@bopen-io/wallet-toolbox 2.15.0-bopen.1 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +183 -45
  2. package/README.md +134 -98
  3. package/docs/client.md +2947 -3080
  4. package/docs/monitor.md +154 -165
  5. package/docs/no-send-expiry.md +7 -2
  6. package/docs/services.md +822 -885
  7. package/docs/setup.md +1 -46
  8. package/docs/storage.md +1636 -1654
  9. package/docs/wallet.md +1975 -2132
  10. package/out/src/CWIStyleWalletManager.d.ts +36 -5
  11. package/out/src/CWIStyleWalletManager.d.ts.map +1 -1
  12. package/out/src/CWIStyleWalletManager.js +356 -60
  13. package/out/src/CWIStyleWalletManager.js.map +1 -1
  14. package/out/src/Setup.d.ts +0 -10
  15. package/out/src/Setup.d.ts.map +1 -1
  16. package/out/src/Setup.js +0 -24
  17. package/out/src/Setup.js.map +1 -1
  18. package/out/src/Wallet.d.ts.map +1 -1
  19. package/out/src/Wallet.js +8 -3
  20. package/out/src/Wallet.js.map +1 -1
  21. package/out/src/WalletAuthenticationManager.d.ts +3 -0
  22. package/out/src/WalletAuthenticationManager.d.ts.map +1 -1
  23. package/out/src/WalletAuthenticationManager.js +86 -3
  24. package/out/src/WalletAuthenticationManager.js.map +1 -1
  25. package/out/src/WalletPermissionsManager.d.ts +63 -9
  26. package/out/src/WalletPermissionsManager.d.ts.map +1 -1
  27. package/out/src/WalletPermissionsManager.js +213 -49
  28. package/out/src/WalletPermissionsManager.js.map +1 -1
  29. package/out/src/monitor/Monitor.js +1 -1
  30. package/out/src/monitor/Monitor.js.map +1 -1
  31. package/out/src/monitor/MonitorDaemon.d.ts +0 -2
  32. package/out/src/monitor/MonitorDaemon.d.ts.map +1 -1
  33. package/out/src/monitor/MonitorDaemon.js +1 -9
  34. package/out/src/monitor/MonitorDaemon.js.map +1 -1
  35. package/out/src/monitor/monitorValidation.d.ts +2 -1
  36. package/out/src/monitor/monitorValidation.d.ts.map +1 -1
  37. package/out/src/monitor/monitorValidation.js +2 -2
  38. package/out/src/monitor/monitorValidation.js.map +1 -1
  39. package/out/src/monitor/tasks/TaskNewHeader.d.ts.map +1 -1
  40. package/out/src/monitor/tasks/TaskNewHeader.js +1 -1
  41. package/out/src/monitor/tasks/TaskNewHeader.js.map +1 -1
  42. package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -1
  43. package/out/src/monitor/tasks/TaskReviewUtxos.js +2 -1
  44. package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -1
  45. package/out/src/sdk/WERR_errors.d.ts +4 -0
  46. package/out/src/sdk/WERR_errors.d.ts.map +1 -1
  47. package/out/src/sdk/WERR_errors.js +4 -0
  48. package/out/src/sdk/WERR_errors.js.map +1 -1
  49. package/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -1
  50. package/out/src/sdk/WalletErrorFromJson.js +23 -2
  51. package/out/src/sdk/WalletErrorFromJson.js.map +1 -1
  52. package/out/src/sdk/WalletStorage.interfaces.d.ts +11 -0
  53. package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
  54. package/out/src/sdk/types.d.ts +12 -1
  55. package/out/src/sdk/types.d.ts.map +1 -1
  56. package/out/src/sdk/types.js +19 -2
  57. package/out/src/sdk/types.js.map +1 -1
  58. package/out/src/services/Services.d.ts.map +1 -1
  59. package/out/src/services/Services.js +5 -3
  60. package/out/src/services/Services.js.map +1 -1
  61. package/out/src/services/chaintracker/BHServiceClient.js +2 -2
  62. package/out/src/services/chaintracker/BHServiceClient.js.map +1 -1
  63. package/out/src/services/chaintracker/chaintracks/Chaintracks.js +2 -2
  64. package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
  65. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.d.ts.map +1 -1
  66. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js +3 -1
  67. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js.map +1 -1
  68. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.d.ts.map +1 -1
  69. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js +3 -1
  70. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js.map +1 -1
  71. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js +1 -1
  72. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js.map +1 -1
  73. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js +1 -1
  74. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js.map +1 -1
  75. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js +1 -1
  76. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js.map +1 -1
  77. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.d.ts.map +1 -1
  78. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js +2 -0
  79. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js.map +1 -1
  80. package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js +2 -2
  81. package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js.map +1 -1
  82. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js +6 -6
  83. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js.map +1 -1
  84. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js +2 -2
  85. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js.map +1 -1
  86. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.d.ts +0 -5
  87. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.d.ts.map +1 -1
  88. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js +5 -13
  89. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js.map +1 -1
  90. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts +1 -0
  91. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts.map +1 -1
  92. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js +11 -3
  93. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js.map +1 -1
  94. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
  95. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +13 -9
  96. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
  97. package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.d.ts.map +1 -1
  98. package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js +2 -2
  99. package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js.map +1 -1
  100. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.d.ts.map +1 -1
  101. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js +2 -2
  102. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js.map +1 -1
  103. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts +23 -5
  104. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts.map +1 -1
  105. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js +58 -16
  106. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js.map +1 -1
  107. package/out/src/services/createDefaultWalletServicesOptions.d.ts +6 -3
  108. package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
  109. package/out/src/services/createDefaultWalletServicesOptions.js +18 -6
  110. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  111. package/out/src/services/networkConfig.d.ts +7 -0
  112. package/out/src/services/networkConfig.d.ts.map +1 -1
  113. package/out/src/services/networkConfig.js +25 -2
  114. package/out/src/services/networkConfig.js.map +1 -1
  115. package/out/src/services/providers/SdkWhatsOnChain.d.ts +8 -2
  116. package/out/src/services/providers/SdkWhatsOnChain.d.ts.map +1 -1
  117. package/out/src/services/providers/SdkWhatsOnChain.js +17 -6
  118. package/out/src/services/providers/SdkWhatsOnChain.js.map +1 -1
  119. package/out/src/services/validateMerklePathResult.d.ts +4 -3
  120. package/out/src/services/validateMerklePathResult.d.ts.map +1 -1
  121. package/out/src/services/validateMerklePathResult.js +6 -6
  122. package/out/src/services/validateMerklePathResult.js.map +1 -1
  123. package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts.map +1 -1
  124. package/out/src/signer/actionBatch/ActionBatchWorkspace.js +3 -2
  125. package/out/src/signer/actionBatch/ActionBatchWorkspace.js.map +1 -1
  126. package/out/src/signer/methods/createAction.d.ts +32 -1
  127. package/out/src/signer/methods/createAction.d.ts.map +1 -1
  128. package/out/src/signer/methods/createAction.js +56 -1
  129. package/out/src/signer/methods/createAction.js.map +1 -1
  130. package/out/src/signer/methods/internalizeAction.js +1 -1
  131. package/out/src/signer/methods/internalizeAction.js.map +1 -1
  132. package/out/src/signer/methods/signAction.js +8 -1
  133. package/out/src/signer/methods/signAction.js.map +1 -1
  134. package/out/src/storage/StorageIdb.js +4 -4
  135. package/out/src/storage/StorageIdb.js.map +1 -1
  136. package/out/src/storage/StorageKnex.d.ts +6 -5
  137. package/out/src/storage/StorageKnex.d.ts.map +1 -1
  138. package/out/src/storage/StorageKnex.js +321 -115
  139. package/out/src/storage/StorageKnex.js.map +1 -1
  140. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  141. package/out/src/storage/WalletStorageManager.js +5 -0
  142. package/out/src/storage/WalletStorageManager.js.map +1 -1
  143. package/out/src/storage/adminServer/adminServer.d.ts.map +1 -1
  144. package/out/src/storage/adminServer/adminServer.js +41 -3
  145. package/out/src/storage/adminServer/adminServer.js.map +1 -1
  146. package/out/src/storage/index.all.d.ts +0 -1
  147. package/out/src/storage/index.all.d.ts.map +1 -1
  148. package/out/src/storage/index.all.js +0 -1
  149. package/out/src/storage/index.all.js.map +1 -1
  150. package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -1
  151. package/out/src/storage/methods/ListOutputsSpecOp.js +84 -0
  152. package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -1
  153. package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts.map +1 -1
  154. package/out/src/storage/methods/attemptToPostReqsToNetwork.js +7 -3
  155. package/out/src/storage/methods/attemptToPostReqsToNetwork.js.map +1 -1
  156. package/out/src/storage/methods/createAction.d.ts +5 -0
  157. package/out/src/storage/methods/createAction.d.ts.map +1 -1
  158. package/out/src/storage/methods/createAction.js +13 -6
  159. package/out/src/storage/methods/createAction.js.map +1 -1
  160. package/out/src/storage/methods/generateChange.d.ts +6 -0
  161. package/out/src/storage/methods/generateChange.d.ts.map +1 -1
  162. package/out/src/storage/methods/generateChange.js +10 -3
  163. package/out/src/storage/methods/generateChange.js.map +1 -1
  164. package/out/src/storage/methods/internalizeAction.d.ts +8 -1
  165. package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
  166. package/out/src/storage/methods/internalizeAction.js +106 -42
  167. package/out/src/storage/methods/internalizeAction.js.map +1 -1
  168. package/out/src/storage/methods/listActionsKnex.d.ts.map +1 -1
  169. package/out/src/storage/methods/listActionsKnex.js +1 -0
  170. package/out/src/storage/methods/listActionsKnex.js.map +1 -1
  171. package/out/src/storage/methods/listOutputsKnex.d.ts.map +1 -1
  172. package/out/src/storage/methods/listOutputsKnex.js +2 -1
  173. package/out/src/storage/methods/listOutputsKnex.js.map +1 -1
  174. package/out/src/storage/methods/noSendExpiry.d.ts.map +1 -1
  175. package/out/src/storage/methods/noSendExpiry.js +14 -4
  176. package/out/src/storage/methods/noSendExpiry.js.map +1 -1
  177. package/out/src/storage/methods/purgeData.d.ts.map +1 -1
  178. package/out/src/storage/methods/purgeData.js +3 -0
  179. package/out/src/storage/methods/purgeData.js.map +1 -1
  180. package/out/src/storage/methods/reviewStatus.d.ts.map +1 -1
  181. package/out/src/storage/methods/reviewStatus.js +3 -0
  182. package/out/src/storage/methods/reviewStatus.js.map +1 -1
  183. package/out/src/storage/portable/index.js +12 -38
  184. package/out/src/storage/portable/index.js.map +1 -1
  185. package/out/src/storage/remoting/StorageClientBase.d.ts.map +1 -1
  186. package/out/src/storage/remoting/StorageClientBase.js +15 -5
  187. package/out/src/storage/remoting/StorageClientBase.js.map +1 -1
  188. package/out/src/storage/remoting/StorageServer.d.ts +4 -17
  189. package/out/src/storage/remoting/StorageServer.d.ts.map +1 -1
  190. package/out/src/storage/remoting/StorageServer.js +25 -23
  191. package/out/src/storage/remoting/StorageServer.js.map +1 -1
  192. package/out/src/storage/remoting/syncChunkBinary.d.ts +10 -0
  193. package/out/src/storage/remoting/syncChunkBinary.d.ts.map +1 -1
  194. package/out/src/storage/remoting/syncChunkBinary.js +15 -11
  195. package/out/src/storage/remoting/syncChunkBinary.js.map +1 -1
  196. package/out/src/storage/schema/KnexMigrations.d.ts +3 -7
  197. package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
  198. package/out/src/storage/schema/KnexMigrations.js +86 -166
  199. package/out/src/storage/schema/KnexMigrations.js.map +1 -1
  200. package/out/src/storage/sync/liveSyncGuards.d.ts +11 -0
  201. package/out/src/storage/sync/liveSyncGuards.d.ts.map +1 -0
  202. package/out/src/storage/sync/liveSyncGuards.js +22 -0
  203. package/out/src/storage/sync/liveSyncGuards.js.map +1 -0
  204. package/out/src/utility/actionOutputAuthorizations.d.ts +10 -0
  205. package/out/src/utility/actionOutputAuthorizations.d.ts.map +1 -0
  206. package/out/src/utility/actionOutputAuthorizations.js +25 -0
  207. package/out/src/utility/actionOutputAuthorizations.js.map +1 -0
  208. package/out/src/utility/index.all.d.ts +1 -0
  209. package/out/src/utility/index.all.d.ts.map +1 -1
  210. package/out/src/utility/index.all.js +1 -0
  211. package/out/src/utility/index.all.js.map +1 -1
  212. package/out/src/utility/index.client.d.ts +1 -0
  213. package/out/src/utility/index.client.d.ts.map +1 -1
  214. package/out/src/utility/index.client.js +1 -0
  215. package/out/src/utility/index.client.js.map +1 -1
  216. package/out/src/utility/numericTotalOutputs.d.ts +7 -0
  217. package/out/src/utility/numericTotalOutputs.d.ts.map +1 -0
  218. package/out/src/utility/numericTotalOutputs.js +15 -0
  219. package/out/src/utility/numericTotalOutputs.js.map +1 -0
  220. package/out/src/utility/utilityHelpers.d.ts.map +1 -1
  221. package/out/src/utility/utilityHelpers.js +2 -0
  222. package/out/src/utility/utilityHelpers.js.map +1 -1
  223. package/package.json +19 -24
  224. package/out/src/storage/adminServer/reqReviewQuery.d.ts +0 -41
  225. package/out/src/storage/adminServer/reqReviewQuery.d.ts.map +0 -1
  226. package/out/src/storage/adminServer/reqReviewQuery.js +0 -67
  227. package/out/src/storage/adminServer/reqReviewQuery.js.map +0 -1
  228. package/out/src/storage/knexPostgres.d.ts +0 -16
  229. package/out/src/storage/knexPostgres.d.ts.map +0 -1
  230. package/out/src/storage/knexPostgres.js +0 -34
  231. package/out/src/storage/knexPostgres.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -6,51 +6,189 @@ attention to changes that materially alter behavior or extend functionality.
