@ckbfs/api 1.2.4 → 1.2.5

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.
@@ -1,110 +1,575 @@
1
- import { CKBFS, NetworkType, ProtocolVersion, getFileContentFromChain, saveFileFromChain } from '../src/index';
2
- import { ClientPublicTestnet } from "@ckb-ccc/core";
1
+ import {
2
+ CKBFS,
3
+ NetworkType,
4
+ ProtocolVersion,
5
+ ProtocolVersionType,
6
+ CKBFSDataType,
7
+ CKBFSData,
8
+ decodeWitnessContent,
9
+ decodeMultipleWitnessContents,
10
+ extractFileFromWitnesses,
11
+ decodeFileFromWitnessData,
12
+ saveFileFromWitnessData,
13
+ getFileContentFromChain,
14
+ saveFileFromChain,
15
+ getFileContentFromChainByTypeId,
16
+ saveFileFromChainByTypeId,
17
+ decodeFileFromChainByTypeId,
18
+ getFileContentFromChainByIdentifier,
19
+ saveFileFromChainByIdentifier,
20
+ decodeFileFromChainByIdentifier,
21
+ parseIdentifier,
22
+ IdentifierType,
23
+ } from "../src/index";
24
+ import { Script, ClientPublicTestnet, Transaction, ccc } from "@ckb-ccc/core";
3
25
 
4
- // Replace with your actual private key (or leave this default if just reading)
5
- const privateKey = process.env.CKB_PRIVATE_KEY || 'your-private-key-here';
26
+ // Replace with your actual private key (optional for this example)
27
+ const privateKey = process.env.CKB_PRIVATE_KEY || "your-private-key-here";
6
28
 
7
29
  // Parse command line arguments for transaction hash
8
- const txHashArg = process.argv.find(arg => arg.startsWith('--txhash='));
9
- const outputArg = process.argv.find(arg => arg.startsWith('--output='));
30
+ const txHashArg = process.argv.find((arg) => arg.startsWith("--txhash="));
31
+ const targetTxHash = txHashArg
32
+ ? txHashArg.split("=")[1]
33
+ : process.env.TARGET_TX_HASH ||
34
+ "0x0000000000000000000000000000000000000000000000000000000000000000";
10
35
 
