@supatype/cli 0.1.6 → 0.1.9
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +152 -102
- package/.turbo/turbo-typecheck.log +1 -1
- package/LICENSE +202 -0
- package/deno.d.ts +52 -0
- package/dist/app/framework.js +1 -1
- package/dist/app/framework.js.map +1 -1
- package/dist/augmentation-generator.d.ts +22 -0
- package/dist/augmentation-generator.d.ts.map +1 -1
- package/dist/augmentation-generator.js +19 -5
- package/dist/augmentation-generator.js.map +1 -1
- package/dist/binary-cache.d.ts +42 -6
- package/dist/binary-cache.d.ts.map +1 -1
- package/dist/binary-cache.js +76 -44
- package/dist/binary-cache.js.map +1 -1
- package/dist/cache-clean.d.ts +15 -0
- package/dist/cache-clean.d.ts.map +1 -0
- package/dist/cache-clean.js +76 -0
- package/dist/cache-clean.js.map +1 -0
- package/dist/cache-pins.d.ts +51 -0
- package/dist/cache-pins.d.ts.map +1 -0
- package/dist/cache-pins.js +184 -0
- package/dist/cache-pins.js.map +1 -0
- package/dist/cli-artifacts.d.ts +32 -0
- package/dist/cli-artifacts.d.ts.map +1 -0
- package/dist/cli-artifacts.js +49 -0
- package/dist/cli-artifacts.js.map +1 -0
- package/dist/cli-install-method.d.ts +27 -0
- package/dist/cli-install-method.d.ts.map +1 -0
- package/dist/cli-install-method.js +78 -0
- package/dist/cli-install-method.js.map +1 -0
- package/dist/cli-package-version.d.ts +1 -1
- package/dist/cli-package-version.d.ts.map +1 -1
- package/dist/cli-package-version.js +6 -1
- package/dist/cli-package-version.js.map +1 -1
- package/dist/cli-standalone.d.ts +13 -4
- package/dist/cli-standalone.d.ts.map +1 -1
- package/dist/cli-standalone.js +86 -31
- package/dist/cli-standalone.js.map +1 -1
- package/dist/cli-version-embedded.d.ts +10 -0
- package/dist/cli-version-embedded.d.ts.map +1 -0
- package/dist/cli-version-embedded.js +13 -0
- package/dist/cli-version-embedded.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/dist/cloud-credentials.d.ts +34 -0
- package/dist/cloud-credentials.d.ts.map +1 -0
- package/dist/cloud-credentials.js +139 -0
- package/dist/cloud-credentials.js.map +1 -0
- package/dist/commands/add.js +1 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/admin.d.ts +11 -0
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +123 -21
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/adopt.js +1 -1
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/app.js +2 -2
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/cache.d.ts +1 -1
- package/dist/commands/cache.d.ts.map +1 -1
- package/dist/commands/cache.js +69 -73
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/cloud.d.ts.map +1 -1
- package/dist/commands/cloud.js +32 -8
- package/dist/commands/cloud.js.map +1 -1
- package/dist/commands/db.d.ts +3 -2
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +149 -3
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts +9 -9
- package/dist/commands/deploy.js +12 -12
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +3 -3
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +63 -23
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts +28 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +60 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/engine.d.ts +1 -1
- package/dist/commands/engine.js +1 -1
- package/dist/commands/functions.d.ts +7 -0
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +45 -11
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +5 -1
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/hooks.d.ts +12 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +118 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +64 -30
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/internal.d.ts +6 -0
- package/dist/commands/internal.d.ts.map +1 -0
- package/dist/commands/internal.js +22 -0
- package/dist/commands/internal.js.map +1 -0
- package/dist/commands/link-helpers.d.ts.map +1 -1
- package/dist/commands/link-helpers.js +8 -2
- package/dist/commands/link-helpers.js.map +1 -1
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +110 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logs.d.ts +1 -1
- package/dist/commands/migrate.js +5 -5
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/pg.d.ts +1 -1
- package/dist/commands/pg.js +1 -1
- package/dist/commands/plugins.js +1 -1
- package/dist/commands/plugins.js.map +1 -1
- package/dist/commands/pull.js +2 -2
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +110 -7
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/self-host.d.ts +1 -1
- package/dist/commands/self-host.js +1 -1
- package/dist/commands/self-update.d.ts +3 -2
- package/dist/commands/self-update.d.ts.map +1 -1
- package/dist/commands/self-update.js +31 -16
- package/dist/commands/self-update.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/update.d.ts +1 -1
- package/dist/commands/update.js +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -4
- package/dist/config.js.map +1 -1
- package/dist/db-preflight.d.ts +78 -0
- package/dist/db-preflight.d.ts.map +1 -0
- package/dist/db-preflight.js +452 -0
- package/dist/db-preflight.js.map +1 -0
- package/dist/dev-compose.d.ts +4 -4
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +143 -88
- package/dist/dev-compose.js.map +1 -1
- package/dist/dev-log-filter.d.ts +1 -1
- package/dist/dev-log-filter.d.ts.map +1 -1
- package/dist/dev-log-filter.js +1 -1
- package/dist/dev-log-filter.js.map +1 -1
- package/dist/dev-ports.d.ts +2 -2
- package/dist/dev-ports.d.ts.map +1 -1
- package/dist/dev-ports.js +2 -2
- package/dist/dev-ports.js.map +1 -1
- package/dist/dev-session.d.ts +5 -5
- package/dist/dev-session.d.ts.map +1 -1
- package/dist/dev-session.js +6 -6
- package/dist/dev-session.js.map +1 -1
- package/dist/dev-shutdown.d.ts +5 -5
- package/dist/dev-shutdown.d.ts.map +1 -1
- package/dist/dev-shutdown.js +7 -7
- package/dist/dev-shutdown.js.map +1 -1
- package/dist/dev-task-colors.d.ts +1 -1
- package/dist/dev-task-colors.d.ts.map +1 -1
- package/dist/dev-task-colors.js +1 -1
- package/dist/dev-task-colors.js.map +1 -1
- package/dist/docker-postgres.d.ts +5 -5
- package/dist/docker-postgres.d.ts.map +1 -1
- package/dist/docker-postgres.js +5 -5
- package/dist/docker-postgres.js.map +1 -1
- package/dist/docker-runtime.d.ts +2 -2
- package/dist/docker-runtime.d.ts.map +1 -1
- package/dist/docker-runtime.js +5 -5
- package/dist/docker-runtime.js.map +1 -1
- package/dist/engine-client.d.ts +1 -1
- package/dist/engine-client.js +3 -3
- package/dist/engine-client.js.map +1 -1
- package/dist/engine-push-output.js +1 -1
- package/dist/engine-push-output.js.map +1 -1
- package/dist/ensure-binary.d.ts.map +1 -1
- package/dist/ensure-binary.js +17 -0
- package/dist/ensure-binary.js.map +1 -1
- package/dist/ensure-component-binaries.js +1 -1
- package/dist/ensure-component-binaries.js.map +1 -1
- package/dist/env-file.d.ts +40 -2
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +132 -11
- package/dist/env-file.js.map +1 -1
- package/dist/field-masking-tier.d.ts +50 -0
- package/dist/field-masking-tier.d.ts.map +1 -0
- package/dist/field-masking-tier.js +91 -0
- package/dist/field-masking-tier.js.map +1 -0
- package/dist/functions-deno-types.d.ts +24 -0
- package/dist/functions-deno-types.d.ts.map +1 -0
- package/dist/functions-deno-types.js +155 -0
- package/dist/functions-deno-types.js.map +1 -0
- package/dist/functions-router-gen.js +1 -1
- package/dist/gitignore.d.ts +2 -2
- package/dist/gitignore.d.ts.map +1 -1
- package/dist/gitignore.js +3 -3
- package/dist/gitignore.js.map +1 -1
- package/dist/hook-upload.d.ts +30 -0
- package/dist/hook-upload.d.ts.map +1 -0
- package/dist/hook-upload.js +86 -0
- package/dist/hook-upload.js.map +1 -0
- package/dist/hooks-generator.d.ts +8 -0
- package/dist/hooks-generator.d.ts.map +1 -0
- package/dist/hooks-generator.js +332 -0
- package/dist/hooks-generator.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/init-project-detect.d.ts +1 -1
- package/dist/init-project-detect.d.ts.map +1 -1
- package/dist/init-project-detect.js +1 -1
- package/dist/init-project-detect.js.map +1 -1
- package/dist/link.d.ts +4 -0
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +2 -0
- package/dist/link.js.map +1 -1
- package/dist/local-secrets.d.ts +71 -0
- package/dist/local-secrets.d.ts.map +1 -0
- package/dist/local-secrets.js +100 -0
- package/dist/local-secrets.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +20 -0
- package/dist/main.js.map +1 -0
- package/dist/model-hooks.d.ts +73 -0
- package/dist/model-hooks.d.ts.map +1 -0
- package/dist/model-hooks.js +211 -0
- package/dist/model-hooks.js.map +1 -0
- package/dist/pgbouncer-userlist.d.ts +1 -1
- package/dist/pgbouncer-userlist.d.ts.map +1 -1
- package/dist/pgbouncer-userlist.js +2 -2
- package/dist/pgbouncer-userlist.js.map +1 -1
- package/dist/postgres-ctl.d.ts +12 -1
- package/dist/postgres-ctl.d.ts.map +1 -1
- package/dist/postgres-ctl.js +28 -5
- package/dist/postgres-ctl.js.map +1 -1
- package/dist/process-manager.d.ts +2 -2
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +4 -4
- package/dist/process-manager.js.map +1 -1
- package/dist/project-config.d.ts +122 -2
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +150 -1
- package/dist/project-config.js.map +1 -1
- package/dist/pull-utils.d.ts +2 -2
- package/dist/pull-utils.d.ts.map +1 -1
- package/dist/pull-utils.js +4 -4
- package/dist/pull-utils.js.map +1 -1
- package/dist/realtime-launch.js +1 -1
- package/dist/realtime-launch.js.map +1 -1
- package/dist/release-pins.d.ts +1 -1
- package/dist/release-pins.js +2 -2
- package/dist/release-pins.js.map +1 -1
- package/dist/resolve-api-url.js +1 -1
- package/dist/resolve-api-url.js.map +1 -1
- package/dist/resolve-target.d.ts +4 -0
- package/dist/resolve-target.d.ts.map +1 -1
- package/dist/resolve-target.js +69 -73
- package/dist/resolve-target.js.map +1 -1
- package/dist/rest-cache-admin.js +2 -2
- package/dist/rest-cache-admin.js.map +1 -1
- package/dist/runtime-routes.d.ts +1 -1
- package/dist/runtime-routes.js +1 -1
- package/dist/schema-ast-v2.d.ts +5 -4
- package/dist/schema-ast-v2.d.ts.map +1 -1
- package/dist/schema-ast-v2.js +5 -3
- package/dist/schema-ast-v2.js.map +1 -1
- package/dist/schema-push-lock.d.ts.map +1 -1
- package/dist/schema-push-lock.js +43 -16
- package/dist/schema-push-lock.js.map +1 -1
- package/dist/scripts/postinstall.d.ts +1 -1
- package/dist/scripts/postinstall.js +1 -1
- package/dist/self-host-compose.d.ts +26 -2
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +305 -73
- package/dist/self-host-compose.js.map +1 -1
- package/dist/service-role-check.d.ts +21 -0
- package/dist/service-role-check.d.ts.map +1 -0
- package/dist/service-role-check.js +85 -0
- package/dist/service-role-check.js.map +1 -0
- package/dist/storage-provision.d.ts +1 -1
- package/dist/storage-provision.js +3 -3
- package/dist/storage-provision.js.map +1 -1
- package/dist/studio-dev-server.d.ts +1 -1
- package/dist/studio-dev-server.d.ts.map +1 -1
- package/dist/systemd.d.ts +1 -1
- package/dist/systemd.js +1 -1
- package/dist/target-client.d.ts +17 -0
- package/dist/target-client.d.ts.map +1 -1
- package/dist/target-client.js +69 -17
- package/dist/target-client.js.map +1 -1
- package/dist/tsx-runner.js +1 -1
- package/dist/tsx-runner.js.map +1 -1
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +738 -34
- package/dist/type-extractor.js.map +1 -1
- package/dist/type-resolver.js +1 -1
- package/dist/type-resolver.js.map +1 -1
- package/dist/ui/brand.d.ts +1 -1
- package/dist/ui/brand.js +1 -1
- package/dist/ui/components/LogoWordmark.d.ts +1 -1
- package/dist/ui/components/LogoWordmark.d.ts.map +1 -1
- package/dist/ui/components/LogoWordmark.js +1 -1
- package/dist/ui/components/LogoWordmark.js.map +1 -1
- package/dist/ui/components/SelectField.js +1 -1
- package/dist/ui/components/SelectField.js.map +1 -1
- package/dist/ui/confirm.d.ts +1 -1
- package/dist/ui/confirm.js +1 -1
- package/dist/ui/fatal.d.ts +1 -1
- package/dist/ui/fatal.d.ts.map +1 -1
- package/dist/ui/fatal.js +1 -1
- package/dist/ui/fatal.js.map +1 -1
- package/dist/ui/flows/prompt-fields.js +1 -1
- package/dist/ui/flows/prompt-fields.js.map +1 -1
- package/dist/ui/interactive.d.ts +1 -1
- package/dist/ui/interactive.d.ts.map +1 -1
- package/dist/ui/interactive.js +1 -1
- package/dist/ui/interactive.js.map +1 -1
- package/dist/ui/progress.d.ts +1 -1
- package/dist/ui/progress.js +1 -1
- package/dist/ui/runtime/command-chrome.js +2 -2
- package/dist/ui/runtime/command-chrome.js.map +1 -1
- package/dist/ui/runtime/run-clack-flow.js +1 -1
- package/dist/ui/runtime/run-clack-flow.js.map +1 -1
- package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -1
- package/dist/ui/runtime/stdin-after-ink.js +4 -2
- package/dist/ui/runtime/stdin-after-ink.js.map +1 -1
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +1 -1
- package/dist/valkey-sidecar.d.ts +1 -1
- package/dist/valkey-sidecar.d.ts.map +1 -1
- package/dist/valkey-sidecar.js +2 -2
- package/dist/valkey-sidecar.js.map +1 -1
- package/package.json +6 -2
- package/scripts/build-release-artifacts.sh +112 -0
- package/scripts/generate-homebrew-formula.mjs +123 -0
- package/scripts/mirror-deno-release.sh +1 -1
- package/src/TYPE-RESOLUTION.md +31 -31
- package/src/app/framework.ts +1 -1
- package/src/augmentation-generator.ts +19 -6
- package/src/binary-cache.ts +94 -47
- package/src/cache-clean.ts +81 -0
- package/src/cache-pins.ts +243 -0
- package/src/cli-artifacts.ts +65 -0
- package/src/cli-install-method.ts +87 -0
- package/src/cli-package-version.ts +5 -1
- package/src/cli-standalone.ts +116 -34
- package/src/cli-version-embedded.ts +12 -0
- package/src/cli.ts +7 -1
- package/src/cloud-credentials.ts +183 -0
- package/src/commands/add.ts +1 -1
- package/src/commands/admin.ts +142 -27
- package/src/commands/adopt.ts +1 -1
- package/src/commands/app.ts +2 -2
- package/src/commands/cache.ts +92 -77
- package/src/commands/cloud.ts +32 -8
- package/src/commands/db.ts +164 -3
- package/src/commands/deploy.ts +12 -12
- package/src/commands/dev.ts +72 -23
- package/src/commands/doctor.ts +69 -3
- package/src/commands/engine.ts +1 -1
- package/src/commands/functions.ts +47 -10
- package/src/commands/generate.ts +5 -1
- package/src/commands/hooks.ts +138 -0
- package/src/commands/init.ts +65 -31
- package/src/commands/internal.ts +23 -0
- package/src/commands/link-helpers.ts +9 -2
- package/src/commands/login.ts +127 -0
- package/src/commands/logs.ts +1 -1
- package/src/commands/migrate.ts +5 -5
- package/src/commands/pg.ts +1 -1
- package/src/commands/plugins.ts +1 -1
- package/src/commands/pull.ts +2 -2
- package/src/commands/push.ts +124 -7
- package/src/commands/self-host.ts +1 -1
- package/src/commands/self-update.ts +41 -19
- package/src/commands/status.ts +1 -1
- package/src/commands/update.ts +1 -1
- package/src/config.ts +23 -4
- package/src/db-preflight.ts +575 -0
- package/src/dev-compose.ts +158 -89
- package/src/dev-log-filter.ts +1 -1
- package/src/dev-ports.ts +3 -3
- package/src/dev-session.ts +6 -6
- package/src/dev-shutdown.ts +8 -8
- package/src/dev-task-colors.ts +1 -1
- package/src/docker-postgres.ts +6 -6
- package/src/docker-runtime.ts +5 -5
- package/src/engine-client.ts +3 -3
- package/src/engine-push-output.ts +1 -1
- package/src/ensure-binary.ts +20 -0
- package/src/ensure-component-binaries.ts +1 -1
- package/src/env-file.ts +157 -11
- package/src/field-masking-tier.ts +107 -0
- package/src/functions-deno-types.ts +188 -0
- package/src/functions-router-gen.ts +1 -1
- package/src/gitignore.ts +3 -3
- package/src/hook-upload.ts +107 -0
- package/src/hooks-generator.ts +352 -0
- package/src/index.ts +1 -1
- package/src/init-project-detect.ts +1 -1
- package/src/link.ts +7 -0
- package/src/local-secrets.ts +104 -0
- package/src/main.ts +20 -0
- package/src/model-hooks.ts +260 -0
- package/src/pgbouncer-userlist.ts +2 -2
- package/src/postgres-ctl.ts +32 -5
- package/src/process-manager.ts +4 -4
- package/src/project-config.ts +237 -3
- package/src/pull-utils.ts +4 -4
- package/src/realtime-launch.ts +1 -1
- package/src/release-pins.ts +2 -2
- package/src/resolve-api-url.ts +1 -1
- package/src/resolve-target.ts +113 -68
- package/src/rest-cache-admin.ts +2 -2
- package/src/runtime-routes.ts +2 -2
- package/src/schema-ast-v2.ts +8 -5
- package/src/schema-push-lock.ts +56 -17
- package/src/scripts/postinstall.ts +1 -1
- package/src/self-host-compose.ts +348 -72
- package/src/service-role-check.ts +111 -0
- package/src/storage-provision.ts +3 -3
- package/src/studio-dev-server.ts +1 -1
- package/src/systemd.ts +1 -1
- package/src/target-client.ts +105 -18
- package/src/tsx-runner.ts +1 -1
- package/src/type-extractor.ts +885 -30
- package/src/type-resolver.ts +1 -1
- package/src/ui/README.md +1 -1
- package/src/ui/brand.ts +1 -1
- package/src/ui/components/LogoWordmark.tsx +1 -1
- package/src/ui/components/SelectField.tsx +1 -1
- package/src/ui/confirm.ts +1 -1
- package/src/ui/fatal.ts +1 -1
- package/src/ui/flows/prompt-fields.tsx +1 -1
- package/src/ui/interactive.ts +1 -1
- package/src/ui/progress.ts +1 -1
- package/src/ui/runtime/command-chrome.ts +2 -2
- package/src/ui/runtime/run-clack-flow.tsx +1 -1
- package/src/ui/runtime/stdin-after-ink.ts +4 -2
- package/src/ui/theme.ts +1 -1
- package/src/valkey-sidecar.ts +2 -2
- package/tests/access-composition.test.ts +667 -0
- package/tests/admin-studio-membership.test.ts +121 -0
- package/tests/api-schemas.test.ts +83 -0
- package/tests/archive-name-alias.test.ts +42 -0
- package/tests/augmentation-generator.test.ts +28 -0
- package/tests/cache-clean.test.ts +206 -0
- package/tests/cli-help.test.ts +11 -2
- package/tests/cli-install-method.test.ts +66 -0
- package/tests/command-chrome-coverage.test.ts +31 -26
- package/tests/command-chrome-wrap.test.ts +1 -0
- package/tests/db-preflight.test.ts +72 -0
- package/tests/doctor-render.test.ts +62 -0
- package/tests/doctor-service-role.test.ts +55 -0
- package/tests/engine-push-output.test.ts +1 -1
- package/tests/env-file.test.ts +121 -0
- package/tests/external-database-compose.test.ts +184 -0
- package/tests/external-database-config.test.ts +154 -0
- package/tests/field-masking-tier.test.ts +184 -0
- package/tests/functions-deno-types.test.ts +197 -0
- package/tests/homebrew-formula.test.ts +100 -0
- package/tests/hook-upload.test.ts +125 -0
- package/tests/hooks-generator.test.ts +212 -0
- package/tests/init.test.ts +5 -2
- package/tests/keys.test.ts +8 -2
- package/tests/local-secrets.test.ts +92 -0
- package/tests/model-hooks.test.ts +322 -0
- package/tests/runtime-contract.test.ts +113 -1
- package/tests/service-role-check.test.ts +109 -0
- package/tests/service-role-routes.test.ts +51 -0
- package/tests/storage-provision.test.ts +1 -1
- package/tests/target-client-refresh.test.ts +94 -0
- package/tests/type-extractor.test.ts +187 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
- package/scripts/build-release-bundle.mjs +0 -27
- package/tests/engine-distribution.test.ts +0 -418
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type DockerBrandOptions } from "./docker-runtime.js";
|
|
2
2
|
import { type SupatypeProjectConfig } from "./project-config.js";
|
|
3
|
+
import { type FieldMaskingTier } from "./field-masking-tier.js";
|
|
3
4
|
/** Env keys written when `versions` pins exist in supatype.config.ts. */
|
|
4
5
|
export declare const COMPOSE_PINNED_IMAGE_ENV_KEYS: readonly ["SUPATYPE_ENGINE_IMAGE", "SUPATYPE_SERVER_IMAGE", "SUPATYPE_POSTGRES_IMAGE"];
|
|
5
6
|
/** Compose image env vars that may be overridden manually in `.env`. */
|
|
@@ -23,7 +24,7 @@ export declare function composePullNeedsIgnoreFailures(config: SupatypeProjectCo
|
|
|
23
24
|
/**
|
|
24
25
|
* Schema-engine image for a one-off `docker compose run` when pushing schema.
|
|
25
26
|
* Uses config pin when set; otherwise CDN engine semver (Docker Hub `:latest` can lag).
|
|
26
|
-
* Does not touch `.env
|
|
27
|
+
* Does not touch `.env`, server/postgres still use compose `:latest` defaults.
|
|
27
28
|
*/
|
|
28
29
|
export declare function schemaEngineImageForPush(config: SupatypeProjectConfig): Promise<string | undefined>;
|
|
29
30
|
export interface SelfHostComposePaths {
|
|
@@ -40,8 +41,31 @@ export declare const COMPOSE_STUDIO_HOST_URL = "http://host.docker.internal:3002
|
|
|
40
41
|
export interface SelfHostComposeOptions {
|
|
41
42
|
/** `supatype dev` with provider docker: internal-only db/server; Kong on host :18473. */
|
|
42
43
|
devLocal?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Which mechanism enforces per-column rules, when the caller knows.
|
|
46
|
+
*
|
|
47
|
+
* Only the call sites that have loaded the schema can say, see `field-masking-tier.ts`. Left
|
|
48
|
+
* unset, the exposed schema list is today's, which is correct for every project without field
|
|
49
|
+
* rules and for every project on `supatype/postgres`.
|
|
50
|
+
*/
|
|
51
|
+
fieldMaskingTier?: FieldMaskingTier;
|
|
43
52
|
}
|
|
44
53
|
export declare function renderSelfHostCompose(config: SupatypeProjectConfig, cwd?: string, options?: SelfHostComposeOptions): string;
|
|
54
|
+
/**
|
|
55
|
+
* A loopback host in the external URL cannot work from inside a container.
|
|
56
|
+
*
|
|
57
|
+
* `127.0.0.1` means "this container" to every service in the stack, so an external database on the
|
|
58
|
+
* host machine is unreachable, while the *CLI* reaches it fine, because the CLI runs on the host.
|
|
59
|
+
* That asymmetry is the trap: `supatype db check` passes, `push` applies the schema, and then
|
|
60
|
+
* storage, realtime and the server all die with ECONNREFUSED against their own loopback. Found by
|
|
61
|
+
* rehearsing exactly that.
|
|
62
|
+
*
|
|
63
|
+
* Refused rather than rewritten. The compose file interpolates one `${DATABASE_URL}` for every
|
|
64
|
+
* service, so silently substituting a different host would mean the CLI and the stack no longer
|
|
65
|
+
* agree about which database they are talking to, the thing every other check here exists to
|
|
66
|
+
* prevent.
|
|
67
|
+
*/
|
|
68
|
+
export declare function loopbackExternalHost(config: SupatypeProjectConfig): string | undefined;
|
|
45
69
|
export declare function writeSelfHostCompose(cwd: string, config: SupatypeProjectConfig, options?: SelfHostComposeOptions): SelfHostComposePaths;
|
|
46
70
|
export interface RunDockerComposeOptions {
|
|
47
71
|
/** Suppress docker compose progress UI (container status lines). */
|
|
@@ -52,7 +76,7 @@ export interface RunDockerComposeOptions {
|
|
|
52
76
|
/** Exit with a friendly compose failure message. */
|
|
53
77
|
export declare function exitComposeFailed(status: number, context: string, brand?: DockerBrandOptions): never;
|
|
54
78
|
export declare function runDockerCompose(composePath: string, args: string[], projectRoot?: string, composeProject?: string, options?: RunDockerComposeOptions): number;
|
|
55
|
-
/** Compose project name for a Supatype project
|
|
79
|
+
/** Compose project name for a Supatype project, isolates docker state per project. */
|
|
56
80
|
export declare function composeProjectName(projectName: string): string;
|
|
57
81
|
export {};
|
|
58
82
|
//# sourceMappingURL=self-host-compose.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-host-compose.d.ts","sourceRoot":"","sources":["../src/self-host-compose.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAElF,OAAO,
|
|
1
|
+
{"version":3,"file":"self-host-compose.d.ts","sourceRoot":"","sources":["../src/self-host-compose.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAElF,OAAO,EASL,KAAK,qBAAqB,EAC3B,MAAM,qBAAqB,CAAA;AAI5B,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE5F,yEAAyE;AACzE,eAAO,MAAM,6BAA6B,wFAIhC,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,qOAOzB,CAAA;AAEV,KAAK,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAA;AAE1D,gEAAgE;AAChE,wBAAgB,cAAc,CAC5B,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,qBAAqB,GAC7B,MAAM,CAeR;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAe3F;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ/D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAS1E;AAcD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAGT;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM7B;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAQtE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAIvF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAIrF;AAiED,oEAAoE;AACpE,eAAO,MAAM,uBAAuB,qCAAqC,CAAA;AAwCzE,MAAM,WAAW,sBAAsB;IACrC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,EAC7B,GAAG,GAAE,MAAsB,EAC3B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CA+UR;AAoGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,SAAS,CAiBtF;AAwCD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,qBAAqB,EAC7B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,oBAAoB,CAgCtB;AAED,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,4DAA4D;IAC5D,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,kBAAkB,GACzB,KAAK,CAMP;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,GAAE,MAAsB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,OAAO,CAAC,EAAE,uBAAuB,GAChC,MAAM,CAsCR;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAG9D"}
|
|
@@ -3,9 +3,11 @@ import { dirname, join, relative, resolve } from "node:path";
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { requireDockerDaemon } from "./docker-runtime.js";
|
|
5
5
|
import { fatalError } from "./ui/fatal.js";
|
|
6
|
-
import { preferredFunctionsPathFromProject, selfHostTlsEnabled } from "./project-config.js";
|
|
6
|
+
import { apiSchemaList, externalDatabaseUrl, hooksPathFromProject, preferredFunctionsPathFromProject, realtimeEnabled, serviceRoleRoutes, selfHostTlsEnabled, usesExternalDatabase, } from "./project-config.js";
|
|
7
7
|
import { hasEngineOverride, hasStudioOverride, pinnedVersion, fetchLatestVersion, VERSION_PIN_LOCAL } from "./binary-cache.js";
|
|
8
8
|
import { buildKongDeclarative } from "./kong-config.js";
|
|
9
|
+
import { readEnvFile } from "./env-file.js";
|
|
10
|
+
import { fieldMaskingTierFromProject } from "./field-masking-tier.js";
|
|
9
11
|
/** Env keys written when `versions` pins exist in supatype.config.ts. */
|
|
10
12
|
export const COMPOSE_PINNED_IMAGE_ENV_KEYS = [
|
|
11
13
|
"SUPATYPE_ENGINE_IMAGE",
|
|
@@ -108,7 +110,7 @@ export function composePullNeedsIgnoreFailures(config, cwd = process.cwd()) {
|
|
|
108
110
|
/**
|
|
109
111
|
* Schema-engine image for a one-off `docker compose run` when pushing schema.
|
|
110
112
|
* Uses config pin when set; otherwise CDN engine semver (Docker Hub `:latest` can lag).
|
|
111
|
-
* Does not touch `.env
|
|
113
|
+
* Does not touch `.env`, server/postgres still use compose `:latest` defaults.
|
|
112
114
|
*/
|
|
113
115
|
export async function schemaEngineImageForPush(config) {
|
|
114
116
|
const pinned = pinnedVersion("engine", config);
|
|
@@ -143,7 +145,7 @@ export function staticDirForCompose(config) {
|
|
|
143
145
|
/**
|
|
144
146
|
* Bind-mount source for `/project` in generated compose files.
|
|
145
147
|
* Paths are resolved from `--project-directory` (always the project root in `runDockerCompose`),
|
|
146
|
-
* not from the compose file directory
|
|
148
|
+
* not from the compose file directory, use `.` not `../..`.
|
|
147
149
|
*/
|
|
148
150
|
function projectMountPath(_cwd) {
|
|
149
151
|
return ".";
|
|
@@ -159,9 +161,45 @@ function relativeFromProjectRoot(cwd, target) {
|
|
|
159
161
|
function kongMountPath(_cwd) {
|
|
160
162
|
return ".supatype/self-host/kong.yml";
|
|
161
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* The DSN every service uses for the schema-owning role.
|
|
166
|
+
*
|
|
167
|
+
* One expression instead of six identical constructions of `@db:5432`. With an external database it
|
|
168
|
+
* becomes `${DATABASE_URL:?…}`: the URL is the operator's, so there is nothing for the generator to
|
|
169
|
+
* build: and interpolating the value into the compose file would write a password into a generated
|
|
170
|
+
* file. Compose resolves the variable from `.env` at up-time, the same place the config's
|
|
171
|
+
* `process.env.DATABASE_URL` read it from.
|
|
172
|
+
*/
|
|
173
|
+
function ownerDatabaseUrl(config, scheme = "postgresql") {
|
|
174
|
+
if (usesExternalDatabase(config)) {
|
|
175
|
+
return "${DATABASE_URL:?DATABASE_URL is missing from .env, required by database.external}";
|
|
176
|
+
}
|
|
177
|
+
return (`${scheme}://\${POSTGRES_USER:-supatype_admin}:` +
|
|
178
|
+
"\${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is missing from .env}" +
|
|
179
|
+
"@db:5432/\${POSTGRES_DB:-supatype}");
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* PostgREST's DSN, which connects as `authenticator` rather than the owner.
|
|
183
|
+
*
|
|
184
|
+
* For an external database the host, port, database and query string are taken from the operator's
|
|
185
|
+
* URL and only the password stays a variable. The alternative, a second full URL in `.env`, is one
|
|
186
|
+
* more thing to keep in step with the first, and two URLs that disagree about *which database* is a
|
|
187
|
+
* split-brain nobody notices until the API is serving one and migrations are landing in the other.
|
|
188
|
+
* A hostname is not the secret here; the password is, and it stays out of the generated file.
|
|
189
|
+
*/
|
|
190
|
+
function postgrestDatabaseUrl(config) {
|
|
191
|
+
const password = "${AUTHENTICATOR_PASSWORD:?AUTHENTICATOR_PASSWORD is missing from .env}";
|
|
192
|
+
const externalUrl = externalDatabaseUrl(config);
|
|
193
|
+
if (externalUrl === undefined) {
|
|
194
|
+
return `postgresql://authenticator:${password}@db:5432/\${POSTGRES_DB:-supatype}`;
|
|
195
|
+
}
|
|
196
|
+
const parsed = new URL(externalUrl);
|
|
197
|
+
const port = parsed.port ? `:${parsed.port}` : "";
|
|
198
|
+
return `postgresql://authenticator:${password}@${parsed.hostname}${port}${parsed.pathname}${parsed.search}`;
|
|
199
|
+
}
|
|
162
200
|
/** Host Vite dev server as seen from Kong inside Docker Compose. */
|
|
163
201
|
export const COMPOSE_STUDIO_HOST_URL = "http://host.docker.internal:3002";
|
|
164
|
-
/** Studio container
|
|
202
|
+
/** Studio container: always Docker Hub unless SUPATYPE_STUDIO_IMAGE is set in .env. */
|
|
165
203
|
function studioServiceBlock() {
|
|
166
204
|
return ` image: \${SUPATYPE_STUDIO_IMAGE:-supatype/studio:latest}`;
|
|
167
205
|
}
|
|
@@ -200,6 +238,14 @@ function serverAppEnvForCompose(config, devLocal) {
|
|
|
200
238
|
export function renderSelfHostCompose(config, cwd = process.cwd(), options) {
|
|
201
239
|
const projectMount = projectMountPath(cwd);
|
|
202
240
|
const kongMount = kongMountPath(cwd);
|
|
241
|
+
const external = usesExternalDatabase(config);
|
|
242
|
+
const ownerUrl = ownerDatabaseUrl(config);
|
|
243
|
+
// GoTrue's driver wants the `postgres://` spelling; an external URL is used as given.
|
|
244
|
+
const gotrueUrl = external ? ownerUrl : ownerDatabaseUrl(config, "postgres");
|
|
245
|
+
// An external URL may already carry query parameters (`?sslmode=require` is common on managed
|
|
246
|
+
// providers), and appending a second `?` produces a DSN that fails to parse.
|
|
247
|
+
const gotrueSearchPathSeparator = externalDatabaseUrl(config)?.includes("?") ? "&" : "?";
|
|
248
|
+
const postgrestUrl = postgrestDatabaseUrl(config);
|
|
203
249
|
const devLocal = options?.devLocal === true;
|
|
204
250
|
const tlsEnabled = selfHostTlsEnabled(config, devLocal);
|
|
205
251
|
const domain = config.server.domain?.trim() ?? "";
|
|
@@ -274,60 +320,122 @@ ${studioService}
|
|
|
274
320
|
# server: { mode: "standalone", domain: "your.domain", tls: { email: "you@example.com" } }
|
|
275
321
|
# then re-run \`supatype self-host compose up -d\`. Kong publishes :80/:443 and provisions certs automatically.
|
|
276
322
|
`;
|
|
323
|
+
// An external database is not ours to declare a volume for.
|
|
277
324
|
const volumesBlock = `volumes:
|
|
278
|
-
db-data:
|
|
279
|
-
minio-data:
|
|
325
|
+
${external ? "" : " db-data:\n"} minio-data:
|
|
280
326
|
valkey-data:
|
|
281
327
|
`;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
328
|
+
// `depends_on` for the services that talk to Postgres. With an external database there is no
|
|
329
|
+
// container to wait on, so the clause disappears entirely and each service retries on connect
|
|
330
|
+
// instead: which is also what covers a database that restarts *after* boot, something no
|
|
331
|
+
// healthcheck ever did.
|
|
332
|
+
const dbDependencyClause = external
|
|
333
|
+
? ""
|
|
334
|
+
: ` db:
|
|
335
|
+
condition: service_healthy
|
|
336
|
+
`;
|
|
337
|
+
const dbDependency = external ? "" : ` depends_on:\n${dbDependencyClause}`;
|
|
338
|
+
// Realtime, omitted entirely when the project has turned it off.
|
|
339
|
+
//
|
|
340
|
+
// Not started-and-disabled: the service degrades gracefully on its own (it reports the reason on
|
|
341
|
+
// /health/ready rather than crash-looping), so this switch is for the operator who has read
|
|
342
|
+
// `supatype db check`, knows their database cannot do logical decoding, and would rather not run a
|
|
343
|
+
// container that can only report that. The server then has no realtime URL, which is what makes
|
|
344
|
+
// subscription requests fail with a clear route error instead of hanging against a dead upstream.
|
|
345
|
+
const realtime = realtimeEnabled(config);
|
|
346
|
+
const realtimeBlock = realtime
|
|
347
|
+
? ` realtime:
|
|
348
|
+
image: \${SUPATYPE_REALTIME_IMAGE:-supatype/realtime:latest}
|
|
349
|
+
expose:
|
|
350
|
+
- "4000"
|
|
351
|
+
environment:
|
|
352
|
+
PORT: "4000"
|
|
353
|
+
DATABASE_URL: "${ownerUrl}"
|
|
354
|
+
JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
|
|
355
|
+
SLOT_NAME: supatype_realtime
|
|
356
|
+
# Matches the publication the supatype/postgres image creates. Read by nothing today,
|
|
357
|
+
# wal2json decodes from the slot, and kept for a future pgoutput decoder.
|
|
358
|
+
PUBLICATION_NAME: supatype_realtime
|
|
359
|
+
${dbDependency}`
|
|
360
|
+
: ` # No \`realtime\` service: database.external.realtime is false. Subscriptions are
|
|
361
|
+
# unavailable; REST, storage, auth and functions are unaffected.
|
|
362
|
+
`;
|
|
363
|
+
const realtimeDependency = realtime
|
|
364
|
+
? ` realtime:
|
|
365
|
+
condition: service_started
|
|
366
|
+
`
|
|
367
|
+
: "";
|
|
368
|
+
const realtimeServerEnv = realtime ? " SUPATYPE_REALTIME_URL: http://realtime:4000" : "";
|
|
369
|
+
const dbServiceBlock = external
|
|
370
|
+
? ` # No \`db\` service: database.external points this stack at a Postgres it does not manage.
|
|
371
|
+
# Every service reads \${DATABASE_URL} from .env, and \`supatype db check\` reports what that
|
|
372
|
+
# database still needs (roles, extensions, wal_level for realtime).
|
|
373
|
+
`
|
|
374
|
+
: ` db:
|
|
286
375
|
image: \${SUPATYPE_POSTGRES_IMAGE:-supatype/postgres:latest}
|
|
287
376
|
environment:
|
|
288
377
|
POSTGRES_USER: \${POSTGRES_USER:-supatype_admin}
|
|
289
|
-
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD
|
|
378
|
+
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is missing from .env}
|
|
290
379
|
POSTGRES_DB: \${POSTGRES_DB:-supatype}
|
|
380
|
+
# Read by the image's init to password the \`authenticator\` role PostgREST connects as.
|
|
381
|
+
AUTHENTICATOR_PASSWORD: \${AUTHENTICATOR_PASSWORD:?AUTHENTICATOR_PASSWORD is missing from .env}
|
|
291
382
|
${dbPorts} volumes:
|
|
292
383
|
- db-data:/var/lib/postgresql/data
|
|
293
384
|
healthcheck:
|
|
294
|
-
|
|
385
|
+
# -h 127.0.0.1 forces TCP. Without it \`pg_isready\` uses the Unix socket, which the
|
|
386
|
+
# entrypoint's temporary init server is already listening on while TCP is still refused,
|
|
387
|
+
# so the container reported healthy, \`depends_on: service_healthy\` released, and every
|
|
388
|
+
# service that connects over the network died with ECONNREFUSED on first boot. PostgREST
|
|
389
|
+
# survived only because it retries. Observed on a clean stack: server, storage and
|
|
390
|
+
# realtime all exited 1 while db said "healthy".
|
|
391
|
+
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U \${POSTGRES_USER:-supatype_admin} -d \${POSTGRES_DB:-supatype}"]
|
|
295
392
|
interval: 5s
|
|
296
393
|
timeout: 5s
|
|
394
|
+
# First boot runs initdb plus every bootstrap migration. Failures inside the start period
|
|
395
|
+
# do not count against retries, so a slow init waits rather than being declared unhealthy.
|
|
396
|
+
start_period: 90s
|
|
297
397
|
retries: 20
|
|
298
398
|
|
|
299
|
-
|
|
399
|
+
`;
|
|
400
|
+
return `# Generated by supatype self-host compose
|
|
401
|
+
# Kong → supatype-server (unified gateway) → internal PostgREST / storage / etc.
|
|
402
|
+
services:
|
|
403
|
+
${dbServiceBlock} postgrest:
|
|
300
404
|
image: postgrest/postgrest:v12.2.8
|
|
301
405
|
expose:
|
|
302
406
|
- "3000"
|
|
303
407
|
environment:
|
|
304
|
-
|
|
305
|
-
|
|
408
|
+
# Connects as \`authenticator\`, not \${POSTGRES_USER}, which is a superuser, and a
|
|
409
|
+
# superuser session may SET ROLE to any role in the cluster, so a request whose JWT
|
|
410
|
+
# named one got it. \`authenticator\` is NOINHERIT with membership in only
|
|
411
|
+
# anon/authenticated/service_role, so the same SET ROLE is refused.
|
|
412
|
+
#
|
|
413
|
+
# Its own credential, not POSTGRES_PASSWORD: yours is for direct SQL access and
|
|
414
|
+
# rotating it must not take the REST API down. \`supatype init\` generates this.
|
|
415
|
+
PGRST_DB_URI: ${postgrestUrl}
|
|
416
|
+
# Derived from schema.pg_schema (or schema.api_schemas). Hardcoding this is why choosing a
|
|
417
|
+
# non-public pg_schema used to give a correct push and an API that answered PGRST106 for
|
|
418
|
+
# everything: the engine moved and PostgREST was never told.
|
|
419
|
+
PGRST_DB_SCHEMA: "${apiSchemaList(config, options?.fieldMaskingTier)}"
|
|
306
420
|
PGRST_DB_ANON_ROLE: anon
|
|
307
|
-
PGRST_JWT_SECRET: \${JWT_SECRET
|
|
421
|
+
PGRST_JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
|
|
308
422
|
PGRST_DB_EXTRA_SEARCH_PATH: public,extensions
|
|
309
423
|
PGRST_DB_POOL: 3
|
|
310
|
-
|
|
311
|
-
db:
|
|
312
|
-
condition: service_healthy
|
|
313
|
-
|
|
424
|
+
${dbDependency}
|
|
314
425
|
storage:
|
|
315
426
|
image: \${SUPATYPE_STORAGE_IMAGE:-supatype/storage:latest}
|
|
316
427
|
expose:
|
|
317
428
|
- "5000"
|
|
318
429
|
environment:
|
|
319
430
|
PORT: 5000
|
|
320
|
-
DATABASE_URL: "
|
|
321
|
-
JWT_SECRET: \${JWT_SECRET
|
|
431
|
+
DATABASE_URL: "${ownerUrl}"
|
|
432
|
+
JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
|
|
322
433
|
S3_ENDPOINT: http://minio:9000
|
|
323
434
|
S3_REGION: us-east-1
|
|
324
435
|
S3_ACCESS_KEY: supatype
|
|
325
436
|
S3_SECRET_KEY: supatype-secret
|
|
326
437
|
S3_FORCE_PATH_STYLE: "true"
|
|
327
|
-
|
|
328
|
-
db:
|
|
329
|
-
condition: service_healthy
|
|
330
|
-
|
|
438
|
+
${dbDependency}
|
|
331
439
|
functions-worker:
|
|
332
440
|
image: \${SUPATYPE_FUNCTIONS_WORKER_IMAGE:-supatype/functions-worker:latest}
|
|
333
441
|
expose:
|
|
@@ -337,31 +445,26 @@ ${dbPorts} volumes:
|
|
|
337
445
|
environment:
|
|
338
446
|
SUPATYPE_FUNCTIONS_ROOT: /project/functions
|
|
339
447
|
SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
|
|
448
|
+
# Model hooks, served by this same worker under a hooks/ route the gateway refuses from
|
|
449
|
+
# outside. One worker rather than two: a second container would cost a pod per project on
|
|
450
|
+
# cloud, for isolation the route boundary already provides.
|
|
451
|
+
SUPATYPE_HOOKS_ROOT: /project/hooks
|
|
340
452
|
PORT: "8001"
|
|
341
|
-
|
|
453
|
+
# In-compose loopback to Kong (not API_EXTERNAL_URL / localhost, unreachable from this container).
|
|
454
|
+
SUPATYPE_URL: http://kong:8000
|
|
455
|
+
SUPATYPE_INTERNAL_URL: http://kong:8000
|
|
342
456
|
SUPATYPE_ANON_KEY: \${ANON_KEY:-}
|
|
457
|
+
# Present so the worker can hand it to hooks, which are procedural and unreachable from
|
|
458
|
+
# outside: and to the public functions named below. Withheld from every other handler before
|
|
459
|
+
# any of them is imported: a function is a public endpoint, and an ambient admin credential made
|
|
460
|
+
# each one able to read past every access rule in the schema.
|
|
343
461
|
SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
|
|
462
|
+
SUPATYPE_SERVICE_ROLE_ROUTES: "${serviceRoleRoutes(config).join(",")}"
|
|
344
463
|
STRIPE_SECRET_KEY: \${STRIPE_SECRET_KEY:-}
|
|
345
464
|
STRIPE_WEBHOOK_SECRET: \${STRIPE_WEBHOOK_SECRET:-}
|
|
346
465
|
SITE_URL: \${SITE_URL:-\${API_EXTERNAL_URL:-${externalUrlFallback}}}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
condition: service_healthy
|
|
350
|
-
|
|
351
|
-
realtime:
|
|
352
|
-
image: \${SUPATYPE_REALTIME_IMAGE:-supatype/realtime:latest}
|
|
353
|
-
expose:
|
|
354
|
-
- "4000"
|
|
355
|
-
environment:
|
|
356
|
-
PORT: "4000"
|
|
357
|
-
DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
|
|
358
|
-
JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
|
|
359
|
-
SLOT_NAME: supatype_realtime
|
|
360
|
-
PUBLICATION_NAME: supatype_realtime_pub
|
|
361
|
-
depends_on:
|
|
362
|
-
db:
|
|
363
|
-
condition: service_healthy
|
|
364
|
-
|
|
466
|
+
${dbDependency}
|
|
467
|
+
${realtimeBlock}
|
|
365
468
|
control-plane:
|
|
366
469
|
image: \${SUPATYPE_CONTROL_PLANE_IMAGE:-supatype/control-plane:latest}
|
|
367
470
|
expose:
|
|
@@ -373,16 +476,13 @@ ${dbPorts} volumes:
|
|
|
373
476
|
PORT: "8080"
|
|
374
477
|
SUPATYPE_PROJECT_REF: ${JSON.stringify(config.project.name)}
|
|
375
478
|
SUPATYPE_PROJECT_ROOT: /project
|
|
376
|
-
DATABASE_URL: "
|
|
479
|
+
DATABASE_URL: "${ownerUrl}"
|
|
377
480
|
SUPATYPE_FUNCTIONS_ROOT: /project/functions
|
|
378
481
|
SUPATYPE_STATIC_ROOT: /project/${staticDir.replace(/^\.\//, "")}
|
|
379
482
|
SUPATYPE_DEPLOYMENTS_DIR: /project/.supatype/deployments
|
|
380
483
|
COMPOSE_PROJECT_NAME: ${composeProject}
|
|
381
484
|
SUPATYPE_ENGINE_BIN: supatype-engine
|
|
382
|
-
|
|
383
|
-
db:
|
|
384
|
-
condition: service_healthy
|
|
385
|
-
|
|
485
|
+
${dbDependency}
|
|
386
486
|
server:
|
|
387
487
|
image: \${SUPATYPE_SERVER_IMAGE:-\${SUPATYPE_AUTH_IMAGE:-supatype/server:latest}}
|
|
388
488
|
${serverPorts} volumes:
|
|
@@ -399,10 +499,10 @@ ${serverPorts} volumes:
|
|
|
399
499
|
SUPATYPE_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
|
|
400
500
|
SUPATYPE_ANON_KEY: \${ANON_KEY:-}
|
|
401
501
|
SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
|
|
402
|
-
SUPATYPE_SQL_DATABASE_URL: "
|
|
502
|
+
SUPATYPE_SQL_DATABASE_URL: "${ownerUrl}"
|
|
403
503
|
SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
|
|
404
504
|
SUPATYPE_FUNCTIONS_WORKER_URL: http://functions-worker:8001
|
|
405
|
-
|
|
505
|
+
${realtimeServerEnv}
|
|
406
506
|
SUPATYPE_CONTROL_PLANE_URL: http://control-plane:8080
|
|
407
507
|
SUPATYPE_VALKEY_ADDR: valkey:6379
|
|
408
508
|
${appEnv}
|
|
@@ -411,9 +511,9 @@ ${appEnv}
|
|
|
411
511
|
API_EXTERNAL_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
|
|
412
512
|
GOTRUE_API_EXTERNAL_URL: \${API_EXTERNAL_URL:-${externalUrlFallback}}
|
|
413
513
|
GOTRUE_DB_DRIVER: postgres
|
|
414
|
-
GOTRUE_DB_DATABASE_URL: "
|
|
514
|
+
GOTRUE_DB_DATABASE_URL: "${gotrueUrl}${gotrueSearchPathSeparator}search_path=auth"
|
|
415
515
|
GOTRUE_SITE_URL: \${SITE_URL:-${siteUrlFallback}}
|
|
416
|
-
GOTRUE_JWT_SECRET: \${JWT_SECRET
|
|
516
|
+
GOTRUE_JWT_SECRET: \${JWT_SECRET:?JWT_SECRET is missing from .env}
|
|
417
517
|
GOTRUE_JWT_EXP: 3600
|
|
418
518
|
GOTRUE_JWT_AUD: authenticated
|
|
419
519
|
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
|
|
@@ -422,9 +522,7 @@ ${appEnv}
|
|
|
422
522
|
GOTRUE_DISABLE_SIGNUP: \${DISABLE_SIGNUP:-false}
|
|
423
523
|
${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
|
|
424
524
|
depends_on:
|
|
425
|
-
|
|
426
|
-
condition: service_healthy
|
|
427
|
-
valkey:
|
|
525
|
+
${dbDependencyClause} valkey:
|
|
428
526
|
condition: service_started
|
|
429
527
|
postgrest:
|
|
430
528
|
condition: service_started
|
|
@@ -432,9 +530,7 @@ ${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
|
|
|
432
530
|
condition: service_started
|
|
433
531
|
functions-worker:
|
|
434
532
|
condition: service_started
|
|
435
|
-
|
|
436
|
-
condition: service_started
|
|
437
|
-
control-plane:
|
|
533
|
+
${realtimeDependency} control-plane:
|
|
438
534
|
condition: service_started
|
|
439
535
|
|
|
440
536
|
minio:
|
|
@@ -453,10 +549,7 @@ ${minioPorts} volumes:
|
|
|
453
549
|
volumes:
|
|
454
550
|
- ${projectMount}:/project
|
|
455
551
|
working_dir: /project
|
|
456
|
-
|
|
457
|
-
db:
|
|
458
|
-
condition: service_healthy
|
|
459
|
-
${studioBlock}${valkeyBlock}${tlsHintComment} kong:
|
|
552
|
+
${dbDependency}${studioBlock}${valkeyBlock}${tlsHintComment} kong:
|
|
460
553
|
image: kong:3.6
|
|
461
554
|
environment:
|
|
462
555
|
KONG_DATABASE: "off"
|
|
@@ -474,30 +567,169 @@ ${kongDependsOn}${kongValkeyDepends}
|
|
|
474
567
|
|
|
475
568
|
${volumesBlock}`;
|
|
476
569
|
}
|
|
477
|
-
|
|
570
|
+
/** In-compose worker address: matches the `functions-worker` service this file always generates. */
|
|
571
|
+
const COMPOSE_FUNCTIONS_WORKER_URL = "http://functions-worker:8001";
|
|
572
|
+
function ensureComposeManifest(cwd, config) {
|
|
478
573
|
const manifestPath = join(cwd, ".supatype", "manifest.json");
|
|
479
|
-
if (existsSync(manifestPath))
|
|
480
|
-
return;
|
|
481
574
|
mkdirSync(dirname(manifestPath), { recursive: true });
|
|
575
|
+
// The manifest is generated, not operator-authored, but `push` writes real values into it (the
|
|
576
|
+
// schema, for one), so an existing file is repaired rather than replaced.
|
|
577
|
+
if (existsSync(manifestPath)) {
|
|
578
|
+
repairComposeFunctionsFlag(manifestPath);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
482
581
|
const manifest = {
|
|
483
582
|
schema: "public",
|
|
484
583
|
postgrest_url: "http://postgrest:3000",
|
|
485
584
|
storage_url: "http://storage:5000",
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
585
|
+
// Matches the compose file: a manifest advertising a service that was not generated is how
|
|
586
|
+
// the server ends up proxying subscriptions to a host that does not resolve.
|
|
587
|
+
realtime_enabled: realtimeEnabled(config),
|
|
588
|
+
...(realtimeEnabled(config) && { realtime_url: "http://realtime:4000" }),
|
|
589
|
+
// True because this file *always* generates a `functions-worker` service and hands the server
|
|
590
|
+
// `SUPATYPE_FUNCTIONS_WORKER_URL`. It said false, so the server answered 404 for every function
|
|
591
|
+
// in a stack that was running a worker for them, provisioned, then switched off.
|
|
592
|
+
functions_enabled: true,
|
|
593
|
+
functions_worker_url: COMPOSE_FUNCTIONS_WORKER_URL,
|
|
489
594
|
};
|
|
490
595
|
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
491
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* Turn functions on in a manifest written by an older CLI, leaving every other key alone.
|
|
599
|
+
*
|
|
600
|
+
* Without this, only new projects get working functions: a stack generated before the flag was
|
|
601
|
+
* corrected keeps `functions_enabled: false` on disk, and regenerating the compose file, the
|
|
602
|
+
* obvious thing to try, does not fix it.
|
|
603
|
+
*/
|
|
604
|
+
function repairComposeFunctionsFlag(manifestPath) {
|
|
605
|
+
let parsed;
|
|
606
|
+
try {
|
|
607
|
+
parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
608
|
+
}
|
|
609
|
+
catch {
|
|
610
|
+
return; // Malformed: leave it for the server to complain about rather than overwrite it here.
|
|
611
|
+
}
|
|
612
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
613
|
+
return;
|
|
614
|
+
if (parsed["functions_enabled"] === true && parsed["functions_worker_url"] !== undefined)
|
|
615
|
+
return;
|
|
616
|
+
parsed["functions_enabled"] = true;
|
|
617
|
+
if (parsed["functions_worker_url"] === undefined) {
|
|
618
|
+
parsed["functions_worker_url"] = COMPOSE_FUNCTIONS_WORKER_URL;
|
|
619
|
+
}
|
|
620
|
+
writeFileSync(manifestPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
|
|
621
|
+
}
|
|
492
622
|
function ensureProjectFunctionsDir(cwd, config) {
|
|
493
623
|
mkdirSync(preferredFunctionsPathFromProject(config, cwd), { recursive: true });
|
|
624
|
+
// Both roots must exist before compose mounts the project read-only: a missing directory becomes
|
|
625
|
+
// a bind mount of a file that is not there, and the worker fails to start rather than serving the
|
|
626
|
+
// half it does have.
|
|
627
|
+
mkdirSync(hooksPathFromProject(config, cwd), { recursive: true });
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* The config's external URL and `.env`'s `DATABASE_URL` must be the same string.
|
|
631
|
+
*
|
|
632
|
+
* The CLI resolves the URL from config; Compose substitutes `.env` at up-time. If the two disagree,
|
|
633
|
+
* `push` migrates one database while the services serve another, which reads as data loss and
|
|
634
|
+
* isn't. It also makes the generated GoTrue DSN wrong, since whether to append `search_path` with
|
|
635
|
+
* `?` or `&` is decided from the config URL's query string.
|
|
636
|
+
*/
|
|
637
|
+
function assertExternalUrlMatchesEnv(cwd, config) {
|
|
638
|
+
const configured = externalDatabaseUrl(config);
|
|
639
|
+
if (configured === undefined)
|
|
640
|
+
return;
|
|
641
|
+
const fromEnv = readEnvFile(cwd)["DATABASE_URL"];
|
|
642
|
+
if (fromEnv === undefined) {
|
|
643
|
+
// Nothing to disagree with. Compose's own `:?` guard reports this at up-time, and the operator
|
|
644
|
+
// may be exporting the variable in their shell rather than keeping a file.
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
if (fromEnv.trim() === configured)
|
|
648
|
+
return;
|
|
649
|
+
fatalError("DATABASE_URL in .env does not match database.external.url", [
|
|
650
|
+
`.env: ${fromEnv.trim()}`,
|
|
651
|
+
`config: ${configured}`,
|
|
652
|
+
"",
|
|
653
|
+
"The CLI connects using the config value and the stack connects using .env, so a push would",
|
|
654
|
+
"land in one database while the services serve the other.",
|
|
655
|
+
"Point the config at the same variable to keep them in step:",
|
|
656
|
+
" database: { external: { url: process.env.DATABASE_URL! } }",
|
|
657
|
+
], { brand: { intro: "Self-host compose" } });
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* A loopback host in the external URL cannot work from inside a container.
|
|
661
|
+
*
|
|
662
|
+
* `127.0.0.1` means "this container" to every service in the stack, so an external database on the
|
|
663
|
+
* host machine is unreachable, while the *CLI* reaches it fine, because the CLI runs on the host.
|
|
664
|
+
* That asymmetry is the trap: `supatype db check` passes, `push` applies the schema, and then
|
|
665
|
+
* storage, realtime and the server all die with ECONNREFUSED against their own loopback. Found by
|
|
666
|
+
* rehearsing exactly that.
|
|
667
|
+
*
|
|
668
|
+
* Refused rather than rewritten. The compose file interpolates one `${DATABASE_URL}` for every
|
|
669
|
+
* service, so silently substituting a different host would mean the CLI and the stack no longer
|
|
670
|
+
* agree about which database they are talking to, the thing every other check here exists to
|
|
671
|
+
* prevent.
|
|
672
|
+
*/
|
|
673
|
+
export function loopbackExternalHost(config) {
|
|
674
|
+
const url = externalDatabaseUrl(config);
|
|
675
|
+
if (url === undefined)
|
|
676
|
+
return undefined;
|
|
677
|
+
let host;
|
|
678
|
+
try {
|
|
679
|
+
host = new URL(url).hostname.toLowerCase();
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
return undefined; // Shape is validated at config load; nothing useful to add here.
|
|
683
|
+
}
|
|
684
|
+
// Node strips the brackets from an IPv6 hostname, and 127.0.0.0/8 is all loopback.
|
|
685
|
+
const loopback = host === "localhost" ||
|
|
686
|
+
host === "::1" ||
|
|
687
|
+
host === "[::1]" ||
|
|
688
|
+
/^127\.\d+\.\d+\.\d+$/.test(host);
|
|
689
|
+
return loopback ? host : undefined;
|
|
690
|
+
}
|
|
691
|
+
function assertExternalUrlReachableFromContainers(config) {
|
|
692
|
+
const host = loopbackExternalHost(config);
|
|
693
|
+
if (host === undefined)
|
|
694
|
+
return;
|
|
695
|
+
fatalError(`database.external.url points at ${host}, which no container can reach`, [
|
|
696
|
+
"Inside a container, localhost is that container, not the machine running Docker. Every",
|
|
697
|
+
"service in the stack would fail to connect, while the CLI succeeds because it runs on the host.",
|
|
698
|
+
"",
|
|
699
|
+
"Use a host the containers can resolve:",
|
|
700
|
+
" host.docker.internal (Docker Desktop on macOS and Windows)",
|
|
701
|
+
" 172.17.0.1 (the docker0 bridge on Linux, or add an extra_hosts entry)",
|
|
702
|
+
" the database's LAN address or hostname",
|
|
703
|
+
"",
|
|
704
|
+
"The CLI reaches the same address, so one value keeps working for both.",
|
|
705
|
+
], { brand: { intro: "Self-host compose" } });
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* The tier to write into the compose file.
|
|
709
|
+
*
|
|
710
|
+
* Resolved here so every caller gets it, rather than threaded through four call sites that load the
|
|
711
|
+
* schema a moment later anyway. A schema that fails to load falls back to the default list: compose
|
|
712
|
+
* generation is the wrong place to report a syntax error, and `push`/`dev` do it properly seconds
|
|
713
|
+
* later with the file and line.
|
|
714
|
+
*/
|
|
715
|
+
function resolveFieldMaskingTier(cwd, config, options) {
|
|
716
|
+
if (options?.fieldMaskingTier !== undefined)
|
|
717
|
+
return options.fieldMaskingTier;
|
|
718
|
+
return fieldMaskingTierFromProject(cwd, config);
|
|
494
719
|
}
|
|
495
720
|
export function writeSelfHostCompose(cwd, config, options) {
|
|
721
|
+
assertExternalUrlMatchesEnv(cwd, config);
|
|
722
|
+
const tier = resolveFieldMaskingTier(cwd, config, options);
|
|
723
|
+
const resolved = {
|
|
724
|
+
...options,
|
|
725
|
+
...(tier !== undefined && { fieldMaskingTier: tier }),
|
|
726
|
+
};
|
|
727
|
+
assertExternalUrlReachableFromContainers(config);
|
|
496
728
|
const paths = selfHostComposePaths(cwd);
|
|
497
729
|
mkdirSync(paths.dir, { recursive: true });
|
|
498
730
|
ensureProjectFunctionsDir(cwd, config);
|
|
499
|
-
ensureComposeManifest(cwd);
|
|
500
|
-
writeFileSync(paths.composePath, renderSelfHostCompose(config, cwd,
|
|
731
|
+
ensureComposeManifest(cwd, config);
|
|
732
|
+
writeFileSync(paths.composePath, renderSelfHostCompose(config, cwd, resolved), "utf8");
|
|
501
733
|
const studioHostDev = options?.devLocal === true && hasStudioOverride(config);
|
|
502
734
|
const tlsEnabled = selfHostTlsEnabled(config, options?.devLocal === true);
|
|
503
735
|
const domain = config.server.domain?.trim();
|
|
@@ -558,7 +790,7 @@ export function runDockerCompose(composePath, args, projectRoot = process.cwd(),
|
|
|
558
790
|
}
|
|
559
791
|
return result.status ?? 1;
|
|
560
792
|
}
|
|
561
|
-
/** Compose project name for a Supatype project
|
|
793
|
+
/** Compose project name for a Supatype project, isolates docker state per project. */
|
|
562
794
|
export function composeProjectName(projectName) {
|
|
563
795
|
const slug = projectName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
564
796
|
return `supatype-${slug || "project"}`;
|