@supatype/cli 0.1.0 → 0.1.2
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 +121 -86
- package/.turbo/turbo-typecheck.log +2 -2
- package/dist/binary-cache.d.ts +2 -0
- package/dist/binary-cache.d.ts.map +1 -1
- package/dist/binary-cache.js +36 -0
- package/dist/binary-cache.js.map +1 -1
- package/dist/binary-download-lock.d.ts +12 -0
- package/dist/binary-download-lock.d.ts.map +1 -0
- package/dist/binary-download-lock.js +106 -0
- package/dist/binary-download-lock.js.map +1 -0
- package/dist/cli-package-version.d.ts +3 -0
- package/dist/cli-package-version.d.ts.map +1 -0
- package/dist/cli-package-version.js +15 -0
- package/dist/cli-package-version.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.js +25 -19
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/admin.d.ts +28 -1
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +290 -112
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/cache.d.ts +1 -1
- package/dist/commands/cache.d.ts.map +1 -1
- package/dist/commands/cache.js +98 -5
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +28 -22
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts +8 -4
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +278 -139
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/link-helpers.d.ts.map +1 -1
- package/dist/commands/link-helpers.js +26 -25
- package/dist/commands/link-helpers.js.map +1 -1
- package/dist/commands/push.js +3 -3
- package/dist/commands/push.js.map +1 -1
- package/dist/compose-local-server-image.d.ts +13 -0
- package/dist/compose-local-server-image.d.ts.map +1 -0
- package/dist/compose-local-server-image.js +57 -0
- package/dist/compose-local-server-image.js.map +1 -0
- package/dist/compose-rename.d.ts +10 -0
- package/dist/compose-rename.d.ts.map +1 -0
- package/dist/compose-rename.js +64 -0
- package/dist/compose-rename.js.map +1 -0
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +138 -97
- package/dist/dev-compose.js.map +1 -1
- package/dist/dev-log-bus.d.ts +5 -0
- package/dist/dev-log-bus.d.ts.map +1 -1
- package/dist/dev-log-bus.js +14 -0
- package/dist/dev-log-bus.js.map +1 -1
- package/dist/dev-log-filter.d.ts +4 -0
- package/dist/dev-log-filter.d.ts.map +1 -1
- package/dist/dev-log-filter.js +52 -0
- package/dist/dev-log-filter.js.map +1 -1
- package/dist/dev-ports.d.ts +27 -0
- package/dist/dev-ports.d.ts.map +1 -0
- package/dist/dev-ports.js +178 -0
- package/dist/dev-ports.js.map +1 -0
- package/dist/dev-ready-panel.d.ts +19 -0
- package/dist/dev-ready-panel.d.ts.map +1 -0
- package/dist/dev-ready-panel.js +49 -0
- package/dist/dev-ready-panel.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 +78 -0
- package/dist/dev-session-lock.js.map +1 -0
- package/dist/dev-session.d.ts +18 -5
- package/dist/dev-session.d.ts.map +1 -1
- package/dist/dev-session.js +91 -18
- package/dist/dev-session.js.map +1 -1
- package/dist/dev-shutdown.d.ts +20 -2
- package/dist/dev-shutdown.d.ts.map +1 -1
- package/dist/dev-shutdown.js +88 -10
- package/dist/dev-shutdown.js.map +1 -1
- package/dist/dev-task-colors.d.ts +3 -1
- package/dist/dev-task-colors.d.ts.map +1 -1
- package/dist/dev-task-colors.js +23 -3
- package/dist/dev-task-colors.js.map +1 -1
- package/dist/docker-runtime.js +1 -1
- package/dist/docker-runtime.js.map +1 -1
- package/dist/engine-push-output.d.ts +1 -0
- package/dist/engine-push-output.d.ts.map +1 -1
- package/dist/engine-push-output.js +4 -1
- package/dist/engine-push-output.js.map +1 -1
- package/dist/ensure-binary.d.ts.map +1 -1
- package/dist/ensure-binary.js +14 -2
- package/dist/ensure-binary.js.map +1 -1
- package/dist/ensure-component-binaries.d.ts +17 -0
- package/dist/ensure-component-binaries.d.ts.map +1 -0
- package/dist/ensure-component-binaries.js +45 -0
- package/dist/ensure-component-binaries.js.map +1 -0
- package/dist/ensure-dev-api-config.d.ts +3 -0
- package/dist/ensure-dev-api-config.d.ts.map +1 -0
- package/dist/ensure-dev-api-config.js +17 -0
- package/dist/ensure-dev-api-config.js.map +1 -0
- 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/init-dependency-versions.d.ts +13 -0
- package/dist/init-dependency-versions.d.ts.map +1 -0
- package/dist/init-dependency-versions.js +53 -0
- package/dist/init-dependency-versions.js.map +1 -0
- package/dist/init-package-json.d.ts +21 -0
- package/dist/init-package-json.d.ts.map +1 -0
- package/dist/init-package-json.js +46 -0
- package/dist/init-package-json.js.map +1 -0
- package/dist/postgres-ctl.d.ts.map +1 -1
- package/dist/postgres-ctl.js +2 -1
- package/dist/postgres-ctl.js.map +1 -1
- package/dist/required-host-components.d.ts +11 -0
- package/dist/required-host-components.d.ts.map +1 -0
- package/dist/required-host-components.js +25 -0
- package/dist/required-host-components.js.map +1 -0
- package/dist/resolve-api-url.d.ts +6 -0
- package/dist/resolve-api-url.d.ts.map +1 -0
- package/dist/resolve-api-url.js +39 -0
- package/dist/resolve-api-url.js.map +1 -0
- package/dist/rest-cache-admin.d.ts +33 -0
- package/dist/rest-cache-admin.d.ts.map +1 -0
- package/dist/rest-cache-admin.js +96 -0
- package/dist/rest-cache-admin.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +4 -6
- package/dist/scripts/postinstall.d.ts.map +1 -1
- package/dist/scripts/postinstall.js +8 -41
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +24 -13
- package/dist/self-host-compose.js.map +1 -1
- package/dist/studio-dev-server.d.ts +4 -2
- package/dist/studio-dev-server.d.ts.map +1 -1
- package/dist/studio-dev-server.js +3 -2
- package/dist/studio-dev-server.js.map +1 -1
- package/dist/ui/brand.d.ts +2 -5
- package/dist/ui/brand.d.ts.map +1 -1
- package/dist/ui/brand.js +2 -7
- package/dist/ui/brand.js.map +1 -1
- package/dist/ui/clack-api.d.ts +44 -0
- package/dist/ui/clack-api.d.ts.map +1 -0
- package/dist/ui/clack-api.js +76 -0
- package/dist/ui/clack-api.js.map +1 -0
- package/dist/ui/clack.d.ts +14 -0
- package/dist/ui/clack.d.ts.map +1 -0
- package/dist/ui/clack.js +147 -0
- package/dist/ui/clack.js.map +1 -0
- package/dist/ui/components/FlowSpinner.d.ts +5 -0
- package/dist/ui/components/FlowSpinner.d.ts.map +1 -0
- package/dist/ui/components/FlowSpinner.js +8 -0
- package/dist/ui/components/FlowSpinner.js.map +1 -0
- package/dist/ui/components/LogoWordmark.d.ts +9 -0
- package/dist/ui/components/LogoWordmark.d.ts.map +1 -0
- package/dist/ui/components/LogoWordmark.js +17 -0
- package/dist/ui/components/LogoWordmark.js.map +1 -0
- package/dist/ui/components/PromptPanel.d.ts +5 -0
- package/dist/ui/components/PromptPanel.d.ts.map +1 -0
- package/dist/ui/components/PromptPanel.js +7 -0
- package/dist/ui/components/PromptPanel.js.map +1 -0
- package/dist/ui/components/SelectField.d.ts +11 -0
- package/dist/ui/components/SelectField.d.ts.map +1 -0
- package/dist/ui/components/SelectField.js +19 -0
- package/dist/ui/components/SelectField.js.map +1 -0
- package/dist/ui/confirm.d.ts +2 -1
- package/dist/ui/confirm.d.ts.map +1 -1
- package/dist/ui/confirm.js +4 -4
- package/dist/ui/confirm.js.map +1 -1
- package/dist/ui/dev/DevDashboard.d.ts +8 -0
- package/dist/ui/dev/DevDashboard.d.ts.map +1 -0
- package/dist/ui/dev/DevDashboard.js +151 -0
- package/dist/ui/dev/DevDashboard.js.map +1 -0
- package/dist/ui/dev/DevReadyPanelView.d.ts +7 -0
- package/dist/ui/dev/DevReadyPanelView.d.ts.map +1 -0
- package/dist/ui/dev/DevReadyPanelView.js +29 -0
- package/dist/ui/dev/DevReadyPanelView.js.map +1 -0
- package/dist/ui/fatal.d.ts.map +1 -1
- package/dist/ui/fatal.js +5 -11
- package/dist/ui/fatal.js.map +1 -1
- package/dist/ui/flows/FlowApp.d.ts +8 -0
- package/dist/ui/flows/FlowApp.d.ts.map +1 -0
- package/dist/ui/flows/FlowApp.js +42 -0
- package/dist/ui/flows/FlowApp.js.map +1 -0
- package/dist/ui/flows/prompt-fields.d.ts +48 -0
- package/dist/ui/flows/prompt-fields.d.ts.map +1 -0
- package/dist/ui/flows/prompt-fields.js +88 -0
- package/dist/ui/flows/prompt-fields.js.map +1 -0
- package/dist/ui/flows/types.d.ts +41 -0
- package/dist/ui/flows/types.d.ts.map +1 -0
- package/dist/ui/flows/types.js +2 -0
- package/dist/ui/flows/types.js.map +1 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/messages.d.ts +1 -0
- package/dist/ui/messages.d.ts.map +1 -1
- package/dist/ui/messages.js +48 -8
- package/dist/ui/messages.js.map +1 -1
- package/dist/ui/progress.d.ts +5 -1
- package/dist/ui/progress.d.ts.map +1 -1
- package/dist/ui/progress.js +12 -3
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/prompts.d.ts +7 -5
- package/dist/ui/prompts.d.ts.map +1 -1
- package/dist/ui/prompts.js +15 -8
- package/dist/ui/prompts.js.map +1 -1
- package/dist/ui/runtime/cancel.d.ts +4 -0
- package/dist/ui/runtime/cancel.d.ts.map +1 -0
- package/dist/ui/runtime/cancel.js +6 -0
- package/dist/ui/runtime/cancel.js.map +1 -0
- package/dist/ui/runtime/command-chrome.d.ts +17 -0
- package/dist/ui/runtime/command-chrome.d.ts.map +1 -0
- package/dist/ui/runtime/command-chrome.js +123 -0
- package/dist/ui/runtime/command-chrome.js.map +1 -0
- package/dist/ui/runtime/dev-prompt-queue.d.ts +30 -0
- package/dist/ui/runtime/dev-prompt-queue.d.ts.map +1 -0
- package/dist/ui/runtime/dev-prompt-queue.js +57 -0
- package/dist/ui/runtime/dev-prompt-queue.js.map +1 -0
- package/dist/ui/runtime/flow-session.d.ts +4 -0
- package/dist/ui/runtime/flow-session.d.ts.map +1 -0
- package/dist/ui/runtime/flow-session.js +8 -0
- package/dist/ui/runtime/flow-session.js.map +1 -0
- package/dist/ui/runtime/run-clack-flow.d.ts +5 -0
- package/dist/ui/runtime/run-clack-flow.d.ts.map +1 -0
- package/dist/ui/runtime/run-clack-flow.js +34 -0
- package/dist/ui/runtime/run-clack-flow.js.map +1 -0
- package/dist/ui/theme.d.ts +24 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +34 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/valkey-sidecar.d.ts +17 -0
- package/dist/valkey-sidecar.d.ts.map +1 -0
- package/dist/valkey-sidecar.js +94 -0
- package/dist/valkey-sidecar.js.map +1 -0
- package/package.json +11 -3
- package/src/binary-cache.ts +61 -0
- package/src/binary-download-lock.ts +124 -0
- package/src/cli-package-version.ts +15 -0
- package/src/cli.ts +6 -2
- package/src/commands/add.ts +26 -19
- package/src/commands/admin.ts +380 -137
- package/src/commands/cache.ts +105 -5
- package/src/commands/dev.ts +29 -21
- package/src/commands/init.ts +217 -46
- package/src/commands/link-helpers.ts +30 -29
- package/src/commands/push.ts +3 -3
- package/src/compose-local-server-image.ts +68 -0
- package/src/compose-rename.ts +73 -0
- package/src/dev-compose.ts +175 -96
- package/src/dev-log-bus.ts +18 -0
- package/src/dev-log-filter.ts +42 -0
- package/src/dev-ports.ts +223 -0
- package/src/dev-ready-panel.ts +63 -0
- package/src/dev-session-lock.ts +98 -0
- package/src/dev-session.ts +98 -18
- package/src/dev-shutdown.ts +114 -9
- package/src/dev-task-colors.ts +22 -3
- package/src/docker-runtime.ts +1 -1
- package/src/engine-push-output.ts +5 -1
- package/src/ensure-binary.ts +21 -1
- package/src/ensure-component-binaries.ts +71 -0
- package/src/ensure-dev-api-config.ts +18 -0
- package/src/env-file.ts +37 -0
- package/src/init-dependency-versions.ts +69 -0
- package/src/init-package-json.ts +63 -0
- package/src/postgres-ctl.ts +2 -1
- package/src/required-host-components.ts +37 -0
- package/src/resolve-api-url.ts +43 -0
- package/src/rest-cache-admin.ts +135 -0
- package/src/scripts/postinstall.ts +9 -46
- package/src/self-host-compose.ts +23 -12
- package/src/studio-dev-server.ts +5 -4
- package/src/ui/README.md +13 -9
- package/src/ui/brand.ts +2 -8
- package/src/ui/clack-api.ts +123 -0
- package/src/ui/clack.ts +153 -0
- package/src/ui/components/FlowSpinner.tsx +15 -0
- package/src/ui/components/LogoWordmark.tsx +36 -0
- package/src/ui/components/PromptPanel.tsx +17 -0
- package/src/ui/components/SelectField.tsx +58 -0
- package/src/ui/confirm.ts +5 -4
- package/src/ui/dev/DevDashboard.tsx +213 -0
- package/src/ui/dev/DevReadyPanelView.tsx +67 -0
- package/src/ui/fatal.ts +5 -10
- package/src/ui/flows/FlowApp.tsx +67 -0
- package/src/ui/flows/prompt-fields.tsx +192 -0
- package/src/ui/flows/types.ts +50 -0
- package/src/ui/index.ts +1 -1
- package/src/ui/messages.ts +50 -8
- package/src/ui/progress.ts +14 -3
- package/src/ui/prompts.ts +17 -9
- package/src/ui/runtime/cancel.ts +6 -0
- package/src/ui/runtime/command-chrome.ts +147 -0
- package/src/ui/runtime/dev-prompt-queue.ts +84 -0
- package/src/ui/runtime/flow-session.ts +11 -0
- package/src/ui/runtime/run-clack-flow.tsx +52 -0
- package/src/ui/theme.ts +41 -0
- package/src/valkey-sidecar.ts +126 -0
- package/tests/admin-ensure.test.ts +59 -0
- package/tests/binary-cache-cloud-overrides.test.ts +2 -2
- package/tests/binary-download-lock.test.ts +41 -0
- package/tests/cli-help.test.ts +7 -4
- package/tests/cli-package-version.test.ts +15 -0
- package/tests/command-chrome-coverage.test.ts +149 -0
- package/tests/command-chrome-wrap.test.ts +51 -0
- package/tests/config.test.ts +8 -4
- package/tests/dev-ports.test.ts +41 -0
- package/tests/dev-ready-panel.test.ts +20 -0
- package/tests/dev-session-lock.test.ts +54 -0
- package/tests/dev-ui.test.ts +66 -3
- package/tests/docker-runtime.test.ts +9 -20
- package/tests/ensure-dev-api-config.test.ts +22 -0
- package/tests/init-dependency-versions.test.ts +62 -0
- package/tests/init-package-json.test.ts +18 -0
- package/tests/init.test.ts +30 -3
- package/tests/required-host-components.test.ts +51 -0
- package/tests/resolve-api-url.test.ts +23 -0
- package/tests/rest-cache-admin.test.ts +28 -0
- package/tests/runtime-contract.test.ts +12 -3
- package/tests/tsconfig.json +8 -2
- package/tests/ui-confirm.test.ts +13 -9
- package/tests/ui-messages.test.ts +4 -18
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +3 -0
- package/dist/dev-tui.d.ts +0 -24
- package/dist/dev-tui.d.ts.map +0 -1
- package/dist/dev-tui.js +0 -188
- package/dist/dev-tui.js.map +0 -1
- package/src/dev-tui.ts +0 -232
package/src/dev-shutdown.ts
CHANGED
|
@@ -1,28 +1,97 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Graceful shutdown for `supatype dev` —
|
|
2
|
+
* Graceful shutdown for `supatype dev` — SIGINT, TUI Ctrl+C, terminal close,
|
|
3
|
+
* and a synchronous compose-down fallback on process exit.
|
|
3
4
|
*/
|
|
4
5
|
|
|
6
|
+
import { existsSync } from "node:fs"
|
|
5
7
|
import { endDevSession } from "./dev-session.js"
|
|
8
|
+
import { clearDevSessionLock } from "./dev-session-lock.js"
|
|
9
|
+
import { runDockerCompose } from "./self-host-compose.js"
|
|
10
|
+
|
|
11
|
+
export interface DevComposeShutdownFallback {
|
|
12
|
+
cwd: string
|
|
13
|
+
composePath: string
|
|
14
|
+
composeProject: string
|
|
15
|
+
}
|
|
6
16
|
|
|
7
17
|
let shutdownWork: (() => Promise<void>) | null = null
|
|
18
|
+
let composeFallback: DevComposeShutdownFallback | null = null
|
|
19
|
+
let shutdownCwd: string | null = null
|
|
8
20
|
let shuttingDown = false
|
|
9
|
-
let
|
|
21
|
+
let shutdownCompleted = false
|
|
22
|
+
let forceQuitRequested = false
|
|
23
|
+
let hooksRegistered = false
|
|
24
|
+
let ignoreSigintUntil = 0
|
|
25
|
+
|
|
26
|
+
/** SIGINT/SIGTERM hooks — call as soon as `supatype dev` starts (before compose is up). */
|
|
27
|
+
export function ensureDevShutdownHooks(): void {
|
|
28
|
+
if (hooksRegistered) return
|
|
29
|
+
hooksRegistered = true
|
|
30
|
+
|
|
31
|
+
process.on("SIGINT", onSignal)
|
|
32
|
+
process.on("SIGTERM", onSignal)
|
|
33
|
+
if (process.platform === "win32") {
|
|
34
|
+
process.on("SIGBREAK", onSignal)
|
|
35
|
+
}
|
|
36
|
+
process.on("exit", onProcessExit)
|
|
37
|
+
|
|
38
|
+
if (process.stdin.isTTY) {
|
|
39
|
+
process.stdin.on("end", onStdinClose)
|
|
40
|
+
process.stdin.on("close", onStdinClose)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
10
43
|
|
|
11
44
|
function onSignal(): void {
|
|
45
|
+
if (Date.now() < ignoreSigintUntil) return
|
|
12
46
|
void runDevShutdown()
|
|
13
47
|
}
|
|
14
48
|
|
|
49
|
+
function onStdinClose(): void {
|
|
50
|
+
if (!process.stdin.isTTY) return
|
|
51
|
+
void runDevShutdown()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function syncComposeDownFallback(): void {
|
|
55
|
+
if (shutdownCompleted || !composeFallback) return
|
|
56
|
+
try {
|
|
57
|
+
runDockerCompose(
|
|
58
|
+
composeFallback.composePath,
|
|
59
|
+
["down"],
|
|
60
|
+
composeFallback.cwd,
|
|
61
|
+
composeFallback.composeProject,
|
|
62
|
+
{ quiet: true },
|
|
63
|
+
)
|
|
64
|
+
} catch {
|
|
65
|
+
// best-effort — process is exiting
|
|
66
|
+
}
|
|
67
|
+
if (shutdownCwd) clearDevSessionLock(shutdownCwd)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function onProcessExit(): void {
|
|
71
|
+
syncComposeDownFallback()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface RegisterDevShutdownOptions {
|
|
75
|
+
/** Sync `docker compose down` when async teardown cannot finish (terminal close, kill). */
|
|
76
|
+
compose?: DevComposeShutdownFallback
|
|
77
|
+
/** Project root — clears `.supatype/dev-session.json` after shutdown. */
|
|
78
|
+
cwd?: string
|
|
79
|
+
}
|
|
80
|
+
|
|
15
81
|
/** Register async teardown (stop children, compose down, etc.). Call once per dev session. */
|
|
16
|
-
export function registerDevShutdown(
|
|
82
|
+
export function registerDevShutdown(
|
|
83
|
+
work: () => Promise<void>,
|
|
84
|
+
opts?: RegisterDevShutdownOptions,
|
|
85
|
+
): void {
|
|
17
86
|
shutdownWork = work
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
process.on("SIGTERM", onSignal)
|
|
87
|
+
composeFallback = opts?.compose ?? null
|
|
88
|
+
shutdownCwd = opts?.cwd ?? opts?.compose?.cwd ?? null
|
|
89
|
+
ensureDevShutdownHooks()
|
|
22
90
|
}
|
|
23
91
|
|
|
24
92
|
/** TUI Ctrl+C — do not re-emit SIGINT (avoids double-fire on Windows raw mode). */
|
|
25
93
|
export function requestDevShutdown(): void {
|
|
94
|
+
ignoreSigintUntil = Date.now() + 400
|
|
26
95
|
void runDevShutdown()
|
|
27
96
|
}
|
|
28
97
|
|
|
@@ -30,13 +99,33 @@ export function isDevShuttingDown(): boolean {
|
|
|
30
99
|
return shuttingDown
|
|
31
100
|
}
|
|
32
101
|
|
|
102
|
+
/** @internal Tests — reset module state between cases. */
|
|
103
|
+
export function resetDevShutdownForTests(): void {
|
|
104
|
+
shutdownWork = null
|
|
105
|
+
composeFallback = null
|
|
106
|
+
shutdownCwd = null
|
|
107
|
+
shuttingDown = false
|
|
108
|
+
shutdownCompleted = false
|
|
109
|
+
forceQuitRequested = false
|
|
110
|
+
hooksRegistered = false
|
|
111
|
+
ignoreSigintUntil = 0
|
|
112
|
+
}
|
|
113
|
+
|
|
33
114
|
async function runDevShutdown(): Promise<void> {
|
|
34
115
|
if (shuttingDown) {
|
|
116
|
+
if (!forceQuitRequested) {
|
|
117
|
+
forceQuitRequested = true
|
|
118
|
+
process.stderr.write(
|
|
119
|
+
"\n[supatype] Still shutting down (stopping Docker)… press Ctrl+C again to force quit.\n",
|
|
120
|
+
)
|
|
121
|
+
return
|
|
122
|
+
}
|
|
35
123
|
try {
|
|
36
124
|
endDevSession()
|
|
37
125
|
} catch {
|
|
38
126
|
// best-effort terminal restore
|
|
39
127
|
}
|
|
128
|
+
process.stderr.write("\n[supatype] Forced quit — Docker containers may still be running.\n")
|
|
40
129
|
process.stdout.write("\n")
|
|
41
130
|
process.exit(130)
|
|
42
131
|
}
|
|
@@ -44,11 +133,27 @@ async function runDevShutdown(): Promise<void> {
|
|
|
44
133
|
|
|
45
134
|
try {
|
|
46
135
|
endDevSession()
|
|
47
|
-
process.
|
|
48
|
-
|
|
136
|
+
process.stderr.write("\n[supatype] Shutting down…\n")
|
|
137
|
+
if (!shutdownWork) {
|
|
138
|
+
if (shutdownCwd) clearDevSessionLock(shutdownCwd)
|
|
139
|
+
process.exit(130)
|
|
140
|
+
}
|
|
141
|
+
await shutdownWork()
|
|
142
|
+
shutdownCompleted = true
|
|
143
|
+
if (shutdownCwd) clearDevSessionLock(shutdownCwd)
|
|
49
144
|
process.exit(0)
|
|
50
145
|
} catch (err) {
|
|
51
146
|
process.stderr.write(`[supatype] Shutdown failed: ${(err as Error).message}\n`)
|
|
147
|
+
process.stderr.write(
|
|
148
|
+
"[supatype] Docker containers may still be running — try: supatype self-host compose down\n",
|
|
149
|
+
)
|
|
150
|
+
syncComposeDownFallback()
|
|
151
|
+
shutdownCompleted = true
|
|
52
152
|
process.exit(1)
|
|
53
153
|
}
|
|
54
154
|
}
|
|
155
|
+
|
|
156
|
+
/** Whether a compose fallback was registered (tests). */
|
|
157
|
+
export function hasComposeShutdownFallback(): boolean {
|
|
158
|
+
return composeFallback !== null && existsSync(composeFallback.composePath)
|
|
159
|
+
}
|
package/src/dev-task-colors.ts
CHANGED
|
@@ -41,7 +41,26 @@ export function colorizeLogLine(taskId: string, line: string): string {
|
|
|
41
41
|
return `${base}${line}${RESET}`
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
/** Ink colour names for React components (parallel to ANSI taskColor). */
|
|
45
|
+
export function taskInkColor(taskId: string): string {
|
|
46
|
+
switch (taskId) {
|
|
47
|
+
case "stack":
|
|
48
|
+
return "magenta"
|
|
49
|
+
case "app":
|
|
50
|
+
return "green"
|
|
51
|
+
case "studio":
|
|
52
|
+
return "cyan"
|
|
53
|
+
case "server":
|
|
54
|
+
return "green"
|
|
55
|
+
case "postgrest":
|
|
56
|
+
return "blue"
|
|
57
|
+
default:
|
|
58
|
+
return "white"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function logInkColor(taskId: string, line: string): string {
|
|
63
|
+
if (line.startsWith("✗ ")) return "red"
|
|
64
|
+
if (line.startsWith("⚠ ")) return "yellow"
|
|
65
|
+
return taskInkColor(taskId)
|
|
47
66
|
}
|
package/src/docker-runtime.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { platform } from "node:os"
|
|
|
7
7
|
import { endDevSession, getActiveDevSession } from "./dev-session.js"
|
|
8
8
|
import { isInteractive } from "./ui/interactive.js"
|
|
9
9
|
import { error, plain } from "./ui/messages.js"
|
|
10
|
-
import {
|
|
10
|
+
import { p, printLogo } from "./ui/prompts.js"
|
|
11
11
|
|
|
12
12
|
export type DockerDaemonProbe =
|
|
13
13
|
| { ok: true }
|
|
@@ -59,6 +59,10 @@ export function formatEnginePushMessage(result: EnginePushResult): string {
|
|
|
59
59
|
const COMPOSE_PROGRESS_LINE =
|
|
60
60
|
/^Container\s+.+\s+(Running|Waiting|Healthy|Created|Starting|Started|Exited|Stopped)\s*$/i
|
|
61
61
|
|
|
62
|
+
export function isComposeProgressLine(line: string): boolean {
|
|
63
|
+
return COMPOSE_PROGRESS_LINE.test(line.trim())
|
|
64
|
+
}
|
|
65
|
+
|
|
62
66
|
/** Drop docker compose progress noise; keep engine JSON and real errors. */
|
|
63
67
|
export function filterComposeNoise(output: string): string {
|
|
64
68
|
return output
|
|
@@ -67,7 +71,7 @@ export function filterComposeNoise(output: string): string {
|
|
|
67
71
|
.filter((line) => {
|
|
68
72
|
const t = line.trim()
|
|
69
73
|
if (!t) return false
|
|
70
|
-
if (
|
|
74
|
+
if (isComposeProgressLine(t)) return false
|
|
71
75
|
return true
|
|
72
76
|
})
|
|
73
77
|
.join("\n")
|
package/src/ensure-binary.ts
CHANGED
|
@@ -7,8 +7,10 @@ import {
|
|
|
7
7
|
download,
|
|
8
8
|
currentPlatform,
|
|
9
9
|
resolveVersionFor,
|
|
10
|
+
isCachedBinaryReady,
|
|
10
11
|
type Component,
|
|
11
12
|
} from "./binary-cache.js"
|
|
13
|
+
import { isDownloadInProgress, waitForComponentDownload } from "./binary-download-lock.js"
|
|
12
14
|
import type { SupatypeProjectConfig } from "./project-config.js"
|
|
13
15
|
|
|
14
16
|
export async function ensureBinary(
|
|
@@ -24,5 +26,23 @@ export async function ensureBinary(
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
const version = await resolveVersionFor(component, config)
|
|
30
|
+
const platform = currentPlatform()
|
|
31
|
+
|
|
32
|
+
if (isDownloadInProgress(component, version)) {
|
|
33
|
+
console.log(`[supatype] Waiting for in-progress ${component} download...`)
|
|
34
|
+
const outcome = await waitForComponentDownload(
|
|
35
|
+
component,
|
|
36
|
+
version,
|
|
37
|
+
() => isCachedBinaryReady(component, version, platform),
|
|
38
|
+
(c) => {
|
|
39
|
+
console.log(`[supatype] Still waiting for ${c}...`)
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
if (outcome === "ready") {
|
|
43
|
+
return resolveBinary(component, config)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return download(component, version, platform)
|
|
28
48
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure CDN component binaries are cached when the host CLI needs them.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ensureBinary } from "./ensure-binary.js"
|
|
6
|
+
import type { Component } from "./components.js"
|
|
7
|
+
import type { SupatypeProjectConfig } from "./project-config.js"
|
|
8
|
+
import {
|
|
9
|
+
describeRequiredHostComponents,
|
|
10
|
+
requiredHostComponents,
|
|
11
|
+
} from "./required-host-components.js"
|
|
12
|
+
import { resolveRuntimeProvider } from "./project-config.js"
|
|
13
|
+
import { error, info, warn } from "./ui/messages.js"
|
|
14
|
+
|
|
15
|
+
export interface ComponentBinaryFailure {
|
|
16
|
+
component: Component
|
|
17
|
+
message: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface EnsureComponentBinariesResult {
|
|
21
|
+
ok: boolean
|
|
22
|
+
failures: ComponentBinaryFailure[]
|
|
23
|
+
skipped: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function ensureComponentBinaries(
|
|
27
|
+
config: SupatypeProjectConfig,
|
|
28
|
+
cwd: string = process.cwd(),
|
|
29
|
+
): Promise<EnsureComponentBinariesResult> {
|
|
30
|
+
const components = requiredHostComponents(config, cwd)
|
|
31
|
+
const provider = resolveRuntimeProvider(config)
|
|
32
|
+
|
|
33
|
+
if (components.length === 0) {
|
|
34
|
+
return { ok: true, failures: [], skipped: true }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const list = describeRequiredHostComponents(components)
|
|
38
|
+
if (provider === "docker") {
|
|
39
|
+
info(
|
|
40
|
+
`Preparing host CLI tools (${list}) — Compose still runs Postgres and the API stack.`,
|
|
41
|
+
)
|
|
42
|
+
} else {
|
|
43
|
+
info(`Preparing local runtime components (${list})…`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const failures: ComponentBinaryFailure[] = []
|
|
47
|
+
|
|
48
|
+
for (const component of components) {
|
|
49
|
+
try {
|
|
50
|
+
await ensureBinary(component, config)
|
|
51
|
+
info(`${component} ready.`)
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
54
|
+
failures.push({ component, message })
|
|
55
|
+
error(`Could not prepare ${component}: ${message}`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { ok: failures.length === 0, failures, skipped: false }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function reportComponentBinaryFailures(failures: ComponentBinaryFailure[]): void {
|
|
63
|
+
if (failures.length === 0) return
|
|
64
|
+
|
|
65
|
+
warn("Some component binaries are still missing.")
|
|
66
|
+
for (const { component, message } of failures) {
|
|
67
|
+
warn(` ${component}: ${message}`)
|
|
68
|
+
}
|
|
69
|
+
warn("Run manually from your project directory: supatype update")
|
|
70
|
+
warn("If downloads keep failing, check your network or try again in a few minutes.")
|
|
71
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync } from "node:fs"
|
|
2
|
+
import { dirname, join } from "node:path"
|
|
3
|
+
|
|
4
|
+
const TEMPLATE_REL = join("config", "api-config.json")
|
|
5
|
+
const TARGET_REL = join(".supatype", "api-config.json")
|
|
6
|
+
|
|
7
|
+
/** Copy committed `config/api-config.json` when `.supatype/api-config.json` is missing. */
|
|
8
|
+
export function ensureDevApiConfig(cwd: string): boolean {
|
|
9
|
+
const target = join(cwd, TARGET_REL)
|
|
10
|
+
if (existsSync(target)) return false
|
|
11
|
+
|
|
12
|
+
const template = join(cwd, TEMPLATE_REL)
|
|
13
|
+
if (!existsSync(template)) return false
|
|
14
|
+
|
|
15
|
+
mkdirSync(dirname(target), { recursive: true })
|
|
16
|
+
copyFileSync(template, target)
|
|
17
|
+
return true
|
|
18
|
+
}
|
package/src/env-file.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
|
|
4
|
+
/** Merge key/value updates into a project `.env` without dropping unrelated lines. */
|
|
5
|
+
export function upsertEnvFile(
|
|
6
|
+
cwd: string,
|
|
7
|
+
updates: Record<string, string>,
|
|
8
|
+
removeKeys: readonly string[] = [],
|
|
9
|
+
): void {
|
|
10
|
+
const envPath = join(cwd, ".env")
|
|
11
|
+
const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : ""
|
|
12
|
+
const keys = new Set([...Object.keys(updates), ...removeKeys])
|
|
13
|
+
const kept = existing
|
|
14
|
+
.split("\n")
|
|
15
|
+
.filter((line) => {
|
|
16
|
+
const key = line.split("=")[0]?.trim()
|
|
17
|
+
return key && line.includes("=") && !keys.has(key)
|
|
18
|
+
})
|
|
19
|
+
const merged = [...kept, ...Object.entries(updates).map(([key, value]) => `${key}=${value}`)]
|
|
20
|
+
writeFileSync(envPath, `${merged.join("\n").trimEnd()}\n`, "utf8")
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function readEnvValue(cwd: string, key: string, fallback: string): string {
|
|
24
|
+
const envPath = join(cwd, ".env")
|
|
25
|
+
if (existsSync(envPath)) {
|
|
26
|
+
const m = readFileSync(envPath, "utf8").match(new RegExp(`^${key}=(.+)$`, "m"))
|
|
27
|
+
if (m?.[1]) return m[1].trim()
|
|
28
|
+
}
|
|
29
|
+
return fallback
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function readEnvInt(cwd: string, key: string): number | null {
|
|
33
|
+
const raw = readEnvValue(cwd, key, "")
|
|
34
|
+
if (!raw) return null
|
|
35
|
+
const port = Number(raw)
|
|
36
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null
|
|
37
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { cliPackageVersion } from "./cli-package-version.js"
|
|
2
|
+
|
|
3
|
+
export interface InitDependencyVersions {
|
|
4
|
+
cli: string
|
|
5
|
+
types: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type NpmRegistryPackage = {
|
|
9
|
+
versions?: Record<string, unknown>
|
|
10
|
+
"dist-tags"?: { latest?: string }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Fallback when the registry is unreachable (offline / tests). */
|
|
14
|
+
export function initDependencyVersionsFallback(): InitDependencyVersions {
|
|
15
|
+
const version = cliPackageVersion()
|
|
16
|
+
return { cli: version, types: version }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function fetchNpmPackage(name: string): Promise<NpmRegistryPackage | null> {
|
|
20
|
+
const url = `https://registry.npmjs.org/${encodeURIComponent(name)}`
|
|
21
|
+
try {
|
|
22
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(10_000) })
|
|
23
|
+
if (!resp.ok) return null
|
|
24
|
+
return (await resp.json()) as NpmRegistryPackage
|
|
25
|
+
} catch {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function versionPublishedOnNpm(meta: NpmRegistryPackage | null, version: string): boolean {
|
|
31
|
+
return Boolean(meta?.versions?.[version])
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function latestPublishedOnNpm(meta: NpmRegistryPackage | null): string | null {
|
|
35
|
+
const latest = meta?.["dist-tags"]?.latest
|
|
36
|
+
return typeof latest === "string" && latest.trim() !== "" ? latest.trim() : null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolvePackageVersion(
|
|
40
|
+
meta: NpmRegistryPackage | null,
|
|
41
|
+
preferred: string,
|
|
42
|
+
): string {
|
|
43
|
+
if (versionPublishedOnNpm(meta, preferred)) return preferred
|
|
44
|
+
const latest = latestPublishedOnNpm(meta)
|
|
45
|
+
if (latest) return latest
|
|
46
|
+
return preferred
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pick @supatype/cli and @supatype/types versions that exist on npm.
|
|
51
|
+
* The running CLI may be a local dev build ahead of the registry (e.g. 0.1.3
|
|
52
|
+
* while types is only published at 0.1.1).
|
|
53
|
+
*/
|
|
54
|
+
export async function resolveInitDependencyVersions(): Promise<InitDependencyVersions> {
|
|
55
|
+
const runningCli = cliPackageVersion()
|
|
56
|
+
const [cliMeta, typesMeta] = await Promise.all([
|
|
57
|
+
fetchNpmPackage("@supatype/cli"),
|
|
58
|
+
fetchNpmPackage("@supatype/types"),
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
if (!cliMeta && !typesMeta) {
|
|
62
|
+
return initDependencyVersionsFallback()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
cli: resolvePackageVersion(cliMeta, runningCli),
|
|
67
|
+
types: resolvePackageVersion(typesMeta, runningCli),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { InitDependencyVersions } from "./init-dependency-versions.js"
|
|
2
|
+
|
|
3
|
+
export interface MergePackageJsonOptions {
|
|
4
|
+
projectName: string
|
|
5
|
+
app: { viteDevUrl?: string; mode: string }
|
|
6
|
+
helloFunction: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type PackageJson = {
|
|
10
|
+
name?: string
|
|
11
|
+
private?: boolean
|
|
12
|
+
type?: string
|
|
13
|
+
scripts?: Record<string, string>
|
|
14
|
+
dependencies?: Record<string, string>
|
|
15
|
+
devDependencies?: Record<string, string>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const CORE_SCRIPTS = {
|
|
19
|
+
dev: "supatype dev",
|
|
20
|
+
push: "supatype push",
|
|
21
|
+
seed: "tsx seed.ts",
|
|
22
|
+
} as const
|
|
23
|
+
|
|
24
|
+
/** Merge Supatype deps/scripts into an existing package.json object. */
|
|
25
|
+
export function mergeSupatypePackageJson(
|
|
26
|
+
pkg: PackageJson,
|
|
27
|
+
opts: MergePackageJsonOptions,
|
|
28
|
+
deps: InitDependencyVersions,
|
|
29
|
+
): PackageJson {
|
|
30
|
+
const next: PackageJson = { ...pkg }
|
|
31
|
+
|
|
32
|
+
if (!next.name) next.name = opts.projectName
|
|
33
|
+
if (next.private === undefined) next.private = true
|
|
34
|
+
if (!next.type) next.type = "module"
|
|
35
|
+
|
|
36
|
+
const scripts = { ...(next.scripts ?? {}) }
|
|
37
|
+
for (const [key, value] of Object.entries(CORE_SCRIPTS)) {
|
|
38
|
+
if (scripts[key] === undefined) scripts[key] = value
|
|
39
|
+
}
|
|
40
|
+
if (scripts.dev !== CORE_SCRIPTS.dev && scripts["supatype:dev"] === undefined) {
|
|
41
|
+
scripts["supatype:dev"] = CORE_SCRIPTS.dev
|
|
42
|
+
}
|
|
43
|
+
if (opts.app.viteDevUrl && scripts.vite === undefined) {
|
|
44
|
+
scripts.vite = "vite"
|
|
45
|
+
}
|
|
46
|
+
if (opts.helloFunction && scripts.functions === undefined) {
|
|
47
|
+
scripts.functions = "supatype functions serve"
|
|
48
|
+
}
|
|
49
|
+
next.scripts = scripts
|
|
50
|
+
|
|
51
|
+
const dependencies = { ...(next.dependencies ?? {}) }
|
|
52
|
+
if (dependencies["@supatype/cli"] === undefined) dependencies["@supatype/cli"] = `^${deps.cli}`
|
|
53
|
+
if (dependencies["@supatype/types"] === undefined) dependencies["@supatype/types"] = `^${deps.types}`
|
|
54
|
+
next.dependencies = dependencies
|
|
55
|
+
|
|
56
|
+
const devDependencies = { ...(next.devDependencies ?? {}) }
|
|
57
|
+
if (devDependencies.tsx === undefined) devDependencies.tsx = "^4.19.2"
|
|
58
|
+
if (devDependencies.typescript === undefined) devDependencies.typescript = "^5"
|
|
59
|
+
if (opts.app.viteDevUrl && devDependencies.vite === undefined) devDependencies.vite = "^6"
|
|
60
|
+
next.devDependencies = devDependencies
|
|
61
|
+
|
|
62
|
+
return next
|
|
63
|
+
}
|
package/src/postgres-ctl.ts
CHANGED
|
@@ -148,7 +148,8 @@ export async function isPortInUse(port: number): Promise<boolean> {
|
|
|
148
148
|
return new Promise((resolve) => {
|
|
149
149
|
const server = createServer()
|
|
150
150
|
server.once("error", (err: NodeJS.ErrnoException) => {
|
|
151
|
-
|
|
151
|
+
// EADDRINUSE — something is listening. EACCES — Windows excluded/reserved port range.
|
|
152
|
+
resolve(err.code === "EADDRINUSE" || err.code === "EACCES")
|
|
152
153
|
})
|
|
153
154
|
server.once("listening", () => {
|
|
154
155
|
server.close(() => resolve(false))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which CDN-cached host binaries a project needs (native vs docker).
|
|
3
|
+
*
|
|
4
|
+
* Docker runs Postgres, API, and schema push in Compose, but the CLI still uses a
|
|
5
|
+
* host engine binary for type generation and admin-config refresh after push.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync } from "node:fs"
|
|
9
|
+
import type { Component } from "./components.js"
|
|
10
|
+
import {
|
|
11
|
+
functionsPathCandidatesFromProject,
|
|
12
|
+
resolveRuntimeProvider,
|
|
13
|
+
type SupatypeProjectConfig,
|
|
14
|
+
} from "./project-config.js"
|
|
15
|
+
|
|
16
|
+
export function requiredHostComponents(
|
|
17
|
+
config: SupatypeProjectConfig,
|
|
18
|
+
cwd: string = process.cwd(),
|
|
19
|
+
): Component[] {
|
|
20
|
+
const provider = resolveRuntimeProvider(config)
|
|
21
|
+
|
|
22
|
+
if (provider === "docker") {
|
|
23
|
+
return ["engine"]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const components: Component[] = ["engine", "server", "postgres"]
|
|
27
|
+
const hasFunctions = functionsPathCandidatesFromProject(config, cwd).some((dir) =>
|
|
28
|
+
existsSync(dir),
|
|
29
|
+
)
|
|
30
|
+
if (hasFunctions) components.push("deno")
|
|
31
|
+
return components
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function describeRequiredHostComponents(components: readonly Component[]): string {
|
|
35
|
+
if (components.length === 0) return ""
|
|
36
|
+
return components.join(", ")
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the project API base URL (Kong gateway or direct server) for CLI HTTP calls.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { loadConfig } from "./config.js"
|
|
6
|
+
import { readEnvValue } from "./env-file.js"
|
|
7
|
+
import { serverBaseUrl } from "./project-config.js"
|
|
8
|
+
|
|
9
|
+
const API_URL_ENV_KEYS = [
|
|
10
|
+
"SUPATYPE_URL",
|
|
11
|
+
"SUPATYPE_API_URL",
|
|
12
|
+
"PUBLIC_SUPATYPE_URL",
|
|
13
|
+
"NEXT_PUBLIC_SUPATYPE_URL",
|
|
14
|
+
"SITE_URL",
|
|
15
|
+
"API_EXTERNAL_URL",
|
|
16
|
+
] as const
|
|
17
|
+
|
|
18
|
+
/** Kong or server origin without a trailing slash. */
|
|
19
|
+
export function resolveProjectApiUrl(cwd: string): string {
|
|
20
|
+
for (const key of API_URL_ENV_KEYS) {
|
|
21
|
+
const value = readEnvValue(cwd, key, "").trim()
|
|
22
|
+
if (value) {
|
|
23
|
+
return value.replace(/\/+$/, "")
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const kongPort = readEnvValue(cwd, "SUPATYPE_KONG_PORT", "").trim()
|
|
28
|
+
if (kongPort) {
|
|
29
|
+
return `http://localhost:${kongPort}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const fromConfig = serverBaseUrl(loadConfig(cwd))
|
|
34
|
+
if (fromConfig) {
|
|
35
|
+
return fromConfig.replace(/\/+$/, "")
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
// No supatype.config — fall through to PORT default.
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const port = readEnvValue(cwd, "PORT", "54321").trim() || "54321"
|
|
42
|
+
return `http://localhost:${port}`
|
|
43
|
+
}
|