11
- const txHash = txHashArg ? txHashArg.split('=')[1] : process.env.CKBFS_TX_HASH || '';
12
- const outputPath = outputArg ? outputArg.split('=')[1] : undefined;
13
-
14
- if (!txHash) {
15
- console.error('Please provide a transaction hash using --txhash=<tx_hash> or the CKBFS_TX_HASH environment variable');
16
- process.exit(1);
17
- }
18
-
19
- // Initialize the SDK (read-only is fine for retrieval)
20
- const ckbfs = new CKBFS(
21
- privateKey,
22
- NetworkType.Testnet,
23
- {
24
- version: ProtocolVersion.V2,
25
- useTypeID: false
36
+ /**
37
+ * Ensures a string is prefixed with '0x'
38
+ * @param value The string to ensure is hex prefixed
39
+ * @returns A hex prefixed string
40
+ */
41
+ function ensureHexPrefix(value: string): `0x${string}` {
42
+ if (value.startsWith("0x")) {
43
+ return value as `0x${string}`;
26
44
  }
27
- );
45
+ return `0x${value}` as `0x${string}`;
46
+ }
28
47
 
29
48
  // Initialize CKB client for testnet
30
49
  const client = new ClientPublicTestnet();
31
50
 
32
51
  /**
33
- * Example of retrieving a file from CKBFS
52
+ * Example of retrieving and decoding file content using traditional blockchain method
34
53
  */
35
- async function retrieveExample() {
54
+ async function traditionalRetrieveExample() {
55
+ console.log("=== Traditional Blockchain Retrieval Method ===");
56
+
36
57
  try {
37
- console.log(`Retrieving CKBFS file from transaction: ${txHash}`);
38
-
39
- // Get transaction details
40
- const txWithStatus = await client.getTransaction(txHash);
58
+ // Get transaction from blockchain
59
+ const txWithStatus = await client.getTransaction(targetTxHash);
41
60
  if (!txWithStatus || !txWithStatus.transaction) {
42
- throw new Error(`Transaction ${txHash} not found`);
43
- }
44
-
45
- // Find index of the CKBFS cell in outputs (assuming it's the first one with a type script)
46
- const tx = txWithStatus.transaction;
47
- let ckbfsCellIndex = 0;
48
-
49
- // Get cell data
61
+ throw new Error(`Transaction ${targetTxHash} not found`);
62
+ }
63
+
64
+ const tx = Transaction.from(txWithStatus.transaction);
65
+ console.log(`Transaction found with ${tx.outputs.length} outputs`);
66
+
67
+ // Find CKBFS cell (first output with type script)
68
+ const ckbfsCellIndex = 0;
69
+ const output = tx.outputs[ckbfsCellIndex];
70
+ if (!output || !output.type) {
71
+ throw new Error("No CKBFS cell found in the transaction");
72
+ }
73
+
74
+ // Get and parse output data
50
75
  const outputData = tx.outputsData[ckbfsCellIndex];
51
76
  if (!outputData) {
52
- throw new Error('Output data not found');
53
- }
54
-
55
- // Get cell info for retrieval
56
- const outPoint = {
57
- txHash,
58
- index: ckbfsCellIndex
59
- };
60
-
61
- // Import necessary components from index
62
- const { CKBFSData } = require('../src/index');
63
-
64
- // Parse the output data
65
- const rawData = outputData.startsWith('0x')
66
- ? Buffer.from(outputData.slice(2), 'hex')
67
- : Buffer.from(outputData, 'hex');
68
-
69
- // Try with both V1 and V2 protocols
70
- let ckbfsData;
77
+ throw new Error("Output data not found");
78
+ }
79
+
80
+ const rawData = outputData.startsWith("0x")
81
+ ? ccc.bytesFrom(outputData.slice(2), "hex")
82
+ : Buffer.from(outputData, "hex");
83
+
84
+ // Try both protocol versions for unpacking
85
+ let ckbfsData: CKBFSDataType;
86
+ let version: ProtocolVersionType;
87
+
88
+ try {
89
+ ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V2);
90
+ version = ProtocolVersion.V2;
91
+ } catch (error) {
92
+ console.log("Failed to unpack as V2, trying V1...");
93
+ try {
94
+ ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V1);
95
+ version = ProtocolVersion.V1;
96
+ } catch (v1Error) {
97
+ throw new Error(
98
+ `Failed to unpack CKBFS data with both versions: V2(${error}), V1(${v1Error})`,
99
+ );
100
+ }
101
+ }
102
+
103
+ console.log(`Successfully unpacked CKBFS data using ${version}:`);
104
+ console.log(`- Filename: ${ckbfsData.filename}`);
105
+ console.log(`- Content Type: ${ckbfsData.contentType}`);
106
+ console.log(`- Checksum: ${ckbfsData.checksum}`);
107
+ console.log(`- Backlinks: ${ckbfsData.backLinks?.length || 0}`);
108
+
109
+ // Retrieve complete file content using traditional method
110
+ const outPoint = { txHash: targetTxHash, index: ckbfsCellIndex };
111
+ const content = await getFileContentFromChain(client, outPoint, ckbfsData);
112
+
113
+ // Save file using traditional method
114
+ const savedPath = saveFileFromChain(
115
+ content,
116
+ ckbfsData,
117
+ `./traditional_${ckbfsData.filename}`,
118
+ );
119
+
120
+ console.log(`Traditional method completed. File saved to: ${savedPath}`);
121
+ console.log(`File size: ${content.length} bytes`);
122
+
123
+ return { ckbfsData, tx, content };
124
+ } catch (error) {
125
+ console.error("Traditional retrieval failed:", error);
126
+ throw error;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Example of decoding file content directly from witnesses (new method)
132
+ */
133
+ async function directWitnessDecodingExample() {
134
+ console.log("\n=== Direct Witness Decoding Method (New) ===");
135
+
136
+ try {
137
+ // Get transaction from blockchain
138
+ const txWithStatus = await client.getTransaction(targetTxHash);
139
+ if (!txWithStatus || !txWithStatus.transaction) {
140
+ throw new Error(`Transaction ${targetTxHash} not found`);
141
+ }
142
+
143
+ const tx = Transaction.from(txWithStatus.transaction);
144
+
145
+ // Get CKBFS data to know which witnesses contain content
146
+ const outputData = tx.outputsData[0];
147
+ if (!outputData) {
148
+ throw new Error("Output data not found");
149
+ }
150
+
151
+ const rawData = outputData.startsWith("0x")
152
+ ? ccc.bytesFrom(outputData.slice(2), "hex")
153
+ : Buffer.from(outputData, "hex");
154
+
155
+ let ckbfsData: CKBFSDataType;
156
+ let version: ProtocolVersionType;
157
+
71
158
  try {
72
- console.log('Trying to unpack with V2...');
73
159
  ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V2);
160
+ version = ProtocolVersion.V2;
74
161
  } catch (error) {
75
- console.log('Failed with V2, trying V1...');
76
162
  ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V1);
163
+ version = ProtocolVersion.V1;
77
164
  }
78
-
79
- // Retrieve full file content
80
- console.log('Retrieving file content by following backlinks...');
81
- const fileContent = await getFileContentFromChain(client, outPoint, ckbfsData);
82
- console.log(`Retrieved file content: ${fileContent.length} bytes`);
83
-
84
- // Save to file
85
- const savedPath = saveFileFromChain(fileContent, ckbfsData, outputPath);
86
- console.log(`File saved to: ${savedPath}`);
87
-
88
- return savedPath;
165
+
166
+ console.log(`Using protocol ${version} for witness decoding`);
167
+
168
+ // Get witness indexes from CKBFS data
169
+ const indexes =
170
+ ckbfsData.indexes ||
171
+ (ckbfsData.index !== undefined ? [ckbfsData.index] : []);
172
+ console.log(`Content witness indexes: ${indexes.join(", ")}`);
173
+
174
+ // Example 1: Decode individual witnesses
175
+ console.log("\n--- Example 1: Decode Individual Witnesses ---");
176
+ for (const idx of indexes) {
177
+ if (idx < tx.witnesses.length) {
178
+ const decoded = decodeWitnessContent(tx.witnesses[idx]);
179
+ if (decoded) {
180
+ console.log(
181
+ `Witness ${idx}: ${decoded.content.length} bytes, valid: ${decoded.isValid}`,
182
+ );
183
+ } else {
184
+ console.log(`Witness ${idx}: Not a valid CKBFS witness`);
185
+ }
186
+ }
187
+ }
188
+
189
+ // Example 2: Decode multiple witnesses at once
190
+ console.log("\n--- Example 2: Decode Multiple Witnesses ---");
191
+ const relevantWitnesses = indexes
192
+ .map((idx) => tx.witnesses[idx])
193
+ .filter(Boolean);
194
+ const combinedContent = decodeMultipleWitnessContents(
195
+ relevantWitnesses,
196
+ true,
197
+ );
198
+ console.log(
199
+ `Combined content from ${relevantWitnesses.length} witnesses: ${combinedContent.length} bytes`,
200
+ );
201
+
202
+ // Example 3: Extract file using witness indexes
203
+ console.log("\n--- Example 3: Extract File Using Indexes ---");
204
+ const extractedContent = extractFileFromWitnesses(tx.witnesses, indexes);
205
+ console.log(`Extracted content: ${extractedContent.length} bytes`);
206
+
207
+ // Example 4: High-level decode with metadata
208
+ console.log("\n--- Example 4: High-level Decode with Metadata ---");
209
+ const decodedFile = decodeFileFromWitnessData({
210
+ witnesses: tx.witnesses,
211
+ indexes: indexes,
212
+ filename: ckbfsData.filename,
213
+ contentType: ckbfsData.contentType,
214
+ });
215
+
216
+ console.log(`Decoded file:`);
217
+ console.log(`- Filename: ${decodedFile.filename}`);
218
+ console.log(`- Content Type: ${decodedFile.contentType}`);
219
+ console.log(`- Size: ${decodedFile.size} bytes`);
220
+
221
+ // Example 5: Save file directly from witness data
222
+ console.log("\n--- Example 5: Save File from Witness Data ---");
223
+ const savedPath = saveFileFromWitnessData(
224
+ {
225
+ witnesses: tx.witnesses,
226
+ indexes: indexes,
227
+ filename: ckbfsData.filename,
228
+ contentType: ckbfsData.contentType,
229
+ },
230
+ `./direct_${ckbfsData.filename}`,
231
+ );
232
+
233
+ console.log(
234
+ `Direct witness decoding completed. File saved to: ${savedPath}`,
235
+ );
236
+
237
+ return { decodedFile, extractedContent };
89
238
  } catch (error) {
90
- console.error('Error retrieving file:', error);
239
+ console.error("Direct witness decoding failed:", error);
91
240
  throw error;
92
241
  }
