Skip to content

Commit fc36794

Browse files
author
Developer
committed
refactor: streamline FS5Advanced API to 4 essential methods
- Remove redundant putWithCID and getMetadataWithCID methods - Users now compose operations: fs.put() + advanced.pathToCID() - Update 37+ tests to use composition pattern - Add composition pattern documentation and examples - Simplify API from 6 to 4 methods while maintaining full functionality - Reduces API surface area by 33% for easier maintenance All 437 tests pass.
1 parent a09b43d commit fc36794

File tree

5 files changed

+120
-393
lines changed

5 files changed

+120
-393
lines changed

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,13 @@ const s5 = await S5.create();
304304
await s5.recoverIdentityFromSeedPhrase(seedPhrase);
305305
const advanced = new FS5Advanced(s5.fs);
306306

307-
// Store data and get both path and CID
308-
const result = await advanced.putWithCID('home/document.txt', 'Important data');
309-
console.log(`Path: ${result.path}`);
310-
console.log(`CID: ${formatCID(result.cid, 'base32')}`);
307+
// Store data and get CID
308+
await s5.fs.put('home/document.txt', 'Important data');
309+
const cid = await advanced.pathToCID('home/document.txt');
310+
console.log(`CID: ${formatCID(cid, 'base32')}`);
311311

312312
// Share the CID string
313-
const cidString = formatCID(result.cid, 'base58btc');
313+
const cidString = formatCID(cid, 'base58btc');
314314

315315
// Recipient: retrieve by CID alone
316316
const receivedCID = parseCID(cidString);
@@ -324,13 +324,15 @@ console.log(path); // "home/document.txt"
324324

325325
### Available Methods
326326

327-
**FS5Advanced Class:**
327+
**FS5Advanced Class (4 essential methods):**
328328
- `pathToCID(path)` - Extract CID from file/directory path
329329
- `cidToPath(cid)` - Find path for a given CID
330-
- `getByCID(cid)` - Retrieve data by CID
331-
- `putByCID(data)` - Store data and return CID
332-
- `putWithCID(path, data)` - Store and get both path and CID
333-
- `getMetadataWithCID(path)` - Get metadata with CID
330+
- `getByCID(cid)` - Retrieve data by CID directly
331+
- `putByCID(data)` - Store content-only and return CID
332+
333+
**Composition Pattern:**
334+
- For path + CID: Use `fs.put(path, data)` then `advanced.pathToCID(path)`
335+
- For metadata + CID: Use `fs.getMetadata(path)` then `advanced.pathToCID(path)`
334336

335337
**CID Utilities:**
336338
- `formatCID(cid, encoding?)` - Format CID as multibase string

docs/API.md

Lines changed: 44 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,84 +2099,58 @@ const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
20992099
const binaryCID = await advanced.putByCID(binaryData);
21002100
```
21012101

2102-
#### putWithCID(path, data, options?)
2102+
### Composition Patterns
21032103

2104-
Store data at a path and return both the path and CID in a single operation.
2104+
The FS5Advanced API is intentionally minimal with just 4 core methods. For common workflows, compose these with regular FS5 methods:
21052105

2106-
```typescript
2107-
async putWithCID(
2108-
path: string,
2109-
data: any,
2110-
options?: PutOptions
2111-
): Promise<{ path: string; cid: Uint8Array }>
2112-
```
2113-
2114-
**Parameters:**
2115-
- `path: string` - The path where to store the data
2116-
- `data: any` - The data to store
2117-
- `options?: PutOptions` - Optional put options (encryption, media type, etc.)
2118-
2119-
**Returns:**
2120-
- `Promise<{ path: string; cid: Uint8Array }>` - Object containing both path and CID
2121-
2122-
**Example:**
2106+
#### Store with Path and Get CID
21232107

21242108
```typescript
2125-
// Store and get both path and CID
2126-
const result = await advanced.putWithCID('home/file.txt', 'Content');
2127-
console.log(result.path); // "home/file.txt"
2128-
console.log(formatCID(result.cid)); // "bafybeif..."
2109+
// Instead of putWithCID(path, data) - use composition:
2110+
await s5.fs.put('home/file.txt', 'Content');
2111+
const cid = await advanced.pathToCID('home/file.txt');
2112+
2113+
console.log(`Stored at: home/file.txt`);
2114+
console.log(`CID: ${formatCID(cid)}`); // "bafybeif..."
21292115

21302116
// With encryption
2131-
const encrypted = await advanced.putWithCID(
2132-
'home/secret.txt',
2133-
'Secret data',
2134-
{ encrypt: true }
2135-
);
2117+
await s5.fs.put('home/secret.txt', 'Secret data', {
2118+
encryption: { algorithm: 'xchacha20-poly1305' }
2119+
});
2120+
const secretCid = await advanced.pathToCID('home/secret.txt');
21362121

