@ckb-ccc/core 1.19.0 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/advanced.d.mts +2 -2
  3. package/dist/advanced.mjs +1 -1
  4. package/{dist.commonjs/advancedBarrel-B565UuhW.d.ts → dist/advancedBarrel-CZxkR1dk.d.mts} +2501 -2121
  5. package/dist/advancedBarrel-CZxkR1dk.d.mts.map +1 -0
  6. package/dist/advancedBarrel.d.mts +2 -2
  7. package/dist/advancedBarrel.mjs +1 -1
  8. package/dist/advancedBarrel.mjs.map +1 -1
  9. package/dist/barrel-CqiwnGqc.mjs +7 -0
  10. package/dist/barrel-CqiwnGqc.mjs.map +1 -0
  11. package/dist/barrel.d.mts +2 -2
  12. package/dist/barrel.mjs +1 -1
  13. package/dist/index.d.mts +2 -2
  14. package/dist/index.mjs +1 -1
  15. package/dist/transformers-BJyj6caX.mjs +2 -0
  16. package/dist/transformers-BJyj6caX.mjs.map +1 -0
  17. package/dist.commonjs/advanced.d.ts +2 -2
  18. package/dist.commonjs/advanced.js +1 -1
  19. package/{dist/advancedBarrel-mPY1Rl-S.d.mts → dist.commonjs/advancedBarrel-Czsr2VlG.d.ts} +2502 -2120
  20. package/dist.commonjs/advancedBarrel-Czsr2VlG.d.ts.map +1 -0
  21. package/dist.commonjs/advancedBarrel.d.ts +2 -2
  22. package/dist.commonjs/advancedBarrel.js +1 -1
  23. package/dist.commonjs/advancedBarrel.js.map +1 -1
  24. package/dist.commonjs/barrel-BCS94_-c.js +23 -0
  25. package/dist.commonjs/barrel-BCS94_-c.js.map +1 -0
  26. package/dist.commonjs/barrel.d.ts +2 -2
  27. package/dist.commonjs/barrel.js +1 -1
  28. package/dist.commonjs/index.d.ts +2 -2
  29. package/dist.commonjs/index.js +1 -1
  30. package/dist.commonjs/{rolldown-runtime-DWNI8pZO.js → rolldown-runtime-Chgba0Kb.js} +1 -1
  31. package/dist.commonjs/transformers-Cue1Z8Up.js +2 -0
  32. package/dist.commonjs/transformers-Cue1Z8Up.js.map +1 -0
  33. package/package.json +8 -7
  34. package/src/advancedBarrel.ts +1 -0
  35. package/src/bytes/advanced.ts +1 -6
  36. package/src/bytes/index.ts +37 -10
  37. package/src/ckb/transaction.ts +5 -5
  38. package/src/client/client.ts +75 -19
  39. package/src/client/clientPublicMainnet.ts +75 -36
  40. package/src/client/clientPublicTestnet.ts +75 -36
  41. package/src/client/jsonRpc/client.ts +77 -30
  42. package/src/client/jsonRpc/transformers.ts +4 -4
  43. package/src/jsonRpc/index.ts +1 -0
  44. package/src/jsonRpc/requestor.ts +74 -21
  45. package/src/jsonRpc/transports/advanced.ts +0 -4
  46. package/src/jsonRpc/transports/factory.ts +12 -5
  47. package/src/jsonRpc/transports/fallback.ts +9 -5
  48. package/src/jsonRpc/transports/http.ts +21 -17
  49. package/src/jsonRpc/transports/index.ts +4 -0
  50. package/src/jsonRpc/transports/transport.ts +32 -6
  51. package/src/jsonRpc/transports/webSocket.ts +67 -20
  52. package/src/keystore/index.ts +3 -3
  53. package/src/molecule/codec.ts +20 -17
  54. package/src/signer/advanced.ts +1 -0
  55. package/src/signer/btc/verify.ts +2 -2
  56. package/src/signer/ckb/secp256k1Signing.ts +3 -3
  57. package/src/signer/doge/signerDoge.ts +1 -1
  58. package/src/signer/doge/signerDogePrivateKey.ts +1 -1
  59. package/src/signer/index.ts +1 -0
  60. package/src/signer/jsonRpc/handler.ts +217 -0
  61. package/src/signer/jsonRpc/index.ts +2 -0
  62. package/src/signer/jsonRpc/network.ts +15 -0
  63. package/src/signer/jsonRpc/signer.ts +181 -0
  64. package/src/signer/jsonRpc/transformers.ts +67 -0
  65. package/src/signer/signer/index.ts +5 -13
  66. package/src/utils/abortSignal.ts +42 -0
  67. package/src/utils/index.ts +2 -0
  68. package/src/utils/owner/aggregated.ts +56 -0
  69. package/src/utils/owner/index.ts +4 -0
  70. package/src/utils/owner/owner.ts +141 -0
  71. package/src/utils/owner/refCount.ts +78 -0
  72. package/src/utils/owner/unique.ts +30 -0
  73. package/tsdown.config.mts +1 -0
  74. package/dist/address.advanced-Cka_9tcR.mjs +0 -2
  75. package/dist/address.advanced-Cka_9tcR.mjs.map +0 -1
  76. package/dist/advancedBarrel-mPY1Rl-S.d.mts.map +0 -1
  77. package/dist/barrel-DsK2p-Rh.mjs +0 -7
  78. package/dist/barrel-DsK2p-Rh.mjs.map +0 -1
  79. package/dist.commonjs/address.advanced-BTrmYDic.js +0 -2
  80. package/dist.commonjs/address.advanced-BTrmYDic.js.map +0 -1
  81. package/dist.commonjs/advancedBarrel-B565UuhW.d.ts.map +0 -1
  82. package/dist.commonjs/barrel-D8_wJLfr.js +0 -23
  83. package/dist.commonjs/barrel-D8_wJLfr.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckb-ccc/core",
