@arkade-os/sdk 0.3.0-alpha.8 → 0.3.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 (101) hide show
  1. package/README.md +48 -14
  2. package/dist/cjs/arknote/index.js +3 -3
  3. package/dist/cjs/forfeit.js +2 -2
  4. package/dist/cjs/identity/singleKey.js +8 -8
  5. package/dist/cjs/index.js +13 -5
  6. package/dist/cjs/{bip322 → intent}/index.js +38 -61
  7. package/dist/cjs/musig2/index.js +2 -1
  8. package/dist/cjs/musig2/nonces.js +4 -0
  9. package/dist/cjs/providers/ark.js +76 -45
  10. package/dist/cjs/providers/errors.js +59 -0
  11. package/dist/cjs/providers/expoArk.js +15 -170
  12. package/dist/cjs/providers/expoIndexer.js +22 -111
  13. package/dist/cjs/providers/expoUtils.js +124 -0
  14. package/dist/cjs/providers/onchain.js +19 -20
  15. package/dist/cjs/repositories/walletRepository.js +64 -28
  16. package/dist/cjs/script/base.js +15 -7
  17. package/dist/cjs/script/tapscript.js +20 -21
  18. package/dist/cjs/script/vhtlc.js +2 -2
  19. package/dist/cjs/tree/signingSession.js +44 -11
  20. package/dist/cjs/tree/txTree.js +3 -4
  21. package/dist/cjs/tree/validation.js +2 -3
  22. package/dist/cjs/utils/arkTransaction.js +105 -15
  23. package/dist/cjs/utils/transaction.js +28 -0
  24. package/dist/cjs/utils/unknownFields.js +7 -7
  25. package/dist/cjs/wallet/onchain.js +6 -7
  26. package/dist/cjs/wallet/serviceWorker/response.js +32 -0
  27. package/dist/cjs/wallet/serviceWorker/utils.js +2 -0
  28. package/dist/cjs/wallet/serviceWorker/wallet.js +7 -8
  29. package/dist/cjs/wallet/serviceWorker/worker.js +46 -27
  30. package/dist/cjs/wallet/unroll.js +7 -9
  31. package/dist/cjs/wallet/utils.js +9 -0
  32. package/dist/cjs/wallet/vtxo-manager.js +323 -0
  33. package/dist/cjs/wallet/wallet.js +98 -125
  34. package/dist/esm/arknote/index.js +2 -2
  35. package/dist/esm/forfeit.js +1 -1
  36. package/dist/esm/identity/singleKey.js +9 -9
  37. package/dist/esm/index.js +14 -10
  38. package/dist/esm/{bip322 → intent}/index.js +32 -54
  39. package/dist/esm/musig2/index.js +1 -1
  40. package/dist/esm/musig2/nonces.js +3 -0
  41. package/dist/esm/providers/ark.js +76 -45
  42. package/dist/esm/providers/errors.js +54 -0
  43. package/dist/esm/providers/expoArk.js +15 -137
  44. package/dist/esm/providers/expoIndexer.js +22 -78
  45. package/dist/esm/providers/expoUtils.js +87 -0
  46. package/dist/esm/providers/onchain.js +19 -20
  47. package/dist/esm/repositories/walletRepository.js +64 -28
  48. package/dist/esm/script/base.js +12 -4
  49. package/dist/esm/script/tapscript.js +1 -2
  50. package/dist/esm/script/vhtlc.js +1 -1
  51. package/dist/esm/tree/signingSession.js +45 -12
  52. package/dist/esm/tree/txTree.js +3 -4
  53. package/dist/esm/tree/validation.js +2 -3
  54. package/dist/esm/utils/arkTransaction.js +97 -8
  55. package/dist/esm/utils/transaction.js +24 -0
  56. package/dist/esm/utils/unknownFields.js +3 -3
  57. package/dist/esm/wallet/onchain.js +3 -4
  58. package/dist/esm/wallet/serviceWorker/response.js +32 -0
  59. package/dist/esm/wallet/serviceWorker/utils.js +1 -0
  60. package/dist/esm/wallet/serviceWorker/wallet.js +8 -9
  61. package/dist/esm/wallet/serviceWorker/worker.js +48 -29
  62. package/dist/esm/wallet/unroll.js +5 -7
  63. package/dist/esm/wallet/utils.js +8 -0
  64. package/dist/esm/wallet/vtxo-manager.js +317 -0
  65. package/dist/esm/wallet/wallet.js +92 -119
  66. package/dist/types/arknote/index.d.ts +1 -1
  67. package/dist/types/forfeit.d.ts +2 -2
  68. package/dist/types/identity/index.d.ts +2 -2
  69. package/dist/types/identity/singleKey.d.ts +2 -2
  70. package/dist/types/index.d.ts +9 -7
  71. package/dist/types/intent/index.d.ts +41 -0
  72. package/dist/types/musig2/index.d.ts +1 -1
  73. package/dist/types/musig2/nonces.d.ts +1 -0
  74. package/dist/types/providers/ark.d.ts +62 -26
  75. package/dist/types/providers/errors.d.ts +13 -0
  76. package/dist/types/providers/expoIndexer.d.ts +2 -10
  77. package/dist/types/providers/expoUtils.d.ts +18 -0
  78. package/dist/types/providers/indexer.d.ts +1 -9
  79. package/dist/types/providers/onchain.d.ts +6 -2
  80. package/dist/types/repositories/walletRepository.d.ts +9 -5
  81. package/dist/types/script/base.d.ts +5 -2
  82. package/dist/types/tree/signingSession.d.ts +16 -11
  83. package/dist/types/utils/anchor.d.ts +2 -2
  84. package/dist/types/utils/arkTransaction.d.ts +12 -4
  85. package/dist/types/utils/transaction.d.ts +13 -0
  86. package/dist/types/utils/unknownFields.d.ts +4 -4
  87. package/dist/types/wallet/index.d.ts +6 -4
  88. package/dist/types/wallet/onchain.d.ts +1 -1
  89. package/dist/types/wallet/serviceWorker/response.d.ts +16 -2
  90. package/dist/types/wallet/serviceWorker/utils.d.ts +1 -0
  91. package/dist/types/wallet/serviceWorker/wallet.d.ts +2 -2
  92. package/dist/types/wallet/serviceWorker/worker.d.ts +7 -1
  93. package/dist/types/wallet/unroll.d.ts +1 -1
  94. package/dist/types/wallet/utils.d.ts +2 -1
  95. package/dist/types/wallet/vtxo-manager.d.ts +179 -0
  96. package/dist/types/wallet/wallet.d.ts +8 -4
  97. package/package.json +1 -2
  98. package/dist/cjs/bip322/errors.js +0 -13
  99. package/dist/esm/bip322/errors.js +0 -9
  100. package/dist/types/bip322/errors.d.ts +0 -6
  101. package/dist/types/bip322/index.d.ts +0 -57
