@arkade-os/sdk 0.5.3 → 0.5.4

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 (88) hide show
  1. package/README.md +36 -34
  2. package/dist/adapters/expo.cjs +9 -5
  3. package/dist/adapters/expo.d.cts +11 -7
  4. package/dist/adapters/expo.d.ts +11 -7
  5. package/dist/adapters/expo.js +3 -3
  6. package/dist/{asyncStorageTaskQueue-B3U5gQ-i.d.ts → asyncStorageTaskQueue-DHMIxY04.d.ts} +2 -2
  7. package/dist/{asyncStorageTaskQueue-C9PkPcW_.d.cts → asyncStorageTaskQueue-DTBa8EH7.d.cts} +2 -2
  8. package/dist/{chunk-P7B4LQ3H.js → chunk-6CUP6ZIF.js} +4 -4
  9. package/dist/{chunk-P7B4LQ3H.js.map → chunk-6CUP6ZIF.js.map} +1 -1
  10. package/dist/{chunk-OPX2HRWM.js → chunk-AG4TFD6F.js} +137 -59
  11. package/dist/chunk-AG4TFD6F.js.map +1 -0
  12. package/dist/{chunk-5WRA66RV.cjs → chunk-B6VNKGIH.cjs} +10 -10
  13. package/dist/chunk-B6VNKGIH.cjs.map +1 -0
  14. package/dist/{chunk-6FL4N4S2.js → chunk-BTRCN4JJ.js} +22 -19
  15. package/dist/chunk-BTRCN4JJ.js.map +1 -0
  16. package/dist/{chunk-ZPF4I3K2.cjs → chunk-DNITZVNG.cjs} +28 -47
  17. package/dist/chunk-DNITZVNG.cjs.map +1 -0
  18. package/dist/{chunk-BYPBVHVA.cjs → chunk-E6OOJEHL.cjs} +49 -49
  19. package/dist/{chunk-BYPBVHVA.cjs.map → chunk-E6OOJEHL.cjs.map} +1 -1
  20. package/dist/{chunk-OUTWUYJ4.cjs → chunk-F3FAE7VJ.cjs} +769 -619
  21. package/dist/chunk-F3FAE7VJ.cjs.map +1 -0
  22. package/dist/{chunk-KW7ZEWYS.cjs → chunk-GHUUT54D.cjs} +140 -58
  23. package/dist/chunk-GHUUT54D.cjs.map +1 -0
  24. package/dist/{chunk-Y4BL3YYX.js → chunk-MWVAWFX6.js} +4 -4
  25. package/dist/chunk-MWVAWFX6.js.map +1 -0
  26. package/dist/{chunk-T7C3E2HL.js → chunk-TUOLZBNC.js} +19 -39
  27. package/dist/chunk-TUOLZBNC.js.map +1 -0
  28. package/dist/{chunk-ZMSM3NOH.cjs → chunk-WXNSISXK.cjs} +37 -34
  29. package/dist/chunk-WXNSISXK.cjs.map +1 -0
  30. package/dist/{chunk-HAQAWBYG.js → chunk-ZJHLLDBP.js} +283 -136
  31. package/dist/chunk-ZJHLLDBP.js.map +1 -0
  32. package/dist/contracts/handlers/index.cjs +9 -9
  33. package/dist/contracts/handlers/index.d.cts +3 -3
  34. package/dist/contracts/handlers/index.d.ts +3 -3
  35. package/dist/contracts/handlers/index.js +2 -2
  36. package/dist/{delegate-ByfKszb6.d.cts → delegate-f4_t864Z.d.cts} +1 -1
  37. package/dist/{delegate-Cd28gxpM.d.ts → delegate-xrSBNybC.d.ts} +1 -1
  38. package/dist/{index-DgH_0j14.d.cts → index-BJDz15ms.d.ts} +5 -5
  39. package/dist/{index-B6X2E7W_.d.ts → index-BjiVGtp8.d.cts} +5 -5
  40. package/dist/{index-BURzbRup.d.ts → index-DRwe0UDN.d.cts} +182 -114
  41. package/dist/{index-BURzbRup.d.cts → index-DRwe0UDN.d.ts} +182 -114
  42. package/dist/index.cjs +333 -313
  43. package/dist/index.d.cts +66 -44
  44. package/dist/index.d.ts +66 -44
  45. package/dist/index.js +4 -4
  46. package/dist/repositories/realm/index.cjs +65 -36
  47. package/dist/repositories/realm/index.cjs.map +1 -1
  48. package/dist/repositories/realm/index.d.cts +7 -3
  49. package/dist/repositories/realm/index.d.ts +7 -3
  50. package/dist/repositories/realm/index.js +35 -6
  51. package/dist/repositories/realm/index.js.map +1 -1
  52. package/dist/repositories/sqlite/index.cjs +176 -110
  53. package/dist/repositories/sqlite/index.cjs.map +1 -1
  54. package/dist/repositories/sqlite/index.d.cts +23 -13
  55. package/dist/repositories/sqlite/index.d.ts +23 -13
  56. package/dist/repositories/sqlite/index.js +148 -83
  57. package/dist/repositories/sqlite/index.js.map +1 -1
  58. package/dist/{taskRunner-i56-drQV.d.cts → taskRunner-BPPU-YHG.d.cts} +4 -4
  59. package/dist/{taskRunner-BaNCSxqK.d.ts → taskRunner-CDlNeth0.d.ts} +4 -4
  60. package/dist/wallet/expo/background.cjs +14 -14
  61. package/dist/wallet/expo/background.cjs.map +1 -1
  62. package/dist/wallet/expo/background.d.cts +3 -3
  63. package/dist/wallet/expo/background.d.ts +3 -3
  64. package/dist/wallet/expo/background.js +7 -7
  65. package/dist/wallet/expo/background.js.map +1 -1
  66. package/dist/wallet/expo/index.cjs +15 -15
  67. package/dist/wallet/expo/index.cjs.map +1 -1
  68. package/dist/wallet/expo/index.d.cts +6 -6
  69. package/dist/wallet/expo/index.d.ts +6 -6
  70. package/dist/wallet/expo/index.js +6 -6
  71. package/dist/wallet/expo/index.js.map +1 -1
  72. package/dist/{wallet-BjQugVUt.d.cts → wallet-Oc3Wd5gv.d.ts} +22 -18
  73. package/dist/{wallet-BnmhohgZ.d.ts → wallet-jVBDQl6R.d.cts} +22 -18
  74. package/dist/worker/expo/index.cjs +9 -9
  75. package/dist/worker/expo/index.d.cts +4 -4
  76. package/dist/worker/expo/index.d.ts +4 -4
  77. package/dist/worker/expo/index.js +5 -5
  78. package/package.json +1 -1
  79. package/dist/chunk-5WRA66RV.cjs.map +0 -1
  80. package/dist/chunk-6FL4N4S2.js.map +0 -1
  81. package/dist/chunk-HAQAWBYG.js.map +0 -1
  82. package/dist/chunk-KW7ZEWYS.cjs.map +0 -1
  83. package/dist/chunk-OPX2HRWM.js.map +0 -1
  84. package/dist/chunk-OUTWUYJ4.cjs.map +0 -1
  85. package/dist/chunk-T7C3E2HL.js.map +0 -1
  86. package/dist/chunk-Y4BL3YYX.js.map +0 -1
  87. package/dist/chunk-ZMSM3NOH.cjs.map +0 -1
  88. package/dist/chunk-ZPF4I3K2.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
