@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.
- 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 +29 -27
- 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 +172 -146
- 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);
|
@@ -182,7 +184,8 @@ async function createAppendTransaction(signer, options) {
|
|
182
184
|
newBackLink = {
|
183
185
|
// In V1, field order is index, checksum, txHash
|
184
186
|
// and index is a single number value, not an array
|
185
|
-
index: data.index ||
|
187
|
+
index: data.index ||
|
188
|
+
(data.indexes && data.indexes.length > 0 ? data.indexes[0] : 0),
|
186
189
|
checksum: data.checksum,
|
187
190
|
txHash: outPoint.txHash,
|
188
191
|
};
|
@@ -228,12 +231,13 @@ async function createAppendTransaction(signer, options) {
|
|
228
231
|
// Get sizes and calculate capacity requirements
|
229
232
|
const newDataSize = outputData.length;
|
230
233
|
// Calculate the required capacity for the output cell
|
231
|
-
// This accounts for:
|
234
|
+
// This accounts for:
|
232
235
|
// 1. The output data size
|
233
236
|
// 2. The type script's occupied size
|
234
237
|
// 3. The lock script's occupied size
|
235
238
|
// 4. A constant of 8 bytes (for header overhead)
|
236
|
-
const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
|
239
|
+
const ckbfsCellSize = BigInt(outputData.length + type.occupiedSize + lock.occupiedSize + 8) *
|
240
|
+
100000000n;
|
237
241
|
console.log(`Original capacity: ${capacity}, Calculated size: ${ckbfsCellSize}, Data size: ${outputData.length}`);
|
238
242
|
// Use the maximum value between calculated size and original capacity
|
239
243
|
// to ensure we have enough capacity but don't decrease capacity unnecessarily
|
@@ -247,18 +251,16 @@ async function createAppendTransaction(signer, options) {
|
|
247
251
|
index: outPoint.index,
|
248
252
|
},
|
249
253
|
since: "0x0",
|
250
|
-
}
|
254
|
+
},
|
251
255
|
],
|
252
256
|
outputs: [
|
253
257
|
{
|
254
258
|
lock,
|
255
259
|
type,
|
256
260
|
capacity: outputCapacity,
|
257
|
-
}
|
261
|
+
},
|
258
262
|
],
|
259
|
-
outputsData: [
|
260
|
-
outputData,
|
261
|
-
]
|
263
|
+
outputsData: [outputData],
|
262
264
|
});
|
263
265
|
// Add the CKBFS dep group cell dependency
|
264
266
|
tx.addCellDeps({
|
@@ -266,7 +268,7 @@ async function createAppendTransaction(signer, options) {
|
|
266
268
|
txHash: ensureHexPrefix(config.depTxHash),
|
267
269
|
index: config.depIndex || 0,
|
268
270
|
},
|
269
|
-
depType: "depGroup"
|
271
|
+
depType: "depGroup",
|
270
272
|
});
|
271
273
|
const inputsBefore = tx.inputs.length;
|
272
274
|
// If we need more capacity than the original cell had, add additional inputs
|
@@ -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.");
|
package/examples/publish.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { CKBFS, NetworkType, ProtocolVersion } from '../src/index';
|
1
|
+
import { CKBFS, NetworkType, ProtocolVersion, PublishContentOptions } from '../src/index';
|
2
2
|
|
3
3
|
// Replace with your actual private key
|
4
4
|
const privateKey = process.env.CKB_PRIVATE_KEY || 'your-private-key-here';
|
@@ -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
|
};
|
@@ -52,6 +52,38 @@ async function publishExample() {
|
|
52
52
|
}
|
53
53
|
}
|
54
54
|
|
55
|
+
/**
|
56
|
+
* Example of publishing content directly (string) to CKBFS
|
57
|
+
*/
|
58
|
+
async function publishContentExample() {
|
59
|
+
try {
|
60
|
+
// Get address info
|
61
|
+
const address = await ckbfs.getAddress();
|
62
|
+
console.log(`Using address for content publish: ${address.toString()}`);
|
63
|
+
|
64
|
+
// Define content and options (contentType and filename are required)
|
65
|
+
const content = "Hello CKBFS from direct content!";
|
66
|
+
const options: PublishContentOptions = {
|
67
|
+
contentType: 'text/plain',
|
68
|
+
filename: 'direct_content_example.txt',
|
69
|
+
// You can optionally specify feeRate, network, version, useTypeID
|
70
|
+
// feeRate: 3000
|
71
|
+
};
|
72
|
+
|
73
|
+
console.log(`Publishing direct content: "${content}"`);
|
74
|
+
const txHash = await ckbfs.publishContent(content, options);
|
75
|
+
|
76
|
+
console.log(`Direct content published successfully!`);
|
77
|
+
console.log(`Transaction Hash: ${txHash}`);
|
78
|
+
console.log(`View at: https://pudge.explorer.nervos.org/transaction/${txHash}`);
|
79
|
+
|
80
|
+
return txHash;
|
81
|
+
} catch (error) {
|
82
|
+
console.error('Error publishing direct content:', error);
|
83
|
+
throw error;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
55
87
|
/**
|
56
88
|
* Main function to run the example
|
57
89
|
*/
|
@@ -62,6 +94,8 @@ async function main() {
|
|
62
94
|
|
63
95
|
try {
|
64
96
|
await publishExample();
|
97
|
+
console.log('----------------------------------');
|
98
|
+
await publishContentExample();
|
65
99
|
console.log('Example completed successfully!');
|
66
100
|
process.exit(0);
|
67
101
|
} catch (error) {
|
@@ -73,4 +107,4 @@ async function main() {
|
|
73
107
|
// Run the example if this file is executed directly
|
74
108
|
if (require.main === module) {
|
75
109
|
main().catch(console.error);
|
76
|
-
}
|
110
|
+
}
|