@@ -4,6 +4,7 @@ exports.RestArkProvider = exports.SettlementEventType = void 0;
4
4
  exports.isFetchTimeoutError = isFetchTimeoutError;
5
5
  const base_1 = require("@scure/base");
6
6
  const utils_1 = require("./utils");
7
+ const errors_1 = require("./errors");
7
8
  var SettlementEventType;
8
9
  (function (SettlementEventType) {
9
10
  SettlementEventType["BatchStarted"] = "batch_started";
@@ -11,7 +12,7 @@ var SettlementEventType;
11
12
  SettlementEventType["BatchFinalized"] = "batch_finalized";
12
13
  SettlementEventType["BatchFailed"] = "batch_failed";
13
14
  SettlementEventType["TreeSigningStarted"] = "tree_signing_started";
14
- SettlementEventType["TreeNoncesAggregated"] = "tree_nonces_aggregated";
15
+ SettlementEventType["TreeNonces"] = "tree_nonces";
15
16
  SettlementEventType["TreeTx"] = "tree_tx";
16
17
  SettlementEventType["TreeSignature"] = "tree_signature";
17
18
  })(SettlementEventType || (exports.SettlementEventType = SettlementEventType = {}));
@@ -32,29 +33,41 @@ class RestArkProvider {
32
33
  const url = `${this.serverUrl}/v1/info`;
33
34
  const response = await fetch(url);
34
35
  if (!response.ok) {
35
- throw new Error(`Failed to get server info: ${response.statusText}`);
36
+ const errorText = await response.text();
37
+ handleError(errorText, `Failed to get server info: ${response.statusText}`);
36
38
  }
37
39
  const fromServer = await response.json();
38
40
  return {
39
- ...fromServer,
40
- vtxoTreeExpiry: BigInt(fromServer.vtxoTreeExpiry ?? 0),
41
- unilateralExitDelay: BigInt(fromServer.unilateralExitDelay ?? 0),
42
- roundInterval: BigInt(fromServer.roundInterval ?? 0),
43
- dust: BigInt(fromServer.dust ?? 0),
44
- utxoMinAmount: BigInt(fromServer.utxoMinAmount ?? 0),
45
- utxoMaxAmount: BigInt(fromServer.utxoMaxAmount ?? -1),
46
- vtxoMinAmount: BigInt(fromServer.vtxoMinAmount ?? 0),
47
- vtxoMaxAmount: BigInt(fromServer.vtxoMaxAmount ?? -1),
48
41
  boardingExitDelay: BigInt(fromServer.boardingExitDelay ?? 0),
49
- checkpointExitClosure: fromServer.checkpointTapscript ?? "",
50
- marketHour: "marketHour" in fromServer && fromServer.marketHour != null
42
+ checkpointTapscript: fromServer.checkpointTapscript ?? "",
43
+ deprecatedSigners: fromServer.deprecatedSigners?.map((signer) => ({
44
+ cutoffDate: BigInt(signer.cutoffDate ?? 0),
45
+ pubkey: signer.pubkey ?? "",
46
+ })) ?? [],
47
+ digest: fromServer.digest ?? "",
48
+ dust: BigInt(fromServer.dust ?? 0),
49
+ fees: fromServer.fees,
50
+ forfeitAddress: fromServer.forfeitAddress ?? "",
51
+ forfeitPubkey: fromServer.forfeitPubkey ?? "",
52
+ network: fromServer.network ?? "",
53
+ scheduledSession: "scheduledSession" in fromServer &&
54
+ fromServer.scheduledSession != null
51
55
  ? {
52
- nextStartTime: BigInt(fromServer.marketHour.nextStartTime ?? 0),
53
- nextEndTime: BigInt(fromServer.marketHour.nextEndTime ?? 0),
54
- period: BigInt(fromServer.marketHour.period ?? 0),
55
- roundInterval: BigInt(fromServer.marketHour.roundInterval ?? 0),
56
+ duration: BigInt(fromServer.scheduledSession.duration ?? 0),
57
+ nextStartTime: BigInt(fromServer.scheduledSession.nextStartTime ?? 0),
58
+ nextEndTime: BigInt(fromServer.scheduledSession.nextEndTime ?? 0),
59
+ period: BigInt(fromServer.scheduledSession.period ?? 0),
56
60
  }
57
61
  : undefined,
62
+ serviceStatus: fromServer.serviceStatus ?? {},
63
+ sessionDuration: BigInt(fromServer.sessionDuration ?? 0),
64
+ signerPubkey: fromServer.signerPubkey ?? "",
65
+ unilateralExitDelay: BigInt(fromServer.unilateralExitDelay ?? 0),
66
+ utxoMaxAmount: BigInt(fromServer.utxoMaxAmount ?? -1),
67
+ utxoMinAmount: BigInt(fromServer.utxoMinAmount ?? 0),
68
+ version: fromServer.version ?? "",
69
+ vtxoMaxAmount: BigInt(fromServer.vtxoMaxAmount ?? -1),
70
+ vtxoMinAmount: BigInt(fromServer.vtxoMinAmount ?? 0),
58
71
  };
59
72
  }
