@attocash/cli 0.1.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 (400) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +707 -0
  3. package/dist/application/app.d.ts +138 -0
  4. package/dist/application/app.js +654 -0
  5. package/dist/application/operations.d.ts +9 -0
  6. package/dist/application/operations.js +96 -0
  7. package/dist/cli/cli.d.ts +1 -0
  8. package/dist/cli/cli.js +460 -0
  9. package/dist/cli/help.d.ts +4 -0
  10. package/dist/cli/help.js +49 -0
  11. package/dist/cli/main.d.ts +2 -0
  12. package/dist/cli/main.js +13 -0
  13. package/dist/cli/onboarding.d.ts +14 -0
  14. package/dist/cli/onboarding.js +144 -0
  15. package/dist/cli/output.d.ts +2 -0
  16. package/dist/cli/output.js +231 -0
  17. package/dist/cli/terminal.d.ts +6 -0
  18. package/dist/cli/terminal.js +92 -0
  19. package/dist/cli/update-check.d.ts +1 -0
  20. package/dist/cli/update-check.js +12 -0
  21. package/dist/cli/updates.d.ts +2 -0
  22. package/dist/cli/updates.js +98 -0
  23. package/dist/core.d.ts +14 -0
  24. package/dist/core.js +14 -0
  25. package/dist/doctor/credential-probe.d.ts +7 -0
  26. package/dist/doctor/credential-probe.js +49 -0
  27. package/dist/doctor/doctor.d.ts +4 -0
  28. package/dist/doctor/doctor.js +213 -0
  29. package/dist/doctor/keyring.d.ts +7 -0
  30. package/dist/doctor/keyring.js +150 -0
  31. package/dist/doctor/profile.d.ts +19 -0
  32. package/dist/doctor/profile.js +73 -0
  33. package/dist/doctor/types.d.ts +40 -0
  34. package/dist/doctor/types.js +1 -0
  35. package/dist/domain/amount.d.ts +6 -0
  36. package/dist/domain/amount.js +27 -0
  37. package/dist/domain/errors.d.ts +10 -0
  38. package/dist/domain/errors.js +16 -0
  39. package/dist/labels/directory.d.ts +87 -0
  40. package/dist/labels/directory.js +140 -0
  41. package/dist/labels/personal.d.ts +17 -0
  42. package/dist/labels/personal.js +56 -0
  43. package/dist/labels/presentation.d.ts +154 -0
  44. package/dist/labels/presentation.js +90 -0
  45. package/dist/network/reader.d.ts +31 -0
  46. package/dist/network/reader.js +370 -0
  47. package/dist/network/retry.d.ts +7 -0
  48. package/dist/network/retry.js +53 -0
  49. package/dist/network/work.d.ts +3 -0
  50. package/dist/network/work.js +66 -0
  51. package/dist/pricing/market.d.ts +29 -0
  52. package/dist/pricing/market.js +150 -0
  53. package/dist/pricing/terms.d.ts +6 -0
  54. package/dist/pricing/terms.js +12 -0
  55. package/dist/spending/destination.d.ts +16 -0
  56. package/dist/spending/destination.js +42 -0
  57. package/dist/spending/journal.d.ts +28 -0
  58. package/dist/spending/journal.js +69 -0
  59. package/dist/spending/ledger.d.ts +118 -0
  60. package/dist/spending/ledger.js +444 -0
  61. package/dist/spending/payments.d.ts +67 -0
  62. package/dist/spending/payments.js +424 -0
  63. package/dist/spending/pool.d.ts +13 -0
  64. package/dist/spending/pool.js +38 -0
  65. package/dist/spending/reconcile.d.ts +18 -0
  66. package/dist/spending/reconcile.js +64 -0
  67. package/dist/storage/profiles.d.ts +13 -0
  68. package/dist/storage/profiles.js +86 -0
  69. package/dist/storage/secrets.d.ts +16 -0
  70. package/dist/storage/secrets.js +104 -0
  71. package/dist/storage/state.d.ts +32 -0
  72. package/dist/storage/state.js +255 -0
  73. package/dist/wallet/auto-receive.d.ts +57 -0
  74. package/dist/wallet/auto-receive.js +140 -0
  75. package/dist/wallet/defaults.d.ts +3 -0
  76. package/dist/wallet/defaults.js +26 -0
  77. package/dist/wallet/signing.d.ts +17 -0
  78. package/dist/wallet/signing.js +128 -0
  79. package/dist/wallet/types.d.ts +65 -0
  80. package/dist/wallet/types.js +1 -0
  81. package/dist/wallet/work.d.ts +29 -0
  82. package/dist/wallet/work.js +154 -0
  83. package/dist/watches/manager.d.ts +75 -0
  84. package/dist/watches/manager.js +197 -0
  85. package/node_modules/@attocash/commons-core/Kotlin-DateTime-library-kotlinx-datetime.mjs +6678 -0
  86. package/node_modules/@attocash/commons-core/Kotlin-DateTime-library-kotlinx-datetime.mjs.map +1 -0
  87. package/node_modules/@attocash/commons-core/LICENSE +28 -0
  88. package/node_modules/@attocash/commons-core/README.md +118 -0
  89. package/node_modules/@attocash/commons-core/commons-commons-core.d.mts +1036 -0
  90. package/node_modules/@attocash/commons-core/commons-commons-core.mjs +7701 -0
  91. package/node_modules/@attocash/commons-core/commons-commons-core.mjs.map +1 -0
  92. package/node_modules/@attocash/commons-core/kotlin-kotlin-stdlib.mjs +17681 -0
  93. package/node_modules/@attocash/commons-core/kotlin-kotlin-stdlib.mjs.map +1 -0
  94. package/node_modules/@attocash/commons-core/kotlin_org_jetbrains_kotlin_kotlin_dom_api_compat.mjs +4 -0
  95. package/node_modules/@attocash/commons-core/kotlin_org_jetbrains_kotlin_kotlin_dom_api_compat.mjs.map +1 -0
  96. package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-bytestring.mjs +209 -0
  97. package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-bytestring.mjs.map +1 -0
  98. package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-core.mjs +2284 -0
  99. package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-core.mjs.map +1 -0
  100. package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-core.mjs +6042 -0
  101. package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-core.mjs.map +1 -0
  102. package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
  103. package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
  104. package/node_modules/@attocash/commons-core/package.json +27 -0
  105. package/node_modules/@attocash/commons-node/LICENSE +28 -0
  106. package/node_modules/@attocash/commons-node/README.md +92 -0
  107. package/node_modules/@attocash/commons-node/commons-commons-node.d.mts +255 -0
  108. package/node_modules/@attocash/commons-node/commons-commons-node.mjs +2977 -0
  109. package/node_modules/@attocash/commons-node/commons-commons-node.mjs.map +1 -0
  110. package/node_modules/@attocash/commons-node/kotlin-logging.mjs +432 -0
  111. package/node_modules/@attocash/commons-node/kotlin-logging.mjs.map +1 -0
  112. package/node_modules/@attocash/commons-node/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
  113. package/node_modules/@attocash/commons-node/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
  114. package/node_modules/@attocash/commons-node/package.json +29 -0
  115. package/node_modules/@attocash/commons-node-remote/LICENSE +28 -0
  116. package/node_modules/@attocash/commons-node-remote/README.md +61 -0
  117. package/node_modules/@attocash/commons-node-remote/commons-commons-node-remote.d.mts +122 -0
  118. package/node_modules/@attocash/commons-node-remote/commons-commons-node-remote.mjs +1810 -0
  119. package/node_modules/@attocash/commons-node-remote/commons-commons-node-remote.mjs.map +1 -0
  120. package/node_modules/@attocash/commons-node-remote/kotlin-logging.mjs +432 -0
  121. package/node_modules/@attocash/commons-node-remote/kotlin-logging.mjs.map +1 -0
  122. package/node_modules/@attocash/commons-node-remote/kotlinx-browser.mjs +8 -0
  123. package/node_modules/@attocash/commons-node-remote/kotlinx-browser.mjs.map +1 -0
  124. package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs +4 -0
  125. package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs.map +1 -0
  126. package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
  127. package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
  128. package/node_modules/@attocash/commons-node-remote/package.json +31 -0
  129. package/node_modules/@attocash/commons-transport/LICENSE +28 -0
  130. package/node_modules/@attocash/commons-transport/README.md +5 -0
  131. package/node_modules/@attocash/commons-transport/commons-commons-transport.d.mts +64 -0
  132. package/node_modules/@attocash/commons-transport/commons-commons-transport.mjs +249 -0
  133. package/node_modules/@attocash/commons-transport/commons-commons-transport.mjs.map +1 -0
  134. package/node_modules/@attocash/commons-transport/kotlinx-atomicfu.mjs +263 -0
  135. package/node_modules/@attocash/commons-transport/kotlinx-atomicfu.mjs.map +1 -0
  136. package/node_modules/@attocash/commons-transport/kotlinx-browser.mjs +8 -0
  137. package/node_modules/@attocash/commons-transport/kotlinx-browser.mjs.map +1 -0
  138. package/node_modules/@attocash/commons-transport/kotlinx-coroutines-core.mjs +11604 -0
  139. package/node_modules/@attocash/commons-transport/kotlinx-coroutines-core.mjs.map +1 -0
  140. package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json-io.mjs +4 -0
  141. package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json-io.mjs.map +1 -0
  142. package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
  143. package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
  144. package/node_modules/@attocash/commons-transport/ktor-ktor-client-content-negotiation.mjs +499 -0
  145. package/node_modules/@attocash/commons-transport/ktor-ktor-client-content-negotiation.mjs.map +1 -0
  146. package/node_modules/@attocash/commons-transport/ktor-ktor-client-core.mjs +6456 -0
  147. package/node_modules/@attocash/commons-transport/ktor-ktor-client-core.mjs.map +1 -0
  148. package/node_modules/@attocash/commons-transport/ktor-ktor-events.mjs +83 -0
  149. package/node_modules/@attocash/commons-transport/ktor-ktor-events.mjs.map +1 -0
  150. package/node_modules/@attocash/commons-transport/ktor-ktor-http-cio.mjs +1714 -0
  151. package/node_modules/@attocash/commons-transport/ktor-ktor-http-cio.mjs.map +1 -0
  152. package/node_modules/@attocash/commons-transport/ktor-ktor-http.mjs +3197 -0
  153. package/node_modules/@attocash/commons-transport/ktor-ktor-http.mjs.map +1 -0
  154. package/node_modules/@attocash/commons-transport/ktor-ktor-io.mjs +2290 -0
  155. package/node_modules/@attocash/commons-transport/ktor-ktor-io.mjs.map +1 -0
  156. package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx-json.mjs +46 -0
  157. package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx-json.mjs.map +1 -0
  158. package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx.mjs +482 -0
  159. package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx.mjs.map +1 -0
  160. package/node_modules/@attocash/commons-transport/ktor-ktor-serialization.mjs +165 -0
  161. package/node_modules/@attocash/commons-transport/ktor-ktor-serialization.mjs.map +1 -0
  162. package/node_modules/@attocash/commons-transport/ktor-ktor-sse.mjs +4 -0
  163. package/node_modules/@attocash/commons-transport/ktor-ktor-sse.mjs.map +1 -0
  164. package/node_modules/@attocash/commons-transport/ktor-ktor-utils.mjs +3222 -0
  165. package/node_modules/@attocash/commons-transport/ktor-ktor-utils.mjs.map +1 -0
  166. package/node_modules/@attocash/commons-transport/ktor-ktor-websocket-serialization.mjs +4 -0
  167. package/node_modules/@attocash/commons-transport/ktor-ktor-websocket-serialization.mjs.map +1 -0
  168. package/node_modules/@attocash/commons-transport/ktor-ktor-websockets.mjs +1485 -0
  169. package/node_modules/@attocash/commons-transport/ktor-ktor-websockets.mjs.map +1 -0
  170. package/node_modules/@attocash/commons-transport/package.json +29 -0
  171. package/node_modules/@attocash/commons-worker/LICENSE +28 -0
  172. package/node_modules/@attocash/commons-worker/README.md +48 -0
  173. package/node_modules/@attocash/commons-worker/commons-commons-worker.d.mts +73 -0
  174. package/node_modules/@attocash/commons-worker/commons-commons-worker.mjs +702 -0
  175. package/node_modules/@attocash/commons-worker/commons-commons-worker.mjs.map +1 -0
  176. package/node_modules/@attocash/commons-worker/kotlin-logging.mjs +432 -0
  177. package/node_modules/@attocash/commons-worker/kotlin-logging.mjs.map +1 -0
  178. package/node_modules/@attocash/commons-worker/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
  179. package/node_modules/@attocash/commons-worker/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
  180. package/node_modules/@attocash/commons-worker/package.json +29 -0
  181. package/node_modules/@attocash/commons-worker-remote/LICENSE +28 -0
  182. package/node_modules/@attocash/commons-worker-remote/README.md +60 -0
  183. package/node_modules/@attocash/commons-worker-remote/commons-commons-worker-remote.d.mts +93 -0
  184. package/node_modules/@attocash/commons-worker-remote/commons-commons-worker-remote.mjs +289 -0
  185. package/node_modules/@attocash/commons-worker-remote/commons-commons-worker-remote.mjs.map +1 -0
  186. package/node_modules/@attocash/commons-worker-remote/kotlin-logging.mjs +432 -0
  187. package/node_modules/@attocash/commons-worker-remote/kotlin-logging.mjs.map +1 -0
  188. package/node_modules/@attocash/commons-worker-remote/kotlinx-browser.mjs +8 -0
  189. package/node_modules/@attocash/commons-worker-remote/kotlinx-browser.mjs.map +1 -0
  190. package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs +4 -0
  191. package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs.map +1 -0
  192. package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
  193. package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
  194. package/node_modules/@attocash/commons-worker-remote/package.json +31 -0
  195. package/node_modules/@js-joda/core/CHANGELOG.md +363 -0
  196. package/node_modules/@js-joda/core/CheatSheet.md +947 -0
  197. package/node_modules/@js-joda/core/LICENSE +34 -0
  198. package/node_modules/@js-joda/core/README.md +155 -0
  199. package/node_modules/@js-joda/core/bower.json +21 -0
  200. package/node_modules/@js-joda/core/dist/js-joda.d.ts +2452 -0
  201. package/node_modules/@js-joda/core/dist/js-joda.esm.js +13564 -0
  202. package/node_modules/@js-joda/core/dist/js-joda.flow.js +949 -0
  203. package/node_modules/@js-joda/core/dist/js-joda.js +13630 -0
  204. package/node_modules/@js-joda/core/dist/js-joda.js.map +1 -0
  205. package/node_modules/@js-joda/core/dist/js-joda.min.js +5 -0
  206. package/node_modules/@js-joda/core/package.json +76 -0
  207. package/node_modules/@js-joda/core/src/Clock.js +330 -0
  208. package/node_modules/@js-joda/core/src/DayOfWeek.js +451 -0
  209. package/node_modules/@js-joda/core/src/Duration.js +1205 -0
  210. package/node_modules/@js-joda/core/src/Enum.js +30 -0
  211. package/node_modules/@js-joda/core/src/Instant.js +1012 -0
  212. package/node_modules/@js-joda/core/src/LocalDate.js +1703 -0
  213. package/node_modules/@js-joda/core/src/LocalDateTime.js +1686 -0
  214. package/node_modules/@js-joda/core/src/LocalTime.js +1415 -0
  215. package/node_modules/@js-joda/core/src/MathUtil.js +236 -0
  216. package/node_modules/@js-joda/core/src/Month.js +600 -0
  217. package/node_modules/@js-joda/core/src/MonthDay.js +730 -0
  218. package/node_modules/@js-joda/core/src/OffsetDateTime.js +757 -0
  219. package/node_modules/@js-joda/core/src/OffsetTime.js +621 -0
  220. package/node_modules/@js-joda/core/src/Period.js +933 -0
  221. package/node_modules/@js-joda/core/src/StringUtil.js +43 -0
  222. package/node_modules/@js-joda/core/src/Year.js +1015 -0
  223. package/node_modules/@js-joda/core/src/YearConstants.js +21 -0
  224. package/node_modules/@js-joda/core/src/YearMonth.js +1096 -0
  225. package/node_modules/@js-joda/core/src/ZoneId.js +236 -0
  226. package/node_modules/@js-joda/core/src/ZoneIdFactory.js +201 -0
  227. package/node_modules/@js-joda/core/src/ZoneOffset.js +486 -0
  228. package/node_modules/@js-joda/core/src/ZoneRegion.js +72 -0
  229. package/node_modules/@js-joda/core/src/ZonedDateTime.js +2007 -0
  230. package/node_modules/@js-joda/core/src/_init.js +68 -0
  231. package/node_modules/@js-joda/core/src/assert.js +33 -0
  232. package/node_modules/@js-joda/core/src/chrono/ChronoLocalDate.js +230 -0
  233. package/node_modules/@js-joda/core/src/chrono/ChronoLocalDateTime.js +130 -0
  234. package/node_modules/@js-joda/core/src/chrono/ChronoZonedDateTime.js +194 -0
  235. package/node_modules/@js-joda/core/src/chrono/IsoChronology.js +235 -0
  236. package/node_modules/@js-joda/core/src/convert.js +83 -0
  237. package/node_modules/@js-joda/core/src/errors.js +54 -0
  238. package/node_modules/@js-joda/core/src/format/DateTimeBuilder.js +535 -0
  239. package/node_modules/@js-joda/core/src/format/DateTimeFormatter.js +728 -0
  240. package/node_modules/@js-joda/core/src/format/DateTimeFormatterBuilder.js +1545 -0
  241. package/node_modules/@js-joda/core/src/format/DateTimeParseContext.js +297 -0
  242. package/node_modules/@js-joda/core/src/format/DateTimePrintContext.js +138 -0
  243. package/node_modules/@js-joda/core/src/format/DecimalStyle.js +113 -0
  244. package/node_modules/@js-joda/core/src/format/EnumMap.js +70 -0
  245. package/node_modules/@js-joda/core/src/format/ParsePosition.js +31 -0
  246. package/node_modules/@js-joda/core/src/format/ResolverStyle.js +93 -0
  247. package/node_modules/@js-joda/core/src/format/SignStyle.js +38 -0
  248. package/node_modules/@js-joda/core/src/format/StringBuilder.js +47 -0
  249. package/node_modules/@js-joda/core/src/format/TextStyle.js +114 -0
  250. package/node_modules/@js-joda/core/src/format/parser/CharLiteralPrinterParser.js +46 -0
  251. package/node_modules/@js-joda/core/src/format/parser/CompositePrinterParser.js +89 -0
  252. package/node_modules/@js-joda/core/src/format/parser/FractionPrinterParser.js +162 -0
  253. package/node_modules/@js-joda/core/src/format/parser/NumberPrinterParser.js +367 -0
  254. package/node_modules/@js-joda/core/src/format/parser/OffsetIdPrinterParser.js +177 -0
  255. package/node_modules/@js-joda/core/src/format/parser/PadPrinterParserDecorator.js +81 -0
  256. package/node_modules/@js-joda/core/src/format/parser/SettingsParser.js +44 -0
  257. package/node_modules/@js-joda/core/src/format/parser/StringLiteralPrinterParser.js +39 -0
  258. package/node_modules/@js-joda/core/src/format/parser/ZoneIdPrinterParser.js +218 -0
  259. package/node_modules/@js-joda/core/src/js-joda.js +210 -0
  260. package/node_modules/@js-joda/core/src/license-preamble.js +3 -0
  261. package/node_modules/@js-joda/core/src/temporal/ChronoField.js +470 -0
  262. package/node_modules/@js-joda/core/src/temporal/ChronoUnit.js +310 -0
  263. package/node_modules/@js-joda/core/src/temporal/DefaultInterfaceTemporal.js +118 -0
  264. package/node_modules/@js-joda/core/src/temporal/IsoFields.js +859 -0
  265. package/node_modules/@js-joda/core/src/temporal/NativeJsTemporal.js +105 -0
  266. package/node_modules/@js-joda/core/src/temporal/Temporal.js +346 -0
  267. package/node_modules/@js-joda/core/src/temporal/TemporalAccessor.js +125 -0
  268. package/node_modules/@js-joda/core/src/temporal/TemporalAdjuster.js +92 -0
  269. package/node_modules/@js-joda/core/src/temporal/TemporalAdjusters.js +464 -0
  270. package/node_modules/@js-joda/core/src/temporal/TemporalAmount.js +166 -0
  271. package/node_modules/@js-joda/core/src/temporal/TemporalField.js +248 -0
  272. package/node_modules/@js-joda/core/src/temporal/TemporalQueries.js +223 -0
  273. package/node_modules/@js-joda/core/src/temporal/TemporalQueriesFactory.js +77 -0
  274. package/node_modules/@js-joda/core/src/temporal/TemporalQuery.js +107 -0
  275. package/node_modules/@js-joda/core/src/temporal/TemporalUnit.js +179 -0
  276. package/node_modules/@js-joda/core/src/temporal/ValueRange.js +257 -0
  277. package/node_modules/@js-joda/core/src/use.js +20 -0
  278. package/node_modules/@js-joda/core/src/zone/SystemDefaultZoneId.js +31 -0
  279. package/node_modules/@js-joda/core/src/zone/SystemDefaultZoneRules.js +162 -0
  280. package/node_modules/@js-joda/core/src/zone/ZoneOffsetTransition.js +289 -0
  281. package/node_modules/@js-joda/core/src/zone/ZoneRules.js +464 -0
  282. package/node_modules/@js-joda/core/src/zone/ZoneRulesProvider.js +36 -0
  283. package/node_modules/@noble/hashes/LICENSE +21 -0
  284. package/node_modules/@noble/hashes/README.md +563 -0
  285. package/node_modules/@noble/hashes/_blake.d.ts +21 -0
  286. package/node_modules/@noble/hashes/_blake.d.ts.map +1 -0
  287. package/node_modules/@noble/hashes/_blake.js +52 -0
  288. package/node_modules/@noble/hashes/_blake.js.map +1 -0
  289. package/node_modules/@noble/hashes/_md.d.ts +99 -0
  290. package/node_modules/@noble/hashes/_md.d.ts.map +1 -0
  291. package/node_modules/@noble/hashes/_md.js +202 -0
  292. package/node_modules/@noble/hashes/_md.js.map +1 -0
  293. package/node_modules/@noble/hashes/_u64.d.ts +63 -0
  294. package/node_modules/@noble/hashes/_u64.d.ts.map +1 -0
  295. package/node_modules/@noble/hashes/_u64.js +84 -0
  296. package/node_modules/@noble/hashes/_u64.js.map +1 -0
  297. package/node_modules/@noble/hashes/argon2.d.ts +112 -0
  298. package/node_modules/@noble/hashes/argon2.d.ts.map +1 -0
  299. package/node_modules/@noble/hashes/argon2.js +517 -0
  300. package/node_modules/@noble/hashes/argon2.js.map +1 -0
  301. package/node_modules/@noble/hashes/blake1.d.ts +156 -0
  302. package/node_modules/@noble/hashes/blake1.d.ts.map +1 -0
  303. package/node_modules/@noble/hashes/blake1.js +560 -0
  304. package/node_modules/@noble/hashes/blake1.js.map +1 -0
  305. package/node_modules/@noble/hashes/blake2.d.ts +184 -0
  306. package/node_modules/@noble/hashes/blake2.d.ts.map +1 -0
  307. package/node_modules/@noble/hashes/blake2.js +501 -0
  308. package/node_modules/@noble/hashes/blake2.js.map +1 -0
  309. package/node_modules/@noble/hashes/blake3.d.ts +68 -0
  310. package/node_modules/@noble/hashes/blake3.d.ts.map +1 -0
  311. package/node_modules/@noble/hashes/blake3.js +284 -0
  312. package/node_modules/@noble/hashes/blake3.js.map +1 -0
  313. package/node_modules/@noble/hashes/eskdf.d.ts +92 -0
  314. package/node_modules/@noble/hashes/eskdf.d.ts.map +1 -0
  315. package/node_modules/@noble/hashes/eskdf.js +218 -0
  316. package/node_modules/@noble/hashes/eskdf.js.map +1 -0
  317. package/node_modules/@noble/hashes/hkdf.d.ts +64 -0
  318. package/node_modules/@noble/hashes/hkdf.d.ts.map +1 -0
  319. package/node_modules/@noble/hashes/hkdf.js +120 -0
  320. package/node_modules/@noble/hashes/hkdf.js.map +1 -0
  321. package/node_modules/@noble/hashes/hmac.d.ts +47 -0
  322. package/node_modules/@noble/hashes/hmac.d.ts.map +1 -0
  323. package/node_modules/@noble/hashes/hmac.js +93 -0
  324. package/node_modules/@noble/hashes/hmac.js.map +1 -0
  325. package/node_modules/@noble/hashes/index.d.ts +2 -0
  326. package/node_modules/@noble/hashes/index.d.ts.map +1 -0
  327. package/node_modules/@noble/hashes/index.js +35 -0
  328. package/node_modules/@noble/hashes/index.js.map +1 -0
  329. package/node_modules/@noble/hashes/legacy.d.ts +102 -0
  330. package/node_modules/@noble/hashes/legacy.d.ts.map +1 -0
  331. package/node_modules/@noble/hashes/legacy.js +327 -0
  332. package/node_modules/@noble/hashes/legacy.js.map +1 -0
  333. package/node_modules/@noble/hashes/package.json +97 -0
  334. package/node_modules/@noble/hashes/pbkdf2.d.ts +56 -0
  335. package/node_modules/@noble/hashes/pbkdf2.d.ts.map +1 -0
  336. package/node_modules/@noble/hashes/pbkdf2.js +135 -0
  337. package/node_modules/@noble/hashes/pbkdf2.js.map +1 -0
  338. package/node_modules/@noble/hashes/scrypt.d.ts +65 -0
  339. package/node_modules/@noble/hashes/scrypt.d.ts.map +1 -0
  340. package/node_modules/@noble/hashes/scrypt.js +257 -0
  341. package/node_modules/@noble/hashes/scrypt.js.map +1 -0
  342. package/node_modules/@noble/hashes/sha2.d.ts +249 -0
  343. package/node_modules/@noble/hashes/sha2.d.ts.map +1 -0
  344. package/node_modules/@noble/hashes/sha2.js +458 -0
  345. package/node_modules/@noble/hashes/sha2.js.map +1 -0
  346. package/node_modules/@noble/hashes/sha3-addons.d.ts +461 -0
  347. package/node_modules/@noble/hashes/sha3-addons.d.ts.map +1 -0
  348. package/node_modules/@noble/hashes/sha3-addons.js +783 -0
  349. package/node_modules/@noble/hashes/sha3-addons.js.map +1 -0
  350. package/node_modules/@noble/hashes/sha3.d.ts +199 -0
  351. package/node_modules/@noble/hashes/sha3.d.ts.map +1 -0
  352. package/node_modules/@noble/hashes/sha3.js +431 -0
  353. package/node_modules/@noble/hashes/sha3.js.map +1 -0
  354. package/node_modules/@noble/hashes/src/_blake.ts +57 -0
  355. package/node_modules/@noble/hashes/src/_md.ts +222 -0
  356. package/node_modules/@noble/hashes/src/_u64.ts +117 -0
  357. package/node_modules/@noble/hashes/src/argon2.ts +667 -0
  358. package/node_modules/@noble/hashes/src/blake1.ts +614 -0
  359. package/node_modules/@noble/hashes/src/blake2.ts +582 -0
  360. package/node_modules/@noble/hashes/src/blake3.ts +317 -0
  361. package/node_modules/@noble/hashes/src/eskdf.ts +259 -0
  362. package/node_modules/@noble/hashes/src/hkdf.ts +133 -0
  363. package/node_modules/@noble/hashes/src/hmac.ts +126 -0
  364. package/node_modules/@noble/hashes/src/index.ts +33 -0
  365. package/node_modules/@noble/hashes/src/legacy.ts +339 -0
  366. package/node_modules/@noble/hashes/src/pbkdf2.ts +175 -0
  367. package/node_modules/@noble/hashes/src/scrypt.ts +315 -0
  368. package/node_modules/@noble/hashes/src/sha2.ts +530 -0
  369. package/node_modules/@noble/hashes/src/sha3-addons.ts +983 -0
  370. package/node_modules/@noble/hashes/src/sha3.ts +485 -0
  371. package/node_modules/@noble/hashes/src/utils.ts +848 -0
  372. package/node_modules/@noble/hashes/src/webcrypto.ts +239 -0
  373. package/node_modules/@noble/hashes/utils.d.ts +519 -0
  374. package/node_modules/@noble/hashes/utils.d.ts.map +1 -0
  375. package/node_modules/@noble/hashes/utils.js +578 -0
  376. package/node_modules/@noble/hashes/utils.js.map +1 -0
  377. package/node_modules/@noble/hashes/webcrypto.d.ts +120 -0
  378. package/node_modules/@noble/hashes/webcrypto.d.ts.map +1 -0
  379. package/node_modules/@noble/hashes/webcrypto.js +165 -0
  380. package/node_modules/@noble/hashes/webcrypto.js.map +1 -0
  381. package/node_modules/ws/LICENSE +20 -0
  382. package/node_modules/ws/README.md +548 -0
  383. package/node_modules/ws/browser.js +8 -0
  384. package/node_modules/ws/index.js +22 -0
  385. package/node_modules/ws/lib/buffer-util.js +131 -0
  386. package/node_modules/ws/lib/constants.js +19 -0
  387. package/node_modules/ws/lib/event-target.js +292 -0
  388. package/node_modules/ws/lib/extension.js +203 -0
  389. package/node_modules/ws/lib/limiter.js +55 -0
  390. package/node_modules/ws/lib/permessage-deflate.js +530 -0
  391. package/node_modules/ws/lib/receiver.js +743 -0
  392. package/node_modules/ws/lib/sender.js +607 -0
  393. package/node_modules/ws/lib/stream.js +161 -0
  394. package/node_modules/ws/lib/subprotocol.js +62 -0
  395. package/node_modules/ws/lib/validation.js +152 -0
  396. package/node_modules/ws/lib/websocket-server.js +562 -0
  397. package/node_modules/ws/lib/websocket.js +1407 -0
  398. package/node_modules/ws/package.json +74 -0
  399. package/node_modules/ws/wrapper.mjs +21 -0
  400. package/package.json +53 -0
