@ckb-ccc/core 0.0.13-alpha.0 → 0.0.13-alpha.2

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 (120) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/ckb/transaction.d.ts.map +1 -1
  3. package/dist/ckb/transaction.js +17 -10
  4. package/dist/client/advanced.d.ts +2 -1
  5. package/dist/client/advanced.d.ts.map +1 -1
  6. package/dist/client/advanced.js +2 -1
  7. package/dist/client/cache/advanced.d.ts +2 -0
  8. package/dist/client/cache/advanced.d.ts.map +1 -0
  9. package/dist/client/cache/advanced.js +1 -0
  10. package/dist/client/cache/cache.d.ts +14 -0
  11. package/dist/client/cache/cache.d.ts.map +1 -0
  12. package/dist/client/cache/cache.js +1 -0
  13. package/dist/client/cache/index.d.ts +3 -0
  14. package/dist/client/cache/index.d.ts.map +1 -0
  15. package/dist/client/cache/index.js +2 -0
  16. package/dist/client/{client.advanced.d.ts → cache/memory.advanced.d.ts} +5 -5
  17. package/dist/client/cache/memory.advanced.d.ts.map +1 -0
  18. package/dist/client/{client.advanced.js → cache/memory.advanced.js} +6 -6
  19. package/dist/client/cache/memory.d.ts +19 -0
  20. package/dist/client/cache/memory.d.ts.map +1 -0
  21. package/dist/client/cache/memory.js +54 -0
  22. package/dist/client/client.d.ts +4 -7
  23. package/dist/client/client.d.ts.map +1 -1
  24. package/dist/client/client.js +22 -39
  25. package/dist/client/clientPublicMainnet.d.ts.map +1 -1
  26. package/dist/client/clientPublicMainnet.js +5 -2
  27. package/dist/client/clientPublicTestnet.d.ts.map +1 -1
  28. package/dist/client/clientPublicTestnet.js +5 -2
  29. package/dist/client/clientTypes.d.ts +1 -1
  30. package/dist/client/clientTypes.d.ts.map +1 -1
  31. package/dist/client/index.d.ts +1 -0
  32. package/dist/client/index.d.ts.map +1 -1
  33. package/dist/client/index.js +1 -0
  34. package/dist/client/jsonRpc/index.d.ts +5 -4
  35. package/dist/client/jsonRpc/index.d.ts.map +1 -1
  36. package/dist/client/jsonRpc/index.js +5 -15
  37. package/dist/client/jsonRpc/types.d.ts +0 -6
  38. package/dist/client/jsonRpc/types.d.ts.map +1 -1
  39. package/dist/client/transports/advanced.d.ts +9 -0
  40. package/dist/client/transports/advanced.d.ts.map +1 -0
  41. package/dist/client/transports/advanced.js +11 -0
  42. package/dist/client/transports/http.d.ts +8 -0
  43. package/dist/client/transports/http.d.ts.map +1 -0
  44. package/dist/client/transports/http.js +20 -0
  45. package/dist/client/transports/transport.d.ts +10 -0
  46. package/dist/client/transports/transport.d.ts.map +1 -0
  47. package/dist/client/transports/transport.js +1 -0
  48. package/dist/client/transports/webSocket.d.ts +10 -0
  49. package/dist/client/transports/webSocket.d.ts.map +1 -0
  50. package/dist/client/transports/webSocket.js +61 -0
  51. package/dist.commonjs/ckb/transaction.d.ts.map +1 -1
  52. package/dist.commonjs/ckb/transaction.js +17 -10
  53. package/dist.commonjs/client/advanced.d.ts +2 -1
  54. package/dist.commonjs/client/advanced.d.ts.map +1 -1
  55. package/dist.commonjs/client/advanced.js +2 -1
  56. package/dist.commonjs/client/cache/advanced.d.ts +2 -0
  57. package/dist.commonjs/client/cache/advanced.d.ts.map +1 -0
  58. package/dist.commonjs/client/cache/advanced.js +17 -0
  59. package/dist.commonjs/client/cache/cache.d.ts +14 -0
  60. package/dist.commonjs/client/cache/cache.d.ts.map +1 -0
  61. package/dist.commonjs/client/cache/cache.js +2 -0
  62. package/dist.commonjs/client/cache/index.d.ts +3 -0
  63. package/dist.commonjs/client/cache/index.d.ts.map +1 -0
  64. package/dist.commonjs/client/cache/index.js +18 -0
  65. package/dist.commonjs/client/{client.advanced.d.ts → cache/memory.advanced.d.ts} +5 -5
  66. package/dist.commonjs/client/cache/memory.advanced.d.ts.map +1 -0
  67. package/dist.commonjs/client/{client.advanced.js → cache/memory.advanced.js} +6 -6
  68. package/dist.commonjs/client/cache/memory.d.ts +19 -0
  69. package/dist.commonjs/client/cache/memory.d.ts.map +1 -0
  70. package/dist.commonjs/client/cache/memory.js +58 -0
  71. package/dist.commonjs/client/client.d.ts +4 -7
  72. package/dist.commonjs/client/client.d.ts.map +1 -1
  73. package/dist.commonjs/client/client.js +22 -39
  74. package/dist.commonjs/client/clientPublicMainnet.d.ts.map +1 -1
  75. package/dist.commonjs/client/clientPublicMainnet.js +5 -2
  76. package/dist.commonjs/client/clientPublicTestnet.d.ts.map +1 -1
  77. package/dist.commonjs/client/clientPublicTestnet.js +5 -2
  78. package/dist.commonjs/client/clientTypes.d.ts +1 -1
  79. package/dist.commonjs/client/clientTypes.d.ts.map +1 -1
  80. package/dist.commonjs/client/index.d.ts +1 -0
  81. package/dist.commonjs/client/index.d.ts.map +1 -1
  82. package/dist.commonjs/client/index.js +1 -0
  83. package/dist.commonjs/client/jsonRpc/index.d.ts +5 -4
  84. package/dist.commonjs/client/jsonRpc/index.d.ts.map +1 -1
  85. package/dist.commonjs/client/jsonRpc/index.js +15 -28
  86. package/dist.commonjs/client/jsonRpc/types.d.ts +0 -6
  87. package/dist.commonjs/client/jsonRpc/types.d.ts.map +1 -1
  88. package/dist.commonjs/client/transports/advanced.d.ts +9 -0
  89. package/dist.commonjs/client/transports/advanced.d.ts.map +1 -0
  90. package/dist.commonjs/client/transports/advanced.js +29 -0
  91. package/dist.commonjs/client/transports/http.d.ts +8 -0
  92. package/dist.commonjs/client/transports/http.d.ts.map +1 -0
  93. package/dist.commonjs/client/transports/http.js +24 -0
  94. package/dist.commonjs/client/transports/transport.d.ts +10 -0
  95. package/dist.commonjs/client/transports/transport.d.ts.map +1 -0
  96. package/dist.commonjs/client/transports/transport.js +2 -0
  97. package/dist.commonjs/client/transports/webSocket.d.ts +10 -0
  98. package/dist.commonjs/client/transports/webSocket.d.ts.map +1 -0
  99. package/dist.commonjs/client/transports/webSocket.js +65 -0
  100. package/package.json +1 -1
  101. package/src/ckb/transaction.ts +24 -16
  102. package/src/client/advanced.ts +2 -1
  103. package/src/client/cache/advanced.ts +1 -0
  104. package/src/client/cache/cache.ts +25 -0
  105. package/src/client/cache/index.ts +2 -0
  106. package/src/client/{client.advanced.ts → cache/memory.advanced.ts} +6 -6
  107. package/src/client/cache/memory.ts +75 -0
  108. package/src/client/client.ts +23 -44
  109. package/src/client/clientPublicMainnet.ts +8 -2
  110. package/src/client/clientPublicTestnet.ts +8 -2
  111. package/src/client/clientTypes.ts +1 -0
  112. package/src/client/index.ts +1 -0
  113. package/src/client/jsonRpc/index.ts +13 -19
  114. package/src/client/jsonRpc/types.ts +0 -7
  115. package/src/client/transports/advanced.ts +14 -0
  116. package/src/client/transports/http.ts +26 -0
  117. package/src/client/transports/transport.ts +10 -0
  118. package/src/client/transports/webSocket.ts +81 -0
  119. package/dist/client/client.advanced.d.ts.map +0 -1
  120. package/dist.commonjs/client/client.advanced.d.ts.map +0 -1
