Understanding Swarm Manifests and How to Manipulate Them with Mantaray-js

Swarm manifests are Merkle-DAG structures that map human-readable paths to content-addressed chunks, and Mantaray-js is the low-level JavaScript library that enables direct creation, serialization, and manipulation of these manifests in Node.js or browser environments.

Swarm organizes data as immutable chunks addressed by their hash, but serving websites or directories requires a mapping layer called a manifest. The ethersphere/awesome-swarm repository lists Mantaray-js as the primary tool for manipulating these structures, providing a pure JavaScript implementation of the manifest data format without network-layer dependencies.

What Are Swarm Manifests?

Swarm manifests are Merkle-DAGs (Directed Acyclic Graphs) that bridge human-readable file paths with content-addressed storage. Each manifest node contains a list of entries, where every entry records four critical fields:

  • path: A UTF-8 string representing the filename or directory component
  • hash: The Swarm hash of the referenced chunk or sub-manifest
  • metadata: Optional JSON-serializable data such as MIME type or file size
  • mode: Unix-like permission bits used by Swarm's POSIX compatibility layer

Because manifests themselves are content-addressed, any modification produces a new root hash while preserving unchanged sub-trees. This immutability enables version-control-style properties and content-addressable URLs in the format bzz:/<root-hash>/path.

The Mantaray-js Architecture

Mantaray-js implements the manifest data structure and serialization logic required to interact with Swarm manifests directly. According to the ethersphere/awesome-swarm source code, this library is referenced as the primary resource for low-level manifest manipulation.

Core Components

The library centers on two primary classes:

MantarayNode (implemented in src/node.ts) represents a single manifest node. It maintains a map of entries (path → MantarayFork) and provides methods for adding, removing, and looking up entries.

MantarayFork (defined in src/fork.ts) wraps the raw Swarm hash alongside entry metadata and mode permissions. This is the atomic unit written to and read from the Swarm network.

Serialization and Traversal

The serialize and deserialize functions (located in src/serialization.ts) convert between the in-memory MantarayNode representation and the binary format expected by Swarm's HTTP gateway. The walk utility (in src/walk.ts) provides depth-first traversal for generating file lists or applying transformations across all entries.

Mantaray-js deliberately avoids network concerns—higher-level tools like bee-js handle uploading the binary blobs produced by this library.

Working with Manifests: A Practical Workflow

Manipulating manifests follows a consistent four-step pattern: create, populate, serialize, and upload. Because manifests are Merkle-DAGs, only changed branches require re-uploading during updates.

Creating a New Manifest and Adding Files

Start with an empty MantarayNode and add file entries wrapped in MantarayFork instances:

import { MantarayNode, MantarayFork } from 'mantaray-js';

// Helper – placeholder for actual Swarm hashing
async function hashChunk(data) {
  return '0x' + Buffer.from(data).toString('hex').slice(0, 64);
}

// Initialize empty manifest
const root = new MantarayNode();

// Prepare file content and compute hash
const fileContent = new TextEncoder().encode('<!DOCTYPE html><html>…</html>');
const fileHash = await hashChunk(fileContent);

// Create fork with metadata
const fork = new MantarayFork({
  hash: fileHash,
  metadata: { mime: 'text/html' },
  mode: 0o644,
});

// Add entry to manifest
await root.addEntry('index.html', fork);

// Serialize for upload
const manifestBinary = root.serialize();

The resulting Uint8Array can be POSTed to a Swarm node's /bzz:/ endpoint to obtain the manifest root hash.

Loading and Listing Entries

To inspect an existing manifest, deserialize the binary payload and traverse the tree:

import { MantarayNode } from 'mantaray-js';

// manifestBinary retrieved from Swarm via GET /bzz:/<rootHash>
const root = MantarayNode.deserialize(manifestBinary);

const entries = [];
root.walk((path, fork) => {
  entries.push({ 
    path, 
    hash: fork.hash, 
    mime: fork.metadata?.mime 
  });
});

console.log('Manifest contents:', entries);

Updating Files in Existing Manifests

Manifest immutability means "updating" creates a new version. Modify the node, then re-serialize:

import { MantarayFork } from 'mantaray-js';

const newContent = new TextEncoder().encode('Updated content');
const newHash = await hashChunk(newContent);

const updatedFork = new MantarayFork({
  hash: newHash,
  metadata: { mime: 'text/plain' },
  mode: 0o644,
});

// Overwrites existing path if present
await root.addEntry('readme.txt', updatedFork);
const updatedManifest = root.serialize();

Removing Entries

Delete paths using removeEntry, which returns true if the path existed:

const removed = await root.removeEntry('old-file.jpg');
if (removed) {
  console.log('Entry removed – re-upload manifest to finalize.');
}

Key Implementation Files

The Mantaray-js source structure reflects its architectural separation of concerns as catalogued in the ethersphere/awesome-swarm repository:

  • src/node.ts – Implements MantarayNode with entry management methods
  • src/fork.ts – Defines MantarayFork, the hash-plus-metadata wrapper used in manifest entries
  • src/serialization.ts – Contains binary encoding/decoding logic for Swarm HTTP API compatibility
  • src/walk.ts – Provides tree traversal utilities for manifest inspection and transformation

Summary

  • Swarm manifests are Merkle-DAGs that map paths to content-addressed chunks, storing path, hash, metadata, and mode in each entry.
  • Mantaray-js provides the low-level JavaScript implementation for creating and manipulating these structures without network dependencies.
  • Key classes include MantarayNode (entry container) and MantarayFork (hash wrapper with metadata), implemented in src/node.ts and src/fork.ts respectively.
  • The serialize and deserialize functions handle binary conversion for Swarm HTTP API compatibility.
  • Only modified branches require re-uploading due to the Merkle-DAG structure, making updates efficient for large datasets.

Frequently Asked Questions

How does Mantaray-js differ from bee-js?

Mantaray-js handles only the data structure and binary serialization of Swarm manifests, while bee-js manages network operations, chunk uploading, and node communication. Use Mantaray-js to build manifest binaries, then use bee-js or swarm-cli to upload them to a Swarm node.

What is the binary format produced by Mantaray-js?

The serialize method produces a Uint8Array containing the compact binary representation of the manifest Merkle-DAG. This format is recognized by Swarm's HTTP gateway at endpoints like POST /bzz:/ and GET /bzz:/<root-hash>/path.

Can Mantaray-js handle large directory structures?

Yes. The Merkle-DAG structure means Mantaray-js can represent deeply nested directories efficiently. The walk utility in src/walk.ts performs depth-first traversal without loading the entire tree into memory at once, enabling processing of large manifests.

What metadata can be stored in a MantarayFork?

The metadata field accepts any JSON-serializable object, commonly used for mime (MIME type), size (file size), and custom application data. The mode field stores Unix-style permission bits for POSIX compatibility.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →