@mysten-incubation/devstack 0.1.1 → 0.2.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/README.md +6 -3
- package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
- package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
- package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
- package/dashboard-ui/index.html +2 -2
- package/dist/api/define-capabilities.d.mts +1 -20
- package/dist/api/define-capabilities.mjs +15 -22
- package/dist/api/define-capabilities.mjs.map +1 -1
- package/dist/api/define-devstack-with.d.mts +7 -1
- package/dist/api/define-devstack-with.mjs.map +1 -1
- package/dist/api/define-devstack.mjs.map +1 -1
- package/dist/api/define-plugin.d.mts +2 -1
- package/dist/api/inference-network.d.mts +31 -17
- package/dist/api/inference-network.mjs +40 -43
- package/dist/api/inference-network.mjs.map +1 -1
- package/dist/api/load-config.mjs +88 -0
- package/dist/api/load-config.mjs.map +1 -0
- package/dist/api/mode-narrowed-factory.d.mts +1 -1
- package/dist/api/mode-narrowed-factory.mjs.map +1 -1
- package/dist/api/run-stack-internal.mjs +202 -0
- package/dist/api/run-stack-internal.mjs.map +1 -0
- package/dist/api/run-stack.d.mts +82 -31
- package/dist/api/run-stack.mjs +22 -141
- package/dist/api/run-stack.mjs.map +1 -1
- package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
- package/dist/build-integrations/dapp-kit/index.mjs +58 -0
- package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
- package/dist/build-integrations/playwright/config.d.mts +1 -30
- package/dist/build-integrations/playwright/config.mjs +1 -27
- package/dist/build-integrations/playwright/config.mjs.map +1 -1
- package/dist/build-integrations/playwright/errors.d.mts +4 -7
- package/dist/build-integrations/playwright/errors.mjs.map +1 -1
- package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
- package/dist/build-integrations/playwright/global-setup.mjs +142 -218
- package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
- package/dist/build-integrations/playwright/index.d.mts +2 -2
- package/dist/build-integrations/playwright/index.mjs +2 -2
- package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
- package/dist/build-integrations/playwright/stack-context.mjs +4 -2
- package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
- package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
- package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
- package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
- package/dist/build-integrations/runtime/discover.d.mts +6 -4
- package/dist/build-integrations/runtime/discover.mjs +15 -4
- package/dist/build-integrations/runtime/discover.mjs.map +1 -1
- package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
- package/dist/build-integrations/runtime/errors.mjs.map +1 -1
- package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
- package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
- package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
- package/dist/build-integrations/vite/index.d.mts +84 -19
- package/dist/build-integrations/vite/index.mjs +203 -28
- package/dist/build-integrations/vite/index.mjs.map +1 -1
- package/dist/build-integrations/vitest/config.d.mts +20 -2
- package/dist/build-integrations/vitest/config.mjs +16 -4
- package/dist/build-integrations/vitest/config.mjs.map +1 -1
- package/dist/build-integrations/vitest/env.d.mts +18 -10
- package/dist/build-integrations/vitest/env.mjs +11 -10
- package/dist/build-integrations/vitest/env.mjs.map +1 -1
- package/dist/build-integrations/vitest/errors.d.mts +7 -11
- package/dist/build-integrations/vitest/errors.mjs +3 -4
- package/dist/build-integrations/vitest/errors.mjs.map +1 -1
- package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
- package/dist/build-integrations/vitest/global-setup.mjs +156 -0
- package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
- package/dist/build-integrations/vitest/index.d.mts +3 -2
- package/dist/build-integrations/vitest/index.mjs +3 -2
- package/dist/build-integrations/vitest/setup.mjs +2 -2
- package/dist/build-integrations/vitest/setup.mjs.map +1 -1
- package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
- package/dist/build-integrations/vitest/stack-context.mjs +3 -2
- package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
- package/dist/cli/bail.mjs.map +1 -1
- package/dist/cli/doctor-probes.mjs +1 -3
- package/dist/cli/doctor-probes.mjs.map +1 -1
- package/dist/cli/main.d.mts +23 -1
- package/dist/cli/main.mjs +63 -8
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/prune-direct.mjs.map +1 -1
- package/dist/cli/snapshot-reader.mjs.map +1 -1
- package/dist/cli/up-lifecycle.mjs.map +1 -1
- package/dist/cli/wirings/apply.mjs +28 -21
- package/dist/cli/wirings/apply.mjs.map +1 -1
- package/dist/cli/wirings/codegen.mjs +108 -0
- package/dist/cli/wirings/codegen.mjs.map +1 -0
- package/dist/cli/wirings/config-loader.mjs +12 -62
- package/dist/cli/wirings/config-loader.mjs.map +1 -1
- package/dist/cli/wirings/dump-ids.mjs +86 -0
- package/dist/cli/wirings/dump-ids.mjs.map +1 -0
- package/dist/cli/wirings/engine-command.mjs +1 -1
- package/dist/cli/wirings/engine-command.mjs.map +1 -1
- package/dist/cli/wirings/identity.mjs +2 -2
- package/dist/cli/wirings/identity.mjs.map +1 -1
- package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
- package/dist/cli/wirings/read-devstack-version.mjs +17 -0
- package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
- package/dist/cli/wirings/snapshot.mjs +27 -34
- package/dist/cli/wirings/snapshot.mjs.map +1 -1
- package/dist/cli/wirings/up-ipc.mjs +147 -0
- package/dist/cli/wirings/up-ipc.mjs.map +1 -0
- package/dist/cli/wirings/up.mjs +218 -198
- package/dist/cli/wirings/up.mjs.map +1 -1
- package/dist/cli/wirings/wipe.mjs +1 -1
- package/dist/cli/wirings/wipe.mjs.map +1 -1
- package/dist/contracts/chain-probe.d.mts +1 -1
- package/dist/contracts/chain-probe.mjs +1 -1
- package/dist/contracts/chain-probe.mjs.map +1 -1
- package/dist/contracts/codegenable.d.mts +60 -6
- package/dist/contracts/codegenable.mjs +28 -0
- package/dist/contracts/codegenable.mjs.map +1 -0
- package/dist/contracts/config-bindings.mjs +162 -0
- package/dist/contracts/config-bindings.mjs.map +1 -0
- package/dist/contracts/container-runtime.d.mts +23 -17
- package/dist/contracts/plugin-expander.mjs.map +1 -1
- package/dist/contracts/snapshotable.d.mts +5 -7
- package/dist/contracts/wallet-protocol.d.mts +2 -5
- package/dist/contracts/wallet-protocol.mjs +2 -5
- package/dist/contracts/wallet-protocol.mjs.map +1 -1
- package/dist/index.d.mts +21 -26
- package/dist/index.mjs +8 -9
- package/dist/orchestrators/boot.d.mts +28 -0
- package/dist/orchestrators/boot.mjs +440 -0
- package/dist/orchestrators/boot.mjs.map +1 -0
- package/dist/orchestrators/codegen/bindings.d.mts +13 -1
- package/dist/orchestrators/codegen/bindings.mjs +23 -9
- package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
- package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
- package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
- package/dist/orchestrators/codegen/emit.mjs +1 -1
- package/dist/orchestrators/codegen/emit.mjs.map +1 -1
- package/dist/orchestrators/codegen/errors.mjs +21 -1
- package/dist/orchestrators/codegen/errors.mjs.map +1 -1
- package/dist/orchestrators/codegen/format.mjs +2 -0
- package/dist/orchestrators/codegen/format.mjs.map +1 -1
- package/dist/orchestrators/codegen/gitignore.mjs +30 -11
- package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
- package/dist/orchestrators/codegen/id-config.mjs +107 -0
- package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
- package/dist/orchestrators/codegen/output-location.mjs +23 -32
- package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
- package/dist/orchestrators/codegen/paths.mjs +8 -1
- package/dist/orchestrators/codegen/paths.mjs.map +1 -1
- package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
- package/dist/orchestrators/codegen/service.mjs +286 -58
- package/dist/orchestrators/codegen/service.mjs.map +1 -1
- package/dist/orchestrators/layers.mjs +31 -0
- package/dist/orchestrators/layers.mjs.map +1 -0
- package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
- package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
- package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
- package/dist/orchestrators/network-options.d.mts +52 -0
- package/dist/orchestrators/network-options.mjs +43 -0
- package/dist/orchestrators/network-options.mjs.map +1 -0
- package/dist/orchestrators/router/cleanup.mjs.map +1 -1
- package/dist/orchestrators/router/cors.mjs.map +1 -1
- package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
- package/dist/orchestrators/router/errors.mjs.map +1 -1
- package/dist/orchestrators/router/file-provider.mjs.map +1 -1
- package/dist/orchestrators/router/hostname.mjs.map +1 -1
- package/dist/orchestrators/router/profile.mjs +1 -1
- package/dist/orchestrators/router/profile.mjs.map +1 -1
- package/dist/orchestrators/router/service.d.mts +2 -2
- package/dist/orchestrators/router/service.mjs +12 -27
- package/dist/orchestrators/router/service.mjs.map +1 -1
- package/dist/orchestrators/router/traefik-container.mjs +1 -1
- package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
- package/dist/orchestrators/snapshot/capture.mjs +171 -195
- package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
- package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
- package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
- package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
- package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
- package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
- package/dist/orchestrators/snapshot/index.mjs +1 -4
- package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
- package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
- package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
- package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
- package/dist/orchestrators/snapshot/prune.mjs +40 -31
- package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
- package/dist/orchestrators/snapshot/restore.mjs +221 -196
- package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
- package/dist/orchestrators/snapshot/service.mjs +72 -62
- package/dist/orchestrators/snapshot/service.mjs.map +1 -1
- package/dist/orchestrators/snapshot/wipe.mjs +67 -56
- package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
- package/dist/plugins/account/codegen.mjs +3 -0
- package/dist/plugins/account/codegen.mjs.map +1 -1
- package/dist/plugins/account/errors.d.mts +2 -2
- package/dist/plugins/account/errors.mjs +1 -4
- package/dist/plugins/account/errors.mjs.map +1 -1
- package/dist/plugins/account/funding.mjs +3 -27
- package/dist/plugins/account/funding.mjs.map +1 -1
- package/dist/plugins/account/index.d.mts +3 -8
- package/dist/plugins/account/index.mjs +71 -35
- package/dist/plugins/account/index.mjs.map +1 -1
- package/dist/plugins/account/keypair.d.mts +8 -7
- package/dist/plugins/account/keypair.mjs +5 -18
- package/dist/plugins/account/keypair.mjs.map +1 -1
- package/dist/plugins/account/lease.mjs.map +1 -1
- package/dist/plugins/account/registry.d.mts +1 -46
- package/dist/plugins/account/registry.mjs.map +1 -1
- package/dist/plugins/account/service.d.mts +43 -34
- package/dist/plugins/account/service.mjs +9 -54
- package/dist/plugins/account/service.mjs.map +1 -1
- package/dist/plugins/account/snapshot.mjs.map +1 -1
- package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
- package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
- package/dist/plugins/account/variants/signer.mjs.map +1 -1
- package/dist/plugins/action/discriminator.mjs.map +1 -1
- package/dist/plugins/action/errors.mjs +1 -4
- package/dist/plugins/action/errors.mjs.map +1 -1
- package/dist/plugins/action/execute.mjs +3 -4
- package/dist/plugins/action/execute.mjs.map +1 -1
- package/dist/plugins/action/index.d.mts +2 -2
- package/dist/plugins/action/index.mjs +7 -11
- package/dist/plugins/action/index.mjs.map +1 -1
- package/dist/plugins/action/service.d.mts +5 -7
- package/dist/plugins/action/service.mjs +2 -16
- package/dist/plugins/action/service.mjs.map +1 -1
- package/dist/plugins/coin/address-resolution.mjs.map +1 -1
- package/dist/plugins/coin/codegen.mjs +97 -16
- package/dist/plugins/coin/codegen.mjs.map +1 -1
- package/dist/plugins/coin/discovery.mjs.map +1 -1
- package/dist/plugins/coin/errors.mjs +1 -4
- package/dist/plugins/coin/errors.mjs.map +1 -1
- package/dist/plugins/coin/index.d.mts +4 -34
- package/dist/plugins/coin/index.mjs +47 -28
- package/dist/plugins/coin/index.mjs.map +1 -1
- package/dist/plugins/coin/metadata.d.mts +1 -0
- package/dist/plugins/coin/metadata.mjs +8 -9
- package/dist/plugins/coin/metadata.mjs.map +1 -1
- package/dist/plugins/coin/mint.mjs +7 -21
- package/dist/plugins/coin/mint.mjs.map +1 -1
- package/dist/plugins/coin/registry.mjs +33 -20
- package/dist/plugins/coin/registry.mjs.map +1 -1
- package/dist/plugins/coin/service.d.mts +1 -1
- package/dist/plugins/coin/service.mjs +1 -8
- package/dist/plugins/coin/service.mjs.map +1 -1
- package/dist/plugins/coin/snapshot.mjs.map +1 -1
- package/dist/plugins/coin/type-strings.mjs.map +1 -1
- package/dist/plugins/dashboard/domain.mjs +106 -167
- package/dist/plugins/dashboard/domain.mjs.map +1 -1
- package/dist/plugins/dashboard/index.mjs +13 -13
- package/dist/plugins/dashboard/index.mjs.map +1 -1
- package/dist/plugins/dashboard/origin-policy.mjs +3 -3
- package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
- package/dist/plugins/dashboard/routable.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/root.mjs +23 -44
- package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/types.mjs +37 -91
- package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
- package/dist/plugins/dashboard/schema.mjs.map +1 -1
- package/dist/plugins/dashboard/server.mjs.map +1 -1
- package/dist/plugins/deepbook/codegen.d.mts +12 -11
- package/dist/plugins/deepbook/codegen.mjs +108 -11
- package/dist/plugins/deepbook/codegen.mjs.map +1 -1
- package/dist/plugins/deepbook/deploy.mjs +7 -14
- package/dist/plugins/deepbook/deploy.mjs.map +1 -1
- package/dist/plugins/deepbook/errors.mjs +4 -2
- package/dist/plugins/deepbook/errors.mjs.map +1 -1
- package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
- package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/deepbook/hash.mjs.map +1 -1
- package/dist/plugins/deepbook/index.d.mts +38 -34
- package/dist/plugins/deepbook/index.mjs +133 -64
- package/dist/plugins/deepbook/index.mjs.map +1 -1
- package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
- package/dist/plugins/deepbook/pyth/index.mjs +4 -8
- package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
- package/dist/plugins/deepbook/snapshot.mjs +0 -1
- package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
- package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
- package/dist/plugins/deepbook/types.d.mts +2 -1
- package/dist/plugins/deepbook/types.mjs.map +1 -1
- package/dist/plugins/faucet/dispatcher.d.mts +3 -3
- package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
- package/dist/plugins/faucet/errors.mjs.map +1 -1
- package/dist/plugins/faucet/http.mjs +2 -10
- package/dist/plugins/faucet/http.mjs.map +1 -1
- package/dist/plugins/faucet/index.mjs +0 -1
- package/dist/plugins/faucet/index.mjs.map +1 -1
- package/dist/plugins/host-service/errors.d.mts +1 -3
- package/dist/plugins/host-service/errors.mjs +1 -2
- package/dist/plugins/host-service/errors.mjs.map +1 -1
- package/dist/plugins/host-service/index.d.mts +1 -2
- package/dist/plugins/host-service/index.mjs +11 -11
- package/dist/plugins/host-service/index.mjs.map +1 -1
- package/dist/plugins/host-service/routable.mjs.map +1 -1
- package/dist/plugins/host-service/service.mjs +13 -13
- package/dist/plugins/host-service/service.mjs.map +1 -1
- package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
- package/dist/plugins/internal/codegen-helpers.mjs +2 -0
- package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
- package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
- package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
- package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
- package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
- package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
- package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
- package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
- package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
- package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
- package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
- package/dist/plugins/package/build.mjs +2 -2
- package/dist/plugins/package/build.mjs.map +1 -1
- package/dist/plugins/package/codegen.d.mts +7 -14
- package/dist/plugins/package/codegen.mjs +187 -59
- package/dist/plugins/package/codegen.mjs.map +1 -1
- package/dist/plugins/package/dep-resolution.mjs +51 -3
- package/dist/plugins/package/dep-resolution.mjs.map +1 -1
- package/dist/plugins/package/errors.mjs +1 -4
- package/dist/plugins/package/errors.mjs.map +1 -1
- package/dist/plugins/package/git-source.d.mts +18 -0
- package/dist/plugins/package/git-source.mjs +119 -0
- package/dist/plugins/package/git-source.mjs.map +1 -0
- package/dist/plugins/package/index.d.mts +28 -19
- package/dist/plugins/package/index.mjs +107 -32
- package/dist/plugins/package/index.mjs.map +1 -1
- package/dist/plugins/package/mode-known.mjs +2 -2
- package/dist/plugins/package/mode-known.mjs.map +1 -1
- package/dist/plugins/package/mode-local.mjs +18 -35
- package/dist/plugins/package/mode-local.mjs.map +1 -1
- package/dist/plugins/package/publish-executor.mjs +13 -8
- package/dist/plugins/package/publish-executor.mjs.map +1 -1
- package/dist/plugins/package/publish-output.d.mts +1 -11
- package/dist/plugins/package/publish-output.mjs +1 -9
- package/dist/plugins/package/publish-output.mjs.map +1 -1
- package/dist/plugins/package/registry.d.mts +1 -1
- package/dist/plugins/package/registry.mjs +26 -14
- package/dist/plugins/package/registry.mjs.map +1 -1
- package/dist/plugins/package/service.mjs.map +1 -1
- package/dist/plugins/package/snapshot.mjs.map +1 -1
- package/dist/plugins/router-entrypoints.mjs +1 -3
- package/dist/plugins/router-entrypoints.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
- package/dist/plugins/seal/codegen.d.mts +1 -5
- package/dist/plugins/seal/codegen.mjs +83 -12
- package/dist/plugins/seal/codegen.mjs.map +1 -1
- package/dist/plugins/seal/config-render.mjs +2 -6
- package/dist/plugins/seal/config-render.mjs.map +1 -1
- package/dist/plugins/seal/deploy.mjs +18 -29
- package/dist/plugins/seal/deploy.mjs.map +1 -1
- package/dist/plugins/seal/errors.d.mts +4 -5
- package/dist/plugins/seal/errors.mjs +1 -8
- package/dist/plugins/seal/errors.mjs.map +1 -1
- package/dist/plugins/seal/index.d.mts +7 -28
- package/dist/plugins/seal/index.mjs +69 -47
- package/dist/plugins/seal/index.mjs.map +1 -1
- package/dist/plugins/seal/key-manager.mjs.map +1 -1
- package/dist/plugins/seal/key-server.mjs +1 -6
- package/dist/plugins/seal/key-server.mjs.map +1 -1
- package/dist/plugins/seal/keygen.mjs +2 -3
- package/dist/plugins/seal/keygen.mjs.map +1 -1
- package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
- package/dist/plugins/seal/mode/live.mjs +1 -1
- package/dist/plugins/seal/mode/live.mjs.map +1 -1
- package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
- package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
- package/dist/plugins/seal/plugin-key.mjs.map +1 -1
- package/dist/plugins/seal/registry-publish.mjs.map +1 -1
- package/dist/plugins/seal/routable.mjs.map +1 -1
- package/dist/plugins/seal/service.mjs.map +1 -1
- package/dist/plugins/seal/snapshot.mjs +1 -2
- package/dist/plugins/seal/snapshot.mjs.map +1 -1
- package/dist/plugins/sui/auto-tick.mjs +5 -5
- package/dist/plugins/sui/auto-tick.mjs.map +1 -1
- package/dist/plugins/sui/chain-build-container.mjs +2 -2
- package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
- package/dist/plugins/sui/chain-probe.mjs +4 -4
- package/dist/plugins/sui/chain-probe.mjs.map +1 -1
- package/dist/plugins/sui/codegen.d.mts +9 -7
- package/dist/plugins/sui/codegen.mjs +49 -46
- package/dist/plugins/sui/codegen.mjs.map +1 -1
- package/dist/plugins/sui/errors.d.mts +1 -1
- package/dist/plugins/sui/errors.mjs +1 -9
- package/dist/plugins/sui/errors.mjs.map +1 -1
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
- package/dist/plugins/sui/exec/index.mjs.map +1 -0
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
- package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
- package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
- package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
- package/dist/plugins/sui/fork-orchestration.mjs +13 -23
- package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
- package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
- package/dist/plugins/sui/index.d.mts +34 -83
- package/dist/plugins/sui/index.mjs +200 -68
- package/dist/plugins/sui/index.mjs.map +1 -1
- package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
- package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
- package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
- package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
- package/dist/plugins/sui/log-attrs.mjs +11 -0
- package/dist/plugins/sui/log-attrs.mjs.map +1 -0
- package/dist/plugins/sui/mode/external.mjs +4 -12
- package/dist/plugins/sui/mode/external.mjs.map +1 -1
- package/dist/plugins/sui/mode/fork.mjs +19 -16
- package/dist/plugins/sui/mode/fork.mjs.map +1 -1
- package/dist/plugins/sui/mode/live.mjs +4 -17
- package/dist/plugins/sui/mode/live.mjs.map +1 -1
- package/dist/plugins/sui/mode/local.d.mts +1 -0
- package/dist/plugins/sui/mode/local.mjs +203 -61
- package/dist/plugins/sui/mode/local.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
- package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared.d.mts +6 -7
- package/dist/plugins/sui/mode/shared.mjs.map +1 -1
- package/dist/plugins/sui/mode/spec.d.mts +23 -6
- package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
- package/dist/plugins/sui/move/index.mjs.map +1 -0
- package/dist/plugins/sui/move-summary-runner.mjs +8 -4
- package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
- package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
- package/dist/plugins/sui/network-resolver.d.mts +6 -6
- package/dist/plugins/sui/routable.mjs.map +1 -1
- package/dist/plugins/sui/service.mjs +10 -6
- package/dist/plugins/sui/service.mjs.map +1 -1
- package/dist/plugins/sui/snapshot.mjs +10 -5
- package/dist/plugins/sui/snapshot.mjs.map +1 -1
- package/dist/plugins/wallet/codegen.d.mts +8 -6
- package/dist/plugins/wallet/codegen.mjs +4 -10
- package/dist/plugins/wallet/codegen.mjs.map +1 -1
- package/dist/plugins/wallet/errors.mjs +1 -4
- package/dist/plugins/wallet/errors.mjs.map +1 -1
- package/dist/plugins/wallet/index.d.mts +3 -6
- package/dist/plugins/wallet/index.mjs +16 -21
- package/dist/plugins/wallet/index.mjs.map +1 -1
- package/dist/plugins/wallet/origin-policy.mjs +3 -3
- package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
- package/dist/plugins/wallet/pairing.mjs +6 -24
- package/dist/plugins/wallet/pairing.mjs.map +1 -1
- package/dist/plugins/wallet/protocol.mjs.map +1 -1
- package/dist/plugins/wallet/routable.mjs.map +1 -1
- package/dist/plugins/wallet/server.mjs +17 -24
- package/dist/plugins/wallet/server.mjs.map +1 -1
- package/dist/plugins/wallet/service.d.mts +2 -2
- package/dist/plugins/wallet/service.mjs +4 -15
- package/dist/plugins/wallet/service.mjs.map +1 -1
- package/dist/plugins/wallet/snapshot.mjs.map +1 -1
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/walrus/codegen.d.mts +2 -13
- package/dist/plugins/walrus/codegen.mjs +93 -28
- package/dist/plugins/walrus/codegen.mjs.map +1 -1
- package/dist/plugins/walrus/deploy-paths.mjs +2 -3
- package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
- package/dist/plugins/walrus/deploy.mjs +26 -19
- package/dist/plugins/walrus/deploy.mjs.map +1 -1
- package/dist/plugins/walrus/errors.mjs +1 -8
- package/dist/plugins/walrus/errors.mjs.map +1 -1
- package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
- package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/walrus/index.d.mts +13 -44
- package/dist/plugins/walrus/index.mjs +119 -122
- package/dist/plugins/walrus/index.mjs.map +1 -1
- package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
- package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
- package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
- package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
- package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
- package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
- package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
- package/dist/plugins/walrus/routable.mjs.map +1 -1
- package/dist/plugins/walrus/service.mjs.map +1 -1
- package/dist/plugins/walrus/snapshot.mjs +3 -3
- package/dist/plugins/walrus/snapshot.mjs.map +1 -1
- package/dist/plugins/walrus/storage-nodes.mjs +53 -14
- package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
- package/dist/plugins/walrus/wal-swap.mjs +4 -8
- package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
- package/dist/primitives/artifact-publisher.mjs.map +1 -1
- package/dist/primitives/cache.d.mts +1 -1
- package/dist/runtime/docker/client.mjs +47 -3
- package/dist/runtime/docker/client.mjs.map +1 -1
- package/dist/runtime/docker/container.mjs +37 -57
- package/dist/runtime/docker/container.mjs.map +1 -1
- package/dist/runtime/docker/errors.mjs.map +1 -1
- package/dist/runtime/docker/exec.mjs +2 -2
- package/dist/runtime/docker/exec.mjs.map +1 -1
- package/dist/runtime/docker/image.mjs +10 -11
- package/dist/runtime/docker/image.mjs.map +1 -1
- package/dist/runtime/docker/index.mjs +0 -1
- package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
- package/dist/runtime/docker/inventory.mjs +9 -9
- package/dist/runtime/docker/inventory.mjs.map +1 -1
- package/dist/runtime/docker/labels.mjs +12 -1
- package/dist/runtime/docker/labels.mjs.map +1 -1
- package/dist/runtime/docker/network.mjs +6 -6
- package/dist/runtime/docker/network.mjs.map +1 -1
- package/dist/runtime/docker/render-run-args.mjs.map +1 -1
- package/dist/runtime/docker/service.mjs +31 -45
- package/dist/runtime/docker/service.mjs.map +1 -1
- package/dist/runtime/docker/sweep.mjs +14 -64
- package/dist/runtime/docker/sweep.mjs.map +1 -1
- package/dist/runtime/docker/volume.mjs +1 -1
- package/dist/runtime/docker/volume.mjs.map +1 -1
- package/dist/runtime/docker/wrap.mjs +14 -2
- package/dist/runtime/docker/wrap.mjs.map +1 -1
- package/dist/substrate/brand.d.mts +2 -5
- package/dist/substrate/brand.mjs +3 -2
- package/dist/substrate/brand.mjs.map +1 -1
- package/dist/substrate/cross-process.mjs +2 -16
- package/dist/substrate/cross-process.mjs.map +1 -1
- package/dist/substrate/event-time.mjs +0 -2
- package/dist/substrate/event-time.mjs.map +1 -1
- package/dist/substrate/events.d.mts +46 -16
- package/dist/substrate/identity.d.mts +11 -5
- package/dist/substrate/manifest.d.mts +33 -26
- package/dist/substrate/manifest.mjs +8 -3
- package/dist/substrate/manifest.mjs.map +1 -1
- package/dist/substrate/options.d.mts +33 -4
- package/dist/substrate/plugin-ctx.d.mts +70 -0
- package/dist/substrate/plugin-ctx.mjs +66 -0
- package/dist/substrate/plugin-ctx.mjs.map +1 -0
- package/dist/substrate/plugin.d.mts +46 -38
- package/dist/substrate/plugin.mjs +13 -9
- package/dist/substrate/plugin.mjs.map +1 -1
- package/dist/substrate/projection.d.mts +1 -1
- package/dist/substrate/runtime/atomic-write.mjs +3 -4
- package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
- package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
- package/dist/substrate/runtime/cache/service.mjs +50 -20
- package/dist/substrate/runtime/cache/service.mjs.map +1 -1
- package/dist/substrate/runtime/config-validation.mjs.map +1 -1
- package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
- package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
- package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/index.mjs +0 -2
- package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
- package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
- package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
- package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
- package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
- package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
- package/dist/substrate/runtime/errors.mjs +1 -13
- package/dist/substrate/runtime/errors.mjs.map +1 -1
- package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
- package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
- package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
- package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
- package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
- package/dist/substrate/runtime/http-probe.d.mts +1 -3
- package/dist/substrate/runtime/http-probe.mjs.map +1 -1
- package/dist/substrate/runtime/index.mjs +1 -6
- package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
- package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
- package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
- package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
- package/dist/substrate/runtime/managed-container.d.mts +5 -1
- package/dist/substrate/runtime/managed-container.mjs +8 -10
- package/dist/substrate/runtime/managed-container.mjs.map +1 -1
- package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
- package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
- package/dist/substrate/runtime/mode-errors.d.mts +1 -2
- package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
- package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
- package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
- package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
- package/dist/substrate/runtime/observability/index.d.mts +1 -1
- package/dist/substrate/runtime/observability/index.mjs +4 -6
- package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
- package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
- package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
- package/dist/substrate/runtime/observability/logger.mjs +3 -3
- package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
- package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
- package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
- package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
- package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
- package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
- package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
- package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
- package/dist/substrate/runtime/paths.mjs +27 -9
- package/dist/substrate/runtime/paths.mjs.map +1 -1
- package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
- package/dist/substrate/runtime/port-broker/service.mjs +10 -27
- package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/probes.d.mts +2 -3
- package/dist/substrate/runtime/probes.mjs.map +1 -1
- package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
- package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
- package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
- package/dist/substrate/runtime/projection/update.mjs +87 -11
- package/dist/substrate/runtime/projection/update.mjs.map +1 -1
- package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
- package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
- package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
- package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/index.mjs +5 -0
- package/dist/substrate/runtime/reconcile/label.mjs +41 -0
- package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
- package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
- package/dist/substrate/runtime/retry-policy.d.mts +2 -3
- package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
- package/dist/substrate/runtime/routed-url.mjs.map +1 -1
- package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
- package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
- package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
- package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
- package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
- package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
- package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
- package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
- package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
- package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
- package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/index.mjs +2 -0
- package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
- package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
- package/dist/substrate/runtime/supervisor/state.mjs +1 -1
- package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
- package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
- package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
- package/dist/substrate/runtime/tar/reader.mjs +216 -0
- package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
- package/dist/substrate/runtime/typed-env.mjs.map +1 -1
- package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
- package/dist/substrate/versioned-doc-sync.mjs +5 -5
- package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
- package/dist/surfaces/cli/command-tree.mjs +49 -7
- package/dist/surfaces/cli/command-tree.mjs.map +1 -1
- package/dist/surfaces/cli/commands/config.mjs +1 -1
- package/dist/surfaces/cli/commands/config.mjs.map +1 -1
- package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
- package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
- package/dist/surfaces/cli/commands/doctor.mjs +1 -1
- package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune.mjs +1 -1
- package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
- package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
- package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
- package/dist/surfaces/cli/commands/status.mjs +1 -1
- package/dist/surfaces/cli/commands/status.mjs.map +1 -1
- package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
- package/dist/surfaces/cli/commands/wipe.mjs +3 -4
- package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
- package/dist/surfaces/cli/envelope.mjs.map +1 -1
- package/dist/surfaces/cli/errors.mjs.map +1 -1
- package/dist/surfaces/cli/flags.mjs.map +1 -1
- package/dist/surfaces/cli/index.mjs +45 -14
- package/dist/surfaces/cli/index.mjs.map +1 -1
- package/dist/surfaces/cli/output.mjs.map +1 -1
- package/dist/surfaces/cli/sysexits.mjs.map +1 -1
- package/dist/surfaces/tui/app.mjs +0 -21
- package/dist/surfaces/tui/app.mjs.map +1 -1
- package/dist/surfaces/tui/dashboard.mjs +0 -48
- package/dist/surfaces/tui/dashboard.mjs.map +1 -1
- package/dist/surfaces/tui/display-derivation.mjs +80 -16
- package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
- package/dist/surfaces/tui/errors.mjs.map +1 -1
- package/dist/surfaces/tui/event-log.mjs +0 -9
- package/dist/surfaces/tui/event-log.mjs.map +1 -1
- package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
- package/dist/surfaces/tui/index.mjs +2 -2
- package/dist/surfaces/tui/index.mjs.map +1 -1
- package/dist/surfaces/tui/input.mjs.map +1 -1
- package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
- package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
- package/dist/surfaces/tui/plain-renderer.mjs +26 -19
- package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
- package/dist/surfaces/tui/resource-table.mjs +8 -10
- package/dist/surfaces/tui/resource-table.mjs.map +1 -1
- package/images/postgres/Dockerfile +0 -1
- package/images/sui/Dockerfile +27 -54
- package/images/sui/entrypoint.sh +17 -179
- package/package.json +23 -15
- package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
- package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
- package/dashboard-ui/assets/index-Deml9drg.css +0 -1
- package/dist/api/plugin-errors.d.mts +0 -7
- package/dist/api/plugin-errors.mjs +0 -10
- package/dist/api/plugin-errors.mjs.map +0 -1
- package/dist/cli/wirings/build-verb-layers.mjs +0 -42
- package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
- package/dist/contracts/capability-decl.d.mts +0 -40
- package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
- package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
- package/dist/orchestrators/run.mjs +0 -91
- package/dist/orchestrators/run.mjs.map +0 -1
- package/dist/orchestrators/runtime-composition.d.mts +0 -10
- package/dist/orchestrators/runtime-composition.mjs +0 -252
- package/dist/orchestrators/runtime-composition.mjs.map +0 -1
- package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
- package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
- package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
- package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
- package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
- package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
- package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
- package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
- package/dist/orchestrators/snapshot/state-document.mjs +0 -58
- package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
- package/dist/plugins/account/spans.mjs +0 -16
- package/dist/plugins/account/spans.mjs.map +0 -1
- package/dist/plugins/account/variants/env.mjs +0 -24
- package/dist/plugins/account/variants/env.mjs.map +0 -1
- package/dist/plugins/account/variants/inline.mjs +0 -13
- package/dist/plugins/account/variants/inline.mjs.map +0 -1
- package/dist/plugins/account/variants/keystore.mjs +0 -91
- package/dist/plugins/account/variants/keystore.mjs.map +0 -1
- package/dist/plugins/action/spans.mjs +0 -11
- package/dist/plugins/action/spans.mjs.map +0 -1
- package/dist/plugins/coin/spans.mjs +0 -20
- package/dist/plugins/coin/spans.mjs.map +0 -1
- package/dist/plugins/deepbook/spans.mjs +0 -18
- package/dist/plugins/deepbook/spans.mjs.map +0 -1
- package/dist/plugins/faucet/spans.mjs +0 -12
- package/dist/plugins/faucet/spans.mjs.map +0 -1
- package/dist/plugins/package/spans.mjs +0 -14
- package/dist/plugins/package/spans.mjs.map +0 -1
- package/dist/plugins/postgres/codegen.mjs +0 -42
- package/dist/plugins/postgres/codegen.mjs.map +0 -1
- package/dist/plugins/postgres/connection.d.mts +0 -33
- package/dist/plugins/postgres/connection.mjs.map +0 -1
- package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
- package/dist/plugins/postgres/errors.d.mts +0 -60
- package/dist/plugins/postgres/errors.mjs +0 -29
- package/dist/plugins/postgres/errors.mjs.map +0 -1
- package/dist/plugins/postgres/index.d.mts +0 -37
- package/dist/plugins/postgres/index.mjs +0 -68
- package/dist/plugins/postgres/index.mjs.map +0 -1
- package/dist/plugins/postgres/routable.mjs +0 -33
- package/dist/plugins/postgres/routable.mjs.map +0 -1
- package/dist/plugins/postgres/service.d.mts +0 -50
- package/dist/plugins/postgres/service.mjs +0 -179
- package/dist/plugins/postgres/service.mjs.map +0 -1
- package/dist/plugins/postgres/snapshot.mjs +0 -32
- package/dist/plugins/postgres/snapshot.mjs.map +0 -1
- package/dist/plugins/postgres/spans.mjs +0 -11
- package/dist/plugins/postgres/spans.mjs.map +0 -1
- package/dist/plugins/seal/spans.mjs +0 -18
- package/dist/plugins/seal/spans.mjs.map +0 -1
- package/dist/plugins/sui/spans.mjs +0 -17
- package/dist/plugins/sui/spans.mjs.map +0 -1
- package/dist/plugins/wallet/spans.mjs +0 -22
- package/dist/plugins/wallet/spans.mjs.map +0 -1
- package/dist/plugins/walrus/registry-publish.d.mts +0 -24
- package/dist/plugins/walrus/spans.mjs +0 -18
- package/dist/plugins/walrus/spans.mjs.map +0 -1
- package/dist/runtime/docker/logs.d.mts +0 -1
- package/dist/runtime/docker/logs.mjs +0 -34
- package/dist/runtime/docker/logs.mjs.map +0 -1
- package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
- package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
- package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
- package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
- package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
- package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
- package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
- package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
- package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
- package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
- package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
- package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
- package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
- package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
- package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
- package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
- package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
- package/dist/substrate/runtime/observability/span-store.mjs +0 -110
- package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
- package/dist/substrate/runtime/observability/spans.d.mts +0 -1
- package/dist/substrate/runtime/observability/spans.mjs +0 -87
- package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
- package/dist/substrate/runtime/projection/index.mjs +0 -4
- package/dist/substrate/runtime/projection/persisted.mjs +0 -213
- package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
- package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
- package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
- package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
- package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
- package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
- package/dist/substrate/runtime/state-store/index.mjs +0 -3
- package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
- package/dist/substrate/runtime/state-store/schema.mjs +0 -41
- package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
- package/dist/substrate/runtime/state-store/service.d.mts +0 -1
- package/dist/substrate/runtime/state-store/service.mjs +0 -145
- package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
- package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
- package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
- package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
- package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
- package/dist/substrate/state-store.d.mts +0 -1
- /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
- /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
- /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
- /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
- /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
- /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
- /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dep-graph.mjs","names":["makePluginKey"],"sources":["../../../../src/substrate/runtime/lifecycle/dep-graph.ts"],"sourcesContent":["// Dep-graph resolution — turn a `Stack` member tuple into a topo-sorted\n// acquire schedule.\n//\n// Architecture § Plugin lifecycle within a stack:\n// \"Resolution. Upstream keys (concrete or capability-typed) resolve\n// once. Bootstrap asset dedup-by-key fires before the scheduler\n// starts node fibers. Scheduling. Plugin enters `pending`. When all\n// upstream keys are `ready`, the node begins `acquiring`. Per-key\n// serialization: only one acquire at a time per key.\"\n//\n// This module is the pure dep-graph math: members in, levels out.\n\nimport { Data, Effect } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport { pluginKey as makePluginKey } from '../../brand.ts';\nimport { uniqueResourceRefs, type AnyPlugin, type AnyResourceRef } from '../../plugin.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** Cycle detected in the dep graph. Carries the offending key path so\n * the user sees the loop. Compile-time `defineDevstack` doesn't catch\n * every cycle (capability-typed consumes resolve at runtime), so this\n * surfaces a typed error at boot. */\nexport class DepGraphCycleError extends Data.TaggedError('DepGraphCycleError')<{\n\treadonly cycle: ReadonlyArray<PluginKey>;\n}> {}\n\n/** A dependency resource matched no provider. This is normally caught by\n * the compile-time `MissingProviders` check, but runtime-built stacks can\n * hit it. */\nexport class UnresolvedDependencyError extends Data.TaggedError('UnresolvedDependencyError')<{\n\treadonly pluginKey: PluginKey;\n\treadonly missingResourceId: string;\n}> {}\n\n/** Two members declared the same `resource id`. The compile-time\n * `MissingProviders` check only catches collisions on the user-typed\n * dependency path, NOT two members declared in the same stack with the\n * same `definePlugin({ id })`. Without this guard the dep-graph would\n * last-writer-wins the provider index and silently bind every dependent\n * to the second declaration. Phase 22e/E3 added a complementary\n * package-plugin-level guard (`plugins/package/mode-local.ts`) for the\n * registry path; this surfaces the same class of mistake for ALL plugins\n * at the substrate dep-graph layer. */\nexport class DuplicateResourceIdError extends Data.TaggedError('DuplicateResourceIdError')<{\n\treadonly resourceId: string;\n\treadonly firstPluginKey: PluginKey;\n\treadonly secondPluginKey: PluginKey;\n}> {}\n\nexport type DepGraphError =\n\t| DepGraphCycleError\n\t| UnresolvedDependencyError\n\t| DuplicateResourceIdError;\n\n// -----------------------------------------------------------------------------\n// Node shape\n// -----------------------------------------------------------------------------\n\n/** A resolved node in the dep graph. Wraps the original plugin with a\n * substrate-assigned `PluginKey`. */\nexport interface DepNode {\n\treadonly key: PluginKey;\n\treadonly member: AnyPlugin;\n\t/** Unique dependency refs and their resolved upstream keys. The two\n\t * arrays are positional peers. */\n\treadonly upstreamResources: ReadonlyArray<AnyResourceRef>;\n\treadonly upstreamKeys: ReadonlyArray<PluginKey>;\n}\n\n/** The result of resolving a member tuple. Levels are batches the\n * scheduler can acquire in parallel; each level's nodes only depend\n * on prior levels. */\nexport interface ResolvedGraph {\n\treadonly nodes: ReadonlyMap<PluginKey, DepNode>;\n\treadonly levels: ReadonlyArray<ReadonlyArray<PluginKey>>;\n\t/** Reverse-dep index: each key → keys that depend on it. The\n\t * supervisor uses this for selective-restart cascade. */\n\treadonly downstream: ReadonlyMap<PluginKey, ReadonlySet<PluginKey>>;\n}\n\n// -----------------------------------------------------------------------------\n// Plugin key minting\n// -----------------------------------------------------------------------------\n\ninterface NamedMember {\n\treadonly key: PluginKey;\n\treadonly member: AnyPlugin;\n}\n\n/** Mint a stable PluginKey for a plugin. Plugins may declare a stable\n * key; otherwise keys derive from resource id + ordinal so duplicates\n * do not collide. */\nconst mintKey = (member: AnyPlugin, ordinal: number): PluginKey => {\n\tif (member.pluginKey !== undefined) {\n\t\treturn makePluginKey(String(member.pluginKey));\n\t}\n\treturn makePluginKey(`${member.id}#${ordinal}`);\n};\n\n/** Walk the member tuple and emit one named-member entry per node. */\nconst expand = (members: ReadonlyArray<AnyPlugin>): ReadonlyArray<NamedMember> => {\n\tconst out: NamedMember[] = [];\n\tlet ordinal = 0;\n\tfor (const member of members) {\n\t\tconst key = mintKey(member, ordinal++);\n\t\tout.push({ key, member });\n\t}\n\treturn out;\n};\n\n// -----------------------------------------------------------------------------\n// Topological sort (Kahn's algorithm)\n// -----------------------------------------------------------------------------\n\n/**\n * Resolve a flat member tuple into a topo-sorted level batch.\n *\n * Steps:\n * 1. Mint a plugin key for every member.\n * 2. Build the resource-id -> key index (providers). Two members with\n * the same `id` fail with `DuplicateResourceIdError`.\n * 3. For each node, resolve its dependency refs to upstream keys.\n * 4. Kahn's algorithm: peel zero-indegree nodes into level 0, decrement\n * downstream indegrees, repeat.\n * 5. If any node remains, return `DepGraphCycleError`.\n *\n * Span-instrumented so trace exports show the resolution alongside the\n * supervisor's acquire spans.\n */\nexport const resolveGraph = (\n\tmembers: ReadonlyArray<AnyPlugin>,\n): Effect.Effect<ResolvedGraph, DepGraphError> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.annotateCurrentSpan({ 'devstack.dep-graph.memberCount': members.length });\n\t\tconst named = expand(members);\n\n\t\t// Provider index: resource-id → key. The compile-time\n\t\t// `MissingProviders` check ensures uniqueness on the user-typed\n\t\t// dependency path, but a runtime-built stack (or a typo'd\n\t\t// `definePlugin({ id })`) can still ship two members with the\n\t\t// same `resource id`. Without an explicit guard the index would\n\t\t// last-writer-wins and every dependent would silently bind to\n\t\t// the second declaration; we fail early with a typed error\n\t\t// instead so a developer sees the conflicting plugin keys at\n\t\t// boot rather than chasing a \"wrong provider\" mystery downstream.\n\t\t// Phase 22e/E3's package-plugin-level guard in\n\t\t// `plugins/package/mode-local.ts` is complementary — it fires on\n\t\t// the registry path before this resolver runs.\n\t\tconst providerByResourceId = new Map<string, PluginKey>();\n\t\tfor (const { key, member } of named) {\n\t\t\tconst existing = providerByResourceId.get(member.id);\n\t\t\tif (existing !== undefined) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew DuplicateResourceIdError({\n\t\t\t\t\t\tresourceId: member.id,\n\t\t\t\t\t\tfirstPluginKey: existing,\n\t\t\t\t\t\tsecondPluginKey: key,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tproviderByResourceId.set(member.id, key);\n\t\t}\n\n\t\tconst nodes = new Map<PluginKey, DepNode>();\n\t\tconst indegree = new Map<PluginKey, number>();\n\t\tconst downstream = new Map<PluginKey, Set<PluginKey>>();\n\t\tfor (const { key } of named) {\n\t\t\tindegree.set(key, 0);\n\t\t\tdownstream.set(key, new Set());\n\t\t}\n\n\t\tfor (const { key, member } of named) {\n\t\t\tconst upstreamKeys: PluginKey[] = [];\n\t\t\tconst upstreamResources = uniqueResourceRefs(member.dependsOn);\n\t\t\tfor (const resource of upstreamResources) {\n\t\t\t\tconst providerKey = providerByResourceId.get(resource.id);\n\t\t\t\tif (providerKey === undefined) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew UnresolvedDependencyError({ pluginKey: key, missingResourceId: resource.id }),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tupstreamKeys.push(providerKey);\n\t\t\t\tdownstream.get(providerKey)?.add(key);\n\t\t\t\tindegree.set(key, (indegree.get(key) ?? 0) + 1);\n\t\t\t}\n\t\t\tnodes.set(key, {\n\t\t\t\tkey,\n\t\t\t\tmember,\n\t\t\t\tupstreamResources,\n\t\t\t\tupstreamKeys,\n\t\t\t});\n\t\t}\n\n\t\t// Kahn's algorithm — peel zero-indegree nodes level by level.\n\t\tconst levels: PluginKey[][] = [];\n\t\tconst settled = new Set<PluginKey>();\n\t\twhile (settled.size < nodes.size) {\n\t\t\tconst layer: PluginKey[] = [];\n\t\t\tfor (const [key, deg] of indegree) {\n\t\t\t\tif (settled.has(key)) continue;\n\t\t\t\tif (deg === 0) layer.push(key);\n\t\t\t}\n\t\t\tif (layer.length === 0) {\n\t\t\t\t// Cycle: collect every unsettled node as the cycle's witness.\n\t\t\t\t// More precise cycle extraction (Tarjan SCC) is overkill for\n\t\t\t\t// the user-facing message; we surface the trapped keys.\n\t\t\t\tconst trapped: PluginKey[] = [];\n\t\t\t\tfor (const key of nodes.keys()) {\n\t\t\t\t\tif (!settled.has(key)) trapped.push(key);\n\t\t\t\t}\n\t\t\t\treturn yield* Effect.fail(new DepGraphCycleError({ cycle: trapped }));\n\t\t\t}\n\t\t\tlevels.push(layer);\n\t\t\tfor (const key of layer) {\n\t\t\t\tsettled.add(key);\n\t\t\t\tfor (const child of downstream.get(key) ?? []) {\n\t\t\t\t\tindegree.set(child, (indegree.get(child) ?? 1) - 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Freeze downstream sets to ReadonlySet shape.\n\t\tconst downstreamFrozen = new Map<PluginKey, ReadonlySet<PluginKey>>();\n\t\tfor (const [k, v] of downstream) downstreamFrozen.set(k, v);\n\n\t\treturn {\n\t\t\tnodes,\n\t\t\tlevels,\n\t\t\tdownstream: downstreamFrozen,\n\t\t} satisfies ResolvedGraph;\n\t}).pipe(Effect.withSpan('lifecycle.dep-graph.resolve'));\n\n// -----------------------------------------------------------------------------\n// Selective-restart helpers\n// -----------------------------------------------------------------------------\n\n/**\n * Compute the closure of nodes downstream of `root` (inclusive).\n * Used by the supervisor to tear down a subgraph in reverse-dep order\n * and re-acquire in forward order.\n *\n * Architecture § Watch-triggered invalidation:\n * Invalidating a producer invalidates downstream consumers along\n * dep-graph edges (cascade semantics).\n */\nexport const downstreamClosure = (\n\tgraph: ResolvedGraph,\n\troot: PluginKey,\n): ReadonlySet<PluginKey> => {\n\tconst closure = new Set<PluginKey>([root]);\n\tconst queue: PluginKey[] = [root];\n\twhile (queue.length > 0) {\n\t\tconst next = queue.shift()!;\n\t\tfor (const child of graph.downstream.get(next) ?? []) {\n\t\t\tif (!closure.has(child)) {\n\t\t\t\tclosure.add(child);\n\t\t\t\tqueue.push(child);\n\t\t\t}\n\t\t}\n\t}\n\treturn closure;\n};\n\n/** Order a set of keys by their dep-graph level — forward (low-to-high)\n * for acquire, reverse (high-to-low) for teardown. */\nexport const orderByLevel = (\n\tgraph: ResolvedGraph,\n\tkeys: ReadonlySet<PluginKey>,\n\tdirection: 'forward' | 'reverse',\n): ReadonlyArray<PluginKey> => {\n\tconst out: PluginKey[] = [];\n\tfor (const level of graph.levels) {\n\t\tfor (const key of level) if (keys.has(key)) out.push(key);\n\t}\n\treturn direction === 'reverse' ? out.slice().reverse() : out;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dep-graph.mjs","names":["makePluginKey"],"sources":["../../../../src/substrate/runtime/lifecycle/dep-graph.ts"],"sourcesContent":["// Dep-graph resolution — turn a `Stack` member tuple into a topo-sorted\n// acquire schedule.\n//\n// Architecture § Plugin lifecycle within a stack:\n// \"Resolution. Upstream keys (concrete or capability-typed) resolve\n// once. Bootstrap asset dedup-by-key fires before the scheduler\n// starts node fibers. Scheduling. Plugin enters `pending`. When all\n// upstream keys are `ready`, the node begins `acquiring`. Per-key\n// serialization: only one acquire at a time per key.\"\n//\n// This module is the pure dep-graph math: members in, levels out.\n\nimport { Data, Effect } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport { pluginKey as makePluginKey } from '../../brand.ts';\nimport { uniqueResourceRefs, type AnyPlugin, type AnyResourceRef } from '../../plugin.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\n/** Cycle detected in the dep graph. Carries the offending key path so\n * the user sees the loop. Compile-time `defineDevstack` doesn't catch\n * every cycle (capability-typed consumes resolve at runtime), so this\n * surfaces a typed error at boot. */\nexport class DepGraphCycleError extends Data.TaggedError('DepGraphCycleError')<{\n\treadonly cycle: ReadonlyArray<PluginKey>;\n}> {}\n\n/** A dependency resource matched no provider. This is normally caught by\n * the compile-time `MissingProviders` check, but runtime-built stacks can\n * hit it. */\nexport class UnresolvedDependencyError extends Data.TaggedError('UnresolvedDependencyError')<{\n\treadonly pluginKey: PluginKey;\n\treadonly missingResourceId: string;\n}> {}\n\n/** Two members declared the same `resource id`. The compile-time\n * `MissingProviders` check only catches collisions on the user-typed\n * dependency path, NOT two members declared in the same stack with the\n * same `definePlugin({ id })`. Without this guard the dep-graph would\n * last-writer-wins the provider index and silently bind every dependent\n * to the second declaration. Phase 22e/E3 added a complementary\n * package-plugin-level guard (`plugins/package/mode-local.ts`) for the\n * registry path; this surfaces the same class of mistake for ALL plugins\n * at the substrate dep-graph layer. */\nexport class DuplicateResourceIdError extends Data.TaggedError('DuplicateResourceIdError')<{\n\treadonly resourceId: string;\n\treadonly firstPluginKey: PluginKey;\n\treadonly secondPluginKey: PluginKey;\n}> {}\n\nexport type DepGraphError =\n\t| DepGraphCycleError\n\t| UnresolvedDependencyError\n\t| DuplicateResourceIdError;\n\n// -----------------------------------------------------------------------------\n// Node shape\n// -----------------------------------------------------------------------------\n\n/** A resolved node in the dep graph. Wraps the original plugin with a\n * substrate-assigned `PluginKey`. */\nexport interface DepNode {\n\treadonly key: PluginKey;\n\treadonly member: AnyPlugin;\n\t/** Unique dependency refs and their resolved upstream keys. The two\n\t * arrays are positional peers. */\n\treadonly upstreamResources: ReadonlyArray<AnyResourceRef>;\n\treadonly upstreamKeys: ReadonlyArray<PluginKey>;\n\t/** Plugin-declared flag: a live restore re-acquire leaves this node\n\t * running instead of draining it. Substrate filters on this with no\n\t * knowledge of which plugin set it (see plugin decl\n\t * `keepAliveOnRestore`). */\n\treadonly keepAliveOnRestore: boolean;\n}\n\n/** The result of resolving a member tuple. Levels are batches the\n * scheduler can acquire in parallel; each level's nodes only depend\n * on prior levels. */\nexport interface ResolvedGraph {\n\treadonly nodes: ReadonlyMap<PluginKey, DepNode>;\n\treadonly levels: ReadonlyArray<ReadonlyArray<PluginKey>>;\n\t/** Reverse-dep index: each key → keys that depend on it. The\n\t * supervisor uses this for selective-restart cascade. */\n\treadonly downstream: ReadonlyMap<PluginKey, ReadonlySet<PluginKey>>;\n}\n\n// -----------------------------------------------------------------------------\n// Plugin key minting\n// -----------------------------------------------------------------------------\n\ninterface NamedMember {\n\treadonly key: PluginKey;\n\treadonly member: AnyPlugin;\n}\n\n/** Mint a stable PluginKey for a plugin. Plugins may declare a stable\n * key; otherwise keys derive from resource id + ordinal so duplicates\n * do not collide. */\nconst mintKey = (member: AnyPlugin, ordinal: number): PluginKey => {\n\tif (member.pluginKey !== undefined) {\n\t\treturn makePluginKey(String(member.pluginKey));\n\t}\n\treturn makePluginKey(`${member.id}#${ordinal}`);\n};\n\n/** Walk the member tuple and emit one named-member entry per node. */\nconst expand = (members: ReadonlyArray<AnyPlugin>): ReadonlyArray<NamedMember> => {\n\tconst out: NamedMember[] = [];\n\tlet ordinal = 0;\n\tfor (const member of members) {\n\t\tconst key = mintKey(member, ordinal++);\n\t\tout.push({ key, member });\n\t}\n\treturn out;\n};\n\n// -----------------------------------------------------------------------------\n// Topological sort (Kahn's algorithm)\n// -----------------------------------------------------------------------------\n\n/**\n * Resolve a flat member tuple into a topo-sorted level batch.\n *\n * Steps:\n * 1. Mint a plugin key for every member.\n * 2. Build the resource-id -> key index (providers). Two members with\n * the same `id` fail with `DuplicateResourceIdError`.\n * 3. For each node, resolve its dependency refs to upstream keys.\n * 4. Kahn's algorithm: peel zero-indegree nodes into level 0, decrement\n * downstream indegrees, repeat.\n * 5. If any node remains, return `DepGraphCycleError`.\n *\n * Span-instrumented so trace exports show the resolution alongside the\n * supervisor's acquire spans.\n */\nexport const resolveGraph = (\n\tmembers: ReadonlyArray<AnyPlugin>,\n): Effect.Effect<ResolvedGraph, DepGraphError> =>\n\tEffect.gen(function* () {\n\t\tconst named = expand(members);\n\n\t\t// Provider index: resource-id → key. The compile-time\n\t\t// `MissingProviders` check ensures uniqueness on the user-typed\n\t\t// dependency path, but a runtime-built stack (or a typo'd\n\t\t// `definePlugin({ id })`) can still ship two members with the\n\t\t// same `resource id`. Without an explicit guard the index would\n\t\t// last-writer-wins and every dependent would silently bind to\n\t\t// the second declaration; we fail early with a typed error\n\t\t// instead so a developer sees the conflicting plugin keys at\n\t\t// boot rather than chasing a \"wrong provider\" mystery downstream.\n\t\t// Phase 22e/E3's package-plugin-level guard in\n\t\t// `plugins/package/mode-local.ts` is complementary — it fires on\n\t\t// the registry path before this resolver runs.\n\t\tconst providerByResourceId = new Map<string, PluginKey>();\n\t\tfor (const { key, member } of named) {\n\t\t\tconst existing = providerByResourceId.get(member.id);\n\t\t\tif (existing !== undefined) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew DuplicateResourceIdError({\n\t\t\t\t\t\tresourceId: member.id,\n\t\t\t\t\t\tfirstPluginKey: existing,\n\t\t\t\t\t\tsecondPluginKey: key,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tproviderByResourceId.set(member.id, key);\n\t\t}\n\n\t\tconst nodes = new Map<PluginKey, DepNode>();\n\t\tconst indegree = new Map<PluginKey, number>();\n\t\tconst downstream = new Map<PluginKey, Set<PluginKey>>();\n\t\tfor (const { key } of named) {\n\t\t\tindegree.set(key, 0);\n\t\t\tdownstream.set(key, new Set());\n\t\t}\n\n\t\tfor (const { key, member } of named) {\n\t\t\tconst upstreamKeys: PluginKey[] = [];\n\t\t\tconst upstreamResources = uniqueResourceRefs(member.dependsOn);\n\t\t\tfor (const resource of upstreamResources) {\n\t\t\t\tconst providerKey = providerByResourceId.get(resource.id);\n\t\t\t\tif (providerKey === undefined) {\n\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\tnew UnresolvedDependencyError({ pluginKey: key, missingResourceId: resource.id }),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tupstreamKeys.push(providerKey);\n\t\t\t\tdownstream.get(providerKey)?.add(key);\n\t\t\t\tindegree.set(key, (indegree.get(key) ?? 0) + 1);\n\t\t\t}\n\t\t\tnodes.set(key, {\n\t\t\t\tkey,\n\t\t\t\tmember,\n\t\t\t\tupstreamResources,\n\t\t\t\tupstreamKeys,\n\t\t\t\tkeepAliveOnRestore: member.keepAliveOnRestore === true,\n\t\t\t});\n\t\t}\n\n\t\t// Kahn's algorithm — peel zero-indegree nodes level by level.\n\t\tconst levels: PluginKey[][] = [];\n\t\tconst settled = new Set<PluginKey>();\n\t\twhile (settled.size < nodes.size) {\n\t\t\tconst layer: PluginKey[] = [];\n\t\t\tfor (const [key, deg] of indegree) {\n\t\t\t\tif (settled.has(key)) continue;\n\t\t\t\tif (deg === 0) layer.push(key);\n\t\t\t}\n\t\t\tif (layer.length === 0) {\n\t\t\t\t// Cycle: collect every unsettled node as the cycle's witness.\n\t\t\t\t// More precise cycle extraction (Tarjan SCC) is overkill for\n\t\t\t\t// the user-facing message; we surface the trapped keys.\n\t\t\t\tconst trapped: PluginKey[] = [];\n\t\t\t\tfor (const key of nodes.keys()) {\n\t\t\t\t\tif (!settled.has(key)) trapped.push(key);\n\t\t\t\t}\n\t\t\t\treturn yield* Effect.fail(new DepGraphCycleError({ cycle: trapped }));\n\t\t\t}\n\t\t\tlevels.push(layer);\n\t\t\tfor (const key of layer) {\n\t\t\t\tsettled.add(key);\n\t\t\t\tfor (const child of downstream.get(key) ?? []) {\n\t\t\t\t\tindegree.set(child, (indegree.get(child) ?? 1) - 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Freeze downstream sets to ReadonlySet shape.\n\t\tconst downstreamFrozen = new Map<PluginKey, ReadonlySet<PluginKey>>();\n\t\tfor (const [k, v] of downstream) downstreamFrozen.set(k, v);\n\n\t\treturn {\n\t\t\tnodes,\n\t\t\tlevels,\n\t\t\tdownstream: downstreamFrozen,\n\t\t} satisfies ResolvedGraph;\n\t});\n\n// -----------------------------------------------------------------------------\n// Selective-restart helpers\n// -----------------------------------------------------------------------------\n\n/**\n * Compute the closure of nodes downstream of `root` (inclusive).\n * Used by the supervisor to tear down a subgraph in reverse-dep order\n * and re-acquire in forward order.\n *\n * Architecture § Watch-triggered invalidation:\n * Invalidating a producer invalidates downstream consumers along\n * dep-graph edges (cascade semantics).\n */\nexport const downstreamClosure = (\n\tgraph: ResolvedGraph,\n\troot: PluginKey,\n): ReadonlySet<PluginKey> => {\n\tconst closure = new Set<PluginKey>([root]);\n\tconst queue: PluginKey[] = [root];\n\twhile (queue.length > 0) {\n\t\tconst next = queue.shift()!;\n\t\tfor (const child of graph.downstream.get(next) ?? []) {\n\t\t\tif (!closure.has(child)) {\n\t\t\t\tclosure.add(child);\n\t\t\t\tqueue.push(child);\n\t\t\t}\n\t\t}\n\t}\n\treturn closure;\n};\n\n/** Order a set of keys by their dep-graph level — forward (low-to-high)\n * for acquire, reverse (high-to-low) for teardown. */\nexport const orderByLevel = (\n\tgraph: ResolvedGraph,\n\tkeys: ReadonlySet<PluginKey>,\n\tdirection: 'forward' | 'reverse',\n): ReadonlyArray<PluginKey> => {\n\tconst out: PluginKey[] = [];\n\tfor (const level of graph.levels) {\n\t\tfor (const key of level) if (keys.has(key)) out.push(key);\n\t}\n\treturn direction === 'reverse' ? out.slice().reverse() : out;\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { graphInputId, nodeInputId } from "../../brand.mjs";
|
|
2
|
+
import { resolveGraph } from "./dep-graph.mjs";
|
|
3
|
+
import { Effect, Exit, Schema } from "effect";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
//#region src/substrate/runtime/lifecycle/graph-input-id.ts
|
|
6
|
+
const GRAPH_INPUT_ID_VERSION = 1;
|
|
7
|
+
var GraphInputIdentityError = class extends Schema.TaggedErrorClass()("GraphInputIdentityError", {
|
|
8
|
+
pluginKey: Schema.String,
|
|
9
|
+
detail: Schema.String,
|
|
10
|
+
cause: Schema.optional(Schema.Defect)
|
|
11
|
+
}) {};
|
|
12
|
+
const canonicalize = (value) => {
|
|
13
|
+
if (typeof value === "bigint") return {
|
|
14
|
+
type: "bigint",
|
|
15
|
+
value: value.toString()
|
|
16
|
+
};
|
|
17
|
+
if (Array.isArray(value)) return value.map((entry) => canonicalize(entry));
|
|
18
|
+
if (value !== null && typeof value === "object") {
|
|
19
|
+
const source = value;
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const key of Object.keys(source).sort((a, b) => a.localeCompare(b))) {
|
|
22
|
+
const entry = source[key];
|
|
23
|
+
if (entry === void 0) continue;
|
|
24
|
+
out[key] = canonicalize(entry);
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
};
|
|
30
|
+
const canonicalStringify = (value) => {
|
|
31
|
+
const encoded = JSON.stringify(canonicalize(value));
|
|
32
|
+
return encoded === void 0 ? String(encoded) : encoded;
|
|
33
|
+
};
|
|
34
|
+
const sha256Hex = (data) => createHash("sha256").update(data).digest("hex");
|
|
35
|
+
const sortStrings = (values) => [...values].sort((a, b) => a.localeCompare(b));
|
|
36
|
+
const graphRelevantOptions = (options) => {
|
|
37
|
+
const { renderer: _renderer, extras: _extras, codegen: _codegen, stackName: _stackName, stateDir: _stateDir, ...rest } = options;
|
|
38
|
+
return rest;
|
|
39
|
+
};
|
|
40
|
+
const nodeBaseDocument = (node, inputIdentity) => ({
|
|
41
|
+
resourceId: node.member.id,
|
|
42
|
+
role: node.member.role,
|
|
43
|
+
section: node.member.section,
|
|
44
|
+
...node.member.endpointSection === void 0 ? {} : { endpointSection: node.member.endpointSection },
|
|
45
|
+
keepAliveOnRestore: node.keepAliveOnRestore,
|
|
46
|
+
upstreamResources: sortStrings(node.upstreamResources.map((resource) => resource.id)),
|
|
47
|
+
...node.member.watch === void 0 ? {} : { watch: {
|
|
48
|
+
paths: sortStrings(node.member.watch.paths),
|
|
49
|
+
cascade: node.member.watch.cascade ?? true
|
|
50
|
+
} },
|
|
51
|
+
...inputIdentity === void 0 ? {} : { inputIdentity }
|
|
52
|
+
});
|
|
53
|
+
const resolveNodeInputIdentity = (node) => {
|
|
54
|
+
const contribution = node.member.inputIdentity;
|
|
55
|
+
if (contribution === void 0) return Effect.succeed(void 0);
|
|
56
|
+
if (contribution.kind === "static") return Effect.succeed(contribution.value);
|
|
57
|
+
const pluginKey = String(node.key);
|
|
58
|
+
return Effect.try({
|
|
59
|
+
try: () => contribution.compute(),
|
|
60
|
+
catch: (cause) => new GraphInputIdentityError({
|
|
61
|
+
pluginKey,
|
|
62
|
+
detail: "node input identity computation could not be created",
|
|
63
|
+
cause
|
|
64
|
+
})
|
|
65
|
+
}).pipe(Effect.flatMap((effect) => Effect.exit(effect)), Effect.flatMap((exit) => Exit.isSuccess(exit) ? Effect.succeed(exit.value) : Effect.fail(new GraphInputIdentityError({
|
|
66
|
+
pluginKey,
|
|
67
|
+
detail: "node input identity computation failed",
|
|
68
|
+
cause: exit.cause
|
|
69
|
+
}))));
|
|
70
|
+
};
|
|
71
|
+
const computeGraphInputIdentity = (args) => Effect.gen(function* () {
|
|
72
|
+
const inputIdByKey = /* @__PURE__ */ new Map();
|
|
73
|
+
const nodeIdentityByKey = /* @__PURE__ */ new Map();
|
|
74
|
+
for (const level of args.graph.levels) for (const key of level) {
|
|
75
|
+
const node = args.graph.nodes.get(key);
|
|
76
|
+
if (node === void 0) continue;
|
|
77
|
+
const upstreamInputIds = [];
|
|
78
|
+
for (const upstreamKey of node.upstreamKeys) {
|
|
79
|
+
const upstreamKeyString = String(upstreamKey);
|
|
80
|
+
const inputId = inputIdByKey.get(upstreamKeyString);
|
|
81
|
+
if (inputId === void 0) return yield* Effect.fail(new GraphInputIdentityError({
|
|
82
|
+
pluginKey: String(key),
|
|
83
|
+
detail: `upstream node input id missing for ${upstreamKeyString}`
|
|
84
|
+
}));
|
|
85
|
+
upstreamInputIds.push({
|
|
86
|
+
key: upstreamKeyString,
|
|
87
|
+
inputId
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
upstreamInputIds.sort((a, b) => a.key.localeCompare(b.key));
|
|
91
|
+
const inputId = nodeInputId(sha256Hex(canonicalStringify({
|
|
92
|
+
v: GRAPH_INPUT_ID_VERSION,
|
|
93
|
+
node: nodeBaseDocument(node, yield* resolveNodeInputIdentity(node)),
|
|
94
|
+
upstreamInputIds
|
|
95
|
+
})));
|
|
96
|
+
inputIdByKey.set(String(key), inputId);
|
|
97
|
+
nodeIdentityByKey.set(String(key), {
|
|
98
|
+
key: String(key),
|
|
99
|
+
inputId,
|
|
100
|
+
upstreamInputIds
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const nodes = [...nodeIdentityByKey.values()].sort((a, b) => a.key.localeCompare(b.key));
|
|
104
|
+
const downstream = [...args.graph.downstream.entries()].map(([key, children]) => ({
|
|
105
|
+
key: String(key),
|
|
106
|
+
children: sortStrings([...children].map(String))
|
|
107
|
+
})).sort((a, b) => a.key.localeCompare(b.key));
|
|
108
|
+
return {
|
|
109
|
+
graphInputId: graphInputId(sha256Hex(canonicalStringify({
|
|
110
|
+
v: GRAPH_INPUT_ID_VERSION,
|
|
111
|
+
devstackVersion: args.devstackVersion,
|
|
112
|
+
options: graphRelevantOptions(args.options),
|
|
113
|
+
levels: args.graph.levels.map((level) => sortStrings(level.map(String))),
|
|
114
|
+
nodes: nodes.map((node) => ({
|
|
115
|
+
key: node.key,
|
|
116
|
+
inputId: node.inputId
|
|
117
|
+
})),
|
|
118
|
+
downstream
|
|
119
|
+
}))),
|
|
120
|
+
nodes
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
const computeStackGraphInputIdentity = (args) => Effect.gen(function* () {
|
|
124
|
+
return yield* computeGraphInputIdentity({
|
|
125
|
+
graph: yield* resolveGraph(args.stack.members),
|
|
126
|
+
options: args.stack.options,
|
|
127
|
+
devstackVersion: args.devstackVersion
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
//#endregion
|
|
131
|
+
export { GraphInputIdentityError, computeGraphInputIdentity, computeStackGraphInputIdentity, graphRelevantOptions };
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=graph-input-id.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-input-id.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/graph-input-id.ts"],"sourcesContent":["// Graph input identity.\n//\n// This is the substrate-level desired-state identity primitive for a resolved\n// graph. Each node gets a deterministic input id from its declared static\n// inputs plus upstream node input ids; the graph gets an aggregate id from\n// node ids, graph shape, graph-relevant options, and the devstack version.\n// Snapshot policy can compare these ids to warn or refuse restores.\n\nimport { createHash } from 'node:crypto';\n\nimport { Effect, Exit, Schema } from 'effect';\n\nimport type { GraphInputId, NodeInputId } from '../../brand.ts';\nimport { graphInputId, nodeInputId } from '../../brand.ts';\nimport type { DevstackOptions } from '../../options.ts';\nimport { resolveGraph, type DepGraphError, type DepNode, type ResolvedGraph } from './dep-graph.ts';\n\nconst GRAPH_INPUT_ID_VERSION = 1 as const;\n\nexport interface NodeInputIdentity {\n\treadonly key: string;\n\treadonly inputId: NodeInputId;\n\treadonly upstreamInputIds: ReadonlyArray<{\n\t\treadonly key: string;\n\t\treadonly inputId: NodeInputId;\n\t}>;\n}\n\nexport interface GraphInputIdentity {\n\treadonly graphInputId: GraphInputId;\n\treadonly nodes: ReadonlyArray<NodeInputIdentity>;\n}\n\nexport interface StackGraphInputSource {\n\treadonly members: ReadonlyArray<DepNode['member']>;\n\treadonly options: DevstackOptions;\n}\n\nexport class GraphInputIdentityError extends Schema.TaggedErrorClass<GraphInputIdentityError>()(\n\t'GraphInputIdentityError',\n\t{\n\t\tpluginKey: Schema.String,\n\t\tdetail: Schema.String,\n\t\tcause: Schema.optional(Schema.Defect),\n\t},\n) {}\n\nexport type StackGraphInputIdentityError = DepGraphError | GraphInputIdentityError;\n\nconst canonicalize = (value: unknown): unknown => {\n\tif (typeof value === 'bigint') {\n\t\treturn { type: 'bigint', value: value.toString() };\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map((entry) => canonicalize(entry));\n\t}\n\tif (value !== null && typeof value === 'object') {\n\t\tconst source = value as Record<string, unknown>;\n\t\tconst out: Record<string, unknown> = {};\n\t\tfor (const key of Object.keys(source).sort((a, b) => a.localeCompare(b))) {\n\t\t\tconst entry = source[key];\n\t\t\tif (entry === undefined) continue;\n\t\t\tout[key] = canonicalize(entry);\n\t\t}\n\t\treturn out;\n\t}\n\treturn value;\n};\n\nconst canonicalStringify = (value: unknown): string => {\n\tconst encoded = JSON.stringify(canonicalize(value));\n\treturn encoded === undefined ? String(encoded) : encoded;\n};\n\nconst sha256Hex = (data: string | Uint8Array): string =>\n\tcreateHash('sha256').update(data).digest('hex');\n\nconst sortStrings = (values: ReadonlyArray<string>): ReadonlyArray<string> =>\n\t[...values].sort((a, b) => a.localeCompare(b));\n\nexport const graphRelevantOptions = (options: DevstackOptions): unknown => {\n\tconst {\n\t\trenderer: _renderer,\n\t\textras: _extras,\n\t\tcodegen: _codegen,\n\t\tstackName: _stackName,\n\t\tstateDir: _stateDir,\n\t\t...rest\n\t} = options;\n\treturn rest;\n};\n\nconst nodeBaseDocument = (node: DepNode, inputIdentity: unknown): unknown => ({\n\tresourceId: node.member.id,\n\trole: node.member.role,\n\tsection: node.member.section,\n\t...(node.member.endpointSection === undefined\n\t\t? {}\n\t\t: { endpointSection: node.member.endpointSection }),\n\tkeepAliveOnRestore: node.keepAliveOnRestore,\n\tupstreamResources: sortStrings(node.upstreamResources.map((resource) => resource.id)),\n\t...(node.member.watch === undefined\n\t\t? {}\n\t\t: {\n\t\t\t\twatch: {\n\t\t\t\t\tpaths: sortStrings(node.member.watch.paths),\n\t\t\t\t\tcascade: node.member.watch.cascade ?? true,\n\t\t\t\t},\n\t\t\t}),\n\t...(inputIdentity === undefined ? {} : { inputIdentity }),\n});\n\nconst resolveNodeInputIdentity = (\n\tnode: DepNode,\n): Effect.Effect<unknown, GraphInputIdentityError> => {\n\tconst contribution = node.member.inputIdentity;\n\tif (contribution === undefined) return Effect.succeed(undefined);\n\tif (contribution.kind === 'static') return Effect.succeed(contribution.value);\n\n\tconst pluginKey = String(node.key);\n\treturn Effect.try({\n\t\ttry: () => contribution.compute(),\n\t\tcatch: (cause) =>\n\t\t\tnew GraphInputIdentityError({\n\t\t\t\tpluginKey,\n\t\t\t\tdetail: 'node input identity computation could not be created',\n\t\t\t\tcause,\n\t\t\t}),\n\t}).pipe(\n\t\tEffect.flatMap((effect) => Effect.exit(effect)),\n\t\tEffect.flatMap((exit) =>\n\t\t\tExit.isSuccess(exit)\n\t\t\t\t? Effect.succeed(exit.value)\n\t\t\t\t: Effect.fail(\n\t\t\t\t\t\tnew GraphInputIdentityError({\n\t\t\t\t\t\t\tpluginKey,\n\t\t\t\t\t\t\tdetail: 'node input identity computation failed',\n\t\t\t\t\t\t\tcause: exit.cause,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t),\n\t);\n};\n\nexport const computeGraphInputIdentity = (args: {\n\treadonly graph: ResolvedGraph;\n\treadonly options: DevstackOptions;\n\treadonly devstackVersion: string;\n}): Effect.Effect<GraphInputIdentity, GraphInputIdentityError> =>\n\tEffect.gen(function* () {\n\t\tconst inputIdByKey = new Map<string, NodeInputId>();\n\t\tconst nodeIdentityByKey = new Map<string, NodeInputIdentity>();\n\n\t\tfor (const level of args.graph.levels) {\n\t\t\tfor (const key of level) {\n\t\t\t\tconst node = args.graph.nodes.get(key);\n\t\t\t\tif (node === undefined) continue;\n\t\t\t\tconst upstreamInputIds: Array<{ key: string; inputId: NodeInputId }> = [];\n\t\t\t\tfor (const upstreamKey of node.upstreamKeys) {\n\t\t\t\t\tconst upstreamKeyString = String(upstreamKey);\n\t\t\t\t\tconst inputId = inputIdByKey.get(upstreamKeyString);\n\t\t\t\t\tif (inputId === undefined) {\n\t\t\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\t\t\tnew GraphInputIdentityError({\n\t\t\t\t\t\t\t\tpluginKey: String(key),\n\t\t\t\t\t\t\t\tdetail: `upstream node input id missing for ${upstreamKeyString}`,\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\tupstreamInputIds.push({ key: upstreamKeyString, inputId });\n\t\t\t\t}\n\t\t\t\tupstreamInputIds.sort((a, b) => a.key.localeCompare(b.key));\n\t\t\t\tconst inputIdentity = yield* resolveNodeInputIdentity(node);\n\t\t\t\tconst inputId = nodeInputId(\n\t\t\t\t\tsha256Hex(\n\t\t\t\t\t\tcanonicalStringify({\n\t\t\t\t\t\t\tv: GRAPH_INPUT_ID_VERSION,\n\t\t\t\t\t\t\tnode: nodeBaseDocument(node, inputIdentity),\n\t\t\t\t\t\t\tupstreamInputIds,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tinputIdByKey.set(String(key), inputId);\n\t\t\t\tnodeIdentityByKey.set(String(key), {\n\t\t\t\t\tkey: String(key),\n\t\t\t\t\tinputId,\n\t\t\t\t\tupstreamInputIds,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst nodes = [...nodeIdentityByKey.values()].sort((a, b) => a.key.localeCompare(b.key));\n\t\tconst downstream = [...args.graph.downstream.entries()]\n\t\t\t.map(([key, children]) => ({\n\t\t\t\tkey: String(key),\n\t\t\t\tchildren: sortStrings([...children].map(String)),\n\t\t\t}))\n\t\t\t.sort((a, b) => a.key.localeCompare(b.key));\n\n\t\tconst graphDoc = {\n\t\t\tv: GRAPH_INPUT_ID_VERSION,\n\t\t\tdevstackVersion: args.devstackVersion,\n\t\t\toptions: graphRelevantOptions(args.options),\n\t\t\tlevels: args.graph.levels.map((level) => sortStrings(level.map(String))),\n\t\t\tnodes: nodes.map((node) => ({ key: node.key, inputId: node.inputId })),\n\t\t\tdownstream,\n\t\t};\n\n\t\treturn {\n\t\t\tgraphInputId: graphInputId(sha256Hex(canonicalStringify(graphDoc))),\n\t\t\tnodes,\n\t\t};\n\t});\n\nexport const computeStackGraphInputIdentity = (args: {\n\treadonly stack: StackGraphInputSource;\n\treadonly devstackVersion: string;\n}): Effect.Effect<GraphInputIdentity, StackGraphInputIdentityError> =>\n\tEffect.gen(function* () {\n\t\tconst graph = yield* resolveGraph(args.stack.members);\n\t\treturn yield* computeGraphInputIdentity({\n\t\t\tgraph,\n\t\t\toptions: args.stack.options,\n\t\t\tdevstackVersion: args.devstackVersion,\n\t\t});\n\t});\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./state-machine.mjs";
|
|
2
|
-
import "./plugin-registry.mjs";
|
|
3
|
-
import "./lifecycle-fact.mjs";
|
|
4
2
|
import "./dep-graph.mjs";
|
|
3
|
+
import "./graph-input-id.mjs";
|
|
4
|
+
import "./plugin-registry.mjs";
|
|
5
5
|
import "./ready-gate.mjs";
|
|
6
6
|
import "./watch-attribution.mjs";
|
|
7
7
|
import "./selective-restart.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { Deferred, Effect, Ref, Scope } from "effect";
|
|
1
|
+
import { Deferred, Effect, Fiber, Ref, Scope } from "effect";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assertTransition } from "./state-machine.mjs";
|
|
2
|
-
import { Data, Deferred, Effect, Ref, Scope } from "effect";
|
|
2
|
+
import { Data, Deferred, Effect, Fiber, Ref, Scope } from "effect";
|
|
3
3
|
//#region src/substrate/runtime/lifecycle/plugin-registry.ts
|
|
4
4
|
/** Tagged failure: a plugin's `start` rejected. Carries the cause and
|
|
5
5
|
* the failing plugin's key so the cause walker / cascade formatter can
|
|
@@ -17,6 +17,7 @@ const makeEntry = (node, parentScope) => Effect.gen(function* () {
|
|
|
17
17
|
return {
|
|
18
18
|
node,
|
|
19
19
|
statusRef: yield* Ref.make("pending"),
|
|
20
|
+
acquireFiberRef: yield* Ref.make(null),
|
|
20
21
|
readyGate: yield* Deferred.make(),
|
|
21
22
|
scope: yield* Scope.fork(parentScope)
|
|
22
23
|
};
|
|
@@ -85,8 +86,11 @@ const makeRegistry = (entries, onTransition) => {
|
|
|
85
86
|
}),
|
|
86
87
|
resetForRestart: (key, parentScope) => Effect.gen(function* () {
|
|
87
88
|
const entry = yield* getEntry(key);
|
|
89
|
+
const acquireFiber = yield* Ref.getAndSet(entry.acquireFiberRef, null);
|
|
90
|
+
if (acquireFiber !== null) yield* Fiber.interrupt(acquireFiber);
|
|
88
91
|
resolved.delete(key);
|
|
89
92
|
const readyGate = yield* Deferred.make();
|
|
93
|
+
const acquireFiberRef = yield* Ref.make(null);
|
|
90
94
|
const scope = yield* Scope.fork(parentScope);
|
|
91
95
|
const from = yield* Ref.get(entry.statusRef);
|
|
92
96
|
yield* Ref.set(entry.statusRef, "pending");
|
|
@@ -94,10 +98,27 @@ const makeRegistry = (entries, onTransition) => {
|
|
|
94
98
|
mutableEntries.set(key, {
|
|
95
99
|
node: entry.node,
|
|
96
100
|
statusRef: entry.statusRef,
|
|
101
|
+
acquireFiberRef,
|
|
97
102
|
readyGate,
|
|
98
103
|
scope
|
|
99
104
|
});
|
|
100
105
|
}),
|
|
106
|
+
setAcquireFiberIfEntry: (key, expectedEntry, fiber) => Effect.gen(function* () {
|
|
107
|
+
const entry = yield* getEntry(key);
|
|
108
|
+
if (entry !== expectedEntry) return false;
|
|
109
|
+
yield* Ref.set(entry.acquireFiberRef, fiber);
|
|
110
|
+
return true;
|
|
111
|
+
}),
|
|
112
|
+
clearAcquireFiberIfEntry: (key, expectedEntry, fiberId) => Effect.gen(function* () {
|
|
113
|
+
const entry = yield* getEntry(key);
|
|
114
|
+
if (entry !== expectedEntry) return;
|
|
115
|
+
yield* Ref.update(entry.acquireFiberRef, (current) => current !== null && current.id === fiberId ? null : current);
|
|
116
|
+
}),
|
|
117
|
+
interruptAcquire: (key) => Effect.gen(function* () {
|
|
118
|
+
const entry = yield* getEntry(key);
|
|
119
|
+
const acquireFiber = yield* Ref.getAndSet(entry.acquireFiberRef, null);
|
|
120
|
+
if (acquireFiber !== null) yield* Fiber.interrupt(acquireFiber);
|
|
121
|
+
}),
|
|
101
122
|
awaitReady: (key) => Effect.gen(function* () {
|
|
102
123
|
const entry = yield* getEntry(key);
|
|
103
124
|
return yield* Deferred.await(entry.readyGate);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-registry.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/plugin-registry.ts"],"sourcesContent":["// Per-plugin lifecycle bookkeeping.\n//\n// One `PluginEntry` per node in the resolved dep-graph. The entry\n// holds:\n// - the live `LifecycleStatus` (Ref, single-fiber linearizable),\n// - the resolved value (set when status transitions to `ready`),\n// - the scope owning the plugin's `start` finalizers,\n// - a `Deferred` that downstream consumers await for the ready gate.\n//\n// The registry tracks per-key lifecycle only; projection concerns stay\n// in the supervisor and reducer.\n\nimport { Data, Deferred, Effect, Ref, Scope } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { LifecycleStatus } from '../../lifecycle.ts';\nimport type { DepNode } from './dep-graph.ts';\nimport { assertTransition } from './state-machine.ts';\n\n/** Per-registry side channel: synchronously-readable resolved values.\n * Keyed by plugin key. Populated by `markReady`; consulted by the\n * synchronous dependency reader. We can't put the value on the\n * `Deferred` itself in a publicly-supported way, and plugin start\n * receives dependency values synchronously; this is the safe escape hatch.\n *\n * Module-private; only `makeRegistry` writes into the map it\n * allocates. */\ntype ResolvedMap = Map<PluginKey, ResolvedValue>;\n\n// -----------------------------------------------------------------------------\n// Resolved-value shape\n// -----------------------------------------------------------------------------\n\n/** Erased resolved value held in the registry. The supervisor casts\n * back to the concrete type at the boundary where it threads the\n * value into a downstream plugin's resolved dependency object. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ResolvedValue = any;\n\n// -----------------------------------------------------------------------------\n// Per-plugin entry\n// -----------------------------------------------------------------------------\n\n/** Mutable lifecycle state for one plugin instance. */\nexport interface PluginEntry {\n\treadonly node: DepNode;\n\treadonly statusRef: Ref.Ref<LifecycleStatus>;\n\t/** Resolved when the plugin reaches `ready`. Downstream consumers\n\t * await this in the ready-gate. Failure is propagated by interruption\n\t * via `Deferred.fail` to keep the error chain in the cause walker. */\n\treadonly readyGate: Deferred.Deferred<ResolvedValue, PluginAcquireFailed>;\n\t/** Per-plugin Scope. Closing it runs the `start` finalizers. */\n\treadonly scope: Scope.Closeable;\n}\n\n/** Tagged failure: a plugin's `start` rejected. Carries the cause and\n * the failing plugin's key so the cause walker / cascade formatter can\n * attribute it. */\nexport class PluginAcquireFailed extends Data.TaggedError('PluginAcquireFailed')<{\n\treadonly pluginKey: PluginKey;\n\treadonly cause: unknown;\n}> {}\n\n/** Tagged failure: a downstream plugin tried to read a resolved value\n * whose entry isn't registered or hasn't reached `ready`. Programmer-\n * level error class — the dep-graph guarantees this can't happen on\n * the supervisor's own scheduling path. Surfaced when a plugin author\n * reaches outside their declared dependencies. */\nexport class UnknownDependency extends Data.TaggedError('UnknownDependency')<{\n\treadonly pluginKey: PluginKey;\n\treadonly requestedResourceId: string;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Registry\n// -----------------------------------------------------------------------------\n\n/** Build a fresh entry for `node`. Caller still owns the entry — the\n * registry below holds a `ReadonlyMap` of these. */\nexport const makeEntry = (\n\tnode: DepNode,\n\tparentScope: Scope.Scope,\n): Effect.Effect<PluginEntry, never, never> =>\n\tEffect.gen(function* () {\n\t\tconst statusRef = yield* Ref.make<LifecycleStatus>('pending');\n\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\tconst scope = yield* Scope.fork(parentScope);\n\t\treturn { node, statusRef, readyGate, scope } satisfies PluginEntry;\n\t});\n\n/** The lifecycle registry. Holds one entry per dep-graph node. */\nexport interface PluginRegistry {\n\treadonly entries: ReadonlyMap<PluginKey, PluginEntry>;\n\t/** Read a plugin's current status. */\n\treadonly getStatus: (key: PluginKey) => Effect.Effect<LifecycleStatus, UnknownDependency>;\n\t/** Transition a plugin to a new status. Validates against the\n\t * transition table; emits via `onTransition`. */\n\treadonly transition: (\n\t\tkey: PluginKey,\n\t\tto: LifecycleStatus,\n\t) => Effect.Effect<\n\t\t{ readonly from: LifecycleStatus; readonly to: LifecycleStatus },\n\t\tUnknownDependency\n\t>;\n\t/** Mark a plugin ready with its resolved value. */\n\treadonly markReady: (\n\t\tkey: PluginKey,\n\t\tvalue: ResolvedValue,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Mark a plugin failed. */\n\treadonly markFailed: (key: PluginKey, cause: unknown) => Effect.Effect<void, UnknownDependency>;\n\t/** Prepare a previously torn-down entry for hot restart. Plugin\n\t * scopes and ready gates are single-use: once a scope has been closed,\n\t * any finalizer registered during a later acquire would run\n\t * immediately, and an already-resolved ready gate would leak the old\n\t * value to downstream consumers. */\n\treadonly resetForRestart: (\n\t\tkey: PluginKey,\n\t\tparentScope: Scope.Scope,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Await `ready` for `key`. Suspends until the plugin's `readyGate`\n\t * resolves. The deferred's failure channel propagates a\n\t * `PluginAcquireFailed` so the supervisor's outer error path picks\n\t * it up. */\n\treadonly awaitReady: (\n\t\tkey: PluginKey,\n\t) => Effect.Effect<ResolvedValue, PluginAcquireFailed | UnknownDependency>;\n}\n\n/** Build a registry from a map of entries. The `onTransition` callback\n * is the supervisor's published event sink — every status change\n * flows through here. */\nexport const makeRegistry = (\n\tentries: ReadonlyMap<PluginKey, PluginEntry>,\n\tonTransition: (key: PluginKey, from: LifecycleStatus, to: LifecycleStatus) => Effect.Effect<void>,\n): PluginRegistry => {\n\tconst mutableEntries = new Map(entries);\n\tconst resolved: ResolvedMap = new Map();\n\n\tconst getEntry = (key: PluginKey): Effect.Effect<PluginEntry, UnknownDependency> => {\n\t\tconst entry = mutableEntries.get(key);\n\t\tif (entry === undefined) {\n\t\t\treturn Effect.fail(new UnknownDependency({ pluginKey: key, requestedResourceId: '' }));\n\t\t}\n\t\treturn Effect.succeed(entry);\n\t};\n\n\tconst reg: PluginRegistry & { __resolved: ResolvedMap } = {\n\t\tentries: mutableEntries,\n\t\t__resolved: resolved,\n\t\tgetStatus: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Ref.get(entry.statusRef);\n\t\t\t}),\n\t\ttransition: (key, to) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* assertTransition(from, to);\n\t\t\t\tyield* Ref.set(entry.statusRef, to);\n\t\t\t\tyield* onTransition(key, from, to);\n\t\t\t\treturn { from, to };\n\t\t\t}),\n\t\tmarkReady: (key, value) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.set(key, value);\n\t\t\t\tif (from !== 'ready') {\n\t\t\t\t\t// `pending → ready` is off-table — the state machine\n\t\t\t\t\t// requires the intermediate `acquiring` hop. Bridge it\n\t\t\t\t\t// here so callers reaching `markReady` from a `pending`\n\t\t\t\t\t// entry (test fixtures, callers that mark a synthetic\n\t\t\t\t\t// already-resolved value) don't have to pre-walk the\n\t\t\t\t\t// machine. Both transitions still emit through\n\t\t\t\t\t// `onTransition` so subscribers see the full path.\n\t\t\t\t\tif (from === 'pending') {\n\t\t\t\t\t\tyield* assertTransition(from, 'acquiring');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'acquiring');\n\t\t\t\t\t\tyield* onTransition(key, from, 'acquiring');\n\t\t\t\t\t\tyield* assertTransition('acquiring', 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, 'acquiring', 'ready');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tyield* assertTransition(from, 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, from, 'ready');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tyield* Deferred.succeed(entry.readyGate, value);\n\t\t\t}),\n\t\tmarkFailed: (key, cause) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tyield* assertTransition(from, 'failed');\n\t\t\t\tyield* Ref.set(entry.statusRef, 'failed');\n\t\t\t\tyield* onTransition(key, from, 'failed');\n\t\t\t\tyield* Deferred.fail(entry.readyGate, new PluginAcquireFailed({ pluginKey: key, cause }));\n\t\t\t}),\n\t\tresetForRestart: (key, parentScope) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\t\t\tconst scope = yield* Scope.fork(parentScope);\n\t\t\t\t// Authoritatively reset the status to `pending`. The\n\t\t\t\t// transition table only admits `→ pending` from terminal\n\t\t\t\t// states (`failed` / `stopped` / `done`), but a selective\n\t\t\t\t// restart can reset a node that is still `acquiring` or\n\t\t\t\t// `pending` (its scope close interrupted an in-flight\n\t\t\t\t// acquire). Routing that through `transition` would die on\n\t\t\t\t// the off-table move — a defect the supervisor's command\n\t\t\t\t// loop can't catch — so we set the Ref directly and emit\n\t\t\t\t// the `statusChanged` event ourselves to keep the\n\t\t\t\t// projection's restart blip and the \"every status change\n\t\t\t\t// flows through `onTransition`\" contract intact. `acquire`\n\t\t\t\t// then performs a clean `pending → acquiring` for every\n\t\t\t\t// prior node state.\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* Ref.set(entry.statusRef, 'pending');\n\t\t\t\tif (from !== 'pending') yield* onTransition(key, from, 'pending');\n\t\t\t\tmutableEntries.set(key, {\n\t\t\t\t\tnode: entry.node,\n\t\t\t\t\tstatusRef: entry.statusRef,\n\t\t\t\t\treadyGate,\n\t\t\t\t\tscope,\n\t\t\t\t});\n\t\t\t}),\n\t\tawaitReady: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Deferred.await(entry.readyGate);\n\t\t\t}),\n\t};\n\treturn reg;\n};\n\n/** Synchronous accessor: snapshot the resolved value for `key`.\n * Returns `undefined` if the plugin isn't ready yet OR isn't\n * registered. The supervisor guarantees readiness before any\n * consumer calls this; it's the ONLY synchronous path. */\nexport const readResolvedSync = (\n\tregistry: PluginRegistry,\n\tkey: PluginKey,\n): ResolvedValue | undefined => {\n\tconst resolved = (registry as PluginRegistry & { __resolved?: ResolvedMap }).__resolved;\n\treturn resolved?.get(key);\n};\n\n// -----------------------------------------------------------------------------\n// Dependency reader over the registry\n// -----------------------------------------------------------------------------\n\n/**\n * Build a synchronous dependency reader over the registry for one\n * plugin. The upstream key must already be `ready`; the supervisor\n * ensures this by awaiting upstream ready-gates before invoking start.\n */\nexport const buildDependencyReaderFor = (\n\tregistry: PluginRegistry,\n\tnode: DepNode,\n): ((resource: { readonly id: string }) => unknown) => {\n\t// Pre-build a resource-id → upstream-key index for this node so the\n\t// lookups are O(1) instead of scanning dependencies.\n\tconst resourceIdToKey = new Map<string, PluginKey>();\n\tnode.upstreamResources.forEach((resource, i) => {\n\t\tconst upstream = node.upstreamKeys[i];\n\t\tif (upstream !== undefined) resourceIdToKey.set(resource.id, upstream);\n\t});\n\treturn (resource): unknown => {\n\t\tconst key = resourceIdToKey.get(resource.id);\n\t\tif (key === undefined) {\n\t\t\t// Programmer error: the plugin reached outside its declared\n\t\t\t// dependencies. The type system normally rules this out — defending\n\t\t\t// here keeps the runtime honest in the face of cast escapes.\n\t\t\tthrow new DependencyReaderViolation({\n\t\t\t\tkind: 'undeclared-dependency',\n\t\t\t\ttarget: resource.id,\n\t\t\t});\n\t\t}\n\t\tconst value = readResolvedSync(registry, key);\n\t\tif (value === undefined) {\n\t\t\tthrow new DependencyReaderViolation({\n\t\t\t\tkind: 'unresolved-upstream',\n\t\t\t\ttarget: key,\n\t\t\t});\n\t\t}\n\t\treturn value;\n\t};\n};\n\n/** Tagged defect surfaced when a plugin's `start` callback reads a\n * dependency outside its declared `dependsOn` set, or an upstream\n * that hasn't been marked ready yet. Throws synchronously inside the\n * dependency-reader closure; the Effect runtime captures it as a\n * defect the cascade-formatter projects via `_tag`. The `kind`\n * discriminator and `target` carry the offending name; consumers\n * read both. */\nexport class DependencyReaderViolation extends Data.TaggedError('DependencyReaderViolation')<{\n\treadonly kind: 'undeclared-dependency' | 'unresolved-upstream';\n\treadonly target: string;\n}> {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugin-registry.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/plugin-registry.ts"],"sourcesContent":["// Per-plugin lifecycle bookkeeping.\n//\n// One `PluginEntry` per node in the resolved dep-graph. The entry\n// holds:\n// - the live `LifecycleStatus` (Ref, single-fiber linearizable),\n// - the resolved value (set when status transitions to `ready`),\n// - the in-flight acquire fiber, when one is running,\n// - the scope owning the plugin's `start` finalizers,\n// - a `Deferred` that downstream consumers await for the ready gate.\n//\n// The registry tracks per-key lifecycle only; projection concerns stay\n// in the supervisor and reducer.\n\nimport { Data, Deferred, Effect, Fiber, Ref, Scope } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport type { LifecycleStatus } from '../../lifecycle.ts';\nimport type { DepNode } from './dep-graph.ts';\nimport { assertTransition } from './state-machine.ts';\n\n/** Per-registry side channel: synchronously-readable resolved values.\n * Keyed by plugin key. Populated by `markReady`; consulted by the\n * synchronous dependency reader. We can't put the value on the\n * `Deferred` itself in a publicly-supported way, and plugin start\n * receives dependency values synchronously; this is the safe escape hatch.\n *\n * Module-private; only `makeRegistry` writes into the map it\n * allocates. */\ntype ResolvedMap = Map<PluginKey, ResolvedValue>;\n\n// -----------------------------------------------------------------------------\n// Resolved-value shape\n// -----------------------------------------------------------------------------\n\n/** Erased resolved value held in the registry. The supervisor casts\n * back to the concrete type at the boundary where it threads the\n * value into a downstream plugin's resolved dependency object. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ResolvedValue = any;\n\n// -----------------------------------------------------------------------------\n// Per-plugin entry\n// -----------------------------------------------------------------------------\n\n/** Mutable lifecycle state for one plugin instance. */\nexport interface PluginEntry {\n\treadonly node: DepNode;\n\treadonly statusRef: Ref.Ref<LifecycleStatus>;\n\treadonly acquireFiberRef: Ref.Ref<Fiber.Fiber<void, never> | null>;\n\t/** Resolved when the plugin reaches `ready`. Downstream consumers\n\t * await this in the ready-gate. Failure is propagated by interruption\n\t * via `Deferred.fail` to keep the error chain in the cause walker. */\n\treadonly readyGate: Deferred.Deferred<ResolvedValue, PluginAcquireFailed>;\n\t/** Per-plugin Scope. Closing it runs the `start` finalizers. */\n\treadonly scope: Scope.Closeable;\n}\n\n/** Tagged failure: a plugin's `start` rejected. Carries the cause and\n * the failing plugin's key so the cause walker / cascade formatter can\n * attribute it. */\nexport class PluginAcquireFailed extends Data.TaggedError('PluginAcquireFailed')<{\n\treadonly pluginKey: PluginKey;\n\treadonly cause: unknown;\n}> {}\n\n/** Tagged failure: a downstream plugin tried to read a resolved value\n * whose entry isn't registered or hasn't reached `ready`. Programmer-\n * level error class — the dep-graph guarantees this can't happen on\n * the supervisor's own scheduling path. Surfaced when a plugin author\n * reaches outside their declared dependencies. */\nexport class UnknownDependency extends Data.TaggedError('UnknownDependency')<{\n\treadonly pluginKey: PluginKey;\n\treadonly requestedResourceId: string;\n}> {}\n\n// -----------------------------------------------------------------------------\n// Registry\n// -----------------------------------------------------------------------------\n\n/** Build a fresh entry for `node`. Caller still owns the entry — the\n * registry below holds a `ReadonlyMap` of these. */\nexport const makeEntry = (\n\tnode: DepNode,\n\tparentScope: Scope.Scope,\n): Effect.Effect<PluginEntry, never, never> =>\n\tEffect.gen(function* () {\n\t\tconst statusRef = yield* Ref.make<LifecycleStatus>('pending');\n\t\tconst acquireFiberRef = yield* Ref.make<Fiber.Fiber<void, never> | null>(null);\n\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\tconst scope = yield* Scope.fork(parentScope);\n\t\treturn { node, statusRef, acquireFiberRef, readyGate, scope } satisfies PluginEntry;\n\t});\n\n/** The lifecycle registry. Holds one entry per dep-graph node. */\nexport interface PluginRegistry {\n\treadonly entries: ReadonlyMap<PluginKey, PluginEntry>;\n\t/** Read a plugin's current status. */\n\treadonly getStatus: (key: PluginKey) => Effect.Effect<LifecycleStatus, UnknownDependency>;\n\t/** Transition a plugin to a new status. Validates against the\n\t * transition table; emits via `onTransition`. */\n\treadonly transition: (\n\t\tkey: PluginKey,\n\t\tto: LifecycleStatus,\n\t) => Effect.Effect<\n\t\t{ readonly from: LifecycleStatus; readonly to: LifecycleStatus },\n\t\tUnknownDependency\n\t>;\n\t/** Mark a plugin ready with its resolved value. */\n\treadonly markReady: (\n\t\tkey: PluginKey,\n\t\tvalue: ResolvedValue,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Mark a plugin failed. */\n\treadonly markFailed: (key: PluginKey, cause: unknown) => Effect.Effect<void, UnknownDependency>;\n\t/** Prepare a previously torn-down entry for hot restart. Plugin\n\t * scopes and ready gates are single-use: once a scope has been closed,\n\t * any finalizer registered during a later acquire would run\n\t * immediately, and an already-resolved ready gate would leak the old\n\t * value to downstream consumers. */\n\treadonly resetForRestart: (\n\t\tkey: PluginKey,\n\t\tparentScope: Scope.Scope,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Record the acquire fiber currently running for this key, but only if\n\t * the caller still owns the same registry entry generation it read before\n\t * forking. Selective restart swaps entries; stale acquire parents must not\n\t * write their old fiber into the new generation. */\n\treadonly setAcquireFiberIfEntry: (\n\t\tkey: PluginKey,\n\t\texpectedEntry: PluginEntry,\n\t\tfiber: Fiber.Fiber<void, never>,\n\t) => Effect.Effect<boolean, UnknownDependency>;\n\t/** Clear the slot only when it still belongs to the same entry generation\n\t * and settling acquire fiber. */\n\treadonly clearAcquireFiberIfEntry: (\n\t\tkey: PluginKey,\n\t\texpectedEntry: PluginEntry,\n\t\tfiberId: number,\n\t) => Effect.Effect<void, UnknownDependency>;\n\t/** Interrupt any acquire fiber still running for this key. */\n\treadonly interruptAcquire: (key: PluginKey) => Effect.Effect<void, UnknownDependency>;\n\t/** Await `ready` for `key`. Suspends until the plugin's `readyGate`\n\t * resolves. The deferred's failure channel propagates a\n\t * `PluginAcquireFailed` so the supervisor's outer error path picks\n\t * it up. */\n\treadonly awaitReady: (\n\t\tkey: PluginKey,\n\t) => Effect.Effect<ResolvedValue, PluginAcquireFailed | UnknownDependency>;\n}\n\n/** Build a registry from a map of entries. The `onTransition` callback\n * is the supervisor's published event sink — every status change\n * flows through here. */\nexport const makeRegistry = (\n\tentries: ReadonlyMap<PluginKey, PluginEntry>,\n\tonTransition: (key: PluginKey, from: LifecycleStatus, to: LifecycleStatus) => Effect.Effect<void>,\n): PluginRegistry => {\n\tconst mutableEntries = new Map(entries);\n\tconst resolved: ResolvedMap = new Map();\n\n\tconst getEntry = (key: PluginKey): Effect.Effect<PluginEntry, UnknownDependency> => {\n\t\tconst entry = mutableEntries.get(key);\n\t\tif (entry === undefined) {\n\t\t\treturn Effect.fail(new UnknownDependency({ pluginKey: key, requestedResourceId: '' }));\n\t\t}\n\t\treturn Effect.succeed(entry);\n\t};\n\n\tconst reg: PluginRegistry & { __resolved: ResolvedMap } = {\n\t\tentries: mutableEntries,\n\t\t__resolved: resolved,\n\t\tgetStatus: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Ref.get(entry.statusRef);\n\t\t\t}),\n\t\ttransition: (key, to) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* assertTransition(from, to);\n\t\t\t\tyield* Ref.set(entry.statusRef, to);\n\t\t\t\tyield* onTransition(key, from, to);\n\t\t\t\treturn { from, to };\n\t\t\t}),\n\t\tmarkReady: (key, value) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.set(key, value);\n\t\t\t\tif (from !== 'ready') {\n\t\t\t\t\t// `pending → ready` is off-table — the state machine\n\t\t\t\t\t// requires the intermediate `acquiring` hop. Bridge it\n\t\t\t\t\t// here so callers reaching `markReady` from a `pending`\n\t\t\t\t\t// entry (test fixtures, callers that mark a synthetic\n\t\t\t\t\t// already-resolved value) don't have to pre-walk the\n\t\t\t\t\t// machine. Both transitions still emit through\n\t\t\t\t\t// `onTransition` so subscribers see the full path.\n\t\t\t\t\tif (from === 'pending') {\n\t\t\t\t\t\tyield* assertTransition(from, 'acquiring');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'acquiring');\n\t\t\t\t\t\tyield* onTransition(key, from, 'acquiring');\n\t\t\t\t\t\tyield* assertTransition('acquiring', 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, 'acquiring', 'ready');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tyield* assertTransition(from, 'ready');\n\t\t\t\t\t\tyield* Ref.set(entry.statusRef, 'ready');\n\t\t\t\t\t\tyield* onTransition(key, from, 'ready');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tyield* Deferred.succeed(entry.readyGate, value);\n\t\t\t}),\n\t\tmarkFailed: (key, cause) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tresolved.delete(key);\n\t\t\t\tyield* assertTransition(from, 'failed');\n\t\t\t\tyield* Ref.set(entry.statusRef, 'failed');\n\t\t\t\tyield* onTransition(key, from, 'failed');\n\t\t\t\tyield* Deferred.fail(entry.readyGate, new PluginAcquireFailed({ pluginKey: key, cause }));\n\t\t\t}),\n\t\tresetForRestart: (key, parentScope) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst acquireFiber = yield* Ref.getAndSet(entry.acquireFiberRef, null);\n\t\t\t\tif (acquireFiber !== null) {\n\t\t\t\t\tyield* Fiber.interrupt(acquireFiber);\n\t\t\t\t}\n\t\t\t\tresolved.delete(key);\n\t\t\t\tconst readyGate = yield* Deferred.make<ResolvedValue, PluginAcquireFailed>();\n\t\t\t\tconst acquireFiberRef = yield* Ref.make<Fiber.Fiber<void, never> | null>(null);\n\t\t\t\tconst scope = yield* Scope.fork(parentScope);\n\t\t\t\t// Authoritatively reset the status to `pending`. The\n\t\t\t\t// transition table only admits `→ pending` from terminal\n\t\t\t\t// states (`failed` / `stopped` / `done`), but a selective\n\t\t\t\t// restart can reset a node that is still `acquiring` or\n\t\t\t\t// `pending` (its scope close interrupted an in-flight\n\t\t\t\t// acquire). Routing that through `transition` would die on\n\t\t\t\t// the off-table move — a defect the supervisor's command\n\t\t\t\t// loop can't catch — so we set the Ref directly and emit\n\t\t\t\t// the `statusChanged` event ourselves to keep the\n\t\t\t\t// projection's restart blip and the \"every status change\n\t\t\t\t// flows through `onTransition`\" contract intact. `acquire`\n\t\t\t\t// then performs a clean `pending → acquiring` for every\n\t\t\t\t// prior node state.\n\t\t\t\tconst from = yield* Ref.get(entry.statusRef);\n\t\t\t\tyield* Ref.set(entry.statusRef, 'pending');\n\t\t\t\tif (from !== 'pending') yield* onTransition(key, from, 'pending');\n\t\t\t\tmutableEntries.set(key, {\n\t\t\t\t\tnode: entry.node,\n\t\t\t\t\tstatusRef: entry.statusRef,\n\t\t\t\t\tacquireFiberRef,\n\t\t\t\t\treadyGate,\n\t\t\t\t\tscope,\n\t\t\t\t});\n\t\t\t}),\n\t\tsetAcquireFiberIfEntry: (key, expectedEntry, fiber) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tif (entry !== expectedEntry) return false;\n\t\t\t\tyield* Ref.set(entry.acquireFiberRef, fiber);\n\t\t\t\treturn true;\n\t\t\t}),\n\t\tclearAcquireFiberIfEntry: (key, expectedEntry, fiberId) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tif (entry !== expectedEntry) return;\n\t\t\t\tyield* Ref.update(entry.acquireFiberRef, (current) =>\n\t\t\t\t\tcurrent !== null && current.id === fiberId ? null : current,\n\t\t\t\t);\n\t\t\t}),\n\t\tinterruptAcquire: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\tconst acquireFiber = yield* Ref.getAndSet(entry.acquireFiberRef, null);\n\t\t\t\tif (acquireFiber !== null) {\n\t\t\t\t\tyield* Fiber.interrupt(acquireFiber);\n\t\t\t\t}\n\t\t\t}),\n\t\tawaitReady: (key) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst entry = yield* getEntry(key);\n\t\t\t\treturn yield* Deferred.await(entry.readyGate);\n\t\t\t}),\n\t};\n\treturn reg;\n};\n\n/** Synchronous accessor: snapshot the resolved value for `key`.\n * Returns `undefined` if the plugin isn't ready yet OR isn't\n * registered. The supervisor guarantees readiness before any\n * consumer calls this; it's the ONLY synchronous path. */\nexport const readResolvedSync = (\n\tregistry: PluginRegistry,\n\tkey: PluginKey,\n): ResolvedValue | undefined => {\n\tconst resolved = (registry as PluginRegistry & { __resolved?: ResolvedMap }).__resolved;\n\treturn resolved?.get(key);\n};\n\n// -----------------------------------------------------------------------------\n// Dependency reader over the registry\n// -----------------------------------------------------------------------------\n\n/**\n * Build a synchronous dependency reader over the registry for one\n * plugin. The upstream key must already be `ready`; the supervisor\n * ensures this by awaiting upstream ready-gates before invoking start.\n */\nexport const buildDependencyReaderFor = (\n\tregistry: PluginRegistry,\n\tnode: DepNode,\n): ((resource: { readonly id: string }) => unknown) => {\n\t// Pre-build a resource-id → upstream-key index for this node so the\n\t// lookups are O(1) instead of scanning dependencies.\n\tconst resourceIdToKey = new Map<string, PluginKey>();\n\tnode.upstreamResources.forEach((resource, i) => {\n\t\tconst upstream = node.upstreamKeys[i];\n\t\tif (upstream !== undefined) resourceIdToKey.set(resource.id, upstream);\n\t});\n\treturn (resource): unknown => {\n\t\tconst key = resourceIdToKey.get(resource.id);\n\t\tif (key === undefined) {\n\t\t\t// Programmer error: the plugin reached outside its declared\n\t\t\t// dependencies. The type system normally rules this out — defending\n\t\t\t// here keeps the runtime honest in the face of cast escapes.\n\t\t\tthrow new DependencyReaderViolation({\n\t\t\t\tkind: 'undeclared-dependency',\n\t\t\t\ttarget: resource.id,\n\t\t\t});\n\t\t}\n\t\tconst value = readResolvedSync(registry, key);\n\t\tif (value === undefined) {\n\t\t\tthrow new DependencyReaderViolation({\n\t\t\t\tkind: 'unresolved-upstream',\n\t\t\t\ttarget: key,\n\t\t\t});\n\t\t}\n\t\treturn value;\n\t};\n};\n\n/** Tagged defect surfaced when a plugin's `start` callback reads a\n * dependency outside its declared `dependsOn` set, or an upstream\n * that hasn't been marked ready yet. Throws synchronously inside the\n * dependency-reader closure; the Effect runtime captures it as a\n * defect the cascade-formatter projects via `_tag`. The `kind`\n * discriminator and `target` carry the offending name; consumers\n * read both. */\nexport class DependencyReaderViolation extends Data.TaggedError('DependencyReaderViolation')<{\n\treadonly kind: 'undeclared-dependency' | 'unresolved-upstream';\n\treadonly target: string;\n}> {}\n"],"mappings":"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"}
|
|
@@ -9,26 +9,13 @@ import { Effect } from "effect";
|
|
|
9
9
|
* the node begins `acquiring`."
|
|
10
10
|
*/
|
|
11
11
|
const awaitUpstreams = (registry, node) => Effect.gen(function* () {
|
|
12
|
-
yield* Effect.annotateCurrentSpan({
|
|
13
|
-
"devstack.plugin.key": node.key,
|
|
14
|
-
"devstack.plugin.upstreamCount": node.upstreamKeys.length
|
|
15
|
-
});
|
|
16
12
|
if (node.upstreamKeys.length === 0) return;
|
|
17
13
|
yield* Effect.all(node.upstreamKeys.map((key) => registry.awaitReady(key)), {
|
|
18
14
|
concurrency: "unbounded",
|
|
19
15
|
discard: true
|
|
20
16
|
});
|
|
21
|
-
})
|
|
22
|
-
/**
|
|
23
|
-
* Wait for every plugin in `keys` to reach `ready`. Used by the
|
|
24
|
-
* supervisor's "stack is ready" gate after the level-batched parallel
|
|
25
|
-
* acquire completes.
|
|
26
|
-
*/
|
|
27
|
-
const awaitAll = (registry, keys) => Effect.all(keys.map((key) => registry.awaitReady(key)), {
|
|
28
|
-
concurrency: "unbounded",
|
|
29
|
-
discard: true
|
|
30
|
-
}).pipe(Effect.withSpan("lifecycle.ready-gate.awaitAll"));
|
|
17
|
+
});
|
|
31
18
|
//#endregion
|
|
32
|
-
export {
|
|
19
|
+
export { awaitUpstreams };
|
|
33
20
|
|
|
34
21
|
//# sourceMappingURL=ready-gate.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ready-gate.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/ready-gate.ts"],"sourcesContent":["// Ready-gate composition over `PluginRegistry`.\n//\n// Architecture § Plugin lifecycle within a stack § Ready gate:\n// \"Plugin's acquire procedure returns the resolved value + capability\n// decls. Substrate writes them to the typed registries. Plugin\n// transitions to `ready`. Downstream consumers are unblocked.\"\n//\n// This module provides the small `
|
|
1
|
+
{"version":3,"file":"ready-gate.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/ready-gate.ts"],"sourcesContent":["// Ready-gate composition over `PluginRegistry`.\n//\n// Architecture § Plugin lifecycle within a stack § Ready gate:\n// \"Plugin's acquire procedure returns the resolved value + capability\n// decls. Substrate writes them to the typed registries. Plugin\n// transitions to `ready`. Downstream consumers are unblocked.\"\n//\n// This module provides the small `awaitUpstreams` helper the\n// supervisor's acquire loop calls. The actual `Deferred` machinery\n// lives on `PluginRegistry`; here we just compose it and short-circuit\n// on the first upstream failure. (The stack-wide \"all ready\" gate is\n// the supervisor's own `allReadyOrTerminal` status signal, which is\n// `done`-tolerant — see supervisor/state.ts — not a per-node\n// ready-gate fan-out.)\n\nimport { Effect } from 'effect';\n\nimport type { DepNode } from './dep-graph.ts';\nimport type { PluginAcquireFailed, PluginRegistry, UnknownDependency } from './plugin-registry.ts';\n\n/**\n * Wait for every upstream of `node` to reach `ready`. Returns when\n * they all have; short-circuits on the first upstream failure (the\n * failed deferred propagates `PluginAcquireFailed`).\n *\n * Architecture § Scheduling: \"When all upstream keys are `ready`,\n * the node begins `acquiring`.\"\n */\nexport const awaitUpstreams = (\n\tregistry: PluginRegistry,\n\tnode: DepNode,\n): Effect.Effect<void, PluginAcquireFailed | UnknownDependency> =>\n\tEffect.gen(function* () {\n\t\tif (node.upstreamKeys.length === 0) return;\n\t\t// Parallelize the awaits — every upstream's ready-gate resolves\n\t\t// once (or fails once); racing them is the right shape.\n\t\tyield* Effect.all(\n\t\t\tnode.upstreamKeys.map((key) => registry.awaitReady(key)),\n\t\t\t{ concurrency: 'unbounded', discard: true },\n\t\t);\n\t});\n"],"mappings":";;;;;;;;;;AA4BA,MAAa,kBACZ,UACA,SAEA,OAAO,IAAI,aAAa;CACvB,IAAI,KAAK,aAAa,WAAW,GAAG;CAGpC,OAAO,OAAO,IACb,KAAK,aAAa,KAAK,QAAQ,SAAS,WAAW,GAAG,CAAC,GACvD;EAAE,aAAa;EAAa,SAAS;CAAK,CAC3C;AACD,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { downstreamClosure
|
|
1
|
+
import { downstreamClosure } from "./dep-graph.mjs";
|
|
2
|
+
import { plan } from "../reconcile/graph.mjs";
|
|
2
3
|
import { Data, Effect } from "effect";
|
|
3
4
|
//#region src/substrate/runtime/lifecycle/selective-restart.ts
|
|
4
5
|
/** Tagged error: a restart was requested for a key that isn't in the
|
|
@@ -7,37 +8,40 @@ import { Data, Effect } from "effect";
|
|
|
7
8
|
var RestartTargetMissing = class extends Data.TaggedError("RestartTargetMissing") {};
|
|
8
9
|
/**
|
|
9
10
|
* Build a restart plan from a set of root invalidation targets. Each
|
|
10
|
-
* root contributes its full downstream closure to the slice.
|
|
11
|
+
* root contributes its full downstream closure to the slice. The
|
|
12
|
+
* downstream-closure slice computation + the root-membership validation
|
|
13
|
+
* are this planner's unique work; the dep-ordering itself delegates to
|
|
14
|
+
* the shared reconcile `plan` body, which returns a `GraphPlan`.
|
|
11
15
|
*/
|
|
12
16
|
const planRestart = (graph, roots) => Effect.gen(function* () {
|
|
13
|
-
yield* Effect.annotateCurrentSpan({ "devstack.restart.rootCount": roots.size });
|
|
14
17
|
for (const root of roots) if (!graph.nodes.has(root)) return yield* Effect.fail(new RestartTargetMissing({ pluginKey: root }));
|
|
15
18
|
const slice = /* @__PURE__ */ new Set();
|
|
16
19
|
for (const root of roots) for (const key of downstreamClosure(graph, root)) slice.add(key);
|
|
17
|
-
return {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*
|
|
25
|
-
* dep-graph order, reverse. Architecture § Stack lifecycle:
|
|
26
|
-
* "shutdown.requested → parallel teardown (max grace, not sum grace)"
|
|
20
|
+
return plan(graph, {
|
|
21
|
+
kind: "graph-keys",
|
|
22
|
+
keys: [...slice]
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
/** Plan a drain + re-acquire of the whole graph MINUS the nodes matched by
|
|
26
|
+
* `exclude`. The excluded nodes stay live while every other plugin is
|
|
27
|
+
* drained + re-acquired.
|
|
27
28
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
* The live `snapshot.restore` re-acquire passes a predicate over the
|
|
30
|
+
* plugin-declared keep-alive flag so a plugin whose transport is
|
|
31
|
+
* answering the restore isn't torn down mid-flight (which would surface
|
|
32
|
+
* to its caller as a 502 even though the restore succeeded). This module
|
|
33
|
+
* filters purely on the node flag — it has no knowledge of which plugins
|
|
34
|
+
* set it. `stack.restart` / CLI full-restart drains everything by passing
|
|
35
|
+
* the full key set straight to `plan`. */
|
|
36
|
+
const planExcluding = (graph, exclude) => {
|
|
37
|
+
const slice = /* @__PURE__ */ new Set();
|
|
38
|
+
for (const [key, node] of graph.nodes) if (!exclude(node)) slice.add(key);
|
|
39
|
+
return plan(graph, {
|
|
40
|
+
kind: "graph-keys",
|
|
41
|
+
keys: [...slice]
|
|
42
|
+
});
|
|
39
43
|
};
|
|
40
44
|
//#endregion
|
|
41
|
-
export { RestartTargetMissing,
|
|
45
|
+
export { RestartTargetMissing, planExcluding, planRestart };
|
|
42
46
|
|
|
43
47
|
//# sourceMappingURL=selective-restart.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selective-restart.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/selective-restart.ts"],"sourcesContent":["// Selective-restart driver.\n//\n// Architecture § Watch-triggered invalidation:\n// \"L0 watcher emits a debounced+deduped content-hash event. L3 watch\n// dispatcher consults plugin watch decls. Matched plugins enter\n// `selective-restart-pending`. Scheduler runs subset invalidate: evict\n// shadow-cache entry BEFORE closing scope; run finalizers (parallel\n// strategy); re-acquire.\"\n//\n// Architecture § Selective restart cascading:\n// \"Invalidating a producer invalidates downstream consumers along\n// dep-graph edges (cascade semantics — engine already has this).\"\n//\n// This module is the planner: given a set of root keys to invalidate,\n// compute the downstream slice, order it for teardown and re-acquire.\n// The actual `Scope.close` / `acquire` calls live in `supervisor.ts`\n// so it can fold them into the per-cycle event stream.\n\nimport { Data, Effect } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport { downstreamClosure,
|
|
1
|
+
{"version":3,"file":"selective-restart.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/selective-restart.ts"],"sourcesContent":["// Selective-restart driver.\n//\n// Architecture § Watch-triggered invalidation:\n// \"L0 watcher emits a debounced+deduped content-hash event. L3 watch\n// dispatcher consults plugin watch decls. Matched plugins enter\n// `selective-restart-pending`. Scheduler runs subset invalidate: evict\n// shadow-cache entry BEFORE closing scope; run finalizers (parallel\n// strategy); re-acquire.\"\n//\n// Architecture § Selective restart cascading:\n// \"Invalidating a producer invalidates downstream consumers along\n// dep-graph edges (cascade semantics — engine already has this).\"\n//\n// This module is the planner: given a set of root keys to invalidate,\n// compute the downstream slice, order it for teardown and re-acquire.\n// The actual `Scope.close` / `acquire` calls live in `supervisor.ts`\n// so it can fold them into the per-cycle event stream.\n\nimport { Data, Effect } from 'effect';\n\nimport type { PluginKey } from '../../brand.ts';\nimport { plan, type GraphPlan } from '../reconcile/graph.ts';\nimport { downstreamClosure, type DepNode, type ResolvedGraph } from './dep-graph.ts';\n\n/** Tagged error: a restart was requested for a key that isn't in the\n * graph. The supervisor lifts this from `attribute()` callers that\n * somehow produced a stale key — defensive. */\nexport class RestartTargetMissing extends Data.TaggedError('RestartTargetMissing')<{\n\treadonly pluginKey: PluginKey;\n}> {}\n\n/**\n * Build a restart plan from a set of root invalidation targets. Each\n * root contributes its full downstream closure to the slice. The\n * downstream-closure slice computation + the root-membership validation\n * are this planner's unique work; the dep-ordering itself delegates to\n * the shared reconcile `plan` body, which returns a `GraphPlan`.\n */\nexport const planRestart = (\n\tgraph: ResolvedGraph,\n\troots: ReadonlySet<PluginKey>,\n): Effect.Effect<GraphPlan, RestartTargetMissing> =>\n\tEffect.gen(function* () {\n\t\tfor (const root of roots) {\n\t\t\tif (!graph.nodes.has(root)) {\n\t\t\t\treturn yield* Effect.fail(new RestartTargetMissing({ pluginKey: root }));\n\t\t\t}\n\t\t}\n\t\tconst slice = new Set<PluginKey>();\n\t\tfor (const root of roots) {\n\t\t\tfor (const key of downstreamClosure(graph, root)) slice.add(key);\n\t\t}\n\t\treturn plan(graph, { kind: 'graph-keys', keys: [...slice] });\n\t});\n\n/** Plan a drain + re-acquire of the whole graph MINUS the nodes matched by\n * `exclude`. The excluded nodes stay live while every other plugin is\n * drained + re-acquired.\n *\n * The live `snapshot.restore` re-acquire passes a predicate over the\n * plugin-declared keep-alive flag so a plugin whose transport is\n * answering the restore isn't torn down mid-flight (which would surface\n * to its caller as a 502 even though the restore succeeded). This module\n * filters purely on the node flag — it has no knowledge of which plugins\n * set it. `stack.restart` / CLI full-restart drains everything by passing\n * the full key set straight to `plan`. */\nexport const planExcluding = (\n\tgraph: ResolvedGraph,\n\texclude: (node: DepNode) => boolean,\n): GraphPlan => {\n\tconst slice = new Set<PluginKey>();\n\tfor (const [key, node] of graph.nodes) {\n\t\tif (!exclude(node)) slice.add(key);\n\t}\n\treturn plan(graph, { kind: 'graph-keys', keys: [...slice] });\n};\n"],"mappings":";;;;;;;AA2BA,IAAa,uBAAb,cAA0C,KAAK,YAAY,sBAAsB,CAAC,CAE/E,CAAC;;;;;;;;AASJ,MAAa,eACZ,OACA,UAEA,OAAO,IAAI,aAAa;CACvB,KAAK,MAAM,QAAQ,OAClB,IAAI,CAAC,MAAM,MAAM,IAAI,IAAI,GACxB,OAAO,OAAO,OAAO,KAAK,IAAI,qBAAqB,EAAE,WAAW,KAAK,CAAC,CAAC;CAGzE,MAAM,wBAAQ,IAAI,IAAe;CACjC,KAAK,MAAM,QAAQ,OAClB,KAAK,MAAM,OAAO,kBAAkB,OAAO,IAAI,GAAG,MAAM,IAAI,GAAG;CAEhE,OAAO,KAAK,OAAO;EAAE,MAAM;EAAc,MAAM,CAAC,GAAG,KAAK;CAAE,CAAC;AAC5D,CAAC;;;;;;;;;;;;AAaF,MAAa,iBACZ,OACA,YACe;CACf,MAAM,wBAAQ,IAAI,IAAe;CACjC,KAAK,MAAM,CAAC,KAAK,SAAS,MAAM,OAC/B,IAAI,CAAC,QAAQ,IAAI,GAAG,MAAM,IAAI,GAAG;CAElC,OAAO,KAAK,OAAO;EAAE,MAAM;EAAc,MAAM,CAAC,GAAG,KAAK;CAAE,CAAC;AAC5D"}
|
|
@@ -57,7 +57,7 @@ const installSignalHandler = (commands, options = {}) => Effect.gen(function* ()
|
|
|
57
57
|
for (const { signal, listener } of handlers) process.removeListener(signal, listener);
|
|
58
58
|
}));
|
|
59
59
|
return yield* Effect.never;
|
|
60
|
-
})
|
|
60
|
+
});
|
|
61
61
|
//#endregion
|
|
62
62
|
export { installSignalHandler };
|
|
63
63
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/signals.ts"],"sourcesContent":["// POSIX signal handling.\n//\n// Architecture § Engine / supervisor split:\n// \"signals → L0 (one POSIX signal handler at process boot), routed\n// via the command channel.\"\n//\n// Discipline:\n// - ONE handler per process. Registering twice is a programmer\n// error.\n// - Signals translate to `EngineCommand`s on the typed command stream\n// (`shutdown.requested` for graceful, `shutdown.hardKillRequested`\n// for hard).\n// - Second SIGINT/SIGTERM escalates to abort: the hard-kill command\n// is offered first, then `process.exit(130)` (or 143 for SIGTERM)\n// is scheduled.\n//\n// The supervisor wires this fiber once at boot via `Effect.forkScoped`;\n// its scope is the supervisor's outer scope, so the handler unregisters\n// when the supervisor tears down (test environments that boot multiple\n// supervisors must close them before booting the next).\n\nimport { Effect, Queue, Scope } from 'effect';\n\nimport type { EngineCommand, ShutdownSignal } from '../../events.ts';\n\n/** Signals the supervisor handles. SIGHUP intentionally omitted —\n * reconfigure is a command-channel concern, not a signal one. */\nconst HANDLED_SIGNALS = ['SIGINT', 'SIGTERM'] as const satisfies ReadonlyArray<ShutdownSignal>;\ntype HandledSignal = (typeof HANDLED_SIGNALS)[number];\n\n/** Map a signal to the exit code POSIX clients expect — 128 + N. */\nconst exitCodeForSignal = (signal: HandledSignal): number => {\n\tswitch (signal) {\n\t\tcase 'SIGINT':\n\t\t\treturn 130;\n\t\tcase 'SIGTERM':\n\t\t\treturn 143;\n\t}\n};\n\nexport interface SignalHandlerOptions {\n\treadonly scheduleExit?: (exitCode: number) => void;\n}\n\nconst scheduleProcessExit = (exitCode: number): void => {\n\tsetImmediate(() => {\n\t\tprocess.exit(exitCode);\n\t});\n};\n\n/**\n * Install signal handlers that publish `shutdown.requested` (first\n * signal) and `shutdown.hardKillRequested` before scheduling process\n * exit (second handled signal).\n *\n * Returns an Effect that runs forever in its Scope; the supervisor\n * forks it via `Effect.forkScoped`. Scope close unregisters the\n * listeners — Node's `process` listeners persist past the scope\n * otherwise, leading to \"ghost\" handlers from prior test boots.\n */\nexport const installSignalHandler = (\n\tcommands: Queue.Enqueue<EngineCommand>,\n\toptions: SignalHandlerOptions = {},\n): Effect.Effect<never, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst scheduleExit = options.scheduleExit ?? scheduleProcessExit;\n\t\t// Capture the surrounding fiber's Context so the signal-listener\n\t\t// fork inherits the supervisor's logger Layer, fiber-refs, and\n\t\t// span context. Bare `Effect.runFork` evaluates against an empty\n\t\t// context — warnings/spans from the offered command would\n\t\t// otherwise bypass redaction rules and supervisor instrumentation.\n\t\tconst supervisorContext = yield* Effect.context<never>();\n\t\tconst runForkInherited = Effect.runForkWith(supervisorContext);\n\t\tlet shutdownRequested = false;\n\n\t\tconst handlers: Array<{\n\t\t\treadonly signal: HandledSignal;\n\t\t\treadonly listener: NodeJS.SignalsListener;\n\t\t}> = [];\n\n\t\tfor (const signal of HANDLED_SIGNALS) {\n\t\t\tconst listener: NodeJS.SignalsListener = () => {\n\t\t\t\tconst exitCode = exitCodeForSignal(signal);\n\t\t\t\tif (shutdownRequested) {\n\t\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\t\ttag: 'shutdown.hardKillRequested',\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tat: Date.now(),\n\t\t\t\t\t} satisfies EngineCommand).pipe(\n\t\t\t\t\t\tEffect.andThen(Effect.sync(() => scheduleExit(exitCode))),\n\t\t\t\t\t);\n\t\t\t\t\trunForkInherited(offerEffect);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tshutdownRequested = true;\n\t\t\t\tprocess.exitCode ??= exitCode;\n\t\t\t\t// Publish `shutdown.requested` — same shape regardless of\n\t\t\t\t// which signal fired. The supervisor decides drain vs abort\n\t\t\t\t// on its own loop.\n\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\ttag: 'shutdown.requested',\n\t\t\t\t} satisfies EngineCommand);\n\t\t\t\t// We're inside a Node listener; bridge into Effect via the\n\t\t\t\t// captured supervisor Context so the offered command\n\t\t\t\t// inherits logger/fiber-refs/spans. `runFork` returns a\n\t\t\t\t// fiber but we don't track it — the queue is bounded by\n\t\t\t\t// the supervisor's lifetime.\n\t\t\t\trunForkInherited(offerEffect);\n\t\t\t};\n\t\t\tprocess.on(signal, listener);\n\t\t\thandlers.push({ signal, listener });\n\t\t}\n\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tfor (const { signal, listener } of handlers) {\n\t\t\t\t\tprocess.removeListener(signal, listener);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\t// Park forever; the listeners themselves run synchronously in\n\t\t// Node's event loop, not in this fiber.\n\t\treturn yield* Effect.never;\n\t})
|
|
1
|
+
{"version":3,"file":"signals.mjs","names":[],"sources":["../../../../src/substrate/runtime/lifecycle/signals.ts"],"sourcesContent":["// POSIX signal handling.\n//\n// Architecture § Engine / supervisor split:\n// \"signals → L0 (one POSIX signal handler at process boot), routed\n// via the command channel.\"\n//\n// Discipline:\n// - ONE handler per process. Registering twice is a programmer\n// error.\n// - Signals translate to `EngineCommand`s on the typed command stream\n// (`shutdown.requested` for graceful, `shutdown.hardKillRequested`\n// for hard).\n// - Second SIGINT/SIGTERM escalates to abort: the hard-kill command\n// is offered first, then `process.exit(130)` (or 143 for SIGTERM)\n// is scheduled.\n//\n// The supervisor wires this fiber once at boot via `Effect.forkScoped`;\n// its scope is the supervisor's outer scope, so the handler unregisters\n// when the supervisor tears down (test environments that boot multiple\n// supervisors must close them before booting the next).\n\nimport { Effect, Queue, Scope } from 'effect';\n\nimport type { EngineCommand, ShutdownSignal } from '../../events.ts';\n\n/** Signals the supervisor handles. SIGHUP intentionally omitted —\n * reconfigure is a command-channel concern, not a signal one. */\nconst HANDLED_SIGNALS = ['SIGINT', 'SIGTERM'] as const satisfies ReadonlyArray<ShutdownSignal>;\ntype HandledSignal = (typeof HANDLED_SIGNALS)[number];\n\n/** Map a signal to the exit code POSIX clients expect — 128 + N. */\nconst exitCodeForSignal = (signal: HandledSignal): number => {\n\tswitch (signal) {\n\t\tcase 'SIGINT':\n\t\t\treturn 130;\n\t\tcase 'SIGTERM':\n\t\t\treturn 143;\n\t}\n};\n\nexport interface SignalHandlerOptions {\n\treadonly scheduleExit?: (exitCode: number) => void;\n}\n\nconst scheduleProcessExit = (exitCode: number): void => {\n\tsetImmediate(() => {\n\t\tprocess.exit(exitCode);\n\t});\n};\n\n/**\n * Install signal handlers that publish `shutdown.requested` (first\n * signal) and `shutdown.hardKillRequested` before scheduling process\n * exit (second handled signal).\n *\n * Returns an Effect that runs forever in its Scope; the supervisor\n * forks it via `Effect.forkScoped`. Scope close unregisters the\n * listeners — Node's `process` listeners persist past the scope\n * otherwise, leading to \"ghost\" handlers from prior test boots.\n */\nexport const installSignalHandler = (\n\tcommands: Queue.Enqueue<EngineCommand>,\n\toptions: SignalHandlerOptions = {},\n): Effect.Effect<never, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst scheduleExit = options.scheduleExit ?? scheduleProcessExit;\n\t\t// Capture the surrounding fiber's Context so the signal-listener\n\t\t// fork inherits the supervisor's logger Layer, fiber-refs, and\n\t\t// span context. Bare `Effect.runFork` evaluates against an empty\n\t\t// context — warnings/spans from the offered command would\n\t\t// otherwise bypass redaction rules and supervisor instrumentation.\n\t\tconst supervisorContext = yield* Effect.context<never>();\n\t\tconst runForkInherited = Effect.runForkWith(supervisorContext);\n\t\tlet shutdownRequested = false;\n\n\t\tconst handlers: Array<{\n\t\t\treadonly signal: HandledSignal;\n\t\t\treadonly listener: NodeJS.SignalsListener;\n\t\t}> = [];\n\n\t\tfor (const signal of HANDLED_SIGNALS) {\n\t\t\tconst listener: NodeJS.SignalsListener = () => {\n\t\t\t\tconst exitCode = exitCodeForSignal(signal);\n\t\t\t\tif (shutdownRequested) {\n\t\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\t\ttag: 'shutdown.hardKillRequested',\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\texitCode,\n\t\t\t\t\t\tat: Date.now(),\n\t\t\t\t\t} satisfies EngineCommand).pipe(\n\t\t\t\t\t\tEffect.andThen(Effect.sync(() => scheduleExit(exitCode))),\n\t\t\t\t\t);\n\t\t\t\t\trunForkInherited(offerEffect);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tshutdownRequested = true;\n\t\t\t\tprocess.exitCode ??= exitCode;\n\t\t\t\t// Publish `shutdown.requested` — same shape regardless of\n\t\t\t\t// which signal fired. The supervisor decides drain vs abort\n\t\t\t\t// on its own loop.\n\t\t\t\tconst offerEffect = Queue.offer(commands, {\n\t\t\t\t\ttag: 'shutdown.requested',\n\t\t\t\t} satisfies EngineCommand);\n\t\t\t\t// We're inside a Node listener; bridge into Effect via the\n\t\t\t\t// captured supervisor Context so the offered command\n\t\t\t\t// inherits logger/fiber-refs/spans. `runFork` returns a\n\t\t\t\t// fiber but we don't track it — the queue is bounded by\n\t\t\t\t// the supervisor's lifetime.\n\t\t\t\trunForkInherited(offerEffect);\n\t\t\t};\n\t\t\tprocess.on(signal, listener);\n\t\t\thandlers.push({ signal, listener });\n\t\t}\n\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\tfor (const { signal, listener } of handlers) {\n\t\t\t\t\tprocess.removeListener(signal, listener);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\n\t\t// Park forever; the listeners themselves run synchronously in\n\t\t// Node's event loop, not in this fiber.\n\t\treturn yield* Effect.never;\n\t});\n\n/** Re-export the handled-signal list so tests / docs can enumerate. */\nexport const handledSignals: ReadonlyArray<HandledSignal> = HANDLED_SIGNALS;\n"],"mappings":";;;;AA2BA,MAAM,kBAAkB,CAAC,UAAU,SAAS;;AAI5C,MAAM,qBAAqB,WAAkC;CAC5D,QAAQ,QAAR;EACC,KAAK,UACJ,OAAO;EACR,KAAK,WACJ,OAAO;CACT;AACD;AAMA,MAAM,uBAAuB,aAA2B;CACvD,mBAAmB;EAClB,QAAQ,KAAK,QAAQ;CACtB,CAAC;AACF;;;;;;;;;;;AAYA,MAAa,wBACZ,UACA,UAAgC,CAAC,MAEjC,OAAO,IAAI,aAAa;CACvB,MAAM,eAAe,QAAQ,gBAAgB;CAM7C,MAAM,oBAAoB,OAAO,OAAO,QAAe;CACvD,MAAM,mBAAmB,OAAO,YAAY,iBAAiB;CAC7D,IAAI,oBAAoB;CAExB,MAAM,WAGD,CAAC;CAEN,KAAK,MAAM,UAAU,iBAAiB;EACrC,MAAM,iBAAyC;GAC9C,MAAM,WAAW,kBAAkB,MAAM;GACzC,IAAI,mBAAmB;IAStB,iBARoB,MAAM,MAAM,UAAU;KACzC,KAAK;KACL;KACA;KACA,IAAI,KAAK,IAAI;IACd,CAAyB,CAAC,CAAC,KAC1B,OAAO,QAAQ,OAAO,WAAW,aAAa,QAAQ,CAAC,CAAC,CAE9B,CAAC;IAC5B;GACD;GACA,oBAAoB;GACpB,QAAQ,aAAa;GAYrB,iBARoB,MAAM,MAAM,UAAU,EACzC,KAAK,qBACN,CAM2B,CAAC;EAC7B;EACA,QAAQ,GAAG,QAAQ,QAAQ;EAC3B,SAAS,KAAK;GAAE;GAAQ;EAAS,CAAC;CACnC;CAEA,OAAO,OAAO,mBACb,OAAO,WAAW;EACjB,KAAK,MAAM,EAAE,QAAQ,cAAc,UAClC,QAAQ,eAAe,QAAQ,QAAQ;CAEzC,CAAC,CACF;CAIA,OAAO,OAAO,OAAO;AACtB,CAAC"}
|