3
- "version": "1.19.0",
3
+ "version": "1.20.0",
4
4
  "description": "Core of CCC - CKBer's Codebase",
5
5
  "author": "Hanssen0 <hanssen0@hanssen0.com>",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "eslint-plugin-prettier": "^5.5.6",
41
41
  "prettier": "^3.8.4",
42
42
  "prettier-plugin-organize-imports": "^4.3.0",
43
- "tsdown": "0.22.14",
43
+ "tsdown": "0.23.0",
44
44
  "@typescript/native": "npm:typescript@^7.0.2",
45
45
  "typescript": "npm:@typescript/typescript6@^6.0.2",
46
46
  "typescript-eslint": "^8.61.1",
@@ -56,22 +56,23 @@
56
56
  "@noble/hashes": "^2.2.0",
57
57
  "bech32": "^2.0.0",
58
58
  "bs58check": "^4.0.0",
59
- "buffer": "^6.0.3",
60
59
  "ethers": "^6.17.0",
61
60
  "isomorphic-ws": "^5.0.0",
61
+ "uint8array-extras": "^1.5.0",
62
62
  "ws": "^8.21.0"
63
63
  },
64
64
  "types": "./dist.commonjs/index.d.ts",
65
65
  "inlinedDependencies": {
66
- "@noble/ciphers": "2.3.0",
67
- "@noble/curves": "2.3.0",
66
+ "@noble/ciphers": "2.4.0",
67
+ "@noble/curves": "2.4.0",
68
68
  "@noble/hashes": [
69
69
  "1.8.0",
70
- "2.3.0"
70
+ "2.4.0"
71
71
  ],
72
72
  "base-x": "5.0.1",
73
73
  "bs58": "6.0.0",
74
- "bs58check": "4.0.0"
74
+ "bs58check": "4.0.0",
75
+ "uint8array-extras": "1.5.0"
75
76
  },
