@mysten-incubation/devstack 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +189 -0
- package/README.md +94 -0
- package/dist/_virtual/_rolldown/runtime.mjs +13 -0
- package/dist/api/define-capabilities.d.mts +25 -0
- package/dist/api/define-capabilities.mjs +19 -0
- package/dist/api/define-capabilities.mjs.map +1 -0
- package/dist/api/define-devstack-with.d.mts +41 -0
- package/dist/api/define-devstack-with.mjs +24 -0
- package/dist/api/define-devstack-with.mjs.map +1 -0
- package/dist/api/define-devstack.d.mts +62 -0
- package/dist/api/define-devstack.mjs +108 -0
- package/dist/api/define-devstack.mjs.map +1 -0
- package/dist/api/define-plugin.d.mts +1 -0
- package/dist/api/inference-network.mjs +122 -0
- package/dist/api/inference-network.mjs.map +1 -0
- package/dist/api/mode-narrowed-factory.d.mts +26 -0
- package/dist/api/mode-narrowed-factory.mjs +8 -0
- package/dist/api/mode-narrowed-factory.mjs.map +1 -0
- package/dist/api/plugin-errors.mjs +10 -0
- package/dist/api/plugin-errors.mjs.map +1 -0
- package/dist/api/run-stack.d.mts +82 -0
- package/dist/api/run-stack.mjs +127 -0
- package/dist/api/run-stack.mjs.map +1 -0
- package/dist/build-integrations/playwright/config.d.mts +92 -0
- package/dist/build-integrations/playwright/config.mjs +71 -0
- package/dist/build-integrations/playwright/config.mjs.map +1 -0
- package/dist/build-integrations/playwright/errors.d.mts +82 -0
- package/dist/build-integrations/playwright/errors.mjs +43 -0
- package/dist/build-integrations/playwright/errors.mjs.map +1 -0
- package/dist/build-integrations/playwright/global-setup.d.mts +64 -0
- package/dist/build-integrations/playwright/global-setup.mjs +44 -0
- package/dist/build-integrations/playwright/global-setup.mjs.map +1 -0
- package/dist/build-integrations/playwright/index.d.mts +6 -0
- package/dist/build-integrations/playwright/index.mjs +6 -0
- package/dist/build-integrations/playwright/stack-context.d.mts +95 -0
- package/dist/build-integrations/playwright/stack-context.mjs +277 -0
- package/dist/build-integrations/playwright/stack-context.mjs.map +1 -0
- package/dist/build-integrations/playwright/wallet-context.d.mts +87 -0
- package/dist/build-integrations/playwright/wallet-context.mjs +148 -0
- package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -0
- package/dist/build-integrations/runtime/cold-start-url.d.mts +67 -0
- package/dist/build-integrations/runtime/cold-start-url.mjs +56 -0
- package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -0
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs +10 -0
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -0
- package/dist/build-integrations/runtime/discover.d.mts +78 -0
- package/dist/build-integrations/runtime/discover.mjs +124 -0
- package/dist/build-integrations/runtime/discover.mjs.map +1 -0
- package/dist/build-integrations/runtime/endpoint-registry.d.mts +26 -0
- package/dist/build-integrations/runtime/endpoint-registry.mjs +41 -0
- package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -0
- package/dist/build-integrations/runtime/errors.d.mts +64 -0
- package/dist/build-integrations/runtime/errors.mjs +51 -0
- package/dist/build-integrations/runtime/errors.mjs.map +1 -0
- package/dist/build-integrations/runtime/index.d.mts +7 -0
- package/dist/build-integrations/runtime/index.mjs +6 -0
- package/dist/build-integrations/runtime/read-stack-context.d.mts +38 -0
- package/dist/build-integrations/runtime/read-stack-context.mjs +130 -0
- package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -0
- package/dist/build-integrations/runtime/stack-context.d.mts +53 -0
- package/dist/build-integrations/vitest/config.d.mts +62 -0
- package/dist/build-integrations/vitest/config.mjs +80 -0
- package/dist/build-integrations/vitest/config.mjs.map +1 -0
- package/dist/build-integrations/vitest/env.d.mts +48 -0
- package/dist/build-integrations/vitest/env.mjs +50 -0
- package/dist/build-integrations/vitest/env.mjs.map +1 -0
- package/dist/build-integrations/vitest/errors.d.mts +44 -0
- package/dist/build-integrations/vitest/errors.mjs +18 -0
- package/dist/build-integrations/vitest/errors.mjs.map +1 -0
- package/dist/build-integrations/vitest/index.d.mts +6 -0
- package/dist/build-integrations/vitest/index.mjs +6 -0
- package/dist/build-integrations/vitest/setup.d.mts +53 -0
- package/dist/build-integrations/vitest/setup.mjs +56 -0
- package/dist/build-integrations/vitest/setup.mjs.map +1 -0
- package/dist/build-integrations/vitest/stack-context.d.mts +58 -0
- package/dist/build-integrations/vitest/stack-context.mjs +67 -0
- package/dist/build-integrations/vitest/stack-context.mjs.map +1 -0
- package/dist/cli/main.d.mts +5 -0
- package/dist/cli/main.mjs +586 -0
- package/dist/cli/main.mjs.map +1 -0
- package/dist/cli/prune-direct.mjs +216 -0
- package/dist/cli/prune-direct.mjs.map +1 -0
- package/dist/cli/snapshot-reader.mjs +73 -0
- package/dist/cli/snapshot-reader.mjs.map +1 -0
- package/dist/cli/up-lifecycle.mjs +28 -0
- package/dist/cli/up-lifecycle.mjs.map +1 -0
- package/dist/contracts/capability-decl.d.mts +42 -0
- package/dist/contracts/chain-probe.d.mts +26 -0
- package/dist/contracts/chain-probe.mjs +8 -0
- package/dist/contracts/chain-probe.mjs.map +1 -0
- package/dist/contracts/codegenable.d.mts +43 -0
- package/dist/contracts/container-runtime.d.mts +245 -0
- package/dist/contracts/liveness-classifier.d.mts +19 -0
- package/dist/contracts/network-resolver.d.mts +15 -0
- package/dist/contracts/network-resolver.mjs +7 -0
- package/dist/contracts/network-resolver.mjs.map +1 -0
- package/dist/contracts/projection.d.mts +15 -0
- package/dist/contracts/routable.d.mts +53 -0
- package/dist/contracts/snapshotable.d.mts +39 -0
- package/dist/contracts/strategy-contributor.d.mts +26 -0
- package/dist/index.d.mts +89 -0
- package/dist/index.mjs +37 -0
- package/dist/orchestrators/codegen/bindings.d.mts +2 -0
- package/dist/orchestrators/codegen/bindings.mjs +340 -0
- package/dist/orchestrators/codegen/bindings.mjs.map +1 -0
- package/dist/orchestrators/codegen/emit.mjs +56 -0
- package/dist/orchestrators/codegen/emit.mjs.map +1 -0
- package/dist/orchestrators/codegen/errors.d.mts +1 -0
- package/dist/orchestrators/codegen/errors.mjs +66 -0
- package/dist/orchestrators/codegen/errors.mjs.map +1 -0
- package/dist/orchestrators/codegen/extras.mjs +16 -0
- package/dist/orchestrators/codegen/extras.mjs.map +1 -0
- package/dist/orchestrators/codegen/format.mjs +109 -0
- package/dist/orchestrators/codegen/format.mjs.map +1 -0
- package/dist/orchestrators/codegen/gitignore.mjs +67 -0
- package/dist/orchestrators/codegen/gitignore.mjs.map +1 -0
- package/dist/orchestrators/codegen/paths.d.mts +1 -0
- package/dist/orchestrators/codegen/paths.mjs +33 -0
- package/dist/orchestrators/codegen/paths.mjs.map +1 -0
- package/dist/orchestrators/codegen/permissions.mjs +6 -0
- package/dist/orchestrators/codegen/permissions.mjs.map +1 -0
- package/dist/orchestrators/codegen/service.d.mts +1 -0
- package/dist/orchestrators/codegen/service.mjs +276 -0
- package/dist/orchestrators/codegen/service.mjs.map +1 -0
- package/dist/orchestrators/router/cleanup.mjs +58 -0
- package/dist/orchestrators/router/cleanup.mjs.map +1 -0
- package/dist/orchestrators/router/cors.mjs +31 -0
- package/dist/orchestrators/router/cors.mjs.map +1 -0
- package/dist/orchestrators/router/entrypoints.d.mts +1 -0
- package/dist/orchestrators/router/entrypoints.mjs +80 -0
- package/dist/orchestrators/router/entrypoints.mjs.map +1 -0
- package/dist/orchestrators/router/errors.d.mts +1 -0
- package/dist/orchestrators/router/errors.mjs +103 -0
- package/dist/orchestrators/router/errors.mjs.map +1 -0
- package/dist/orchestrators/router/file-provider.d.mts +1 -0
- package/dist/orchestrators/router/file-provider.mjs +320 -0
- package/dist/orchestrators/router/file-provider.mjs.map +1 -0
- package/dist/orchestrators/router/hostname.d.mts +1 -0
- package/dist/orchestrators/router/hostname.mjs +107 -0
- package/dist/orchestrators/router/hostname.mjs.map +1 -0
- package/dist/orchestrators/router/index.d.mts +1 -0
- package/dist/orchestrators/router/profile.d.mts +1 -0
- package/dist/orchestrators/router/profile.mjs +109 -0
- package/dist/orchestrators/router/profile.mjs.map +1 -0
- package/dist/orchestrators/router/service.d.mts +3 -0
- package/dist/orchestrators/router/service.mjs +421 -0
- package/dist/orchestrators/router/service.mjs.map +1 -0
- package/dist/orchestrators/router/traefik-container.d.mts +1 -0
- package/dist/orchestrators/router/traefik-container.mjs +229 -0
- package/dist/orchestrators/router/traefik-container.mjs.map +1 -0
- package/dist/orchestrators/runtime-composition.d.mts +10 -0
- package/dist/orchestrators/runtime-composition.mjs +168 -0
- package/dist/orchestrators/runtime-composition.mjs.map +1 -0
- package/dist/orchestrators/snapshot/capture.d.mts +1 -0
- package/dist/orchestrators/snapshot/capture.mjs +350 -0
- package/dist/orchestrators/snapshot/capture.mjs.map +1 -0
- package/dist/orchestrators/snapshot/descriptor.d.mts +1 -0
- package/dist/orchestrators/snapshot/descriptor.mjs +109 -0
- package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -0
- package/dist/orchestrators/snapshot/identity-guard.d.mts +1 -0
- package/dist/orchestrators/snapshot/identity-guard.mjs +132 -0
- package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -0
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs +207 -0
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -0
- package/dist/orchestrators/snapshot/index.d.mts +1 -0
- package/dist/orchestrators/snapshot/integrity.d.mts +1 -0
- package/dist/orchestrators/snapshot/integrity.mjs +74 -0
- package/dist/orchestrators/snapshot/integrity.mjs.map +1 -0
- package/dist/orchestrators/snapshot/prune.d.mts +1 -0
- package/dist/orchestrators/snapshot/prune.mjs +110 -0
- package/dist/orchestrators/snapshot/prune.mjs.map +1 -0
- package/dist/orchestrators/snapshot/restore.d.mts +1 -0
- package/dist/orchestrators/snapshot/restore.mjs +404 -0
- package/dist/orchestrators/snapshot/restore.mjs.map +1 -0
- package/dist/orchestrators/snapshot/service.d.mts +1 -0
- package/dist/orchestrators/snapshot/service.mjs +296 -0
- package/dist/orchestrators/snapshot/service.mjs.map +1 -0
- package/dist/orchestrators/snapshot/state-document.mjs +18 -0
- package/dist/orchestrators/snapshot/state-document.mjs.map +1 -0
- package/dist/orchestrators/snapshot/wipe.d.mts +1 -0
- package/dist/orchestrators/snapshot/wipe.mjs +59 -0
- package/dist/orchestrators/snapshot/wipe.mjs.map +1 -0
- package/dist/plugins/account/codegen.d.mts +12 -0
- package/dist/plugins/account/codegen.mjs +22 -0
- package/dist/plugins/account/codegen.mjs.map +1 -0
- package/dist/plugins/account/errors.d.mts +44 -0
- package/dist/plugins/account/errors.mjs +16 -0
- package/dist/plugins/account/errors.mjs.map +1 -0
- package/dist/plugins/account/funding.d.mts +94 -0
- package/dist/plugins/account/funding.mjs +199 -0
- package/dist/plugins/account/funding.mjs.map +1 -0
- package/dist/plugins/account/index.d.mts +54 -0
- package/dist/plugins/account/index.mjs +151 -0
- package/dist/plugins/account/index.mjs.map +1 -0
- package/dist/plugins/account/keypair.d.mts +32 -0
- package/dist/plugins/account/keypair.mjs +99 -0
- package/dist/plugins/account/keypair.mjs.map +1 -0
- package/dist/plugins/account/lease.mjs +21 -0
- package/dist/plugins/account/lease.mjs.map +1 -0
- package/dist/plugins/account/registry.d.mts +33 -0
- package/dist/plugins/account/registry.mjs +36 -0
- package/dist/plugins/account/registry.mjs.map +1 -0
- package/dist/plugins/account/service.d.mts +104 -0
- package/dist/plugins/account/service.mjs +405 -0
- package/dist/plugins/account/service.mjs.map +1 -0
- package/dist/plugins/account/snapshot.mjs +33 -0
- package/dist/plugins/account/snapshot.mjs.map +1 -0
- package/dist/plugins/account/variants/env.mjs +24 -0
- package/dist/plugins/account/variants/env.mjs.map +1 -0
- package/dist/plugins/account/variants/ephemeral.mjs +72 -0
- package/dist/plugins/account/variants/ephemeral.mjs.map +1 -0
- package/dist/plugins/account/variants/impersonate.d.mts +16 -0
- package/dist/plugins/account/variants/impersonate.mjs +48 -0
- package/dist/plugins/account/variants/impersonate.mjs.map +1 -0
- package/dist/plugins/account/variants/inline.mjs +13 -0
- package/dist/plugins/account/variants/inline.mjs.map +1 -0
- package/dist/plugins/account/variants/keystore.mjs +93 -0
- package/dist/plugins/account/variants/keystore.mjs.map +1 -0
- package/dist/plugins/account/variants/signer.mjs +31 -0
- package/dist/plugins/account/variants/signer.mjs.map +1 -0
- package/dist/plugins/action/build-context.d.mts +41 -0
- package/dist/plugins/action/discriminator.d.mts +20 -0
- package/dist/plugins/action/discriminator.mjs +13 -0
- package/dist/plugins/action/discriminator.mjs.map +1 -0
- package/dist/plugins/action/errors.d.mts +31 -0
- package/dist/plugins/action/errors.mjs +13 -0
- package/dist/plugins/action/errors.mjs.map +1 -0
- package/dist/plugins/action/execute.d.mts +2 -0
- package/dist/plugins/action/execute.mjs +145 -0
- package/dist/plugins/action/execute.mjs.map +1 -0
- package/dist/plugins/action/index.d.mts +56 -0
- package/dist/plugins/action/index.mjs +82 -0
- package/dist/plugins/action/index.mjs.map +1 -0
- package/dist/plugins/action/service.d.mts +26 -0
- package/dist/plugins/action/service.mjs +84 -0
- package/dist/plugins/action/service.mjs.map +1 -0
- package/dist/plugins/coin/address-resolution.d.mts +34 -0
- package/dist/plugins/coin/address-resolution.mjs +80 -0
- package/dist/plugins/coin/address-resolution.mjs.map +1 -0
- package/dist/plugins/coin/codegen.d.mts +16 -0
- package/dist/plugins/coin/codegen.mjs +21 -0
- package/dist/plugins/coin/codegen.mjs.map +1 -0
- package/dist/plugins/coin/discovery.d.mts +26 -0
- package/dist/plugins/coin/discovery.mjs +112 -0
- package/dist/plugins/coin/discovery.mjs.map +1 -0
- package/dist/plugins/coin/errors.d.mts +48 -0
- package/dist/plugins/coin/errors.mjs +13 -0
- package/dist/plugins/coin/errors.mjs.map +1 -0
- package/dist/plugins/coin/index.d.mts +95 -0
- package/dist/plugins/coin/index.mjs +172 -0
- package/dist/plugins/coin/index.mjs.map +1 -0
- package/dist/plugins/coin/metadata.d.mts +15 -0
- package/dist/plugins/coin/metadata.mjs +99 -0
- package/dist/plugins/coin/metadata.mjs.map +1 -0
- package/dist/plugins/coin/mint.d.mts +34 -0
- package/dist/plugins/coin/mint.mjs +164 -0
- package/dist/plugins/coin/mint.mjs.map +1 -0
- package/dist/plugins/coin/registry.d.mts +1 -0
- package/dist/plugins/coin/registry.mjs +37 -0
- package/dist/plugins/coin/registry.mjs.map +1 -0
- package/dist/plugins/coin/service.d.mts +47 -0
- package/dist/plugins/coin/service.mjs +51 -0
- package/dist/plugins/coin/service.mjs.map +1 -0
- package/dist/plugins/coin/snapshot.mjs +19 -0
- package/dist/plugins/coin/snapshot.mjs.map +1 -0
- package/dist/plugins/coin/type-strings.mjs +49 -0
- package/dist/plugins/coin/type-strings.mjs.map +1 -0
- package/dist/plugins/deepbook/codegen.d.mts +39 -0
- package/dist/plugins/deepbook/codegen.mjs +15 -0
- package/dist/plugins/deepbook/codegen.mjs.map +1 -0
- package/dist/plugins/deepbook/deploy.mjs +437 -0
- package/dist/plugins/deepbook/deploy.mjs.map +1 -0
- package/dist/plugins/deepbook/errors.d.mts +29 -0
- package/dist/plugins/deepbook/errors.mjs +26 -0
- package/dist/plugins/deepbook/errors.mjs.map +1 -0
- package/dist/plugins/deepbook/faucet-strategy.d.mts +8 -0
- package/dist/plugins/deepbook/faucet-strategy.mjs +81 -0
- package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -0
- package/dist/plugins/deepbook/index.d.mts +171 -0
- package/dist/plugins/deepbook/index.mjs +359 -0
- package/dist/plugins/deepbook/index.mjs.map +1 -0
- package/dist/plugins/deepbook/plugin-key.mjs +7 -0
- package/dist/plugins/deepbook/plugin-key.mjs.map +1 -0
- package/dist/plugins/deepbook/pyth/index.mjs +226 -0
- package/dist/plugins/deepbook/pyth/index.mjs.map +1 -0
- package/dist/plugins/deepbook/routable.mjs +21 -0
- package/dist/plugins/deepbook/routable.mjs.map +1 -0
- package/dist/plugins/deepbook/snapshot.mjs +49 -0
- package/dist/plugins/deepbook/snapshot.mjs.map +1 -0
- package/dist/plugins/deepbook/types.d.mts +125 -0
- package/dist/plugins/deepbook/types.mjs +12 -0
- package/dist/plugins/deepbook/types.mjs.map +1 -0
- package/dist/plugins/faucet/dispatcher.d.mts +9 -0
- package/dist/plugins/faucet/dispatcher.mjs +13 -0
- package/dist/plugins/faucet/dispatcher.mjs.map +1 -0
- package/dist/plugins/faucet/errors.d.mts +86 -0
- package/dist/plugins/faucet/errors.mjs +19 -0
- package/dist/plugins/faucet/errors.mjs.map +1 -0
- package/dist/plugins/faucet/http.mjs +127 -0
- package/dist/plugins/faucet/http.mjs.map +1 -0
- package/dist/plugins/faucet/index.d.mts +43 -0
- package/dist/plugins/faucet/index.mjs +42 -0
- package/dist/plugins/faucet/index.mjs.map +1 -0
- package/dist/plugins/faucet/service.d.mts +20 -0
- package/dist/plugins/faucet/strategies/sui-local.d.mts +23 -0
- package/dist/plugins/faucet/strategies/sui-local.mjs +29 -0
- package/dist/plugins/faucet/strategies/sui-local.mjs.map +1 -0
- package/dist/plugins/host-service/errors.d.mts +27 -0
- package/dist/plugins/host-service/errors.mjs +14 -0
- package/dist/plugins/host-service/errors.mjs.map +1 -0
- package/dist/plugins/host-service/index.d.mts +10 -0
- package/dist/plugins/host-service/index.mjs +48 -0
- package/dist/plugins/host-service/index.mjs.map +1 -0
- package/dist/plugins/host-service/routable.mjs +24 -0
- package/dist/plugins/host-service/routable.mjs.map +1 -0
- package/dist/plugins/host-service/service.d.mts +49 -0
- package/dist/plugins/host-service/service.mjs +375 -0
- package/dist/plugins/host-service/service.mjs.map +1 -0
- package/dist/plugins/package/build.d.mts +1 -0
- package/dist/plugins/package/build.mjs +24 -0
- package/dist/plugins/package/build.mjs.map +1 -0
- package/dist/plugins/package/codegen.d.mts +19 -0
- package/dist/plugins/package/codegen.mjs +41 -0
- package/dist/plugins/package/codegen.mjs.map +1 -0
- package/dist/plugins/package/dep-resolution.mjs +10 -0
- package/dist/plugins/package/dep-resolution.mjs.map +1 -0
- package/dist/plugins/package/errors.d.mts +34 -0
- package/dist/plugins/package/errors.mjs +13 -0
- package/dist/plugins/package/errors.mjs.map +1 -0
- package/dist/plugins/package/index.d.mts +109 -0
- package/dist/plugins/package/index.mjs +207 -0
- package/dist/plugins/package/index.mjs.map +1 -0
- package/dist/plugins/package/mode-known.mjs +41 -0
- package/dist/plugins/package/mode-known.mjs.map +1 -0
- package/dist/plugins/package/mode-local.d.mts +1 -0
- package/dist/plugins/package/mode-local.mjs +183 -0
- package/dist/plugins/package/mode-local.mjs.map +1 -0
- package/dist/plugins/package/publish-executor.mjs +202 -0
- package/dist/plugins/package/publish-executor.mjs.map +1 -0
- package/dist/plugins/package/publish-output.d.mts +28 -0
- package/dist/plugins/package/publish-output.mjs +45 -0
- package/dist/plugins/package/publish-output.mjs.map +1 -0
- package/dist/plugins/package/registry.d.mts +25 -0
- package/dist/plugins/package/registry.mjs +30 -0
- package/dist/plugins/package/registry.mjs.map +1 -0
- package/dist/plugins/package/service.mjs +20 -0
- package/dist/plugins/package/service.mjs.map +1 -0
- package/dist/plugins/package/snapshot.mjs +25 -0
- package/dist/plugins/package/snapshot.mjs.map +1 -0
- package/dist/plugins/postgres/codegen.mjs +42 -0
- package/dist/plugins/postgres/codegen.mjs.map +1 -0
- package/dist/plugins/postgres/connection.d.mts +33 -0
- package/dist/plugins/postgres/connection.mjs +19 -0
- package/dist/plugins/postgres/connection.mjs.map +1 -0
- package/dist/plugins/postgres/db-ensure.mjs +100 -0
- package/dist/plugins/postgres/db-ensure.mjs.map +1 -0
- package/dist/plugins/postgres/errors.d.mts +55 -0
- package/dist/plugins/postgres/errors.mjs +29 -0
- package/dist/plugins/postgres/errors.mjs.map +1 -0
- package/dist/plugins/postgres/index.d.mts +37 -0
- package/dist/plugins/postgres/index.mjs +75 -0
- package/dist/plugins/postgres/index.mjs.map +1 -0
- package/dist/plugins/postgres/routable.mjs +33 -0
- package/dist/plugins/postgres/routable.mjs.map +1 -0
- package/dist/plugins/postgres/service.d.mts +50 -0
- package/dist/plugins/postgres/service.mjs +145 -0
- package/dist/plugins/postgres/service.mjs.map +1 -0
- package/dist/plugins/postgres/snapshot.d.mts +1 -0
- package/dist/plugins/postgres/snapshot.mjs +32 -0
- package/dist/plugins/postgres/snapshot.mjs.map +1 -0
- package/dist/plugins/router-entrypoints.mjs +21 -0
- package/dist/plugins/router-entrypoints.mjs.map +1 -0
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +59 -0
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -0
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +132 -0
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -0
- package/dist/plugins/seal/codegen.d.mts +19 -0
- package/dist/plugins/seal/codegen.mjs +16 -0
- package/dist/plugins/seal/codegen.mjs.map +1 -0
- package/dist/plugins/seal/config-render.mjs +82 -0
- package/dist/plugins/seal/config-render.mjs.map +1 -0
- package/dist/plugins/seal/deploy.mjs +198 -0
- package/dist/plugins/seal/deploy.mjs.map +1 -0
- package/dist/plugins/seal/errors.d.mts +52 -0
- package/dist/plugins/seal/errors.mjs +19 -0
- package/dist/plugins/seal/errors.mjs.map +1 -0
- package/dist/plugins/seal/index.d.mts +161 -0
- package/dist/plugins/seal/index.mjs +235 -0
- package/dist/plugins/seal/index.mjs.map +1 -0
- package/dist/plugins/seal/key-manager.d.mts +22 -0
- package/dist/plugins/seal/key-manager.mjs +22 -0
- package/dist/plugins/seal/key-manager.mjs.map +1 -0
- package/dist/plugins/seal/key-server.mjs +175 -0
- package/dist/plugins/seal/key-server.mjs.map +1 -0
- package/dist/plugins/seal/keygen.mjs +96 -0
- package/dist/plugins/seal/keygen.mjs.map +1 -0
- package/dist/plugins/seal/mode/fork-known.d.mts +8 -0
- package/dist/plugins/seal/mode/fork-known.mjs +23 -0
- package/dist/plugins/seal/mode/fork-known.mjs.map +1 -0
- package/dist/plugins/seal/mode/live.d.mts +18 -0
- package/dist/plugins/seal/mode/live.mjs +64 -0
- package/dist/plugins/seal/mode/live.mjs.map +1 -0
- package/dist/plugins/seal/mode/local-keygen.mjs +180 -0
- package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -0
- package/dist/plugins/seal/plugin-key.mjs +7 -0
- package/dist/plugins/seal/plugin-key.mjs.map +1 -0
- package/dist/plugins/seal/registry-publish.d.mts +43 -0
- package/dist/plugins/seal/registry-publish.mjs +9 -0
- package/dist/plugins/seal/registry-publish.mjs.map +1 -0
- package/dist/plugins/seal/routable.mjs +57 -0
- package/dist/plugins/seal/routable.mjs.map +1 -0
- package/dist/plugins/seal/service.mjs +17 -0
- package/dist/plugins/seal/service.mjs.map +1 -0
- package/dist/plugins/seal/snapshot.mjs +51 -0
- package/dist/plugins/seal/snapshot.mjs.map +1 -0
- package/dist/plugins/sui/auto-tick.mjs +45 -0
- package/dist/plugins/sui/auto-tick.mjs.map +1 -0
- package/dist/plugins/sui/chain-build-container.d.mts +1 -0
- package/dist/plugins/sui/chain-probe.d.mts +85 -0
- package/dist/plugins/sui/chain-probe.mjs +104 -0
- package/dist/plugins/sui/chain-probe.mjs.map +1 -0
- package/dist/plugins/sui/codegen.d.mts +14 -0
- package/dist/plugins/sui/codegen.mjs +26 -0
- package/dist/plugins/sui/codegen.mjs.map +1 -0
- package/dist/plugins/sui/errors.d.mts +74 -0
- package/dist/plugins/sui/errors.mjs +28 -0
- package/dist/plugins/sui/errors.mjs.map +1 -0
- package/dist/plugins/sui/fork-orchestration.mjs +24 -0
- package/dist/plugins/sui/fork-orchestration.mjs.map +1 -0
- package/dist/plugins/sui/fork-transaction.mjs +96 -0
- package/dist/plugins/sui/fork-transaction.mjs.map +1 -0
- package/dist/plugins/sui/index.d.mts +318 -0
- package/dist/plugins/sui/index.mjs +182 -0
- package/dist/plugins/sui/index.mjs.map +1 -0
- package/dist/plugins/sui/mode/external.mjs +60 -0
- package/dist/plugins/sui/mode/external.mjs.map +1 -0
- package/dist/plugins/sui/mode/fork.mjs +283 -0
- package/dist/plugins/sui/mode/fork.mjs.map +1 -0
- package/dist/plugins/sui/mode/live.mjs +103 -0
- package/dist/plugins/sui/mode/live.mjs.map +1 -0
- package/dist/plugins/sui/mode/local.mjs +293 -0
- package/dist/plugins/sui/mode/local.mjs.map +1 -0
- package/dist/plugins/sui/mode/shared-boot.mjs +254 -0
- package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -0
- package/dist/plugins/sui/mode/shared.d.mts +103 -0
- package/dist/plugins/sui/mode/shared.mjs +12 -0
- package/dist/plugins/sui/mode/shared.mjs.map +1 -0
- package/dist/plugins/sui/mode/spec.d.mts +94 -0
- package/dist/plugins/sui/network-resolver.d.mts +23 -0
- package/dist/plugins/sui/routable.mjs +88 -0
- package/dist/plugins/sui/routable.mjs.map +1 -0
- package/dist/plugins/sui/seed-objects.d.mts +18 -0
- package/dist/plugins/sui/seed-objects.mjs +25 -0
- package/dist/plugins/sui/seed-objects.mjs.map +1 -0
- package/dist/plugins/sui/service.mjs +38 -0
- package/dist/plugins/sui/service.mjs.map +1 -0
- package/dist/plugins/sui/snapshot.mjs +53 -0
- package/dist/plugins/sui/snapshot.mjs.map +1 -0
- package/dist/plugins/wallet/codegen.d.mts +33 -0
- package/dist/plugins/wallet/codegen.mjs +34 -0
- package/dist/plugins/wallet/codegen.mjs.map +1 -0
- package/dist/plugins/wallet/errors.d.mts +66 -0
- package/dist/plugins/wallet/errors.mjs +16 -0
- package/dist/plugins/wallet/errors.mjs.map +1 -0
- package/dist/plugins/wallet/index.d.mts +63 -0
- package/dist/plugins/wallet/index.mjs +126 -0
- package/dist/plugins/wallet/index.mjs.map +1 -0
- package/dist/plugins/wallet/origin-policy.d.mts +1 -0
- package/dist/plugins/wallet/origin-policy.mjs +65 -0
- package/dist/plugins/wallet/origin-policy.mjs.map +1 -0
- package/dist/plugins/wallet/pairing.d.mts +11 -0
- package/dist/plugins/wallet/pairing.mjs +125 -0
- package/dist/plugins/wallet/pairing.mjs.map +1 -0
- package/dist/plugins/wallet/protocol.d.mts +1 -0
- package/dist/plugins/wallet/protocol.mjs +96 -0
- package/dist/plugins/wallet/protocol.mjs.map +1 -0
- package/dist/plugins/wallet/routable.mjs +32 -0
- package/dist/plugins/wallet/routable.mjs.map +1 -0
- package/dist/plugins/wallet/server.d.mts +12 -0
- package/dist/plugins/wallet/server.mjs +317 -0
- package/dist/plugins/wallet/server.mjs.map +1 -0
- package/dist/plugins/wallet/service.d.mts +68 -0
- package/dist/plugins/wallet/service.mjs +97 -0
- package/dist/plugins/wallet/service.mjs.map +1 -0
- package/dist/plugins/wallet/snapshot.d.mts +1 -0
- package/dist/plugins/wallet/snapshot.mjs +14 -0
- package/dist/plugins/wallet/snapshot.mjs.map +1 -0
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +42 -0
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -0
- package/dist/plugins/walrus/codegen.d.mts +38 -0
- package/dist/plugins/walrus/codegen.mjs +34 -0
- package/dist/plugins/walrus/codegen.mjs.map +1 -0
- package/dist/plugins/walrus/deploy-paths.mjs +14 -0
- package/dist/plugins/walrus/deploy-paths.mjs.map +1 -0
- package/dist/plugins/walrus/deploy.d.mts +1 -0
- package/dist/plugins/walrus/deploy.mjs +224 -0
- package/dist/plugins/walrus/deploy.mjs.map +1 -0
- package/dist/plugins/walrus/errors.d.mts +38 -0
- package/dist/plugins/walrus/errors.mjs +26 -0
- package/dist/plugins/walrus/errors.mjs.map +1 -0
- package/dist/plugins/walrus/faucet-strategy.d.mts +12 -0
- package/dist/plugins/walrus/faucet-strategy.mjs +62 -0
- package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -0
- package/dist/plugins/walrus/index.d.mts +177 -0
- package/dist/plugins/walrus/index.mjs +284 -0
- package/dist/plugins/walrus/index.mjs.map +1 -0
- package/dist/plugins/walrus/mode/known-deploy.d.mts +25 -0
- package/dist/plugins/walrus/mode/known-deploy.mjs +71 -0
- package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -0
- package/dist/plugins/walrus/mode/local-cluster.d.mts +34 -0
- package/dist/plugins/walrus/mode/local-cluster.mjs +153 -0
- package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -0
- package/dist/plugins/walrus/plugin-key.mjs +7 -0
- package/dist/plugins/walrus/plugin-key.mjs.map +1 -0
- package/dist/plugins/walrus/registry-publish.d.mts +24 -0
- package/dist/plugins/walrus/registry-publish.mjs +7 -0
- package/dist/plugins/walrus/registry-publish.mjs.map +1 -0
- package/dist/plugins/walrus/routable.mjs +99 -0
- package/dist/plugins/walrus/routable.mjs.map +1 -0
- package/dist/plugins/walrus/service.mjs +20 -0
- package/dist/plugins/walrus/service.mjs.map +1 -0
- package/dist/plugins/walrus/snapshot.mjs +53 -0
- package/dist/plugins/walrus/snapshot.mjs.map +1 -0
- package/dist/plugins/walrus/storage-nodes.d.mts +15 -0
- package/dist/plugins/walrus/storage-nodes.mjs +154 -0
- package/dist/plugins/walrus/storage-nodes.mjs.map +1 -0
- package/dist/plugins/walrus/wal-swap.d.mts +2 -0
- package/dist/plugins/walrus/wal-swap.mjs +58 -0
- package/dist/plugins/walrus/wal-swap.mjs.map +1 -0
- package/dist/primitives/artifact-publisher.d.mts +12 -0
- package/dist/primitives/cache.d.mts +1 -0
- package/dist/runtime/built-in-plugin-layers.mjs +49 -0
- package/dist/runtime/built-in-plugin-layers.mjs.map +1 -0
- package/dist/runtime/docker/client.d.mts +2 -0
- package/dist/runtime/docker/client.mjs +54 -0
- package/dist/runtime/docker/client.mjs.map +1 -0
- package/dist/runtime/docker/container.d.mts +1 -0
- package/dist/runtime/docker/container.mjs +562 -0
- package/dist/runtime/docker/container.mjs.map +1 -0
- package/dist/runtime/docker/errors.d.mts +1 -0
- package/dist/runtime/docker/errors.mjs +187 -0
- package/dist/runtime/docker/errors.mjs.map +1 -0
- package/dist/runtime/docker/exec.d.mts +1 -0
- package/dist/runtime/docker/exec.mjs +63 -0
- package/dist/runtime/docker/exec.mjs.map +1 -0
- package/dist/runtime/docker/image.d.mts +1 -0
- package/dist/runtime/docker/image.mjs +278 -0
- package/dist/runtime/docker/image.mjs.map +1 -0
- package/dist/runtime/docker/index.d.mts +1 -0
- package/dist/runtime/docker/inventory.d.mts +1 -0
- package/dist/runtime/docker/inventory.mjs +167 -0
- package/dist/runtime/docker/inventory.mjs.map +1 -0
- package/dist/runtime/docker/labels.d.mts +1 -0
- package/dist/runtime/docker/labels.mjs +97 -0
- package/dist/runtime/docker/labels.mjs.map +1 -0
- package/dist/runtime/docker/logs.d.mts +1 -0
- package/dist/runtime/docker/logs.mjs +34 -0
- package/dist/runtime/docker/logs.mjs.map +1 -0
- package/dist/runtime/docker/network.d.mts +1 -0
- package/dist/runtime/docker/network.mjs +168 -0
- package/dist/runtime/docker/network.mjs.map +1 -0
- package/dist/runtime/docker/service.d.mts +9 -0
- package/dist/runtime/docker/service.mjs +266 -0
- package/dist/runtime/docker/service.mjs.map +1 -0
- package/dist/runtime/docker/sweep.d.mts +1 -0
- package/dist/runtime/docker/sweep.mjs +220 -0
- package/dist/runtime/docker/sweep.mjs.map +1 -0
- package/dist/runtime/docker/volume.d.mts +1 -0
- package/dist/runtime/docker/volume.mjs +24 -0
- package/dist/runtime/docker/volume.mjs.map +1 -0
- package/dist/runtime/docker/wrap.d.mts +1 -0
- package/dist/runtime/docker/wrap.mjs +131 -0
- package/dist/runtime/docker/wrap.mjs.map +1 -0
- package/dist/substrate/brand.d.mts +24 -0
- package/dist/substrate/brand.mjs +14 -0
- package/dist/substrate/brand.mjs.map +1 -0
- package/dist/substrate/cross-process.d.mts +1 -0
- package/dist/substrate/cross-process.mjs +28 -0
- package/dist/substrate/cross-process.mjs.map +1 -0
- package/dist/substrate/events.d.mts +117 -0
- package/dist/substrate/identity.d.mts +13 -0
- package/dist/substrate/lifecycle.d.mts +12 -0
- package/dist/substrate/manifest.d.mts +39 -0
- package/dist/substrate/manifest.mjs +33 -0
- package/dist/substrate/manifest.mjs.map +1 -0
- package/dist/substrate/network.d.mts +34 -0
- package/dist/substrate/options.d.mts +23 -0
- package/dist/substrate/plugin.d.mts +101 -0
- package/dist/substrate/plugin.mjs +61 -0
- package/dist/substrate/plugin.mjs.map +1 -0
- package/dist/substrate/projection.d.mts +100 -0
- package/dist/substrate/runtime/artifact-publisher/index.mjs +76 -0
- package/dist/substrate/runtime/artifact-publisher/index.mjs.map +1 -0
- package/dist/substrate/runtime/atomic-write.mjs +106 -0
- package/dist/substrate/runtime/atomic-write.mjs.map +1 -0
- package/dist/substrate/runtime/cache/index.d.mts +1 -0
- package/dist/substrate/runtime/cache/schema.d.mts +1 -0
- package/dist/substrate/runtime/cache/schema.mjs +22 -0
- package/dist/substrate/runtime/cache/schema.mjs.map +1 -0
- package/dist/substrate/runtime/cache/service.d.mts +1 -0
- package/dist/substrate/runtime/cache/service.mjs +89 -0
- package/dist/substrate/runtime/cache/service.mjs.map +1 -0
- package/dist/substrate/runtime/capability-sinks/index.d.mts +1 -0
- package/dist/substrate/runtime/capability-sinks/layer.d.mts +1 -0
- package/dist/substrate/runtime/capability-sinks/layer.mjs +31 -0
- package/dist/substrate/runtime/capability-sinks/layer.mjs.map +1 -0
- package/dist/substrate/runtime/capability-sinks/service.d.mts +36 -0
- package/dist/substrate/runtime/capability-sinks/service.mjs +74 -0
- package/dist/substrate/runtime/capability-sinks/service.mjs.map +1 -0
- package/dist/substrate/runtime/config-validation.d.mts +38 -0
- package/dist/substrate/runtime/config-validation.mjs +137 -0
- package/dist/substrate/runtime/config-validation.mjs.map +1 -0
- package/dist/substrate/runtime/context-helpers.mjs +32 -0
- package/dist/substrate/runtime/context-helpers.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +128 -0
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs +136 -0
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs +49 -0
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs +9 -0
- package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/liveness.mjs +119 -0
- package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/roster.mjs +275 -0
- package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/snapshot-reservation.d.mts +1 -0
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +117 -0
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +1 -0
- package/dist/substrate/runtime/cross-process/stack-lock.d.mts +1 -0
- package/dist/substrate/runtime/cross-process/stack-lock.mjs +142 -0
- package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -0
- package/dist/substrate/runtime/current-plugin.mjs +15 -0
- package/dist/substrate/runtime/current-plugin.mjs.map +1 -0
- package/dist/substrate/runtime/errors.d.mts +1 -0
- package/dist/substrate/runtime/errors.mjs +76 -0
- package/dist/substrate/runtime/errors.mjs.map +1 -0
- package/dist/substrate/runtime/host-tree-tar/index.mjs +364 -0
- package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -0
- package/dist/substrate/runtime/http-probe.d.mts +35 -0
- package/dist/substrate/runtime/http-probe.mjs +65 -0
- package/dist/substrate/runtime/http-probe.mjs.map +1 -0
- package/dist/substrate/runtime/lease-broker/index.d.mts +1 -0
- package/dist/substrate/runtime/lease-broker/service.d.mts +64 -0
- package/dist/substrate/runtime/lease-broker/service.mjs +155 -0
- package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/dep-graph.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs +138 -0
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/index.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +31 -0
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +133 -0
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/ready-gate.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs +34 -0
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/selective-restart.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs +43 -0
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/signals.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/signals.mjs +64 -0
- package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/state-machine.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/state-machine.mjs +38 -0
- package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +27 -0
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -0
- package/dist/substrate/runtime/managed-container.d.mts +30 -0
- package/dist/substrate/runtime/managed-container.mjs +32 -0
- package/dist/substrate/runtime/managed-container.mjs.map +1 -0
- package/dist/substrate/runtime/manifest/manifest.mjs +73 -0
- package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -0
- package/dist/substrate/runtime/mode-errors.d.mts +36 -0
- package/dist/substrate/runtime/observability/cascade-formatter.d.mts +1 -0
- package/dist/substrate/runtime/observability/cascade-formatter.mjs +135 -0
- package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -0
- package/dist/substrate/runtime/observability/formatter-registry.d.mts +1 -0
- package/dist/substrate/runtime/observability/formatter-registry.mjs +65 -0
- package/dist/substrate/runtime/observability/formatter-registry.mjs.map +1 -0
- package/dist/substrate/runtime/observability/index.d.mts +3 -0
- package/dist/substrate/runtime/observability/logger.d.mts +58 -0
- package/dist/substrate/runtime/observability/logger.mjs +89 -0
- package/dist/substrate/runtime/observability/logger.mjs.map +1 -0
- package/dist/substrate/runtime/observability/pretty-error.d.mts +1 -0
- package/dist/substrate/runtime/observability/pretty-error.mjs +119 -0
- package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -0
- package/dist/substrate/runtime/observability/process-lines.d.mts +31 -0
- package/dist/substrate/runtime/observability/process-lines.mjs +40 -0
- package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -0
- package/dist/substrate/runtime/observability/redaction.d.mts +28 -0
- package/dist/substrate/runtime/observability/redaction.mjs +45 -0
- package/dist/substrate/runtime/observability/redaction.mjs.map +1 -0
- package/dist/substrate/runtime/observability/spans.d.mts +1 -0
- package/dist/substrate/runtime/observability/spans.mjs +87 -0
- package/dist/substrate/runtime/observability/spans.mjs.map +1 -0
- package/dist/substrate/runtime/observability/subprocess-capture.d.mts +2 -0
- package/dist/substrate/runtime/observability/subprocess-capture.mjs +82 -0
- package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -0
- package/dist/substrate/runtime/paths.d.mts +17 -0
- package/dist/substrate/runtime/paths.mjs +61 -0
- package/dist/substrate/runtime/paths.mjs.map +1 -0
- package/dist/substrate/runtime/port-broker/index.d.mts +1 -0
- package/dist/substrate/runtime/port-broker/service.d.mts +1 -0
- package/dist/substrate/runtime/port-broker/service.mjs +319 -0
- package/dist/substrate/runtime/port-broker/service.mjs.map +1 -0
- package/dist/substrate/runtime/post-acquire-tasks.d.mts +1 -0
- package/dist/substrate/runtime/post-acquire-tasks.mjs +34 -0
- package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -0
- package/dist/substrate/runtime/probes.d.mts +51 -0
- package/dist/substrate/runtime/probes.mjs +84 -0
- package/dist/substrate/runtime/probes.mjs.map +1 -0
- package/dist/substrate/runtime/process-supervisor.d.mts +57 -0
- package/dist/substrate/runtime/process-supervisor.mjs +73 -0
- package/dist/substrate/runtime/process-supervisor.mjs.map +1 -0
- package/dist/substrate/runtime/projection/operational-endpoints.mjs +44 -0
- package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -0
- package/dist/substrate/runtime/projection/persisted.mjs +195 -0
- package/dist/substrate/runtime/projection/persisted.mjs.map +1 -0
- package/dist/substrate/runtime/projection/state-ref.mjs +48 -0
- package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -0
- package/dist/substrate/runtime/projection/update.mjs +200 -0
- package/dist/substrate/runtime/projection/update.mjs.map +1 -0
- package/dist/substrate/runtime/retry-policy.d.mts +18 -0
- package/dist/substrate/runtime/retry-policy.mjs +16 -0
- package/dist/substrate/runtime/retry-policy.mjs.map +1 -0
- package/dist/substrate/runtime/run.mjs +86 -0
- package/dist/substrate/runtime/run.mjs.map +1 -0
- package/dist/substrate/runtime/runtime-decode.d.mts +32 -0
- package/dist/substrate/runtime/runtime-decode.mjs +53 -0
- package/dist/substrate/runtime/runtime-decode.mjs.map +1 -0
- package/dist/substrate/runtime/scoped-http-server.mjs +36 -0
- package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -0
- package/dist/substrate/runtime/scoped-ref-map/service.mjs +83 -0
- package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +1 -0
- package/dist/substrate/runtime/stage-and-swap/index.d.mts +1 -0
- package/dist/substrate/runtime/stage-and-swap/index.mjs +131 -0
- package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -0
- package/dist/substrate/runtime/state-store/schema.mjs +36 -0
- package/dist/substrate/runtime/state-store/schema.mjs.map +1 -0
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.d.mts +1 -0
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs +22 -0
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -0
- package/dist/substrate/runtime/strategy-registry/faucet-capability-for.d.mts +1 -0
- package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs +30 -0
- package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs.map +1 -0
- package/dist/substrate/runtime/strategy-registry/index.d.mts +1 -0
- package/dist/substrate/runtime/strategy-registry/service.d.mts +1 -0
- package/dist/substrate/runtime/strategy-registry/service.mjs +67 -0
- package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -0
- package/dist/substrate/runtime/sui-execute/index.d.mts +11 -0
- package/dist/substrate/runtime/sui-execute/index.mjs +144 -0
- package/dist/substrate/runtime/sui-execute/index.mjs.map +1 -0
- package/dist/substrate/runtime/sui-move-build/index.d.mts +1 -0
- package/dist/substrate/runtime/sui-move-build/index.mjs +283 -0
- package/dist/substrate/runtime/sui-move-build/index.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor.d.mts +1 -0
- package/dist/substrate/runtime/supervisor.mjs +831 -0
- package/dist/substrate/runtime/supervisor.mjs.map +1 -0
- package/dist/surfaces/cli/command-tree.mjs +276 -0
- package/dist/surfaces/cli/command-tree.mjs.map +1 -0
- package/dist/surfaces/cli/commands/config.mjs +31 -0
- package/dist/surfaces/cli/commands/config.mjs.map +1 -0
- package/dist/surfaces/cli/commands/confirm-node.mjs +26 -0
- package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -0
- package/dist/surfaces/cli/commands/confirm.mjs +26 -0
- package/dist/surfaces/cli/commands/confirm.mjs.map +1 -0
- package/dist/surfaces/cli/commands/doctor-probes.mjs +452 -0
- package/dist/surfaces/cli/commands/doctor-probes.mjs.map +1 -0
- package/dist/surfaces/cli/commands/doctor.mjs +38 -0
- package/dist/surfaces/cli/commands/doctor.mjs.map +1 -0
- package/dist/surfaces/cli/commands/prune-picker.mjs +347 -0
- package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -0
- package/dist/surfaces/cli/commands/prune.mjs +178 -0
- package/dist/surfaces/cli/commands/prune.mjs.map +1 -0
- package/dist/surfaces/cli/commands/snapshot.mjs +141 -0
- package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -0
- package/dist/surfaces/cli/commands/status.mjs +95 -0
- package/dist/surfaces/cli/commands/status.mjs.map +1 -0
- package/dist/surfaces/cli/commands/supervisor-presence.mjs +33 -0
- package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -0
- package/dist/surfaces/cli/commands/wipe.mjs +28 -0
- package/dist/surfaces/cli/commands/wipe.mjs.map +1 -0
- package/dist/surfaces/cli/envelope.mjs +43 -0
- package/dist/surfaces/cli/envelope.mjs.map +1 -0
- package/dist/surfaces/cli/errors.mjs +110 -0
- package/dist/surfaces/cli/errors.mjs.map +1 -0
- package/dist/surfaces/cli/flags.mjs +56 -0
- package/dist/surfaces/cli/flags.mjs.map +1 -0
- package/dist/surfaces/cli/index.mjs +418 -0
- package/dist/surfaces/cli/index.mjs.map +1 -0
- package/dist/surfaces/cli/output.mjs +115 -0
- package/dist/surfaces/cli/output.mjs.map +1 -0
- package/dist/surfaces/cli/sysexits.mjs +139 -0
- package/dist/surfaces/cli/sysexits.mjs.map +1 -0
- package/dist/surfaces/tui/app.mjs +104 -0
- package/dist/surfaces/tui/app.mjs.map +1 -0
- package/dist/surfaces/tui/dashboard.mjs +261 -0
- package/dist/surfaces/tui/dashboard.mjs.map +1 -0
- package/dist/surfaces/tui/display-derivation.mjs +395 -0
- package/dist/surfaces/tui/display-derivation.mjs.map +1 -0
- package/dist/surfaces/tui/errors.mjs +11 -0
- package/dist/surfaces/tui/errors.mjs.map +1 -0
- package/dist/surfaces/tui/event-log.mjs +155 -0
- package/dist/surfaces/tui/event-log.mjs.map +1 -0
- package/dist/surfaces/tui/heartbeat.mjs +33 -0
- package/dist/surfaces/tui/heartbeat.mjs.map +1 -0
- package/dist/surfaces/tui/index.mjs +50 -0
- package/dist/surfaces/tui/index.mjs.map +1 -0
- package/dist/surfaces/tui/input.mjs +104 -0
- package/dist/surfaces/tui/input.mjs.map +1 -0
- package/dist/surfaces/tui/mode-detect.mjs +32 -0
- package/dist/surfaces/tui/mode-detect.mjs.map +1 -0
- package/dist/surfaces/tui/mount-ink.mjs +31 -0
- package/dist/surfaces/tui/mount-ink.mjs.map +1 -0
- package/dist/surfaces/tui/plain-renderer.mjs +170 -0
- package/dist/surfaces/tui/plain-renderer.mjs.map +1 -0
- package/dist/surfaces/tui/resource-table.mjs +507 -0
- package/dist/surfaces/tui/resource-table.mjs.map +1 -0
- package/images/_shared/signal-forward.sh +77 -0
- package/images/postgres/Dockerfile +32 -0
- package/images/seal/Dockerfile +68 -0
- package/images/seal/entrypoint.sh +65 -0
- package/images/sui/Dockerfile +73 -0
- package/images/sui/entrypoint.sh +244 -0
- package/images/sui-fork/Dockerfile +53 -0
- package/images/sui-fork/entrypoint.sh +51 -0
- package/images/walrus/Dockerfile +122 -0
- package/images/walrus/deploy-walrus.sh +305 -0
- package/images/walrus/run-walrus.sh +53 -0
- package/package.json +94 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { tarHostTree } from "../../substrate/runtime/host-tree-tar/index.mjs";
|
|
2
|
+
import { SnapshotLayout, containerImagesBundlePath, contributionPath, isRestorableContainerImageName, isSafeSnapshotPathSegment } from "./descriptor.mjs";
|
|
3
|
+
import { readImageBundleTags, verifyImageBundleTags } from "./image-bundle-tags.mjs";
|
|
4
|
+
import { writeArtifactIntegrity } from "./integrity.mjs";
|
|
5
|
+
import { requireIdentity } from "./identity-guard.mjs";
|
|
6
|
+
import { readSnapshotStateDocument, writeSnapshotStateDocument } from "./state-document.mjs";
|
|
7
|
+
import { Effect, Exit, FileSystem, Schema, Stream } from "effect";
|
|
8
|
+
//#region src/orchestrators/snapshot/capture.ts
|
|
9
|
+
/** Tagged failure during one capture step. `phase` discriminates so
|
|
10
|
+
* the user-facing message names the failing step. */
|
|
11
|
+
var CapturePhaseError = class extends Schema.TaggedErrorClass()("SnapshotCapturePhaseError", {
|
|
12
|
+
phase: Schema.Literals([
|
|
13
|
+
"enumerate-containers",
|
|
14
|
+
"quiesce",
|
|
15
|
+
"pause",
|
|
16
|
+
"commit",
|
|
17
|
+
"save-images",
|
|
18
|
+
"tar-subtree",
|
|
19
|
+
"tar-host-tree",
|
|
20
|
+
"read-state",
|
|
21
|
+
"write-state",
|
|
22
|
+
"write-contribution",
|
|
23
|
+
"write-meta",
|
|
24
|
+
"write-integrity",
|
|
25
|
+
"unpause"
|
|
26
|
+
]),
|
|
27
|
+
plugin: Schema.optional(Schema.String),
|
|
28
|
+
detail: Schema.String,
|
|
29
|
+
cause: Schema.optional(Schema.Defect)
|
|
30
|
+
}) {};
|
|
31
|
+
const failPhase = (phase, detail, plugin) => (cause) => Effect.fail(new CapturePhaseError({
|
|
32
|
+
phase,
|
|
33
|
+
plugin,
|
|
34
|
+
detail,
|
|
35
|
+
cause
|
|
36
|
+
}));
|
|
37
|
+
const failImageBundleTagScan = (cause) => Effect.fail(new CapturePhaseError({
|
|
38
|
+
phase: "save-images",
|
|
39
|
+
detail: cause.detail,
|
|
40
|
+
cause
|
|
41
|
+
}));
|
|
42
|
+
const validateSnapshotPathSegment = (kind, value, phase, plugin) => isSafeSnapshotPathSegment(value) ? Effect.void : Effect.fail(new CapturePhaseError({
|
|
43
|
+
phase,
|
|
44
|
+
plugin,
|
|
45
|
+
detail: `unsafe snapshot ${kind} path segment: ${value}`
|
|
46
|
+
}));
|
|
47
|
+
const validateCapturedContainer = (handle, labels, participant) => Effect.gen(function* () {
|
|
48
|
+
yield* validateSnapshotPathSegment("plugin", labels.plugin, "commit", participant.plugin);
|
|
49
|
+
yield* validateSnapshotPathSegment("role", labels.role, "commit", participant.plugin);
|
|
50
|
+
if (!isRestorableContainerImageName(handle.imageName)) return yield* Effect.fail(new CapturePhaseError({
|
|
51
|
+
phase: "commit",
|
|
52
|
+
plugin: participant.plugin,
|
|
53
|
+
detail: `container ${handle.name} imageName is not a restorable Docker tag destination: ${handle.imageName}`
|
|
54
|
+
}));
|
|
55
|
+
});
|
|
56
|
+
const detectContainerArtifactCollisions = (planned) => Effect.gen(function* () {
|
|
57
|
+
const seen = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const candidate of planned) {
|
|
59
|
+
const key = `${candidate.labels.plugin}/${candidate.labels.role}`;
|
|
60
|
+
const previous = seen.get(key);
|
|
61
|
+
if (previous !== void 0) return yield* Effect.fail(new CapturePhaseError({
|
|
62
|
+
phase: "commit",
|
|
63
|
+
plugin: candidate.participant.plugin,
|
|
64
|
+
detail: `duplicate managed container snapshot identity ${key} for ${previous.handle.name} and ${candidate.handle.name}`
|
|
65
|
+
}));
|
|
66
|
+
seen.set(key, candidate);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* Enumerate a participant's live managed containers, then run its
|
|
71
|
+
* optional app-level quiesce hook. Already-paused, exited, and
|
|
72
|
+
* created containers are committed as-is and are not unpaused by
|
|
73
|
+
* capture finalization.
|
|
74
|
+
*
|
|
75
|
+
* Architecture § Invariants: "A running container must be paused
|
|
76
|
+
* around the writable-layer commit; the unpause must fire on both
|
|
77
|
+
* success and failure paths (no orphaned paused containers). A
|
|
78
|
+
* stopped container is already quiescent and must not be paused."
|
|
79
|
+
*
|
|
80
|
+
* The default quiescence is `pauseAndCommit`; participants that need
|
|
81
|
+
* an application-level flush (postgres, RocksDB) declare a longer-grace
|
|
82
|
+
* `quiesce` effect on their decl — the orchestrator runs it BEFORE
|
|
83
|
+
* `pauseAndCommit`.
|
|
84
|
+
*/
|
|
85
|
+
const quiesceParticipant = (participant, runtime) => Effect.gen(function* () {
|
|
86
|
+
const labelTuples = participant.decl.managedContainers ?? [];
|
|
87
|
+
const containers = [];
|
|
88
|
+
for (const tuple of labelTuples) {
|
|
89
|
+
const matched = yield* runtime.inspectByLabels(tuple).pipe(Effect.catch(failPhase("enumerate-containers", `inspect by labels failed for ${tuple.plugin}/${tuple.role}`, participant.plugin)));
|
|
90
|
+
for (const handle of matched) if (handle.status === "running") containers.push({
|
|
91
|
+
handle,
|
|
92
|
+
labels: tuple,
|
|
93
|
+
unpauseAfterCapture: true
|
|
94
|
+
});
|
|
95
|
+
else if (handle.status === "paused" || handle.status === "exited" || handle.status === "created") containers.push({
|
|
96
|
+
handle,
|
|
97
|
+
labels: tuple,
|
|
98
|
+
unpauseAfterCapture: false
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (participant.decl.quiesce) yield* participant.decl.quiesce.pipe(Effect.scoped, Effect.ignore);
|
|
102
|
+
return containers;
|
|
103
|
+
}).pipe(Effect.withSpan("orchestrator.snapshot.capture.quiesce"));
|
|
104
|
+
/** Commit one container's writable layer to a temporary snapshot image tag. */
|
|
105
|
+
const commitContainerToImage = (handle, labels, runtime, participant, registerCommittedRef) => Effect.gen(function* () {
|
|
106
|
+
const imageRef = yield* runtime.pauseAndCommit(handle).pipe(Effect.catch(failPhase("commit", `pauseAndCommit failed for ${handle.name}`, participant.plugin)));
|
|
107
|
+
const snapshotTag = imageRef.tag;
|
|
108
|
+
yield* registerCommittedRef(imageRef);
|
|
109
|
+
if (!isRestorableContainerImageName(snapshotTag)) return yield* Effect.fail(new CapturePhaseError({
|
|
110
|
+
phase: "commit",
|
|
111
|
+
plugin: participant.plugin,
|
|
112
|
+
detail: `committed image for ${handle.name} did not receive a restorable snapshot tag`
|
|
113
|
+
}));
|
|
114
|
+
return {
|
|
115
|
+
captured: {
|
|
116
|
+
plugin: labels.plugin,
|
|
117
|
+
role: labels.role,
|
|
118
|
+
imageName: handle.imageName,
|
|
119
|
+
snapshotTag,
|
|
120
|
+
tarPath: containerImagesBundlePath()
|
|
121
|
+
},
|
|
122
|
+
imageRef
|
|
123
|
+
};
|
|
124
|
+
}).pipe(Effect.withSpan("orchestrator.snapshot.capture.commit"));
|
|
125
|
+
const saveCommittedImages = (committed, stagingDir, runtime) => Effect.gen(function* () {
|
|
126
|
+
if (committed.length === 0) return;
|
|
127
|
+
const fs = yield* FileSystem.FileSystem;
|
|
128
|
+
const tarPath = containerImagesBundlePath();
|
|
129
|
+
const tarDest = `${stagingDir}/${tarPath}`;
|
|
130
|
+
yield* fs.makeDirectory(`${stagingDir}/${SnapshotLayout.containersDir}`, { recursive: true }).pipe(Effect.catch(failPhase("save-images", `mkdir containers dir failed`)));
|
|
131
|
+
yield* Stream.run(runtime.saveImages(committed.map((entry) => entry.imageRef), { removeAfterSave: true }), fs.sink(tarDest)).pipe(Effect.catch(failPhase("save-images", `save ${committed.length} committed container images to ${tarDest} failed`)));
|
|
132
|
+
yield* verifyImageBundleTags(tarPath, yield* readImageBundleTags(tarDest, tarPath).pipe(Effect.catch(failImageBundleTagScan)), committed.map((entry) => entry.captured.snapshotTag)).pipe(Effect.catch(failImageBundleTagScan));
|
|
133
|
+
}).pipe(Effect.withSpan("orchestrator.snapshot.capture.save-images"));
|
|
134
|
+
const cleanupCommittedRefs = (runtime, refs) => Effect.forEach(refs, (ref) => runtime.removeImage(ref).pipe(Effect.catch((cause) => Effect.logWarning(`remove committed snapshot image ${ref.tag} failed during capture cleanup: ${String(cause)}`))), { concurrency: "unbounded" }).pipe(Effect.asVoid);
|
|
135
|
+
const isSafeSubtreePath = (relPath) => relPath !== "" && relPath !== "." && !relPath.startsWith("/") && !relPath.split(/[\\/]+/).includes("..");
|
|
136
|
+
/** Resolve declared subtrees against the live stack root. Missing
|
|
137
|
+
* `fine` subtrees are skipped; missing `fatal` subtrees fail before
|
|
138
|
+
* tar starts so the error names the responsible plugin. */
|
|
139
|
+
const resolveCapturedSubtrees = (subtrees, stackRoot) => Effect.gen(function* () {
|
|
140
|
+
const fs = yield* FileSystem.FileSystem;
|
|
141
|
+
const captured = [];
|
|
142
|
+
for (const subtree of subtrees) {
|
|
143
|
+
if (!isSafeSubtreePath(subtree.relPath)) return yield* Effect.fail(new CapturePhaseError({
|
|
144
|
+
phase: "tar-subtree",
|
|
145
|
+
plugin: subtree.plugin,
|
|
146
|
+
detail: `unsafe snapshot subtree path: ${subtree.relPath}`
|
|
147
|
+
}));
|
|
148
|
+
if (!(yield* fs.exists(`${stackRoot}/${subtree.relPath}`).pipe(Effect.catch(() => Effect.succeed(false))))) {
|
|
149
|
+
if (subtree.missingTolerance === "fatal") return yield* Effect.fail(new CapturePhaseError({
|
|
150
|
+
phase: "tar-subtree",
|
|
151
|
+
plugin: subtree.plugin,
|
|
152
|
+
detail: `required snapshot subtree missing: ${subtree.relPath}`
|
|
153
|
+
}));
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
captured.push(subtree);
|
|
157
|
+
}
|
|
158
|
+
return captured;
|
|
159
|
+
});
|
|
160
|
+
/** Tar the union of declared live subtrees into one `host-tree.tar`. */
|
|
161
|
+
const writeHostTreeTar = (stackRoot, subtrees, tarDest) => Effect.gen(function* () {
|
|
162
|
+
const fs = yield* FileSystem.FileSystem;
|
|
163
|
+
const archive = tarHostTree({
|
|
164
|
+
parentDir: stackRoot,
|
|
165
|
+
relPaths: subtrees.map((s) => s.relPath)
|
|
166
|
+
});
|
|
167
|
+
yield* Stream.run(archive, fs.sink(tarDest)).pipe(Effect.catch(failPhase("tar-host-tree", `tar host-tree (${subtrees.length} subtrees) to ${tarDest} failed`)));
|
|
168
|
+
}).pipe(Effect.withSpan("orchestrator.snapshot.capture.tar-host-tree"));
|
|
169
|
+
/**
|
|
170
|
+
* Populate `stagingDir` with a complete snapshot artifact.
|
|
171
|
+
*
|
|
172
|
+
* Discipline:
|
|
173
|
+
* - Iterate participants — no service names appear.
|
|
174
|
+
* - Pause-around-commit with always-unpause via `addFinalizer`.
|
|
175
|
+
* - Mode bits preserved by the host-tree tar primitive.
|
|
176
|
+
* - meta.json is written LAST so a crashed save leaves the artifact
|
|
177
|
+
* invisible to the catalog (architecture § "Partial saves are inert").
|
|
178
|
+
*
|
|
179
|
+
* Caller wraps this in `stageAndSwap` + `acquireReservation` + the
|
|
180
|
+
* stack lock.
|
|
181
|
+
*/
|
|
182
|
+
const runCapture = (inputs) => Effect.gen(function* () {
|
|
183
|
+
const fs = yield* FileSystem.FileSystem;
|
|
184
|
+
yield* Effect.annotateCurrentSpan({
|
|
185
|
+
"devstack.snapshot.phase": "capture",
|
|
186
|
+
"devstack.snapshot.id": inputs.snapshotId
|
|
187
|
+
});
|
|
188
|
+
const report = (progress) => inputs.onProgress?.(progress) ?? Effect.void;
|
|
189
|
+
return yield* Effect.scoped(Effect.gen(function* () {
|
|
190
|
+
const capturedContainers = [];
|
|
191
|
+
const paused = [];
|
|
192
|
+
yield* Effect.addFinalizer(() => Effect.gen(function* () {
|
|
193
|
+
if (paused.length > 0) yield* report({
|
|
194
|
+
phase: "resuming",
|
|
195
|
+
detail: `unpausing ${paused.length} container${paused.length === 1 ? "" : "s"}`,
|
|
196
|
+
pausedContainers: paused.length,
|
|
197
|
+
totalContainers: paused.length
|
|
198
|
+
});
|
|
199
|
+
yield* Effect.forEach(paused, (handle) => inputs.runtime.unpause(handle).pipe(Effect.catch((cause) => Effect.logWarning(`unpause(${handle.name}) failed during snapshot capture: ${String(cause)}`))), { concurrency: "unbounded" });
|
|
200
|
+
}).pipe(Effect.asVoid));
|
|
201
|
+
const plannedContainers = [];
|
|
202
|
+
const committedRefs = [];
|
|
203
|
+
yield* Effect.addFinalizer((exit) => Exit.isFailure(exit) ? cleanupCommittedRefs(inputs.runtime, committedRefs) : Effect.void);
|
|
204
|
+
yield* report({
|
|
205
|
+
phase: "quiescing",
|
|
206
|
+
detail: `checking ${inputs.participants.length} snapshot participant${inputs.participants.length === 1 ? "" : "s"}`
|
|
207
|
+
});
|
|
208
|
+
for (const participant of inputs.participants) {
|
|
209
|
+
const containers = yield* quiesceParticipant(participant, inputs.runtime);
|
|
210
|
+
for (const { handle, labels, unpauseAfterCapture } of containers) {
|
|
211
|
+
yield* validateCapturedContainer(handle, labels, participant);
|
|
212
|
+
plannedContainers.push({
|
|
213
|
+
handle,
|
|
214
|
+
labels,
|
|
215
|
+
unpauseAfterCapture,
|
|
216
|
+
participant
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
yield* detectContainerArtifactCollisions(plannedContainers);
|
|
221
|
+
const runningContainers = plannedContainers.filter((entry) => entry.unpauseAfterCapture);
|
|
222
|
+
if (runningContainers.length > 0) yield* report({
|
|
223
|
+
phase: "pausing",
|
|
224
|
+
detail: `pausing ${runningContainers.length} running container${runningContainers.length === 1 ? "" : "s"}`,
|
|
225
|
+
pausedContainers: 0,
|
|
226
|
+
totalContainers: runningContainers.length
|
|
227
|
+
});
|
|
228
|
+
const readyContainers = [];
|
|
229
|
+
for (const entry of plannedContainers) {
|
|
230
|
+
const { handle, unpauseAfterCapture } = entry;
|
|
231
|
+
if (unpauseAfterCapture) {
|
|
232
|
+
yield* inputs.runtime.pause(handle).pipe(Effect.catch(failPhase("pause", `pause failed for ${handle.name}`, entry.participant.plugin)));
|
|
233
|
+
paused.push(handle);
|
|
234
|
+
}
|
|
235
|
+
readyContainers.push({
|
|
236
|
+
...entry,
|
|
237
|
+
commitHandle: unpauseAfterCapture ? {
|
|
238
|
+
...handle,
|
|
239
|
+
status: "paused"
|
|
240
|
+
} : handle
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (runningContainers.length > 0) yield* report({
|
|
244
|
+
phase: "paused",
|
|
245
|
+
detail: `stack paused for snapshot (${paused.length}/${runningContainers.length} containers)`,
|
|
246
|
+
pausedContainers: paused.length,
|
|
247
|
+
totalContainers: runningContainers.length
|
|
248
|
+
});
|
|
249
|
+
const committedContainers = [];
|
|
250
|
+
if (readyContainers.length > 0) yield* report({
|
|
251
|
+
phase: "capturing-containers",
|
|
252
|
+
detail: `committing ${readyContainers.length} container${readyContainers.length === 1 ? "" : "s"}`,
|
|
253
|
+
pausedContainers: paused.length,
|
|
254
|
+
totalContainers: runningContainers.length
|
|
255
|
+
});
|
|
256
|
+
for (const { commitHandle, labels, participant } of readyContainers) {
|
|
257
|
+
const committed = yield* commitContainerToImage(commitHandle, labels, inputs.runtime, participant, (ref) => Effect.sync(() => {
|
|
258
|
+
committedRefs.push(ref);
|
|
259
|
+
}));
|
|
260
|
+
committedContainers.push(committed);
|
|
261
|
+
capturedContainers.push(committed.captured);
|
|
262
|
+
}
|
|
263
|
+
if (committedContainers.length > 0) yield* report({
|
|
264
|
+
phase: "saving-images",
|
|
265
|
+
detail: `saving ${committedContainers.length} committed image${committedContainers.length === 1 ? "" : "s"}`,
|
|
266
|
+
pausedContainers: paused.length,
|
|
267
|
+
totalContainers: runningContainers.length
|
|
268
|
+
});
|
|
269
|
+
yield* saveCommittedImages(committedContainers, inputs.stagingDir, inputs.runtime);
|
|
270
|
+
const subtrees = yield* resolveCapturedSubtrees(inputs.participants.flatMap((p) => p.decl.subtrees.map((relPath) => ({
|
|
271
|
+
plugin: p.plugin,
|
|
272
|
+
relPath,
|
|
273
|
+
missingTolerance: p.decl.missingTolerance,
|
|
274
|
+
secretMaterial: p.decl.secretMaterial ?? false
|
|
275
|
+
}))), inputs.runtimeStackRoot);
|
|
276
|
+
const hostTreeIncluded = subtrees.length > 0;
|
|
277
|
+
if (hostTreeIncluded) {
|
|
278
|
+
yield* report({
|
|
279
|
+
phase: "capturing-host-tree",
|
|
280
|
+
detail: `archiving ${subtrees.length} host subtree${subtrees.length === 1 ? "" : "s"}`,
|
|
281
|
+
pausedContainers: paused.length,
|
|
282
|
+
totalContainers: runningContainers.length
|
|
283
|
+
});
|
|
284
|
+
yield* writeHostTreeTar(inputs.runtimeStackRoot, subtrees, `${inputs.stagingDir}/${SnapshotLayout.hostTreeTar}`);
|
|
285
|
+
}
|
|
286
|
+
if (yield* fs.exists(inputs.stateFilePath).pipe(Effect.catch(() => Effect.succeed(false)))) {
|
|
287
|
+
yield* report({
|
|
288
|
+
phase: "saving-state",
|
|
289
|
+
detail: "copying runtime state",
|
|
290
|
+
pausedContainers: paused.length,
|
|
291
|
+
totalContainers: runningContainers.length
|
|
292
|
+
});
|
|
293
|
+
const stateDoc = yield* readSnapshotStateDocument(inputs.stateFilePath).pipe(Effect.catch(failPhase("read-state", `state.json failed schema validation`)));
|
|
294
|
+
yield* writeSnapshotStateDocument(`${inputs.stagingDir}/${SnapshotLayout.stateFile}`, stateDoc).pipe(Effect.catch(failPhase("write-state", `write state.json failed`)));
|
|
295
|
+
}
|
|
296
|
+
yield* report({
|
|
297
|
+
phase: "saving-contributions",
|
|
298
|
+
detail: `writing ${inputs.participants.length} contribution document${inputs.participants.length === 1 ? "" : "s"}`,
|
|
299
|
+
pausedContainers: paused.length,
|
|
300
|
+
totalContainers: runningContainers.length
|
|
301
|
+
});
|
|
302
|
+
yield* fs.makeDirectory(`${inputs.stagingDir}/${SnapshotLayout.contributionsDir}`, { recursive: true }).pipe(Effect.catch(failPhase("write-contribution", `mkdir contributions dir failed`)));
|
|
303
|
+
const identityMerged = {};
|
|
304
|
+
const participantKeys = [];
|
|
305
|
+
for (const participant of inputs.participants) {
|
|
306
|
+
const identity = yield* participant.captureIdentity;
|
|
307
|
+
for (const [k, v] of Object.entries(identity)) identityMerged[k] = v;
|
|
308
|
+
const state = yield* participant.captureContribution;
|
|
309
|
+
const doc = {
|
|
310
|
+
version: 1,
|
|
311
|
+
plugin: participant.plugin,
|
|
312
|
+
identity,
|
|
313
|
+
...state === void 0 ? {} : { opaqueState: {
|
|
314
|
+
encoding: "json",
|
|
315
|
+
value: state
|
|
316
|
+
} }
|
|
317
|
+
};
|
|
318
|
+
yield* fs.writeFileString(`${inputs.stagingDir}/${contributionPath(participant.plugin)}`, JSON.stringify(doc, null, 2)).pipe(Effect.catch(failPhase("write-contribution", `write contribution doc failed`, participant.plugin)));
|
|
319
|
+
participantKeys.push(participant.plugin);
|
|
320
|
+
}
|
|
321
|
+
yield* requireIdentity(identityMerged, "snapshot");
|
|
322
|
+
yield* report({
|
|
323
|
+
phase: "writing-metadata",
|
|
324
|
+
detail: "finalizing snapshot artifact",
|
|
325
|
+
pausedContainers: paused.length,
|
|
326
|
+
totalContainers: runningContainers.length
|
|
327
|
+
});
|
|
328
|
+
const meta = {
|
|
329
|
+
version: 3,
|
|
330
|
+
id: inputs.snapshotId,
|
|
331
|
+
label: inputs.label,
|
|
332
|
+
createdAt: Date.now(),
|
|
333
|
+
app: inputs.app,
|
|
334
|
+
stack: inputs.stack,
|
|
335
|
+
network: inputs.network,
|
|
336
|
+
hostTreeIncluded,
|
|
337
|
+
subtrees,
|
|
338
|
+
containers: capturedContainers,
|
|
339
|
+
identity: identityMerged,
|
|
340
|
+
participants: participantKeys
|
|
341
|
+
};
|
|
342
|
+
yield* fs.writeFileString(`${inputs.stagingDir}/${SnapshotLayout.metaFile}`, JSON.stringify(meta, null, 2)).pipe(Effect.catch(failPhase("write-meta", `write meta.json failed`)));
|
|
343
|
+
yield* writeArtifactIntegrity(inputs.stagingDir).pipe(Effect.catch(failPhase("write-integrity", `write integrity.json failed`)));
|
|
344
|
+
return meta;
|
|
345
|
+
}));
|
|
346
|
+
}).pipe(Effect.withSpan("orchestrator.snapshot.capture"));
|
|
347
|
+
//#endregion
|
|
348
|
+
export { runCapture };
|
|
349
|
+
|
|
350
|
+
//# sourceMappingURL=capture.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.mjs","names":["streamHostTreeTar"],"sources":["../../../src/orchestrators/snapshot/capture.ts"],"sourcesContent":["// Capture pipeline.\n//\n// Architecture § Snapshot lifecycle (capture half):\n//\n// Walk Snapshotable registry; group by plugin.\n// Validate the full capture set.\n// Pause every running managed container (unless already stopped).\n// While paused:\n// docker commit + tag committed images\n// tar host-tree subtrees with mode round-trip\n// collect metadata slice\n// Unpause (always — success AND failure)\n// Stage everything in tempdir.\n// Atomic rename → snapshot catalog entry.\n//\n// The orchestrator is name-blind: it walks `Snapshotable` contributions\n// without referencing any service. Containers are enumerated via the\n// label tuple the participant declared; subtrees via the relative\n// paths the participant declared.\n\nimport { Effect, Exit, FileSystem, Schema, Stream } from 'effect';\n\nimport type {\n\tContainerRuntime,\n\tContainerHandle,\n\tTaggedImageRef,\n} from '../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple, SnapshotableDecl } from '../../contracts/snapshotable.ts';\nimport { tarHostTree as streamHostTreeTar } from '../../substrate/runtime/host-tree-tar/index.ts';\nimport {\n\tcontainerImagesBundlePath,\n\tcontributionPath,\n\tSnapshotLayout,\n\ttype CapturedContainer,\n\ttype CapturedSubtree,\n\ttype ContributionDoc,\n\ttype IdentitySlice,\n\ttype SnapshotMetadata,\n\ttype SnapshotId,\n\tSNAPSHOT_META_VERSION,\n\tisRestorableContainerImageName,\n\tisSafeSnapshotPathSegment,\n\tSNAPSHOT_CONTRIBUTION_VERSION,\n} from './descriptor.ts';\nimport {\n\tImageBundleTagScanError,\n\treadImageBundleTags,\n\tverifyImageBundleTags,\n} from './image-bundle-tags.ts';\nimport { writeArtifactIntegrity } from './integrity.ts';\nimport { requireIdentity, type IdentityGuardError } from './identity-guard.ts';\nimport { readSnapshotStateDocument, writeSnapshotStateDocument } from './state-document.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** Tagged failure during one capture step. `phase` discriminates so\n * the user-facing message names the failing step. */\nexport class CapturePhaseError extends Schema.TaggedErrorClass<CapturePhaseError>()(\n\t'SnapshotCapturePhaseError',\n\t{\n\t\tphase: Schema.Literals([\n\t\t\t'enumerate-containers',\n\t\t\t'quiesce',\n\t\t\t'pause',\n\t\t\t'commit',\n\t\t\t'save-images',\n\t\t\t'tar-subtree',\n\t\t\t'tar-host-tree',\n\t\t\t'read-state',\n\t\t\t'write-state',\n\t\t\t'write-contribution',\n\t\t\t'write-meta',\n\t\t\t'write-integrity',\n\t\t\t'unpause',\n\t\t]),\n\t\tplugin: Schema.optional(Schema.String),\n\t\tdetail: Schema.String,\n\t\tcause: Schema.optional(Schema.Defect),\n\t},\n) {}\n\n// -----------------------------------------------------------------------------\n// Participant — what the orchestrator receives from each plugin\n// -----------------------------------------------------------------------------\n\n/** Capture-time projection of one `SnapshotableDecl` plus the\n * contributing plugin's identity. The orchestrator does not see\n * `SnapshotableDecl` directly — it consumes this normalized shape so\n * the contribution is closed over the plugin's key (the contract\n * doesn't carry it; the substrate stamps it at registration time). */\nexport interface SnapshotParticipant {\n\treadonly plugin: string;\n\treadonly decl: SnapshotableDecl;\n\t/** Identity slice this participant contributes to the guard. The\n\t * orchestrator merges contributions across participants — see\n\t * `identity-guard.ts`. Returned by the participant's preRestore\n\t * hook on RESTORE; on CAPTURE the substrate reads the live value\n\t * via this `captureIdentity` helper (separately wired). */\n\treadonly captureIdentity: Effect.Effect<IdentitySlice>;\n\t/** Opaque JSON metadata the plugin wants snapshotted. The\n\t * contribution document validates only an envelope around this\n\t * payload; the orchestrator never relies on the payload shape. */\n\treadonly captureContribution: Effect.Effect<unknown>;\n}\n\nexport type SnapshotCaptureProgressPhase =\n\t| 'quiescing'\n\t| 'pausing'\n\t| 'paused'\n\t| 'capturing-containers'\n\t| 'saving-images'\n\t| 'capturing-host-tree'\n\t| 'saving-state'\n\t| 'saving-contributions'\n\t| 'writing-metadata'\n\t| 'resuming';\n\nexport interface SnapshotCaptureProgress {\n\treadonly phase: SnapshotCaptureProgressPhase;\n\treadonly detail?: string;\n\treadonly pausedContainers?: number;\n\treadonly totalContainers?: number;\n}\n\nexport type SnapshotProgressReporter = (\n\tprogress: SnapshotCaptureProgress,\n) => Effect.Effect<void, never>;\n\n// -----------------------------------------------------------------------------\n// Staging — populate a directory; the caller wraps in stage-and-swap.\n// -----------------------------------------------------------------------------\n\nconst failPhase =\n\t(\n\t\tphase: CapturePhaseError['phase'],\n\t\tdetail: string,\n\t\tplugin?: string,\n\t): ((cause: unknown) => Effect.Effect<never, CapturePhaseError>) =>\n\t(cause) =>\n\t\tEffect.fail(new CapturePhaseError({ phase, plugin, detail, cause }));\n\nconst failImageBundleTagScan = (\n\tcause: ImageBundleTagScanError,\n): Effect.Effect<never, CapturePhaseError> =>\n\tEffect.fail(new CapturePhaseError({ phase: 'save-images', detail: cause.detail, cause }));\n\ninterface QuiescedContainer {\n\treadonly handle: ContainerHandle;\n\treadonly labels: ContainerLabelTuple;\n\treadonly unpauseAfterCapture: boolean;\n}\n\ninterface PlannedContainerCapture extends QuiescedContainer {\n\treadonly participant: SnapshotParticipant;\n}\n\ninterface ReadyContainerCapture extends PlannedContainerCapture {\n\treadonly commitHandle: ContainerHandle;\n}\n\ninterface CommittedContainerCapture {\n\treadonly captured: CapturedContainer;\n\treadonly imageRef: TaggedImageRef;\n}\n\nconst validateSnapshotPathSegment = (\n\tkind: string,\n\tvalue: string,\n\tphase: CapturePhaseError['phase'],\n\tplugin?: string,\n): Effect.Effect<void, CapturePhaseError> =>\n\tisSafeSnapshotPathSegment(value)\n\t\t? Effect.void\n\t\t: Effect.fail(\n\t\t\t\tnew CapturePhaseError({\n\t\t\t\t\tphase,\n\t\t\t\t\tplugin,\n\t\t\t\t\tdetail: `unsafe snapshot ${kind} path segment: ${value}`,\n\t\t\t\t}),\n\t\t\t);\n\nconst validateCapturedContainer = (\n\thandle: ContainerHandle,\n\tlabels: ContainerLabelTuple,\n\tparticipant: SnapshotParticipant,\n): Effect.Effect<void, CapturePhaseError> =>\n\tEffect.gen(function* () {\n\t\tyield* validateSnapshotPathSegment('plugin', labels.plugin, 'commit', participant.plugin);\n\t\tyield* validateSnapshotPathSegment('role', labels.role, 'commit', participant.plugin);\n\t\tif (!isRestorableContainerImageName(handle.imageName)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CapturePhaseError({\n\t\t\t\t\tphase: 'commit',\n\t\t\t\t\tplugin: participant.plugin,\n\t\t\t\t\tdetail: `container ${handle.name} imageName is not a restorable Docker tag destination: ${handle.imageName}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t});\n\nconst detectContainerArtifactCollisions = (\n\tplanned: ReadonlyArray<PlannedContainerCapture>,\n): Effect.Effect<void, CapturePhaseError> =>\n\tEffect.gen(function* () {\n\t\tconst seen = new Map<string, PlannedContainerCapture>();\n\t\tfor (const candidate of planned) {\n\t\t\tconst key = `${candidate.labels.plugin}/${candidate.labels.role}`;\n\t\t\tconst previous = seen.get(key);\n\t\t\tif (previous !== undefined) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CapturePhaseError({\n\t\t\t\t\t\tphase: 'commit',\n\t\t\t\t\t\tplugin: candidate.participant.plugin,\n\t\t\t\t\t\tdetail: `duplicate managed container snapshot identity ${key} for ${previous.handle.name} and ${candidate.handle.name}`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tseen.set(key, candidate);\n\t\t}\n\t});\n\n/**\n * Enumerate a participant's live managed containers, then run its\n * optional app-level quiesce hook. Already-paused, exited, and\n * created containers are committed as-is and are not unpaused by\n * capture finalization.\n *\n * Architecture § Invariants: \"A running container must be paused\n * around the writable-layer commit; the unpause must fire on both\n * success and failure paths (no orphaned paused containers). A\n * stopped container is already quiescent and must not be paused.\"\n *\n * The default quiescence is `pauseAndCommit`; participants that need\n * an application-level flush (postgres, RocksDB) declare a longer-grace\n * `quiesce` effect on their decl — the orchestrator runs it BEFORE\n * `pauseAndCommit`.\n */\nconst quiesceParticipant = (\n\tparticipant: SnapshotParticipant,\n\truntime: ContainerRuntime,\n): Effect.Effect<ReadonlyArray<QuiescedContainer>, CapturePhaseError> =>\n\tEffect.gen(function* () {\n\t\tconst labelTuples = participant.decl.managedContainers ?? [];\n\t\tconst containers: QuiescedContainer[] = [];\n\t\tfor (const tuple of labelTuples) {\n\t\t\tconst matched = yield* runtime\n\t\t\t\t.inspectByLabels(tuple)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t\t'enumerate-containers',\n\t\t\t\t\t\t\t`inspect by labels failed for ${tuple.plugin}/${tuple.role}`,\n\t\t\t\t\t\t\tparticipant.plugin,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\tfor (const handle of matched) {\n\t\t\t\tif (handle.status === 'running') {\n\t\t\t\t\tcontainers.push({ handle, labels: tuple, unpauseAfterCapture: true });\n\t\t\t\t} else if (\n\t\t\t\t\thandle.status === 'paused' ||\n\t\t\t\t\thandle.status === 'exited' ||\n\t\t\t\t\thandle.status === 'created'\n\t\t\t\t) {\n\t\t\t\t\tcontainers.push({ handle, labels: tuple, unpauseAfterCapture: false });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Run the optional app-level flush hook first; default pause\n\t\t// follows. The hook itself only signals failure-or-success in\n\t\t// `Cause<never>` (per `SnapshotableDecl.quiesce`'s typed shape) —\n\t\t// the orchestrator does not surface flush errors as a separate\n\t\t// tag; defects propagate through the underlying Cause.\n\t\tif (participant.decl.quiesce) {\n\t\t\tyield* participant.decl.quiesce.pipe(Effect.scoped, Effect.ignore);\n\t\t}\n\t\treturn containers;\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.capture.quiesce'));\n\n/** Commit one container's writable layer to a temporary snapshot image tag. */\nconst commitContainerToImage = (\n\thandle: ContainerHandle,\n\tlabels: ContainerLabelTuple,\n\truntime: ContainerRuntime,\n\tparticipant: SnapshotParticipant,\n\tregisterCommittedRef: (ref: TaggedImageRef) => Effect.Effect<void>,\n): Effect.Effect<CommittedContainerCapture, CapturePhaseError> =>\n\tEffect.gen(function* () {\n\t\t// pause+commit produces the image; the orchestrator does NOT\n\t\t// unpause here — `runCapture` owns the unpause-on-all-paths\n\t\t// finalizer.\n\t\tconst imageRef = yield* runtime\n\t\t\t.pauseAndCommit(handle)\n\t\t\t.pipe(\n\t\t\t\tEffect.catch(\n\t\t\t\t\tfailPhase('commit', `pauseAndCommit failed for ${handle.name}`, participant.plugin),\n\t\t\t\t),\n\t\t\t);\n\t\tconst snapshotTag = imageRef.tag;\n\t\tyield* registerCommittedRef(imageRef);\n\t\tif (!isRestorableContainerImageName(snapshotTag)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew CapturePhaseError({\n\t\t\t\t\tphase: 'commit',\n\t\t\t\t\tplugin: participant.plugin,\n\t\t\t\t\tdetail: `committed image for ${handle.name} did not receive a restorable snapshot tag`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tcaptured: {\n\t\t\t\tplugin: labels.plugin,\n\t\t\t\trole: labels.role,\n\t\t\t\timageName: handle.imageName,\n\t\t\t\tsnapshotTag,\n\t\t\t\ttarPath: containerImagesBundlePath(),\n\t\t\t},\n\t\t\timageRef,\n\t\t};\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.capture.commit'));\n\nconst saveCommittedImages = (\n\tcommitted: ReadonlyArray<CommittedContainerCapture>,\n\tstagingDir: string,\n\truntime: ContainerRuntime,\n): Effect.Effect<void, CapturePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tif (committed.length === 0) return;\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst tarPath = containerImagesBundlePath();\n\t\tconst tarDest = `${stagingDir}/${tarPath}`;\n\t\tyield* fs\n\t\t\t.makeDirectory(`${stagingDir}/${SnapshotLayout.containersDir}`, { recursive: true })\n\t\t\t.pipe(Effect.catch(failPhase('save-images', `mkdir containers dir failed`)));\n\t\tyield* Stream.run(\n\t\t\truntime.saveImages(\n\t\t\t\tcommitted.map((entry) => entry.imageRef),\n\t\t\t\t{ removeAfterSave: true },\n\t\t\t),\n\t\t\tfs.sink(tarDest),\n\t\t).pipe(\n\t\t\tEffect.catch(\n\t\t\t\tfailPhase(\n\t\t\t\t\t'save-images',\n\t\t\t\t\t`save ${committed.length} committed container images to ${tarDest} failed`,\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tconst savedTags = yield* readImageBundleTags(tarDest, tarPath).pipe(\n\t\t\tEffect.catch(failImageBundleTagScan),\n\t\t);\n\t\tyield* verifyImageBundleTags(\n\t\t\ttarPath,\n\t\t\tsavedTags,\n\t\t\tcommitted.map((entry) => entry.captured.snapshotTag),\n\t\t).pipe(Effect.catch(failImageBundleTagScan));\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.capture.save-images'));\n\nconst cleanupCommittedRefs = (\n\truntime: ContainerRuntime,\n\trefs: ReadonlyArray<TaggedImageRef>,\n): Effect.Effect<void> =>\n\tEffect.forEach(\n\t\trefs,\n\t\t(ref) =>\n\t\t\truntime\n\t\t\t\t.removeImage(ref)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.logWarning(\n\t\t\t\t\t\t\t`remove committed snapshot image ${ref.tag} failed during capture cleanup: ${String(\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t{ concurrency: 'unbounded' },\n\t).pipe(Effect.asVoid);\n\nconst isSafeSubtreePath = (relPath: string): boolean =>\n\trelPath !== '' &&\n\trelPath !== '.' &&\n\t!relPath.startsWith('/') &&\n\t!relPath.split(/[\\\\/]+/).includes('..');\n\n/** Resolve declared subtrees against the live stack root. Missing\n * `fine` subtrees are skipped; missing `fatal` subtrees fail before\n * tar starts so the error names the responsible plugin. */\nconst resolveCapturedSubtrees = (\n\tsubtrees: ReadonlyArray<CapturedSubtree>,\n\tstackRoot: string,\n): Effect.Effect<ReadonlyArray<CapturedSubtree>, CapturePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst captured: CapturedSubtree[] = [];\n\t\tfor (const subtree of subtrees) {\n\t\t\tif (!isSafeSubtreePath(subtree.relPath)) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew CapturePhaseError({\n\t\t\t\t\t\tphase: 'tar-subtree',\n\t\t\t\t\t\tplugin: subtree.plugin,\n\t\t\t\t\t\tdetail: `unsafe snapshot subtree path: ${subtree.relPath}`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst exists = yield* fs\n\t\t\t\t.exists(`${stackRoot}/${subtree.relPath}`)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\tif (!exists) {\n\t\t\t\tif (subtree.missingTolerance === 'fatal') {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew CapturePhaseError({\n\t\t\t\t\t\t\tphase: 'tar-subtree',\n\t\t\t\t\t\t\tplugin: subtree.plugin,\n\t\t\t\t\t\t\tdetail: `required snapshot subtree missing: ${subtree.relPath}`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcaptured.push(subtree);\n\t\t}\n\t\treturn captured;\n\t});\n\n/** Tar the union of declared live subtrees into one `host-tree.tar`. */\nconst writeHostTreeTar = (\n\tstackRoot: string,\n\tsubtrees: ReadonlyArray<CapturedSubtree>,\n\ttarDest: string,\n): Effect.Effect<void, CapturePhaseError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst archive = streamHostTreeTar({\n\t\t\tparentDir: stackRoot,\n\t\t\trelPaths: subtrees.map((s) => s.relPath),\n\t\t});\n\t\tyield* Stream.run(archive, fs.sink(tarDest)).pipe(\n\t\t\tEffect.catch(\n\t\t\t\tfailPhase(\n\t\t\t\t\t'tar-host-tree',\n\t\t\t\t\t`tar host-tree (${subtrees.length} subtrees) to ${tarDest} failed`,\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.capture.tar-host-tree'));\n\n// -----------------------------------------------------------------------------\n// Top-level capture — populate a staging directory; caller wraps in swap.\n// -----------------------------------------------------------------------------\n\nexport interface CaptureInputs {\n\treadonly stagingDir: string;\n\treadonly snapshotId: SnapshotId;\n\treadonly label: string | null;\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly network: string;\n\treadonly runtimeStackRoot: string;\n\treadonly stateFilePath: string;\n\treadonly participants: ReadonlyArray<SnapshotParticipant>;\n\treadonly runtime: ContainerRuntime;\n\treadonly onProgress?: SnapshotProgressReporter;\n}\n\n/**\n * Populate `stagingDir` with a complete snapshot artifact.\n *\n * Discipline:\n * - Iterate participants — no service names appear.\n * - Pause-around-commit with always-unpause via `addFinalizer`.\n * - Mode bits preserved by the host-tree tar primitive.\n * - meta.json is written LAST so a crashed save leaves the artifact\n * invisible to the catalog (architecture § \"Partial saves are inert\").\n *\n * Caller wraps this in `stageAndSwap` + `acquireReservation` + the\n * stack lock.\n */\nexport const runCapture = (\n\tinputs: CaptureInputs,\n): Effect.Effect<SnapshotMetadata, CapturePhaseError | IdentityGuardError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tyield* Effect.annotateCurrentSpan({\n\t\t\t'devstack.snapshot.phase': 'capture',\n\t\t\t'devstack.snapshot.id': inputs.snapshotId,\n\t\t});\n\n\t\tconst report = (progress: SnapshotCaptureProgress): Effect.Effect<void, never> =>\n\t\t\tinputs.onProgress?.(progress) ?? Effect.void;\n\n\t\treturn yield* Effect.scoped(\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// 1. Quiesce every participant, validate the full capture\n\t\t\t\t// set, then pause all running managed containers before\n\t\t\t\t// any artifact is written. The pause finalizer covers the\n\t\t\t\t// entire capture pipeline so container commits, host-tree\n\t\t\t\t// tar, scalar state, and contribution metadata share one\n\t\t\t\t// consistent snapshot window.\n\t\t\t\tconst capturedContainers: CapturedContainer[] = [];\n\t\t\t\tconst paused: ContainerHandle[] = [];\n\t\t\t\tyield* Effect.addFinalizer(() =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tif (paused.length > 0) {\n\t\t\t\t\t\t\tyield* report({\n\t\t\t\t\t\t\t\tphase: 'resuming',\n\t\t\t\t\t\t\t\tdetail: `unpausing ${paused.length} container${paused.length === 1 ? '' : 's'}`,\n\t\t\t\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\t\t\t\ttotalContainers: paused.length,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield* Effect.forEach(\n\t\t\t\t\t\t\tpaused,\n\t\t\t\t\t\t\t(handle) =>\n\t\t\t\t\t\t\t\tinputs.runtime\n\t\t\t\t\t\t\t\t\t.unpause(handle)\n\t\t\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\t\t\t\t\t\tEffect.logWarning(\n\t\t\t\t\t\t\t\t\t\t\t\t`unpause(${handle.name}) failed during snapshot capture: ${String(cause)}`,\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t{ concurrency: 'unbounded' },\n\t\t\t\t\t\t);\n\t\t\t\t\t}).pipe(Effect.asVoid),\n\t\t\t\t);\n\t\t\t\tconst plannedContainers: PlannedContainerCapture[] = [];\n\t\t\t\tconst committedRefs: TaggedImageRef[] = [];\n\t\t\t\tyield* Effect.addFinalizer((exit) =>\n\t\t\t\t\tExit.isFailure(exit) ? cleanupCommittedRefs(inputs.runtime, committedRefs) : Effect.void,\n\t\t\t\t);\n\t\t\t\tyield* report({\n\t\t\t\t\tphase: 'quiescing',\n\t\t\t\t\tdetail: `checking ${inputs.participants.length} snapshot participant${\n\t\t\t\t\t\tinputs.participants.length === 1 ? '' : 's'\n\t\t\t\t\t}`,\n\t\t\t\t});\n\t\t\t\tfor (const participant of inputs.participants) {\n\t\t\t\t\tconst containers = yield* quiesceParticipant(participant, inputs.runtime);\n\t\t\t\t\tfor (const { handle, labels, unpauseAfterCapture } of containers) {\n\t\t\t\t\t\tyield* validateCapturedContainer(handle, labels, participant);\n\t\t\t\t\t\tplannedContainers.push({\n\t\t\t\t\t\t\thandle,\n\t\t\t\t\t\t\tlabels,\n\t\t\t\t\t\t\tunpauseAfterCapture,\n\t\t\t\t\t\t\tparticipant,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tyield* detectContainerArtifactCollisions(plannedContainers);\n\t\t\t\tconst runningContainers = plannedContainers.filter((entry) => entry.unpauseAfterCapture);\n\t\t\t\tif (runningContainers.length > 0) {\n\t\t\t\t\tyield* report({\n\t\t\t\t\t\tphase: 'pausing',\n\t\t\t\t\t\tdetail: `pausing ${runningContainers.length} running container${\n\t\t\t\t\t\t\trunningContainers.length === 1 ? '' : 's'\n\t\t\t\t\t\t}`,\n\t\t\t\t\t\tpausedContainers: 0,\n\t\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst readyContainers: ReadyContainerCapture[] = [];\n\t\t\t\tfor (const entry of plannedContainers) {\n\t\t\t\t\tconst { handle, unpauseAfterCapture } = entry;\n\t\t\t\t\tif (unpauseAfterCapture) {\n\t\t\t\t\t\tyield* inputs.runtime\n\t\t\t\t\t\t\t.pause(handle)\n\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\t\t\t\tfailPhase('pause', `pause failed for ${handle.name}`, entry.participant.plugin),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\tpaused.push(handle);\n\t\t\t\t\t}\n\t\t\t\t\treadyContainers.push({\n\t\t\t\t\t\t...entry,\n\t\t\t\t\t\tcommitHandle: unpauseAfterCapture ? { ...handle, status: 'paused' as const } : handle,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (runningContainers.length > 0) {\n\t\t\t\t\tyield* report({\n\t\t\t\t\t\tphase: 'paused',\n\t\t\t\t\t\tdetail: `stack paused for snapshot (${paused.length}/${runningContainers.length} containers)`,\n\t\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// 2. Commit managed containers while the whole capture set\n\t\t\t\t// remains paused.\n\t\t\t\tconst committedContainers: CommittedContainerCapture[] = [];\n\t\t\t\tif (readyContainers.length > 0) {\n\t\t\t\t\tyield* report({\n\t\t\t\t\t\tphase: 'capturing-containers',\n\t\t\t\t\t\tdetail: `committing ${readyContainers.length} container${\n\t\t\t\t\t\t\treadyContainers.length === 1 ? '' : 's'\n\t\t\t\t\t\t}`,\n\t\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tfor (const { commitHandle, labels, participant } of readyContainers) {\n\t\t\t\t\tconst committed = yield* commitContainerToImage(\n\t\t\t\t\t\tcommitHandle,\n\t\t\t\t\t\tlabels,\n\t\t\t\t\t\tinputs.runtime,\n\t\t\t\t\t\tparticipant,\n\t\t\t\t\t\t(ref) =>\n\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\tcommittedRefs.push(ref);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tcommittedContainers.push(committed);\n\t\t\t\t\tcapturedContainers.push(committed.captured);\n\t\t\t\t}\n\t\t\t\tif (committedContainers.length > 0) {\n\t\t\t\t\tyield* report({\n\t\t\t\t\t\tphase: 'saving-images',\n\t\t\t\t\t\tdetail: `saving ${committedContainers.length} committed image${\n\t\t\t\t\t\t\tcommittedContainers.length === 1 ? '' : 's'\n\t\t\t\t\t\t}`,\n\t\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tyield* saveCommittedImages(committedContainers, inputs.stagingDir, inputs.runtime);\n\n\t\t\t\t// 3. Tar the host-tree subtrees declared by participants.\n\t\t\t\tconst declaredSubtrees: CapturedSubtree[] = inputs.participants.flatMap((p) =>\n\t\t\t\t\tp.decl.subtrees.map((relPath) => ({\n\t\t\t\t\t\tplugin: p.plugin,\n\t\t\t\t\t\trelPath,\n\t\t\t\t\t\tmissingTolerance: p.decl.missingTolerance,\n\t\t\t\t\t\tsecretMaterial: p.decl.secretMaterial ?? false,\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tconst subtrees = yield* resolveCapturedSubtrees(declaredSubtrees, inputs.runtimeStackRoot);\n\t\t\t\tconst hostTreeIncluded = subtrees.length > 0;\n\t\t\t\tif (hostTreeIncluded) {\n\t\t\t\t\tyield* report({\n\t\t\t\t\t\tphase: 'capturing-host-tree',\n\t\t\t\t\t\tdetail: `archiving ${subtrees.length} host subtree${subtrees.length === 1 ? '' : 's'}`,\n\t\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t\t});\n\t\t\t\t\tyield* writeHostTreeTar(\n\t\t\t\t\t\tinputs.runtimeStackRoot,\n\t\t\t\t\t\tsubtrees,\n\t\t\t\t\t\t`${inputs.stagingDir}/${SnapshotLayout.hostTreeTar}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// 4. Copy the scalar state file (best-effort missing-OK —\n\t\t\t\t// empty stack on first-boot has no state.json yet).\n\t\t\t\tconst stateExists = yield* fs\n\t\t\t\t\t.exists(inputs.stateFilePath)\n\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(false)));\n\t\t\t\tif (stateExists) {\n\t\t\t\t\tyield* report({\n\t\t\t\t\t\tphase: 'saving-state',\n\t\t\t\t\t\tdetail: 'copying runtime state',\n\t\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t\t});\n\t\t\t\t\tconst stateDoc = yield* readSnapshotStateDocument(inputs.stateFilePath).pipe(\n\t\t\t\t\t\tEffect.catch(failPhase('read-state', `state.json failed schema validation`)),\n\t\t\t\t\t);\n\t\t\t\t\tyield* writeSnapshotStateDocument(\n\t\t\t\t\t\t`${inputs.stagingDir}/${SnapshotLayout.stateFile}`,\n\t\t\t\t\t\tstateDoc,\n\t\t\t\t\t).pipe(Effect.catch(failPhase('write-state', `write state.json failed`)));\n\t\t\t\t}\n\n\t\t\t\t// 5. Write per-participant contribution docs + collect identity.\n\t\t\t\tyield* report({\n\t\t\t\t\tphase: 'saving-contributions',\n\t\t\t\t\tdetail: `writing ${inputs.participants.length} contribution document${\n\t\t\t\t\t\tinputs.participants.length === 1 ? '' : 's'\n\t\t\t\t\t}`,\n\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t});\n\t\t\t\tyield* fs\n\t\t\t\t\t.makeDirectory(`${inputs.stagingDir}/${SnapshotLayout.contributionsDir}`, {\n\t\t\t\t\t\trecursive: true,\n\t\t\t\t\t})\n\t\t\t\t\t.pipe(Effect.catch(failPhase('write-contribution', `mkdir contributions dir failed`)));\n\t\t\t\tconst identityMerged: Record<string, string> = {};\n\t\t\t\tconst participantKeys: string[] = [];\n\t\t\t\tfor (const participant of inputs.participants) {\n\t\t\t\t\tconst identity = yield* participant.captureIdentity;\n\t\t\t\t\tfor (const [k, v] of Object.entries(identity)) {\n\t\t\t\t\t\t// Conflict-on-same-key handled by identity-guard's\n\t\t\t\t\t\t// `mergeContributions` on the restore side; on capture we\n\t\t\t\t\t\t// last-write-wins (typical: only one plugin contributes\n\t\t\t\t\t\t// each key on capture).\n\t\t\t\t\t\tidentityMerged[k] = v;\n\t\t\t\t\t}\n\t\t\t\t\tconst state = yield* participant.captureContribution;\n\t\t\t\t\tconst doc: ContributionDoc = {\n\t\t\t\t\t\tversion: SNAPSHOT_CONTRIBUTION_VERSION,\n\t\t\t\t\t\tplugin: participant.plugin,\n\t\t\t\t\t\tidentity,\n\t\t\t\t\t\t...(state === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\topaqueState: {\n\t\t\t\t\t\t\t\t\t\tencoding: 'json' as const,\n\t\t\t\t\t\t\t\t\t\tvalue: state,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t};\n\t\t\t\t\tyield* fs\n\t\t\t\t\t\t.writeFileString(\n\t\t\t\t\t\t\t`${inputs.stagingDir}/${contributionPath(participant.plugin)}`,\n\t\t\t\t\t\t\tJSON.stringify(doc, null, 2),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\tEffect.catch(\n\t\t\t\t\t\t\t\tfailPhase(\n\t\t\t\t\t\t\t\t\t'write-contribution',\n\t\t\t\t\t\t\t\t\t`write contribution doc failed`,\n\t\t\t\t\t\t\t\t\tparticipant.plugin,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\tparticipantKeys.push(participant.plugin);\n\t\t\t\t}\n\t\t\t\tyield* requireIdentity(identityMerged, 'snapshot');\n\n\t\t\t\t// 6. Write meta.json, then integrity over the full artifact.\n\t\t\t\t// The caller publishes via stage-and-swap, so catalog\n\t\t\t\t// readers still never observe a half-written artifact.\n\t\t\t\tyield* report({\n\t\t\t\t\tphase: 'writing-metadata',\n\t\t\t\t\tdetail: 'finalizing snapshot artifact',\n\t\t\t\t\tpausedContainers: paused.length,\n\t\t\t\t\ttotalContainers: runningContainers.length,\n\t\t\t\t});\n\t\t\t\tconst meta: SnapshotMetadata = {\n\t\t\t\t\tversion: SNAPSHOT_META_VERSION,\n\t\t\t\t\tid: inputs.snapshotId,\n\t\t\t\t\tlabel: inputs.label,\n\t\t\t\t\tcreatedAt: Date.now(),\n\t\t\t\t\tapp: inputs.app,\n\t\t\t\t\tstack: inputs.stack,\n\t\t\t\t\tnetwork: inputs.network,\n\t\t\t\t\thostTreeIncluded,\n\t\t\t\t\tsubtrees,\n\t\t\t\t\tcontainers: capturedContainers,\n\t\t\t\t\tidentity: identityMerged,\n\t\t\t\t\tparticipants: participantKeys,\n\t\t\t\t};\n\t\t\t\tyield* fs\n\t\t\t\t\t.writeFileString(\n\t\t\t\t\t\t`${inputs.stagingDir}/${SnapshotLayout.metaFile}`,\n\t\t\t\t\t\tJSON.stringify(meta, null, 2),\n\t\t\t\t\t)\n\t\t\t\t\t.pipe(Effect.catch(failPhase('write-meta', `write meta.json failed`)));\n\t\t\t\tyield* writeArtifactIntegrity(inputs.stagingDir).pipe(\n\t\t\t\t\tEffect.catch(failPhase('write-integrity', `write integrity.json failed`)),\n\t\t\t\t);\n\n\t\t\t\treturn meta;\n\t\t\t}),\n\t\t);\n\t}).pipe(Effect.withSpan('orchestrator.snapshot.capture'));\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
//#region src/orchestrators/snapshot/descriptor.ts
|
|
3
|
+
/** Canonical file / directory names inside one snapshot artifact. */
|
|
4
|
+
const SnapshotLayout = {
|
|
5
|
+
metaFile: "meta.json",
|
|
6
|
+
stateFile: "state.json",
|
|
7
|
+
hostTreeTar: "host-tree.tar",
|
|
8
|
+
containersDir: "containers",
|
|
9
|
+
contributionsDir: "contributions",
|
|
10
|
+
integrityFile: "integrity.json"
|
|
11
|
+
};
|
|
12
|
+
const SNAPSHOT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
13
|
+
const SNAPSHOT_ID_RULE = "snapshot ids must be 1-128 characters matching [A-Za-z0-9][A-Za-z0-9_-]*";
|
|
14
|
+
const isValidSnapshotId = (value) => SNAPSHOT_ID_PATTERN.test(value) && isSafeSnapshotPathSegment(value);
|
|
15
|
+
const parseSnapshotId = (value) => isValidSnapshotId(value) ? value : null;
|
|
16
|
+
const isSafeSnapshotPathSegment = (segment) => segment.length > 0 && segment !== "." && segment !== ".." && !segment.includes("/") && !segment.includes("\\") && !segment.includes("\0");
|
|
17
|
+
const isSafeSnapshotRelativePath = (relPath) => relPath !== "" && relPath !== "." && !relPath.startsWith("/") && !relPath.includes("\\") && !relPath.includes("\0") && !relPath.split(/[\\/]+/).includes("..");
|
|
18
|
+
const isRestorableContainerImageName = (imageName) => imageName.length > 0 && imageName.trim() === imageName && !/\s/.test(imageName) && !imageName.includes("@") && !imageName.startsWith("sha256:");
|
|
19
|
+
const encodedSnapshotPathSegment = (value) => {
|
|
20
|
+
let hex = "";
|
|
21
|
+
for (const byte of new TextEncoder().encode(value)) hex += byte.toString(16).padStart(2, "0");
|
|
22
|
+
return `p-${hex}`;
|
|
23
|
+
};
|
|
24
|
+
/** Canonical sub-path for the deduplicated managed-container image bundle. */
|
|
25
|
+
const containerImagesBundlePath = () => `${SnapshotLayout.containersDir}/images.tar`;
|
|
26
|
+
/** Canonical sub-path for one participant's typed metadata slice. */
|
|
27
|
+
const contributionPath = (plugin) => `${SnapshotLayout.contributionsDir}/${encodedSnapshotPathSegment(plugin)}.json`;
|
|
28
|
+
/** A label tuple recorded for re-tag-on-restore. Mirrors
|
|
29
|
+
* `ContainerLabelTuple` from `contracts/snapshotable.ts` so the
|
|
30
|
+
* metadata file holds the same shape the runtime adapter filters on. */
|
|
31
|
+
const CapturedContainerSchema = Schema.Struct({
|
|
32
|
+
plugin: Schema.String,
|
|
33
|
+
role: Schema.String,
|
|
34
|
+
/** Original image name the supervisor used when last creating this
|
|
35
|
+
* container — must be re-tagged on restore so the supervisor's
|
|
36
|
+
* reuse-if-name-and-image-match probe adopts the restored image. */
|
|
37
|
+
imageName: Schema.String,
|
|
38
|
+
/** Temporary tag assigned to this committed container image inside
|
|
39
|
+
* the Docker save bundle. Restore loads the bundle once, then
|
|
40
|
+
* re-tags this source to `imageName`. */
|
|
41
|
+
snapshotTag: Schema.String,
|
|
42
|
+
/** Sub-path of the committed image bundle inside the artifact. */
|
|
43
|
+
tarPath: Schema.String
|
|
44
|
+
});
|
|
45
|
+
/** Captured host-tree subtree entry — preserved for missing-tolerance
|
|
46
|
+
* classification on restore. */
|
|
47
|
+
const CapturedSubtreeSchema = Schema.Struct({
|
|
48
|
+
plugin: Schema.String,
|
|
49
|
+
/** Subtree path relative to the runtime root (i.e. `<plugin>/...`). */
|
|
50
|
+
relPath: Schema.String,
|
|
51
|
+
/** `fatal` = restore must refuse if absent on disk at restore time;
|
|
52
|
+
* `fine` = silently skipped. Mirrors `SnapshotableDecl.missingTolerance`. */
|
|
53
|
+
missingTolerance: Schema.Literals(["fatal", "fine"]),
|
|
54
|
+
/** Did the subtree carry secret material at capture time? Drives
|
|
55
|
+
* the 0o600/0o700 mode round-trip discipline. */
|
|
56
|
+
secretMaterial: Schema.Boolean
|
|
57
|
+
});
|
|
58
|
+
/** Identity slice that fires the cross-chain refusal guard. The
|
|
59
|
+
* orchestrator threads contributions from participating plugins
|
|
60
|
+
* through this map — `chain` is the canonical case but other plugins
|
|
61
|
+
* may contribute (e.g. `postgres.majorVersion`). */
|
|
62
|
+
const IdentitySliceSchema = Schema.Record(Schema.String, Schema.String);
|
|
63
|
+
/** Plugin-owned JSON payload. The orchestrator validates only this
|
|
64
|
+
* envelope and never interprets `value`; plugins that need stronger
|
|
65
|
+
* guarantees own their schema at the plugin boundary. */
|
|
66
|
+
const OpaqueContributionStateSchema = Schema.Struct({
|
|
67
|
+
encoding: Schema.Literal("json"),
|
|
68
|
+
value: Schema.Unknown
|
|
69
|
+
});
|
|
70
|
+
/** Per-participant metadata envelope. The plugin payload is explicitly
|
|
71
|
+
* opaque so a successful decode cannot be mistaken for validation of
|
|
72
|
+
* plugin-owned state. */
|
|
73
|
+
const ContributionDocSchema = Schema.Struct({
|
|
74
|
+
version: Schema.Literal(1),
|
|
75
|
+
plugin: Schema.String,
|
|
76
|
+
identity: Schema.optional(IdentitySliceSchema),
|
|
77
|
+
opaqueState: Schema.optional(OpaqueContributionStateSchema)
|
|
78
|
+
});
|
|
79
|
+
/** Top-level metadata record. Architecture § Snapshot — single canonical
|
|
80
|
+
* metadata; "metadata absent = do not trust this directory". */
|
|
81
|
+
const SnapshotMetadataSchema = Schema.Struct({
|
|
82
|
+
version: Schema.Literal(3),
|
|
83
|
+
/** Stable snapshot id (caller-supplied or substrate-minted). */
|
|
84
|
+
id: Schema.String,
|
|
85
|
+
/** User-facing name. It is never used as filesystem authority. */
|
|
86
|
+
label: Schema.NullOr(Schema.String),
|
|
87
|
+
createdAt: Schema.Number,
|
|
88
|
+
app: Schema.String,
|
|
89
|
+
stack: Schema.String,
|
|
90
|
+
network: Schema.String,
|
|
91
|
+
/** Whether `host-tree.tar` is present in the artifact (false for
|
|
92
|
+
* the first-boot / empty-stack capture). */
|
|
93
|
+
hostTreeIncluded: Schema.Boolean,
|
|
94
|
+
subtrees: Schema.Array(CapturedSubtreeSchema),
|
|
95
|
+
containers: Schema.Array(CapturedContainerSchema),
|
|
96
|
+
identity: IdentitySliceSchema,
|
|
97
|
+
/** Plugin keys that contributed a contribution doc. Mirror is on
|
|
98
|
+
* disk under `contributions/<encoded-plugin>.json`. */
|
|
99
|
+
participants: Schema.Array(Schema.String)
|
|
100
|
+
});
|
|
101
|
+
const IntegrityFileSchema = Schema.Struct({
|
|
102
|
+
version: Schema.Literal(1),
|
|
103
|
+
/** Relative-path → hex-encoded SHA-256 of the file's bytes. */
|
|
104
|
+
hashes: Schema.Record(Schema.String, Schema.String)
|
|
105
|
+
});
|
|
106
|
+
//#endregion
|
|
107
|
+
export { ContributionDocSchema, IntegrityFileSchema, SNAPSHOT_ID_RULE, SnapshotLayout, SnapshotMetadataSchema, containerImagesBundlePath, contributionPath, isRestorableContainerImageName, isSafeSnapshotPathSegment, isSafeSnapshotRelativePath, parseSnapshotId };
|
|
108
|
+
|
|
109
|
+
//# sourceMappingURL=descriptor.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"descriptor.mjs","names":[],"sources":["../../../src/orchestrators/snapshot/descriptor.ts"],"sourcesContent":["// Snapshot artifact descriptor + metadata schema.\n//\n// Architecture § Snapshot:\n// \"A tar of declared filesystem subtrees, committed container images\n// (one per managed container identified by label tuples), a typed\n// metadata slice (identity-guard contributions + plugin's structured\n// state).\"\n//\n// On-disk layout of one snapshot artifact (under\n// `<stackRoot>/snapshots/<snapshotId>/`):\n//\n// meta.json — versioned metadata record, schema-decoded\n// state.json — copy of the stack's scalar state-store\n// host-tree.tar — tar of subtrees declared by participants\n// containers/images.tar — deduplicated Docker save bundle for all\n// committed managed-container images\n// contributions/<encoded-plugin>.json\n// — one typed metadata slice per participant\n// integrity.json — hashes over the above for resume / probe\n//\n// Layout discipline:\n// - `meta.json` is authoritative. Architecture § Snapshotable\n// \"Metadata is authoritative\": if it's absent or unparseable,\n// restore refuses (no silent partial-restore downgrade).\n// - Anything else missing surfaces as a phase-tagged\n// `SnapshotPartialError` and aborts before any destructive mutation.\n// - The artifact directory itself becomes \"complete\" only via the\n// stage-and-swap atomic rename — readers never observe a\n// half-written tree.\n\nimport { Schema } from 'effect';\n\nimport type { Brand } from '../../substrate/brand.ts';\n\n// -----------------------------------------------------------------------------\n// File layout — string constants the capture / restore code reaches for\n// -----------------------------------------------------------------------------\n\n/** Canonical file / directory names inside one snapshot artifact. */\nexport const SnapshotLayout = {\n\tmetaFile: 'meta.json',\n\tstateFile: 'state.json',\n\thostTreeTar: 'host-tree.tar',\n\tcontainersDir: 'containers',\n\tcontributionsDir: 'contributions',\n\tintegrityFile: 'integrity.json',\n} as const;\n\nexport type SnapshotId = Brand<string, 'SnapshotId'>;\n\nconst SNAPSHOT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;\n\nexport const SNAPSHOT_ID_RULE =\n\t'snapshot ids must be 1-128 characters matching [A-Za-z0-9][A-Za-z0-9_-]*';\n\nexport const isValidSnapshotId = (value: string): boolean =>\n\tSNAPSHOT_ID_PATTERN.test(value) && isSafeSnapshotPathSegment(value);\n\nexport const parseSnapshotId = (value: string): SnapshotId | null =>\n\tisValidSnapshotId(value) ? (value as SnapshotId) : null;\n\nexport const snapshotIdFromString = (value: string): SnapshotId => {\n\tconst parsed = parseSnapshotId(value);\n\tif (parsed === null) {\n\t\tthrow new Error(`${SNAPSHOT_ID_RULE}: ${value}`);\n\t}\n\treturn parsed;\n};\n\nexport const isSafeSnapshotPathSegment = (segment: string): boolean =>\n\tsegment.length > 0 &&\n\tsegment !== '.' &&\n\tsegment !== '..' &&\n\t!segment.includes('/') &&\n\t!segment.includes('\\\\') &&\n\t!segment.includes('\\0');\n\nexport const isSafeSnapshotRelativePath = (relPath: string): boolean =>\n\trelPath !== '' &&\n\trelPath !== '.' &&\n\t!relPath.startsWith('/') &&\n\t!relPath.includes('\\\\') &&\n\t!relPath.includes('\\0') &&\n\t!relPath.split(/[\\\\/]+/).includes('..');\n\nexport const isRestorableContainerImageName = (imageName: string): boolean =>\n\timageName.length > 0 &&\n\timageName.trim() === imageName &&\n\t!/\\s/.test(imageName) &&\n\t!imageName.includes('@') &&\n\t!imageName.startsWith('sha256:');\n\nconst snapshotPathSegment = (kind: string, value: string): string => {\n\tif (!isSafeSnapshotPathSegment(value)) {\n\t\tthrow new Error(`unsafe snapshot ${kind} path segment: ${value}`);\n\t}\n\treturn value;\n};\n\nconst encodedSnapshotPathSegment = (value: string): string => {\n\tlet hex = '';\n\tfor (const byte of new TextEncoder().encode(value)) {\n\t\thex += byte.toString(16).padStart(2, '0');\n\t}\n\treturn `p-${hex}`;\n};\n\n/** Canonical sub-path for one captured container image. */\nexport const containerImagePath = (plugin: string, role: string): string =>\n\t`${SnapshotLayout.containersDir}/${snapshotPathSegment(\n\t\t'plugin',\n\t\tplugin,\n\t)}/${snapshotPathSegment('role', role)}.tar`;\n\n/** Canonical sub-path for the deduplicated managed-container image bundle. */\nexport const containerImagesBundlePath = (): string => `${SnapshotLayout.containersDir}/images.tar`;\n\n/** Canonical sub-path for one participant's typed metadata slice. */\nexport const contributionPath = (plugin: string): string =>\n\t`${SnapshotLayout.contributionsDir}/${encodedSnapshotPathSegment(plugin)}.json`;\n\n// -----------------------------------------------------------------------------\n// Metadata schemas — versioned record\n// -----------------------------------------------------------------------------\n\n/** A label tuple recorded for re-tag-on-restore. Mirrors\n * `ContainerLabelTuple` from `contracts/snapshotable.ts` so the\n * metadata file holds the same shape the runtime adapter filters on. */\nexport const CapturedContainerSchema = Schema.Struct({\n\tplugin: Schema.String,\n\trole: Schema.String,\n\t/** Original image name the supervisor used when last creating this\n\t * container — must be re-tagged on restore so the supervisor's\n\t * reuse-if-name-and-image-match probe adopts the restored image. */\n\timageName: Schema.String,\n\t/** Temporary tag assigned to this committed container image inside\n\t * the Docker save bundle. Restore loads the bundle once, then\n\t * re-tags this source to `imageName`. */\n\tsnapshotTag: Schema.String,\n\t/** Sub-path of the committed image bundle inside the artifact. */\n\ttarPath: Schema.String,\n});\nexport type CapturedContainer = Schema.Schema.Type<typeof CapturedContainerSchema>;\n\n/** Captured host-tree subtree entry — preserved for missing-tolerance\n * classification on restore. */\nexport const CapturedSubtreeSchema = Schema.Struct({\n\tplugin: Schema.String,\n\t/** Subtree path relative to the runtime root (i.e. `<plugin>/...`). */\n\trelPath: Schema.String,\n\t/** `fatal` = restore must refuse if absent on disk at restore time;\n\t * `fine` = silently skipped. Mirrors `SnapshotableDecl.missingTolerance`. */\n\tmissingTolerance: Schema.Literals(['fatal', 'fine']),\n\t/** Did the subtree carry secret material at capture time? Drives\n\t * the 0o600/0o700 mode round-trip discipline. */\n\tsecretMaterial: Schema.Boolean,\n});\nexport type CapturedSubtree = Schema.Schema.Type<typeof CapturedSubtreeSchema>;\n\n/** Identity slice that fires the cross-chain refusal guard. The\n * orchestrator threads contributions from participating plugins\n * through this map — `chain` is the canonical case but other plugins\n * may contribute (e.g. `postgres.majorVersion`). */\nexport const IdentitySliceSchema = Schema.Record(Schema.String, Schema.String);\nexport type IdentitySlice = Schema.Schema.Type<typeof IdentitySliceSchema>;\n\nexport const SNAPSHOT_CONTRIBUTION_VERSION = 1 as const;\n\n/** Plugin-owned JSON payload. The orchestrator validates only this\n * envelope and never interprets `value`; plugins that need stronger\n * guarantees own their schema at the plugin boundary. */\nexport const OpaqueContributionStateSchema = Schema.Struct({\n\tencoding: Schema.Literal('json'),\n\tvalue: Schema.Unknown,\n});\nexport type OpaqueContributionState = Schema.Schema.Type<typeof OpaqueContributionStateSchema>;\n\n/** Per-participant metadata envelope. The plugin payload is explicitly\n * opaque so a successful decode cannot be mistaken for validation of\n * plugin-owned state. */\nexport const ContributionDocSchema = Schema.Struct({\n\tversion: Schema.Literal(SNAPSHOT_CONTRIBUTION_VERSION),\n\tplugin: Schema.String,\n\tidentity: Schema.optional(IdentitySliceSchema),\n\topaqueState: Schema.optional(OpaqueContributionStateSchema),\n});\nexport type ContributionDoc = Schema.Schema.Type<typeof ContributionDocSchema>;\n\n/** Schema version of the metadata record. Bumped when the on-disk\n * shape changes in a way that earlier readers cannot ignore. */\nexport const SNAPSHOT_META_VERSION = 3 as const;\n\n/** Top-level metadata record. Architecture § Snapshot — single canonical\n * metadata; \"metadata absent = do not trust this directory\". */\nexport const SnapshotMetadataSchema = Schema.Struct({\n\tversion: Schema.Literal(SNAPSHOT_META_VERSION),\n\t/** Stable snapshot id (caller-supplied or substrate-minted). */\n\tid: Schema.String,\n\t/** User-facing name. It is never used as filesystem authority. */\n\tlabel: Schema.NullOr(Schema.String),\n\tcreatedAt: Schema.Number,\n\tapp: Schema.String,\n\tstack: Schema.String,\n\tnetwork: Schema.String,\n\t/** Whether `host-tree.tar` is present in the artifact (false for\n\t * the first-boot / empty-stack capture). */\n\thostTreeIncluded: Schema.Boolean,\n\tsubtrees: Schema.Array(CapturedSubtreeSchema),\n\tcontainers: Schema.Array(CapturedContainerSchema),\n\tidentity: IdentitySliceSchema,\n\t/** Plugin keys that contributed a contribution doc. Mirror is on\n\t * disk under `contributions/<encoded-plugin>.json`. */\n\tparticipants: Schema.Array(Schema.String),\n});\nexport type SnapshotMetadata = Schema.Schema.Type<typeof SnapshotMetadataSchema>;\n\n/** Integrity record — per-file SHA-256 over the artifact's contents.\n * Separate file so restore can re-verify after an atomic swap landed\n * without re-reading the (potentially large) tar. */\nexport const SNAPSHOT_INTEGRITY_VERSION = 1 as const;\n\nexport const IntegrityFileSchema = Schema.Struct({\n\tversion: Schema.Literal(SNAPSHOT_INTEGRITY_VERSION),\n\t/** Relative-path → hex-encoded SHA-256 of the file's bytes. */\n\thashes: Schema.Record(Schema.String, Schema.String),\n});\nexport type IntegrityFile = Schema.Schema.Type<typeof IntegrityFileSchema>;\n\n// -----------------------------------------------------------------------------\n// Catalog-listing shape — projected by service.ts; partial / corrupt\n// entries collapse to `null` so the listing tolerates damage.\n// -----------------------------------------------------------------------------\n\nexport interface SnapshotCatalogEntry {\n\treadonly id: string;\n\treadonly directory: string;\n\treadonly metadata: SnapshotMetadata | null;\n}\n"],"mappings":";;;AAuCA,MAAa,iBAAiB;CAC7B,UAAU;CACV,WAAW;CACX,aAAa;CACb,eAAe;CACf,kBAAkB;CAClB,eAAe;CACf;AAID,MAAM,sBAAsB;AAE5B,MAAa,mBACZ;AAED,MAAa,qBAAqB,UACjC,oBAAoB,KAAK,MAAM,IAAI,0BAA0B,MAAM;AAEpE,MAAa,mBAAmB,UAC/B,kBAAkB,MAAM,GAAI,QAAuB;AAUpD,MAAa,6BAA6B,YACzC,QAAQ,SAAS,KACjB,YAAY,OACZ,YAAY,QACZ,CAAC,QAAQ,SAAS,IAAI,IACtB,CAAC,QAAQ,SAAS,KAAK,IACvB,CAAC,QAAQ,SAAS,KAAK;AAExB,MAAa,8BAA8B,YAC1C,YAAY,MACZ,YAAY,OACZ,CAAC,QAAQ,WAAW,IAAI,IACxB,CAAC,QAAQ,SAAS,KAAK,IACvB,CAAC,QAAQ,SAAS,KAAK,IACvB,CAAC,QAAQ,MAAM,SAAS,CAAC,SAAS,KAAK;AAExC,MAAa,kCAAkC,cAC9C,UAAU,SAAS,KACnB,UAAU,MAAM,KAAK,aACrB,CAAC,KAAK,KAAK,UAAU,IACrB,CAAC,UAAU,SAAS,IAAI,IACxB,CAAC,UAAU,WAAW,UAAU;AASjC,MAAM,8BAA8B,UAA0B;CAC7D,IAAI,MAAM;AACV,MAAK,MAAM,QAAQ,IAAI,aAAa,CAAC,OAAO,MAAM,CACjD,QAAO,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;AAE1C,QAAO,KAAK;;;AAWb,MAAa,kCAA0C,GAAG,eAAe,cAAc;;AAGvF,MAAa,oBAAoB,WAChC,GAAG,eAAe,iBAAiB,GAAG,2BAA2B,OAAO,CAAC;;;;AAS1E,MAAa,0BAA0B,OAAO,OAAO;CACpD,QAAQ,OAAO;CACf,MAAM,OAAO;;;;CAIb,WAAW,OAAO;;;;CAIlB,aAAa,OAAO;;CAEpB,SAAS,OAAO;CAChB,CAAC;;;AAKF,MAAa,wBAAwB,OAAO,OAAO;CAClD,QAAQ,OAAO;;CAEf,SAAS,OAAO;;;CAGhB,kBAAkB,OAAO,SAAS,CAAC,SAAS,OAAO,CAAC;;;CAGpD,gBAAgB,OAAO;CACvB,CAAC;;;;;AAOF,MAAa,sBAAsB,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;;;;AAQ9E,MAAa,gCAAgC,OAAO,OAAO;CAC1D,UAAU,OAAO,QAAQ,OAAO;CAChC,OAAO,OAAO;CACd,CAAC;;;;AAMF,MAAa,wBAAwB,OAAO,OAAO;CAClD,SAAS,OAAO,QAAA,EAAsC;CACtD,QAAQ,OAAO;CACf,UAAU,OAAO,SAAS,oBAAoB;CAC9C,aAAa,OAAO,SAAS,8BAA8B;CAC3D,CAAC;;;AASF,MAAa,yBAAyB,OAAO,OAAO;CACnD,SAAS,OAAO,QAAA,EAA8B;;CAE9C,IAAI,OAAO;;CAEX,OAAO,OAAO,OAAO,OAAO,OAAO;CACnC,WAAW,OAAO;CAClB,KAAK,OAAO;CACZ,OAAO,OAAO;CACd,SAAS,OAAO;;;CAGhB,kBAAkB,OAAO;CACzB,UAAU,OAAO,MAAM,sBAAsB;CAC7C,YAAY,OAAO,MAAM,wBAAwB;CACjD,UAAU;;;CAGV,cAAc,OAAO,MAAM,OAAO,OAAO;CACzC,CAAC;AAQF,MAAa,sBAAsB,OAAO,OAAO;CAChD,SAAS,OAAO,QAAA,EAAmC;;CAEnD,QAAQ,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO;CACnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|