Advanced CID API
The Advanced CID API provides direct access to Content Identifiers (CIDs) for power users who need content-addressed storage capabilities.
Overview
Section titled “Overview”Enhanced s5.js provides two APIs:
- Path-based API - Simple filesystem-like operations (recommended for most apps)
- Advanced CID API - Content-addressed storage for power users
The Advanced CID API is exported separately (
@julesl23/s5js/advanced) and does not affect the simplicity of the standard path-based API.
When to Use
Section titled “When to Use”Use the Advanced CID API when you need:
- Content-addressed storage (reference data by cryptographic hash)
- Content deduplication or verification
- Distributed systems that use CIDs
- Track content independently of file paths
- Build content-addressed applications
Use the Path-based API for:
- Simple file storage and retrieval (most use cases)
- Traditional file system operations
- User-facing applications
- When paths are more meaningful than hashes
Installation
Section titled “Installation”import { S5 } from '@julesl23/s5js';import { FS5Advanced, formatCID, parseCID, verifyCID } from '@julesl23/s5js/advanced';Bundle Size: 60.60 KB (brotli) - includes core + CID utilities
FS5Advanced Class
Section titled “FS5Advanced Class”The FS5Advanced class wraps an FS5 instance to provide CID-aware operations.
Constructor
Section titled “Constructor”const advanced = new FS5Advanced(s5.fs);Core Methods
Section titled “Core Methods”pathToCID(path)
Section titled “pathToCID(path)”Extract the CID (Content Identifier) from a file or directory path.
async pathToCID(path: string): Promise<Uint8Array>Example:
// Store a fileawait s5.fs.put('home/data.txt', 'Hello, World!');
// Extract its CIDconst advanced = new FS5Advanced(s5.fs);const cid = await advanced.pathToCID('home/data.txt');
// Format for displayconst formatted = formatCID(cid, 'base32');console.log(formatted); // "bafybeig..."cidToPath(cid)
Section titled “cidToPath(cid)”Find the path for a given CID.
async cidToPath(cid: Uint8Array): Promise<string | null>Example:
const cid = await advanced.pathToCID('home/data.txt');
// Find path from CIDconst path = await advanced.cidToPath(cid);console.log(path); // "home/data.txt"
// Returns null if CID not foundconst missing = await advanced.cidToPath(someCID);console.log(missing); // nullNote (beta.50+): if a directory in the search is temporarily unavailable (transient network 404),
cidToPath()throws a retryableS5DirectoryLoadErrorinstead of returning a falsenull(“CID not found”). Retry with backoff — see Error Handling.nullnow reliably means the CID genuinely isn’t referenced anywhere in your tree.
getByCID(cid)
Section titled “getByCID(cid)”Retrieve data directly by its CID without knowing the path.
async getByCID(cid: Uint8Array): Promise<any | undefined>Example:
// Retrieve data by CIDconst data = await advanced.getByCID(cid);console.log(data); // "Hello, World!"
// Works even if path is unknownconst cidString = 'bafybeig...';const parsedCID = parseCID(cidString);const content = await advanced.getByCID(parsedCID);putByCID(data)
Section titled “putByCID(data)”Store data without assigning a path (content-only storage).
async putByCID(data: any): Promise<Uint8Array>Example:
// Store content without pathconst cid = await advanced.putByCID('Temporary data');console.log(formatCID(cid)); // "bafybeig..."
// Retrieve later by CIDconst data = await advanced.getByCID(cid);console.log(data); // "Temporary data"CID Utility Functions
Section titled “CID Utility Functions”formatCID(cid, format?)
Section titled “formatCID(cid, format?)”Convert a CID from bytes to a formatted string.
function formatCID(cid: Uint8Array, format?: 'base32' | 'base58btc' | 'hex'): stringFormats:
base32- Multibase base32 withbafybprefix (default)base58btc- Multibase base58btc withzb2rhprefixhex- Hexadecimal (for debugging)
Example:
const cid = await advanced.pathToCID('home/file.txt');
// Base32 (IPFS/S5 standard)console.log(formatCID(cid, 'base32'));// "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
// Base58btc (Bitcoin-style)console.log(formatCID(cid, 'base58btc'));// "zb2rhk6GMPQF8p1NMJEqvJ3XFfNBqJNfiXzJaJkPiA9kMvNaJ"
// Hex (debugging)console.log(formatCID(cid, 'hex'));// "1a2b3c..."parseCID(cidString)
Section titled “parseCID(cidString)”Parse a formatted CID string back to bytes.
function parseCID(cidString: string): Uint8ArraySupported Formats:
- Base32 with prefix:
"bafybei..." - Base32 without prefix:
"afybei..." - Base58btc with prefix:
"zb2rh..." - Base58btc without prefix:
"Qm..." - Base64 with prefix:
"mAXASI..." - Hex:
"1a2b3c..."
Example:
// Parse base32const cid1 = parseCID('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi');
// Parse base58btcconst cid2 = parseCID('zb2rhk6GMPQF8p1NMJEqvJ3XFfNBqJNfiXzJaJkPiA9kMvNaJ');
// Parse without prefix (auto-detect)const cid3 = parseCID('afybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi');verifyCID(cid, data, crypto)
Section titled “verifyCID(cid, data, crypto)”Verify that a CID matches the given data by recomputing the hash.
async function verifyCID( cid: Uint8Array, data: Uint8Array, crypto: CryptoImplementation): Promise<boolean>Example:
import { JSCryptoImplementation } from '@julesl23/s5js';
const crypto = new JSCryptoImplementation();const data = new TextEncoder().encode('Hello, World!');
// Verify CID matchesconst isValid = await verifyCID(cid, data, s5.api.crypto);console.log(isValid); // true
// Tampered data fails verificationconst tamperedData = new TextEncoder().encode('Goodbye, World!');const isInvalid = await verifyCID(cid, tamperedData, s5.api.crypto);console.log(isInvalid); // falsecidToString(cid)
Section titled “cidToString(cid)”Convert a CID to hexadecimal string for debugging.
function cidToString(cid: Uint8Array): stringExample:
const cid = await advanced.pathToCID('home/file.txt');console.log(cidToString(cid));// "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"Complete Workflow Example
Section titled “Complete Workflow Example”import { S5 } from '@julesl23/s5js';import { FS5Advanced, formatCID, parseCID, verifyCID } from '@julesl23/s5js/advanced';
// Initialize S5const s5 = await S5.create();const seedPhrase = generatePhrase(s5.api.crypto);await s5.recoverIdentityFromSeedPhrase(seedPhrase);
// Create Advanced APIconst advanced = new FS5Advanced(s5.fs);
// 1. Store data using path-based APIawait s5.fs.put('home/document.txt', 'Important data');
// 2. Get the CIDconst cid = await advanced.pathToCID('home/document.txt');const cidString = formatCID(cid, 'base32');console.log(`CID: ${cidString}`);
// 3. Verify the CIDconst data = new TextEncoder().encode('Important data');const isValid = await verifyCID(cid, data, s5.api.crypto);console.log(`Valid: ${isValid}`); // true
// 4. Share the CID (someone else can retrieve)const sharedCID = cidString;
// 5. Recipient: parse CID and retrieve dataconst receivedCID = parseCID(sharedCID);const retrievedData = await advanced.getByCID(receivedCID);console.log(`Data: ${retrievedData}`); // "Important data"
// 6. Find path from CIDconst path = await advanced.cidToPath(receivedCID);console.log(`Path: ${path}`); // "home/document.txt"Composition Pattern
Section titled “Composition Pattern”Combine path-based API with CID utilities:
// Store with pathawait s5.fs.put('home/photo.jpg', imageBlob);
// Get metadata and CIDconst metadata = await s5.fs.getMetadata('home/photo.jpg');const cid = await advanced.pathToCID('home/photo.jpg');
console.log({ path: 'home/photo.jpg', size: metadata.size, cid: formatCID(cid)});Use Cases
Section titled “Use Cases”Content Deduplication
Section titled “Content Deduplication”// Check if content already existsconst newFileCID = await advanced.putByCID(newFileData);const existingPath = await advanced.cidToPath(newFileCID);
if (existingPath) { console.log(`Content already exists at: ${existingPath}`);} else { // Store with path await s5.fs.put('home/new-file.txt', newFileData);}Content Verification
Section titled “Content Verification”// Verify downloaded file matches expected CIDconst expectedCID = parseCID('bafybei...');const downloadedData = await advanced.getByCID(expectedCID);const isValid = await verifyCID(expectedCID, downloadedData, s5.api.crypto);
if (!isValid) { throw new Error('Downloaded data corrupted!');}Distributed File System
Section titled “Distributed File System”// Share CID instead of path (content-addressed)const cid = await advanced.pathToCID('home/shared-file.pdf');const shareLink = `s5://${formatCID(cid, 'base32')}`;
// Anyone with the CID can retrieveconst data = await advanced.getByCID(parseCID(shareLink.slice(5)));Public Sharing Between Users
Section titled “Public Sharing Between Users”The downloadByCID method enables true public sharing - one user uploads content, shares the CID, and another user downloads it from S5 portals:
// === User A: Upload and share ===const s5a = await S5.create();await s5a.recoverIdentityFromSeedPhrase(seedPhraseA);await s5a.registerOnNewPortal('https://s5.ninja');
// Upload contentawait s5a.fs.put('home/public/photo.jpg', imageData);
// Get CID and shareconst advanced = new FS5Advanced(s5a.fs);const cid = await advanced.pathToCID('home/public/photo.jpg');const cidString = formatCID(cid);console.log('Share this CID:', cidString);// e.g., "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
// === User B: Download by CID ===const s5b = await S5.create();await s5b.recoverIdentityFromSeedPhrase(seedPhraseB);await s5b.registerOnNewPortal('https://s5.ninja');
// Download using the shared CIDconst downloadedData = await s5b.downloadByCID(cidString);console.log('Downloaded:', downloadedData.length, 'bytes');How it works:
- User A uploads content (stored on S5 network via portal)
- User A extracts the CID (32-byte BLAKE3 hash)
- User A shares the CID string (53 or 59 characters)
- User B downloads from any configured portal using the CID
- Downloaded data is verified against the CID hash
CID Formats Supported:
- 53-char format: Raw 32-byte BLAKE3 hash (
b+ 52 base32 chars) - 59-char format: BlobIdentifier with prefix + hash + size
TypeScript Types
Section titled “TypeScript Types”interface PutWithCIDResult { cid: Uint8Array;}
interface MetadataWithCIDResult { type: 'file' | 'directory'; name: string; size?: number; cid: Uint8Array;}
type CIDFormat = 'base32' | 'base58btc' | 'hex';Performance
Section titled “Performance”CID operations add minimal overhead:
- pathToCID: O(1) - reads directory metadata
- cidToPath: O(n) - searches directory tree
- getByCID: O(1) - direct retrieval
- putByCID: O(1) - direct storage
- formatCID: O(1) - base encoding
- parseCID: O(1) - base decoding
- verifyCID: O(n) - rehashes data
Next Steps
Section titled “Next Steps”- Path-based API - Standard file operations
- Cross-Identity Public Directory Access - Multi-user reads and live subscriptions using shared public keys (a different kind of “public content” than CID-addressed blobs)
- Performance & Scaling - Optimize large datasets
- API Reference - Complete API documentation
- S5 CID Specification - CID format details