- import { W as WalletRepository, P as PageRequest, O as Outpoint, F as PageResult, D as ExtendedVirtualCoin, H as ScriptVtxoCursor, J as ScriptVtxoPageOptions, K as StoredVtxo, L as VtxoRepositoryKey, E as ExtendedCoin, M as TransactionHistoryPageFilter, Q as TransactionHistoryPageCursor, h as ArkTransaction, U as WalletState, C as ContractRepository, X as ContractFilter, B as Contract, Y as IntentRepository, Z as ArkIntent, _ as IntentPageFilter, $ as VirtualTxRepository, a0 as VirtualTx, a1 as VtxoBranch } from '../../index-BURzbRup.js';
2
- export { a2 as ChainedTxType } from '../../index-BURzbRup.js';
1
+ import { W as WalletRepository, X as AtomicWalletState, P as PageRequest, F as Outpoint, H as PageResult, D as ExtendedVirtualCoin, J as ScriptVtxoCursor, K as ScriptVtxoPageOptions, L as StoredVtxo, M as VtxoRepositoryKey, E as ExtendedCoin, Q as TransactionHistoryPageFilter, U as TransactionHistoryPageCursor, h as ArkTransaction, Y as WalletState, C as ContractRepository, Z as ContractFilter, B as Contract, _ as IntentRepository, $ as ArkIntent, a0 as IntentPageFilter, a1 as VirtualTxRepository, a2 as VirtualTx, a3 as VtxoBranch } from '../../index-DRwe0UDN.js';
2
+ export { a4 as ChainedTxType } from '../../index-DRwe0UDN.js';
3
3
  import '@scure/btc-signer/utils.js';
