@ckbfs/api 1.2.3 → 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.
- package/README.md +506 -74
- package/code.png +0 -0
- package/demo-output.txt +1 -0
- package/direct_direct_content_example.txt +1 -0
- package/dist/index.d.ts +55 -13
- package/dist/index.js +143 -18
- package/dist/utils/constants.d.ts +7 -3
- package/dist/utils/constants.js +41 -34
- package/dist/utils/file.d.ts +179 -0
- package/dist/utils/file.js +599 -31
- package/dist/utils/molecule.d.ts +3 -2
- package/dist/utils/molecule.js +22 -24
- package/dist/utils/transaction.d.ts +10 -4
- package/dist/utils/transaction.js +34 -32
- package/examples/example.txt +1 -0
- package/examples/identifier-test.ts +178 -0
- package/examples/index.ts +36 -24
- package/examples/publish.ts +39 -5
- package/examples/retrieve.ts +542 -77
- package/examples/witness-decode-demo.ts +190 -0
- package/identifier_direct_content_example.txt +1 -0
- package/package-lock.json +4978 -0
- package/package.json +3 -2
- package/src/index.ts +312 -96
- package/src/utils/constants.ts +77 -43
- package/src/utils/file.ts +864 -59
- package/src/utils/molecule.ts +41 -36
- package/src/utils/transaction.ts +177 -151
- package/traditional_direct_content_example.txt +1 -0
- package/typeid_direct_content_example.txt +1 -0
- package/.cursor/rules/typescript.mdc +0 -49
- package/ABC.LOGS +0 -1
- package/RFC.v2.md +0 -341
- package/append.txt +0 -1
- package/example.txt +0 -1
- package/publish-tx-hash-v1.txt +0 -1
- package/src/utils/createPublishTransaction +0 -24
- package/test-download.txt +0 -2
package/dist/utils/molecule.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { molecule, number } from "@ckb-lumos/codec";
|
2
|
+
import { ProtocolVersionType } from "./constants";
|
2
3
|
/**
|
3
4
|
* Molecule definitions for CKBFS data structures.
|
4
5
|
*/
|
@@ -70,8 +71,8 @@ export type CKBFSDataType = {
|
|
70
71
|
backLinks: BackLinkType[];
|
71
72
|
};
|
72
73
|
export declare const CKBFSData: {
|
73
|
-
pack: (data: CKBFSDataType, version?:
|
74
|
-
unpack: (buf: Uint8Array, version?:
|
74
|
+
pack: (data: CKBFSDataType, version?: ProtocolVersionType) => Uint8Array;
|
75
|
+
unpack: (buf: Uint8Array, version?: ProtocolVersionType) => CKBFSDataType;
|
75
76
|
};
|
76
77
|
export declare const CKBFS_HEADER: Uint8Array<ArrayBuffer>;
|
77
78
|
export declare const CKBFS_HEADER_STRING = "CKBFS";
|
package/dist/utils/molecule.js
CHANGED
@@ -45,13 +45,13 @@ exports.CKBFSDataV2 = codec_1.molecule.table({
|
|
45
45
|
function getIndexes(data) {
|
46
46
|
if (data.indexes)
|
47
47
|
return data.indexes;
|
48
|
-
if (typeof data.index ===
|
48
|
+
if (typeof data.index === "number")
|
49
49
|
return [data.index];
|
50
50
|
return [];
|
51
51
|
}
|
52
52
|
// Helper function to get single index from data
|
53
53
|
function getIndex(data) {
|
54
|
-
if (typeof data.index ===
|
54
|
+
if (typeof data.index === "number")
|
55
55
|
return data.index;
|
56
56
|
if (data.indexes && data.indexes.length > 0)
|
57
57
|
return data.indexes[0];
|
@@ -59,7 +59,7 @@ function getIndex(data) {
|
|
59
59
|
}
|
60
60
|
// Helper function to safely get either index or indexes from BackLinkType for V1
|
61
61
|
function getBackLinkIndex(bl) {
|
62
|
-
if (typeof bl.index ===
|
62
|
+
if (typeof bl.index === "number") {
|
63
63
|
return bl.index;
|
64
64
|
}
|
65
65
|
if (Array.isArray(bl.indexes) && bl.indexes.length > 0) {
|
@@ -72,7 +72,7 @@ function getBackLinkIndexes(bl) {
|
|
72
72
|
if (Array.isArray(bl.indexes)) {
|
73
73
|
return bl.indexes;
|
74
74
|
}
|
75
|
-
if (typeof bl.index ===
|
75
|
+
if (typeof bl.index === "number") {
|
76
76
|
return [bl.index];
|
77
77
|
}
|
78
78
|
return [0];
|
@@ -85,11 +85,11 @@ exports.CKBFSData = {
|
|
85
85
|
return exports.CKBFSDataV1.pack({
|
86
86
|
index: getIndex(data),
|
87
87
|
checksum: data.checksum,
|
88
|
-
contentType: core_1.ccc.bytesFrom(data.contentType,
|
89
|
-
filename: core_1.ccc.bytesFrom(data.filename,
|
90
|
-
backLinks: data.backLinks.map(bl => {
|
88
|
+
contentType: core_1.ccc.bytesFrom(data.contentType, "utf8"),
|
89
|
+
filename: core_1.ccc.bytesFrom(data.filename, "utf8"),
|
90
|
+
backLinks: data.backLinks.map((bl) => {
|
91
91
|
// Ensure txHash is in proper format for molecule encoding
|
92
|
-
const txHash = typeof bl.txHash ===
|
92
|
+
const txHash = typeof bl.txHash === "string"
|
93
93
|
? core_1.ccc.bytesFrom(bl.txHash)
|
94
94
|
: bl.txHash;
|
95
95
|
return {
|
@@ -105,13 +105,11 @@ exports.CKBFSData = {
|
|
105
105
|
return exports.CKBFSDataV2.pack({
|
106
106
|
indexes: getIndexes(data),
|
107
107
|
checksum: data.checksum,
|
108
|
-
contentType: core_1.ccc.bytesFrom(data.contentType,
|
109
|
-
filename: core_1.ccc.bytesFrom(data.filename,
|
110
|
-
backLinks: data.backLinks.map(bl => {
|
108
|
+
contentType: core_1.ccc.bytesFrom(data.contentType, "utf8"),
|
109
|
+
filename: core_1.ccc.bytesFrom(data.filename, "utf8"),
|
110
|
+
backLinks: data.backLinks.map((bl) => {
|
111
111
|
// Ensure txHash is in proper format for molecule encoding
|
112
|
-
const txHash = typeof bl.txHash ===
|
113
|
-
? bl.txHash
|
114
|
-
: bl.txHash;
|
112
|
+
const txHash = typeof bl.txHash === "string" ? bl.txHash : bl.txHash;
|
115
113
|
return {
|
116
114
|
indexes: getBackLinkIndexes(bl),
|
117
115
|
checksum: bl.checksum,
|
@@ -128,9 +126,9 @@ exports.CKBFSData = {
|
|
128
126
|
return {
|
129
127
|
index: unpacked.index,
|
130
128
|
checksum: unpacked.checksum,
|
131
|
-
contentType: core_1.ccc.bytesTo(unpacked.contentType,
|
132
|
-
filename: core_1.ccc.bytesTo(unpacked.filename,
|
133
|
-
backLinks: unpacked.backLinks.map(bl => ({
|
129
|
+
contentType: core_1.ccc.bytesTo(unpacked.contentType, "utf8"),
|
130
|
+
filename: core_1.ccc.bytesTo(unpacked.filename, "utf8"),
|
131
|
+
backLinks: unpacked.backLinks.map((bl) => ({
|
134
132
|
index: bl.index,
|
135
133
|
checksum: bl.checksum,
|
136
134
|
txHash: bl.txHash,
|
@@ -143,9 +141,9 @@ exports.CKBFSData = {
|
|
143
141
|
return {
|
144
142
|
indexes: unpacked.indexes,
|
145
143
|
checksum: unpacked.checksum,
|
146
|
-
contentType: core_1.ccc.bytesTo(unpacked.contentType,
|
147
|
-
filename: core_1.ccc.bytesTo(unpacked.filename,
|
148
|
-
backLinks: unpacked.backLinks.map(bl => ({
|
144
|
+
contentType: core_1.ccc.bytesTo(unpacked.contentType, "utf8"),
|
145
|
+
filename: core_1.ccc.bytesTo(unpacked.filename, "utf8"),
|
146
|
+
backLinks: unpacked.backLinks.map((bl) => ({
|
149
147
|
indexes: bl.indexes,
|
150
148
|
checksum: bl.checksum,
|
151
149
|
txHash: bl.txHash,
|
@@ -154,11 +152,11 @@ exports.CKBFSData = {
|
|
154
152
|
}
|
155
153
|
}
|
156
154
|
catch (error) {
|
157
|
-
console.error(
|
158
|
-
throw new Error(
|
155
|
+
console.error("Error unpacking CKBFSData:", error);
|
156
|
+
throw new Error("Failed to unpack CKBFSData: " + error);
|
159
157
|
}
|
160
|
-
}
|
158
|
+
},
|
161
159
|
};
|
162
160
|
// Constants for CKBFS protocol
|
163
|
-
exports.CKBFS_HEADER = new Uint8Array([0x43,
|
161
|
+
exports.CKBFS_HEADER = new Uint8Array([0x43, 0x4b, 0x42, 0x46, 0x53]); // "CKBFS" in ASCII
|
164
162
|
exports.CKBFS_HEADER_STRING = "CKBFS";
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ccc, Transaction, Script, Signer } from "@ckb-ccc/core";
|
2
|
-
import { CKBFSDataType } from
|
3
|
-
import { NetworkType } from
|
2
|
+
import { CKBFSDataType } from "./molecule";
|
3
|
+
import { NetworkType, ProtocolVersionType } from "./constants";
|
4
4
|
/**
|
5
5
|
* Utility functions for CKB transaction creation and handling
|
6
6
|
*/
|
@@ -13,7 +13,7 @@ export interface CKBFSCellOptions {
|
|
13
13
|
capacity?: bigint;
|
14
14
|
lock: Script;
|
15
15
|
network?: NetworkType;
|
16
|
-
version?:
|
16
|
+
version?: ProtocolVersionType;
|
17
17
|
useTypeID?: boolean;
|
18
18
|
}
|
19
19
|
/**
|
@@ -40,8 +40,14 @@ export interface AppendOptions {
|
|
40
40
|
contentChunks: Uint8Array[];
|
41
41
|
feeRate?: number;
|
42
42
|
network?: NetworkType;
|
43
|
-
version?:
|
43
|
+
version?: ProtocolVersionType;
|
44
44
|
}
|
45
|
+
/**
|
46
|
+
* Ensures a string is prefixed with '0x'
|
47
|
+
* @param value The string to ensure is hex prefixed
|
48
|
+
* @returns A hex prefixed string
|
49
|
+
*/
|
50
|
+
export declare function ensureHexPrefix(value: string): `0x${string}`;
|
45
51
|
/**
|
46
52
|
* Creates a CKBFS cell
|
47
53
|
* @param options Options for creating the CKBFS cell
|
@@ -1,5 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ensureHexPrefix = ensureHexPrefix;
|
3
4
|
exports.createCKBFSCell = createCKBFSCell;
|
4
5
|
exports.createPublishTransaction = createPublishTransaction;
|
5
6
|
exports.createAppendTransaction = createAppendTransaction;
|
@@ -16,7 +17,7 @@ const constants_1 = require("./constants");
|
|
16
17
|
* @returns A hex prefixed string
|
17
18
|
*/
|
18
19
|
function ensureHexPrefix(value) {
|
19
|
-
if (value.startsWith(
|
20
|
+
if (value.startsWith("0x")) {
|
20
21
|
return value;
|
21
22
|
}
|
22
23
|
return `0x${value}`;
|
@@ -27,7 +28,7 @@ function ensureHexPrefix(value) {
|
|
27
28
|
* @returns The created cell output
|
28
29
|
*/
|
29
30
|
function createCKBFSCell(options) {
|
30
|
-
const { contentType, filename, capacity, lock, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, useTypeID = false } = options;
|
31
|
+
const { contentType, filename, capacity, lock, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, useTypeID = false, } = options;
|
31
32
|
// Get CKBFS script config
|
32
33
|
const config = (0, constants_1.getCKBFSScriptConfig)(network, version, useTypeID);
|
33
34
|
// Create pre CKBFS type script
|
@@ -46,7 +47,7 @@ function createCKBFSCell(options) {
|
|
46
47
|
* @returns Promise resolving to the created transaction
|
47
48
|
*/
|
48
49
|
async function createPublishTransaction(signer, options) {
|
49
|
-
const { contentChunks, contentType, filename, lock, capacity, feeRate, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, useTypeID = false } = options;
|
50
|
+
const { contentChunks, contentType, filename, lock, capacity, feeRate, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, useTypeID = false, } = options;
|
50
51
|
// Calculate checksum for the combined content
|
51
52
|
const textEncoder = new TextEncoder();
|
52
53
|
const combinedContent = Buffer.concat(contentChunks);
|
@@ -87,7 +88,10 @@ async function createPublishTransaction(signer, options) {
|
|
87
88
|
// Get CKBFS script config
|
88
89
|
const config = (0, constants_1.getCKBFSScriptConfig)(network, version, useTypeID);
|
89
90
|
const preCkbfsTypeScript = new core_1.Script(ensureHexPrefix(config.codeHash), config.hashType, "0x0000000000000000000000000000000000000000000000000000000000000000");
|
90
|
-
const ckbfsCellSize = BigInt(outputData.length +
|
91
|
+
const ckbfsCellSize = BigInt(outputData.length +
|
92
|
+
preCkbfsTypeScript.occupiedSize +
|
93
|
+
lock.occupiedSize +
|
94
|
+
8) * 100000000n;
|
91
95
|
// Create pre transaction without cell deps initially
|
92
96
|
const preTx = core_1.Transaction.from({
|
93
97
|
outputs: [
|
@@ -98,16 +102,14 @@ async function createPublishTransaction(signer, options) {
|
|
98
102
|
network,
|
99
103
|
version,
|
100
104
|
useTypeID,
|
101
|
-
capacity: ckbfsCellSize || capacity
|
102
|
-
})
|
105
|
+
capacity: ckbfsCellSize || capacity,
|
106
|
+
}),
|
103
107
|
],
|
104
108
|
witnesses: [
|
105
109
|
[], // Empty secp witness for signing
|
106
|
-
...ckbfsWitnesses.map(w => `0x${Buffer.from(w).toString(
|
110
|
+
...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
|
107
111
|
],
|
108
|
-
outputsData: [
|
109
|
-
outputData,
|
110
|
-
]
|
112
|
+
outputsData: [outputData],
|
111
113
|
});
|
112
114
|
// Add the CKBFS dep group cell dependency
|
113
115
|
preTx.addCellDeps({
|
@@ -115,7 +117,7 @@ async function createPublishTransaction(signer, options) {
|
|
115
117
|
txHash: ensureHexPrefix(config.depTxHash),
|
116
118
|
index: config.depIndex || 0,
|
117
119
|
},
|
118
|
-
depType: "depGroup"
|
120
|
+
depType: "depGroup",
|
119
121
|
});
|
120
122
|
// Get the recommended address to ensure lock script cell deps are included
|
121
123
|
const address = await signer.getRecommendedAddressObj();
|
@@ -132,7 +134,7 @@ async function createPublishTransaction(signer, options) {
|
|
132
134
|
cellDeps: preTx.cellDeps,
|
133
135
|
witnesses: [
|
134
136
|
[], // Reset first witness for signing
|
135
|
-
...preTx.witnesses.slice(1)
|
137
|
+
...preTx.witnesses.slice(1),
|
136
138
|
],
|
137
139
|
outputsData: preTx.outputsData,
|
138
140
|
inputs: preTx.inputs,
|
@@ -142,8 +144,8 @@ async function createPublishTransaction(signer, options) {
|
|
142
144
|
type: ckbfsTypeScript,
|
143
145
|
capacity: preTx.outputs[0].capacity,
|
144
146
|
},
|
145
|
-
...preTx.outputs.slice(1) // Include rest of outputs (e.g., change)
|
146
|
-
]
|
147
|
+
...preTx.outputs.slice(1), // Include rest of outputs (e.g., change)
|
148
|
+
],
|
147
149
|
});
|
148
150
|
return tx;
|
149
151
|
}
|
@@ -154,7 +156,7 @@ async function createPublishTransaction(signer, options) {
|
|
154
156
|
* @returns Promise resolving to the created transaction
|
155
157
|
*/
|
156
158
|
async function createAppendTransaction(signer, options) {
|
157
|
-
const { ckbfsCell, contentChunks, feeRate, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION } = options;
|
159
|
+
const { ckbfsCell, contentChunks, feeRate, network = constants_1.DEFAULT_NETWORK, version = constants_1.DEFAULT_VERSION, } = options;
|
158
160
|
const { outPoint, data, type, lock, capacity } = ckbfsCell;
|
159
161
|
// Get CKBFS script config early to use version info
|
160
162
|
const config = (0, constants_1.getCKBFSScriptConfig)(network, version);
|
@@ -168,10 +170,12 @@ async function createAppendTransaction(signer, options) {
|
|
168
170
|
// cumulative nature as required by Rule 11 in the RFC
|
169
171
|
const contentChecksum = await (0, checksum_1.updateChecksum)(data.checksum, combinedContent);
|
170
172
|
console.log(`Updated checksum from ${data.checksum} to ${contentChecksum} for appended content`);
|
173
|
+
// Get the recommended address to ensure lock script cell deps are included
|
174
|
+
const address = await signer.getRecommendedAddressObj();
|
171
175
|
// Calculate the actual witness indices where our content is placed
|
172
|
-
//
|
173
|
-
//
|
174
|
-
const contentStartIndex = 1;
|
176
|
+
// CKBFS data starts at index 1 if signer's lock script is the same as ckbfs's lock script
|
177
|
+
// else CKBFS data starts at index 0
|
178
|
+
const contentStartIndex = address.script.hash() === lock.hash() ? 1 : 0;
|
175
179
|
const witnessIndices = Array.from({ length: contentChunks.length }, (_, i) => contentStartIndex + i);
|
176
180
|
// Create backlink for the current state based on version
|
177
181
|
let newBackLink;
|
@@ -180,7 +184,8 @@ async function createAppendTransaction(signer, options) {
|
|
180
184
|
newBackLink = {
|
181
185
|
// In V1, field order is index, checksum, txHash
|
182
186
|
// and index is a single number value, not an array
|
183
|
-
index: data.index ||
|
187
|
+
index: data.index ||
|
188
|
+
(data.indexes && data.indexes.length > 0 ? data.indexes[0] : 0),
|
184
189
|
checksum: data.checksum,
|
185
190
|
txHash: outPoint.txHash,
|
186
191
|
};
|
@@ -226,12 +231,13 @@ async function createAppendTransaction(signer, options) {
|
|
226
231
|
// Get sizes and calculate capacity requirements
|
227
232
|
const newDataSize = outputData.length;
|
228
233
|
// Calculate the required capacity for the output cell
|
229
|
-
// This accounts for:
|
234
|
+
// This accounts for:
|
230
235
|
// 1. The output data size
|
231
236
|
// 2. The type script's occupied size
|
232
237
|
// 3. The lock script's occupied size
|
233
238
|
// 4. A constant of 8 bytes (for header overhead)
|
234
|
-
const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
|
239
|
+
const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
|
240
|
+
100000000n;
|
235
241
|
console.log(`Original capacity: ${capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`);
|
236
242
|
// Use the maximum value between calculated size and original capacity
|
237
243
|
// to ensure we have enough capacity but don't decrease capacity unnecessarily
|
@@ -245,18 +251,16 @@ async function createAppendTransaction(signer, options) {
|
|
245
251
|
index: outPoint.index,
|
246
252
|
},
|
247
253
|
since: "0x0",
|
248
|
-
}
|
254
|
+
},
|
249
255
|
],
|
250
256
|
outputs: [
|
251
257
|
{
|
252
258
|
lock,
|
253
259
|
type,
|
254
260
|
capacity: outputCapacity,
|
255
|
-
}
|
261
|
+
},
|
256
262
|
],
|
257
|
-
outputsData: [
|
258
|
-
outputData,
|
259
|
-
]
|
263
|
+
outputsData: [outputData],
|
260
264
|
});
|
261
265
|
// Add the CKBFS dep group cell dependency
|
262
266
|
tx.addCellDeps({
|
@@ -264,10 +268,8 @@ async function createAppendTransaction(signer, options) {
|
|
264
268
|
txHash: ensureHexPrefix(config.depTxHash),
|
265
269
|
index: config.depIndex || 0,
|
266
270
|
},
|
267
|
-
depType: "depGroup"
|
271
|
+
depType: "depGroup",
|
268
272
|
});
|
269
|
-
// Get the recommended address to ensure lock script cell deps are included
|
270
|
-
const address = await signer.getRecommendedAddressObj();
|
271
273
|
const inputsBefore = tx.inputs.length;
|
272
274
|
// If we need more capacity than the original cell had, add additional inputs
|
273
275
|
if (outputCapacity > capacity) {
|
@@ -278,14 +280,14 @@ async function createAppendTransaction(signer, options) {
|
|
278
280
|
const witnesses = [];
|
279
281
|
// add empty witness for signer if ckbfs's lock is the same as signer's lock
|
280
282
|
if (address.script.hash() === lock.hash()) {
|
281
|
-
witnesses.push(
|
283
|
+
witnesses.push("0x");
|
282
284
|
}
|
283
285
|
// add ckbfs witnesses
|
284
|
-
witnesses.push(...ckbfsWitnesses.map(w => `0x${Buffer.from(w).toString(
|
286
|
+
witnesses.push(...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`));
|
285
287
|
// Add empty witnesses for signer's input
|
286
288
|
// This is to ensure that the transaction is valid and can be signed
|
287
289
|
for (let i = inputsBefore; i < tx.inputs.length; i++) {
|
288
|
-
witnesses.push(
|
290
|
+
witnesses.push("0x");
|
289
291
|
}
|
290
292
|
tx.witnesses = witnesses;
|
291
293
|
// Complete fee
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello CKBFS!
|
@@ -0,0 +1,178 @@
|
|
1
|
+
import {
|
2
|
+
parseIdentifier,
|
3
|
+
IdentifierType,
|
4
|
+
getFileContentFromChainByIdentifier,
|
5
|
+
saveFileFromChainByIdentifier,
|
6
|
+
decodeFileFromChainByIdentifier,
|
7
|
+
} from '../src/index';
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Simple test script to verify generic identifier functionality
|
11
|
+
* This script demonstrates parsing and using different identifier formats
|
12
|
+
*/
|
13
|
+
|
14
|
+
// Test identifiers
|
15
|
+
const testIdentifiers = [
|
16
|
+
// Type 1: Pure TypeID hex string
|
17
|
+
'0xbce89252cece632ef819943bed9cd0e2576f8ce26f9f02075b621b1c9a28056a',
|
18
|
+
|
19
|
+
// Type 2: CKBFS URI with TypeID
|
20
|
+
'ckbfs://bce89252cece632ef819943bed9cd0e2576f8ce26f9f02075b621b1c9a28056a',
|
21
|
+
|
22
|
+
// Type 3: CKBFS URI with transaction hash and index
|
23
|
+
'ckbfs://431c9d668c1815d26eb4f7ac6256eb350ab351474daea8d588400146ab228780i0',
|
24
|
+
|
25
|
+
// Invalid formats for testing
|
26
|
+
'invalid-identifier',
|
27
|
+
'ckbfs://invalid',
|
28
|
+
'0xinvalid'
|
29
|
+
];
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Test identifier parsing functionality
|
33
|
+
*/
|
34
|
+
function testIdentifierParsing() {
|
35
|
+
console.log('=== Testing Identifier Parsing ===');
|
36
|
+
|
37
|
+
testIdentifiers.forEach((identifier, index) => {
|
38
|
+
console.log(`\nTest ${index + 1}: ${identifier}`);
|
39
|
+
|
40
|
+
try {
|
41
|
+
const parsed = parseIdentifier(identifier);
|
42
|
+
console.log(` Type: ${parsed.type}`);
|
43
|
+
|
44
|
+
if (parsed.type === IdentifierType.TypeID) {
|
45
|
+
console.log(` TypeID: ${parsed.typeId}`);
|
46
|
+
} else if (parsed.type === IdentifierType.OutPoint) {
|
47
|
+
console.log(` TxHash: ${parsed.txHash}`);
|
48
|
+
console.log(` Index: ${parsed.index}`);
|
49
|
+
} else {
|
50
|
+
console.log(` Status: Invalid identifier format`);
|
51
|
+
}
|
52
|
+
|
53
|
+
console.log(` Original: ${parsed.original}`);
|
54
|
+
} catch (error) {
|
55
|
+
console.error(` Error: ${error}`);
|
56
|
+
}
|
57
|
+
});
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Test file retrieval with different identifier formats
|
62
|
+
* Note: This requires a real CKB client and valid identifiers
|
63
|
+
*/
|
64
|
+
async function testFileRetrieval() {
|
65
|
+
console.log('\n=== Testing File Retrieval ===');
|
66
|
+
console.log('Note: This test requires valid identifiers and network connection');
|
67
|
+
|
68
|
+
// This is a mock test - in real usage you would:
|
69
|
+
// 1. Initialize a CKB client
|
70
|
+
// 2. Use real identifiers from actual transactions
|
71
|
+
// 3. Test the retrieval functions
|
72
|
+
|
73
|
+
const mockClient = null; // Replace with real client
|
74
|
+
const validIdentifier = testIdentifiers[0]; // Use a real identifier
|
75
|
+
|
76
|
+
if (!mockClient) {
|
77
|
+
console.log('Skipping file retrieval test - no client configured');
|
78
|
+
return;
|
79
|
+
}
|
80
|
+
|
81
|
+
try {
|
82
|
+
console.log(`Testing retrieval with: ${validIdentifier}`);
|
83
|
+
|
84
|
+
// Test generic identifier function
|
85
|
+
const fileData = await getFileContentFromChainByIdentifier(
|
86
|
+
mockClient,
|
87
|
+
validIdentifier,
|
88
|
+
{
|
89
|
+
network: 'testnet',
|
90
|
+
version: '20241025.db973a8e8032',
|
91
|
+
useTypeID: false
|
92
|
+
}
|
93
|
+
);
|
94
|
+
|
95
|
+
if (fileData) {
|
96
|
+
console.log(`✓ Retrieved: ${fileData.filename}`);
|
97
|
+
console.log(` Size: ${fileData.size} bytes`);
|
98
|
+
console.log(` Content Type: ${fileData.contentType}`);
|
99
|
+
console.log(` Parsed ID Type: ${fileData.parsedId.type}`);
|
100
|
+
} else {
|
101
|
+
console.log('✗ File not found');
|
102
|
+
}
|
103
|
+
} catch (error) {
|
104
|
+
console.error(`✗ Error: ${error}`);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Demonstrate identifier format conversion
|
110
|
+
*/
|
111
|
+
function demonstrateFormatConversion() {
|
112
|
+
console.log('\n=== Demonstrating Format Conversion ===');
|
113
|
+
|
114
|
+
const typeId = 'bce89252cece632ef819943bed9cd0e2576f8ce26f9f02075b621b1c9a28056a';
|
115
|
+
const txHash = '431c9d668c1815d26eb4f7ac6256eb350ab351474daea8d588400146ab228780';
|
116
|
+
const index = 0;
|
117
|
+
|
118
|
+
console.log('Creating different formats from the same data:');
|
119
|
+
console.log(`1. TypeID hex: 0x${typeId}`);
|
120
|
+
console.log(`2. CKBFS TypeID URI: ckbfs://${typeId}`);
|
121
|
+
console.log(`3. CKBFS OutPoint URI: ckbfs://${txHash}i${index}`);
|
122
|
+
|
123
|
+
// Parse each format
|
124
|
+
const formats = [
|
125
|
+
`0x${typeId}`,
|
126
|
+
`ckbfs://${typeId}`,
|
127
|
+
`ckbfs://${txHash}i${index}`
|
128
|
+
];
|
129
|
+
|
130
|
+
formats.forEach((format, index) => {
|
131
|
+
const parsed = parseIdentifier(format);
|
132
|
+
console.log(`\nFormat ${index + 1} parsed as: ${parsed.type}`);
|
133
|
+
});
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Main test function
|
138
|
+
*/
|
139
|
+
async function main() {
|
140
|
+
console.log('CKBFS Generic Identifier Test');
|
141
|
+
console.log('=============================');
|
142
|
+
|
143
|
+
try {
|
144
|
+
// Test identifier parsing
|
145
|
+
testIdentifierParsing();
|
146
|
+
|
147
|
+
// Demonstrate format conversion
|
148
|
+
demonstrateFormatConversion();
|
149
|
+
|
150
|
+
// Test file retrieval (requires real setup)
|
151
|
+
await testFileRetrieval();
|
152
|
+
|
153
|
+
console.log('\n=== Test Summary ===');
|
154
|
+
console.log('✓ Identifier parsing test completed');
|
155
|
+
console.log('✓ Format conversion demonstration completed');
|
156
|
+
console.log('ℹ File retrieval test requires real network setup');
|
157
|
+
|
158
|
+
console.log('\nTo test with real data:');
|
159
|
+
console.log('1. Set up a CKB client (testnet or mainnet)');
|
160
|
+
console.log('2. Replace mock identifiers with real ones');
|
161
|
+
console.log('3. Run the file retrieval tests');
|
162
|
+
|
163
|
+
} catch (error) {
|
164
|
+
console.error('Test failed:', error);
|
165
|
+
process.exit(1);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
// Run tests if this file is executed directly
|
170
|
+
if (require.main === module) {
|
171
|
+
main().catch(console.error);
|
172
|
+
}
|
173
|
+
|
174
|
+
export {
|
175
|
+
testIdentifierParsing,
|
176
|
+
testFileRetrieval,
|
177
|
+
demonstrateFormatConversion
|
178
|
+
};
|
package/examples/index.ts
CHANGED
@@ -1,43 +1,55 @@
|
|
1
|
-
import { CKBFS, NetworkType, ProtocolVersion } from
|
1
|
+
import { CKBFS, NetworkType, ProtocolVersion } from "../src/index";
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Main CKBFS Examples
|
5
|
-
*
|
5
|
+
*
|
6
6
|
* This file serves as the entry point for running all CKBFS SDK examples.
|
7
|
-
*
|
7
|
+
*
|
8
8
|
* To run all examples:
|
9
9
|
* npm run example
|
10
|
-
*
|
10
|
+
*
|
11
11
|
* To run specific examples:
|
12
12
|
* npm run example:publish
|
13
13
|
* npm run example:append -- --txhash=0x123456...
|
14
14
|
*/
|
15
15
|
|
16
|
-
console.log(
|
17
|
-
console.log(
|
18
|
-
console.log(
|
19
|
-
console.log(
|
20
|
-
console.log(
|
21
|
-
console.log(
|
22
|
-
|
23
|
-
|
24
|
-
console.log(
|
25
|
-
|
26
|
-
|
27
|
-
console.log(
|
28
|
-
console.log(
|
16
|
+
console.log("CKBFS SDK Examples");
|
17
|
+
console.log("=================");
|
18
|
+
console.log("");
|
19
|
+
console.log("Available examples:");
|
20
|
+
console.log("1. Publish File Example - npm run example:publish");
|
21
|
+
console.log(
|
22
|
+
"2. Append File Example - npm run example:append -- --txhash=0x123456...",
|
23
|
+
);
|
24
|
+
console.log(
|
25
|
+
"3. Retrieve File Example - npm run example:retrieve -- --txhash=0x123456...",
|
26
|
+
);
|
27
|
+
console.log("");
|
28
|
+
console.log("Run all examples with: npm run example");
|
29
|
+
console.log("");
|
30
|
+
console.log(
|
31
|
+
"Note: For the append and retrieve examples, you need to provide a transaction hash",
|
32
|
+
);
|
33
|
+
console.log("of a previously published file using the --txhash parameter or");
|
34
|
+
console.log(
|
35
|
+
"by setting the PUBLISH_TX_HASH/TARGET_TX_HASH environment variable.",
|
36
|
+
);
|
37
|
+
console.log("");
|
29
38
|
|
30
39
|
// Check if we should run all examples
|
31
|
-
const runAll = process.argv.includes(
|
40
|
+
const runAll = process.argv.includes("--all");
|
32
41
|
|
33
42
|
if (runAll) {
|
34
|
-
console.log(
|
35
|
-
|
36
|
-
|
37
|
-
console.log(
|
38
|
-
console.log(
|
43
|
+
console.log(
|
44
|
+
"Running all examples is not recommended. Please run specific examples instead.",
|
45
|
+
);
|
46
|
+
console.log("");
|
47
|
+
console.log("For example:");
|
48
|
+
console.log(" npm run example:publish");
|
49
|
+
console.log(" npm run example:append -- --txhash=0x123456...");
|
50
|
+
console.log(" npm run example:retrieve -- --txhash=0x123456...");
|
39
51
|
process.exit(1);
|
40
52
|
}
|
41
53
|
|
42
54
|
// Default behavior - just show instructions
|
43
|
-
console.log(
|
55
|
+
console.log("For more information, see the README.md file.");
|