@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
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect and clean up Docker Compose state when `project.name` changes.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
6
|
+
import { join } from "node:path"
|
|
7
|
+
import { loadLocalEnvironment } from "./link.js"
|
|
8
|
+
import { composeStackHasContainers } from "./dev-session-lock.js"
|
|
9
|
+
import { composeProjectName, runDockerCompose, type SelfHostComposePaths } from "./self-host-compose.js"
|
|
10
|
+
import { confirm as uiConfirm } from "./ui/confirm.js"
|
|
11
|
+
import { isInteractive } from "./ui/interactive.js"
|
|
12
|
+
import { success, warn } from "./ui/messages.js"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* When `project.name` changes, the compose project slug changes too (`supatype-{name}`).
|
|
16
|
+
* Offer to stop containers from the previous slug so volumes/ports do not linger.
|
|
17
|
+
*/
|
|
18
|
+
export async function handleComposeProjectRename(
|
|
19
|
+
cwd: string,
|
|
20
|
+
currentProjectName: string,
|
|
21
|
+
paths: SelfHostComposePaths,
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
const local = loadLocalEnvironment(cwd)
|
|
24
|
+
const previousRef = local?.projectRef?.trim()
|
|
25
|
+
if (!previousRef || previousRef === currentProjectName) return
|
|
26
|
+
|
|
27
|
+
const previousCompose = composeProjectName(previousRef)
|
|
28
|
+
const currentCompose = composeProjectName(currentProjectName)
|
|
29
|
+
if (previousCompose === currentCompose) return
|
|
30
|
+
if (!composeStackHasContainers(previousCompose)) return
|
|
31
|
+
|
|
32
|
+
const message =
|
|
33
|
+
`Project renamed from "${previousRef}" to "${currentProjectName}".\n` +
|
|
34
|
+
`Docker stack "${previousCompose}" may still be running.`
|
|
35
|
+
|
|
36
|
+
if (!isInteractive()) {
|
|
37
|
+
warn(message)
|
|
38
|
+
warn(`Stop it manually: docker compose -p ${previousCompose} down`)
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const stopOld = await uiConfirm(`${message}\n\nStop the old Docker stack now?`, { default: true })
|
|
43
|
+
|
|
44
|
+
if (!stopOld) {
|
|
45
|
+
warn(`Leaving "${previousCompose}" running. Stop it with: docker compose -p ${previousCompose} down`)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const status = runDockerCompose(paths.composePath, ["down"], cwd, previousCompose, { quiet: true })
|
|
50
|
+
if (status === 0) {
|
|
51
|
+
success(`Stopped old stack "${previousCompose}".`)
|
|
52
|
+
warnIfHardcodedComposeScripts(cwd, previousCompose)
|
|
53
|
+
} else {
|
|
54
|
+
warn(`Could not stop "${previousCompose}" (exit ${status}). Try: docker compose -p ${previousCompose} down`)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function warnIfHardcodedComposeScripts(cwd: string, oldComposeProject: string): void {
|
|
59
|
+
const pkgPath = join(cwd, "package.json")
|
|
60
|
+
if (!existsSync(pkgPath)) return
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as { scripts?: Record<string, string> }
|
|
63
|
+
const scripts = Object.values(pkg.scripts ?? {}).join("\n")
|
|
64
|
+
if (scripts.includes(`-p ${oldComposeProject}`)) {
|
|
65
|
+
warn(
|
|
66
|
+
`package.json scripts still reference compose project "${oldComposeProject}". ` +
|
|
67
|
+
"Update them if you renamed project.name in supatype.config.ts.",
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
// ignore invalid package.json
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/dev-compose.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* `supatype dev` when `provider: docker` — full self-host Compose stack (Kong gateway).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { existsSync, mkdirSync,
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs"
|
|
6
6
|
import { homedir } from "node:os"
|
|
7
7
|
import { dirname, join, resolve } from "node:path"
|
|
8
8
|
import { spawnSync } from "node:child_process"
|
|
9
|
-
import { startProxyDevApp } from "./app/proxy-dev-app.js"
|
|
9
|
+
import { startProxyDevApp, resolveProxyDevScript } from "./app/proxy-dev-app.js"
|
|
10
10
|
import { loadSchemaAst } from "./config.js"
|
|
11
11
|
import {
|
|
12
12
|
COMPOSE_DEV_KONG_PORT,
|
|
@@ -17,7 +17,11 @@ import {
|
|
|
17
17
|
type SupatypeProjectConfig,
|
|
18
18
|
} from "./project-config.js"
|
|
19
19
|
import { signJwt } from "./jwt.js"
|
|
20
|
-
import {
|
|
20
|
+
import { ensureDevDbPort, ensureKongPort } from "./dev-ports.js"
|
|
21
|
+
import { handleComposeProjectRename } from "./compose-rename.js"
|
|
22
|
+
import { recoverStaleDevSession, writeDevSessionLock } from "./dev-session-lock.js"
|
|
23
|
+
import { endDevSession, startDevSession } from "./dev-session.js"
|
|
24
|
+
import { ensureDevApiConfig } from "./ensure-dev-api-config.js"
|
|
21
25
|
import {
|
|
22
26
|
COMPOSE_PINNED_IMAGE_ENV_KEYS,
|
|
23
27
|
composeDockerImageEnv,
|
|
@@ -30,10 +34,11 @@ import {
|
|
|
30
34
|
} from "./self-host-compose.js"
|
|
31
35
|
import type { DockerBrandOptions } from "./docker-runtime.js"
|
|
32
36
|
import { hasEngineOverride } from "./binary-cache.js"
|
|
33
|
-
import { startStudioViteDevServer } from "./studio-dev-server.js"
|
|
37
|
+
import { STUDIO_DEV_PORT, startStudioViteDevServer } from "./studio-dev-server.js"
|
|
38
|
+
import { ensureLocalServerDockerImage } from "./compose-local-server-image.js"
|
|
34
39
|
import { ensureEngine, engineRequest, type DiffResult } from "./engine-client.js"
|
|
35
40
|
import { writeSchemaSourcePushArtifacts, type SchemaSourcePushArtifacts } from "./schema-sources.js"
|
|
36
|
-
import {
|
|
41
|
+
import { readEnvValue, upsertEnvFile } from "./env-file.js"
|
|
37
42
|
import { writeLocalEnvironment } from "./link.js"
|
|
38
43
|
import { registerDevShutdown } from "./dev-shutdown.js"
|
|
39
44
|
import {
|
|
@@ -46,6 +51,8 @@ import { withAdminRoles } from "./studio-admin-roles.js"
|
|
|
46
51
|
import { restoreSystemRelationTargets } from "./restore-system-relation-targets.js"
|
|
47
52
|
import { provisionBucketsFromAst } from "./storage-provision.js"
|
|
48
53
|
import type { ExtractedSchemaAstV2 } from "./schema-ast-v2.js"
|
|
54
|
+
import { ensureFirstAdminUserForProject } from "./commands/admin.js"
|
|
55
|
+
import { publishDevReady } from "./dev-ready-panel.js"
|
|
49
56
|
|
|
50
57
|
const LOCAL_JWT_SECRET = "super-secret-jwt-token-with-at-least-32-characters-long"
|
|
51
58
|
|
|
@@ -70,30 +77,12 @@ export function composeDbUrl(): string {
|
|
|
70
77
|
|
|
71
78
|
/**
|
|
72
79
|
* Resolve the host Kong port for this project. Persisted in `.env` as
|
|
73
|
-
* SUPATYPE_KONG_PORT
|
|
74
|
-
* (18473) or the next free port, so multiple projects can run concurrently.
|
|
80
|
+
* SUPATYPE_KONG_PORT; prompts when the configured port is already taken.
|
|
75
81
|
*/
|
|
76
82
|
async function resolveDevDbPort(cwd: string): Promise<number> {
|
|
77
|
-
|
|
78
|
-
if (existsSync(envPath)) {
|
|
79
|
-
const m = readFileSync(envPath, "utf8").match(/^SUPATYPE_DEV_DB_PORT=(\d+)/m)
|
|
80
|
-
if (m && m[1]) return Number(m[1])
|
|
81
|
-
}
|
|
82
|
-
let port = COMPOSE_DEV_DB_PORT
|
|
83
|
-
while (await isPortInUse(port)) port++
|
|
84
|
-
return port
|
|
83
|
+
return ensureDevDbPort(cwd)
|
|
85
84
|
}
|
|
86
85
|
|
|
87
|
-
function readEnvValue(cwd: string, key: string, fallback: string): string {
|
|
88
|
-
const envPath = join(cwd, ".env")
|
|
89
|
-
if (existsSync(envPath)) {
|
|
90
|
-
const m = readFileSync(envPath, "utf8").match(new RegExp(`^${key}=(.+)$`, "m"))
|
|
91
|
-
if (m?.[1]) return m[1].trim()
|
|
92
|
-
}
|
|
93
|
-
return fallback
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Postgres DSN for compose db when published to the host (local engine push). */
|
|
97
86
|
function hostComposeDbUrl(cwd: string): string {
|
|
98
87
|
const port = readEnvValue(cwd, "SUPATYPE_DEV_DB_PORT", String(COMPOSE_DEV_DB_PORT))
|
|
99
88
|
const user = readEnvValue(cwd, "POSTGRES_USER", "supatype_admin")
|
|
@@ -175,42 +164,17 @@ export async function resolveHostEngineDatabaseUrl(
|
|
|
175
164
|
}
|
|
176
165
|
|
|
177
166
|
async function resolveKongPort(cwd: string): Promise<number> {
|
|
178
|
-
|
|
179
|
-
if (existsSync(envPath)) {
|
|
180
|
-
const m = readFileSync(envPath, "utf8").match(/^SUPATYPE_KONG_PORT=(\d+)/m)
|
|
181
|
-
if (m && m[1]) return Number(m[1])
|
|
182
|
-
}
|
|
183
|
-
let port = COMPOSE_DEV_KONG_PORT
|
|
184
|
-
while (await isPortInUse(port)) port++
|
|
185
|
-
return port
|
|
167
|
+
return ensureKongPort(cwd, { context: "dev" })
|
|
186
168
|
}
|
|
187
169
|
|
|
188
|
-
function
|
|
189
|
-
cwd: string,
|
|
190
|
-
updates: Record<string, string>,
|
|
191
|
-
removeKeys: readonly string[] = [],
|
|
192
|
-
): void {
|
|
193
|
-
const envPath = join(cwd, ".env")
|
|
194
|
-
const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : ""
|
|
195
|
-
const keys = new Set([...Object.keys(updates), ...removeKeys])
|
|
196
|
-
const kept = existing
|
|
197
|
-
.split("\n")
|
|
198
|
-
.filter((line) => {
|
|
199
|
-
const key = line.split("=")[0]?.trim()
|
|
200
|
-
return key && line.includes("=") && !keys.has(key)
|
|
201
|
-
})
|
|
202
|
-
const merged = [...kept, ...Object.entries(updates).map(([key, value]) => `${key}=${value}`)]
|
|
203
|
-
writeFileSync(envPath, `${merged.join("\n").trimEnd()}\n`, "utf8")
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/** Keep compose + Studio on the same freshly signed dev JWTs; sync optional image pins from config. */
|
|
207
|
-
function ensureDevComposeEnv(
|
|
170
|
+
function upsertDevComposeEnv(
|
|
208
171
|
cwd: string,
|
|
209
172
|
config: SupatypeProjectConfig,
|
|
210
173
|
anonKey: string,
|
|
211
174
|
serviceRoleKey: string,
|
|
212
175
|
kongPort: number,
|
|
213
176
|
devDbPort?: number,
|
|
177
|
+
localServerImage?: string,
|
|
214
178
|
): void {
|
|
215
179
|
const apiUrl = `http://localhost:${kongPort}`
|
|
216
180
|
const imagePins = composeDockerImageEnv(config)
|
|
@@ -222,12 +186,14 @@ function ensureDevComposeEnv(
|
|
|
222
186
|
ANON_KEY: anonKey,
|
|
223
187
|
SERVICE_ROLE_KEY: serviceRoleKey,
|
|
224
188
|
PUBLIC_SUPATYPE_ANON_KEY: anonKey,
|
|
189
|
+
VITE_SUPATYPE_ANON_KEY: anonKey,
|
|
225
190
|
PUBLIC_SUPATYPE_URL: apiUrl,
|
|
226
191
|
SUPATYPE_KONG_PORT: String(kongPort),
|
|
227
192
|
API_EXTERNAL_URL: apiUrl,
|
|
228
193
|
SITE_URL: apiUrl,
|
|
229
194
|
GOTRUE_MAILER_AUTOCONFIRM: "true",
|
|
230
195
|
...imagePins,
|
|
196
|
+
...(localServerImage !== undefined && { SUPATYPE_SERVER_IMAGE: localServerImage }),
|
|
231
197
|
}
|
|
232
198
|
if (devDbPort !== undefined) {
|
|
233
199
|
updates.SUPATYPE_DEV_DB_PORT = String(devDbPort)
|
|
@@ -238,6 +204,19 @@ function ensureDevComposeEnv(
|
|
|
238
204
|
upsertEnvFile(cwd, updates, removeImageKeys)
|
|
239
205
|
}
|
|
240
206
|
|
|
207
|
+
/** Keep compose + Studio on the same freshly signed dev JWTs; sync optional image pins from config. */
|
|
208
|
+
function ensureDevComposeEnv(
|
|
209
|
+
cwd: string,
|
|
210
|
+
config: SupatypeProjectConfig,
|
|
211
|
+
anonKey: string,
|
|
212
|
+
serviceRoleKey: string,
|
|
213
|
+
kongPort: number,
|
|
214
|
+
devDbPort?: number,
|
|
215
|
+
localServerImage?: string,
|
|
216
|
+
): void {
|
|
217
|
+
upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort, localServerImage)
|
|
218
|
+
}
|
|
219
|
+
|
|
241
220
|
async function waitComposeHealthy(paths: SelfHostComposePaths, cwd: string, maxMs: number, composeProject: string): Promise<void> {
|
|
242
221
|
const composeDir = dirname(paths.composePath)
|
|
243
222
|
const envFile = join(cwd, ".env")
|
|
@@ -271,6 +250,34 @@ async function waitKongReady(kongPort: number, maxSec: number): Promise<void> {
|
|
|
271
250
|
throw new Error(`Kong gateway at ${base} did not become ready within ${maxSec}s`)
|
|
272
251
|
}
|
|
273
252
|
|
|
253
|
+
/** Kong may be up while server → storage is still starting (503 or upstream errors). */
|
|
254
|
+
async function waitStorageApiReady(
|
|
255
|
+
kongPort: number,
|
|
256
|
+
serviceRoleKey: string,
|
|
257
|
+
maxSec: number,
|
|
258
|
+
): Promise<void> {
|
|
259
|
+
const url = `http://localhost:${kongPort}/storage/v1/bucket`
|
|
260
|
+
const headers = { Authorization: `Bearer ${serviceRoleKey}` }
|
|
261
|
+
for (let i = 0; i < maxSec; i++) {
|
|
262
|
+
try {
|
|
263
|
+
const res = await fetch(url, { headers })
|
|
264
|
+
if (res.ok) return
|
|
265
|
+
const body = await res.text()
|
|
266
|
+
const kongUpstreamDown = body.includes("invalid response was received from the upstream server")
|
|
267
|
+
if (!kongUpstreamDown && res.status !== 503) {
|
|
268
|
+
// Non-transient storage response (e.g. 401) — stop waiting.
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
/* retry */
|
|
273
|
+
}
|
|
274
|
+
await new Promise((r) => setTimeout(r, 1000))
|
|
275
|
+
}
|
|
276
|
+
console.warn(
|
|
277
|
+
`[supatype] Storage API at ${url} did not become ready within ${maxSec}s — bucket provisioning may fail.`,
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
|
|
274
281
|
async function provisionDockerStorageBuckets(
|
|
275
282
|
ast: ExtractedSchemaAstV2,
|
|
276
283
|
kongPort: number,
|
|
@@ -668,8 +675,13 @@ export async function pushSchemaDocker(cwd: string, config: SupatypeProjectConfi
|
|
|
668
675
|
exitComposeFailed(upGateway, "Could not start the Compose gateway stack.", pushBrand)
|
|
669
676
|
}
|
|
670
677
|
await waitKongReady(kongPort, 120)
|
|
678
|
+
await waitStorageApiReady(kongPort, serviceRoleKey, 90)
|
|
671
679
|
await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey)
|
|
672
680
|
|
|
681
|
+
await ensureFirstAdminUserForProject(cwd, config, {
|
|
682
|
+
compose: { project, composePath: paths.composePath },
|
|
683
|
+
})
|
|
684
|
+
|
|
673
685
|
console.log("[supatype] Schema pushed.")
|
|
674
686
|
}
|
|
675
687
|
|
|
@@ -689,12 +701,56 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
689
701
|
const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
|
|
690
702
|
const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
|
|
691
703
|
|
|
692
|
-
|
|
704
|
+
const devBrand = { intro: "Local development" }
|
|
705
|
+
const localServerImage = await ensureLocalServerDockerImage(cwd, config, devBrand)
|
|
706
|
+
|
|
707
|
+
ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort, localServerImage)
|
|
693
708
|
|
|
694
709
|
console.log(`[supatype] provider: docker — starting self-host Compose stack (project ${project}, gateway :${kongPort})...`)
|
|
695
710
|
const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
|
|
696
|
-
|
|
711
|
+
if (ensureDevApiConfig(cwd)) {
|
|
712
|
+
console.log("[supatype] API config written to .supatype/api-config.json")
|
|
713
|
+
}
|
|
697
714
|
|
|
715
|
+
type StudioProc = Awaited<ReturnType<typeof startStudioViteDevServer>>
|
|
716
|
+
type AppProc = ReturnType<typeof startProxyDevApp>
|
|
717
|
+
const shutdownState: {
|
|
718
|
+
studioProc: StudioProc
|
|
719
|
+
appProc: AppProc
|
|
720
|
+
schemaWatcher: import("node:fs").FSWatcher | null
|
|
721
|
+
debounceTimer: ReturnType<typeof setTimeout> | null
|
|
722
|
+
} = {
|
|
723
|
+
studioProc: null,
|
|
724
|
+
appProc: null,
|
|
725
|
+
schemaWatcher: null,
|
|
726
|
+
debounceTimer: null,
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
registerDevShutdown(async () => {
|
|
730
|
+
shutdownState.schemaWatcher?.close()
|
|
731
|
+
shutdownState.schemaWatcher = null
|
|
732
|
+
if (shutdownState.debounceTimer) {
|
|
733
|
+
clearTimeout(shutdownState.debounceTimer)
|
|
734
|
+
shutdownState.debounceTimer = null
|
|
735
|
+
}
|
|
736
|
+
console.log("[supatype] Shutting down compose...")
|
|
737
|
+
await shutdownState.studioProc?.stop()
|
|
738
|
+
await shutdownState.appProc?.stop()
|
|
739
|
+
const downStatus = runDockerCompose(paths.composePath, ["down"], cwd, project, { quiet: true })
|
|
740
|
+
if (downStatus === 0) {
|
|
741
|
+
console.log("[supatype] Compose stack stopped.")
|
|
742
|
+
} else {
|
|
743
|
+
console.warn(`[supatype] Compose down exited with status ${downStatus}.`)
|
|
744
|
+
}
|
|
745
|
+
}, {
|
|
746
|
+
cwd,
|
|
747
|
+
compose: { cwd, composePath: paths.composePath, composeProject: project },
|
|
748
|
+
})
|
|
749
|
+
|
|
750
|
+
await recoverStaleDevSession(cwd)
|
|
751
|
+
await handleComposeProjectRename(cwd, config.project.name, paths)
|
|
752
|
+
|
|
753
|
+
console.log("[supatype] Bringing up Docker Compose services...")
|
|
698
754
|
const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
|
|
699
755
|
quiet: true,
|
|
700
756
|
brand: devBrand,
|
|
@@ -712,8 +768,29 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
712
768
|
console.error("[supatype] Initial schema push failed:", (e as Error).message),
|
|
713
769
|
)
|
|
714
770
|
|
|
771
|
+
await ensureFirstAdminUserForProject(cwd, config, {
|
|
772
|
+
compose: { project, composePath: paths.composePath },
|
|
773
|
+
})
|
|
774
|
+
|
|
775
|
+
if (localServerImage !== undefined) {
|
|
776
|
+
console.log("[supatype] Recreating server with local image...")
|
|
777
|
+
const recreateStatus = runDockerCompose(
|
|
778
|
+
paths.composePath,
|
|
779
|
+
["up", "-d", "--force-recreate", "--no-deps", "server"],
|
|
780
|
+
cwd,
|
|
781
|
+
project,
|
|
782
|
+
{ quiet: true, brand: devBrand },
|
|
783
|
+
)
|
|
784
|
+
if (recreateStatus !== 0) {
|
|
785
|
+
endDevSession()
|
|
786
|
+
exitComposeFailed(recreateStatus, "Could not recreate the server container with the local image.", devBrand)
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
715
790
|
console.log("[supatype] Waiting for API gateway...")
|
|
716
791
|
await waitKongReady(kongPort, 120)
|
|
792
|
+
console.log("[supatype] Waiting for storage API...")
|
|
793
|
+
await waitStorageApiReady(kongPort, serviceRoleKey, 90)
|
|
717
794
|
|
|
718
795
|
writeLocalEnvironment(cwd, {
|
|
719
796
|
target: "local",
|
|
@@ -724,13 +801,23 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
724
801
|
provider: "docker",
|
|
725
802
|
})
|
|
726
803
|
|
|
804
|
+
writeDevSessionLock(cwd, {
|
|
805
|
+
composeProject: project,
|
|
806
|
+
projectRef: config.project.name,
|
|
807
|
+
composePath: paths.composePath,
|
|
808
|
+
kongPort,
|
|
809
|
+
startedAt: new Date().toISOString(),
|
|
810
|
+
})
|
|
811
|
+
|
|
727
812
|
const ast = loadSchemaAst(schemaPath, cwd)
|
|
728
813
|
await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey)
|
|
729
814
|
|
|
730
815
|
const pidDir = join(homedir(), ".supatype", "projects", config.project.name, "pid")
|
|
731
816
|
mkdirSync(pidDir, { recursive: true })
|
|
732
817
|
|
|
733
|
-
|
|
818
|
+
startDevSession()
|
|
819
|
+
|
|
820
|
+
let studioProc: StudioProc = null
|
|
734
821
|
const studioOverride = config.overrides?.studio
|
|
735
822
|
if (studioOverride) {
|
|
736
823
|
studioProc = startStudioViteDevServer({
|
|
@@ -739,63 +826,55 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
739
826
|
pidDir,
|
|
740
827
|
serviceRoleKey,
|
|
741
828
|
proxyTarget: `http://localhost:${kongPort}`,
|
|
742
|
-
viteSupatypeUrl: `http://localhost:${
|
|
829
|
+
viteSupatypeUrl: `http://localhost:${STUDIO_DEV_PORT}`,
|
|
743
830
|
basePath: "/studio/",
|
|
744
831
|
})
|
|
745
832
|
studioProc?.start()
|
|
833
|
+
shutdownState.studioProc = studioProc
|
|
746
834
|
if (studioProc) {
|
|
747
|
-
console.log(
|
|
835
|
+
console.log(
|
|
836
|
+
`[supatype] Studio (overrides.studio) — live reload proxied at http://localhost:${kongPort}/studio/`,
|
|
837
|
+
)
|
|
748
838
|
}
|
|
749
839
|
}
|
|
750
840
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
841
|
+
const links = [
|
|
842
|
+
{ label: "API", url: `http://localhost:${kongPort}` },
|
|
843
|
+
{ label: "REST", url: `http://localhost:${kongPort}/rest/v1/` },
|
|
844
|
+
{ label: "Auth", url: `http://localhost:${kongPort}/auth/v1/` },
|
|
845
|
+
{ label: "Storage", url: `http://localhost:${kongPort}/storage/v1/` },
|
|
846
|
+
{ label: "Realtime", url: `ws://localhost:${kongPort}/realtime/v1/` },
|
|
847
|
+
]
|
|
848
|
+
if (resolveProxyDevScript(config) !== null) {
|
|
849
|
+
links.push({ label: "App", url: `http://localhost:${kongPort}/` })
|
|
850
|
+
}
|
|
851
|
+
links.push({ label: "Studio", url: `http://localhost:${kongPort}/studio/` })
|
|
759
852
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
853
|
+
const hints: string[] = []
|
|
854
|
+
if (existsSync(join(cwd, "seed.ts"))) {
|
|
855
|
+
hints.push("Demo data: pnpm seed")
|
|
856
|
+
}
|
|
763
857
|
|
|
764
|
-
|
|
765
|
-
`)
|
|
858
|
+
publishDevReady({
|
|
859
|
+
title: `Services running (Docker · ${project})`,
|
|
860
|
+
links,
|
|
861
|
+
anonKey,
|
|
862
|
+
serviceRoleKey,
|
|
863
|
+
...(hints.length > 0 ? { hints } : {}),
|
|
864
|
+
})
|
|
766
865
|
|
|
767
866
|
const appProc = startProxyDevApp(cwd, config, pidDir)
|
|
768
|
-
|
|
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...")
|
|
780
|
-
await studioProc?.stop()
|
|
781
|
-
await appProc?.stop()
|
|
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
|
-
})
|
|
867
|
+
shutdownState.appProc = appProc
|
|
789
868
|
|
|
790
869
|
if (opts.watch) {
|
|
791
870
|
const schemaDir = join(projectRootFromConfig(config, cwd), config.schema?.path ?? "schema/index.ts", "..")
|
|
792
871
|
console.log(`[supatype] Watching ${schemaDir} for changes...`)
|
|
793
872
|
const { watch } = await import("node:fs")
|
|
794
|
-
schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
|
|
873
|
+
shutdownState.schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
|
|
795
874
|
if (!filename?.endsWith(".ts")) return
|
|
796
|
-
if (debounceTimer) clearTimeout(debounceTimer)
|
|
797
|
-
debounceTimer = setTimeout(() => {
|
|
798
|
-
debounceTimer = null
|
|
875
|
+
if (shutdownState.debounceTimer) clearTimeout(shutdownState.debounceTimer)
|
|
876
|
+
shutdownState.debounceTimer = setTimeout(() => {
|
|
877
|
+
shutdownState.debounceTimer = null
|
|
799
878
|
console.log(`\n[supatype] Change detected in ${filename}, pushing schema...`)
|
|
800
879
|
runComposeSchemaPushQueued(cwd, config, paths, schemaPath, project)
|
|
801
880
|
.then(async () => {
|
package/src/dev-log-bus.ts
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Per-task log buffers for `supatype dev` TUI mode.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { DevReadyPanel } from "./dev-ready-panel.js"
|
|
6
|
+
import { devReadyPanelRowCount } from "./dev-ready-panel.js"
|
|
7
|
+
|
|
5
8
|
export type DevLogLevel = "log" | "warn" | "error"
|
|
6
9
|
|
|
7
10
|
export interface DevTask {
|
|
@@ -18,6 +21,7 @@ export class DevLogBus {
|
|
|
18
21
|
private readonly order: string[] = []
|
|
19
22
|
private readonly listeners = new Set<() => void>()
|
|
20
23
|
private focusedTaskId = "stack"
|
|
24
|
+
private readyPanel: DevReadyPanel | null = null
|
|
21
25
|
|
|
22
26
|
constructor(private readonly maxLines = DEFAULT_MAX_LINES) {
|
|
23
27
|
this.registerTask("stack", "supatype")
|
|
@@ -66,6 +70,20 @@ export class DevLogBus {
|
|
|
66
70
|
if (prev) this.setFocusedTaskId(prev)
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
setReadyPanel(panel: DevReadyPanel): void {
|
|
74
|
+
this.readyPanel = panel
|
|
75
|
+
this.notify()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getReadyPanel(): DevReadyPanel | null {
|
|
79
|
+
return this.readyPanel
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
readyPanelRowCount(): number {
|
|
83
|
+
if (!this.readyPanel) return 0
|
|
84
|
+
return devReadyPanelRowCount(this.readyPanel)
|
|
85
|
+
}
|
|
86
|
+
|
|
69
87
|
append(taskId: string, line: string, level: DevLogLevel = "log"): void {
|
|
70
88
|
this.ensureTask(taskId, taskId)
|
|
71
89
|
const task = this.tasks.get(taskId)
|
package/src/dev-log-filter.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Line filters for subprocess output during `supatype dev`.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { isComposeProgressLine } from "./engine-push-output.js"
|
|
6
|
+
|
|
5
7
|
/** Strip ANSI SGR sequences for TUI rendering. */
|
|
6
8
|
export function stripAnsi(text: string): string {
|
|
7
9
|
return text.replace(/\x1b\[[0-9;]*m/g, "")
|
|
@@ -17,6 +19,46 @@ export function filterDevSubprocessLine(taskId: string, line: string): boolean {
|
|
|
17
19
|
return true
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
const DOCKER_BUILD_NOISE =
|
|
23
|
+
/^#\d+\s|^#\d+ \[|^\s*=> \[|^\s*=>\s|^\s*--->\s|^\s*\d+\.\d+s\s|^\s*CACHED\s|^\s*DONE\s[\d.]+s?$|^Step \d+\/\d+|^Successfully (built|tagged)|^WARNING:|^DEPRECATED:|^View build details:|^What's next:|^The push refers to|^Using docker|^Sending build context|^Pulling fs layer|^Waiting$|^Verifying Checksum|^Download complete|^Pull complete|^Extracting \[|^Already exists$|^Building dependency tree|^Reading state information|^Get:\d+ |^Fetched \d+ |^Reading package lists|^Preparing to unpack|^Unpacking |^Setting up /i
|
|
24
|
+
|
|
25
|
+
/** Drop docker build / compose progress from the orchestrator (stack) pane. */
|
|
26
|
+
export function filterStackLogLine(line: string): boolean {
|
|
27
|
+
const t = stripAnsi(line).trim()
|
|
28
|
+
if (!t) return false
|
|
29
|
+
|
|
30
|
+
if (t.startsWith("✗ ") || t.startsWith("⚠ ")) return true
|
|
31
|
+
if (/https?:\/\//.test(t) || /^ws:\/\//.test(t)) return true
|
|
32
|
+
if (/\[supatype\]/.test(line)) return true
|
|
33
|
+
if (/^Services running/i.test(t)) return true
|
|
34
|
+
if (/^(anon key|service_role|API \(Kong\)|REST API|Auth|Storage|Realtime|Studio|App|Demo data|Postgres|supatype-server|Press Ctrl)/.test(t)) {
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
if (/^Applied \d+ operation|^Schema up to date|^Schema pushed|^Watching .+ for changes|^Change detected|^Shutting down|^Compose stack stopped|^Local server image ready|^Building local server|^Waiting for |^Recreating server|^API config written|^provider: docker|^Bringing up Docker|^Schema push failed|^Initial schema push failed|^Storage bucket|^Storage API at|^Local binary overrides active|^Resolving component binaries|^Postgres |^Demo data:|^JWT secret:/.test(t)) {
|
|
38
|
+
return true
|
|
39
|
+
}
|
|
40
|
+
if (/^\S+\s+→\s/.test(t)) return true
|
|
41
|
+
if (isComposeProgressLine(t)) return false
|
|
42
|
+
if (DOCKER_BUILD_NOISE.test(t)) return false
|
|
43
|
+
if (/^Container\s+/i.test(t)) return false
|
|
44
|
+
if (/^Image\s+/i.test(t)) return false
|
|
45
|
+
if (/^network\s+\S+\s+(Creating|Created)/i.test(t)) return false
|
|
46
|
+
if (/^volume\s+\S+\s+(Creating|Created)/i.test(t)) return false
|
|
47
|
+
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Drop docker noise only — keep diff tables, push status, and command output. */
|
|
52
|
+
export function filterCommandLogLine(line: string): boolean {
|
|
53
|
+
const t = stripAnsi(line).trim()
|
|
54
|
+
if (!t) return false
|
|
55
|
+
if (isComposeProgressLine(t)) return false
|
|
56
|
+
if (DOCKER_BUILD_NOISE.test(t)) return false
|
|
57
|
+
if (/^Container\s+/i.test(t)) return false
|
|
58
|
+
if (/^Image\s+/i.test(t)) return false
|
|
59
|
+
return true
|
|
60
|
+
}
|
|
61
|
+
|
|
20
62
|
/** Format console.* arguments the way Node does for a single log line. */
|
|
21
63
|
export function formatConsoleArgs(args: unknown[]): string {
|
|
22
64
|
return args
|