21372122
// Can retrieve by either path or CID
21382123
const byPath = await s5.fs.get('home/secret.txt');
2139-
const byCID = await advanced.getByCID(encrypted.cid);
2124+
const byCID = await advanced.getByCID(secretCid);
21402125
console.log(byPath === byCID); // true
21412126
```
21422127

2143-
#### getMetadataWithCID(path)
2144-
2145-
Get metadata for a file or directory along with its CID.
2146-
2147-
```typescript
2148-
async getMetadataWithCID(path: string): Promise<{
2149-
metadata: any;
2150-
cid: Uint8Array;
2151-
}>
2152-
```
2153-
2154-
**Parameters:**
2155-
- `path: string` - The file or directory path
2156-
2157-
**Returns:**
2158-
- `Promise<{ metadata: any; cid: Uint8Array }>` - Object containing metadata and CID
2159-
2160-
**Throws:**
2161-
- `Error` if path does not exist
2162-
2163-
**Example:**
2128+
#### Get Metadata with CID
21642129

21652130
```typescript
2131+
// Instead of getMetadataWithCID(path) - use composition:
21662132
await s5.fs.put('home/data.txt', 'Content');
21672133

2168-
const result = await advanced.getMetadataWithCID('home/data.txt');
2169-
console.log(result.metadata);
2134+
const metadata = await s5.fs.getMetadata('home/data.txt');
2135+
const cid = await advanced.pathToCID('home/data.txt');
2136+
2137+
console.log(metadata);
21702138
// {
21712139
// type: 'file',
21722140
// size: 7,
21732141
// created: 1234567890,
21742142
// modified: 1234567890
21752143
// }
21762144

2177-
console.log(formatCID(result.cid)); // "bafybeih..."
2145+
console.log(formatCID(cid)); // "bafybeih..."
21782146
```
21792147

2148+
**Why Composition?**
2149+
- Keeps API minimal and easy to learn (4 methods vs 6)
2150+
- Makes intent explicit (store *then* extract CID)
2151+
- Reduces maintenance burden
2152+
- Still provides all functionality
2153+
21802154
### CID Utility Functions
21812155

21822156
#### formatCID(cid, encoding?)
@@ -2293,16 +2267,17 @@ import { JSCryptoImplementation } from 's5/core';
22932267
const crypto = new JSCryptoImplementation();
22942268
const data = new TextEncoder().encode('Hello, World!');
22952269
2296-
// Store data
2297-
const result = await advanced.putWithCID('home/data.txt', 'Hello, World!');
2270+
// Store data and get CID
2271+
await s5.fs.put('home/data.txt', 'Hello, World!');
2272+
const cid = await advanced.pathToCID('home/data.txt');
22982273
22992274
// Verify CID matches
2300-
const isValid = await verifyCID(result.cid, data, crypto);
2275+
const isValid = await verifyCID(cid, data, crypto);
23012276
console.log(isValid); // true
23022277
23032278
// Tampered data fails verification
23042279
const tamperedData = new TextEncoder().encode('Goodbye, World!');
2305-
const isInvalid = await verifyCID(result.cid, tamperedData, crypto);
2280+
const isInvalid = await verifyCID(cid, tamperedData, crypto);
23062281
console.log(isInvalid); // false
23072282
```
23082283

@@ -2354,18 +2329,19 @@ await s5.recoverIdentityFromSeedPhrase(seedPhrase);
23542329
const advanced = new FS5Advanced(s5.fs);
23552330
const crypto = new JSCryptoImplementation();
23562331
2357-
// 1. Store data and get CID
2358-
const result = await advanced.putWithCID('home/document.txt', 'Important data');
2359-
console.log(`Stored at: ${result.path}`);
2360-
console.log(`CID: ${formatCID(result.cid, 'base32')}`);
2332+
// 1. Store data and get CID (composition pattern)
2333+
await s5.fs.put('home/document.txt', 'Important data');
2334+
const cid = await advanced.pathToCID('home/document.txt');
2335+
console.log(`Stored at: home/document.txt`);
2336+
console.log(`CID: ${formatCID(cid, 'base32')}`);
23612337
23622338
// 2. Verify the CID
23632339
const data = new TextEncoder().encode('Important data');
2364-
const isValid = await verifyCID(result.cid, data, crypto);
2340+
const isValid = await verifyCID(cid, data, crypto);
23652341
console.log(`CID valid: ${isValid}`); // true
23662342
23672343
// 3. Share the CID (as string)
2368-
const cidString = formatCID(result.cid, 'base58btc');
2344+
const cidString = formatCID(cid, 'base58btc');
23692345
console.log(`Share this CID: ${cidString}`);
23702346
23712347
// 4. Recipient: parse CID and retrieve data
@@ -2377,13 +2353,12 @@ console.log(`Retrieved: ${retrievedData}`); // "Important data"
23772353
const foundPath = await advanced.cidToPath(receivedCID);
23782354
console.log(`Path: ${foundPath}`); // "home/document.txt"
23792355
2380-
// 6. Get metadata with CID
2381-
const metadata = await advanced.getMetadataWithCID(foundPath);
2356+
// 6. Get metadata and CID (composition pattern)
2357+
const metadata = await s5.fs.getMetadata(foundPath);
2358+
const metaCid = await advanced.pathToCID(foundPath);
23822359
console.log(metadata);
2383-
// {
2384-
// metadata: { type: 'file', size: 14, ... },
2385-
// cid: Uint8Array(32) [...]
2386-
// }
2360+
// { type: 'file', size: 14, ... }
2361+
console.log(`CID: ${formatCID(metaCid)}`)
23872362
23882363
// 7. CID-only storage (no path)
23892364
const tempCID = await advanced.putByCID('Temporary content');

