@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
@@ -1,13 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WalletPermissionsManager = void 0;
4
+ exports.withBrc205Capabilities = withBrc205Capabilities;
5
+ exports.encryptMetadata = encryptMetadata;
6
+ exports.maybeDecryptMetadata = maybeDecryptMetadata;
4
7
  const validationHelpers_1 = require("@bsv/sdk/wallet/validationHelpers");
5
8
  const sdk_1 = require("@bsv/sdk");
6
9
  const utils_1 = require("@bsv/sdk/primitives/utils");
7
10
  const brc114ActionTimeLabels_1 = require("./utility/brc114ActionTimeLabels");
8
11
  const brc177NoSendExpiry_1 = require("./utility/brc177NoSendExpiry");
9
12
  const exactActionSpend_1 = require("./utility/exactActionSpend");
13
+ const actionOutputAuthorizations_1 = require("./utility/actionOutputAuthorizations");
10
14
  const WERR_errors_1 = require("./sdk/WERR_errors");
15
+ const types_1 = require("./sdk/types");
11
16
  // Imported from the leaf module directly (not generateChange.ts, which
12
17
  // transitively imports StorageProvider.ts and the full signer/create-action
13
18
  // module graph) to avoid an unrelated circular-import edge from this file.
@@ -115,6 +120,70 @@ function deepEqual(object1, object2) {
115
120
  function isObject(object) {
116
121
  return object != null && typeof object === 'object';
117
122
  }
123
+ /**
124
+ * A permissions module handles request/response transformation for a specific P-protocol or P-basket scheme under BRC-98/99.
125
+ * Modules are registered in the config mapped by their scheme ID.
126
+ *
127
+ * Modules that handled a `createAction` returning a signable transaction also receive that action's
128
+ * `signAction` through `onRequest` and `onResponse`, with method `signAction` and the `action` being
129
+ * signed. A module may add `spends`
130
+ * for inputs it supplied.
131
+ */
132
+ // BRC-205 attribute grammar: key = lower *( lower / DIGIT / "-" ); value = 1*( unreserved / pct-encoded ).
133
+ const BRC205_KEY = /^[a-z][a-z0-9-]*$/;
134
+ const BRC205_VALUE = /^(?:[A-Za-z0-9._~-]|%[0-9A-F]{2})+$/;
135
+ const BRC205_MAX_KEY_BYTES = 64;
136
+ const BRC205_MAX_VALUE_BYTES = 256;
137
+ const BRC205_MAX_ATTRIBUTES = 24;
138
+ const BRC205_MAX_BYTES = 2048;
139
+ /** UTF-16 code-unit order: locale-independent, so the advertised attribute order is stable everywhere. */
140
+ const compareCodeUnits = (a, b) => Number(a > b) - Number(a < b);
141
+ /**
142
+ * Appends the BRC-205 capability attributes of `modules` to a wallet version string:
143
+ * `base; key=value; key2=value2;`, one space after every nonterminal semicolon, no spaces around
144
+ * `=`, a trailing semicolon when attributes are present. Modules are visited by scheme id and
145
+ * their keys in order, so the result is deterministic. Attributes the underlying string already
146
+ * carries are kept and their keys are not repeated; an invalid key or value, or one that would
147
+ * exceed BRC-205's limits, is left out. With nothing to add the string is returned unchanged.
148
+ */
149
+ function withBrc205Capabilities(version, modules) {
150
+ const separator = version.indexOf(';');
151
+ const base = separator === -1 ? version : version.slice(0, separator);
152
+ const attributes = separator === -1
153
+ ? []
154
+ : version
155
+ .slice(separator + 1)
156
+ .split(';')
157
+ .map(attribute => attribute.trim())
158
+ .filter(attribute => attribute !== '');
159
+ const keys = new Set(attributes.map(attribute => attribute.split('=')[0]));
160
+ let added = 0;
161
+ for (const scheme of Object.keys(modules).sort(compareCodeUnits)) {
162
+ const capabilities = modules[scheme]?.capabilities ?? {};
163
+ for (const key of Object.keys(capabilities).sort(compareCodeUnits)) {
164
+ const value = capabilities[key];
165
+ if (!BRC205_KEY.test(key) ||
166
+ key.length > BRC205_MAX_KEY_BYTES ||
167
+ typeof value !== 'string' ||
168
+ !BRC205_VALUE.test(value) ||
169
+ value.length > BRC205_MAX_VALUE_BYTES ||
170
+ keys.has(key) ||
171
+ attributes.length >= BRC205_MAX_ATTRIBUTES) {
172
+ continue;
173
+ }
174
+ const attribute = `${key}=${value}`;
175
+ const candidate = `${base}; ${[...attributes, attribute].join('; ')};`;
176
+ if (candidate.length > BRC205_MAX_BYTES)
177
+ continue;
178
+ keys.add(key);
179
+ attributes.push(attribute);
180
+ added++;
181
+ }
182
+ }
183
+ if (added === 0)
184
+ return version;
185
+ return `${base}; ${attributes.join('; ')};`;
186
+ }
118
187
  /**
119
188
  * A map from each permission type to a special "admin basket" name used for storing
120
189
  * the tokens. The tokens themselves are unspent transaction outputs (UTXOs) with a
@@ -126,6 +195,42 @@ const BASKET_MAP = {
126
195
  certificate: 'admin certificate-access',
127
196
  spending: 'admin spending-authorization'
128
197
  };
198
+ /**
199
+ * Preserves the confidentiality of transaction descriptions, input/output descriptions and
200
+ * custom instructions from lower storage layers. Always used with `keyID="1"` and `counterparty="self"`.
201
+ */
202
+ const METADATA_ENCRYPTION_PROTOCOL = [2, 'admin metadata encryption'];
203
+ /**
204
+ * Encrypts metadata through `wallet` as a permissions manager with `encryptWalletMetadata` does.
205
+ * Permission modules use this for metadata they store through the underlying wallet directly.
206
+ */
207
+ async function encryptMetadata(wallet, plaintext, originator) {
208
+ const { ciphertext } = await wallet.encrypt({
209
+ plaintext: (0, utils_1.toArray)(plaintext, 'utf8'),
210
+ protocolID: METADATA_ENCRYPTION_PROTOCOL,
211
+ keyID: '1'
212
+ }, originator);
213
+ return (0, utils_1.toBase64)(ciphertext);
214
+ }
215
+ /**
216
+ * Decrypts metadata that a permissions manager with `encryptWalletMetadata` stored through `wallet`.
217
+ * A value that does not decrypt, such as metadata stored without encryption, is returned unchanged.
218
+ * Permission modules use this to read metadata from their own baskets through the underlying wallet.
219
+ */
220
+ async function maybeDecryptMetadata(wallet, ciphertext, originator) {
221
+ try {
222
+ const { plaintext } = await wallet.decrypt({
223
+ ciphertext: (0, utils_1.toArray)(ciphertext, 'base64'),
224
+ protocolID: METADATA_ENCRYPTION_PROTOCOL,
225
+ keyID: '1'
226
+ }, originator);
227
+ return (0, utils_1.toUTF8)(plaintext);
228
+ }
229
+ catch {
230
+ // Decryption failed (e.g. wrong key, unencrypted legacy value) — return original string unchanged
231
+ return ciphertext;
232
+ }
233
+ }
129
234
  /**
130
235
  * @class WalletPermissionsManager
131
236
  *
@@ -196,6 +301,10 @@ class WalletPermissionsManager {
196
301
  blockedActionReferences = new Set();
197
302
  /** Pending references whose action was created with `noSend`. */
198
303
  pendingNoSendReferences = new Set();
304
+ /** P-modules that handled each pending action's createAction, in request order. */
305
+ pendingActionModules = new Map();
306
+ /** The createAction arguments those P-modules returned, for their signAction hooks. */
307
+ pendingActionCreateArgs = new Map();
199
308
  /**
200
309
  * Originator binding for signed no-send actions, keyed by lowercase txid.
201
310
  * Signing drops the pending reference, so without this a non-admin caller
@@ -284,7 +393,12 @@ class WalletPermissionsManager {
284
393
  ...config.permissionModules,
285
394
  // BRC-177 is a built-in reserved BRC-111 module in every Toolbox wallet.
286
395
  nosend: {
396
+ // BRC-177 L365: this revision, including batches and `never`.
397
+ capabilities: { 'brc177-nosend': '2' },
287
398
  onRequest: async (req) => {
399
+ // Signing an action this module already authorized at createAction needs nothing further.
400
+ if (req.method === 'signAction')
401
+ return { args: req.args };
288
402
  const labels = req.args.labels;
289
403
  (0, brc177NoSendExpiry_1.parseBrc177NoSendExpiryLabels)(labels);
290
404
  if (req.method !== 'createAction' && req.method !== 'listActions') {
@@ -1867,14 +1981,6 @@ class WalletPermissionsManager {
1867
1981
  2,
1868
1982
  'admin permission token encryption'
1869
1983
  ];
1870
- /**
1871
- * Similarly, we will use a "metadata encryption" protocol to preserve the confidentiality
1872
- * of transaction descriptions and input/output descriptions from lower storage layers.
1873
- */
1874
- static METADATA_ENCRYPTION_PROTOCOL = [
1875
- 2,
1876
- 'admin metadata encryption'
1877
- ];
1878
1984
  /** We always use `keyID="1"` and `counterparty="self"` for these encryption ops. */
1879
1985
  async encryptPermissionTokenField(plaintext) {
1880
1986
  const data = typeof plaintext === 'string' ? (0, utils_1.toArray)(plaintext, 'utf8') : plaintext;
@@ -2003,12 +2109,7 @@ class WalletPermissionsManager {
2003
2109
  if (!this.config.encryptWalletMetadata) {
2004
2110
  return plaintext;
2005
2111
  }
2006
- const { ciphertext } = await this.underlying.encrypt({
2007
- plaintext: (0, utils_1.toArray)(plaintext, 'utf8'),
2008
- protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
2009
- keyID: '1'
2010
- }, this.adminOriginator);
2011
- return (0, utils_1.toBase64)(ciphertext);
2112
+ return await encryptMetadata(this.underlying, plaintext, this.adminOriginator);
2012
2113
  }
2013
2114
  /**
2014
2115
  * Attempts to decrypt metadata. if decryption fails, assumes the value is already plaintext and returns it.
@@ -2016,18 +2117,7 @@ class WalletPermissionsManager {
2016
2117
  * @returns The decrypted metadata. If decryption fails, returns the original value instead.
2017
2118
  */
2018
2119
  async maybeDecryptMetadata(ciphertext) {
2019
- try {
2020
- const { plaintext } = await this.underlying.decrypt({
2021
- ciphertext: (0, utils_1.toArray)(ciphertext, 'base64'),
2022
- protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
2023
- keyID: '1'
2024
- }, this.adminOriginator);
2025
- return (0, utils_1.toUTF8)(plaintext);
2026
- }
2027
- catch {
2028
- // Decryption failed (e.g. wrong key, unencrypted legacy value) — return original string unchanged
2029
- return ciphertext;
2030
- }
2120
+ return await maybeDecryptMetadata(this.underlying, ciphertext, this.adminOriginator);
2031
2121
  }
2032
2122
  /** Helper to see if a token's expiry is in the past. */
2033
2123
  isTokenExpired(expiry) {
@@ -3106,8 +3196,10 @@ class WalletPermissionsManager {
3106
3196
  labels: [...(args.labels || []), `admin originator ${originator}`, `admin month ${this.getCurrentMonthYearUTC()}`]
3107
3197
  };
3108
3198
  let createResult;
3199
+ let moduleArgs;
3109
3200
  try {
3110
- createResult = await this.callCreateActionWithPModules(finalArgs, pModulesByScheme, originator);
3201
+ ;
3202
+ ({ createResult, moduleArgs } = await this.callCreateActionWithPModules(finalArgs, pModulesByScheme, originator));
3111
3203
  }
3112
3204
  catch (error) {
3113
3205
  this.forgetSentNoSendActionsInError(error);
@@ -3120,7 +3212,8 @@ class WalletPermissionsManager {
3120
3212
  // data. This ensures malformed BEEF is still aborted and cannot leave an
3121
3213
  // untracked action that may later be signed under another originator.
3122
3214
  const reference = createResult.signableTransaction.reference;
3123
- this.bindPendingAction(reference, originator, vargs.isNoSend);
3215
+ const pModules = Array.from(pModulesByScheme.values());
3216
+ this.bindPendingAction(reference, originator, vargs.isNoSend, pModules, moduleArgs);
3124
3217
  // 7a) Parse the signable tx to determine net spend, then gate on spending
3125
3218
  // authorization. SECURITY (GHSA-36f9-7rg5-cpf8) defense-in-depth: confirm every
3126
3219
  // caller-requested output actually appears in the transaction we are about to
@@ -3167,30 +3260,34 @@ class WalletPermissionsManager {
3167
3260
  // 9) Finalize or return the signable transaction based on whether more signatures are needed.
3168
3261
  if (vargs.isSignAction)
3169
3262
  return createResult;
3263
+ let signResult;
3264
+ const action = this.signingAction(reference, vargs.isNoSend);
3170
3265
  try {
3171
- const signResult = await this.underlying.signAction({
3266
+ const signArgs = await this.signActionArgsThroughPModules(pModules, {
3172
3267
  reference,
3173
3268
  spends: {},
3174
3269
  options: { ...args.options, returnTXIDOnly: false }
3175
- }, originator);
3176
- this.assertAuthorizedSignResult(reference, {}, signResult);
3270
+ }, action, originator);
3271
+ signResult = await this.underlying.signAction(signArgs, originator);
3272
+ this.assertAuthorizedSignResult(reference, signArgs.spends, signResult);
3177
3273
  this.clearPendingAction(reference);
3178
3274
  if (vargs.isNoSend && signResult.txid != null) {
3179
3275
  this.recordNoSendAction(signResult.txid, originator);
3180
3276
  }
3181
3277
  this.forgetSentNoSendActions(signResult.sendWithResults);
3182
- return {
3183
- ...createResult,
3184
- ...signResult,
3185
- noSendChange: noSendChangeOnSignedTransaction(createResult.noSendChange, signResult.txid),
3186
- signableTransaction: undefined
3187
- };
3188
3278
  }
3189
3279
  catch (error) {
3190
3280
  this.forgetSentNoSendActionsInError(error);
3191
3281
  await this.blockAndAbortAction(reference);
3192
3282
  throw error;
3193
3283
  }
3284
+ signResult = await this.signActionResultThroughPModules(pModules, signResult, action, originator);
3285
+ return {
3286
+ ...createResult,
3287
+ ...signResult,
3288
+ noSendChange: noSendChangeOnSignedTransaction(createResult.noSendChange, signResult.txid),
3289
+ signableTransaction: undefined
3290
+ };
3194
3291
  }
3195
3292
  /** Scans outputs to split P-scheme baskets from regular baskets; registers P-modules as a side effect. */
3196
3293
  collectNonPBaskets(outputs, pModulesByScheme) {
@@ -3235,7 +3332,8 @@ class WalletPermissionsManager {
3235
3332
  originalOutputDescriptions[i] = output.outputDescription;
3236
3333
  output.outputDescription = await this.maybeEncryptMetadata(output.outputDescription);
3237
3334
  }
3238
- if (output.customInstructions) {
3335
+ // P-basket custom instructions are encrypted after the permission modules run.
3336
+ if (output.customInstructions && output.basket?.startsWith('p ') !== true) {
3239
3337
  output.customInstructions = await this.maybeEncryptMetadata(output.customInstructions);
3240
3338
  }
3241
3339
  });
@@ -3248,6 +3346,15 @@ class WalletPermissionsManager {
3248
3346
  ]);
3249
3347
  return { originalInputDescriptions, originalOutputDescriptions };
3250
3348
  }
3349
+ /** Encrypts P-basket output custom instructions as the permission modules left them. */
3350
+ async encryptCreateActionModuleMetadata(args) {
3351
+ if (args.outputs === undefined)
3352
+ return args;
3353
+ const outputs = await Promise.all(args.outputs.map(async (output) => !output.customInstructions || output.basket?.startsWith('p ') !== true
3354
+ ? output
3355
+ : { ...output, customInstructions: await this.maybeEncryptMetadata(output.customInstructions) }));
3356
+ return { ...args, outputs };
3357
+ }
3251
3358
  /** Calls underlying createAction, chaining P-module request/response transforms when needed. */
3252
3359
  async callCreateActionWithPModules(finalArgs, pModulesByScheme, originator) {
3253
3360
  const pModules = Array.from(pModulesByScheme.values());
@@ -3260,7 +3367,9 @@ class WalletPermissionsManager {
3260
3367
  });
3261
3368
  transformedArgs = transformed.args;
3262
3369
  }
3263
- let createResult = await this.underlying.createAction(transformedArgs, originator);
3370
+ const moduleArgs = transformedArgs;
3371
+ let createResult = await this.underlying.createAction(await this.encryptCreateActionModuleMetadata(moduleArgs), originator);
3372
+ const locallyAuthorizedResult = createResult;
3264
3373
  const exactWalletSpend = (0, exactActionSpend_1.getExactActionSpend)(createResult);
3265
3374
  for (let i = pModules.length - 1; i >= 0; i--) {
3266
3375
  createResult = await pModules[i].onResponse(createResult, { method: 'createAction', originator: originator });
@@ -3271,7 +3380,8 @@ class WalletPermissionsManager {
3271
3380
  if (exactWalletSpend !== undefined) {
3272
3381
  (0, exactActionSpend_1.setExactActionSpend)(publicResult, exactWalletSpend);
3273
3382
  }
3274
- return publicResult;
3383
+ (0, actionOutputAuthorizations_1.copyActionOutputAuthorizations)(locallyAuthorizedResult, publicResult);
3384
+ return { createResult: publicResult, moduleArgs };
3275
3385
  }
3276
3386
  /**
3277
3387
  * Computes the net satoshis the originator is spending in a createAction call,
@@ -3505,19 +3615,25 @@ class WalletPermissionsManager {
3505
3615
  throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference belongs to a different originator.');
3506
3616
  }
3507
3617
  }
3508
- bindPendingAction(reference, originator, noSend) {
3618
+ bindPendingAction(reference, originator, noSend, pModules, createArgs) {
3509
3619
  if (this.pendingActionOriginators.has(reference)) {
3510
3620
  throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference is already pending.');
3511
3621
  }
3512
3622
  this.pendingActionOriginators.set(reference, originator ?? '');
3513
3623
  if (noSend)
3514
3624
  this.pendingNoSendReferences.add(reference);
3625
+ if (pModules.length > 0) {
3626
+ this.pendingActionModules.set(reference, pModules);
3627
+ this.pendingActionCreateArgs.set(reference, createArgs);
3628
+ }
3515
3629
  }
3516
3630
  clearPendingAction(reference) {
3517
3631
  this.pendingActionOriginators.delete(reference);
3518
3632
  this.pendingActionTemplates.delete(reference);
3519
3633
  this.blockedActionReferences.delete(reference);
3520
3634
  this.pendingNoSendReferences.delete(reference);
3635
+ this.pendingActionModules.delete(reference);
3636
+ this.pendingActionCreateArgs.delete(reference);
3521
3637
  }
3522
3638
  /** Lets the originator that created a signed no-send action, and only it, abort it. */
3523
3639
  recordNoSendAction(txid, originator, reference) {
@@ -3554,29 +3670,51 @@ class WalletPermissionsManager {
3554
3670
  this.forgetSentNoSendActions(error.sendWithResults);
3555
3671
  }
3556
3672
  }
3673
+ /** The action a signAction hook call signs, from the template bound at createAction. */
3674
+ signingAction(reference, noSend) {
3675
+ const transaction = this.pendingActionTemplates.get(reference);
3676
+ if (transaction === undefined)
3677
+ return undefined;
3678
+ const createArgs = this.pendingActionCreateArgs.get(reference);
3679
+ return createArgs === undefined
3680
+ ? { reference, transaction, noSend }
3681
+ : { reference, transaction, noSend, createArgs };
3682
+ }
3683
+ /** Passes signAction args through the P-modules that handled the action's createAction, in request order. */
3684
+ async signActionArgsThroughPModules(pModules, args, action, originator) {
3685
+ return (await pModules.reduce(async (previous, module) => (await module.onRequest({ method: 'signAction', args: await previous, originator: originator, action })).args, Promise.resolve(args)));
3686
+ }
3687
+ /** Passes a signAction result back through the same P-modules in reverse order. */
3688
+ async signActionResultThroughPModules(pModules, result, action, originator) {
3689
+ return await pModules.reduceRight(async (previous, module) => await module.onResponse(await previous, { method: 'signAction', originator: originator, action }), Promise.resolve(result));
3690
+ }
3557
3691
  async signAction(...args) {
3558
3692
  const [requestArgs, originator] = args;
3559
3693
  this.assertPendingActionOriginator(requestArgs.reference, originator, false);
3560
3694
  // The wallet takes noSend from signAction's options, else from createAction's.
3561
3695
  const noSend = (requestArgs.options?.noSend ?? this.pendingNoSendReferences.has(requestArgs.reference)) === true;
3696
+ const pModules = this.pendingActionModules.get(requestArgs.reference) ?? [];
3697
+ const action = this.signingAction(requestArgs.reference, noSend);
3698
+ let result;
3562
3699
  try {
3563
- const result = await this.underlying.signAction({
3700
+ const signArgs = await this.signActionArgsThroughPModules(pModules, {
3564
3701
  ...requestArgs,
3565
3702
  options: { ...requestArgs.options, returnTXIDOnly: false }
3566
- }, originator);
3567
- this.assertAuthorizedSignResult(requestArgs.reference, requestArgs.spends, result);
3703
+ }, action, originator);
3704
+ result = await this.underlying.signAction(signArgs, originator);
3705
+ this.assertAuthorizedSignResult(requestArgs.reference, signArgs.spends, result);
3568
3706
  this.clearPendingAction(requestArgs.reference);
3569
3707
  if (noSend && result.txid != null) {
3570
3708
  this.recordNoSendAction(result.txid, originator, requestArgs.reference);
3571
3709
  }
3572
3710
  this.forgetSentNoSendActions(result.sendWithResults);
3573
- return result;
3574
3711
  }
3575
3712
  catch (error) {
3576
3713
  this.forgetSentNoSendActionsInError(error);
3577
3714
  await this.blockAndAbortAction(requestArgs.reference);
3578
3715
  throw error;
3579
3716
  }
3717
+ return await this.signActionResultThroughPModules(pModules, result, action, originator);
3580
3718
  }
3581
3719
  async abortAction(...args) {
3582
3720
  const [requestArgs, originator] = args;
@@ -3689,14 +3827,29 @@ class WalletPermissionsManager {
3689
3827
  });
3690
3828
  }
3691
3829
  }
3830
+ /**
3831
+ * Encrypts custom instructions that permission modules can still introduce.
3832
+ * Normal-basket instructions are already encrypted once by
3833
+ * authorizeInternalizeActionBaskets, before modules run. Encrypting them
3834
+ * again here wrapped ciphertext inside ciphertext whenever a registered
3835
+ * p-label or p-basket caused modules to run, and listOutputs decrypts only
3836
+ * one layer. Permission-module baskets are not covered by that earlier pass.
3837
+ */
3692
3838
  async encryptInternalizeActionModuleMetadata(requestArgs) {
3839
+ const encryptionTasks = [];
3693
3840
  for (const outIndex in requestArgs.outputs) {
3694
3841
  const output = requestArgs.outputs[outIndex];
3695
- const customInstructions = output.insertionRemittance?.customInstructions;
3696
- if (output.protocol !== 'basket insertion' || !customInstructions)
3842
+ const remittance = output.insertionRemittance;
3843
+ const customInstructions = remittance?.customInstructions;
3844
+ if (output.protocol !== 'basket insertion' || remittance == null || !customInstructions)
3697
3845
  continue;
3698
- output.insertionRemittance.customInstructions = await this.maybeEncryptMetadata(customInstructions);
3846
+ if (!remittance.basket.startsWith('p '))
3847
+ continue;
3848
+ encryptionTasks.push(this.maybeEncryptMetadata(customInstructions).then(encrypted => {
3849
+ remittance.customInstructions = encrypted;
3850
+ }));
3699
3851
  }
3852
+ await Promise.all(encryptionTasks);
3700
3853
  }
3701
3854
  async runInternalizeActionModules(requestArgs, originator, modules) {
3702
3855
  let transformedArgs = requestArgs;
@@ -4090,8 +4243,16 @@ class WalletPermissionsManager {
4090
4243
  async getNetwork(...args) {
4091
4244
  return await this.underlying.getNetwork(...args);
4092
4245
  }
4246
+ /**
4247
+ * The underlying wallet's version string with the BRC-205 capability attributes of every
4248
+ * configured permission module appended (see `withBrc205Capabilities`).
4249
+ */
4093
4250
  async getVersion(...args) {
4094
- return await this.underlying.getVersion(...args);
4251
+ const result = await this.underlying.getVersion(...args);
4252
+ return {
4253
+ ...result,
4254
+ version: withBrc205Capabilities(result.version, this.config.permissionModules ?? {})
4255
+ };
4095
4256
  }
4096
4257
  /* ---------------------------------------------------------------------
4097
4258
  * 8) INTERNAL HELPER UTILITIES
@@ -4144,6 +4305,9 @@ class WalletPermissionsManager {
4144
4305
  return true;
4145
4306
  if (basket.startsWith('admin'))
4146
4307
  return true;
4308
+ // Lists P-basket outputs past their permission modules.
4309
+ if (basket === types_1.specOpBasketPrefixOutputs)
4310
+ return true;
4147
4311
  return false;
4148
4312
  }
4149
4313
  /**