@arkade-os/sdk 0.5.0-rc.2 → 0.5.0-rc.21

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 (126) hide show
  1. package/README.md +90 -83
  2. package/dist/adapters/expo.cjs +5 -6
  3. package/dist/adapters/expo.d.cts +4 -4
  4. package/dist/adapters/expo.d.ts +4 -4
  5. package/dist/adapters/expo.js +3 -4
  6. package/dist/{asyncStorageTaskQueue-C5rBYlru.d.ts → asyncStorageTaskQueue-aL7K14e4.d.ts} +2 -2
  7. package/dist/{asyncStorageTaskQueue-BuDvgWh6.d.cts → asyncStorageTaskQueue-x8ok3tJy.d.cts} +2 -2
  8. package/dist/{chunk-ISO4TI5J.js → chunk-4FDNOLBO.js} +566 -459
  9. package/dist/chunk-4FDNOLBO.js.map +1 -0
  10. package/dist/{chunk-JZWLXNHV.cjs → chunk-5XBH5SAL.cjs} +574 -464
  11. package/dist/chunk-5XBH5SAL.cjs.map +1 -0
  12. package/dist/{chunk-3R476TDV.js → chunk-CXHJGED6.js} +293 -1071
  13. package/dist/chunk-CXHJGED6.js.map +1 -0
  14. package/dist/{chunk-ZRNQV6HV.js → chunk-EXFU6MTA.js} +4578 -4396
  15. package/dist/chunk-EXFU6MTA.js.map +1 -0
  16. package/dist/{chunk-43FKNLX4.cjs → chunk-GVF4OCTL.cjs} +357 -1114
  17. package/dist/chunk-GVF4OCTL.cjs.map +1 -0
  18. package/dist/{chunk-HLCGYOIH.cjs → chunk-HIZNPHB2.cjs} +37 -36
  19. package/dist/chunk-HIZNPHB2.cjs.map +1 -0
  20. package/dist/{chunk-4PKLULWT.js → chunk-JZAEFOE4.js} +109 -246
  21. package/dist/chunk-JZAEFOE4.js.map +1 -0
  22. package/dist/{chunk-ZOTXDOS5.js → chunk-LNJPVLIC.js} +30 -29
  23. package/dist/chunk-LNJPVLIC.js.map +1 -0
  24. package/dist/{chunk-NVZJSKZS.cjs → chunk-Q7PC3NHX.cjs} +121 -257
  25. package/dist/chunk-Q7PC3NHX.cjs.map +1 -0
  26. package/dist/{chunk-GMZZQXV5.cjs → chunk-R5OFJ23O.cjs} +4961 -4767
  27. package/dist/chunk-R5OFJ23O.cjs.map +1 -0
  28. package/dist/{chunk-6DNR46C7.js → chunk-S2WWOVFC.js} +7 -5
  29. package/dist/chunk-S2WWOVFC.js.map +1 -0
  30. package/dist/{chunk-D25O4EGY.cjs → chunk-VZMLADXQ.cjs} +12 -10
  31. package/dist/chunk-VZMLADXQ.cjs.map +1 -0
  32. package/dist/contracts/handlers/index.cjs +9 -10
  33. package/dist/contracts/handlers/index.d.cts +5 -5
  34. package/dist/contracts/handlers/index.d.ts +5 -5
  35. package/dist/contracts/handlers/index.js +2 -3
  36. package/dist/{delegate-BAX5QftB.d.ts → delegate-BT5iON1T.d.ts} +1 -1
  37. package/dist/{delegate-1yp1HyP7.d.cts → delegate-u6kXTtWY.d.cts} +1 -1
  38. package/dist/index-BCnhItOQ.d.cts +639 -0
  39. package/dist/{index-DUxufw76.d.cts → index-CK5QbTmZ.d.cts} +1387 -2404
  40. package/dist/{index-DUxufw76.d.ts → index-CK5QbTmZ.d.ts} +1387 -2404
  41. package/dist/index-D1D4cR-G.d.ts +639 -0
  42. package/dist/index.cjs +375 -340
  43. package/dist/index.d.cts +784 -1197
  44. package/dist/index.d.ts +784 -1197
  45. package/dist/index.js +4 -5
  46. package/dist/repositories/realm/index.cjs +201 -106
  47. package/dist/repositories/realm/index.cjs.map +1 -1
  48. package/dist/repositories/realm/index.d.cts +28 -16
  49. package/dist/repositories/realm/index.d.ts +28 -16
  50. package/dist/repositories/realm/index.js +190 -95
  51. package/dist/repositories/realm/index.js.map +1 -1
  52. package/dist/repositories/sqlite/index.cjs +301 -189
  53. package/dist/repositories/sqlite/index.cjs.map +1 -1
  54. package/dist/repositories/sqlite/index.d.cts +32 -21
  55. package/dist/repositories/sqlite/index.d.ts +32 -21
  56. package/dist/repositories/sqlite/index.js +294 -182
  57. package/dist/repositories/sqlite/index.js.map +1 -1
  58. package/dist/{taskRunner-D_iPiZIi.d.ts → taskRunner-BeYR6NpQ.d.ts} +2 -2
  59. package/dist/{taskRunner-Dr3NStc0.d.cts → taskRunner-Csey3EYJ.d.cts} +2 -2
  60. package/dist/wallet/expo/background.cjs +14 -15
  61. package/dist/wallet/expo/background.cjs.map +1 -1
  62. package/dist/wallet/expo/background.d.cts +10 -16
  63. package/dist/wallet/expo/background.d.ts +10 -16
  64. package/dist/wallet/expo/background.js +6 -7
  65. package/dist/wallet/expo/background.js.map +1 -1
  66. package/dist/wallet/expo/index.cjs +16 -23
  67. package/dist/wallet/expo/index.cjs.map +1 -1
  68. package/dist/wallet/expo/index.d.cts +6 -9
  69. package/dist/wallet/expo/index.d.ts +6 -9
  70. package/dist/wallet/expo/index.js +8 -15
  71. package/dist/wallet/expo/index.js.map +1 -1
  72. package/dist/wallet-DG3Qmbmt.d.cts +1848 -0
  73. package/dist/wallet-DzSLMxBZ.d.ts +1848 -0
  74. package/dist/worker/expo/index.cjs +9 -10
  75. package/dist/worker/expo/index.cjs.map +1 -1
  76. package/dist/worker/expo/index.d.cts +6 -6
  77. package/dist/worker/expo/index.d.ts +6 -6
  78. package/dist/worker/expo/index.js +5 -6
  79. package/dist/worker/expo/index.js.map +1 -1
  80. package/package.json +12 -51
  81. package/dist/adapters/asyncStorage.cjs +0 -48
  82. package/dist/adapters/asyncStorage.cjs.map +0 -1
  83. package/dist/adapters/asyncStorage.d.cts +0 -16
  84. package/dist/adapters/asyncStorage.d.ts +0 -16
  85. package/dist/adapters/asyncStorage.js +0 -46
  86. package/dist/adapters/asyncStorage.js.map +0 -1
  87. package/dist/adapters/fileSystem.cjs +0 -116
  88. package/dist/adapters/fileSystem.cjs.map +0 -1
  89. package/dist/adapters/fileSystem.d.cts +0 -17
  90. package/dist/adapters/fileSystem.d.ts +0 -17
  91. package/dist/adapters/fileSystem.js +0 -93
  92. package/dist/adapters/fileSystem.js.map +0 -1
  93. package/dist/adapters/indexedDB.cjs +0 -103
  94. package/dist/adapters/indexedDB.cjs.map +0 -1
  95. package/dist/adapters/indexedDB.d.cts +0 -18
  96. package/dist/adapters/indexedDB.d.ts +0 -18
  97. package/dist/adapters/indexedDB.js +0 -101
  98. package/dist/adapters/indexedDB.js.map +0 -1
  99. package/dist/adapters/localStorage.cjs +0 -50
  100. package/dist/adapters/localStorage.cjs.map +0 -1
  101. package/dist/adapters/localStorage.d.cts +0 -14
  102. package/dist/adapters/localStorage.d.ts +0 -14
  103. package/dist/adapters/localStorage.js +0 -48
  104. package/dist/adapters/localStorage.js.map +0 -1
  105. package/dist/chunk-3R476TDV.js.map +0 -1
  106. package/dist/chunk-43FKNLX4.cjs.map +0 -1
  107. package/dist/chunk-4PKLULWT.js.map +0 -1
  108. package/dist/chunk-5BLDMQED.cjs +0 -18
  109. package/dist/chunk-5BLDMQED.cjs.map +0 -1
  110. package/dist/chunk-6DNR46C7.js.map +0 -1
  111. package/dist/chunk-D25O4EGY.cjs.map +0 -1
  112. package/dist/chunk-GMZZQXV5.cjs.map +0 -1
  113. package/dist/chunk-HLCGYOIH.cjs.map +0 -1
  114. package/dist/chunk-ISO4TI5J.js.map +0 -1
  115. package/dist/chunk-JZWLXNHV.cjs.map +0 -1
  116. package/dist/chunk-NSBPE2FW.js +0 -15
  117. package/dist/chunk-NSBPE2FW.js.map +0 -1
  118. package/dist/chunk-NVZJSKZS.cjs.map +0 -1
  119. package/dist/chunk-ZOTXDOS5.js.map +0 -1
  120. package/dist/chunk-ZRNQV6HV.js.map +0 -1
  121. package/dist/hdWalletCapable-CmEU0NP1.d.ts +0 -2232
  122. package/dist/hdWalletCapable-eJgaT-ec.d.cts +0 -2232
  123. package/dist/index-Bem5vKzX.d.ts +0 -850
  124. package/dist/index-C0IanN1m.d.cts +0 -11
  125. package/dist/index-C0IanN1m.d.ts +0 -11
  126. package/dist/index-W_oMcOmG.d.cts +0 -850