60
73
  async submitTx(signedArkTx, checkpointTxs) {
@@ -65,22 +78,13 @@ class RestArkProvider {
65
78
  "Content-Type": "application/json",
66
79
  },
67
80
  body: JSON.stringify({
68
- signedArkTx: signedArkTx,
69
- checkpointTxs: checkpointTxs,
81
+ signedArkTx,
82
+ checkpointTxs,
70
83
  }),
71
84
  });
72
85
  if (!response.ok) {
73
86
  const errorText = await response.text();
74
- try {
75
- const grpcError = JSON.parse(errorText);
76
- // gRPC errors usually have a message and code field
77
- throw new Error(`Failed to submit virtual transaction: ${grpcError.message || grpcError.error || errorText}`);
78
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
79
- }
80
- catch (_) {
81
- // If JSON parse fails, use the raw error text
82
- throw new Error(`Failed to submit virtual transaction: ${errorText}`);
83
- }
87
+ handleError(errorText, `Failed to submit virtual transaction: ${errorText}`);
84
88
  }
85
89
  const data = await response.json();
86
90
  return {
@@ -103,7 +107,7 @@ class RestArkProvider {
103
107
  });
104
108
  if (!response.ok) {
105
109
  const errorText = await response.text();
106
- throw new Error(`Failed to finalize offchain transaction: ${errorText}`);
110
+ handleError(errorText, `Failed to finalize offchain transaction: ${errorText}`);
107
111
  }
