@mysten-incubation/devstack 0.0.1 → 0.1.1
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/README.md +8 -4
- package/dashboard-ui/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dashboard-ui/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dashboard-ui/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dashboard-ui/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dashboard-ui/assets/geist-mono-cyrillic-ext-wght-normal-I4S5GZfc.woff2 +0 -0
- package/dashboard-ui/assets/geist-mono-cyrillic-wght-normal-BmXc_FBt.woff2 +0 -0
- package/dashboard-ui/assets/geist-mono-latin-ext-wght-normal-DrnZ1wKl.woff2 +0 -0
- package/dashboard-ui/assets/geist-mono-latin-wght-normal-B_7UjwxQ.woff2 +0 -0
- package/dashboard-ui/assets/geist-mono-symbols2-wght-normal-GZpp1pK2.woff2 +0 -0
- package/dashboard-ui/assets/geist-mono-vietnamese-wght-normal-D8KDMBhC.woff2 +0 -0
- package/dashboard-ui/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dashboard-ui/assets/index-Bmi1UtAg.js +1356 -0
- package/dashboard-ui/assets/index-D5EShVt4.js +3 -0
- package/dashboard-ui/assets/index-Deml9drg.css +1 -0
- package/dashboard-ui/index.html +13 -0
- package/dist/api/define-capabilities.d.mts +14 -3
- package/dist/api/define-capabilities.mjs +18 -1
- package/dist/api/define-capabilities.mjs.map +1 -1
- package/dist/api/define-devstack.d.mts +1 -1
- package/dist/api/define-devstack.mjs +6 -26
- package/dist/api/define-devstack.mjs.map +1 -1
- package/dist/api/define-plugin.d.mts +1 -0
- package/dist/api/define-plugin.mjs +2 -0
- package/dist/api/inference-network.d.mts +132 -0
- package/dist/api/inference-network.mjs +105 -16
- package/dist/api/inference-network.mjs.map +1 -1
- package/dist/api/plugin-errors.d.mts +7 -0
- package/dist/api/run-stack.d.mts +20 -9
- package/dist/api/run-stack.mjs +56 -29
- package/dist/api/run-stack.mjs.map +1 -1
- package/dist/build-integrations/playwright/config.d.mts +6 -4
- package/dist/build-integrations/playwright/config.mjs +5 -3
- package/dist/build-integrations/playwright/config.mjs.map +1 -1
- package/dist/build-integrations/playwright/errors.d.mts +1 -1
- package/dist/build-integrations/playwright/global-setup.d.mts +43 -17
- package/dist/build-integrations/playwright/global-setup.mjs +250 -13
- package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
- package/dist/build-integrations/playwright/index.d.mts +5 -3
- package/dist/build-integrations/playwright/index.mjs +4 -2
- package/dist/build-integrations/playwright/stack-context.d.mts +0 -1
- package/dist/build-integrations/playwright/stack-context.mjs +24 -63
- package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
- package/dist/build-integrations/playwright/wallet-context.d.mts +7 -10
- package/dist/build-integrations/playwright/wallet-context.mjs +8 -13
- package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/cold-start-url.d.mts +5 -0
- package/dist/build-integrations/runtime/cold-start-url.mjs +4 -3
- package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
- package/dist/build-integrations/runtime/conventional-routes.d.mts +51 -0
- package/dist/build-integrations/runtime/conventional-routes.mjs +92 -0
- package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -0
- package/dist/build-integrations/runtime/discover.d.mts +38 -30
- package/dist/build-integrations/runtime/discover.mjs +73 -70
- package/dist/build-integrations/runtime/discover.mjs.map +1 -1
- package/dist/build-integrations/runtime/endpoint-registry.d.mts +3 -1
- package/dist/build-integrations/runtime/endpoint-registry.mjs +3 -1
- package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
- package/dist/build-integrations/runtime/index.d.mts +7 -2
- package/dist/build-integrations/runtime/index.mjs +9 -2
- package/dist/build-integrations/runtime/manifest-types.d.mts +2 -0
- package/dist/build-integrations/runtime/manifest-types.mjs +3 -0
- package/dist/build-integrations/runtime/playwright-stack-context-slot.d.mts +29 -0
- package/dist/build-integrations/runtime/playwright-stack-context-slot.mjs +10 -0
- package/dist/build-integrations/runtime/playwright-stack-context-slot.mjs.map +1 -0
- package/dist/build-integrations/runtime/read-stack-context.d.mts +1 -1
- package/dist/build-integrations/runtime/read-stack-context.mjs +10 -4
- package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +48 -0
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs +42 -0
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -0
- package/dist/build-integrations/runtime/stack-context.d.mts +1 -1
- package/dist/build-integrations/runtime/wallet-paths.mjs +2 -0
- package/dist/build-integrations/vite/index.d.mts +51 -0
- package/dist/build-integrations/vite/index.mjs +73 -0
- package/dist/build-integrations/vite/index.mjs.map +1 -0
- package/dist/build-integrations/vitest/env.d.mts +4 -3
- package/dist/build-integrations/vitest/env.mjs +6 -4
- package/dist/build-integrations/vitest/env.mjs.map +1 -1
- package/dist/build-integrations/vitest/errors.d.mts +25 -4
- package/dist/build-integrations/vitest/errors.mjs +15 -2
- package/dist/build-integrations/vitest/errors.mjs.map +1 -1
- package/dist/build-integrations/vitest/index.d.mts +2 -2
- package/dist/build-integrations/vitest/index.mjs +3 -3
- package/dist/build-integrations/vitest/setup.d.mts +4 -2
- package/dist/build-integrations/vitest/setup.mjs +2 -2
- package/dist/build-integrations/vitest/setup.mjs.map +1 -1
- package/dist/build-integrations/vitest/stack-context.d.mts +0 -1
- package/dist/build-integrations/vitest/stack-context.mjs +33 -13
- package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
- package/dist/cli/bail.mjs +23 -0
- package/dist/cli/bail.mjs.map +1 -0
- package/dist/{surfaces/cli/commands → cli}/doctor-probes.mjs +26 -16
- package/dist/cli/doctor-probes.mjs.map +1 -0
- package/dist/cli/main.d.mts +15 -1
- package/dist/cli/main.mjs +166 -482
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/prune-direct.mjs +31 -201
- package/dist/cli/prune-direct.mjs.map +1 -1
- package/dist/cli/snapshot-reader.mjs +14 -11
- package/dist/cli/snapshot-reader.mjs.map +1 -1
- package/dist/cli/up-lifecycle.mjs +4 -1
- package/dist/cli/up-lifecycle.mjs.map +1 -1
- package/dist/cli/wirings/apply.mjs +95 -0
- package/dist/cli/wirings/apply.mjs.map +1 -0
- package/dist/cli/wirings/build-verb-layers.mjs +42 -0
- package/dist/cli/wirings/build-verb-layers.mjs.map +1 -0
- package/dist/cli/wirings/config-loader.mjs +69 -0
- package/dist/cli/wirings/config-loader.mjs.map +1 -0
- package/dist/cli/wirings/engine-command.mjs +30 -0
- package/dist/cli/wirings/engine-command.mjs.map +1 -0
- package/dist/cli/wirings/identity.mjs +72 -0
- package/dist/cli/wirings/identity.mjs.map +1 -0
- package/dist/cli/wirings/provide-file-system.mjs +7 -0
- package/dist/cli/wirings/provide-file-system.mjs.map +1 -0
- package/dist/cli/wirings/snapshot.mjs +177 -0
- package/dist/cli/wirings/snapshot.mjs.map +1 -0
- package/dist/cli/wirings/up.mjs +287 -0
- package/dist/cli/wirings/up.mjs.map +1 -0
- package/dist/cli/wirings/wipe.mjs +40 -0
- package/dist/cli/wirings/wipe.mjs.map +1 -0
- package/dist/contracts/capability-decl.d.mts +0 -2
- package/dist/contracts/codegenable.d.mts +43 -0
- package/dist/contracts/container-runtime.d.mts +26 -1
- package/dist/contracts/faucet-strategy.d.mts +25 -0
- package/dist/contracts/funding-strategy.d.mts +42 -0
- package/dist/contracts/plugin-expander.mjs +60 -0
- package/dist/contracts/plugin-expander.mjs.map +1 -0
- package/dist/contracts/projection.d.mts +5 -3
- package/dist/contracts/renderer.d.mts +23 -0
- package/dist/contracts/routable.d.mts +14 -1
- package/dist/contracts/snapshotable.d.mts +25 -3
- package/dist/contracts/wallet-protocol.d.mts +52 -0
- package/dist/contracts/wallet-protocol.mjs +52 -0
- package/dist/contracts/wallet-protocol.mjs.map +1 -0
- package/dist/index.d.mts +26 -25
- package/dist/index.mjs +20 -13
- package/dist/{runtime → orchestrators}/built-in-plugin-layers.mjs +10 -5
- package/dist/orchestrators/built-in-plugin-layers.mjs.map +1 -0
- package/dist/orchestrators/codegen/bindings.d.mts +1 -2
- package/dist/orchestrators/codegen/bindings.mjs +52 -186
- package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
- package/dist/orchestrators/codegen/emit.mjs +19 -1
- package/dist/orchestrators/codegen/emit.mjs.map +1 -1
- package/dist/orchestrators/codegen/errors.mjs +8 -3
- package/dist/orchestrators/codegen/errors.mjs.map +1 -1
- package/dist/orchestrators/codegen/format.mjs +47 -39
- package/dist/orchestrators/codegen/format.mjs.map +1 -1
- package/dist/orchestrators/codegen/gitignore.mjs +3 -1
- package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
- package/dist/orchestrators/codegen/output-location.mjs +41 -0
- package/dist/orchestrators/codegen/output-location.mjs.map +1 -0
- package/dist/orchestrators/codegen/paths.d.mts +1 -1
- package/dist/orchestrators/codegen/paths.mjs +40 -14
- package/dist/orchestrators/codegen/paths.mjs.map +1 -1
- package/dist/orchestrators/codegen/permissions.mjs +3 -1
- package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
- package/dist/orchestrators/codegen/service.mjs +157 -105
- package/dist/orchestrators/codegen/service.mjs.map +1 -1
- package/dist/orchestrators/lifecycle-prune/errors.mjs +31 -0
- package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -0
- package/dist/orchestrators/lifecycle-prune/index.mjs +350 -0
- package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -0
- package/dist/orchestrators/router/cleanup.mjs +26 -27
- package/dist/orchestrators/router/cleanup.mjs.map +1 -1
- package/dist/orchestrators/router/entrypoints.mjs +2 -2
- package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
- package/dist/orchestrators/router/file-provider.mjs +14 -5
- package/dist/orchestrators/router/file-provider.mjs.map +1 -1
- package/dist/orchestrators/router/hostname.mjs +19 -55
- package/dist/orchestrators/router/hostname.mjs.map +1 -1
- package/dist/orchestrators/router/index.mjs +11 -0
- package/dist/orchestrators/router/profile.mjs +2 -2
- package/dist/orchestrators/router/sentinels.mjs +26 -0
- package/dist/orchestrators/router/sentinels.mjs.map +1 -0
- package/dist/orchestrators/router/service.mjs +40 -37
- package/dist/orchestrators/router/service.mjs.map +1 -1
- package/dist/orchestrators/router/traefik-container.mjs +27 -16
- package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
- package/dist/{substrate/runtime → orchestrators}/run.mjs +26 -21
- package/dist/orchestrators/run.mjs.map +1 -0
- package/dist/orchestrators/runtime-composition.d.mts +1 -1
- package/dist/orchestrators/runtime-composition.mjs +123 -39
- package/dist/orchestrators/runtime-composition.mjs.map +1 -1
- package/dist/orchestrators/snapshot/capture-command.d.mts +1 -0
- package/dist/orchestrators/snapshot/capture-command.mjs +25 -0
- package/dist/orchestrators/snapshot/capture-command.mjs.map +1 -0
- package/dist/orchestrators/snapshot/capture.mjs +42 -28
- package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
- package/dist/orchestrators/snapshot/descriptor.mjs +35 -10
- package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
- package/dist/orchestrators/snapshot/identity-guard.mjs +1 -1
- package/dist/orchestrators/snapshot/index.mjs +13 -0
- package/dist/orchestrators/snapshot/integrity.d.mts +1 -1
- package/dist/orchestrators/snapshot/integrity.mjs +73 -17
- package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
- package/dist/orchestrators/snapshot/pending-marker.d.mts +1 -0
- package/dist/orchestrators/snapshot/pending-marker.mjs +99 -0
- package/dist/orchestrators/snapshot/pending-marker.mjs.map +1 -0
- package/dist/orchestrators/snapshot/phase-error.mjs +23 -0
- package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -0
- package/dist/orchestrators/snapshot/prune.mjs +20 -55
- package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
- package/dist/orchestrators/snapshot/recover-pending.d.mts +1 -0
- package/dist/orchestrators/snapshot/recover-pending.mjs +223 -0
- package/dist/orchestrators/snapshot/recover-pending.mjs.map +1 -0
- package/dist/orchestrators/snapshot/restore.mjs +118 -84
- package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
- package/dist/orchestrators/snapshot/service.mjs +53 -56
- package/dist/orchestrators/snapshot/service.mjs.map +1 -1
- package/dist/orchestrators/snapshot/state-document.d.mts +1 -0
- package/dist/orchestrators/snapshot/state-document.mjs +47 -7
- package/dist/orchestrators/snapshot/state-document.mjs.map +1 -1
- package/dist/orchestrators/snapshot/wipe.mjs +67 -10
- package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
- package/dist/plugins/account/codegen.mjs +9 -8
- package/dist/plugins/account/codegen.mjs.map +1 -1
- package/dist/plugins/account/errors.d.mts +33 -6
- package/dist/plugins/account/errors.mjs.map +1 -1
- package/dist/plugins/account/funding.d.mts +29 -19
- package/dist/plugins/account/funding.mjs +84 -66
- package/dist/plugins/account/funding.mjs.map +1 -1
- package/dist/plugins/account/index.d.mts +2 -4
- package/dist/plugins/account/index.mjs +64 -31
- package/dist/plugins/account/index.mjs.map +1 -1
- package/dist/plugins/account/keypair.mjs +6 -9
- package/dist/plugins/account/keypair.mjs.map +1 -1
- package/dist/plugins/account/lease.mjs +1 -0
- package/dist/plugins/account/lease.mjs.map +1 -1
- package/dist/plugins/account/registry.d.mts +14 -1
- package/dist/plugins/account/registry.mjs +18 -18
- package/dist/plugins/account/registry.mjs.map +1 -1
- package/dist/plugins/account/service.d.mts +23 -4
- package/dist/plugins/account/service.mjs +83 -45
- package/dist/plugins/account/service.mjs.map +1 -1
- package/dist/plugins/account/snapshot.mjs +2 -5
- package/dist/plugins/account/snapshot.mjs.map +1 -1
- package/dist/plugins/account/spans.mjs +16 -0
- package/dist/plugins/account/spans.mjs.map +1 -0
- package/dist/plugins/account/variants/keystore.mjs +6 -8
- package/dist/plugins/account/variants/keystore.mjs.map +1 -1
- package/dist/plugins/action/build-context.d.mts +3 -2
- package/dist/plugins/action/errors.d.mts +16 -12
- package/dist/plugins/action/errors.mjs.map +1 -1
- package/dist/plugins/action/execute.mjs +65 -103
- package/dist/plugins/action/execute.mjs.map +1 -1
- package/dist/plugins/action/index.d.mts +0 -2
- package/dist/plugins/action/index.mjs +17 -13
- package/dist/plugins/action/index.mjs.map +1 -1
- package/dist/plugins/action/service.mjs +38 -35
- package/dist/plugins/action/service.mjs.map +1 -1
- package/dist/plugins/action/spans.mjs +11 -0
- package/dist/plugins/action/spans.mjs.map +1 -0
- package/dist/plugins/coin/codegen.mjs +9 -8
- package/dist/plugins/coin/codegen.mjs.map +1 -1
- package/dist/plugins/coin/discovery.mjs +8 -4
- package/dist/plugins/coin/discovery.mjs.map +1 -1
- package/dist/plugins/coin/index.d.mts +11 -29
- package/dist/plugins/coin/index.mjs +56 -27
- package/dist/plugins/coin/index.mjs.map +1 -1
- package/dist/plugins/coin/metadata.mjs +8 -15
- package/dist/plugins/coin/metadata.mjs.map +1 -1
- package/dist/plugins/coin/mint.d.mts +30 -11
- package/dist/plugins/coin/mint.mjs +78 -74
- package/dist/plugins/coin/mint.mjs.map +1 -1
- package/dist/plugins/coin/registry.mjs +4 -7
- package/dist/plugins/coin/registry.mjs.map +1 -1
- package/dist/plugins/coin/service.d.mts +39 -1
- package/dist/plugins/coin/service.mjs +11 -4
- package/dist/plugins/coin/service.mjs.map +1 -1
- package/dist/plugins/coin/spans.mjs +20 -0
- package/dist/plugins/coin/spans.mjs.map +1 -0
- package/dist/plugins/dashboard/domain.mjs +402 -0
- package/dist/plugins/dashboard/domain.mjs.map +1 -0
- package/dist/plugins/dashboard/index.d.mts +29 -0
- package/dist/plugins/dashboard/index.mjs +91 -0
- package/dist/plugins/dashboard/index.mjs.map +1 -0
- package/dist/plugins/dashboard/origin-policy.mjs +36 -0
- package/dist/plugins/dashboard/origin-policy.mjs.map +1 -0
- package/dist/plugins/dashboard/routable.mjs +27 -0
- package/dist/plugins/dashboard/routable.mjs.map +1 -0
- package/dist/plugins/dashboard/schema/builder.mjs +21 -0
- package/dist/plugins/dashboard/schema/builder.mjs.map +1 -0
- package/dist/plugins/dashboard/schema/enums.mjs +72 -0
- package/dist/plugins/dashboard/schema/enums.mjs.map +1 -0
- package/dist/plugins/dashboard/schema/root.mjs +351 -0
- package/dist/plugins/dashboard/schema/root.mjs.map +1 -0
- package/dist/plugins/dashboard/schema/types.mjs +508 -0
- package/dist/plugins/dashboard/schema/types.mjs.map +1 -0
- package/dist/plugins/dashboard/schema.mjs +11 -0
- package/dist/plugins/dashboard/schema.mjs.map +1 -0
- package/dist/plugins/dashboard/server.mjs +166 -0
- package/dist/plugins/dashboard/server.mjs.map +1 -0
- package/dist/plugins/deepbook/deploy.mjs +53 -115
- package/dist/plugins/deepbook/deploy.mjs.map +1 -1
- package/dist/plugins/deepbook/errors.mjs +1 -0
- package/dist/plugins/deepbook/errors.mjs.map +1 -1
- package/dist/plugins/deepbook/faucet-strategy.mjs +47 -34
- package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/deepbook/hash.mjs +9 -0
- package/dist/plugins/deepbook/hash.mjs.map +1 -0
- package/dist/plugins/deepbook/index.d.mts +1 -10
- package/dist/plugins/deepbook/index.mjs +25 -22
- package/dist/plugins/deepbook/index.mjs.map +1 -1
- package/dist/plugins/deepbook/pyth/index.mjs +26 -55
- package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
- package/dist/plugins/deepbook/snapshot.mjs +17 -29
- package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
- package/dist/plugins/deepbook/spans.mjs +18 -0
- package/dist/plugins/deepbook/spans.mjs.map +1 -0
- package/dist/plugins/deepbook/type-strings.mjs +65 -0
- package/dist/plugins/deepbook/type-strings.mjs.map +1 -0
- package/dist/plugins/deepbook/types.d.mts +2 -3
- package/dist/plugins/deepbook/types.mjs.map +1 -1
- package/dist/plugins/faucet/dispatcher.d.mts +21 -2
- package/dist/plugins/faucet/dispatcher.mjs +1 -2
- package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
- package/dist/plugins/faucet/errors.d.mts +11 -24
- package/dist/plugins/faucet/errors.mjs.map +1 -1
- package/dist/plugins/faucet/http.mjs +33 -14
- package/dist/plugins/faucet/http.mjs.map +1 -1
- package/dist/plugins/faucet/index.d.mts +15 -5
- package/dist/plugins/faucet/index.mjs +3 -0
- package/dist/plugins/faucet/index.mjs.map +1 -1
- package/dist/plugins/faucet/spans.mjs +12 -0
- package/dist/plugins/faucet/spans.mjs.map +1 -0
- package/dist/plugins/host-service/errors.d.mts +1 -1
- package/dist/plugins/host-service/index.mjs +34 -8
- package/dist/plugins/host-service/index.mjs.map +1 -1
- package/dist/plugins/host-service/routable.mjs +2 -1
- package/dist/plugins/host-service/routable.mjs.map +1 -1
- package/dist/plugins/host-service/service.d.mts +21 -0
- package/dist/plugins/host-service/service.mjs +136 -81
- package/dist/plugins/host-service/service.mjs.map +1 -1
- package/dist/plugins/internal/acquire-on-chain-artifact.mjs +23 -0
- package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -0
- package/dist/plugins/internal/codegen-helpers.mjs +18 -0
- package/dist/plugins/internal/codegen-helpers.mjs.map +1 -0
- package/dist/plugins/internal/funding-failure-error.mjs +32 -0
- package/dist/plugins/internal/funding-failure-error.mjs.map +1 -0
- package/dist/plugins/package/build.mjs +1 -1
- package/dist/plugins/package/build.mjs.map +1 -1
- package/dist/plugins/package/codegen.mjs +26 -0
- package/dist/plugins/package/codegen.mjs.map +1 -1
- package/dist/plugins/package/errors.d.mts +16 -6
- package/dist/plugins/package/errors.mjs.map +1 -1
- package/dist/plugins/package/index.d.mts +0 -4
- package/dist/plugins/package/index.mjs +27 -21
- package/dist/plugins/package/index.mjs.map +1 -1
- package/dist/plugins/package/mode-known.mjs +26 -12
- package/dist/plugins/package/mode-known.mjs.map +1 -1
- package/dist/plugins/package/mode-local.mjs +47 -41
- package/dist/plugins/package/mode-local.mjs.map +1 -1
- package/dist/plugins/package/publish-executor.mjs +55 -114
- package/dist/plugins/package/publish-executor.mjs.map +1 -1
- package/dist/plugins/package/registry.mjs +2 -1
- package/dist/plugins/package/registry.mjs.map +1 -1
- package/dist/plugins/package/service.mjs.map +1 -1
- package/dist/plugins/package/spans.mjs +14 -0
- package/dist/plugins/package/spans.mjs.map +1 -0
- package/dist/plugins/postgres/db-ensure.mjs +19 -12
- package/dist/plugins/postgres/db-ensure.mjs.map +1 -1
- package/dist/plugins/postgres/errors.d.mts +5 -0
- package/dist/plugins/postgres/errors.mjs.map +1 -1
- package/dist/plugins/postgres/index.mjs +10 -17
- package/dist/plugins/postgres/index.mjs.map +1 -1
- package/dist/plugins/postgres/service.mjs +58 -24
- package/dist/plugins/postgres/service.mjs.map +1 -1
- package/dist/plugins/postgres/snapshot.mjs.map +1 -1
- package/dist/plugins/postgres/spans.mjs +11 -0
- package/dist/plugins/postgres/spans.mjs.map +1 -0
- package/dist/plugins/router-entrypoints.mjs +4 -4
- package/dist/plugins/router-entrypoints.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +15 -13
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +15 -19
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
- package/dist/plugins/seal/codegen.d.mts +2 -3
- package/dist/plugins/seal/codegen.mjs.map +1 -1
- package/dist/plugins/seal/config-render.mjs +35 -8
- package/dist/plugins/seal/config-render.mjs.map +1 -1
- package/dist/plugins/seal/deploy.mjs +31 -39
- package/dist/plugins/seal/deploy.mjs.map +1 -1
- package/dist/plugins/seal/errors.d.mts +1 -3
- package/dist/plugins/seal/errors.mjs +7 -1
- package/dist/plugins/seal/errors.mjs.map +1 -1
- package/dist/plugins/seal/index.d.mts +1 -6
- package/dist/plugins/seal/index.mjs +40 -14
- package/dist/plugins/seal/index.mjs.map +1 -1
- package/dist/plugins/seal/key-manager.d.mts +1 -9
- package/dist/plugins/seal/key-manager.mjs +2 -18
- package/dist/plugins/seal/key-manager.mjs.map +1 -1
- package/dist/plugins/seal/key-server.mjs +37 -36
- package/dist/plugins/seal/key-server.mjs.map +1 -1
- package/dist/plugins/seal/keygen.mjs +16 -17
- package/dist/plugins/seal/keygen.mjs.map +1 -1
- package/dist/plugins/seal/mode/fork-known.mjs +36 -14
- package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
- package/dist/plugins/seal/mode/live.d.mts +6 -4
- package/dist/plugins/seal/mode/live.mjs +14 -21
- package/dist/plugins/seal/mode/live.mjs.map +1 -1
- package/dist/plugins/seal/mode/local-keygen.mjs +57 -21
- package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
- package/dist/plugins/seal/registry-publish.mjs +1 -0
- package/dist/plugins/seal/registry-publish.mjs.map +1 -1
- package/dist/plugins/seal/routable.mjs.map +1 -1
- package/dist/plugins/seal/service.mjs.map +1 -1
- package/dist/plugins/seal/spans.mjs +18 -0
- package/dist/plugins/seal/spans.mjs.map +1 -0
- package/dist/plugins/sui/auto-tick.mjs +17 -23
- package/dist/plugins/sui/auto-tick.mjs.map +1 -1
- package/dist/plugins/sui/chain-build-container.mjs +18 -0
- package/dist/plugins/sui/chain-build-container.mjs.map +1 -0
- package/dist/plugins/sui/chain-probe.d.mts +5 -5
- package/dist/plugins/sui/chain-probe.mjs +28 -58
- package/dist/plugins/sui/chain-probe.mjs.map +1 -1
- package/dist/plugins/sui/codegen.mjs +26 -0
- package/dist/plugins/sui/codegen.mjs.map +1 -1
- package/dist/plugins/sui/errors.d.mts +2 -29
- package/dist/plugins/sui/errors.mjs +1 -3
- package/dist/plugins/sui/errors.mjs.map +1 -1
- package/dist/plugins/sui/fork-faucet-strategy.d.mts +1 -0
- package/dist/plugins/sui/fork-faucet-strategy.mjs +55 -0
- package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -0
- package/dist/plugins/sui/fork-orchestration.d.mts +1 -0
- package/dist/plugins/sui/fork-orchestration.mjs +170 -2
- package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
- package/dist/plugins/sui/fork-transaction.d.mts +2 -0
- package/dist/plugins/sui/fork-transaction.mjs +92 -28
- package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
- package/dist/plugins/sui/index.d.mts +33 -70
- package/dist/plugins/sui/index.mjs +58 -35
- package/dist/plugins/sui/index.mjs.map +1 -1
- package/dist/plugins/{faucet/strategies/sui-local.mjs → sui/local-faucet-strategy.mjs} +10 -7
- package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -0
- package/dist/plugins/sui/mode/external.mjs +7 -13
- package/dist/plugins/sui/mode/external.mjs.map +1 -1
- package/dist/plugins/sui/mode/fork.mjs +136 -59
- package/dist/plugins/sui/mode/fork.mjs.map +1 -1
- package/dist/plugins/sui/mode/live.mjs +10 -16
- package/dist/plugins/sui/mode/live.mjs.map +1 -1
- package/dist/plugins/sui/mode/local.mjs +37 -36
- package/dist/plugins/sui/mode/local.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared-boot.mjs +38 -115
- package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared.d.mts +1 -5
- package/dist/plugins/sui/mode/shared.mjs.map +1 -1
- package/dist/plugins/sui/mode/spec.d.mts +18 -0
- package/dist/plugins/sui/move-summary-runner.mjs +207 -0
- package/dist/plugins/sui/move-summary-runner.mjs.map +1 -0
- package/dist/plugins/sui/network-resolver.d.mts +4 -3
- package/dist/plugins/sui/service.mjs.map +1 -1
- package/dist/plugins/sui/snapshot.mjs +3 -0
- package/dist/plugins/sui/snapshot.mjs.map +1 -1
- package/dist/plugins/sui/spans.mjs +17 -0
- package/dist/plugins/sui/spans.mjs.map +1 -0
- package/dist/plugins/wallet/codegen.d.mts +0 -1
- package/dist/plugins/wallet/codegen.mjs +8 -9
- package/dist/plugins/wallet/codegen.mjs.map +1 -1
- package/dist/plugins/wallet/index.d.mts +6 -8
- package/dist/plugins/wallet/index.mjs +46 -35
- package/dist/plugins/wallet/index.mjs.map +1 -1
- package/dist/plugins/wallet/origin-policy.mjs +12 -28
- package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
- package/dist/plugins/wallet/pairing.mjs +6 -4
- package/dist/plugins/wallet/pairing.mjs.map +1 -1
- package/dist/plugins/wallet/protocol.d.mts +1 -0
- package/dist/plugins/wallet/protocol.mjs +5 -44
- package/dist/plugins/wallet/protocol.mjs.map +1 -1
- package/dist/plugins/wallet/routable.mjs +2 -8
- package/dist/plugins/wallet/routable.mjs.map +1 -1
- package/dist/plugins/wallet/server.mjs +36 -44
- package/dist/plugins/wallet/server.mjs.map +1 -1
- package/dist/plugins/wallet/service.d.mts +1 -5
- package/dist/plugins/wallet/service.mjs +22 -18
- package/dist/plugins/wallet/service.mjs.map +1 -1
- package/dist/plugins/wallet/spans.mjs +22 -0
- package/dist/plugins/wallet/spans.mjs.map +1 -0
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +33 -8
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/walrus/codegen.d.mts +3 -3
- package/dist/plugins/walrus/codegen.mjs.map +1 -1
- package/dist/plugins/walrus/deploy-paths.mjs +21 -5
- package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
- package/dist/plugins/walrus/deploy.mjs +67 -69
- package/dist/plugins/walrus/deploy.mjs.map +1 -1
- package/dist/plugins/walrus/errors.mjs +1 -0
- package/dist/plugins/walrus/errors.mjs.map +1 -1
- package/dist/plugins/walrus/faucet-strategy.mjs +12 -7
- package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/walrus/index.d.mts +2 -13
- package/dist/plugins/walrus/index.mjs +18 -23
- package/dist/plugins/walrus/index.mjs.map +1 -1
- package/dist/plugins/walrus/mode/known-deploy.mjs +7 -5
- package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
- package/dist/plugins/walrus/mode/local-cluster.mjs +26 -7
- package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
- package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
- package/dist/plugins/walrus/routable.mjs +7 -23
- package/dist/plugins/walrus/routable.mjs.map +1 -1
- package/dist/plugins/walrus/service.mjs.map +1 -1
- package/dist/plugins/walrus/spans.mjs +18 -0
- package/dist/plugins/walrus/spans.mjs.map +1 -0
- package/dist/plugins/walrus/storage-nodes.d.mts +6 -2
- package/dist/plugins/walrus/storage-nodes.mjs +15 -8
- package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
- package/dist/plugins/walrus/wal-swap.mjs +58 -15
- package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
- package/dist/primitives/artifact-publisher.d.mts +1 -1
- package/dist/primitives/artifact-publisher.mjs +15 -0
- package/dist/primitives/artifact-publisher.mjs.map +1 -0
- package/dist/runtime/docker/client.mjs +17 -4
- package/dist/runtime/docker/client.mjs.map +1 -1
- package/dist/runtime/docker/container.mjs +219 -132
- package/dist/runtime/docker/container.mjs.map +1 -1
- package/dist/runtime/docker/errors.mjs +0 -6
- package/dist/runtime/docker/errors.mjs.map +1 -1
- package/dist/runtime/docker/exec.mjs +21 -18
- package/dist/runtime/docker/exec.mjs.map +1 -1
- package/dist/runtime/docker/image.mjs +36 -13
- package/dist/runtime/docker/image.mjs.map +1 -1
- package/dist/runtime/docker/index.mjs +14 -0
- package/dist/runtime/docker/inspect-and-decode.mjs +51 -0
- package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -0
- package/dist/runtime/docker/inventory.mjs +14 -11
- package/dist/runtime/docker/inventory.mjs.map +1 -1
- package/dist/runtime/docker/labels.mjs +38 -5
- package/dist/runtime/docker/labels.mjs.map +1 -1
- package/dist/runtime/docker/logs.d.mts +1 -1
- package/dist/runtime/docker/logs.mjs.map +1 -1
- package/dist/runtime/docker/network.mjs +83 -47
- package/dist/runtime/docker/network.mjs.map +1 -1
- package/dist/runtime/docker/render-run-args.mjs +82 -0
- package/dist/runtime/docker/render-run-args.mjs.map +1 -0
- package/dist/runtime/docker/service.d.mts +1 -1
- package/dist/runtime/docker/service.mjs +12 -7
- package/dist/runtime/docker/service.mjs.map +1 -1
- package/dist/runtime/docker/sweep.mjs +118 -43
- package/dist/runtime/docker/sweep.mjs.map +1 -1
- package/dist/runtime/docker/volume.mjs +2 -0
- package/dist/runtime/docker/volume.mjs.map +1 -1
- package/dist/runtime/docker/wrap.mjs +30 -1
- package/dist/runtime/docker/wrap.mjs.map +1 -1
- package/dist/substrate/cross-process.mjs +14 -8
- package/dist/substrate/cross-process.mjs.map +1 -1
- package/dist/substrate/event-time.mjs +33 -0
- package/dist/substrate/event-time.mjs.map +1 -0
- package/dist/substrate/events.d.mts +28 -8
- package/dist/substrate/identity.d.mts +2 -1
- package/dist/substrate/manifest.d.mts +68 -5
- package/dist/substrate/manifest.mjs +34 -5
- package/dist/substrate/manifest.mjs.map +1 -1
- package/dist/substrate/network.d.mts +3 -5
- package/dist/substrate/options.d.mts +0 -2
- package/dist/substrate/plugin.d.mts +13 -0
- package/dist/substrate/plugin.mjs +4 -2
- package/dist/substrate/plugin.mjs.map +1 -1
- package/dist/substrate/projection.d.mts +35 -3
- package/dist/substrate/runtime/artifact-publisher/index.mjs +19 -9
- package/dist/substrate/runtime/artifact-publisher/index.mjs.map +1 -1
- package/dist/substrate/runtime/atomic-write.mjs +97 -32
- package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
- package/dist/substrate/runtime/cache/index.mjs +3 -0
- package/dist/substrate/runtime/cache/schema.mjs +2 -2
- package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
- package/dist/substrate/runtime/cache/service.mjs +9 -7
- package/dist/substrate/runtime/cache/service.mjs.map +1 -1
- package/dist/substrate/runtime/capability-sinks/index.d.mts +1 -1
- package/dist/substrate/runtime/capability-sinks/index.mjs +3 -0
- package/dist/substrate/runtime/capability-sinks/layer.mjs +1 -1
- package/dist/substrate/runtime/capability-sinks/service.d.mts +61 -2
- package/dist/substrate/runtime/capability-sinks/service.mjs +21 -26
- package/dist/substrate/runtime/capability-sinks/service.mjs.map +1 -1
- package/dist/substrate/runtime/config-validation.d.mts +1 -13
- package/dist/substrate/runtime/config-validation.mjs +2 -91
- package/dist/substrate/runtime/config-validation.mjs.map +1 -1
- package/dist/substrate/runtime/container-runtime.d.mts +1 -0
- package/dist/substrate/runtime/container-runtime.mjs +2 -0
- package/dist/substrate/runtime/control-plane/domain.mjs +101 -0
- package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -0
- package/dist/substrate/runtime/control-plane/service.mjs +7 -0
- package/dist/substrate/runtime/control-plane/service.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +46 -19
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs +30 -12
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/index.mjs +5 -0
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs +11 -2
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs +1 -1
- package/dist/substrate/runtime/cross-process/index.mjs +11 -0
- package/dist/substrate/runtime/cross-process/live-clock.mjs +34 -0
- package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/liveness.mjs +52 -10
- package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/lock.d.mts +1 -0
- package/dist/substrate/runtime/cross-process/lock.mjs +23 -0
- package/dist/substrate/runtime/cross-process/lock.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +64 -0
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/roster.mjs +97 -83
- package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/self-pid.mjs +8 -0
- package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +24 -28
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/stack-lock.mjs +41 -20
- package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
- package/dist/substrate/runtime/current-plugin.mjs +2 -2
- package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
- package/dist/substrate/runtime/errors.mjs +12 -6
- package/dist/substrate/runtime/errors.mjs.map +1 -1
- package/dist/substrate/runtime/format-unknown-error.mjs +30 -0
- package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -0
- package/dist/substrate/runtime/host-bind-mount-owner.mjs +10 -0
- package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -0
- package/dist/substrate/runtime/host-gateway.mjs +20 -0
- package/dist/substrate/runtime/host-gateway.mjs.map +1 -0
- package/dist/substrate/runtime/host-tree-tar/index.mjs +61 -50
- package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
- package/dist/substrate/runtime/http-probe.d.mts +1 -1
- package/dist/substrate/runtime/index.mjs +14 -0
- package/dist/substrate/runtime/lease-broker/index.d.mts +1 -1
- package/dist/substrate/runtime/lease-broker/index.mjs +2 -0
- package/dist/substrate/runtime/lease-broker/service.d.mts +1 -64
- package/dist/substrate/runtime/lease-broker/service.mjs +1 -1
- package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs +22 -3
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/index.mjs +9 -0
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +20 -3
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs +5 -5
- package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/state-machine.mjs +1 -1
- package/dist/substrate/runtime/managed-container.d.mts +19 -1
- package/dist/substrate/runtime/managed-container.mjs +20 -1
- package/dist/substrate/runtime/managed-container.mjs.map +1 -1
- package/dist/substrate/runtime/manifest/index.mjs +3 -0
- package/dist/substrate/runtime/manifest/manifest.mjs +15 -11
- package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
- package/dist/substrate/runtime/mode-errors.mjs +20 -0
- package/dist/substrate/runtime/mode-errors.mjs.map +1 -0
- package/dist/substrate/runtime/observability/cascade-formatter.mjs +9 -13
- package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
- package/dist/substrate/runtime/observability/formatter-registry.mjs +19 -36
- package/dist/substrate/runtime/observability/formatter-registry.mjs.map +1 -1
- package/dist/substrate/runtime/observability/ignore-with-log.d.mts +1 -0
- package/dist/substrate/runtime/observability/ignore-with-log.mjs +17 -0
- package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -0
- package/dist/substrate/runtime/observability/index.d.mts +1 -1
- package/dist/substrate/runtime/observability/index.mjs +13 -0
- package/dist/substrate/runtime/observability/log-store.d.mts +1 -0
- package/dist/substrate/runtime/observability/log-store.mjs +175 -0
- package/dist/substrate/runtime/observability/log-store.mjs.map +1 -0
- package/dist/substrate/runtime/observability/logger.d.mts +2 -1
- package/dist/substrate/runtime/observability/logger.mjs +5 -9
- package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
- package/dist/substrate/runtime/observability/output-truncate.mjs +35 -0
- package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -0
- package/dist/substrate/runtime/observability/pretty-error.mjs +9 -12
- package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
- package/dist/substrate/runtime/observability/redaction.d.mts +2 -13
- package/dist/substrate/runtime/observability/redaction.mjs +8 -14
- package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
- package/dist/substrate/runtime/observability/span-store.d.mts +1 -0
- package/dist/substrate/runtime/observability/span-store.mjs +110 -0
- package/dist/substrate/runtime/observability/span-store.mjs.map +1 -0
- package/dist/substrate/runtime/observability/spans.mjs +14 -14
- package/dist/substrate/runtime/observability/spans.mjs.map +1 -1
- package/dist/substrate/runtime/observability/subprocess-capture.mjs +1 -1
- package/dist/substrate/runtime/passthrough-or-wrap.mjs +33 -0
- package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -0
- package/dist/substrate/runtime/paths.d.mts +1 -1
- package/dist/substrate/runtime/paths.mjs +4 -3
- package/dist/substrate/runtime/paths.mjs.map +1 -1
- package/dist/substrate/runtime/phase-preserving-produce.mjs +40 -0
- package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -0
- package/dist/substrate/runtime/port-broker/index.mjs +3 -0
- package/dist/substrate/runtime/port-broker/service.mjs +170 -126
- package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/post-acquire-tasks.mjs +1 -1
- package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/probes.d.mts +7 -5
- package/dist/substrate/runtime/probes.mjs +3 -1
- package/dist/substrate/runtime/probes.mjs.map +1 -1
- package/dist/substrate/runtime/projection/index.mjs +4 -0
- package/dist/substrate/runtime/projection/operational-endpoints.mjs +1 -2
- package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
- package/dist/substrate/runtime/projection/persisted.mjs +33 -15
- package/dist/substrate/runtime/projection/persisted.mjs.map +1 -1
- package/dist/substrate/runtime/projection/state-ref.mjs +26 -2
- package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
- package/dist/substrate/runtime/projection/update.mjs +88 -24
- package/dist/substrate/runtime/projection/update.mjs.map +1 -1
- package/dist/substrate/runtime/random-suffix.mjs +11 -0
- package/dist/substrate/runtime/random-suffix.mjs.map +1 -0
- package/dist/substrate/runtime/retry-policy.d.mts +59 -1
- package/dist/substrate/runtime/retry-policy.mjs +66 -1
- package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
- package/dist/substrate/runtime/routed-url.d.mts +1 -0
- package/dist/substrate/runtime/routed-url.mjs +79 -0
- package/dist/substrate/runtime/routed-url.mjs.map +1 -0
- package/dist/substrate/runtime/runtime-decode.d.mts +1 -1
- package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
- package/dist/substrate/runtime/scoped-http-server.mjs +2 -3
- package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
- package/dist/substrate/runtime/scoped-multimap/index.mjs +2 -0
- package/dist/substrate/runtime/scoped-multimap/service.mjs +52 -0
- package/dist/substrate/runtime/scoped-multimap/service.mjs.map +1 -0
- package/dist/substrate/runtime/scoped-ref-map/index.mjs +2 -0
- package/dist/substrate/runtime/scoped-ref-map/service.mjs +2 -2
- package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +1 -1
- package/dist/substrate/runtime/stage-and-swap/index.mjs +72 -4
- package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
- package/dist/substrate/runtime/state-store/index.d.mts +1 -0
- package/dist/substrate/runtime/state-store/index.mjs +3 -0
- package/dist/substrate/runtime/state-store/schema.d.mts +1 -0
- package/dist/substrate/runtime/state-store/schema.mjs +19 -14
- package/dist/substrate/runtime/state-store/schema.mjs.map +1 -1
- package/dist/substrate/runtime/state-store/service.d.mts +1 -0
- package/dist/substrate/runtime/state-store/service.mjs +145 -0
- package/dist/substrate/runtime/state-store/service.mjs.map +1 -0
- package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.d.mts +1 -0
- package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs +33 -0
- package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -0
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/index.mjs +4 -0
- package/dist/substrate/runtime/strategy-registry/service.mjs +19 -33
- package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
- package/dist/substrate/runtime/subnet-broker.mjs +60 -0
- package/dist/substrate/runtime/subnet-broker.mjs.map +1 -0
- package/dist/substrate/runtime/sui-execute/index.d.mts +21 -1
- package/dist/substrate/runtime/sui-execute/index.mjs +84 -20
- package/dist/substrate/runtime/sui-execute/index.mjs.map +1 -1
- package/dist/substrate/runtime/sui-execute/sign-and-dispatch.d.mts +1 -0
- package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs +32 -0
- package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +1 -0
- package/dist/substrate/runtime/sui-ledger/object-ref.mjs +32 -0
- package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +1 -0
- package/dist/substrate/runtime/sui-move-build/index.mjs +93 -19
- package/dist/substrate/runtime/sui-move-build/index.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/acquire-node.mjs +181 -0
- package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/background-tasks.mjs +144 -0
- package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/command-loop.mjs +68 -0
- package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +151 -0
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/errors.d.mts +1 -0
- package/dist/substrate/runtime/supervisor/errors.mjs +9 -0
- package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/index.d.mts +1 -0
- package/dist/substrate/runtime/supervisor/index.mjs +3 -0
- package/dist/substrate/runtime/supervisor/shutdown.mjs +51 -0
- package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/start-supervisor.d.mts +1 -0
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs +250 -0
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/state.d.mts +1 -0
- package/dist/substrate/runtime/supervisor/state.mjs +22 -0
- package/dist/substrate/runtime/supervisor/state.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/teardown.mjs +57 -0
- package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/types.d.mts +1 -0
- package/dist/substrate/runtime/supervisor/wiring.mjs +133 -0
- package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -0
- package/dist/substrate/runtime/typed-env.mjs +8 -0
- package/dist/substrate/runtime/typed-env.mjs.map +1 -0
- package/dist/substrate/state-store.d.mts +1 -0
- package/dist/substrate/versioned-doc-schema.mjs +17 -0
- package/dist/substrate/versioned-doc-schema.mjs.map +1 -0
- package/dist/substrate/versioned-doc-sync.mjs +94 -0
- package/dist/substrate/versioned-doc-sync.mjs.map +1 -0
- package/dist/surfaces/cli/command-tree.mjs.map +1 -1
- package/dist/surfaces/cli/commands/index.mjs +9 -0
- package/dist/surfaces/cli/commands/prune-picker-entry.mjs +13 -0
- package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -0
- package/dist/surfaces/cli/commands/prune-picker.mjs +3 -2
- package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune.mjs +34 -17
- package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
- package/dist/surfaces/cli/commands/status.mjs +2 -2
- package/dist/surfaces/cli/commands/status.mjs.map +1 -1
- package/dist/surfaces/cli/commands/supervisor-presence.mjs +5 -3
- package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
- package/dist/surfaces/cli/commands/wipe.mjs +38 -4
- package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
- package/dist/surfaces/cli/errors.mjs +1 -1
- package/dist/surfaces/cli/errors.mjs.map +1 -1
- package/dist/surfaces/cli/flags.mjs +0 -1
- package/dist/surfaces/cli/flags.mjs.map +1 -1
- package/dist/surfaces/cli/index.mjs +98 -18
- package/dist/surfaces/cli/index.mjs.map +1 -1
- package/dist/surfaces/cli/output.mjs +1 -0
- package/dist/surfaces/cli/output.mjs.map +1 -1
- package/dist/surfaces/cli/sysexits.mjs +2 -1
- package/dist/surfaces/cli/sysexits.mjs.map +1 -1
- package/dist/surfaces/tui/app.mjs +25 -3
- package/dist/surfaces/tui/app.mjs.map +1 -1
- package/dist/surfaces/tui/display-derivation.mjs +23 -74
- package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
- package/dist/surfaces/tui/event-log.mjs +35 -23
- package/dist/surfaces/tui/event-log.mjs.map +1 -1
- package/dist/surfaces/tui/input.mjs +5 -1
- package/dist/surfaces/tui/input.mjs.map +1 -1
- package/dist/surfaces/tui/plain-renderer.mjs +70 -34
- package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
- package/package.json +24 -4
- package/dist/contracts/liveness-classifier.d.mts +0 -19
- package/dist/contracts/network-resolver.d.mts +0 -15
- package/dist/contracts/network-resolver.mjs +0 -7
- package/dist/contracts/network-resolver.mjs.map +0 -1
- package/dist/orchestrators/codegen/extras.mjs +0 -16
- package/dist/orchestrators/codegen/extras.mjs.map +0 -1
- package/dist/plugins/deepbook/routable.mjs +0 -21
- package/dist/plugins/deepbook/routable.mjs.map +0 -1
- package/dist/plugins/faucet/service.d.mts +0 -20
- package/dist/plugins/faucet/strategies/sui-local.d.mts +0 -23
- package/dist/plugins/faucet/strategies/sui-local.mjs.map +0 -1
- package/dist/plugins/sui/seed-objects.d.mts +0 -18
- package/dist/plugins/sui/seed-objects.mjs +0 -25
- package/dist/plugins/sui/seed-objects.mjs.map +0 -1
- package/dist/runtime/built-in-plugin-layers.mjs.map +0 -1
- package/dist/substrate/runtime/context-helpers.mjs +0 -32
- package/dist/substrate/runtime/context-helpers.mjs.map +0 -1
- package/dist/substrate/runtime/run.mjs.map +0 -1
- package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs +0 -30
- package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs.map +0 -1
- package/dist/substrate/runtime/supervisor.d.mts +0 -1
- package/dist/substrate/runtime/supervisor.mjs +0 -831
- package/dist/substrate/runtime/supervisor.mjs.map +0 -1
- package/dist/surfaces/cli/commands/doctor-probes.mjs.map +0 -1
- /package/dist/{substrate/runtime/strategy-registry/faucet-capability-for.d.mts → plugins/faucet/http.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"origin-policy.mjs","names":[],"sources":["../../../src/plugins/wallet/origin-policy.ts"],"sourcesContent":["// Wallet plugin — CORS / origin allowlist policy.\n//\n//
|
|
1
|
+
{"version":3,"file":"origin-policy.mjs","names":[],"sources":["../../../src/plugins/wallet/origin-policy.ts"],"sourcesContent":["// Wallet plugin — CORS / origin allowlist policy.\n//\n// The allowlist is built from two real, substrate-wired sources: the\n// router-fronted dev-server origin for this stack (`routedAppOrigin`)\n// and any caller-supplied `extraOrigins`. Both are stack-scoped or\n// explicit, so neither opens the cross-stack pairing risk described in\n// 15-wallet.md.\n//\n// History (removed): an earlier design auto-allowlisted a vite-port-\n// derived origin (`http://dev.<stack>.<app>.localhost:<vite-port>`,\n// plus an opt-in `http://localhost:<vite-port>`). That branch was dead\n// AT THE TIME: there was no vite plugin and the port broker only\n// allocated ports for in-stack plugins with no reader/lookup API, so\n// `vitePortForThisStack` was always `null` at the only production call\n// site and the branch never fired. Per STYLE_GUIDE §5 (\"code either\n// works or doesn't exist\") the whole vite-origin path — and the\n// `allowLocalhostVite` opt-in it gated — was removed rather than left as\n// an unreachable allowlist seam.\n//\n// Note (no longer dead, but deliberately NOT re-added here): with the\n// `hostService(...)` plugin devstack now DOES own the dev server's bind\n// port (the broker allocates it; Vite binds it via `--port {port}`). So\n// the raw-loopback origin (`http://127.0.0.1:<port>` /\n// `http://localhost:<port>`) the dev sees in Vite's own console banner is\n// a real, knowable origin. The canonical fix lives on the host-service\n// side instead: it now publishes the ROUTED origin as its\n// `HostServiceValue.url`, so `devstack up` output (and any consumer\n// holding the resolved host-service value) point devs at the URL whose\n// Origin THIS allowlist already accepts (the routed `routedAppOrigin`).\n// Re-adding a raw-loopback branch\n// here is intentionally deferred — it would have to thread the\n// host-service's dynamic bind port into the wallet, which runs in the\n// OPPOSITE direction of the current dependency edge (host-service\n// `dependsOn` wallet), so the wallet has no view of that port at its own\n// boot. Devs who must load the raw Vite URL can pass it via\n// `allowedOrigins` (→ `extraOrigins`) until that plumbing is justified.\n//\n// Why \"origin + bearer together\": bearer alone leaves a non-browser-\n// tooling bypass — curl / fetch from a service worker can forge\n// `Authorization` from a leaked token. Browsers always send `Origin`;\n// non-browsers omit it. Demanding BOTH closes the bypass.\n\nimport { Effect } from 'effect';\n\nimport { SpanAttr } from '../../substrate/runtime/observability/spans.ts';\n\n// ----------------------------------------------------------------------\n// Policy shape\n// ----------------------------------------------------------------------\n\n/** Result of resolving the origin allowlist at boot. Captured into\n * the HTTP handler closure so per-request checks are pure-string\n * comparison. */\nexport interface OriginPolicy {\n\treadonly allowed: ReadonlySet<string>;\n}\n\n/** Per-stack inputs the policy resolver needs. Supplied by the\n * substrate at acquire time (identity + routed-url derivation); this\n * module doesn't reach into the broker itself. */\nexport interface OriginPolicyInputs {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly routedAppOrigin: string | null;\n\treadonly extraOrigins: ReadonlyArray<string>;\n}\n\n// ----------------------------------------------------------------------\n// Resolution\n// ----------------------------------------------------------------------\n\n/**\n * Resolve the per-stack origin allowlist.\n *\n * - Always allowlisted: the router-fronted dev-server origin for this\n * stack (`routedAppOrigin`), when the router derivation produced one.\n * - Always allowlisted: any explicit caller-supplied origins from\n * `extraOrigins`.\n *\n * Empty-allowlist policy (no `routedAppOrigin` AND no `extraOrigins`):\n * allowed. The wallet boots normally; with an empty allowlist the\n * per-request gate refuses every request (every Origin lands in\n * `forbidden`). This is the correct behavior for a stack composed\n * without any client UI (e.g. node-only smoke / e2e configs) — the\n * wallet's keypair + token are still useful for the host process, but\n * the HTTP surface is effectively closed. A `Effect.logWarning`\n * surfaces the configuration for operator visibility.\n */\nexport const resolveOriginPolicy = (inputs: OriginPolicyInputs): Effect.Effect<OriginPolicy> =>\n\tEffect.gen(function* () {\n\t\tconst allowed = new Set<string>();\n\n\t\tif (inputs.routedAppOrigin !== null) {\n\t\t\tallowed.add(inputs.routedAppOrigin);\n\t\t}\n\n\t\tfor (const o of inputs.extraOrigins) {\n\t\t\tallowed.add(o);\n\t\t}\n\n\t\tif (allowed.size === 0) {\n\t\t\tyield* Effect.logWarning('wallet origin allowlist is empty').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t[SpanAttr.app]: inputs.app,\n\t\t\t\t\t[SpanAttr.stack]: inputs.stack,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn { allowed } satisfies OriginPolicy;\n\t});\n\n// ----------------------------------------------------------------------\n// Per-request check\n// ----------------------------------------------------------------------\n\n/** Per-request origin gate. Returns `'missing'` for absent Origin,\n * `'forbidden'` for Origin not in the allowlist, `'ok'` for accepted.\n *\n * Distilled-doc invariant (C12): missing Origin is its OWN refusal\n * shape (closes the curl / non-browser bypass — bearer alone is not\n * enough). */\nexport type OriginCheckResult = 'missing' | 'forbidden' | 'ok';\n\nexport const checkOrigin = (\n\tpolicy: OriginPolicy,\n\theaderValue: string | undefined,\n): OriginCheckResult => {\n\tif (headerValue === undefined || headerValue.length === 0) return 'missing';\n\treturn policy.allowed.has(headerValue) ? 'ok' : 'forbidden';\n};\n\n/** Compose CORS headers for a successful request. Single-allowed-origin\n * echo (browsers don't honor wildcard with credentials, and we want\n * to keep `Access-Control-Allow-Credentials` open for fetch with\n * `credentials: 'include'` if a future codegen seam needs it). */\nexport const corsHeadersFor = (origin: string): Readonly<Record<string, string>> => ({\n\t'access-control-allow-origin': origin,\n\t'access-control-allow-methods': 'GET, POST, OPTIONS',\n\t'access-control-allow-headers': 'authorization, content-type',\n\t'access-control-allow-credentials': 'true',\n\tvary: 'origin',\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwFA,MAAa,uBAAuB,WACnC,OAAO,IAAI,aAAa;CACvB,MAAM,0BAAU,IAAI,KAAa;AAEjC,KAAI,OAAO,oBAAoB,KAC9B,SAAQ,IAAI,OAAO,gBAAgB;AAGpC,MAAK,MAAM,KAAK,OAAO,aACtB,SAAQ,IAAI,EAAE;AAGf,KAAI,QAAQ,SAAS,EACpB,QAAO,OAAO,WAAW,mCAAmC,CAAC,KAC5D,OAAO,aAAa;GAClB,SAAS,MAAM,OAAO;GACtB,SAAS,QAAQ,OAAO;EACzB,CAAC,CACF;AAGF,QAAO,EAAE,SAAS;EACjB;AAcH,MAAa,eACZ,QACA,gBACuB;AACvB,KAAI,gBAAgB,KAAA,KAAa,YAAY,WAAW,EAAG,QAAO;AAClE,QAAO,OAAO,QAAQ,IAAI,YAAY,GAAG,OAAO;;;;;;AAOjD,MAAa,kBAAkB,YAAsD;CACpF,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;CAChC,oCAAoC;CACpC,MAAM;CACN"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { atomicWriteFile } from "../../substrate/runtime/atomic-write.mjs";
|
|
2
|
-
import { SpanAttr } from "../../substrate/runtime/observability/spans.mjs";
|
|
3
1
|
import { redactText } from "../../substrate/runtime/observability/redaction.mjs";
|
|
2
|
+
import { atomicWriteFile } from "../../substrate/runtime/atomic-write.mjs";
|
|
3
|
+
import "../../substrate/runtime/observability/index.mjs";
|
|
4
|
+
import { WALLET_BEARER_PREFIX, WALLET_TOKEN_FRAGMENT_KEY } from "../../contracts/wallet-protocol.mjs";
|
|
4
5
|
import { walletBootError } from "./errors.mjs";
|
|
5
|
-
import {
|
|
6
|
+
import { WalletSpans } from "./spans.mjs";
|
|
7
|
+
import "./protocol.mjs";
|
|
6
8
|
import { Effect } from "effect";
|
|
7
9
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
8
10
|
import { join } from "node:path";
|
|
@@ -49,7 +51,7 @@ const acquirePairingToken = (path) => Effect.gen(function* () {
|
|
|
49
51
|
if (existing !== null) {
|
|
50
52
|
const trimmed = existing.trim();
|
|
51
53
|
if (TOKEN_RE.test(trimmed)) return asToken(trimmed);
|
|
52
|
-
yield* Effect.logWarning("wallet token file is malformed; re-minting").pipe(Effect.annotateLogs({ [
|
|
54
|
+
yield* Effect.logWarning("wallet token file is malformed; re-minting").pipe(Effect.annotateLogs({ [WalletSpans.tokenFile]: path }));
|
|
53
55
|
}
|
|
54
56
|
const token = yield* mintToken();
|
|
55
57
|
yield* atomicWriteFile(path, new TextEncoder().encode(token), { mode: 384 }).pipe(Effect.mapError((cause) => walletBootError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pairing.mjs","names":["joinPath"],"sources":["../../../src/plugins/wallet/pairing.ts"],"sourcesContent":["// Wallet plugin — pairing-token discipline.\n//\n// What this module owns (15-wallet.md \"Token comparison MUST be\n// constant-time\", \"Token MUST live in URL fragment (not query)\",\n// \"Token MUST NOT appear in log lines\", \"Token file MUST be mode\n// 0o600\"):\n//\n// 1. Token generation: 16 random bytes → 32 hex chars.\n// 2. Token persistence: file at `<stateRoot>/wallet/token`, mode\n// `0o600`, atomic write.\n// 3. Token rehydration: read-existing-or-mint so warm starts +\n// snapshot restore preserve the dev-wallet pairing.\n// 4. URL-fragment ↔ Authorization-header bridge: helpers that\n// compose the pair URL (token in fragment) and parse the\n// bearer-prefixed header back to the raw token.\n// 5. Constant-time bearer compare: timing-safe equality so a\n// remote attacker can't recover the token byte-by-byte via\n// response-time measurement.\n//\n// What this module does NOT own:\n//\n// - The HTTP server (see `server.ts`).\n// - The CORS / Origin allowlist (see `origin-policy.ts`).\n// - The codegen file (see `codegen.ts`).\n\nimport { Effect, FileSystem } from 'effect';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { join as joinPath } from 'node:path';\n\nimport { atomicWriteFile } from '../../substrate/runtime/atomic-write.ts';\nimport { redactText, type RedactionRule } from '../../substrate/runtime/observability/index.ts';\nimport { SpanAttr } from '../../substrate/runtime/observability/spans.ts';\nimport { walletBootError, type WalletBootError } from './errors.ts';\nimport {\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n} from './protocol.ts';\n\n// ----------------------------------------------------------------------\n// Token shape\n// ----------------------------------------------------------------------\n\n/** A pairing token. Branded so it can't be confused with arbitrary\n * strings at the type level — only this module mints them. */\nexport type PairingToken = string & { readonly __pairingToken: unique symbol };\n\n/** Token-charset regex: lowercase hex, exactly 32 chars. Reject any\n * on-disk value that doesn't match (re-mint). */\nconst TOKEN_RE = /^[0-9a-f]{32}$/;\n\nconst asToken = (s: string): PairingToken => s as PairingToken;\n\n// ----------------------------------------------------------------------\n// Generation\n// ----------------------------------------------------------------------\n\n/** Mint a fresh token. 16 random bytes → 32 hex chars. */\nexport const mintToken = (): Effect.Effect<PairingToken> =>\n\tEffect.sync(() => asToken(randomBytes(16).toString('hex')));\n\n// ----------------------------------------------------------------------\n// Persistence\n// ----------------------------------------------------------------------\n\n/** Resolve the on-disk token path under a state root. The state root\n * is supplied by the substrate's identity / state-store config; this\n * helper centralises the layout convention.\n *\n * Convention: `<stateRoot>/wallet/token` — one token per stack, lives\n * alongside other per-stack runtime artifacts. */\nexport const tokenPath = (stateRoot: string): string => joinPath(stateRoot, 'wallet', 'token');\n\n/**\n * Read the on-disk token if it exists and is well-formed; otherwise\n * mint + persist a fresh one via the substrate's atomic-write primitive\n * (mkdir-parent → O_EXCL temp → write → fsync → rename, mode 0o600).\n * Warm starts and snapshot restores both land in the \"read existing\"\n * branch so a previously-paired dev-wallet keeps working without a\n * re-pair UX.\n */\nexport const acquirePairingToken = (\n\tpath: string,\n): Effect.Effect<PairingToken, WalletBootError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\t// Try to read an existing token.\n\t\tconst existing = yield* Effect.tryPromise({\n\t\t\ttry: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await readFile(path, 'utf8');\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return null;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcatch: (cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'read-token',\n\t\t\t\t\tmessage: `read of wallet token file failed at ${path}`,\n\t\t\t\t\thint: 'check filesystem permissions / disk availability',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\n\t\tif (existing !== null) {\n\t\t\tconst trimmed = existing.trim();\n\t\t\tif (TOKEN_RE.test(trimmed)) {\n\t\t\t\treturn asToken(trimmed);\n\t\t\t}\n\t\t\t// Malformed — fall through to mint + overwrite.\n\t\t\tyield* Effect.logWarning('wallet token file is malformed; re-minting').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t[SpanAttr.walletTokenFile]: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\t// Mint a new one + persist via substrate's atomic-write\n\t\t// (mode 0o600). The token survives partial-write failures: the\n\t\t// in-memory value is authoritative for the current cycle, and a\n\t\t// failed persist surfaces as `write-token` so callers can choose\n\t\t// to fail-fast or continue with a transient pairing.\n\t\tconst token = yield* mintToken();\n\t\tconst bytes = new TextEncoder().encode(token);\n\t\tyield* atomicWriteFile(path, bytes, { mode: 0o600 }).pipe(\n\t\t\tEffect.mapError((cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'write-token',\n\t\t\t\t\tmessage: `failed to persist wallet token at ${path}`,\n\t\t\t\t\thint: 'ENOSPC / EROFS / EACCES — boot continues with in-memory token; new pairing required next cycle',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\n\t\treturn token;\n\t});\n\n// ----------------------------------------------------------------------\n// Pair-URL composition (fragment-only)\n// ----------------------------------------------------------------------\n\n/**\n * Compose the pair URL the dev-wallet adapter reads.\n *\n * The token rides the URL FRAGMENT (`#token=...`), never a query\n * parameter. Fragments are not sent to servers, so the token can't\n * land in access logs / referrer headers / Sentry breadcrumbs.\n */\nexport const composePairUrl = (walletUrl: string, token: PairingToken): string =>\n\t`${walletUrl}/#${WALLET_TOKEN_FRAGMENT_KEY}=${token}`;\n\n/**\n * Inverse — parse the token out of a pair URL fragment. Used by tests +\n * by the dev-wallet adapter (mirrored there because of the workspace-\n * cycle constraint).\n */\nexport const parsePairUrl = (pairUrl: string): PairingToken | null => {\n\tconst hashIdx = pairUrl.indexOf('#');\n\tif (hashIdx < 0) return null;\n\tconst fragment = pairUrl.slice(hashIdx + 1);\n\tconst prefix = `${WALLET_TOKEN_FRAGMENT_KEY}=`;\n\tif (!fragment.startsWith(prefix)) return null;\n\tconst raw = fragment.slice(prefix.length);\n\treturn TOKEN_RE.test(raw) ? asToken(raw) : null;\n};\n\n// ----------------------------------------------------------------------\n// Authorization-header bridge\n// ----------------------------------------------------------------------\n\n/**\n * Parse a raw `Authorization` header value into the bearer token. The\n * dev-wallet adapter copies the token from `url.hash` into the\n * `Authorization: Bearer <token>` header on every request — this\n * helper is the symmetric inverse.\n *\n * Returns `null` on missing / malformed header so the caller can map\n * to the structured `unauthorized` request error.\n */\nexport const parseBearerHeader = (header: string | undefined): string | null => {\n\tif (header === undefined) return null;\n\tif (!header.startsWith(WALLET_BEARER_PREFIX)) return null;\n\tconst raw = header.slice(WALLET_BEARER_PREFIX.length);\n\t// Don't TOKEN_RE-test here — the constant-time compare against the\n\t// expected token covers shape mismatch (length-difference shortcut\n\t// is acceptable since token length is public knowledge).\n\treturn raw.length === WALLET_TOKEN_HEX_LENGTH ? raw : null;\n};\n\n// ----------------------------------------------------------------------\n// Constant-time compare\n// ----------------------------------------------------------------------\n\n/**\n * Constant-time bearer-token compare. The length-mismatch shortcut is\n * intentional — token length is public knowledge (always 32 hex\n * chars), so leaking \"wrong length\" is not a credential leak. The\n * shortcut also prevents `timingSafeEqual` from throwing on mismatched\n * buffer sizes.\n *\n * Invariant (15-wallet.md \"Token comparison MUST be constant-time\"):\n * NEVER `===` two tokens. `===` on strings short-circuits at the first\n * mismatching byte, leaking the prefix byte-by-byte via response-time\n * measurement to a remote attacker.\n */\nexport const safeBearerEquals = (a: string, b: PairingToken | string): boolean => {\n\tif (a.length !== b.length) return false;\n\t// Both strings are 32 hex chars, ASCII — a fixed-length byte compare\n\t// is sufficient. UTF-8 encoding via `Buffer.from(_, 'utf8')` is\n\t// constant-time for the ASCII subset (each char → 1 byte).\n\tconst ab = Buffer.from(a, 'utf8');\n\tconst bb = Buffer.from(b, 'utf8');\n\tif (ab.length !== bb.length) return false; // defensive\n\treturn timingSafeEqual(ab, bb);\n};\n\n// ----------------------------------------------------------------------\n// Logging hygiene\n// ----------------------------------------------------------------------\n\nconst TOKEN_REDACTION_RULE: RedactionRule = {\n\tkind: 'pattern',\n\tpattern: /([#?&]token=)[A-Za-z0-9]+/g,\n\treplacement: '$1<redacted>',\n};\n\n/**\n * Redact the token fragment from any URL-shaped string for logging /\n * TUI rendering. Defense-in-depth — the engine's log sink should never\n * see the unredacted pair URL anyway, but this exists for callers that\n * accidentally pass `pairUrl` straight into a log line.\n *\n * Distilled-doc opportunity (15-wallet.md): the legacy redactor only\n * covered `#token=`. This regex covers BOTH the fragment form and a\n * hypothetical query form so a future config change doesn't silently\n * leak.\n */\nexport const redactToken = (s: string): string => redactText(s, [TOKEN_REDACTION_RULE]);\n"],"mappings":";;;;;;;;;;;;AAkDA,MAAM,WAAW;AAEjB,MAAM,WAAW,MAA4B;;AAO7C,MAAa,kBACZ,OAAO,WAAW,QAAQ,YAAY,GAAG,CAAC,SAAS,MAAM,CAAC,CAAC;;;;;;;AAY5D,MAAa,aAAa,cAA8BA,KAAS,WAAW,UAAU,QAAQ;;;;;;;;;AAU9F,MAAa,uBACZ,SAEA,OAAO,IAAI,aAAa;CAEvB,MAAM,WAAW,OAAO,OAAO,WAAW;EACzC,KAAK,YAAY;AAChB,OAAI;AACH,WAAO,MAAM,SAAS,MAAM,OAAO;YAC3B,KAAK;AACb,QAAK,KAA+B,SAAS,SAAU,QAAO;AAC9D,UAAM;;;EAGR,QAAQ,UACP,gBAAgB;GACf,OAAO;GACP,SAAS,uCAAuC;GAChD,MAAM;GACN;GACA,CAAC;EACH,CAAC;AAEF,KAAI,aAAa,MAAM;EACtB,MAAM,UAAU,SAAS,MAAM;AAC/B,MAAI,SAAS,KAAK,QAAQ,CACzB,QAAO,QAAQ,QAAQ;AAGxB,SAAO,OAAO,WAAW,6CAA6C,CAAC,KACtE,OAAO,aAAa,GAClB,SAAS,kBAAkB,MAC5B,CAAC,CACF;;CAQF,MAAM,QAAQ,OAAO,WAAW;AAEhC,QAAO,gBAAgB,MADT,IAAI,aAAa,CAAC,OAAO,MACL,EAAE,EAAE,MAAM,KAAO,CAAC,CAAC,KACpD,OAAO,UAAU,UAChB,gBAAgB;EACf,OAAO;EACP,SAAS,qCAAqC;EAC9C,MAAM;EACN;EACA,CAAC,CACF,CACD;AAED,QAAO;EACN;;;;;;;;AAaH,MAAa,kBAAkB,WAAmB,UACjD,GAAG,UAAU,IAAI,0BAA0B,GAAG;;;;;;;;;;AA8B/C,MAAa,qBAAqB,WAA8C;AAC/E,KAAI,WAAW,KAAA,EAAW,QAAO;AACjC,KAAI,CAAC,OAAO,WAAA,UAAgC,CAAE,QAAO;CACrD,MAAM,MAAM,OAAO,MAAM,qBAAqB,OAAO;AAIrD,QAAO,IAAI,WAAA,KAAqC,MAAM;;;;;;;;;;;;;;AAmBvD,MAAa,oBAAoB,GAAW,MAAsC;AACjF,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;CAIlC,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;CACjC,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;AACjC,KAAI,GAAG,WAAW,GAAG,OAAQ,QAAO;AACpC,QAAO,gBAAgB,IAAI,GAAG;;AAO/B,MAAM,uBAAsC;CAC3C,MAAM;CACN,SAAS;CACT,aAAa;CACb;;;;;;;;;;;;AAaD,MAAa,eAAe,MAAsB,WAAW,GAAG,CAAC,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"pairing.mjs","names":["joinPath"],"sources":["../../../src/plugins/wallet/pairing.ts"],"sourcesContent":["// Wallet plugin — pairing-token discipline.\n//\n// What this module owns (15-wallet.md \"Token comparison MUST be\n// constant-time\", \"Token MUST live in URL fragment (not query)\",\n// \"Token MUST NOT appear in log lines\", \"Token file MUST be mode\n// 0o600\"):\n//\n// 1. Token generation: 16 random bytes → 32 hex chars.\n// 2. Token persistence: file at `<stateRoot>/wallet/token`, mode\n// `0o600`, atomic write.\n// 3. Token rehydration: read-existing-or-mint so warm starts +\n// snapshot restore preserve the dev-wallet pairing.\n// 4. URL-fragment ↔ Authorization-header bridge: helpers that\n// compose the pair URL (token in fragment) and parse the\n// bearer-prefixed header back to the raw token.\n// 5. Constant-time bearer compare: timing-safe equality so a\n// remote attacker can't recover the token byte-by-byte via\n// response-time measurement.\n//\n// What this module does NOT own:\n//\n// - The HTTP server (see `server.ts`).\n// - The CORS / Origin allowlist (see `origin-policy.ts`).\n// - The codegen file (see `codegen.ts`).\n\nimport { Effect, FileSystem } from 'effect';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { join as joinPath } from 'node:path';\n\nimport { atomicWriteFile } from '../../substrate/runtime/atomic-write.ts';\nimport { redactText, type RedactionRule } from '../../substrate/runtime/observability/index.ts';\nimport { walletBootError, type WalletBootError } from './errors.ts';\nimport { WalletSpans } from './spans.ts';\nimport {\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n} from './protocol.ts';\n\n// ----------------------------------------------------------------------\n// Token shape\n// ----------------------------------------------------------------------\n\n/** A pairing token. Branded so it can't be confused with arbitrary\n * strings at the type level — only this module mints them. */\nexport type PairingToken = string & { readonly __pairingToken: unique symbol };\n\n/** Token-charset regex: lowercase hex, exactly 32 chars. Reject any\n * on-disk value that doesn't match (re-mint). */\nconst TOKEN_RE = /^[0-9a-f]{32}$/;\n\nconst asToken = (s: string): PairingToken => s as PairingToken;\n\n// ----------------------------------------------------------------------\n// Generation\n// ----------------------------------------------------------------------\n\n/** Mint a fresh token. 16 random bytes → 32 hex chars. */\nexport const mintToken = (): Effect.Effect<PairingToken> =>\n\tEffect.sync(() => asToken(randomBytes(16).toString('hex')));\n\n// ----------------------------------------------------------------------\n// Persistence\n// ----------------------------------------------------------------------\n\n/** Resolve the on-disk token path under a state root. The state root\n * is supplied by the substrate's identity / state-store config; this\n * helper centralises the layout convention.\n *\n * Convention: `<stateRoot>/wallet/token` — one token per stack, lives\n * alongside other per-stack runtime artifacts. */\nexport const tokenPath = (stateRoot: string): string => joinPath(stateRoot, 'wallet', 'token');\n\n/**\n * Read the on-disk token if it exists and is well-formed; otherwise\n * mint + persist a fresh one via the substrate's atomic-write primitive\n * (mkdir-parent → O_EXCL temp → write → fsync → rename, mode 0o600).\n * Warm starts and snapshot restores both land in the \"read existing\"\n * branch so a previously-paired dev-wallet keeps working without a\n * re-pair UX.\n */\nexport const acquirePairingToken = (\n\tpath: string,\n): Effect.Effect<PairingToken, WalletBootError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\t// Try to read an existing token.\n\t\tconst existing = yield* Effect.tryPromise({\n\t\t\ttry: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await readFile(path, 'utf8');\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return null;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcatch: (cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'read-token',\n\t\t\t\t\tmessage: `read of wallet token file failed at ${path}`,\n\t\t\t\t\thint: 'check filesystem permissions / disk availability',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\n\t\tif (existing !== null) {\n\t\t\tconst trimmed = existing.trim();\n\t\t\tif (TOKEN_RE.test(trimmed)) {\n\t\t\t\treturn asToken(trimmed);\n\t\t\t}\n\t\t\t// Malformed — fall through to mint + overwrite.\n\t\t\tyield* Effect.logWarning('wallet token file is malformed; re-minting').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t[WalletSpans.tokenFile]: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\t// Mint a new one + persist via substrate's atomic-write\n\t\t// (mode 0o600). The token survives partial-write failures: the\n\t\t// in-memory value is authoritative for the current cycle, and a\n\t\t// failed persist surfaces as `write-token` so callers can choose\n\t\t// to fail-fast or continue with a transient pairing.\n\t\tconst token = yield* mintToken();\n\t\tconst bytes = new TextEncoder().encode(token);\n\t\tyield* atomicWriteFile(path, bytes, { mode: 0o600 }).pipe(\n\t\t\tEffect.mapError((cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'write-token',\n\t\t\t\t\tmessage: `failed to persist wallet token at ${path}`,\n\t\t\t\t\thint: 'ENOSPC / EROFS / EACCES — boot continues with in-memory token; new pairing required next cycle',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\n\t\treturn token;\n\t});\n\n// ----------------------------------------------------------------------\n// Pair-URL composition (fragment-only)\n// ----------------------------------------------------------------------\n\n/**\n * Compose the pair URL the dev-wallet adapter reads.\n *\n * The token rides the URL FRAGMENT (`#token=...`), never a query\n * parameter. Fragments are not sent to servers, so the token can't\n * land in access logs / referrer headers / Sentry breadcrumbs.\n */\nexport const composePairUrl = (walletUrl: string, token: PairingToken): string =>\n\t`${walletUrl}/#${WALLET_TOKEN_FRAGMENT_KEY}=${token}`;\n\n/**\n * Inverse — parse the token out of a pair URL fragment. Used by tests +\n * by the dev-wallet adapter (mirrored there because of the workspace-\n * cycle constraint).\n */\nexport const parsePairUrl = (pairUrl: string): PairingToken | null => {\n\tconst hashIdx = pairUrl.indexOf('#');\n\tif (hashIdx < 0) return null;\n\tconst fragment = pairUrl.slice(hashIdx + 1);\n\tconst prefix = `${WALLET_TOKEN_FRAGMENT_KEY}=`;\n\tif (!fragment.startsWith(prefix)) return null;\n\tconst raw = fragment.slice(prefix.length);\n\treturn TOKEN_RE.test(raw) ? asToken(raw) : null;\n};\n\n// ----------------------------------------------------------------------\n// Authorization-header bridge\n// ----------------------------------------------------------------------\n\n/**\n * Parse a raw `Authorization` header value into the bearer token. The\n * dev-wallet adapter copies the token from `url.hash` into the\n * `Authorization: Bearer <token>` header on every request — this\n * helper is the symmetric inverse.\n *\n * Returns `null` on missing / malformed header so the caller can map\n * to the structured `unauthorized` request error.\n */\nexport const parseBearerHeader = (header: string | undefined): string | null => {\n\tif (header === undefined) return null;\n\tif (!header.startsWith(WALLET_BEARER_PREFIX)) return null;\n\tconst raw = header.slice(WALLET_BEARER_PREFIX.length);\n\t// Don't TOKEN_RE-test here — the constant-time compare against the\n\t// expected token covers shape mismatch (length-difference shortcut\n\t// is acceptable since token length is public knowledge).\n\treturn raw.length === WALLET_TOKEN_HEX_LENGTH ? raw : null;\n};\n\n// ----------------------------------------------------------------------\n// Constant-time compare\n// ----------------------------------------------------------------------\n\n/**\n * Constant-time bearer-token compare. The length-mismatch shortcut is\n * intentional — token length is public knowledge (always 32 hex\n * chars), so leaking \"wrong length\" is not a credential leak. The\n * shortcut also prevents `timingSafeEqual` from throwing on mismatched\n * buffer sizes.\n *\n * Invariant (15-wallet.md \"Token comparison MUST be constant-time\"):\n * NEVER `===` two tokens. `===` on strings short-circuits at the first\n * mismatching byte, leaking the prefix byte-by-byte via response-time\n * measurement to a remote attacker.\n */\nexport const safeBearerEquals = (a: string, b: PairingToken | string): boolean => {\n\tif (a.length !== b.length) return false;\n\t// `a` is attacker-controlled — a multi-byte UTF-8 codepoint in `a`\n\t// would inflate `ab.length` past `bb.length` even though\n\t// `a.length === b.length` passed (string length counts UTF-16 code\n\t// units, byte length counts UTF-8 bytes). The second length guard\n\t// stops `timingSafeEqual` from throwing in that case (its contract\n\t// requires equal-length buffers) and keeps the function total. For\n\t// the canonical case (`b` is a 32-hex `PairingToken`) the guard is\n\t// redundant; for the defensive case it prevents a malformed-input\n\t// throw from leaking up the dispatcher path.\n\tconst ab = Buffer.from(a, 'utf8');\n\tconst bb = Buffer.from(b, 'utf8');\n\tif (ab.length !== bb.length) return false;\n\treturn timingSafeEqual(ab, bb);\n};\n\n// ----------------------------------------------------------------------\n// Logging hygiene\n// ----------------------------------------------------------------------\n\nconst TOKEN_REDACTION_RULE: RedactionRule = {\n\tkind: 'pattern',\n\tpattern: /([#?&]token=)[A-Za-z0-9]+/g,\n\treplacement: '$1<redacted>',\n};\n\n/**\n * Redact the token fragment from any URL-shaped string for logging /\n * TUI rendering. Defense-in-depth — the engine's log sink should never\n * see the unredacted pair URL anyway, but this exists for callers that\n * accidentally pass `pairUrl` straight into a log line.\n *\n * Distilled-doc opportunity (15-wallet.md): the legacy redactor only\n * covered `#token=`. This regex covers BOTH the fragment form and a\n * hypothetical query form so a future config change doesn't silently\n * leak.\n */\nexport const redactToken = (s: string): string => redactText(s, [TOKEN_REDACTION_RULE]);\n"],"mappings":";;;;;;;;;;;;;;AAkDA,MAAM,WAAW;AAEjB,MAAM,WAAW,MAA4B;;AAO7C,MAAa,kBACZ,OAAO,WAAW,QAAQ,YAAY,GAAG,CAAC,SAAS,MAAM,CAAC,CAAC;;;;;;;AAY5D,MAAa,aAAa,cAA8BA,KAAS,WAAW,UAAU,QAAQ;;;;;;;;;AAU9F,MAAa,uBACZ,SAEA,OAAO,IAAI,aAAa;CAEvB,MAAM,WAAW,OAAO,OAAO,WAAW;EACzC,KAAK,YAAY;AAChB,OAAI;AACH,WAAO,MAAM,SAAS,MAAM,OAAO;YAC3B,KAAK;AACb,QAAK,KAA+B,SAAS,SAAU,QAAO;AAC9D,UAAM;;;EAGR,QAAQ,UACP,gBAAgB;GACf,OAAO;GACP,SAAS,uCAAuC;GAChD,MAAM;GACN;GACA,CAAC;EACH,CAAC;AAEF,KAAI,aAAa,MAAM;EACtB,MAAM,UAAU,SAAS,MAAM;AAC/B,MAAI,SAAS,KAAK,QAAQ,CACzB,QAAO,QAAQ,QAAQ;AAGxB,SAAO,OAAO,WAAW,6CAA6C,CAAC,KACtE,OAAO,aAAa,GAClB,YAAY,YAAY,MACzB,CAAC,CACF;;CAQF,MAAM,QAAQ,OAAO,WAAW;AAEhC,QAAO,gBAAgB,MADT,IAAI,aAAa,CAAC,OAAO,MACL,EAAE,EAAE,MAAM,KAAO,CAAC,CAAC,KACpD,OAAO,UAAU,UAChB,gBAAgB;EACf,OAAO;EACP,SAAS,qCAAqC;EAC9C,MAAM;EACN;EACA,CAAC,CACF,CACD;AAED,QAAO;EACN;;;;;;;;AAaH,MAAa,kBAAkB,WAAmB,UACjD,GAAG,UAAU,IAAI,0BAA0B,GAAG;;;;;;;;;;AA8B/C,MAAa,qBAAqB,WAA8C;AAC/E,KAAI,WAAW,KAAA,EAAW,QAAO;AACjC,KAAI,CAAC,OAAO,WAAA,UAAgC,CAAE,QAAO;CACrD,MAAM,MAAM,OAAO,MAAM,qBAAqB,OAAO;AAIrD,QAAO,IAAI,WAAA,KAAqC,MAAM;;;;;;;;;;;;;;AAmBvD,MAAa,oBAAoB,GAAW,MAAsC;AACjF,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;CAUlC,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;CACjC,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;AACjC,KAAI,GAAG,WAAW,GAAG,OAAQ,QAAO;AACpC,QAAO,gBAAgB,IAAI,GAAG;;AAO/B,MAAM,uBAAsC;CAC3C,MAAM;CACN,SAAS;CACT,aAAa;CACb;;;;;;;;;;;;AAaD,MAAa,eAAe,MAAsB,WAAW,GAAG,CAAC,qBAAqB,CAAC"}
|
|
@@ -1,27 +1,7 @@
|
|
|
1
|
+
import "../../contracts/wallet-protocol.mjs";
|
|
1
2
|
import { Schema } from "effect";
|
|
2
3
|
//#region src/plugins/wallet/protocol.ts
|
|
3
4
|
/**
|
|
4
|
-
* Canonical path constants under the `/api/v1/devstack/*` prefix.
|
|
5
|
-
*
|
|
6
|
-
* Distilled-doc note (15-wallet.md "Fork-control routes declared but
|
|
7
|
-
* unimplemented"): the legacy server declared four `FORK_*` path
|
|
8
|
-
* constants whose handlers never landed. Per "no compat for never-
|
|
9
|
-
* cases", we drop them from the wire protocol entirely — when the
|
|
10
|
-
* fork-control surface is wired, those routes will be added (and the
|
|
11
|
-
* dev-wallet adapter shipped together). No half-done stubs.
|
|
12
|
-
*/
|
|
13
|
-
const WalletHttpPath = {
|
|
14
|
-
HEALTH: "/api/v1/devstack/health",
|
|
15
|
-
ACCOUNTS: "/api/v1/devstack/accounts",
|
|
16
|
-
SIGN_TRANSACTION: "/api/v1/devstack/sign-transaction",
|
|
17
|
-
SIGN_PERSONAL_MESSAGE: "/api/v1/devstack/sign-personal-message",
|
|
18
|
-
EXECUTE: "/api/v1/devstack/execute"
|
|
19
|
-
};
|
|
20
|
-
/** Prefix gate: ANY path under this prefix is treated as protocol traffic
|
|
21
|
-
* (and subject to mandatory Origin + bearer); anything else is a flat
|
|
22
|
-
* 404. */
|
|
23
|
-
const WALLET_PROTOCOL_PREFIX = "/api/v1/devstack/";
|
|
24
|
-
/**
|
|
25
5
|
* Sui address — `0x` + 64 hex chars. Schema-validated so a typo or
|
|
26
6
|
* truncated address surfaces as a structured `body-invalid` request
|
|
27
7
|
* error rather than a confusing `address-not-found` (no account bound
|
|
@@ -40,9 +20,9 @@ const SignatureSchemeSchema = Schema.Union([
|
|
|
40
20
|
Schema.Literal("secp256r1")
|
|
41
21
|
]);
|
|
42
22
|
/** Account-source discriminator. `'impersonate'` accounts cannot
|
|
43
|
-
* satisfy `signTransaction` / `signPersonalMessage` —
|
|
44
|
-
*
|
|
45
|
-
*
|
|
23
|
+
* satisfy `signTransaction` / `signPersonalMessage` — fork-admin
|
|
24
|
+
* surfaces (not part of this protocol today) are the only sensible
|
|
25
|
+
* consumers. */
|
|
46
26
|
const AccountSourceSchema = Schema.Union([Schema.Literal("real"), Schema.Literal("impersonate")]);
|
|
47
27
|
Schema.Struct({ ok: Schema.Literal(true) });
|
|
48
28
|
const AccountSummarySchema = Schema.Struct({
|
|
@@ -67,30 +47,11 @@ Schema.Struct({
|
|
|
67
47
|
bytes: Base64Schema,
|
|
68
48
|
signature: Schema.String
|
|
69
49
|
});
|
|
70
|
-
/** Execute request — `bytes` is the BCS-serialized transaction.
|
|
71
|
-
* Impersonation accounts route through fork-admin (no signature
|
|
72
|
-
* needed); real accounts route through `signAndExecute`. */
|
|
73
|
-
const ExecuteRequestSchema = Schema.Struct({
|
|
74
|
-
address: SuiAddressSchema,
|
|
75
|
-
bytes: Base64Schema
|
|
76
|
-
});
|
|
77
|
-
Schema.Struct({
|
|
78
|
-
digest: Schema.String,
|
|
79
|
-
effects: Schema.Unknown,
|
|
80
|
-
objectChanges: Schema.Array(Schema.Unknown),
|
|
81
|
-
balanceChanges: Schema.Array(Schema.Unknown)
|
|
82
|
-
});
|
|
83
50
|
Schema.Struct({
|
|
84
51
|
error: Schema.String,
|
|
85
52
|
code: Schema.String
|
|
86
53
|
});
|
|
87
|
-
const WALLET_AUTH_HEADER = "authorization";
|
|
88
|
-
const WALLET_BEARER_PREFIX = "Bearer ";
|
|
89
|
-
/** URL-fragment key the pair-URL carries the token under
|
|
90
|
-
* (`<wallet-url>/#token=<32-hex>`). Fragments are not sent to the
|
|
91
|
-
* server, so the token never appears in access logs / referrers. */
|
|
92
|
-
const WALLET_TOKEN_FRAGMENT_KEY = "token";
|
|
93
54
|
//#endregion
|
|
94
|
-
export { AccountSourceSchema, AccountSummarySchema, Base64Schema,
|
|
55
|
+
export { AccountSourceSchema, AccountSummarySchema, Base64Schema, SignRequestSchema, SignatureSchemeSchema, SuiAddressSchema };
|
|
95
56
|
|
|
96
57
|
//# sourceMappingURL=protocol.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.mjs","names":[],"sources":["../../../src/plugins/wallet/protocol.ts"],"sourcesContent":["// Wallet plugin — wire-level protocol.\n//\n// This file is the ONE cross-boundary contract between the devstack-\n// side HTTP server (this plugin) and the browser-side adapter (the\n// `dev-wallet` package). The browser-side adapter MUST be kept in\n// lock-step with these schemas; today that's enforced by a mirror in\n// `dev-wallet/src/adapters/devstack-paths.ts` + a byte-equality test.\n//\n// Distilled-doc opportunity (15-wallet.md \"Acyclic-edge duplication\"):\n// the duplication exists because devstack peer-deps on dev-wallet (for\n// codegen output) and a reverse edge would close a workspace cycle.\n// Per the task's architecture-revision flag: the long-term fix is to\n// hoist this file into a third tiny package (e.g.\n// `@mysten-incubation/devstack-wallet-protocol`) consumed by BOTH\n// sides. See `## Architecture-doc revisions` in the report.\n//\n// Canonical envelope choice (15-wallet.md \"Asymmetric sign-response\n// field names\" + \"Dual field-name acceptance\"):\n//\n// - Sign endpoints accept `{ address, bytes }` (always `bytes`, never\n// `txBytes` or `messageBytes`).\n// - Sign endpoints respond `{ bytes, signature }` (always those two\n// names; never `txBytes` / `suiSignature`).\n//\n// This mirrors `@mysten/sui`'s `Signer.signTransaction` /\n// `signPersonalMessage` return shape exactly, eliminating the asymmetry\n// the legacy server carried. Per the memory note \"no compat for\n// never-cases\" — devstack is unreleased, no migration burden.\n//\n// Effect v4 Schema is the validator. Each request/response is a\n// Schema.Struct; handlers `Schema.decodeUnknown(...)` the body and\n// `catchTag('ParseError', ...)` into a `body-invalid` request error.\n\nimport { Schema } from 'effect';\n\n// ----------------------------------------------------------------------\n// Path constants\n// ----------------------------------------------------------------------\n\n/**\n * Canonical path constants under the `/api/v1/devstack/*` prefix.\n *\n * Distilled-doc note (15-wallet.md \"Fork-control routes declared but\n * unimplemented\"): the legacy server declared four `FORK_*` path\n * constants whose handlers never landed. Per \"no compat for never-\n * cases\", we drop them from the wire protocol entirely — when the\n * fork-control surface is wired, those routes will be added (and the\n * dev-wallet adapter shipped together). No half-done stubs.\n */\nexport const WalletHttpPath = {\n\tHEALTH: '/api/v1/devstack/health',\n\tACCOUNTS: '/api/v1/devstack/accounts',\n\tSIGN_TRANSACTION: '/api/v1/devstack/sign-transaction',\n\tSIGN_PERSONAL_MESSAGE: '/api/v1/devstack/sign-personal-message',\n\tEXECUTE: '/api/v1/devstack/execute',\n} as const;\n\nexport type WalletHttpPathValue = (typeof WalletHttpPath)[keyof typeof WalletHttpPath];\n\n/** Prefix gate: ANY path under this prefix is treated as protocol traffic\n * (and subject to mandatory Origin + bearer); anything else is a flat\n * 404. */\nexport const WALLET_PROTOCOL_PREFIX = '/api/v1/devstack/' as const;\n\n// ----------------------------------------------------------------------\n// Shared primitives\n// ----------------------------------------------------------------------\n\n/**\n * Sui address — `0x` + 64 hex chars. Schema-validated so a typo or\n * truncated address surfaces as a structured `body-invalid` request\n * error rather than a confusing `address-not-found` (no account bound\n * at the address would be the same shape if we didn't validate).\n */\nexport const SuiAddressSchema = Schema.String.check(Schema.isPattern(/^0x[0-9a-fA-F]{64}$/));\n\n/** Base64-encoded bytes — string-typed at the wire (we keep base64 over\n * the cross-boundary; the server decodes with `Uint8Array.fromBase64`\n * or equivalent before handing to the Account sign closures). */\nexport const Base64Schema = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9+/]*={0,2}$/));\n\n/** Signature scheme discriminator surfaced on `/accounts`. Mirrors the\n * `AccountValue.scheme` shape from the account plugin. */\nexport const SignatureSchemeSchema = Schema.Union([\n\tSchema.Literal('ed25519'),\n\tSchema.Literal('secp256k1'),\n\tSchema.Literal('secp256r1'),\n]);\n\n/** Account-source discriminator. `'impersonate'` accounts cannot\n * satisfy `signTransaction` / `signPersonalMessage` — only\n * `/execute` (which routes through the fork-admin surface) makes\n * sense for them. */\nexport const AccountSourceSchema = Schema.Union([\n\tSchema.Literal('real'),\n\tSchema.Literal('impersonate'),\n]);\n\n// ----------------------------------------------------------------------\n// Response envelopes (200)\n// ----------------------------------------------------------------------\n\nexport const HealthResponseSchema = Schema.Struct({\n\tok: Schema.Literal(true),\n});\nexport type HealthResponse = Schema.Schema.Type<typeof HealthResponseSchema>;\n\nexport const AccountSummarySchema = Schema.Struct({\n\tname: Schema.String,\n\taddress: SuiAddressSchema,\n\tscheme: SignatureSchemeSchema,\n\t/** Base64-encoded `publicKey`. Impersonation accounts publish a\n\t * zero-length string here — consumers branch on `source`, not on\n\t * publicKey emptiness. */\n\tpublicKey: Base64Schema,\n\tsource: AccountSourceSchema,\n});\nexport type AccountSummary = Schema.Schema.Type<typeof AccountSummarySchema>;\n\nexport const AccountsResponseSchema = Schema.Struct({\n\taccounts: Schema.Array(AccountSummarySchema),\n});\nexport type AccountsResponse = Schema.Schema.Type<typeof AccountsResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Sign endpoints — request + response\n// ----------------------------------------------------------------------\n\n/** Canonical sign request — same shape for transaction and personal-\n * message routes. `bytes` is the only payload key (no `txBytes`,\n * `message`, or `messageBytes` aliases). */\nexport const SignRequestSchema = Schema.Struct({\n\taddress: SuiAddressSchema,\n\tbytes: Base64Schema,\n});\nexport type SignRequest = Schema.Schema.Type<typeof SignRequestSchema>;\n\n/** Canonical sign response — same shape for transaction and personal-\n * message routes. Matches `@mysten/sui`'s `Signer` return shape\n * byte-for-byte. */\nexport const SignResponseSchema = Schema.Struct({\n\tbytes: Base64Schema,\n\tsignature: Schema.String,\n});\nexport type SignResponse = Schema.Schema.Type<typeof SignResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Execute endpoint — request + response\n// ----------------------------------------------------------------------\n\n/** Execute request — `bytes` is the BCS-serialized transaction.\n * Impersonation accounts route through fork-admin (no signature\n * needed); real accounts route through `signAndExecute`. */\nexport const ExecuteRequestSchema = Schema.Struct({\n\taddress: SuiAddressSchema,\n\tbytes: Base64Schema,\n});\nexport type ExecuteRequest = Schema.Schema.Type<typeof ExecuteRequestSchema>;\n\n/** Execute response — the narrow `TxResult` projection the account\n * plugin already publishes. The `effects` / `objectChanges` /\n * `balanceChanges` fields cross the wire as opaque JSON; downstream\n * consumers do their own parsing. */\nexport const ExecuteResponseSchema = Schema.Struct({\n\tdigest: Schema.String,\n\teffects: Schema.Unknown,\n\tobjectChanges: Schema.Array(Schema.Unknown),\n\tbalanceChanges: Schema.Array(Schema.Unknown),\n});\nexport type ExecuteResponse = Schema.Schema.Type<typeof ExecuteResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Error envelope\n// ----------------------------------------------------------------------\n\n/** Error response body. The HTTP status carries the broad classification\n * (400/401/403/404/500); `code` carries the narrow phase so callers\n * can branch programmatically. */\nexport const ErrorResponseSchema = Schema.Struct({\n\terror: Schema.String,\n\tcode: Schema.String,\n});\nexport type ErrorResponse = Schema.Schema.Type<typeof ErrorResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Header constants (shared so the dev-wallet adapter doesn't open-code\n// the same strings).\n// ----------------------------------------------------------------------\n\nexport const WALLET_AUTH_HEADER = 'authorization' as const;\nexport const WALLET_BEARER_PREFIX = 'Bearer ' as const;\n\n/** URL-fragment key the pair-URL carries the token under\n * (`<wallet-url>/#token=<32-hex>`). Fragments are not sent to the\n * server, so the token never appears in access logs / referrers. */\nexport const WALLET_TOKEN_FRAGMENT_KEY = 'token' as const;\n\n/** Constant carried token byte length (16 random bytes → 32 hex chars).\n * The on-disk token file is rejected + re-minted if it doesn't match. */\nexport const WALLET_TOKEN_HEX_LENGTH = 32 as const;\n"],"mappings":";;;;;;;;;;;;AAiDA,MAAa,iBAAiB;CAC7B,QAAQ;CACR,UAAU;CACV,kBAAkB;CAClB,uBAAuB;CACvB,SAAS;CACT;;;;AAOD,MAAa,yBAAyB;;;;;;;AAYtC,MAAa,mBAAmB,OAAO,OAAO,MAAM,OAAO,UAAU,sBAAsB,CAAC;;;;AAK5F,MAAa,eAAe,OAAO,OAAO,MAAM,OAAO,UAAU,yBAAyB,CAAC;;;AAI3F,MAAa,wBAAwB,OAAO,MAAM;CACjD,OAAO,QAAQ,UAAU;CACzB,OAAO,QAAQ,YAAY;CAC3B,OAAO,QAAQ,YAAY;CAC3B,CAAC;;;;;AAMF,MAAa,sBAAsB,OAAO,MAAM,CAC/C,OAAO,QAAQ,OAAO,EACtB,OAAO,QAAQ,cAAc,CAC7B,CAAC;AAMkC,OAAO,OAAO,EACjD,IAAI,OAAO,QAAQ,KAAK,EACxB,CAAC;AAGF,MAAa,uBAAuB,OAAO,OAAO;CACjD,MAAM,OAAO;CACb,SAAS;CACT,QAAQ;;;;CAIR,WAAW;CACX,QAAQ;CACR,CAAC;AAGoC,OAAO,OAAO,EACnD,UAAU,OAAO,MAAM,qBAAqB,EAC5C,CAAC;;;;AAUF,MAAa,oBAAoB,OAAO,OAAO;CAC9C,SAAS;CACT,OAAO;CACP,CAAC;AAMgC,OAAO,OAAO;CAC/C,OAAO;CACP,WAAW,OAAO;CAClB,CAAC;;;;AAUF,MAAa,uBAAuB,OAAO,OAAO;CACjD,SAAS;CACT,OAAO;CACP,CAAC;AAOmC,OAAO,OAAO;CAClD,QAAQ,OAAO;CACf,SAAS,OAAO;CAChB,eAAe,OAAO,MAAM,OAAO,QAAQ;CAC3C,gBAAgB,OAAO,MAAM,OAAO,QAAQ;CAC5C,CAAC;AAUiC,OAAO,OAAO;CAChD,OAAO,OAAO;CACd,MAAM,OAAO;CACb,CAAC;AAQF,MAAa,qBAAqB;AAClC,MAAa,uBAAuB;;;;AAKpC,MAAa,4BAA4B"}
|
|
1
|
+
{"version":3,"file":"protocol.mjs","names":[],"sources":["../../../src/plugins/wallet/protocol.ts"],"sourcesContent":["// Wallet plugin — wire-level protocol.\n//\n// This file is the ONE cross-boundary contract between the devstack-\n// side HTTP server (this plugin) and the browser-side adapter (the\n// `dev-wallet` package). The browser-side adapter MUST be kept in\n// lock-step with these schemas; today that's enforced by a mirror in\n// `dev-wallet/src/adapters/devstack-paths.ts` + a byte-equality test.\n//\n// Distilled-doc opportunity (15-wallet.md \"Acyclic-edge duplication\"):\n// the duplication exists because devstack peer-deps on dev-wallet (for\n// codegen output) and a reverse edge would close a workspace cycle.\n// Per the task's architecture-revision flag: the long-term fix is to\n// hoist this file into a third tiny package (e.g.\n// `@mysten-incubation/devstack-wallet-protocol`) consumed by BOTH\n// sides. See `## Architecture-doc revisions` in the report.\n//\n// Canonical envelope choice (15-wallet.md \"Asymmetric sign-response\n// field names\" + \"Dual field-name acceptance\"):\n//\n// - Sign endpoints accept `{ address, bytes }` (always `bytes`, never\n// `txBytes` or `messageBytes`).\n// - Sign endpoints respond `{ bytes, signature }` (always those two\n// names; never `txBytes` / `suiSignature`).\n//\n// This mirrors `@mysten/sui`'s `Signer.signTransaction` /\n// `signPersonalMessage` return shape exactly, eliminating the asymmetry\n// the legacy server carried. Per the memory note \"no compat for\n// never-cases\" — devstack is unreleased, no migration burden.\n//\n// Effect v4 Schema is the validator. Each request/response is a\n// Schema.Struct; handlers `Schema.decodeUnknown(...)` the body and\n// `catchTag('ParseError', ...)` into a `body-invalid` request error.\n\nimport { Schema } from 'effect';\n\n// Pure wire constants live in the name-blind contract so L5 build\n// integrations can consume them without importing this L2 plugin\n// module; re-exported here so plugin-internal callers keep their\n// current import sites.\nexport {\n\tWalletHttpPath,\n\tWALLET_PROTOCOL_PREFIX,\n\tWALLET_AUTH_HEADER,\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n\ttype WalletHttpPathValue,\n} from '../../contracts/wallet-protocol.ts';\n\n// ----------------------------------------------------------------------\n// Shared primitives\n// ----------------------------------------------------------------------\n\n/**\n * Sui address — `0x` + 64 hex chars. Schema-validated so a typo or\n * truncated address surfaces as a structured `body-invalid` request\n * error rather than a confusing `address-not-found` (no account bound\n * at the address would be the same shape if we didn't validate).\n */\nexport const SuiAddressSchema = Schema.String.check(Schema.isPattern(/^0x[0-9a-fA-F]{64}$/));\n\n/** Base64-encoded bytes — string-typed at the wire (we keep base64 over\n * the cross-boundary; the server decodes with `Uint8Array.fromBase64`\n * or equivalent before handing to the Account sign closures). */\nexport const Base64Schema = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9+/]*={0,2}$/));\n\n/** Signature scheme discriminator surfaced on `/accounts`. Mirrors the\n * `AccountValue.scheme` shape from the account plugin. */\nexport const SignatureSchemeSchema = Schema.Union([\n\tSchema.Literal('ed25519'),\n\tSchema.Literal('secp256k1'),\n\tSchema.Literal('secp256r1'),\n]);\n\n/** Account-source discriminator. `'impersonate'` accounts cannot\n * satisfy `signTransaction` / `signPersonalMessage` — fork-admin\n * surfaces (not part of this protocol today) are the only sensible\n * consumers. */\nexport const AccountSourceSchema = Schema.Union([\n\tSchema.Literal('real'),\n\tSchema.Literal('impersonate'),\n]);\n\n// ----------------------------------------------------------------------\n// Response envelopes (200)\n// ----------------------------------------------------------------------\n\nexport const HealthResponseSchema = Schema.Struct({\n\tok: Schema.Literal(true),\n});\nexport type HealthResponse = Schema.Schema.Type<typeof HealthResponseSchema>;\n\nexport const AccountSummarySchema = Schema.Struct({\n\tname: Schema.String,\n\taddress: SuiAddressSchema,\n\tscheme: SignatureSchemeSchema,\n\t/** Base64-encoded `publicKey`. Impersonation accounts publish a\n\t * zero-length string here — consumers branch on `source`, not on\n\t * publicKey emptiness. */\n\tpublicKey: Base64Schema,\n\tsource: AccountSourceSchema,\n});\nexport type AccountSummary = Schema.Schema.Type<typeof AccountSummarySchema>;\n\nexport const AccountsResponseSchema = Schema.Struct({\n\taccounts: Schema.Array(AccountSummarySchema),\n});\nexport type AccountsResponse = Schema.Schema.Type<typeof AccountsResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Sign endpoints — request + response\n// ----------------------------------------------------------------------\n\n/** Canonical sign request — same shape for transaction and personal-\n * message routes. `bytes` is the only payload key (no `txBytes`,\n * `message`, or `messageBytes` aliases). */\nexport const SignRequestSchema = Schema.Struct({\n\taddress: SuiAddressSchema,\n\tbytes: Base64Schema,\n});\nexport type SignRequest = Schema.Schema.Type<typeof SignRequestSchema>;\n\n/** Canonical sign response — same shape for transaction and personal-\n * message routes. Matches `@mysten/sui`'s `Signer` return shape\n * byte-for-byte. */\nexport const SignResponseSchema = Schema.Struct({\n\tbytes: Base64Schema,\n\tsignature: Schema.String,\n});\nexport type SignResponse = Schema.Schema.Type<typeof SignResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Error envelope\n// ----------------------------------------------------------------------\n\n/** Error response body. The HTTP status carries the broad classification\n * (400/401/403/404/500); `code` carries the narrow phase so callers\n * can branch programmatically. */\nexport const ErrorResponseSchema = Schema.Struct({\n\terror: Schema.String,\n\tcode: Schema.String,\n});\nexport type ErrorResponse = Schema.Schema.Type<typeof ErrorResponseSchema>;\n\n// Header / token constants are re-exported above from\n// `../../contracts/wallet-protocol.ts`.\n"],"mappings":";;;;;;;;;AA2DA,MAAa,mBAAmB,OAAO,OAAO,MAAM,OAAO,UAAU,sBAAsB,CAAC;;;;AAK5F,MAAa,eAAe,OAAO,OAAO,MAAM,OAAO,UAAU,yBAAyB,CAAC;;;AAI3F,MAAa,wBAAwB,OAAO,MAAM;CACjD,OAAO,QAAQ,UAAU;CACzB,OAAO,QAAQ,YAAY;CAC3B,OAAO,QAAQ,YAAY;CAC3B,CAAC;;;;;AAMF,MAAa,sBAAsB,OAAO,MAAM,CAC/C,OAAO,QAAQ,OAAO,EACtB,OAAO,QAAQ,cAAc,CAC7B,CAAC;AAMkC,OAAO,OAAO,EACjD,IAAI,OAAO,QAAQ,KAAK,EACxB,CAAC;AAGF,MAAa,uBAAuB,OAAO,OAAO;CACjD,MAAM,OAAO;CACb,SAAS;CACT,QAAQ;;;;CAIR,WAAW;CACX,QAAQ;CACR,CAAC;AAGoC,OAAO,OAAO,EACnD,UAAU,OAAO,MAAM,qBAAqB,EAC5C,CAAC;;;;AAUF,MAAa,oBAAoB,OAAO,OAAO;CAC9C,SAAS;CACT,OAAO;CACP,CAAC;AAMgC,OAAO,OAAO;CAC/C,OAAO;CACP,WAAW,OAAO;CAClB,CAAC;AAUiC,OAAO,OAAO;CAChD,OAAO,OAAO;CACd,MAAM,OAAO;CACb,CAAC"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
/** Canonical endpoint name. The router orchestrator surfaces this in
|
|
3
|
-
* the manifest under `endpoints['wallet-app']`; downstream consumers
|
|
4
|
-
* (codegen, TUI, doctor) read it by this key.
|
|
5
|
-
*
|
|
6
|
-
* Stable across rewrite + legacy so existing consumers don't break. */
|
|
7
|
-
const WALLET_ENDPOINT_NAME = "wallet-app";
|
|
1
|
+
import { WALLET_ENDPOINT_NAME } from "../../contracts/wallet-protocol.mjs";
|
|
8
2
|
const WALLET_ENTRYPOINT_PORT = 6173;
|
|
9
3
|
const WALLET_ENTRYPOINTS = [{
|
|
10
4
|
name: WALLET_ENDPOINT_NAME,
|
|
@@ -27,6 +21,6 @@ const makeWalletRoutable = (parts) => ({
|
|
|
27
21
|
wireProtocol: "http"
|
|
28
22
|
});
|
|
29
23
|
//#endregion
|
|
30
|
-
export {
|
|
24
|
+
export { WALLET_ENTRYPOINTS, WALLET_ENTRYPOINT_PORT, makeWalletRoutable };
|
|
31
25
|
|
|
32
26
|
//# sourceMappingURL=routable.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routable.mjs","names":[],"sources":["../../../src/plugins/wallet/routable.ts"],"sourcesContent":["// Wallet plugin — Routable contribution.\n//\n// The wallet's HTTP server is a HOST PROCESS (not a docker container)\n// listening on a loopback port the substrate's port broker hands us.\n// The router (Traefik) fronts the loopback port under a stack-scoped\n// hostname like `wallet.<app>.localhost:<router-port>`.\n//\n// This contribution is what tells the router about the upstream. The\n// router orchestrator reads the decl, mints the stack-scoped hostname,\n// and writes the file-provider YAML without ever naming the wallet\n// plugin.\n//\n// The wallet always emits this decl. The router is the standard app\n// and wallet entrypoint, while the loopback URL remains an internal\n// fallback for tests and direct host tooling.\n\nimport type { EntrypointDecl, RoutableDecl } from '../../contracts/routable.ts';\n\n//
|
|
1
|
+
{"version":3,"file":"routable.mjs","names":[],"sources":["../../../src/plugins/wallet/routable.ts"],"sourcesContent":["// Wallet plugin — Routable contribution.\n//\n// The wallet's HTTP server is a HOST PROCESS (not a docker container)\n// listening on a loopback port the substrate's port broker hands us.\n// The router (Traefik) fronts the loopback port under a stack-scoped\n// hostname like `wallet.<app>.localhost:<router-port>`.\n//\n// This contribution is what tells the router about the upstream. The\n// router orchestrator reads the decl, mints the stack-scoped hostname,\n// and writes the file-provider YAML without ever naming the wallet\n// plugin.\n//\n// The wallet always emits this decl. The router is the standard app\n// and wallet entrypoint, while the loopback URL remains an internal\n// fallback for tests and direct host tooling.\n\nimport type { EntrypointDecl, RoutableDecl } from '../../contracts/routable.ts';\n\n// The routed-endpoint identity constants live in the name-blind\n// contract so L5 build integrations can consume them without importing\n// this L2 plugin module; re-exported here so plugin-internal callers\n// (and the conventional-routes alias table) keep one source of truth.\nexport {\n\tWALLET_ENDPOINT_NAME,\n\tWALLET_ENDPOINT_KEY,\n} from '../../contracts/wallet-protocol.ts';\n\nimport { WALLET_ENDPOINT_NAME } from '../../contracts/wallet-protocol.ts';\n\nexport const WALLET_ROUTE_ROLE = 'api' as const;\nexport const WALLET_ENTRYPOINT_PORT = 6173;\n\nexport const WALLET_ENTRYPOINTS: ReadonlyArray<EntrypointDecl> = [\n\t{ name: WALLET_ENDPOINT_NAME, port: WALLET_ENTRYPOINT_PORT, protocol: 'http' },\n];\n\n// ----------------------------------------------------------------------\n// Decl\n// ----------------------------------------------------------------------\n\n/** Construct the Routable decl for the stack-scoped wallet endpoint. */\nexport const makeWalletRoutable = (parts: {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly port: number;\n}): RoutableDecl => ({\n\tkind: 'routable',\n\tendpointName: WALLET_ENDPOINT_NAME,\n\tdispatchId: {\n\t\t// Convention: `<plugin>.<app>.<stack>` keeps dispatch-file\n\t\t// listings readable; the router still hashes the full\n\t\t// `(app, stack, serviceKey, role)` tuple for uniqueness.\n\t\tserviceKey: `wallet.${parts.app}.${parts.stack}`,\n\t\trole: WALLET_ROUTE_ROLE,\n\t},\n\tupstream: { type: 'host-loopback', port: parts.port },\n\tcors: true,\n\twireProtocol: 'http',\n});\n"],"mappings":";AA8BA,MAAa,yBAAyB;AAEtC,MAAa,qBAAoD,CAChE;CAAE,MAAM;CAAsB,MAAM;CAAwB,UAAU;CAAQ,CAC9E;;AAOD,MAAa,sBAAsB,WAId;CACpB,MAAM;CACN,cAAc;CACd,YAAY;EAIX,YAAY,UAAU,MAAM,IAAI,GAAG,MAAM;EACzC,MAAA;EACA;CACD,UAAU;EAAE,MAAM;EAAiB,MAAM,MAAM;EAAM;CACrD,MAAM;CACN,cAAc;CACd"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { decodeJsonText } from "../../substrate/runtime/runtime-decode.mjs";
|
|
2
1
|
import { SpanAttr } from "../../substrate/runtime/observability/spans.mjs";
|
|
2
|
+
import { decodeJsonText } from "../../substrate/runtime/runtime-decode.mjs";
|
|
3
|
+
import { WALLET_AUTH_HEADER, WalletHttpPath } from "../../contracts/wallet-protocol.mjs";
|
|
4
|
+
import { formatUnknownError } from "../../substrate/runtime/format-unknown-error.mjs";
|
|
3
5
|
import { walletBootError, walletRequestError } from "./errors.mjs";
|
|
4
|
-
import {
|
|
6
|
+
import { WalletSpans } from "./spans.mjs";
|
|
7
|
+
import { SignRequestSchema } from "./protocol.mjs";
|
|
5
8
|
import { parseBearerHeader, safeBearerEquals } from "./pairing.mjs";
|
|
6
9
|
import { checkOrigin, corsHeadersFor } from "./origin-policy.mjs";
|
|
7
10
|
import { listenScopedHttpServer } from "../../substrate/runtime/scoped-http-server.mjs";
|
|
8
|
-
import { Effect } from "effect";
|
|
11
|
+
import { Cause, Effect } from "effect";
|
|
9
12
|
import { randomUUID } from "node:crypto";
|
|
10
13
|
//#region src/plugins/wallet/server.ts
|
|
11
14
|
/** Body cap — 64 KiB. Above the largest reasonable sign-tx payload,
|
|
@@ -53,7 +56,7 @@ const startHttpServer = (config) => Effect.gen(function* () {
|
|
|
53
56
|
listener: makeRequestListener(config, runDispatch),
|
|
54
57
|
onListenError: (cause) => walletBootError({
|
|
55
58
|
phase: "listen",
|
|
56
|
-
message: `wallet HTTP server listen failed on ${config.bindAddress}:${config.port} — ` + (cause
|
|
59
|
+
message: `wallet HTTP server listen failed on ${config.bindAddress}:${config.port} — ` + formatUnknownError(cause),
|
|
57
60
|
hint: "check that the port broker did not hand out a busy port; a sibling devstack on the same address would also explain this.",
|
|
58
61
|
cause
|
|
59
62
|
})
|
|
@@ -107,15 +110,20 @@ const makeRequestListener = (config, runDispatch) => (req, res) => {
|
|
|
107
110
|
req.on("end", () => {
|
|
108
111
|
if (overflowed) return;
|
|
109
112
|
const body = Buffer.concat(chunks).toString("utf8");
|
|
110
|
-
|
|
113
|
+
const walletReq = {
|
|
111
114
|
method: req.method ?? "GET",
|
|
112
115
|
url: req.url ?? "/",
|
|
113
116
|
headers: normalizeHeaders(req.headers),
|
|
114
117
|
body
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
};
|
|
119
|
+
runDispatch(dispatch(config, walletReq).pipe(Effect.matchCauseEffect({
|
|
120
|
+
onFailure: (cause) => Effect.logError("wallet dispatcher defect").pipe(Effect.annotateLogs({
|
|
121
|
+
[WalletSpans.requestMethod]: walletReq.method,
|
|
122
|
+
[WalletSpans.requestUrl]: walletReq.url,
|
|
123
|
+
cause: Cause.pretty(cause)
|
|
124
|
+
}), Effect.flatMap(() => Effect.sync(() => {
|
|
125
|
+
writeServerError(res);
|
|
126
|
+
}))),
|
|
119
127
|
onSuccess: (resp) => Effect.sync(() => writeResponse(res, resp))
|
|
120
128
|
})));
|
|
121
129
|
});
|
|
@@ -132,7 +140,11 @@ const writeOverflow = (res) => {
|
|
|
132
140
|
res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
133
141
|
res.end("payload too large");
|
|
134
142
|
};
|
|
135
|
-
|
|
143
|
+
/** Write an opaque 500 — no token, no internal state leak. The
|
|
144
|
+
* caller is responsible for logging the underlying cause (see the
|
|
145
|
+
* `Effect.logError('wallet dispatcher defect')` in `dispatch`'s
|
|
146
|
+
* `matchCauseEffect` onFailure branch). */
|
|
147
|
+
const writeServerError = (res) => {
|
|
136
148
|
if (res.writableEnded) return;
|
|
137
149
|
res.statusCode = 500;
|
|
138
150
|
res.setHeader("content-type", "application/json; charset=utf-8");
|
|
@@ -174,10 +186,12 @@ const text = (status, body, extraHeaders = {}) => ({
|
|
|
174
186
|
* are projected to JSON envelopes via `errorEnvelope` below.
|
|
175
187
|
*
|
|
176
188
|
* The dispatch order matters:
|
|
177
|
-
* 1.
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
189
|
+
* 1. Path-prefix gate — anything not under `/api/v1/devstack/` is
|
|
190
|
+
* a flat 404 (text/plain). PROTECTS the auth gate (and the CORS
|
|
191
|
+
* preflight) from being visible on arbitrary URLs.
|
|
192
|
+
* 2. OPTIONS preflight (returns 204 + CORS) — no auth required, but
|
|
193
|
+
* scoped to the protocol prefix by step 1 so an allowed origin
|
|
194
|
+
* cannot extract CORS headers for unrelated paths.
|
|
181
195
|
* 3. Origin check (must be in policy.allowed; missing → 403).
|
|
182
196
|
* 4. Bearer check (must constant-time-equal `config.token`).
|
|
183
197
|
* 5. Method+path route to handler.
|
|
@@ -185,10 +199,12 @@ const text = (status, body, extraHeaders = {}) => ({
|
|
|
185
199
|
const dispatch = (config, req) => Effect.gen(function* () {
|
|
186
200
|
const requestId = randomUUID();
|
|
187
201
|
yield* Effect.annotateCurrentSpan({
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
202
|
+
[WalletSpans.requestId]: requestId,
|
|
203
|
+
[WalletSpans.requestMethod]: req.method,
|
|
204
|
+
[WalletSpans.requestUrl]: req.url
|
|
191
205
|
});
|
|
206
|
+
const path = req.url.split("?")[0] ?? "";
|
|
207
|
+
if (!path.startsWith("/api/v1/devstack/")) return text(404, "not found");
|
|
192
208
|
if (req.method === "OPTIONS") {
|
|
193
209
|
const origin = req.headers["origin"];
|
|
194
210
|
if (origin !== void 0 && config.policy.allowed.has(origin)) return {
|
|
@@ -198,8 +214,6 @@ const dispatch = (config, req) => Effect.gen(function* () {
|
|
|
198
214
|
};
|
|
199
215
|
return text(403, "forbidden origin");
|
|
200
216
|
}
|
|
201
|
-
const path = req.url.split("?")[0] ?? "";
|
|
202
|
-
if (!path.startsWith("/api/v1/devstack/")) return text(404, "not found");
|
|
203
217
|
const originResult = checkOrigin(config.policy, req.headers["origin"]);
|
|
204
218
|
if (originResult === "missing") {
|
|
205
219
|
yield* Effect.logWarning("wallet origin missing").pipe(Effect.annotateLogs({
|
|
@@ -212,7 +226,7 @@ const dispatch = (config, req) => Effect.gen(function* () {
|
|
|
212
226
|
if (originResult === "forbidden") {
|
|
213
227
|
yield* Effect.logWarning("wallet origin forbidden").pipe(Effect.annotateLogs({
|
|
214
228
|
[SpanAttr.requestId]: requestId,
|
|
215
|
-
[
|
|
229
|
+
[WalletSpans.origin]: req.headers.origin ?? "(missing)",
|
|
216
230
|
[SpanAttr.httpMethod]: req.method,
|
|
217
231
|
[SpanAttr.httpPath]: path
|
|
218
232
|
}));
|
|
@@ -221,11 +235,11 @@ const dispatch = (config, req) => Effect.gen(function* () {
|
|
|
221
235
|
const origin = req.headers["origin"];
|
|
222
236
|
const bearer = parseBearerHeader(req.headers[WALLET_AUTH_HEADER]);
|
|
223
237
|
const bearerValid = bearer !== null && safeBearerEquals(bearer, config.token);
|
|
224
|
-
yield* Effect.annotateCurrentSpan({ [
|
|
238
|
+
yield* Effect.annotateCurrentSpan({ [WalletSpans.bearerValid]: bearerValid });
|
|
225
239
|
if (!bearerValid) {
|
|
226
240
|
yield* Effect.logWarning("wallet bearer check failed").pipe(Effect.annotateLogs({
|
|
227
241
|
[SpanAttr.requestId]: requestId,
|
|
228
|
-
[
|
|
242
|
+
[WalletSpans.bearerValid]: bearerValid,
|
|
229
243
|
[SpanAttr.httpMethod]: req.method,
|
|
230
244
|
[SpanAttr.httpPath]: path
|
|
231
245
|
}));
|
|
@@ -243,7 +257,6 @@ const routeRequest = (config, req, path, corsHdr) => {
|
|
|
243
257
|
if (req.method === "GET" && path === WalletHttpPath.ACCOUNTS) return handleAccounts(config, corsHdr);
|
|
244
258
|
if (req.method === "POST" && path === WalletHttpPath.SIGN_TRANSACTION) return handleSign(config, req, "transaction", corsHdr);
|
|
245
259
|
if (req.method === "POST" && path === WalletHttpPath.SIGN_PERSONAL_MESSAGE) return handleSign(config, req, "personal-message", corsHdr);
|
|
246
|
-
if (req.method === "POST" && path === WalletHttpPath.EXECUTE) return handleExecute(config, req, corsHdr);
|
|
247
260
|
return Effect.fail(walletRequestError({
|
|
248
261
|
phase: "route-not-found",
|
|
249
262
|
httpStatus: 404,
|
|
@@ -260,11 +273,6 @@ const handleAccounts = (config, corsHdr) => Effect.sync(() => {
|
|
|
260
273
|
})) }, corsHdr);
|
|
261
274
|
});
|
|
262
275
|
const decodeJsonBody = (schema, body) => Effect.gen(function* () {
|
|
263
|
-
if (body.length > 65536) return yield* Effect.fail(walletRequestError({
|
|
264
|
-
phase: "body-invalid",
|
|
265
|
-
httpStatus: 400,
|
|
266
|
-
message: `body exceeds ${MAX_BODY_BYTES}-byte cap`
|
|
267
|
-
}));
|
|
268
276
|
return yield* decodeJsonText(schema, body, {
|
|
269
277
|
source: "wallet request body",
|
|
270
278
|
mkError: (issue) => walletRequestError({
|
|
@@ -291,22 +299,6 @@ const handleSign = (config, req, kind, corsHdr) => Effect.gen(function* () {
|
|
|
291
299
|
cause
|
|
292
300
|
}))), corsHdr);
|
|
293
301
|
});
|
|
294
|
-
const handleExecute = (config, req, corsHdr) => Effect.gen(function* () {
|
|
295
|
-
const body = yield* decodeJsonBody(ExecuteRequestSchema, req.body);
|
|
296
|
-
const account = config.accountsByAddress.get(body.address);
|
|
297
|
-
if (account === void 0) return yield* Effect.fail(walletRequestError({
|
|
298
|
-
phase: "address-not-found",
|
|
299
|
-
httpStatus: 404,
|
|
300
|
-
message: `no account for address '${body.address}'`
|
|
301
|
-
}));
|
|
302
|
-
const bytes = Buffer.from(body.bytes, "base64");
|
|
303
|
-
return json(200, yield* account.signAndExecute(bytes).pipe(Effect.mapError((cause) => walletRequestError({
|
|
304
|
-
phase: "sign-route-failed",
|
|
305
|
-
httpStatus: 500,
|
|
306
|
-
message: "signAndExecute failed",
|
|
307
|
-
cause
|
|
308
|
-
}))), corsHdr);
|
|
309
|
-
});
|
|
310
302
|
const errorEnvelope = (err, corsHdr) => json(err.httpStatus, {
|
|
311
303
|
error: err.message,
|
|
312
304
|
code: err.phase
|