@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,73 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { parseOperation } from '../application/operations.js';
|
|
6
|
+
import { amountRaw } from '../domain/amount.js';
|
|
7
|
+
import { AttoError } from '../domain/errors.js';
|
|
8
|
+
import { parseAddress } from '../network/reader.js';
|
|
9
|
+
import { marketTerms } from '../pricing/terms.js';
|
|
10
|
+
import { defaultSettings } from '../wallet/defaults.js';
|
|
11
|
+
const identitySchema = z.strictObject({ address: z.string().max(128), fingerprint: z.string().regex(/^[a-f\d]{64}$/i) });
|
|
12
|
+
const addressesSchema = z.array(z.strictObject({ index: z.number().int().min(0).max(2147483647),
|
|
13
|
+
address: z.string().max(128), publicKey: z.string().regex(/^[a-f\d]{64}$/i), active: z.boolean() }));
|
|
14
|
+
/** Read a consistent snapshot without StateStore's initialization, migration, or chmod. */
|
|
15
|
+
export function readDoctorProfile(directory) {
|
|
16
|
+
let parent = directory;
|
|
17
|
+
while (!existsSync(parent) && dirname(parent) !== parent)
|
|
18
|
+
parent = dirname(parent);
|
|
19
|
+
accessSync(parent, constants.R_OK | constants.W_OK | constants.X_OK);
|
|
20
|
+
const file = join(directory, 'state.sqlite');
|
|
21
|
+
const directoryInfo = existsSync(directory) ? statSync(directory) : undefined;
|
|
22
|
+
const databaseInfo = existsSync(file) ? statSync(file) : undefined;
|
|
23
|
+
const permissions = process.platform !== 'win32' && directoryInfo ? {
|
|
24
|
+
private: (directoryInfo.mode & 0o077) === 0 && (!databaseInfo || (databaseInfo.mode & 0o077) === 0),
|
|
25
|
+
directoryMode: (directoryInfo.mode & 0o777).toString(8),
|
|
26
|
+
...(databaseInfo ? { databaseMode: (databaseInfo.mode & 0o777).toString(8) } : {}),
|
|
27
|
+
} : undefined;
|
|
28
|
+
if (!databaseInfo)
|
|
29
|
+
return { settings: defaultSettings(), settingsSource: 'defaults', addresses: [], access: 'read-only', poolIndexes: [0], pendingPayments: 0, resetPending: false, termsAccepted: false, permissions };
|
|
30
|
+
accessSync(file, constants.R_OK | constants.W_OK);
|
|
31
|
+
const state = new DatabaseSync(file, { readOnly: true });
|
|
32
|
+
try {
|
|
33
|
+
state.exec('PRAGMA busy_timeout = 1000; BEGIN;');
|
|
34
|
+
if (state.prepare('PRAGMA user_version').get()?.user_version !== 1)
|
|
35
|
+
throw new AttoError('STATE_VERSION', 'This wallet state requires a supported Atto CLI version.');
|
|
36
|
+
const get = (key) => {
|
|
37
|
+
const row = state.prepare('SELECT value FROM settings WHERE key = ?').get(key);
|
|
38
|
+
if (!row)
|
|
39
|
+
return undefined;
|
|
40
|
+
if (typeof row.value !== 'string' || row.value.length > 1_048_576)
|
|
41
|
+
throw new Error('Invalid state value');
|
|
42
|
+
return JSON.parse(row.value);
|
|
43
|
+
};
|
|
44
|
+
const settings = parseOperation('wallet_configure', get('settings'));
|
|
45
|
+
if (['network', 'nodeUrl', 'workerUrl', 'representative', 'autoReceive', 'minReceiveRaw'].some(key => !Object.hasOwn(settings, key)))
|
|
46
|
+
throw new Error('Incomplete settings');
|
|
47
|
+
parseAddress(settings.representative);
|
|
48
|
+
amountRaw(settings.minReceiveRaw, 'RAW');
|
|
49
|
+
const savedIdentity = get('identity');
|
|
50
|
+
const identity = savedIdentity === undefined ? undefined : identitySchema.parse(savedIdentity);
|
|
51
|
+
if (identity)
|
|
52
|
+
parseAddress(identity.address);
|
|
53
|
+
const addresses = addressesSchema.parse(get('addresses') ?? []);
|
|
54
|
+
if (new Set(addresses.map(address => address.index)).size !== addresses.length)
|
|
55
|
+
throw new Error('Duplicate account indexes');
|
|
56
|
+
for (const address of addresses) {
|
|
57
|
+
if (parseAddress(address.address).publicKey.toString().toUpperCase() !== address.publicKey.toUpperCase())
|
|
58
|
+
throw new Error('Account identity mismatch');
|
|
59
|
+
}
|
|
60
|
+
if (identity && addresses.find(address => address.index === 0)?.address !== identity.address)
|
|
61
|
+
throw new Error('Wallet identity mismatch');
|
|
62
|
+
const access = z.enum(['read-only', 'spend']).parse(get('spending.mcpAccess') ?? 'read-only');
|
|
63
|
+
const proposed = parseOperation('limits_propose', { policy: get('spending.policy') ?? { perRequest: null, rolling: [] }, access, pool: get('spending.pool') ?? { indexes: [0], consolidate: false } });
|
|
64
|
+
const pending = state.prepare("SELECT COUNT(*) AS count FROM settings, json_each(settings.value) WHERE settings.key = 'spending.records' AND json_extract(json_each.value, '$.status') IN ('reserved', 'signed', 'unknown')").get();
|
|
65
|
+
const terms = get('market.terms');
|
|
66
|
+
return { settings, settingsSource: 'profile', identity, addresses, access, permissions,
|
|
67
|
+
poolIndexes: proposed.pool.indexes, pendingPayments: Number(pending?.count ?? 0),
|
|
68
|
+
resetPending: Boolean(get('wallet.reset')), termsAccepted: terms?.version === marketTerms.version };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
state.close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type DoctorStatus = 'pass' | 'warn' | 'fail' | 'skipped';
|
|
2
|
+
export interface DoctorCheck {
|
|
3
|
+
id: string;
|
|
4
|
+
status: DoctorStatus;
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
evidence?: Record<string, unknown>;
|
|
8
|
+
remediation?: {
|
|
9
|
+
steps: string[];
|
|
10
|
+
command?: string[];
|
|
11
|
+
suggestedEnv?: Record<string, string>;
|
|
12
|
+
restartRequired?: boolean;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export interface DoctorOptions {
|
|
16
|
+
directory?: string;
|
|
17
|
+
access?: 'mcp';
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
globalDirectory?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface DoctorReport {
|
|
22
|
+
status: 'pass' | 'warn' | 'fail';
|
|
23
|
+
context: {
|
|
24
|
+
interface: 'cli' | 'mcp';
|
|
25
|
+
executable: string;
|
|
26
|
+
nodeVersion: string;
|
|
27
|
+
cliVersion: string;
|
|
28
|
+
mcpVersion?: string;
|
|
29
|
+
platform: string;
|
|
30
|
+
directory?: string;
|
|
31
|
+
credentialService?: string;
|
|
32
|
+
credentialAccount?: string;
|
|
33
|
+
network?: string;
|
|
34
|
+
nodeUrl?: string;
|
|
35
|
+
workerUrl?: string;
|
|
36
|
+
settingsSource?: 'profile' | 'defaults';
|
|
37
|
+
};
|
|
38
|
+
checks: DoctorCheck[];
|
|
39
|
+
durationMs: number;
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AttoAmount, AttoUnit } from '@attocash/commons-core';
|
|
2
|
+
import { AttoError } from './errors.js';
|
|
3
|
+
export function amountRaw(value, unit = 'ATTO', allowZero = false) {
|
|
4
|
+
if (typeof value !== 'string' || !/^\d+(?:\.\d+)?$/.test(value) || !['ATTO', 'RAW'].includes(unit)) {
|
|
5
|
+
throw new AttoError('INVALID_AMOUNT', 'Use a nonnegative decimal string with an ATTO or RAW unit.');
|
|
6
|
+
}
|
|
7
|
+
const fraction = (value.split('.')[1] ?? '').replace(/0+$/, '');
|
|
8
|
+
if (fraction.length > (unit === 'ATTO' ? 9 : 0)) {
|
|
9
|
+
throw new AttoError('INVALID_AMOUNT', 'ATTO supports nine decimal places; RAW must be a whole number.');
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const normalized = `${value.split('.')[0]}${fraction ? `.${fraction}` : ''}`;
|
|
13
|
+
const amount = AttoAmount.from(unit === 'RAW' ? AttoUnit.RAW : AttoUnit.ATTO, normalized);
|
|
14
|
+
const raw = amount.toString();
|
|
15
|
+
if (!allowZero && BigInt(raw) === 0n)
|
|
16
|
+
throw new Error();
|
|
17
|
+
return raw;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new AttoError('INVALID_AMOUNT', 'Amount is outside the Atto range or precision.');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function amountOutput(raw) {
|
|
24
|
+
const value = BigInt(raw);
|
|
25
|
+
const fraction = (value % 1000000000n).toString().padStart(9, '0').replace(/0+$/, '');
|
|
26
|
+
return { raw, atto: `${value / 1000000000n}${fraction ? `.${fraction}` : ''}` };
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class AttoError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly details?: unknown | undefined;
|
|
4
|
+
constructor(code: string, message: string, details?: unknown | undefined);
|
|
5
|
+
}
|
|
6
|
+
export declare function errorResult(error: unknown): {
|
|
7
|
+
code: string;
|
|
8
|
+
message: string;
|
|
9
|
+
details?: unknown;
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class AttoError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
details;
|
|
4
|
+
constructor(code, message, details) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.details = details;
|
|
8
|
+
this.name = 'AttoError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function errorResult(error) {
|
|
12
|
+
if (error instanceof AttoError)
|
|
13
|
+
return { code: error.code, message: error.message, details: error.details };
|
|
14
|
+
// Dependency errors can include request headers or key material. Never return their raw messages.
|
|
15
|
+
return { code: 'OPERATION_FAILED', message: 'The operation failed. Check wallet status and endpoint availability.' };
|
|
16
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const DIRECTORY_URL = "https://gatekeeper.live.application.atto.cash/projections/addresses";
|
|
3
|
+
export declare const directorySchema: z.ZodObject<{
|
|
4
|
+
entities: z.ZodArray<z.ZodObject<{
|
|
5
|
+
entity: z.ZodString;
|
|
6
|
+
organization: z.ZodString;
|
|
7
|
+
label: z.ZodString;
|
|
8
|
+
website: z.ZodString;
|
|
9
|
+
tags: z.ZodArray<z.ZodString>;
|
|
10
|
+
addedAt: z.ZodString;
|
|
11
|
+
description: z.ZodString;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
addresses: z.ZodArray<z.ZodObject<{
|
|
14
|
+
address: z.ZodString;
|
|
15
|
+
label: z.ZodString;
|
|
16
|
+
entity: z.ZodString;
|
|
17
|
+
addedAt: z.ZodString;
|
|
18
|
+
description: z.ZodString;
|
|
19
|
+
}, z.core.$strip>>;
|
|
20
|
+
voters: z.ZodArray<z.ZodObject<{
|
|
21
|
+
address: z.ZodString;
|
|
22
|
+
label: z.ZodString;
|
|
23
|
+
entity: z.ZodString;
|
|
24
|
+
addedAt: z.ZodString;
|
|
25
|
+
description: z.ZodString;
|
|
26
|
+
payToAddress: z.ZodNullable<z.ZodString>;
|
|
27
|
+
sharePercentage: z.ZodNumber;
|
|
28
|
+
voteWeight: z.ZodString;
|
|
29
|
+
lastVotedAt: z.ZodString;
|
|
30
|
+
}, z.core.$strip>>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export type DirectorySnapshot = z.infer<typeof directorySchema>;
|
|
33
|
+
/** Fetches only the public URL, with no wallet addresses or personal labels. */
|
|
34
|
+
export declare function fetchDirectory(fetcher?: typeof fetch, signal?: AbortSignal): Promise<DirectorySnapshot>;
|
|
35
|
+
/** Disposable public cache, kept outside the profile's durable SQLite state. */
|
|
36
|
+
export declare class GlobalDirectory {
|
|
37
|
+
private readonly directory;
|
|
38
|
+
private readonly fetcher;
|
|
39
|
+
private readonly now;
|
|
40
|
+
private pending?;
|
|
41
|
+
private memory;
|
|
42
|
+
private readonly path;
|
|
43
|
+
constructor(directory: string, fetcher?: typeof fetch, now?: () => number);
|
|
44
|
+
private read;
|
|
45
|
+
private save;
|
|
46
|
+
cached(): {
|
|
47
|
+
snapshot: {
|
|
48
|
+
entities: {
|
|
49
|
+
entity: string;
|
|
50
|
+
organization: string;
|
|
51
|
+
label: string;
|
|
52
|
+
website: string;
|
|
53
|
+
tags: string[];
|
|
54
|
+
addedAt: string;
|
|
55
|
+
description: string;
|
|
56
|
+
}[];
|
|
57
|
+
addresses: {
|
|
58
|
+
address: string;
|
|
59
|
+
label: string;
|
|
60
|
+
entity: string;
|
|
61
|
+
addedAt: string;
|
|
62
|
+
description: string;
|
|
63
|
+
}[];
|
|
64
|
+
voters: {
|
|
65
|
+
address: string;
|
|
66
|
+
label: string;
|
|
67
|
+
entity: string;
|
|
68
|
+
addedAt: string;
|
|
69
|
+
description: string;
|
|
70
|
+
payToAddress: string | null;
|
|
71
|
+
sharePercentage: number;
|
|
72
|
+
voteWeight: string;
|
|
73
|
+
lastVotedAt: string;
|
|
74
|
+
}[];
|
|
75
|
+
} | undefined;
|
|
76
|
+
status: {
|
|
77
|
+
lastError?: string | undefined;
|
|
78
|
+
retryAt?: string | undefined;
|
|
79
|
+
fetchedAt?: string | undefined;
|
|
80
|
+
source: string;
|
|
81
|
+
network: string;
|
|
82
|
+
available: boolean;
|
|
83
|
+
stale: boolean;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
refresh(force?: boolean): Promise<void>;
|
|
87
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { parseAddress } from '../network/reader.js';
|
|
6
|
+
export const DIRECTORY_URL = 'https://gatekeeper.live.application.atto.cash/projections/addresses';
|
|
7
|
+
const FRESH_MS = 3_600_000;
|
|
8
|
+
const RETRY_MS = 300_000;
|
|
9
|
+
const MAX_BYTES = 2 * 1024 * 1024;
|
|
10
|
+
const string = z.string().max(4096);
|
|
11
|
+
const address = z.string().max(128).refine(value => { try {
|
|
12
|
+
return parseAddress(value).value === value;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
} });
|
|
17
|
+
const entity = z.object({ entity: string, organization: string, label: string, website: string, tags: z.array(string).max(100), addedAt: string, description: string });
|
|
18
|
+
const entry = z.object({ address, label: string, entity: string, addedAt: string, description: string });
|
|
19
|
+
const voter = entry.extend({ payToAddress: address.nullable(), sharePercentage: z.number().min(0).max(100), voteWeight: z.string().regex(/^\d+$/).max(40), lastVotedAt: string });
|
|
20
|
+
export const directorySchema = z.object({ entities: z.array(entity).max(10_000), addresses: z.array(entry).max(10_000), voters: z.array(voter).max(10_000) })
|
|
21
|
+
.superRefine((snapshot, context) => {
|
|
22
|
+
const entities = new Set(snapshot.entities.map(value => value.entity));
|
|
23
|
+
if (entities.size !== snapshot.entities.length || [...snapshot.addresses, ...snapshot.voters].some(value => !entities.has(value.entity))) {
|
|
24
|
+
context.addIssue({ code: 'custom', message: 'Invalid directory entity references.' });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
/** Fetches only the public URL, with no wallet addresses or personal labels. */
|
|
28
|
+
export async function fetchDirectory(fetcher = fetch, signal) {
|
|
29
|
+
const response = await fetcher(DIRECTORY_URL, { signal: AbortSignal.any([AbortSignal.timeout(3000), ...(signal ? [signal] : [])]), redirect: 'error', headers: { accept: 'application/json' } });
|
|
30
|
+
try {
|
|
31
|
+
if (!response.ok || !response.body || !/^application\/json\b/i.test(response.headers.get('content-type') ?? '')
|
|
32
|
+
|| Number(response.headers.get('content-length') ?? 0) > MAX_BYTES)
|
|
33
|
+
throw new Error('Invalid directory response.');
|
|
34
|
+
const reader = response.body.getReader();
|
|
35
|
+
const chunks = [];
|
|
36
|
+
let size = 0;
|
|
37
|
+
try {
|
|
38
|
+
for (;;) {
|
|
39
|
+
const { done, value } = await reader.read();
|
|
40
|
+
if (done)
|
|
41
|
+
break;
|
|
42
|
+
size += value.length;
|
|
43
|
+
if (size > MAX_BYTES)
|
|
44
|
+
throw new Error('Directory response too large.');
|
|
45
|
+
chunks.push(value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
await reader.cancel();
|
|
50
|
+
reader.releaseLock();
|
|
51
|
+
}
|
|
52
|
+
return directorySchema.parse(JSON.parse(Buffer.concat(chunks).toString('utf8')));
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
if (!response.body?.locked)
|
|
56
|
+
await response.body?.cancel();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Disposable public cache, kept outside the profile's durable SQLite state. */
|
|
60
|
+
export class GlobalDirectory {
|
|
61
|
+
directory;
|
|
62
|
+
fetcher;
|
|
63
|
+
now;
|
|
64
|
+
pending;
|
|
65
|
+
memory = {};
|
|
66
|
+
path;
|
|
67
|
+
constructor(directory, fetcher = fetch, now = Date.now) {
|
|
68
|
+
this.directory = directory;
|
|
69
|
+
this.fetcher = fetcher;
|
|
70
|
+
this.now = now;
|
|
71
|
+
this.path = join(directory, 'cache', 'global-addresses.json');
|
|
72
|
+
}
|
|
73
|
+
read() {
|
|
74
|
+
try {
|
|
75
|
+
if (statSync(this.path).size > MAX_BYTES + 1024)
|
|
76
|
+
throw new Error();
|
|
77
|
+
const bytes = readFileSync(this.path);
|
|
78
|
+
if (bytes.length > MAX_BYTES + 1024)
|
|
79
|
+
throw new Error();
|
|
80
|
+
const cache = JSON.parse(bytes.toString('utf8'));
|
|
81
|
+
for (const time of [cache.fetchedAt, cache.failedAt])
|
|
82
|
+
if (time !== undefined && (!Number.isSafeInteger(time) || time < 0 || time > 8_640_000_000_000_000 - RETRY_MS))
|
|
83
|
+
throw new Error();
|
|
84
|
+
if (cache.snapshot) {
|
|
85
|
+
cache.snapshot = directorySchema.parse(cache.snapshot);
|
|
86
|
+
if (cache.fetchedAt === undefined)
|
|
87
|
+
throw new Error();
|
|
88
|
+
}
|
|
89
|
+
return this.memory = cache;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return this.memory;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
save(cache) {
|
|
96
|
+
this.memory = cache;
|
|
97
|
+
const temporary = `${this.path}.${randomUUID()}.tmp`;
|
|
98
|
+
try {
|
|
99
|
+
mkdirSync(join(this.directory, 'cache'), { recursive: true, mode: 0o700 });
|
|
100
|
+
writeFileSync(temporary, JSON.stringify(cache), { mode: 0o600 });
|
|
101
|
+
renameSync(temporary, this.path);
|
|
102
|
+
}
|
|
103
|
+
catch { /* Public-cache storage failures must not break wallet operations. */ }
|
|
104
|
+
finally {
|
|
105
|
+
try {
|
|
106
|
+
rmSync(temporary, { force: true });
|
|
107
|
+
}
|
|
108
|
+
catch { /* Best effort. */ }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
cached() {
|
|
112
|
+
const cache = this.read();
|
|
113
|
+
return { snapshot: cache.snapshot, status: { source: DIRECTORY_URL, network: 'LIVE',
|
|
114
|
+
available: Boolean(cache.snapshot), stale: !cache.snapshot || this.now() - cache.fetchedAt >= FRESH_MS,
|
|
115
|
+
...(cache.fetchedAt !== undefined ? { fetchedAt: new Date(cache.fetchedAt).toISOString() } : {}),
|
|
116
|
+
...(cache.failedAt !== undefined ? { lastError: 'DIRECTORY_UNAVAILABLE', retryAt: new Date(cache.failedAt + RETRY_MS).toISOString() } : {}) } };
|
|
117
|
+
}
|
|
118
|
+
async refresh(force = false) {
|
|
119
|
+
if (this.pending)
|
|
120
|
+
return this.pending;
|
|
121
|
+
const cache = this.read();
|
|
122
|
+
if (!force && ((cache.fetchedAt !== undefined && this.now() - cache.fetchedAt < FRESH_MS)
|
|
123
|
+
|| (cache.failedAt !== undefined && this.now() - cache.failedAt < RETRY_MS)))
|
|
124
|
+
return;
|
|
125
|
+
this.pending = (async () => {
|
|
126
|
+
try {
|
|
127
|
+
this.save({ snapshot: await fetchDirectory(this.fetcher), fetchedAt: this.now() });
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
this.save({ ...cache, failedAt: this.now() });
|
|
131
|
+
}
|
|
132
|
+
})();
|
|
133
|
+
try {
|
|
134
|
+
await this.pending;
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
this.pending = undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { StateStore } from '../storage/state.js';
|
|
3
|
+
import type { NetworkName } from '../wallet/types.js';
|
|
4
|
+
export declare const personalNameSchema: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
5
|
+
export declare const nameKey: (name: string) => string;
|
|
6
|
+
export interface PersonalLabel {
|
|
7
|
+
address: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class PersonalLabels {
|
|
11
|
+
private readonly store;
|
|
12
|
+
constructor(store: StateStore);
|
|
13
|
+
list(network: NetworkName): PersonalLabel[];
|
|
14
|
+
set(network: NetworkName, address: string, input: string): PersonalLabel;
|
|
15
|
+
remove(network: NetworkName, address: string): void;
|
|
16
|
+
resolve(network: NetworkName, label: string): PersonalLabel;
|
|
17
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AttoError } from '../domain/errors.js';
|
|
3
|
+
import { parseAddress } from '../network/reader.js';
|
|
4
|
+
// Count Unicode code points, not UTF-16 units. Formatting controls are rejected
|
|
5
|
+
// too, so invisible direction changes cannot disguise a payment destination.
|
|
6
|
+
export const personalNameSchema = z.string().refine(value => !/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u.test(value), 'Labels cannot contain control characters.')
|
|
7
|
+
.transform(value => value.trim()).refine(value => [...value].length >= 1 && [...value].length <= 128, 'Labels must contain 1–128 characters after trimming.');
|
|
8
|
+
export const nameKey = (name) => name.trim().toLowerCase();
|
|
9
|
+
export class PersonalLabels {
|
|
10
|
+
store;
|
|
11
|
+
constructor(store) {
|
|
12
|
+
this.store = store;
|
|
13
|
+
}
|
|
14
|
+
list(network) {
|
|
15
|
+
const rows = this.store.get(`labels.personal.${network}`) ?? [];
|
|
16
|
+
try {
|
|
17
|
+
if (!Array.isArray(rows))
|
|
18
|
+
throw new Error();
|
|
19
|
+
const names = new Set();
|
|
20
|
+
const addresses = new Set();
|
|
21
|
+
for (const row of rows) {
|
|
22
|
+
if (parseAddress(row.address).value !== row.address || personalNameSchema.parse(row.label) !== row.label
|
|
23
|
+
|| names.has(nameKey(row.label)) || addresses.has(row.address))
|
|
24
|
+
throw new Error();
|
|
25
|
+
names.add(nameKey(row.label));
|
|
26
|
+
addresses.add(row.address);
|
|
27
|
+
}
|
|
28
|
+
return rows;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new AttoError('INVALID_STATE', 'The saved personal labels are invalid. Restore verified profile state.');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
set(network, address, input) {
|
|
35
|
+
const label = personalNameSchema.parse(input);
|
|
36
|
+
address = parseAddress(address).value;
|
|
37
|
+
return this.store.transaction(() => {
|
|
38
|
+
const rows = this.list(network);
|
|
39
|
+
if (rows.some(row => nameKey(row.label) === nameKey(label) && row.address !== address)) {
|
|
40
|
+
throw new AttoError('LABEL_EXISTS', 'This personal name already belongs to another address on this network.');
|
|
41
|
+
}
|
|
42
|
+
const row = { address, label };
|
|
43
|
+
this.store.set(`labels.personal.${network}`, [...rows.filter(row => row.address !== address), row]);
|
|
44
|
+
return row;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
remove(network, address) {
|
|
48
|
+
this.store.transaction(() => this.store.set(`labels.personal.${network}`, this.list(network).filter(row => row.address !== address)));
|
|
49
|
+
}
|
|
50
|
+
resolve(network, label) {
|
|
51
|
+
const row = this.list(network).find(row => nameKey(row.label) === nameKey(label));
|
|
52
|
+
if (!row)
|
|
53
|
+
throw new AttoError('LABEL_NOT_FOUND', 'No personal label matches this name on this network. Global names cannot be used for payments.');
|
|
54
|
+
return row;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { NetworkName } from '../wallet/types.js';
|
|
2
|
+
import { GlobalDirectory } from './directory.js';
|
|
3
|
+
import { PersonalLabels } from './personal.js';
|
|
4
|
+
export declare function modelAddress(value: Record<string, unknown>, prefix?: string): string | undefined;
|
|
5
|
+
/** Read protocol keys without rewriting network objects or interpreting metadata. */
|
|
6
|
+
export declare function resultAddresses(value: unknown): string[];
|
|
7
|
+
export declare class AddressLabels {
|
|
8
|
+
private readonly personal;
|
|
9
|
+
readonly global: GlobalDirectory;
|
|
10
|
+
constructor(personal: PersonalLabels, global: GlobalDirectory);
|
|
11
|
+
dictionary(network: NetworkName, addresses: string[]): {
|
|
12
|
+
[k: string]: {
|
|
13
|
+
global: ({
|
|
14
|
+
source: string;
|
|
15
|
+
entityInfo: {
|
|
16
|
+
entity: string;
|
|
17
|
+
organization: string;
|
|
18
|
+
label: string;
|
|
19
|
+
website: string;
|
|
20
|
+
tags: string[];
|
|
21
|
+
addedAt: string;
|
|
22
|
+
description: string;
|
|
23
|
+
} | undefined;
|
|
24
|
+
stale: boolean;
|
|
25
|
+
kind: "address";
|
|
26
|
+
address: string;
|
|
27
|
+
label: string;
|
|
28
|
+
entity: string;
|
|
29
|
+
addedAt: string;
|
|
30
|
+
description: string;
|
|
31
|
+
} | {
|
|
32
|
+
source: string;
|
|
33
|
+
entityInfo: {
|
|
34
|
+
entity: string;
|
|
35
|
+
organization: string;
|
|
36
|
+
label: string;
|
|
37
|
+
website: string;
|
|
38
|
+
tags: string[];
|
|
39
|
+
addedAt: string;
|
|
40
|
+
description: string;
|
|
41
|
+
} | undefined;
|
|
42
|
+
stale: boolean;
|
|
43
|
+
kind: "voter";
|
|
44
|
+
address: string;
|
|
45
|
+
label: string;
|
|
46
|
+
entity: string;
|
|
47
|
+
addedAt: string;
|
|
48
|
+
description: string;
|
|
49
|
+
payToAddress: string | null;
|
|
50
|
+
sharePercentage: number;
|
|
51
|
+
voteWeight: string;
|
|
52
|
+
lastVotedAt: string;
|
|
53
|
+
})[];
|
|
54
|
+
payoutFor: {
|
|
55
|
+
voterAddress: string;
|
|
56
|
+
label: string;
|
|
57
|
+
entity: string;
|
|
58
|
+
source: string;
|
|
59
|
+
stale: boolean;
|
|
60
|
+
}[];
|
|
61
|
+
personal?: {
|
|
62
|
+
source: string;
|
|
63
|
+
label: string;
|
|
64
|
+
} | undefined;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
status(network: NetworkName): {
|
|
68
|
+
lastError?: string | undefined;
|
|
69
|
+
retryAt?: string | undefined;
|
|
70
|
+
fetchedAt?: string | undefined;
|
|
71
|
+
source: string;
|
|
72
|
+
network: string;
|
|
73
|
+
available: boolean;
|
|
74
|
+
stale: boolean;
|
|
75
|
+
} | {
|
|
76
|
+
network: string;
|
|
77
|
+
applicable: boolean;
|
|
78
|
+
};
|
|
79
|
+
list(network: NetworkName, all?: boolean, search?: string): {
|
|
80
|
+
network: NetworkName;
|
|
81
|
+
items: {
|
|
82
|
+
address: string;
|
|
83
|
+
}[];
|
|
84
|
+
addressLabels: {
|
|
85
|
+
[k: string]: {
|
|
86
|
+
global: ({
|
|
87
|
+
source: string;
|
|
88
|
+
entityInfo: {
|
|
89
|
+
entity: string;
|
|
90
|
+
organization: string;
|
|
91
|
+
label: string;
|
|
92
|
+
website: string;
|
|
93
|
+
tags: string[];
|
|
94
|
+
addedAt: string;
|
|
95
|
+
description: string;
|
|
96
|
+
} | undefined;
|
|
97
|
+
stale: boolean;
|
|
98
|
+
kind: "address";
|
|
99
|
+
address: string;
|
|
100
|
+
label: string;
|
|
101
|
+
entity: string;
|
|
102
|
+
addedAt: string;
|
|
103
|
+
description: string;
|
|
104
|
+
} | {
|
|
105
|
+
source: string;
|
|
106
|
+
entityInfo: {
|
|
107
|
+
entity: string;
|
|
108
|
+
organization: string;
|
|
109
|
+
label: string;
|
|
110
|
+
website: string;
|
|
111
|
+
tags: string[];
|
|
112
|
+
addedAt: string;
|
|
113
|
+
description: string;
|
|
114
|
+
} | undefined;
|
|
115
|
+
stale: boolean;
|
|
116
|
+
kind: "voter";
|
|
117
|
+
address: string;
|
|
118
|
+
label: string;
|
|
119
|
+
entity: string;
|
|
120
|
+
addedAt: string;
|
|
121
|
+
description: string;
|
|
122
|
+
payToAddress: string | null;
|
|
123
|
+
sharePercentage: number;
|
|
124
|
+
voteWeight: string;
|
|
125
|
+
lastVotedAt: string;
|
|
126
|
+
})[];
|
|
127
|
+
payoutFor: {
|
|
128
|
+
voterAddress: string;
|
|
129
|
+
label: string;
|
|
130
|
+
entity: string;
|
|
131
|
+
source: string;
|
|
132
|
+
stale: boolean;
|
|
133
|
+
}[];
|
|
134
|
+
personal?: {
|
|
135
|
+
source: string;
|
|
136
|
+
label: string;
|
|
137
|
+
} | undefined;
|
|
138
|
+
} | undefined;
|
|
139
|
+
};
|
|
140
|
+
globalDirectory: {
|
|
141
|
+
lastError?: string | undefined;
|
|
142
|
+
retryAt?: string | undefined;
|
|
143
|
+
fetchedAt?: string | undefined;
|
|
144
|
+
source: string;
|
|
145
|
+
network: string;
|
|
146
|
+
available: boolean;
|
|
147
|
+
stale: boolean;
|
|
148
|
+
} | {
|
|
149
|
+
network: string;
|
|
150
|
+
applicable: boolean;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
decorate(result: unknown, network: NetworkName): unknown;
|
|
154
|
+
}
|