@@ -1,10 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkGMZZQXV5_cjs = require('../../chunk-GMZZQXV5.cjs');
4
- require('../../chunk-NVZJSKZS.cjs');
5
- require('../../chunk-43FKNLX4.cjs');
6
- require('../../chunk-JZWLXNHV.cjs');
7
- require('../../chunk-5BLDMQED.cjs');
3
+ var chunkR5OFJ23O_cjs = require('../../chunk-R5OFJ23O.cjs');
4
+ require('../../chunk-Q7PC3NHX.cjs');
5
+ require('../../chunk-GVF4OCTL.cjs');
6
+ var chunk5XBH5SAL_cjs = require('../../chunk-5XBH5SAL.cjs');
8
7
 
9
8
  // src/repositories/sqlite/transaction.ts
10
9
  var writeChains = /* @__PURE__ */ new WeakMap();
@@ -31,11 +30,19 @@ function runInTransaction(db, fn) {
31
30
  return run;
32
31
  }
33
32
 
33
+ // src/repositories/sqlite/prefix.ts
34
+ var SAFE_PREFIX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
35
+ function sanitizeTablePrefix(p) {
36
+ if (!SAFE_PREFIX.test(p)) throw new Error(`Invalid table prefix "${p}"`);
37
+ return p;
38
+ }
39
+
34
40
  // src/repositories/sqlite/walletRepository.ts
