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