4
4
  import '@scure/btc-signer/psbt.js';
5
5
  import '@scure/btc-signer';
@@ -8,6 +8,8 @@ import '@scure/btc-signer/transaction.js';
8
8
  /**
9
9
  * Minimal SQL execution interface that consumers implement
10
10
  * to connect their SQLite (or any SQL) database to the SDK.
11
+ * Share one executor object per connection across SDK repositories; separate wrappers
12
+ * and direct raw-driver calls bypass the SDK operation queue.
11
13
  *
12
14
  * Example for expo-sqlite:
13
15
  * ```
@@ -27,6 +29,12 @@ interface SQLExecutor {
27
29
  interface SQLiteWalletRepositoryOptions {
28
30
  /** Table name prefix (default: "ark_") */
29
31
  prefix?: string;
32
+ /** Opt in only with a dedicated connection or all operations coordinated through
33
+ * getSerializedExecutor/runInTransaction on the same executor object. Default: false.
34
+ * All read-modify-write callers must use atomic updates; queued legacy updates can still race. */
35
+ walletStateTransactions?: boolean;
36
+ /** Caller asserts durable backing; requires walletStateTransactions. No storage detection. */
37
+ persistentWalletState?: boolean;
30
38
  }
31
39
  /**
32
40
  * SQLite-based implementation of WalletRepository.
@@ -38,8 +46,9 @@ interface SQLiteWalletRepositoryOptions {
38
46
  * The consumer owns the SQLExecutor lifecycle — `[Symbol.asyncDispose]` is a no-op.
39
47
  */