41
+ var MAX_BOUND_PARAMETERS = 999;
35
42
  var SQLiteWalletRepository = class {
36
43
  constructor(db, options) {
37
44
  this.db = db;
38
- this.prefix = sanitizePrefix(options?.prefix ?? "ark_");
45
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
39
46
  this.tables = {
40
47
  vtxos: `${this.prefix}vtxos`,
41
48
  utxos: `${this.prefix}utxos`,
@@ -44,7 +51,7 @@ var SQLiteWalletRepository = class {
44
51
  };
45
52
  }
46
53
  db;
47
- version = 1;
54
+ version = 2;
48
55
  initPromise = null;
49
56
  prefix;
50
57
  tables;
@@ -100,23 +107,42 @@ var SQLiteWalletRepository = class {
100
107
  await this.db.run(
101
108
  `CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_script ON ${this.tables.vtxos} (script)`
102
109
  );
110
+ await this.db.run(
111
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_script_page ON ${this.tables.vtxos} (script, address, txid, vout)`
112
+ );
113
+ await this.db.run(
114
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_address_page ON ${this.tables.vtxos} (address, txid, vout)`
115
+ );
116
+ await this.db.run(`DROP INDEX IF EXISTS idx_${this.prefix}vtxos_live_script`);
117
+ await this.db.run(
118
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}vtxos_live_script_page ON ${this.tables.vtxos} (script, address, txid, vout)
119
+ WHERE ${UNSPENT_VTXO_PREDICATE}`
120
+ );
103
121
  await this.db.run(
104
122
  `CREATE INDEX IF NOT EXISTS idx_${this.prefix}utxos_address ON ${this.tables.utxos} (address)`
105
123
  );
124
+ await this.db.run(
125
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}utxos_address_page ON ${this.tables.utxos} (address, txid, vout)`
126
+ );
106
127
  await this.db.run(
107
128
  `CREATE INDEX IF NOT EXISTS idx_${this.prefix}transactions_address ON ${this.tables.transactions} (address)`
108
129
  );
130
+ await this.db.run(
131
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}transactions_history ON ${this.tables.transactions} (address, created_at, boarding_txid, commitment_txid, ark_txid)`
132
+ );
109
133
  }
110
134
  /**
111
135
  * Bring the `vtxos` table to the current schema (v1 = `script` NOT NULL).
112
136
  *
113
- * Three cases:
137
+ * Four cases:
114
138
  * - Fresh install: create the v1 schema directly.
115
139
  * - Legacy install without a `script` column: add it, backfill from
116
140
  * `address`, then rebuild the table with NOT NULL (SQLite cannot add
117
141
  * the NOT NULL constraint in place).
118
142
  * - Legacy install with a nullable `script` column: backfill the NULLs
119
143
  * and rebuild.
144
+ * - 0.4.x install: `script` is already NOT NULL but `virtual_status_json
145
+ * NOT NULL` is still there, and `saveVtxos` no longer writes it.
120
146
  *
121
147
  * The backfill derives `script` from the Ark address, matching what the
122
148
  * indexer would have returned — new rows from the indexer always carry a
@@ -144,7 +170,27 @@ var SQLiteWalletRepository = class {
144
170
  `PRAGMA table_info(${this.tables.vtxos})`
145
171
  );
146
172
  const scriptCol = cols.find((c) => c.name === "script");
147
- if (scriptCol && scriptCol.notnull === 1) {
173
+ const nullableCanonicalColumns = [
174
+ ["is_swept", "INTEGER"],
175
+ ["is_preconfirmed", "INTEGER"],
176
+ ["commitment_txids_json", "TEXT"],
177
+ ["expires_at", "TEXT"],
178
+ ["expires_at_height", "INTEGER"]
179
+ ];
180
+ let addedCanonicalColumns = false;
181
+ for (const [name, type] of nullableCanonicalColumns) {
182
+ if (!cols.some((c) => c.name === name)) {
183
+ await this.db.run(
184
+ `ALTER TABLE ${this.tables.vtxos} ADD COLUMN ${name} ${type}`
185
+ );
186
+ addedCanonicalColumns = true;
187
+ }
188
+ }
189
+ const hasLegacyBlob = cols.some((c) => c.name === "virtual_status_json");
190
+ if (addedCanonicalColumns && hasLegacyBlob) {
191
+ await this.backfillCanonicalVtxoColumns();
192
+ }
193
+ if (scriptCol && scriptCol.notnull === 1 && !hasLegacyBlob) {
148
194
  return;
149
195
  }
150
196
  if (!scriptCol) {
@@ -154,7 +200,7 @@ var SQLiteWalletRepository = class {
154
200
  for (const row of nullRows) {
155
201
  await this.db.run(
156
202
  `UPDATE ${this.tables.vtxos} SET script = ? WHERE txid = ? AND vout = ?`,
157
- [chunkGMZZQXV5_cjs.scriptFromArkAddress(row.address), row.txid, row.vout]
203
+ [chunkR5OFJ23O_cjs.scriptFromArkAddress(row.address), row.txid, row.vout]
158
204
  );
159
205
  }
160
206
  const tempName = `${this.tables.vtxos}__migrate_tmp`;
@@ -164,20 +210,58 @@ var SQLiteWalletRepository = class {
164
210
  INSERT INTO ${tempName}
165
211
  (txid, vout, value, address, tap_tree,
166
212
  forfeit_cb, forfeit_s, intent_cb, intent_s,
167
- status_json, virtual_status_json, created_at,
168
- is_unrolled, is_spent, spent_by, settled_by, ark_tx_id,
169
- extra_witness_json, assets_json, script)
213
+ status_json, created_at, is_unrolled, is_spent,
214
+ is_swept, is_preconfirmed, commitment_txids_json,
215
+ expires_at, expires_at_height,
216
+ spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script)
170
217
  SELECT txid, vout, value, address, tap_tree,
171
218
  forfeit_cb, forfeit_s, intent_cb, intent_s,
172
- status_json, virtual_status_json, created_at,
173
- is_unrolled, is_spent, spent_by, settled_by, ark_tx_id,
174
- extra_witness_json, assets_json, script
219
+ status_json, created_at, is_unrolled, is_spent,
220
+ is_swept, is_preconfirmed, commitment_txids_json,
221
+ expires_at, expires_at_height,
222
+ spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script
175
223
  FROM ${this.tables.vtxos}
176
224
  `);
177
225
  await this.db.run(`DROP TABLE ${this.tables.vtxos}`);
178
226
  await this.db.run(`ALTER TABLE ${tempName} RENAME TO ${this.tables.vtxos}`);
179
227
  });
180
228
  }
229
+ /**
230
+ * Copy the canonical VTXO facts out of the legacy `virtual_status_json` blob.
231
+ *
232
+ * Scoped to rows that still have `is_swept` NULL, which is what "never backfilled" looks
233
+ * like: the copy writes 0 or 1 to every row it touches, so a second pass — a later column
234
+ * addition, say — cannot overwrite what an indexer sync has since corrected. Rows whose blob
235
+ * is missing or corrupt are left alone: a migration must not be stopped by one bad row, and
236
+ * the next sync repairs it.
237
+ */
238
+ async backfillCanonicalVtxoColumns() {
239
+ const rows = await this.db.all(
240
+ `SELECT txid, vout, virtual_status_json FROM ${this.tables.vtxos}
241
+ WHERE virtual_status_json IS NOT NULL AND is_swept IS NULL`
242
+ );
243
+ for (const row of rows) {
244
+ const facts = chunkR5OFJ23O_cjs.legacyVtxoFacts(row.virtual_status_json);
245
+ if (!facts) continue;
246
+ await this.db.run(
247
+ `UPDATE ${this.tables.vtxos}
248
+ SET is_swept = ?, is_preconfirmed = ?, commitment_txids_json = ?,
249
+ expires_at = ?, expires_at_height = ?,
250
+ is_spent = COALESCE(is_spent, ?)
251
+ WHERE txid = ? AND vout = ?`,
252
+ [
253
+ facts.isSwept ? 1 : 0,
254
+ facts.isPreconfirmed ? 1 : 0,
255
+ facts.commitmentTxIds ? JSON.stringify(facts.commitmentTxIds) : null,
256
+ facts.expiresAt ? facts.expiresAt.toISOString() : null,
257
+ facts.expiresAtHeight ?? null,
258
+ facts.isSpent ? 1 : 0,
259
+ row.txid,
260
+ row.vout
261
+ ]
262
+ );
263
+ }
264
+ }
181
265
  vtxosCreateSql(tableName) {
182
266
  return `CREATE TABLE ${tableName} (
183
267
  txid TEXT NOT NULL,
@@ -190,10 +274,14 @@ var SQLiteWalletRepository = class {
190
274
  intent_cb TEXT NOT NULL,
191
275
  intent_s TEXT NOT NULL,
192
276
  status_json TEXT NOT NULL,
193
- virtual_status_json TEXT NOT NULL,
194
277
  created_at TEXT NOT NULL,
195
278
  is_unrolled INTEGER NOT NULL DEFAULT 0,
196
279
  is_spent INTEGER,
280
+ is_swept INTEGER,
281
+ is_preconfirmed INTEGER,
282
+ commitment_txids_json TEXT,
283
+ expires_at TEXT,
284
+ expires_at_height INTEGER,
197
285
  spent_by TEXT,
198
286
  settled_by TEXT,
199
287
  ark_tx_id TEXT,
@@ -203,6 +291,23 @@ var SQLiteWalletRepository = class {
203
291
  PRIMARY KEY (txid, vout)
204
292
  )`;
205
293
  }
