@ckbfs/api 1.2.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -7,10 +7,10 @@ import {
7
7
  } from './utils/checksum';
8
8
  import {
9
9
  createCKBFSCell,
10
- createPublishTransaction,
11
- createAppendTransaction,
12
- publishCKBFS,
13
- appendCKBFS,
10
+ createPublishTransaction as utilCreatePublishTransaction,
11
+ createAppendTransaction as utilCreateAppendTransaction,
12
+ publishCKBFS as utilPublishCKBFS,
13
+ appendCKBFS as utilAppendCKBFS,
14
14
  CKBFSCellOptions,
15
15
  PublishOptions,
16
16
  AppendOptions
@@ -56,6 +56,10 @@ import {
56
56
  getCKBFSScriptConfig,
57
57
  CKBFSScriptConfig
58
58
  } from './utils/constants';
59
+ import { ensureHexPrefix } from './utils/transaction';
60
+
61
+ // Helper to encode string to Uint8Array
62
+ const textEncoder = new TextEncoder();
59
63
 
60
64
  /**
61
65
  * Custom options for file publishing and appending
@@ -70,6 +74,19 @@ export interface FileOptions {
70
74
  useTypeID?: boolean;
71
75
  }
72
76
 
77
+ /**
78
+ * Options required when publishing content directly (string or Uint8Array)
79
+ */
80
+ export type PublishContentOptions = Omit<FileOptions, 'capacity' | 'contentType' | 'filename'> &
81
+ Required<Pick<FileOptions, 'contentType' | 'filename'>> &
82
+ { capacity?: bigint };
83
+
84
+ /**
85
+ * Options required when appending content directly (string or Uint8Array)
86
+ */
87
+ export type AppendContentOptions = Omit<FileOptions, 'contentType' | 'filename' | 'capacity'> &
88
+ { capacity?: bigint };
89
+
73
90
  /**
74
91
  * Configuration options for the CKBFS SDK
75
92
  */
@@ -176,8 +193,8 @@ export class CKBFS {
176
193
  const pathParts = filePath.split(/[\\\/]/);
177
194
  const filename = options.filename || pathParts[pathParts.length - 1];
178
195
 
179
- // Create and sign the transaction
180
- const tx = await publishCKBFS(this.signer, {
196
+ // Create and sign the transaction using the utility function
197
+ const tx = await utilPublishCKBFS(this.signer, {
181
198
  contentChunks,
182
199
  contentType,
183
200
  filename,
@@ -189,16 +206,53 @@ export class CKBFS {
189
206
  useTypeID: options.useTypeID !== undefined ? options.useTypeID : this.useTypeID
190
207
  });
191
208
 
192
- console.log('tx', tx.stringify());
209
+ console.log('Publish file tx:', tx.stringify());
193
210
 
194
211
  // Send the transaction
195
212
  const txHash = await this.signer.sendTransaction(tx);
196
213
 
197
- return txHash;
214
+ return ensureHexPrefix(txHash);
215
+ }
216
+
217
+ /**
218
+ * Publishes content (string or Uint8Array) directly to CKBFS
219
+ * @param content The content string or byte array to publish
220
+ * @param options Options for publishing the content (contentType and filename are required)
221
+ * @returns Promise resolving to the transaction hash
222
+ */
223
+ async publishContent(content: string | Uint8Array, options: PublishContentOptions): Promise<string> {
224
+ const contentBytes = typeof content === 'string' ? textEncoder.encode(content) : content;
225
+ const contentChunks = [];
226
+
227
+ for (let i = 0; i < contentBytes.length; i += this.chunkSize) {
228
+ contentChunks.push(contentBytes.slice(i, i + this.chunkSize));
229
+ }
230
+
231
+ const lock = await this.getLock();
232
+
233
+ // Use provided contentType and filename (required)
234
+ const { contentType, filename } = options;
235
+
236
+ const tx = await utilPublishCKBFS(this.signer, {
237
+ contentChunks,
238
+ contentType,
239
+ filename,
240
+ lock,
241
+ capacity: options.capacity,
242
+ feeRate: options.feeRate,
243
+ network: options.network || this.network,
244
+ version: options.version || this.version,
245
+ useTypeID: options.useTypeID !== undefined ? options.useTypeID : this.useTypeID
246
+ });
247
+
248
+ console.log('Publish content tx:', tx.stringify());
249
+
250
+ const txHash = await this.signer.sendTransaction(tx);
251
+ return ensureHexPrefix(txHash);
198
252
  }
199
253
 
200
254
  /**
201
- * Appends content to an existing CKBFS file
255
+ * Appends content from a file to an existing CKBFS file
202
256
  * @param filePath The path to the file containing the content to append
203
257
  * @param ckbfsCell The CKBFS cell to append to
204
258
  * @param options Additional options for the append operation
@@ -217,19 +271,55 @@ export class CKBFS {
217
271
  contentChunks.push(fileContent.slice(i, i + this.chunkSize));
218
272
  }
219
273
 
220
- // Create and sign the transaction
221
- const tx = await appendCKBFS(this.signer, {
274
+ // Create and sign the transaction using the utility function
275
+ const tx = await utilAppendCKBFS(this.signer, {
222
276
  ckbfsCell,
223
277
  contentChunks,
224
278
  feeRate: options.feeRate,
225
279
  network: options.network || this.network,
226
280
  version: options.version || this.version
227
281
  });
282
+
283
+ console.log('Append file tx:', tx.stringify());
228
284
 
229
285
  // Send the transaction
230
286
  const txHash = await this.signer.sendTransaction(tx);
231
287
 
232
- return txHash;
288
+ return ensureHexPrefix(txHash);
289
+ }
290
+
291
+ /**
292
+ * Appends content (string or Uint8Array) directly to an existing CKBFS file
293
+ * @param content The content string or byte array to append
294
+ * @param ckbfsCell The CKBFS cell to append to
295
+ * @param options Additional options for the append operation
296
+ * @returns Promise resolving to the transaction hash
297
+ */
298
+ async appendContent(
299
+ content: string | Uint8Array,
300
+ ckbfsCell: AppendOptions['ckbfsCell'],
301
+ options: AppendContentOptions = {}
302
+ ): Promise<string> {
303
+ const contentBytes = typeof content === 'string' ? textEncoder.encode(content) : content;
304
+ const contentChunks = [];
305
+
306
+ for (let i = 0; i < contentBytes.length; i += this.chunkSize) {
307
+ contentChunks.push(contentBytes.slice(i, i + this.chunkSize));
308
+ }
309
+
310
+ const tx = await utilAppendCKBFS(this.signer, {
311
+ ckbfsCell,
312
+ contentChunks,
313
+ feeRate: options.feeRate,
314
+ network: options.network || this.network,
315
+ version: options.version || this.version
316
+ // No useTypeID option for append
317
+ });
318
+
319
+ console.log('Append content tx:', tx.stringify());
320
+
321
+ const txHash = await this.signer.sendTransaction(tx);
322
+ return ensureHexPrefix(txHash);
233
323
  }
234
324
 
235
325
  /**
@@ -257,8 +347,40 @@ export class CKBFS {
257
347
  const pathParts = filePath.split(/[\\\/]/);
258
348
  const filename = options.filename || pathParts[pathParts.length - 1];
259
349
 
260
- // Create the transaction
261
- return createPublishTransaction(this.signer, {
350
+ // Create the transaction using the utility function
351
+ return utilCreatePublishTransaction(this.signer, {
352
+ contentChunks,
353
+ contentType,
354
+ filename,
355
+ lock,
356
+ capacity: options.capacity,
357
+ feeRate: options.feeRate,
358
+ network: options.network || this.network,
359
+ version: options.version || this.version,
360
+ useTypeID: options.useTypeID !== undefined ? options.useTypeID : this.useTypeID
361
+ });
362
+ }
363
+
364
+ /**
365
+ * Creates a new transaction for publishing content (string or Uint8Array) directly, but doesn't sign or send it
366
+ * @param content The content string or byte array to publish
367
+ * @param options Options for publishing the content (contentType and filename are required)
368
+ * @returns Promise resolving to the unsigned transaction
369
+ */
370
+ async createPublishContentTransaction(content: string | Uint8Array, options: PublishContentOptions): Promise<Transaction> {
371
+ const contentBytes = typeof content === 'string' ? textEncoder.encode(content) : content;
372
+ const contentChunks = [];
373
+
374
+ for (let i = 0; i < contentBytes.length; i += this.chunkSize) {
375
+ contentChunks.push(contentBytes.slice(i, i + this.chunkSize));
376
+ }
377
+
378
+ const lock = await this.getLock();
379
+
380
+ // Use provided contentType and filename (required)
381
+ const { contentType, filename } = options;
382
+
383
+ return utilCreatePublishTransaction(this.signer, {
262
384
  contentChunks,
263
385
  contentType,
264
386
  filename,
@@ -272,7 +394,7 @@ export class CKBFS {
272
394
  }
273
395
 
274
396
  /**
275
- * Creates a new transaction for appending content but doesn't sign or send it
397
+ * Creates a new transaction for appending content from a file but doesn't sign or send it
276
398
  * @param filePath The path to the file containing the content to append
277
399
  * @param ckbfsCell The CKBFS cell to append to
278
400
  * @param options Additional options for the append operation
@@ -291,13 +413,42 @@ export class CKBFS {
291
413
  contentChunks.push(fileContent.slice(i, i + this.chunkSize));
292
414
  }
293
415
 
294
- // Create the transaction
295
- return createAppendTransaction(this.signer, {
416
+ // Create the transaction using the utility function
417
+ return utilCreateAppendTransaction(this.signer, {
418
+ ckbfsCell,
419
+ contentChunks,
420
+ feeRate: options.feeRate,
421
+ network: options.network || this.network,
422
+ version: options.version || this.version
423
+ });
424
+ }
425
+
426
+ /**
427
+ * Creates a new transaction for appending content (string or Uint8Array) directly, but doesn't sign or send it
428
+ * @param content The content string or byte array to append
429
+ * @param ckbfsCell The CKBFS cell to append to
430
+ * @param options Additional options for the append operation
431
+ * @returns Promise resolving to the unsigned transaction
432
+ */
433
+ async createAppendContentTransaction(
434
+ content: string | Uint8Array,
435
+ ckbfsCell: AppendOptions['ckbfsCell'],
436
+ options: AppendContentOptions = {}
437
+ ): Promise<Transaction> {
438
+ const contentBytes = typeof content === 'string' ? textEncoder.encode(content) : content;
439
+ const contentChunks = [];
440
+
441
+ for (let i = 0; i < contentBytes.length; i += this.chunkSize) {
442
+ contentChunks.push(contentBytes.slice(i, i + this.chunkSize));
443
+ }
444
+
445
+ return utilCreateAppendTransaction(this.signer, {
296
446
  ckbfsCell,
297
447
  contentChunks,
298
448
  feeRate: options.feeRate,
299
449
  network: options.network || this.network,
300
450
  version: options.version || this.version
451
+ // No useTypeID option for append
301
452
  });
302
453
  }
303
454
  }
@@ -310,12 +461,12 @@ export {
310
461
  updateChecksum,
311
462
  verifyWitnessChecksum,
312
463
 
313
- // Transaction utilities
464
+ // Transaction utilities (Exporting original names from transaction.ts)
314
465
  createCKBFSCell,
315
- createPublishTransaction,
316
- createAppendTransaction,
317
- publishCKBFS,
318
- appendCKBFS,
466
+ utilCreatePublishTransaction as createPublishTransaction,
467
+ utilCreateAppendTransaction as createAppendTransaction,
468
+ utilPublishCKBFS as publishCKBFS,
469
+ utilAppendCKBFS as appendCKBFS,
319
470
 
320
471
  // File utilities
321
472
  readFile,
@@ -57,7 +57,7 @@ export interface AppendOptions {
57
57
  * @param value The string to ensure is hex prefixed
58
58
  * @returns A hex prefixed string
59
59
  */
60
- function ensureHexPrefix(value: string): `0x${string}` {
60
+ export function ensureHexPrefix(value: string): `0x${string}` {
61
61
  if (value.startsWith('0x')) {
62
62
  return value as `0x${string}`;
63
63
  }
@@ -1,49 +0,0 @@
1
- ---
2
- description:
3
- globs:
4
- alwaysApply: true
5
- ---
6
-
7
- You are an expert in TypeScript, Node.js, Next.js App Router, React, Shadcn UI, Radix UI and Tailwind.
8
-
9
- Code Style and Structure
10
- - Write concise, technical TypeScript code with accurate examples.
11
- - Use functional and declarative programming patterns; avoid classes.
12
- - Prefer iteration and modularization over code duplication.
13
- - Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
14
- - Structure files: exported component, subcomponents, helpers, static content, types.
15
-
16
- Naming Conventions
17
- - Use lowercase with dashes for directories (e.g., components/auth-wizard).
18
- - Favor named exports for components.
19
-
20
- TypeScript Usage
21
- - Use TypeScript for all code; prefer interfaces over types.
22
- - Avoid enums; use maps instead.
23
- - Use functional components with TypeScript interfaces.
24
-
25
- Syntax and Formatting
26
- - Use the "function" keyword for pure functions.
27
- - Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
28
- - Use declarative JSX.
29
-
30
- UI and Styling
31
- - Use Shadcn UI, Radix, and Tailwind for components and styling.
32
- - Implement responsive design with Tailwind CSS; use a mobile-first approach.
33
-
34
- Performance Optimization
35
- - Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).
36
- - Wrap client components in Suspense with fallback.
37
- - Use dynamic loading for non-critical components.
38
- - Optimize images: use WebP format, include size data, implement lazy loading.
39
-
40
- Key Conventions
41
- - Use 'nuqs' for URL search parameter state management.
42
- - Optimize Web Vitals (LCP, CLS, FID).
43
- - Limit 'use client':
44
- - Favor server components and Next.js SSR.
45
- - Use only for Web API access in small components.
46
- - Avoid for data fetching or state management.
47
-
48
- Follow Next.js docs for Data Fetching, Rendering, and Routing.
49
-
package/ABC.LOGS DELETED
@@ -1 +0,0 @@
1
- MINT,TO:ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsqdpallzwnhe64rqnqmev7hf98yrmh4yzucgdw7qwGIVE_NAME,NEW_NAME:NERVAPE_COOKIE
package/README.md DELETED
@@ -1,138 +0,0 @@
1
- # CKBFS API SDK
2
-
3
- A JavaScript/TypeScript SDK for the CKBFS (Cell Knowledge Base File System) protocol on Nervos CKB.
4
-
5
- ## Overview
6
-
7
- CKBFS is a protocol designed to describe a witnesses-based file storage system on Nervos CKB Network. With CKBFS, you can:
8
-
9
- - Store files on Nervos CKB Network
10
- - Publish large files that may exceed block size limitation (~500kb), across multiple blocks
11
- - Maintain simple indexing and retrieval
12
-
13
- This SDK provides a simple way to interact with the CKBFS protocol, allowing you to:
14
-
15
- - Read and write files to CKB
16
- - Calculate and verify Adler32 checksums
17
- - Create, manage, and update CKBFS cells
18
- - Handle witnesses creation and verification
19
- - Create and send CKB transactions for file operations
20
-
21
- ## Installation
22
-
23
- ```bash
24
- npm install ckbfs-api
25
- ```
26
-
27
- ## Basic Usage
28
-
29
- ```typescript
30
- import { CKBFS } from 'ckbfs-api';
31
-
32
- // Initialize the SDK with your private key
33
- const privateKey = process.env.CKB_PRIVATE_KEY;
34
- const ckbfs = new CKBFS(privateKey);
35
-
36
- // Publish a file to CKBFS
37
- async function publishExample() {
38
- const txHash = await ckbfs.publishFile('path/to/your/file.txt');
39
- console.log(`File published with transaction: ${txHash}`);
40
- }
41
-
42
- // Append content to an existing CKBFS file
43
- async function appendExample(ckbfsCell) {
44
- const txHash = await ckbfs.appendFile('path/to/more/content.txt', ckbfsCell);
45
- console.log(`Content appended with transaction: ${txHash}`);
46
- }
47
- ```
48
-
49
- ## Advanced Usage
50
-
51
- The SDK provides utility functions for more granular control:
52
-
53
- ### Working with Files
54
-
55
- ```typescript
56
- import { readFileAsUint8Array, splitFileIntoChunks } from 'ckbfs-api';
57
-
58
- // Read a file
59
- const fileContent = readFileAsUint8Array('path/to/file.txt');
60
-
61
- // Split a file into chunks (e.g., for large files)
62
- const chunks = splitFileIntoChunks('path/to/large/file.bin', 30 * 1024); // 30KB chunks
63
- ```
64
-
65
- ### Checksum Operations
66
-
67
- ```typescript
68
- import { calculateChecksum, verifyChecksum } from 'ckbfs-api';
69
-
70
- // Calculate Adler32 checksum
71
- const content = new TextEncoder().encode('Hello CKBFS');
72
- const checksum = await calculateChecksum(content);
73
-
74
- // Verify checksum
75
- const isValid = await verifyChecksum(content, checksum);
76
- ```
77
-
78
- ### Transaction Utilities
79
-
80
- ```typescript
81
- import { createPublishTransaction, createAppendTransaction } from 'ckbfs-api';
82
-
83
- // Create a transaction without signing or sending
84
- const tx = await ckbfs.createPublishTransaction('path/to/file.txt');
85
-
86
- // Customize the transaction before signing
87
- // ... modify tx ...
88
-
89
- // Sign and send manually
90
- const signedTx = await signer.signTransaction(tx);
91
- const txHash = await client.sendTransaction(signedTx);
92
- ```
93
-
94
- ## Examples
95
-
96
- The SDK comes with several examples demonstrating how to use it:
97
-
98
- ### Running Examples
99
-
100
- ```bash
101
- # Show available examples
102
- npm run example
103
-
104
- # Run the publish file example
105
- npm run example:publish
106
-
107
- # Run the append file example (requires a transaction hash)
108
- npm run example:append -- --txhash=0x123456...
109
- # OR
110
- PUBLISH_TX_HASH=0x123456... npm run example:append
111
-
112
- # Run the retrieve file example (download a file from blockchain)
113
- npm run example:retrieve -- --txhash=0x123456... --output=./downloaded-file.txt
114
- # OR
115
- CKBFS_TX_HASH=0x123456... npm run example:retrieve
116
- ```
117
-
118
- ### Example Files
119
-
120
- - `examples/publish.ts` - Shows how to publish a file to CKBFS
121
- - `examples/append.ts` - Shows how to append to a previously published file
122
- - `examples/retrieve.ts` - Shows how to retrieve a complete file from the blockchain
123
-
124
- To run the examples, first set your CKB private key:
125
-
126
- ```bash
127
- export CKB_PRIVATE_KEY=your_private_key_here
128
- ```
129
-
130
- Note: The append example requires a valid transaction hash from a previously published file. You can either provide it via command line argument or environment variable.
131
-
132
- ## Contributing
133
-
134
- Contributions are welcome! Please feel free to submit a Pull Request.
135
-
136
- ## License
137
-
138
- This project is licensed under the MIT License - see the LICENSE file for details.