@waiaas/daemon 2.11.0-rc → 2.11.0-rc.13

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 (224) hide show
  1. package/dist/api/middleware/resolve-asset.d.ts +26 -0
  2. package/dist/api/middleware/resolve-asset.d.ts.map +1 -0
  3. package/dist/api/middleware/resolve-asset.js +81 -0
  4. package/dist/api/middleware/resolve-asset.js.map +1 -0
  5. package/dist/api/routes/actions.d.ts +4 -0
  6. package/dist/api/routes/actions.d.ts.map +1 -1
  7. package/dist/api/routes/actions.js +120 -0
  8. package/dist/api/routes/actions.js.map +1 -1
  9. package/dist/api/routes/admin-auth.d.ts.map +1 -1
  10. package/dist/api/routes/admin-auth.js +4 -1
  11. package/dist/api/routes/admin-auth.js.map +1 -1
  12. package/dist/api/routes/admin-credentials.d.ts +20 -0
  13. package/dist/api/routes/admin-credentials.d.ts.map +1 -0
  14. package/dist/api/routes/admin-credentials.js +115 -0
  15. package/dist/api/routes/admin-credentials.js.map +1 -0
  16. package/dist/api/routes/admin-settings.d.ts.map +1 -1
  17. package/dist/api/routes/admin-settings.js +70 -1
  18. package/dist/api/routes/admin-settings.js.map +1 -1
  19. package/dist/api/routes/admin-wallets.d.ts.map +1 -1
  20. package/dist/api/routes/admin-wallets.js +27 -14
  21. package/dist/api/routes/admin-wallets.js.map +1 -1
  22. package/dist/api/routes/connect-info.d.ts +2 -0
  23. package/dist/api/routes/connect-info.d.ts.map +1 -1
  24. package/dist/api/routes/connect-info.js +32 -1
  25. package/dist/api/routes/connect-info.js.map +1 -1
  26. package/dist/api/routes/credentials.d.ts +20 -0
  27. package/dist/api/routes/credentials.d.ts.map +1 -0
  28. package/dist/api/routes/credentials.js +120 -0
  29. package/dist/api/routes/credentials.js.map +1 -0
  30. package/dist/api/routes/defi-positions.d.ts.map +1 -1
  31. package/dist/api/routes/defi-positions.js +10 -0
  32. package/dist/api/routes/defi-positions.js.map +1 -1
  33. package/dist/api/routes/external-actions.d.ts +19 -0
  34. package/dist/api/routes/external-actions.d.ts.map +1 -0
  35. package/dist/api/routes/external-actions.js +199 -0
  36. package/dist/api/routes/external-actions.js.map +1 -0
  37. package/dist/api/routes/incoming.d.ts.map +1 -1
  38. package/dist/api/routes/incoming.js +2 -1
  39. package/dist/api/routes/incoming.js.map +1 -1
  40. package/dist/api/routes/index.d.ts +3 -0
  41. package/dist/api/routes/index.d.ts.map +1 -1
  42. package/dist/api/routes/index.js +3 -0
  43. package/dist/api/routes/index.js.map +1 -1
  44. package/dist/api/routes/nfts.js +24 -4
  45. package/dist/api/routes/nfts.js.map +1 -1
  46. package/dist/api/routes/openapi-schemas.d.ts +321 -139
  47. package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
  48. package/dist/api/routes/openapi-schemas.js +24 -0
  49. package/dist/api/routes/openapi-schemas.js.map +1 -1
  50. package/dist/api/routes/rpc-proxy.d.ts +55 -0
  51. package/dist/api/routes/rpc-proxy.d.ts.map +1 -0
  52. package/dist/api/routes/rpc-proxy.js +285 -0
  53. package/dist/api/routes/rpc-proxy.js.map +1 -0
  54. package/dist/api/routes/staking.d.ts.map +1 -1
  55. package/dist/api/routes/staking.js +15 -0
  56. package/dist/api/routes/staking.js.map +1 -1
  57. package/dist/api/routes/tokens.d.ts.map +1 -1
  58. package/dist/api/routes/tokens.js +8 -1
  59. package/dist/api/routes/tokens.js.map +1 -1
  60. package/dist/api/routes/transactions.d.ts +35 -0
  61. package/dist/api/routes/transactions.d.ts.map +1 -1
  62. package/dist/api/routes/transactions.js +220 -20
  63. package/dist/api/routes/transactions.js.map +1 -1
  64. package/dist/api/routes/wallet.d.ts.map +1 -1
  65. package/dist/api/routes/wallet.js +18 -4
  66. package/dist/api/routes/wallet.js.map +1 -1
  67. package/dist/api/server.d.ts +2 -0
  68. package/dist/api/server.d.ts.map +1 -1
  69. package/dist/api/server.js +52 -1
  70. package/dist/api/server.js.map +1 -1
  71. package/dist/infrastructure/action/action-provider-registry.d.ts.map +1 -1
  72. package/dist/infrastructure/action/action-provider-registry.js +12 -0
  73. package/dist/infrastructure/action/action-provider-registry.js.map +1 -1
  74. package/dist/infrastructure/credential/credential-crypto.d.ts +43 -0
  75. package/dist/infrastructure/credential/credential-crypto.d.ts.map +1 -0
  76. package/dist/infrastructure/credential/credential-crypto.js +64 -0
  77. package/dist/infrastructure/credential/credential-crypto.js.map +1 -0
  78. package/dist/infrastructure/credential/credential-vault.d.ts +42 -0
  79. package/dist/infrastructure/credential/credential-vault.d.ts.map +1 -0
  80. package/dist/infrastructure/credential/credential-vault.js +235 -0
  81. package/dist/infrastructure/credential/credential-vault.js.map +1 -0
  82. package/dist/infrastructure/credential/index.d.ts +6 -0
  83. package/dist/infrastructure/credential/index.d.ts.map +1 -0
  84. package/dist/infrastructure/credential/index.js +6 -0
  85. package/dist/infrastructure/credential/index.js.map +1 -0
  86. package/dist/infrastructure/database/migrate.d.ts +1 -1
  87. package/dist/infrastructure/database/migrate.d.ts.map +1 -1
  88. package/dist/infrastructure/database/migrate.js +191 -6
  89. package/dist/infrastructure/database/migrate.js.map +1 -1
  90. package/dist/infrastructure/database/schema.d.ts +281 -1
  91. package/dist/infrastructure/database/schema.d.ts.map +1 -1
  92. package/dist/infrastructure/database/schema.js +34 -3
  93. package/dist/infrastructure/database/schema.js.map +1 -1
  94. package/dist/infrastructure/keystore/re-encrypt.d.ts +9 -0
  95. package/dist/infrastructure/keystore/re-encrypt.d.ts.map +1 -1
  96. package/dist/infrastructure/keystore/re-encrypt.js +47 -1
  97. package/dist/infrastructure/keystore/re-encrypt.js.map +1 -1
  98. package/dist/infrastructure/settings/index.d.ts +2 -2
  99. package/dist/infrastructure/settings/index.d.ts.map +1 -1
  100. package/dist/infrastructure/settings/index.js +1 -1
  101. package/dist/infrastructure/settings/index.js.map +1 -1
  102. package/dist/infrastructure/settings/setting-keys.d.ts +16 -2
  103. package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
  104. package/dist/infrastructure/settings/setting-keys.js +296 -206
  105. package/dist/infrastructure/settings/setting-keys.js.map +1 -1
  106. package/dist/lifecycle/daemon.d.ts.map +1 -1
  107. package/dist/lifecycle/daemon.js +31 -0
  108. package/dist/lifecycle/daemon.js.map +1 -1
  109. package/dist/notifications/templates/message-templates.d.ts.map +1 -1
  110. package/dist/notifications/templates/message-templates.js +5 -6
  111. package/dist/notifications/templates/message-templates.js.map +1 -1
  112. package/dist/pipeline/database-policy-engine.d.ts +36 -0
  113. package/dist/pipeline/database-policy-engine.d.ts.map +1 -1
  114. package/dist/pipeline/database-policy-engine.js +185 -0
  115. package/dist/pipeline/database-policy-engine.js.map +1 -1
  116. package/dist/pipeline/external-action-pipeline.d.ts +64 -0
  117. package/dist/pipeline/external-action-pipeline.d.ts.map +1 -0
  118. package/dist/pipeline/external-action-pipeline.js +427 -0
  119. package/dist/pipeline/external-action-pipeline.js.map +1 -0
  120. package/dist/pipeline/pipeline.d.ts +4 -0
  121. package/dist/pipeline/pipeline.d.ts.map +1 -1
  122. package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -1
  123. package/dist/pipeline/resolve-effective-amount-usd.js +2 -1
  124. package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -1
  125. package/dist/pipeline/stages.d.ts.map +1 -1
  126. package/dist/pipeline/stages.js +59 -10
  127. package/dist/pipeline/stages.js.map +1 -1
  128. package/dist/rpc-proxy/completion-waiter.d.ts +35 -0
  129. package/dist/rpc-proxy/completion-waiter.d.ts.map +1 -0
  130. package/dist/rpc-proxy/completion-waiter.js +72 -0
  131. package/dist/rpc-proxy/completion-waiter.js.map +1 -0
  132. package/dist/rpc-proxy/dispatcher.d.ts +37 -0
  133. package/dist/rpc-proxy/dispatcher.d.ts.map +1 -0
  134. package/dist/rpc-proxy/dispatcher.js +54 -0
  135. package/dist/rpc-proxy/dispatcher.js.map +1 -0
  136. package/dist/rpc-proxy/index.d.ts +15 -0
  137. package/dist/rpc-proxy/index.d.ts.map +1 -0
  138. package/dist/rpc-proxy/index.js +15 -0
  139. package/dist/rpc-proxy/index.js.map +1 -0
  140. package/dist/rpc-proxy/json-rpc.d.ts +78 -0
  141. package/dist/rpc-proxy/json-rpc.d.ts.map +1 -0
  142. package/dist/rpc-proxy/json-rpc.js +123 -0
  143. package/dist/rpc-proxy/json-rpc.js.map +1 -0
  144. package/dist/rpc-proxy/method-handlers.d.ts +54 -0
  145. package/dist/rpc-proxy/method-handlers.d.ts.map +1 -0
  146. package/dist/rpc-proxy/method-handlers.js +171 -0
  147. package/dist/rpc-proxy/method-handlers.js.map +1 -0
  148. package/dist/rpc-proxy/nonce-tracker.d.ts +39 -0
  149. package/dist/rpc-proxy/nonce-tracker.d.ts.map +1 -0
  150. package/dist/rpc-proxy/nonce-tracker.js +80 -0
  151. package/dist/rpc-proxy/nonce-tracker.js.map +1 -0
  152. package/dist/rpc-proxy/passthrough.d.ts +37 -0
  153. package/dist/rpc-proxy/passthrough.d.ts.map +1 -0
  154. package/dist/rpc-proxy/passthrough.js +86 -0
  155. package/dist/rpc-proxy/passthrough.js.map +1 -0
  156. package/dist/rpc-proxy/sync-pipeline.d.ts +40 -0
  157. package/dist/rpc-proxy/sync-pipeline.d.ts.map +1 -0
  158. package/dist/rpc-proxy/sync-pipeline.js +74 -0
  159. package/dist/rpc-proxy/sync-pipeline.js.map +1 -0
  160. package/dist/rpc-proxy/tx-adapter.d.ts +79 -0
  161. package/dist/rpc-proxy/tx-adapter.d.ts.map +1 -0
  162. package/dist/rpc-proxy/tx-adapter.js +117 -0
  163. package/dist/rpc-proxy/tx-adapter.js.map +1 -0
  164. package/dist/services/async-polling-service.d.ts.map +1 -1
  165. package/dist/services/async-polling-service.js +95 -2
  166. package/dist/services/async-polling-service.js.map +1 -1
  167. package/dist/signing/bootstrap.d.ts +12 -0
  168. package/dist/signing/bootstrap.d.ts.map +1 -0
  169. package/dist/signing/bootstrap.js +15 -0
  170. package/dist/signing/bootstrap.js.map +1 -0
  171. package/dist/signing/capabilities/ecdsa-signer.d.ts +7 -0
  172. package/dist/signing/capabilities/ecdsa-signer.d.ts.map +1 -0
  173. package/dist/signing/capabilities/ecdsa-signer.js +42 -0
  174. package/dist/signing/capabilities/ecdsa-signer.js.map +1 -0
  175. package/dist/signing/capabilities/ed25519-signer.d.ts +7 -0
  176. package/dist/signing/capabilities/ed25519-signer.d.ts.map +1 -0
  177. package/dist/signing/capabilities/ed25519-signer.js +39 -0
  178. package/dist/signing/capabilities/ed25519-signer.js.map +1 -0
  179. package/dist/signing/capabilities/eip712-signer.d.ts +7 -0
  180. package/dist/signing/capabilities/eip712-signer.d.ts.map +1 -0
  181. package/dist/signing/capabilities/eip712-signer.js +35 -0
  182. package/dist/signing/capabilities/eip712-signer.js.map +1 -0
  183. package/dist/signing/capabilities/erc8128-signer.d.ts +7 -0
  184. package/dist/signing/capabilities/erc8128-signer.d.ts.map +1 -0
  185. package/dist/signing/capabilities/erc8128-signer.js +55 -0
  186. package/dist/signing/capabilities/erc8128-signer.js.map +1 -0
  187. package/dist/signing/capabilities/hmac-signer.d.ts +7 -0
  188. package/dist/signing/capabilities/hmac-signer.d.ts.map +1 -0
  189. package/dist/signing/capabilities/hmac-signer.js +32 -0
  190. package/dist/signing/capabilities/hmac-signer.js.map +1 -0
  191. package/dist/signing/capabilities/index.d.ts +13 -0
  192. package/dist/signing/capabilities/index.d.ts.map +1 -0
  193. package/dist/signing/capabilities/index.js +13 -0
  194. package/dist/signing/capabilities/index.js.map +1 -0
  195. package/dist/signing/capabilities/personal-signer.d.ts +7 -0
  196. package/dist/signing/capabilities/personal-signer.d.ts.map +1 -0
  197. package/dist/signing/capabilities/personal-signer.js +35 -0
  198. package/dist/signing/capabilities/personal-signer.js.map +1 -0
  199. package/dist/signing/capabilities/rsa-pss-signer.d.ts +7 -0
  200. package/dist/signing/capabilities/rsa-pss-signer.d.ts.map +1 -0
  201. package/dist/signing/capabilities/rsa-pss-signer.js +35 -0
  202. package/dist/signing/capabilities/rsa-pss-signer.js.map +1 -0
  203. package/dist/signing/index.d.ts +13 -0
  204. package/dist/signing/index.d.ts.map +1 -0
  205. package/dist/signing/index.js +5 -0
  206. package/dist/signing/index.js.map +1 -0
  207. package/dist/signing/registry.d.ts +36 -0
  208. package/dist/signing/registry.d.ts.map +1 -0
  209. package/dist/signing/registry.js +27 -0
  210. package/dist/signing/registry.js.map +1 -0
  211. package/dist/signing/signing-error.d.ts +22 -0
  212. package/dist/signing/signing-error.d.ts.map +1 -0
  213. package/dist/signing/signing-error.js +17 -0
  214. package/dist/signing/signing-error.js.map +1 -0
  215. package/dist/signing/types.d.ts +91 -0
  216. package/dist/signing/types.d.ts.map +1 -0
  217. package/dist/signing/types.js +2 -0
  218. package/dist/signing/types.js.map +1 -0
  219. package/package.json +6 -5
  220. package/public/admin/assets/index-COymjGTe.js +3 -0
  221. package/public/admin/assets/index-CTHU1J8K.css +1 -0
  222. package/public/admin/index.html +4 -2
  223. package/public/admin/assets/index-BpDnuS0k.css +0 -1
  224. package/public/admin/assets/index-By5VUJ-B.js +0 -3
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Credential Vault -- secure encrypted storage for external service credentials.
3
+ *
4
+ * ICredentialVault defines the interface for credential CRUD operations.
5
+ * LocalCredentialVault implements it using the local SQLite database with
6
+ * AES-256-GCM encryption (HKDF-derived key from master password).
7
+ *
8
+ * Resolution priority for name-based lookup:
9
+ * 1. Per-wallet credential (walletId + name match)
10
+ * 2. Global credential (walletId IS NULL + name match)
11
+ *
12
+ * @see docs/81-external-action-design.md D3.6 CredentialVault
13
+ */
14
+ import { eq, and, isNull } from 'drizzle-orm';
15
+ import { WAIaaSError } from '@waiaas/core';
16
+ import { walletCredentials } from '../database/schema.js';
17
+ import { generateId } from '../database/id.js';
18
+ import { encryptCredential, decryptCredential } from './credential-crypto.js';
19
+ // ---------------------------------------------------------------------------
20
+ // Implementation
21
+ // ---------------------------------------------------------------------------
22
+ // UUID v7 regex (loose): 8-4-4-4-12 hex groups
23
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
24
+ /**
25
+ * Build AAD string for a credential row.
26
+ * Format: "{id}:{walletId|global}:{type}"
27
+ */
28
+ function buildAad(id, walletId, type) {
29
+ return `${id}:${walletId ?? 'global'}:${type}`;
30
+ }
31
+ /**
32
+ * Convert a DB row to CredentialMetadata (without value).
33
+ */
34
+ function toMetadata(row) {
35
+ return {
36
+ id: row.id,
37
+ walletId: row.walletId,
38
+ type: row.type,
39
+ name: row.name,
40
+ metadata: JSON.parse(row.metadata),
41
+ expiresAt: row.expiresAt,
42
+ createdAt: row.createdAt instanceof Date
43
+ ? Math.floor(row.createdAt.getTime() / 1000)
44
+ : row.createdAt,
45
+ updatedAt: row.updatedAt instanceof Date
46
+ ? Math.floor(row.updatedAt.getTime() / 1000)
47
+ : row.updatedAt,
48
+ };
49
+ }
50
+ export class LocalCredentialVault {
51
+ db;
52
+ getMasterPassword;
53
+ constructor(db, getMasterPassword) {
54
+ this.db = db;
55
+ this.getMasterPassword = getMasterPassword;
56
+ }
57
+ // -----------------------------------------------------------------------
58
+ // create
59
+ // -----------------------------------------------------------------------
60
+ async create(walletId, params) {
61
+ // Check for duplicate name in same scope
62
+ // (SQLite NULL != NULL for unique indexes, so global duplicates need manual check)
63
+ const existingCondition = walletId
64
+ ? and(eq(walletCredentials.walletId, walletId), eq(walletCredentials.name, params.name))
65
+ : and(isNull(walletCredentials.walletId), eq(walletCredentials.name, params.name));
66
+ const existing = this.db.select().from(walletCredentials).where(existingCondition).get();
67
+ if (existing) {
68
+ throw new WAIaaSError('ACTION_VALIDATION_FAILED', {
69
+ message: `Credential with name "${params.name}" already exists for this scope`,
70
+ });
71
+ }
72
+ const id = generateId();
73
+ const masterPassword = this.getMasterPassword();
74
+ const aad = buildAad(id, walletId, params.type);
75
+ const encrypted = encryptCredential(params.value, masterPassword, aad);
76
+ const now = new Date();
77
+ try {
78
+ this.db
79
+ .insert(walletCredentials)
80
+ .values({
81
+ id,
82
+ walletId,
83
+ type: params.type,
84
+ name: params.name,
85
+ encryptedValue: encrypted.encryptedValue,
86
+ iv: encrypted.iv,
87
+ authTag: encrypted.authTag,
88
+ metadata: JSON.stringify(params.metadata ?? {}),
89
+ expiresAt: params.expiresAt ?? null,
90
+ createdAt: now,
91
+ updatedAt: now,
92
+ })
93
+ .run();
94
+ }
95
+ catch (err) {
96
+ // SQLite UNIQUE constraint violation (belt-and-suspenders after pre-check above)
97
+ if (err instanceof Error && err.message.includes('UNIQUE constraint failed')) {
98
+ throw new WAIaaSError('ACTION_VALIDATION_FAILED', {
99
+ message: `Credential with name "${params.name}" already exists for this scope`,
100
+ });
101
+ }
102
+ throw err;
103
+ }
104
+ return {
105
+ id,
106
+ walletId,
107
+ type: params.type,
108
+ name: params.name,
109
+ metadata: params.metadata ?? {},
110
+ expiresAt: params.expiresAt ?? null,
111
+ createdAt: Math.floor(now.getTime() / 1000),
112
+ updatedAt: Math.floor(now.getTime() / 1000),
113
+ };
114
+ }
115
+ // -----------------------------------------------------------------------
116
+ // get
117
+ // -----------------------------------------------------------------------
118
+ async get(ref, walletId) {
119
+ const row = await this.resolveRow(ref, walletId);
120
+ // Check expiry
121
+ if (row.expiresAt !== null) {
122
+ const nowSec = Math.floor(Date.now() / 1000);
123
+ if (row.expiresAt < nowSec) {
124
+ throw new WAIaaSError('CREDENTIAL_EXPIRED', {
125
+ message: `Credential "${row.name}" has expired`,
126
+ });
127
+ }
128
+ }
129
+ const masterPassword = this.getMasterPassword();
130
+ const aad = buildAad(row.id, row.walletId, row.type);
131
+ const value = decryptCredential({
132
+ encryptedValue: row.encryptedValue,
133
+ iv: row.iv,
134
+ authTag: row.authTag,
135
+ }, masterPassword, aad);
136
+ return {
137
+ ...toMetadata(row),
138
+ value,
139
+ };
140
+ }
141
+ // -----------------------------------------------------------------------
142
+ // list
143
+ // -----------------------------------------------------------------------
144
+ async list(walletId) {
145
+ const condition = walletId
146
+ ? eq(walletCredentials.walletId, walletId)
147
+ : isNull(walletCredentials.walletId);
148
+ const rows = this.db
149
+ .select()
150
+ .from(walletCredentials)
151
+ .where(condition)
152
+ .all();
153
+ return rows.map(toMetadata);
154
+ }
155
+ // -----------------------------------------------------------------------
156
+ // delete
157
+ // -----------------------------------------------------------------------
158
+ async delete(ref) {
159
+ const row = await this.resolveRow(ref);
160
+ this.db.delete(walletCredentials).where(eq(walletCredentials.id, row.id)).run();
161
+ }
162
+ // -----------------------------------------------------------------------
163
+ // rotate
164
+ // -----------------------------------------------------------------------
165
+ async rotate(ref, newValue) {
166
+ const row = await this.resolveRow(ref);
167
+ const masterPassword = this.getMasterPassword();
168
+ const aad = buildAad(row.id, row.walletId, row.type);
169
+ const encrypted = encryptCredential(newValue, masterPassword, aad);
170
+ const now = new Date();
171
+ this.db
172
+ .update(walletCredentials)
173
+ .set({
174
+ encryptedValue: encrypted.encryptedValue,
175
+ iv: encrypted.iv,
176
+ authTag: encrypted.authTag,
177
+ updatedAt: now,
178
+ })
179
+ .where(eq(walletCredentials.id, row.id))
180
+ .run();
181
+ return {
182
+ ...toMetadata(row),
183
+ updatedAt: Math.floor(now.getTime() / 1000),
184
+ };
185
+ }
186
+ // -----------------------------------------------------------------------
187
+ // Internal helpers
188
+ // -----------------------------------------------------------------------
189
+ /**
190
+ * Resolve a credential reference to a DB row.
191
+ *
192
+ * Reference formats:
193
+ * 1. UUID (direct lookup)
194
+ * 2. Name string (per-wallet priority, then global fallback)
195
+ */
196
+ async resolveRow(ref, walletId) {
197
+ // 1. UUID direct lookup
198
+ if (UUID_RE.test(ref)) {
199
+ const row = this.db
200
+ .select()
201
+ .from(walletCredentials)
202
+ .where(eq(walletCredentials.id, ref))
203
+ .get();
204
+ if (!row) {
205
+ throw new WAIaaSError('CREDENTIAL_NOT_FOUND', {
206
+ message: `Credential not found: ${ref}`,
207
+ });
208
+ }
209
+ return row;
210
+ }
211
+ // 2. Name-based resolution with per-wallet priority
212
+ if (walletId) {
213
+ // Try per-wallet first
214
+ const perWallet = this.db
215
+ .select()
216
+ .from(walletCredentials)
217
+ .where(and(eq(walletCredentials.walletId, walletId), eq(walletCredentials.name, ref)))
218
+ .get();
219
+ if (perWallet)
220
+ return perWallet;
221
+ }
222
+ // Try global fallback
223
+ const global = this.db
224
+ .select()
225
+ .from(walletCredentials)
226
+ .where(and(isNull(walletCredentials.walletId), eq(walletCredentials.name, ref)))
227
+ .get();
228
+ if (global)
229
+ return global;
230
+ throw new WAIaaSError('CREDENTIAL_NOT_FOUND', {
231
+ message: `Credential not found: ${ref}`,
232
+ });
233
+ }
234
+ }
235
+ //# sourceMappingURL=credential-vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-vault.js","sourceRoot":"","sources":["../../../src/infrastructure/credential/credential-vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Credential vault module barrel export.
3
+ */
4
+ export { deriveCredentialKey, encryptCredential, decryptCredential, type EncryptedCredentialData, } from './credential-crypto.js';
5
+ export { type ICredentialVault, LocalCredentialVault, } from './credential-vault.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/credential/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,uBAAuB,GAC7B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,KAAK,gBAAgB,EACrB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Credential vault module barrel export.
3
+ */
4
+ export { deriveCredentialKey, encryptCredential, decryptCredential, } from './credential-crypto.js';
5
+ export { LocalCredentialVault, } from './credential-vault.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infrastructure/credential/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAEL,oBAAoB,GACrB,MAAM,uBAAuB,CAAC"}
@@ -28,7 +28,7 @@ import type { Database } from 'better-sqlite3';
28
28
  * pushSchema() records this version for fresh databases so migrations are skipped.
