@treeseed/sdk 0.11.0 → 0.12.5
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 +9 -4
- package/dist/agent-capacity.d.ts +916 -0
- package/dist/agent-capacity.js +1600 -0
- package/dist/agent-tools.d.ts +37 -0
- package/dist/agent-tools.js +301 -0
- package/dist/api/app.d.ts +1 -1
- package/dist/api/auth/d1-database.d.ts +2 -2
- package/dist/api/auth/d1-provider.d.ts +4 -4
- package/dist/api/auth/d1-store.d.ts +2 -2
- package/dist/api/auth/memory-provider.d.ts +1 -1
- package/dist/api/auth/tokens.d.ts +1 -1
- package/dist/api/config.d.ts +3 -1
- package/dist/api/config.js +34 -10
- package/dist/api/http.d.ts +2 -2
- package/dist/api/index.d.ts +10 -10
- package/dist/api/index.js +4 -2
- package/dist/api/operations-routes.d.ts +3 -3
- package/dist/api/operations.d.ts +1 -1
- package/dist/api/providers.d.ts +1 -1
- package/dist/api/providers.js +21 -4
- package/dist/api/railway.d.ts +3 -2
- package/dist/api/sdk-dispatch.d.ts +4 -4
- package/dist/api/sdk-routes.d.ts +2 -2
- package/dist/api/templates.d.ts +2 -2
- package/dist/api/types.d.ts +3 -2
- package/dist/capacity-provider.d.ts +117 -60
- package/dist/capacity-provider.js +215 -43
- package/dist/capacity.d.ts +2 -2
- package/dist/cli-tools.d.ts +1 -1
- package/dist/content-operations.d.ts +97 -0
- package/dist/content-operations.js +250 -0
- package/dist/content-store.d.ts +4 -4
- package/dist/control-plane-client.d.ts +13 -18
- package/dist/control-plane-client.js +8 -86
- package/dist/control-plane.d.ts +2 -2
- package/dist/copilot.d.ts +3 -0
- package/dist/copilot.js +16 -1
- package/dist/d1-http.d.ts +1 -1
- package/dist/d1-store.d.ts +32 -57
- package/dist/d1-store.js +115 -318
- package/dist/db/d1.d.ts +1 -232
- package/dist/db/index.d.ts +3 -3
- package/dist/db/market-schema.d.ts +49037 -11843
- package/dist/db/market-schema.js +1788 -50
- package/dist/db/node-sqlite.d.ts +1 -232
- package/dist/db/schema.d.ts +0 -462
- package/dist/db/schema.js +2 -22
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +0 -11
- package/dist/fixture-support.js +52 -4
- package/dist/governance.d.ts +133 -0
- package/dist/governance.js +285 -0
- package/dist/graph/build.d.ts +2 -2
- package/dist/graph/context-query-contracts.d.ts +1 -1
- package/dist/graph/dsl.d.ts +1 -1
- package/dist/graph/query.d.ts +4 -4
- package/dist/graph/ranking.d.ts +1 -1
- package/dist/graph/schema.d.ts +1 -1
- package/dist/graph.d.ts +11 -11
- package/dist/guarantees/index.d.ts +425 -0
- package/dist/guarantees/index.js +1146 -0
- package/dist/hosting/apps.d.ts +1 -1
- package/dist/hosting/builtins.d.ts +1 -1
- package/dist/hosting/builtins.js +9 -198
- package/dist/hosting/contracts.d.ts +3 -2
- package/dist/hosting/graph.d.ts +24 -21
- package/dist/hosting/graph.js +280 -294
- package/dist/hosting/index.d.ts +4 -4
- package/dist/index.d.ts +88 -74
- package/dist/index.js +81 -10
- package/dist/local-dev/managed-dev.d.ts +85 -0
- package/dist/local-dev/managed-dev.js +368 -0
- package/dist/managed-dependencies.d.ts +9 -0
- package/dist/managed-dependencies.js +10 -8
- package/dist/market-client.d.ts +265 -7
- package/dist/market-client.js +381 -9
- package/dist/model-registry.d.ts +1 -1
- package/dist/model-registry.js +19 -19
- package/dist/operations/agent-tools.d.ts +2 -11
- package/dist/operations/agent-tools.js +2 -14
- package/dist/operations/providers/default.d.ts +1 -1
- package/dist/operations/providers/default.js +20 -37
- package/dist/operations/repository-operations.d.ts +26 -2
- package/dist/operations/repository-operations.js +159 -1
- package/dist/operations/runtime.d.ts +3 -3
- package/dist/operations/services/bootstrap-runner.d.ts +1 -1
- package/dist/operations/services/build-warning-policy.d.ts +34 -0
- package/dist/operations/services/build-warning-policy.js +81 -82
- package/dist/operations/services/commit-message-provider.js +4 -4
- package/dist/operations/services/config-runtime.d.ts +73 -19
- package/dist/operations/services/config-runtime.js +276 -100
- package/dist/operations/services/deploy.d.ts +41 -622
- package/dist/operations/services/deploy.js +181 -213
- package/dist/operations/services/deployment-readiness.d.ts +1 -1
- package/dist/operations/services/deployment-readiness.js +38 -7
- package/dist/operations/services/git-remote-policy.js +12 -4
- package/dist/operations/services/git-runner.d.ts +66 -0
- package/dist/operations/services/git-runner.js +479 -0
- package/dist/operations/services/git-workflow.d.ts +43 -5
- package/dist/operations/services/git-workflow.js +242 -20
- package/dist/operations/services/github-actions-verification.d.ts +3 -1
- package/dist/operations/services/github-actions-verification.js +11 -3
- package/dist/operations/services/github-api.js +21 -5
- package/dist/operations/services/github-automation.d.ts +3 -3
- package/dist/operations/services/github-automation.js +15 -18
- package/dist/operations/services/github-credentials.js +2 -1
- package/dist/operations/services/hosted-service-checks.d.ts +19 -1
- package/dist/operations/services/hosted-service-checks.js +162 -11
- package/dist/operations/services/hosting-audit.d.ts +2 -2
- package/dist/operations/services/hosting-audit.js +7 -7
- package/dist/operations/services/hub-launch.d.ts +1 -1
- package/dist/operations/services/hub-provider-launch.d.ts +5 -5
- package/dist/operations/services/hub-provider-launch.js +19 -14
- package/dist/operations/services/live-hosted-service-checks.d.ts +2 -1
- package/dist/operations/services/live-hosted-service-checks.js +193 -80
- package/dist/operations/services/local-dev.js +0 -1
- package/dist/operations/services/managed-host-security.d.ts +1 -1
- package/dist/operations/services/managed-repositories.d.ts +37 -0
- package/dist/operations/services/managed-repositories.js +177 -0
- package/dist/operations/services/operations-runner-smoke.d.ts +3 -2
- package/dist/operations/services/operations-runner-smoke.js +22 -4
- package/dist/operations/services/package-adapters.d.ts +77 -2
- package/dist/operations/services/package-adapters.js +629 -56
- package/dist/operations/services/package-reference-policy.d.ts +12 -88
- package/dist/operations/services/package-reference-policy.js +81 -213
- package/dist/operations/services/project-host-operations.d.ts +4 -4
- package/dist/operations/services/project-platform.d.ts +19 -193
- package/dist/operations/services/project-platform.js +31 -103
- package/dist/operations/services/project-web-monitor.d.ts +2 -2
- package/dist/operations/services/project-web-monitor.js +97 -2
- package/dist/operations/services/railway-api.d.ts +36 -7
- package/dist/operations/services/railway-api.js +331 -100
- package/dist/operations/services/railway-deploy.d.ts +7 -95
- package/dist/operations/services/railway-deploy.js +334 -742
- package/dist/operations/services/release-history.js +3 -4
- package/dist/operations/services/release-proof-ledger.d.ts +13 -0
- package/dist/operations/services/release-proof-ledger.js +81 -0
- package/dist/operations/services/release-proof-planner.d.ts +48 -0
- package/dist/operations/services/release-proof-planner.js +195 -0
- package/dist/operations/services/release-proof-runner.d.ts +16 -0
- package/dist/operations/services/release-proof-runner.js +169 -0
- package/dist/operations/services/release-proof.d.ts +81 -0
- package/dist/operations/services/release-proof.js +79 -0
- package/dist/operations/services/repository-save-orchestrator.d.ts +6 -7
- package/dist/operations/services/repository-save-orchestrator.js +353 -174
- package/dist/operations/services/runtime-paths.d.ts +1 -3
- package/dist/operations/services/runtime-paths.js +0 -4
- package/dist/operations/services/runtime-tools.d.ts +1 -192
- package/dist/operations/services/runtime-tools.js +4 -444
- package/dist/operations/services/save-deploy-preflight.js +9 -1
- package/dist/operations/services/template-host-bindings.d.ts +2 -2
- package/dist/operations/services/template-host-bindings.js +3 -2
- package/dist/operations/services/template-registry.d.ts +6 -6
- package/dist/operations/services/template-registry.js +33 -14
- package/dist/operations/services/template-secret-sync.d.ts +3 -3
- package/dist/operations/services/workflow-timing.d.ts +25 -0
- package/dist/operations/services/workflow-timing.js +79 -0
- package/dist/operations/services/workspace-dependency-mode.js +41 -4
- package/dist/operations/services/workspace-preflight.js +8 -8
- package/dist/operations/services/workspace-save-script.d.ts +4 -4
- package/dist/operations/services/workspace-save.d.ts +1 -0
- package/dist/operations/services/workspace-save.js +41 -18
- package/dist/operations/services/workspace-tools.js +40 -6
- package/dist/operations-registry.d.ts +1 -1
- package/dist/operations-registry.js +5 -6
- package/dist/operations-types.d.ts +1 -1
- package/dist/operations.d.ts +17 -11
- package/dist/operations.js +57 -3
- package/dist/platform/book-export.js +2 -0
- package/dist/platform/books-data.d.ts +1 -1
- package/dist/platform/config.d.ts +27 -0
- package/dist/platform/config.js +100 -0
- package/dist/platform/content-runtime-source.d.ts +54 -0
- package/dist/platform/content-runtime-source.js +169 -0
- package/dist/platform/contracts.d.ts +6 -1
- package/dist/platform/deploy-config.d.ts +1 -1
- package/dist/platform/deploy-config.js +7 -1
- package/dist/platform/deploy-runtime.d.ts +1 -1
- package/dist/platform/desired-state.d.ts +66 -0
- package/dist/platform/desired-state.js +1052 -0
- package/dist/platform/env.yaml +414 -19
- package/dist/platform/environment.d.ts +2 -2
- package/dist/platform/environment.js +54 -22
- package/dist/platform/local-content-materialization.d.ts +9 -0
- package/dist/platform/local-content-materialization.js +212 -0
- package/dist/platform/plugin.d.ts +5 -5
- package/dist/platform/plugins/runtime.d.ts +3 -3
- package/dist/platform/plugins/runtime.js +62 -1
- package/dist/platform/plugins.d.ts +6 -6
- package/dist/platform/published-content-pipeline.d.ts +3 -3
- package/dist/platform/published-content-pipeline.js +5 -1
- package/dist/platform/published-content.d.ts +4 -3
- package/dist/platform/site-config-schema.d.ts +1 -0
- package/dist/platform/site-config-schema.js +4 -1
- package/dist/platform/tenant/runtime-config.d.ts +152 -2
- package/dist/platform/tenant-config.d.ts +1 -1
- package/dist/platform/utils/site-config-schema.d.ts +154 -0
- package/dist/platform/utils/site-config-schema.js +400 -461
- package/dist/platform-operation-store.d.ts +1 -1
- package/dist/plugin-default.d.ts +1 -1
- package/dist/plugin-default.js +27 -12
- package/dist/project-import.d.ts +91 -0
- package/dist/project-import.js +257 -0
- package/dist/project-workflow.d.ts +1 -1
- package/dist/reconcile/bootstrap-systems.d.ts +2 -2
- package/dist/reconcile/bootstrap-systems.js +3 -3
- package/dist/reconcile/builtin-adapters.d.ts +7 -1
- package/dist/reconcile/builtin-adapters.js +2924 -346
- package/dist/reconcile/contracts.d.ts +15 -2
- package/dist/reconcile/desired-state.d.ts +2 -193
- package/dist/reconcile/desired-state.js +24 -33
- package/dist/reconcile/engine.d.ts +60 -397
- package/dist/reconcile/engine.js +182 -18
- package/dist/reconcile/index.d.ts +10 -10
- package/dist/reconcile/live-acceptance.d.ts +22 -1
- package/dist/reconcile/live-acceptance.js +456 -44
- package/dist/reconcile/providers/docker-private.d.ts +54 -0
- package/dist/reconcile/providers/docker-private.js +101 -0
- package/dist/reconcile/providers/github-private.d.ts +65 -0
- package/dist/reconcile/providers/github-private.js +119 -0
- package/dist/reconcile/providers/local-private.d.ts +28 -0
- package/dist/reconcile/providers/local-private.js +75 -0
- package/dist/reconcile/providers/railway-iac.d.ts +66 -0
- package/dist/reconcile/providers/railway-iac.js +275 -0
- package/dist/reconcile/providers/release-private.d.ts +92 -0
- package/dist/reconcile/providers/release-private.js +152 -0
- package/dist/reconcile/registry.d.ts +2 -2
- package/dist/reconcile/registry.js +16 -1
- package/dist/reconcile/state.d.ts +1 -1
- package/dist/reconcile/state.js +3 -40
- package/dist/reconcile/units.d.ts +1 -1
- package/dist/reconcile/units.js +7 -1
- package/dist/remote.d.ts +6 -6
- package/dist/scenes/artifacts.d.ts +16 -0
- package/dist/scenes/artifacts.js +61 -0
- package/dist/scenes/auth.d.ts +2 -0
- package/dist/scenes/auth.js +28 -0
- package/dist/scenes/base-url.d.ts +12 -0
- package/dist/scenes/base-url.js +123 -0
- package/dist/scenes/builtin-plugins.d.ts +2 -0
- package/dist/scenes/builtin-plugins.js +447 -0
- package/dist/scenes/checkpoints.d.ts +14 -0
- package/dist/scenes/checkpoints.js +33 -0
- package/dist/scenes/device-matrix.d.ts +2 -0
- package/dist/scenes/device-matrix.js +97 -0
- package/dist/scenes/devices.d.ts +11 -0
- package/dist/scenes/devices.js +22 -0
- package/dist/scenes/diagnostics.d.ts +5 -0
- package/dist/scenes/diagnostics.js +22 -0
- package/dist/scenes/diagram-providers.d.ts +2 -0
- package/dist/scenes/diagram-providers.js +181 -0
- package/dist/scenes/diagram-validation.d.ts +22 -0
- package/dist/scenes/diagram-validation.js +74 -0
- package/dist/scenes/environment.d.ts +2 -0
- package/dist/scenes/environment.js +65 -0
- package/dist/scenes/evidence-bundle.d.ts +5 -0
- package/dist/scenes/evidence-bundle.js +42 -0
- package/dist/scenes/evidence-report.d.ts +10 -0
- package/dist/scenes/evidence-report.js +73 -0
- package/dist/scenes/evidence.d.ts +16 -0
- package/dist/scenes/evidence.js +277 -0
- package/dist/scenes/index.d.ts +48 -0
- package/dist/scenes/index.js +312 -0
- package/dist/scenes/inspect.d.ts +9 -0
- package/dist/scenes/inspect.js +64 -0
- package/dist/scenes/loader.d.ts +3 -0
- package/dist/scenes/loader.js +38 -0
- package/dist/scenes/logs.d.ts +2 -0
- package/dist/scenes/logs.js +47 -0
- package/dist/scenes/operations.d.ts +3 -0
- package/dist/scenes/operations.js +128 -0
- package/dist/scenes/phase0.d.ts +9 -0
- package/dist/scenes/phase0.js +637 -0
- package/dist/scenes/planner.d.ts +12 -0
- package/dist/scenes/planner.js +166 -0
- package/dist/scenes/playwright-adapter.d.ts +2 -0
- package/dist/scenes/playwright-adapter.js +63 -0
- package/dist/scenes/plugins.d.ts +5 -0
- package/dist/scenes/plugins.js +115 -0
- package/dist/scenes/progress.d.ts +17 -0
- package/dist/scenes/progress.js +24 -0
- package/dist/scenes/publish-destinations.d.ts +12 -0
- package/dist/scenes/publish-destinations.js +99 -0
- package/dist/scenes/publish-plan-report.d.ts +10 -0
- package/dist/scenes/publish-plan-report.js +70 -0
- package/dist/scenes/publish-plan.d.ts +15 -0
- package/dist/scenes/publish-plan.js +248 -0
- package/dist/scenes/publish-redaction.d.ts +16 -0
- package/dist/scenes/publish-redaction.js +148 -0
- package/dist/scenes/publish-release-record.d.ts +13 -0
- package/dist/scenes/publish-release-record.js +34 -0
- package/dist/scenes/publish-report.d.ts +10 -0
- package/dist/scenes/publish-report.js +67 -0
- package/dist/scenes/publish.d.ts +16 -0
- package/dist/scenes/publish.js +298 -0
- package/dist/scenes/registry.d.ts +12 -0
- package/dist/scenes/registry.js +65 -0
- package/dist/scenes/remotion-adapter.d.ts +3 -0
- package/dist/scenes/remotion-adapter.js +94 -0
- package/dist/scenes/remotion-composition-registry.d.ts +2 -0
- package/dist/scenes/remotion-composition-registry.js +12 -0
- package/dist/scenes/remotion-compositions.d.ts +15 -0
- package/dist/scenes/remotion-compositions.js +464 -0
- package/dist/scenes/remotion-diagrams.d.ts +9 -0
- package/dist/scenes/remotion-diagrams.js +188 -0
- package/dist/scenes/remotion-input.d.ts +13 -0
- package/dist/scenes/remotion-input.js +291 -0
- package/dist/scenes/remotion-visuals.d.ts +29 -0
- package/dist/scenes/remotion-visuals.js +198 -0
- package/dist/scenes/render-media-assets.d.ts +9 -0
- package/dist/scenes/render-media-assets.js +117 -0
- package/dist/scenes/render-report.d.ts +10 -0
- package/dist/scenes/render-report.js +27 -0
- package/dist/scenes/render.d.ts +2 -0
- package/dist/scenes/render.js +218 -0
- package/dist/scenes/reporter.d.ts +3 -0
- package/dist/scenes/reporter.js +101 -0
- package/dist/scenes/resume.d.ts +2 -0
- package/dist/scenes/resume.js +79 -0
- package/dist/scenes/runner.d.ts +2 -0
- package/dist/scenes/runner.js +674 -0
- package/dist/scenes/schema.d.ts +6 -0
- package/dist/scenes/schema.js +994 -0
- package/dist/scenes/seed.d.ts +2 -0
- package/dist/scenes/seed.js +83 -0
- package/dist/scenes/segments.d.ts +15 -0
- package/dist/scenes/segments.js +79 -0
- package/dist/scenes/selectors.d.ts +3 -0
- package/dist/scenes/selectors.js +21 -0
- package/dist/scenes/timeline.d.ts +11 -0
- package/dist/scenes/timeline.js +26 -0
- package/dist/scenes/timeouts.d.ts +6 -0
- package/dist/scenes/timeouts.js +17 -0
- package/dist/scenes/training-captions.d.ts +14 -0
- package/dist/scenes/training-captions.js +98 -0
- package/dist/scenes/training-report.d.ts +10 -0
- package/dist/scenes/training-report.js +78 -0
- package/dist/scenes/training-transcript.d.ts +24 -0
- package/dist/scenes/training-transcript.js +204 -0
- package/dist/scenes/training.d.ts +10 -0
- package/dist/scenes/training.js +134 -0
- package/dist/scenes/types.d.ts +1872 -0
- package/dist/scenes/types.js +8 -0
- package/dist/scenes/visual-audit-contact-sheets.d.ts +6 -0
- package/dist/scenes/visual-audit-contact-sheets.js +119 -0
- package/dist/scenes/visual-audit-fixtures.d.ts +25 -0
- package/dist/scenes/visual-audit-fixtures.js +210 -0
- package/dist/scenes/visual-audit-report.d.ts +11 -0
- package/dist/scenes/visual-audit-report.js +85 -0
- package/dist/scenes/visual-audit-review.d.ts +23 -0
- package/dist/scenes/visual-audit-review.js +829 -0
- package/dist/scenes/visual-audit-routes.d.ts +13 -0
- package/dist/scenes/visual-audit-routes.js +308 -0
- package/dist/scenes/visual-audit.d.ts +3 -0
- package/dist/scenes/visual-audit.js +596 -0
- package/dist/scripts/build-dist.js +154 -40
- package/dist/scripts/check-build-warnings.js +42 -53
- package/dist/scripts/cleanup-markdown.js +1 -1
- package/dist/scripts/cli-test-fixtures.js +24 -28
- package/dist/scripts/migrate-journey-csv-to-guarantees.js +140 -0
- package/dist/scripts/package-tools.js +12 -1
- package/dist/scripts/prepare.js +3 -7
- package/dist/scripts/release-verify.js +2 -5
- package/dist/scripts/run-fixture-astro-command.js +1 -1
- package/dist/scripts/template-catalog.test.js +68 -82
- package/dist/scripts/tenant-dev.js +0 -10
- package/dist/scripts/test-cloudflare-local.js +1 -1
- package/dist/scripts/test-scaffold.js +0 -1
- package/dist/scripts/test-smoke.js +3 -3
- package/dist/scripts/treeseed-build-dist.js +4 -7
- package/dist/scripts/treeseed-release-verify.js +1 -1
- package/dist/scripts/verify-driver.js +30 -21
- package/dist/scripts/workflow-commands.test.js +18 -27
- package/dist/scripts/workspace-command-e2e.js +1 -1
- package/dist/scripts/workspace-lint.js +6 -0
- package/dist/scripts/workspace-release-test.js +90 -1
- package/dist/scripts/workspace-test.js +6 -0
- package/dist/sdk-dispatch.d.ts +1 -1
- package/dist/sdk-dispatch.js +0 -16
- package/dist/sdk-fields.d.ts +1 -1
- package/dist/sdk-filters.d.ts +1 -1
- package/dist/sdk-types.d.ts +1184 -113
- package/dist/sdk-types.js +393 -0
- package/dist/sdk.d.ts +74 -79
- package/dist/sdk.js +27 -36
- package/dist/secrets-capability.d.ts +421 -0
- package/dist/secrets-capability.js +530 -0
- package/dist/seeds/normalize.js +1 -0
- package/dist/seeds/planner.js +38 -0
- package/dist/seeds/schema.js +293 -4
- package/dist/seeds/types.d.ts +60 -0
- package/dist/seeds/types.js +9 -1
- package/dist/service-credentials.d.ts +54 -0
- package/dist/service-credentials.js +112 -0
- package/dist/stores/cursor-store.d.ts +2 -2
- package/dist/stores/envelopes.d.ts +1 -1
- package/dist/stores/helpers.d.ts +1 -1
- package/dist/stores/lease-store.d.ts +2 -2
- package/dist/stores/message-store.d.ts +2 -2
- package/dist/stores/operational-store.d.ts +3 -26
- package/dist/stores/operational-store.js +0 -225
- package/dist/stores/project-workflow-store.d.ts +2 -2
- package/dist/stores/run-store.d.ts +2 -3
- package/dist/stores/run-store.js +0 -98
- package/dist/stores/subscription-store.d.ts +2 -3
- package/dist/stores/subscription-store.js +0 -100
- package/dist/template-catalog.d.ts +1 -1
- package/dist/template-launch-requirements.d.ts +2 -2
- package/dist/template-launch-ui.d.ts +2 -2
- package/dist/treedx/adapters.d.ts +6 -6
- package/dist/treedx/client.d.ts +1 -1
- package/dist/treedx/errors.d.ts +1 -1
- package/dist/treedx/federated-client.d.ts +3 -3
- package/dist/treedx/graph-adapter.d.ts +2 -2
- package/dist/treedx/index.d.ts +14 -14
- package/dist/treedx/market-integration.d.ts +1 -1
- package/dist/treedx/ports.d.ts +30 -30
- package/dist/treedx/query-adapter.d.ts +3 -3
- package/dist/treedx/registry-client.d.ts +2 -2
- package/dist/treedx/repository-adapter.d.ts +4 -4
- package/dist/treedx/repository-adapter.js +14 -3
- package/dist/treedx/sdk-integration.d.ts +3 -3
- package/dist/treedx/types.d.ts +2 -2
- package/dist/treedx/workspace-adapter.d.ts +2 -2
- package/dist/treedx-backends.d.ts +13 -11
- package/dist/treedx-backends.js +52 -50
- package/dist/treedx-client.d.ts +3 -0
- package/dist/treedx-client.js +10 -1
- package/dist/treeseed/services/compose.yml +2 -3
- package/dist/treeseed/template-catalog/catalog.fixture.json +4 -4
- package/dist/types/agents.d.ts +256 -0
- package/dist/types/agents.js +42 -1
- package/dist/verification.d.ts +1 -0
- package/dist/verification.js +143 -14
- package/dist/workflow/operations.d.ts +510 -559
- package/dist/workflow/operations.js +1891 -1342
- package/dist/workflow/policy.js +19 -7
- package/dist/workflow/runs.d.ts +9 -3
- package/dist/workflow/runs.js +66 -26
- package/dist/workflow/session.d.ts +4 -1
- package/dist/workflow/session.js +50 -10
- package/dist/workflow/worktrees.d.ts +6 -2
- package/dist/workflow/worktrees.js +98 -15
- package/dist/workflow-state.d.ts +5 -5
- package/dist/workflow-state.js +27 -17
- package/dist/workflow-support.d.ts +26 -25
- package/dist/workflow-support.js +27 -31
- package/dist/workflow.d.ts +46 -16
- package/dist/workflow.js +19 -7
- package/drizzle/d1/0000_treeseed_d1.sql +0 -18
- package/drizzle/market/0000_market_control_plane.sql +1793 -1499
- package/drizzle/market/0005_agent_capacity_coordination.sql +145 -0
- package/drizzle/market/0006_provider_assignment_lifecycle.sql +9 -0
- package/drizzle/market/0007_agent_architecture_gap_closure.sql +157 -0
- package/drizzle/market/0008_agent_capacity_operational_closure.sql +27 -0
- package/drizzle/market/0009_agent_capacity_runtime_hardening.sql +29 -0
- package/drizzle/market/0010_secrets_capability_persistence.sql +130 -0
- package/drizzle/market/0011_github_app_adapter.sql +47 -0
- package/drizzle/market/0012_workday_test_runs.sql +44 -0
- package/drizzle/market/0013_runtime_task_lifecycle.sql +39 -0
- package/drizzle/market/0014_governance_pipeline.sql +189 -0
- package/package.json +75 -18
- package/scripts/{verify-driver.mjs → verify-driver.ts} +19 -4
- package/templates/github/deploy-web.workflow.yml +12 -8
- package/dist/operations/services/mailpit-runtime.d.ts +0 -20
- package/dist/operations/services/mailpit-runtime.js +0 -67
- package/dist/operations/services/release-candidate.d.ts +0 -60
- package/dist/operations/services/release-candidate.js +0 -953
- package/dist/scripts/ensure-mailpit.js +0 -48
- package/dist/scripts/logs-mailpit.js +0 -2
- package/dist/scripts/run-ts.js +0 -45
- package/dist/scripts/stop-mailpit.js +0 -5
- package/dist/scripts/treeseed-run-ts.js +0 -45
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { relative, resolve } from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
4
|
import { loadCliDeployConfig } from "./runtime-tools.js";
|
|
5
|
+
import { resolveTreeseedMachineEnvironmentValues } from "./config-runtime.js";
|
|
5
6
|
import { createPersistentDeployTarget, resolveTreeseedResourceIdentity } from "./deploy.js";
|
|
7
|
+
import { classifyTreeseedGitMode, runTreeseedGitText } from "./git-runner.js";
|
|
6
8
|
import { discoverTreeseedApplications } from "../../hosting/apps.js";
|
|
7
9
|
import { runPrefixedCommand, sleep } from "./bootstrap-runner.js";
|
|
8
|
-
import { resolveTreeseedToolCommand } from "../../managed-dependencies.js";
|
|
9
10
|
import {
|
|
10
11
|
ensureRailwayEnvironment,
|
|
11
12
|
ensureRailwayProject,
|
|
@@ -22,7 +23,6 @@ import {
|
|
|
22
23
|
railwayGraphqlRequest,
|
|
23
24
|
resolveRailwayApiToken,
|
|
24
25
|
resolveRailwayApiUrl,
|
|
25
|
-
resolveRailwayWorkspace,
|
|
26
26
|
resolveRailwayWorkspaceContext,
|
|
27
27
|
upsertRailwayVariables
|
|
28
28
|
} from "./railway-api.js";
|
|
@@ -33,11 +33,12 @@ function normalizeScope(scope) {
|
|
|
33
33
|
function resolveRailwayEnvironmentForScope(scope, configuredEnvironment) {
|
|
34
34
|
return normalizeRailwayEnvironmentName(configuredEnvironment || normalizeScope(scope));
|
|
35
35
|
}
|
|
36
|
-
const RAILWAY_SERVICE_KEYS = ["api", "operationsRunner"];
|
|
36
|
+
const RAILWAY_SERVICE_KEYS = ["api", "operationsRunner", "capacityProviderManager", "capacityProviderRunner"];
|
|
37
37
|
const HOSTED_PROJECT_SERVICE_KEYS = ["api"];
|
|
38
38
|
const WORKER_RUNNER_BOOTSTRAP_INDEX = 1;
|
|
39
39
|
const WORKER_RUNNER_VOLUME_MOUNT_PATH = "/data";
|
|
40
40
|
const OPERATIONS_RUNNER_BOOTSTRAP_COUNT = 2;
|
|
41
|
+
const PUBLIC_TREEDX_NODE_SERVICE_KEY_PREFIX = "public-treedx-node-";
|
|
41
42
|
function isTreeseedOperationsRunnerResourceName(value) {
|
|
42
43
|
const normalized = String(value ?? "").trim().toLowerCase();
|
|
43
44
|
if (!normalized) {
|
|
@@ -60,7 +61,7 @@ function shouldManageRailwaySchedules(scope, phase = "deploy") {
|
|
|
60
61
|
return phase === "deploy" && (environment === "staging" || environment === "production");
|
|
61
62
|
}
|
|
62
63
|
function railwayServiceNameSuffix(serviceKey) {
|
|
63
|
-
return serviceKey === "workdayManager" ? "workday-manager" : serviceKey === "workerRunner" ? "worker-runner" : serviceKey === "operationsRunner" ? "operations-runner" : serviceKey;
|
|
64
|
+
return serviceKey === "capacityProviderManager" ? "capacity-provider-manager" : serviceKey === "capacityProviderRunner" ? "capacity-provider-runner" : serviceKey === "workdayManager" ? "workday-manager" : serviceKey === "workerRunner" ? "worker-runner" : serviceKey === "operationsRunner" ? "operations-runner" : serviceKey;
|
|
64
65
|
}
|
|
65
66
|
function deriveRailwayWorkerRunnerServiceName(projectSlug, index = WORKER_RUNNER_BOOTSTRAP_INDEX) {
|
|
66
67
|
const normalizedIndex = Math.max(1, Number.parseInt(String(index), 10) || WORKER_RUNNER_BOOTSTRAP_INDEX);
|
|
@@ -71,12 +72,49 @@ function deriveRailwayOperationsRunnerServiceName(baseServiceName, index = WORKE
|
|
|
71
72
|
const base = String(baseServiceName ?? "").trim().replace(/-\d+$/u, "").replace(/-\d{2}$/u, "") || "treeseed-api-operations-runner";
|
|
72
73
|
return `${base}-${String(normalizedIndex).padStart(2, "0")}`;
|
|
73
74
|
}
|
|
75
|
+
function railwayImageRefEnvForService(serviceKey) {
|
|
76
|
+
if (serviceKey === "api") return "TREESEED_API_IMAGE_REF";
|
|
77
|
+
if (serviceKey === "operationsRunner") return "TREESEED_OPERATIONS_RUNNER_IMAGE_REF";
|
|
78
|
+
if (serviceKey === "capacityProviderManager") return "TREESEED_AGENT_MANAGER_IMAGE_REF";
|
|
79
|
+
if (serviceKey === "capacityProviderRunner") return "TREESEED_AGENT_RUNNER_IMAGE_REF";
|
|
80
|
+
if (isPublicTreeDxNodeServiceKey(serviceKey)) return "TREESEED_PUBLIC_TREEDX_IMAGE_REF";
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
function defaultRailwayImageRef(serviceKey, scope = "staging", env = process.env) {
|
|
84
|
+
if (serviceKey === "api") {
|
|
85
|
+
return envValue("TREESEED_API_IMAGE_REF", env) || null;
|
|
86
|
+
}
|
|
87
|
+
if (serviceKey === "operationsRunner") {
|
|
88
|
+
return envValue("TREESEED_OPERATIONS_RUNNER_IMAGE_REF", env) || null;
|
|
89
|
+
}
|
|
90
|
+
if (serviceKey === "capacityProviderManager") {
|
|
91
|
+
return envValue("TREESEED_AGENT_MANAGER_IMAGE_REF", env) || null;
|
|
92
|
+
}
|
|
93
|
+
if (serviceKey === "capacityProviderRunner") {
|
|
94
|
+
return envValue("TREESEED_AGENT_RUNNER_IMAGE_REF", env) || null;
|
|
95
|
+
}
|
|
96
|
+
if (isPublicTreeDxNodeServiceKey(serviceKey)) {
|
|
97
|
+
return envValue("TREESEED_PUBLIC_TREEDX_IMAGE_REF", env) || null;
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function isPublicTreeDxNodeServiceKey(serviceKey) {
|
|
102
|
+
return String(serviceKey ?? "").startsWith(PUBLIC_TREEDX_NODE_SERVICE_KEY_PREFIX);
|
|
103
|
+
}
|
|
74
104
|
function deriveRailwayWorkerRunnerVolumeName(serviceName, environmentName = "") {
|
|
75
105
|
return `${serviceName}-volume`;
|
|
76
106
|
}
|
|
77
107
|
function deriveRailwayOperationsRunnerVolumeName(serviceName, environmentName = "") {
|
|
78
108
|
return `${serviceName}-volume`;
|
|
79
109
|
}
|
|
110
|
+
function deriveRailwayCapacityProviderRunnerServiceName(baseServiceName, index = WORKER_RUNNER_BOOTSTRAP_INDEX) {
|
|
111
|
+
const normalizedIndex = Math.max(1, Number.parseInt(String(index), 10) || WORKER_RUNNER_BOOTSTRAP_INDEX);
|
|
112
|
+
const base = String(baseServiceName ?? "").trim().replace(/-\d+$/u, "").replace(/-\d{2}$/u, "") || "treeseed-capacity-provider-runner";
|
|
113
|
+
return `${base}-${String(normalizedIndex).padStart(2, "0")}`;
|
|
114
|
+
}
|
|
115
|
+
function deriveRailwayCapacityProviderRunnerVolumeName(serviceName, environmentName = "") {
|
|
116
|
+
return `${serviceName}-volume`;
|
|
117
|
+
}
|
|
80
118
|
function railwayServiceRuntimeStartCommand(service) {
|
|
81
119
|
return service.startCommand;
|
|
82
120
|
}
|
|
@@ -89,8 +127,8 @@ function normalizeScheduleExpressions(value) {
|
|
|
89
127
|
}
|
|
90
128
|
return [];
|
|
91
129
|
}
|
|
92
|
-
function envValue(name) {
|
|
93
|
-
const value =
|
|
130
|
+
function envValue(name, env = process.env) {
|
|
131
|
+
const value = env?.[name];
|
|
94
132
|
return typeof value === "string" && value.trim() ? value.trim() : "";
|
|
95
133
|
}
|
|
96
134
|
function relativeRailwayRootDir(tenantRoot, serviceRoot) {
|
|
@@ -271,7 +309,7 @@ function resolveRailwayAuthToken(env = process.env) {
|
|
|
271
309
|
function buildRailwayCommandEnv(env = process.env) {
|
|
272
310
|
const merged = { ...env };
|
|
273
311
|
const token = resolveRailwayAuthToken(merged);
|
|
274
|
-
const projectToken = configuredEnvValue(merged, "
|
|
312
|
+
const projectToken = configuredEnvValue(merged, "TREESEED_RAILWAY_TOKEN");
|
|
275
313
|
if (token) {
|
|
276
314
|
merged.RAILWAY_API_TOKEN = token;
|
|
277
315
|
} else {
|
|
@@ -280,15 +318,6 @@ function buildRailwayCommandEnv(env = process.env) {
|
|
|
280
318
|
merged.RAILWAY_TOKEN = projectToken || void 0;
|
|
281
319
|
return merged;
|
|
282
320
|
}
|
|
283
|
-
function buildRailwayDeployCommandEnv(env = process.env) {
|
|
284
|
-
const merged = buildRailwayCommandEnv(env);
|
|
285
|
-
if (shouldAttachRailwayDeployLogs(merged)) {
|
|
286
|
-
merged.CI = "true";
|
|
287
|
-
} else {
|
|
288
|
-
merged.CI = void 0;
|
|
289
|
-
}
|
|
290
|
-
return merged;
|
|
291
|
-
}
|
|
292
321
|
function normalizeRailwaySchedule(schedule) {
|
|
293
322
|
if (!schedule || typeof schedule !== "object") {
|
|
294
323
|
return null;
|
|
@@ -338,47 +367,6 @@ function collectRailwaySchedules(value, seen = /* @__PURE__ */ new Set()) {
|
|
|
338
367
|
visit(value);
|
|
339
368
|
return matches;
|
|
340
369
|
}
|
|
341
|
-
function normalizeRailwayProjectList(payload) {
|
|
342
|
-
try {
|
|
343
|
-
const parsed = JSON.parse(payload);
|
|
344
|
-
if (!Array.isArray(parsed)) {
|
|
345
|
-
return [];
|
|
346
|
-
}
|
|
347
|
-
return parsed.map((entry) => {
|
|
348
|
-
if (!entry || typeof entry !== "object") {
|
|
349
|
-
return null;
|
|
350
|
-
}
|
|
351
|
-
const id = typeof entry.id === "string" ? entry.id.trim() : "";
|
|
352
|
-
const name = typeof entry.name === "string" ? entry.name.trim() : "";
|
|
353
|
-
if (!id && !name) {
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
return { id, name };
|
|
357
|
-
}).filter(Boolean);
|
|
358
|
-
} catch {
|
|
359
|
-
return [];
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
function railwayMessage(result) {
|
|
363
|
-
return `${result?.stderr ?? ""}
|
|
364
|
-
${result?.stdout ?? ""}`.trim();
|
|
365
|
-
}
|
|
366
|
-
function isRailwayAlreadyExistsMessage(result) {
|
|
367
|
-
return /already exists|already taken|duplicate|has already been taken/iu.test(railwayMessage(result));
|
|
368
|
-
}
|
|
369
|
-
function isRailwayTransientFailure(result) {
|
|
370
|
-
const message = railwayMessage(result);
|
|
371
|
-
if (!message.trim() && result?.status === 1) {
|
|
372
|
-
return true;
|
|
373
|
-
}
|
|
374
|
-
return /timed out|failed to fetch|error decoding response body|expected value at line 1 column 1|temporarily unavailable|econnreset|etimedout|failed to stream build logs|failed to retrieve build log/iu.test(message);
|
|
375
|
-
}
|
|
376
|
-
function sleepSync(milliseconds) {
|
|
377
|
-
if (!Number.isFinite(milliseconds) || milliseconds <= 0) {
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
|
|
381
|
-
}
|
|
382
370
|
function isRailwayScheduleCapabilityError(error) {
|
|
383
371
|
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
384
372
|
return /cronTriggers|cronTriggerCreate|cronTriggerUpdate/iu.test(message);
|
|
@@ -451,42 +439,6 @@ mutation TreeseedScheduleUpdate($id: String!, $name: String!, $schedule: String!
|
|
|
451
439
|
`.trim()
|
|
452
440
|
};
|
|
453
441
|
}
|
|
454
|
-
function runRailway(args, { cwd, capture = false, allowFailure = false, input, env, retryTransient = true, retryAttempts = 3, retryDelayMs = 2e3, timeoutMs = 12e4 } = {}) {
|
|
455
|
-
const effectiveEnv = buildRailwayCommandEnv({ ...process.env, ...env ?? {} });
|
|
456
|
-
const railway = resolveTreeseedToolCommand("railway", { env: effectiveEnv });
|
|
457
|
-
if (!railway) {
|
|
458
|
-
throw new Error("Railway CLI is unavailable.");
|
|
459
|
-
}
|
|
460
|
-
const runWithEnv = (spawnEnv) => spawnSync(railway.command, [...railway.argsPrefix, ...args], {
|
|
461
|
-
cwd,
|
|
462
|
-
stdio: input !== void 0 ? ["pipe", capture ? "pipe" : "inherit", capture ? "pipe" : "inherit"] : capture ? "pipe" : "inherit",
|
|
463
|
-
encoding: "utf8",
|
|
464
|
-
env: spawnEnv,
|
|
465
|
-
input,
|
|
466
|
-
timeout: Number.isFinite(timeoutMs) && Number(timeoutMs) > 0 ? Number(timeoutMs) : void 0
|
|
467
|
-
});
|
|
468
|
-
let result = null;
|
|
469
|
-
const maxAttempts = retryTransient && !allowFailure ? Math.max(1, Number(retryAttempts) || 1) : 1;
|
|
470
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
471
|
-
result = runWithEnv(effectiveEnv);
|
|
472
|
-
if (result.status === 0 || allowFailure || !isRailwayTransientFailure(result) || attempt === maxAttempts) {
|
|
473
|
-
break;
|
|
474
|
-
}
|
|
475
|
-
sleepSync((Number(retryDelayMs) || 0) * attempt);
|
|
476
|
-
}
|
|
477
|
-
if (result?.error) {
|
|
478
|
-
const errorMessage = result.error instanceof Error ? result.error.message : String(result.error);
|
|
479
|
-
const timeoutMessage = /timed out|ETIMEDOUT/iu.test(errorMessage) ? `railway ${args.join(" ")} timed out after ${Math.round(Number(timeoutMs) / 1e3)}s` : errorMessage;
|
|
480
|
-
if (!allowFailure) {
|
|
481
|
-
throw new Error(timeoutMessage);
|
|
482
|
-
}
|
|
483
|
-
result.stderr = result.stderr || timeoutMessage;
|
|
484
|
-
}
|
|
485
|
-
if (result?.status !== 0 && !allowFailure) {
|
|
486
|
-
throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${args.join(" ")} failed`);
|
|
487
|
-
}
|
|
488
|
-
return result;
|
|
489
|
-
}
|
|
490
442
|
async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
|
|
491
443
|
services = configuredRailwayServices(tenantRoot, scope),
|
|
492
444
|
env = process.env,
|
|
@@ -659,263 +611,21 @@ query TreeseedRailwayDeploymentStatus($projectId: String!) {
|
|
|
659
611
|
});
|
|
660
612
|
return payload.data?.project ?? null;
|
|
661
613
|
}
|
|
662
|
-
function
|
|
663
|
-
const effectiveEnv = buildRailwayCommandEnv({
|
|
664
|
-
...process.env,
|
|
665
|
-
...env ?? {}
|
|
666
|
-
});
|
|
667
|
-
let result = null;
|
|
668
|
-
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
669
|
-
const railway = resolveTreeseedToolCommand("railway", { env: effectiveEnv });
|
|
670
|
-
if (!railway) {
|
|
671
|
-
throw new Error("Railway CLI is unavailable.");
|
|
672
|
-
}
|
|
673
|
-
result = spawnSync(railway.command, [
|
|
674
|
-
...railway.argsPrefix,
|
|
675
|
-
"variable",
|
|
676
|
-
"set",
|
|
677
|
-
"--service",
|
|
678
|
-
service,
|
|
679
|
-
"--environment",
|
|
680
|
-
environment,
|
|
681
|
-
"--stdin",
|
|
682
|
-
"--skip-deploys",
|
|
683
|
-
key
|
|
684
|
-
], {
|
|
685
|
-
cwd,
|
|
686
|
-
stdio: ["pipe", capture ? "pipe" : "inherit", capture ? "pipe" : "inherit"],
|
|
687
|
-
encoding: "utf8",
|
|
688
|
-
env: effectiveEnv,
|
|
689
|
-
input: `${value}
|
|
690
|
-
`
|
|
691
|
-
});
|
|
692
|
-
if (result.status === 0) {
|
|
693
|
-
return result;
|
|
694
|
-
}
|
|
695
|
-
if (!isRailwayTransientFailure(result)) {
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
if (result?.status !== 0 && !allowFailure) {
|
|
700
|
-
throw new Error(result?.stderr?.trim() || result?.stdout?.trim() || `railway variable set --stdin ${key} failed`);
|
|
701
|
-
}
|
|
702
|
-
return result;
|
|
703
|
-
}
|
|
704
|
-
function ensureRailwayProjectExists(service, { env = process.env } = {}) {
|
|
705
|
-
const projectName = typeof service?.projectName === "string" ? service.projectName.trim() : "";
|
|
706
|
-
const projectId = typeof service?.projectId === "string" ? service.projectId.trim() : "";
|
|
707
|
-
const listed = runRailway(["list", "--json"], {
|
|
708
|
-
cwd: service.rootDir,
|
|
709
|
-
capture: true,
|
|
710
|
-
allowFailure: true,
|
|
711
|
-
env
|
|
712
|
-
});
|
|
713
|
-
if (listed.status === 0) {
|
|
714
|
-
const match = normalizeRailwayProjectList(listed.stdout ?? "").find((entry) => entry.name === projectName || entry.id === projectName || entry.id === projectId);
|
|
715
|
-
if (match) {
|
|
716
|
-
return match;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
if (!projectName) {
|
|
720
|
-
if (projectId) {
|
|
721
|
-
return { id: projectId, name: "" };
|
|
722
|
-
}
|
|
723
|
-
throw new Error(`Railway service ${service?.key ?? service?.serviceName ?? service?.serviceId ?? "(unknown)"} is missing a projectName.`);
|
|
724
|
-
}
|
|
725
|
-
const args = ["init", "--name", projectName, "--json"];
|
|
726
|
-
const workspace = resolveRailwayWorkspace(env);
|
|
727
|
-
if (workspace) {
|
|
728
|
-
args.push("--workspace", workspace);
|
|
729
|
-
}
|
|
730
|
-
const created = runRailway(args, {
|
|
731
|
-
cwd: service.rootDir,
|
|
732
|
-
capture: true,
|
|
733
|
-
allowFailure: true,
|
|
734
|
-
env
|
|
735
|
-
});
|
|
736
|
-
if (created.status !== 0 && !isRailwayAlreadyExistsMessage(created)) {
|
|
737
|
-
throw new Error(railwayMessage(created) || `railway ${args.join(" ")} failed`);
|
|
738
|
-
}
|
|
739
|
-
return null;
|
|
740
|
-
}
|
|
741
|
-
function ensureRailwayEnvironmentExists(service, { env = process.env } = {}) {
|
|
742
|
-
const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
|
|
743
|
-
if (!environmentName) {
|
|
744
|
-
return null;
|
|
745
|
-
}
|
|
746
|
-
const linkResult = runRailway(["environment", "link", environmentName, "--json"], {
|
|
747
|
-
cwd: service.rootDir,
|
|
748
|
-
capture: true,
|
|
749
|
-
allowFailure: true,
|
|
750
|
-
env
|
|
751
|
-
});
|
|
752
|
-
if (linkResult.status === 0) {
|
|
753
|
-
return linkResult;
|
|
754
|
-
}
|
|
755
|
-
const createResult = runRailway(["environment", "new", environmentName, "--json"], {
|
|
756
|
-
cwd: service.rootDir,
|
|
757
|
-
capture: true,
|
|
758
|
-
allowFailure: true,
|
|
759
|
-
env
|
|
760
|
-
});
|
|
761
|
-
if (createResult.status !== 0 && !isRailwayAlreadyExistsMessage(createResult)) {
|
|
762
|
-
throw new Error(railwayMessage(createResult) || `railway environment new ${environmentName} failed`);
|
|
763
|
-
}
|
|
764
|
-
const relinkResult = runRailway(["environment", "link", environmentName, "--json"], {
|
|
765
|
-
cwd: service.rootDir,
|
|
766
|
-
capture: true,
|
|
767
|
-
allowFailure: true,
|
|
768
|
-
env
|
|
769
|
-
});
|
|
770
|
-
if (relinkResult.status !== 0) {
|
|
771
|
-
throw new Error(railwayMessage(relinkResult) || `railway environment link ${environmentName} failed`);
|
|
772
|
-
}
|
|
773
|
-
return relinkResult;
|
|
774
|
-
}
|
|
775
|
-
function ensureRailwayServiceExists(service, { env = process.env } = {}) {
|
|
776
|
-
const serviceSelector = typeof (service?.serviceName ?? service?.serviceId) === "string" ? String(service.serviceName ?? service.serviceId).trim() : "";
|
|
777
|
-
if (!serviceSelector) {
|
|
778
|
-
throw new Error(`Railway service ${service?.key ?? "(unknown)"} is missing a service selector.`);
|
|
779
|
-
}
|
|
780
|
-
const statusArgs = ["service", "status", "--service", serviceSelector, "--environment", service.railwayEnvironment, "--json"];
|
|
781
|
-
const statusResult = runRailway(statusArgs, {
|
|
782
|
-
cwd: service.rootDir,
|
|
783
|
-
capture: true,
|
|
784
|
-
allowFailure: true,
|
|
785
|
-
env
|
|
786
|
-
});
|
|
787
|
-
if (statusResult.status === 0) {
|
|
788
|
-
return statusResult;
|
|
789
|
-
}
|
|
790
|
-
const createResult = runRailway(["add", "--service", serviceSelector, "--json"], {
|
|
791
|
-
cwd: service.rootDir,
|
|
792
|
-
capture: true,
|
|
793
|
-
allowFailure: true,
|
|
794
|
-
env
|
|
795
|
-
});
|
|
796
|
-
if (createResult.status !== 0 && !isRailwayAlreadyExistsMessage(createResult)) {
|
|
797
|
-
throw new Error(railwayMessage(createResult) || `railway add --service ${serviceSelector} failed`);
|
|
798
|
-
}
|
|
799
|
-
const refreshed = runRailway(statusArgs, {
|
|
800
|
-
cwd: service.rootDir,
|
|
801
|
-
capture: true,
|
|
802
|
-
allowFailure: true,
|
|
803
|
-
env
|
|
804
|
-
});
|
|
805
|
-
if (refreshed.status !== 0) {
|
|
806
|
-
throw new Error(railwayMessage(refreshed) || `railway service status --service ${serviceSelector} failed`);
|
|
807
|
-
}
|
|
808
|
-
return refreshed;
|
|
809
|
-
}
|
|
810
|
-
function ensureRailwayDatabaseServiceExists(service, {
|
|
811
|
-
database = "postgres",
|
|
812
|
-
env = process.env
|
|
813
|
-
} = {}) {
|
|
814
|
-
const serviceSelector = typeof (service?.serviceName ?? service?.serviceId) === "string" ? String(service.serviceName ?? service.serviceId).trim() : "";
|
|
815
|
-
if (!serviceSelector) {
|
|
816
|
-
throw new Error(`Railway database service ${service?.key ?? "(unknown)"} is missing a service selector.`);
|
|
817
|
-
}
|
|
818
|
-
const projectSelector = typeof service?.projectId === "string" && service.projectId.trim() ? service.projectId.trim() : typeof service?.projectName === "string" && service.projectName.trim() ? service.projectName.trim() : "";
|
|
819
|
-
if (!projectSelector) {
|
|
820
|
-
throw new Error(`Railway database service ${service?.key ?? serviceSelector} is missing a project selector.`);
|
|
821
|
-
}
|
|
822
|
-
const linkArgs = ["link", "--project", projectSelector];
|
|
823
|
-
const workspace = resolveRailwayWorkspace(env);
|
|
824
|
-
if (workspace) {
|
|
825
|
-
linkArgs.push("--workspace", workspace);
|
|
826
|
-
}
|
|
827
|
-
const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
|
|
828
|
-
if (environmentName) {
|
|
829
|
-
linkArgs.push("--environment", environmentName);
|
|
830
|
-
}
|
|
831
|
-
const linkResult = runRailway(linkArgs, {
|
|
832
|
-
cwd: service.rootDir,
|
|
833
|
-
capture: true,
|
|
834
|
-
allowFailure: true,
|
|
835
|
-
env
|
|
836
|
-
});
|
|
837
|
-
if ((linkResult.status ?? 1) !== 0) {
|
|
838
|
-
throw new Error(railwayMessage(linkResult) || `railway ${linkArgs.join(" ")} failed`);
|
|
839
|
-
}
|
|
840
|
-
const statusArgs = ["service", "status", "--service", serviceSelector, "--environment", service.railwayEnvironment, "--json"];
|
|
841
|
-
const statusResult = runRailway(statusArgs, {
|
|
842
|
-
cwd: service.rootDir,
|
|
843
|
-
capture: true,
|
|
844
|
-
allowFailure: true,
|
|
845
|
-
env
|
|
846
|
-
});
|
|
847
|
-
if (statusResult.status === 0) {
|
|
848
|
-
return statusResult;
|
|
849
|
-
}
|
|
850
|
-
const addResult = runRailway(["add", "--database", database, "--service", serviceSelector, "--json"], {
|
|
851
|
-
cwd: service.rootDir,
|
|
852
|
-
capture: true,
|
|
853
|
-
allowFailure: true,
|
|
854
|
-
env
|
|
855
|
-
});
|
|
856
|
-
if (addResult.status !== 0 && !isRailwayAlreadyExistsMessage(addResult)) {
|
|
857
|
-
throw new Error(railwayMessage(addResult) || `railway add --database ${database} --service ${serviceSelector} failed`);
|
|
858
|
-
}
|
|
859
|
-
const refreshed = runRailway(statusArgs, {
|
|
860
|
-
cwd: service.rootDir,
|
|
861
|
-
capture: true,
|
|
862
|
-
allowFailure: true,
|
|
863
|
-
env
|
|
864
|
-
});
|
|
865
|
-
if (refreshed.status !== 0) {
|
|
866
|
-
throw new Error(railwayMessage(refreshed) || `railway service status --service ${serviceSelector} failed`);
|
|
867
|
-
}
|
|
868
|
-
return refreshed;
|
|
869
|
-
}
|
|
870
|
-
function ensureRailwayProjectContext(service, { env = process.env, allowFailure = false, capture = false } = {}) {
|
|
871
|
-
ensureRailwayProjectExists(service, { env });
|
|
872
|
-
let projectSelector = service?.projectId ?? "";
|
|
873
|
-
if ((!projectSelector || !String(projectSelector).trim()) && service?.projectName) {
|
|
874
|
-
const listed = runRailway(["list", "--json"], {
|
|
875
|
-
cwd: service.rootDir,
|
|
876
|
-
capture: true,
|
|
877
|
-
allowFailure: true,
|
|
878
|
-
env
|
|
879
|
-
});
|
|
880
|
-
if (listed.status === 0) {
|
|
881
|
-
const match = normalizeRailwayProjectList(listed.stdout ?? "").find((entry) => entry.name === service.projectName || entry.id === service.projectName);
|
|
882
|
-
projectSelector = match?.id || match?.name || service.projectName;
|
|
883
|
-
} else {
|
|
884
|
-
projectSelector = service.projectName;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
projectSelector = typeof projectSelector === "string" ? projectSelector.trim() : "";
|
|
888
|
-
if (typeof projectSelector !== "string" || projectSelector.trim().length === 0) {
|
|
889
|
-
throw new Error(`Railway service ${service?.key ?? service?.serviceName ?? service?.serviceId ?? "(unknown)"} is missing a project selector.`);
|
|
890
|
-
}
|
|
891
|
-
const args = ["link", "--project", projectSelector];
|
|
892
|
-
const workspace = resolveRailwayWorkspace(env);
|
|
893
|
-
if (workspace) {
|
|
894
|
-
args.push("--workspace", workspace);
|
|
895
|
-
}
|
|
896
|
-
const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
|
|
897
|
-
if (environmentName) {
|
|
898
|
-
args.push("--environment", environmentName);
|
|
899
|
-
}
|
|
900
|
-
runRailway(args, {
|
|
901
|
-
cwd: service.rootDir,
|
|
902
|
-
capture,
|
|
903
|
-
allowFailure,
|
|
904
|
-
env
|
|
905
|
-
});
|
|
906
|
-
if (environmentName) {
|
|
907
|
-
ensureRailwayEnvironmentExists(service, { env });
|
|
908
|
-
return runRailway(["environment", "link", environmentName, "--json"], {
|
|
909
|
-
cwd: service.rootDir,
|
|
910
|
-
capture,
|
|
911
|
-
allowFailure,
|
|
912
|
-
env
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
return null;
|
|
916
|
-
}
|
|
917
|
-
function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, application = null) {
|
|
614
|
+
function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, application = null, machineConfigRoot = tenantRoot) {
|
|
918
615
|
const normalizedScope = normalizeScope(scope);
|
|
616
|
+
const imageRefKeys = [
|
|
617
|
+
"TREESEED_API_IMAGE_REF",
|
|
618
|
+
"TREESEED_OPERATIONS_RUNNER_IMAGE_REF",
|
|
619
|
+
"TREESEED_AGENT_MANAGER_IMAGE_REF",
|
|
620
|
+
"TREESEED_AGENT_RUNNER_IMAGE_REF"
|
|
621
|
+
];
|
|
622
|
+
let machineEnv = {};
|
|
623
|
+
try {
|
|
624
|
+
machineEnv = resolveTreeseedMachineEnvironmentValues(machineConfigRoot, normalizedScope, imageRefKeys);
|
|
625
|
+
} catch {
|
|
626
|
+
machineEnv = {};
|
|
627
|
+
}
|
|
628
|
+
const imageRefEnv = { ...process.env, ...machineEnv };
|
|
919
629
|
let identity;
|
|
920
630
|
try {
|
|
921
631
|
identity = resolveTreeseedResourceIdentity(deployConfig, createPersistentDeployTarget(normalizedScope));
|
|
@@ -929,13 +639,14 @@ function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, app
|
|
|
929
639
|
}
|
|
930
640
|
const configuredOptionalServiceKeys = Object.keys(deployConfig.services ?? {}).filter((serviceKey) => RAILWAY_SERVICE_KEYS.includes(serviceKey));
|
|
931
641
|
const serviceKeys = hostingKind === "hosted_project" ? [.../* @__PURE__ */ new Set([...HOSTED_PROJECT_SERVICE_KEYS, ...configuredOptionalServiceKeys])] : RAILWAY_SERVICE_KEYS;
|
|
932
|
-
|
|
642
|
+
const configuredServices = serviceKeys.flatMap((serviceKey) => {
|
|
933
643
|
const service = deployConfig.services?.[serviceKey];
|
|
934
644
|
if (!service || service.enabled === false || (service.provider ?? "railway") !== "railway") {
|
|
935
645
|
return [];
|
|
936
646
|
}
|
|
937
|
-
const
|
|
938
|
-
const
|
|
647
|
+
const isCapacityProviderService = String(serviceKey).startsWith("capacityProvider");
|
|
648
|
+
const defaultRootDir = ["api", "operationsRunner"].includes(serviceKey) ? "." : isCapacityProviderService ? "packages/agent" : "packages/core";
|
|
649
|
+
const serviceRoot = isCapacityProviderService ? resolveRailwayCapacityProviderRoot(tenantRoot, service) : resolve(tenantRoot, service.railway?.rootDir ?? service.rootDir ?? defaultRootDir);
|
|
939
650
|
const railwayEnvironment = resolveRailwayEnvironmentForScope(
|
|
940
651
|
normalizedScope,
|
|
941
652
|
service.environments?.[normalizedScope]?.railwayEnvironment
|
|
@@ -943,47 +654,233 @@ function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, app
|
|
|
943
654
|
const publicBaseUrl = service.environments?.[normalizedScope]?.baseUrl ?? service.publicBaseUrl ?? null;
|
|
944
655
|
const configuredServiceName = service.railway?.serviceName ?? (serviceKey === "workerRunner" ? deriveRailwayWorkerRunnerServiceName(identity.deploymentKey) : `${identity.deploymentKey}-${railwayServiceNameSuffix(serviceKey)}`);
|
|
945
656
|
const configuredRunnerPool = service.railway?.runnerPool && typeof service.railway.runnerPool === "object" ? service.railway.runnerPool : null;
|
|
946
|
-
const runnerPool = serviceKey === "operationsRunner" ? {
|
|
947
|
-
bootstrapCount: Math.max(1, Number.parseInt(String(configuredRunnerPool?.bootstrapCount ?? OPERATIONS_RUNNER_BOOTSTRAP_COUNT), 10) || OPERATIONS_RUNNER_BOOTSTRAP_COUNT),
|
|
948
|
-
maxRunners: Math.max(1, Number.parseInt(String(configuredRunnerPool?.maxRunners ?? configuredRunnerPool?.bootstrapCount ?? OPERATIONS_RUNNER_BOOTSTRAP_COUNT), 10) || OPERATIONS_RUNNER_BOOTSTRAP_COUNT),
|
|
657
|
+
const runnerPool = serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? {
|
|
658
|
+
bootstrapCount: Math.max(1, Number.parseInt(String(configuredRunnerPool?.bootstrapCount ?? (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)), 10) || (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)),
|
|
659
|
+
maxRunners: Math.max(1, Number.parseInt(String(configuredRunnerPool?.maxRunners ?? configuredRunnerPool?.bootstrapCount ?? (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)), 10) || (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)),
|
|
949
660
|
volumeMountPath: service.railway?.volumeMountPath ?? configuredRunnerPool?.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH
|
|
950
661
|
} : serviceKey === "workerRunner" ? {
|
|
951
662
|
bootstrapIndex: WORKER_RUNNER_BOOTSTRAP_INDEX,
|
|
952
663
|
volumeMountPath: WORKER_RUNNER_VOLUME_MOUNT_PATH
|
|
953
664
|
} : null;
|
|
954
|
-
const instanceCount = serviceKey === "operationsRunner" ? runnerPool.bootstrapCount : 1;
|
|
665
|
+
const instanceCount = serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? runnerPool.bootstrapCount : 1;
|
|
955
666
|
return Array.from({ length: instanceCount }, (_, offset) => {
|
|
956
667
|
const runnerIndex = offset + 1;
|
|
957
|
-
const serviceName = serviceKey === "operationsRunner" ? deriveRailwayOperationsRunnerServiceName(configuredServiceName, runnerIndex) : configuredServiceName;
|
|
668
|
+
const serviceName = serviceKey === "operationsRunner" ? deriveRailwayOperationsRunnerServiceName(configuredServiceName, runnerIndex) : serviceKey === "capacityProviderRunner" ? deriveRailwayCapacityProviderRunnerServiceName(configuredServiceName, runnerIndex) : configuredServiceName;
|
|
669
|
+
const configuredImageRefEnv = service.railway?.imageRefEnv ?? railwayImageRefEnvForService(serviceKey);
|
|
670
|
+
const imageRef = service.railway?.imageRef ?? (configuredImageRefEnv ? envValue(configuredImageRefEnv, imageRefEnv) || null : null) ?? defaultRailwayImageRef(serviceKey, normalizedScope, imageRefEnv);
|
|
671
|
+
const sourcePolicy = resolveRailwayServiceSourcePolicy({
|
|
672
|
+
tenantRoot,
|
|
673
|
+
scope: normalizedScope,
|
|
674
|
+
serviceKey,
|
|
675
|
+
service,
|
|
676
|
+
serviceRoot,
|
|
677
|
+
imageRef
|
|
678
|
+
});
|
|
679
|
+
const resolvedImageRef = sourcePolicy.sourceMode === "image" ? imageRef : null;
|
|
958
680
|
return {
|
|
959
681
|
key: serviceKey,
|
|
960
|
-
instanceKey: serviceKey === "operationsRunner" ? `${serviceKey}:${runnerIndex}` : serviceKey,
|
|
961
|
-
runnerIndex: serviceKey === "operationsRunner" ? runnerIndex : null,
|
|
682
|
+
instanceKey: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? `${serviceKey}:${runnerIndex}` : serviceKey,
|
|
683
|
+
runnerIndex: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? runnerIndex : null,
|
|
962
684
|
serviceConfig: service,
|
|
963
685
|
scope: normalizedScope,
|
|
964
686
|
projectId: service.railway?.projectId ?? null,
|
|
965
687
|
projectName: service.railway?.projectName ?? identity.deploymentKey,
|
|
966
688
|
serviceId: service.railway?.serviceId ?? null,
|
|
967
689
|
serviceName,
|
|
968
|
-
runnerId: serviceKey === "operationsRunner" ? serviceName : null,
|
|
690
|
+
runnerId: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? serviceName : null,
|
|
969
691
|
rootDir: serviceRoot,
|
|
970
692
|
publicBaseUrl,
|
|
971
693
|
railwayEnvironment,
|
|
972
|
-
buildCommand: service.railway?.buildCommand ?? null,
|
|
973
|
-
startCommand: service.railway?.startCommand ?? null,
|
|
694
|
+
buildCommand: resolvedImageRef ? null : service.railway?.buildCommand ?? null,
|
|
695
|
+
startCommand: isCapacityProviderService ? null : resolvedImageRef ? null : service.railway?.startCommand ?? null,
|
|
696
|
+
imageRef: resolvedImageRef,
|
|
697
|
+
sourceMode: sourcePolicy.sourceMode,
|
|
698
|
+
sourceRepo: sourcePolicy.sourceRepo,
|
|
699
|
+
sourceBranch: sourcePolicy.sourceBranch,
|
|
700
|
+
sourceCommit: sourcePolicy.sourceCommit,
|
|
701
|
+
sourceRootDirectory: sourcePolicy.sourceRootDirectory,
|
|
702
|
+
dockerfilePath: sourcePolicy.sourceMode === "git" ? service.railway?.dockerfilePath ?? null : null,
|
|
974
703
|
healthcheckPath: service.railway?.healthcheckPath ?? null,
|
|
975
704
|
healthcheckTimeoutSeconds: service.railway?.healthcheckTimeoutSeconds ?? null,
|
|
976
705
|
healthcheckIntervalSeconds: service.railway?.healthcheckIntervalSeconds ?? null,
|
|
977
706
|
restartPolicy: service.railway?.restartPolicy ?? null,
|
|
978
707
|
runtimeMode: service.railway?.runtimeMode ?? null,
|
|
979
|
-
volumeMountPath: serviceKey === "operationsRunner" ? runnerPool.volumeMountPath : service.railway?.volumeMountPath ?? null,
|
|
708
|
+
volumeMountPath: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? runnerPool.volumeMountPath : service.railway?.volumeMountPath ?? null,
|
|
980
709
|
schedule: normalizeScheduleExpressions(service.railway?.schedule),
|
|
981
710
|
hostingKind,
|
|
982
711
|
runnerPool,
|
|
983
|
-
application
|
|
712
|
+
application,
|
|
713
|
+
secretRefs: Array.isArray(service.secretRefs) ? service.secretRefs : [],
|
|
714
|
+
variableRefs: Array.isArray(service.variableRefs) ? service.variableRefs : []
|
|
984
715
|
};
|
|
985
716
|
});
|
|
986
717
|
}).filter(Boolean);
|
|
718
|
+
return [
|
|
719
|
+
...configuredServices,
|
|
720
|
+
...configuredPublicTreeDxRailwayServices({
|
|
721
|
+
tenantRoot,
|
|
722
|
+
scope: normalizedScope,
|
|
723
|
+
deployConfig,
|
|
724
|
+
identity,
|
|
725
|
+
hostingKind,
|
|
726
|
+
application,
|
|
727
|
+
imageRefEnv,
|
|
728
|
+
workspaceRoot: machineConfigRoot
|
|
729
|
+
})
|
|
730
|
+
];
|
|
731
|
+
}
|
|
732
|
+
function configuredPublicTreeDxRailwayServices({ tenantRoot, scope, deployConfig, identity, hostingKind, application, imageRefEnv, workspaceRoot }) {
|
|
733
|
+
if (deployConfig.hosting?.kind !== "treeseed_control_plane") {
|
|
734
|
+
return [];
|
|
735
|
+
}
|
|
736
|
+
const railway = deployConfig.publicTreeDxFederation?.railway ?? {};
|
|
737
|
+
const nodePool = railway.nodePool && typeof railway.nodePool === "object" && !Array.isArray(railway.nodePool) ? railway.nodePool : {};
|
|
738
|
+
const bootstrapCount = Math.max(0, Number.parseInt(String(nodePool.bootstrapCount ?? 1), 10) || 0);
|
|
739
|
+
if (bootstrapCount <= 0) {
|
|
740
|
+
return [];
|
|
741
|
+
}
|
|
742
|
+
const configuredSource = railway.source && typeof railway.source === "object" && !Array.isArray(railway.source) ? railway.source : {};
|
|
743
|
+
const treeDxRoot = resolve(workspaceRoot ?? tenantRoot, "packages", "treedx");
|
|
744
|
+
const configuredMode = typeof railway.sourceMode === "string" ? railway.sourceMode : null;
|
|
745
|
+
const sourceMode = scope === "prod" ? "image" : configuredMode === "git" || configuredMode === "image" ? configuredMode : "git";
|
|
746
|
+
const repository = typeof railway.sourceRepo === "string" ? railway.sourceRepo : typeof configuredSource.repository === "string" ? configuredSource.repository : typeof configuredSource.repo === "string" ? configuredSource.repo : readTreeseedPackageRepository(treeDxRoot) ?? "treeseed-ai/treedx";
|
|
747
|
+
const sourceBranch = typeof railway.sourceBranch === "string" ? railway.sourceBranch : typeof configuredSource.branch === "string" ? configuredSource.branch : scope === "staging" ? "staging" : null;
|
|
748
|
+
const sourceRootDirectory = typeof railway.sourceRootDirectory === "string" ? railway.sourceRootDirectory : typeof configuredSource.rootDirectory === "string" ? configuredSource.rootDirectory : ".";
|
|
749
|
+
const projectName = typeof railway.projectName === "string" && railway.projectName.trim() ? railway.projectName.trim() : typeof imageRefEnv.TREESEED_PUBLIC_TREEDX_RAILWAY_PROJECT_NAME === "string" && imageRefEnv.TREESEED_PUBLIC_TREEDX_RAILWAY_PROJECT_NAME.trim() ? imageRefEnv.TREESEED_PUBLIC_TREEDX_RAILWAY_PROJECT_NAME.trim() : identity.deploymentKey;
|
|
750
|
+
const railwayEnvironment = resolveRailwayEnvironmentForScope(scope, railway.environmentName);
|
|
751
|
+
const baseImageRef = envValue("TREESEED_PUBLIC_TREEDX_IMAGE_REF", imageRefEnv) || "treeseed/treedx";
|
|
752
|
+
return Array.from({ length: bootstrapCount }, (_, offset) => {
|
|
753
|
+
const index = offset + 1;
|
|
754
|
+
const serviceName = `${PUBLIC_TREEDX_NODE_SERVICE_KEY_PREFIX}${String(index).padStart(2, "0")}`;
|
|
755
|
+
return {
|
|
756
|
+
key: serviceName,
|
|
757
|
+
instanceKey: serviceName,
|
|
758
|
+
runnerIndex: null,
|
|
759
|
+
serviceConfig: null,
|
|
760
|
+
scope,
|
|
761
|
+
projectId: typeof railway.projectId === "string" ? railway.projectId : null,
|
|
762
|
+
projectName,
|
|
763
|
+
serviceId: typeof railway.serviceId === "string" && bootstrapCount === 1 ? railway.serviceId : null,
|
|
764
|
+
serviceName,
|
|
765
|
+
runnerId: null,
|
|
766
|
+
rootDir: treeDxRoot,
|
|
767
|
+
publicBaseUrl: null,
|
|
768
|
+
railwayEnvironment,
|
|
769
|
+
buildCommand: sourceMode === "git" ? railway.buildCommand ?? null : null,
|
|
770
|
+
startCommand: sourceMode === "git" ? railway.startCommand ?? null : null,
|
|
771
|
+
imageRef: sourceMode === "image" ? baseImageRef : null,
|
|
772
|
+
sourceMode,
|
|
773
|
+
sourceRepo: sourceMode === "git" ? repository : null,
|
|
774
|
+
sourceBranch: sourceMode === "git" ? sourceBranch : null,
|
|
775
|
+
sourceCommit: sourceMode === "git" ? headCommitSafe(treeDxRoot) ?? headCommitSafe(tenantRoot) : null,
|
|
776
|
+
sourceRootDirectory: sourceMode === "git" ? sourceRootDirectory : null,
|
|
777
|
+
dockerfilePath: sourceMode === "git" ? railway.dockerfilePath ?? "/Dockerfile" : null,
|
|
778
|
+
healthcheckPath: railway.healthcheckPath ?? null,
|
|
779
|
+
healthcheckTimeoutSeconds: railway.healthcheckTimeoutSeconds ?? null,
|
|
780
|
+
healthcheckIntervalSeconds: railway.healthcheckIntervalSeconds ?? null,
|
|
781
|
+
restartPolicy: railway.restartPolicy ?? null,
|
|
782
|
+
runtimeMode: railway.runtimeMode ?? "replicated",
|
|
783
|
+
volumeMountPath: railway.volumeMountPath ?? "/data",
|
|
784
|
+
schedule: [],
|
|
785
|
+
hostingKind,
|
|
786
|
+
runnerPool: null,
|
|
787
|
+
application,
|
|
788
|
+
environmentVariables: {
|
|
789
|
+
PORT: "4000",
|
|
790
|
+
TREEDX_DATA_DIR: railway.volumeMountPath ?? "/data",
|
|
791
|
+
TREEDX_AUTH_MODE: "connected",
|
|
792
|
+
TREEDX_AUTH_VERIFIER: "hs256_dev",
|
|
793
|
+
TREEDX_ALLOW_DEV_VERIFIER_IN_PROD: "true",
|
|
794
|
+
TREEDX_EXEC_BACKEND: "container_sandbox",
|
|
795
|
+
TREEDX_FEDERATION_MODE: "connected_library",
|
|
796
|
+
TREEDX_JWT_AUDIENCE: "treedx-public-federation",
|
|
797
|
+
TREEDX_JWT_ISSUER: "https://api.treeseed.local/treedx",
|
|
798
|
+
TREEDX_BOOTSTRAP_TRUST_ACTOR_ID: "treeseed-api",
|
|
799
|
+
TREEDX_BOOTSTRAP_TRUST_TENANT_ID: "treeseed-control-plane",
|
|
800
|
+
TREEDX_BOOTSTRAP_TRUST_REPO_IDS: "*",
|
|
801
|
+
TREEDX_BOOTSTRAP_TRUST_REFS: "*",
|
|
802
|
+
TREEDX_BOOTSTRAP_TRUST_PATHS: "**",
|
|
803
|
+
TREEDX_SCOPE: "public_federation"
|
|
804
|
+
},
|
|
805
|
+
secretRefs: ["TREEDX_SECRET_KEY_BASE", "TREEDX_ADMIN_TOKEN", "TREEDX_JWT_HS256_SECRET"],
|
|
806
|
+
variableRefs: [
|
|
807
|
+
"PORT",
|
|
808
|
+
"TREEDX_DATA_DIR",
|
|
809
|
+
"TREEDX_AUTH_MODE",
|
|
810
|
+
"TREEDX_AUTH_VERIFIER",
|
|
811
|
+
"TREEDX_ALLOW_DEV_VERIFIER_IN_PROD",
|
|
812
|
+
"TREEDX_EXEC_BACKEND",
|
|
813
|
+
"TREEDX_FEDERATION_MODE",
|
|
814
|
+
"TREEDX_JWT_AUDIENCE",
|
|
815
|
+
"TREEDX_JWT_ISSUER",
|
|
816
|
+
"TREEDX_BOOTSTRAP_TRUST_ACTOR_ID",
|
|
817
|
+
"TREEDX_BOOTSTRAP_TRUST_TENANT_ID",
|
|
818
|
+
"TREEDX_BOOTSTRAP_TRUST_REPO_IDS",
|
|
819
|
+
"TREEDX_BOOTSTRAP_TRUST_REFS",
|
|
820
|
+
"TREEDX_BOOTSTRAP_TRUST_PATHS",
|
|
821
|
+
"TREEDX_SCOPE"
|
|
822
|
+
]
|
|
823
|
+
};
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
function readTreeseedPackageRepository(packageRoot) {
|
|
827
|
+
const manifestPath = resolve(packageRoot, "treeseed.package.yaml");
|
|
828
|
+
if (!existsSync(manifestPath)) return null;
|
|
829
|
+
try {
|
|
830
|
+
const manifest = parseYaml(readFileSync(manifestPath, "utf8"));
|
|
831
|
+
const repository = manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest.repository : null;
|
|
832
|
+
return typeof repository === "string" && /^[^/\s]+\/[^/\s]+$/u.test(repository.trim()) ? repository.trim() : null;
|
|
833
|
+
} catch {
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
function headCommitSafe(cwd) {
|
|
838
|
+
try {
|
|
839
|
+
return runTreeseedGitText(["rev-parse", "HEAD"], {
|
|
840
|
+
cwd,
|
|
841
|
+
mode: classifyTreeseedGitMode(["rev-parse", "HEAD"])
|
|
842
|
+
}).trim();
|
|
843
|
+
} catch {
|
|
844
|
+
return null;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
function resolveRailwayServiceSourcePolicy({ tenantRoot, scope, serviceKey, service, serviceRoot, imageRef }) {
|
|
848
|
+
const configuredMode = typeof service.railway?.sourceMode === "string" ? service.railway.sourceMode : null;
|
|
849
|
+
const configuredSource = service.railway?.source && typeof service.railway.source === "object" && !Array.isArray(service.railway.source) ? service.railway.source : {};
|
|
850
|
+
const configuredRepo = typeof service.railway?.sourceRepo === "string" ? service.railway.sourceRepo : typeof configuredSource.repository === "string" ? configuredSource.repository : typeof configuredSource.repo === "string" ? configuredSource.repo : null;
|
|
851
|
+
const packageRepository = configuredRepo ?? readTreeseedPackageRepository(serviceRoot) ?? readTreeseedPackageRepository(tenantRoot);
|
|
852
|
+
const sourceEligible = ["api", "operationsRunner", "capacityProviderManager", "capacityProviderRunner"].includes(serviceKey);
|
|
853
|
+
const sourceMode = scope === "prod" ? "image" : configuredMode === "git" || configuredMode === "image" ? configuredMode : imageRef ? "image" : scope === "staging" && sourceEligible && packageRepository ? "git" : "git";
|
|
854
|
+
if (sourceMode !== "git") {
|
|
855
|
+
return {
|
|
856
|
+
sourceMode: "image",
|
|
857
|
+
sourceRepo: null,
|
|
858
|
+
sourceBranch: null,
|
|
859
|
+
sourceCommit: null,
|
|
860
|
+
sourceRootDirectory: null
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
return {
|
|
864
|
+
sourceMode: "git",
|
|
865
|
+
sourceRepo: packageRepository,
|
|
866
|
+
sourceBranch: typeof service.railway?.sourceBranch === "string" ? service.railway.sourceBranch : typeof configuredSource.branch === "string" ? configuredSource.branch : scope === "staging" ? "staging" : null,
|
|
867
|
+
sourceCommit: headCommitSafe(serviceRoot),
|
|
868
|
+
sourceRootDirectory: typeof service.railway?.sourceRootDirectory === "string" ? service.railway.sourceRootDirectory : typeof configuredSource.rootDirectory === "string" ? configuredSource.rootDirectory : "."
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
function resolveRailwayCapacityProviderRoot(tenantRoot, service) {
|
|
872
|
+
if (service.railway?.rootDir) {
|
|
873
|
+
return resolve(tenantRoot, service.railway.rootDir);
|
|
874
|
+
}
|
|
875
|
+
const candidates = [
|
|
876
|
+
resolve(tenantRoot, "..", "agent"),
|
|
877
|
+
resolve(tenantRoot, "packages", "agent"),
|
|
878
|
+
resolve(tenantRoot, "..", "..", "packages", "agent")
|
|
879
|
+
];
|
|
880
|
+
const found = candidates.find(
|
|
881
|
+
(candidate) => existsSync(resolve(candidate, "treeseed.package.yaml")) || existsSync(resolve(candidate, "package.json"))
|
|
882
|
+
);
|
|
883
|
+
return found ?? resolve(tenantRoot, "packages", "agent");
|
|
987
884
|
}
|
|
988
885
|
function configuredRailwayServices(tenantRoot, scope) {
|
|
989
886
|
const deployConfig = loadCliDeployConfig(tenantRoot);
|
|
@@ -996,7 +893,8 @@ function configuredRailwayServices(tenantRoot, scope) {
|
|
|
996
893
|
id: application.id,
|
|
997
894
|
root: application.root,
|
|
998
895
|
relativeRoot: application.relativeRoot
|
|
999
|
-
}
|
|
896
|
+
},
|
|
897
|
+
tenantRoot
|
|
1000
898
|
));
|
|
1001
899
|
return [...direct, ...nested];
|
|
1002
900
|
}
|
|
@@ -1094,7 +992,11 @@ function validateRailwayServiceConfiguration(tenantRoot, scope) {
|
|
|
1094
992
|
if (!service.projectName && !service.projectId) {
|
|
1095
993
|
issues.push(`${service.key}: set railway.projectName or railway.projectId in treeseed.site.yaml.`);
|
|
1096
994
|
}
|
|
1097
|
-
if (!
|
|
995
|
+
if (service.sourceMode === "git" && !service.sourceRepo) {
|
|
996
|
+
issues.push(`${service.key}: staging source builds require railway.source.repository or package repository metadata.`);
|
|
997
|
+
}
|
|
998
|
+
const usesExternalGitSource = service.sourceMode === "git" && Boolean(service.sourceRepo);
|
|
999
|
+
if (!service.imageRef && !usesExternalGitSource && !existsSync(service.rootDir)) {
|
|
1098
1000
|
issues.push(`${service.key}: service root ${service.rootDir} does not exist.`);
|
|
1099
1001
|
}
|
|
1100
1002
|
if (service.schedule?.length && !service.startCommand) {
|
|
@@ -1116,7 +1018,7 @@ function validateRailwayDeployPrerequisites(tenantRoot, scope, { env = process.e
|
|
|
1116
1018
|
const validation = validateRailwayServiceConfiguration(tenantRoot, scope);
|
|
1117
1019
|
const token = resolveRailwayAuthToken(env);
|
|
1118
1020
|
if (typeof token !== "string" || token.trim().length === 0) {
|
|
1119
|
-
throw new Error("Configure
|
|
1021
|
+
throw new Error("Configure TREESEED_RAILWAY_API_TOKEN before deploying Railway-managed services.");
|
|
1120
1022
|
}
|
|
1121
1023
|
return validation;
|
|
1122
1024
|
}
|
|
@@ -1128,7 +1030,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
|
|
|
1128
1030
|
const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
|
|
1129
1031
|
const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
|
|
1130
1032
|
if (typeof effectiveApiToken !== "string" || effectiveApiToken.trim().length === 0) {
|
|
1131
|
-
throw new Error("Configure
|
|
1033
|
+
throw new Error("Configure TREESEED_RAILWAY_API_TOKEN before deploying Railway-managed services.");
|
|
1132
1034
|
}
|
|
1133
1035
|
const results = [];
|
|
1134
1036
|
try {
|
|
@@ -1154,7 +1056,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
|
|
|
1154
1056
|
const current = await getRailwayServiceInstance({
|
|
1155
1057
|
serviceId: target.service.id,
|
|
1156
1058
|
environmentId: target.environment.id,
|
|
1157
|
-
env: { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
|
|
1059
|
+
env: { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
|
|
1158
1060
|
fetchImpl
|
|
1159
1061
|
});
|
|
1160
1062
|
const desired = {
|
|
@@ -1184,7 +1086,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
|
|
|
1184
1086
|
environmentId: target.environment.id,
|
|
1185
1087
|
startCommand: desired.command,
|
|
1186
1088
|
cronSchedule: desired.schedule,
|
|
1187
|
-
env: { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
|
|
1089
|
+
env: { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
|
|
1188
1090
|
fetchImpl
|
|
1189
1091
|
});
|
|
1190
1092
|
results.push({
|
|
@@ -1214,7 +1116,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
|
|
|
1214
1116
|
return results;
|
|
1215
1117
|
}
|
|
1216
1118
|
async function verifyRailwayScheduledJobs(tenantRoot, scope, { fetchImpl = fetch, apiToken, apiUrl, env = process.env } = {}) {
|
|
1217
|
-
const effectiveApiToken = apiToken || env
|
|
1119
|
+
const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
|
|
1218
1120
|
const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
|
|
1219
1121
|
const configured = configuredRailwayScheduledJobs(tenantRoot, scope);
|
|
1220
1122
|
const checks = [];
|
|
@@ -1238,7 +1140,7 @@ async function verifyRailwayScheduledJobs(tenantRoot, scope, { fetchImpl = fetch
|
|
|
1238
1140
|
const existing = await getRailwayServiceInstance({
|
|
1239
1141
|
serviceId: target.service.id,
|
|
1240
1142
|
environmentId: target.environment.id,
|
|
1241
|
-
env: { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
|
|
1143
|
+
env: { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
|
|
1242
1144
|
fetchImpl
|
|
1243
1145
|
});
|
|
1244
1146
|
checks.push({
|
|
@@ -1293,7 +1195,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
|
|
|
1293
1195
|
} = {}) {
|
|
1294
1196
|
const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
|
|
1295
1197
|
const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
|
|
1296
|
-
const effectiveEnv = { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl };
|
|
1198
|
+
const effectiveEnv = { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl };
|
|
1297
1199
|
const services = configuredRailwayServices(tenantRoot, scope);
|
|
1298
1200
|
const checks = [];
|
|
1299
1201
|
const deploymentStatusServices = [];
|
|
@@ -1353,18 +1255,19 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
|
|
|
1353
1255
|
} : null,
|
|
1354
1256
|
message: instance.id ? void 0 : `Railway service instance for ${target.service.name} is missing in ${target.environment.name}.`
|
|
1355
1257
|
});
|
|
1356
|
-
|
|
1357
|
-
|
|
1258
|
+
const expectedVolumeMountPath = service.volumeMountPath ?? service.runnerPool?.volumeMountPath ?? null;
|
|
1259
|
+
if (expectedVolumeMountPath) {
|
|
1260
|
+
const expectedVolumeName = service.key === "operationsRunner" ? deriveRailwayOperationsRunnerVolumeName(target.service.name, target.environment.name) : service.key === "capacityProviderRunner" ? deriveRailwayCapacityProviderRunnerVolumeName(target.service.name, target.environment.name) : deriveRailwayWorkerRunnerVolumeName(target.service.name, target.environment.name);
|
|
1358
1261
|
const volumes = await listRailwayVolumes({
|
|
1359
1262
|
projectId: target.project.id,
|
|
1360
1263
|
env: effectiveEnv,
|
|
1361
1264
|
fetchImpl
|
|
1362
1265
|
});
|
|
1363
1266
|
const volume = volumes.find(
|
|
1364
|
-
(candidate) => candidate.name === expectedVolumeName && candidate.instances.some((entry) => entry.serviceId === target.service.id && entry.environmentId === target.environment.id && entry.mountPath ===
|
|
1267
|
+
(candidate) => candidate.name === expectedVolumeName && candidate.instances.some((entry) => entry.serviceId === target.service.id && entry.environmentId === target.environment.id && entry.mountPath === expectedVolumeMountPath)
|
|
1365
1268
|
) ?? null;
|
|
1366
1269
|
checks.push({
|
|
1367
|
-
type: "
|
|
1270
|
+
type: "service-volume",
|
|
1368
1271
|
service: service.key,
|
|
1369
1272
|
serviceName: target.service.name,
|
|
1370
1273
|
serviceId: target.service.id,
|
|
@@ -1372,7 +1275,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
|
|
|
1372
1275
|
environment: target.environment.name,
|
|
1373
1276
|
environmentId: target.environment.id,
|
|
1374
1277
|
volumeName: expectedVolumeName,
|
|
1375
|
-
mountPath:
|
|
1278
|
+
mountPath: expectedVolumeMountPath,
|
|
1376
1279
|
ok: Boolean(volume),
|
|
1377
1280
|
status: volume ? "checked" : "missing",
|
|
1378
1281
|
observed: volume ? {
|
|
@@ -1380,7 +1283,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
|
|
|
1380
1283
|
name: volume.name,
|
|
1381
1284
|
instances: volume.instances
|
|
1382
1285
|
} : null,
|
|
1383
|
-
message: volume ? void 0 : `Railway
|
|
1286
|
+
message: volume ? void 0 : `Railway volume ${expectedVolumeName} is missing or is not mounted on ${target.service.name} at ${expectedVolumeMountPath}.`
|
|
1384
1287
|
});
|
|
1385
1288
|
}
|
|
1386
1289
|
}
|
|
@@ -1414,30 +1317,6 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
|
|
|
1414
1317
|
checks
|
|
1415
1318
|
};
|
|
1416
1319
|
}
|
|
1417
|
-
function shouldAttachRailwayDeployLogs(env = process.env) {
|
|
1418
|
-
const configured = configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_ATTACH_LOGS");
|
|
1419
|
-
if (configured === "1" || configured === "true") {
|
|
1420
|
-
return true;
|
|
1421
|
-
}
|
|
1422
|
-
if (configured === "0" || configured === "false") {
|
|
1423
|
-
return false;
|
|
1424
|
-
}
|
|
1425
|
-
return false;
|
|
1426
|
-
}
|
|
1427
|
-
function shouldUseVerboseRailwayDeploy(env = process.env) {
|
|
1428
|
-
const configured = configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_VERBOSE");
|
|
1429
|
-
if (configured === "1" || configured === "true") {
|
|
1430
|
-
return true;
|
|
1431
|
-
}
|
|
1432
|
-
if (configured === "0" || configured === "false") {
|
|
1433
|
-
return false;
|
|
1434
|
-
}
|
|
1435
|
-
return shouldAttachRailwayDeployLogs(env);
|
|
1436
|
-
}
|
|
1437
|
-
function railwayDeployCommandTimeoutMs(env = process.env) {
|
|
1438
|
-
const configured = Number.parseInt(configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_COMMAND_TIMEOUT_MS"), 10);
|
|
1439
|
-
return Number.isFinite(configured) && configured > 0 ? configured : 3e5;
|
|
1440
|
-
}
|
|
1441
1320
|
function railwayPhaseTimeoutMs(env = process.env, phase = "default") {
|
|
1442
1321
|
const configured = Number.parseInt(configuredEnvValue(env, `TREESEED_RAILWAY_${String(phase).toUpperCase().replace(/[^A-Z0-9]+/gu, "_")}_TIMEOUT_MS`), 10);
|
|
1443
1322
|
if (Number.isFinite(configured) && configured > 0) {
|
|
@@ -1467,10 +1346,6 @@ async function withRailwayPhaseTimeout(run, timeoutMs, message) {
|
|
|
1467
1346
|
}
|
|
1468
1347
|
}
|
|
1469
1348
|
}
|
|
1470
|
-
function shouldIncludeRailwayIgnoredFiles(env = process.env) {
|
|
1471
|
-
const configured = configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_INCLUDE_IGNORED");
|
|
1472
|
-
return configured === "1" || configured === "true";
|
|
1473
|
-
}
|
|
1474
1349
|
function shouldRunRailwayPredeployBuild(env = process.env) {
|
|
1475
1350
|
const configured = configuredEnvValue(env, "TREESEED_RAILWAY_PREDEPLOY_BUILD");
|
|
1476
1351
|
if (configured === "1" || configured === "true") {
|
|
@@ -1481,56 +1356,6 @@ function shouldRunRailwayPredeployBuild(env = process.env) {
|
|
|
1481
1356
|
}
|
|
1482
1357
|
return configuredEnvValue(env, "CI") !== "true";
|
|
1483
1358
|
}
|
|
1484
|
-
function planRailwayServiceDeploy(service, { env = process.env, projectTokenMode = false } = {}) {
|
|
1485
|
-
const serviceSelector = service.serviceName ?? service.serviceId;
|
|
1486
|
-
const args = ["up"];
|
|
1487
|
-
if (serviceSelector) {
|
|
1488
|
-
args.push("--service", serviceSelector);
|
|
1489
|
-
}
|
|
1490
|
-
if (shouldIncludeRailwayIgnoredFiles(env)) {
|
|
1491
|
-
args.push("--no-gitignore");
|
|
1492
|
-
}
|
|
1493
|
-
args.push(shouldAttachRailwayDeployLogs(env) ? "--ci" : "--detach");
|
|
1494
|
-
if (shouldUseVerboseRailwayDeploy(env)) {
|
|
1495
|
-
args.push("--verbose");
|
|
1496
|
-
}
|
|
1497
|
-
if (!projectTokenMode && service.projectId) {
|
|
1498
|
-
args.push("--project", service.projectId);
|
|
1499
|
-
}
|
|
1500
|
-
const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
|
|
1501
|
-
if (!projectTokenMode && environmentName) {
|
|
1502
|
-
args.push("--environment", environmentName);
|
|
1503
|
-
}
|
|
1504
|
-
return {
|
|
1505
|
-
command: "railway",
|
|
1506
|
-
args,
|
|
1507
|
-
cwd: service.rootDir
|
|
1508
|
-
};
|
|
1509
|
-
}
|
|
1510
|
-
function planRailwayProjectEnvironmentLink(service) {
|
|
1511
|
-
const args = ["link"];
|
|
1512
|
-
if (service.projectId) {
|
|
1513
|
-
args.push("--project", service.projectId);
|
|
1514
|
-
}
|
|
1515
|
-
const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
|
|
1516
|
-
if (environmentName) {
|
|
1517
|
-
args.push("--environment", environmentName);
|
|
1518
|
-
}
|
|
1519
|
-
args.push("--json");
|
|
1520
|
-
return {
|
|
1521
|
-
command: "railway",
|
|
1522
|
-
args,
|
|
1523
|
-
cwd: service.rootDir
|
|
1524
|
-
};
|
|
1525
|
-
}
|
|
1526
|
-
function buildRailwayCliContextEnv(env, service) {
|
|
1527
|
-
return {
|
|
1528
|
-
...env,
|
|
1529
|
-
RAILWAY_PROJECT_ID: configuredEnvValue(service, "projectId") || configuredEnvValue(env, "RAILWAY_PROJECT_ID") || void 0,
|
|
1530
|
-
RAILWAY_ENVIRONMENT_ID: configuredEnvValue(service, "environmentId") || configuredEnvValue(env, "RAILWAY_ENVIRONMENT_ID") || void 0,
|
|
1531
|
-
RAILWAY_SERVICE_ID: configuredEnvValue(service, "serviceId") || configuredEnvValue(env, "RAILWAY_SERVICE_ID") || void 0
|
|
1532
|
-
};
|
|
1533
|
-
}
|
|
1534
1359
|
async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
|
|
1535
1360
|
if (service.key !== "api") {
|
|
1536
1361
|
return null;
|
|
@@ -1545,7 +1370,7 @@ async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
|
|
|
1545
1370
|
[
|
|
1546
1371
|
"TREESEED_API_AUTH_APPROVAL_BASE_URL",
|
|
1547
1372
|
"TREESEED_SITE_URL",
|
|
1548
|
-
"
|
|
1373
|
+
"TREESEED_BETTER_AUTH_URL"
|
|
1549
1374
|
].map((key) => [key, configuredEnvValue(env, key)]).filter(([, value]) => value)
|
|
1550
1375
|
);
|
|
1551
1376
|
if (Object.keys(variables).length === 0) {
|
|
@@ -1561,166 +1386,6 @@ async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
|
|
|
1561
1386
|
write ? write(`[${prefix.scope}][${prefix.system}][${prefix.task}][vars] Synced device login approval URL variables for ${service.serviceName ?? serviceId}.`, "stdout") : null;
|
|
1562
1387
|
return { variables: Object.keys(variables) };
|
|
1563
1388
|
}
|
|
1564
|
-
function buildRailwayLinkCommandEnv(env = process.env, service = {}) {
|
|
1565
|
-
return buildRailwayCliContextEnv({
|
|
1566
|
-
...buildRailwayDeployCommandEnv({ ...env, RAILWAY_TOKEN: void 0 }),
|
|
1567
|
-
RAILWAY_TOKEN: void 0
|
|
1568
|
-
}, service);
|
|
1569
|
-
}
|
|
1570
|
-
function railwayCliConfigPath(env = process.env) {
|
|
1571
|
-
const railwayHome = configuredEnvValue(env, "RAILWAY_HOME");
|
|
1572
|
-
if (railwayHome) {
|
|
1573
|
-
return resolve(railwayHome, "config.json");
|
|
1574
|
-
}
|
|
1575
|
-
const home = configuredEnvValue(env, "HOME");
|
|
1576
|
-
if (!home) {
|
|
1577
|
-
return "";
|
|
1578
|
-
}
|
|
1579
|
-
return resolve(home, ".railway", "config.json");
|
|
1580
|
-
}
|
|
1581
|
-
function readRailwayCliConfig(configPath) {
|
|
1582
|
-
if (!configPath || !existsSync(configPath)) {
|
|
1583
|
-
return {};
|
|
1584
|
-
}
|
|
1585
|
-
try {
|
|
1586
|
-
const parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
1587
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
1588
|
-
} catch {
|
|
1589
|
-
return {};
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
function writeRailwayCliProjectConfig(service, { env = process.env, cwd = service.rootDir } = {}) {
|
|
1593
|
-
const projectId = configuredEnvValue(service, "projectId");
|
|
1594
|
-
const environmentId = configuredEnvValue(service, "environmentId");
|
|
1595
|
-
const serviceId = configuredEnvValue(service, "serviceId");
|
|
1596
|
-
const projectPath = cwd ? resolve(cwd) : "";
|
|
1597
|
-
const configPath = railwayCliConfigPath(env);
|
|
1598
|
-
if (!configPath || !projectPath || !projectId || !environmentId || !serviceId) {
|
|
1599
|
-
return null;
|
|
1600
|
-
}
|
|
1601
|
-
const existing = readRailwayCliConfig(configPath);
|
|
1602
|
-
const projects = existing.projects && typeof existing.projects === "object" ? existing.projects : {};
|
|
1603
|
-
const next = {
|
|
1604
|
-
...existing,
|
|
1605
|
-
projects: {
|
|
1606
|
-
...projects,
|
|
1607
|
-
[projectPath]: {
|
|
1608
|
-
projectPath,
|
|
1609
|
-
name: configuredEnvValue(service, "projectName") || configuredEnvValue(service, "serviceName") || projectId,
|
|
1610
|
-
project: projectId,
|
|
1611
|
-
environment: environmentId,
|
|
1612
|
-
environmentName: normalizeRailwayEnvironmentName(service.railwayEnvironment) || configuredEnvValue(service, "environmentName") || environmentId,
|
|
1613
|
-
service: serviceId
|
|
1614
|
-
}
|
|
1615
|
-
},
|
|
1616
|
-
user: existing.user && typeof existing.user === "object" ? existing.user : {
|
|
1617
|
-
token: null,
|
|
1618
|
-
accessToken: null,
|
|
1619
|
-
refreshToken: null,
|
|
1620
|
-
tokenExpiresAt: null
|
|
1621
|
-
},
|
|
1622
|
-
linkedFunctions: existing.linkedFunctions ?? null
|
|
1623
|
-
};
|
|
1624
|
-
mkdirSync(dirname(configPath), { recursive: true });
|
|
1625
|
-
writeFileSync(configPath, `${JSON.stringify(next, null, 2)}
|
|
1626
|
-
`, "utf8");
|
|
1627
|
-
return {
|
|
1628
|
-
configPath,
|
|
1629
|
-
projectPath,
|
|
1630
|
-
projectId,
|
|
1631
|
-
environmentId,
|
|
1632
|
-
serviceId
|
|
1633
|
-
};
|
|
1634
|
-
}
|
|
1635
|
-
function planRailwayServiceLink(service, { env = process.env } = {}) {
|
|
1636
|
-
const args = ["link"];
|
|
1637
|
-
if (service.projectId) {
|
|
1638
|
-
args.push("--project", service.projectId);
|
|
1639
|
-
}
|
|
1640
|
-
const workspace = resolveRailwayWorkspace(env);
|
|
1641
|
-
if (workspace) {
|
|
1642
|
-
args.push("--workspace", workspace);
|
|
1643
|
-
}
|
|
1644
|
-
const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
|
|
1645
|
-
if (environmentName) {
|
|
1646
|
-
args.push("--environment", environmentName);
|
|
1647
|
-
}
|
|
1648
|
-
const serviceSelector = service.serviceName ?? service.serviceId;
|
|
1649
|
-
if (serviceSelector) {
|
|
1650
|
-
args.push("--service", serviceSelector);
|
|
1651
|
-
}
|
|
1652
|
-
args.push("--json");
|
|
1653
|
-
return {
|
|
1654
|
-
command: "railway",
|
|
1655
|
-
args,
|
|
1656
|
-
cwd: service.rootDir
|
|
1657
|
-
};
|
|
1658
|
-
}
|
|
1659
|
-
function railwayProjectTokenName(service) {
|
|
1660
|
-
const environment = normalizeRailwayEnvironmentName(service.railwayEnvironment) || "environment";
|
|
1661
|
-
const serviceName = String(service.serviceName ?? service.serviceId ?? service.key ?? "service").toLowerCase().replace(/[^a-z0-9-]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 48) || "service";
|
|
1662
|
-
return `treeseed-ci-${environment}-${serviceName}`;
|
|
1663
|
-
}
|
|
1664
|
-
async function createRailwayCliProjectToken(service, { env = process.env } = {}) {
|
|
1665
|
-
const projectId = configuredEnvValue(service, "projectId");
|
|
1666
|
-
const environmentId = configuredEnvValue(service, "environmentId");
|
|
1667
|
-
if (!projectId || !environmentId) {
|
|
1668
|
-
return "";
|
|
1669
|
-
}
|
|
1670
|
-
const name = railwayProjectTokenName(service);
|
|
1671
|
-
try {
|
|
1672
|
-
const existingPayload = await railwayGraphqlRequest({
|
|
1673
|
-
query: `
|
|
1674
|
-
query TreeseedProjectTokens($projectId: String!) {
|
|
1675
|
-
projectTokens(projectId: $projectId, first: 100) {
|
|
1676
|
-
edges {
|
|
1677
|
-
node {
|
|
1678
|
-
id
|
|
1679
|
-
name
|
|
1680
|
-
projectId
|
|
1681
|
-
environmentId
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
`.trim(),
|
|
1687
|
-
variables: { projectId },
|
|
1688
|
-
env
|
|
1689
|
-
});
|
|
1690
|
-
const existingTokens = railwayEdgeNodes(existingPayload.data?.projectTokens);
|
|
1691
|
-
for (const token2 of existingTokens) {
|
|
1692
|
-
if (token2?.name === name && token2?.projectId === projectId && token2?.environmentId === environmentId && token2?.id) {
|
|
1693
|
-
await railwayGraphqlRequest({
|
|
1694
|
-
query: `
|
|
1695
|
-
mutation TreeseedProjectTokenDelete($id: String!) {
|
|
1696
|
-
projectTokenDelete(id: $id)
|
|
1697
|
-
}
|
|
1698
|
-
`.trim(),
|
|
1699
|
-
variables: { id: token2.id },
|
|
1700
|
-
env
|
|
1701
|
-
});
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
} catch {
|
|
1705
|
-
}
|
|
1706
|
-
const payload = await railwayGraphqlRequest({
|
|
1707
|
-
query: `
|
|
1708
|
-
mutation TreeseedProjectTokenCreate($input: ProjectTokenCreateInput!) {
|
|
1709
|
-
projectTokenCreate(input: $input)
|
|
1710
|
-
}
|
|
1711
|
-
`.trim(),
|
|
1712
|
-
variables: {
|
|
1713
|
-
input: {
|
|
1714
|
-
projectId,
|
|
1715
|
-
environmentId,
|
|
1716
|
-
name
|
|
1717
|
-
}
|
|
1718
|
-
},
|
|
1719
|
-
env
|
|
1720
|
-
});
|
|
1721
|
-
const token = payload.data?.projectTokenCreate;
|
|
1722
|
-
return typeof token === "string" && token.trim() ? token.trim() : "";
|
|
1723
|
-
}
|
|
1724
1389
|
async function resolveRailwayDeployProjectContext(service, { env = process.env } = {}) {
|
|
1725
1390
|
if (service.projectId) {
|
|
1726
1391
|
return service;
|
|
@@ -1745,8 +1410,8 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
|
|
|
1745
1410
|
writePhase(`sync-runtime-config:${stage}`, message);
|
|
1746
1411
|
}
|
|
1747
1412
|
};
|
|
1748
|
-
const wantsInstanceConfig = service.buildCommand || service.startCommand || service.rootDir || service.healthcheckPath || service.healthcheckTimeoutSeconds !== null || service.healthcheckTimeoutSeconds !== void 0 || service.healthcheckIntervalSeconds !== null || service.healthcheckIntervalSeconds !== void 0 || service.restartPolicy || service.runtimeMode;
|
|
1749
|
-
const wantsRunnerVolume = service.key === "workerRunner" ||
|
|
1413
|
+
const wantsInstanceConfig = service.buildCommand || service.startCommand || !(service.imageRef || service.sourceMode === "image") && service.rootDir || service.healthcheckPath || service.healthcheckTimeoutSeconds !== null || service.healthcheckTimeoutSeconds !== void 0 || service.healthcheckIntervalSeconds !== null || service.healthcheckIntervalSeconds !== void 0 || service.restartPolicy || service.runtimeMode;
|
|
1414
|
+
const wantsRunnerVolume = service.key === "workerRunner" || service.key === "operationsRunner" || service.key === "capacityProviderRunner";
|
|
1750
1415
|
if (!wantsInstanceConfig && !wantsRunnerVolume) {
|
|
1751
1416
|
writeSyncPhase("skip", "No runtime configuration changes requested.");
|
|
1752
1417
|
return null;
|
|
@@ -1794,6 +1459,21 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
|
|
|
1794
1459
|
projectId: project.id,
|
|
1795
1460
|
serviceId: service.serviceId,
|
|
1796
1461
|
serviceName: service.serviceName,
|
|
1462
|
+
environmentId: environment.id,
|
|
1463
|
+
imageRef: service.imageRef,
|
|
1464
|
+
sourceRepo: service.sourceRepo,
|
|
1465
|
+
sourceBranch: service.sourceBranch,
|
|
1466
|
+
env
|
|
1467
|
+
}).then((result) => result.service);
|
|
1468
|
+
} else if (service.imageRef) {
|
|
1469
|
+
railwayService = await ensureRailwayService({
|
|
1470
|
+
projectId: project.id,
|
|
1471
|
+
serviceId: service.serviceId,
|
|
1472
|
+
serviceName: service.serviceName,
|
|
1473
|
+
environmentId: environment.id,
|
|
1474
|
+
imageRef: service.imageRef,
|
|
1475
|
+
sourceRepo: service.sourceRepo,
|
|
1476
|
+
sourceBranch: service.sourceBranch,
|
|
1797
1477
|
env
|
|
1798
1478
|
}).then((result) => result.service);
|
|
1799
1479
|
}
|
|
@@ -1806,7 +1486,7 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
|
|
|
1806
1486
|
buildCommand: service.buildCommand,
|
|
1807
1487
|
startCommand: railwayServiceRuntimeStartCommand(service),
|
|
1808
1488
|
cronSchedule: service.schedule?.[0] ?? null,
|
|
1809
|
-
rootDirectory: ".",
|
|
1489
|
+
rootDirectory: service.imageRef || service.sourceMode === "image" ? null : service.sourceRootDirectory ?? ".",
|
|
1810
1490
|
healthcheckPath: service.healthcheckPath,
|
|
1811
1491
|
healthcheckTimeoutSeconds: service.healthcheckTimeoutSeconds,
|
|
1812
1492
|
healthcheckIntervalSeconds: service.healthcheckIntervalSeconds,
|
|
@@ -1822,6 +1502,14 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
|
|
|
1822
1502
|
serviceId: railwayService.id,
|
|
1823
1503
|
variables: {
|
|
1824
1504
|
TREESEED_SKIP_PACKAGE_PREPARE: "1",
|
|
1505
|
+
...service.sourceMode === "git" ? {
|
|
1506
|
+
TREESEED_DEPLOY_SOURCE_MODE: "git",
|
|
1507
|
+
...service.sourceRepo ? { TREESEED_DEPLOY_SOURCE_REPOSITORY: service.sourceRepo } : {},
|
|
1508
|
+
...service.sourceBranch ? { TREESEED_DEPLOY_SOURCE_BRANCH: service.sourceBranch } : {},
|
|
1509
|
+
...service.sourceCommit ? { TREESEED_DEPLOY_SOURCE_COMMIT: service.sourceCommit } : {}
|
|
1510
|
+
} : {
|
|
1511
|
+
TREESEED_DEPLOY_SOURCE_MODE: "image"
|
|
1512
|
+
},
|
|
1825
1513
|
...service.key === "operationsRunner" ? {
|
|
1826
1514
|
NIXPACKS_APT_PKGS: "git",
|
|
1827
1515
|
NIXPACKS_PKGS: "git",
|
|
@@ -1829,12 +1517,25 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
|
|
|
1829
1517
|
TREESEED_PLATFORM_RUNNER_DATA_DIR: service.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH,
|
|
1830
1518
|
TREESEED_PLATFORM_RUNNER_ENVIRONMENT: normalizeScope(service.scope) === "prod" ? "production" : normalizeScope(service.scope),
|
|
1831
1519
|
TREESEED_MANAGER_ID: normalizeScope(service.scope),
|
|
1832
|
-
...configuredEnvValue(env, "
|
|
1520
|
+
...configuredEnvValue(env, "TREESEED_RAILWAY_API_TOKEN") ? { TREESEED_RAILWAY_API_TOKEN: configuredEnvValue(env, "TREESEED_RAILWAY_API_TOKEN") } : {},
|
|
1833
1521
|
...configuredEnvValue(env, "TREESEED_RAILWAY_WORKSPACE") ? { TREESEED_RAILWAY_WORKSPACE: configuredEnvValue(env, "TREESEED_RAILWAY_WORKSPACE") } : {},
|
|
1834
1522
|
...configuredEnvValue(env, "TREESEED_PLATFORM_RUNNER_SECRET") ? { TREESEED_PLATFORM_RUNNER_SECRET: configuredEnvValue(env, "TREESEED_PLATFORM_RUNNER_SECRET") } : {},
|
|
1835
1523
|
...configuredEnvValue(env, "TREESEED_API_BASE_URL") || configuredEnvValue(env, "TREESEED_URL") ? {
|
|
1836
1524
|
TREESEED_API_BASE_URL: configuredEnvValue(env, "TREESEED_API_BASE_URL") || configuredEnvValue(env, "TREESEED_URL")
|
|
1837
1525
|
} : {}
|
|
1526
|
+
} : {},
|
|
1527
|
+
...String(service.key).startsWith("capacityProvider") ? {
|
|
1528
|
+
TREESEED_PROVIDER_ENVIRONMENT: normalizeScope(service.scope) === "prod" ? "production" : normalizeScope(service.scope),
|
|
1529
|
+
TREESEED_MANAGER_ID: normalizeScope(service.scope),
|
|
1530
|
+
TREESEED_MARKET_ID: normalizeScope(service.scope),
|
|
1531
|
+
TREESEED_PROVIDER_ROLE: service.key === "capacityProviderManager" ? "manager" : "runner",
|
|
1532
|
+
...service.key === "capacityProviderRunner" ? {
|
|
1533
|
+
TREESEED_PROVIDER_DATA_DIR: service.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH,
|
|
1534
|
+
TREESEED_PROVIDER_RUNNER_ID: service.runnerId ?? railwayService.name
|
|
1535
|
+
} : {},
|
|
1536
|
+
...configuredEnvValue(env, "TREESEED_MARKET_URL") ? { TREESEED_MARKET_URL: configuredEnvValue(env, "TREESEED_MARKET_URL") } : {},
|
|
1537
|
+
...configuredEnvValue(env, "TREESEED_CAPACITY_PROVIDER_API_KEY") ? { TREESEED_CAPACITY_PROVIDER_API_KEY: configuredEnvValue(env, "TREESEED_CAPACITY_PROVIDER_API_KEY") } : {},
|
|
1538
|
+
...configuredEnvValue(env, "TREESEED_CODEX_AUTH_JSON_B64") ? { TREESEED_CODEX_AUTH_JSON_B64: configuredEnvValue(env, "TREESEED_CODEX_AUTH_JSON_B64") } : {}
|
|
1838
1539
|
} : {}
|
|
1839
1540
|
},
|
|
1840
1541
|
env
|
|
@@ -1847,7 +1548,7 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
|
|
|
1847
1548
|
projectId: project.id,
|
|
1848
1549
|
environmentId: environment.id,
|
|
1849
1550
|
serviceId: railwayService.id,
|
|
1850
|
-
name: service.key === "operationsRunner" ? deriveRailwayOperationsRunnerVolumeName(railwayService.name, environment.name) : deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
|
|
1551
|
+
name: service.key === "operationsRunner" ? deriveRailwayOperationsRunnerVolumeName(railwayService.name, environment.name) : service.key === "capacityProviderRunner" ? deriveRailwayCapacityProviderRunnerVolumeName(railwayService.name, environment.name) : deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
|
|
1851
1552
|
mountPath: volumeMountPath,
|
|
1852
1553
|
env
|
|
1853
1554
|
}) : null;
|
|
@@ -1896,12 +1597,11 @@ async function deployRailwayService(tenantRoot, service, {
|
|
|
1896
1597
|
} = {}) {
|
|
1897
1598
|
const timings = [];
|
|
1898
1599
|
if (dryRun) {
|
|
1899
|
-
const plan2 = planRailwayServiceDeploy(service, { env });
|
|
1900
1600
|
return {
|
|
1901
1601
|
service: service.key,
|
|
1902
1602
|
status: "planned",
|
|
1903
|
-
command:
|
|
1904
|
-
cwd:
|
|
1603
|
+
command: "railway-api serviceInstanceDeployV2",
|
|
1604
|
+
cwd: service.rootDir,
|
|
1905
1605
|
publicBaseUrl: service.publicBaseUrl,
|
|
1906
1606
|
timings,
|
|
1907
1607
|
transport: {
|
|
@@ -1916,7 +1616,6 @@ async function deployRailwayService(tenantRoot, service, {
|
|
|
1916
1616
|
service: service.key
|
|
1917
1617
|
});
|
|
1918
1618
|
const commandEnv = buildRailwayCommandEnv({ ...process.env, ...env });
|
|
1919
|
-
let railwayDeployEnv = buildRailwayDeployCommandEnv(commandEnv);
|
|
1920
1619
|
const deployTransport = railwayDeployTransport(commandEnv);
|
|
1921
1620
|
const taskPrefix = prefix ?? {
|
|
1922
1621
|
scope: normalizeScope(deployService.scope ?? deployService.railwayEnvironment ?? "railway"),
|
|
@@ -1951,7 +1650,7 @@ async function deployRailwayService(tenantRoot, service, {
|
|
|
1951
1650
|
), {
|
|
1952
1651
|
service: cliDeployService.key
|
|
1953
1652
|
});
|
|
1954
|
-
if (deployService.buildCommand && shouldRunRailwayPredeployBuild(commandEnv)) {
|
|
1653
|
+
if (deployService.buildCommand && !deployService.imageRef && shouldRunRailwayPredeployBuild(commandEnv)) {
|
|
1955
1654
|
const buildResult = await timedRailwayPhase(timings, "railway:predeploy-build", () => runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
|
|
1956
1655
|
cwd: deployService.rootDir,
|
|
1957
1656
|
env: commandEnv,
|
|
@@ -1996,139 +1695,32 @@ async function deployRailwayService(tenantRoot, service, {
|
|
|
1996
1695
|
} : null
|
|
1997
1696
|
};
|
|
1998
1697
|
}
|
|
1999
|
-
|
|
2000
|
-
if (!railway) {
|
|
2001
|
-
throw new Error("Railway CLI deploy fallback requested, but Railway CLI is unavailable.");
|
|
2002
|
-
}
|
|
2003
|
-
railwayDeployEnv = buildRailwayCliContextEnv(railwayDeployEnv, cliDeployService);
|
|
2004
|
-
const hasCommandApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
|
|
2005
|
-
let usesProjectToken = Boolean(configuredEnvValue(railwayDeployEnv, "RAILWAY_TOKEN"));
|
|
2006
|
-
if (usesProjectToken) {
|
|
2007
|
-
railwayDeployEnv = { ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0 };
|
|
2008
|
-
}
|
|
2009
|
-
writePhase("project-token", usesProjectToken || hasCommandApiToken ? "Using configured Railway authentication." : "Creating Railway project token.");
|
|
2010
|
-
await timedRailwayPhase(timings, "railway:project-token", () => withRailwayPhaseTimeout(async () => {
|
|
2011
|
-
if (usesProjectToken || hasCommandApiToken) {
|
|
2012
|
-
return null;
|
|
2013
|
-
}
|
|
2014
|
-
const projectToken = await createRailwayCliProjectToken(cliDeployService, { env: commandEnv });
|
|
2015
|
-
if (projectToken) {
|
|
2016
|
-
railwayDeployEnv = buildRailwayCliContextEnv({ ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0, RAILWAY_TOKEN: projectToken }, cliDeployService);
|
|
2017
|
-
usesProjectToken = true;
|
|
2018
|
-
} else if (configuredEnvValue(commandEnv, "CI") === "true") {
|
|
2019
|
-
throw new Error(`Railway CI deploy requires a project token for ${cliDeployService.serviceName ?? cliDeployService.key}. Automatic project token creation did not return a token.`);
|
|
2020
|
-
}
|
|
2021
|
-
return null;
|
|
2022
|
-
}, railwayPhaseTimeoutMs(commandEnv, "project_token"), `Railway project-token phase timed out for ${cliDeployService.serviceName ?? cliDeployService.key}.`), { service: cliDeployService.key });
|
|
2023
|
-
const linkPlan = planRailwayServiceLink(cliDeployService, { env: commandEnv });
|
|
2024
|
-
const plan = planRailwayServiceDeploy(cliDeployService, { env, projectTokenMode: usesProjectToken });
|
|
2025
|
-
const hasRailwayApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
|
|
2026
|
-
const cliConfig = configuredEnvValue(commandEnv, "CI") === "true" ? writeRailwayCliProjectConfig(cliDeployService, { env: railwayDeployEnv, cwd: plan.cwd }) : null;
|
|
2027
|
-
const effectiveLinkPlan = hasRailwayApiToken ? linkPlan : usesProjectToken ? planRailwayProjectEnvironmentLink(cliDeployService) : linkPlan;
|
|
2028
|
-
const railwayLinkEnv = hasRailwayApiToken ? buildRailwayLinkCommandEnv(commandEnv, cliDeployService) : railwayDeployEnv;
|
|
2029
|
-
writePhase("link", `Linking Railway project context for ${cliDeployService.serviceName ?? cliDeployService.serviceId ?? cliDeployService.key}.`);
|
|
2030
|
-
await timedRailwayPhase(timings, "railway:link", () => withRailwayPhaseTimeout(async () => {
|
|
2031
|
-
if (cliConfig) {
|
|
2032
|
-
write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][link] Wrote Railway CLI project context for ${cliConfig.projectPath}.`, "stdout") : null;
|
|
2033
|
-
return;
|
|
2034
|
-
}
|
|
2035
|
-
const linkResult = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...effectiveLinkPlan.args], {
|
|
2036
|
-
cwd: effectiveLinkPlan.cwd,
|
|
2037
|
-
env: railwayLinkEnv,
|
|
2038
|
-
write,
|
|
2039
|
-
prefix: { ...taskPrefix, stage: "link" }
|
|
2040
|
-
});
|
|
2041
|
-
if (linkResult.status !== 0) {
|
|
2042
|
-
throw new Error(linkResult.stderr?.trim() || linkResult.stdout?.trim() || `railway ${effectiveLinkPlan.args.join(" ")} failed with exit code ${linkResult.status ?? "unknown"} in ${effectiveLinkPlan.cwd}`);
|
|
2043
|
-
}
|
|
2044
|
-
}, railwayPhaseTimeoutMs(commandEnv, "link"), `Railway link phase timed out for ${cliDeployService.serviceName ?? cliDeployService.key}.`), { service: cliDeployService.key });
|
|
2045
|
-
await timedRailwayPhase(timings, "railway:deploy", () => withRailwayPhaseTimeout(async () => {
|
|
2046
|
-
let lastFailure = null;
|
|
2047
|
-
for (let attempt = 1; attempt <= 5; attempt += 1) {
|
|
2048
|
-
if (write && attempt === 1) {
|
|
2049
|
-
write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][deploy] $ railway ${plan.args.join(" ")}`, "stdout");
|
|
2050
|
-
}
|
|
2051
|
-
const result = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...plan.args], {
|
|
2052
|
-
cwd: plan.cwd,
|
|
2053
|
-
env: railwayDeployEnv,
|
|
2054
|
-
write,
|
|
2055
|
-
prefix: taskPrefix,
|
|
2056
|
-
timeoutMs: railwayDeployCommandTimeoutMs(commandEnv)
|
|
2057
|
-
});
|
|
2058
|
-
if (result.status === 0) {
|
|
2059
|
-
lastFailure = null;
|
|
2060
|
-
break;
|
|
2061
|
-
}
|
|
2062
|
-
lastFailure = result;
|
|
2063
|
-
if (!isRailwayTransientFailure(result) || attempt === 5) {
|
|
2064
|
-
throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${plan.args.join(" ")} failed with exit code ${result.status ?? "unknown"} in ${plan.cwd}`);
|
|
2065
|
-
}
|
|
2066
|
-
const backoffMs = 5e3 * attempt;
|
|
2067
|
-
const warning = `Railway deploy for ${deployService.serviceName ?? deployService.serviceId ?? deployService.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
|
|
2068
|
-
write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][retry] ${warning}`, "stderr") : console.warn(warning);
|
|
2069
|
-
await sleep(backoffMs);
|
|
2070
|
-
}
|
|
2071
|
-
if (lastFailure) {
|
|
2072
|
-
throw new Error(lastFailure.stderr?.trim() || lastFailure.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
|
|
2073
|
-
}
|
|
2074
|
-
}, railwayPhaseTimeoutMs(commandEnv, "deploy"), `Railway deploy phase timed out for ${cliDeployService.serviceName ?? cliDeployService.key}.`), { service: cliDeployService.key });
|
|
2075
|
-
return {
|
|
2076
|
-
service: deployService.key,
|
|
2077
|
-
status: "deployed",
|
|
2078
|
-
command: [plan.command, ...plan.args].join(" "),
|
|
2079
|
-
cwd: plan.cwd,
|
|
2080
|
-
publicBaseUrl: deployService.publicBaseUrl,
|
|
2081
|
-
timings,
|
|
2082
|
-
transport: {
|
|
2083
|
-
railway: {
|
|
2084
|
-
reconcile: "api",
|
|
2085
|
-
deploy: "cli-fallback"
|
|
2086
|
-
}
|
|
2087
|
-
},
|
|
2088
|
-
runtimeConfiguration: runtimeConfiguration ? {
|
|
2089
|
-
updated: runtimeConfiguration.updated,
|
|
2090
|
-
healthcheckPath: runtimeConfiguration.instance?.healthcheckPath ?? null,
|
|
2091
|
-
healthcheckTimeoutSeconds: runtimeConfiguration.instance?.healthcheckTimeoutSeconds ?? null,
|
|
2092
|
-
runtimeMode: runtimeConfiguration.instance?.runtimeMode ?? null,
|
|
2093
|
-
volume: runtimeConfiguration.volume ?? null
|
|
2094
|
-
} : null
|
|
2095
|
-
};
|
|
1698
|
+
throw new Error(`Railway deployment for ${cliDeployService.serviceName ?? cliDeployService.serviceId ?? cliDeployService.key} requires Railway API deployment support. CLI deploy fallback has been removed.`);
|
|
2096
1699
|
}
|
|
2097
1700
|
export {
|
|
2098
1701
|
buildRailwayCommandEnv,
|
|
2099
|
-
buildRailwayDeployCommandEnv,
|
|
2100
|
-
buildRailwayLinkCommandEnv,
|
|
2101
1702
|
collectRailwayDeploymentStatusChecks,
|
|
2102
1703
|
configuredRailwayScheduledJobs,
|
|
2103
1704
|
configuredRailwayServices,
|
|
2104
1705
|
deployRailwayService,
|
|
1706
|
+
deriveRailwayCapacityProviderRunnerServiceName,
|
|
1707
|
+
deriveRailwayCapacityProviderRunnerVolumeName,
|
|
2105
1708
|
deriveRailwayOperationsRunnerServiceName,
|
|
2106
1709
|
deriveRailwayOperationsRunnerVolumeName,
|
|
2107
1710
|
deriveRailwayWorkerRunnerServiceName,
|
|
2108
1711
|
deriveRailwayWorkerRunnerVolumeName,
|
|
2109
|
-
ensureRailwayDatabaseServiceExists,
|
|
2110
|
-
ensureRailwayEnvironmentExists,
|
|
2111
|
-
ensureRailwayProjectContext,
|
|
2112
|
-
ensureRailwayProjectExists,
|
|
2113
1712
|
ensureRailwayScheduledJobs,
|
|
2114
|
-
ensureRailwayServiceExists,
|
|
2115
1713
|
findStaleTreeseedOperationsRunnerResources,
|
|
2116
|
-
isRailwayTransientFailure,
|
|
2117
1714
|
isTreeseedOperationsRunnerResourceName,
|
|
2118
1715
|
isUsableRailwayToken,
|
|
2119
1716
|
parseRailwayJsonOutput,
|
|
2120
|
-
planRailwayServiceDeploy,
|
|
2121
|
-
planRailwayServiceLink,
|
|
2122
1717
|
railwayServiceRuntimeStartCommand,
|
|
2123
1718
|
resolveRailwayAuthToken,
|
|
2124
1719
|
resolveRailwayDeploymentProfile,
|
|
2125
|
-
runRailway,
|
|
2126
|
-
setRailwaySecretVariable,
|
|
2127
1720
|
shouldRunRailwayPredeployBuild,
|
|
2128
1721
|
validateRailwayDeployPrerequisites,
|
|
2129
1722
|
validateRailwayServiceConfiguration,
|
|
2130
1723
|
verifyRailwayManagedResources,
|
|
2131
1724
|
verifyRailwayScheduledJobs,
|
|
2132
|
-
waitForRailwayManagedDeploymentsSettled
|
|
2133
|
-
writeRailwayCliProjectConfig
|
|
1725
|
+
waitForRailwayManagedDeploymentsSettled
|
|
2134
1726
|
};
|