@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.
- package/README.md +90 -83
- package/dist/adapters/expo.cjs +5 -6
- package/dist/adapters/expo.d.cts +4 -4
- package/dist/adapters/expo.d.ts +4 -4
- package/dist/adapters/expo.js +3 -4
- package/dist/{asyncStorageTaskQueue-C5rBYlru.d.ts → asyncStorageTaskQueue-aL7K14e4.d.ts} +2 -2
- package/dist/{asyncStorageTaskQueue-BuDvgWh6.d.cts → asyncStorageTaskQueue-x8ok3tJy.d.cts} +2 -2
- package/dist/{chunk-ISO4TI5J.js → chunk-4FDNOLBO.js} +566 -459
- package/dist/chunk-4FDNOLBO.js.map +1 -0
- package/dist/{chunk-JZWLXNHV.cjs → chunk-5XBH5SAL.cjs} +574 -464
- package/dist/chunk-5XBH5SAL.cjs.map +1 -0
- package/dist/{chunk-3R476TDV.js → chunk-CXHJGED6.js} +293 -1071
- package/dist/chunk-CXHJGED6.js.map +1 -0
- package/dist/{chunk-ZRNQV6HV.js → chunk-EXFU6MTA.js} +4578 -4396
- package/dist/chunk-EXFU6MTA.js.map +1 -0
- package/dist/{chunk-43FKNLX4.cjs → chunk-GVF4OCTL.cjs} +357 -1114
- package/dist/chunk-GVF4OCTL.cjs.map +1 -0
- package/dist/{chunk-HLCGYOIH.cjs → chunk-HIZNPHB2.cjs} +37 -36
- package/dist/chunk-HIZNPHB2.cjs.map +1 -0
- package/dist/{chunk-4PKLULWT.js → chunk-JZAEFOE4.js} +109 -246
- package/dist/chunk-JZAEFOE4.js.map +1 -0
- package/dist/{chunk-ZOTXDOS5.js → chunk-LNJPVLIC.js} +30 -29
- package/dist/chunk-LNJPVLIC.js.map +1 -0
- package/dist/{chunk-NVZJSKZS.cjs → chunk-Q7PC3NHX.cjs} +121 -257
- package/dist/chunk-Q7PC3NHX.cjs.map +1 -0
- package/dist/{chunk-GMZZQXV5.cjs → chunk-R5OFJ23O.cjs} +4961 -4767
- package/dist/chunk-R5OFJ23O.cjs.map +1 -0
- package/dist/{chunk-6DNR46C7.js → chunk-S2WWOVFC.js} +7 -5
- package/dist/chunk-S2WWOVFC.js.map +1 -0
- package/dist/{chunk-D25O4EGY.cjs → chunk-VZMLADXQ.cjs} +12 -10
- package/dist/chunk-VZMLADXQ.cjs.map +1 -0
- package/dist/contracts/handlers/index.cjs +9 -10
- package/dist/contracts/handlers/index.d.cts +5 -5
- package/dist/contracts/handlers/index.d.ts +5 -5
- package/dist/contracts/handlers/index.js +2 -3
- package/dist/{delegate-BAX5QftB.d.ts → delegate-BT5iON1T.d.ts} +1 -1
- package/dist/{delegate-1yp1HyP7.d.cts → delegate-u6kXTtWY.d.cts} +1 -1
- package/dist/index-BCnhItOQ.d.cts +639 -0
- package/dist/{index-DUxufw76.d.cts → index-CK5QbTmZ.d.cts} +1387 -2404
- package/dist/{index-DUxufw76.d.ts → index-CK5QbTmZ.d.ts} +1387 -2404
- package/dist/index-D1D4cR-G.d.ts +639 -0
- package/dist/index.cjs +375 -340
- package/dist/index.d.cts +784 -1197
- package/dist/index.d.ts +784 -1197
- package/dist/index.js +4 -5
- package/dist/repositories/realm/index.cjs +201 -106
- package/dist/repositories/realm/index.cjs.map +1 -1
- package/dist/repositories/realm/index.d.cts +28 -16
- package/dist/repositories/realm/index.d.ts +28 -16
- package/dist/repositories/realm/index.js +190 -95
- package/dist/repositories/realm/index.js.map +1 -1
- package/dist/repositories/sqlite/index.cjs +301 -189
- package/dist/repositories/sqlite/index.cjs.map +1 -1
- package/dist/repositories/sqlite/index.d.cts +32 -21
- package/dist/repositories/sqlite/index.d.ts +32 -21
- package/dist/repositories/sqlite/index.js +294 -182
- package/dist/repositories/sqlite/index.js.map +1 -1
- package/dist/{taskRunner-D_iPiZIi.d.ts → taskRunner-BeYR6NpQ.d.ts} +2 -2
- package/dist/{taskRunner-Dr3NStc0.d.cts → taskRunner-Csey3EYJ.d.cts} +2 -2
- package/dist/wallet/expo/background.cjs +14 -15
- package/dist/wallet/expo/background.cjs.map +1 -1
- package/dist/wallet/expo/background.d.cts +10 -16
- package/dist/wallet/expo/background.d.ts +10 -16
- package/dist/wallet/expo/background.js +6 -7
- package/dist/wallet/expo/background.js.map +1 -1
- package/dist/wallet/expo/index.cjs +16 -23
- package/dist/wallet/expo/index.cjs.map +1 -1
- package/dist/wallet/expo/index.d.cts +6 -9
- package/dist/wallet/expo/index.d.ts +6 -9
- package/dist/wallet/expo/index.js +8 -15
- package/dist/wallet/expo/index.js.map +1 -1
- package/dist/wallet-DG3Qmbmt.d.cts +1848 -0
- package/dist/wallet-DzSLMxBZ.d.ts +1848 -0
- package/dist/worker/expo/index.cjs +9 -10
- package/dist/worker/expo/index.cjs.map +1 -1
- package/dist/worker/expo/index.d.cts +6 -6
- package/dist/worker/expo/index.d.ts +6 -6
- package/dist/worker/expo/index.js +5 -6
- package/dist/worker/expo/index.js.map +1 -1
- package/package.json +12 -51
- package/dist/adapters/asyncStorage.cjs +0 -48
- package/dist/adapters/asyncStorage.cjs.map +0 -1
- package/dist/adapters/asyncStorage.d.cts +0 -16
- package/dist/adapters/asyncStorage.d.ts +0 -16
- package/dist/adapters/asyncStorage.js +0 -46
- package/dist/adapters/asyncStorage.js.map +0 -1
- package/dist/adapters/fileSystem.cjs +0 -116
- package/dist/adapters/fileSystem.cjs.map +0 -1
- package/dist/adapters/fileSystem.d.cts +0 -17
- package/dist/adapters/fileSystem.d.ts +0 -17
- package/dist/adapters/fileSystem.js +0 -93
- package/dist/adapters/fileSystem.js.map +0 -1
- package/dist/adapters/indexedDB.cjs +0 -103
- package/dist/adapters/indexedDB.cjs.map +0 -1
- package/dist/adapters/indexedDB.d.cts +0 -18
- package/dist/adapters/indexedDB.d.ts +0 -18
- package/dist/adapters/indexedDB.js +0 -101
- package/dist/adapters/indexedDB.js.map +0 -1
- package/dist/adapters/localStorage.cjs +0 -50
- package/dist/adapters/localStorage.cjs.map +0 -1
- package/dist/adapters/localStorage.d.cts +0 -14
- package/dist/adapters/localStorage.d.ts +0 -14
- package/dist/adapters/localStorage.js +0 -48
- package/dist/adapters/localStorage.js.map +0 -1
- package/dist/chunk-3R476TDV.js.map +0 -1
- package/dist/chunk-43FKNLX4.cjs.map +0 -1
- package/dist/chunk-4PKLULWT.js.map +0 -1
- package/dist/chunk-5BLDMQED.cjs +0 -18
- package/dist/chunk-5BLDMQED.cjs.map +0 -1
- package/dist/chunk-6DNR46C7.js.map +0 -1
- package/dist/chunk-D25O4EGY.cjs.map +0 -1
- package/dist/chunk-GMZZQXV5.cjs.map +0 -1
- package/dist/chunk-HLCGYOIH.cjs.map +0 -1
- package/dist/chunk-ISO4TI5J.js.map +0 -1
- package/dist/chunk-JZWLXNHV.cjs.map +0 -1
- package/dist/chunk-NSBPE2FW.js +0 -15
- package/dist/chunk-NSBPE2FW.js.map +0 -1
- package/dist/chunk-NVZJSKZS.cjs.map +0 -1
- package/dist/chunk-ZOTXDOS5.js.map +0 -1
- package/dist/chunk-ZRNQV6HV.js.map +0 -1
- package/dist/hdWalletCapable-CmEU0NP1.d.ts +0 -2232
- package/dist/hdWalletCapable-eJgaT-ec.d.cts +0 -2232
- package/dist/index-Bem5vKzX.d.ts +0 -850
- package/dist/index-C0IanN1m.d.cts +0 -11
- package/dist/index-C0IanN1m.d.ts +0 -11
- package/dist/index-W_oMcOmG.d.cts +0 -850
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../../chunk-
|
|
5
|
-
require('../../chunk-
|
|
6
|
-
require('../../chunk-
|
|
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 =
|
|
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 =
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
[
|
|
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,
|
|
168
|
-
|
|
169
|
-
|
|
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,
|
|
173
|
-
|
|
174
|
-
|
|
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
|
|
218
|
-
|
|
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
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 ${
|
|
300
|
-
|
|
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
|
-
|
|
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(
|
|
418
|
+
async saveUtxos(addressOrBatch, utxos) {
|
|
305
419
|
await this.ensureInit();
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
|
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
|
|
341
|
-
|
|
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
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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
|
|
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 ??
|
|
566
|
+
script: row.script ?? chunkR5OFJ23O_cjs.scriptFromArkAddress(row.address)
|
|
438
567
|
};
|
|
439
|
-
return
|
|
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
|
|
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 =
|
|
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 =
|
|
612
|
+
this.prefix = sanitizeTablePrefix(options?.prefix ?? "ark_");
|
|
483
613
|
this.table = `${this.prefix}contracts`;
|
|
484
614
|
}
|
|
485
615
|
db;
|
|
486
|
-
version =
|
|
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
|
|
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.
|
|
679
|
+
this.addFilterCondition(conditions, params, WATCH_STATE, filter.watch);
|
|
542
680
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
681
|
+
if (page.after !== void 0) {
|
|
682
|
+
conditions.push("script > ?");
|
|
683
|
+
params.push(page.after);
|
|
546
684
|
}
|
|
547
|
-
const
|
|
548
|
-
|
|
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 =
|
|
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.
|
|
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.
|
|
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
|
|
852
|
+
async getIntentsPage(filter, page) {
|
|
853
|
+
chunkR5OFJ23O_cjs.assertPageRequest(page);
|
|
741
854
|
await this.ensureInit();
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
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 (
|
|
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 =
|
|
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.
|
|
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.
|
|
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 =
|
|
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.
|
|
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.
|
|
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
|
|
1055
|
+
get: function () { return chunkR5OFJ23O_cjs.ChainedTxType; }
|
|
944
1056
|
});
|
|
945
1057
|
exports.SQLiteContractRepository = SQLiteContractRepository;
|
|
946
1058
|
exports.SQLiteIntentRepository = SQLiteIntentRepository;
|