@@ -1538,8 +1538,9 @@ export class Transaction {
1538
1538
  }> {
1539
1539
  const scripts = (await from.getAddressObjs()).map(({ script }) => script);
1540
1540
  const collectedCells = [];
1541
- let acc: T = init;
1542
1541
 
1542
+ let acc: T = init;
1543
+ let fulfilled = false;
1543
1544
  for (const script of scripts) {
1544
1545
  for await (const cell of from.client.findCellsByCollectableSearchKey({
1545
1546
  script,
@@ -1556,26 +1557,33 @@ export class Transaction {
1556
1557
  continue;
1557
1558
  }
1558
1559
  const i = collectedCells.push(cell);
1559
- const next: T | undefined = await Promise.resolve(
1560
+ const next = await Promise.resolve(
1560
1561
  accumulator(acc, cell, i - 1, collectedCells),
1561
1562
  );
1562
1563
  if (next === undefined) {
1563
- this.inputs.push(
1564
- ...collectedCells.map(({ outPoint, outputData, cellOutput }) =>
1565
- CellInput.from({
1566
- previousOutput: outPoint,
1567
- since: 0,
1568
- outputData,
1569
- cellOutput,
1570
- }),
1571
- ),
1572
- );
1573
- return {
1574
- addedCount: collectedCells.length,
1575
- };
1564
+ fulfilled = true;
1565
+ break;
1576
1566
  }
1577
- acc = next;
1578
1567
  }
1568
+ if (fulfilled) {
1569
+ break;
1570
+ }
1571
+ }
1572
+
1573
+ this.inputs.push(
1574
+ ...collectedCells.map(({ outPoint, outputData, cellOutput }) =>
1575
+ CellInput.from({
1576
+ previousOutput: outPoint,
1577
+ since: 0,
1578
+ outputData,
1579
+ cellOutput,
1580
+ }),
1581
+ ),
1582
+ );
1583
+ if (fulfilled) {
1584
+ return {
1585
+ addedCount: collectedCells.length,
1586
+ };
1579
1587
  }
1580
1588
 
1581
1589
  return {
@@ -1,5 +1,6 @@
1
- export * from "./client.advanced.js";
1
+ export * from "./cache/advanced.js";
2
2
  export * from "./clientPublicMainnet.advanced.js";
3
3
  export * from "./clientPublicTestnet.advanced.js";
4
4
  export * from "./clientTypes.advanced.js";
5
5
  export * from "./jsonRpc/advanced.js";
6
+ export * from "./transports/advanced.js";
@@ -0,0 +1 @@
1
+ export * from "./memory.advanced.js";
@@ -0,0 +1,25 @@
1
+ import {
2
+ Cell,
3
+ CellLike,
4
+ OutPointLike,
5
+ Transaction,
6
+ TransactionLike,
7
+ } from "../../ckb/index.js";
8
+ import { HexLike } from "../../hex/index.js";
9
+ import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
10
+
11
+ export interface ClientCache {
12
+ markUsable(cellLike: CellLike): Promise<void>;
13
+ markUnusable(outPointLike: OutPointLike): Promise<void>;
14
+
15
+ isUnusable(outPointLike: OutPointLike): Promise<boolean>;
16
+
17
+ recordTransactions(
18
+ ...transactions: (TransactionLike | TransactionLike[])[]
19
+ ): Promise<void>;
20
+ getTransaction(txHash: HexLike): Promise<Transaction | undefined>;
21
+
22
+ recordCells(...cells: (CellLike | CellLike[])[]): Promise<void>;
23
+ getCell(outPoint: OutPointLike): Promise<Cell | undefined>;
24
+ findCells(filter: ClientCollectableSearchKeyLike): AsyncGenerator<Cell>;
25
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./cache.js";
2
+ export * from "./memory.js";
@@ -1,12 +1,12 @@
1
- import { bytesFrom } from "../bytes/index.js";
2
- import { Cell, CellLike, Script, ScriptLike } from "../ckb/index.js";
3
- import { HexLike, hexFrom } from "../hex/index.js";
4
- import { NumLike, numFrom } from "../num/index.js";
1
+ import { bytesFrom } from "../../bytes/index.js";
2
+ import { Cell, CellLike, Script, ScriptLike } from "../../ckb/index.js";
3
+ import { HexLike, hexFrom } from "../../hex/index.js";
4
+ import { NumLike, numFrom } from "../../num/index.js";
5
5
  import {
6
6
  ClientCollectableSearchKeyLike,
7
7
  clientSearchKeyRangeFrom,
8
- } from "./clientTypes.advanced.js";
9
- import { ClientIndexerSearchKey } from "./clientTypes.js";
8
+ } from "../clientTypes.advanced.js";
9
+ import { ClientIndexerSearchKey } from "../clientTypes.js";
10
10
 
11
11
  export function filterData(
12
12
  dataLike: HexLike,
@@ -0,0 +1,75 @@
1
+ import {
2
+ Cell,
3
+ CellLike,
4
+ OutPoint,
5
+ OutPointLike,
6
+ Transaction,
7
+ TransactionLike,
8
+ } from "../../ckb/index.js";
9
+ import { HexLike, hexFrom } from "../../hex/index.js";
10
+ import { ClientCollectableSearchKeyLike } from "../clientTypes.advanced.js";
11
+ import { ClientCache } from "./cache.js";
12
+ import { filterCell } from "./memory.advanced.js";
13
+
14
+ export class ClientCacheMemory implements ClientCache {
15
+ private readonly cachedTransactions: Transaction[] = [];
16
+ private readonly unusableOutPoints: OutPoint[] = [];
17
+ private readonly usableCells: Cell[] = [];
18
+ private readonly knownCells: Cell[] = [];
19
+
20
+ async markUsable(cellLike: CellLike): Promise<void> {
21
+ const cell = Cell.from(cellLike).clone();
22
+ this.usableCells.push(cell);
23
+ this.knownCells.push(cell);
24
+
25
+ const index = this.unusableOutPoints.findIndex((o) => cell.outPoint.eq(o));
26
+ if (index !== -1) {
27
+ this.unusableOutPoints.splice(index, 1);
28
+ }
29
+ }
30
+
31
+ async markUnusable(outPointLike: OutPointLike): Promise<void> {
32
+ const outPoint = OutPoint.from(outPointLike);
33
+ this.unusableOutPoints.push(outPoint.clone());
34
+
35
+ const index = this.usableCells.findIndex((c) => c.outPoint.eq(outPoint));
36
+ if (index !== -1) {
37
+ this.usableCells.splice(index, 1);
38
+ }
39
+ }
40
+
41
+ async isUnusable(outPointLike: OutPointLike): Promise<boolean> {
42
+ const outPoint = OutPoint.from(outPointLike);
43
+ return this.unusableOutPoints.find((o) => o.eq(outPoint)) !== undefined;
44
+ }
45
+
46
+ async recordTransactions(
47
+ ...transactions: (TransactionLike | TransactionLike[])[]
48
+ ): Promise<void> {
49
+ this.cachedTransactions.push(...transactions.flat().map(Transaction.from));
50
+ }
51
+ async getTransaction(txHashLike: HexLike): Promise<Transaction | undefined> {
52
+ const txHash = hexFrom(txHashLike);
53
+ return this.cachedTransactions.find((tx) => tx.hash() === txHash);
54
+ }
55
+
56
+ async recordCells(...cells: (CellLike | CellLike[])[]): Promise<void> {
57
+ this.usableCells.push(...cells.flat().map(Cell.from));
58
+ }
59
+ async getCell(outPointLike: OutPointLike): Promise<Cell | undefined> {
60
+ const outPoint = OutPoint.from(outPointLike);
61
+ return this.usableCells.find((cell) => cell.outPoint.eq(outPoint));
62
+ }
63
+
64
+ async *findCells(
65
+ keyLike: ClientCollectableSearchKeyLike,
66
+ ): AsyncGenerator<Cell> {
67
+ for (const cell of this.usableCells) {
68
+ if (!filterCell(keyLike, cell)) {
69
+ continue;
70
+ }
71
+
72
+ yield cell;
73
+ }
74
+ }
75
+ }
@@ -2,7 +2,6 @@ import {
2
2
  Cell,
3
3
  CellDep,
4
4
  CellDepLike,
5
- CellLike,
6
5
  OutPoint,
7
6
  OutPointLike,
8
7
  Script,
@@ -14,7 +13,8 @@ import { Zero } from "../fixedPoint/index.js";
14
13
  import { Hex, HexLike, hexFrom } from "../hex/index.js";
15
14
  import { Num, NumLike, numFrom } from "../num/index.js";
16
15
  import { apply, reduceAsync } from "../utils/index.js";
17
- import { filterCell } from "./client.advanced.js";
16
+ import { ClientCache } from "./cache/index.js";
17
+ import { ClientCacheMemory } from "./cache/memory.js";
18
18
  import { ClientCollectableSearchKeyLike } from "./clientTypes.advanced.js";
19
19
  import {
20
20
  ClientBlock,
@@ -76,10 +76,7 @@ export class CellDepInfo {
76
76
  * @public
77
77
  */
78
78
  export abstract class Client {
79
- private readonly cachedTransactions: Transaction[] = [];
80
- private readonly unusableOutPoints: OutPoint[] = [];
81
- private readonly usableCells: Cell[] = [];
82
- private readonly knownCells: Cell[] = [];
79
+ constructor(public cache: ClientCache = new ClientCacheMemory()) {}
83
80
 
84
81
  abstract get url(): string;
85
82
  abstract get addressPrefix(): string;
@@ -102,27 +99,6 @@ export abstract class Client {
102
99
  withCycles?: boolean | null,
103
100
  ): Promise<ClientBlock | undefined>;
104
101
 
105
- async markUsable(cellLike: CellLike): Promise<void> {
106
- const cell = Cell.from(cellLike).clone();
107
- this.usableCells.push(cell);
108
- this.knownCells.push(cell);
109
-
110
- const index = this.unusableOutPoints.findIndex((o) => cell.outPoint.eq(o));
111
- if (index !== -1) {
112
- this.unusableOutPoints.splice(index, 1);
113
- }
114
- }
115
-
116
- async markUnusable(outPointLike: OutPointLike): Promise<void> {
117
- const outPoint = OutPoint.from(outPointLike);
118
- this.unusableOutPoints.push(outPoint.clone());
119
-
120
- const index = this.usableCells.findIndex((c) => c.outPoint.eq(outPoint));
121
- if (index !== -1) {
122
- this.usableCells.splice(index, 1);
123
- }
124
- }
125
-
126
102
  abstract sendTransactionNoCache(
127
103
  transaction: TransactionLike,
128
104
  validator?: OutputsValidator,
@@ -133,10 +109,10 @@ export abstract class Client {
133
109
 
134
110
  async getCell(outPointLike: OutPointLike): Promise<Cell | undefined> {
135
111
  const outPoint = OutPoint.from(outPointLike);
136
- const cached = this.knownCells.find((cell) => cell.outPoint.eq(outPoint));
112
+ const cached = await this.cache.getCell(outPoint);
137
113
 
138
114
  if (cached) {
139
- return cached.clone();
115
+ return cached;
140
116
  }
141
117
 
142
118
  const transaction = await this.getTransactionNoCache(outPoint.txHash);
@@ -154,8 +130,8 @@ export abstract class Client {
154
130
  cellOutput: transaction.transaction.outputs[index],
155
131
  outputData: transaction.transaction.outputsData[index] ?? "0x",
156
132
  });
157
- this.knownCells.push(cell);
158
- return cell.clone();
133
+ await this.cache.recordCells(cell);
134
+ return cell;
159
135
  }
160
136
 
161
137
  abstract findCellsPagedNoCache(
@@ -171,7 +147,7 @@ export abstract class Client {
171
147
  after?: string,
172
148
  ): Promise<ClientFindCellsResponse> {
173
149
  const res = await this.findCellsPagedNoCache(key, order, limit, after);
174
- this.knownCells.push(...res.cells);
150
+ await this.cache.recordCells(res.cells);
175
151
  return res;
176
152
  }
177
153
 
@@ -213,18 +189,14 @@ export abstract class Client {
213
189
  const key = ClientIndexerSearchKey.from(keyLike);
214
190
  const foundedOutPoints = [];
215
191
 
216
- for (const cell of this.usableCells) {
217
- if (!filterCell(key, cell)) {
218
- continue;
219
- }
220
-
192
+ for await (const cell of this.cache.findCells(key)) {
221
193
  foundedOutPoints.push(cell.outPoint);
222
194
  yield cell;
223
195
  }
224
196
 
225
197
  for await (const cell of this.findCells(key, order, limit)) {
226
198
  if (
227
- this.unusableOutPoints.some((o) => o.eq(cell.outPoint)) ||
199
+ (await this.cache.isUnusable(cell.outPoint)) ||
228
200
  foundedOutPoints.some((founded) => founded.eq(cell.outPoint))
229
201
  ) {
230
202
  continue;
@@ -506,13 +478,13 @@ export abstract class Client {
506
478
 
507
479
  const txHash = await this.sendTransactionNoCache(tx, validator);
508
480
 
509
- this.cachedTransactions.push(tx.clone());
481
+ await this.cache.recordTransactions(tx);
510
482
  await Promise.all(
511
- tx.inputs.map((i) => this.markUnusable(i.previousOutput)),
483
+ tx.inputs.map((i) => this.cache.markUnusable(i.previousOutput)),
512
484
  );
513
485
  await Promise.all(
514
486
  tx.outputs.map((o, i) =>
515
- this.markUsable({
487
+ this.cache.markUsable({
516
488
  cellOutput: o,
517
489
  outputData: tx.outputsData[i],
518
490
  outPoint: {
@@ -530,18 +502,25 @@ export abstract class Client {
530
502
  ): Promise<ClientTransactionResponse | undefined> {
531
503
  const txHash = hexFrom(txHashLike);
532
504
  const res = await this.getTransactionNoCache(txHash);
533
- if (res !== null) {
505
+ if (res?.transaction) {
534
506
  return res;
535
507
  }
536
508
 
537
- const tx = this.cachedTransactions.find((t) => t.hash() === txHash);
509
+ const tx = await this.cache.getTransaction(txHash);
538
510
  if (!tx) {
539
511
  return;
540
512
  }
541
513
 
514
+ if (!res) {
515
+ return {
516
+ transaction: tx,
517
+ status: "sent",
518
+ };
519
+ }
520
+
542
521
  return {
522
+ ...res,
543
523
  transaction: tx,
544
- status: "proposed",
545
524
  };
546
525
  }
547
526
  }
@@ -8,11 +8,17 @@ import { ClientJsonRpc } from "./jsonRpc/index.js";
8
8
  */
9
9
  export class ClientPublicMainnet extends ClientJsonRpc {
10
10
  constructor(
11
- url = "https://mainnet.ckb.dev/",
11
+ url?: string,
12
12
  timeout?: number,
13
13
  private readonly scripts = MAINNET_SCRIPTS,
14
14
  ) {
15
- super(url, timeout);
15
+ super(
16
+ url ??
17
+ (typeof WebSocket !== "undefined"
18
+ ? "wss://mainnet.ckb.dev/ws"
19
+ : "https://mainnet.ckb.dev/"),
20
+ timeout,
21
+ );
16
22
  }
17
23
 
18
24
  get addressPrefix(): string {
@@ -8,11 +8,17 @@ import { ClientJsonRpc } from "./jsonRpc/index.js";
8
8
  */
9
9
  export class ClientPublicTestnet extends ClientJsonRpc {
10
10
  constructor(
11
- url = "https://testnet.ckb.dev/",
11
+ url?: string,
12
12
  timeout?: number,
13
13
  private readonly scripts = TESTNET_SCRIPTS,
14
14
  ) {
15
- super(url, timeout);
15
+ super(
16
+ url ??
17
+ (typeof WebSocket !== "undefined"
18
+ ? "wss://testnet.ckb.dev/ws"
19
+ : "https://testnet.ckb.dev/"),
20
+ timeout,
21
+ );
16
22
  }
17
23
 
18
24
  get addressPrefix(): string {
@@ -17,6 +17,7 @@ export type OutputsValidator = "passthrough" | "well_known_scripts_only";
17
17
  * @public
18
18
  */
19
19
  export type TransactionStatus =
20
+ | "sent"
20
21
  | "pending"
21
22
  | "proposed"
22
23
  | "committed"
@@ -1,3 +1,4 @@
1
+ export * from "./cache/index.js";
1
2
  export * from "./client.js";
2
3
  export * from "./clientPublicMainnet.js";
3
4
  export * from "./clientPublicTestnet.js";
@@ -1,4 +1,3 @@
1
- import fetch from "cross-fetch";
2
1
  import { apply } from "../../barrel.js";
3
2
  import { TransactionLike } from "../../ckb/index.js";
4
3
  import { Hex, HexLike, hexFrom } from "../../hex/index.js";
@@ -10,7 +9,12 @@ import {
10
9
  ClientTransactionResponse,
11
10
  OutputsValidator,
12
11
  } from "../clientTypes.js";
13
- import { JsonRpcPayload, JsonRpcTransformers } from "./advanced.js";
12
+ import {
13
+ JsonRpcPayload,
14
+ Transport,
15
+ transportFromUri,
16
+ } from "../transports/advanced.js";
17
+ import { JsonRpcTransformers } from "./advanced.js";
14
18
 
15
19
  /**
16
20
  * Applies a transformation function to a value if the transformer is provided.
@@ -42,18 +46,22 @@ async function transform(
42
46
  */
43
47
 
44
48
  export abstract class ClientJsonRpc extends Client {
49
+ private readonly transport: Transport;
50
+
45
51
  /**
46
52
  * Creates an instance of ClientJsonRpc.
47
53
  *
48
54
  * @param url_ - The URL of the JSON-RPC server.
49
- * @param timeout - The timeout for requests in milliseconds, default is 30000.
55
+ * @param timeout - The timeout for requests in milliseconds
50
56
  */
51
57
 
52
58
  constructor(
53
59
  private readonly url_: string,
54
- private readonly timeout = 30000,
60
+ private readonly timeout?: number,
55
61
  ) {
56
62
  super();
63
+
64
+ this.transport = transportFromUri(url_);
57
65
  }
58
66
 
59
67
  /**
@@ -232,22 +240,8 @@ export abstract class ClientJsonRpc extends Client {
232
240
  *
233
241
  * @throws Will throw an error if the response ID does not match the request ID, or if the response contains an error.
234
242
  */
235
-
236
243
  async send(payload: JsonRpcPayload): Promise<unknown> {
237
- const aborter = new AbortController();
238
- const abortTimer = setTimeout(() => aborter.abort(), this.timeout);
239
-
240
- const raw = await fetch(this.url, {
241
- method: "POST",
242
- headers: {
243
- "content-type": "application/json",
244
- },
245
- body: JSON.stringify(payload),
246
- signal: aborter.signal,
247
- });
248
- clearTimeout(abortTimer);
249
-
250
- const res = (await raw.json()) as {
244
+ const res = (await this.transport.request(payload)) as {
251
245
  id: number;
252
246
  error: unknown;
253
247
  result: unknown;
@@ -1,12 +1,5 @@
1
1
  import { Hex } from "../../hex/index.js";
2
2
 
3
- export type JsonRpcPayload = {
4
- id: number;
5
- jsonrpc: "2.0";
6
- method: string;
7
- params: unknown[] | Record<string, unknown>;
8
- };
9
-
10
3
  export type JsonRpcHashType = "type" | "data" | "data1" | "data2";
11
4
  export type JsonRpcDepType = "dep_group" | "code";
12
5
 
@@ -0,0 +1,14 @@
1
+ import { TransportHttp } from "./http.js";
2
+ import { TransportWebSocket } from "./webSocket.js";
3
+
4
+ export * from "./http.js";
5
+ export * from "./transport.js";
6
+ export * from "./webSocket.js";
7
+
8
+ export function transportFromUri(uri: string, config?: { timeout?: number }) {
9
+ if (uri.startsWith("wss://")) {
10
+ return new TransportWebSocket(uri, config?.timeout);
11
+ }
12
+
13
+ return new TransportHttp(uri, config?.timeout);
14
+ }
@@ -0,0 +1,26 @@
1
+ import { JsonRpcPayload, Transport } from "./transport.js";
2
+
3
+ export class TransportHttp implements Transport {
4
+ constructor(
5
+ private readonly url: string,
6
+ private readonly timeout = 30000,
7
+ ) {}
8
+
9
+ async request(payload: JsonRpcPayload) {
10
+ const aborter = new AbortController();
11
+ const abortTimer = setTimeout(() => aborter.abort(), this.timeout);
12
+
13
+ const raw = await (
14
+ await fetch(this.url, {
15
+ method: "POST",
16
+ headers: {
17
+ "content-type": "application/json",
18
+ },
19
+ body: JSON.stringify(payload),
20
+ signal: aborter.signal,
21
+ })
22
+ ).json();
23
+ clearTimeout(abortTimer);
24
+ return raw;
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ export type JsonRpcPayload = {
2
+ id: number;
3
+ jsonrpc: "2.0";
4
+ method: string;
5
+ params: unknown[] | Record<string, unknown>;
6
+ };
7
+
8
+ export interface Transport {
9
+ request(data: JsonRpcPayload): Promise<unknown>;
10
+ }
@@ -0,0 +1,81 @@
1
+ import { JsonRpcPayload, Transport } from "./transport.js";
2
+
3
+ export class TransportWebSocket implements Transport {
4
+ private ongoing: Map<
5
+ number,
6
+ [
7
+ (response: unknown) => unknown,
8
+ (error: unknown) => unknown,
9
+ ReturnType<typeof setTimeout>,
10
+ ]
11
+ > = new Map();
12
+ private socket?: Promise<WebSocket>;
13
+
14
+ constructor(
15
+ private readonly url: string,
16
+ private readonly timeout = 30000,
17
+ ) {}
18
+
19
+ async request(data: JsonRpcPayload) {
20
+ const socket = (() => {
21
+ if (this.socket) {
22
+ return this.socket;
23
+ }
24
+
25
+ const socket = new WebSocket(this.url);
26
+ const onMessage = ({ data }: { data: string }) => {
27
+ const res = JSON.parse(data);
28
+ if (typeof res !== "object" || res === null) {
29
+ throw new Error(`Unknown response ${data}`);
30
+ }
31
+
32
+ const req = this.ongoing.get(res.id);
33
+ if (!req) {
34
+ return;
35
+ }
36
+ clearTimeout(req[2]);
37
+ this.ongoing.delete(res.id);
38
+
39
+ req[0](res);
40
+ };
41
+ const onClose = (error?: unknown) => {
42
+ this.socket = undefined;
43
+ this.ongoing.forEach(([_, onError]) =>
44
+ onError(error ?? new Error("Connection closed")),
45
+ );
46
+ this.ongoing.clear();
47
+ };
48
+
49
+ socket.onclose = onClose;
50
+ socket.onerror = onClose;
51
+ socket.onmessage = onMessage;
52
+
53
+ this.socket = new Promise((resolve) => {
54
+ if (socket.readyState === socket.CONNECTING) {
55
+ socket.onopen = resolve;
56
+ } else {
57
+ resolve(undefined);
58
+ }
59
+ }).then(() => socket);
60
+ return this.socket;
61
+ })();
62
+
63
+ return new Promise((resolve, reject) => {
64
+ this.ongoing.set(data.id, [
65
+ resolve,
66
+ reject,
67
+ setTimeout(() => reject(new Error("Request timeout")), this.timeout),
68
+ ]);
69
+ socket.then((socket) => {
70
+ if (
71
+ socket.readyState === socket.CLOSED ||
72
+ socket.readyState === socket.CLOSING
73
+ ) {
74
+ reject(new Error("Connection closed"));
75
+ } else {
76
+ socket.send(JSON.stringify(data));
77
+ }
78
+ });
79
+ });
80
+ }
81
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.advanced.d.ts","sourceRoot":"","sources":["../../src/client/client.advanced.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,QAAQ,EAAU,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAW,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAW,MAAM,iBAAiB,CAAC;AACnD,OAAO,EACL,8BAA8B,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,wBAAgB,UAAU,CACxB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,OAAO,GAAG,SAAS,EAC/B,UAAU,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GACzC,OAAO,CAgBT;AAED,wBAAgB,YAAY,CAC1B,SAAS,EAAE,UAAU,GAAG,SAAS,EACjC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GACzC,OAAO,CAkBT;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,OAAO,EACnB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,SAAS,GACpC,OAAO,CAQT;AAED,wBAAgB,sBAAsB,CACpC,SAAS,CAAC,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAClC,OAAO,CAYT;AAED,wBAAgB,UAAU,CACxB,aAAa,EAAE,8BAA8B,EAC7C,QAAQ,EAAE,QAAQ,GACjB,OAAO,CA4CT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.advanced.d.ts","sourceRoot":"","sources":["../../src/client/client.advanced.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,QAAQ,EAAU,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAW,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAW,MAAM,iBAAiB,CAAC;AACnD,OAAO,EACL,8BAA8B,EAE/B,MAAM,2BAA2B,CAAC;AAGnC,wBAAgB,UAAU,CACxB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,OAAO,GAAG,SAAS,EAC/B,UAAU,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GACzC,OAAO,CAgBT;AAED,wBAAgB,YAAY,CAC1B,SAAS,EAAE,UAAU,GAAG,SAAS,EACjC,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,UAAU,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GACzC,OAAO,CAkBT;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,OAAO,EACnB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,SAAS,GACpC,OAAO,CAQT;AAED,wBAAgB,sBAAsB,CACpC,SAAS,CAAC,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAClC,OAAO,CAYT;AAED,wBAAgB,UAAU,CACxB,aAAa,EAAE,8BAA8B,EAC7C,QAAQ,EAAE,QAAQ,GACjB,OAAO,CA4CT"}