6
6
 
7
7
  ## wallet-toolbox 2.15.0
8
8
 
9
- - `StorageKnex` runs on Postgres through the knex `pg` client. Settings report
10
- `dbtype: 'Postgres'`, and `StorageClient` accepts that value from a remote
11
- `StorageServer`; older clients reject it. Install `pg` in the application.
12
- - On a Postgres knex, `StorageKnex` sets an int8 parser on each connection it
13
- acquires, so bigint columns and counts come back as numbers, as with mysql2
14
- and better-sqlite3. The process-wide `pg.types` defaults are not changed.
15
- `usePostgresInt8Numbers(knex)` applies the same parser to a knex directly, and
16
- `Setup.createPostgresKnex(connectionJson, database)` creates one with it.
17
- - Postgres runs at READ COMMITTED. The findOrInsert helpers retry a failed
18
- insert as a find in the same transaction; on Postgres the insert now runs in
19
- a savepoint so the transaction stays usable. `allocateChangeInput` re-checks
20
- action batch reservations after taking the output row lock.
21
- - On Postgres, migrations that add indexes to existing tables run outside a
22
- transaction and use `CREATE INDEX CONCURRENTLY IF NOT EXISTS`; an invalid
23
- index left by an interrupted build is dropped and rebuilt. `StorageKnex.migrate`
24
- runs Postgres migrations one at a time so every other migration keeps its
25
- journal row in its own transaction. SQLite and MySQL migrations are unchanged.
26
- - `adminStats` and the admin server's proof request review run on MySQL and
27
- Postgres. `adminStats` still reports `WERR_NOT_IMPLEMENTED` on SQLite.
28
- - `MonitorDaemon` accepts `postgresConnection` (JSON node-postgres config), and
29
- the operator `monitor-daemon` command accepts `--database-client postgres`.
30
- - `ChaintracksStorageKnex` rejects a Postgres knex before running migrations.
31
- - Paged `StorageKnex` find queries and the `get*ForUser` sync queries order rows
32
- by key. Without an order, Postgres could return consecutive LIMIT/OFFSET pages
33
- in different orders, so `getSyncChunk` repeated some rows and skipped others.
34
- - `StorageServer.app` is public, so a host can mount the storage server in its
35
- own Express application (`hostApp.use('/storage', server.app)`) instead of
36
- calling `start()`. `port` is optional and only required by `start()`.
37
- - `preRpcMiddleware` adds Express handlers on `POST /` after authentication,
38
- the authenticated rate limit and payment, immediately before JSON-RPC
39
- dispatch. A handler that responds stops the call before dispatch.
40
- - `publicRoutes: false` removes the unauthenticated `GET /`, `/robots.txt` and
41
- `/healthz` routes. Defaults are unchanged.
42
-
43
- - Knex storage adds a unique index on `sync_states` (`userId`,
44
- `storageIdentityKey`). Concurrent `findOrInsertSyncStateAuth` calls for a new
45
- source could each insert a row, after which every sync with that source failed
46
- with `Storage identity has conflicting sync states`. The losing insert now
47
- re-reads the row that won. The migration deletes existing duplicates, keeping
48
- the oldest row; when the duplicates had different storage names, the kept row
49
- restarts as a new sync state because its checkpoint may belong to a different
50
- source database.
51
- - BRC-38 import keeps one sync state per storage identity. An export holding
52
- several for one identity imports the oldest under the same rule, and merge
53
- updates the target's row for that identity even when its storage name differs.
9
+ - Adds a `regtest` `Chain` for Teranode regression-network deployments
10
+ (go-chaincfg `RegressionNetParams`). `genesisHeader('regtest')` returns the
11
+ canonical regtest genesis header; `ChaintracksServiceClient` and
12
+ `GoChaintracksServiceClient` accept a service that reports its chain as
13
+ `regtest`; Arcade and ChainTracks endpoints come from `REGTEST_ARCADE_URL` and
14
+ `REGTEST_CHAINTRACKS_URL` (`regtestArcadeUrl`, `regtestChaintracksUrl`). Like
15
+ TTN, the default regtest services use Arcade as broadcaster and Merkle-path
16
+ provider and register no legacy ARC fallback; like `tstn`, no WhatsOnChain
17
+ provider is registered.
18
+ - Header proof-of-work and chain-work checks take an optional `chain`, and the
19
+ new `proofOfWorkLimitBits(chain)` reports the limit it selects. Only
20
+ `regtest` raises it, to `0x207fffff`. Every other chain, and every check that
21
+ names no chain, keeps the mainnet limit of `0x1d00ffff`, so no existing
22
+ validation is relaxed. Every ChainTracks client, storage, ingestor, bulk-file
23
+ path and Monitor header check now passes its configured chain.
24
+ - `tstn` is unchanged: it keeps go-chaincfg's `TeraScalingTestNetParams`
25
+ genesis and proof-of-work limit. A deployment that runs regtest parameters
26
+ should configure `regtest`, not `tstn`.
27
+ - A WhatsOnChain instance for a network with no WhatsOnChain service (`tstn`,
28
+ `regtest`) now refuses every request (`isAvailable` is `false`) instead of
29
+ sending it to a relative URL, which a browser resolves against the page's
30
+ origin. `Services.hashToHeader` no longer falls back to WhatsOnChain on those
31
+ networks, so their headers come only from ChainTracks.
32
+ - `WalletPermissionsManager` passes `signAction` through the permission modules
33
+ that handled the action's `createAction`, both for a caller's `signAction`
34
+ and for the signing step of a one-call `createAction`. Modules receive it via
35
+ `onRequest` and `onResponse` with method `signAction` and may add `spends`
36
+ for inputs they supplied. Both calls carry `action` (`reference`, the
37
+ signable `transaction`, `noSend` and `createArgs`, the `createAction`
38
+ arguments as the modules returned them), so a module keeps no state between
39
+ `createAction` and `signAction`. A module request failure aborts the action; a
40
+ module response failure is thrown without aborting the signed action. A
41
+ module that rejects unknown methods must accept `signAction`.
42
+ - `encryptMetadata(wallet, plaintext, originator?)` and
43
+ `maybeDecryptMetadata(wallet, value, originator?)` are exported. They encrypt
44
+ and decrypt metadata as a permissions manager with `encryptWalletMetadata`
45
+ does, so a permission module can store and read its own baskets' custom
46
+ instructions through the underlying wallet. The manager uses the same
47
+ functions.
48
+ - `createAction` encrypts P-basket output custom instructions after the
49
+ permission modules run, as `internalizeAction` already does, so instructions a
50
+ module adds or replaces are stored encrypted.
51
+ - New `listOutputs` special operation `specOpBasketPrefixOutputs`: with a
52
+ basket namespace such as `p color` in tag 0, it lists outputs from every
53
+ basket in that namespace that are unspent or reserved as an input of a
54
+ pending action (`spendable` false), ordered by txid and vout. Spent outputs
55
+ are excluded. The permissions manager reserves it for the admin originator.
56
+ - `listOutputs` rejects a `balance p <module> <basket>` query with
57
+ `WERR_INVALID_PARAMETER`, as BRC-112 requires: the satoshi sum of a BRC-99
58
+ module basket is never reported past its module. `balance <basket>` on other
59
+ baskets is unchanged, and a module may offer `p <module> balance <basket>`.
60
+ - `WalletPermissionsManager.getVersion` advertises the BRC-205 capability
61
+ attributes of the configured permission modules: a `PermissionsModule` may
62
+ declare `capabilities` (attribute key to value), appended to the underlying
63
+ version string as `base; key=value;` in scheme-id and key order, merged with
64
+ attributes the wallet already reports and never repeating a key. The built-in
65
+ BRC-177 module advertises `brc177-nosend=2`. `withBrc205Capabilities` is
66
+ exported.
67
+ - `createAction` locks the known inputs it marks spent on MySQL and Postgres,
68
+ so of two concurrent actions spending the same input, the second sees it spent
69
+ and fails with the existing double-spend or unspendable-input error instead of
70
+ overwriting `spentBy`. SQLite and IndexedDB already serialize these writes.
71
+ - Callers that count `listOutputs` results narrow `totalOutputs` to a number
72
+ with the exported `numericTotalOutputs`, following the `@bsv/sdk` change that
73
+ lets BRC-112 module balance queries return decimal text.
74
+ - `@bsv/sdk` 4.0.0 is accepted as a peer alongside the existing 2.x and 3.x
75
+ ranges.
76
+
77
+ ## wallet-toolbox 2.14.10
78
+
79
+ - Live `syncToWriter` / `syncFromReader` compare reader and writer
80
+ `TableSettings.chain` before any chunk moves and throw `WERR_NETWORK_CHAIN`
81
+ on mismatch. The class remains a public sdk export with its deserializer and
82
+ JSON round-trip. Portable BRC-38 import still throws a generic `Error`.
83
+ Custom `processSyncChunk` writers may set `ProcessSyncChunkResult.error`;
84
+ both live-sync loops throw that error and stop. First-party providers still
85
+ throw. No API or schema migration is required.
86
+
87
+ ## wallet-toolbox 2.14.9
88
+
89
+ - Complete per-transaction broadcast results when the refreshed request is
90
+ already `unmined` or `completed`, preserving that durable state. Successful
91
+ first receipt without a mining proof no longer throws an internal unknown
92
+ status error on shared storage or when another worker advances the request.
93
+ Negative broadcast results and competing-transaction evidence remain negative;
94
+ they do not authorize recipient output credit. Repeated successful receipt
95
+ remains idempotent, and valid mined payments retain the proof path.
96
+ - SQL storage uses a durable, leased user/TXID receipt claim to keep a second
97
+ pod from crediting a pending first receipt. Completed claims remain as
98
+ coordination keys; expired claims can be recovered, and an old owner cannot
99
+ finalize after its claim is replaced. The migration preserves historical
100
+ transactions and outputs, including duplicates. No API or wire migration.
101
+ Back up and preflight SQL storage, then coordinate all storage instances in
102
+ the protected rollout; this source candidate does not deploy hosted storage.
103
+
104
+ ## wallet-toolbox 2.14.8
105
+
106
+ - `WalletPermissionsManager.internalizeAction` stores basket `customInstructions`
107
+ with one metadata encryption when `encryptWalletMetadata` is enabled.
108
+ A normal basket on a call that also carries a registered `p <scheme>` label
109
+ was encrypted before the permission module ran and again afterwards, so
110
+ `listOutputs` (which decrypts once) returned ciphertext. The after-module
111
+ pass now encrypts only permission-module baskets, matching `createAction`'s
112
+ once-only rule.- Preserve bounded pre-construction double-spend reviews from remote storage.
113
+ An empty attempted TXID is accepted only with one doubleSpend result, empty
114
+ send results, absent constructed-action fields and nonempty competing evidence.
115
+ Consumers must validate the evidence and synchronize the winning transaction
116
+ before rebuilding a save. The existing JSON transport carries this evidence;
117
+ binary wire framing is unchanged. No database or call migration is required.
118
+
119
+ - Confirmed `internalizeAction` resolves the block header before the storage
120
+ writer opens. IndexedDB otherwise finished that transaction during the
121
+ asynchronous lookup and rejected a valid mined payment before storing the
122
+ proven transaction, transaction, or requested output. A missing or malformed
123
+ header, or an invalid proof, still rejects with no partial records. Upgrade
124
+ the active storage implementation, including the browser client; no API, wire,
125
+ or schema migration is required.
126
+
127
+ - Restart-safe WAB registration checkpoints preserve the original wallet root
128
+ across interrupted faucet redemption and UMP publication. Persist through
129
+ `pendingRegistrationTokenSaver`, reload with `loadPendingRegistrationToken`
130
+ before authentication, and retain the checkpoint until an authenticated
131
+ snapshot is saved and `hasPendingRegistrationToken()` returns false. Recover
132
+ older pending registrations without checkpoints using their original wallet
133
+ state. WAB wire behavior is unchanged.
134
+
135
+ - Profile additions and deletions change the local list only when the replacement
136
+ UMP token is published. Failed factor retrieval or publication preserves the
137
+ list for retry. A failed active-profile deletion attempts to restore that
138
+ profile without masking the update error.
139
+ - Concurrent profile creation reserves case-insensitive names until the attempt
140
+ settles, preventing duplicate names while preserving retry after failure.
141
+ - If restoring the active wallet fails after publication, the committed token
142
+ and profile list remain in place. Inspect `listProfiles()` before retrying.
143
+ The underlying factor-decryption failure still requires separate diagnosis.
144
+
145
+ ## wallet-toolbox 2.14.7
146
+
147
+ - Internalization broadcasts unproven transactions new to the receiving user,
148
+ including shared-storage no-send payments. A rejected broadcast stores no
149
+ recipient outputs; proven transactions are not rebroadcast. Upgrade active
150
+ storage; no API, wire or schema migration is required.
151
+
152
+ - IndexedDB empty certificate certifier/type, transaction status and output-tag
153
+ ID arrays mean no optional filter, matching Knex. Nonempty arrays, partial
154
+ predicates and user ownership remain enforced; no schema migration is required.
155
+
156
+ - BEEF requests and schema-declared storage response bytes use the existing
157
+ negotiated compact binary JSON codec. Legacy peers retain numeric-array
158
+ JSON and identical transaction/proof bytes. Existing authentication and
159
+ payload ceilings remain unchanged; no API or database migration is required.
160
+
161
+ - BRC-177 anchors cover both the protected action and an economic reclaim.
162
+ Protected actions keep their only managed input bound to the named anchor,
163
+ create no wallet change, and pay the bounded reclaim surplus as miner fee.
164
+ Ordinary actions retain their existing change planning. No API, wire or
165
+ database migration is required.
166
+
167
+ ## wallet-toolbox 2.14.6
168
+
169
+ - UMP support pins anchor verified update lineage. Password and token updates
170
+ supersede the pinned predecessor, including multi-hop updates and recovery-hash
171
+ continuity. Unrelated historical continuations cannot override the anchor.
172
+ Competing descendants remain indeterminate rather than falling back to a spent
173
+ pin. No API or schema migration is required.
174
+
175
+ - Every retained token spend proves control through its unlocking script,
176
+ including confirmed updates and presentation/recovery-hash rotation. Funding
177
+ paths do not establish a token-update lineage.
178
+
179
+ - Explicit overlay history is linked past confirmed Merkle anchors. Deploy the
180
+ UMP history decider and engine retention fix with this client patch; missing
181
+ pin ancestry remains indeterminate rather than selecting an unrelated continuation.
182
+
183
+ - WAB faucet redemption accepts the local signer's independently validated
184
+ service charge and derived change, with exact SDK transaction binding. Empty
185
+ wallets no longer reject legitimate fee outputs financed by the faucet input.
186
+ Upgrade the SDK alongside the toolbox to enable the new capability. Older SDK
187
+ peers retain strict behavior; serialization discards local output authority.
188
+ Signup interruption/retry persistence remains unchanged.
189
+
190
+ ## wallet-toolbox 2.14.5
191
+
54
192
  - `WalletPermissionsManager` retires no-send transaction ownership and reference
