@ckbfs/api 1.0.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.
@@ -0,0 +1,123 @@
1
+ /**
2
+ * CKBFS protocol deployment constants
3
+ */
4
+
5
+ export enum NetworkType {
6
+ Mainnet = 'mainnet',
7
+ Testnet = 'testnet'
8
+ }
9
+
10
+ // Use string literals for version values to avoid TypeScript indexing issues
11
+ export const ProtocolVersion = {
12
+ V1: '20240906.ce6724722cf6', // Original version, compact and simple, suitable for small files
13
+ V2: '20241025.db973a8e8032' // New version, more features and can do complex operations
14
+ } as const;
15
+
16
+ export type ProtocolVersionType = typeof ProtocolVersion[keyof typeof ProtocolVersion];
17
+
18
+ // CKBFS Type Script Constants
19
+ export const CKBFS_CODE_HASH: Record<NetworkType, Record<string, string>> = {
20
+ [NetworkType.Mainnet]: {
21
+ [ProtocolVersion.V2]: '0x31e6376287d223b8c0410d562fb422f04d1d617b2947596a14c3d2efb7218d3a'
22
+ },
23
+ [NetworkType.Testnet]: {
24
+ [ProtocolVersion.V1]: '0xe8905ad29a02cf8befa9c258f4f941773839a618d75a64afc22059de9413f712',
25
+ [ProtocolVersion.V2]: '0x31e6376287d223b8c0410d562fb422f04d1d617b2947596a14c3d2efb7218d3a'
26
+ }
27
+ };
28
+
29
+ export const CKBFS_TYPE_ID: Record<NetworkType, Record<string, string>> = {
30
+ [NetworkType.Mainnet]: {
31
+ [ProtocolVersion.V2]: '0xfd2058c9a0c0183354cf637e25d2707ffa9bb6fa2ba9b29f4ebc6be3e54ad7eb'
32
+ },
33
+ [NetworkType.Testnet]: {
34
+ [ProtocolVersion.V1]: '0x88ef4d436af35684a27edda0d44dd8771318330285f90f02d13606e095aea86f',
35
+ [ProtocolVersion.V2]: '0x7c6dcab8268201f064dc8676b5eafa60ca2569e5c6209dcbab0eb64a9cb3aaa3'
36
+ }
37
+ };
38
+
39
+ // Adler32 Hasher Constants
40
+ export const ADLER32_CODE_HASH: Record<NetworkType, Record<string, string>> = {
41
+ [NetworkType.Mainnet]: {
42
+ [ProtocolVersion.V2]: '0x2138683f76944437c0c643664120d620bdb5858dd6c9d1d156805e279c2c536f'
43
+ },
44
+ [NetworkType.Testnet]: {
45
+ [ProtocolVersion.V1]: '0x8af42cd329cf1bcffb4c73b48252e99cb32346fdbc1cdaa5ae1d000232d47e84',
46
+ [ProtocolVersion.V2]: '0x2138683f76944437c0c643664120d620bdb5858dd6c9d1d156805e279c2c536f'
47
+ }
48
+ };
49
+
50
+ export const ADLER32_TYPE_ID: Record<NetworkType, Record<string, string>> = {
51
+ [NetworkType.Mainnet]: {
52
+ [ProtocolVersion.V2]: '0x641c01d590833a3f5471bd441651d9f2a8a200141949cdfeef2d68d8094c5876'
53
+ },
54
+ [NetworkType.Testnet]: {
55
+ [ProtocolVersion.V1]: '0xccf29a0d8e860044a3d2f6a6e709f6572f77e4fe245fadd212fc342337048d60',
56
+ [ProtocolVersion.V2]: '0x5f73f128be76e397f5a3b56c94ca16883a8ee91b498bc0ee80473818318c05ac'
57
+ }
58
+ };
59
+
60
+ // Dep Group Transaction Constants
61
+ export const DEP_GROUP_TX_HASH: Record<NetworkType, Record<string, string>> = {
62
+ [NetworkType.Mainnet]: {
63
+ [ProtocolVersion.V2]: '0xfab07962ed7178ed88d450774e2a6ecd50bae856bdb9b692980be8c5147d1bfa'
64
+ },
65
+ [NetworkType.Testnet]: {
66
+ [ProtocolVersion.V1]: '0xc8fd44aba36f0c4b37536b6c7ea3b88df65fa97e02f77cd33b9bf20bf241a09b',
67
+ [ProtocolVersion.V2]: '0x469af0d961dcaaedd872968a9388b546717a6ccfa47b3165b3f9c981e9d66aaa'
68
+ }
69
+ };
70
+
71
+ // Deploy Transaction Constants
72
+ export const DEPLOY_TX_HASH: Record<NetworkType, Record<string, { ckbfs: string; adler32: string }>> = {
73
+ [NetworkType.Mainnet]: {
74
+ [ProtocolVersion.V2]: {
75
+ ckbfs: '0xc9b6698f44c3b80e7e1c48823b2714e432b93f0206ffaf9df885d23267ed2ebc',
76
+ adler32: '0xc9b6698f44c3b80e7e1c48823b2714e432b93f0206ffaf9df885d23267ed2ebc'
77
+ }
78
+ },
79
+ [NetworkType.Testnet]: {
80
+ [ProtocolVersion.V1]: {
81
+ ckbfs: '0xde8eb09151fbcdcba398423159ce348cc89a38a736de3fd0960b18b084465382',
82
+ adler32: '0x042f264d7397a181437b51ff9981cf536f252ab5740b61ce52ce31ada04ed54b'
83
+ },
84
+ [ProtocolVersion.V2]: {
85
+ ckbfs: '0x2c8c9ad3134743368b5a79977648f96c5bd0aba187021a72fb624301064d3616',
86
+ adler32: '0x2c8c9ad3134743368b5a79977648f96c5bd0aba187021a72fb624301064d3616'
87
+ }
88
+ }
89
+ };
90
+
91
+ // Default values - V2 is now the default
92
+ export const DEFAULT_VERSION = ProtocolVersion.V2;
93
+ export const DEFAULT_NETWORK = NetworkType.Testnet;
94
+
95
+ // Helper function to get CKBFS script configuration
96
+ export interface CKBFSScriptConfig {
97
+ codeHash: string;
98
+ hashType: 'data1' | 'type';
99
+ depTxHash: string;
100
+ depIndex?: number;
101
+ }
102
+
103
+ /**
104
+ * Get CKBFS script configuration for a specific network and version
105
+ * @param network Network type (mainnet or testnet)
106
+ * @param version Protocol version (default: latest version)
107
+ * @param useTypeID Whether to use type ID instead of code hash (default: false)
108
+ * @returns CKBFS script configuration
109
+ */
110
+ export function getCKBFSScriptConfig(
111
+ network: NetworkType = DEFAULT_NETWORK,
112
+ version: string = DEFAULT_VERSION,
113
+ useTypeID: boolean = false
114
+ ): CKBFSScriptConfig {
115
+ return {
116
+ codeHash: useTypeID
117
+ ? CKBFS_TYPE_ID[network][version]
118
+ : CKBFS_CODE_HASH[network][version],
119
+ hashType: useTypeID ? 'type' : 'data1',
120
+ depTxHash: DEP_GROUP_TX_HASH[network][version],
121
+ depIndex: 0
122
+ };
123
+ }
@@ -0,0 +1,109 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Utility functions for file operations
6
+ */
7
+
8
+ /**
9
+ * Reads a file from the file system
10
+ * @param filePath The path to the file to read
11
+ * @returns Buffer containing the file contents
12
+ */
13
+ export function readFile(filePath: string): Buffer {
14
+ return fs.readFileSync(filePath);
15
+ }
16
+
17
+ /**
18
+ * Reads a file as text from the file system
19
+ * @param filePath The path to the file to read
20
+ * @returns String containing the file contents
21
+ */
22
+ export function readFileAsText(filePath: string): string {
23
+ return fs.readFileSync(filePath, 'utf-8');
24
+ }
25
+
26
+ /**
27
+ * Reads a file as Uint8Array from the file system
28
+ * @param filePath The path to the file to read
29
+ * @returns Uint8Array containing the file contents
30
+ */
31
+ export function readFileAsUint8Array(filePath: string): Uint8Array {
32
+ const buffer = fs.readFileSync(filePath);
33
+ return new Uint8Array(buffer);
34
+ }
35
+
36
+ /**
37
+ * Writes data to a file in the file system
38
+ * @param filePath The path to write the file to
39
+ * @param data The data to write to the file
40
+ */
41
+ export function writeFile(filePath: string, data: Buffer | string): void {
42
+ // Ensure the directory exists
43
+ const dirPath = path.dirname(filePath);
44
+ if (!fs.existsSync(dirPath)) {
45
+ fs.mkdirSync(dirPath, { recursive: true });
46
+ }
47
+
48
+ fs.writeFileSync(filePath, data);
49
+ }
50
+
51
+ /**
52
+ * Gets the MIME content type based on file extension
53
+ * @param filePath The path to the file
54
+ * @returns The MIME content type for the file
55
+ */
56
+ export function getContentType(filePath: string): string {
57
+ const extension = path.extname(filePath).toLowerCase();
58
+
59
+ const mimeTypes: { [key: string]: string } = {
60
+ '.txt': 'text/plain',
61
+ '.html': 'text/html',
62
+ '.htm': 'text/html',
63
+ '.css': 'text/css',
64
+ '.js': 'application/javascript',
65
+ '.json': 'application/json',
66
+ '.jpg': 'image/jpeg',
67
+ '.jpeg': 'image/jpeg',
68
+ '.png': 'image/png',
69
+ '.gif': 'image/gif',
70
+ '.svg': 'image/svg+xml',
71
+ '.pdf': 'application/pdf',
72
+ '.mp3': 'audio/mpeg',
73
+ '.mp4': 'video/mp4',
74
+ '.wav': 'audio/wav',
75
+ '.xml': 'application/xml',
76
+ '.zip': 'application/zip',
77
+ '.md': 'text/markdown',
78
+ '.markdown': 'text/markdown',
79
+ };
80
+
81
+ return mimeTypes[extension] || 'application/octet-stream';
82
+ }
83
+
84
+ /**
85
+ * Splits a file into chunks of a specific size
86
+ * @param filePath The path to the file to split
87
+ * @param chunkSize The maximum size of each chunk in bytes
88
+ * @returns Array of Uint8Array chunks
89
+ */
90
+ export function splitFileIntoChunks(filePath: string, chunkSize: number): Uint8Array[] {
91
+ const fileBuffer = fs.readFileSync(filePath);
92
+ const chunks: Uint8Array[] = [];
93
+
94
+ for (let i = 0; i < fileBuffer.length; i += chunkSize) {
95
+ chunks.push(new Uint8Array(fileBuffer.slice(i, i + chunkSize)));
96
+ }
97
+
98
+ return chunks;
99
+ }
100
+
101
+ /**
102
+ * Combines chunks into a single file
103
+ * @param chunks Array of chunks to combine
104
+ * @param outputPath The path to write the combined file to
105
+ */
106
+ export function combineChunksToFile(chunks: Uint8Array[], outputPath: string): void {
107
+ const combinedBuffer = Buffer.concat(chunks.map(chunk => Buffer.from(chunk)));
108
+ writeFile(outputPath, combinedBuffer);
109
+ }
@@ -0,0 +1,190 @@
1
+ import { molecule, number } from "@ckb-lumos/codec";
2
+ import { blockchain } from "@ckb-lumos/base";
3
+ import { ProtocolVersion } from "./constants";
4
+
5
+ /**
6
+ * Molecule definitions for CKBFS data structures.
7
+ */
8
+
9
+ // Define the Indexes vector
10
+ export const Indexes = molecule.vector(number.Uint32);
11
+
12
+ // Define the BackLink table structure for V1
13
+ export const BackLinkV1 = molecule.table(
14
+ {
15
+ txHash: blockchain.Byte32,
16
+ index: number.Uint32,
17
+ checksum: number.Uint32,
18
+ },
19
+ ["txHash", "index", "checksum"]
20
+ );
21
+
22
+ // Define the BackLink table structure for V2
23
+ export const BackLinkV2 = molecule.table(
24
+ {
25
+ txHash: blockchain.Byte32,
26
+ indexes: Indexes,
27
+ checksum: number.Uint32,
28
+ },
29
+ ["txHash", "indexes", "checksum"]
30
+ );
31
+
32
+ // Define the BackLinks vector for V1
33
+ export const BackLinksV1 = molecule.vector(BackLinkV1);
34
+
35
+ // Define the BackLinks vector for V2
36
+ export const BackLinksV2 = molecule.vector(BackLinkV2);
37
+
38
+ // Define the CKBFSData table structure for V1
39
+ export const CKBFSDataV1 = molecule.table(
40
+ {
41
+ index: Indexes,
42
+ checksum: number.Uint32,
43
+ contentType: blockchain.Bytes,
44
+ filename: blockchain.Bytes,
45
+ backLinks: BackLinksV1,
46
+ },
47
+ ["index", "checksum", "contentType", "filename", "backLinks"]
48
+ );
49
+
50
+ // Define the CKBFSData table structure for V2
51
+ export const CKBFSDataV2 = molecule.table(
52
+ {
53
+ indexes: Indexes,
54
+ checksum: number.Uint32,
55
+ contentType: blockchain.Bytes,
56
+ filename: blockchain.Bytes,
57
+ backLinks: BackLinksV2,
58
+ },
59
+ ["indexes", "checksum", "contentType", "filename", "backLinks"]
60
+ );
61
+
62
+ // Type definitions for TypeScript
63
+ export type BackLinkTypeV1 = {
64
+ txHash: string;
65
+ index: number;
66
+ checksum: number;
67
+ };
68
+
69
+ export type BackLinkTypeV2 = {
70
+ txHash: string;
71
+ indexes: number[];
72
+ checksum: number;
73
+ };
74
+
75
+ // Combined type that works with both versions
76
+ export type BackLinkType = {
77
+ txHash: string;
78
+ index?: number;
79
+ indexes?: number[];
80
+ checksum: number;
81
+ };
82
+
83
+ // Combined CKBFSData type that works with both versions
84
+ export type CKBFSDataType = {
85
+ index?: number[];
86
+ indexes?: number[];
87
+ checksum: number;
88
+ contentType: Uint8Array;
89
+ filename: Uint8Array;
90
+ backLinks: BackLinkType[];
91
+ };
92
+
93
+ // Helper function to safely get either index or indexes
94
+ function getIndexes(data: CKBFSDataType): number[] {
95
+ return data.indexes || data.index || [];
96
+ }
97
+
98
+ // Helper function to safely get either index or indexes from BackLinkType
99
+ function getBackLinkIndex(bl: BackLinkType): number {
100
+ if (typeof bl.index === 'number') {
101
+ return bl.index;
102
+ }
103
+ if (Array.isArray(bl.indexes) && bl.indexes.length > 0) {
104
+ return bl.indexes[0];
105
+ }
106
+ return 0;
107
+ }
108
+
109
+ // Helper function to safely get indexes array from BackLinkType
110
+ function getBackLinkIndexes(bl: BackLinkType): number[] {
111
+ if (Array.isArray(bl.indexes)) {
112
+ return bl.indexes;
113
+ }
114
+ if (typeof bl.index === 'number') {
115
+ return [bl.index];
116
+ }
117
+ return [0];
118
+ }
119
+
120
+ // Helper function to get the right CKBFSData based on version
121
+ export const CKBFSData = {
122
+ pack: (data: CKBFSDataType, version: string = ProtocolVersion.V2): Uint8Array => {
123
+ if (version === ProtocolVersion.V1) {
124
+ // V1 formatting
125
+ return CKBFSDataV1.pack({
126
+ index: getIndexes(data),
127
+ checksum: data.checksum,
128
+ contentType: data.contentType,
129
+ filename: data.filename,
130
+ backLinks: data.backLinks.map(bl => ({
131
+ txHash: bl.txHash,
132
+ index: getBackLinkIndex(bl),
133
+ checksum: bl.checksum,
134
+ })),
135
+ });
136
+ } else {
137
+ // V2 formatting
138
+ return CKBFSDataV2.pack({
139
+ indexes: getIndexes(data),
140
+ checksum: data.checksum,
141
+ contentType: data.contentType,
142
+ filename: data.filename,
143
+ backLinks: data.backLinks.map(bl => ({
144
+ txHash: bl.txHash,
145
+ indexes: getBackLinkIndexes(bl),
146
+ checksum: bl.checksum,
147
+ })),
148
+ });
149
+ }
150
+ },
151
+ unpack: (buf: Uint8Array, version: string = ProtocolVersion.V2): CKBFSDataType => {
152
+ try {
153
+ if (version === ProtocolVersion.V1) {
154
+ const unpacked = CKBFSDataV1.unpack(buf);
155
+ return {
156
+ index: unpacked.index,
157
+ checksum: unpacked.checksum,
158
+ contentType: new Uint8Array(Buffer.from(unpacked.contentType)),
159
+ filename: new Uint8Array(Buffer.from(unpacked.filename)),
160
+ backLinks: unpacked.backLinks.map(bl => ({
161
+ txHash: bl.txHash,
162
+ index: bl.index,
163
+ checksum: bl.checksum,
164
+ })),
165
+ };
166
+ } else {
167
+ // V2 format
168
+ const unpacked = CKBFSDataV2.unpack(buf);
169
+ return {
170
+ indexes: unpacked.indexes,
171
+ checksum: unpacked.checksum,
172
+ contentType: new Uint8Array(Buffer.from(unpacked.contentType)),
173
+ filename: new Uint8Array(Buffer.from(unpacked.filename)),
174
+ backLinks: unpacked.backLinks.map(bl => ({
175
+ txHash: bl.txHash,
176
+ indexes: bl.indexes,
177
+ checksum: bl.checksum,
178
+ })),
179
+ };
180
+ }
181
+ } catch (error) {
182
+ console.error('Error unpacking CKBFSData:', error);
183
+ throw new Error('Failed to unpack CKBFSData: ' + error);
184
+ }
185
+ }
186
+ };
187
+
188
+ // Constants for CKBFS protocol
189
+ export const CKBFS_HEADER = new Uint8Array([0x43, 0x4B, 0x42, 0x46, 0x53]); // "CKBFS" in ASCII
190
+ export const CKBFS_HEADER_STRING = "CKBFS";