40
48
  declare class SQLiteWalletRepository implements WalletRepository {
41
- private readonly db;
42
49
  readonly version: 2;
50
+ readonly atomicWalletState?: AtomicWalletState;
51
+ private readonly db;
43
52
  private initPromise;
44
53
  private readonly prefix;
45
54
  private readonly tables;
@@ -103,6 +112,7 @@ declare class SQLiteWalletRepository implements WalletRepository {
103
112
  getTransactionHistoryPage(filter: TransactionHistoryPageFilter, page: PageRequest<TransactionHistoryPageCursor>): Promise<PageResult<ArkTransaction, TransactionHistoryPageCursor>>;
104
113
  saveTransactions(address: string, txs: ArkTransaction[]): Promise<void>;
105
114
  deleteTransactions(address: string): Promise<void>;
115
+ private readonly atomicState;
106
116
  getWalletState(): Promise<WalletState | null>;
107
117
  saveWalletState(state: WalletState): Promise<void>;
108
118
  }
@@ -121,8 +131,8 @@ interface SQLiteContractRepositoryOptions {
121
131
  * The consumer owns the SQLExecutor lifecycle — `[Symbol.asyncDispose]` is a no-op.
122
132
  */
123
133
  declare class SQLiteContractRepository implements ContractRepository {
124
- private readonly db;
125
134
  readonly version: 3;
135
+ private readonly db;
126
136
  private initPromise;
127
137
  private readonly prefix;
128
138
  private readonly table;
@@ -139,8 +149,8 @@ declare class SQLiteContractRepository implements ContractRepository {
139
149
  }
140
150
 
141
151
  declare class SQLiteIntentRepository implements IntentRepository {
142
- private readonly db;
143
152
  readonly version: 1;
153
+ private readonly db;
144
154
  private initPromise;
145
155
  private readonly prefix;
146
156
  private readonly t;
@@ -157,8 +167,8 @@ declare class SQLiteIntentRepository implements IntentRepository {
157
167
  }
158
168
 
159
169
  declare class SQLiteVirtualTxRepository implements VirtualTxRepository {
160
- private readonly db;
161
170
  readonly version: 1;
171
+ private readonly db;
162
172
  private initPromise;
163
173
  private readonly prefix;
164
174
  private readonly tTx;
@@ -178,14 +188,14 @@ declare class SQLiteVirtualTxRepository implements VirtualTxRepository {
178
188
  [Symbol.asyncDispose](): Promise<void>;
179
189
  }
180
190
 
191
+ /** SDK reads and writes share the transaction queue; direct raw-driver calls do not. */
192
+ declare function getSerializedExecutor(db: SQLExecutor): SQLExecutor;
181
193
  /**
182
- * Run `fn` inside a serialized `BEGIN IMMEDIATE` / `COMMIT` on `db`.
183
- *
184
- * `fn` must issue only raw `db.run`/`db.all` calls: calling `runInTransaction`
185
- * again on the same `db` from within `fn` would wait on the chain it is part of
186
- * and deadlock.
194
+ * Run `fn` inside `BEGIN IMMEDIATE` / `COMMIT`, excluding queued SDK reads and writes.
195
+ * Use only the supplied raw executor inside `fn`; repository calls or nested transactions deadlock.
196
+ * Existing zero-argument callbacks closing over the original raw executor remain supported.
187
197
  */
188
- declare function runInTransaction(db: SQLExecutor, fn: () => Promise<void>): Promise<void>;
198
+ declare function runInTransaction(db: SQLExecutor, fn: (tx: SQLExecutor) => Promise<void>): Promise<void>;
189
199
 
190
200
  /**
191
201
  * Validate a SQLite table prefix and return it unchanged.
@@ -195,4 +205,4 @@ declare function runInTransaction(db: SQLExecutor, fn: () => Promise<void>): Pro
195
205
  */
196
206
  declare function sanitizeTablePrefix(p: string): string;
197
207
 
198
- export { type SQLExecutor, SQLiteContractRepository, SQLiteIntentRepository, SQLiteVirtualTxRepository, SQLiteWalletRepository, VirtualTx, VirtualTxRepository, VtxoBranch, runInTransaction, sanitizeTablePrefix };
208
+ export { type SQLExecutor, SQLiteContractRepository, SQLiteIntentRepository, SQLiteVirtualTxRepository, SQLiteWalletRepository, VirtualTx, VirtualTxRepository, VtxoBranch, getSerializedExecutor, runInTransaction, sanitizeTablePrefix };
@@ -1,32 +1,69 @@
1
- import { scriptFromArkAddress, legacyVtxoFacts, serializeVtxo, createdAtToIso, assertPageRequest, pageResult, checkSaveVtxosForScript, utxoEntries, serializeUtxo, assertHistoryPageFilter, serializeAssets, deserializeVtxo, deserializeUtxo, deserializeAssets, contractFilterMatchesNothing, intentMatchesFilter, isTerminalIntentState, mergeChainedTxType } from '../../chunk-HAQAWBYG.js';
2
- export { ChainedTxType } from '../../chunk-HAQAWBYG.js';
3
- import '../../chunk-6FL4N4S2.js';
4
- import '../../chunk-P7B4LQ3H.js';
5
- import { isVtxoSpent } from '../../chunk-OPX2HRWM.js';
1
+ import { legacyVtxoFacts, serializeVtxo, createdAtToIso, assertPageRequest, pageResult, checkSaveVtxosForScript, utxoEntries, serializeUtxo, assertHistoryPageFilter, serializeAssets, scriptFromArkAddress, deserializeVtxo, deserializeUtxo, deserializeAssets, contractFilterMatchesNothing, intentMatchesFilter, isTerminalIntentState, applyWalletStateUpdate, mergeChainedTxType } from '../../chunk-ZJHLLDBP.js';
2
+ export { ChainedTxType } from '../../chunk-ZJHLLDBP.js';
3
+ import '../../chunk-BTRCN4JJ.js';
4
+ import '../../chunk-6CUP6ZIF.js';
5
+ import { isVtxoSpent } from '../../chunk-AG4TFD6F.js';
6
6
 
7
7
  // src/repositories/sqlite/transaction.ts
8
- var writeChains = /* @__PURE__ */ new WeakMap();
8
+ var executorQueues = /* @__PURE__ */ new WeakMap();
9
+ var STALL_WARN_MS = 1e4;
10
+ function enqueue(queue, operation) {
11
+ let stall;
12
+ if (queue.inTransaction) {
13
+ const site = new Error(
14
+ `SQLite operation waited ${STALL_WARN_MS / 1e3}s behind a transaction. A repository, getSerializedExecutor or runInTransaction call inside a runInTransaction callback deadlocks; use the callback's tx.`
15
+ );
16
+ stall = setTimeout(() => console.warn(site), STALL_WARN_MS);
17
+ }
18
+ const run = queue.tail.then(() => {
19
+ clearTimeout(stall);
20
+ return operation();
21
+ });
22
+ queue.tail = run.catch(() => void 0);
23
+ return run;
24
+ }
25
+ function queueFor(db) {
26
+ const existing = executorQueues.get(db);
27
+ if (existing) return existing;
28
+ const facade = {
29
+ run: (sql, params) => enqueue(queue, () => db.run(sql, params)),
30
+ get: (sql, params) => enqueue(queue, () => db.get(sql, params)),
31
+ all: (sql, params) => enqueue(queue, () => db.all(sql, params))
32
+ };
33
+ const queue = {
34
+ raw: db,
35
+ facade,
36
+ tail: Promise.resolve(),
37
+ inTransaction: false
38
+ };
39
+ executorQueues.set(db, queue);
40
+ executorQueues.set(facade, queue);
41
+ return queue;
42
+ }
43
+ function getSerializedExecutor(db) {
44
+ return queueFor(db).facade;
45
+ }
9
46
  function runInTransaction(db, fn) {
10
- const prev = writeChains.get(db) ?? Promise.resolve();
11
- const run = prev.then(async () => {
12
- await db.run("BEGIN IMMEDIATE");
47
+ const queue = queueFor(db);
48
+ return enqueue(queue, async () => {
49
+ const tx = queue.raw;
50
+ queue.inTransaction = true;
13
51
  try {
14
- await fn();
15
- await db.run("COMMIT");
16
- } catch (e) {
52
+ await tx.run("BEGIN IMMEDIATE");
17
53
  try {
18
- await db.run("ROLLBACK");
19
- } catch {
54
+ await fn(tx);
55
+ await tx.run("COMMIT");
56
+ } catch (e) {
57
+ try {
58
+ await tx.run("ROLLBACK");
59
+ } catch {
60
+ }
61
+ throw e;
20
62
  }
21
- throw e;
63
+ } finally {
64
+ queue.inTransaction = false;
22
65
  }
23
66
  });
24
- writeChains.set(
25
- db,
26
- run.catch(() => {
27
- })
28
- );
29
- return run;
30
67
  }
31
68
 
32
69
  // src/repositories/sqlite/prefix.ts
@@ -39,8 +76,17 @@ function sanitizeTablePrefix(p) {
39
76
  // src/repositories/sqlite/walletRepository.ts
40
77
  var MAX_BOUND_PARAMETERS = 999;
41
78
  var SQLiteWalletRepository = class {
79
+ version = 2;
80
+ atomicWalletState;
81
+ db;
82
+ initPromise = null;
83
+ prefix;
84
+ tables;
42
85
  constructor(db, options) {
43
- this.db = db;
86
+ this.db = getSerializedExecutor(db);
87
+ if (options?.walletStateTransactions === true) {
88
+ this.atomicWalletState = options.persistentWalletState === true ? { ...this.atomicState, persistent: true } : this.atomicState;
89
+ }
44
90
  this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
45
91
  this.tables = {
46
92
  vtxos: `${this.prefix}vtxos`,
@@ -49,11 +95,6 @@ var SQLiteWalletRepository = class {
49
95
  walletState: `${this.prefix}wallet_state`
50
96
  };
51
97
  }
52
- db;
53
- version = 2;
54
- initPromise = null;
55
- prefix;
56
- tables;
57
98
  // ── Lifecycle ──────────────────────────────────────────────────────
58
99
  ensureInit() {
59
100
  if (!this.initPromise) {
@@ -156,16 +197,16 @@ var SQLiteWalletRepository = class {
156
197
  * leave the next startup seeing no `vtxos` table.
157
198
  */
158
199
  async migrateVtxosTable() {
159
- await runInTransaction(this.db, async () => {
160
- const tableExists = await this.db.get(
200
+ await runInTransaction(this.db, async (tx) => {
201
+ const tableExists = await tx.get(
161
202
  `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
162
203
  [this.tables.vtxos]
163
204
  );
164
205
  if (!tableExists) {
165
- await this.db.run(this.vtxosCreateSql(this.tables.vtxos));
206
+ await tx.run(this.vtxosCreateSql(this.tables.vtxos));
166
207
  return;
167
208
  }
168
- const cols = await this.db.all(
209
+ const cols = await tx.all(
169
210
  `PRAGMA table_info(${this.tables.vtxos})`
170
211
  );
171
212
  const scriptCol = cols.find((c) => c.name === "script");
@@ -179,33 +220,31 @@ var SQLiteWalletRepository = class {
179
220
  let addedCanonicalColumns = false;
180
221
  for (const [name, type] of nullableCanonicalColumns) {
181
222
  if (!cols.some((c) => c.name === name)) {
182
- await this.db.run(
183
- `ALTER TABLE ${this.tables.vtxos} ADD COLUMN ${name} ${type}`
184
- );
223
+ await tx.run(`ALTER TABLE ${this.tables.vtxos} ADD COLUMN ${name} ${type}`);
185
224
  addedCanonicalColumns = true;
186
225
  }
187
226
  }
188
227
  const hasLegacyBlob = cols.some((c) => c.name === "virtual_status_json");
189
228
  if (addedCanonicalColumns && hasLegacyBlob) {
190
- await this.backfillCanonicalVtxoColumns();
229
+ await this.backfillCanonicalVtxoColumns(tx);
191
230
  }
192
231
  if (scriptCol && scriptCol.notnull === 1 && !hasLegacyBlob) {
193
232
  return;
194
233
  }
195
234
  if (!scriptCol) {
196
- await this.db.run(`ALTER TABLE ${this.tables.vtxos} ADD COLUMN script TEXT`);
235
+ await tx.run(`ALTER TABLE ${this.tables.vtxos} ADD COLUMN script TEXT`);
197
236
  }
198
- const nullRows = await this.db.all(`SELECT txid, vout, address FROM ${this.tables.vtxos} WHERE script IS NULL`);
237
+ const nullRows = await tx.all(`SELECT txid, vout, address FROM ${this.tables.vtxos} WHERE script IS NULL`);
199
238
  for (const row of nullRows) {
200
- await this.db.run(
239
+ await tx.run(
201
240
  `UPDATE ${this.tables.vtxos} SET script = ? WHERE txid = ? AND vout = ?`,
202
241
  [scriptFromArkAddress(row.address), row.txid, row.vout]
203
242
  );
204
243
  }
205
244
  const tempName = `${this.tables.vtxos}__migrate_tmp`;
206
- await this.db.run(`DROP TABLE IF EXISTS ${tempName}`);
207
- await this.db.run(this.vtxosCreateSql(tempName));
208
- await this.db.run(`
245
+ await tx.run(`DROP TABLE IF EXISTS ${tempName}`);
246
+ await tx.run(this.vtxosCreateSql(tempName));
247
+ await tx.run(`
209
248
  INSERT INTO ${tempName}
210
249
  (txid, vout, value, address, tap_tree,
211
250
  forfeit_cb, forfeit_s, intent_cb, intent_s,
@@ -221,8 +260,8 @@ var SQLiteWalletRepository = class {
221
260
  spent_by, settled_by, ark_tx_id, extra_witness_json, assets_json, script
222
261
  FROM ${this.tables.vtxos}
223
262
  `);
224
- await this.db.run(`DROP TABLE ${this.tables.vtxos}`);
225
- await this.db.run(`ALTER TABLE ${tempName} RENAME TO ${this.tables.vtxos}`);
263
+ await tx.run(`DROP TABLE ${this.tables.vtxos}`);
264
+ await tx.run(`ALTER TABLE ${tempName} RENAME TO ${this.tables.vtxos}`);
226
265
  });
227
266
  }
228
267
  /**
@@ -234,15 +273,15 @@ var SQLiteWalletRepository = class {
234
273
  * is missing or corrupt are left alone: a migration must not be stopped by one bad row, and
235
274
  * the next sync repairs it.
236
275
  */
237
- async backfillCanonicalVtxoColumns() {
238
- const rows = await this.db.all(
276
+ async backfillCanonicalVtxoColumns(tx) {
277
+ const rows = await tx.all(
239
278
  `SELECT txid, vout, virtual_status_json FROM ${this.tables.vtxos}
240
279
  WHERE virtual_status_json IS NOT NULL AND is_swept IS NULL`
241
280
  );
242
281
  for (const row of rows) {
243
282
  const facts = legacyVtxoFacts(row.virtual_status_json);
244
283
  if (!facts) continue;
245
- await this.db.run(
284
+ await tx.run(
246
285
  `UPDATE ${this.tables.vtxos}
247
286
  SET is_swept = ?, is_preconfirmed = ?, commitment_txids_json = ?,
248
287
  expires_at = ?, expires_at_height = ?,
@@ -502,6 +541,32 @@ var SQLiteWalletRepository = class {
502
541
  await this.db.run(`DELETE FROM ${this.tables.transactions} WHERE address = ?`, [address]);
503
542
  }
504
543
  // ── Wallet state ───────────────────────────────────────────────────
544
+ atomicState = {
545
+ version: 1,
546
+ update: async (updater) => {
547
+ await this.ensureInit();
548
+ await runInTransaction(this.db, async (tx) => {
549
+ const row = await tx.get(
550
+ `SELECT * FROM ${this.tables.walletState} WHERE key = ?`,
551
+ ["state"]
552
+ );
553
+ const current = row ? {
554
+ settings: row.settings_json ? JSON.parse(row.settings_json) : void 0,
555
+ lastSyncTime: row.last_sync_time ?? void 0
556
+ } : {};
557
+ const state = applyWalletStateUpdate(current, updater);
558
+ await tx.run(
559
+ `INSERT OR REPLACE INTO ${this.tables.walletState}
560
+ (key, settings_json, last_sync_time) VALUES (?, ?, ?)`,
561
+ [
562
+ "state",
563
+ state.settings ? JSON.stringify(state.settings) : null,
564
+ state.lastSyncTime ?? null
565
+ ]
566
+ );
567
+ });
568
+ }
569
+ };
505
570
  async getWalletState() {
506
571
  await this.ensureInit();
507
572
  const row = await this.db.get(
@@ -606,16 +671,16 @@ function txRowToDomain(row) {
606
671
  // src/repositories/sqlite/contractRepository.ts
607
672
  var WATCH_STATE = "IFNULL(watch, 'watched')";
608
673
  var SQLiteContractRepository = class {
609
- constructor(db, options) {
610
- this.db = db;
611
- this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
612
- this.table = `${this.prefix}contracts`;
613
- }
614
- db;
615
674
  version = 3;
675
+ db;
616
676
  initPromise = null;
617
677
  prefix;
618
678
  table;
679
+ constructor(db, options) {
680
+ this.db = getSerializedExecutor(db);
681
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
682
+ this.table = `${this.prefix}contracts`;
683
+ }
619
684
  // ── Lifecycle ──────────────────────────────────────────────────────
620
685
  ensureInit() {
621
686
  if (!this.initPromise) {
@@ -750,16 +815,16 @@ function contractRowToDomain(row) {
750
815
 
751
816
  // src/repositories/sqlite/intentRepository.ts
752
817
  var SQLiteIntentRepository = class {
753
- constructor(db, options) {
754
- this.db = db;
755
- this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
756
- this.t = `${this.prefix}intents`;
757
- }
758
- db;
759
818
  version = 1;
819
+ db;
760
820
  initPromise = null;
761
821
  prefix;
762
822
  t;
823
+ constructor(db, options) {
824
+ this.db = getSerializedExecutor(db);
825
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
826
+ this.t = `${this.prefix}intents`;
827
+ }
763
828
  ensureInit() {
764
829
  if (!this.initPromise) this.initPromise = this.init();
765
830
  return this.initPromise;
@@ -793,15 +858,15 @@ var SQLiteIntentRepository = class {
793
858
  }
794
859
  async clear() {
795
860
  await this.ensureInit();
796
- await runInTransaction(this.db, async () => {
797
- await this.db.run(`DELETE FROM ${this.t}`);
861
+ await runInTransaction(this.db, async (tx) => {
862
+ await tx.run(`DELETE FROM ${this.t}`);
798
863
  });
799
864
  }
800
865
  async saveIntent(intent) {
801
866
  await this.ensureInit();
802
867
  const now = Date.now();
803
- await runInTransaction(this.db, async () => {
804
- await this.db.run(
868
+ await runInTransaction(this.db, async (tx) => {
869
+ await tx.run(
805
870
  `INSERT INTO ${this.t}
806
871
  (intent_tx_id, intent_id, state, valid_from, valid_until,
807
872
  created_at, updated_at, register_proof, register_proof_message,
@@ -910,18 +975,18 @@ function rowToIntent(r) {
910
975
 
911
976
  // src/repositories/sqlite/virtualTxRepository.ts
912
977
  var SQLiteVirtualTxRepository = class {
913
- constructor(db, options) {
914
- this.db = db;
915
- this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
916
- this.tTx = `${this.prefix}virtual_txs`;
917
- this.tBranch = `${this.prefix}vtxo_branches`;
918
- }
919
- db;
920
978
  version = 1;
979
+ db;
921
980
  initPromise = null;
922
981
  prefix;
923
982
  tTx;
924
983
  tBranch;
984
+ constructor(db, options) {
985
+ this.db = getSerializedExecutor(db);
986
+ this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
987
+ this.tTx = `${this.prefix}virtual_txs`;
988
+ this.tBranch = `${this.prefix}vtxo_branches`;
989
+ }
925
990
  ensureInit() {
926
991
  if (!this.initPromise) this.initPromise = this.init();
927
992
  return this.initPromise;
@@ -946,17 +1011,17 @@ var SQLiteVirtualTxRepository = class {
946
1011
  }
947
1012
  async clear() {
948
1013
  await this.ensureInit();
949
- await runInTransaction(this.db, async () => {
950
- await this.db.run(`DELETE FROM ${this.tTx}`);
951
- await this.db.run(`DELETE FROM ${this.tBranch}`);
1014
+ await runInTransaction(this.db, async (tx) => {
1015
+ await tx.run(`DELETE FROM ${this.tTx}`);
1016
+ await tx.run(`DELETE FROM ${this.tBranch}`);
952
1017
  });
953
1018
  }
954
1019
  async upsertVirtualTxs(txs) {
955
1020
  if (txs.length === 0) return;
956
1021
  await this.ensureInit();
957
- await runInTransaction(this.db, async () => {
1022
+ await runInTransaction(this.db, async (tx) => {
958
1023
  const placeholders = txs.map(() => "?").join(", ");
959
- const existing = await this.db.all(
1024
+ const existing = await tx.all(
960
1025
  `SELECT * FROM ${this.tTx} WHERE txid IN (${placeholders})`,
961
1026
  txs.map((t) => t.txid)
962
1027
  );
@@ -966,7 +1031,7 @@ var SQLiteVirtualTxRepository = class {
966
1031
  const psbt = t.psbt ?? prev?.psbt ?? null;
967
1032
  const expires = t.expiresAt ?? prev?.expires_at ?? null;
968
1033
  const type = mergeChainedTxType(t.type, prev?.type);
969
- await this.db.run(
1034
+ await tx.run(
970
1035
  `INSERT OR REPLACE INTO ${this.tTx} (txid, psbt, expires_at, type) VALUES (?, ?, ?, ?)`,
971
1036
  [t.txid, psbt, expires, type]
972
1037
  );
@@ -981,13 +1046,13 @@ var SQLiteVirtualTxRepository = class {
981
1046
  }
982
1047
  async setBranch(vtxo, branch) {
983
1048
  await this.ensureInit();
984
- await runInTransaction(this.db, async () => {
985
- await this.db.run(`DELETE FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`, [
1049
+ await runInTransaction(this.db, async (tx) => {
1050
+ await tx.run(`DELETE FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`, [
986
1051
  vtxo.txid,
987
1052
  vtxo.vout
988
1053
  ]);
989
1054
  for (const b of branch) {
990
- await this.db.run(
1055
+ await tx.run(
991
1056
  `INSERT OR REPLACE INTO ${this.tBranch} (vtxo_txid, vtxo_vout, virtual_txid, position) VALUES (?, ?, ?, ?)`,
992
1057
  [b.vtxoTxid, b.vtxoVout, b.virtualTxid, b.position]
993
1058
  );
@@ -1016,18 +1081,18 @@ var SQLiteVirtualTxRepository = class {
1016
1081
  }
1017
1082
  async pruneForSpentVtxo(vtxo) {
1018
1083
  await this.ensureInit();
1019
- await runInTransaction(this.db, async () => {
1020
- const removed = await this.db.all(
1084
+ await runInTransaction(this.db, async (tx) => {
1085
+ const removed = await tx.all(
1021
1086
  `SELECT DISTINCT virtual_txid FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`,
1022
1087
  [vtxo.txid, vtxo.vout]
1023
1088
  );
1024
- await this.db.run(`DELETE FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`, [
1089
+ await tx.run(`DELETE FROM ${this.tBranch} WHERE vtxo_txid = ? AND vtxo_vout = ?`, [
1025
1090
  vtxo.txid,
1026
1091
  vtxo.vout
1027
1092
  ]);
1028
1093
  if (removed.length === 0) return;
1029
1094
  const placeholders = removed.map(() => "?").join(", ");
1030
- await this.db.run(
1095
+ await tx.run(
1031
1096
  `DELETE FROM ${this.tTx}
1032
1097
  WHERE txid IN (${placeholders})
1033
1098
  AND NOT EXISTS (
@@ -1049,6 +1114,6 @@ function rowToTx(r) {
1049
1114
  };
1050
1115
  }
1051
1116
 
1052
- export { SQLiteContractRepository, SQLiteIntentRepository, SQLiteVirtualTxRepository, SQLiteWalletRepository, runInTransaction, sanitizeTablePrefix };
1117
+ export { SQLiteContractRepository, SQLiteIntentRepository, SQLiteVirtualTxRepository, SQLiteWalletRepository, getSerializedExecutor, runInTransaction, sanitizeTablePrefix };
1053
1118
  //# sourceMappingURL=index.js.map
1054
1119
  //# sourceMappingURL=index.js.map