@ckbfs/api 1.3.0 → 1.4.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/README.md +570 -0
- package/code.png +0 -0
- package/demo-output.txt +1 -0
- package/direct_direct_content_example.txt +1 -0
- package/dist/index.d.ts +15 -15
- package/dist/index.js +41 -22
- 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 +4 -4
- package/dist/utils/transaction.js +28 -27
- package/examples/append.ts +2 -39
- package/examples/example.txt +1 -0
- package/examples/identifier-test.ts +178 -0
- package/examples/index.ts +36 -24
- package/examples/publish.ts +5 -5
- package/examples/retrieve.ts +580 -0
- 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 +168 -99
- 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 +171 -145
- package/traditional_direct_content_example.txt +1 -0
- package/typeid_direct_content_example.txt +1 -0
- package/example.txt +0 -1
- package/src/utils/createPublishTransaction +0 -24
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,7 +40,7 @@ export interface AppendOptions {
|
|
|
40
40
|
contentChunks: Uint8Array[];
|
|
41
41
|
feeRate?: number;
|
|
42
42
|
network?: NetworkType;
|
|
43
|
-
version?:
|
|
43
|
+
version?: ProtocolVersionType;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Ensures a string is prefixed with '0x'
|
|
@@ -17,7 +17,7 @@ const constants_1 = require("./constants");
|
|
|
17
17
|
* @returns A hex prefixed string
|
|
18
18
|
*/
|
|
19
19
|
function ensureHexPrefix(value) {
|
|
20
|
-
if (value.startsWith(
|
|
20
|
+
if (value.startsWith("0x")) {
|
|
21
21
|
return value;
|
|
22
22
|
}
|
|
23
23
|
return `0x${value}`;
|
|
@@ -28,7 +28,7 @@ function ensureHexPrefix(value) {
|
|
|
28
28
|
* @returns The created cell output
|
|
29
29
|
*/
|
|
30
30
|
function createCKBFSCell(options) {
|
|
31
|
-
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;
|
|
32
32
|
// Get CKBFS script config
|
|
33
33
|
const config = (0, constants_1.getCKBFSScriptConfig)(network, version, useTypeID);
|
|
34
34
|
// Create pre CKBFS type script
|
|
@@ -47,7 +47,7 @@ function createCKBFSCell(options) {
|
|
|
47
47
|
* @returns Promise resolving to the created transaction
|
|
48
48
|
*/
|
|
49
49
|
async function createPublishTransaction(signer, options) {
|
|
50
|
-
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;
|
|
51
51
|
// Calculate checksum for the combined content
|
|
52
52
|
const textEncoder = new TextEncoder();
|
|
53
53
|
const combinedContent = Buffer.concat(contentChunks);
|
|
@@ -88,7 +88,10 @@ async function createPublishTransaction(signer, options) {
|
|
|
88
88
|
// Get CKBFS script config
|
|
89
89
|
const config = (0, constants_1.getCKBFSScriptConfig)(network, version, useTypeID);
|
|
90
90
|
const preCkbfsTypeScript = new core_1.Script(ensureHexPrefix(config.codeHash), config.hashType, "0x0000000000000000000000000000000000000000000000000000000000000000");
|
|
91
|
-
const ckbfsCellSize = BigInt(outputData.length +
|
|
91
|
+
const ckbfsCellSize = BigInt(outputData.length +
|
|
92
|
+
preCkbfsTypeScript.occupiedSize +
|
|
93
|
+
lock.occupiedSize +
|
|
94
|
+
8) * 100000000n;
|
|
92
95
|
// Create pre transaction without cell deps initially
|
|
93
96
|
const preTx = core_1.Transaction.from({
|
|
94
97
|
outputs: [
|
|
@@ -99,16 +102,14 @@ async function createPublishTransaction(signer, options) {
|
|
|
99
102
|
network,
|
|
100
103
|
version,
|
|
101
104
|
useTypeID,
|
|
102
|
-
capacity: ckbfsCellSize || capacity
|
|
103
|
-
})
|
|
105
|
+
capacity: ckbfsCellSize || capacity,
|
|
106
|
+
}),
|
|
104
107
|
],
|
|
105
108
|
witnesses: [
|
|
106
109
|
[], // Empty secp witness for signing
|
|
107
|
-
...ckbfsWitnesses.map(w => `0x${Buffer.from(w).toString(
|
|
110
|
+
...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`),
|
|
108
111
|
],
|
|
109
|
-
outputsData: [
|
|
110
|
-
outputData,
|
|
111
|
-
]
|
|
112
|
+
outputsData: [outputData],
|
|
112
113
|
});
|
|
113
114
|
// Add the CKBFS dep group cell dependency
|
|
114
115
|
preTx.addCellDeps({
|
|
@@ -116,7 +117,7 @@ async function createPublishTransaction(signer, options) {
|
|
|
116
117
|
txHash: ensureHexPrefix(config.depTxHash),
|
|
117
118
|
index: config.depIndex || 0,
|
|
118
119
|
},
|
|
119
|
-
depType: "depGroup"
|
|
120
|
+
depType: "depGroup",
|
|
120
121
|
});
|
|
121
122
|
// Get the recommended address to ensure lock script cell deps are included
|
|
122
123
|
const address = await signer.getRecommendedAddressObj();
|
|
@@ -133,7 +134,7 @@ async function createPublishTransaction(signer, options) {
|
|
|
133
134
|
cellDeps: preTx.cellDeps,
|
|
134
135
|
witnesses: [
|
|
135
136
|
[], // Reset first witness for signing
|
|
136
|
-
...preTx.witnesses.slice(1)
|
|
137
|
+
...preTx.witnesses.slice(1),
|
|
137
138
|
],
|
|
138
139
|
outputsData: preTx.outputsData,
|
|
139
140
|
inputs: preTx.inputs,
|
|
@@ -143,8 +144,8 @@ async function createPublishTransaction(signer, options) {
|
|
|
143
144
|
type: ckbfsTypeScript,
|
|
144
145
|
capacity: preTx.outputs[0].capacity,
|
|
145
146
|
},
|
|
146
|
-
...preTx.outputs.slice(1) // Include rest of outputs (e.g., change)
|
|
147
|
-
]
|
|
147
|
+
...preTx.outputs.slice(1), // Include rest of outputs (e.g., change)
|
|
148
|
+
],
|
|
148
149
|
});
|
|
149
150
|
return tx;
|
|
150
151
|
}
|
|
@@ -155,7 +156,7 @@ async function createPublishTransaction(signer, options) {
|
|
|
155
156
|
* @returns Promise resolving to the created transaction
|
|
156
157
|
*/
|
|
157
158
|
async function createAppendTransaction(signer, options) {
|
|
158
|
-
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;
|
|
159
160
|
const { outPoint, data, type, lock, capacity } = ckbfsCell;
|
|
160
161
|
// Get CKBFS script config early to use version info
|
|
161
162
|
const config = (0, constants_1.getCKBFSScriptConfig)(network, version);
|
|
@@ -183,7 +184,8 @@ async function createAppendTransaction(signer, options) {
|
|
|
183
184
|
newBackLink = {
|
|
184
185
|
// In V1, field order is index, checksum, txHash
|
|
185
186
|
// and index is a single number value, not an array
|
|
186
|
-
index: data.index ||
|
|
187
|
+
index: data.index ||
|
|
188
|
+
(data.indexes && data.indexes.length > 0 ? data.indexes[0] : 0),
|
|
187
189
|
checksum: data.checksum,
|
|
188
190
|
txHash: outPoint.txHash,
|
|
189
191
|
};
|
|
@@ -229,12 +231,13 @@ async function createAppendTransaction(signer, options) {
|
|
|
229
231
|
// Get sizes and calculate capacity requirements
|
|
230
232
|
const newDataSize = outputData.length;
|
|
231
233
|
// Calculate the required capacity for the output cell
|
|
232
|
-
// This accounts for:
|
|
234
|
+
// This accounts for:
|
|
233
235
|
// 1. The output data size
|
|
234
236
|
// 2. The type script's occupied size
|
|
235
237
|
// 3. The lock script's occupied size
|
|
236
238
|
// 4. A constant of 8 bytes (for header overhead)
|
|
237
|
-
const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
|
|
239
|
+
const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
|
|
240
|
+
100000000n;
|
|
238
241
|
console.log(`Original capacity: ${capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`);
|
|
239
242
|
// Use the maximum value between calculated size and original capacity
|
|
240
243
|
// to ensure we have enough capacity but don't decrease capacity unnecessarily
|
|
@@ -248,18 +251,16 @@ async function createAppendTransaction(signer, options) {
|
|
|
248
251
|
index: outPoint.index,
|
|
249
252
|
},
|
|
250
253
|
since: "0x0",
|
|
251
|
-
}
|
|
254
|
+
},
|
|
252
255
|
],
|
|
253
256
|
outputs: [
|
|
254
257
|
{
|
|
255
258
|
lock,
|
|
256
259
|
type,
|
|
257
260
|
capacity: outputCapacity,
|
|
258
|
-
}
|
|
261
|
+
},
|
|
259
262
|
],
|
|
260
|
-
outputsData: [
|
|
261
|
-
outputData,
|
|
262
|
-
]
|
|
263
|
+
outputsData: [outputData],
|
|
263
264
|
});
|
|
264
265
|
// Add the CKBFS dep group cell dependency
|
|
265
266
|
tx.addCellDeps({
|
|
@@ -267,7 +268,7 @@ async function createAppendTransaction(signer, options) {
|
|
|
267
268
|
txHash: ensureHexPrefix(config.depTxHash),
|
|
268
269
|
index: config.depIndex || 0,
|
|
269
270
|
},
|
|
270
|
-
depType: "depGroup"
|
|
271
|
+
depType: "depGroup",
|
|
271
272
|
});
|
|
272
273
|
const inputsBefore = tx.inputs.length;
|
|
273
274
|
// If we need more capacity than the original cell had, add additional inputs
|
|
@@ -279,14 +280,14 @@ async function createAppendTransaction(signer, options) {
|
|
|
279
280
|
const witnesses = [];
|
|
280
281
|
// add empty witness for signer if ckbfs's lock is the same as signer's lock
|
|
281
282
|
if (address.script.hash() === lock.hash()) {
|
|
282
|
-
witnesses.push(
|
|
283
|
+
witnesses.push("0x");
|
|
283
284
|
}
|
|
284
285
|
// add ckbfs witnesses
|
|
285
|
-
witnesses.push(...ckbfsWitnesses.map(w => `0x${Buffer.from(w).toString(
|
|
286
|
+
witnesses.push(...ckbfsWitnesses.map((w) => `0x${Buffer.from(w).toString("hex")}`));
|
|
286
287
|
// Add empty witnesses for signer's input
|
|
287
288
|
// This is to ensure that the transaction is valid and can be signed
|
|
288
289
|
for (let i = inputsBefore; i < tx.inputs.length; i++) {
|
|
289
|
-
witnesses.push(
|
|
290
|
+
witnesses.push("0x");
|
|
290
291
|
}
|
|
291
292
|
tx.witnesses = witnesses;
|
|
292
293
|
// Complete fee
|
package/examples/append.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CKBFS, NetworkType, ProtocolVersion, CKBFSDataType, extractCKBFSWitnessContent, isCKBFSWitness, CKBFSData
|
|
1
|
+
import { CKBFS, NetworkType, ProtocolVersion, CKBFSDataType, extractCKBFSWitnessContent, isCKBFSWitness, CKBFSData } from '../src/index';
|
|
2
2
|
import { Script, ClientPublicTestnet, Transaction, ccc } from "@ckb-ccc/core";
|
|
3
3
|
|
|
4
4
|
// Replace with your actual private key
|
|
@@ -169,37 +169,6 @@ async function appendExample() {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
/**
|
|
173
|
-
* Example of appending content directly (string) to an existing CKBFS file
|
|
174
|
-
* @param previousAppendTxHash The transaction hash from the previous append operation
|
|
175
|
-
*/
|
|
176
|
-
async function appendContentExample(previousAppendTxHash: string) {
|
|
177
|
-
try {
|
|
178
|
-
console.log(`Getting cell info from previous append transaction: ${previousAppendTxHash}`);
|
|
179
|
-
const ckbfsCell = await getCellInfoFromTransaction(previousAppendTxHash);
|
|
180
|
-
|
|
181
|
-
const contentToAppend = "\nAnd this is more content appended directly as a string!";
|
|
182
|
-
const options: AppendContentOptions = {
|
|
183
|
-
// You can optionally specify feeRate, network, version
|
|
184
|
-
// feeRate: 3000
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
console.log(`Appending direct content: "${contentToAppend}"`);
|
|
188
|
-
|
|
189
|
-
// Append the string content
|
|
190
|
-
const txHash = await ckbfs.appendContent(contentToAppend, ckbfsCell, options);
|
|
191
|
-
|
|
192
|
-
console.log(`Direct content appended successfully!`);
|
|
193
|
-
console.log(`Transaction Hash: ${txHash}`);
|
|
194
|
-
console.log(`View at: https://pudge.explorer.nervos.org/transaction/${txHash}`);
|
|
195
|
-
|
|
196
|
-
return txHash;
|
|
197
|
-
} catch (error) {
|
|
198
|
-
console.error('Error appending direct content:', error);
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
172
|
/**
|
|
204
173
|
* Main function to run the example
|
|
205
174
|
*/
|
|
@@ -209,13 +178,7 @@ async function main() {
|
|
|
209
178
|
console.log(`Using CKBFS protocol version: ${ProtocolVersion.V2}`);
|
|
210
179
|
|
|
211
180
|
try {
|
|
212
|
-
|
|
213
|
-
const firstAppendTxHash = await appendExample();
|
|
214
|
-
console.log('-------------------------------');
|
|
215
|
-
|
|
216
|
-
// Now run the content append, using the output from the first append
|
|
217
|
-
await appendContentExample(firstAppendTxHash);
|
|
218
|
-
|
|
181
|
+
await appendExample();
|
|
219
182
|
console.log('Example completed successfully!');
|
|
220
183
|
process.exit(0);
|
|
221
184
|
} catch (error) {
|
|
@@ -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.");
|
package/examples/publish.ts
CHANGED
|
@@ -6,7 +6,7 @@ const privateKey = process.env.CKB_PRIVATE_KEY || 'your-private-key-here';
|
|
|
6
6
|
// Initialize the SDK with network and version options
|
|
7
7
|
const ckbfs = new CKBFS(
|
|
8
8
|
privateKey,
|
|
9
|
-
NetworkType.
|
|
9
|
+
NetworkType.Mainnet, // Use testnet
|
|
10
10
|
{
|
|
11
11
|
version: ProtocolVersion.V2, // Use the latest version (V2)
|
|
12
12
|
chunkSize: 30 * 1024, // 30KB chunks
|
|
@@ -28,12 +28,12 @@ async function publishExample() {
|
|
|
28
28
|
console.log('Using CKBFS config:', config);
|
|
29
29
|
|
|
30
30
|
// Publish a text file to CKBFS
|
|
31
|
-
const filePath = './
|
|
31
|
+
const filePath = './code.png';
|
|
32
32
|
|
|
33
33
|
// You can provide additional options
|
|
34
34
|
const options = {
|
|
35
|
-
contentType: '
|
|
36
|
-
filename: '
|
|
35
|
+
contentType: 'image/png',
|
|
36
|
+
filename: 'code.png',
|
|
37
37
|
// Specify capacity if needed (default is 200 CKB)
|
|
38
38
|
// capacity: 250n * 100000000n
|
|
39
39
|
};
|
|
@@ -107,4 +107,4 @@ async function main() {
|
|
|
107
107
|
// Run the example if this file is executed directly
|
|
108
108
|
if (require.main === module) {
|
|
109
109
|
main().catch(console.error);
|
|
110
|
-
}
|
|
110
|
+
}
|