29
29
  * Increment this whenever DDL statements are updated to match a new migration.
30
30
  */
31
- export declare const LATEST_SCHEMA_VERSION = 54;
31
+ export declare const LATEST_SCHEMA_VERSION = 58;
32
32
  /** A single incremental migration (ALTER TABLE, CREATE INDEX, etc.). */
33
33
  export interface Migration {
34
34
  /** Monotonically increasing version number (must be > 1, since version 1 = initial schema). */
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/database/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAmD/C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AA0kBxC,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,2FAA2F;IAC3F,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;CAChC;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,EAAO,CAAC;AAm2E1C;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,UAAU,GAAE,SAAS,EAAe,GACnC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgFtC;AAMD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAsGjD"}
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/database/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAmD/C;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AA4mBxC,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,2FAA2F;IAC3F,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;CAChC;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,EAAO,CAAC;AAghF1C;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,UAAU,GAAE,SAAS,EAAe,GACnC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAgFtC;AAMD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAsGjD"}
@@ -47,14 +47,14 @@ const LEGACY_NETWORK_NORMALIZE = {
47
47
  testnet: 'solana-testnet',
48
48
  };
49
49
  // ---------------------------------------------------------------------------
50
- // DDL statements for all 30 tables (latest schema: wallets + wallet_id + session_wallets + token_registry + settings + telegram_users + wc_sessions + wc_store + incoming_transactions + incoming_tx_cursors + defi_positions + wallet_apps + webhooks + webhook_logs + agent_identities + reputation_cache + nft_metadata_cache + userop_builds + hyperliquid_orders + hyperliquid_sub_accounts + polymarket_orders + polymarket_positions + polymarket_api_keys)
50
+ // DDL statements for all 31 tables (latest schema: wallets + wallet_id + session_wallets + token_registry + settings + telegram_users + wc_sessions + wc_store + incoming_transactions + incoming_tx_cursors + defi_positions + wallet_apps + webhooks + webhook_logs + agent_identities + reputation_cache + nft_metadata_cache + userop_builds + hyperliquid_orders + hyperliquid_sub_accounts + polymarket_orders + polymarket_positions + polymarket_api_keys + wallet_credentials)
51
51
  // ---------------------------------------------------------------------------
52
52
  /**
53
53
  * The latest schema version that getCreateTableStatements() represents.
54
54
  * pushSchema() records this version for fresh databases so migrations are skipped.
55
55
  * Increment this whenever DDL statements are updated to match a new migration.
56
56
  */
57
- export const LATEST_SCHEMA_VERSION = 54;
57
+ export const LATEST_SCHEMA_VERSION = 58;
58
58
  function getCreateTableStatements() {
59
59
  return [
60
60
  // Table 1: wallets (renamed from agents in v3, environment model in v6b, v29.3: default_network removed)
@@ -136,8 +136,12 @@ function getCreateTableStatements() {
136
136
  error TEXT,
137
137
  metadata TEXT,
138
138
  network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)})),
