@supatype/cli 0.1.0-alpha.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/.turbo/turbo-test.log +285 -69
- package/.turbo/turbo-typecheck.log +1 -1
- package/assets/supatype-logo-wordmark.ascii.txt +6 -0
- package/bin/dev-entry.ts +2 -1
- package/dist/app/framework.js +1 -3
- package/dist/app/framework.js.map +1 -1
- package/dist/app/proxy-dev-app.d.ts +14 -0
- package/dist/app/proxy-dev-app.d.ts.map +1 -1
- package/dist/app/proxy-dev-app.js +110 -6
- package/dist/app/proxy-dev-app.js.map +1 -1
- package/dist/app-config.d.ts +10 -0
- package/dist/app-config.d.ts.map +1 -1
- package/dist/app-config.js +72 -0
- package/dist/app-config.js.map +1 -1
- package/dist/assets/supatype-logo-wordmark.ascii.txt +6 -0
- package/dist/binary-cache.d.ts +19 -7
- package/dist/binary-cache.d.ts.map +1 -1
- package/dist/binary-cache.js +92 -46
- package/dist/binary-cache.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +17 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +86 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/admin.d.ts +28 -1
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +297 -149
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/adopt.d.ts +3 -0
- package/dist/commands/adopt.d.ts.map +1 -0
- package/dist/commands/adopt.js +55 -0
- package/dist/commands/adopt.js.map +1 -0
- package/dist/commands/app.d.ts.map +1 -1
- package/dist/commands/app.js +20 -17
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/cache.d.ts.map +1 -1
- package/dist/commands/cache.js +11 -10
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/cloud.d.ts +4 -9
- package/dist/commands/cloud.d.ts.map +1 -1
- package/dist/commands/cloud.js +75 -125
- package/dist/commands/cloud.js.map +1 -1
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +37 -58
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +140 -96
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +74 -39
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +39 -39
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +78 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +5 -4
- package/dist/commands/engine.js.map +1 -1
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +172 -119
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +5 -4
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts +35 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +883 -107
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/introspect.d.ts +3 -0
- package/dist/commands/introspect.d.ts.map +1 -0
- package/dist/commands/introspect.js +35 -0
- package/dist/commands/introspect.js.map +1 -0
- package/dist/commands/keys.d.ts +15 -1
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +46 -10
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/link-helpers.d.ts +15 -0
- package/dist/commands/link-helpers.d.ts.map +1 -0
- package/dist/commands/link-helpers.js +225 -0
- package/dist/commands/link-helpers.js.map +1 -0
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +5 -4
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/migrate-from-v1.d.ts.map +1 -1
- package/dist/commands/migrate-from-v1.js +3 -2
- package/dist/commands/migrate-from-v1.js.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +119 -26
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/pg.d.ts.map +1 -1
- package/dist/commands/pg.js +11 -12
- package/dist/commands/pg.js.map +1 -1
- package/dist/commands/plugins.d.ts.map +1 -1
- package/dist/commands/plugins.js +55 -46
- package/dist/commands/plugins.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +33 -5
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +111 -138
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/seed.js +4 -3
- package/dist/commands/seed.js.map +1 -1
- package/dist/commands/self-host.d.ts +2 -2
- package/dist/commands/self-host.d.ts.map +1 -1
- package/dist/commands/self-host.js +65 -50
- package/dist/commands/self-host.js.map +1 -1
- package/dist/commands/self-update.d.ts.map +1 -1
- package/dist/commands/self-update.js +3 -2
- package/dist/commands/self-update.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +95 -29
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js +3 -2
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +54 -21
- package/dist/commands/update.js.map +1 -1
- package/dist/compose-rename.d.ts +10 -0
- package/dist/compose-rename.d.ts.map +1 -0
- package/dist/compose-rename.js +67 -0
- package/dist/compose-rename.js.map +1 -0
- package/dist/config.d.ts +2 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/dev-compose.d.ts +26 -0
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +357 -79
- package/dist/dev-compose.js.map +1 -1
- package/dist/dev-log-bus.d.ts +30 -0
- package/dist/dev-log-bus.d.ts.map +1 -0
- package/dist/dev-log-bus.js +87 -0
- package/dist/dev-log-bus.js.map +1 -0
- package/dist/dev-log-filter.d.ts +10 -0
- package/dist/dev-log-filter.d.ts.map +1 -0
- package/dist/dev-log-filter.js +36 -0
- package/dist/dev-log-filter.js.map +1 -0
- package/dist/dev-logo.d.ts +12 -0
- package/dist/dev-logo.d.ts.map +1 -0
- package/dist/dev-logo.js +56 -0
- package/dist/dev-logo.js.map +1 -0
- package/dist/dev-ports.d.ts +27 -0
- package/dist/dev-ports.d.ts.map +1 -0
- package/dist/dev-ports.js +171 -0
- package/dist/dev-ports.js.map +1 -0
- package/dist/dev-session-lock.d.ts +25 -0
- package/dist/dev-session-lock.d.ts.map +1 -0
- package/dist/dev-session-lock.js +81 -0
- package/dist/dev-session-lock.js.map +1 -0
- package/dist/dev-session.d.ts +26 -0
- package/dist/dev-session.d.ts.map +1 -0
- package/dist/dev-session.js +106 -0
- package/dist/dev-session.js.map +1 -0
- package/dist/dev-shutdown.d.ts +25 -0
- package/dist/dev-shutdown.d.ts.map +1 -0
- package/dist/dev-shutdown.js +114 -0
- package/dist/dev-shutdown.js.map +1 -0
- package/dist/dev-task-colors.d.ts +13 -0
- package/dist/dev-task-colors.d.ts.map +1 -0
- package/dist/dev-task-colors.js +43 -0
- package/dist/dev-task-colors.js.map +1 -0
- package/dist/dev-tui.d.ts +24 -0
- package/dist/dev-tui.d.ts.map +1 -0
- package/dist/dev-tui.js +188 -0
- package/dist/dev-tui.js.map +1 -0
- package/dist/diff-output.d.ts +5 -1
- package/dist/diff-output.d.ts.map +1 -1
- package/dist/diff-output.js +69 -0
- package/dist/diff-output.js.map +1 -1
- package/dist/docker-runtime.d.ts +30 -0
- package/dist/docker-runtime.d.ts.map +1 -0
- package/dist/docker-runtime.js +118 -0
- package/dist/docker-runtime.js.map +1 -0
- package/dist/engine-client.d.ts +10 -1
- package/dist/engine-client.d.ts.map +1 -1
- package/dist/engine-client.js +76 -17
- package/dist/engine-client.js.map +1 -1
- package/dist/engine-push-output.d.ts +17 -0
- package/dist/engine-push-output.d.ts.map +1 -0
- package/dist/engine-push-output.js +64 -0
- package/dist/engine-push-output.js.map +1 -0
- package/dist/ensure-binary.js +2 -2
- package/dist/ensure-binary.js.map +1 -1
- package/dist/env-file.d.ts +5 -0
- package/dist/env-file.d.ts.map +1 -0
- package/dist/env-file.js +33 -0
- package/dist/env-file.js.map +1 -0
- package/dist/gitignore.d.ts +8 -0
- package/dist/gitignore.d.ts.map +1 -0
- package/dist/gitignore.js +41 -0
- package/dist/gitignore.js.map +1 -0
- package/dist/kong-config.d.ts +9 -0
- package/dist/kong-config.d.ts.map +1 -1
- package/dist/kong-config.js +18 -1
- package/dist/kong-config.js.map +1 -1
- package/dist/link.d.ts +66 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +160 -0
- package/dist/link.js.map +1 -0
- package/dist/process-manager.d.ts +8 -0
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +53 -9
- package/dist/process-manager.js.map +1 -1
- package/dist/project-config.d.ts +30 -3
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +37 -4
- package/dist/project-config.js.map +1 -1
- package/dist/prompts.d.ts +3 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +3 -0
- package/dist/prompts.js.map +1 -0
- package/dist/pull-utils.d.ts +50 -14
- package/dist/pull-utils.d.ts.map +1 -1
- package/dist/pull-utils.js +152 -12
- package/dist/pull-utils.js.map +1 -1
- package/dist/resolve-target.d.ts +86 -0
- package/dist/resolve-target.d.ts.map +1 -0
- package/dist/resolve-target.js +291 -0
- package/dist/resolve-target.js.map +1 -0
- package/dist/restore-system-relation-targets.d.ts +3 -0
- package/dist/restore-system-relation-targets.d.ts.map +1 -0
- package/dist/restore-system-relation-targets.js +45 -0
- package/dist/restore-system-relation-targets.js.map +1 -0
- package/dist/runtime-routes.d.ts.map +1 -1
- package/dist/runtime-routes.js +7 -0
- package/dist/runtime-routes.js.map +1 -1
- package/dist/schema-ast-v2.d.ts +1 -1
- package/dist/schema-ast-v2.d.ts.map +1 -1
- package/dist/schema-ast-v2.js +2 -2
- package/dist/schema-ast-v2.js.map +1 -1
- package/dist/schema-sources.d.ts +40 -0
- package/dist/schema-sources.d.ts.map +1 -0
- package/dist/schema-sources.js +183 -0
- package/dist/schema-sources.js.map +1 -0
- package/dist/scripts/postinstall.js +5 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/self-host-compose.d.ts +37 -1
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +234 -43
- package/dist/self-host-compose.js.map +1 -1
- package/dist/storage-provision.d.ts +4 -0
- package/dist/storage-provision.d.ts.map +1 -1
- package/dist/storage-provision.js +24 -2
- package/dist/storage-provision.js.map +1 -1
- package/dist/supatype-eval-1781522769253.d.mts +2 -0
- package/dist/supatype-eval-1781522769253.d.mts.map +1 -0
- package/dist/supatype-eval-1781522769253.mjs +3 -0
- package/dist/supatype-eval-1781522769253.mjs.map +1 -0
- package/dist/systemd.js +2 -2
- package/dist/systemd.js.map +1 -1
- package/dist/target-client.d.ts +10 -0
- package/dist/target-client.d.ts.map +1 -0
- package/dist/target-client.js +22 -0
- package/dist/target-client.js.map +1 -0
- package/dist/type-extractor.d.ts +11 -0
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +95 -8
- package/dist/type-extractor.js.map +1 -1
- package/dist/ui/brand.d.ts +9 -0
- package/dist/ui/brand.d.ts.map +1 -0
- package/dist/ui/brand.js +11 -0
- package/dist/ui/brand.js.map +1 -0
- package/dist/ui/confirm.d.ts +12 -0
- package/dist/ui/confirm.d.ts.map +1 -0
- package/dist/ui/confirm.js +28 -0
- package/dist/ui/confirm.js.map +1 -0
- package/dist/ui/fatal.d.ts +10 -0
- package/dist/ui/fatal.d.ts.map +1 -0
- package/dist/ui/fatal.js +34 -0
- package/dist/ui/fatal.js.map +1 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/interactive.d.ts +3 -0
- package/dist/ui/interactive.d.ts.map +1 -0
- package/dist/ui/interactive.js +5 -0
- package/dist/ui/interactive.js.map +1 -0
- package/dist/ui/messages.d.ts +10 -0
- package/dist/ui/messages.d.ts.map +1 -0
- package/dist/ui/messages.js +35 -0
- package/dist/ui/messages.js.map +1 -0
- package/dist/ui/next-steps.d.ts +3 -0
- package/dist/ui/next-steps.d.ts.map +1 -0
- package/dist/ui/next-steps.js +10 -0
- package/dist/ui/next-steps.js.map +1 -0
- package/dist/ui/progress.d.ts +5 -0
- package/dist/ui/progress.d.ts.map +1 -0
- package/dist/ui/progress.js +24 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/prompts.d.ts +14 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +34 -0
- package/dist/ui/prompts.js.map +1 -0
- package/package.json +5 -2
- package/src/app/framework.ts +1 -3
- package/src/app/proxy-dev-app.ts +114 -6
- package/src/app-config.ts +80 -0
- package/src/binary-cache.ts +102 -52
- package/src/cli.ts +16 -2
- package/src/commands/add.ts +97 -0
- package/src/commands/admin.ts +381 -190
- package/src/commands/adopt.ts +82 -0
- package/src/commands/app.ts +20 -17
- package/src/commands/cache.ts +11 -10
- package/src/commands/cloud.ts +91 -142
- package/src/commands/db.ts +40 -63
- package/src/commands/deploy.ts +186 -126
- package/src/commands/dev.ts +98 -55
- package/src/commands/diff.ts +52 -43
- package/src/commands/doctor.ts +103 -0
- package/src/commands/engine.ts +5 -4
- package/src/commands/functions.ts +187 -123
- package/src/commands/generate.ts +5 -4
- package/src/commands/init.ts +1087 -104
- package/src/commands/introspect.ts +48 -0
- package/src/commands/keys.ts +56 -14
- package/src/commands/link-helpers.ts +273 -0
- package/src/commands/logs.ts +5 -4
- package/src/commands/migrate-from-v1.ts +3 -2
- package/src/commands/migrate.ts +167 -27
- package/src/commands/pg.ts +13 -18
- package/src/commands/plugins.ts +55 -46
- package/src/commands/pull.ts +38 -9
- package/src/commands/push.ts +148 -175
- package/src/commands/seed.ts +5 -4
- package/src/commands/self-host.ts +85 -54
- package/src/commands/self-update.ts +3 -2
- package/src/commands/status.ts +102 -33
- package/src/commands/types.ts +3 -2
- package/src/commands/update.ts +59 -23
- package/src/compose-rename.ts +76 -0
- package/src/config.ts +2 -1
- package/src/dev-compose.ts +462 -76
- package/src/dev-log-bus.ts +101 -0
- package/src/dev-log-filter.ts +32 -0
- package/src/dev-logo.ts +61 -0
- package/src/dev-ports.ts +212 -0
- package/src/dev-session-lock.ts +101 -0
- package/src/dev-session.ts +130 -0
- package/src/dev-shutdown.ts +147 -0
- package/src/dev-task-colors.ts +47 -0
- package/src/dev-tui.ts +232 -0
- package/src/diff-output.ts +79 -1
- package/src/docker-runtime.ts +151 -0
- package/src/engine-client.ts +81 -17
- package/src/engine-push-output.ts +75 -0
- package/src/ensure-binary.ts +2 -2
- package/src/env-file.ts +37 -0
- package/src/gitignore.ts +48 -0
- package/src/kong-config.ts +24 -1
- package/src/link.ts +243 -0
- package/src/process-manager.ts +66 -10
- package/src/project-config.ts +62 -7
- package/src/prompts.ts +2 -0
- package/src/pull-utils.ts +217 -23
- package/src/resolve-target.ts +419 -0
- package/src/restore-system-relation-targets.ts +45 -0
- package/src/runtime-routes.ts +7 -0
- package/src/schema-ast-v2.ts +2 -1
- package/src/schema-sources.ts +248 -0
- package/src/scripts/postinstall.ts +7 -1
- package/src/self-host-compose.ts +262 -46
- package/src/storage-provision.ts +33 -1
- package/src/supatype-eval-1781522769253.mts +1 -0
- package/src/systemd.ts +2 -2
- package/src/target-client.ts +40 -0
- package/src/type-extractor.ts +124 -11
- package/src/ui/README.md +17 -0
- package/src/ui/brand.ts +12 -0
- package/src/ui/confirm.ts +38 -0
- package/src/ui/fatal.ts +43 -0
- package/src/ui/index.ts +8 -0
- package/src/ui/interactive.ts +4 -0
- package/src/ui/messages.ts +43 -0
- package/src/ui/next-steps.ts +10 -0
- package/src/ui/progress.ts +28 -0
- package/src/ui/prompts.ts +40 -0
- package/tests/admin-ensure.test.ts +59 -0
- package/tests/cli-help.test.ts +27 -2
- package/tests/config.test.ts +29 -2
- package/tests/dev-ports.test.ts +41 -0
- package/tests/dev-session-lock.test.ts +54 -0
- package/tests/dev-ui.test.ts +162 -0
- package/tests/docker-runtime.test.ts +236 -0
- package/tests/engine-push-output.test.ts +67 -0
- package/tests/init.test.ts +197 -18
- package/tests/link.test.ts +148 -0
- package/tests/minisign.test.ts +102 -0
- package/tests/proxy-dev-app.test.ts +45 -1
- package/tests/pull-utils.test.ts +5 -4
- package/tests/runtime-contract.test.ts +186 -2
- package/tests/schema-sources.test.ts +119 -0
- package/tests/storage-provision.test.ts +100 -0
- package/tests/ui-confirm.test.ts +41 -0
- package/tests/ui-messages.test.ts +66 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/dev-compose.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `supatype dev` when `provider: docker` — full self-host Compose stack (Kong gateway).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { existsSync, mkdirSync,
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs"
|
|
6
6
|
import { homedir } from "node:os"
|
|
7
7
|
import { dirname, join, resolve } from "node:path"
|
|
8
8
|
import { spawnSync } from "node:child_process"
|
|
@@ -10,24 +10,59 @@ import { startProxyDevApp } from "./app/proxy-dev-app.js"
|
|
|
10
10
|
import { loadSchemaAst } from "./config.js"
|
|
11
11
|
import {
|
|
12
12
|
COMPOSE_DEV_KONG_PORT,
|
|
13
|
+
connectionString,
|
|
13
14
|
projectRootFromConfig,
|
|
14
15
|
resolveRuntimeProvider,
|
|
15
16
|
schemaPathFromProject,
|
|
16
17
|
type SupatypeProjectConfig,
|
|
17
18
|
} from "./project-config.js"
|
|
18
19
|
import { signJwt } from "./jwt.js"
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
20
|
+
import { ensureDevDbPort, ensureKongPort } from "./dev-ports.js"
|
|
21
|
+
import { handleComposeProjectRename } from "./compose-rename.js"
|
|
22
|
+
import { recoverStaleDevSession, writeDevSessionLock } from "./dev-session-lock.js"
|
|
23
|
+
import { readEnvValue, upsertEnvFile } from "./env-file.js"
|
|
24
|
+
import {
|
|
25
|
+
COMPOSE_PINNED_IMAGE_ENV_KEYS,
|
|
26
|
+
composeDockerImageEnv,
|
|
27
|
+
composeProjectName,
|
|
28
|
+
exitComposeFailed,
|
|
29
|
+
runDockerCompose,
|
|
30
|
+
schemaEngineImageForPush,
|
|
31
|
+
writeSelfHostCompose,
|
|
32
|
+
type SelfHostComposePaths,
|
|
33
|
+
} from "./self-host-compose.js"
|
|
34
|
+
import type { DockerBrandOptions } from "./docker-runtime.js"
|
|
21
35
|
import { hasEngineOverride } from "./binary-cache.js"
|
|
22
36
|
import { startStudioViteDevServer } from "./studio-dev-server.js"
|
|
23
|
-
import { ensureEngine, engineRequest } from "./engine-client.js"
|
|
37
|
+
import { ensureEngine, engineRequest, type DiffResult } from "./engine-client.js"
|
|
38
|
+
import { writeSchemaSourcePushArtifacts, type SchemaSourcePushArtifacts } from "./schema-sources.js"
|
|
39
|
+
import { endDevSession } from "./dev-session.js"
|
|
40
|
+
import { writeLocalEnvironment } from "./link.js"
|
|
41
|
+
import { registerDevShutdown } from "./dev-shutdown.js"
|
|
42
|
+
import {
|
|
43
|
+
filterComposeNoise,
|
|
44
|
+
formatEnginePushMessage,
|
|
45
|
+
parseEngineJsonOutput,
|
|
46
|
+
parseEnginePushOutput,
|
|
47
|
+
} from "./engine-push-output.js"
|
|
24
48
|
import { withAdminRoles } from "./studio-admin-roles.js"
|
|
49
|
+
import { restoreSystemRelationTargets } from "./restore-system-relation-targets.js"
|
|
50
|
+
import { provisionBucketsFromAst } from "./storage-provision.js"
|
|
51
|
+
import type { ExtractedSchemaAstV2 } from "./schema-ast-v2.js"
|
|
52
|
+
import { ensureFirstAdminUserForProject } from "./commands/admin.js"
|
|
25
53
|
|
|
26
54
|
const LOCAL_JWT_SECRET = "super-secret-jwt-token-with-at-least-32-characters-long"
|
|
27
55
|
|
|
28
56
|
/** Default host port for compose Postgres when `overrides.engine` is set (devLocal). */
|
|
29
57
|
const COMPOSE_DEV_DB_PORT = 54329
|
|
30
58
|
|
|
59
|
+
/** Sync optional Docker image pins from config into `.env` (no JWT rotation). */
|
|
60
|
+
export function syncComposeImagePins(cwd: string, config: SupatypeProjectConfig): void {
|
|
61
|
+
const imagePins = composeDockerImageEnv(config)
|
|
62
|
+
const removeImageKeys = COMPOSE_PINNED_IMAGE_ENV_KEYS.filter((key) => !(key in imagePins))
|
|
63
|
+
upsertEnvFile(cwd, imagePins, removeImageKeys)
|
|
64
|
+
}
|
|
65
|
+
|
|
31
66
|
export interface DevComposeOptions {
|
|
32
67
|
watch: boolean
|
|
33
68
|
}
|
|
@@ -39,30 +74,12 @@ export function composeDbUrl(): string {
|
|
|
39
74
|
|
|
40
75
|
/**
|
|
41
76
|
* Resolve the host Kong port for this project. Persisted in `.env` as
|
|
42
|
-
* SUPATYPE_KONG_PORT
|
|
43
|
-
* (18473) or the next free port, so multiple projects can run concurrently.
|
|
77
|
+
* SUPATYPE_KONG_PORT; prompts when the configured port is already taken.
|
|
44
78
|
*/
|
|
45
79
|
async function resolveDevDbPort(cwd: string): Promise<number> {
|
|
46
|
-
|
|
47
|
-
if (existsSync(envPath)) {
|
|
48
|
-
const m = readFileSync(envPath, "utf8").match(/^SUPATYPE_DEV_DB_PORT=(\d+)/m)
|
|
49
|
-
if (m && m[1]) return Number(m[1])
|
|
50
|
-
}
|
|
51
|
-
let port = COMPOSE_DEV_DB_PORT
|
|
52
|
-
while (await isPortInUse(port)) port++
|
|
53
|
-
return port
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function readEnvValue(cwd: string, key: string, fallback: string): string {
|
|
57
|
-
const envPath = join(cwd, ".env")
|
|
58
|
-
if (existsSync(envPath)) {
|
|
59
|
-
const m = readFileSync(envPath, "utf8").match(new RegExp(`^${key}=(.+)$`, "m"))
|
|
60
|
-
if (m?.[1]) return m[1].trim()
|
|
61
|
-
}
|
|
62
|
-
return fallback
|
|
80
|
+
return ensureDevDbPort(cwd)
|
|
63
81
|
}
|
|
64
82
|
|
|
65
|
-
/** Postgres DSN for compose db when published to the host (local engine push). */
|
|
66
83
|
function hostComposeDbUrl(cwd: string): string {
|
|
67
84
|
const port = readEnvValue(cwd, "SUPATYPE_DEV_DB_PORT", String(COMPOSE_DEV_DB_PORT))
|
|
68
85
|
const user = readEnvValue(cwd, "POSTGRES_USER", "supatype_admin")
|
|
@@ -71,40 +88,92 @@ function hostComposeDbUrl(cwd: string): string {
|
|
|
71
88
|
return `postgresql://${user}:${pass}@127.0.0.1:${port}/${db}?sslmode=disable`
|
|
72
89
|
}
|
|
73
90
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
/**
|
|
92
|
+
* When `provider: docker` and `overrides.engine` is set, ensure Postgres is published
|
|
93
|
+
* on the host (SUPATYPE_DEV_DB_PORT) so the local engine binary can connect.
|
|
94
|
+
*/
|
|
95
|
+
export async function ensureDockerDbPublishedForHostEngine(
|
|
96
|
+
cwd: string,
|
|
97
|
+
config: SupatypeProjectConfig,
|
|
98
|
+
brand?: DockerBrandOptions,
|
|
99
|
+
): Promise<void> {
|
|
100
|
+
if (resolveRuntimeProvider(config) !== "docker") {
|
|
101
|
+
throw new Error("ensureDockerDbPublishedForHostEngine requires provider: docker")
|
|
102
|
+
}
|
|
103
|
+
if (!hasEngineOverride(config)) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"Docker Postgres is not published to the host without overrides.engine. " +
|
|
106
|
+
"Set overrides.engine in supatype.local.config.ts or pass --connection.",
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const project = composeProjectName(config.project.name)
|
|
111
|
+
const kongPort = await resolveKongPort(cwd)
|
|
112
|
+
const devDbPort = await resolveDevDbPort(cwd)
|
|
113
|
+
|
|
114
|
+
const now = Math.floor(Date.now() / 1000)
|
|
115
|
+
const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 }
|
|
116
|
+
const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
|
|
117
|
+
const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
|
|
118
|
+
ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
119
|
+
|
|
120
|
+
const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
|
|
121
|
+
const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project, {
|
|
122
|
+
quiet: true,
|
|
123
|
+
...(brand !== undefined && { brand }),
|
|
124
|
+
})
|
|
125
|
+
if (up !== 0) {
|
|
126
|
+
exitComposeFailed(up, "Could not start Postgres (compose db service).", brand)
|
|
127
|
+
}
|
|
128
|
+
await waitComposeHealthy(paths, cwd, 120_000, project)
|
|
83
129
|
}
|
|
84
130
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
writeFileSync(envPath, `${merged.join("\n").trimEnd()}\n`, "utf8")
|
|
131
|
+
/**
|
|
132
|
+
* True when CLI should publish local Compose Postgres for the host-side engine
|
|
133
|
+
* (local dev with overrides.engine). False for remote DB URLs via config or --connection.
|
|
134
|
+
*/
|
|
135
|
+
export function usesLocalDockerEngineDb(
|
|
136
|
+
config: SupatypeProjectConfig,
|
|
137
|
+
explicitConnection?: string,
|
|
138
|
+
): boolean {
|
|
139
|
+
if (explicitConnection?.trim()) return false
|
|
140
|
+
if (config.connection?.trim()) return false
|
|
141
|
+
return resolveRuntimeProvider(config) === "docker" && hasEngineOverride(config)
|
|
97
142
|
}
|
|
98
143
|
|
|
99
|
-
/**
|
|
100
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Resolve a Postgres URL reachable from the host-side engine binary.
|
|
146
|
+
* Local docker + overrides.engine → SUPATYPE_DEV_DB_PORT on localhost.
|
|
147
|
+
* Remote self-host → set `connection` in config or pass `--connection`.
|
|
148
|
+
*/
|
|
149
|
+
export async function resolveHostEngineDatabaseUrl(
|
|
150
|
+
cwd: string,
|
|
151
|
+
config: SupatypeProjectConfig,
|
|
152
|
+
explicit?: string,
|
|
153
|
+
): Promise<string> {
|
|
154
|
+
if (explicit?.trim()) return explicit
|
|
155
|
+
if (config.connection?.trim()) return config.connection
|
|
156
|
+
if (usesLocalDockerEngineDb(config)) {
|
|
157
|
+
await ensureDockerDbPublishedForHostEngine(cwd, config)
|
|
158
|
+
return hostComposeDbUrl(cwd)
|
|
159
|
+
}
|
|
160
|
+
return connectionString(config)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function resolveKongPort(cwd: string): Promise<number> {
|
|
164
|
+
return ensureKongPort(cwd, { context: "dev" })
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function upsertDevComposeEnv(
|
|
101
168
|
cwd: string,
|
|
169
|
+
config: SupatypeProjectConfig,
|
|
102
170
|
anonKey: string,
|
|
103
171
|
serviceRoleKey: string,
|
|
104
172
|
kongPort: number,
|
|
105
173
|
devDbPort?: number,
|
|
106
174
|
): void {
|
|
107
175
|
const apiUrl = `http://localhost:${kongPort}`
|
|
176
|
+
const imagePins = composeDockerImageEnv(config)
|
|
108
177
|
const updates: Record<string, string> = {
|
|
109
178
|
POSTGRES_USER: "supatype_admin",
|
|
110
179
|
POSTGRES_PASSWORD: "postgres",
|
|
@@ -113,16 +182,33 @@ function ensureDevComposeEnv(
|
|
|
113
182
|
ANON_KEY: anonKey,
|
|
114
183
|
SERVICE_ROLE_KEY: serviceRoleKey,
|
|
115
184
|
PUBLIC_SUPATYPE_ANON_KEY: anonKey,
|
|
185
|
+
VITE_SUPATYPE_ANON_KEY: anonKey,
|
|
116
186
|
PUBLIC_SUPATYPE_URL: apiUrl,
|
|
117
187
|
SUPATYPE_KONG_PORT: String(kongPort),
|
|
118
188
|
API_EXTERNAL_URL: apiUrl,
|
|
119
189
|
SITE_URL: apiUrl,
|
|
120
190
|
GOTRUE_MAILER_AUTOCONFIRM: "true",
|
|
191
|
+
...imagePins,
|
|
121
192
|
}
|
|
122
193
|
if (devDbPort !== undefined) {
|
|
123
194
|
updates.SUPATYPE_DEV_DB_PORT = String(devDbPort)
|
|
195
|
+
updates.DATABASE_URL =
|
|
196
|
+
`postgresql://supatype_admin:postgres@localhost:${devDbPort}/supatype?sslmode=disable`
|
|
124
197
|
}
|
|
125
|
-
|
|
198
|
+
const removeImageKeys = COMPOSE_PINNED_IMAGE_ENV_KEYS.filter((key) => !(key in imagePins))
|
|
199
|
+
upsertEnvFile(cwd, updates, removeImageKeys)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Keep compose + Studio on the same freshly signed dev JWTs; sync optional image pins from config. */
|
|
203
|
+
function ensureDevComposeEnv(
|
|
204
|
+
cwd: string,
|
|
205
|
+
config: SupatypeProjectConfig,
|
|
206
|
+
anonKey: string,
|
|
207
|
+
serviceRoleKey: string,
|
|
208
|
+
kongPort: number,
|
|
209
|
+
devDbPort?: number,
|
|
210
|
+
): void {
|
|
211
|
+
upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
126
212
|
}
|
|
127
213
|
|
|
128
214
|
async function waitComposeHealthy(paths: SelfHostComposePaths, cwd: string, maxMs: number, composeProject: string): Promise<void> {
|
|
@@ -158,8 +244,18 @@ async function waitKongReady(kongPort: number, maxSec: number): Promise<void> {
|
|
|
158
244
|
throw new Error(`Kong gateway at ${base} did not become ready within ${maxSec}s`)
|
|
159
245
|
}
|
|
160
246
|
|
|
247
|
+
async function provisionDockerStorageBuckets(
|
|
248
|
+
ast: ExtractedSchemaAstV2,
|
|
249
|
+
kongPort: number,
|
|
250
|
+
serviceRoleKey: string,
|
|
251
|
+
): Promise<void> {
|
|
252
|
+
await provisionBucketsFromAst(ast, `http://localhost:${kongPort}/storage/v1`, serviceRoleKey)
|
|
253
|
+
}
|
|
254
|
+
|
|
161
255
|
let _lastPushedAst: string | null = null
|
|
162
256
|
let _lastFailedAst: string | null = null
|
|
257
|
+
let _composePushInFlight = false
|
|
258
|
+
let _composePushQueued = false
|
|
163
259
|
|
|
164
260
|
/**
|
|
165
261
|
* Regenerate admin-config + TypeScript types from the AST using the **host** engine.
|
|
@@ -207,6 +303,7 @@ async function refreshSchemaArtifacts(
|
|
|
207
303
|
|
|
208
304
|
try {
|
|
209
305
|
const admin = withAdminRoles(await engineRequest<unknown>("/admin", { ast }), config)
|
|
306
|
+
restoreSystemRelationTargets(admin, ast)
|
|
210
307
|
writeFileSync(adminConfigPath, `${JSON.stringify(admin, null, 2)}\n`)
|
|
211
308
|
console.log("[supatype] Admin config written to .supatype/admin-config.json")
|
|
212
309
|
} catch (err) {
|
|
@@ -245,12 +342,19 @@ async function runComposeSchemaPush(
|
|
|
245
342
|
console.log("[supatype] Applying schema via local engine (overrides.engine)...")
|
|
246
343
|
await ensureEngine()
|
|
247
344
|
const pgSchema = config.schema?.pg_schema ?? "public"
|
|
345
|
+
const sources = writeSchemaSourcePushArtifacts(cwd)
|
|
248
346
|
try {
|
|
249
347
|
await engineRequest("/push", {
|
|
250
348
|
ast,
|
|
251
349
|
database_url: hostComposeDbUrl(cwd),
|
|
252
350
|
schema: pgSchema,
|
|
253
351
|
force: true,
|
|
352
|
+
...(sources
|
|
353
|
+
? {
|
|
354
|
+
schema_sources_gz_base64: sources.payload.dataBase64,
|
|
355
|
+
schema_sources_manifest: sources.payload.manifest,
|
|
356
|
+
}
|
|
357
|
+
: {}),
|
|
254
358
|
})
|
|
255
359
|
} catch (err) {
|
|
256
360
|
_lastFailedAst = astJson
|
|
@@ -258,34 +362,66 @@ async function runComposeSchemaPush(
|
|
|
258
362
|
}
|
|
259
363
|
_lastPushedAst = astJson
|
|
260
364
|
_lastFailedAst = null
|
|
365
|
+
if (astHasSystemAuthRelation(ast)) {
|
|
366
|
+
grantAuthSchemaAccess(paths, cwd, composeProject)
|
|
367
|
+
}
|
|
261
368
|
console.log("[supatype] Schema applied.")
|
|
262
369
|
return
|
|
263
370
|
}
|
|
264
371
|
|
|
265
372
|
console.log("[supatype] Applying schema via compose schema-engine...")
|
|
266
|
-
|
|
373
|
+
const sources = writeSchemaSourcePushArtifacts(cwd)
|
|
374
|
+
let push = await runComposeEnginePush(paths, cwd, composeProject, config, sources)
|
|
267
375
|
// Windows Docker bind mounts can lag briefly after the host write.
|
|
268
376
|
if (push.status !== 0) {
|
|
269
377
|
await new Promise((r) => setTimeout(r, 250))
|
|
270
|
-
push = runComposeEnginePush(paths, cwd, composeProject)
|
|
378
|
+
push = await runComposeEnginePush(paths, cwd, composeProject, config, sources)
|
|
271
379
|
}
|
|
272
380
|
if (push.status !== 0) {
|
|
273
381
|
_lastFailedAst = astJson
|
|
274
|
-
|
|
382
|
+
const detail = filterComposeNoise(push.output) || push.output
|
|
383
|
+
throw new Error(detail || `Engine schema push failed (exit ${push.status})`)
|
|
275
384
|
}
|
|
276
385
|
_lastPushedAst = astJson
|
|
277
386
|
_lastFailedAst = null
|
|
278
387
|
|
|
279
|
-
|
|
388
|
+
if (astHasSystemAuthRelation(ast)) {
|
|
389
|
+
grantAuthSchemaAccess(paths, cwd, composeProject)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/** Serialize watch-triggered pushes so docker output cannot interleave. */
|
|
394
|
+
async function runComposeSchemaPushQueued(
|
|
395
|
+
cwd: string,
|
|
396
|
+
config: SupatypeProjectConfig,
|
|
397
|
+
paths: SelfHostComposePaths,
|
|
398
|
+
schemaPath: string,
|
|
399
|
+
composeProject: string,
|
|
400
|
+
): Promise<void> {
|
|
401
|
+
if (_composePushInFlight) {
|
|
402
|
+
_composePushQueued = true
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
_composePushInFlight = true
|
|
406
|
+
try {
|
|
407
|
+
do {
|
|
408
|
+
_composePushQueued = false
|
|
409
|
+
await runComposeSchemaPush(cwd, config, paths, schemaPath, composeProject)
|
|
410
|
+
} while (_composePushQueued)
|
|
411
|
+
} finally {
|
|
412
|
+
_composePushInFlight = false
|
|
413
|
+
}
|
|
280
414
|
}
|
|
281
415
|
|
|
282
|
-
function runComposeEnginePush(
|
|
416
|
+
async function runComposeEnginePush(
|
|
283
417
|
paths: SelfHostComposePaths,
|
|
284
418
|
cwd: string,
|
|
285
419
|
composeProject: string,
|
|
286
|
-
|
|
420
|
+
config: SupatypeProjectConfig,
|
|
421
|
+
sources?: SchemaSourcePushArtifacts | null,
|
|
422
|
+
): Promise<{ status: number; output: string }> {
|
|
287
423
|
const envFile = resolve(cwd, ".env")
|
|
288
|
-
const composeArgs = ["compose"]
|
|
424
|
+
const composeArgs = ["compose", "--progress", "quiet"]
|
|
289
425
|
if (composeProject) composeArgs.push("-p", composeProject)
|
|
290
426
|
composeArgs.push("--project-directory", cwd)
|
|
291
427
|
composeArgs.push("-f", paths.composePath)
|
|
@@ -306,16 +442,159 @@ function runComposeEnginePush(
|
|
|
306
442
|
"--force",
|
|
307
443
|
"--non-interactive",
|
|
308
444
|
)
|
|
445
|
+
if (sources) {
|
|
446
|
+
composeArgs.push(
|
|
447
|
+
"--schema-sources-gz",
|
|
448
|
+
sources.dockerGzPath,
|
|
449
|
+
"--schema-sources-manifest",
|
|
450
|
+
sources.dockerManifestPath,
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
const pushEnv: NodeJS.ProcessEnv = {
|
|
454
|
+
...process.env,
|
|
455
|
+
COMPOSE_PROGRESS: "quiet",
|
|
456
|
+
}
|
|
457
|
+
const engineImage = await schemaEngineImageForPush(config)
|
|
458
|
+
if (engineImage) {
|
|
459
|
+
pushEnv.SUPATYPE_ENGINE_IMAGE = engineImage
|
|
460
|
+
}
|
|
309
461
|
const result = spawnSync("docker", composeArgs, {
|
|
310
462
|
cwd,
|
|
311
463
|
encoding: "utf8",
|
|
312
464
|
maxBuffer: 10 * 1024 * 1024,
|
|
465
|
+
env: pushEnv,
|
|
313
466
|
})
|
|
314
467
|
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim()
|
|
315
|
-
|
|
316
|
-
|
|
468
|
+
const exitStatus = result.status ?? 1
|
|
469
|
+
const pushResult = parseEnginePushOutput(output)
|
|
470
|
+
|
|
471
|
+
if (exitStatus === 0) {
|
|
472
|
+
if (pushResult) {
|
|
473
|
+
console.log(`[supatype] ${formatEnginePushMessage(pushResult)}`)
|
|
474
|
+
} else {
|
|
475
|
+
console.log("[supatype] Schema applied.")
|
|
476
|
+
}
|
|
317
477
|
}
|
|
318
|
-
|
|
478
|
+
|
|
479
|
+
return { status: exitStatus, output }
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function runComposeEngineDiff(
|
|
483
|
+
paths: SelfHostComposePaths,
|
|
484
|
+
cwd: string,
|
|
485
|
+
composeProject: string,
|
|
486
|
+
config: SupatypeProjectConfig,
|
|
487
|
+
pgSchema: string,
|
|
488
|
+
): Promise<{ status: number; output: string; diff: DiffResult | null }> {
|
|
489
|
+
const envFile = resolve(cwd, ".env")
|
|
490
|
+
const composeArgs = ["compose", "--progress", "quiet"]
|
|
491
|
+
if (composeProject) composeArgs.push("-p", composeProject)
|
|
492
|
+
composeArgs.push("--project-directory", cwd)
|
|
493
|
+
composeArgs.push("-f", paths.composePath)
|
|
494
|
+
if (existsSync(envFile)) {
|
|
495
|
+
composeArgs.push("--env-file", envFile)
|
|
496
|
+
}
|
|
497
|
+
composeArgs.push(
|
|
498
|
+
"--profile",
|
|
499
|
+
"tools",
|
|
500
|
+
"run",
|
|
501
|
+
"--rm",
|
|
502
|
+
"schema-engine",
|
|
503
|
+
"diff",
|
|
504
|
+
"-i",
|
|
505
|
+
"/project/.supatype/schema.ast.json",
|
|
506
|
+
"--database-url",
|
|
507
|
+
composeDbUrl(),
|
|
508
|
+
"--schema",
|
|
509
|
+
pgSchema,
|
|
510
|
+
)
|
|
511
|
+
const diffEnv: NodeJS.ProcessEnv = {
|
|
512
|
+
...process.env,
|
|
513
|
+
COMPOSE_PROGRESS: "quiet",
|
|
514
|
+
}
|
|
515
|
+
const engineImage = await schemaEngineImageForPush(config)
|
|
516
|
+
if (engineImage) {
|
|
517
|
+
diffEnv.SUPATYPE_ENGINE_IMAGE = engineImage
|
|
518
|
+
}
|
|
519
|
+
const result = spawnSync("docker", composeArgs, {
|
|
520
|
+
cwd,
|
|
521
|
+
encoding: "utf8",
|
|
522
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
523
|
+
env: diffEnv,
|
|
524
|
+
})
|
|
525
|
+
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim()
|
|
526
|
+
const exitStatus = result.status ?? 1
|
|
527
|
+
const diff = parseEngineJsonOutput<DiffResult>(output)
|
|
528
|
+
|
|
529
|
+
return { status: exitStatus, output, diff }
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* `supatype diff` when `provider: docker`. Uses in-compose schema-engine unless
|
|
534
|
+
* `overrides.engine` is set — then Postgres is published to the host and diff runs
|
|
535
|
+
* through the local engine binary.
|
|
536
|
+
*/
|
|
537
|
+
export async function diffSchemaDocker(cwd: string, config: SupatypeProjectConfig): Promise<DiffResult> {
|
|
538
|
+
if (resolveRuntimeProvider(config) !== "docker") {
|
|
539
|
+
throw new Error("diffSchemaDocker requires provider: docker")
|
|
540
|
+
}
|
|
541
|
+
const project = composeProjectName(config.project.name)
|
|
542
|
+
const pgSchema = config.schema?.pg_schema ?? "public"
|
|
543
|
+
|
|
544
|
+
if (hasEngineOverride(config)) {
|
|
545
|
+
const brand = { intro: "Schema diff" }
|
|
546
|
+
await ensureDockerDbPublishedForHostEngine(cwd, config, brand)
|
|
547
|
+
const schemaPath = schemaPathFromProject(config, cwd)
|
|
548
|
+
const ast = loadSchemaAst(schemaPath, cwd)
|
|
549
|
+
await ensureEngine()
|
|
550
|
+
return engineRequest<DiffResult>("/diff", {
|
|
551
|
+
ast,
|
|
552
|
+
database_url: hostComposeDbUrl(cwd),
|
|
553
|
+
schema: pgSchema,
|
|
554
|
+
})
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const kongPort = await resolveKongPort(cwd)
|
|
558
|
+
const now = Math.floor(Date.now() / 1000)
|
|
559
|
+
const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 }
|
|
560
|
+
const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
|
|
561
|
+
const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
|
|
562
|
+
ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, undefined)
|
|
563
|
+
|
|
564
|
+
const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
|
|
565
|
+
const diffBrand = { intro: "Schema diff" }
|
|
566
|
+
|
|
567
|
+
const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project, {
|
|
568
|
+
quiet: true,
|
|
569
|
+
brand: diffBrand,
|
|
570
|
+
})
|
|
571
|
+
if (up !== 0) {
|
|
572
|
+
exitComposeFailed(up, "Could not start Postgres (compose db service).", diffBrand)
|
|
573
|
+
}
|
|
574
|
+
await waitComposeHealthy(paths, cwd, 120_000, project)
|
|
575
|
+
|
|
576
|
+
const schemaPath = schemaPathFromProject(config, cwd)
|
|
577
|
+
const ast = loadSchemaAst(schemaPath, cwd)
|
|
578
|
+
|
|
579
|
+
const supatypeDir = join(cwd, ".supatype")
|
|
580
|
+
mkdirSync(supatypeDir, { recursive: true })
|
|
581
|
+
const astPath = join(supatypeDir, "schema.ast.json")
|
|
582
|
+
writeFileSync(astPath, JSON.stringify(ast))
|
|
583
|
+
|
|
584
|
+
let result = await runComposeEngineDiff(paths, cwd, project, config, pgSchema)
|
|
585
|
+
// Windows Docker bind mounts can lag briefly after the host write.
|
|
586
|
+
if (result.status !== 0) {
|
|
587
|
+
await new Promise((r) => setTimeout(r, 250))
|
|
588
|
+
result = await runComposeEngineDiff(paths, cwd, project, config, pgSchema)
|
|
589
|
+
}
|
|
590
|
+
if (result.status !== 0) {
|
|
591
|
+
const detail = filterComposeNoise(result.output) || result.output
|
|
592
|
+
throw new Error(detail || `Engine schema diff failed (exit ${result.status})`)
|
|
593
|
+
}
|
|
594
|
+
if (!result.diff) {
|
|
595
|
+
throw new Error("Engine diff returned no result")
|
|
596
|
+
}
|
|
597
|
+
return result.diff
|
|
319
598
|
}
|
|
320
599
|
|
|
321
600
|
/**
|
|
@@ -335,17 +614,39 @@ export async function pushSchemaDocker(cwd: string, config: SupatypeProjectConfi
|
|
|
335
614
|
const jwtBase = { iss: "supatype", iat: now, exp: now + 315_360_000 }
|
|
336
615
|
const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
|
|
337
616
|
const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
|
|
338
|
-
ensureDevComposeEnv(cwd, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
617
|
+
ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
339
618
|
|
|
340
619
|
const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
|
|
620
|
+
const pushBrand = { intro: "Push schema" }
|
|
341
621
|
|
|
342
622
|
console.log(`[supatype] provider: docker — applying schema via compose (project ${project})...`)
|
|
343
|
-
const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project
|
|
344
|
-
|
|
623
|
+
const up = runDockerCompose(paths.composePath, ["up", "-d", "db"], cwd, project, {
|
|
624
|
+
quiet: true,
|
|
625
|
+
brand: pushBrand,
|
|
626
|
+
})
|
|
627
|
+
if (up !== 0) {
|
|
628
|
+
exitComposeFailed(up, "Could not start Postgres (compose db service).", pushBrand)
|
|
629
|
+
}
|
|
345
630
|
await waitComposeHealthy(paths, cwd, 120_000, project)
|
|
346
631
|
|
|
347
632
|
const schemaPath = schemaPathFromProject(config, cwd)
|
|
633
|
+
const ast = loadSchemaAst(schemaPath, cwd)
|
|
348
634
|
await runComposeSchemaPush(cwd, config, paths, schemaPath, project)
|
|
635
|
+
|
|
636
|
+
const upGateway = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
|
|
637
|
+
quiet: true,
|
|
638
|
+
brand: pushBrand,
|
|
639
|
+
})
|
|
640
|
+
if (upGateway !== 0) {
|
|
641
|
+
exitComposeFailed(upGateway, "Could not start the Compose gateway stack.", pushBrand)
|
|
642
|
+
}
|
|
643
|
+
await waitKongReady(kongPort, 120)
|
|
644
|
+
await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey)
|
|
645
|
+
|
|
646
|
+
await ensureFirstAdminUserForProject(cwd, config, {
|
|
647
|
+
compose: { project, composePath: paths.composePath },
|
|
648
|
+
})
|
|
649
|
+
|
|
349
650
|
console.log("[supatype] Schema pushed.")
|
|
350
651
|
}
|
|
351
652
|
|
|
@@ -365,13 +666,22 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
365
666
|
const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
|
|
366
667
|
const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
|
|
367
668
|
|
|
368
|
-
ensureDevComposeEnv(cwd, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
669
|
+
ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
369
670
|
|
|
370
671
|
console.log(`[supatype] provider: docker — starting self-host Compose stack (project ${project}, gateway :${kongPort})...`)
|
|
371
672
|
const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
|
|
673
|
+
await recoverStaleDevSession(cwd)
|
|
674
|
+
await handleComposeProjectRename(cwd, config.project.name, paths)
|
|
675
|
+
const devBrand = { intro: "Local development" }
|
|
372
676
|
|
|
373
|
-
const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project
|
|
374
|
-
|
|
677
|
+
const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
|
|
678
|
+
quiet: true,
|
|
679
|
+
brand: devBrand,
|
|
680
|
+
})
|
|
681
|
+
if (upStatus !== 0) {
|
|
682
|
+
endDevSession()
|
|
683
|
+
exitComposeFailed(upStatus, "Could not start the local Compose stack.", devBrand)
|
|
684
|
+
}
|
|
375
685
|
|
|
376
686
|
console.log("[supatype] Waiting for Postgres (compose)...")
|
|
377
687
|
await waitComposeHealthy(paths, cwd, 180_000, project)
|
|
@@ -381,9 +691,33 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
381
691
|
console.error("[supatype] Initial schema push failed:", (e as Error).message),
|
|
382
692
|
)
|
|
383
693
|
|
|
694
|
+
await ensureFirstAdminUserForProject(cwd, config, {
|
|
695
|
+
compose: { project, composePath: paths.composePath },
|
|
696
|
+
})
|
|
697
|
+
|
|
384
698
|
console.log("[supatype] Waiting for API gateway...")
|
|
385
699
|
await waitKongReady(kongPort, 120)
|
|
386
700
|
|
|
701
|
+
writeLocalEnvironment(cwd, {
|
|
702
|
+
target: "local",
|
|
703
|
+
apiUrl: `http://localhost:${kongPort}`,
|
|
704
|
+
databaseUrl: hasEngineOverride(config) ? hostComposeDbUrl(cwd) : composeDbUrl(),
|
|
705
|
+
projectRef: config.project.name,
|
|
706
|
+
kongPort,
|
|
707
|
+
provider: "docker",
|
|
708
|
+
})
|
|
709
|
+
|
|
710
|
+
writeDevSessionLock(cwd, {
|
|
711
|
+
composeProject: project,
|
|
712
|
+
projectRef: config.project.name,
|
|
713
|
+
composePath: paths.composePath,
|
|
714
|
+
kongPort,
|
|
715
|
+
startedAt: new Date().toISOString(),
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
const ast = loadSchemaAst(schemaPath, cwd)
|
|
719
|
+
await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey)
|
|
720
|
+
|
|
387
721
|
const pidDir = join(homedir(), ".supatype", "projects", config.project.name, "pid")
|
|
388
722
|
mkdirSync(pidDir, { recursive: true })
|
|
389
723
|
|
|
@@ -423,33 +757,85 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
423
757
|
|
|
424
758
|
const appProc = startProxyDevApp(cwd, config, pidDir)
|
|
425
759
|
|
|
426
|
-
|
|
427
|
-
|
|
760
|
+
let schemaWatcher: import("node:fs").FSWatcher | null = null
|
|
761
|
+
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
|
762
|
+
|
|
763
|
+
registerDevShutdown(async () => {
|
|
764
|
+
schemaWatcher?.close()
|
|
765
|
+
schemaWatcher = null
|
|
766
|
+
if (debounceTimer) {
|
|
767
|
+
clearTimeout(debounceTimer)
|
|
768
|
+
debounceTimer = null
|
|
769
|
+
}
|
|
770
|
+
console.log("[supatype] Shutting down compose...")
|
|
428
771
|
await studioProc?.stop()
|
|
429
772
|
await appProc?.stop()
|
|
430
|
-
runDockerCompose(paths.composePath, ["down"], cwd, project)
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
773
|
+
const downStatus = runDockerCompose(paths.composePath, ["down"], cwd, project, { quiet: true })
|
|
774
|
+
if (downStatus === 0) {
|
|
775
|
+
console.log("[supatype] Compose stack stopped.")
|
|
776
|
+
} else {
|
|
777
|
+
console.warn(`[supatype] Compose down exited with status ${downStatus}.`)
|
|
778
|
+
}
|
|
779
|
+
}, {
|
|
780
|
+
cwd,
|
|
781
|
+
compose: { cwd, composePath: paths.composePath, composeProject: project },
|
|
782
|
+
})
|
|
435
783
|
|
|
436
784
|
if (opts.watch) {
|
|
437
785
|
const schemaDir = join(projectRootFromConfig(config, cwd), config.schema?.path ?? "schema/index.ts", "..")
|
|
438
786
|
console.log(`[supatype] Watching ${schemaDir} for changes...`)
|
|
439
787
|
const { watch } = await import("node:fs")
|
|
440
|
-
|
|
441
|
-
watch(schemaDir, { recursive: true }, (_eventType, filename) => {
|
|
788
|
+
schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
|
|
442
789
|
if (!filename?.endsWith(".ts")) return
|
|
443
790
|
if (debounceTimer) clearTimeout(debounceTimer)
|
|
444
791
|
debounceTimer = setTimeout(() => {
|
|
445
792
|
debounceTimer = null
|
|
446
793
|
console.log(`\n[supatype] Change detected in ${filename}, pushing schema...`)
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
794
|
+
runComposeSchemaPushQueued(cwd, config, paths, schemaPath, project)
|
|
795
|
+
.then(async () => {
|
|
796
|
+
const updatedAst = loadSchemaAst(schemaPath, cwd)
|
|
797
|
+
await provisionDockerStorageBuckets(updatedAst, kongPort, serviceRoleKey)
|
|
798
|
+
})
|
|
799
|
+
.catch((e: unknown) =>
|
|
800
|
+
console.error("[supatype] Schema push failed:", (e as Error).message),
|
|
801
|
+
)
|
|
450
802
|
}, 300)
|
|
451
803
|
})
|
|
452
804
|
}
|
|
453
805
|
|
|
454
806
|
await new Promise<never>(() => undefined)
|
|
455
807
|
}
|
|
808
|
+
|
|
809
|
+
function astHasSystemAuthRelation(ast: unknown): boolean {
|
|
810
|
+
const obj = ast as { models?: Array<{ fields?: Record<string, { kind?: string; target?: string }> }> }
|
|
811
|
+
if (!obj?.models) return false
|
|
812
|
+
for (const model of obj.models) {
|
|
813
|
+
if (!model.fields) continue
|
|
814
|
+
for (const field of Object.values(model.fields)) {
|
|
815
|
+
if (field.kind === "relation" && field.target === "supatype:user") return true
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
return false
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function grantAuthSchemaAccess(
|
|
822
|
+
paths: SelfHostComposePaths,
|
|
823
|
+
cwd: string,
|
|
824
|
+
composeProject: string,
|
|
825
|
+
): void {
|
|
826
|
+
const composeDir = dirname(paths.composePath)
|
|
827
|
+
const baseArgs = [
|
|
828
|
+
"compose", "-p", composeProject,
|
|
829
|
+
"-f", paths.composePath,
|
|
830
|
+
]
|
|
831
|
+
const sql = "GRANT USAGE ON SCHEMA auth TO service_role; GRANT SELECT ON auth.users TO service_role;"
|
|
832
|
+
const result = spawnSync(
|
|
833
|
+
"docker",
|
|
834
|
+
[...baseArgs, "exec", "-T", "-e", "PGPASSWORD=postgres", "db",
|
|
835
|
+
"psql", "-U", "supatype_admin", "-d", "supatype", "-c", sql],
|
|
836
|
+
{ cwd: composeDir, encoding: "utf8", timeout: 10_000 },
|
|
837
|
+
)
|
|
838
|
+
if (result.status !== 0) {
|
|
839
|
+
console.warn("[supatype] Could not grant service_role access to auth.users — Studio relation preview may fail.")
|
|
840
|
+
}
|
|
841
|
+
}
|