93
242
  }
94
243
 
95
244
  /**
96
- * Main function to run the example
245
+ * Example of handling backlinks with direct witness decoding
246
+ */
247
+ async function backlinksDecodingExample() {
248
+ console.log("\n=== Backlinks Decoding Example ===");
249
+
250
+ try {
251
+ // Get main transaction
252
+ const txWithStatus = await client.getTransaction(targetTxHash);
253
+ if (!txWithStatus || !txWithStatus.transaction) {
254
+ throw new Error(`Transaction ${targetTxHash} not found`);
255
+ }
256
+
257
+ const tx = Transaction.from(txWithStatus.transaction);
258
+ const outputData = tx.outputsData[0];
259
+ const rawData = outputData.startsWith("0x")
260
+ ? ccc.bytesFrom(outputData.slice(2), "hex")
261
+ : Buffer.from(outputData, "hex");
262
+
263
+ let ckbfsData: CKBFSDataType;
264
+ try {
265
+ ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V2);
266
+ } catch (error) {
267
+ ckbfsData = CKBFSData.unpack(rawData, ProtocolVersion.V1);
268
+ }
269
+
270
+ console.log(`Found ${ckbfsData.backLinks?.length || 0} backlinks`);
271
+
272
+ if (ckbfsData.backLinks && ckbfsData.backLinks.length > 0) {
273
+ // Process each backlink
274
+ for (let i = 0; i < ckbfsData.backLinks.length; i++) {
275
+ const backlink = ckbfsData.backLinks[i];
276
+ console.log(`\nProcessing backlink ${i + 1}:`);
277
+ console.log(`- Transaction: ${backlink.txHash}`);
278
+ console.log(`- Checksum: ${backlink.checksum}`);
279
+
280
+ try {
281
+ // Get backlink transaction
282
+ const backTxWithStatus = await client.getTransaction(backlink.txHash);
283
+ if (backTxWithStatus && backTxWithStatus.transaction) {
284
+ const backTx = Transaction.from(backTxWithStatus.transaction);
285
+
286
+ // Get backlink indexes
287
+ const backIndexes =
288
+ backlink.indexes ||
289
+ (backlink.index !== undefined ? [backlink.index] : []);
290
+ console.log(`- Witness indexes: ${backIndexes.join(", ")}`);
291
+
292
+ // Decode content from backlink witnesses
293
+ const backlinkContent = extractFileFromWitnesses(
294
+ backTx.witnesses,
295
+ backIndexes,
296
+ );
297
+ console.log(`- Content size: ${backlinkContent.length} bytes`);
298
+
299
+ // Save backlink content
300
+ const backlinkPath = `./backlink_${i + 1}_content.bin`;
301
+ require("fs").writeFileSync(backlinkPath, backlinkContent);
302
+ console.log(`- Saved to: ${backlinkPath}`);
303
+ }
304
+ } catch (error) {
305
+ console.warn(`Failed to process backlink ${i + 1}: ${error}`);
306
+ }
307
+ }
308
+ } else {
309
+ console.log("No backlinks found in this file");
310
+ }
311
+ } catch (error) {
312
+ console.error("Backlinks decoding failed:", error);
313
+ throw error;
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Example of retrieving files using generic identifiers (new method)
319
+ */
320
+ async function genericIdentifierRetrievalExample() {
321
+ console.log("\n=== Generic Identifier Retrieval Example ===");
322
+
323
+ try {
324
+ // Get transaction to extract TypeID from it
325
+ const txWithStatus = await client.getTransaction(targetTxHash);
326
+ if (!txWithStatus || !txWithStatus.transaction) {
327
+ throw new Error(`Transaction ${targetTxHash} not found`);
328
+ }
329
+
330
+ const tx = Transaction.from(txWithStatus.transaction);
331
+
332
+ // Find CKBFS cell (first output with type script)
333
+ const ckbfsCellIndex = 0;
334
+ const output = tx.outputs[ckbfsCellIndex];
335
+ if (!output || !output.type) {
336
+ throw new Error("No CKBFS cell found in the transaction");
337
+ }
338
+
339
+ // Extract TypeID from the type script args
340
+ const typeId = output.type.args;
341
+ console.log(`Extracted TypeID: ${typeId}`);
342
+
343
+ if (!typeId || typeId === "0x") {
344
+ console.log(
345
+ "No TypeID found in this transaction, skipping identifier examples",
346
+ );
347
+ return;
348
+ }
349
+
350
+ // Create different identifier formats for demonstration
351
+ const identifiers = [
352
+ typeId, // Pure TypeID hex string
353
+ `ckbfs://${typeId.slice(2)}`, // CKBFS URI with TypeID
354
+ `ckbfs://${targetTxHash.slice(2)}i${ckbfsCellIndex}`, // CKBFS URI with outPoint
355
+ ];
356
+
357
+ console.log("\nTesting different identifier formats:");
358
+ identifiers.forEach((id, index) => {
359
+ const parsed = parseIdentifier(id);
360
+ console.log(`${index + 1}. ${id}`);
361
+ console.log(` Type: ${parsed.type}`);
362
+ if (parsed.typeId) console.log(` TypeID: ${parsed.typeId}`);
363
+ if (parsed.txHash)
364
+ console.log(` TxHash: ${parsed.txHash}, Index: ${parsed.index}`);
365
+ });
366
+
367
+ // Example 1: Get file content using generic identifier (traditional method with backlinks)
368
+ console.log(
369
+ "\n--- Example 1: Get File Content by Generic Identifier (Traditional) ---",
370
+ );
371
+
372
+ // Test with TypeID format
373
+ const fileData = await getFileContentFromChainByIdentifier(
374
+ client,
375
+ identifiers[0],
376
+ {
377
+ network: "testnet",
378
+ version: ProtocolVersion.V2,
379
+ useTypeID: false,
380
+ },
381
+ );
382
+
383
+ if (fileData) {
384
+ console.log(`Retrieved file: ${fileData.filename}`);
385
+ console.log(`Content type: ${fileData.contentType}`);
386
+ console.log(`Size: ${fileData.size} bytes`);
387
+ console.log(`Checksum: ${fileData.checksum}`);
388
+ console.log(`Backlinks: ${fileData.backLinks.length}`);
389
+ console.log(`Parsed identifier type: ${fileData.parsedId.type}`);
390
+ } else {
391
+ console.log("File not found by identifier");
392
+ return;
393
+ }
394
+
395
+ // Example 2: Test all identifier formats
396
+ console.log("\n--- Example 2: Test All Identifier Formats ---");
397
+ for (let i = 0; i < identifiers.length; i++) {
398
+ const identifier = identifiers[i];
399
+ console.log(`\nTesting identifier ${i + 1}: ${identifier}`);
400
+
401
+ try {
402
+ const testData = await getFileContentFromChainByIdentifier(
403
+ client,
404
+ identifier,
405
+ {
406
+ network: "testnet",
407
+ version: ProtocolVersion.V2,
408
+ useTypeID: false,
409
+ },
410
+ );
411
+
412
+ if (testData) {
413
+ console.log(
414
+ `✓ Success: ${testData.filename} (${testData.size} bytes)`,
415
+ );
416
+ console.log(` Parsed as: ${testData.parsedId.type}`);
417
+ } else {
418
+ console.log(`✗ Failed: File not found`);
419
+ }
420
+ } catch (error) {
421
+ console.log(`✗ Error: ${error}`);
422
+ }
423
+ }
424
+
425
+ // Example 3: Save file using CKBFS URI format
426
+ console.log("\n--- Example 3: Save File using CKBFS URI ---");
427
+ const savedPath = await saveFileFromChainByIdentifier(
428
+ client,
429
+ identifiers[1], // Use CKBFS URI format
430
+ `./identifier_${fileData.filename}`,
431
+ {
432
+ network: "testnet",
433
+ version: ProtocolVersion.V2,
434
+ useTypeID: false,
435
+ },
436
+ );
437
+
438
+ if (savedPath) {
439
+ console.log(`File saved via identifier to: ${savedPath}`);
440
+ }
441
+
442
+ // Example 4: Decode file using outPoint format with direct witness method
443
+ console.log(
444
+ "\n--- Example 4: Decode File using OutPoint Format (Direct Witness) ---",
445
+ );
446
+ const decodedData = await decodeFileFromChainByIdentifier(
447
+ client,
448
+ identifiers[2],
449
+ {
450
+ network: "testnet",
451
+ version: ProtocolVersion.V2,
452
+ useTypeID: false,
453
+ },
454
+ );
455
+
456
+ if (decodedData) {
457
+ console.log(`Decoded file: ${decodedData.filename}`);
458
+ console.log(`Content type: ${decodedData.contentType}`);
459
+ console.log(`Size: ${decodedData.size} bytes`);
460
+ console.log(`Checksum: ${decodedData.checksum}`);
461
+ console.log(`Parsed identifier type: ${decodedData.parsedId.type}`);
462
+
463
+ // Verify content matches
464
+ const contentMatches =
465
+ Buffer.compare(fileData.content, decodedData.content) === 0;
466
+ console.log(
467
+ `Content verification: ${contentMatches ? "PASSED" : "FAILED"}`,
468
+ );
469
+ }
470
+
471
+ console.log("\nGeneric identifier retrieval completed successfully!");
472
+ return { fileData, decodedData, identifiers };
473
+ } catch (error) {
474
+ console.error("Generic identifier retrieval failed:", error);
475
+ throw error;
476
+ }
477
+ }
478
+
479
+ /**
480
+ * Performance comparison between traditional and direct methods
481
+ */
482
+ async function performanceComparisonExample() {
483
+ console.log("\n=== Performance Comparison ===");
484
+
485
+ try {
486
+ // Traditional method timing
487
+ const traditionalStart = Date.now();
488
+ const traditionalResult = await traditionalRetrieveExample();
489
+ const traditionalTime = Date.now() - traditionalStart;
490
+
491
+ // Direct method timing
492
+ const directStart = Date.now();
493
+ const directResult = await directWitnessDecodingExample();
494
+ const directTime = Date.now() - directStart;
495
+
496
+ console.log("\n--- Performance Results ---");
497
+ console.log(`Traditional method: ${traditionalTime}ms`);
498
+ console.log(`Direct witness method: ${directTime}ms`);
499
+ console.log(
500
+ `Performance improvement: ${(((traditionalTime - directTime) / traditionalTime) * 100).toFixed(1)}%`,
501
+ );
502
+
503
+ // Verify content matches
504
+ const contentMatches =
505
+ Buffer.compare(
506
+ traditionalResult.content,
507
+ directResult.extractedContent,
508
+ ) === 0;
509
+ console.log(
510
+ `Content verification: ${contentMatches ? "PASSED" : "FAILED"}`,
511
+ );
512
+ } catch (error) {
513
+ console.error("Performance comparison failed:", error);
514
+ }
515
+ }
516
+
517
+ /**
518
+ * Main function to run all examples
97
519
  */
98
520
  async function main() {
99
- console.log('Running CKBFS file retrieval example...');
100
- console.log('--------------------------------------');
101
-
521
+ console.log("Running CKBFS retrieve and witness decoding examples...");
522
+ console.log("=========================================================");
523
+ console.log(`Target transaction: ${targetTxHash}`);
524
+
525
+ // Validate transaction hash
526
+ if (
527
+ targetTxHash ===
528
+ "0x0000000000000000000000000000000000000000000000000000000000000000"
529
+ ) {
530
+ console.error(
531
+ "Please provide a valid transaction hash by setting the TARGET_TX_HASH environment variable or using --txhash=0x... argument",
532
+ );
533
+ console.log("\nExample usage:");
534
+ console.log(" npm run example:retrieve -- --txhash=0x123456...");
535
+ console.log(" TARGET_TX_HASH=0x123456... npm run example:retrieve");
536
+ process.exit(1);
537
+ }
538
+
102
539
  try {
103
- await retrieveExample();
104
- console.log('Example completed successfully!');
540
+ // Run traditional method
541
+ await traditionalRetrieveExample();
542
+
543
+ // Run new direct witness decoding methods
544
+ await directWitnessDecodingExample();
545
+
546
+ // Handle backlinks if present
547
+ await backlinksDecodingExample();
548
+
549
+ // Run generic identifier-based retrieval examples
550
+ await genericIdentifierRetrievalExample();
551
+
552
+ console.log("\n=== Summary ===");
553
+ console.log("All examples completed successfully!");
554
+ console.log("\nKey advantages of direct witness decoding:");
555
+ console.log("- No need for recursive blockchain queries");
556
+ console.log("- Faster performance for simple cases");
557
+ console.log("- More control over witness processing");
558
+ console.log("- Useful for offline processing with cached data");
559
+ console.log("\nTraditional method advantages:");
560
+ console.log("- Automatic backlink following");
561
+ console.log("- Complete file reconstruction");
562
+ console.log("- Built-in error handling for complex cases");
563
+ console.log("\nGeneric identifier method advantages:");
564
+ console.log("- Flexible input formats (TypeID, CKBFS URIs, outPoint)");
565
+ console.log("- Simple interface - works with any identifier format");
566
+ console.log("- No need to know specific format beforehand");
567
+ console.log("- Automatic format detection and parsing");
568
+ console.log("- Works with both traditional and direct witness decoding");
569
+
105
570
  process.exit(0);
106
571
  } catch (error) {
107
- console.error('Example failed:', error);
572
+ console.error("Examples failed:", error);
108
573
  process.exit(1);
109
574
  }
110
575
  }
@@ -112,4 +577,4 @@ async function main() {
112
577
  // Run the example if this file is executed directly
113
578
  if (require.main === module) {
114
579
  main().catch(console.error);
115
- }
580
+ }