294
+ /**
295
+ * `INSERT OR REPLACE` rows, as many to a statement as the parameter budget allows.
296
+ * No enclosing transaction: on the shared connection it would take in other repos' writes.
297
+ */
298
+ async insertOrReplace(table, columns, rows) {
299
+ const width = columns.split(",").length;
300
+ const tuple = `(${Array(width).fill("?").join(", ")})`;
301
+ const rowsPerStatement = Math.floor(MAX_BOUND_PARAMETERS / width);
302
+ for (let i = 0; i < rows.length; i += rowsPerStatement) {
303
+ const chunk = rows.slice(i, i + rowsPerStatement);
304
+ await this.db.run(
305
+ `INSERT OR REPLACE INTO ${table} (${columns})
306
+ VALUES ${chunk.map(() => tuple).join(", ")}`,
307
+ chunk.flat()
308
+ );
309
+ }
310
+ }
206
311
  async [Symbol.asyncDispose]() {
207
312
  }
208
313
  // ── Clear ──────────────────────────────────────────────────────────
@@ -214,31 +319,22 @@ var SQLiteWalletRepository = class {
214
319
  await this.db.run(`DELETE FROM ${this.tables.walletState}`);
215
320
  }
216
321
  // ── VTXO management ────────────────────────────────────────────────