src/fs/fs5-advanced.ts

Lines changed: 7 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,19 @@
1414
*
1515
* const advanced = new FS5Advanced(s5.fs);
1616
*
17-
* // Get CID for a file
18-
* const cid = await advanced.pathToCID('home/data.txt');
17+
* // Store content and get CID
18+
* await s5.fs.put('home/file.txt', 'content');
19+
* const cid = await advanced.pathToCID('home/file.txt');
1920
*
2021
* // Retrieve by CID
2122
* const data = await advanced.getByCID(cid);
2223
*
23-
* // Store with both path and CID
24-
* const result = await advanced.putWithCID('home/file.txt', 'content');
25-
* console.log(result.path, result.cid);
24+
* // Store content-only (without path)
25+
* const cidOnly = await advanced.putByCID('anonymous content');
2626
* ```
2727
*/
2828

2929
import type { FS5 } from './fs5.js';
30-
import type { PutOptions } from './dirv1/types.js';
31-
32-
/**
33-
* Result of putWithCID operation
34-
*/
35-
export interface PutWithCIDResult {
36-
path: string;
37-
cid: Uint8Array;
38-
}
39-
40-
/**
41-
* Result of getMetadataWithCID operation
42-
*/
43-
export interface MetadataWithCIDResult {
44-
metadata: any;
45-
cid: Uint8Array;
46-
}
4730

4831
/**
4932
* Advanced CID-aware file system operations
@@ -178,8 +161,8 @@ export class FS5Advanced {
178161
/**
179162
* Store data and return its CID
180163
*
181-
* Note: This stores the data in the content-addressed storage but does not
182-
* assign it a path. Use putWithCID if you want both a path and CID.
164+
* Stores data in content-addressed storage without requiring a user-specified path.
165+
* Useful for content-only storage where you only care about the CID.
183166
*
184167
* @param data - The data to store
185168
* @returns The CID of the stored data
@@ -206,69 +189,6 @@ export class FS5Advanced {
206189
return cid;
207190
}
208191

209-
/**
210-
* Store data at path and return both path and CID
211-
*
212-
* @param path - The path where to store the data
213-
* @param data - The data to store
214-
* @param options - Optional put options
215-
* @returns Object containing both path and CID
216-
*
217-
* @example
218-
* ```typescript
219-
* const result = await advanced.putWithCID('home/file.txt', 'content');
220-
* console.log(result.path); // 'home/file.txt'
221-
* console.log(result.cid); // Uint8Array(32) [...]
222-
* ```
223-
*/
224-
async putWithCID(
225-
path: string,
226-
data: any,
227-
options?: PutOptions
228-
): Promise<PutWithCIDResult> {
229-
// Store using path-based API
230-
await this.fs5.put(path, data, options);
231-
232-
// Extract CID
233-
const cid = await this.pathToCID(path);
234-
235-
return {
236-
path,
237-
cid,
238-
};
239-
}
240-
241-
/**
242-
* Get metadata with CID for a file or directory
243-
*
244-
* @param path - The file or directory path
245-
* @returns Object containing metadata and CID
246-
* @throws Error if path does not exist
247-
*
248-
* @example
249-
* ```typescript
250-
* const result = await advanced.getMetadataWithCID('home/file.txt');
251-
* console.log(result.metadata); // { type: 'file', size: 123, ... }
252-
* console.log(result.cid); // Uint8Array(32) [...]
253-
* ```
254-
*/
255-
async getMetadataWithCID(path: string): Promise<MetadataWithCIDResult> {
256-
// Get metadata using path-based API
257-
const metadata = await this.fs5.getMetadata(path);
258-
259-
if (!metadata) {
260-
throw new Error(`Path not found: ${path}`);
261-
}
262-
263-
// Extract CID
264-
const cid = await this.pathToCID(path);
265-
266-
return {
267-
metadata,
268-
cid,
269-
};
270-
}
271-
272192
// Private helper methods
273193

274194
/**

0 commit comments

Comments
 (0)