76
77
  "scripts": {
77
78
  "test": "vitest",
@@ -4,3 +4,4 @@ export * from "./ckb/advanced.js";
4
4
  export * from "./client/advanced.js";
5
5
  export * from "./hasher/advanced.js";
6
6
  export * from "./jsonRpc/advanced.js";
7
+ export * from "./signer/advanced.js";
@@ -4,11 +4,6 @@
4
4
  */
5
5
  export type BytesFromEncoding =
6
6
  | "utf8" // UTF-8 encoding
7
- | "utf16le" // UTF-16 Little Endian encoding
8
- | "latin1" // Latin-1 (ISO-8859-1) encoding
9
7
  | "base64" // Base64 encoding
10
8
  | "base64url" // Base64 URL encoding
11
- | "hex" // Hexadecimal encoding
12
- | "ascii" // ASCII encoding
13
- | "binary" // Binary encoding
14
- | "ucs2"; // UCS-2 (alias of UTF-16LE) encoding
9
+ | "hex"; // Hexadecimal encoding
@@ -1,5 +1,12 @@
1
- import { Buffer } from "buffer/index.js";
2
- import { BytesFromEncoding } from "./advanced.js";
1
+ import {
2
+ base64ToUint8Array,
3
+ hexToUint8Array,
4
+ stringToUint8Array,
5
+ uint8ArrayToBase64,
6
+ uint8ArrayToHex,
7
+ uint8ArrayToString,
8
+ } from "uint8array-extras";
9
+ import type { BytesFromEncoding } from "./advanced.js";
3
10
 
4
11
  /**
5
12
  * @public
@@ -91,7 +98,18 @@ export function bytesConcat(...args: BytesLike[]): Bytes {
91
98
  */
92
99
 
93
100
  export function bytesTo(val: BytesLike, encoding: BytesFromEncoding): string {
94
- return Buffer.from(bytesFrom(val)).toString(encoding);
101
+ const bytes = bytesFrom(val);
102
+
103
+ switch (encoding) {
104
+ case "utf8":
105
+ return uint8ArrayToString(bytes);
106
+ case "base64":
107
+ return uint8ArrayToBase64(bytes);
108
+ case "base64url":
109
+ return uint8ArrayToBase64(bytes, { urlSafe: true });
110
+ case "hex":
111
+ return uint8ArrayToHex(bytes);
112
+ }
95
113
  }
96
114
 
97
115
  /**
@@ -133,17 +151,13 @@ export function bytesFrom(
133
151
  }
134
152
 
135
153
  if (typeof bytes === "string") {
136
- if (encoding !== undefined) {
137
- return Buffer.from(bytes, encoding);
154
+ if (encoding !== undefined && encoding !== "hex") {
155
+ return bytesFromString(bytes, encoding);
138
156
  }
139
157
 
140
158
  const str = bytes.startsWith("0x") ? bytes.slice(2) : bytes;
141
159
  const paddedStr = str.length % 2 === 0 ? str : `0${str}`;
142
- const data = Buffer.from(paddedStr, "hex");
143
- if (data.length * 2 !== paddedStr.length) {
144
- throw new Error(`Invalid bytes ${bytes}`);
145
- }
146
- return data;
160
+ return hexToUint8Array(paddedStr);
147
161
  }
148
162
 
149
163
  const bytesArr = Array.from(bytes);
@@ -153,6 +167,19 @@ export function bytesFrom(
153
167
  return new Uint8Array(bytes);
154
168
  }
155
169
 
170
+ function bytesFromString(
171
+ value: string,
172
+ encoding: Exclude<BytesFromEncoding, "hex">,
173
+ ): Bytes {
174
+ switch (encoding) {
175
+ case "utf8":
176
+ return stringToUint8Array(value);
177
+ case "base64":
178
+ case "base64url":
179
+ return base64ToUint8Array(value);
180
+ }
181
+ }
182
+
156
183
  /**
157
184
  * Compares two byte-like values for equality.
158
185
  * @public
@@ -1,11 +1,11 @@
1
1
  import { Bytes, BytesLike, bytesFrom } from "../bytes/index.js";
2
+ import type { Client } from "../client/client.js";
2
3
  import type { ClientCollectableSearchKeyFilterLike } from "../client/clientTypes.advanced.js";
3
4
  import {
4
5
  ClientBlockHeader,
5
6
  type CellDepInfoLike,
6
- type Client,
7
7
  type ClientBlockHeaderLike,
8
- } from "../client/index.js";
8
+ } from "../client/clientTypes.js";
9
9
  import { KnownScript } from "../client/knownScript.js";
10
10
  import { Codec, Entity, codec } from "../codec/index.js";
11
11
  import { Zero, fixedPointFrom } from "../fixedPoint/index.js";
@@ -1098,7 +1098,7 @@ export class WitnessArgs extends Entity.Base<WitnessArgsLike, WitnessArgs>() {
1098
1098
  * @public
1099
1099
  */
1100
1100
  export function udtBalanceFrom(dataLike: BytesLike): Num {
1101
- const data = bytesFrom(dataLike).slice(0, 16);
1101
+ const data = bytesFrom(dataLike).subarray(0, 16);
1102
1102
  return data.length === 0 ? Zero : numFromBytes(data);
1103
1103
  }
1104
1104
 
@@ -2795,9 +2795,9 @@ export function calcDaoClaimEpoch(
2795
2795
  if (
2796
2796
  partialCycle !== Zero ||
2797
2797
  // deposit.numerator withdraw.numerator
2798
- // --------------------- <= ----------------------
2798
+ // --------------------- < -----------------------
2799
2799
  // deposit.denominator withdraw.denominator
2800
- deposit.numerator * withdraw.denominator <=
2800
+ deposit.numerator * withdraw.denominator <
2801
2801
  withdraw.numerator * deposit.denominator
2802
2802
  ) {
2803
2803
  // Need to wait for the next cycle
@@ -34,19 +34,33 @@ import {
34
34
  ErrorClientWaitTransactionTimeout,
35
35
  OutputsValidator,
36
36
  ScriptInfo,
37
+ type ScriptInfoLike,
37
38
  } from "./clientTypes.js";
38
39
  import { KnownScript } from "./knownScript.js";
39
40
 
41
+ export type ClientConfig = {
42
+ cache?: ClientCache;
43
+ scripts?: Partial<Record<KnownScript, ScriptInfoLike>>;
44
+ };
45
+
40
46
  /**
41
47
  * @public
42
48
  */
43
49
  export abstract class Client {
44
50
  public cache: ClientCache;
51
+ private readonly scripts: Partial<Record<KnownScript, ScriptInfoLike>>;
45
52
 
46
- constructor(config?: { cache?: ClientCache }) {
53
+ constructor(config?: ClientConfig) {
47
54
  this.cache = config?.cache ?? new ClientCacheMemory();
55
+ this.scripts = config?.scripts ?? {};
48
56
  }
49
57
 
58
+ /**
59
+ * The legacy primary URL associated with this Client.
60
+ *
61
+ * @deprecated A Client may use multiple endpoints or a Transport without a
62
+ * URL, so this value does not reliably identify its connection.
63
+ */
50
64
  abstract get url(): string;
51
65
  abstract get addressPrefix(): string;
52
66
 
@@ -61,7 +75,9 @@ export abstract class Client {
61
75
  * ```typescript
62
76
  * import { ccc } from "@ckb-ccc/core";
63
77
  *
64
- * const client = new ccc.ClientPublicTestnet();
78
+ * const clientOwner = ccc.ClientPublicTestnet.open();
79
+ * const client = clientOwner.value;
80
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
65
81
  *
66
82
  * // Get xUDT script deployment info
67
83
  * const xudtInfo = await client.getKnownScript(ccc.KnownScript.XUdt);
@@ -75,7 +91,15 @@ export abstract class Client {
75
91
  * );
76
92
  * ```
77
93
  */
78
- abstract getKnownScript(script: KnownScript): Promise<ScriptInfo>;
94
+ async getKnownScript(script: KnownScript): Promise<ScriptInfo> {
95
+ const found = this.scripts[script];
96
+ if (!found) {
97
+ throw new Error(
98
+ `No script information was found for ${script} on ${this.addressPrefix}`,
99
+ );
100
+ }
101
+ return ScriptInfo.from(found);
102
+ }
79
103
 
80
104
  abstract getFeeRateStatistics(
81
105
  blockRange?: NumLike,
@@ -92,7 +116,9 @@ export abstract class Client {
92
116
  * ```typescript
93
117
  * import { ccc } from "@ckb-ccc/core";
94
118
  *
95
- * const client = new ccc.ClientPublicTestnet();
119
+ * const clientOwner = ccc.ClientPublicTestnet.open();
120
+ * const client = clientOwner.value;
121
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
96
122
  * const feeRate = await client.getFeeRate();
97
123
  * console.log(`Current fee rate: ${feeRate} Shannons/KB`);
98
124
  * ```
@@ -123,7 +149,9 @@ export abstract class Client {
123
149
  * ```typescript
124
150
  * import { ccc } from "@ckb-ccc/core";
125
151
  *
126
- * const client = new ccc.ClientPublicTestnet();
152
+ * const clientOwner = ccc.ClientPublicTestnet.open();
153
+ * const client = clientOwner.value;
154
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
127
155
  * const tipBlockNumber = await client.getTip();
128
156
  * console.log(`Current block height: ${tipBlockNumber}`);
129
157
  * ```
@@ -140,7 +168,9 @@ export abstract class Client {
140
168
  * ```typescript
141
169
  * import { ccc } from "@ckb-ccc/core";
142
170
  *
143
- * const client = new ccc.ClientPublicTestnet();
171
+ * const clientOwner = ccc.ClientPublicTestnet.open();
172
+ * const client = clientOwner.value;
173
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
144
174
  * const header = await client.getTipHeader();
145
175
  * console.log(`Block #${header.number}, hash: ${header.hash}`);
146
176
  * ```
@@ -260,7 +290,9 @@ export abstract class Client {
260
290
  * ```typescript
261
291
  * import { ccc } from "@ckb-ccc/core";
262
292
  *
263
- * const client = new ccc.ClientPublicTestnet();
293
+ * const clientOwner = ccc.ClientPublicTestnet.open();
294
+ * const client = clientOwner.value;
295
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
264
296
  * const cell = await client.getCell({
265
297
  * txHash: "0xTX_HASH...",
266
298
  * index: 0,
@@ -339,7 +371,9 @@ export abstract class Client {
339
371
  * ```typescript
340
372
  * import { ccc } from "@ckb-ccc/core";
341
373
  *
342
- * const client = new ccc.ClientPublicTestnet();
374
+ * const clientOwner = ccc.ClientPublicTestnet.open();
375
+ * const client = clientOwner.value;
376
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
343
377
  * const cell = await client.getCellLive(
344
378
  * { txHash: "0xTX_HASH...", index: 0 },
345
379
  * true, // include data
@@ -388,7 +422,9 @@ export abstract class Client {
388
422
  * ```typescript
389
423
  * import { ccc } from "@ckb-ccc/core";
390
424
  *
391
- * const client = new ccc.ClientPublicTestnet();
425
+ * const clientOwner = ccc.ClientPublicTestnet.open();
426
+ * const client = clientOwner.value;
427
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
392
428
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
393
429
  *
394
430
  * // Get first page of cells
@@ -453,7 +489,9 @@ export abstract class Client {
453
489
  * ```typescript
454
490
  * import { ccc } from "@ckb-ccc/core";
455
491
  *
456
- * const client = new ccc.ClientPublicTestnet();
492
+ * const clientOwner = ccc.ClientPublicTestnet.open();
493
+ * const client = clientOwner.value;
494
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
457
495
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
458
496
  *
459
497
  * // Find all cells owned by a lock script
@@ -507,7 +545,9 @@ export abstract class Client {
507
545
  * ```typescript
508
546
  * import { ccc } from "@ckb-ccc/core";
509
547
  *
510
- * const client = new ccc.ClientPublicTestnet();
548
+ * const clientOwner = ccc.ClientPublicTestnet.open();
549
+ * const client = clientOwner.value;
550
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
511
551
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
512
552
  *
513
553
  * // Find all cells belonging to this address
@@ -559,7 +599,9 @@ export abstract class Client {
559
599
  * ```typescript
560
600
  * import { ccc } from "@ckb-ccc/core";
561
601
  *
562
- * const client = new ccc.ClientPublicTestnet();
602
+ * const clientOwner = ccc.ClientPublicTestnet.open();
603
+ * const client = clientOwner.value;
604
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
563
605
  * // Find all xUDT cells of a specific token
564
606
  * const xudtType = await ccc.Script.fromKnownScript(
565
607
  * client, ccc.KnownScript.XUdt, "0xOWNER_LOCK_HASH...",
@@ -612,7 +654,9 @@ export abstract class Client {
612
654
  * ```typescript
613
655
  * import { ccc } from "@ckb-ccc/core";
614
656
  *
615
- * const client = new ccc.ClientPublicTestnet();
657
+ * const clientOwner = ccc.ClientPublicTestnet.open();
658
+ * const client = clientOwner.value;
659
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
616
660
  * const xudtInfo = await client.getKnownScript(ccc.KnownScript.XUdt);
617
661
  * const cellDeps = await client.getCellDeps(xudtInfo.cellDeps);
618
662
  * // cellDeps can be added to a transaction:
@@ -729,7 +773,9 @@ export abstract class Client {
729
773
  * ```typescript
730
774
  * import { ccc } from "@ckb-ccc/core";
731
775
  *
732
- * const client = new ccc.ClientPublicTestnet();
776
+ * const clientOwner = ccc.ClientPublicTestnet.open();
777
+ * const client = clientOwner.value;
778
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
733
779
  * const { script: lock } = await ccc.Address.fromString("ckt1q...", client);
734
780
  *
735
781
  * // List all transactions related to an address (grouped)
@@ -842,7 +888,9 @@ export abstract class Client {
842
888
  * ```typescript
843
889
  * import { ccc } from "@ckb-ccc/core";
844
890
  *
845
- * const client = new ccc.ClientPublicTestnet();
891
+ * const clientOwner = ccc.ClientPublicTestnet.open();
892
+ * const client = clientOwner.value;
893
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
846
894
  * const { script: lock } = await ccc.Address.fromString(
847
895
  * "ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq...",
848
896
  * client,
@@ -874,7 +922,9 @@ export abstract class Client {
874
922
  * ```typescript
875
923
  * import { ccc } from "@ckb-ccc/core";
876
924
  *
877
- * const client = new ccc.ClientPublicTestnet();
925
+ * const clientOwner = ccc.ClientPublicTestnet.open();
926
+ * const client = clientOwner.value;
927
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
878
928
  * const signer = new ccc.SignerCkbPrivateKey(client, "0x...");
879
929
  * await signer.connect();
880
930
  *
@@ -905,7 +955,9 @@ export abstract class Client {
905
955
  * ```typescript
906
956
  * import { ccc } from "@ckb-ccc/core";
907
957
  *
908
- * const client = new ccc.ClientPublicTestnet();
958
+ * const clientOwner = ccc.ClientPublicTestnet.open();
959
+ * const client = clientOwner.value;
960
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
909
961
  * const signer = new ccc.SignerCkbPrivateKey(client, "0x...");
910
962
  * await signer.connect();
911
963
  *
@@ -949,7 +1001,9 @@ export abstract class Client {
949
1001
  * ```typescript
950
1002
  * import { ccc } from "@ckb-ccc/core";
951
1003
  *
952
- * const client = new ccc.ClientPublicTestnet();
1004
+ * const clientOwner = ccc.ClientPublicTestnet.open();
1005
+ * const client = clientOwner.value;
1006
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
953
1007
  * const txResponse = await client.getTransaction("0xTX_HASH...");
954
1008
  * if (txResponse) {
955
1009
  * console.log(`Status: ${txResponse.status}`);
@@ -1022,7 +1076,9 @@ export abstract class Client {
1022
1076
  * ```typescript
1023
1077
  * import { ccc } from "@ckb-ccc/core";
1024
1078
  *
1025
- * const client = new ccc.ClientPublicTestnet();
1079
+ * const clientOwner = ccc.ClientPublicTestnet.open();
1080
+ * const client = clientOwner.value;
1081
+ * // Call `await clientOwner.dispose()` when the client is no longer needed.
1026
1082
  * // Wait for transaction to be committed (0 confirmations)
1027
1083
  * const tx = await client.waitTransaction("0xTX_HASH...");
1028
1084
  * console.log(`Confirmed in block: ${tx?.blockNumber}`);
@@ -1,55 +1,94 @@
1
1
  import WebSocket from "isomorphic-ws";
2
+ import { RequestorJsonRpc } from "../jsonRpc/requestor.js";
3
+ import type { ClientConfig } from "./client.js";
2
4
  import { MAINNET_SCRIPTS } from "./clientPublicMainnet.advanced.js";
3
- import { ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
4
- import { ClientJsonRpc, ClientJsonRpcConfig } from "./jsonRpc/index.js";
5
- import { KnownScript } from "./knownScript.js";
5
+ import { ClientJsonRpc, type ClientJsonRpcConfig } from "./jsonRpc/client.js";
6
6
 
7
7
  /**
8
8
  * @public
9
9
  */
10
10
  export class ClientPublicMainnet extends ClientJsonRpc {
11
+ private static defaultUrls(): readonly [string, ...string[]] {
12
+ return typeof WebSocket !== "undefined"
13
+ ? [
14
+ "wss://mainnet.ckb.dev/ws",
15
+ "https://mainnet.ckb.dev/",
16
+ "https://mainnet.ckbapp.dev/",
17
+ ]
18
+ : ["https://mainnet.ckb.dev/", "https://mainnet.ckbapp.dev/"];
19
+ }
20
+
21
+ private static resolveConfig(
22
+ config?: ClientJsonRpcConfig & {
23
+ /** @deprecated URL belongs to Transport construction. */
24
+ url?: string;
25
+ },
26
+ ): ClientJsonRpcConfig & { url: string; fallbacks: string[] } {
27
+ const defaultUrls = this.defaultUrls();
28
+ return {
29
+ ...config,
30
+ url: config?.url ?? defaultUrls[0],
31
+ fallbacks: config?.fallbacks ?? [...defaultUrls],
32
+ scripts: config?.scripts ?? MAINNET_SCRIPTS,
33
+ };
34
+ }
35
+
36
+ /**
37
+ * @deprecated Use {@link ClientPublicMainnet.new} with a borrowed Transport or
38
+ * {@link ClientPublicMainnet.open} when creating Transports.
39
+ */
11
40
  constructor(
12
- private readonly config?: ClientJsonRpcConfig & {
41
+ config?: ClientJsonRpcConfig & {
42
+ /** @deprecated URL belongs to Transport construction. */
13
43
  url?: string;
14
- scripts?: Record<KnownScript, ScriptInfoLike | undefined>;
15
44
  },
16
45
  ) {
17
- const hasWebSocket = typeof WebSocket !== "undefined";
18
- super(
19
- config?.url ??
20
- (hasWebSocket
21
- ? "wss://mainnet.ckb.dev/ws"
22
- : "https://mainnet.ckb.dev/"),
23
- {
24
- ...config,
25
- fallbacks:
26
- config?.fallbacks ??
27
- (hasWebSocket
28
- ? [
29
- "wss://mainnet.ckb.dev/ws",
30
- "https://mainnet.ckb.dev/",
31
- "https://mainnet.ckbapp.dev/",
32
- ]
33
- : ["https://mainnet.ckb.dev/", "https://mainnet.ckbapp.dev/"]),
34
- },
35
- );
46
+ const resolved = ClientPublicMainnet.resolveConfig(config);
47
+ super(resolved.url, resolved);
36
48
  }
37
49
 
38
- get scripts(): Record<KnownScript, ScriptInfoLike | undefined> {
39
- return this.config?.scripts ?? MAINNET_SCRIPTS;
50
+ /** Creates a Client that borrows an existing Transport. */
51
+ static new(
52
+ config: Omit<Parameters<typeof RequestorJsonRpc.new>[0], "onError"> &
53
+ ClientConfig,
54
+ ): ClientPublicMainnet {
55
+ const { cache, scripts, ...requestorConfig } = config;
56
+ const requestor = this.newRequestor(requestorConfig);
57
+ return new ClientPublicMainnet({ cache, scripts, requestor });
40
58
  }
41
59
 
42
- get addressPrefix(): string {
43
- return "ckb";
60
+ /** Opens a Client with explicit ownership of its default dependencies. */
61
+ static open(
62
+ config?: Omit<
63
+ Parameters<typeof RequestorJsonRpc.open>[0],
64
+ "onError" | "urls"
65
+ > &
66
+ ClientConfig & {
67
+ urls?: Parameters<typeof RequestorJsonRpc.open>[0]["urls"];
68
+ },
69
+ ) {
70
+ const {
71
+ cache,
72
+ scripts,
73
+ urls = this.defaultUrls(),
74
+ ...requestorConfig
75
+ } = config ?? {};
76
+ return this.openRequestor({
77
+ ...requestorConfig,
78
+ urls,
79
+ }).map(
80
+ (requestor) =>
81
+ new ClientPublicMainnet({
82
+ cache,
83
+ scripts,
84
+ requestor,
85
+ url: urls[0],
86
+ fallbacks: [...urls.slice(1)],
87
+ }),
88
+ );
44
89
  }
45
90
 
46
- async getKnownScript(script: KnownScript): Promise<ScriptInfo> {
47
- const found = this.scripts[script];
48
- if (!found) {
49
- throw new Error(
50
- `No script information was found for ${script} on ${this.addressPrefix}`,
51
- );
52
- }
53
- return ScriptInfo.from(found);
91
+ get addressPrefix(): string {
92
+ return "ckb";
54
93
  }
55
94
  }
@@ -1,55 +1,94 @@
1
1
  import WebSocket from "isomorphic-ws";
2
+ import { RequestorJsonRpc } from "../jsonRpc/requestor.js";
3
+ import type { ClientConfig } from "./client.js";
2
4
  import { TESTNET_SCRIPTS } from "./clientPublicTestnet.advanced.js";
3
- import { ScriptInfo, ScriptInfoLike } from "./clientTypes.js";
4
- import { ClientJsonRpc, ClientJsonRpcConfig } from "./jsonRpc/index.js";
5
- import { KnownScript } from "./knownScript.js";
5
+ import { ClientJsonRpc, type ClientJsonRpcConfig } from "./jsonRpc/client.js";
6
6
 
7
7
  /**
8
8
  * @public
9
9
  */
10
10
  export class ClientPublicTestnet extends ClientJsonRpc {
11
+ private static defaultUrls(): readonly [string, ...string[]] {
12
+ return typeof WebSocket !== "undefined"
13
+ ? [
14
+ "wss://testnet.ckb.dev/ws",
15
+ "https://testnet.ckb.dev/",
16
+ "https://testnet.ckbapp.dev/",
17
+ ]
18
+ : ["https://testnet.ckb.dev/", "https://testnet.ckbapp.dev/"];
19
+ }
20
+
21
+ private static resolveConfig(
22
+ config?: ClientJsonRpcConfig & {
23
+ /** @deprecated URL belongs to Transport construction. */
24
+ url?: string;
25
+ },
26
+ ): ClientJsonRpcConfig & { url: string; fallbacks: string[] } {
27
+ const defaultUrls = this.defaultUrls();
28
+ return {
29
+ ...config,
30
+ url: config?.url ?? defaultUrls[0],
31
+ fallbacks: config?.fallbacks ?? [...defaultUrls],
32
+ scripts: config?.scripts ?? TESTNET_SCRIPTS,
33
+ };
34
+ }
35
+
36
+ /**
37
+ * @deprecated Use {@link ClientPublicTestnet.new} with a borrowed Transport or
38
+ * {@link ClientPublicTestnet.open} when creating Transports.
39
+ */
11
40
  constructor(
12
- private readonly config?: ClientJsonRpcConfig & {
41
+ config?: ClientJsonRpcConfig & {
42
+ /** @deprecated URL belongs to Transport construction. */
13
43
  url?: string;
14
- scripts?: Record<KnownScript, ScriptInfoLike | undefined>;
15
44
  },
16
45
  ) {
17
- const hasWebSocket = typeof WebSocket !== "undefined";
18
- super(
19
- config?.url ??
20
- (hasWebSocket
21
- ? "wss://testnet.ckb.dev/ws"
22
- : "https://testnet.ckb.dev/"),
23
- {
24
- ...config,
25
- fallbacks:
26
- config?.fallbacks ??
27
- (hasWebSocket
28
- ? [
29
- "wss://testnet.ckb.dev/ws",
30
- "https://testnet.ckb.dev/",
31
- "https://testnet.ckbapp.dev/",
32
- ]
33
- : ["https://testnet.ckb.dev/", "https://testnet.ckbapp.dev/"]),
34
- },
35
- );
46
+ const resolved = ClientPublicTestnet.resolveConfig(config);
47
+ super(resolved.url, resolved);
36
48
  }
37
49
 
38
- get scripts(): Record<KnownScript, ScriptInfoLike | undefined> {
39
- return this.config?.scripts ?? TESTNET_SCRIPTS;
50
+ /** Creates a Client that borrows an existing Transport. */
51
+ static new(
52
+ config: Omit<Parameters<typeof RequestorJsonRpc.new>[0], "onError"> &
53
+ ClientConfig,
54
+ ): ClientPublicTestnet {
55
+ const { cache, scripts, ...requestorConfig } = config;
56
+ const requestor = this.newRequestor(requestorConfig);
57
+ return new ClientPublicTestnet({ cache, scripts, requestor });
40
58
  }
41
59
 
42
- get addressPrefix(): string {
43
- return "ckt";
60
+ /** Opens a Client with explicit ownership of its default dependencies. */
61
+ static open(
62
+ config?: Omit<
63
+ Parameters<typeof RequestorJsonRpc.open>[0],
64
+ "onError" | "urls"
65
+ > &
66
+ ClientConfig & {
67
+ urls?: Parameters<typeof RequestorJsonRpc.open>[0]["urls"];
68
+ },
69
+ ) {
70
+ const {
71
+ cache,
72
+ scripts,
73
+ urls = this.defaultUrls(),
74
+ ...requestorConfig
75
+ } = config ?? {};
76
+ return this.openRequestor({
77
+ ...requestorConfig,
78
+ urls,
79
+ }).map(
80
+ (requestor) =>
81
+ new ClientPublicTestnet({
82
+ cache,
83
+ scripts,
84
+ requestor,
85
+ url: urls[0],
86
+ fallbacks: [...urls.slice(1)],
87
+ }),
88
+ );
44
89
  }
45
90
 
46
- async getKnownScript(script: KnownScript): Promise<ScriptInfo> {
47
- const found = this.scripts[script];
48
- if (!found) {
49
- throw new Error(
50
- `No script information was found for ${script} on ${this.addressPrefix}`,
51
- );
52
- }
53
- return ScriptInfo.from(found);
91
+ get addressPrefix(): string {
92
+ return "ckt";
54
93
  }
55
94
  }