@@ -0,0 +1,444 @@
1
+ import { validateDestinationBinding } from './destination.js';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+ import { amountRaw } from '../domain/amount.js';
5
+ import { AttoError } from '../domain/errors.js';
6
+ import { paymentMetadataSchema, validatePaymentPlan } from './journal.js';
7
+ const DAY_MS = 86_400_000;
8
+ const POLICY_KEY = 'spending.policy';
9
+ const RECORDS_KEY = 'spending.records';
10
+ const REVISION_KEY = 'spending.policyRevision';
11
+ const ACCESS_KEY = 'spending.mcpAccess';
12
+ const PROPOSAL_KEY = 'spending.proposal';
13
+ const POOL_KEY = 'spending.pool';
14
+ export class SpendLedger {
15
+ store;
16
+ constructor(store) {
17
+ this.store = store;
18
+ }
19
+ policy() {
20
+ const policy = this.store.get(POLICY_KEY) ?? { perRequest: null, rolling: [] };
21
+ this.validatePolicy(policy);
22
+ return policy;
23
+ }
24
+ setPolicy(policy) {
25
+ this.validatePolicy(policy);
26
+ this.store.transaction(() => this.replacePolicy(policy));
27
+ }
28
+ mcpAccess() {
29
+ const access = this.store.get(ACCESS_KEY) ?? 'read-only';
30
+ if (access !== 'read-only' && access !== 'spend')
31
+ throw new AttoError('INVALID_STATE', 'The saved MCP access setting is invalid.');
32
+ return access;
33
+ }
34
+ pool() {
35
+ const pool = this.store.get(POOL_KEY) ?? { indexes: [0], consolidate: false };
36
+ this.validatePool(pool);
37
+ return pool;
38
+ }
39
+ proposePolicy(policy, access, wallet, pool = this.pool()) {
40
+ this.validatePolicy(policy);
41
+ this.validatePool(pool);
42
+ if (access !== 'read-only' && access !== 'spend')
43
+ throw new AttoError('INVALID_POLICY', 'Choose read-only or spend access for MCP.');
44
+ const createdAt = Date.now();
45
+ const proposal = {
46
+ ...wallet, id: randomUUID(), policy, access, pool, createdAt, expiresAt: createdAt + DAY_MS,
47
+ baseRevision: this.revision(), status: 'pending',
48
+ };
49
+ // One immutable proposal is current per profile. A new request gets a new
50
+ // ID, so an approval already displayed in another terminal cannot change it.
51
+ this.store.set(PROPOSAL_KEY, proposal);
52
+ return proposal;
53
+ }
54
+ proposal() {
55
+ const proposal = this.store.get(PROPOSAL_KEY);
56
+ if (proposal === undefined)
57
+ return null;
58
+ try {
59
+ if (!proposal || typeof proposal.id !== 'string' || !proposal.id || proposal.id.length > 128
60
+ || !['pending', 'approved', 'rejected'].includes(proposal.status)
61
+ || !['read-only', 'spend'].includes(proposal.access)
62
+ || !Number.isSafeInteger(proposal.createdAt) || proposal.createdAt < 0
63
+ || !Number.isSafeInteger(proposal.expiresAt) || proposal.expiresAt <= proposal.createdAt
64
+ || !Number.isSafeInteger(proposal.baseRevision) || proposal.baseRevision < 0
65
+ || typeof proposal.directory !== 'string' || typeof proposal.network !== 'string'
66
+ || (proposal.walletFingerprint !== null && typeof proposal.walletFingerprint !== 'string'))
67
+ throw new Error();
68
+ this.validatePolicy(proposal.policy);
69
+ if (proposal.pool !== undefined)
70
+ this.validatePool(proposal.pool);
71
+ return proposal;
72
+ }
73
+ catch {
74
+ throw new AttoError('INVALID_STATE', 'The saved limit proposal is invalid.');
75
+ }
76
+ }
77
+ reviewProposal(id, wallet) {
78
+ const proposal = this.proposal();
79
+ if (!proposal || proposal.id !== id)
80
+ throw new AttoError('PROPOSAL_NOT_FOUND', 'This proposal is unavailable or was replaced. Request the current limits before trying again.');
81
+ if (proposal.directory !== wallet.directory || proposal.walletFingerprint !== wallet.walletFingerprint || proposal.network !== wallet.network) {
82
+ throw new AttoError('PROPOSAL_STALE', 'The proposal belongs to a different wallet, profile, or network. Request a new proposal.');
83
+ }
84
+ if (proposal.status === 'pending') {
85
+ if (Date.now() >= proposal.expiresAt)
86
+ throw new AttoError('PROPOSAL_EXPIRED', 'This proposal expired. Request a new proposal.');
87
+ if (proposal.baseRevision !== this.revision())
88
+ throw new AttoError('PROPOSAL_STALE', 'The policy changed after this proposal was created. Request a new proposal.');
89
+ }
90
+ return proposal;
91
+ }
92
+ approveProposal(id, wallet) {
93
+ this.store.transaction(() => {
94
+ const proposal = this.reviewProposal(id, wallet);
95
+ if (proposal.status === 'approved')
96
+ return;
97
+ if (proposal.status === 'rejected')
98
+ throw new AttoError('PROPOSAL_REJECTED', 'This proposal was rejected. Request a new proposal.');
99
+ this.replacePolicy(proposal.policy);
100
+ this.store.set(ACCESS_KEY, proposal.access);
101
+ if (proposal.pool !== undefined)
102
+ this.store.set(POOL_KEY, proposal.pool);
103
+ this.store.set(PROPOSAL_KEY, { ...proposal, status: 'approved', decidedAt: Date.now() });
104
+ });
105
+ }
106
+ rejectProposal(id, wallet) {
107
+ this.store.transaction(() => {
108
+ const proposal = this.reviewProposal(id, wallet);
109
+ if (proposal.status === 'approved')
110
+ throw new AttoError('PROPOSAL_APPROVED', 'This proposal was already approved. Propose a new policy to change it.');
111
+ if (proposal.status === 'rejected')
112
+ return;
113
+ this.store.set(PROPOSAL_KEY, { ...proposal, status: 'rejected', decidedAt: Date.now() });
114
+ });
115
+ }
116
+ revision() {
117
+ const revision = this.store.get(REVISION_KEY) ?? 0;
118
+ if (!Number.isSafeInteger(revision) || revision < 0 || revision === Number.MAX_SAFE_INTEGER)
119
+ throw new AttoError('INVALID_STATE', 'The saved spending-policy revision is invalid.');
120
+ return revision;
121
+ }
122
+ replacePolicy(policy) {
123
+ const revision = this.revision();
124
+ this.store.set(POLICY_KEY, policy);
125
+ this.store.set(REVISION_KEY, revision + 1);
126
+ }
127
+ assertCanReserve(raw, now = Date.now()) {
128
+ this.assertAllowance(amountRaw(raw, 'RAW'), now, this.records());
129
+ }
130
+ /** Recheck the current policy before signing without charging this reservation twice. */
131
+ assertReservationAllowed(id, now = Date.now()) {
132
+ const records = this.records();
133
+ const record = records.find(value => value.id === id);
134
+ if (!record)
135
+ throw new AttoError('SEND_NOT_FOUND', 'The payment request was not found.');
136
+ if (!['reserved', 'signed', 'unknown'].includes(record.status)) {
137
+ throw new AttoError('SEND_STATE', 'Only a pending payment can use its spending reservation.');
138
+ }
139
+ this.assertAllowance(record.raw, now, records.filter(value => value.id !== id));
140
+ }
141
+ assertAllowance(raw, now, records) {
142
+ if (!Number.isSafeInteger(now) || now < 0)
143
+ throw new AttoError('INVALID_REQUEST', 'Spending checks require a valid timestamp.');
144
+ const policy = this.policy();
145
+ if (policy.perRequest && BigInt(raw) > BigInt(amountRaw(policy.perRequest.amount, policy.perRequest.unit, true))) {
146
+ throw new AttoError('SPENDING_LIMIT', 'The payment exceeds the per-request spending limit.');
147
+ }
148
+ for (const rule of policy.rolling) {
149
+ const usage = this.ruleUsage(rule, records, now);
150
+ if (BigInt(usage.usedRaw) + BigInt(raw) > BigInt(usage.limitRaw)) {
151
+ throw new AttoError('SPENDING_LIMIT', `The payment exceeds the ${rule.days}-day rolling spending limit.`, usage);
152
+ }
153
+ }
154
+ }
155
+ reserve(request) {
156
+ if (typeof request.id !== 'string' || request.id.length === 0 || request.id.length > 200
157
+ || !Number.isSafeInteger(request.index) || request.index < 0 || request.index > 0x7fff_ffff
158
+ || typeof request.destination !== 'string' || !request.destination
159
+ || !Number.isSafeInteger(request.createdAt) || request.createdAt < 0) {
160
+ throw new AttoError('INVALID_REQUEST', 'Send requests require an ID, address index, destination, and timestamp.');
161
+ }
162
+ const raw = amountRaw(request.raw, 'RAW');
163
+ try {
164
+ this.validateDetails(request);
165
+ if (request.plan?.steps.some(step => step.status !== 'planned' || step.hash !== undefined))
166
+ throw new Error();
167
+ }
168
+ catch {
169
+ throw new AttoError('INVALID_REQUEST', 'The payment metadata, source, or consolidation plan is invalid.');
170
+ }
171
+ return this.store.transaction(() => {
172
+ const records = this.records();
173
+ const existing = records.find((record) => record.id === request.id);
174
+ if (existing) {
175
+ if (existing.index !== request.index || existing.destination !== request.destination || existing.raw !== raw
176
+ || ['sourceAddress', 'network', 'metadata', 'quote', 'selection'].some(key => {
177
+ const field = key;
178
+ return request[field] !== undefined && !isDeepStrictEqual(request[field], existing[field]);
179
+ }) || (request.plan !== undefined && !isDeepStrictEqual(this.planDefinition(request.plan), this.planDefinition(existing.plan)))) {
180
+ throw new AttoError('REQUEST_CONFLICT', 'This request ID already belongs to a different payment.');
181
+ }
182
+ return existing;
183
+ }
184
+ this.assertAllowance(raw, request.createdAt, records);
185
+ const record = { ...request, raw, status: 'reserved' };
186
+ records.push(record);
187
+ this.store.set(RECORDS_KEY, records);
188
+ return record;
189
+ });
190
+ }
191
+ get(id) { return this.records().find((record) => record.id === id); }
192
+ journalGet(requestId) { return this.get(requestId); }
193
+ journalList(options = {}) {
194
+ const limit = options.limit ?? 50;
195
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100
196
+ || (options.status !== undefined && !['reserved', 'signed', 'published', 'unknown', 'failed'].includes(options.status))) {
197
+ throw new AttoError('INVALID_INPUT', 'Journal pages require a limit from 1 to 100 and a valid payment status.');
198
+ }
199
+ const records = this.records();
200
+ let before = records.length;
201
+ if (options.cursor !== undefined) {
202
+ try {
203
+ if (typeof options.cursor !== 'string' || options.cursor.length > 2048)
204
+ throw new Error();
205
+ const cursor = JSON.parse(Buffer.from(options.cursor, 'base64url').toString('utf8'));
206
+ if (cursor.version !== 1 || typeof cursor.before !== 'string' || cursor.status !== (options.status ?? null))
207
+ throw new Error();
208
+ before = records.findIndex(record => record.id === cursor.before);
209
+ if (before < 0)
210
+ throw new Error();
211
+ }
212
+ catch {
213
+ throw new AttoError('INVALID_CURSOR', 'Use a journal cursor with the same status filter.');
214
+ }
215
+ }
216
+ const matching = records.slice(0, before).reverse().filter(record => options.status === undefined || record.status === options.status);
217
+ const items = matching.slice(0, limit);
218
+ return { items, ...(matching.length > limit ? {
219
+ nextCursor: Buffer.from(JSON.stringify({ version: 1, before: items.at(-1).id, status: options.status ?? null })).toString('base64url'),
220
+ } : {}) };
221
+ }
222
+ signed(id, hash, blockJson) {
223
+ this.update(id, (record) => {
224
+ if (record.status === 'published' || record.status === 'failed' || (record.hash && record.hash !== hash)) {
225
+ throw new AttoError('SEND_STATE', 'This payment cannot be assigned a new block.');
226
+ }
227
+ if (!hash || !blockJson)
228
+ throw new AttoError('SEND_STATE', 'A signed payment requires its block hash and block.');
229
+ if (record.plan?.steps.some(step => step.status !== 'published'))
230
+ throw new AttoError('SEND_STATE', 'Complete every consolidation step before signing the external payment.');
231
+ return { ...record, hash, blockJson, status: 'signed' };
232
+ });
233
+ }
234
+ complete(id, result, publishedAt) {
235
+ this.update(id, (record) => {
236
+ if (record.status === 'published')
237
+ return record;
238
+ if (!record.hash || record.status === 'failed' || !Number.isSafeInteger(publishedAt) || publishedAt < 0) {
239
+ throw new AttoError('SEND_STATE', 'Only a recorded block can complete a payment.');
240
+ }
241
+ return { ...record, status: 'published', result, publishedAt };
242
+ });
243
+ }
244
+ uncertain(id) {
245
+ this.update(id, (record) => record.status === 'published' || record.status === 'failed' ? record : { ...record, status: 'unknown' });
246
+ }
247
+ fail(id) {
248
+ this.update(id, (record) => {
249
+ if (record.hash || record.status === 'published' || record.plan?.steps.some(step => step.hash))
250
+ throw new AttoError('SEND_STATE', 'A payment with a recorded block must be reconciled before releasing its reservation.');
251
+ return { ...record, status: 'failed' };
252
+ });
253
+ }
254
+ /** Caller must first prove a different canonical block at this block's height. */
255
+ reject(id) {
256
+ this.update(id, (record) => {
257
+ if (!record.hash || record.status === 'published')
258
+ throw new AttoError('SEND_STATE', 'Only an unpublished recorded block can be rejected after reconciliation.');
259
+ return { ...record, status: 'failed' };
260
+ });
261
+ }
262
+ stepSigned(id, stepId, hash, blockJson) {
263
+ this.updateStep(id, stepId, (step, position, plan) => {
264
+ if (step.status === 'published' || step.status === 'failed' || !hash || !blockJson
265
+ || (step.hash !== undefined && (step.hash !== hash || step.blockJson !== blockJson))
266
+ || plan.steps.slice(0, position).some(previous => previous.status !== 'published')) {
267
+ throw new AttoError('SEND_STATE', 'This consolidation step cannot be assigned a new block.');
268
+ }
269
+ return { ...step, hash, blockJson, status: 'signed' };
270
+ });
271
+ }
272
+ stepComplete(id, stepId, result, publishedAt) {
273
+ this.updateStep(id, stepId, step => {
274
+ if (step.status === 'published')
275
+ return step;
276
+ if (!step.hash || step.status === 'failed' || !Number.isSafeInteger(publishedAt) || publishedAt < 0) {
277
+ throw new AttoError('SEND_STATE', 'Only a recorded consolidation block can complete a step.');
278
+ }
279
+ return { ...step, result, publishedAt, status: 'published' };
280
+ });
281
+ }
282
+ stepUncertain(id, stepId) {
283
+ this.updateStep(id, stepId, step => {
284
+ if (step.status === 'published' || step.status === 'failed')
285
+ return step;
286
+ if (!step.hash)
287
+ throw new AttoError('SEND_STATE', 'An uncertain consolidation step requires its recorded block.');
288
+ return { ...step, status: 'unknown' };
289
+ });
290
+ }
291
+ /** Caller must prove this internal block conflicts with the canonical chain.
292
+ * The pinned plan cannot complete; retain all step evidence in the failed parent. */
293
+ stepReject(id, stepId) {
294
+ this.updateStep(id, stepId, step => {
295
+ if (!step.hash || step.status === 'published')
296
+ throw new AttoError('SEND_STATE', 'Only an unpublished recorded consolidation block can be rejected.');
297
+ return { ...step, status: 'failed' };
298
+ }, true);
299
+ }
300
+ updateStep(id, stepId, change, reject = false) {
301
+ this.update(id, record => {
302
+ if (!record.plan || record.hash || record.status === 'published' || record.status === 'failed') {
303
+ throw new AttoError('SEND_STATE', 'This payment no longer accepts consolidation changes.');
304
+ }
305
+ const position = record.plan.steps.findIndex(step => step.id === stepId);
306
+ if (position < 0)
307
+ throw new AttoError('SEND_NOT_FOUND', 'The consolidation step was not found.');
308
+ const steps = [...record.plan.steps];
309
+ steps[position] = change(steps[position], position, record.plan);
310
+ return { ...record, ...(reject ? { status: 'failed' } : {}), plan: { ...record.plan, steps } };
311
+ });
312
+ }
313
+ pending() {
314
+ return this.records().filter((record) => ['reserved', 'signed', 'unknown'].includes(record.status));
315
+ }
316
+ usage(now = Date.now()) {
317
+ const policy = this.policy();
318
+ const records = this.records();
319
+ return {
320
+ policy,
321
+ mcpAccess: this.mcpAccess(),
322
+ pool: this.pool(),
323
+ proposal: this.proposal(),
324
+ pendingRaw: this.pendingTotal(records).toString(),
325
+ perRequest: policy.perRequest ? { ...policy.perRequest, limitRaw: amountRaw(policy.perRequest.amount, policy.perRequest.unit, true) } : null,
326
+ rolling: policy.rolling.map((rule) => this.ruleUsage(rule, records, now)),
327
+ };
328
+ }
329
+ records() {
330
+ const records = this.store.get(RECORDS_KEY) ?? [];
331
+ try {
332
+ if (!Array.isArray(records))
333
+ throw new Error();
334
+ const ids = new Set();
335
+ for (const record of records) {
336
+ if (!record || typeof record !== 'object' || typeof record.id !== 'string' || !record.id || ids.has(record.id)
337
+ || !Number.isSafeInteger(record.index) || record.index < 0 || record.index > 0x7fff_ffff || typeof record.destination !== 'string' || !record.destination
338
+ || !Number.isSafeInteger(record.createdAt) || record.createdAt < 0
339
+ || !['reserved', 'signed', 'published', 'unknown', 'failed'].includes(record.status))
340
+ throw new Error();
341
+ if (amountRaw(record.raw, 'RAW') !== record.raw)
342
+ throw new Error();
343
+ if (record.hash !== undefined && (typeof record.hash !== 'string' || !record.hash || typeof record.blockJson !== 'string' || !record.blockJson))
344
+ throw new Error();
345
+ if (record.status === 'signed' && !record.hash)
346
+ throw new Error();
347
+ if (record.status === 'published' && (!record.hash || !Number.isSafeInteger(record.publishedAt) || (record.publishedAt ?? -1) < 0))
348
+ throw new Error();
349
+ this.validateDetails(record);
350
+ ids.add(record.id);
351
+ }
352
+ return records;
353
+ }
354
+ catch {
355
+ throw new AttoError('INVALID_STATE', 'The spending history is invalid. Restore verified wallet state before making payments.');
356
+ }
357
+ }
358
+ update(id, change) {
359
+ this.store.transaction(() => {
360
+ const records = this.records();
361
+ const index = records.findIndex((record) => record.id === id);
362
+ const record = records[index];
363
+ if (!record)
364
+ throw new AttoError('SEND_NOT_FOUND', 'The payment request was not found.');
365
+ records[index] = change(record);
366
+ this.validateDetails(records[index]);
367
+ this.store.set(RECORDS_KEY, records);
368
+ });
369
+ }
370
+ pendingTotal(records) {
371
+ return records.reduce((sum, record) => ['reserved', 'signed', 'unknown'].includes(record.status) ? sum + BigInt(record.raw) : sum, 0n);
372
+ }
373
+ ruleUsage(rule, records, now) {
374
+ const from = now - rule.days * DAY_MS;
375
+ // Future timestamps remain counted if the system clock moves backwards.
376
+ const published = records.reduce((sum, record) => record.status === 'published' && (record.publishedAt ?? record.createdAt) > from ? sum + BigInt(record.raw) : sum, 0n);
377
+ const reserved = this.pendingTotal(records);
378
+ const used = published + reserved;
379
+ const limit = BigInt(amountRaw(rule.amount, rule.unit, true));
380
+ return {
381
+ ...rule,
382
+ from,
383
+ until: now,
384
+ limitRaw: limit.toString(),
385
+ publishedRaw: published.toString(),
386
+ reservedRaw: reserved.toString(),
387
+ usedRaw: used.toString(),
388
+ remainingRaw: (limit > used ? limit - used : 0n).toString(),
389
+ };
390
+ }
391
+ validatePolicy(policy) {
392
+ if (!policy || typeof policy !== 'object' || !Array.isArray(policy.rolling) || policy.perRequest === undefined) {
393
+ throw new AttoError('INVALID_POLICY', 'Provide a per-request limit or null and an array of rolling limits.');
394
+ }
395
+ try {
396
+ if (policy.perRequest !== null) {
397
+ if (!['ATTO', 'RAW'].includes(policy.perRequest.unit))
398
+ throw new Error();
399
+ amountRaw(policy.perRequest.amount, policy.perRequest.unit, true);
400
+ }
401
+ for (const rule of policy.rolling) {
402
+ if (!rule || !Number.isSafeInteger(rule.days) || rule.days <= 0 || !Number.isSafeInteger(rule.days * DAY_MS))
403
+ throw new Error();
404
+ if (!['ATTO', 'RAW'].includes(rule.unit))
405
+ throw new Error();
406
+ amountRaw(rule.amount, rule.unit, true);
407
+ }
408
+ }
409
+ catch {
410
+ throw new AttoError('INVALID_POLICY', 'Limits require valid decimal amounts, explicit ATTO or RAW units, and positive whole days.');
411
+ }
412
+ }
413
+ validatePool(pool) {
414
+ if (!pool || !Array.isArray(pool.indexes) || pool.indexes.length < 1 || pool.indexes.length > 100
415
+ || pool.indexes.some(index => !Number.isSafeInteger(index) || index < 0 || index > 0x7fff_ffff)
416
+ || new Set(pool.indexes).size !== pool.indexes.length || typeof pool.consolidate !== 'boolean') {
417
+ throw new AttoError('INVALID_POOL', 'Choose 1 to 100 distinct wallet indexes and an explicit consolidation setting.');
418
+ }
419
+ }
420
+ validateDetails(record) {
421
+ if (record.destinationBinding !== undefined) {
422
+ validateDestinationBinding(record.destinationBinding);
423
+ if (record.destinationBinding.address !== record.destination || record.destinationBinding.network !== record.network)
424
+ throw new Error('Payment destination binding mismatch.');
425
+ }
426
+ if (record.sourceAddress !== undefined && (typeof record.sourceAddress !== 'string' || !record.sourceAddress || record.sourceAddress.length > 128))
427
+ throw new Error();
428
+ if (record.network !== undefined && !['LIVE', 'BETA', 'DEV', 'LOCAL'].includes(record.network))
429
+ throw new Error();
430
+ if (record.selection !== undefined && record.selection !== 'automatic' && record.selection !== 'explicit')
431
+ throw new Error();
432
+ if (record.metadata !== undefined)
433
+ paymentMetadataSchema.parse(record.metadata);
434
+ if (record.plan !== undefined)
435
+ validatePaymentPlan(record.plan, record);
436
+ }
437
+ planDefinition(plan) {
438
+ if (!plan)
439
+ return undefined;
440
+ return { indexes: plan.indexes, steps: plan.steps.map(({ id, kind, index, sourceAddress, destination, raw, sourceStepId }) => ({
441
+ id, kind, index, sourceAddress, destination, raw, ...(sourceStepId === undefined ? {} : { sourceStepId }),
442
+ })) };
443
+ }
444
+ }
@@ -0,0 +1,67 @@
1
+ import { type DestinationBinding } from './destination.js';
2
+ import { AttoSeed } from '@attocash/commons-core';
3
+ import { type SendRetry } from '../network/retry.js';
4
+ import type { MarketData } from '../pricing/market.js';
5
+ import type { StateStore } from '../storage/state.js';
6
+ import type { SendRequest, WalletAddress, WalletSettings } from '../wallet/types.js';
7
+ import type { WalletWork } from '../wallet/work.js';
8
+ import type { SpendLedger } from './ledger.js';
9
+ interface PaymentWallet {
10
+ settings(): WalletSettings;
11
+ addresses(): WalletAddress[];
12
+ seed(): Promise<AttoSeed>;
13
+ requireWrite(): void;
14
+ mcp: boolean;
15
+ }
16
+ /** Owns payment selection, reservations, publication and recovery as one workflow. */
17
+ export declare class Payments {
18
+ private readonly store;
19
+ private readonly ledger;
20
+ private readonly wallet;
21
+ private readonly market;
22
+ private readonly work;
23
+ private readonly retry?;
24
+ private readonly onDestination?;
25
+ constructor(store: StateStore, ledger: SpendLedger, wallet: PaymentWallet, market: MarketData, work: WalletWork, retry?: SendRetry | undefined, onDestination?: ((binding: DestinationBinding) => void) | undefined);
26
+ private reader;
27
+ private indexes;
28
+ private result;
29
+ private paymentResult;
30
+ private checkRequest;
31
+ private requireApproved;
32
+ /** Caller owns this account's lock; unresolved plans keep their accounts reserved. */
33
+ requireAvailable(index: number): void;
34
+ send(request: SendRequest): Promise<unknown>;
35
+ private checkAccount;
36
+ private resume;
37
+ private uncertain;
38
+ private execute;
39
+ private executeStep;
40
+ private publish;
41
+ private pendingReceivable;
42
+ reconcile(): Promise<void>;
43
+ private reconcileRecord;
44
+ poolStatus(): Promise<{
45
+ pool: import("../wallet/types.js").AccountPool;
46
+ accounts: {
47
+ index: number;
48
+ address: string | null;
49
+ opened: boolean;
50
+ balance: {
51
+ raw: string;
52
+ atto: string;
53
+ };
54
+ workReady: boolean;
55
+ busy: boolean;
56
+ }[];
57
+ total: {
58
+ raw: string;
59
+ atto: string;
60
+ };
61
+ available: {
62
+ raw: string;
63
+ atto: string;
64
+ };
65
+ }>;
66
+ }
67
+ export {};