From e866243d92532bde8c776b0ac971e718ec537833 Mon Sep 17 00:00:00 2001 From: Hanssen0 Date: Thu, 8 Jan 2026 20:18:18 +0800 Subject: [PATCH 1/5] feat(core): auto complete cell capacity if it's not enough --- .changeset/weak-adults-rhyme.md | 6 +++ packages/core/src/ckb/transaction.test.ts | 55 ++++++++++------------- packages/core/src/ckb/transaction.ts | 8 ++-- packages/core/src/client/client.ts | 2 +- 4 files changed, 36 insertions(+), 35 deletions(-) create mode 100644 .changeset/weak-adults-rhyme.md diff --git a/.changeset/weak-adults-rhyme.md b/.changeset/weak-adults-rhyme.md new file mode 100644 index 00000000..54dca531 --- /dev/null +++ b/.changeset/weak-adults-rhyme.md @@ -0,0 +1,6 @@ +--- +"@ckb-ccc/core": minor +--- + +feat(core): auto complete cell capacity if it's not enough + \ No newline at end of file diff --git a/packages/core/src/ckb/transaction.test.ts b/packages/core/src/ckb/transaction.test.ts index 6271517d..c6a3a9d4 100644 --- a/packages/core/src/ckb/transaction.test.ts +++ b/packages/core/src/ckb/transaction.test.ts @@ -385,6 +385,9 @@ describe("Transaction", () => { { previousOutput: mockCapacityCells[0].outPoint, }, + { + previousOutput: mockCapacityCells[1].outPoint, + }, ], outputs: [ { @@ -647,22 +650,13 @@ describe("Transaction", () => { describe("Automatic Capacity Completion", () => { describe("CellOutput.from", () => { - it("should use explicit capacity when provided", () => { - const cellOutput = ccc.CellOutput.from({ - capacity: 1000n, - lock, - }); - - expect(cellOutput.capacity).toBe(1000n); - }); - it("should not modify capacity when data is not provided", () => { const cellOutput = ccc.CellOutput.from({ - capacity: 0n, + capacity: 100n, lock, }); - expect(cellOutput.capacity).toBe(0n); + expect(cellOutput.capacity).toBe(100n); }); it("should calculate capacity automatically when capacity is 0", () => { @@ -679,6 +673,20 @@ describe("Transaction", () => { expect(cellOutput.capacity).toBe(ccc.fixedPointFrom(expectedCapacity)); }); + it("should calculate capacity automatically when capacity is less than min requirement", () => { + const outputData = "0x1234"; // 2 bytes + const cellOutput = ccc.CellOutput.from( + { + capacity: 1000n, + lock, + }, + outputData, + ); + + const expectedCapacity = cellOutput.occupiedSize + 2; // occupiedSize + outputData length + expect(cellOutput.capacity).toBe(ccc.fixedPointFrom(expectedCapacity)); + }); + it("should calculate capacity automatically when capacity is omitted", () => { const outputData = "0x5678"; // 2 bytes const cellOutput = ccc.CellOutput.from( @@ -732,9 +740,9 @@ describe("Transaction", () => { expect(cellOutput.capacity).toBe(ccc.fixedPointFrom(expectedCapacity)); }); - it("should not auto-calculate when capacity is explicitly provided even with outputData", () => { + it("should not auto-calculate when capacity is enough even with outputData", () => { const outputData = "0x1234"; // 2 bytes - const explicitCapacity = 5000n; + const explicitCapacity = ccc.fixedPointFrom(100); const cellOutput = ccc.CellOutput.from( { capacity: explicitCapacity, @@ -745,21 +753,6 @@ describe("Transaction", () => { expect(cellOutput.capacity).toBe(explicitCapacity); }); - - it("should handle the overloaded signature correctly", () => { - // Test the overloaded signature where capacity is omitted and outputData is required - const outputData = "0xabcd"; - const cellOutput = ccc.CellOutput.from( - { - lock, - type, - }, - outputData, - ); - - const expectedCapacity = cellOutput.occupiedSize + 2; - expect(cellOutput.capacity).toBe(ccc.fixedPointFrom(expectedCapacity)); - }); }); describe("Transaction.from", () => { @@ -798,7 +791,7 @@ describe("Transaction", () => { it("should handle mixed explicit and automatic capacity calculation", () => { const outputsData = ["0x12", "0x3456"]; - const explicitCapacity = 5000n; + const explicitCapacity = ccc.fixedPointFrom(100); const tx = ccc.Transaction.from({ outputs: [ { @@ -951,7 +944,7 @@ describe("Transaction", () => { it("should add output with explicit capacity", () => { const tx = ccc.Transaction.default(); const outputData = "0x12"; - const explicitCapacity = 10000n; + const explicitCapacity = ccc.fixedPointFrom(100); tx.addOutput( { @@ -1142,7 +1135,7 @@ describe("Transaction", () => { it("should calculate capacityFree correctly", () => { const outputData = "0x1234"; - const explicitCapacity = 1000n; + const explicitCapacity = ccc.fixedPointFrom(100); const cell = ccc.Cell.from({ outPoint: { txHash: "0x" + "0".repeat(64), diff --git a/packages/core/src/ckb/transaction.ts b/packages/core/src/ckb/transaction.ts index d6e8ae3f..ad1d9d4d 100644 --- a/packages/core/src/ckb/transaction.ts +++ b/packages/core/src/ckb/transaction.ts @@ -16,6 +16,7 @@ import { NumLike, numFrom, numFromBytes, + numMax, numToBytes, numToHex, } from "../num/index.js"; @@ -274,9 +275,10 @@ export class CellOutput extends mol.Entity.Base() { ); })(); - if (output.capacity === Zero && outputData != null) { - output.capacity = fixedPointFrom( - output.occupiedSize + bytesFrom(outputData).length, + if (outputData != null) { + output.capacity = numMax( + output.capacity, + fixedPointFrom(output.occupiedSize + bytesFrom(outputData).length), ); } diff --git a/packages/core/src/client/client.ts b/packages/core/src/client/client.ts index 8c0cec7a..f8d8d5e2 100644 --- a/packages/core/src/client/client.ts +++ b/packages/core/src/client/client.ts @@ -369,7 +369,7 @@ export abstract class Client { async findSingletonCellByType( type: ScriptLike, - withData = false, + withData = true, ): Promise { for await (const cell of this.findCellsByType( type, From 99c34767ff6fe058b6ae9df7ea2ff3c302869f9a Mon Sep 17 00:00:00 2001 From: Hanssen0 Date: Tue, 16 Dec 2025 21:49:19 +0800 Subject: [PATCH 2/5] feat(core): add known script did ckb --- .changeset/poor-days-guess.md | 6 +++++ .../client/clientPublicMainnet.advanced.ts | 23 +++++++++++++++++++ .../client/clientPublicTestnet.advanced.ts | 23 +++++++++++++++++++ packages/core/src/client/knownScript.ts | 1 + 4 files changed, 53 insertions(+) create mode 100644 .changeset/poor-days-guess.md diff --git a/.changeset/poor-days-guess.md b/.changeset/poor-days-guess.md new file mode 100644 index 00000000..d6269460 --- /dev/null +++ b/.changeset/poor-days-guess.md @@ -0,0 +1,6 @@ +--- +"@ckb-ccc/core": minor +--- + +feat(core): add known script did ckb + \ No newline at end of file diff --git a/packages/core/src/client/clientPublicMainnet.advanced.ts b/packages/core/src/client/clientPublicMainnet.advanced.ts index 979b0955..bdcec4cc 100644 --- a/packages/core/src/client/clientPublicMainnet.advanced.ts +++ b/packages/core/src/client/clientPublicMainnet.advanced.ts @@ -321,6 +321,29 @@ export const MAINNET_SCRIPTS: Record = }, ], }, + [KnownScript.DidCkb]: { + codeHash: + "0x4a06164dc34dccade5afe3e847a97b6db743e79f5477fa3295acf02849c5984a", + hashType: "type", + cellDeps: [ + { + cellDep: { + outPoint: { + txHash: + "0xe2f74c56cdc610d2b9fe898a96a80118845f5278605d7f9ad535dad69ae015bf", + index: 0, + }, + depType: "code", + }, + type: { + codeHash: + "0x00000000000000000000000000000000000000000000000000545950455f4944", + args: "0x55573ef6d78e3ca75170ff476176732309a8b31efe94320a954ded3d75c2cb18", + hashType: "type", + }, + }, + ], + }, [KnownScript.AlwaysSuccess]: { codeHash: "0x3b521cc4b552f109d092d8cc468a8048acb53c5952dbe769d2b2f9cf6e47f7f1", diff --git a/packages/core/src/client/clientPublicTestnet.advanced.ts b/packages/core/src/client/clientPublicTestnet.advanced.ts index be811c7e..9453d252 100644 --- a/packages/core/src/client/clientPublicTestnet.advanced.ts +++ b/packages/core/src/client/clientPublicTestnet.advanced.ts @@ -333,6 +333,29 @@ export const TESTNET_SCRIPTS: Record = }, ], }, + [KnownScript.DidCkb]: { + codeHash: + "0x510150477b10d6ab551a509b71265f3164e9fd4137fcb5a4322f49f03092c7c5", + hashType: "type", + cellDeps: [ + { + cellDep: { + outPoint: { + txHash: + "0x0e7a830e2d5ebd05cd45a55f93f94559edea0ef1237b7233f49f7facfb3d6a6c", + index: 0, + }, + depType: "code", + }, + type: { + codeHash: + "0x00000000000000000000000000000000000000000000000000545950455f4944", + args: "0x3c27695173b888ed44ddf36f901789014384ad6c05a9137f3db9a0779c141c35", + hashType: "type", + }, + }, + ], + }, [KnownScript.AlwaysSuccess]: { codeHash: "0x3b521cc4b552f109d092d8cc468a8048acb53c5952dbe769d2b2f9cf6e47f7f1", diff --git a/packages/core/src/client/knownScript.ts b/packages/core/src/client/knownScript.ts index 2171b90b..90a1546f 100644 --- a/packages/core/src/client/knownScript.ts +++ b/packages/core/src/client/knownScript.ts @@ -15,6 +15,7 @@ export enum KnownScript { OmniLock = "OmniLock", NostrLock = "NostrLock", UniqueType = "UniqueType", + DidCkb = "DidCkb", // ckb-proxy-locks https://github.com/ckb-devrel/ckb-proxy-locks AlwaysSuccess = "AlwaysSuccess", From c093763d606d29df63c230caca2b9fe28cb224d8 Mon Sep 17 00:00:00 2001 From: Hanssen0 Date: Thu, 8 Jan 2026 18:43:49 +0800 Subject: [PATCH 3/5] feat(core): extract a universal `Codec` from `mol.Codec` --- .changeset/calm-doors-poke.md | 6 + packages/core/src/barrel.ts | 1 + packages/core/src/ckb/epoch.ts | 13 +- packages/core/src/ckb/script.ts | 7 +- packages/core/src/ckb/transaction.ts | 37 ++-- packages/core/src/codec/codec.ts | 108 ++++++++++ .../core/src/{molecule => codec}/entity.ts | 12 +- packages/core/src/codec/index.ts | 3 + packages/core/src/codec/predefined.ts | 145 ++++++++++++++ packages/core/src/molecule/barrel.ts | 11 +- packages/core/src/molecule/codec.ts | 188 +++--------------- packages/core/src/molecule/predefined.ts | 113 ++++++----- packages/spore/src/cobuild/index.ts | 20 +- packages/spore/src/codec/cluster.ts | 4 +- packages/spore/src/codec/spore.ts | 2 +- packages/spore/src/spore/advanced.ts | 4 +- 16 files changed, 417 insertions(+), 257 deletions(-) create mode 100644 .changeset/calm-doors-poke.md create mode 100644 packages/core/src/codec/codec.ts rename packages/core/src/{molecule => codec}/entity.ts (94%) create mode 100644 packages/core/src/codec/index.ts create mode 100644 packages/core/src/codec/predefined.ts diff --git a/.changeset/calm-doors-poke.md b/.changeset/calm-doors-poke.md new file mode 100644 index 00000000..9809e521 --- /dev/null +++ b/.changeset/calm-doors-poke.md @@ -0,0 +1,6 @@ +--- +"@ckb-ccc/core": minor +--- + +feat(core): extract a universal `Codec` from `mol.Codec` + \ No newline at end of file diff --git a/packages/core/src/barrel.ts b/packages/core/src/barrel.ts index a9285507..85d94232 100644 --- a/packages/core/src/barrel.ts +++ b/packages/core/src/barrel.ts @@ -2,6 +2,7 @@ export * from "./address/index.js"; export * from "./bytes/index.js"; export * from "./ckb/index.js"; export * from "./client/index.js"; +export * from "./codec/index.js"; export * from "./fixedPoint/index.js"; export * from "./hasher/index.js"; export * from "./hex/index.js"; diff --git a/packages/core/src/ckb/epoch.ts b/packages/core/src/ckb/epoch.ts index 36185a05..8ee254ad 100644 --- a/packages/core/src/ckb/epoch.ts +++ b/packages/core/src/ckb/epoch.ts @@ -1,4 +1,5 @@ import type { ClientBlockHeader } from "../client/clientTypes.js"; +import { codec, codecPadding, codecUint, Entity } from "../codec/index.js"; import { Zero } from "../fixedPoint/index.js"; import { type Hex, type HexLike } from "../hex/index.js"; import { mol } from "../molecule/index.js"; @@ -54,15 +55,15 @@ export type EpochLike = * @remarks * This class is primarily a thin value-object; operations return new Epoch instances. */ -@mol.codec( +@codec( mol.struct({ - padding: mol.padding(1), - denominator: mol.uint(2), - numerator: mol.uint(2), - integer: mol.uint(3), + padding: codecPadding(1), + denominator: codecUint(2), + numerator: codecUint(2), + integer: codecUint(3), }), ) -export class Epoch extends mol.Entity.Base() { +export class Epoch extends Entity.Base() { /** * Construct a new Epoch instance. * diff --git a/packages/core/src/ckb/script.ts b/packages/core/src/ckb/script.ts index 1de3c7ac..21405c8a 100644 --- a/packages/core/src/ckb/script.ts +++ b/packages/core/src/ckb/script.ts @@ -1,6 +1,7 @@ import { Bytes, BytesLike, bytesFrom } from "../bytes/index.js"; import type { Client } from "../client/index.js"; import { KnownScript } from "../client/knownScript.js"; +import { Codec, Entity, codec } from "../codec/index.js"; import { Hex, HexLike, hexFrom } from "../hex/index.js"; import { mol } from "../molecule/index.js"; import { @@ -9,7 +10,7 @@ import { NUM_TO_HASH_TYPE, } from "./script.advanced.js"; -export const HashTypeCodec: mol.Codec = mol.Codec.from({ +export const HashTypeCodec: Codec = Codec.from({ byteLength: 1, encode: hashTypeToBytes, decode: hashTypeFromBytes, @@ -108,14 +109,14 @@ export type ScriptLike = { /** * @public */ -@mol.codec( +@codec( mol.table({ codeHash: mol.Byte32, hashType: HashTypeCodec, args: mol.Bytes, }), ) -export class Script extends mol.Entity.Base() { +export class Script extends Entity.Base() { /** * Creates an instance of Script. * diff --git a/packages/core/src/ckb/transaction.ts b/packages/core/src/ckb/transaction.ts index ad1d9d4d..2cb60e90 100644 --- a/packages/core/src/ckb/transaction.ts +++ b/packages/core/src/ckb/transaction.ts @@ -7,6 +7,7 @@ import { type ClientBlockHeaderLike, } from "../client/index.js"; import { KnownScript } from "../client/knownScript.js"; +import { Codec, Entity, codec } from "../codec/index.js"; import { Zero, fixedPointFrom } from "../fixedPoint/index.js"; import { Hasher, HasherCkb, hashCkb } from "../hasher/index.js"; import { Hex, HexLike, hexFrom } from "../hex/index.js"; @@ -31,7 +32,7 @@ import { } from "./transactionErrors.js"; import type { LumosTransactionSkeletonType } from "./transactionLumos.js"; -export const DepTypeCodec: mol.Codec = mol.Codec.from({ +export const DepTypeCodec: Codec = Codec.from({ byteLength: 1, encode: depTypeToBytes, decode: depTypeFromBytes, @@ -126,13 +127,13 @@ export type OutPointLike = { /** * @public */ -@mol.codec( +@codec( mol.struct({ txHash: mol.Byte32, index: mol.Uint32, }), ) -export class OutPoint extends mol.Entity.Base() { +export class OutPoint extends Entity.Base() { /** * Creates an instance of OutPoint. * @@ -207,14 +208,14 @@ export type CellOutputLike = { /** * @public */ -@mol.codec( +@codec( mol.table({ capacity: mol.Uint64, lock: Script, type: ScriptOpt, }), ) -export class CellOutput extends mol.Entity.Base() { +export class CellOutput extends Entity.Base() { /** * Creates an instance of CellOutput. * @@ -666,10 +667,10 @@ export type SinceLike = /** * @public */ -@mol.codec( +@codec( mol.Uint64.mapIn((encodable: SinceLike) => Since.from(encodable).toNum()), ) -export class Since extends mol.Entity.Base() { +export class Since extends Entity.Base() { /** * Creates an instance of Since. * @@ -787,7 +788,7 @@ export type CellInputLike = ( /** * @public */ -@mol.codec( +@codec( mol .struct({ since: Since, @@ -795,7 +796,7 @@ export type CellInputLike = ( }) .mapIn((encodable: CellInputLike) => CellInput.from(encodable)), ) -export class CellInput extends mol.Entity.Base() { +export class CellInput extends Entity.Base() { /** * Creates an instance of CellInput. * @@ -924,13 +925,13 @@ export type CellDepLike = { /** * @public */ -@mol.codec( +@codec( mol.struct({ outPoint: OutPoint, depType: DepTypeCodec, }), ) -export class CellDep extends mol.Entity.Base() { +export class CellDep extends Entity.Base() { /** * Creates an instance of CellDep. * @@ -998,17 +999,14 @@ export type WitnessArgsLike = { /** * @public */ -@mol.codec( +@codec( mol.table({ lock: mol.BytesOpt, inputType: mol.BytesOpt, outputType: mol.BytesOpt, }), ) -export class WitnessArgs extends mol.Entity.Base< - WitnessArgsLike, - WitnessArgs ->() { +export class WitnessArgs extends Entity.Base() { /** * Creates an instance of WitnessArgs. * @@ -1091,7 +1089,7 @@ export type TransactionLike = { /** * @public */ -@mol.codec( +@codec( mol .table({ raw: RawTransaction, @@ -1106,10 +1104,7 @@ export type TransactionLike = { }) .mapOut((tx) => Transaction.from({ ...tx.raw, witnesses: tx.witnesses })), ) -export class Transaction extends mol.Entity.Base< - TransactionLike, - Transaction ->() { +export class Transaction extends Entity.Base() { /** * Creates an instance of Transaction. * diff --git a/packages/core/src/codec/codec.ts b/packages/core/src/codec/codec.ts new file mode 100644 index 00000000..77a9c4e6 --- /dev/null +++ b/packages/core/src/codec/codec.ts @@ -0,0 +1,108 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { Bytes, bytesFrom, BytesLike } from "../bytes/index.js"; + +export type CodecLike = { + readonly encode: (encodable: Encodable) => Bytes; + readonly decode: ( + decodable: BytesLike, + config?: { isExtraFieldIgnored?: boolean }, + ) => Decoded; + readonly byteLength?: number; +}; +export class Codec { + constructor( + public readonly encode: (encodable: Encodable) => Bytes, + public readonly decode: ( + decodable: BytesLike, + config?: { isExtraFieldIgnored?: boolean }, // This is equivalent to "compatible" in the Rust implementation of Molecule. + ) => Decoded, + public readonly byteLength?: number, // if provided, treat codec as fixed length + ) {} + + encodeOr(encodable: Encodable, fallback: T): Bytes | T { + try { + return this.encode(encodable); + } catch (_) { + return fallback; + } + } + + decodeOr( + decodable: BytesLike, + fallback: T, + config?: { isExtraFieldIgnored?: boolean }, // This is equivalent to "compatible" in the Rust implementation of Molecule. + ) { + try { + return this.decode(decodable, config); + } catch (_) { + return fallback; + } + } + + static from({ + encode, + decode, + byteLength, + }: CodecLike): Codec { + return new Codec( + (encodable: Encodable) => { + const encoded = encode(encodable); + if (byteLength !== undefined && encoded.byteLength !== byteLength) { + throw new Error( + `Codec.encode: expected byte length ${byteLength}, got ${encoded.byteLength}`, + ); + } + return encoded; + }, + (decodable, config) => { + const decodableBytes = bytesFrom(decodable); + if ( + byteLength !== undefined && + decodableBytes.byteLength !== byteLength + ) { + throw new Error( + `Codec.decode: expected byte length ${byteLength}, got ${decodableBytes.byteLength}`, + ); + } + return decode(decodable, config); + }, + byteLength, + ); + } + + map({ + inMap, + outMap, + }: { + inMap?: (encodable: NewEncodable) => Encodable; + outMap?: (decoded: Decoded) => NewDecoded; + }): Codec { + return new Codec( + (encodable) => + this.encode((inMap ? inMap(encodable) : encodable) as Encodable), + (buffer, config) => + (outMap + ? outMap(this.decode(buffer, config)) + : this.decode(buffer, config)) as NewDecoded, + this.byteLength, + ); + } + + mapIn( + map: (encodable: NewEncodable) => Encodable, + ): Codec { + return this.map({ inMap: map }); + } + + mapOut( + map: (decoded: Decoded) => NewDecoded, + ): Codec { + return this.map({ outMap: map }); + } +} + +export type EncodableType> = + T extends CodecLike ? Encodable : never; +export type DecodedType> = + T extends CodecLike ? Decoded : never; diff --git a/packages/core/src/molecule/entity.ts b/packages/core/src/codec/entity.ts similarity index 94% rename from packages/core/src/molecule/entity.ts rename to packages/core/src/codec/entity.ts index 4486aa5e..d62a7a53 100644 --- a/packages/core/src/molecule/entity.ts +++ b/packages/core/src/codec/entity.ts @@ -32,7 +32,7 @@ export abstract class Entity { */ static encode(_: SubTypeLike): Bytes { throw new Error( - "encode not implemented, use @ccc.mol.codec to decorate your type", + "encode not implemented, use @ccc.codec to decorate your type", ); } /** @@ -45,7 +45,7 @@ export abstract class Entity { */ static decode(_: BytesLike): SubType { throw new Error( - "decode not implemented, use @ccc.mol.codec to decorate your type", + "decode not implemented, use @ccc.codec to decorate your type", ); } @@ -59,7 +59,7 @@ export abstract class Entity { */ static fromBytes(_bytes: BytesLike): SubType { throw new Error( - "fromBytes not implemented, use @ccc.mol.codec to decorate your type", + "fromBytes not implemented, use @ccc.codec to decorate your type", ); } @@ -156,14 +156,14 @@ export abstract class Entity { * A class decorator to add methods implementation on the {@link Entity.Base} class * @example * ```typescript - * @mol.codec( + * @codec( * mol.table({ * codeHash: mol.Byte32, * hashType: HashTypeCodec, * args: mol.Bytes, * }), * ) - * export class Script extends mol.Entity.Base() { + * export class Script extends Entity.Base() { * from(scriptLike: ScriptLike): Script {} * } * ``` @@ -186,7 +186,7 @@ export function codec< Constructor.byteLength = codec.byteLength; if (Constructor.encode === undefined) { Constructor.encode = function (encodable: TypeLike) { - return codec.encode(encodable); + return codec.encode(Constructor.from(encodable)); }; } if (Constructor.decode === undefined) { diff --git a/packages/core/src/codec/index.ts b/packages/core/src/codec/index.ts new file mode 100644 index 00000000..7688d875 --- /dev/null +++ b/packages/core/src/codec/index.ts @@ -0,0 +1,3 @@ +export * from "./codec.js"; +export * from "./entity.js"; +export * from "./predefined.js"; diff --git a/packages/core/src/codec/predefined.ts b/packages/core/src/codec/predefined.ts new file mode 100644 index 00000000..b14b90da --- /dev/null +++ b/packages/core/src/codec/predefined.ts @@ -0,0 +1,145 @@ +import { Bytes, bytesFrom, BytesLike } from "../bytes/index.js"; +import { Hex, hexFrom, HexLike } from "../hex/index.js"; +import { + Num, + numBeFromBytes, + numBeToBytes, + numFromBytes, + NumLike, + numToBytes, +} from "../num/index.js"; +import { Codec } from "./codec.js"; + +/** + * Create a codec to deal with fixed LE or BE bytes. + * @param byteLength + * @param littleEndian + */ +export function codecUint( + byteLength: number, + littleEndian = false, +): Codec { + return Codec.from({ + byteLength, + encode: (numLike) => { + if (littleEndian) { + return numToBytes(numLike, byteLength); + } else { + return numBeToBytes(numLike, byteLength); + } + }, + decode: (buffer) => { + if (littleEndian) { + return numFromBytes(buffer); + } else { + return numBeFromBytes(buffer); + } + }, + }); +} + +/** + * Create a codec to deal with fixed LE or BE bytes. + * @param byteLength + * @param littleEndian + */ +export function codecUintNumber( + byteLength: number, + littleEndian = false, +): Codec { + if (byteLength > 4) { + throw new Error("uintNumber: byteLength must be less than or equal to 4"); + } + return codecUint(byteLength, littleEndian).map({ + outMap: (num) => Number(num), + }); +} + +/** + * Create a codec for padding bytes. + * The padding bytes are zero-filled when encoding and ignored when decoding. + * @param byteLength The length of the padding in bytes. + */ +export function codecPadding( + byteLength: number, +): Codec { + return Codec.from({ + byteLength, + encode: () => { + return new Uint8Array(byteLength); + }, + decode: () => {}, + }); +} + +export const CodecRaw: Codec = Codec.from({ + encode: (value) => bytesFrom(value), + decode: (buffer) => bytesFrom(buffer), +}); + +export const CodecBytes: Codec = Codec.from({ + encode: (value) => bytesFrom(value), + decode: (buffer) => hexFrom(buffer), +}); + +export const CodecUint8 = codecUintNumber(1, true); + +export const CodecUint16LE = codecUintNumber(2, true); +export const CodecUint16BE = codecUintNumber(2); +export const CodecUint16 = CodecUint16LE; + +export const CodecUint32LE = codecUintNumber(4, true); +export const CodecUint32BE = codecUintNumber(4); +export const CodecUint32 = CodecUint32LE; + +export const CodecUint64LE = codecUint(8, true); +export const CodecUint64BE = codecUint(8); +export const CodecUint64 = CodecUint64LE; + +export const CodecUint128LE = codecUint(16, true); +export const CodecUint128BE = codecUint(16); +export const CodecUint128 = CodecUint128LE; + +export const CodecUint256LE = codecUint(32, true); +export const CodecUint256BE = codecUint(32); +export const CodecUint256 = CodecUint256LE; + +export const CodecUint512LE = codecUint(64, true); +export const CodecUint512BE = codecUint(64); +export const CodecUint512 = CodecUint512LE; + +export const CodecBool: Codec = Codec.from({ + byteLength: 1, + encode: (value) => bytesFrom(value ? [1] : [0]), + decode: (buffer) => bytesFrom(buffer)[0] !== 0, +}); + +export const CodecByte: Codec = Codec.from({ + byteLength: 1, + encode: (value) => bytesFrom(value), + decode: (buffer) => hexFrom(buffer), +}); + +export const CodecByte4: Codec = Codec.from({ + byteLength: 4, + encode: (value) => bytesFrom(value), + decode: (buffer) => hexFrom(buffer), +}); + +export const CodecByte8: Codec = Codec.from({ + byteLength: 8, + encode: (value) => bytesFrom(value), + decode: (buffer) => hexFrom(buffer), +}); + +export const CodecByte16: Codec = Codec.from({ + byteLength: 16, + encode: (value) => bytesFrom(value), + decode: (buffer) => hexFrom(buffer), +}); + +export const CodecByte32: Codec = Codec.from({ + byteLength: 32, + encode: (value) => bytesFrom(value), + decode: (buffer) => hexFrom(buffer), +}); diff --git a/packages/core/src/molecule/barrel.ts b/packages/core/src/molecule/barrel.ts index 7688d875..98d88a3c 100644 --- a/packages/core/src/molecule/barrel.ts +++ b/packages/core/src/molecule/barrel.ts @@ -1,3 +1,12 @@ +export { + /** + * @deprecated Use ccc.Entity instead + */ + Entity, + /** + * @deprecated Use ccc.codec instead + */ + codec, +} from "../codec/entity.js"; export * from "./codec.js"; -export * from "./entity.js"; export * from "./predefined.js"; diff --git a/packages/core/src/molecule/codec.ts b/packages/core/src/molecule/codec.ts index 70af71fa..ff09cab9 100644 --- a/packages/core/src/molecule/codec.ts +++ b/packages/core/src/molecule/codec.ts @@ -1,105 +1,45 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { - Bytes, bytesConcat, bytesConcatTo, bytesFrom, BytesLike, } from "../bytes/index.js"; import { - Num, - numBeFromBytes, - numBeToBytes, - numFromBytes, - NumLike, - numToBytes, -} from "../num/index.js"; - -export type CodecLike = { - readonly encode: (encodable: Encodable) => Bytes; - readonly decode: ( - decodable: BytesLike, - config?: { isExtraFieldIgnored?: boolean }, - ) => Decoded; - readonly byteLength?: number; -}; -export class Codec { - constructor( - public readonly encode: (encodable: Encodable) => Bytes, - public readonly decode: ( - decodable: BytesLike, - config?: { isExtraFieldIgnored?: boolean }, // This is equivalent to "compatible" in the Rust implementation of Molecule. - ) => Decoded, - public readonly byteLength?: number, // if provided, treat codec as fixed length - ) {} - - static from({ - encode, - decode, - byteLength, - }: CodecLike): Codec { - return new Codec( - (encodable: Encodable) => { - const encoded = encode(encodable); - if (byteLength !== undefined && encoded.byteLength !== byteLength) { - throw new Error( - `Codec.encode: expected byte length ${byteLength}, got ${encoded.byteLength}`, - ); - } - return encoded; - }, - (decodable, config) => { - const decodableBytes = bytesFrom(decodable); - if ( - byteLength !== undefined && - decodableBytes.byteLength !== byteLength - ) { - throw new Error( - `Codec.decode: expected byte length ${byteLength}, got ${decodableBytes.byteLength}`, - ); - } - return decode(decodable, config); - }, - byteLength, - ); - } - - map({ - inMap, - outMap, - }: { - inMap?: (encodable: NewEncodable) => Encodable; - outMap?: (decoded: Decoded) => NewDecoded; - }): Codec { - return new Codec( - (encodable) => - this.encode((inMap ? inMap(encodable) : encodable) as Encodable), - (buffer, config) => - (outMap - ? outMap(this.decode(buffer, config)) - : this.decode(buffer, config)) as NewDecoded, - this.byteLength, - ); - } - - mapIn( - map: (encodable: NewEncodable) => Encodable, - ): Codec { - return this.map({ inMap: map }); - } - - mapOut( - map: (decoded: Decoded) => NewDecoded, - ): Codec { - return this.map({ outMap: map }); - } -} - -export type EncodableType> = - T extends CodecLike ? Encodable : never; -export type DecodedType> = - T extends CodecLike ? Decoded : never; + Codec, + CodecLike, + DecodedType, + EncodableType, +} from "../codec/index.js"; +import { numFromBytes, NumLike, numToBytes } from "../num/index.js"; + +export { + /** + * @deprecated Use ccc.Codec instead + */ + Codec, + /** + * @deprecated Use ccc.CodecLike instead + */ + CodecLike, + /** + * @deprecated Use ccc.DecodedType instead + */ + DecodedType, + /** + * @deprecated Use ccc.EncodableType instead + */ + EncodableType, + /** + * @deprecated Use ccc.codecUint instead + */ + codecUint as uint, + /** + * @deprecated Use ccc.codecUintNumber instead + */ + codecUintNumber as uintNumber, +} from "../codec/index.js"; function uint32To(numLike: NumLike) { return numToBytes(numLike, 4); @@ -673,65 +613,3 @@ export function array( }, }); } - -/** - * Create a codec to deal with fixed LE or BE bytes. - * @param byteLength - * @param littleEndian - */ -export function uint( - byteLength: number, - littleEndian = false, -): Codec { - return Codec.from({ - byteLength, - encode: (numLike) => { - if (littleEndian) { - return numToBytes(numLike, byteLength); - } else { - return numBeToBytes(numLike, byteLength); - } - }, - decode: (buffer) => { - if (littleEndian) { - return numFromBytes(buffer); - } else { - return numBeFromBytes(buffer); - } - }, - }); -} - -/** - * Create a codec to deal with fixed LE or BE bytes. - * @param byteLength - * @param littleEndian - */ -export function uintNumber( - byteLength: number, - littleEndian = false, -): Codec { - if (byteLength > 4) { - throw new Error("uintNumber: byteLength must be less than or equal to 4"); - } - return uint(byteLength, littleEndian).map({ - outMap: (num) => Number(num), - }); -} - -/** - * Create a codec for padding bytes. - * The padding bytes are zero-filled when encoding and ignored when decoding. - * @param byteLength The length of the padding in bytes. - */ -export function padding( - byteLength: number, -): Codec { - return Codec.from({ - byteLength, - encode: () => { - return new Uint8Array(byteLength); - }, - decode: () => {}, - }); -} diff --git a/packages/core/src/molecule/predefined.ts b/packages/core/src/molecule/predefined.ts index 176da41c..7e13c3ff 100644 --- a/packages/core/src/molecule/predefined.ts +++ b/packages/core/src/molecule/predefined.ts @@ -1,91 +1,104 @@ import { bytesFrom, bytesTo } from "../bytes/index.js"; -import { Hex, hexFrom, HexLike } from "../hex/index.js"; -import { byteVec, Codec, option, uint, uintNumber, vector } from "./codec.js"; +import { Codec, CodecBytes } from "../codec/index.js"; +import { Hex, HexLike } from "../hex/index.js"; +import { byteVec, option, vector } from "./codec.js"; + +import { + CodecBool as Bool, + CodecByte as Byte, + CodecByte16 as Byte16, + CodecByte32 as Byte32, + CodecByte4 as Byte4, + CodecByte8 as Byte8, + CodecUint128 as Uint128, + CodecUint128BE as Uint128BE, + CodecUint128LE as Uint128LE, + CodecUint16 as Uint16, + CodecUint16BE as Uint16BE, + CodecUint16LE as Uint16LE, + CodecUint256 as Uint256, + CodecUint256BE as Uint256BE, + CodecUint256LE as Uint256LE, + CodecUint32 as Uint32, + CodecUint32BE as Uint32BE, + CodecUint32LE as Uint32LE, + CodecUint512 as Uint512, + CodecUint512BE as Uint512BE, + CodecUint512LE as Uint512LE, + CodecUint64 as Uint64, + CodecUint64BE as Uint64BE, + CodecUint64LE as Uint64LE, + CodecUint8 as Uint8, +} from "../codec/index.js"; + +export { + Bool, + Byte, + Byte16, + Byte32, + Byte4, + Byte8, + Uint128, + Uint128BE, + Uint128LE, + Uint16, + Uint16BE, + Uint16LE, + Uint256, + Uint256BE, + Uint256LE, + Uint32, + Uint32BE, + Uint32LE, + Uint512, + Uint512BE, + Uint512LE, + Uint64, + Uint64BE, + Uint64LE, + Uint8, +}; -export const Uint8 = uintNumber(1, true); export const Uint8Opt = option(Uint8); export const Uint8Vec = vector(Uint8); -export const Uint16LE = uintNumber(2, true); -export const Uint16BE = uintNumber(2); -export const Uint16 = Uint16LE; export const Uint16Opt = option(Uint16); export const Uint16Vec = vector(Uint16); -export const Uint32LE = uintNumber(4, true); -export const Uint32BE = uintNumber(4); -export const Uint32 = Uint32LE; export const Uint32Opt = option(Uint32); export const Uint32Vec = vector(Uint32); -export const Uint64LE = uint(8, true); -export const Uint64BE = uint(8); -export const Uint64 = Uint64LE; export const Uint64Opt = option(Uint64); export const Uint64Vec = vector(Uint64); -export const Uint128LE = uint(16, true); -export const Uint128BE = uint(16); -export const Uint128 = Uint128LE; export const Uint128Opt = option(Uint128); export const Uint128Vec = vector(Uint128); -export const Uint256LE = uint(32, true); -export const Uint256BE = uint(32); -export const Uint256 = Uint256LE; export const Uint256Opt = option(Uint256); export const Uint256Vec = vector(Uint256); -export const Uint512LE = uint(64, true); -export const Uint512BE = uint(64); -export const Uint512 = Uint512LE; export const Uint512Opt = option(Uint512); export const Uint512Vec = vector(Uint512); -export const Bytes: Codec = byteVec({ - encode: (value) => bytesFrom(value), - decode: (buffer) => hexFrom(buffer), -}); +export const Bytes: Codec = byteVec(CodecBytes); export const BytesOpt = option(Bytes); export const BytesVec = vector(Bytes); -export const Bool: Codec = Codec.from({ - byteLength: 1, - encode: (value) => bytesFrom(value ? [1] : [0]), - decode: (buffer) => bytesFrom(buffer)[0] !== 0, -}); export const BoolOpt = option(Bool); export const BoolVec = vector(Bool); -export const Byte4: Codec = Codec.from({ - byteLength: 4, - encode: (value) => bytesFrom(value), - decode: (buffer) => hexFrom(buffer), -}); +export const ByteOpt = option(Byte); +export const ByteVec = vector(Byte); + export const Byte4Opt = option(Byte4); export const Byte4Vec = vector(Byte4); -export const Byte8: Codec = Codec.from({ - byteLength: 8, - encode: (value) => bytesFrom(value), - decode: (buffer) => hexFrom(buffer), -}); export const Byte8Opt = option(Byte8); export const Byte8Vec = vector(Byte8); -export const Byte16: Codec = Codec.from({ - byteLength: 16, - encode: (value) => bytesFrom(value), - decode: (buffer) => hexFrom(buffer), -}); export const Byte16Opt = option(Byte16); export const Byte16Vec = vector(Byte16); -export const Byte32: Codec = Codec.from({ - byteLength: 32, - encode: (value) => bytesFrom(value), - decode: (buffer) => hexFrom(buffer), -}); export const Byte32Opt = option(Byte32); export const Byte32Vec = vector(Byte32); diff --git a/packages/spore/src/cobuild/index.ts b/packages/spore/src/cobuild/index.ts index c1c5b52b..4437f56d 100644 --- a/packages/spore/src/cobuild/index.ts +++ b/packages/spore/src/cobuild/index.ts @@ -1,4 +1,4 @@ -import { ccc, mol } from "@ckb-ccc/core"; +import { ccc } from "@ckb-ccc/core"; import { Action, ActionVec, @@ -11,7 +11,7 @@ export function assembleCreateSporeAction( sporeOutput: ccc.CellOutputLike, sporeData: ccc.BytesLike, scriptInfoHash: ccc.HexLike = DEFAULT_COBUILD_INFO_HASH, -): mol.EncodableType { +): ccc.EncodableType { if (!sporeOutput.type) { throw new Error("Spore cell must have a type script"); } @@ -39,7 +39,7 @@ export function assembleTransferSporeAction( sporeInput: ccc.CellOutputLike, sporeOutput: ccc.CellOutputLike, scriptInfoHash: ccc.HexLike = DEFAULT_COBUILD_INFO_HASH, -): mol.EncodableType { +): ccc.EncodableType { if (!sporeInput.type || !sporeOutput.type) { throw new Error("Spore cell must have a type script"); } @@ -70,7 +70,7 @@ export function assembleTransferSporeAction( export function assembleMeltSporeAction( sporeInput: ccc.CellOutputLike, scriptInfoHash: ccc.HexLike = DEFAULT_COBUILD_INFO_HASH, -): mol.EncodableType { +): ccc.EncodableType { if (!sporeInput.type) { throw new Error("Spore cell must have a type script"); } @@ -97,7 +97,7 @@ export function assembleCreateClusterAction( clusterOutput: ccc.CellOutputLike, clusterData: ccc.BytesLike, scriptInfoHash: ccc.HexLike = DEFAULT_COBUILD_INFO_HASH, -): mol.EncodableType { +): ccc.EncodableType { if (!clusterOutput.type) { throw new Error("Cluster cell must have a type script"); } @@ -125,7 +125,7 @@ export function assembleTransferClusterAction( clusterInput: ccc.CellOutputLike, clusterOutput: ccc.CellOutputLike, scriptInfoHash: ccc.HexLike = DEFAULT_COBUILD_INFO_HASH, -): mol.EncodableType { +): ccc.EncodableType { if (!clusterInput.type || !clusterOutput.type) { throw new Error("Cluster cell must have a type script"); } @@ -155,7 +155,7 @@ export function assembleTransferClusterAction( export async function prepareSporeTransaction( signer: ccc.Signer, txLike: ccc.TransactionLike, - actions: mol.EncodableType, + actions: ccc.EncodableType, ): Promise { let tx = ccc.Transaction.from(txLike); @@ -171,7 +171,7 @@ export async function prepareSporeTransaction( export function unpackCommonCobuildProof( data: ccc.HexLike, -): mol.EncodableType | undefined { +): ccc.EncodableType | undefined { try { return WitnessLayout.decode(ccc.bytesFrom(data)); } catch { @@ -181,7 +181,7 @@ export function unpackCommonCobuildProof( export function extractCobuildActionsFromTx( tx: ccc.Transaction, -): mol.EncodableType { +): ccc.EncodableType { if (tx.witnesses.length === 0) { return []; } @@ -202,7 +202,7 @@ export function extractCobuildActionsFromTx( export function injectCobuild( tx: ccc.Transaction, - actions: mol.EncodableType, + actions: ccc.EncodableType, ): void { tx.setWitnessAt( Math.max(tx.witnesses.length, tx.inputs.length), diff --git a/packages/spore/src/codec/cluster.ts b/packages/spore/src/codec/cluster.ts index e8f7e636..cc9dc7b4 100644 --- a/packages/spore/src/codec/cluster.ts +++ b/packages/spore/src/codec/cluster.ts @@ -5,7 +5,7 @@ export interface ClusterDataV1View { description: string; } -export const ClusterDataV1: mol.Codec = mol.table({ +export const ClusterDataV1: ccc.Codec = mol.table({ name: mol.String, description: mol.String, }); @@ -16,7 +16,7 @@ export interface ClusterDataV2View { mutantId?: ccc.HexLike; } -export const ClusterDataV2: mol.Codec = mol.table({ +export const ClusterDataV2: ccc.Codec = mol.table({ name: mol.String, description: mol.String, mutantId: mol.BytesOpt, diff --git a/packages/spore/src/codec/spore.ts b/packages/spore/src/codec/spore.ts index 4f41555c..4f1ebef3 100644 --- a/packages/spore/src/codec/spore.ts +++ b/packages/spore/src/codec/spore.ts @@ -6,7 +6,7 @@ export interface SporeDataView { clusterId?: ccc.HexLike; } -export const SporeData: mol.Codec = mol.table({ +export const SporeData: ccc.Codec = mol.table({ contentType: mol.String, content: mol.Bytes, clusterId: mol.BytesOpt, diff --git a/packages/spore/src/spore/advanced.ts b/packages/spore/src/spore/advanced.ts index 23aa84aa..e83c0dc8 100644 --- a/packages/spore/src/spore/advanced.ts +++ b/packages/spore/src/spore/advanced.ts @@ -1,4 +1,4 @@ -import { ccc, mol } from "@ckb-ccc/core"; +import { ccc } from "@ckb-ccc/core"; import { assembleTransferClusterAction } from "../advanced.js"; import { assertCluster } from "../cluster/index.js"; import { Action, SporeDataView } from "../codec/index.js"; @@ -9,7 +9,7 @@ export async function prepareCluster( data: SporeDataView, clusterMode?: "lockProxy" | "clusterCell" | "skip", scriptInfoHash?: ccc.HexLike, -): Promise | undefined> { +): Promise | undefined> { // skip if the spore is not belong to a cluster if (!data.clusterId || clusterMode === "skip") { return; From b2dce2e4d69e9f7320187a781d949cc057f25e4d Mon Sep 17 00:00:00 2001 From: Hanssen0 Date: Wed, 7 Jan 2026 00:00:37 +0800 Subject: [PATCH 4/5] feat(type-id): add type-id package for Type ID operations --- .changeset/fifty-parks-dress.md | 7 + packages/shell/package.json | 1 + packages/shell/src/advancedBarrel.ts | 1 + packages/shell/src/barrel.ts | 1 + packages/type-id/.npmignore | 21 + packages/type-id/.prettierignore | 15 + packages/type-id/README.md | 41 ++ packages/type-id/eslint.config.mjs | 62 ++ .../misc/basedirs/dist.commonjs/package.json | 3 + .../type-id/misc/basedirs/dist/package.json | 3 + packages/type-id/package.json | 62 ++ packages/type-id/prettier.config.cjs | 11 + packages/type-id/src/advanced.ts | 2 + packages/type-id/src/advancedBarrel.test.ts | 493 ++++++++++++++++ packages/type-id/src/advancedBarrel.ts | 229 ++++++++ packages/type-id/src/barrel.ts | 12 + packages/type-id/src/index.ts | 2 + packages/type-id/tsconfig.base.json | 22 + packages/type-id/tsconfig.commonjs.json | 8 + packages/type-id/tsconfig.json | 8 + packages/type-id/tsdown.config.mts | 36 ++ packages/type-id/typedoc.json | 6 + packages/type-id/vitest.config.mts | 10 + pnpm-lock.yaml | 553 +++++++++++++++--- typedoc.config.mjs | 1 + vitest.config.mts | 4 +- 26 files changed, 1528 insertions(+), 86 deletions(-) create mode 100644 .changeset/fifty-parks-dress.md create mode 100644 packages/type-id/.npmignore create mode 100644 packages/type-id/.prettierignore create mode 100644 packages/type-id/README.md create mode 100644 packages/type-id/eslint.config.mjs create mode 100644 packages/type-id/misc/basedirs/dist.commonjs/package.json create mode 100644 packages/type-id/misc/basedirs/dist/package.json create mode 100644 packages/type-id/package.json create mode 100644 packages/type-id/prettier.config.cjs create mode 100644 packages/type-id/src/advanced.ts create mode 100644 packages/type-id/src/advancedBarrel.test.ts create mode 100644 packages/type-id/src/advancedBarrel.ts create mode 100644 packages/type-id/src/barrel.ts create mode 100644 packages/type-id/src/index.ts create mode 100644 packages/type-id/tsconfig.base.json create mode 100644 packages/type-id/tsconfig.commonjs.json create mode 100644 packages/type-id/tsconfig.json create mode 100644 packages/type-id/tsdown.config.mts create mode 100644 packages/type-id/typedoc.json create mode 100644 packages/type-id/vitest.config.mts diff --git a/.changeset/fifty-parks-dress.md b/.changeset/fifty-parks-dress.md new file mode 100644 index 00000000..38435915 --- /dev/null +++ b/.changeset/fifty-parks-dress.md @@ -0,0 +1,7 @@ +--- +"@ckb-ccc/shell": minor +"@ckb-ccc/type-id": patch +--- + +feat(type-id): add type-id package for Type ID operations + diff --git a/packages/shell/package.json b/packages/shell/package.json index d5aed9bb..0f7efafc 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -59,6 +59,7 @@ "@ckb-ccc/core": "workspace:*", "@ckb-ccc/spore": "workspace:*", "@ckb-ccc/ssri": "workspace:*", + "@ckb-ccc/type-id": "workspace:*", "@ckb-ccc/udt": "workspace:*" }, "packageManager": "pnpm@10.8.1" diff --git a/packages/shell/src/advancedBarrel.ts b/packages/shell/src/advancedBarrel.ts index ec239348..f2a60e5b 100644 --- a/packages/shell/src/advancedBarrel.ts +++ b/packages/shell/src/advancedBarrel.ts @@ -1,2 +1,3 @@ export * from "@ckb-ccc/core/advancedBarrel"; export { sporeA } from "@ckb-ccc/spore/advanced"; +export { typeIdA } from "@ckb-ccc/type-id/advanced"; diff --git a/packages/shell/src/barrel.ts b/packages/shell/src/barrel.ts index 9cca15d6..3c7752a3 100644 --- a/packages/shell/src/barrel.ts +++ b/packages/shell/src/barrel.ts @@ -1,4 +1,5 @@ export * from "@ckb-ccc/core/barrel"; export { spore } from "@ckb-ccc/spore"; export { ssri } from "@ckb-ccc/ssri"; +export { typeId } from "@ckb-ccc/type-id"; export { udt } from "@ckb-ccc/udt"; diff --git a/packages/type-id/.npmignore b/packages/type-id/.npmignore new file mode 100644 index 00000000..7a88408a --- /dev/null +++ b/packages/type-id/.npmignore @@ -0,0 +1,21 @@ +node_modules/ +misc/ + +*test.js +*test.ts +*test.d.ts +*test.d.ts.map +*spec.js +*spec.ts +*spec.d.ts +*spec.d.ts.map + +tsconfig.json +tsconfig.*.json +eslint.config.mjs +.prettierrc +.prettierignore + +tsconfig.tsbuildinfo +tsconfig.*.tsbuildinfo +.github/ diff --git a/packages/type-id/.prettierignore b/packages/type-id/.prettierignore new file mode 100644 index 00000000..aef5d239 --- /dev/null +++ b/packages/type-id/.prettierignore @@ -0,0 +1,15 @@ +node_modules/ + +dist/ +dist.commonjs/ + +.npmignore +.prettierrc +tsconfig.json +eslint.config.mjs +prettier.config.* + +tsconfig.tsbuildinfo +.github/ + +CHANGELOG.md diff --git a/packages/type-id/README.md b/packages/type-id/README.md new file mode 100644 index 00000000..a569c812 --- /dev/null +++ b/packages/type-id/README.md @@ -0,0 +1,41 @@ +

+ + Logo + +

+ +

+ CCC's Support for Type ID +

+ +

+ NPM Version + GitHub commit activity + GitHub last commit + GitHub branch check runs + Playground + App + Docs +

+ +

+ CCC - CKBers' Codebase is a one-stop solution for your CKB JS/TS ecosystem development. +
+ Empower yourself with CCC to discover the unlimited potential of CKB. +
+ Interoperate with wallets from different chain ecosystems. +
+ Fully enabling CKB's Turing completeness and cryptographic freedom power. +

+ +

+ Read more about CCC on our website or GitHub Repo. +

diff --git a/packages/type-id/eslint.config.mjs b/packages/type-id/eslint.config.mjs new file mode 100644 index 00000000..b6132c27 --- /dev/null +++ b/packages/type-id/eslint.config.mjs @@ -0,0 +1,62 @@ +// @ts-check + +import eslint from "@eslint/js"; +import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; +import tseslint from "typescript-eslint"; + +import { dirname } from "path"; +import { fileURLToPath } from "url"; + +export default [ + ...tseslint.config({ + files: ["**/*.ts"], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ], + rules: { + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + "@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }], + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/only-throw-error": [ + "error", + { + allowThrowingAny: true, + allowThrowingUnknown: true, + allowRethrowing: true, + }, + ], + "@typescript-eslint/prefer-promise-reject-errors": [ + "error", + { + allowThrowingAny: true, + allowThrowingUnknown: true, + }, + ], + "no-empty": "off", + "prefer-const": [ + "error", + { ignoreReadBeforeAssign: true, destructuring: "all" }, + ], + }, + languageOptions: { + parserOptions: { + project: true, + tsconfigRootDir: dirname(fileURLToPath(import.meta.url)), + }, + }, + }), + eslintPluginPrettierRecommended, +]; diff --git a/packages/type-id/misc/basedirs/dist.commonjs/package.json b/packages/type-id/misc/basedirs/dist.commonjs/package.json new file mode 100644 index 00000000..5bbefffb --- /dev/null +++ b/packages/type-id/misc/basedirs/dist.commonjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/packages/type-id/misc/basedirs/dist/package.json b/packages/type-id/misc/basedirs/dist/package.json new file mode 100644 index 00000000..3dbc1ca5 --- /dev/null +++ b/packages/type-id/misc/basedirs/dist/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/type-id/package.json b/packages/type-id/package.json new file mode 100644 index 00000000..dcdf82b3 --- /dev/null +++ b/packages/type-id/package.json @@ -0,0 +1,62 @@ +{ + "name": "@ckb-ccc/type-id", + "version": "0.0.0", + "description": "CCC - CKBer's Codebase. CCC's support for Type ID", + "author": "Hanssen0 ", + "license": "MIT", + "private": false, + "homepage": "https://github.com/ckb-devrel/ccc", + "repository": { + "type": "git", + "url": "git://github.com/ckb-devrel/ccc.git" + }, + "main": "./dist.commonjs/index.js", + "module": "./dist/index.mjs", + "exports": { + ".": { + "require": "./dist.commonjs/index.js", + "import": "./dist/index.mjs" + }, + "./advanced": { + "require": "./dist.commonjs/advanced.js", + "import": "./dist/advanced.mjs" + }, + "./advancedBarrel": { + "require": "./dist.commonjs/advancedBarrel.js", + "import": "./dist/advancedBarrel.mjs" + }, + "./barrel": { + "require": "./dist.commonjs/barrel.js", + "import": "./dist/barrel.mjs" + }, + "./package.json": "./package.json" + }, + "scripts": { + "test": "vitest", + "test:ci": "vitest run", + "build": "tsdown", + "lint": "eslint ./src", + "format": "prettier --write . && eslint --fix ./src" + }, + "devDependencies": { + "@eslint/js": "^9.34.0", + "@types/node": "^24.3.0", + "eslint": "^9.34.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "prettier": "^3.6.2", + "prettier-plugin-organize-imports": "^4.2.0", + "tsdown": "0.19.0-beta.3", + "typescript": "^5.9.2", + "typescript-eslint": "^8.41.0", + "vitest": "^3.2.4" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@ckb-ccc/core": "workspace:*" + }, + "packageManager": "pnpm@10.8.1", + "types": "./dist.commonjs/index.d.ts" +} diff --git a/packages/type-id/prettier.config.cjs b/packages/type-id/prettier.config.cjs new file mode 100644 index 00000000..5e181036 --- /dev/null +++ b/packages/type-id/prettier.config.cjs @@ -0,0 +1,11 @@ +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +const config = { + singleQuote: false, + trailingComma: "all", + plugins: [require.resolve("prettier-plugin-organize-imports")], +}; + +module.exports = config; diff --git a/packages/type-id/src/advanced.ts b/packages/type-id/src/advanced.ts new file mode 100644 index 00000000..fa30ed27 --- /dev/null +++ b/packages/type-id/src/advanced.ts @@ -0,0 +1,2 @@ +export * from "./advancedBarrel.js"; +export * as typeIdA from "./advancedBarrel.js"; diff --git a/packages/type-id/src/advancedBarrel.test.ts b/packages/type-id/src/advancedBarrel.test.ts new file mode 100644 index 00000000..d7fad237 --- /dev/null +++ b/packages/type-id/src/advancedBarrel.test.ts @@ -0,0 +1,493 @@ +import { ccc } from "@ckb-ccc/core"; +import { beforeEach, describe, expect, it, Mock, vi } from "vitest"; +import { buildTypeIdOperations } from "./advancedBarrel.js"; + +describe("type-id", () => { + let client: ccc.Client; + let signer: ccc.Signer; + + const typeIdScript = { + codeHash: + "0x00000000000000000000000000000000000000000000000000545950455f4944", + hashType: "type" as const, + args: "0x", + }; + const typeIdCellDep = { + outPoint: { + txHash: + "0x1111111111111111111111111111111111111111111111111111111111111111", + index: 0, + }, + depType: "code" as const, + }; + + beforeEach(() => { + client = { + getKnownScript: vi.fn(), + getCellDeps: vi.fn(), + findSingletonCellByType: vi.fn(), + } as unknown as ccc.Client; + + signer = { + client, + getRecommendedAddressObj: vi.fn(), + findCells: vi.fn(), + } as unknown as ccc.Signer; + + (client.getKnownScript as Mock).mockResolvedValue({ + ...typeIdScript, + cellDeps: [{ cellDep: typeIdCellDep }], + }); + + (client.getCellDeps as Mock).mockImplementation( + async (deps: ccc.CellDepInfoLike[]) => + deps.map((d) => ccc.CellDep.from(d.cellDep)), + ); + + (signer.getRecommendedAddressObj as Mock).mockResolvedValue({ + script: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x1234", + }), + }); + }); + + describe("buildTypeIdOperations with custom options", () => { + it("should use custom codec", async () => { + const customCodec = { + encode: (data: number) => ccc.numLeToBytes(data, 4), + decode: (bytes: ccc.BytesLike) => Number(ccc.numLeFromBytes(bytes)), + }; + + const { create } = buildTypeIdOperations({ + getScriptInfo: async () => ({ + ...typeIdScript, + cellDeps: [{ cellDep: typeIdCellDep }], + }), + codec: customCodec, + }); + + const inputCell = ccc.Cell.from({ + outPoint: { txHash: "0x" + "2".repeat(64), index: 0 }, + cellOutput: { + capacity: ccc.fixedPointFrom(1000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }, + outputData: "0x", + }); + (signer.findCells as Mock).mockImplementation(async function* () { + yield inputCell; + }); + + const { tx } = await create({ + signer, + data: 123456, + }); + + expect(tx.outputsData[0]).toBe(ccc.hexFrom(ccc.numLeToBytes(123456, 4))); + }); + + it("should use custom calculateTypeId", async () => { + const customId = "0x" + "9".repeat(64); + const calculateTypeId = vi.fn().mockResolvedValue(customId); + + const { create } = buildTypeIdOperations({ + getScriptInfo: async () => ({ + ...typeIdScript, + cellDeps: [{ cellDep: typeIdCellDep }], + }), + calculateTypeId, + }); + + const inputCell = ccc.Cell.from({ + outPoint: { txHash: "0x" + "2".repeat(64), index: 0 }, + cellOutput: { + capacity: ccc.fixedPointFrom(1000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }, + outputData: "0x", + }); + (signer.findCells as Mock).mockImplementation(async function* () { + yield inputCell; + }); + + const { id, tx } = await create({ + signer, + data: "0x", + }); + + expect(calculateTypeId).toHaveBeenCalled(); + expect(id).toBe(customId); + expect(tx.outputs[0].type?.args).toBe(customId); + }); + + it("should use custom addCellDeps", async () => { + const customDep = ccc.CellDep.from({ + outPoint: { txHash: "0x" + "a".repeat(64), index: 0 }, + depType: "code", + }); + const addCellDeps = vi + .fn() + .mockImplementation(async (_: ccc.Client, tx: ccc.Transaction) => { + tx.addCellDeps(customDep); + return tx; + }); + + const { create } = buildTypeIdOperations({ + getScriptInfo: async () => ({ + ...typeIdScript, + cellDeps: [{ cellDep: typeIdCellDep }], + }), + addCellDeps, + }); + + const inputCell = ccc.Cell.from({ + outPoint: { txHash: "0x" + "2".repeat(64), index: 0 }, + cellOutput: { + capacity: ccc.fixedPointFrom(1000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }, + outputData: "0x", + }); + (signer.findCells as Mock).mockImplementation(async function* () { + yield inputCell; + }); + + const { tx } = await create({ + signer, + data: "0x", + }); + + expect(addCellDeps).toHaveBeenCalled(); + expect(tx.cellDeps).toContainEqual(customDep); + }); + }); + + describe("Type ID Operations", () => { + const { create, transfer, destroy } = buildTypeIdOperations({ + getScriptInfo: async () => ({ + ...typeIdScript, + cellDeps: [{ cellDep: typeIdCellDep }], + }), + }); + + describe("create", () => { + it("should create a transaction with correct type id", async () => { + const inputCell = ccc.Cell.from({ + outPoint: { + txHash: "0x" + "2".repeat(64), + index: 0, + }, + cellOutput: { + capacity: ccc.fixedPointFrom(1000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }, + outputData: "0x", + }); + + (signer.findCells as Mock).mockImplementation(async function* () { + yield inputCell; + }); + + const data = "0x1234"; + const { tx, id, index } = await create({ + signer, + data, + }); + + expect(tx.inputs.length).toBe(1); + expect(tx.inputs[0].previousOutput).toEqual(inputCell.outPoint); + + expect(tx.outputs.length).toBe(1); + expect(index).toBe(0); + + const expectedId = ccc.hashTypeId(tx.inputs[0], 0); + expect(id).toBe(expectedId); + + const output = tx.outputs[0]; + expect(output.type).toBeDefined(); + expect(output.type?.codeHash).toBe(typeIdScript.codeHash); + expect(output.type?.hashType).toBe(typeIdScript.hashType); + expect(output.type?.args).toBe(id); + expect(tx.outputsData[0]).toBe(ccc.hexFrom(data)); + + expect(tx.cellDeps.length).toBeGreaterThan(0); + expect(tx.cellDeps[0].outPoint).toEqual( + ccc.OutPoint.from(typeIdCellDep.outPoint), + ); + }); + + it(" should append to existing tx", async () => { + const existingTx = ccc.Transaction.from({ + headerDeps: ["0x" + "e".repeat(64)], + }); + + const inputCell = ccc.Cell.from({ + outPoint: { txHash: "0x" + "2".repeat(64), index: 0 }, + cellOutput: { + capacity: ccc.fixedPointFrom(1000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }, + outputData: "0x", + }); + (signer.findCells as Mock).mockImplementation(async function* () { + yield inputCell; + }); + + const { tx } = await create({ + signer, + data: "0x", + tx: existingTx, + }); + + expect(tx.headerDeps).toContain("0x" + "e".repeat(64)); + }); + }); + + it("should accept explicit receiver", async () => { + const receiver = ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0xffee", + }); + + const inputCell = ccc.Cell.from({ + outPoint: { txHash: "0x" + "2".repeat(64), index: 0 }, + cellOutput: { + capacity: ccc.fixedPointFrom(1000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }, + outputData: "0x", + }); + (signer.findCells as Mock).mockImplementation(async function* () { + yield inputCell; + }); + + const { tx } = await create({ + signer, + data: "0x", + receiver, + }); + + expect(tx.outputs[0].lock).toEqual(receiver); + }); + + describe("transferTypeId", () => { + it("should transfer type id cell to new receiver", async () => { + const id = "0x" + "3".repeat(64); + const receiver = ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0xabcd", + }); + + const typeScript = ccc.Script.from({ + ...typeIdScript, + args: id, + }); + + const existingCell = ccc.Cell.from({ + outPoint: { + txHash: "0x" + "4".repeat(64), + index: 0, + }, + cellOutput: { + capacity: ccc.fixedPointFrom(2000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + type: typeScript, + }, + outputData: "0x5678", + }); + + (client.findSingletonCellByType as Mock).mockResolvedValue( + existingCell, + ); + + const newData = "0x9999"; + const { tx, inIndex, outIndex } = await transfer({ + client, + id, + receiver, + data: newData, + }); + + expect(tx.inputs[inIndex].previousOutput).toEqual( + existingCell.outPoint, + ); + + const output = tx.outputs[outIndex]; + expect(output.lock).toEqual(receiver); + expect(output.type).toEqual(typeScript); + expect(tx.outputsData[outIndex]).toBe(ccc.hexFrom(newData)); + }); + + it("transfer should preserve data if not provided", async () => { + const id = "0x" + "3".repeat(64); + const receiver = ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0xabcd", + }); + const typeScript = ccc.Script.from({ ...typeIdScript, args: id }); + const existingCell = ccc.Cell.from({ + outPoint: { txHash: "0x" + "4".repeat(64), index: 0 }, + cellOutput: { + capacity: ccc.fixedPointFrom(2000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + type: typeScript, + }, + outputData: "0x123456", + }); + + (client.findSingletonCellByType as Mock).mockResolvedValue( + existingCell, + ); + + const { tx, outIndex } = await transfer({ + client, + id, + receiver, + }); + + expect(tx.outputsData[outIndex]).toBe("0x123456"); + }); + + it("should transfer type id cell with data transformer", async () => { + const id = "0x" + "3".repeat(64); + const receiver = ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0xabcd", + }); + + const typeScript = ccc.Script.from({ + ...typeIdScript, + args: id, + }); + + const existingCell = ccc.Cell.from({ + outPoint: { + txHash: "0x" + "4".repeat(64), + index: 0, + }, + cellOutput: { + capacity: ccc.fixedPointFrom(2000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + type: typeScript, + }, + outputData: "0x1234", + }); + + (client.findSingletonCellByType as Mock).mockResolvedValue( + existingCell, + ); + + const { tx, outIndex } = await transfer({ + client, + id, + receiver, + data: (c, d) => ccc.bytesConcat(c.outputData, d ?? "0x", "0x5678"), + }); + + const output = tx.outputs[outIndex]; + expect(output.lock).toEqual(receiver); + expect(output.type).toEqual(typeScript); + expect(tx.outputsData[outIndex]).toBe(ccc.hexFrom("0x123412345678")); + }); + + it("should throw error if type id cell not found", async () => { + (client.findSingletonCellByType as Mock).mockResolvedValue(undefined); + + await expect( + transfer({ + client, + id: "0x" + "0".repeat(64), + receiver: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + }), + ).rejects.toThrow("Type ID"); + }); + }); + + describe("destroyTypeId", () => { + it("should consume type id cell without creating new one", async () => { + const id = "0x" + "5".repeat(64); + const typeScript = ccc.Script.from({ + ...typeIdScript, + args: id, + }); + + const existingCell = ccc.Cell.from({ + outPoint: { + txHash: "0x" + "6".repeat(64), + index: 0, + }, + cellOutput: { + capacity: ccc.fixedPointFrom(3000), + lock: ccc.Script.from({ + codeHash: "0x" + "0".repeat(64), + hashType: "type", + args: "0x", + }), + type: typeScript, + }, + outputData: "0x", + }); + + (client.findSingletonCellByType as Mock).mockResolvedValue( + existingCell, + ); + + const { tx, index } = await destroy({ + client, + id, + }); + + expect(tx.inputs[index].previousOutput).toEqual(existingCell.outPoint); + + const hasTypeOutput = tx.outputs.some((o) => o.type?.eq(typeScript)); + expect(hasTypeOutput).toBe(false); + }); + }); + }); +}); diff --git a/packages/type-id/src/advancedBarrel.ts b/packages/type-id/src/advancedBarrel.ts new file mode 100644 index 00000000..29a171d4 --- /dev/null +++ b/packages/type-id/src/advancedBarrel.ts @@ -0,0 +1,229 @@ +import { ccc } from "@ckb-ccc/core"; + +/** + * Build Type ID operations. + * + * @param props The properties to build the operations. + * @param props.getScriptInfo Function to get the script info. + * @param props.calculateTypeId Function to calculate the Type ID. + * @param props.addCellDeps Function to add cell dependencies. + */ + +export function buildTypeIdOperations< + Encodable = ccc.BytesLike, + Decoded = ccc.Bytes, +>(props: { + getScriptInfo: (client: ccc.Client) => Promise; + codec?: ccc.CodecLike | null; + calculateTypeId?: + | ((client: ccc.Client, tx: ccc.Transaction) => Promise) + | null; + addCellDeps?: + | (( + client: ccc.Client, + tx: ccc.Transaction, + scriptInfo: ccc.ScriptInfo, + ) => Promise) + | null; +}) { + async function getScriptInfo(client: ccc.Client): Promise { + return ccc.ScriptInfo.from(await props.getScriptInfo(client)); + } + + const codec = ( + props.codec ? ccc.Codec.from(props.codec) : ccc.CodecRaw + ) as ccc.Codec; + + function getTypeScript(scriptInfo: ccc.ScriptInfo, args: ccc.HexLike) { + return ccc.Script.from({ + ...scriptInfo, + args, + }); + } + + async function addCellDeps( + client: ccc.Client, + tx: ccc.Transaction, + scriptInfo: ccc.ScriptInfo, + ): Promise { + if (props.addCellDeps) { + return ccc.Transaction.from( + await props.addCellDeps(client, tx, scriptInfo), + ); + } + + tx.addCellDeps(...(await client.getCellDeps(scriptInfo.cellDeps))); + return tx; + } + + async function calculateTypeId( + client: ccc.Client, + tx: ccc.Transaction, + ): Promise { + if (props.calculateTypeId) { + return ccc.hexFrom(await props.calculateTypeId(client, tx)); + } + + return ccc.hashTypeId(tx.inputs[0], tx.outputs.length); + } + + return { + /** + * Create a Type ID cell. + * + * @param props The arguments for creating the cell. + * @param props.signer The signer to sign the transaction. + * @param props.receiver The receiver script (optional). + * @param props.data The output data. + * @param props.tx The transaction skeleton (optional). + */ + async create( + this: void, + props: { + signer: ccc.Signer; + data: Encodable; + receiver?: ccc.ScriptLike | null; + tx?: ccc.TransactionLike | null; + }, + ): Promise<{ + tx: ccc.Transaction; + id: ccc.Hex; + index: number; + }> { + const { signer, receiver, data, tx: txLike } = props; + const tx = ccc.Transaction.from(txLike ?? {}); + + await tx.completeInputsAtLeastOne(signer); + const id = await calculateTypeId(signer.client, tx); + + const scriptInfo = await getScriptInfo(signer.client); + const len = tx.addOutput({ + cellOutput: { + type: getTypeScript(scriptInfo, id), + lock: receiver + ? ccc.Script.from(receiver) + : (await signer.getRecommendedAddressObj()).script, + }, + outputData: codec.encode(data), + }); + + return { + tx: await addCellDeps(signer.client, tx, scriptInfo), + id, + index: len - 1, + }; + }, + + /** + * Transfer a Type ID cell. + * + * @param props The arguments for transferring the cell. + * @param props.client The client to communicate with CKB. + * @param props.id The Type ID to transfer. + * @param props.receiver The new receiver script. + * @param props.tx The transaction skeleton (optional). + * @param props.data The new output data or a transformer to update the data (optional). + */ + async transfer( + this: void, + props: { + client: ccc.Client; + id: ccc.HexLike; + receiver: ccc.ScriptLike; + tx?: ccc.TransactionLike | null; + data?: + | Encodable + | ((cell: ccc.Cell, data?: Decoded) => Encodable | Promise) + | null; + }, + ): Promise<{ + tx: ccc.Transaction; + inIndex: number; + outIndex: number; + }> { + const { client, id, receiver, tx: txLike, data } = props; + const tx = ccc.Transaction.from(txLike ?? {}); + + const scriptInfo = await getScriptInfo(client); + const type = getTypeScript(scriptInfo, id); + const inCell = await client.findSingletonCellByType(type); + if (!inCell) { + throw new Error(`Type ID ${ccc.stringify(type)} not found`); + } + + const outputData = await (async () => { + if (!data) { + return inCell.outputData; + } + + if (typeof data === "function") { + return codec.encode( + await ( + data as ( + cell: ccc.Cell, + data?: Decoded, + ) => Encodable | Promise + )(inCell, codec.decodeOr(inCell.outputData, undefined)), + ); + } + + return codec.encode(data); + })(); + + const outCell = ccc.CellAny.from({ + ...inCell, + cellOutput: { + ...inCell.cellOutput, + lock: ccc.Script.from(receiver), + }, + outputData, + }); + + const inLen = tx.addInput(inCell); + const outLen = tx.addOutput(outCell); + + return { + tx: await addCellDeps(client, tx, scriptInfo), + inIndex: inLen - 1, + outIndex: outLen - 1, + }; + }, + + /** + * Destroy a Type ID cell. + * + * @param props The arguments for destroying the cell. + * @param props.client The client to communicate with CKB. + * @param props.id The Type ID to destroy. + * @param props.tx The transaction skeleton (optional). + */ + async destroy( + this: void, + props: { + client: ccc.Client; + id: ccc.HexLike; + tx?: ccc.TransactionLike | null; + }, + ): Promise<{ + tx: ccc.Transaction; + index: number; + }> { + const { client, id, tx: txLike } = props; + const tx = ccc.Transaction.from(txLike ?? {}); + + const scriptInfo = await getScriptInfo(client); + const type = getTypeScript(scriptInfo, id); + const cell = await client.findSingletonCellByType(type); + if (!cell) { + throw new Error(`Type ID ${ccc.stringify(type)} not found`); + } + + const len = tx.addInput(cell); + + return { + tx: await addCellDeps(client, tx, scriptInfo), + index: len - 1, + }; + }, + }; +} diff --git a/packages/type-id/src/barrel.ts b/packages/type-id/src/barrel.ts new file mode 100644 index 00000000..f948bf58 --- /dev/null +++ b/packages/type-id/src/barrel.ts @@ -0,0 +1,12 @@ +import { ccc } from "@ckb-ccc/core"; +import { buildTypeIdOperations } from "./advancedBarrel"; + +export const { + create: createTypeId, + transfer: transferTypeId, + destroy: destroyTypeId, +} = buildTypeIdOperations({ + async getScriptInfo(client: ccc.Client) { + return client.getKnownScript(ccc.KnownScript.TypeId); + }, +}); diff --git a/packages/type-id/src/index.ts b/packages/type-id/src/index.ts new file mode 100644 index 00000000..6a528c1a --- /dev/null +++ b/packages/type-id/src/index.ts @@ -0,0 +1,2 @@ +export * from "./barrel.js"; +export * as typeId from "./barrel.js"; diff --git a/packages/type-id/tsconfig.base.json b/packages/type-id/tsconfig.base.json new file mode 100644 index 00000000..7e5ac952 --- /dev/null +++ b/packages/type-id/tsconfig.base.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es2020", + "incremental": true, + "allowJs": true, + "importHelpers": false, + "declaration": true, + "declarationMap": true, + "experimentalDecorators": true, + "useDefineForClassFields": false, + "esModuleInterop": true, + "strict": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "strictNullChecks": true, + "alwaysStrict": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/packages/type-id/tsconfig.commonjs.json b/packages/type-id/tsconfig.commonjs.json new file mode 100644 index 00000000..76a25e98 --- /dev/null +++ b/packages/type-id/tsconfig.commonjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist.commonjs" + } +} diff --git a/packages/type-id/tsconfig.json b/packages/type-id/tsconfig.json new file mode 100644 index 00000000..df22faec --- /dev/null +++ b/packages/type-id/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "outDir": "./dist", + } +} diff --git a/packages/type-id/tsdown.config.mts b/packages/type-id/tsdown.config.mts new file mode 100644 index 00000000..9f79d88f --- /dev/null +++ b/packages/type-id/tsdown.config.mts @@ -0,0 +1,36 @@ +import { defineConfig } from "tsdown"; + +const common = { + minify: true, + dts: true, + platform: "neutral" as const, + exports: true, +}; + +export default defineConfig( + ( + [ + { + entry: { + index: "src/index.ts", + barrel: "src/barrel.ts", + advanced: "src/advanced.ts", + advancedBarrel: "src/advancedBarrel.ts", + }, + format: "esm", + copy: "./misc/basedirs/dist/*", + }, + { + entry: { + index: "src/index.ts", + barrel: "src/barrel.ts", + advanced: "src/advanced.ts", + advancedBarrel: "src/advancedBarrel.ts", + }, + format: "cjs", + outDir: "dist.commonjs", + copy: "./misc/basedirs/dist.commonjs/*", + }, + ] as const + ).map((c) => ({ ...c, ...common })), +); diff --git a/packages/type-id/typedoc.json b/packages/type-id/typedoc.json new file mode 100644 index 00000000..2eb611e3 --- /dev/null +++ b/packages/type-id/typedoc.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["./src/index.ts", "./src/advanced.ts"], + "extends": ["../../typedoc.base.json"], + "name": "@ckb-ccc type-id" +} diff --git a/packages/type-id/vitest.config.mts b/packages/type-id/vitest.config.mts new file mode 100644 index 00000000..dc6a5878 --- /dev/null +++ b/packages/type-id/vitest.config.mts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.test.ts"], + coverage: { + include: ["src/**/*.ts"], + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d52d483a..7a7acb14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -378,7 +378,7 @@ importers: version: 9.34.0(jiti@2.5.1) eslint-config-next: specifier: 16.0.10 - version: 16.0.10(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + version: 16.0.10(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) eslint-config-prettier: specifier: ^10.1.8 version: 10.1.8(eslint@9.34.0(jiti@2.5.1)) @@ -965,6 +965,9 @@ importers: '@ckb-ccc/ssri': specifier: workspace:* version: link:../ssri + '@ckb-ccc/type-id': + specifier: workspace:* + version: link:../type-id '@ckb-ccc/udt': specifier: workspace:* version: link:../udt @@ -1122,6 +1125,46 @@ importers: specifier: ^8.41.0 version: 8.41.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + packages/type-id: + dependencies: + '@ckb-ccc/core': + specifier: workspace:* + version: link:../core + devDependencies: + '@eslint/js': + specifier: ^9.34.0 + version: 9.34.0 + '@types/node': + specifier: ^24.3.0 + version: 24.3.0 + eslint: + specifier: ^9.34.0 + version: 9.34.0(jiti@2.5.1) + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.34.0(jiti@2.5.1)) + eslint-plugin-prettier: + specifier: ^5.5.4 + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1))(prettier@3.6.2) + prettier: + specifier: ^3.6.2 + version: 3.6.2 + prettier-plugin-organize-imports: + specifier: ^4.2.0 + version: 4.2.0(prettier@3.6.2)(typescript@5.9.2) + tsdown: + specifier: 0.19.0-beta.3 + version: 0.19.0-beta.3(synckit@0.11.11)(typescript@5.9.2) + typescript: + specifier: ^5.9.2 + version: 5.9.2 + typescript-eslint: + specifier: ^8.41.0 + version: 8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1) + packages/udt: dependencies: '@ckb-ccc/core': @@ -1408,6 +1451,10 @@ packages: resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -1483,6 +1530,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -1504,6 +1555,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} engines: {node: '>=6.9.0'} @@ -2043,6 +2099,10 @@ packages: resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -2629,12 +2689,18 @@ packages: '@emnapi/core@1.4.5': resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/wasi-threads@1.0.4': resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.25.9': resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} engines: {node: '>=18'} @@ -3414,6 +3480,9 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@nervina-labs/dob-render@0.2.5': resolution: {integrity: sha512-PZ5hcoTYfbdyI51xlHdK1j9VYTd6L1oYxEv9CzpYuu0AtkOqSNmrbn2FkI4noUJl+tqxqWSsJRju7JJiOApTpg==} peerDependencies: @@ -3612,6 +3681,9 @@ packages: engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} hasBin: true + '@oxc-project/types@0.106.0': + resolution: {integrity: sha512-QdsH3rZq480VnOHSHgPYOhjL8O8LBdcnSjM408BpPCCUc0JYYZPG9Gafl9i3OcGk/7137o+gweb4cCv3WAUykg==} + '@paralleldrive/cuid2@2.2.2': resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} @@ -3638,6 +3710,9 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@quansync/fs@1.0.0': + resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@react-aria/focus@3.21.1': resolution: {integrity: sha512-hmH1IhHlcQ2lSIxmki1biWzMbGgnhdxJUM0MFfzc71Rv6YAzhlx4kX3GYn4VNcjCeb6cdPv4RZ5vunV4kgMZYQ==} peerDependencies: @@ -3675,6 +3750,86 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + '@rolldown/binding-android-arm64@1.0.0-beta.58': + resolution: {integrity: sha512-mWj5eE4Qc8TbPdGGaaLvBb9XfDPvE1EmZkJQgiGKwchkWH4oAJcRAKMTw7ZHnb1L+t7Ah41sBkAecaIsuUgsug==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.58': + resolution: {integrity: sha512-wFxUymI/5R8bH8qZFYDfAxAN9CyISEIYke+95oZPiv6EWo88aa5rskjVcCpKA532R+klFmdqjbbaD56GNmTF4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.58': + resolution: {integrity: sha512-ybp3MkPj23VDV9PhtRwdU5qrGhlViWRV5BjKwO6epaSlUD5lW0WyY+roN3ZAzbma/9RrMTgZ/a/gtQq8YXOcqw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.58': + resolution: {integrity: sha512-Evxj3yh7FWvyklUYZa0qTVT9N2zX9TPDqGF056hl8hlCZ9/ndQ2xMv6uw9PD1VlLpukbsqL+/C6M0qwipL0QMg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.58': + resolution: {integrity: sha512-tYeXprDOrEgVHUbPXH6MPso4cM/c6RTkmJNICMQlYdki4hGMh92aj3yU6CKs+4X5gfG0yj5kVUw/L4M685SYag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.58': + resolution: {integrity: sha512-N78vmZzP6zG967Ohr+MasCjmKtis0geZ1SOVmxrA0/bklTQSzH5kHEjW5Qn+i1taFno6GEre1E40v0wuWsNOQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.58': + resolution: {integrity: sha512-l+p4QVtG72C7wI2SIkNQw/KQtSjuYwS3rV6AKcWrRBF62ClsFUcif5vLaZIEbPrCXu5OFRXigXFJnxYsVVZqdQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.58': + resolution: {integrity: sha512-urzJX0HrXxIh0FfxwWRjfPCMeInU9qsImLQxHBgLp5ivji1EEUnOfux8KxPPnRQthJyneBrN2LeqUix9DYrNaQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.58': + resolution: {integrity: sha512-7ijfVK3GISnXIwq/1FZo+KyAUJjL3kWPJ7rViAL6MWeEBhEgRzJ0yEd9I8N9aut8Y8ab+EKFJyRNMWZuUBwQ0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.58': + resolution: {integrity: sha512-/m7sKZCS+cUULbzyJTIlv8JbjNohxbpAOA6cM+lgWgqVzPee3U6jpwydrib328JFN/gF9A99IZEnuGYqEDJdww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.58': + resolution: {integrity: sha512-6SZk7zMgv+y3wFFQ9qE5P9NnRHcRsptL1ypmudD26PDY+PvFCvfHRkJNfclWnvacVGxjowr7JOL3a9fd1wWhUw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.58': + resolution: {integrity: sha512-sFqfYPnBZ6xBhMkadB7UD0yjEDRvs7ipR3nCggblN+N4ODCXY6qhg/bKL39+W+dgQybL7ErD4EGERVbW9DAWvg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.58': + resolution: {integrity: sha512-AnFWJdAqB8+IDPcGrATYs67Kik/6tnndNJV2jGRmwlbeNiQQ8GhRJU8ETRlINfII0pqi9k4WWLnb00p1QCxw/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.58': + resolution: {integrity: sha512-qWhDs6yFGR5xDfdrwiSa3CWGIHxD597uGE/A9xGqytBjANvh4rLCTTkq7szhMV4+Ygh+PMS90KVJ8xWG/TkX4w==} + '@rollup/rollup-android-arm-eabi@4.49.0': resolution: {integrity: sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA==} cpu: [arm] @@ -4065,6 +4220,9 @@ packages: '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -4799,6 +4957,10 @@ packages: resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} engines: {node: '>=14'} + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -4871,6 +5033,10 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} @@ -4999,6 +5165,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -5721,6 +5890,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -5840,6 +6012,15 @@ packages: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} + dts-resolver@2.1.3: + resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} + engines: {node: '>=20.19.0'} + peerDependencies: + oxc-resolver: '>=11.0.0' + peerDependenciesMeta: + oxc-resolver: + optional: true + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -5882,6 +6063,10 @@ packages: emoticon@4.1.0: resolution: {integrity: sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -6517,6 +6702,9 @@ packages: get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} @@ -6707,6 +6895,9 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hookable@6.0.1: + resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -6843,6 +7034,10 @@ packages: engines: {node: '>=8'} hasBin: true + import-without-cache@0.2.5: + resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==} + engines: {node: '>=20.19.0'} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -8161,6 +8356,9 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -8967,6 +9165,9 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + quansync@1.0.0: + resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -9267,6 +9468,30 @@ packages: engines: {node: 20 || >=22} hasBin: true + rolldown-plugin-dts@0.20.0: + resolution: {integrity: sha512-cLAY1kN2ilTYMfZcFlGWbXnu6Nb+8uwUBsi+Mjbh4uIx7IN8uMOmJ7RxrrRgPsO4H7eSz3E+JwGoL1gyugiyUA==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@ts-macro/tsc': ^0.3.6 + '@typescript/native-preview': '>=7.0.0-dev.20250601.1' + rolldown: ^1.0.0-beta.57 + typescript: ^5.0.0 + vue-tsc: ~3.2.0 + peerDependenciesMeta: + '@ts-macro/tsc': + optional: true + '@typescript/native-preview': + optional: true + typescript: + optional: true + vue-tsc: + optional: true + + rolldown@1.0.0-beta.58: + resolution: {integrity: sha512-v1FCjMZCan7f+xGAHBi+mqiE4MlH7I+SXEHSQSJoMOGNNB2UYtvMiejsq9YuUOiZjNeUeV/a21nSFbrUR+4ZCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.49.0: resolution: {integrity: sha512-3IVq0cGJ6H7fKXXEdVt+RcYvRCt8beYY9K1760wGQwSAHZcS9eot1zDG5axUbcp/kWRi5zKIIDX8MoKv/TzvZA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -9837,6 +10062,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} @@ -9966,6 +10195,31 @@ packages: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} + tsdown@0.19.0-beta.3: + resolution: {integrity: sha512-Ud75SBmTap0kDf9hs31yBBlU0iAV17gtZgTJlW6nG/e4J6wXPXwQtUXt/Fck4XSmHXXgSuYRwGrjF6AxTLwk+Q==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + '@arethetypeswrong/core': ^0.18.1 + '@vitejs/devtools': '*' + publint: ^0.3.0 + typescript: ^5.0.0 + unplugin-lightningcss: ^0.4.0 + unplugin-unused: ^0.5.0 + peerDependenciesMeta: + '@arethetypeswrong/core': + optional: true + '@vitejs/devtools': + optional: true + publint: + optional: true + typescript: + optional: true + unplugin-lightningcss: + optional: true + unplugin-unused: + optional: true + tslib@2.3.1: resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} @@ -10117,6 +10371,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + unconfig-core@7.4.2: + resolution: {integrity: sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==} + uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} @@ -10189,6 +10446,16 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + unrun@0.2.22: + resolution: {integrity: sha512-vlQce4gTLNyCZxGylEQXGG+fSrrEFWiM/L8aghtp+t6j8xXh+lmsBtQJknG7ZSvv7P+/MRgbQtHWHBWk981uTg==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + synckit: ^0.11.11 + peerDependenciesMeta: + synckit: + optional: true + untildify@4.0.0: resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} engines: {node: '>=8'} @@ -10830,6 +11097,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.30 jsesc: 3.1.0 + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.28.2 @@ -10933,6 +11208,8 @@ snapshots: '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': @@ -10959,6 +11236,10 @@ snapshots: dependencies: '@babel/types': 7.28.2 + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 @@ -11626,6 +11907,11 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@0.2.3': {} '@bcoe/v8-coverage@1.0.2': {} @@ -12962,6 +13248,12 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/core@1.8.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 @@ -12972,6 +13264,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.9': optional: true @@ -13833,6 +14130,13 @@ snapshots: '@tybys/wasm-util': 0.10.0 optional: true + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + '@nervina-labs/dob-render@0.2.5(satori@0.10.14)': dependencies: satori: 0.10.14 @@ -14035,6 +14339,8 @@ snapshots: dependencies: consola: 3.4.2 + '@oxc-project/types@0.106.0': {} + '@paralleldrive/cuid2@2.2.2': dependencies: '@noble/hashes': 1.8.0 @@ -14058,6 +14364,10 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@quansync/fs@1.0.0': + dependencies: + quansync: 1.0.0 + '@react-aria/focus@3.21.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@react-aria/interactions': 3.25.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -14107,6 +14417,49 @@ snapshots: dependencies: react: 19.2.3 + '@rolldown/binding-android-arm64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.58': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.58': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.58': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.58': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.58': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.58': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.58': {} + '@rollup/rollup-android-arm-eabi@4.49.0': optional: true @@ -14476,6 +14829,11 @@ snapshots: tslib: 2.8.1 optional: true + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.28.3 @@ -15343,6 +15701,8 @@ snapshots: ansis@4.1.0: {} + ansis@4.2.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -15439,6 +15799,11 @@ snapshots: assertion-error@2.0.1: {} + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.28.5 + pathe: 2.0.3 + ast-types-flow@0.0.8: {} ast-v8-to-istanbul@0.3.4: @@ -15594,6 +15959,8 @@ snapshots: binary-extensions@2.3.0: {} + birpc@4.0.0: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -16374,6 +16741,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.4: {} + delayed-stream@1.0.0: {} depd@1.1.2: {} @@ -16486,6 +16855,8 @@ snapshots: dotenv@8.6.0: {} + dts-resolver@2.1.3: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -16524,6 +16895,8 @@ snapshots: emoticon@4.1.0: {} + empathic@2.0.0: {} + encodeurl@1.0.2: {} encodeurl@2.0.0: {} @@ -16713,28 +17086,8 @@ snapshots: '@next/eslint-plugin-next': 16.0.10 eslint: 9.34.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-react: 7.37.5(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-react-hooks: 7.0.1(eslint@9.34.0(jiti@2.5.1)) - globals: 16.4.0 - typescript-eslint: 8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - - eslint-config-next@16.0.10(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2): - dependencies: - '@next/eslint-plugin-next': 16.0.10 - eslint: 9.34.0(jiti@2.5.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.34.0(jiti@2.5.1)) eslint-plugin-react: 7.37.5(eslint@9.34.0(jiti@2.5.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.34.0(jiti@2.5.1)) @@ -16769,7 +17122,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -16780,48 +17133,22 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.34.0(jiti@2.5.1)): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1 - eslint: 9.34.0(jiti@2.5.1) - get-tsconfig: 4.10.1 - is-bun-module: 2.0.0 - stable-hash: 0.0.5 - tinyglobby: 0.2.14 - unrs-resolver: 1.11.1 - optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.34.0(jiti@2.5.1)) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.34.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.2) eslint: 9.34.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.34.0(jiti@2.5.1)) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.34.0(jiti@2.5.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.34.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -16832,7 +17159,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.34.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.34.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -16850,35 +17177,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 9.34.0(jiti@2.5.1) - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.49.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.34.0(jiti@2.5.1)): dependencies: aria-query: 5.3.2 @@ -17564,6 +17862,10 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + github-slugger@1.5.0: {} glob-parent@5.1.2: @@ -17857,6 +18159,8 @@ snapshots: dependencies: react-is: 16.13.1 + hookable@6.0.1: {} + hosted-git-info@2.8.9: {} hpack.js@2.1.6: @@ -18002,6 +18306,8 @@ snapshots: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + import-without-cache@0.2.5: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -19697,6 +20003,8 @@ snapshots: obuf@1.1.2: {} + obug@2.1.1: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -20476,6 +20784,8 @@ snapshots: quansync@0.2.11: {} + quansync@1.0.0: {} + queue-microtask@1.2.3: {} quick-lru@5.1.1: {} @@ -20866,6 +21176,41 @@ snapshots: glob: 11.0.3 package-json-from-dist: 1.0.1 + rolldown-plugin-dts@0.20.0(rolldown@1.0.0-beta.58)(typescript@5.9.2): + dependencies: + '@babel/generator': 7.28.5 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + ast-kit: 2.2.0 + birpc: 4.0.0 + dts-resolver: 2.1.3 + get-tsconfig: 4.13.0 + obug: 2.1.1 + rolldown: 1.0.0-beta.58 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - oxc-resolver + + rolldown@1.0.0-beta.58: + dependencies: + '@oxc-project/types': 0.106.0 + '@rolldown/pluginutils': 1.0.0-beta.58 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.58 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.58 + '@rolldown/binding-darwin-x64': 1.0.0-beta.58 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.58 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.58 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.58 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.58 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.58 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.58 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.58 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.58 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.58 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.58 + rollup@4.49.0: dependencies: '@types/estree': 1.0.8 @@ -21606,6 +21951,8 @@ snapshots: tinyexec@0.3.2: {} + tinyexec@1.0.2: {} + tinyglobby@0.2.14: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -21726,6 +22073,33 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tsdown@0.19.0-beta.3(synckit@0.11.11)(typescript@5.9.2): + dependencies: + ansis: 4.2.0 + cac: 6.7.14 + defu: 6.1.4 + empathic: 2.0.0 + hookable: 6.0.1 + import-without-cache: 0.2.5 + obug: 2.1.1 + picomatch: 4.0.3 + rolldown: 1.0.0-beta.58 + rolldown-plugin-dts: 0.20.0(rolldown@1.0.0-beta.58)(typescript@5.9.2) + semver: 7.7.3 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + unconfig-core: 7.4.2 + unrun: 0.2.22(synckit@0.11.11) + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - '@ts-macro/tsc' + - '@typescript/native-preview' + - oxc-resolver + - synckit + - vue-tsc + tslib@2.3.1: {} tslib@2.7.0: {} @@ -21882,6 +22256,11 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + unconfig-core@7.4.2: + dependencies: + '@quansync/fs': 1.0.0 + quansync: 1.0.0 + uncrypto@0.1.3: {} undici-types@6.19.8: {} @@ -21977,6 +22356,12 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + unrun@0.2.22(synckit@0.11.11): + dependencies: + rolldown: 1.0.0-beta.58 + optionalDependencies: + synckit: 0.11.11 + untildify@4.0.0: {} update-browserslist-db@1.1.3(browserslist@4.25.3): diff --git a/typedoc.config.mjs b/typedoc.config.mjs index 515df932..428dfce6 100644 --- a/typedoc.config.mjs +++ b/typedoc.config.mjs @@ -4,6 +4,7 @@ const config = { name: "CCC Docs", entryPoints: [ "packages/core", + "packages/type-id", "packages/ssri", "packages/udt", "packages/spore", diff --git a/vitest.config.mts b/vitest.config.mts index 7af3d4a8..5d03d85e 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -2,9 +2,9 @@ import { defineConfig, coverageConfigDefaults } from "vitest/config"; export default defineConfig({ test: { - projects: ["packages/core"], + projects: ["packages/core", "packages/type-id"], coverage: { - include: ["packages/core"], + include: ["packages/core", "packages/type-id"], exclude: [ "**/dist/**", "**/dist.commonjs/**", From 35d816a94cc075e5ab21299a47cd65bb21fb9ff9 Mon Sep 17 00:00:00 2001 From: Hanssen0 Date: Thu, 8 Jan 2026 19:08:27 +0800 Subject: [PATCH 5/5] feat(did-ckb): add did-ckb package for basic did operations --- .changeset/fruity-drinks-kick.md | 7 + packages/did-ckb/.npmignore | 21 +++ packages/did-ckb/.prettierignore | 15 ++ packages/did-ckb/README.md | 41 +++++ packages/did-ckb/eslint.config.mjs | 62 ++++++++ .../misc/basedirs/dist.commonjs/package.json | 3 + .../did-ckb/misc/basedirs/dist/package.json | 3 + packages/did-ckb/package.json | 56 +++++++ packages/did-ckb/prettier.config.cjs | 11 ++ packages/did-ckb/src/barrel.ts | 2 + packages/did-ckb/src/codec.ts | 146 ++++++++++++++++++ packages/did-ckb/src/didCkb.ts | 89 +++++++++++ packages/did-ckb/src/index.ts | 2 + packages/did-ckb/tsconfig.base.json | 22 +++ packages/did-ckb/tsconfig.commonjs.json | 8 + packages/did-ckb/tsconfig.json | 8 + packages/did-ckb/tsdown.config.mts | 33 ++++ packages/did-ckb/typedoc.json | 6 + packages/did-ckb/vitest.config.mts | 10 ++ packages/examples/package.json | 4 +- packages/examples/src/createDid.ts | 20 +++ packages/examples/src/createDidWithLocalId.ts | 63 ++++++++ packages/examples/src/destroyDid.ts | 31 ++++ packages/examples/src/transferDid.ts | 47 ++++++ packages/shell/package.json | 1 + packages/shell/src/barrel.ts | 1 + pnpm-lock.yaml | 84 +++++++++- typedoc.config.mjs | 1 + vitest.config.mts | 6 +- 29 files changed, 795 insertions(+), 8 deletions(-) create mode 100644 .changeset/fruity-drinks-kick.md create mode 100644 packages/did-ckb/.npmignore create mode 100644 packages/did-ckb/.prettierignore create mode 100644 packages/did-ckb/README.md create mode 100644 packages/did-ckb/eslint.config.mjs create mode 100644 packages/did-ckb/misc/basedirs/dist.commonjs/package.json create mode 100644 packages/did-ckb/misc/basedirs/dist/package.json create mode 100644 packages/did-ckb/package.json create mode 100644 packages/did-ckb/prettier.config.cjs create mode 100644 packages/did-ckb/src/barrel.ts create mode 100644 packages/did-ckb/src/codec.ts create mode 100644 packages/did-ckb/src/didCkb.ts create mode 100644 packages/did-ckb/src/index.ts create mode 100644 packages/did-ckb/tsconfig.base.json create mode 100644 packages/did-ckb/tsconfig.commonjs.json create mode 100644 packages/did-ckb/tsconfig.json create mode 100644 packages/did-ckb/tsdown.config.mts create mode 100644 packages/did-ckb/typedoc.json create mode 100644 packages/did-ckb/vitest.config.mts create mode 100644 packages/examples/src/createDid.ts create mode 100644 packages/examples/src/createDidWithLocalId.ts create mode 100644 packages/examples/src/destroyDid.ts create mode 100644 packages/examples/src/transferDid.ts diff --git a/.changeset/fruity-drinks-kick.md b/.changeset/fruity-drinks-kick.md new file mode 100644 index 00000000..abb409ec --- /dev/null +++ b/.changeset/fruity-drinks-kick.md @@ -0,0 +1,7 @@ +--- +"@ckb-ccc/shell": minor +"@ckb-ccc/did-ckb": patch +--- + +feat(did-ckb): add did-ckb package for basic did operations + \ No newline at end of file diff --git a/packages/did-ckb/.npmignore b/packages/did-ckb/.npmignore new file mode 100644 index 00000000..7a88408a --- /dev/null +++ b/packages/did-ckb/.npmignore @@ -0,0 +1,21 @@ +node_modules/ +misc/ + +*test.js +*test.ts +*test.d.ts +*test.d.ts.map +*spec.js +*spec.ts +*spec.d.ts +*spec.d.ts.map + +tsconfig.json +tsconfig.*.json +eslint.config.mjs +.prettierrc +.prettierignore + +tsconfig.tsbuildinfo +tsconfig.*.tsbuildinfo +.github/ diff --git a/packages/did-ckb/.prettierignore b/packages/did-ckb/.prettierignore new file mode 100644 index 00000000..aef5d239 --- /dev/null +++ b/packages/did-ckb/.prettierignore @@ -0,0 +1,15 @@ +node_modules/ + +dist/ +dist.commonjs/ + +.npmignore +.prettierrc +tsconfig.json +eslint.config.mjs +prettier.config.* + +tsconfig.tsbuildinfo +.github/ + +CHANGELOG.md diff --git a/packages/did-ckb/README.md b/packages/did-ckb/README.md new file mode 100644 index 00000000..1423faaf --- /dev/null +++ b/packages/did-ckb/README.md @@ -0,0 +1,41 @@ +

+ + Logo + +

+ +

+ CCC's Support for DID CKB +

+ +

+ NPM Version + GitHub commit activity + GitHub last commit + GitHub branch check runs + Playground + App + Docs +

+ +

+ CCC - CKBers' Codebase is a one-stop solution for your CKB JS/TS ecosystem development. +
+ Empower yourself with CCC to discover the unlimited potential of CKB. +
+ Interoperate with wallets from different chain ecosystems. +
+ Fully enabling CKB's Turing completeness and cryptographic freedom power. +

+ +

+ Read more about CCC on our website or GitHub Repo. +

diff --git a/packages/did-ckb/eslint.config.mjs b/packages/did-ckb/eslint.config.mjs new file mode 100644 index 00000000..b6132c27 --- /dev/null +++ b/packages/did-ckb/eslint.config.mjs @@ -0,0 +1,62 @@ +// @ts-check + +import eslint from "@eslint/js"; +import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; +import tseslint from "typescript-eslint"; + +import { dirname } from "path"; +import { fileURLToPath } from "url"; + +export default [ + ...tseslint.config({ + files: ["**/*.ts"], + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ], + rules: { + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + "@typescript-eslint/unbound-method": ["error", { ignoreStatic: true }], + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/only-throw-error": [ + "error", + { + allowThrowingAny: true, + allowThrowingUnknown: true, + allowRethrowing: true, + }, + ], + "@typescript-eslint/prefer-promise-reject-errors": [ + "error", + { + allowThrowingAny: true, + allowThrowingUnknown: true, + }, + ], + "no-empty": "off", + "prefer-const": [ + "error", + { ignoreReadBeforeAssign: true, destructuring: "all" }, + ], + }, + languageOptions: { + parserOptions: { + project: true, + tsconfigRootDir: dirname(fileURLToPath(import.meta.url)), + }, + }, + }), + eslintPluginPrettierRecommended, +]; diff --git a/packages/did-ckb/misc/basedirs/dist.commonjs/package.json b/packages/did-ckb/misc/basedirs/dist.commonjs/package.json new file mode 100644 index 00000000..5bbefffb --- /dev/null +++ b/packages/did-ckb/misc/basedirs/dist.commonjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/packages/did-ckb/misc/basedirs/dist/package.json b/packages/did-ckb/misc/basedirs/dist/package.json new file mode 100644 index 00000000..3dbc1ca5 --- /dev/null +++ b/packages/did-ckb/misc/basedirs/dist/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/packages/did-ckb/package.json b/packages/did-ckb/package.json new file mode 100644 index 00000000..e6165120 --- /dev/null +++ b/packages/did-ckb/package.json @@ -0,0 +1,56 @@ +{ + "name": "@ckb-ccc/did-ckb", + "version": "0.0.0", + "description": "CCC - CKBer's Codebase. CCC's support for DID on CKB", + "author": "Hanssen0 ", + "license": "MIT", + "private": false, + "homepage": "https://github.com/ckb-devrel/ccc", + "repository": { + "type": "git", + "url": "git://github.com/ckb-devrel/ccc.git" + }, + "main": "./dist.commonjs/index.js", + "module": "./dist/index.mjs", + "exports": { + ".": { + "require": "./dist.commonjs/index.js", + "import": "./dist/index.mjs" + }, + "./barrel": { + "require": "./dist.commonjs/barrel.js", + "import": "./dist/barrel.mjs" + }, + "./package.json": "./package.json" + }, + "scripts": { + "test": "vitest", + "test:ci": "vitest run", + "build": "tsdown", + "lint": "eslint ./src", + "format": "prettier --write . && eslint --fix ./src" + }, + "devDependencies": { + "@eslint/js": "^9.34.0", + "@types/node": "^24.3.0", + "eslint": "^9.34.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "prettier": "^3.6.2", + "prettier-plugin-organize-imports": "^4.2.0", + "tsdown": "0.19.0-beta.3", + "typescript": "^5.9.2", + "typescript-eslint": "^8.41.0", + "vitest": "^3.2.4" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@ckb-ccc/core": "workspace:*", + "@ckb-ccc/type-id": "workspace:*", + "@ipld/dag-cbor": "^9.2.5" + }, + "packageManager": "pnpm@10.8.1", + "types": "./dist.commonjs/index.d.ts" +} diff --git a/packages/did-ckb/prettier.config.cjs b/packages/did-ckb/prettier.config.cjs new file mode 100644 index 00000000..5e181036 --- /dev/null +++ b/packages/did-ckb/prettier.config.cjs @@ -0,0 +1,11 @@ +/** + * @see https://prettier.io/docs/configuration + * @type {import("prettier").Config} + */ +const config = { + singleQuote: false, + trailingComma: "all", + plugins: [require.resolve("prettier-plugin-organize-imports")], +}; + +module.exports = config; diff --git a/packages/did-ckb/src/barrel.ts b/packages/did-ckb/src/barrel.ts new file mode 100644 index 00000000..6112c76c --- /dev/null +++ b/packages/did-ckb/src/barrel.ts @@ -0,0 +1,2 @@ +export * from "./codec.js"; +export * from "./didCkb.js"; diff --git a/packages/did-ckb/src/codec.ts b/packages/did-ckb/src/codec.ts new file mode 100644 index 00000000..c89ba8e5 --- /dev/null +++ b/packages/did-ckb/src/codec.ts @@ -0,0 +1,146 @@ +import { ccc } from "@ckb-ccc/core"; +import { decode as cborDecode, encode as cborEncode } from "@ipld/dag-cbor"; + +export type DidCkbDataV1Like = { + document: unknown; + localId?: string | null; +}; +@ccc.codec( + ccc.mol + .table({ + document: ccc.mol.Bytes, + localId: ccc.mol.StringOpt, + }) + .map({ + inMap: (data: DidCkbDataV1Like) => ({ + ...data, + document: ccc.hexFrom(cborEncode(data.document)), + }), + outMap: (data) => ({ + ...data, + document: cborDecode(ccc.bytesFrom(data.document)), + }), + }), +) +export class DidCkbDataV1 extends ccc.Entity.Base< + DidCkbDataV1Like, + DidCkbDataV1 +>() { + constructor( + public document: unknown, + public localId?: string, + ) { + super(); + } + + static from(data: DidCkbDataV1Like): DidCkbDataV1 { + if (data instanceof DidCkbDataV1) { + return data; + } + + return new DidCkbDataV1(data.document, data.localId ?? undefined); + } +} + +export type DidCkbDataLike = { + type?: "v1" | null; + value: DidCkbDataV1Like; +}; +@ccc.codec( + ccc.mol.union({ + v1: DidCkbDataV1, + }), +) +export class DidCkbData extends ccc.Entity.Base() { + constructor( + public type: "v1", + public value: DidCkbDataV1, + ) { + super(); + } + + static from(data: DidCkbDataLike): DidCkbData { + if (data instanceof DidCkbData) { + return data; + } + return new DidCkbData(data.type ?? "v1", DidCkbDataV1.from(data.value)); + } + + static fromV1( + data: DidCkbDataV1Like, + ): DidCkbData & { type: "v1"; value: DidCkbDataV1 } { + return new DidCkbData("v1", DidCkbDataV1.from(data)); + } +} + +export type PlcAuthorizationLike = { + history: object[]; + sig: ccc.HexLike; + rotationKeyIndices: ccc.NumLike[]; +}; +@ccc.codec( + ccc.mol + .table({ + history: ccc.mol.BytesVec, + sig: ccc.mol.Bytes, + rotationKeyIndices: ccc.mol.Uint8Vec, + }) + + .map({ + inMap: (data: PlcAuthorizationLike) => ({ + ...data, + history: data.history.map((h) => ccc.hexFrom(cborEncode(h))), + }), + outMap: (data) => ({ + ...data, + history: data.history.map((h) => cborDecode(ccc.bytesFrom(h))), + }), + }), +) +export class PlcAuthorization extends ccc.Entity.Base< + PlcAuthorizationLike, + PlcAuthorization +>() { + constructor( + public history: object[], + public sig: ccc.Hex, + public rotationKeyIndices: ccc.Num[], + ) { + super(); + } + + static from(data: PlcAuthorizationLike): PlcAuthorization { + if (data instanceof PlcAuthorization) { + return data; + } + return new PlcAuthorization( + data.history, + ccc.hexFrom(data.sig), + data.rotationKeyIndices.map(ccc.numFrom), + ); + } +} + +export type DidCkbWitnessLike = { + localIdAuthorization: PlcAuthorizationLike; +}; +@ccc.codec( + ccc.mol.table({ + localIdAuthorization: PlcAuthorization, + }), +) +export class DidCkbWitness extends ccc.Entity.Base< + DidCkbWitnessLike, + DidCkbWitness +>() { + constructor(public localIdAuthorization: PlcAuthorization) { + super(); + } + + static from(data: DidCkbWitnessLike): DidCkbWitness { + if (data instanceof DidCkbWitness) { + return data; + } + return new DidCkbWitness(PlcAuthorization.from(data.localIdAuthorization)); + } +} diff --git a/packages/did-ckb/src/didCkb.ts b/packages/did-ckb/src/didCkb.ts new file mode 100644 index 00000000..0b3ede18 --- /dev/null +++ b/packages/did-ckb/src/didCkb.ts @@ -0,0 +1,89 @@ +import { ccc } from "@ckb-ccc/core"; +import { typeIdA } from "@ckb-ccc/type-id/advanced"; +import { DidCkbData, DidCkbDataLike } from "./codec"; + +const OPERATIONS = typeIdA.buildTypeIdOperations({ + async getScriptInfo(client: ccc.Client): Promise { + return client.getKnownScript(ccc.KnownScript.DidCkb); + }, + codec: DidCkbData, + async calculateTypeId( + _: ccc.Client, + tx: ccc.Transaction, + ): Promise { + return ccc + .bytesFrom(ccc.hashTypeId(tx.inputs[0], tx.outputs.length)) + .slice(0, 20); + }, +}); + +/** + * Create a DID CKB cell. + * + * @param props The arguments for creating the cell. + * @param props.signer The signer to sign the transaction. + * @param props.receiver The receiver script (optional). + * @param props.data The output data. + * @param props.tx The transaction skeleton (optional). + */ +export function createDidCkb(props: { + signer: ccc.Signer; + data: DidCkbDataLike; + receiver?: ccc.ScriptLike | null; + tx?: ccc.TransactionLike | null; +}): Promise<{ + tx: ccc.Transaction; + id: ccc.Hex; + index: number; +}> { + return OPERATIONS.create(props); +} + +/** + * Transfer a DID CKB cell. + * + * @param props The arguments for transferring the cell. + * @param props.client The client to communicate with CKB. + * @param props.id The Type ID to transfer. + * @param props.receiver The new receiver script. + * @param props.tx The transaction skeleton (optional). + * @param props.data The new output data or a transformer to update the data (optional). + */ +export async function transferDidCkb(props: { + client: ccc.Client; + id: ccc.HexLike; + receiver: ccc.ScriptLike; + tx?: ccc.TransactionLike | null; + data?: + | DidCkbDataLike + | (( + cell: ccc.Cell, + data?: DidCkbData, + ) => DidCkbDataLike | Promise) + | null; +}): Promise<{ + tx: ccc.Transaction; + inIndex: number; + outIndex: number; +}> { + return OPERATIONS.transfer(props); +} + +/** + * Destroy a DID CKB cell. + * + * @param props The arguments for destroying the cell. + * @param props.client The client to communicate with CKB. + * @param props.id The Type ID to destroy. + * @param props.tx The transaction skeleton (optional). + */ +export async function destroyDidCkb(props: { + client: ccc.Client; + id: ccc.HexLike; + tx?: ccc.TransactionLike | null; +}): Promise<{ + tx: ccc.Transaction; + index: number; +}> { + return OPERATIONS.destroy(props); +} diff --git a/packages/did-ckb/src/index.ts b/packages/did-ckb/src/index.ts new file mode 100644 index 00000000..58026564 --- /dev/null +++ b/packages/did-ckb/src/index.ts @@ -0,0 +1,2 @@ +export * from "./barrel.js"; +export * as didCkb from "./barrel.js"; diff --git a/packages/did-ckb/tsconfig.base.json b/packages/did-ckb/tsconfig.base.json new file mode 100644 index 00000000..7e5ac952 --- /dev/null +++ b/packages/did-ckb/tsconfig.base.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es2020", + "incremental": true, + "allowJs": true, + "importHelpers": false, + "declaration": true, + "declarationMap": true, + "experimentalDecorators": true, + "useDefineForClassFields": false, + "esModuleInterop": true, + "strict": true, + "noImplicitAny": true, + "strictBindCallApply": true, + "strictNullChecks": true, + "alwaysStrict": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/packages/did-ckb/tsconfig.commonjs.json b/packages/did-ckb/tsconfig.commonjs.json new file mode 100644 index 00000000..76a25e98 --- /dev/null +++ b/packages/did-ckb/tsconfig.commonjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist.commonjs" + } +} diff --git a/packages/did-ckb/tsconfig.json b/packages/did-ckb/tsconfig.json new file mode 100644 index 00000000..df22faec --- /dev/null +++ b/packages/did-ckb/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "outDir": "./dist", + } +} diff --git a/packages/did-ckb/tsdown.config.mts b/packages/did-ckb/tsdown.config.mts new file mode 100644 index 00000000..d952699a --- /dev/null +++ b/packages/did-ckb/tsdown.config.mts @@ -0,0 +1,33 @@ +import { defineConfig } from "tsdown"; + +const common = { + minify: true, + dts: true, + platform: "neutral" as const, + exports: true, +}; + +export default defineConfig( + ( + [ + { + entry: { + index: "src/index.ts", + barrel: "src/barrel.ts", + }, + format: "esm", + copy: "./misc/basedirs/dist/*", + }, + { + entry: { + index: "src/index.ts", + barrel: "src/barrel.ts", + }, + noExternal: ["@ipld/dag-cbor"] as string[], + format: "cjs", + outDir: "dist.commonjs", + copy: "./misc/basedirs/dist.commonjs/*", + }, + ] as const + ).map((c) => ({ ...c, ...common })), +); diff --git a/packages/did-ckb/typedoc.json b/packages/did-ckb/typedoc.json new file mode 100644 index 00000000..5cdb8bef --- /dev/null +++ b/packages/did-ckb/typedoc.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["./src/index.ts"], + "extends": ["../../typedoc.base.json"], + "name": "@ckb-ccc did-ckb" +} diff --git a/packages/did-ckb/vitest.config.mts b/packages/did-ckb/vitest.config.mts new file mode 100644 index 00000000..dc6a5878 --- /dev/null +++ b/packages/did-ckb/vitest.config.mts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/**/*.test.ts"], + coverage: { + include: ["src/**/*.ts"], + }, + }, +}); diff --git a/packages/examples/package.json b/packages/examples/package.json index 756bf2d1..bac19e45 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -31,7 +31,9 @@ }, "dependencies": { "@ckb-ccc/ccc": "workspace:*", - "@ckb-ccc/playground": "file:src/playground" + "@ckb-ccc/playground": "file:src/playground", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0" }, "packageManager": "pnpm@10.8.1" } diff --git a/packages/examples/src/createDid.ts b/packages/examples/src/createDid.ts new file mode 100644 index 00000000..2d01a686 --- /dev/null +++ b/packages/examples/src/createDid.ts @@ -0,0 +1,20 @@ +import { ccc } from "@ckb-ccc/ccc"; +import { render, signer } from "@ckb-ccc/playground"; + +// Construct create did tx +const { tx } = await ccc.didCkb.createDidCkb({ + signer, + data: { value: { document: {} } }, +}); + +// Complete missing parts: Fill inputs +await tx.completeInputsByCapacity(signer); +await render(tx); + +// Complete missing parts: Pay fee +await tx.completeFeeBy(signer); +await render(tx); + +// Sign and send the transaction +const txHash = await signer.sendTransaction(tx); +console.log(`Transaction ${txHash} sent`); diff --git a/packages/examples/src/createDidWithLocalId.ts b/packages/examples/src/createDidWithLocalId.ts new file mode 100644 index 00000000..957e4b08 --- /dev/null +++ b/packages/examples/src/createDidWithLocalId.ts @@ -0,0 +1,63 @@ +import { ccc } from "@ckb-ccc/ccc"; +import { render, signer } from "@ckb-ccc/playground"; +import { secp256k1 } from "@noble/curves/secp256k1"; +import { sha256 } from "@noble/hashes/sha2"; + +// From https://github.com/bluesky-social/atproto/blob/main/packages/crypto +function plcSign(key: ccc.BytesLike, msg: ccc.BytesLike): ccc.Bytes { + const msgHash = sha256(ccc.bytesFrom(msg)); + const sig = secp256k1.sign(msgHash, ccc.bytesFrom(key), { lowS: true }); + return sig.toBytes("compact"); +} + +// Construct create did tx +const { tx } = await ccc.didCkb.createDidCkb({ + signer, + data: { + value: { document: {}, localId: "did:plc:yunkr6vorfgzmvzeoofbkhq5" }, + }, +}); + +// Complete missing parts: Fill inputs +await tx.completeInputsByCapacity(signer); +await render(tx); + +// Complete missing parts: Pay fee +await tx.completeFeeBy(signer); +await render(tx); + +// Authorize the transaction with the rotation key +const rotationKey = + "0x806d1925698097c64bc70f629e25b91b48a15eee4e492bb239402cee85356a10"; +const witness = ccc.didCkb.DidCkbWitness.from({ + localIdAuthorization: { + history: [ + { + type: "plc_operation", + verificationMethods: { + atproto: "did:key:zQ3shn3qejTEyEiokszFc4MWEqbdAwyj2XR1oS2AuXKvEBTuN", + }, + rotationKeys: [ + "did:key:zQ3shqtXEdagupBhLzL2vFUACfdVjDEvciip79uY8iHBuu7FD", + "did:key:zDnaefn5fMKvoZ1n4vyxJ9npjWE5P3D8GkM9zNqaGbLqdDrtX", + ], + alsoKnownAs: ["at://alice.example.com"], + services: { + atproto_pds: { + type: "AtprotoPersonalDataServer", + endpoint: "https://example.com", + }, + }, + prev: null, + sig: "2ySrMKwAQ8j_7HlJlNdE9kXFXG6VAGzy0s4P5O12UuMQqUgDHlAe3PQza5zWxIi6TC9K3K8ghmypfhDyJm8LuQ", + }, + ], + rotationKeyIndices: [0n, 0n], + sig: plcSign(rotationKey, tx.hash()), + }, +}); +tx.setWitnessArgsAt(0, ccc.WitnessArgs.from({ outputType: witness.toBytes() })); + +// Sign and send the transaction +const txHash = await signer.sendTransaction(tx); +console.log(`Transaction ${txHash} sent`); diff --git a/packages/examples/src/destroyDid.ts b/packages/examples/src/destroyDid.ts new file mode 100644 index 00000000..55f38b18 --- /dev/null +++ b/packages/examples/src/destroyDid.ts @@ -0,0 +1,31 @@ +import { ccc } from "@ckb-ccc/ccc"; +import { render, signer } from "@ckb-ccc/playground"; + +// === Create a did first === +// Check https://live.ckbccc.com/?src=https://raw.githubusercontent.com/ckb-devrel/ccc/refs/heads/master/packages/examples/src/createDid.ts for the full example +const { tx: createTx, id } = await ccc.didCkb.createDidCkb({ + signer, + data: { + value: { document: {} }, + }, +}); +await createTx.completeFeeBy(signer); +await render(createTx); +const createTxHash = await signer.sendTransaction(createTx); +console.log(`Transaction ${createTxHash} sent`); +// === Create a did first === + +// Construct destroy did tx +const { tx } = await ccc.didCkb.destroyDidCkb({ client: signer.client, id }); + +// Complete missing parts: Fill inputs +await tx.completeInputsByCapacity(signer); +await render(tx); + +// Complete missing parts: Pay fee +await tx.completeFeeBy(signer); +await render(tx); + +// Sign and send the transaction +const txHash = await signer.sendTransaction(tx); +console.log(`Transaction ${txHash} sent`); diff --git a/packages/examples/src/transferDid.ts b/packages/examples/src/transferDid.ts new file mode 100644 index 00000000..90af8e3c --- /dev/null +++ b/packages/examples/src/transferDid.ts @@ -0,0 +1,47 @@ +import { ccc } from "@ckb-ccc/ccc"; +import { render, signer } from "@ckb-ccc/playground"; + +// === Create a did first === +// Check https://live.ckbccc.com/?src=https://raw.githubusercontent.com/ckb-devrel/ccc/refs/heads/master/packages/examples/src/createDid.ts for the full example +const { tx: createTx, id } = await ccc.didCkb.createDidCkb({ + signer, + data: { + value: { document: {} }, + }, +}); +await createTx.completeFeeBy(signer); +await render(createTx); +const createTxHash = await signer.sendTransaction(createTx); +console.log(`Transaction ${createTxHash} sent`); +// === Create a did first === + +// The receiver is the signer itself on mainnet +const receiver = (await signer.getRecommendedAddressObj()).script; +console.log(receiver); + +// Construct transfer did tx +const { tx } = await ccc.didCkb.transferDidCkb({ + client: signer.client, + id, + receiver, + data: (_, data) => { + if (!data) { + throw Error("Unknown error"); + } + + (data.value.document as Record)["foo"] = "bar"; + return data; + }, +}); + +// Complete missing parts: Fill inputs +await tx.completeInputsByCapacity(signer); +await render(tx); + +// Complete missing parts: Pay fee +await tx.completeFeeBy(signer); +await render(tx); + +// Sign and send the transaction +const txHash = await signer.sendTransaction(tx); +console.log(`Transaction ${txHash} sent`); diff --git a/packages/shell/package.json b/packages/shell/package.json index 0f7efafc..f20cbdf2 100644 --- a/packages/shell/package.json +++ b/packages/shell/package.json @@ -57,6 +57,7 @@ }, "dependencies": { "@ckb-ccc/core": "workspace:*", + "@ckb-ccc/did-ckb": "workspace:*", "@ckb-ccc/spore": "workspace:*", "@ckb-ccc/ssri": "workspace:*", "@ckb-ccc/type-id": "workspace:*", diff --git a/packages/shell/src/barrel.ts b/packages/shell/src/barrel.ts index 3c7752a3..e9d7adb7 100644 --- a/packages/shell/src/barrel.ts +++ b/packages/shell/src/barrel.ts @@ -1,4 +1,5 @@ export * from "@ckb-ccc/core/barrel"; +export { didCkb } from "@ckb-ccc/did-ckb"; export { spore } from "@ckb-ccc/spore"; export { ssri } from "@ckb-ccc/ssri"; export { typeId } from "@ckb-ccc/type-id"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7a7acb14..33d5adee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -404,6 +404,52 @@ importers: specifier: ^5.9.2 version: 5.9.2 + packages/did-ckb: + dependencies: + '@ckb-ccc/core': + specifier: workspace:* + version: link:../core + '@ckb-ccc/type-id': + specifier: workspace:* + version: link:../type-id + '@ipld/dag-cbor': + specifier: ^9.2.5 + version: 9.2.5 + devDependencies: + '@eslint/js': + specifier: ^9.34.0 + version: 9.34.0 + '@types/node': + specifier: ^24.3.0 + version: 24.3.0 + eslint: + specifier: ^9.34.0 + version: 9.34.0(jiti@2.5.1) + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.34.0(jiti@2.5.1)) + eslint-plugin-prettier: + specifier: ^5.5.4 + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1))(prettier@3.6.2) + prettier: + specifier: ^3.6.2 + version: 3.6.2 + prettier-plugin-organize-imports: + specifier: ^4.2.0 + version: 4.2.0(prettier@3.6.2)(typescript@5.9.2) + tsdown: + specifier: 0.19.0-beta.3 + version: 0.19.0-beta.3(synckit@0.11.11)(typescript@5.9.2) + typescript: + specifier: ^5.9.2 + version: 5.9.2 + typescript-eslint: + specifier: ^8.41.0 + version: 8.41.0(eslint@9.34.0(jiti@2.5.1))(typescript@5.9.2) + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(tsx@4.20.5)(yaml@2.8.1) + packages/docs: dependencies: '@docusaurus/core': @@ -486,6 +532,12 @@ importers: '@ckb-ccc/playground': specifier: file:src/playground version: playground@file:packages/examples/src/playground + '@noble/curves': + specifier: ^1.9.7 + version: 1.9.7 + '@noble/hashes': + specifier: ^1.8.0 + version: 1.8.0 devDependencies: '@eslint/js': specifier: ^9.34.0 @@ -959,6 +1011,9 @@ importers: '@ckb-ccc/core': specifier: workspace:* version: link:../core + '@ckb-ccc/did-ckb': + specifier: workspace:* + version: link:../did-ckb '@ckb-ccc/spore': specifier: workspace:* version: link:../spore @@ -3253,6 +3308,10 @@ packages: '@types/node': optional: true + '@ipld/dag-cbor@9.2.5': + resolution: {integrity: sha512-84wSr4jv30biui7endhobYhXBQzQE4c/wdoWlFrKcfiwH+ofaPg8fwsM8okX9cOzkkrsAsNdDyH3ou+kiLquwQ==} + engines: {node: '>=16.0.0', npm: '>=7.0.0'} + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -5317,6 +5376,10 @@ packages: caniuse-lite@1.0.30001737: resolution: {integrity: sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==} + cborg@4.3.2: + resolution: {integrity: sha512-l+QzebEAG0vb09YKkaOrMi2zmm80UNjmbvocMIeW5hO7JOXWdrQ/H49yOKfYX0MBgrj/KWgatBnEgRXyNyKD+A==} + hasBin: true + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -8199,6 +8262,9 @@ packages: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true + multiformats@13.4.2: + resolution: {integrity: sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==} + mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -13739,6 +13805,11 @@ snapshots: optionalDependencies: '@types/node': 24.3.0 + '@ipld/dag-cbor@9.2.5': + dependencies: + cborg: 4.3.2 + multiformats: 13.4.2 + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.0': @@ -16163,6 +16234,8 @@ snapshots: caniuse-lite@1.0.30001737: {} + cborg@4.3.2: {} + ccount@2.0.1: {} chai@5.3.3: @@ -16757,8 +16830,7 @@ snapshots: detect-libc@2.0.4: {} - detect-libc@2.1.2: - optional: true + detect-libc@2.1.2: {} detect-newline@3.1.0: {} @@ -17130,7 +17202,7 @@ snapshots: get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)))(eslint@9.34.0(jiti@2.5.1)) @@ -19086,7 +19158,7 @@ snapshots: lightningcss@1.30.1: dependencies: - detect-libc: 2.0.4 + detect-libc: 2.1.2 optionalDependencies: lightningcss-darwin-arm64: 1.30.1 lightningcss-darwin-x64: 1.30.1 @@ -19856,6 +19928,8 @@ snapshots: dns-packet: 5.6.1 thunky: 1.1.0 + multiformats@13.4.2: {} + mute-stream@2.0.0: {} nanoassert@2.0.0: {} @@ -22109,7 +22183,7 @@ snapshots: tsx@4.20.5: dependencies: esbuild: 0.25.9 - get-tsconfig: 4.10.1 + get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 diff --git a/typedoc.config.mjs b/typedoc.config.mjs index 428dfce6..35f05db4 100644 --- a/typedoc.config.mjs +++ b/typedoc.config.mjs @@ -8,6 +8,7 @@ const config = { "packages/ssri", "packages/udt", "packages/spore", + "packages/did-ckb", "packages/shell", "packages/ccc", "packages/connector", diff --git a/vitest.config.mts b/vitest.config.mts index 5d03d85e..9b64c135 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -1,10 +1,12 @@ import { defineConfig, coverageConfigDefaults } from "vitest/config"; +const packages = ["packages/core", "packages/did-ckb", "packages/type-id"]; + export default defineConfig({ test: { - projects: ["packages/core", "packages/type-id"], + projects: packages, coverage: { - include: ["packages/core", "packages/type-id"], + include: packages, exclude: [ "**/dist/**", "**/dist.commonjs/**",