139
- bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED')),
140
- bridge_metadata TEXT
139
+ bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED', 'PARTIALLY_FILLED', 'FILLED', 'CANCELED', 'SETTLED', 'EXPIRED')),
140
+ bridge_metadata TEXT,
141
+ action_kind TEXT NOT NULL DEFAULT 'contractCall',
142
+ venue TEXT,
143
+ operation TEXT,
144
+ external_id TEXT
141
145
  )`,
142
146
  // Table 4: policies (network column added in v8)
143
147
  `CREATE TABLE IF NOT EXISTS policies (
@@ -472,6 +476,21 @@ function getCreateTableStatements() {
472
476
  proxy_address TEXT,
473
477
  created_at INTEGER NOT NULL DEFAULT (unixepoch()),
474
478
  UNIQUE(wallet_id)
479
+ )`,
480
+ // Table 31: wallet_credentials (External Action credential vault, v55)
481
+ `CREATE TABLE IF NOT EXISTS wallet_credentials (
482
+ id TEXT NOT NULL PRIMARY KEY,
483
+ wallet_id TEXT,
484
+ type TEXT NOT NULL CHECK (type IN ('api-key','hmac-secret','rsa-private-key','session-token','custom')),
485
+ name TEXT NOT NULL,
486
+ encrypted_value BLOB NOT NULL,
487
+ iv BLOB NOT NULL,
488
+ auth_tag BLOB NOT NULL,
489
+ metadata TEXT NOT NULL DEFAULT '{}',
490
+ expires_at INTEGER,
491
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
492
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
493
+ FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE
475
494
  )`,
476
495
  ];
477
496
  }
@@ -577,6 +596,17 @@ function getCreateIndexStatements() {
577
596
  'CREATE INDEX IF NOT EXISTS idx_pm_positions_condition ON polymarket_positions(condition_id)',
578
597
  'CREATE INDEX IF NOT EXISTS idx_pm_positions_resolved ON polymarket_positions(market_resolved)',
579
598
  // v54: polymarket_api_keys indexes (UNIQUE on wallet_id is inline)
599
+ // v55: wallet_credentials indexes
600
+ 'CREATE UNIQUE INDEX IF NOT EXISTS idx_wallet_credentials_wallet_name ON wallet_credentials(wallet_id, name)',
601
+ 'CREATE INDEX IF NOT EXISTS idx_wallet_credentials_global_name ON wallet_credentials(name) WHERE wallet_id IS NULL',
602
+ 'CREATE INDEX IF NOT EXISTS idx_wallet_credentials_wallet_id ON wallet_credentials(wallet_id)',
603
+ 'CREATE INDEX IF NOT EXISTS idx_wallet_credentials_expires_at ON wallet_credentials(expires_at) WHERE expires_at IS NOT NULL',
604
+ // v56: transactions action tracking indexes
605
+ 'CREATE INDEX IF NOT EXISTS idx_transactions_action_kind ON transactions(action_kind)',
606
+ 'CREATE INDEX IF NOT EXISTS idx_transactions_venue ON transactions(venue) WHERE venue IS NOT NULL',
607
+ 'CREATE INDEX IF NOT EXISTS idx_transactions_external_id ON transactions(external_id) WHERE external_id IS NOT NULL',
608
+ // v57: composite index for external action tracking queries
609
+ 'CREATE INDEX IF NOT EXISTS idx_transactions_action_kind_bridge_status ON transactions(action_kind, bridge_status) WHERE bridge_status IS NOT NULL',
580
610
  ];
581
611
  }
582
612
  /**
@@ -1659,7 +1689,7 @@ MIGRATIONS.push({
1659
1689
  error TEXT,
1660
1690
  metadata TEXT,
1661
1691
  network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES_WITH_LEGACY)})),
1662
- bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED')),
1692
+ bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED', 'PARTIALLY_FILLED', 'FILLED', 'CANCELED', 'SETTLED', 'EXPIRED')),
1663
1693
  bridge_metadata TEXT
1664
1694
  )`);