108
112
  }
109
113
  async registerIntent(intent) {
@@ -115,14 +119,14 @@ class RestArkProvider {
115
119
  },
116
120
  body: JSON.stringify({
117
121
  intent: {
118
- signature: intent.signature,
122
+ proof: intent.proof,
119
123
  message: intent.message,
120
124
  },
121
125
  }),
122
126
  });
123
127
  if (!response.ok) {
124
128
  const errorText = await response.text();
125
- throw new Error(`Failed to register intent: ${errorText}`);
129
+ handleError(errorText, `Failed to register intent: ${errorText}`);
126
130
  }
127
131
  const data = await response.json();
128
132
  return data.intentId;
@@ -136,14 +140,14 @@ class RestArkProvider {
136
140
  },
137
141
  body: JSON.stringify({
138
142
  proof: {
139
- signature: intent.signature,
143
+ proof: intent.proof,
140
144
  message: intent.message,
141
145
  },
142
146
  }),
143
147
  });
144
148
  if (!response.ok) {
145
149
  const errorText = await response.text();
146
- throw new Error(`Failed to delete intent: ${errorText}`);
150
+ handleError(errorText, `Failed to delete intent: ${errorText}`);
147
151
  }
148
152
  }
149
153
  async confirmRegistration(intentId) {
@@ -159,7 +163,7 @@ class RestArkProvider {
159
163
  });
160
164
  if (!response.ok) {
161
165
  const errorText = await response.text();
162
- throw new Error(`Failed to confirm registration: ${errorText}`);
166
+ handleError(errorText, `Failed to confirm registration: ${errorText}`);
163
167
  }
164
168
  }
165
169
  async submitTreeNonces(batchId, pubkey, nonces) {
@@ -177,7 +181,7 @@ class RestArkProvider {
177
181
  });
178
182
  if (!response.ok) {
179
183
  const errorText = await response.text();
180
- throw new Error(`Failed to submit tree nonces: ${errorText}`);
184
+ handleError(errorText, `Failed to submit tree nonces: ${errorText}`);
181
185
  }
182
186
  }
183
187
  async submitTreeSignatures(batchId, pubkey, signatures) {
@@ -195,7 +199,7 @@ class RestArkProvider {
195
199
  });
196
200
  if (!response.ok) {
197
201
  const errorText = await response.text();
198
- throw new Error(`Failed to submit tree signatures: ${errorText}`);
202
+ handleError(errorText, `Failed to submit tree signatures: ${errorText}`);
199
203
  }
200
204
  }
201
205
  async submitSignedForfeitTxs(signedForfeitTxs, signedCommitmentTx) {
@@ -211,7 +215,8 @@ class RestArkProvider {
211
215
  }),
212
216
  });
213
217
  if (!response.ok) {
214
- throw new Error(`Failed to submit forfeit transactions: ${response.statusText}`);
218
+ const errorText = await response.text();
219
+ handleError(errorText, `Failed to submit forfeit transactions: ${response.statusText}`);
215
220
  }
216
221
  }
217
222
  async *getEventStream(signal, topics) {
@@ -309,6 +314,22 @@ class RestArkProvider {
309
314
  }
310
315
  }
311
316
  }
