@supatype/cli 0.1.0-alpha.6 → 0.1.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +208 -1
- package/.turbo/turbo-typecheck.log +1 -1
- package/dist/app/proxy-dev-app.d.ts +13 -0
- package/dist/app/proxy-dev-app.d.ts.map +1 -0
- package/dist/app/proxy-dev-app.js +53 -0
- package/dist/app/proxy-dev-app.js.map +1 -0
- package/dist/app-config.d.ts +7 -0
- package/dist/app-config.d.ts.map +1 -0
- package/dist/app-config.js +113 -0
- package/dist/app-config.js.map +1 -0
- package/dist/augmentation-generator.d.ts +2 -0
- package/dist/augmentation-generator.d.ts.map +1 -0
- package/dist/augmentation-generator.js +111 -0
- package/dist/augmentation-generator.js.map +1 -0
- package/dist/binary-cache.d.ts +94 -0
- package/dist/binary-cache.d.ts.map +1 -0
- package/dist/binary-cache.js +669 -0
- package/dist/binary-cache.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +13 -7
- package/dist/cli.js.map +1 -1
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +4 -3
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/app.d.ts.map +1 -1
- package/dist/commands/app.js +56 -209
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/cache.d.ts +6 -0
- package/dist/commands/cache.d.ts.map +1 -0
- package/dist/commands/cache.js +105 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/cloud.d.ts +20 -0
- package/dist/commands/cloud.d.ts.map +1 -1
- package/dist/commands/cloud.js +50 -52
- package/dist/commands/cloud.js.map +1 -1
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +47 -54
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts +2 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +79 -52
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +11 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +759 -385
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +30 -15
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/engine.d.ts +1 -3
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +13 -85
- package/dist/commands/engine.js.map +1 -1
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +92 -105
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +22 -12
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +137 -410
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate-from-v1.d.ts +5 -0
- package/dist/commands/migrate-from-v1.d.ts.map +1 -0
- package/dist/commands/migrate-from-v1.js +125 -0
- package/dist/commands/migrate-from-v1.js.map +1 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +27 -23
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/pg.d.ts +8 -0
- package/dist/commands/pg.d.ts.map +1 -0
- package/dist/commands/pg.js +102 -0
- package/dist/commands/pg.js.map +1 -0
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +5 -66
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +128 -38
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/seed.d.ts +2 -0
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/seed.js +44 -11
- package/dist/commands/seed.js.map +1 -1
- package/dist/commands/self-host.d.ts +7 -1
- package/dist/commands/self-host.d.ts.map +1 -1
- package/dist/commands/self-host.js +272 -758
- package/dist/commands/self-host.js.map +1 -1
- package/dist/commands/self-update.d.ts +9 -0
- package/dist/commands/self-update.d.ts.map +1 -0
- package/dist/commands/self-update.js +33 -0
- package/dist/commands/self-update.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +4 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/types.d.ts +3 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +62 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +93 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/components.d.ts +5 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +3 -0
- package/dist/components.js.map +1 -0
- package/dist/config.d.ts +10 -51
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +101 -33
- package/dist/config.js.map +1 -1
- package/dist/dev-compose.d.ts +17 -0
- package/dist/dev-compose.d.ts.map +1 -0
- package/dist/dev-compose.js +374 -0
- package/dist/dev-compose.js.map +1 -0
- package/dist/diff-output.d.ts +4 -0
- package/dist/diff-output.d.ts.map +1 -0
- package/dist/diff-output.js +12 -0
- package/dist/diff-output.js.map +1 -0
- package/dist/docker-postgres.d.ts +57 -0
- package/dist/docker-postgres.d.ts.map +1 -0
- package/dist/docker-postgres.js +208 -0
- package/dist/docker-postgres.js.map +1 -0
- package/dist/engine-client.d.ts +69 -0
- package/dist/engine-client.d.ts.map +1 -0
- package/dist/engine-client.js +157 -0
- package/dist/engine-client.js.map +1 -0
- package/dist/ensure-binary.d.ts +7 -0
- package/dist/ensure-binary.d.ts.map +1 -0
- package/dist/ensure-binary.js +17 -0
- package/dist/ensure-binary.js.map +1 -0
- package/dist/functions-router-gen.d.ts +14 -0
- package/dist/functions-router-gen.d.ts.map +1 -0
- package/dist/functions-router-gen.js +199 -0
- package/dist/functions-router-gen.js.map +1 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/kong-config.d.ts +25 -0
- package/dist/kong-config.d.ts.map +1 -0
- package/dist/kong-config.js +71 -0
- package/dist/kong-config.js.map +1 -0
- package/dist/local-gateway.d.ts +7 -0
- package/dist/local-gateway.d.ts.map +1 -0
- package/dist/local-gateway.js +9 -0
- package/dist/local-gateway.js.map +1 -0
- package/dist/local-storage.d.ts +8 -0
- package/dist/local-storage.d.ts.map +1 -0
- package/dist/local-storage.js +14 -0
- package/dist/local-storage.js.map +1 -0
- package/dist/pgbouncer-userlist.d.ts +5 -0
- package/dist/pgbouncer-userlist.d.ts.map +1 -0
- package/dist/pgbouncer-userlist.js +14 -0
- package/dist/pgbouncer-userlist.js.map +1 -0
- package/dist/postgres-ctl.d.ts +44 -0
- package/dist/postgres-ctl.d.ts.map +1 -0
- package/dist/postgres-ctl.js +137 -0
- package/dist/postgres-ctl.js.map +1 -0
- package/dist/process-manager.d.ts +43 -0
- package/dist/process-manager.d.ts.map +1 -0
- package/dist/process-manager.js +135 -0
- package/dist/process-manager.js.map +1 -0
- package/dist/project-config.d.ts +235 -0
- package/dist/project-config.d.ts.map +1 -0
- package/dist/project-config.js +160 -0
- package/dist/project-config.js.map +1 -0
- package/dist/pull-utils.d.ts +15 -0
- package/dist/pull-utils.d.ts.map +1 -1
- package/dist/pull-utils.js +12 -0
- package/dist/pull-utils.js.map +1 -1
- package/dist/release-pins.d.ts +7 -0
- package/dist/release-pins.d.ts.map +1 -0
- package/dist/release-pins.js +27 -0
- package/dist/release-pins.js.map +1 -0
- package/dist/release-public-key.d.ts +8 -0
- package/dist/release-public-key.d.ts.map +1 -0
- package/dist/release-public-key.js +13 -0
- package/dist/release-public-key.js.map +1 -0
- package/dist/runtime-routes.d.ts +34 -0
- package/dist/runtime-routes.d.ts.map +1 -0
- package/dist/runtime-routes.js +252 -0
- package/dist/runtime-routes.js.map +1 -0
- package/dist/schema-ast-v2.d.ts +127 -0
- package/dist/schema-ast-v2.d.ts.map +1 -0
- package/dist/schema-ast-v2.js +226 -0
- package/dist/schema-ast-v2.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +5 -6
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +36 -20
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/self-host-compose.d.ts +22 -0
- package/dist/self-host-compose.d.ts.map +1 -0
- package/dist/self-host-compose.js +347 -0
- package/dist/self-host-compose.js.map +1 -0
- package/dist/storage-provision.d.ts +24 -0
- package/dist/storage-provision.d.ts.map +1 -0
- package/dist/storage-provision.js +44 -0
- package/dist/storage-provision.js.map +1 -0
- package/dist/studio-admin-roles.d.ts +7 -0
- package/dist/studio-admin-roles.d.ts.map +1 -0
- package/dist/studio-admin-roles.js +14 -0
- package/dist/studio-admin-roles.js.map +1 -0
- package/dist/studio-dev-server.d.ts +22 -0
- package/dist/studio-dev-server.d.ts.map +1 -0
- package/dist/studio-dev-server.js +28 -0
- package/dist/studio-dev-server.js.map +1 -0
- package/dist/systemd.d.ts +26 -0
- package/dist/systemd.d.ts.map +1 -0
- package/dist/systemd.js +102 -0
- package/dist/systemd.js.map +1 -0
- package/dist/tsx-runner.d.ts.map +1 -1
- package/dist/tsx-runner.js +9 -2
- package/dist/tsx-runner.js.map +1 -1
- package/dist/type-extractor.d.ts +4 -0
- package/dist/type-extractor.d.ts.map +1 -0
- package/dist/type-extractor.js +1213 -0
- package/dist/type-extractor.js.map +1 -0
- package/dist/type-resolver.d.ts +33 -0
- package/dist/type-resolver.d.ts.map +1 -0
- package/dist/type-resolver.js +338 -0
- package/dist/type-resolver.js.map +1 -0
- package/package.json +4 -3
- package/releases/deno/VERSION +1 -0
- package/scripts/mirror-deno-release.sh +76 -0
- package/src/TYPE-RESOLUTION.md +294 -0
- package/src/app/proxy-dev-app.ts +67 -0
- package/src/app-config.ts +128 -0
- package/src/augmentation-generator.ts +126 -0
- package/src/binary-cache.ts +822 -0
- package/src/cli.ts +13 -8
- package/src/commands/admin.ts +4 -3
- package/src/commands/app.ts +67 -231
- package/src/commands/cache.ts +117 -0
- package/src/commands/cloud.ts +63 -64
- package/src/commands/db.ts +54 -63
- package/src/commands/deploy.ts +96 -62
- package/src/commands/dev.ts +933 -405
- package/src/commands/diff.ts +31 -29
- package/src/commands/engine.ts +13 -116
- package/src/commands/functions.ts +97 -115
- package/src/commands/generate.ts +23 -10
- package/src/commands/init.ts +149 -414
- package/src/commands/migrate-from-v1.ts +131 -0
- package/src/commands/migrate.ts +27 -23
- package/src/commands/pg.ts +133 -0
- package/src/commands/pull.ts +6 -85
- package/src/commands/push.ts +161 -56
- package/src/commands/seed.ts +54 -12
- package/src/commands/self-host.ts +312 -880
- package/src/commands/self-update.ts +45 -0
- package/src/commands/status.ts +4 -3
- package/src/commands/types.ts +76 -0
- package/src/commands/update.ts +109 -0
- package/src/components.ts +6 -0
- package/src/config.ts +127 -94
- package/src/dev-compose.ts +455 -0
- package/src/diff-output.ts +12 -0
- package/src/docker-postgres.ts +295 -0
- package/src/engine-client.ts +236 -0
- package/src/ensure-binary.ts +28 -0
- package/src/functions-router-gen.ts +224 -0
- package/src/index.ts +4 -12
- package/src/kong-config.ts +93 -0
- package/src/local-gateway.ts +9 -0
- package/src/local-storage.ts +14 -0
- package/src/pgbouncer-userlist.ts +15 -0
- package/src/postgres-ctl.ts +171 -0
- package/src/process-manager.ts +168 -0
- package/src/project-config.ts +386 -0
- package/src/pull-utils.ts +24 -0
- package/src/release-pins.ts +31 -0
- package/src/release-public-key.ts +12 -0
- package/src/runtime-routes.ts +291 -0
- package/src/schema-ast-v2.ts +324 -0
- package/src/scripts/postinstall.ts +36 -25
- package/src/self-host-compose.ts +389 -0
- package/src/storage-provision.ts +58 -0
- package/src/studio-admin-roles.ts +16 -0
- package/src/studio-dev-server.ts +53 -0
- package/src/systemd.ts +137 -0
- package/src/tsx-runner.ts +11 -1
- package/src/type-extractor.ts +1479 -0
- package/src/type-resolver.ts +457 -0
- package/tests/app-command.test.ts +54 -0
- package/tests/augmentation-generator.test.ts +59 -0
- package/tests/binary-cache-cloud-overrides.test.ts +123 -0
- package/tests/cached-artifact-format.test.ts +84 -0
- package/tests/cli-help.test.ts +40 -14
- package/tests/config.test.ts +171 -37
- package/tests/docker-postgres.test.ts +39 -0
- package/tests/engine-distribution.test.ts +3 -3
- package/tests/ensure-binary.test.ts +59 -0
- package/tests/init.test.ts +28 -86
- package/tests/migrate-from-v1.test.ts +29 -0
- package/tests/normalize-admin-config.test.ts +48 -0
- package/tests/pg-spawn-env.test.ts +18 -0
- package/tests/postgres-archive-tag.test.ts +9 -0
- package/tests/proxy-dev-app.test.ts +33 -0
- package/tests/pull-utils.test.ts +36 -1
- package/tests/release-pins.test.ts +28 -0
- package/tests/runtime-contract.test.ts +351 -0
- package/tests/seed-discover.test.ts +31 -0
- package/tests/studio-admin-roles.test.ts +27 -0
- package/tests/tsconfig.json +9 -0
- package/tests/type-extractor.test.ts +985 -0
- package/tests/type-resolver.test.ts +59 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +12 -0
- package/dist/engine/cache.d.ts +0 -37
- package/dist/engine/cache.d.ts.map +0 -1
- package/dist/engine/cache.js +0 -121
- package/dist/engine/cache.js.map +0 -1
- package/dist/engine/download.d.ts +0 -19
- package/dist/engine/download.d.ts.map +0 -1
- package/dist/engine/download.js +0 -108
- package/dist/engine/download.js.map +0 -1
- package/dist/engine/platform.d.ts +0 -24
- package/dist/engine/platform.d.ts.map +0 -1
- package/dist/engine/platform.js +0 -50
- package/dist/engine/platform.js.map +0 -1
- package/dist/engine/resolve.d.ts +0 -37
- package/dist/engine/resolve.d.ts.map +0 -1
- package/dist/engine/resolve.js +0 -133
- package/dist/engine/resolve.js.map +0 -1
- package/dist/engine/update-notify.d.ts +0 -11
- package/dist/engine/update-notify.d.ts.map +0 -1
- package/dist/engine/update-notify.js +0 -43
- package/dist/engine/update-notify.js.map +0 -1
- package/dist/engine/verify.d.ts +0 -50
- package/dist/engine/verify.d.ts.map +0 -1
- package/dist/engine/verify.js +0 -161
- package/dist/engine/verify.js.map +0 -1
- package/dist/engine-version.d.ts +0 -35
- package/dist/engine-version.d.ts.map +0 -1
- package/dist/engine-version.js +0 -35
- package/dist/engine-version.js.map +0 -1
- package/dist/engine.d.ts +0 -34
- package/dist/engine.d.ts.map +0 -1
- package/dist/engine.js +0 -76
- package/dist/engine.js.map +0 -1
- package/src/engine/cache.ts +0 -135
- package/src/engine/download.ts +0 -143
- package/src/engine/platform.ts +0 -66
- package/src/engine/resolve.ts +0 -197
- package/src/engine/update-notify.ts +0 -50
- package/src/engine/verify.ts +0 -206
- package/src/engine-version.ts +0 -39
- package/src/engine.ts +0 -99
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { dirname, join, relative, resolve } from "node:path"
|
|
3
|
+
import { spawnSync } from "node:child_process"
|
|
4
|
+
import { preferredFunctionsPathFromProject, type SupatypeProjectConfig } from "./project-config.js"
|
|
5
|
+
import { hasEngineOverride, hasStudioOverride } from "./binary-cache.js"
|
|
6
|
+
import { buildKongDeclarative } from "./kong-config.js"
|
|
7
|
+
|
|
8
|
+
export interface SelfHostComposePaths {
|
|
9
|
+
dir: string
|
|
10
|
+
composePath: string
|
|
11
|
+
kongPath: string
|
|
12
|
+
nginxPath: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function selfHostComposePaths(cwd: string): SelfHostComposePaths {
|
|
16
|
+
const dir = resolve(cwd, ".supatype", "self-host")
|
|
17
|
+
return {
|
|
18
|
+
dir,
|
|
19
|
+
composePath: join(dir, "docker-compose.yml"),
|
|
20
|
+
kongPath: join(dir, "kong.yml"),
|
|
21
|
+
nginxPath: join(dir, "nginx.conf"),
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function appUpstreamForCompose(config: SupatypeProjectConfig): string | undefined {
|
|
26
|
+
if (config.app.mode !== "proxy") return undefined
|
|
27
|
+
const upstream = config.app.upstream?.trim()
|
|
28
|
+
return upstream && upstream.length > 0 ? upstream : undefined
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function staticDirForCompose(config: SupatypeProjectConfig): string | undefined {
|
|
32
|
+
if (config.app.mode !== "static") return undefined
|
|
33
|
+
const dir = config.app.static_dir?.trim()
|
|
34
|
+
return dir && dir.length > 0 ? dir : "./public"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Bind-mount source for `/project` in generated compose files.
|
|
39
|
+
* Paths are resolved from `--project-directory` (always the project root in `runDockerCompose`),
|
|
40
|
+
* not from the compose file directory — use `.` not `../..`.
|
|
41
|
+
*/
|
|
42
|
+
function projectMountPath(_cwd: string): string {
|
|
43
|
+
return "."
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Paths in generated compose are resolved from `--project-directory` (project root). */
|
|
47
|
+
function relativeFromProjectRoot(cwd: string, target: string): string {
|
|
48
|
+
let rel = relative(resolve(cwd), resolve(target)).replace(/\\/g, "/")
|
|
49
|
+
if (!rel.startsWith(".") && !rel.startsWith("/")) {
|
|
50
|
+
rel = `./${rel}`
|
|
51
|
+
}
|
|
52
|
+
return rel
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function kongMountPath(_cwd: string): string {
|
|
56
|
+
return ".supatype/self-host/kong.yml"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Host Vite dev server as seen from Kong inside Docker Compose. */
|
|
60
|
+
export const COMPOSE_STUDIO_HOST_URL = "http://host.docker.internal:3002"
|
|
61
|
+
|
|
62
|
+
/** Local monorepo Studio image for `supatype dev` (dogfooding). */
|
|
63
|
+
function studioServiceBlock(cwd: string, devLocal: boolean): string {
|
|
64
|
+
if (!devLocal) {
|
|
65
|
+
return ` image: \${SUPATYPE_STUDIO_IMAGE:-supatype/studio:latest}`
|
|
66
|
+
}
|
|
67
|
+
const monorepoRoot = resolve(cwd, "..", "supatype")
|
|
68
|
+
const studioDockerfile = join(monorepoRoot, "packages", "studio", "Dockerfile")
|
|
69
|
+
if (!existsSync(studioDockerfile) || !existsSync(join(monorepoRoot, "pnpm-workspace.yaml"))) {
|
|
70
|
+
return ` image: \${SUPATYPE_STUDIO_IMAGE:-supatype/studio:latest}`
|
|
71
|
+
}
|
|
72
|
+
const context = relativeFromProjectRoot(cwd, monorepoRoot)
|
|
73
|
+
return ` build:
|
|
74
|
+
context: ${context}
|
|
75
|
+
dockerfile: packages/studio/Dockerfile
|
|
76
|
+
image: supatype/studio:dev-local`
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Host dev app (Astro/Vite on the machine) as seen from inside compose services. */
|
|
80
|
+
function proxyUpstreamForCompose(upstream: string, devLocal: boolean): string {
|
|
81
|
+
const trimmed = upstream.trim()
|
|
82
|
+
if (!devLocal) return trimmed
|
|
83
|
+
try {
|
|
84
|
+
const url = new URL(trimmed)
|
|
85
|
+
if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
|
|
86
|
+
url.hostname = "host.docker.internal"
|
|
87
|
+
return url.toString()
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
// keep literal upstream when not a URL
|
|
91
|
+
}
|
|
92
|
+
return trimmed
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function serverAppEnvForCompose(config: SupatypeProjectConfig, devLocal: boolean): string {
|
|
96
|
+
const mode = config.app.mode ?? "none"
|
|
97
|
+
const lines = [` SUPATYPE_APP_MODE: ${mode}`]
|
|
98
|
+
if (mode === "static") {
|
|
99
|
+
const dir = staticDirForCompose(config) ?? "./public"
|
|
100
|
+
lines.push(` SUPATYPE_APP_STATIC_DIR: /project/${dir.replace(/^\.\//, "")}`)
|
|
101
|
+
} else if (mode === "proxy" && config.app.upstream?.trim()) {
|
|
102
|
+
lines.push(` SUPATYPE_APP_UPSTREAM: ${proxyUpstreamForCompose(config.app.upstream, devLocal)}`)
|
|
103
|
+
}
|
|
104
|
+
return lines.join("\n")
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface SelfHostComposeOptions {
|
|
108
|
+
/** `supatype dev` with provider docker: internal-only db/server; Kong on host :18473. */
|
|
109
|
+
devLocal?: boolean
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function renderSelfHostCompose(
|
|
113
|
+
config: SupatypeProjectConfig,
|
|
114
|
+
cwd: string = process.cwd(),
|
|
115
|
+
options?: SelfHostComposeOptions,
|
|
116
|
+
): string {
|
|
117
|
+
const projectMount = projectMountPath(cwd)
|
|
118
|
+
const kongMount = kongMountPath(cwd)
|
|
119
|
+
const devLocal = options?.devLocal === true
|
|
120
|
+
const studioHostDev = devLocal && hasStudioOverride(config)
|
|
121
|
+
const appEnv = serverAppEnvForCompose(config, devLocal)
|
|
122
|
+
const studioService = studioServiceBlock(cwd, devLocal)
|
|
123
|
+
const studioBlock = studioHostDev
|
|
124
|
+
? ""
|
|
125
|
+
: `
|
|
126
|
+
studio:
|
|
127
|
+
${studioService}
|
|
128
|
+
environment:
|
|
129
|
+
SUPATYPE_CLOUD_JSON: '{"url":"\${API_EXTERNAL_URL:-http://localhost:18473}","anonKey":"\${ANON_KEY:-}"}'
|
|
130
|
+
expose:
|
|
131
|
+
- "3002"
|
|
132
|
+
`
|
|
133
|
+
const kongDependsOn = studioHostDev
|
|
134
|
+
? ` - server`
|
|
135
|
+
: ` - server
|
|
136
|
+
- studio`
|
|
137
|
+
const publishDbToHost = !devLocal || hasEngineOverride(config)
|
|
138
|
+
const dbPorts = publishDbToHost
|
|
139
|
+
? devLocal
|
|
140
|
+
? ` ports:
|
|
141
|
+
- "127.0.0.1:\${SUPATYPE_DEV_DB_PORT:-54329}:5432"
|
|
142
|
+
`
|
|
143
|
+
: ` ports:
|
|
144
|
+
- "5432:5432"
|
|
145
|
+
`
|
|
146
|
+
: ""
|
|
147
|
+
const serverPorts = devLocal
|
|
148
|
+
? ""
|
|
149
|
+
: ` ports:
|
|
150
|
+
- "9999:9999"
|
|
151
|
+
`
|
|
152
|
+
const minioPorts = devLocal
|
|
153
|
+
? ""
|
|
154
|
+
: ` ports:
|
|
155
|
+
- "9000:9000"
|
|
156
|
+
- "9001:9001"
|
|
157
|
+
`
|
|
158
|
+
|
|
159
|
+
return `# Generated by supatype self-host compose
|
|
160
|
+
# Kong → supatype-server (unified gateway) → internal PostgREST / storage / etc.
|
|
161
|
+
services:
|
|
162
|
+
db:
|
|
163
|
+
image: \${SUPATYPE_POSTGRES_IMAGE:-supatype/postgres:latest}
|
|
164
|
+
environment:
|
|
165
|
+
POSTGRES_USER: \${POSTGRES_USER:-supatype_admin}
|
|
166
|
+
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-postgres}
|
|
167
|
+
POSTGRES_DB: \${POSTGRES_DB:-supatype}
|
|
168
|
+
${dbPorts} volumes:
|
|
169
|
+
- db-data:/var/lib/postgresql/data
|
|
170
|
+
healthcheck:
|
|
171
|
+
test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-supatype_admin}"]
|
|
172
|
+
interval: 5s
|
|
173
|
+
timeout: 5s
|
|
174
|
+
retries: 20
|
|
175
|
+
|
|
176
|
+
postgrest:
|
|
177
|
+
image: postgrest/postgrest:v12.2.8
|
|
178
|
+
expose:
|
|
179
|
+
- "3000"
|
|
180
|
+
environment:
|
|
181
|
+
PGRST_DB_URI: postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}
|
|
182
|
+
PGRST_DB_SCHEMA: "public, supatype, graphql_public"
|
|
183
|
+
PGRST_DB_ANON_ROLE: anon
|
|
184
|
+
PGRST_JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
|
|
185
|
+
PGRST_DB_EXTRA_SEARCH_PATH: public,extensions
|
|
186
|
+
PGRST_DB_POOL: 3
|
|
187
|
+
depends_on:
|
|
188
|
+
db:
|
|
189
|
+
condition: service_healthy
|
|
190
|
+
|
|
191
|
+
storage:
|
|
192
|
+
image: \${SUPATYPE_STORAGE_IMAGE:-supatype/storage:latest}
|
|
193
|
+
expose:
|
|
194
|
+
- "5000"
|
|
195
|
+
environment:
|
|
196
|
+
PORT: 5000
|
|
197
|
+
DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
|
|
198
|
+
JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
|
|
199
|
+
S3_ENDPOINT: http://minio:9000
|
|
200
|
+
S3_REGION: us-east-1
|
|
201
|
+
S3_ACCESS_KEY: supatype
|
|
202
|
+
S3_SECRET_KEY: supatype-secret
|
|
203
|
+
S3_FORCE_PATH_STYLE: "true"
|
|
204
|
+
depends_on:
|
|
205
|
+
db:
|
|
206
|
+
condition: service_healthy
|
|
207
|
+
|
|
208
|
+
functions-worker:
|
|
209
|
+
image: \${SUPATYPE_FUNCTIONS_WORKER_IMAGE:-supatype/functions-worker:latest}
|
|
210
|
+
expose:
|
|
211
|
+
- "8001"
|
|
212
|
+
volumes:
|
|
213
|
+
- ${projectMount}:/project:ro
|
|
214
|
+
environment:
|
|
215
|
+
SUPATYPE_FUNCTIONS_ROOT: /project/functions
|
|
216
|
+
SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
|
|
217
|
+
PORT: "8001"
|
|
218
|
+
SUPATYPE_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
|
|
219
|
+
SUPATYPE_ANON_KEY: \${ANON_KEY:-}
|
|
220
|
+
SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
|
|
221
|
+
STRIPE_SECRET_KEY: \${STRIPE_SECRET_KEY:-}
|
|
222
|
+
STRIPE_WEBHOOK_SECRET: \${STRIPE_WEBHOOK_SECRET:-}
|
|
223
|
+
SITE_URL: \${SITE_URL:-\${API_EXTERNAL_URL:-http://localhost:18473}}
|
|
224
|
+
depends_on:
|
|
225
|
+
db:
|
|
226
|
+
condition: service_healthy
|
|
227
|
+
|
|
228
|
+
server:
|
|
229
|
+
image: \${SUPATYPE_SERVER_IMAGE:-\${SUPATYPE_AUTH_IMAGE:-supatype/server:latest}}
|
|
230
|
+
${serverPorts} volumes:
|
|
231
|
+
- ${projectMount}:/project:ro
|
|
232
|
+
working_dir: /project
|
|
233
|
+
environment:
|
|
234
|
+
SUPATYPE_MODE: ${devLocal ? "dev" : "standalone"}
|
|
235
|
+
SUPATYPE_MANIFEST_PATH: /project/.supatype/manifest.json
|
|
236
|
+
SUPATYPE_ADMIN_CONFIG_PATH: /project/.supatype/admin-config.json
|
|
237
|
+
SUPATYPE_API_CONFIG_PATH: /project/.supatype/api-config.json
|
|
238
|
+
SUPATYPE_POSTGREST_URL: http://postgrest:3000
|
|
239
|
+
SUPATYPE_GRAPHQL_URL: http://postgrest:3000
|
|
240
|
+
SUPATYPE_STORAGE_URL: http://storage:5000
|
|
241
|
+
SUPATYPE_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
|
|
242
|
+
SUPATYPE_ANON_KEY: \${ANON_KEY:-}
|
|
243
|
+
SUPATYPE_SERVICE_ROLE_KEY: \${SERVICE_ROLE_KEY:-}
|
|
244
|
+
SUPATYPE_SQL_DATABASE_URL: "postgresql://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}"
|
|
245
|
+
SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
|
|
246
|
+
SUPATYPE_FUNCTIONS_WORKER_URL: http://functions-worker:8001
|
|
247
|
+
${appEnv}
|
|
248
|
+
GOTRUE_API_HOST: 0.0.0.0
|
|
249
|
+
GOTRUE_API_PORT: 9999
|
|
250
|
+
API_EXTERNAL_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
|
|
251
|
+
GOTRUE_API_EXTERNAL_URL: \${API_EXTERNAL_URL:-http://localhost:18473}
|
|
252
|
+
GOTRUE_DB_DRIVER: postgres
|
|
253
|
+
GOTRUE_DB_DATABASE_URL: "postgres://\${POSTGRES_USER:-supatype_admin}:\${POSTGRES_PASSWORD:-postgres}@db:5432/\${POSTGRES_DB:-supatype}?search_path=auth"
|
|
254
|
+
GOTRUE_SITE_URL: \${SITE_URL:-http://localhost:3000}
|
|
255
|
+
GOTRUE_JWT_SECRET: \${JWT_SECRET:-super-secret-jwt-token-change-in-production}
|
|
256
|
+
GOTRUE_JWT_EXP: 3600
|
|
257
|
+
GOTRUE_JWT_AUD: authenticated
|
|
258
|
+
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
|
|
259
|
+
GOTRUE_JWT_ADMIN_ROLES: service_role,supatype_admin
|
|
260
|
+
GOTRUE_MAILER_AUTOCONFIRM: \${GOTRUE_MAILER_AUTOCONFIRM:-true}
|
|
261
|
+
GOTRUE_DISABLE_SIGNUP: \${DISABLE_SIGNUP:-false}
|
|
262
|
+
${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
|
|
263
|
+
depends_on:
|
|
264
|
+
db:
|
|
265
|
+
condition: service_healthy
|
|
266
|
+
postgrest:
|
|
267
|
+
condition: service_started
|
|
268
|
+
storage:
|
|
269
|
+
condition: service_started
|
|
270
|
+
functions-worker:
|
|
271
|
+
condition: service_started
|
|
272
|
+
|
|
273
|
+
minio:
|
|
274
|
+
image: minio/minio:RELEASE.2024-11-07T00-52-20Z
|
|
275
|
+
command: server /data --console-address ":9001"
|
|
276
|
+
environment:
|
|
277
|
+
MINIO_ROOT_USER: supatype
|
|
278
|
+
MINIO_ROOT_PASSWORD: supatype-secret
|
|
279
|
+
${minioPorts} volumes:
|
|
280
|
+
- minio-data:/data
|
|
281
|
+
|
|
282
|
+
schema-engine:
|
|
283
|
+
image: \${SUPATYPE_ENGINE_IMAGE:-supatype/schema-engine:latest}
|
|
284
|
+
profiles: ["tools"]
|
|
285
|
+
entrypoint: ["supatype-engine"]
|
|
286
|
+
volumes:
|
|
287
|
+
- ${projectMount}:/project
|
|
288
|
+
working_dir: /project
|
|
289
|
+
depends_on:
|
|
290
|
+
db:
|
|
291
|
+
condition: service_healthy
|
|
292
|
+
${studioBlock}
|
|
293
|
+
kong:
|
|
294
|
+
image: kong:3.6
|
|
295
|
+
environment:
|
|
296
|
+
KONG_DATABASE: "off"
|
|
297
|
+
KONG_DECLARATIVE_CONFIG: /etc/kong/kong.yml
|
|
298
|
+
KONG_PROXY_ACCESS_LOG: /dev/stdout
|
|
299
|
+
KONG_ADMIN_ACCESS_LOG: /dev/stdout
|
|
300
|
+
KONG_PROXY_ERROR_LOG: /dev/stderr
|
|
301
|
+
KONG_ADMIN_ERROR_LOG: /dev/stderr
|
|
302
|
+
volumes:
|
|
303
|
+
- ${kongMount}:/etc/kong/kong.yml:ro
|
|
304
|
+
ports:
|
|
305
|
+
- "\${SUPATYPE_KONG_PORT:-18473}:8000"
|
|
306
|
+
depends_on:
|
|
307
|
+
${kongDependsOn}
|
|
308
|
+
|
|
309
|
+
volumes:
|
|
310
|
+
db-data:
|
|
311
|
+
minio-data:
|
|
312
|
+
`
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function ensureComposeManifest(cwd: string): void {
|
|
316
|
+
const manifestPath = join(cwd, ".supatype", "manifest.json")
|
|
317
|
+
if (existsSync(manifestPath)) return
|
|
318
|
+
mkdirSync(dirname(manifestPath), { recursive: true })
|
|
319
|
+
const manifest = {
|
|
320
|
+
schema: "public",
|
|
321
|
+
postgrest_url: "http://postgrest:3000",
|
|
322
|
+
storage_url: "http://storage:5000",
|
|
323
|
+
realtime_enabled: true,
|
|
324
|
+
functions_enabled: false,
|
|
325
|
+
}
|
|
326
|
+
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8")
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function ensureProjectFunctionsDir(cwd: string, config: SupatypeProjectConfig): void {
|
|
330
|
+
mkdirSync(preferredFunctionsPathFromProject(config, cwd), { recursive: true })
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function writeSelfHostCompose(
|
|
334
|
+
cwd: string,
|
|
335
|
+
config: SupatypeProjectConfig,
|
|
336
|
+
options?: SelfHostComposeOptions,
|
|
337
|
+
): SelfHostComposePaths {
|
|
338
|
+
const paths = selfHostComposePaths(cwd)
|
|
339
|
+
mkdirSync(paths.dir, { recursive: true })
|
|
340
|
+
ensureProjectFunctionsDir(cwd, config)
|
|
341
|
+
ensureComposeManifest(cwd)
|
|
342
|
+
writeFileSync(paths.composePath, renderSelfHostCompose(config, cwd, options), "utf8")
|
|
343
|
+
const studioHostDev = options?.devLocal === true && hasStudioOverride(config)
|
|
344
|
+
writeFileSync(
|
|
345
|
+
paths.kongPath,
|
|
346
|
+
buildKongDeclarative({
|
|
347
|
+
unifiedGateway: true,
|
|
348
|
+
...(studioHostDev && {
|
|
349
|
+
studioServiceUrl: COMPOSE_STUDIO_HOST_URL,
|
|
350
|
+
studioStripPath: false,
|
|
351
|
+
}),
|
|
352
|
+
}),
|
|
353
|
+
"utf8",
|
|
354
|
+
)
|
|
355
|
+
return paths
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function runDockerCompose(
|
|
359
|
+
composePath: string,
|
|
360
|
+
args: string[],
|
|
361
|
+
projectRoot: string = process.cwd(),
|
|
362
|
+
composeProject?: string,
|
|
363
|
+
): number {
|
|
364
|
+
const envFile = resolve(projectRoot, ".env")
|
|
365
|
+
const composeArgs = ["compose"]
|
|
366
|
+
// Per-project name isolates containers/volumes/network so multiple Supatype
|
|
367
|
+
// projects on one machine never share a database (default would be the
|
|
368
|
+
// ".supatype/self-host" dir name, identical for every project).
|
|
369
|
+
if (composeProject) composeArgs.push("-p", composeProject)
|
|
370
|
+
// Resolve ${VAR} in compose.yml from the project root .env (not .supatype/self-host/).
|
|
371
|
+
composeArgs.push("--project-directory", projectRoot)
|
|
372
|
+
composeArgs.push("-f", composePath)
|
|
373
|
+
if (existsSync(envFile)) {
|
|
374
|
+
composeArgs.push("--env-file", envFile)
|
|
375
|
+
}
|
|
376
|
+
composeArgs.push(...args)
|
|
377
|
+
const result = spawnSync(
|
|
378
|
+
"docker",
|
|
379
|
+
composeArgs,
|
|
380
|
+
{ stdio: "inherit", cwd: projectRoot },
|
|
381
|
+
)
|
|
382
|
+
return result.status ?? 1
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/** Compose project name for a Supatype project — isolates docker state per project. */
|
|
386
|
+
export function composeProjectName(projectName: string): string {
|
|
387
|
+
const slug = projectName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "")
|
|
388
|
+
return `supatype-${slug || "project"}`
|
|
389
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provision storage buckets declared in a schema AST via the storage server API.
|
|
3
|
+
*
|
|
4
|
+
* The storage server is the authority on bucket existence — going through the API
|
|
5
|
+
* ensures it creates any backing resources (directories, S3 buckets, etc.).
|
|
6
|
+
* Buckets already registered return 409 Conflict, which is treated as success.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface BucketSpec {
|
|
10
|
+
id: string
|
|
11
|
+
public: boolean
|
|
12
|
+
allowed_mime_types?: string[] | null
|
|
13
|
+
file_size_limit?: number | null
|
|
14
|
+
access_mode?: "public" | "private" | "custom"
|
|
15
|
+
s3_bucket_policy?: string | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Ensure all declared buckets exist in the storage server.
|
|
20
|
+
*
|
|
21
|
+
* @param storageApiUrl Base URL of the storage API, e.g. "http://localhost:54321/storage/v1"
|
|
22
|
+
* @param serviceRoleKey A service_role JWT for the storage server
|
|
23
|
+
* @param buckets Buckets to provision (from the resolved AST)
|
|
24
|
+
*/
|
|
25
|
+
export async function provisionBuckets(
|
|
26
|
+
storageApiUrl: string,
|
|
27
|
+
serviceRoleKey: string,
|
|
28
|
+
buckets: BucketSpec[],
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
const base = storageApiUrl.replace(/\/$/, "")
|
|
31
|
+
const headers = {
|
|
32
|
+
"Authorization": `Bearer ${serviceRoleKey}`,
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const bucket of buckets) {
|
|
37
|
+
const body = JSON.stringify({
|
|
38
|
+
id: bucket.id,
|
|
39
|
+
name: bucket.id,
|
|
40
|
+
public: bucket.public,
|
|
41
|
+
...(bucket.allowed_mime_types != null && { allowed_mime_types: bucket.allowed_mime_types }),
|
|
42
|
+
...(bucket.file_size_limit != null && { file_size_limit: bucket.file_size_limit }),
|
|
43
|
+
...(bucket.access_mode != null && { access_mode: bucket.access_mode }),
|
|
44
|
+
...(bucket.s3_bucket_policy != null &&
|
|
45
|
+
bucket.s3_bucket_policy !== "" && { s3_bucket_policy: bucket.s3_bucket_policy }),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
const res = await fetch(`${base}/bucket`, { method: "POST", headers, body })
|
|
49
|
+
.catch(() => null)
|
|
50
|
+
|
|
51
|
+
if (res === null) continue // server not reachable — skip silently
|
|
52
|
+
if (res.status === 409) continue // already exists — fine
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
const msg = await res.text().catch(() => res.statusText)
|
|
55
|
+
console.warn(`[storage] Failed to provision bucket "${bucket.id}": ${msg}`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SupatypeProjectConfig } from "./project-config.js"
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_STUDIO_ADMIN_ROLES = ["admin", "supatype_admin"] as const
|
|
4
|
+
|
|
5
|
+
/** Studio admin roles from `supatype.config.ts` `admin.roles` or defaults. */
|
|
6
|
+
export function studioAdminRoles(cfg: SupatypeProjectConfig): string[] {
|
|
7
|
+
const roles = cfg.admin?.roles
|
|
8
|
+
if (roles !== undefined && roles.length > 0) return roles
|
|
9
|
+
return [...DEFAULT_STUDIO_ADMIN_ROLES]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Merge `adminRoles` into engine admin-config JSON for Studio and supatype-server. */
|
|
13
|
+
export function withAdminRoles(admin: unknown, cfg: SupatypeProjectConfig): Record<string, unknown> {
|
|
14
|
+
const base = typeof admin === "object" && admin !== null ? (admin as Record<string, unknown>) : {}
|
|
15
|
+
return { ...base, adminRoles: studioAdminRoles(cfg) }
|
|
16
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { join, resolve } from "node:path"
|
|
3
|
+
import { ProcessManager } from "./process-manager.js"
|
|
4
|
+
|
|
5
|
+
const STUDIO_PORT = 3002
|
|
6
|
+
|
|
7
|
+
export interface StudioDevServerOptions {
|
|
8
|
+
cwd: string
|
|
9
|
+
studioOverride: string
|
|
10
|
+
pidDir: string
|
|
11
|
+
serviceRoleKey: string
|
|
12
|
+
/**
|
|
13
|
+
* Where Vite proxies API requests (Kong gateway port for compose dev, or
|
|
14
|
+
* supatype-server port for native `supatype dev`).
|
|
15
|
+
*/
|
|
16
|
+
proxyTarget: string
|
|
17
|
+
/**
|
|
18
|
+
* Public Supatype URL the browser uses. Compose dev: Kong on the host.
|
|
19
|
+
* Native dev: Vite dev server (same origin as Studio).
|
|
20
|
+
*/
|
|
21
|
+
viteSupatypeUrl: string
|
|
22
|
+
/** Vite `base` — `/studio/` when behind Kong at `/studio/`; `/` for native dev on :3002. */
|
|
23
|
+
basePath?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Start @supatype/studio Vite dev server when `overrides.studio` is set. */
|
|
27
|
+
export function startStudioViteDevServer(opts: StudioDevServerOptions): ProcessManager | null {
|
|
28
|
+
const studioDir = resolve(opts.cwd, opts.studioOverride)
|
|
29
|
+
const viteJs = join(studioDir, "node_modules", "vite", "bin", "vite.js")
|
|
30
|
+
if (!existsSync(viteJs)) {
|
|
31
|
+
console.warn(`[supatype] ⚠ Studio override set but vite not found at ${viteJs}. Run: pnpm install`)
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const basePath = opts.basePath ?? "/"
|
|
36
|
+
return new ProcessManager(
|
|
37
|
+
process.execPath,
|
|
38
|
+
[viteJs, "--port", String(STUDIO_PORT), "--strictPort", "--host"],
|
|
39
|
+
{
|
|
40
|
+
label: "studio",
|
|
41
|
+
pidDir: opts.pidDir,
|
|
42
|
+
cwd: studioDir,
|
|
43
|
+
colour: "\x1b[35m",
|
|
44
|
+
env: {
|
|
45
|
+
VITE_SUPATYPE_URL: opts.viteSupatypeUrl,
|
|
46
|
+
SUPATYPE_PROXY_TARGET: opts.proxyTarget,
|
|
47
|
+
VITE_SUPATYPE_ANON_KEY: opts.serviceRoleKey,
|
|
48
|
+
VITE_SUPATYPE_SERVICE_ROLE_KEY: opts.serviceRoleKey,
|
|
49
|
+
VITE_BASE_PATH: basePath,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
}
|
package/src/systemd.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* systemd.ts — generate systemd unit files for self-hosted deployments.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* generateUnits(config, outputDir)
|
|
6
|
+
* → writes supatype-postgres.service + supatype-server.service to outputDir
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { writeFileSync, mkdirSync } from "node:fs"
|
|
10
|
+
import { join, resolve } from "node:path"
|
|
11
|
+
import { homedir } from "node:os"
|
|
12
|
+
import type { SupatypeProjectConfig } from "./project-config.js"
|
|
13
|
+
|
|
14
|
+
export interface SystemdOptions {
|
|
15
|
+
/** Directory where unit files are written. Defaults to .supatype/systemd/. */
|
|
16
|
+
outputDir?: string
|
|
17
|
+
/** User to run services as. Defaults to current user. */
|
|
18
|
+
user?: string
|
|
19
|
+
/** EnvironmentFile path injected into the units. Defaults to project .env. */
|
|
20
|
+
envFile?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Public API
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate supatype-postgres.service and supatype-server.service.
|
|
29
|
+
*
|
|
30
|
+
* Returns the paths of the written files.
|
|
31
|
+
*/
|
|
32
|
+
export function generateUnits(
|
|
33
|
+
config: SupatypeProjectConfig,
|
|
34
|
+
projectDir: string,
|
|
35
|
+
opts: SystemdOptions = {},
|
|
36
|
+
): { postgres: string; server: string } {
|
|
37
|
+
const outputDir = opts.outputDir ?? resolve(projectDir, ".supatype", "systemd")
|
|
38
|
+
mkdirSync(outputDir, { recursive: true })
|
|
39
|
+
|
|
40
|
+
const user = opts.user ?? process.env["USER"] ?? "supatype"
|
|
41
|
+
const envFile = opts.envFile ?? resolve(projectDir, ".env")
|
|
42
|
+
const stateDir = join(homedir(), ".supatype", "projects", config.project.name)
|
|
43
|
+
|
|
44
|
+
const postgresPath = join(outputDir, "supatype-postgres.service")
|
|
45
|
+
const serverPath = join(outputDir, "supatype-server.service")
|
|
46
|
+
|
|
47
|
+
writeFileSync(postgresPath, postgresUnit(config, stateDir, user, envFile), "utf8")
|
|
48
|
+
writeFileSync(serverPath, serverUnit(config, stateDir, user, envFile), "utf8")
|
|
49
|
+
|
|
50
|
+
return { postgres: postgresPath, server: serverPath }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Unit templates
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
function postgresUnit(
|
|
58
|
+
config: SupatypeProjectConfig,
|
|
59
|
+
stateDir: string,
|
|
60
|
+
user: string,
|
|
61
|
+
envFile: string,
|
|
62
|
+
): string {
|
|
63
|
+
const dataDir = config.database.data_dir ?? join(stateDir, "data")
|
|
64
|
+
const logDir = join(stateDir, "logs")
|
|
65
|
+
const pgBinDir = `%h/.supatype/cache/postgres/${config.versions.postgres}/bin`
|
|
66
|
+
|
|
67
|
+
return `[Unit]
|
|
68
|
+
Description=Supatype Postgres (${config.project.name})
|
|
69
|
+
After=network.target
|
|
70
|
+
StartLimitIntervalSec=60
|
|
71
|
+
StartLimitBurst=5
|
|
72
|
+
|
|
73
|
+
[Service]
|
|
74
|
+
Type=forking
|
|
75
|
+
User=${user}
|
|
76
|
+
EnvironmentFile=-${envFile}
|
|
77
|
+
ExecStartPre=/bin/mkdir -p ${logDir}
|
|
78
|
+
ExecStart=${pgBinDir}/pg_ctl start \\
|
|
79
|
+
-D ${dataDir} \\
|
|
80
|
+
-l ${logDir}/postgres.log \\
|
|
81
|
+
-w \\
|
|
82
|
+
-t 60
|
|
83
|
+
ExecStop=${pgBinDir}/pg_ctl stop -D ${dataDir} -m fast
|
|
84
|
+
ExecReload=${pgBinDir}/pg_ctl reload -D ${dataDir}
|
|
85
|
+
PIDFile=${stateDir}/pid/postgres.pid
|
|
86
|
+
Restart=on-failure
|
|
87
|
+
RestartSec=5s
|
|
88
|
+
TimeoutStartSec=90
|
|
89
|
+
TimeoutStopSec=30
|
|
90
|
+
|
|
91
|
+
[Install]
|
|
92
|
+
WantedBy=multi-user.target
|
|
93
|
+
`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function serverUnit(
|
|
97
|
+
config: SupatypeProjectConfig,
|
|
98
|
+
stateDir: string,
|
|
99
|
+
user: string,
|
|
100
|
+
envFile: string,
|
|
101
|
+
): string {
|
|
102
|
+
const port = config.server.port ?? 54321
|
|
103
|
+
const serverBin = `%h/.supatype/cache/server/${config.versions.server}/supatype-server`
|
|
104
|
+
const logDir = join(stateDir, "logs")
|
|
105
|
+
|
|
106
|
+
const extraArgs: string[] = [`--mode ${config.server.mode}`]
|
|
107
|
+
if (config.server.domain) extraArgs.push(`--domain ${config.server.domain}`)
|
|
108
|
+
|
|
109
|
+
return `[Unit]
|
|
110
|
+
Description=Supatype Server (${config.project.name})
|
|
111
|
+
After=network.target supatype-postgres.service
|
|
112
|
+
Requires=supatype-postgres.service
|
|
113
|
+
StartLimitIntervalSec=60
|
|
114
|
+
StartLimitBurst=5
|
|
115
|
+
|
|
116
|
+
[Service]
|
|
117
|
+
Type=simple
|
|
118
|
+
User=${user}
|
|
119
|
+
EnvironmentFile=-${envFile}
|
|
120
|
+
ExecStartPre=/bin/mkdir -p ${logDir}
|
|
121
|
+
ExecStart=${serverBin} \\
|
|
122
|
+
--port ${port} \\
|
|
123
|
+
${extraArgs.join(" \\\n ")}
|
|
124
|
+
PIDFile=${stateDir}/pid/server.pid
|
|
125
|
+
StandardOutput=append:${logDir}/server.log
|
|
126
|
+
StandardError=append:${logDir}/server.log
|
|
127
|
+
Restart=on-failure
|
|
128
|
+
RestartSec=5s
|
|
129
|
+
TimeoutStartSec=30
|
|
130
|
+
TimeoutStopSec=15
|
|
131
|
+
KillMode=mixed
|
|
132
|
+
KillSignal=SIGTERM
|
|
133
|
+
|
|
134
|
+
[Install]
|
|
135
|
+
WantedBy=multi-user.target
|
|
136
|
+
`
|
|
137
|
+
}
|
package/src/tsx-runner.ts
CHANGED
|
@@ -7,11 +7,16 @@ import { spawnSync, type SpawnSyncOptions } from "node:child_process"
|
|
|
7
7
|
import { existsSync, readFileSync } from "node:fs"
|
|
8
8
|
import { resolve, dirname } from "node:path"
|
|
9
9
|
import { createRequire } from "node:module"
|
|
10
|
+
import { fileURLToPath } from "node:url"
|
|
10
11
|
import { writeFileSync, unlinkSync } from "node:fs"
|
|
11
12
|
import { tmpdir } from "node:os"
|
|
12
13
|
|
|
13
14
|
const _require = createRequire(import.meta.url)
|
|
14
15
|
|
|
16
|
+
// The CLI's own source directory — workspace packages are
|
|
17
|
+
// resolvable from here. Eval snippets are written here so ESM resolution finds them.
|
|
18
|
+
const CLI_SRC_DIR = dirname(fileURLToPath(import.meta.url))
|
|
19
|
+
|
|
15
20
|
/**
|
|
16
21
|
* Resolve the absolute path to the tsx CLI entry point.
|
|
17
22
|
* tsx is a direct dependency so this will always succeed after `npm install`.
|
|
@@ -34,6 +39,7 @@ function findTsxBin(): string {
|
|
|
34
39
|
|
|
35
40
|
const TSX_BIN = findTsxBin()
|
|
36
41
|
|
|
42
|
+
|
|
37
43
|
export interface RunResult {
|
|
38
44
|
stdout: string
|
|
39
45
|
stderr: string
|
|
@@ -65,7 +71,11 @@ export function evalTsSnippet(
|
|
|
65
71
|
snippet: string,
|
|
66
72
|
opts: SpawnSyncOptions = {},
|
|
67
73
|
): RunResult {
|
|
68
|
-
|
|
74
|
+
// Always write the temp file into the CLI's source directory so that ESM
|
|
75
|
+
// resolution can find workspace packages from there.
|
|
76
|
+
// The subprocess CWD is kept as opts.cwd (the user's project dir) so that
|
|
77
|
+
// any relative paths in the snippet resolve correctly.
|
|
78
|
+
const tmpFile = resolve(CLI_SRC_DIR, `supatype-eval-${Date.now()}.mts`)
|
|
69
79
|
writeFileSync(tmpFile, snippet, "utf8")
|
|
70
80
|
try {
|
|
71
81
|
return runTsFile(tmpFile, opts)
|