1665
1695
  // Step 2: Copy existing data (bridge_status and bridge_metadata default to NULL)
@@ -1953,7 +1983,7 @@ MIGRATIONS.push({
1953
1983
  error TEXT,
1954
1984
  metadata TEXT,
1955
1985
  network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)})),
1956
- bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED')),
1986
+ bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED', 'PARTIALLY_FILLED', 'FILLED', 'CANCELED', 'SETTLED', 'EXPIRED')),
1957
1987
  bridge_metadata TEXT
1958
1988
  )`);
1959
1989
  sqlite.exec(`INSERT INTO transactions_new
@@ -2688,6 +2718,161 @@ MIGRATIONS.push({
2688
2718
  }
2689
2719
  },
2690
2720
  });
2721
+ // ---------------------------------------------------------------------------
2722
+ // v55: wallet_credentials table for External Action credential vault
2723
+ // ---------------------------------------------------------------------------
2724
+ MIGRATIONS.push({
2725
+ version: 55,
2726
+ description: 'Create wallet_credentials table for External Action credential vault',
2727
+ up: (sqlite) => {
2728
+ // Idempotent check
2729
+ const tables = sqlite
2730
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='wallet_credentials'")
2731
+ .all();
2732
+ if (tables.length > 0)
2733
+ return;
2734
+ sqlite.exec(`
2735
+ CREATE TABLE wallet_credentials (
2736
+ id TEXT NOT NULL PRIMARY KEY,
2737
+ wallet_id TEXT,
2738
+ type TEXT NOT NULL CHECK (type IN ('api-key','hmac-secret','rsa-private-key','session-token','custom')),
2739
+ name TEXT NOT NULL,
2740
+ encrypted_value BLOB NOT NULL,
2741
+ iv BLOB NOT NULL,
2742
+ auth_tag BLOB NOT NULL,
2743
+ metadata TEXT NOT NULL DEFAULT '{}',
2744
+ expires_at INTEGER,
2745
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
2746
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
2747
+ FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE
2748
+ );
2749
+ CREATE UNIQUE INDEX idx_wallet_credentials_wallet_name ON wallet_credentials(wallet_id, name);
2750
+ CREATE INDEX idx_wallet_credentials_global_name ON wallet_credentials(name) WHERE wallet_id IS NULL;
2751
+ CREATE INDEX idx_wallet_credentials_wallet_id ON wallet_credentials(wallet_id);
2752
+ CREATE INDEX idx_wallet_credentials_expires_at ON wallet_credentials(expires_at) WHERE expires_at IS NOT NULL;
2753
+ `);
2754
+ },
2755
+ });
2756
+ // ---------------------------------------------------------------------------
2757
+ // v56: transactions table action tracking columns
2758
+ // ---------------------------------------------------------------------------
2759
+ MIGRATIONS.push({
2760
+ version: 56,
2761
+ description: 'Add action_kind, venue, operation, external_id columns to transactions',
2762
+ up: (sqlite) => {
2763
+ // Check if columns already exist (pushSchema may have already added them)
2764
+ const cols = sqlite.prepare('PRAGMA table_info(transactions)').all()
2765
+ .map(c => c.name);
2766
+ if (!cols.includes('action_kind')) {
2767
+ sqlite.exec("ALTER TABLE transactions ADD COLUMN action_kind TEXT NOT NULL DEFAULT 'contractCall'");
2768
+ }
2769
+ if (!cols.includes('venue')) {
2770
+ sqlite.exec('ALTER TABLE transactions ADD COLUMN venue TEXT');
2771
+ }
2772
+ if (!cols.includes('operation')) {
2773
+ sqlite.exec('ALTER TABLE transactions ADD COLUMN operation TEXT');
2774
+ }
2775
+ if (!cols.includes('external_id')) {
2776
+ sqlite.exec('ALTER TABLE transactions ADD COLUMN external_id TEXT');
2777
+ }
2778
+ // Create indexes (idempotent with IF NOT EXISTS)
2779
+ sqlite.exec('CREATE INDEX IF NOT EXISTS idx_transactions_action_kind ON transactions(action_kind)');
2780
+ sqlite.exec('CREATE INDEX IF NOT EXISTS idx_transactions_venue ON transactions(venue) WHERE venue IS NOT NULL');
2781
+ sqlite.exec('CREATE INDEX IF NOT EXISTS idx_transactions_external_id ON transactions(external_id) WHERE external_id IS NOT NULL');
2782
+ },
2783
+ });
2784
+ // ---------------------------------------------------------------------------
2785
+ // v57: composite index for external action tracking queries
2786
+ // ---------------------------------------------------------------------------
2787
+ MIGRATIONS.push({
2788
+ version: 57,
2789
+ description: 'Add composite index idx_transactions_action_kind_bridge_status',
2790
+ up: (sqlite) => {
2791
+ sqlite.exec('CREATE INDEX IF NOT EXISTS idx_transactions_action_kind_bridge_status ON transactions(action_kind, bridge_status) WHERE bridge_status IS NOT NULL');
2792
+ },
2793
+ });
2794
+ // ---------------------------------------------------------------------------
2795
+ // v58: Update transactions type CHECK constraint to include CONTRACT_DEPLOY
2796
+ // ---------------------------------------------------------------------------
2797
+ MIGRATIONS.push({
2798
+ version: 58,
2799
+ description: 'Add CONTRACT_DEPLOY to transactions type CHECK constraint (12-step table recreation)',
2800
+ managesOwnTransaction: true,
2801
+ up: (sqlite) => {
2802
+ sqlite.exec('BEGIN');
2803
+ try {
2804
+ // Step 1: Create transactions_new with updated CHECK constraints (CONTRACT_DEPLOY in TRANSACTION_TYPES)
2805
+ sqlite.exec(`CREATE TABLE transactions_new (
2806
+ id TEXT PRIMARY KEY,
2807
+ wallet_id TEXT NOT NULL REFERENCES wallets(id) ON DELETE RESTRICT,
2808
+ session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
2809
+ chain TEXT NOT NULL,
2810
+ tx_hash TEXT,
2811
+ type TEXT NOT NULL CHECK (type IN (${inList(TRANSACTION_TYPES)})),
2812
+ amount TEXT,
2813
+ to_address TEXT,
2814
+ token_mint TEXT,
2815
+ contract_address TEXT,
2816
+ method_signature TEXT,
2817
+ spender_address TEXT,
2818
+ approved_amount TEXT,
2819
+ parent_id TEXT REFERENCES transactions_new(id) ON DELETE CASCADE,
2820
+ batch_index INTEGER,
2821
+ status TEXT NOT NULL DEFAULT 'PENDING' CHECK (status IN (${inList(TRANSACTION_STATUSES)})),
2822
+ tier TEXT CHECK (tier IS NULL OR tier IN (${inList(POLICY_TIERS)})),
2823
+ queued_at INTEGER,
2824
+ executed_at INTEGER,
2825
+ created_at INTEGER NOT NULL,
2826
+ reserved_amount TEXT,
2827
+ amount_usd REAL,
2828
+ reserved_amount_usd REAL,
2829
+ error TEXT,
2830
+ metadata TEXT,
2831
+ network TEXT CHECK (network IS NULL OR network IN (${inList(NETWORK_TYPES)})),
2832
+ bridge_status TEXT CHECK (bridge_status IS NULL OR bridge_status IN ('PENDING', 'COMPLETED', 'FAILED', 'BRIDGE_MONITORING', 'TIMEOUT', 'REFUNDED', 'PARTIALLY_FILLED', 'FILLED', 'CANCELED', 'SETTLED', 'EXPIRED')),
2833
+ bridge_metadata TEXT,
2834
+ action_kind TEXT NOT NULL DEFAULT 'contractCall',
2835
+ venue TEXT,
2836
+ operation TEXT,
2837
+ external_id TEXT
2838
+ )`);
2839
+ // Step 2: Copy existing data
2840
+ sqlite.exec(`INSERT INTO transactions_new (id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, amount_usd, reserved_amount_usd, error, metadata, network, bridge_status, bridge_metadata, action_kind, venue, operation, external_id)
2841
+ SELECT id, wallet_id, session_id, chain, tx_hash, type, amount, to_address, token_mint, contract_address, method_signature, spender_address, approved_amount, parent_id, batch_index, status, tier, queued_at, executed_at, created_at, reserved_amount, amount_usd, reserved_amount_usd, error, metadata, network, bridge_status, bridge_metadata, action_kind, venue, operation, external_id FROM transactions`);
2842
+ // Step 3: Drop old table
2843
+ sqlite.exec('DROP TABLE transactions');
2844
+ // Step 4: Rename new table
2845
+ sqlite.exec('ALTER TABLE transactions_new RENAME TO transactions');
2846
+ // Step 5: Recreate all 14 indexes
2847
+ sqlite.exec('CREATE INDEX idx_transactions_wallet_status ON transactions(wallet_id, status)');
2848
+ sqlite.exec('CREATE INDEX idx_transactions_session_id ON transactions(session_id)');
2849
+ sqlite.exec('CREATE UNIQUE INDEX idx_transactions_tx_hash ON transactions(tx_hash)');
2850
+ sqlite.exec('CREATE INDEX idx_transactions_queued_at ON transactions(queued_at)');
2851
+ sqlite.exec('CREATE INDEX idx_transactions_created_at ON transactions(created_at)');
2852
+ sqlite.exec('CREATE INDEX idx_transactions_type ON transactions(type)');
2853
+ sqlite.exec('CREATE INDEX idx_transactions_contract_address ON transactions(contract_address)');
2854
+ sqlite.exec('CREATE INDEX idx_transactions_parent_id ON transactions(parent_id)');
2855
+ sqlite.exec("CREATE INDEX idx_transactions_bridge_status ON transactions(bridge_status) WHERE bridge_status IS NOT NULL");
2856
+ sqlite.exec("CREATE INDEX idx_transactions_gas_waiting ON transactions(status) WHERE status = 'GAS_WAITING'");
2857
+ sqlite.exec('CREATE INDEX idx_transactions_action_kind ON transactions(action_kind)');
2858
+ sqlite.exec("CREATE INDEX idx_transactions_venue ON transactions(venue) WHERE venue IS NOT NULL");
2859
+ sqlite.exec("CREATE INDEX idx_transactions_external_id ON transactions(external_id) WHERE external_id IS NOT NULL");
2860
+ sqlite.exec('CREATE INDEX idx_transactions_action_kind_bridge_status ON transactions(action_kind, bridge_status) WHERE bridge_status IS NOT NULL');
2861
+ // Step 6: Commit
2862
+ sqlite.exec('COMMIT');
2863
+ }
2864
+ catch (err) {
2865
+ sqlite.exec('ROLLBACK');
2866
+ throw err;
2867
+ }
2868
+ // Step 7: Re-enable foreign keys and verify integrity
2869
+ sqlite.pragma('foreign_keys = ON');
2870
+ const fkErrors = sqlite.pragma('foreign_key_check');
2871
+ if (fkErrors.length > 0) {
2872
+ throw new Error(`FK integrity violation after v58: ${JSON.stringify(fkErrors)}`);
2873
+ }
2874
+ },
2875
+ });
2691
2876
  /**
2692
2877
  * Run incremental migrations against the database.
2693
2878
  *