317
+ async getPendingTxs(intent) {
318
+ const url = `${this.serverUrl}/v1/tx/pending`;
319
+ const response = await fetch(url, {
320
+ method: "POST",
321
+ headers: {
322
+ "Content-Type": "application/json",
323
+ },
324
+ body: JSON.stringify({ intent }),
325
+ });
326
+ if (!response.ok) {
327
+ const errorText = await response.text();
328
+ handleError(errorText, `Failed to get pending transactions: ${errorText}`);
329
+ }
330
+ const data = await response.json();
331
+ return data.pendingTxs;
332
+ }
312
333
  parseSettlementEvent(data) {
313
334
  // Check for BatchStarted event
314
335
  if (data.batchStarted) {
@@ -354,10 +375,16 @@ class RestArkProvider {
354
375
  }
355
376
  // Check for TreeNoncesAggregated event
356
377
  if (data.treeNoncesAggregated) {
378
+ // skip treeNoncesAggregated event, deprecated
379
+ return null;
380
+ }
381
+ if (data.treeNonces) {
357
382
  return {
358
- type: SettlementEventType.TreeNoncesAggregated,
359
- id: data.treeNoncesAggregated.id,
360
- treeNonces: decodeMusig2Nonces(data.treeNoncesAggregated.treeNonces),
383
+ type: SettlementEventType.TreeNonces,
384
+ id: data.treeNonces.id,
385
+ topic: data.treeNonces.topic,
386
+ txid: data.treeNonces.txid,
387
+ nonces: decodeMusig2Nonces(data.treeNonces.nonces), // pubkey -> public nonce
361
388
  };
362
389
  }
363
390
  // Check for TreeTx event
@@ -431,17 +458,16 @@ function encodeMusig2Nonces(nonces) {
431
458
  for (const [txid, nonce] of nonces) {
432
459
  noncesObject[txid] = base_1.hex.encode(nonce.pubNonce);
433
460
  }
434
- return JSON.stringify(noncesObject);
461
+ return noncesObject;
435
462
  }
436
463
  function encodeMusig2Signatures(signatures) {
437
464
  const sigObject = {};
438
465
  for (const [txid, sig] of signatures) {
439
466
  sigObject[txid] = base_1.hex.encode(sig.encode());
440
467
  }
441
- return JSON.stringify(sigObject);
468
+ return sigObject;
442
469
  }
443
- function decodeMusig2Nonces(str) {
444
- const noncesObject = JSON.parse(str);
470
+ function decodeMusig2Nonces(noncesObject) {
445
471
  return new Map(Object.entries(noncesObject).map(([txid, nonce]) => {
446
472
  if (typeof nonce !== "string") {
447
473
  throw new Error("invalid nonce");
@@ -483,3 +509,8 @@ function mapVtxo(vtxo) {
483
509
  arkTxid: vtxo.arkTxid,
484
510
  };
485
511
  }
512
+ function handleError(errorText, defaultMessage) {
513
+ const error = new Error(errorText);
514
+ const arkError = (0, errors_1.maybeArkError)(error);
515
+ throw arkError ?? new Error(defaultMessage);
516
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ArkError = void 0;
4
+ exports.maybeArkError = maybeArkError;
5
+ class ArkError extends Error {
6
+ constructor(code, message, name, metadata) {
7
+ super(message);
8
+ this.code = code;
9
+ this.message = message;
10
+ this.name = name;
11
+ this.metadata = metadata;
12
+ }
13
+ }
14
+ exports.ArkError = ArkError;
15
+ /**
16
+ * Try to convert an error to an ArkError class, returning undefined if the error is not an ArkError
17
+ * @param error - The error to parse
18
+ * @returns The parsed ArkError, or undefined if the error is not an ArkError
19
+ */
20
+ function maybeArkError(error) {
21
+ try {
22
+ if (!(error instanceof Error))
23
+ return undefined;
24
+ const decoded = JSON.parse(error.message);
25
+ if (!("details" in decoded))
26
+ return undefined;
27
+ if (!Array.isArray(decoded.details))
28
+ return undefined;
29
+ // search for a valid details object with the correct type
30
+ for (const details of decoded.details) {
31
+ if (!("@type" in details))
32
+ continue;
33
+ const type = details["@type"];
34
+ if (type !== "type.googleapis.com/ark.v1.ErrorDetails")
35
+ continue;
36
+ if (!("code" in details))
37
+ continue;
38
+ const code = details.code;
39
+ if (!("message" in details))
40
+ continue;
41
+ const message = details.message;
42
+ if (!("name" in details))
43
+ continue;
44
+ const name = details.name;
45
+ let metadata;
46
+ if ("metadata" in details && isMetadata(details.metadata)) {
47
+ metadata = details.metadata;
48
+ }
49
+ return new ArkError(code, message, name, metadata);
50
+ }
51
+ return undefined;
52
+ }
53
+ catch (e) {
54
+ return undefined;
55
+ }
56
+ }
57
+ function isMetadata(value) {
58
+ return typeof value === "object" && value !== null && !Array.isArray(value);
59
+ }
@@ -1,40 +1,8 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.ExpoArkProvider = void 0;
37
4
  const ark_1 = require("./ark");
5
+ const expoUtils_1 = require("./expoUtils");
38
6
  /**
39
7
  * Expo-compatible Ark provider implementation using expo/fetch for SSE support.
40
8
  * This provider works specifically in React Native/Expo environments where
@@ -53,87 +21,23 @@ class ExpoArkProvider extends ark_1.RestArkProvider {
53
21
  super(serverUrl);
54
22
  }
55
23
  async *getEventStream(signal, topics) {
56
- // Dynamic import to avoid bundling expo/fetch in non-Expo environments
57
- let expoFetch = fetch; // Default to standard fetch
58
- try {
59
- const expoFetchModule = await Promise.resolve().then(() => __importStar(require("expo/fetch")));
60
- // expo/fetch returns a compatible fetch function but with different types
61
- expoFetch = expoFetchModule.fetch;
62
- console.debug("Using expo/fetch for SSE");
63
- }
64
- catch (error) {
65
- // Fall back to standard fetch if expo/fetch is not available
66
- console.warn("Using standard fetch instead of expo/fetch. " +
67
- "Streaming may not be fully supported in some environments.", error);
68
- }
24
+ const expoFetch = await (0, expoUtils_1.getExpoFetch)();
69
25
  const url = `${this.serverUrl}/v1/batch/events`;
70
26
  const queryParams = topics.length > 0
71
27
  ? `?${topics.map((topic) => `topics=${encodeURIComponent(topic)}`).join("&")}`
72
28
  : "";
73
29
  while (!signal?.aborted) {
74
- // Create a new AbortController for this specific fetch attempt
75
- // to prevent accumulating listeners on the parent signal
76
- const fetchController = new AbortController();
77
- const cleanup = () => fetchController.abort();
78
- signal?.addEventListener("abort", cleanup, { once: true });
79
30
  try {
80
- const response = await expoFetch(url + queryParams, {
81
- headers: {
82
- Accept: "text/event-stream",
83
- },
84
- signal: fetchController.signal,
85
- });
86
- if (!response.ok) {
87
- throw new Error(`Unexpected status ${response.status} when fetching event stream`);
88
- }
89
- if (!response.body) {
90
- throw new Error("Response body is null");
91
- }
92
- const reader = response.body.getReader();
93
- const decoder = new TextDecoder();
94
- let buffer = "";
95
- while (!signal?.aborted) {
96
- const { done, value } = await reader.read();
97
- if (done) {
98
- break;
99
- }
100
- // Append new data to buffer and split by newlines
101
- buffer += decoder.decode(value, { stream: true });
102
- const lines = buffer.split("\n");
103
- // Process all complete lines
104
- for (let i = 0; i < lines.length - 1; i++) {
105
- const line = lines[i].trim();
106
- if (!line)
107
- continue;
108
- try {
109
- // Parse SSE format: "data: {json}"
110
- if (line.startsWith("data:")) {
111
- const jsonStr = line.substring(5).trim();
112
- if (!jsonStr)
113
- continue;
114
- const data = JSON.parse(jsonStr);
115
- // Handle different response structures
116
- // v8 mesh API might wrap in {result: ...} or send directly
117
- const eventData = data.result || data;
118
- // Skip heartbeat messages
119
- if (eventData.heartbeat !== undefined) {
120
- continue;
121
- }
122
- const event = this.parseSettlementEvent(eventData);
123
- if (event) {
124
- yield event;
125
- }
126
- }
127
- }
128
- catch (err) {
129
- console.error("Failed to parse event:", line);
130
- console.error("Parse error:", err);
131
- throw err;
132
- }
31
+ yield* (0, expoUtils_1.sseStreamIterator)(url + queryParams, signal, expoFetch, {}, (data) => {
32
+ // Handle different response structures
33
+ // v8 mesh API might wrap in {result: ...} or send directly
34
+ const eventData = data.result || data;
35
+ // Skip heartbeat messages
36
+ if (eventData.heartbeat !== undefined) {
37
+ return null;
133
38
  }
134
- // Keep the last partial line in the buffer
135
- buffer = lines[lines.length - 1];
136
- }
39
+ return this.parseSettlementEvent(eventData);
40
+ });
137
41
  }
138
42
  catch (error) {
139
43
  if (error instanceof Error && error.name === "AbortError") {
@@ -148,71 +52,16 @@ class ExpoArkProvider extends ark_1.RestArkProvider {
148
52
  console.error("Event stream error:", error);
149
53
  throw error;
150
54
  }
151
- finally {
152
- // Clean up the abort listener
153
- signal?.removeEventListener("abort", cleanup);
154
- }
155
55
  }
156
56
  }
157
57
  async *getTransactionsStream(signal) {
158
- // Dynamic import to avoid bundling expo/fetch in non-Expo environments
159
- let expoFetch = fetch; // Default to standard fetch
160
- try {
161
- const expoFetchModule = await Promise.resolve().then(() => __importStar(require("expo/fetch")));
162
- // expo/fetch returns a compatible fetch function but with different types
163
- expoFetch = expoFetchModule.fetch;
164
- console.debug("Using expo/fetch for transaction stream");
165
- }
166
- catch (error) {
167
- // Fall back to standard fetch if expo/fetch is not available
168
- console.warn("Using standard fetch instead of expo/fetch. " +
169
- "Streaming may not be fully supported in some environments.", error);
170
- }
58
+ const expoFetch = await (0, expoUtils_1.getExpoFetch)();
171
59
  const url = `${this.serverUrl}/v1/txs`;
172
60
  while (!signal?.aborted) {
173
- // Create a new AbortController for this specific fetch attempt
174
- // to prevent accumulating listeners on the parent signal
175
- const fetchController = new AbortController();
176
- const cleanup = () => fetchController.abort();
177
- signal?.addEventListener("abort", cleanup, { once: true });
178
61
  try {
179
- const response = await expoFetch(url, {
180
- headers: {
181
- Accept: "text/event-stream",
182
- },
183
- signal: fetchController.signal,
62
+ yield* (0, expoUtils_1.sseStreamIterator)(url, signal, expoFetch, {}, (data) => {
63
+ return this.parseTransactionNotification(data.result);
184
64
  });
185
- if (!response.ok) {
186
- throw new Error(`Unexpected status ${response.status} when fetching transaction stream`);
187
- }
188
- if (!response.body) {
189
- throw new Error("Response body is null");
190
- }
191
- const reader = response.body.getReader();
192
- const decoder = new TextDecoder();
193
- let buffer = "";
194
- while (!signal?.aborted) {
195
- const { done, value } = await reader.read();
196
- if (done) {
197
- break;
198
- }
199
- // Append new data to buffer and split by newlines
200
- buffer += decoder.decode(value, { stream: true });
201
- const lines = buffer.split("\n");
202
- // Process all complete lines
203
- for (let i = 0; i < lines.length - 1; i++) {
204
- const line = lines[i].trim();
205
- if (!line)
206
- continue;
207
- const data = JSON.parse(line);
208
- const txNotification = this.parseTransactionNotification(data.result);
209
- if (txNotification) {
210
- yield txNotification;
211
- }
212
- }
213
- // Keep the last partial line in the buffer
214
- buffer = lines[lines.length - 1];
215
- }
216
65
  }
217
66
  catch (error) {
218
67
  if (error instanceof Error && error.name === "AbortError") {
@@ -224,13 +73,9 @@ class ExpoArkProvider extends ark_1.RestArkProvider {
224
73
  console.debug("Timeout error ignored");
225
74
  continue;
226
75
  }
227
- console.error("Address subscription error:", error);
76
+ console.error("Transaction stream error:", error);
228
77
  throw error;
229
78
  }
230
- finally {
231
- // Clean up the abort listener
232
- signal?.removeEventListener("abort", cleanup);
233
- }
234
79
  }
235
80
  }
236
81
  }