217
- async getVtxos(address) {
218
- await this.ensureInit();
219
- const rows = await this.db.all(
220
- `SELECT * FROM ${this.tables.vtxos} WHERE address = ?`,
221
- [address]
222
- );
223
- return rows.map(vtxoRowToDomain);
322
+ async getVtxosPage(address, page) {
323
+ return this.pageByAddress(this.tables.vtxos, address, page, vtxoRowToDomain);
224
324
  }
225
325
  async saveVtxos(address, vtxos) {
226
326
  await this.ensureInit();
227
- for (const vtxo of vtxos) {
228
- const s = chunkGMZZQXV5_cjs.serializeVtxo(vtxo);
229
- await this.db.run(
230
- `INSERT OR REPLACE INTO ${this.tables.vtxos}
231
- (txid, vout, value, address,
232
- tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
233
- status_json, virtual_status_json, created_at,
234
- is_unrolled, is_spent, spent_by, settled_by, ark_tx_id,
235
- extra_witness_json, assets_json, script)
236
- VALUES (?, ?, ?, ?,
237
- ?, ?, ?, ?, ?,
238
- ?, ?, ?,
239
- ?, ?, ?, ?, ?,
240
- ?, ?, ?)`,
241
- [
327
+ await this.insertOrReplace(
328
+ this.tables.vtxos,
329
+ `txid, vout, value, address,
330
+ tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
331
+ status_json, created_at, is_unrolled, is_spent,
332
+ is_swept, is_preconfirmed, commitment_txids_json,
333
+ expires_at, expires_at_height,
334
+ spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script`,
335
+ vtxos.map((vtxo) => {
336
+ const s = chunkR5OFJ23O_cjs.serializeVtxo(vtxo);
337
+ return [
242
338
  s.txid,
243
339
  s.vout,
244
340
  s.value,
@@ -249,71 +345,82 @@ var SQLiteWalletRepository = class {
249
345
  s.intentTapLeafScript.cb,
250
346
  s.intentTapLeafScript.s,
251
347
  JSON.stringify(s.status),
252
- JSON.stringify(s.virtualStatus),
253
- typeof s.createdAt === "string" ? s.createdAt : s.createdAt instanceof Date ? s.createdAt.toISOString() : new Date(s.createdAt).toISOString(),
348
+ chunkR5OFJ23O_cjs.createdAtToIso(s.createdAt),
254
349
  s.isUnrolled ? 1 : 0,
255
350
  s.isSpent === void 0 ? null : s.isSpent ? 1 : 0,
351
+ s.isSwept === void 0 ? null : s.isSwept ? 1 : 0,
352
+ s.isPreconfirmed === void 0 ? null : s.isPreconfirmed ? 1 : 0,
353
+ s.commitmentTxIds ? JSON.stringify(s.commitmentTxIds) : null,
354
+ s.expiresAt === void 0 ? null : new Date(s.expiresAt).toISOString(),
355
+ s.expiresAtHeight ?? null,
256
356
  s.spentBy ?? null,
257
357
  s.settledBy ?? null,
258
358
  s.arkTxId ?? null,
259
359
  s.extraWitness ? JSON.stringify(s.extraWitness) : null,
260
360
  s.assets ? JSON.stringify(s.assets) : null,
261
361
  s.script ?? null
262
- ]
263
- );
264
- }
362
+ ];
363
+ })
364
+ );
265
365
  }
266
366
  async deleteVtxos(address) {
267
367
  await this.ensureInit();
268
368
  await this.db.run(`DELETE FROM ${this.tables.vtxos} WHERE address = ?`, [address]);
269
369
  }
270
- async getVtxosForScript(script) {
370
+ async getVtxosForScriptPage(script, page, options) {
371
+ chunkR5OFJ23O_cjs.assertPageRequest(page);
271
372
  await this.ensureInit();
373
+ const after = page.after;
272
374
  const rows = await this.db.all(
273
- `SELECT * FROM ${this.tables.vtxos} WHERE script = ?`,
274
- [script]
375
+ `SELECT * FROM ${this.tables.vtxos} WHERE script = ?
376
+ ${options?.unspentOnly ? `AND ${UNSPENT_VTXO_PREDICATE}` : ""}
377
+ ${after ? "AND (address > ? OR (address = ? AND (txid > ? OR (txid = ? AND vout > ?))))" : ""}
378
+ ORDER BY address, txid, vout LIMIT ?`,
379
+ after ? [
380
+ script,
381
+ after.address,
382
+ after.address,
383
+ after.txid,
384
+ after.txid,
385
+ after.vout,
386
+ page.limit + 1
387
+ ] : [script, page.limit + 1]
275
388
  );
276
- return rows.map(vtxoRowToDomain);
389
+ const result = chunkR5OFJ23O_cjs.pageResult(
390
+ rows.map((row) => ({ address: row.address, vtxo: vtxoRowToDomain(row) })),
391
+ page.limit,
392
+ (row) => ({ address: row.address, txid: row.vtxo.txid, vout: row.vtxo.vout })
393
+ );
394
+ return options?.unspentOnly ? { ...result, items: result.items.filter((row) => !chunk5XBH5SAL_cjs.isVtxoSpent(row.vtxo)) } : result;
277
395
  }
278
396
  async saveVtxosForScript(key, vtxos) {
279
- if (!key.address) {
280
- throw new Error("SQLiteWalletRepository requires an address");
281
- }
282
- for (const vtxo of vtxos) {
283
- if (!chunkGMZZQXV5_cjs.isVtxoForScript(vtxo, key.script)) {
284
- throw new Error(
285
- `VTXO ${vtxo.txid}:${vtxo.vout} script mismatch: expected ${key.script}, got ${vtxo.script}`
286
- );
287
- }
288
- }
289
- return this.saveVtxos(key.address, vtxos);
397
+ return this.saveVtxos(chunkR5OFJ23O_cjs.checkSaveVtxosForScript("SQLiteWalletRepository", key, vtxos), vtxos);
290
398
  }
291
399
  async deleteVtxosForScript(script) {
292
400
  await this.ensureInit();
293
401
  await this.db.run(`DELETE FROM ${this.tables.vtxos} WHERE script = ?`, [script]);
294
402
  }
295
403
  // ── UTXO management ────────────────────────────────────────────────
296
- async getUtxos(address) {
404
+ async getUtxosPage(address, page) {
405
+ return this.pageByAddress(this.tables.utxos, address, page, utxoRowToDomain);
406
+ }
407
+ async pageByAddress(table, address, page, deserialize) {
408
+ chunkR5OFJ23O_cjs.assertPageRequest(page);
297
409
  await this.ensureInit();
298
410
  const rows = await this.db.all(
299
- `SELECT * FROM ${this.tables.utxos} WHERE address = ?`,
300
- [address]
411
+ `SELECT * FROM ${table} WHERE address = ? AND (txid, vout) > (?, ?)
412
+ ORDER BY txid, vout LIMIT ?`,
413
+ [address, page.after?.txid ?? "", page.after?.vout ?? -1, page.limit + 1]
301
414
  );
302
- return rows.map(utxoRowToDomain);
415
+ const result = chunkR5OFJ23O_cjs.pageResult(rows, page.limit, ({ txid, vout }) => ({ txid, vout }));
416
+ return { items: result.items.map(deserialize), nextCursor: result.nextCursor };
303
417
  }
304
- async saveUtxos(address, utxos) {
418
+ async saveUtxos(addressOrBatch, utxos) {
305
419
  await this.ensureInit();
306
- for (const utxo of utxos) {
307
- const s = chunkGMZZQXV5_cjs.serializeUtxo(utxo);
308
- await this.db.run(
309
- `INSERT OR REPLACE INTO ${this.tables.utxos}
310
- (txid, vout, value, address,
311
- tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
312
- status_json, extra_witness_json)
313
- VALUES (?, ?, ?, ?,
314
- ?, ?, ?, ?, ?,
315
- ?, ?)`,
316
- [
420
+ const rows = chunkR5OFJ23O_cjs.utxoEntries(addressOrBatch, utxos).flatMap(
421
+ ([address, list]) => list.map((utxo) => {
422
+ const s = chunkR5OFJ23O_cjs.serializeUtxo(utxo);
423
+ return [
317
424
  s.txid,
318
425
  s.vout,
319
426
  s.value,
@@ -325,45 +432,71 @@ var SQLiteWalletRepository = class {
325
432
  s.intentTapLeafScript.s,
326
433
  JSON.stringify(s.status),
327
434
  s.extraWitness ? JSON.stringify(s.extraWitness) : null
328
- ]
329
- );
330
- }
435
+ ];
436
+ })
437
+ );
438
+ await this.insertOrReplace(
439
+ this.tables.utxos,
440
+ `txid, vout, value, address,
441
+ tap_tree, forfeit_cb, forfeit_s, intent_cb, intent_s,
442
+ status_json, extra_witness_json`,
443
+ rows
444
+ );
331
445
  }
332
446
  async deleteUtxos(address) {
333
447
  await this.ensureInit();
334
448
  await this.db.run(`DELETE FROM ${this.tables.utxos} WHERE address = ?`, [address]);
335
449
  }
336
450
  // ── Transaction history ────────────────────────────────────────────
337
- async getTransactionHistory(address) {
451
+ async getTransactionHistoryPage(filter, page) {
452
+ chunkR5OFJ23O_cjs.assertPageRequest(page);
453
+ chunkR5OFJ23O_cjs.assertHistoryPageFilter(filter);
338
454
  await this.ensureInit();
455
+ const conditions = ["address = ?"];
456
+ const params = [filter.address];
457
+ if (filter.since !== void 0) {
458
+ conditions.push("created_at >= ?");
459
+ params.push(filter.since);
460
+ }
461
+ if (page.after !== void 0) {
462
+ conditions.push(
463
+ "(created_at, boarding_txid, commitment_txid, ark_txid) > (?, ?, ?, ?)"
464
+ );
465
+ params.push(
466
+ page.after.createdAt,
467
+ page.after.key.boardingTxid,
468
+ page.after.key.commitmentTxid,
469
+ page.after.key.arkTxid
470
+ );
471
+ }
339
472
  const rows = await this.db.all(
340
- `SELECT * FROM ${this.tables.transactions} WHERE address = ? ORDER BY created_at ASC`,
341
- [address]
473
+ `SELECT * FROM ${this.tables.transactions} WHERE ${conditions.join(" AND ")}
474
+ ORDER BY created_at, boarding_txid, commitment_txid, ark_txid LIMIT ?`,
475
+ [...params, page.limit + 1]
342
476
  );
343
- return rows.map(txRowToDomain);
477
+ return chunkR5OFJ23O_cjs.pageResult(rows.map(txRowToDomain), page.limit, (tx) => ({
478
+ createdAt: tx.createdAt,
479
+ key: tx.key
480
+ }));
344
481
  }
345
482
  async saveTransactions(address, txs) {
346
483
  await this.ensureInit();
347
- for (const tx of txs) {
348
- await this.db.run(
349
- `INSERT OR REPLACE INTO ${this.tables.transactions}
350
- (address, boarding_txid, commitment_txid, ark_txid,
351
- type, amount, settled, created_at, assets_json)
352
- VALUES (?, ?, ?, ?,
353
- ?, ?, ?, ?, ?)`,
354
- [
355
- address,
356
- tx.key.boardingTxid,
357
- tx.key.commitmentTxid,
358
- tx.key.arkTxid,
359
- tx.type,
360
- tx.amount,
361
- tx.settled ? 1 : 0,
362
- tx.createdAt,
363
- tx.assets ? JSON.stringify(chunkGMZZQXV5_cjs.serializeAssets(tx.assets)) : null
364
- ]
365
- );
366
- }
484
+ await this.insertOrReplace(
485
+ this.tables.transactions,
486
+ `address, boarding_txid, commitment_txid, ark_txid,
487
+ type, amount, settled, created_at, assets_json`,
488
+ txs.map((tx) => [
489
+ address,
490
+ tx.key.boardingTxid,
491
+ tx.key.commitmentTxid,
492
+ tx.key.arkTxid,
493
+ tx.type,
494
+ tx.amount,
495
+ tx.settled ? 1 : 0,
496
+ tx.createdAt,
497
+ tx.assets ? JSON.stringify(chunkR5OFJ23O_cjs.serializeAssets(tx.assets)) : null
498
+ ])
499
+ );
367
500
  }
368
501
  async deleteTransactions(address) {
369
502
  await this.ensureInit();
@@ -398,15 +531,7 @@ var SQLiteWalletRepository = class {
398
531
  );
399
532
  }
400
533
  };
401
- var SAFE_PREFIX = /^[a-zA-Z0-9_]+$/;
402
- function sanitizePrefix(prefix) {
403
- if (!SAFE_PREFIX.test(prefix)) {
404
- throw new Error(
405
- `Invalid table prefix "${prefix}": only letters, digits, and underscores are allowed`
406
- );
407
- }
408
- return prefix;
409
- }
534
+ var UNSPENT_VTXO_PREDICATE = "(is_spent IS NULL OR is_spent = 0) AND (spent_by IS NULL OR spent_by = '') AND (settled_by IS NULL OR settled_by = '')";
410
535
  function vtxoRowToDomain(row) {
411
536
  const serialized = {
412
537
  txid: row.txid,
@@ -422,10 +547,14 @@ function vtxoRowToDomain(row) {
422
547
  s: row.intent_s
423
548
  },
424
549
  status: JSON.parse(row.status_json),
425
- virtualStatus: JSON.parse(row.virtual_status_json),
426
550
  createdAt: new Date(row.created_at),
427
551
  isUnrolled: row.is_unrolled === 1,
428
552
  isSpent: row.is_spent === null ? void 0 : row.is_spent === 1,
553
+ isSwept: row.is_swept == null ? void 0 : row.is_swept === 1,
554
+ isPreconfirmed: row.is_preconfirmed == null ? void 0 : row.is_preconfirmed === 1,
555
+ commitmentTxIds: row.commitment_txids_json ? JSON.parse(row.commitment_txids_json) : void 0,
556
+ expiresAt: row.expires_at ? new Date(row.expires_at) : void 0,
557
+ expiresAtHeight: row.expires_at_height ?? void 0,
429
558
  spentBy: row.spent_by ?? void 0,
430
559
  settledBy: row.settled_by ?? void 0,
431
560
  arkTxId: row.ark_tx_id ?? void 0,
@@ -434,9 +563,9 @@ function vtxoRowToDomain(row) {
434
563
  // Post-migration every row has `script`, but the backfill is
435
564
  // idempotent: derive from `address` if the legacy column is still
436
565
  // null (e.g. the migration hasn't run yet on this handle).
437
- script: row.script ?? chunkGMZZQXV5_cjs.scriptFromArkAddress(row.address)
566
+ script: row.script ?? chunkR5OFJ23O_cjs.scriptFromArkAddress(row.address)
438
567
  };
439
- return chunkGMZZQXV5_cjs.deserializeVtxo(serialized);
568
+ return chunkR5OFJ23O_cjs.deserializeVtxo(serialized);
440
569
  }
441
570
  function utxoRowToDomain(row) {
442
571
  const serialized = {
@@ -455,7 +584,7 @@ function utxoRowToDomain(row) {
455
584
  status: JSON.parse(row.status_json),
456
585
  extraWitness: row.extra_witness_json ? JSON.parse(row.extra_witness_json) : void 0
457
586
  };
458
- return chunkGMZZQXV5_cjs.deserializeUtxo(serialized);
587
+ return chunkR5OFJ23O_cjs.deserializeUtxo(serialized);
459
588
  }
460
589
  function txRowToDomain(row) {
461
590
  const tx = {
@@ -470,20 +599,21 @@ function txRowToDomain(row) {
470
599
  createdAt: row.created_at
471
600
  };
472
601
  if (row.assets_json) {
473
- tx.assets = chunkGMZZQXV5_cjs.deserializeAssets(JSON.parse(row.assets_json));
602
+ tx.assets = chunkR5OFJ23O_cjs.deserializeAssets(JSON.parse(row.assets_json));
474
603
  }
475
604
  return tx;
476
605
  }
477
606
 
478
607
  // src/repositories/sqlite/contractRepository.ts
608
+ var WATCH_STATE = "IFNULL(watch, 'watched')";
479
609
  var SQLiteContractRepository = class {
480
610
  constructor(db, options) {
481
611
  this.db = db;
482
- this.prefix = sanitizePrefix2(options?.prefix ?? "ark_");
612
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
483
613
  this.table = `${this.prefix}contracts`;
484
614
  }
485
615
  db;
486
- version = 2;
616
+ version = 3;
487
617
  initPromise = null;
488
618
  prefix;
489
619
  table;
@@ -516,6 +646,12 @@ var SQLiteContractRepository = class {
516
646
  await this.db.run(
517
647
  `CREATE INDEX IF NOT EXISTS idx_${this.prefix}contracts_state ON ${this.table} (state)`
518
648
  );
649
+ await this.db.run(
650
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}contracts_watch_state ON ${this.table} (${WATCH_STATE}, script)`
651
+ );
652
+ await this.db.run(
653
+ `CREATE INDEX IF NOT EXISTS idx_${this.prefix}contracts_type_watch_state ON ${this.table} (type, ${WATCH_STATE}, script)`
654
+ );
519
655
  }
520
656
  async addColumnIfMissing(column, type) {
521
657
  const columns = await this.db.all(`PRAGMA table_info(${this.table})`);
@@ -530,22 +666,28 @@ var SQLiteContractRepository = class {
530
666
  await this.db.run(`DELETE FROM ${this.table}`);
531
667
  }
532
668
  // ── Contract management ────────────────────────────────────────────
533
- async getContracts(filter) {
669
+ async getContractsPage(filter, page) {
670
+ chunkR5OFJ23O_cjs.assertPageRequest(page);
534
671
  await this.ensureInit();
672
+ if (chunkR5OFJ23O_cjs.contractFilterMatchesNothing(filter)) return { items: [] };
535
673
  const conditions = [];
536
674
  const params = [];
537
675
  if (filter) {
538
676
  this.addFilterCondition(conditions, params, "script", filter.script);
539
677
  this.addFilterCondition(conditions, params, "state", filter.state);
540
678
  this.addFilterCondition(conditions, params, "type", filter.type);
541
- this.addWatchCondition(conditions, params, filter.watch);
679
+ this.addFilterCondition(conditions, params, WATCH_STATE, filter.watch);
542
680
  }
543
- let sql = `SELECT * FROM ${this.table}`;
544
- if (conditions.length > 0) {
545
- sql += ` WHERE ${conditions.join(" AND ")}`;
681
+ if (page.after !== void 0) {
682
+ conditions.push("script > ?");
683
+ params.push(page.after);
546
684
  }
547
- const rows = await this.db.all(sql, params);
548
- return rows.map(contractRowToDomain);
685
+ const where = conditions.length ? ` WHERE ${conditions.join(" AND ")}` : "";
686
+ const rows = await this.db.all(
687
+ `SELECT * FROM ${this.table}${where} ORDER BY script LIMIT ?`,
688
+ [...params, page.limit + 1]
689
+ );
690
+ return chunkR5OFJ23O_cjs.pageResult(rows.map(contractRowToDomain), page.limit, (contract) => contract.script);
549
691
  }
550
692
  async saveContract(contract) {
551
693
  await this.ensureInit();
@@ -585,29 +727,7 @@ var SQLiteContractRepository = class {
585
727
  params.push(value);
586
728
  }
587
729
  }
588
- /**
589
- * Same as {@link addFilterCondition}, except a row predating the
590
- * column stores NULL and must match `"watched"`.
591
- */
592
- addWatchCondition(conditions, params, value) {
593
- if (value === void 0) return;
594
- const wanted = Array.isArray(value) ? value : [value];
595
- if (wanted.length === 0) return;
596
- const placeholders = wanted.map(() => "?").join(", ");
597
- const clause = `watch IN (${placeholders})`;
598
- conditions.push(wanted.includes("watched") ? `(${clause} OR watch IS NULL)` : clause);
599
- params.push(...wanted);
600
- }
601
730
  };
602
- var SAFE_PREFIX2 = /^[a-zA-Z0-9_]+$/;
603
- function sanitizePrefix2(prefix) {
604
- if (!SAFE_PREFIX2.test(prefix)) {
605
- throw new Error(
606
- `Invalid table prefix "${prefix}": only letters, digits, and underscores are allowed`
607
- );
608
- }
609
- return prefix;
610
- }
611
731
  function contractRowToDomain(row) {
612
732
  const contract = {
613
733
  script: row.script,
@@ -630,15 +750,10 @@ function contractRowToDomain(row) {
630
750
  }
631
751
 
632
752
  // src/repositories/sqlite/intentRepository.ts
633
- var SAFE_PREFIX3 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
634
- function sanitizePrefix3(p) {
635
- if (!SAFE_PREFIX3.test(p)) throw new Error(`Invalid table prefix "${p}"`);
636
- return p;
637
- }
638
753
  var SQLiteIntentRepository = class {
639
754
  constructor(db, options) {
640
755
  this.db = db;
641
- this.prefix = sanitizePrefix3(options?.prefix ?? "ark_");
756
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
642
757
  this.t = `${this.prefix}intents`;
643
758
  }
644
759
  db;
@@ -677,19 +792,16 @@ var SQLiteIntentRepository = class {
677
792
  `CREATE INDEX IF NOT EXISTS idx_${this.prefix}intent_state ON ${this.t} (state)`
678
793
  );
679
794
  }
680
- withTx(fn) {
681
- return runInTransaction(this.db, fn);
682
- }
683
795
  async clear() {
684
796
  await this.ensureInit();
685
- await this.withTx(async () => {
797
+ await runInTransaction(this.db, async () => {
686
798
  await this.db.run(`DELETE FROM ${this.t}`);
687
799
  });
688
800
  }
689
801
  async saveIntent(intent) {
690
802
  await this.ensureInit();
691
803
  const now = Date.now();
692
- await this.withTx(async () => {
804
+ await runInTransaction(this.db, async () => {
693
805
  await this.db.run(
694
806
  `INSERT INTO ${this.t}
695
807
  (intent_tx_id, intent_id, state, valid_from, valid_until,
@@ -737,22 +849,37 @@ var SQLiteIntentRepository = class {
737
849
  );
738
850
  });
739
851
  }
740
- async getIntents(filter) {
852
+ async getIntentsPage(filter, page) {
853
+ chunkR5OFJ23O_cjs.assertPageRequest(page);
741
854
  await this.ensureInit();
742
- const rows = await this.db.all(
743
- `SELECT * FROM ${this.t} ORDER BY created_at ASC, intent_tx_id ASC`
744
- );
745
- let out = rows.map(rowToIntent);
746
- if (filter) out = out.filter((i) => chunkGMZZQXV5_cjs.intentMatchesFilter(i, filter));
747
- const { skip, end } = chunkGMZZQXV5_cjs.intentPageBounds(filter, out.length);
748
- return out.slice(skip, end);
855
+ if (filter?.states?.length === 0) return { items: [] };
856
+ const stateSql = filter?.states ? ` AND state IN (${filter.states.map(() => "?").join(", ")})` : "";
857
+ const stateParams = filter?.states ?? [];
858
+ const batchSize = Math.max(64, page.limit + 1);
859
+ const rows = [];
860
+ let after = page.after;
861
+ while (rows.length <= page.limit) {
862
+ const batch = await this.db.all(
863
+ `SELECT * FROM ${this.t} WHERE intent_tx_id > ?${stateSql} ORDER BY intent_tx_id LIMIT ?`,
864
+ [after ?? "", ...stateParams, batchSize]
865
+ );
866
+ if (batch.length === 0) break;
867
+ for (const row of batch) {
868
+ after = row.intent_tx_id;
869
+ const intent = rowToIntent(row);
870
+ if (!filter || chunkR5OFJ23O_cjs.intentMatchesFilter(intent, filter)) rows.push(intent);
871
+ if (rows.length > page.limit) break;
872
+ }
873
+ if (batch.length < batchSize) break;
874
+ }
875
+ return chunkR5OFJ23O_cjs.pageResult(rows, page.limit, (intent) => intent.intentTxId);
749
876
  }
750
877
  async getLockedVtxoOutpoints() {
751
878
  await this.ensureInit();
752
879
  const rows = await this.db.all(`SELECT * FROM ${this.t}`);
753
880
  const out = [];
754
881
  for (const r of rows) {
755
- if (chunkGMZZQXV5_cjs.isTerminalIntentState(r.state)) continue;
882
+ if (chunkR5OFJ23O_cjs.isTerminalIntentState(r.state)) continue;
756
883
  for (const o of JSON.parse(r.intent_vtxos_json)) out.push(o);
757
884
  }
758
885
  return out;
@@ -783,15 +910,10 @@ function rowToIntent(r) {
783
910
  }
784
911
 
785
912
  // src/repositories/sqlite/virtualTxRepository.ts
786
- var SAFE_PREFIX4 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
787
- function sanitizePrefix4(p) {
788
- if (!SAFE_PREFIX4.test(p)) throw new Error(`Invalid table prefix "${p}"`);
789
- return p;
790
- }
791
913
  var SQLiteVirtualTxRepository = class {
792
914
  constructor(db, options) {
793
915
  this.db = db;
794
- this.prefix = sanitizePrefix4(options?.prefix ?? "ark_");
916
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
795
917
  this.tTx = `${this.prefix}virtual_txs`;
796
918
  this.tBranch = `${this.prefix}vtxo_branches`;
797
919
  }
@@ -823,12 +945,9 @@ var SQLiteVirtualTxRepository = class {
823
945
  `CREATE INDEX IF NOT EXISTS idx_${this.prefix}branch_vtxid ON ${this.tBranch} (virtual_txid)`
824
946
  );
825
947
  }
826
- tx(fn) {
827
- return runInTransaction(this.db, fn);
828
- }
829
948
  async clear() {
830
949
  await this.ensureInit();
831
- await this.tx(async () => {
950
+ await runInTransaction(this.db, async () => {
832
951
  await this.db.run(`DELETE FROM ${this.tTx}`);
833
952
  await this.db.run(`DELETE FROM ${this.tBranch}`);
834
953
  });
@@ -836,7 +955,7 @@ var SQLiteVirtualTxRepository = class {
836
955
  async upsertVirtualTxs(txs) {
837
956
  if (txs.length === 0) return;
838
957
  await this.ensureInit();
839
- await this.tx(async () => {
958
+ await runInTransaction(this.db, async () => {
840
959
  const placeholders = txs.map(() => "?").join(", ");
841
960
  const existing = await this.db.all(
842
961
  `SELECT * FROM ${this.tTx} WHERE txid IN (${placeholders})`,
@@ -847,7 +966,7 @@ var SQLiteVirtualTxRepository = class {
847
966
  const prev = prevByTxid.get(t.txid);
848
967
  const psbt = t.psbt ?? prev?.psbt ?? null;
849
968
  const expires = t.expiresAt ?? prev?.expires_at ?? null;
850
- const type = chunkGMZZQXV5_cjs.mergeChainedTxType(t.type, prev?.type);
969
+ const type = chunkR5OFJ23O_cjs.mergeChainedTxType(t.type, prev?.type);
851
970
  await this.db.run(
852
971
  `INSERT OR REPLACE INTO ${this.tTx} (txid, psbt, expires_at, type) VALUES (?, ?, ?, ?)`,
853
972
  [t.txid, psbt, expires, type]
@@ -863,7 +982,7 @@ var SQLiteVirtualTxRepository = class {
863
982
  }
864
983
  async setBranch(vtxo, branch) {
865
984
  await this.ensureInit();
866
- await this.tx(async () => {
985
+ await runInTransaction(this.db, async () => {
867
986
  await this.db.run(`DELETE FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`, [
868
987
  vtxo.txid,
869
988
  vtxo.vout
@@ -898,7 +1017,7 @@ var SQLiteVirtualTxRepository = class {
898
1017
  }
899
1018
  async pruneForSpentVtxo(vtxo) {
900
1019
  await this.ensureInit();
901
- await this.tx(async () => {
1020
+ await runInTransaction(this.db, async () => {
902
1021
  const removed = await this.db.all(
903
1022
  `SELECT DISTINCT virtual_txid FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`,
904
1023
  [vtxo.txid, vtxo.vout]
@@ -931,16 +1050,9 @@ function rowToTx(r) {
931
1050
  };
932
1051
  }
933
1052
 
934
- // src/repositories/sqlite/prefix.ts
935
- var SAFE_PREFIX5 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
936
- function sanitizeTablePrefix(p) {
937
- if (!SAFE_PREFIX5.test(p)) throw new Error(`Invalid table prefix "${p}"`);
938
- return p;
939
- }
940
-
941
1053
  Object.defineProperty(exports, "ChainedTxType", {
942
1054
  enumerable: true,
943
- get: function () { return chunkGMZZQXV5_cjs.ChainedTxType; }
1055
+ get: function () { return chunkR5OFJ23O_cjs.ChainedTxType; }
944
1056
  });
945
1057
  exports.SQLiteContractRepository = SQLiteContractRepository;
946
1058
  exports.SQLiteIntentRepository = SQLiteIntentRepository;