55
193
  aliases when `createAction` or `signAction` reports them as `sending` or
56
194
  `unproven`, including sendWith-only calls and successful members of an
package/README.md CHANGED
@@ -6,6 +6,30 @@
6
6
 
7
7
  A [BRC-100](https://github.com/bitcoin-sv/BRCs/blob/master/wallet/0100.md) conforming wallet implementation for the BSV blockchain, built on the [BSV SDK](https://bsv-blockchain.github.io/ts-stack/packages/sdk/). Provides persistent storage, protocol-based key derivation, transaction monitoring, chain tracking, and signing — everything needed to build wallet-powered applications on BSV.
8
8
 
9
+ ## Receiving already-broadcast payments
10
+
11
+ The 2.14.9 source candidate completes broadcast results even when storage
12
+ already marks the request `unmined` or `completed`. This fixes first receipt
13
+ without a mining proof on shared storage, and the same result path when another
14
+ storage worker advances the request before the broadcast result refresh. The
15
+ stored advanced state remains intact; unsuccessful provider results still
16
+ reject receipt and do not credit new recipient outputs. Repeated successful
17
+ receipt remains idempotent. A payment carrying its valid mining proof follows
18
+ the existing proof path without rebroadcast.
19
+
20
+ SQL storage now serializes receipt ownership across independent processes
21
+ through a durable user/TXID claim. The migration preserves legacy transaction
22
+ and output rows, including historical duplicates, while adding the claim table.
23
+ Ambiguous historical receipts still require separate reconciliation; this
24
+ change prevents a new same-recipient overlap from creating another local credit.
25
+ Back up and preflight the database before rollout, then upgrade all storage
26
+ instances together; an older instance can bypass the new receipt claim.
27
+ Pending claims recover after their database-timed lease expires. No
28
+ public API or wire migration is required. Browser IndexedDB does not use the
29
+ SQL receipt claim. Source versions are candidates until published through the
30
+ protected release workflow; upgrading an app alone does not upgrade its remote
31
+ storage server.
32
+
9
33
  ## Backup and recovery: keep both keys and wallet data
10
34
 
11
35
  **A root key or seed alone is not a complete BRC-100 wallet backup.** Users
@@ -66,23 +90,16 @@ journal before recovery; do not delete journal rows or wallet data blindly.
66
90
  ### Postgres storage
67
91
 
68
92
  `StorageKnex` runs on Postgres through the knex `pg` client. Install `pg` in the
69
- application. Settings report `dbtype: 'Postgres'`; remote clients older than
70
- this release reject that value.
93
+ application and pass a Postgres knex:
71
94
 
72
- node-postgres returns int8 (bigint columns, counts) as strings by default.
73
- `StorageKnex` sets a parser on each connection its knex acquires so these come
74
- back as numbers, as with mysql2 and better-sqlite3. The process-wide `pg.types`
75
- defaults are not changed. `Setup.createPostgresKnex(connectionJson, database)`
76
- creates a knex with the same parser installed.
95
+ ```ts
96
+ import { knex as makeKnex } from 'knex'
77
97
 
78
- Postgres migrations run one at a time. Migrations that add indexes to existing
79
- tables run outside a transaction and use `CREATE INDEX CONCURRENTLY`, so writes
80
- continue while an index is built. `MonitorDaemon` takes a `postgresConnection`
81
- (JSON node-postgres config). `ChaintracksStorageKnex` does not support Postgres.
98
+ const knex = makeKnex({ client: 'pg', connection: { host, port, user, password, database } })
99
+ const storage = new StorageKnex({ ...StorageKnex.defaultOptions(), chain: 'main', knex })
100
+ ```
82
101
 
83
- Set `RUNPOSTGRES=1` and `POSTGRES_CONNECTION` (JSON node-postgres connection
84
- config) to include Postgres in the Knex test suites. Test databases are created
85
- on that server as needed.
102
+ `ChaintracksStorageKnex` and `adminStats` do not support Postgres.
86
103
 
87
104
  ## Overview
88
105
 
@@ -285,10 +302,6 @@ serialized RPC response exceeds the service ceiling, remote clients retry the
285
302
  read-only request with a smaller chunk budget and remember the working limit
286
303
  for the rest of the session.
287
304
 
288
- Knex storage keeps one sync state per user and source storage identity, enforced
289
- by a unique index. Concurrent registrations of the same source return the row the
290
- first caller inserted.
291
-
292
305
  Output synchronization requires a local mapping for every non-null source basket
293
306
  ID. A missing mapping rejects the page so its transaction and checkpoint can roll
294
307
  back; retry after transferring the missing basket. Newer source updates apply
@@ -383,6 +396,22 @@ retained privately, outside this repository.
383
396
  page for both Knex and IndexedDB storage, including short final pages and pages
384
397
  requested at or past the end of the result set.
385
398
 
399
+ ### Profile update failures
400
+
401
+ `CWIStyleWalletManager.addProfile` and `deleteProfile` commit the local profile
402
+ list when the replacement UMP token is published. A factor-decryption or
403
+ publication failure preserves the previous list, so a failed creation can be
404
+ retried with the same name. Concurrent creations reserve names without regard
405
+ to case until each attempt settles. A failed deletion of the active profile
406
+ attempts to restore that profile and preserves the original update error if
407
+ restoration also fails.
408
+
409
+ Restoring the active wallet can fail after publication has succeeded. In that
410
+ case, the token and profile list already contain the change, and the default
411
+ profile may remain active. Inspect `listProfiles()` before retrying and switch
412
+ to an available profile as needed. This bookkeeping fix does not correct the
413
+ underlying factor-decryption error; diagnose that error separately.
414
+
386
415
  ### UMP account continuity and phone changes
387
416
 
388
417
  Argon2id password derivation uses a proven-ready host backend when one is
@@ -406,11 +435,24 @@ WebAssembly global is absent. Native and JavaScript results both pass the same
406
435
  byte-type and exact-length validation.
407
436
 
408
437
  `WalletAuthenticationManager` accepts an optional `umpTokenOutpoint` in the
409
- backward-compatible WAB authentication response. Normal verified lookup and
410
- lineage resolution always run first. The WAB pin is considered only when those
411
- checks leave multiple valid UMP tokens, and only when the pinned outpoint is
412
- present in the verified candidates. A pin cannot introduce an outpoint that the
413
- wallet did not independently retrieve and validate.
438
+ backward-compatible WAB authentication response. When verified lookup returns
439
+ competing records, the pin anchors its own update lineage. A password or token
440
+ update that consumes the pinned outpoint supersedes it, including a multi-hop
441
+ update whose old pin is available only in authenticated token ancestry.
442
+ Each token input must prove spend authorization, including across confirmation;
443
+ ordinary funding inputs do not establish token lineage. Unmined updates also
444
+ require complete funding ancestry. A truncated input reference cannot override
445
+ the verified pin. An unrelated historical continuation
446
+ cannot override that lineage. A pin cannot
447
+ introduce an unverified token or resolve competing descendants of a spent pin.
448
+ Clients link explicit overlay history past confirmed Merkle anchors. UMP hosts
449
+ must request retained token lineage with a history decider and preserve it in
450
+ lookup BEEF (`@bsv/overlay` 2.6.4 and `@bsv/overlay-topics` 2.0.1, or equivalent
451
+ custom hosting). If an older host names an absent pin but omits its authenticated
452
+ source, lookup remains indeterminate instead of choosing an unrelated continuation.
453
+ Ordinary lineage resolution still applies when no pin relationship is present.
454
+ Operators should clear redundant pins after unpinned lookup independently returns
455
+ the correct current token; pinning is a recovery measure for remaining forks.
414
456
 
415
457
  UMP renewal consumes only the exact canonical predecessor returned for its
416
458
  outpoint. Its signed fields, presentation/recovery hashes, and locally derived
@@ -424,21 +466,49 @@ response must contain the exact declared Atomic BEEF target and output zero must
424
466
  commit to the supplied nonzero R-puzzle scalar. The manager signs that outpoint
425
467
  at its actual wallet input index and sends the fee-adjusted balance only to an
426
468
  explicit BRC-29 output derived for the authenticated wallet. That output's exact
427
- script and bounded amount are authorized before signing; an unrequested wallet
428
- output cannot consume the faucet input. The signed action is staged locally,
429
- labeled, and recorded in a recovery basket before broadcast. A retry recovers
430
- and internalizes that exact transaction, or recognizes its already-internalized
431
- managed output, instead of authorizing a second destination. Missing, reordered,
432
- substituted, ambiguous, or result-only transactions fail closed.
433
-
434
- New WAB registrations are interruption-safe across the off-chain/on-chain
435
- boundary. A WAB that advertises `registrationStatus: "pending"` lets a verified
436
- retry reuse the stored presentation key when a clean UMP lookup confirms that
437
- publication has not happened. After publishing the UMP token, the manager
438
- finalizes WAB idempotently. A lost finalization response is non-fatal: the next
439
- verified login finds the published token and repairs the pending state. Missing
440
- or invalid lifecycle metadata remains fail-closed for established accounts, and
441
- older WAB servers and clients retain their existing wire behavior.
469
+ script and bounded amount are authorized before signing. With a compatible SDK,
470
+ its local signer also authorizes independently validated storage commission and
471
+ locally derived change, bound to exact output indices, scripts and amounts. The
472
+ permissions wrapper preserves this private decision; serialized results or
473
+ unknown wallet adapters do not gain this authority. Other unrequested outputs
474
+ cannot consume the faucet input.
475
+
476
+ Upgrade wallet-toolbox to 2.14.6 and the SDK to a release exposing
477
+ `completeBoundAction.outputAuthorizationVersion=1` together. Older SDK peers retain
478
+ the existing strict behavior and cannot redeem a fee-bearing faucet input for an
479
+ empty wallet. Main currently carries the separate SDK3.1 candidate; SDK2 hosts
480
+ need an additive backport or the documented SDK3 migration.
481
+
482
+ The signed action is staged locally, labeled, and recorded in a recovery basket
483
+ before broadcast. Internalization clears the output's custom instructions, and
484
+ standard `listActions` does not return them. A retry with the same wallet root
485
+ can recover the prior faucet action; missing, substituted, ambiguous, or
486
+ result-only recovery evidence fails closed. Preserve the wallet's storage when
487
+ reconciling an interrupted signup.
488
+
489
+ For restart-safe WAB registrations, store an unpublished UMP token checkpoint
490
+ before faucet redemption. Pass `pendingRegistrationTokenSaver` in
491
+ `WalletAuthenticationManagerOptions` and synchronously verify that the token
492
+ bytes are stored before the callback resolves. On app restart, call
493
+ `loadPendingRegistrationToken(bytes)` before starting authentication. The token
494
+ contains encrypted UMP fields and no plaintext wallet root, snapshot key, or on-chain
495
+ outpoint. Keep it through failed funding and logout; clear it only after a
496
+ successful authenticated snapshot has been stored and
497
+ `hasPendingRegistrationToken()` returns false. If an older pending WAB
498
+ registration has no checkpoint, the manager refuses to redeem its faucet output
499
+ again. Recover that registration using its original wallet state instead of
500
+ creating a new root. A checkpoint for another presentation key does not block
501
+ login to an already published wallet; retain that checkpoint until its own
502
+ registration is reconciled.
503
+
504
+ A WAB that advertises `registrationStatus: "pending"` lets a verified retry
505
+ reuse the stored presentation key when a clean UMP lookup confirms that
506
+ publication has not happened. The loaded checkpoint reconstructs the original
507
+ root, so the wallet can recover its prior faucet action. After publishing the
508
+ UMP token, the manager finalizes WAB idempotently. A lost finalization response
509
+ is non-fatal: the next verified login finds the published token and repairs the
510
+ pending state. Missing or invalid lifecycle metadata remains fail-closed for
511
+ established accounts; WAB wire behavior is unchanged.
442
512
 
443
513
  Authenticated applications can verify a phone number and roll the presentation
444
514
  key, including when the user enters the same phone number:
@@ -517,11 +587,22 @@ synchronized tracker can continue serving its last-good checked data during a
517
587
  provider outage. WhatsOnChain remains a mainnet/testnet fallback and anonymous
518
588
  requests are serialized below its documented public rate.
519
589
 
520
- The supported chain identifiers are `main`, `test`, `stn`, `ttn`, and `tstn`
521
- (`mock` remains available for test utilities). STN and Terra Scaling TestNet do
522
- not have operator-independent public endpoints: set `STN_CHAINTRACKS_URL` or
523
- `TSTN_CHAINTRACKS_URL`, use the matching Arcade environment variable, or inject
524
- an explicit `ChaintracksClientApi`. URLs ending in `/v2` use the reconnecting
590
+ The supported chain identifiers are `main`, `test`, `stn`, `ttn`, `tstn`, and
591
+ `regtest` (`mock` remains available for test utilities). STN, Terra Scaling
592
+ TestNet, and regtest do not have operator-independent public endpoints: set
593
+ `STN_CHAINTRACKS_URL`, `TSTN_CHAINTRACKS_URL`, or `REGTEST_CHAINTRACKS_URL`, use
594
+ the matching Arcade environment variable, or inject an explicit
595
+ `ChaintracksClientApi`. Like TTN, the default regtest services use Arcade
596
+ (`REGTEST_ARCADE_URL`) as broadcaster and Merkle-path provider and register no
597
+ legacy ARC fallback.
598
+
599
+ `regtest` is Teranode's regression network (go-chaincfg `RegressionNetParams`):
600
+ the canonical regtest genesis header and a proof-of-work limit of `0x207fffff`.
601
+ Only a caller that names `regtest` gets that limit; every other chain, and every
602
+ header check that names no chain, keeps the mainnet limit of `0x1d00ffff`.
603
+ Regtest proof of work costs nothing to produce, so a regtest wallet trusts its
604
+ ChainTracks service for the header chain. Use it for private test deployments
605
+ only. URLs ending in `/v2` use the reconnecting
525
606
  go-chaintracks client; existing legacy v1 URLs and explicit clients remain
526
607
  compatible. Browser and mobile distributions expose the same fetch/SSE client
527
608
  without Node `Buffer` or filesystem dependencies.
@@ -1035,61 +1116,6 @@ Run `StorageKnex.migrate(...)` before constructing the manager during an
1035
1116
  upgrade. `makeAvailable()` validates and loads an already-migrated database; it
1036
1117
  does not apply schema changes.
1037
1118
 
1038
- ### Mounting StorageServer in an Express application
1039
-
1040
- `server.app` is the configured Express application. Mount it in a host
1041
- application instead of calling `start()`; `port` and `http` are only used by
1042
- `start()`.
1043
-
1044
- ```typescript
1045
- import express from 'express'
1046
- import { SessionManager } from '@bsv/sdk'
1047
- import { AuthRequest, createAuthMiddleware } from '@bsv/auth-express-middleware'
1048
- import { StorageServer } from '@bsv/wallet-toolbox'
1049
-
1050
- // Use KnexSessionManager when the host runs more than one process.
1051
- const sessionManager = new SessionManager()
1052
-
1053
- const storageServer = new StorageServer(storage, {
1054
- wallet,
1055
- monetize: false,
1056
- sessionManager,
1057
- // Leave GET /, /robots.txt and /healthz to the host.
1058
- publicRoutes: false,
1059
- preRpcMiddleware: [
1060
- async (req, res, next) => {
1061
- if (await overQuota((req as AuthRequest).auth.identityKey, req.body.method)) {
1062
- res.status(507).json({ status: 'error', code: 'ERR_QUOTA_EXCEEDED' })
1063
- return
1064
- }
1065
- next()
1066
- }
1067
- ]
1068
- })
1069
-
1070
- const app = express()
1071
- app.use('/storage', storageServer.app)
1072
- app.use(express.json())
1073
- app.use(createAuthMiddleware({ wallet, sessionManager }))
1074
- // ...host routes
1075
- app.listen(8080)
1076
- ```
1077
-
1078
- Clients connect with `new StorageClient(wallet, 'https://host.example/storage')`.
1079
- `AuthFetch` sends the BRC-104 handshake to the origin's `/.well-known/auth`,
1080
- not to the mount path, so the host must answer it with its own auth middleware
1081
- using the same `wallet` and the same `sessionManager` as the storage server.
1082
- Mount the storage server before the host's auth middleware and body parsers;
1083
- the storage app authenticates and parses its own requests. It keeps its own
1084
- security headers, CORS, concurrency and rate limits, and inherits the host's
1085
- `trust proxy` setting unless `trustProxy` is set.
1086
-
1087
- `preRpcMiddleware` handlers run on JSON-RPC `POST /` requests after
1088
- authentication, the authenticated rate limit and, when `monetize` is set, the
1089
- payment middleware. They see `req.auth` and the parsed body. A handler that
1090
- responds instead of calling `next()` stops the call before dispatch. They do not
1091
- run on the action batch upload routes.
1092
-
1093
1119
  ## Development
1094
1120
 
1095
1121
  ### Overlay identity verification
@@ -1188,3 +1214,13 @@ for the full stack-wide policy.
1188
1214
  This package is released under the [Open BSV License Version 6](./LICENSE.txt).
1189
1215
  The accompanying [THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md) and
1190
1216
  [LICENSES/](./LICENSES/) preserve the package's earlier Open BSV grant.
1217
+
1218
+ ## Pre-construction conflict recovery
1219
+
1220
+ The 2.14.7 candidate preserves remote storage's empty attempted-TXID sentinel
1221
+ only for a bounded double-spend review before transaction construction. It does
1222
+ not authorize a retry. Applications must verify complete competing transactions
1223
+ against the requested explicit inputs, synchronize the accepted winner, then
1224
+ read fresh state before rebuilding. Upgrade the application SDK alongside the
1225
+ wallet parser. Use the existing JSON wallet API for structured review errors;
1226
+ the binary wire format is unchanged. No database or call migration is required.