@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.
- package/LICENSE +28 -0
- package/README.md +707 -0
- package/dist/application/app.d.ts +138 -0
- package/dist/application/app.js +654 -0
- package/dist/application/operations.d.ts +9 -0
- package/dist/application/operations.js +96 -0
- package/dist/cli/cli.d.ts +1 -0
- package/dist/cli/cli.js +460 -0
- package/dist/cli/help.d.ts +4 -0
- package/dist/cli/help.js +49 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +13 -0
- package/dist/cli/onboarding.d.ts +14 -0
- package/dist/cli/onboarding.js +144 -0
- package/dist/cli/output.d.ts +2 -0
- package/dist/cli/output.js +231 -0
- package/dist/cli/terminal.d.ts +6 -0
- package/dist/cli/terminal.js +92 -0
- package/dist/cli/update-check.d.ts +1 -0
- package/dist/cli/update-check.js +12 -0
- package/dist/cli/updates.d.ts +2 -0
- package/dist/cli/updates.js +98 -0
- package/dist/core.d.ts +14 -0
- package/dist/core.js +14 -0
- package/dist/doctor/credential-probe.d.ts +7 -0
- package/dist/doctor/credential-probe.js +49 -0
- package/dist/doctor/doctor.d.ts +4 -0
- package/dist/doctor/doctor.js +213 -0
- package/dist/doctor/keyring.d.ts +7 -0
- package/dist/doctor/keyring.js +150 -0
- package/dist/doctor/profile.d.ts +19 -0
- package/dist/doctor/profile.js +73 -0
- package/dist/doctor/types.d.ts +40 -0
- package/dist/doctor/types.js +1 -0
- package/dist/domain/amount.d.ts +6 -0
- package/dist/domain/amount.js +27 -0
- package/dist/domain/errors.d.ts +10 -0
- package/dist/domain/errors.js +16 -0
- package/dist/labels/directory.d.ts +87 -0
- package/dist/labels/directory.js +140 -0
- package/dist/labels/personal.d.ts +17 -0
- package/dist/labels/personal.js +56 -0
- package/dist/labels/presentation.d.ts +154 -0
- package/dist/labels/presentation.js +90 -0
- package/dist/network/reader.d.ts +31 -0
- package/dist/network/reader.js +370 -0
- package/dist/network/retry.d.ts +7 -0
- package/dist/network/retry.js +53 -0
- package/dist/network/work.d.ts +3 -0
- package/dist/network/work.js +66 -0
- package/dist/pricing/market.d.ts +29 -0
- package/dist/pricing/market.js +150 -0
- package/dist/pricing/terms.d.ts +6 -0
- package/dist/pricing/terms.js +12 -0
- package/dist/spending/destination.d.ts +16 -0
- package/dist/spending/destination.js +42 -0
- package/dist/spending/journal.d.ts +28 -0
- package/dist/spending/journal.js +69 -0
- package/dist/spending/ledger.d.ts +118 -0
- package/dist/spending/ledger.js +444 -0
- package/dist/spending/payments.d.ts +67 -0
- package/dist/spending/payments.js +424 -0
- package/dist/spending/pool.d.ts +13 -0
- package/dist/spending/pool.js +38 -0
- package/dist/spending/reconcile.d.ts +18 -0
- package/dist/spending/reconcile.js +64 -0
- package/dist/storage/profiles.d.ts +13 -0
- package/dist/storage/profiles.js +86 -0
- package/dist/storage/secrets.d.ts +16 -0
- package/dist/storage/secrets.js +104 -0
- package/dist/storage/state.d.ts +32 -0
- package/dist/storage/state.js +255 -0
- package/dist/wallet/auto-receive.d.ts +57 -0
- package/dist/wallet/auto-receive.js +140 -0
- package/dist/wallet/defaults.d.ts +3 -0
- package/dist/wallet/defaults.js +26 -0
- package/dist/wallet/signing.d.ts +17 -0
- package/dist/wallet/signing.js +128 -0
- package/dist/wallet/types.d.ts +65 -0
- package/dist/wallet/types.js +1 -0
- package/dist/wallet/work.d.ts +29 -0
- package/dist/wallet/work.js +154 -0
- package/dist/watches/manager.d.ts +75 -0
- package/dist/watches/manager.js +197 -0
- package/node_modules/@attocash/commons-core/Kotlin-DateTime-library-kotlinx-datetime.mjs +6678 -0
- package/node_modules/@attocash/commons-core/Kotlin-DateTime-library-kotlinx-datetime.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/LICENSE +28 -0
- package/node_modules/@attocash/commons-core/README.md +118 -0
- package/node_modules/@attocash/commons-core/commons-commons-core.d.mts +1036 -0
- package/node_modules/@attocash/commons-core/commons-commons-core.mjs +7701 -0
- package/node_modules/@attocash/commons-core/commons-commons-core.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/kotlin-kotlin-stdlib.mjs +17681 -0
- package/node_modules/@attocash/commons-core/kotlin-kotlin-stdlib.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/kotlin_org_jetbrains_kotlin_kotlin_dom_api_compat.mjs +4 -0
- package/node_modules/@attocash/commons-core/kotlin_org_jetbrains_kotlin_kotlin_dom_api_compat.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-bytestring.mjs +209 -0
- package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-bytestring.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-core.mjs +2284 -0
- package/node_modules/@attocash/commons-core/kotlinx-io-kotlinx-io-core.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-core.mjs +6042 -0
- package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-core.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
- package/node_modules/@attocash/commons-core/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-core/package.json +27 -0
- package/node_modules/@attocash/commons-node/LICENSE +28 -0
- package/node_modules/@attocash/commons-node/README.md +92 -0
- package/node_modules/@attocash/commons-node/commons-commons-node.d.mts +255 -0
- package/node_modules/@attocash/commons-node/commons-commons-node.mjs +2977 -0
- package/node_modules/@attocash/commons-node/commons-commons-node.mjs.map +1 -0
- package/node_modules/@attocash/commons-node/kotlin-logging.mjs +432 -0
- package/node_modules/@attocash/commons-node/kotlin-logging.mjs.map +1 -0
- package/node_modules/@attocash/commons-node/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
- package/node_modules/@attocash/commons-node/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-node/package.json +29 -0
- package/node_modules/@attocash/commons-node-remote/LICENSE +28 -0
- package/node_modules/@attocash/commons-node-remote/README.md +61 -0
- package/node_modules/@attocash/commons-node-remote/commons-commons-node-remote.d.mts +122 -0
- package/node_modules/@attocash/commons-node-remote/commons-commons-node-remote.mjs +1810 -0
- package/node_modules/@attocash/commons-node-remote/commons-commons-node-remote.mjs.map +1 -0
- package/node_modules/@attocash/commons-node-remote/kotlin-logging.mjs +432 -0
- package/node_modules/@attocash/commons-node-remote/kotlin-logging.mjs.map +1 -0
- package/node_modules/@attocash/commons-node-remote/kotlinx-browser.mjs +8 -0
- package/node_modules/@attocash/commons-node-remote/kotlinx-browser.mjs.map +1 -0
- package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs +4 -0
- package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs.map +1 -0
- package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
- package/node_modules/@attocash/commons-node-remote/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-node-remote/package.json +31 -0
- package/node_modules/@attocash/commons-transport/LICENSE +28 -0
- package/node_modules/@attocash/commons-transport/README.md +5 -0
- package/node_modules/@attocash/commons-transport/commons-commons-transport.d.mts +64 -0
- package/node_modules/@attocash/commons-transport/commons-commons-transport.mjs +249 -0
- package/node_modules/@attocash/commons-transport/commons-commons-transport.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/kotlinx-atomicfu.mjs +263 -0
- package/node_modules/@attocash/commons-transport/kotlinx-atomicfu.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/kotlinx-browser.mjs +8 -0
- package/node_modules/@attocash/commons-transport/kotlinx-browser.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/kotlinx-coroutines-core.mjs +11604 -0
- package/node_modules/@attocash/commons-transport/kotlinx-coroutines-core.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json-io.mjs +4 -0
- package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json-io.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
- package/node_modules/@attocash/commons-transport/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-client-content-negotiation.mjs +499 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-client-content-negotiation.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-client-core.mjs +6456 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-client-core.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-events.mjs +83 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-events.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-http-cio.mjs +1714 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-http-cio.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-http.mjs +3197 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-http.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-io.mjs +2290 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-io.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx-json.mjs +46 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx.mjs +482 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-serialization-kotlinx.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-serialization.mjs +165 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-serialization.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-sse.mjs +4 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-sse.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-utils.mjs +3222 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-utils.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-websocket-serialization.mjs +4 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-websocket-serialization.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-websockets.mjs +1485 -0
- package/node_modules/@attocash/commons-transport/ktor-ktor-websockets.mjs.map +1 -0
- package/node_modules/@attocash/commons-transport/package.json +29 -0
- package/node_modules/@attocash/commons-worker/LICENSE +28 -0
- package/node_modules/@attocash/commons-worker/README.md +48 -0
- package/node_modules/@attocash/commons-worker/commons-commons-worker.d.mts +73 -0
- package/node_modules/@attocash/commons-worker/commons-commons-worker.mjs +702 -0
- package/node_modules/@attocash/commons-worker/commons-commons-worker.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker/kotlin-logging.mjs +432 -0
- package/node_modules/@attocash/commons-worker/kotlin-logging.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
- package/node_modules/@attocash/commons-worker/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker/package.json +29 -0
- package/node_modules/@attocash/commons-worker-remote/LICENSE +28 -0
- package/node_modules/@attocash/commons-worker-remote/README.md +60 -0
- package/node_modules/@attocash/commons-worker-remote/commons-commons-worker-remote.d.mts +93 -0
- package/node_modules/@attocash/commons-worker-remote/commons-commons-worker-remote.mjs +289 -0
- package/node_modules/@attocash/commons-worker-remote/commons-commons-worker-remote.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker-remote/kotlin-logging.mjs +432 -0
- package/node_modules/@attocash/commons-worker-remote/kotlin-logging.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker-remote/kotlinx-browser.mjs +8 -0
- package/node_modules/@attocash/commons-worker-remote/kotlinx-browser.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs +4 -0
- package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json-io.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json.mjs +5294 -0
- package/node_modules/@attocash/commons-worker-remote/kotlinx-serialization-kotlinx-serialization-json.mjs.map +1 -0
- package/node_modules/@attocash/commons-worker-remote/package.json +31 -0
- package/node_modules/@js-joda/core/CHANGELOG.md +363 -0
- package/node_modules/@js-joda/core/CheatSheet.md +947 -0
- package/node_modules/@js-joda/core/LICENSE +34 -0
- package/node_modules/@js-joda/core/README.md +155 -0
- package/node_modules/@js-joda/core/bower.json +21 -0
- package/node_modules/@js-joda/core/dist/js-joda.d.ts +2452 -0
- package/node_modules/@js-joda/core/dist/js-joda.esm.js +13564 -0
- package/node_modules/@js-joda/core/dist/js-joda.flow.js +949 -0
- package/node_modules/@js-joda/core/dist/js-joda.js +13630 -0
- package/node_modules/@js-joda/core/dist/js-joda.js.map +1 -0
- package/node_modules/@js-joda/core/dist/js-joda.min.js +5 -0
- package/node_modules/@js-joda/core/package.json +76 -0
- package/node_modules/@js-joda/core/src/Clock.js +330 -0
- package/node_modules/@js-joda/core/src/DayOfWeek.js +451 -0
- package/node_modules/@js-joda/core/src/Duration.js +1205 -0
- package/node_modules/@js-joda/core/src/Enum.js +30 -0
- package/node_modules/@js-joda/core/src/Instant.js +1012 -0
- package/node_modules/@js-joda/core/src/LocalDate.js +1703 -0
- package/node_modules/@js-joda/core/src/LocalDateTime.js +1686 -0
- package/node_modules/@js-joda/core/src/LocalTime.js +1415 -0
- package/node_modules/@js-joda/core/src/MathUtil.js +236 -0
- package/node_modules/@js-joda/core/src/Month.js +600 -0
- package/node_modules/@js-joda/core/src/MonthDay.js +730 -0
- package/node_modules/@js-joda/core/src/OffsetDateTime.js +757 -0
- package/node_modules/@js-joda/core/src/OffsetTime.js +621 -0
- package/node_modules/@js-joda/core/src/Period.js +933 -0
- package/node_modules/@js-joda/core/src/StringUtil.js +43 -0
- package/node_modules/@js-joda/core/src/Year.js +1015 -0
- package/node_modules/@js-joda/core/src/YearConstants.js +21 -0
- package/node_modules/@js-joda/core/src/YearMonth.js +1096 -0
- package/node_modules/@js-joda/core/src/ZoneId.js +236 -0
- package/node_modules/@js-joda/core/src/ZoneIdFactory.js +201 -0
- package/node_modules/@js-joda/core/src/ZoneOffset.js +486 -0
- package/node_modules/@js-joda/core/src/ZoneRegion.js +72 -0
- package/node_modules/@js-joda/core/src/ZonedDateTime.js +2007 -0
- package/node_modules/@js-joda/core/src/_init.js +68 -0
- package/node_modules/@js-joda/core/src/assert.js +33 -0
- package/node_modules/@js-joda/core/src/chrono/ChronoLocalDate.js +230 -0
- package/node_modules/@js-joda/core/src/chrono/ChronoLocalDateTime.js +130 -0
- package/node_modules/@js-joda/core/src/chrono/ChronoZonedDateTime.js +194 -0
- package/node_modules/@js-joda/core/src/chrono/IsoChronology.js +235 -0
- package/node_modules/@js-joda/core/src/convert.js +83 -0
- package/node_modules/@js-joda/core/src/errors.js +54 -0
- package/node_modules/@js-joda/core/src/format/DateTimeBuilder.js +535 -0
- package/node_modules/@js-joda/core/src/format/DateTimeFormatter.js +728 -0
- package/node_modules/@js-joda/core/src/format/DateTimeFormatterBuilder.js +1545 -0
- package/node_modules/@js-joda/core/src/format/DateTimeParseContext.js +297 -0
- package/node_modules/@js-joda/core/src/format/DateTimePrintContext.js +138 -0
- package/node_modules/@js-joda/core/src/format/DecimalStyle.js +113 -0
- package/node_modules/@js-joda/core/src/format/EnumMap.js +70 -0
- package/node_modules/@js-joda/core/src/format/ParsePosition.js +31 -0
- package/node_modules/@js-joda/core/src/format/ResolverStyle.js +93 -0
- package/node_modules/@js-joda/core/src/format/SignStyle.js +38 -0
- package/node_modules/@js-joda/core/src/format/StringBuilder.js +47 -0
- package/node_modules/@js-joda/core/src/format/TextStyle.js +114 -0
- package/node_modules/@js-joda/core/src/format/parser/CharLiteralPrinterParser.js +46 -0
- package/node_modules/@js-joda/core/src/format/parser/CompositePrinterParser.js +89 -0
- package/node_modules/@js-joda/core/src/format/parser/FractionPrinterParser.js +162 -0
- package/node_modules/@js-joda/core/src/format/parser/NumberPrinterParser.js +367 -0
- package/node_modules/@js-joda/core/src/format/parser/OffsetIdPrinterParser.js +177 -0
- package/node_modules/@js-joda/core/src/format/parser/PadPrinterParserDecorator.js +81 -0
- package/node_modules/@js-joda/core/src/format/parser/SettingsParser.js +44 -0
- package/node_modules/@js-joda/core/src/format/parser/StringLiteralPrinterParser.js +39 -0
- package/node_modules/@js-joda/core/src/format/parser/ZoneIdPrinterParser.js +218 -0
- package/node_modules/@js-joda/core/src/js-joda.js +210 -0
- package/node_modules/@js-joda/core/src/license-preamble.js +3 -0
- package/node_modules/@js-joda/core/src/temporal/ChronoField.js +470 -0
- package/node_modules/@js-joda/core/src/temporal/ChronoUnit.js +310 -0
- package/node_modules/@js-joda/core/src/temporal/DefaultInterfaceTemporal.js +118 -0
- package/node_modules/@js-joda/core/src/temporal/IsoFields.js +859 -0
- package/node_modules/@js-joda/core/src/temporal/NativeJsTemporal.js +105 -0
- package/node_modules/@js-joda/core/src/temporal/Temporal.js +346 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAccessor.js +125 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAdjuster.js +92 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAdjusters.js +464 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAmount.js +166 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalField.js +248 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalQueries.js +223 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalQueriesFactory.js +77 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalQuery.js +107 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalUnit.js +179 -0
- package/node_modules/@js-joda/core/src/temporal/ValueRange.js +257 -0
- package/node_modules/@js-joda/core/src/use.js +20 -0
- package/node_modules/@js-joda/core/src/zone/SystemDefaultZoneId.js +31 -0
- package/node_modules/@js-joda/core/src/zone/SystemDefaultZoneRules.js +162 -0
- package/node_modules/@js-joda/core/src/zone/ZoneOffsetTransition.js +289 -0
- package/node_modules/@js-joda/core/src/zone/ZoneRules.js +464 -0
- package/node_modules/@js-joda/core/src/zone/ZoneRulesProvider.js +36 -0
- package/node_modules/@noble/hashes/LICENSE +21 -0
- package/node_modules/@noble/hashes/README.md +563 -0
- package/node_modules/@noble/hashes/_blake.d.ts +21 -0
- package/node_modules/@noble/hashes/_blake.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_blake.js +52 -0
- package/node_modules/@noble/hashes/_blake.js.map +1 -0
- package/node_modules/@noble/hashes/_md.d.ts +99 -0
- package/node_modules/@noble/hashes/_md.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_md.js +202 -0
- package/node_modules/@noble/hashes/_md.js.map +1 -0
- package/node_modules/@noble/hashes/_u64.d.ts +63 -0
- package/node_modules/@noble/hashes/_u64.d.ts.map +1 -0
- package/node_modules/@noble/hashes/_u64.js +84 -0
- package/node_modules/@noble/hashes/_u64.js.map +1 -0
- package/node_modules/@noble/hashes/argon2.d.ts +112 -0
- package/node_modules/@noble/hashes/argon2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/argon2.js +517 -0
- package/node_modules/@noble/hashes/argon2.js.map +1 -0
- package/node_modules/@noble/hashes/blake1.d.ts +156 -0
- package/node_modules/@noble/hashes/blake1.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake1.js +560 -0
- package/node_modules/@noble/hashes/blake1.js.map +1 -0
- package/node_modules/@noble/hashes/blake2.d.ts +184 -0
- package/node_modules/@noble/hashes/blake2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake2.js +501 -0
- package/node_modules/@noble/hashes/blake2.js.map +1 -0
- package/node_modules/@noble/hashes/blake3.d.ts +68 -0
- package/node_modules/@noble/hashes/blake3.d.ts.map +1 -0
- package/node_modules/@noble/hashes/blake3.js +284 -0
- package/node_modules/@noble/hashes/blake3.js.map +1 -0
- package/node_modules/@noble/hashes/eskdf.d.ts +92 -0
- package/node_modules/@noble/hashes/eskdf.d.ts.map +1 -0
- package/node_modules/@noble/hashes/eskdf.js +218 -0
- package/node_modules/@noble/hashes/eskdf.js.map +1 -0
- package/node_modules/@noble/hashes/hkdf.d.ts +64 -0
- package/node_modules/@noble/hashes/hkdf.d.ts.map +1 -0
- package/node_modules/@noble/hashes/hkdf.js +120 -0
- package/node_modules/@noble/hashes/hkdf.js.map +1 -0
- package/node_modules/@noble/hashes/hmac.d.ts +47 -0
- package/node_modules/@noble/hashes/hmac.d.ts.map +1 -0
- package/node_modules/@noble/hashes/hmac.js +93 -0
- package/node_modules/@noble/hashes/hmac.js.map +1 -0
- package/node_modules/@noble/hashes/index.d.ts +2 -0
- package/node_modules/@noble/hashes/index.d.ts.map +1 -0
- package/node_modules/@noble/hashes/index.js +35 -0
- package/node_modules/@noble/hashes/index.js.map +1 -0
- package/node_modules/@noble/hashes/legacy.d.ts +102 -0
- package/node_modules/@noble/hashes/legacy.d.ts.map +1 -0
- package/node_modules/@noble/hashes/legacy.js +327 -0
- package/node_modules/@noble/hashes/legacy.js.map +1 -0
- package/node_modules/@noble/hashes/package.json +97 -0
- package/node_modules/@noble/hashes/pbkdf2.d.ts +56 -0
- package/node_modules/@noble/hashes/pbkdf2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/pbkdf2.js +135 -0
- package/node_modules/@noble/hashes/pbkdf2.js.map +1 -0
- package/node_modules/@noble/hashes/scrypt.d.ts +65 -0
- package/node_modules/@noble/hashes/scrypt.d.ts.map +1 -0
- package/node_modules/@noble/hashes/scrypt.js +257 -0
- package/node_modules/@noble/hashes/scrypt.js.map +1 -0
- package/node_modules/@noble/hashes/sha2.d.ts +249 -0
- package/node_modules/@noble/hashes/sha2.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha2.js +458 -0
- package/node_modules/@noble/hashes/sha2.js.map +1 -0
- package/node_modules/@noble/hashes/sha3-addons.d.ts +461 -0
- package/node_modules/@noble/hashes/sha3-addons.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha3-addons.js +783 -0
- package/node_modules/@noble/hashes/sha3-addons.js.map +1 -0
- package/node_modules/@noble/hashes/sha3.d.ts +199 -0
- package/node_modules/@noble/hashes/sha3.d.ts.map +1 -0
- package/node_modules/@noble/hashes/sha3.js +431 -0
- package/node_modules/@noble/hashes/sha3.js.map +1 -0
- package/node_modules/@noble/hashes/src/_blake.ts +57 -0
- package/node_modules/@noble/hashes/src/_md.ts +222 -0
- package/node_modules/@noble/hashes/src/_u64.ts +117 -0
- package/node_modules/@noble/hashes/src/argon2.ts +667 -0
- package/node_modules/@noble/hashes/src/blake1.ts +614 -0
- package/node_modules/@noble/hashes/src/blake2.ts +582 -0
- package/node_modules/@noble/hashes/src/blake3.ts +317 -0
- package/node_modules/@noble/hashes/src/eskdf.ts +259 -0
- package/node_modules/@noble/hashes/src/hkdf.ts +133 -0
- package/node_modules/@noble/hashes/src/hmac.ts +126 -0
- package/node_modules/@noble/hashes/src/index.ts +33 -0
- package/node_modules/@noble/hashes/src/legacy.ts +339 -0
- package/node_modules/@noble/hashes/src/pbkdf2.ts +175 -0
- package/node_modules/@noble/hashes/src/scrypt.ts +315 -0
- package/node_modules/@noble/hashes/src/sha2.ts +530 -0
- package/node_modules/@noble/hashes/src/sha3-addons.ts +983 -0
- package/node_modules/@noble/hashes/src/sha3.ts +485 -0
- package/node_modules/@noble/hashes/src/utils.ts +848 -0
- package/node_modules/@noble/hashes/src/webcrypto.ts +239 -0
- package/node_modules/@noble/hashes/utils.d.ts +519 -0
- package/node_modules/@noble/hashes/utils.d.ts.map +1 -0
- package/node_modules/@noble/hashes/utils.js +578 -0
- package/node_modules/@noble/hashes/utils.js.map +1 -0
- package/node_modules/@noble/hashes/webcrypto.d.ts +120 -0
- package/node_modules/@noble/hashes/webcrypto.d.ts.map +1 -0
- package/node_modules/@noble/hashes/webcrypto.js +165 -0
- package/node_modules/@noble/hashes/webcrypto.js.map +1 -0
- package/node_modules/ws/LICENSE +20 -0
- package/node_modules/ws/README.md +548 -0
- package/node_modules/ws/browser.js +8 -0
- package/node_modules/ws/index.js +22 -0
- package/node_modules/ws/lib/buffer-util.js +131 -0
- package/node_modules/ws/lib/constants.js +19 -0
- package/node_modules/ws/lib/event-target.js +292 -0
- package/node_modules/ws/lib/extension.js +203 -0
- package/node_modules/ws/lib/limiter.js +55 -0
- package/node_modules/ws/lib/permessage-deflate.js +530 -0
- package/node_modules/ws/lib/receiver.js +743 -0
- package/node_modules/ws/lib/sender.js +607 -0
- package/node_modules/ws/lib/stream.js +161 -0
- package/node_modules/ws/lib/subprotocol.js +62 -0
- package/node_modules/ws/lib/validation.js +152 -0
- package/node_modules/ws/lib/websocket-server.js +562 -0
- package/node_modules/ws/lib/websocket.js +1407 -0
- package/node_modules/ws/package.json +74 -0
- package/node_modules/ws/wrapper.mjs +21 -0
- package/package.json +53 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { amountOutput, amountRaw } from '../domain/amount.js';
|
|
2
|
+
import { AttoError } from '../domain/errors.js';
|
|
3
|
+
export const DEFAULT_METRICS_URL = 'https://gatekeeper.live.application.atto.cash/projections/metrics';
|
|
4
|
+
const MAX_RESPONSE_BYTES = 1_048_576;
|
|
5
|
+
// Projections are dated daily, so accept a UTC metric date at most 72 hours old.
|
|
6
|
+
const MAX_PRICE_AGE_MS = 72 * 60 * 60 * 1000;
|
|
7
|
+
const RAW_PER_ATTO = 1000000000n;
|
|
8
|
+
function decimal(value) {
|
|
9
|
+
// Bound parsing work while preserving substantially more precision than RAW.
|
|
10
|
+
if (typeof value !== 'string' || !/^\d{1,40}(?:\.\d{1,40})?$/.test(value))
|
|
11
|
+
throw new Error('Invalid decimal');
|
|
12
|
+
const [whole, fraction = ''] = value.split('.');
|
|
13
|
+
return { coefficient: BigInt(`${whole}${fraction}`), scale: 10n ** BigInt(fraction.length) };
|
|
14
|
+
}
|
|
15
|
+
export class MarketData {
|
|
16
|
+
fetchImpl;
|
|
17
|
+
source;
|
|
18
|
+
constructor(url = DEFAULT_METRICS_URL, fetchImpl = fetch) {
|
|
19
|
+
this.fetchImpl = fetchImpl;
|
|
20
|
+
let parsed;
|
|
21
|
+
try {
|
|
22
|
+
parsed = new URL(url);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new AttoError('INVALID_MARKET_URL', 'Market data requires an HTTPS URL without credentials.');
|
|
26
|
+
}
|
|
27
|
+
if (parsed.protocol !== 'https:' || parsed.username || parsed.password)
|
|
28
|
+
throw new AttoError('INVALID_MARKET_URL', 'Market data requires an HTTPS URL without credentials.');
|
|
29
|
+
this.source = parsed.href;
|
|
30
|
+
}
|
|
31
|
+
async metrics(signal) {
|
|
32
|
+
let payload;
|
|
33
|
+
try {
|
|
34
|
+
const response = await this.fetchImpl(this.source, {
|
|
35
|
+
signal: AbortSignal.any([AbortSignal.timeout(10_000), ...(signal ? [signal] : [])]),
|
|
36
|
+
headers: { Accept: 'application/json' },
|
|
37
|
+
credentials: 'omit',
|
|
38
|
+
redirect: 'error',
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok || !response.body) {
|
|
41
|
+
await response.body?.cancel();
|
|
42
|
+
throw new AttoError('MARKET_DATA_UNAVAILABLE', 'Market data is currently unavailable.', { httpStatus: response.status });
|
|
43
|
+
}
|
|
44
|
+
if (Number(response.headers.get('content-length') ?? 0) > MAX_RESPONSE_BYTES) {
|
|
45
|
+
await response.body.cancel();
|
|
46
|
+
throw new AttoError('MARKET_DATA_INVALID', 'The market-data response exceeds the supported size.');
|
|
47
|
+
}
|
|
48
|
+
const reader = response.body.getReader();
|
|
49
|
+
const chunks = [];
|
|
50
|
+
let size = 0;
|
|
51
|
+
try {
|
|
52
|
+
for (;;) {
|
|
53
|
+
const { done, value } = await reader.read();
|
|
54
|
+
if (done)
|
|
55
|
+
break;
|
|
56
|
+
size += value.byteLength;
|
|
57
|
+
if (size > MAX_RESPONSE_BYTES) {
|
|
58
|
+
await reader.cancel();
|
|
59
|
+
throw new AttoError('MARKET_DATA_INVALID', 'The market-data response exceeds the supported size.');
|
|
60
|
+
}
|
|
61
|
+
chunks.push(value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
reader.releaseLock();
|
|
66
|
+
}
|
|
67
|
+
const bytes = new Uint8Array(size);
|
|
68
|
+
let offset = 0;
|
|
69
|
+
for (const chunk of chunks) {
|
|
70
|
+
bytes.set(chunk, offset);
|
|
71
|
+
offset += chunk.byteLength;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
payload = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new AttoError('MARKET_DATA_INVALID', 'The market-data response is not valid JSON.');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof AttoError)
|
|
82
|
+
throw error;
|
|
83
|
+
throw new AttoError('MARKET_DATA_UNAVAILABLE', 'Market data could not be retrieved within ten seconds.');
|
|
84
|
+
}
|
|
85
|
+
if (!payload || typeof payload !== 'object' || !('metrics' in payload) || !Array.isArray(payload.metrics)) {
|
|
86
|
+
throw new AttoError('MARKET_DATA_INVALID', 'The market-data response must contain a metrics array.');
|
|
87
|
+
}
|
|
88
|
+
const metrics = payload.metrics.map((metric) => {
|
|
89
|
+
if (!metric || typeof metric !== 'object' || !('name' in metric) || typeof metric.name !== 'string'
|
|
90
|
+
|| !('date' in metric) || typeof metric.date !== 'string' || !('value' in metric) || typeof metric.value !== 'string') {
|
|
91
|
+
throw new AttoError('MARKET_DATA_INVALID', 'Each market metric requires a name, date, and string value.');
|
|
92
|
+
}
|
|
93
|
+
return { name: metric.name, date: metric.date, value: metric.value };
|
|
94
|
+
});
|
|
95
|
+
return { metrics, source: this.source, fetchedAt: new Date().toISOString() };
|
|
96
|
+
}
|
|
97
|
+
async quoteUsd(amount, signal) {
|
|
98
|
+
let usd;
|
|
99
|
+
try {
|
|
100
|
+
usd = decimal(amount);
|
|
101
|
+
if (usd.coefficient <= 0n)
|
|
102
|
+
throw new Error();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new AttoError('INVALID_USD_AMOUNT', 'USD amount must be a positive decimal string with at most 40 digits on either side of the decimal point.');
|
|
106
|
+
}
|
|
107
|
+
const snapshot = await this.metrics(signal);
|
|
108
|
+
const prices = snapshot.metrics.filter((metric) => metric.name === 'price.usd');
|
|
109
|
+
const price = prices[0];
|
|
110
|
+
if (prices.length !== 1 || !price)
|
|
111
|
+
throw new AttoError('INVALID_PRICE', 'Market data must contain exactly one USD price.');
|
|
112
|
+
let ratio;
|
|
113
|
+
try {
|
|
114
|
+
ratio = decimal(price.value);
|
|
115
|
+
if (ratio.coefficient <= 0n)
|
|
116
|
+
throw new Error();
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
throw new AttoError('INVALID_PRICE', 'The USD price must be a positive decimal string.');
|
|
120
|
+
}
|
|
121
|
+
const priceTime = Date.parse(`${price.date}T00:00:00.000Z`);
|
|
122
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(price.date) || !Number.isFinite(priceTime) || new Date(priceTime).toISOString().slice(0, 10) !== price.date) {
|
|
123
|
+
throw new AttoError('INVALID_PRICE', 'The USD price requires a valid UTC calendar date.');
|
|
124
|
+
}
|
|
125
|
+
const age = Date.parse(snapshot.fetchedAt) - priceTime;
|
|
126
|
+
if (age < 0)
|
|
127
|
+
throw new AttoError('PRICE_FUTURE', 'The USD price has a future date.');
|
|
128
|
+
if (age > MAX_PRICE_AGE_MS)
|
|
129
|
+
throw new AttoError('PRICE_STALE', 'The daily USD price is more than 72 hours old.');
|
|
130
|
+
const raw = usd.coefficient * ratio.scale * RAW_PER_ATTO / (usd.scale * ratio.coefficient);
|
|
131
|
+
if (raw === 0n)
|
|
132
|
+
throw new AttoError('INVALID_USD_AMOUNT', 'The USD amount converts to less than 1 RAW.');
|
|
133
|
+
let converted;
|
|
134
|
+
try {
|
|
135
|
+
converted = amountRaw(raw.toString(), 'RAW');
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
throw new AttoError('INVALID_USD_AMOUNT', 'The USD amount converts to more than the Atto amount range allows.');
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
usd: amount,
|
|
142
|
+
priceUsd: price.value,
|
|
143
|
+
priceDate: price.date,
|
|
144
|
+
source: snapshot.source,
|
|
145
|
+
fetchedAt: snapshot.fetchedAt,
|
|
146
|
+
amount: amountOutput(converted),
|
|
147
|
+
informational: true,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Informational acknowledgement, adapted from the desktop wallet's market-data notice. */
|
|
2
|
+
export const marketTerms = {
|
|
3
|
+
version: '2026-09-05',
|
|
4
|
+
title: 'USD conversion and wallet responsibility',
|
|
5
|
+
text: 'USD conversions use an indicative daily Atto market-data price, not an executable market quote. '
|
|
6
|
+
+ 'Prices may be incorrect, delayed, unavailable, or outdated, and the displayed source and price date should be checked. '
|
|
7
|
+
+ 'Conversions round down to whole RAW and transactions send ATTO, not USD. No USD proceeds, exchange rate, or realizable value are promised. '
|
|
8
|
+
+ 'This information is not financial, investment, trading, legal, or tax advice and should not be your only basis for a decision. '
|
|
9
|
+
+ 'This wallet uses self-custody: you are responsible for securing your device and recovery phrase and checking destination addresses and amounts. '
|
|
10
|
+
+ 'Anyone with the recovery phrase may control your funds; confirmed network transactions may be irreversible. '
|
|
11
|
+
+ 'Acknowledgement records that you have read this information.',
|
|
12
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { StateStore } from '../storage/state.js';
|
|
2
|
+
import type { NetworkName } from '../wallet/types.js';
|
|
3
|
+
import type { SpendLedger } from './ledger.js';
|
|
4
|
+
export interface DestinationBinding {
|
|
5
|
+
address: string;
|
|
6
|
+
network: NetworkName;
|
|
7
|
+
label?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function validateDestinationBinding(binding: DestinationBinding): void;
|
|
10
|
+
/** Pins destinations even when selection/pricing fails before a reservation.
|
|
11
|
+
* The label lookup and first binding share one SQLite write transaction. */
|
|
12
|
+
export declare function bindDestination(store: StateStore, ledger: SpendLedger, network: NetworkName, request: {
|
|
13
|
+
requestId: string;
|
|
14
|
+
destination?: string;
|
|
15
|
+
destinationLabel?: string;
|
|
16
|
+
}): DestinationBinding;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AttoError } from '../domain/errors.js';
|
|
2
|
+
import { PersonalLabels, nameKey, personalNameSchema } from '../labels/personal.js';
|
|
3
|
+
import { parseAddress } from '../network/reader.js';
|
|
4
|
+
export function validateDestinationBinding(binding) {
|
|
5
|
+
if (!binding || !['LIVE', 'BETA', 'DEV', 'LOCAL'].includes(binding.network) || parseAddress(binding.address).value !== binding.address
|
|
6
|
+
|| (binding.label !== undefined && personalNameSchema.parse(binding.label) !== binding.label))
|
|
7
|
+
throw new Error('Invalid payment destination binding.');
|
|
8
|
+
}
|
|
9
|
+
/** Pins destinations even when selection/pricing fails before a reservation.
|
|
10
|
+
* The label lookup and first binding share one SQLite write transaction. */
|
|
11
|
+
export function bindDestination(store, ledger, network, request) {
|
|
12
|
+
return store.transaction(() => {
|
|
13
|
+
const key = `send.destination.${request.requestId}`;
|
|
14
|
+
const saved = store.get(key);
|
|
15
|
+
const record = ledger.get(request.requestId);
|
|
16
|
+
const prior = saved ?? record?.destinationBinding;
|
|
17
|
+
if (prior) {
|
|
18
|
+
try {
|
|
19
|
+
validateDestinationBinding(prior);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new AttoError('INVALID_STATE', 'The saved payment destination is invalid. Restore verified profile state.');
|
|
23
|
+
}
|
|
24
|
+
if (prior.network !== network)
|
|
25
|
+
throw new AttoError('NETWORK_MISMATCH', 'This request ID belongs to another network.');
|
|
26
|
+
if (request.destinationLabel !== undefined
|
|
27
|
+
? prior.label === undefined || nameKey(prior.label) !== nameKey(request.destinationLabel)
|
|
28
|
+
: parseAddress(request.destination).value !== prior.address) {
|
|
29
|
+
throw new AttoError('REQUEST_CONFLICT', 'This request ID belongs to a different destination. Use its original personal name or full address.');
|
|
30
|
+
}
|
|
31
|
+
return prior;
|
|
32
|
+
}
|
|
33
|
+
const local = request.destinationLabel === undefined ? undefined : new PersonalLabels(store).resolve(network, request.destinationLabel);
|
|
34
|
+
const binding = { network, address: local?.address ?? parseAddress(request.destination).value,
|
|
35
|
+
...(local ? { label: local.label } : {}) };
|
|
36
|
+
if (record && (record.destination !== binding.address || (record.network && record.network !== network))) {
|
|
37
|
+
throw new AttoError('REQUEST_CONFLICT', 'This request ID belongs to a different payment destination or network.');
|
|
38
|
+
}
|
|
39
|
+
store.set(key, binding);
|
|
40
|
+
return binding;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const paymentMetadataSchema: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
|
|
3
|
+
export type PaymentMetadata = z.infer<typeof paymentMetadataSchema>;
|
|
4
|
+
export type PaymentStepStatus = 'planned' | 'signed' | 'published' | 'unknown' | 'failed';
|
|
5
|
+
export interface ConsolidationStep {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: 'send' | 'receive';
|
|
8
|
+
index: number;
|
|
9
|
+
sourceAddress: string;
|
|
10
|
+
destination: string;
|
|
11
|
+
raw: string;
|
|
12
|
+
sourceStepId?: string;
|
|
13
|
+
status: PaymentStepStatus;
|
|
14
|
+
hash?: string;
|
|
15
|
+
blockJson?: string;
|
|
16
|
+
result?: unknown;
|
|
17
|
+
publishedAt?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface PaymentPlan {
|
|
20
|
+
indexes: number[];
|
|
21
|
+
steps: ConsolidationStep[];
|
|
22
|
+
}
|
|
23
|
+
/** Check durable structure here; the payment engine verifies derived addresses
|
|
24
|
+
* and the exact transaction content again before each signature. */
|
|
25
|
+
export declare function validatePaymentPlan(plan: PaymentPlan, parent: {
|
|
26
|
+
index: number;
|
|
27
|
+
sourceAddress?: string;
|
|
28
|
+
}): void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { amountRaw } from '../domain/amount.js';
|
|
3
|
+
export const paymentMetadataSchema = z.record(z.string().min(1).max(128), z.json()).superRefine((metadata, context) => {
|
|
4
|
+
let nodes = 0;
|
|
5
|
+
const bounded = (value, depth) => {
|
|
6
|
+
if (++nodes > 256 || depth > 5)
|
|
7
|
+
return false;
|
|
8
|
+
if (value !== null && typeof value === 'object')
|
|
9
|
+
return Object.values(value).every(child => bounded(child, depth + 1));
|
|
10
|
+
return true;
|
|
11
|
+
};
|
|
12
|
+
if (!bounded(metadata, 0) || Buffer.byteLength(JSON.stringify(metadata), 'utf8') > 4096) {
|
|
13
|
+
context.addIssue({ code: 'custom', message: 'Payment metadata must fit 4096 bytes, 256 values, and five nesting levels.' });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
/** Check durable structure here; the payment engine verifies derived addresses
|
|
17
|
+
* and the exact transaction content again before each signature. */
|
|
18
|
+
export function validatePaymentPlan(plan, parent) {
|
|
19
|
+
if (!plan || !Array.isArray(plan.indexes) || plan.indexes.length < 1 || plan.indexes.length > 100
|
|
20
|
+
|| plan.indexes.some(index => !Number.isSafeInteger(index) || index < 0 || index > 0x7fff_ffff)
|
|
21
|
+
|| new Set(plan.indexes).size !== plan.indexes.length || !plan.indexes.includes(parent.index)
|
|
22
|
+
|| !Array.isArray(plan.steps) || plan.steps.length > 200 || !parent.sourceAddress)
|
|
23
|
+
throw new Error('Invalid payment plan.');
|
|
24
|
+
const steps = new Map();
|
|
25
|
+
const received = new Set();
|
|
26
|
+
const accountAddresses = new Map([[parent.index, parent.sourceAddress]]);
|
|
27
|
+
let sentRaw = 0n;
|
|
28
|
+
let receivedRaw = 0n;
|
|
29
|
+
let unfinished = false;
|
|
30
|
+
for (const step of plan.steps) {
|
|
31
|
+
if (!step || typeof step.id !== 'string' || !step.id || step.id.length > 200 || steps.has(step.id)
|
|
32
|
+
|| !['send', 'receive'].includes(step.kind) || !plan.indexes.includes(step.index)
|
|
33
|
+
|| typeof step.sourceAddress !== 'string' || !step.sourceAddress || step.sourceAddress.length > 128
|
|
34
|
+
|| step.destination !== parent.sourceAddress || amountRaw(step.raw, 'RAW') !== step.raw
|
|
35
|
+
|| !['planned', 'signed', 'published', 'unknown', 'failed'].includes(step.status))
|
|
36
|
+
throw new Error('Invalid consolidation step.');
|
|
37
|
+
if (accountAddresses.has(step.index) && accountAddresses.get(step.index) !== step.sourceAddress)
|
|
38
|
+
throw new Error('Inconsistent step account.');
|
|
39
|
+
accountAddresses.set(step.index, step.sourceAddress);
|
|
40
|
+
if (step.hash !== undefined && (typeof step.hash !== 'string' || !step.hash || typeof step.blockJson !== 'string' || !step.blockJson))
|
|
41
|
+
throw new Error('Invalid recorded step.');
|
|
42
|
+
if (['signed', 'published', 'unknown'].includes(step.status) && !step.hash)
|
|
43
|
+
throw new Error('Missing step block.');
|
|
44
|
+
if (step.status === 'planned' && step.hash !== undefined)
|
|
45
|
+
throw new Error('Planned step already has a block.');
|
|
46
|
+
if (unfinished && step.status !== 'planned')
|
|
47
|
+
throw new Error('Consolidation steps advanced out of order.');
|
|
48
|
+
if (step.status !== 'published')
|
|
49
|
+
unfinished = true;
|
|
50
|
+
if (step.status === 'published' && (!Number.isSafeInteger(step.publishedAt) || (step.publishedAt ?? -1) < 0))
|
|
51
|
+
throw new Error('Invalid publication timestamp.');
|
|
52
|
+
if (step.kind === 'send') {
|
|
53
|
+
if (step.index === parent.index || step.sourceAddress === parent.sourceAddress || step.sourceStepId !== undefined)
|
|
54
|
+
throw new Error('Invalid consolidation source.');
|
|
55
|
+
sentRaw += BigInt(step.raw);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const source = step.sourceStepId === undefined ? undefined : steps.get(step.sourceStepId);
|
|
59
|
+
if (!source || source.kind !== 'send' || received.has(source.id) || source.raw !== step.raw
|
|
60
|
+
|| source.destination !== step.destination || step.index !== parent.index || step.sourceAddress !== parent.sourceAddress)
|
|
61
|
+
throw new Error('Invalid consolidation receipt.');
|
|
62
|
+
received.add(source.id);
|
|
63
|
+
receivedRaw += BigInt(step.raw);
|
|
64
|
+
}
|
|
65
|
+
steps.set(step.id, step);
|
|
66
|
+
}
|
|
67
|
+
if (sentRaw !== receivedRaw || [...steps.values()].some(step => step.kind === 'send' && !received.has(step.id)))
|
|
68
|
+
throw new Error('Incomplete consolidation plan.');
|
|
69
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type DestinationBinding } from './destination.js';
|
|
2
|
+
import type { StateStore } from '../storage/state.js';
|
|
3
|
+
import type { AccountPool, SpendingPolicy } from '../wallet/types.js';
|
|
4
|
+
import { type PaymentMetadata, type PaymentPlan } from './journal.js';
|
|
5
|
+
export type { ConsolidationStep, PaymentMetadata, PaymentPlan } from './journal.js';
|
|
6
|
+
export interface SendRecord {
|
|
7
|
+
id: string;
|
|
8
|
+
index: number;
|
|
9
|
+
destination: string;
|
|
10
|
+
destinationBinding?: DestinationBinding;
|
|
11
|
+
raw: string;
|
|
12
|
+
createdAt: number;
|
|
13
|
+
status: 'reserved' | 'signed' | 'published' | 'unknown' | 'failed';
|
|
14
|
+
hash?: string;
|
|
15
|
+
blockJson?: string;
|
|
16
|
+
result?: unknown;
|
|
17
|
+
publishedAt?: number;
|
|
18
|
+
sourceAddress?: string;
|
|
19
|
+
network?: string;
|
|
20
|
+
metadata?: PaymentMetadata;
|
|
21
|
+
quote?: unknown;
|
|
22
|
+
selection?: 'automatic' | 'explicit';
|
|
23
|
+
plan?: PaymentPlan;
|
|
24
|
+
}
|
|
25
|
+
export type SendReservation = Pick<SendRecord, 'id' | 'index' | 'destination' | 'raw' | 'createdAt'> & Partial<Pick<SendRecord, 'sourceAddress' | 'network' | 'metadata' | 'quote' | 'selection' | 'plan' | 'destinationBinding'>>;
|
|
26
|
+
export type McpAccess = 'read-only' | 'spend';
|
|
27
|
+
export interface ProposalWallet {
|
|
28
|
+
directory: string;
|
|
29
|
+
walletFingerprint: string | null;
|
|
30
|
+
network: string;
|
|
31
|
+
}
|
|
32
|
+
export interface LimitsProposal extends ProposalWallet {
|
|
33
|
+
id: string;
|
|
34
|
+
policy: SpendingPolicy;
|
|
35
|
+
access: McpAccess;
|
|
36
|
+
createdAt: number;
|
|
37
|
+
expiresAt: number;
|
|
38
|
+
baseRevision: number;
|
|
39
|
+
status: 'pending' | 'approved' | 'rejected';
|
|
40
|
+
decidedAt?: number;
|
|
41
|
+
pool?: AccountPool;
|
|
42
|
+
}
|
|
43
|
+
export declare class SpendLedger {
|
|
44
|
+
private readonly store;
|
|
45
|
+
constructor(store: StateStore);
|
|
46
|
+
policy(): SpendingPolicy;
|
|
47
|
+
setPolicy(policy: SpendingPolicy): void;
|
|
48
|
+
mcpAccess(): McpAccess;
|
|
49
|
+
pool(): AccountPool;
|
|
50
|
+
proposePolicy(policy: SpendingPolicy, access: McpAccess, wallet: ProposalWallet, pool?: AccountPool): LimitsProposal;
|
|
51
|
+
proposal(): LimitsProposal | null;
|
|
52
|
+
reviewProposal(id: string, wallet: ProposalWallet): LimitsProposal;
|
|
53
|
+
approveProposal(id: string, wallet: ProposalWallet): void;
|
|
54
|
+
rejectProposal(id: string, wallet: ProposalWallet): void;
|
|
55
|
+
private revision;
|
|
56
|
+
private replacePolicy;
|
|
57
|
+
assertCanReserve(raw: string, now?: number): void;
|
|
58
|
+
/** Recheck the current policy before signing without charging this reservation twice. */
|
|
59
|
+
assertReservationAllowed(id: string, now?: number): void;
|
|
60
|
+
private assertAllowance;
|
|
61
|
+
reserve(request: SendReservation): SendRecord;
|
|
62
|
+
get(id: string): SendRecord | undefined;
|
|
63
|
+
journalGet(requestId: string): SendRecord | undefined;
|
|
64
|
+
journalList(options?: {
|
|
65
|
+
limit?: number;
|
|
66
|
+
cursor?: string;
|
|
67
|
+
status?: SendRecord['status'];
|
|
68
|
+
}): {
|
|
69
|
+
items: SendRecord[];
|
|
70
|
+
nextCursor?: string;
|
|
71
|
+
};
|
|
72
|
+
signed(id: string, hash: string, blockJson: string): void;
|
|
73
|
+
complete(id: string, result: unknown, publishedAt: number): void;
|
|
74
|
+
uncertain(id: string): void;
|
|
75
|
+
fail(id: string): void;
|
|
76
|
+
/** Caller must first prove a different canonical block at this block's height. */
|
|
77
|
+
reject(id: string): void;
|
|
78
|
+
stepSigned(id: string, stepId: string, hash: string, blockJson: string): void;
|
|
79
|
+
stepComplete(id: string, stepId: string, result: unknown, publishedAt: number): void;
|
|
80
|
+
stepUncertain(id: string, stepId: string): void;
|
|
81
|
+
/** Caller must prove this internal block conflicts with the canonical chain.
|
|
82
|
+
* The pinned plan cannot complete; retain all step evidence in the failed parent. */
|
|
83
|
+
stepReject(id: string, stepId: string): void;
|
|
84
|
+
private updateStep;
|
|
85
|
+
pending(): SendRecord[];
|
|
86
|
+
usage(now?: number): {
|
|
87
|
+
policy: SpendingPolicy;
|
|
88
|
+
mcpAccess: McpAccess;
|
|
89
|
+
pool: AccountPool;
|
|
90
|
+
proposal: LimitsProposal | null;
|
|
91
|
+
pendingRaw: string;
|
|
92
|
+
perRequest: {
|
|
93
|
+
limitRaw: string;
|
|
94
|
+
amount: string;
|
|
95
|
+
unit: import("../wallet/types.js").AmountUnit;
|
|
96
|
+
} | null;
|
|
97
|
+
rolling: {
|
|
98
|
+
from: number;
|
|
99
|
+
until: number;
|
|
100
|
+
limitRaw: string;
|
|
101
|
+
publishedRaw: string;
|
|
102
|
+
reservedRaw: string;
|
|
103
|
+
usedRaw: string;
|
|
104
|
+
remainingRaw: string;
|
|
105
|
+
days: number;
|
|
106
|
+
amount: string;
|
|
107
|
+
unit: import("../wallet/types.js").AmountUnit;
|
|
108
|
+
}[];
|
|
109
|
+
};
|
|
110
|
+
private records;
|
|
111
|
+
private update;
|
|
112
|
+
private pendingTotal;
|
|
113
|
+
private ruleUsage;
|
|
114
|
+
private validatePolicy;
|
|
115
|
+
private validatePool;
|
|
116
|
+
private validateDetails;
|
|
117
|
+
private planDefinition;
|
|
118
|
+
}
|