UNPKG

@ckbfs/api

Version:

SDK for CKBFS protocol on CKB

212 lines (193 loc) 6.17 kB
import { molecule, number } from "@ckb-lumos/codec"; import { blockchain } from "@ckb-lumos/base"; import { ProtocolVersion } from "./constants"; import { ccc } from "@ckb-ccc/core"; /** * Molecule definitions for CKBFS data structures. */ // Define the Indexes vector for V2 export const Indexes = molecule.vector(number.Uint32); // V1: BackLink has index as Uint32, and fields are ordered differently export const BackLinkV1 = molecule.table( { index: number.Uint32, checksum: number.Uint32, txHash: blockchain.Byte32, }, ["index", "checksum", "txHash"] ); // V2: BackLink has indexes as vector of Uint32 export const BackLinkV2 = molecule.table( { indexes: Indexes, checksum: number.Uint32, txHash: blockchain.Byte32, }, ["indexes", "checksum", "txHash"] ); // Define the BackLinks vector for V1 and V2 export const BackLinksV1 = molecule.vector(BackLinkV1); export const BackLinksV2 = molecule.vector(BackLinkV2); // V1: CKBFSData has index as optional Uint32 export const CKBFSDataV1 = molecule.table( { index: number.Uint32, checksum: number.Uint32, contentType: blockchain.Bytes, filename: blockchain.Bytes, backLinks: BackLinksV1, }, ["index", "checksum", "contentType", "filename", "backLinks"] ); // V2: CKBFSData has indexes as vector of Uint32 export const CKBFSDataV2 = molecule.table( { indexes: Indexes, checksum: number.Uint32, contentType: blockchain.Bytes, filename: blockchain.Bytes, backLinks: BackLinksV2, }, ["indexes", "checksum", "contentType", "filename", "backLinks"] ); // Type definitions for TypeScript export type BackLinkTypeV1 = { index: number; checksum: number; txHash: string; }; export type BackLinkTypeV2 = { indexes: number[]; checksum: number; txHash: string; }; // Combined type that works with both versions export type BackLinkType = { index?: number; indexes?: number[]; checksum: number; txHash: string; }; // Combined CKBFSData type that works with both versions export type CKBFSDataType = { index?: number; indexes?: number[]; checksum: number; contentType: string; filename: string; backLinks: BackLinkType[]; }; // Helper function to get indexes array from data function getIndexes(data: CKBFSDataType): number[] { if (data.indexes) return data.indexes; if (typeof data.index === 'number') return [data.index]; return []; } // Helper function to get single index from data function getIndex(data: CKBFSDataType): number { if (typeof data.index === 'number') return data.index; if (data.indexes && data.indexes.length > 0) return data.indexes[0]; return 0; } // Helper function to safely get either index or indexes from BackLinkType for V1 function getBackLinkIndex(bl: BackLinkType): number { if (typeof bl.index === 'number') { return bl.index; } if (Array.isArray(bl.indexes) && bl.indexes.length > 0) { return bl.indexes[0]; } return 0; } // Helper function to safely get indexes array from BackLinkType for V2 function getBackLinkIndexes(bl: BackLinkType): number[] { if (Array.isArray(bl.indexes)) { return bl.indexes; } if (typeof bl.index === 'number') { return [bl.index]; } return [0]; } // Helper function to get the right CKBFSData based on version export const CKBFSData = { pack: (data: CKBFSDataType, version: string = ProtocolVersion.V2): Uint8Array => { if (version === ProtocolVersion.V1) { // V1 formatting - uses single index return CKBFSDataV1.pack({ index: getIndex(data), checksum: data.checksum, contentType: ccc.bytesFrom(data.contentType, 'utf8'), filename: ccc.bytesFrom(data.filename, 'utf8'), backLinks: data.backLinks.map(bl => { // Ensure txHash is in proper format for molecule encoding const txHash = typeof bl.txHash === 'string' ? ccc.bytesFrom(bl.txHash) : bl.txHash; return { index: getBackLinkIndex(bl), checksum: bl.checksum, txHash, }; }), }); } else { // V2 formatting - uses indexes array return CKBFSDataV2.pack({ indexes: getIndexes(data), checksum: data.checksum, contentType: ccc.bytesFrom(data.contentType, 'utf8'), filename: ccc.bytesFrom(data.filename, 'utf8'), backLinks: data.backLinks.map(bl => { // Ensure txHash is in proper format for molecule encoding const txHash = typeof bl.txHash === 'string' ? bl.txHash : bl.txHash; return { indexes: getBackLinkIndexes(bl), checksum: bl.checksum, txHash, }; }), }); } }, unpack: (buf: Uint8Array, version: string = ProtocolVersion.V2): CKBFSDataType => { try { if (version === ProtocolVersion.V1) { const unpacked = CKBFSDataV1.unpack(buf); return { index: unpacked.index, checksum: unpacked.checksum, contentType: ccc.bytesTo(unpacked.contentType, 'utf8'), filename: ccc.bytesTo(unpacked.filename, 'utf8'), backLinks: unpacked.backLinks.map(bl => ({ index: bl.index, checksum: bl.checksum, txHash: bl.txHash, })), }; } else { // V2 format const unpacked = CKBFSDataV2.unpack(buf); return { indexes: unpacked.indexes, checksum: unpacked.checksum, contentType: ccc.bytesTo(unpacked.contentType, 'utf8'), filename: ccc.bytesTo(unpacked.filename, 'utf8'), backLinks: unpacked.backLinks.map(bl => ({ indexes: bl.indexes, checksum: bl.checksum, txHash: bl.txHash, })), }; } } catch (error) { console.error('Error unpacking CKBFSData:', error); throw new Error('Failed to unpack CKBFSData: ' + error); } } }; // Constants for CKBFS protocol export const CKBFS_HEADER = new Uint8Array([0x43, 0x4B, 0x42, 0x46, 0x53]); // "CKBFS" in ASCII export const CKBFS_HEADER_STRING = "CKBFS";