@supatype/cli 0.1.1 → 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 +114 -90
- 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.map +1 -1
- package/dist/commands/admin.js +22 -6
- 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 +26 -22
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts +3 -4
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +238 -168
- 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/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.map +1 -1
- package/dist/compose-rename.js +5 -8
- package/dist/compose-rename.js.map +1 -1
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +111 -54
- 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.map +1 -1
- package/dist/dev-ports.js +19 -12
- package/dist/dev-ports.js.map +1 -1
- 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.map +1 -1
- package/dist/dev-session-lock.js +5 -8
- package/dist/dev-session-lock.js.map +1 -1
- 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 +2 -0
- package/dist/dev-shutdown.d.ts.map +1 -1
- package/dist/dev-shutdown.js +29 -15
- 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/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 +23 -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 +9 -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 +24 -6
- package/src/commands/cache.ts +105 -5
- package/src/commands/dev.ts +26 -21
- package/src/commands/init.ts +124 -45
- package/src/commands/link-helpers.ts +30 -29
- package/src/compose-local-server-image.ts +68 -0
- package/src/compose-rename.ts +5 -8
- package/src/dev-compose.ts +136 -51
- package/src/dev-log-bus.ts +18 -0
- package/src/dev-log-filter.ts +42 -0
- package/src/dev-ports.ts +22 -11
- package/src/dev-ready-panel.ts +63 -0
- package/src/dev-session-lock.ts +5 -8
- package/src/dev-session.ts +98 -18
- package/src/dev-shutdown.ts +29 -17
- 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/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 +22 -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/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-ready-panel.test.ts +20 -0
- package/tests/dev-ui.test.ts +42 -2
- 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/compose-rename.ts
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs"
|
|
6
6
|
import { join } from "node:path"
|
|
7
|
-
import * as p from "@clack/prompts"
|
|
8
7
|
import { loadLocalEnvironment } from "./link.js"
|
|
9
8
|
import { composeStackHasContainers } from "./dev-session-lock.js"
|
|
10
9
|
import { composeProjectName, runDockerCompose, type SelfHostComposePaths } from "./self-host-compose.js"
|
|
10
|
+
import { confirm as uiConfirm } from "./ui/confirm.js"
|
|
11
11
|
import { isInteractive } from "./ui/interactive.js"
|
|
12
|
-
import { warn } from "./ui/messages.js"
|
|
12
|
+
import { success, warn } from "./ui/messages.js"
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* When `project.name` changes, the compose project slug changes too (`supatype-{name}`).
|
|
@@ -39,19 +39,16 @@ export async function handleComposeProjectRename(
|
|
|
39
39
|
return
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const stopOld = await
|
|
43
|
-
message: `${message}\n\nStop the old Docker stack now?`,
|
|
44
|
-
initialValue: true,
|
|
45
|
-
})
|
|
42
|
+
const stopOld = await uiConfirm(`${message}\n\nStop the old Docker stack now?`, { default: true })
|
|
46
43
|
|
|
47
|
-
if (
|
|
44
|
+
if (!stopOld) {
|
|
48
45
|
warn(`Leaving "${previousCompose}" running. Stop it with: docker compose -p ${previousCompose} down`)
|
|
49
46
|
return
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
const status = runDockerCompose(paths.composePath, ["down"], cwd, previousCompose, { quiet: true })
|
|
53
50
|
if (status === 0) {
|
|
54
|
-
|
|
51
|
+
success(`Stopped old stack "${previousCompose}".`)
|
|
55
52
|
warnIfHardcodedComposeScripts(cwd, previousCompose)
|
|
56
53
|
} else {
|
|
57
54
|
warn(`Could not stop "${previousCompose}" (exit ${status}). Try: docker compose -p ${previousCompose} down`)
|
package/src/dev-compose.ts
CHANGED
|
@@ -6,7 +6,7 @@ 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,
|
|
@@ -20,7 +20,8 @@ import { signJwt } from "./jwt.js"
|
|
|
20
20
|
import { ensureDevDbPort, ensureKongPort } from "./dev-ports.js"
|
|
21
21
|
import { handleComposeProjectRename } from "./compose-rename.js"
|
|
22
22
|
import { recoverStaleDevSession, writeDevSessionLock } from "./dev-session-lock.js"
|
|
23
|
-
import {
|
|
23
|
+
import { endDevSession, startDevSession } from "./dev-session.js"
|
|
24
|
+
import { ensureDevApiConfig } from "./ensure-dev-api-config.js"
|
|
24
25
|
import {
|
|
25
26
|
COMPOSE_PINNED_IMAGE_ENV_KEYS,
|
|
26
27
|
composeDockerImageEnv,
|
|
@@ -33,10 +34,11 @@ import {
|
|
|
33
34
|
} from "./self-host-compose.js"
|
|
34
35
|
import type { DockerBrandOptions } from "./docker-runtime.js"
|
|
35
36
|
import { hasEngineOverride } from "./binary-cache.js"
|
|
36
|
-
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"
|
|
37
39
|
import { ensureEngine, engineRequest, type DiffResult } from "./engine-client.js"
|
|
38
40
|
import { writeSchemaSourcePushArtifacts, type SchemaSourcePushArtifacts } from "./schema-sources.js"
|
|
39
|
-
import {
|
|
41
|
+
import { readEnvValue, upsertEnvFile } from "./env-file.js"
|
|
40
42
|
import { writeLocalEnvironment } from "./link.js"
|
|
41
43
|
import { registerDevShutdown } from "./dev-shutdown.js"
|
|
42
44
|
import {
|
|
@@ -50,6 +52,7 @@ import { restoreSystemRelationTargets } from "./restore-system-relation-targets.
|
|
|
50
52
|
import { provisionBucketsFromAst } from "./storage-provision.js"
|
|
51
53
|
import type { ExtractedSchemaAstV2 } from "./schema-ast-v2.js"
|
|
52
54
|
import { ensureFirstAdminUserForProject } from "./commands/admin.js"
|
|
55
|
+
import { publishDevReady } from "./dev-ready-panel.js"
|
|
53
56
|
|
|
54
57
|
const LOCAL_JWT_SECRET = "super-secret-jwt-token-with-at-least-32-characters-long"
|
|
55
58
|
|
|
@@ -171,6 +174,7 @@ function upsertDevComposeEnv(
|
|
|
171
174
|
serviceRoleKey: string,
|
|
172
175
|
kongPort: number,
|
|
173
176
|
devDbPort?: number,
|
|
177
|
+
localServerImage?: string,
|
|
174
178
|
): void {
|
|
175
179
|
const apiUrl = `http://localhost:${kongPort}`
|
|
176
180
|
const imagePins = composeDockerImageEnv(config)
|
|
@@ -189,6 +193,7 @@ function upsertDevComposeEnv(
|
|
|
189
193
|
SITE_URL: apiUrl,
|
|
190
194
|
GOTRUE_MAILER_AUTOCONFIRM: "true",
|
|
191
195
|
...imagePins,
|
|
196
|
+
...(localServerImage !== undefined && { SUPATYPE_SERVER_IMAGE: localServerImage }),
|
|
192
197
|
}
|
|
193
198
|
if (devDbPort !== undefined) {
|
|
194
199
|
updates.SUPATYPE_DEV_DB_PORT = String(devDbPort)
|
|
@@ -207,8 +212,9 @@ function ensureDevComposeEnv(
|
|
|
207
212
|
serviceRoleKey: string,
|
|
208
213
|
kongPort: number,
|
|
209
214
|
devDbPort?: number,
|
|
215
|
+
localServerImage?: string,
|
|
210
216
|
): void {
|
|
211
|
-
upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort)
|
|
217
|
+
upsertDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort, localServerImage)
|
|
212
218
|
}
|
|
213
219
|
|
|
214
220
|
async function waitComposeHealthy(paths: SelfHostComposePaths, cwd: string, maxMs: number, composeProject: string): Promise<void> {
|
|
@@ -244,6 +250,34 @@ async function waitKongReady(kongPort: number, maxSec: number): Promise<void> {
|
|
|
244
250
|
throw new Error(`Kong gateway at ${base} did not become ready within ${maxSec}s`)
|
|
245
251
|
}
|
|
246
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
|
+
|
|
247
281
|
async function provisionDockerStorageBuckets(
|
|
248
282
|
ast: ExtractedSchemaAstV2,
|
|
249
283
|
kongPort: number,
|
|
@@ -641,6 +675,7 @@ export async function pushSchemaDocker(cwd: string, config: SupatypeProjectConfi
|
|
|
641
675
|
exitComposeFailed(upGateway, "Could not start the Compose gateway stack.", pushBrand)
|
|
642
676
|
}
|
|
643
677
|
await waitKongReady(kongPort, 120)
|
|
678
|
+
await waitStorageApiReady(kongPort, serviceRoleKey, 90)
|
|
644
679
|
await provisionDockerStorageBuckets(ast, kongPort, serviceRoleKey)
|
|
645
680
|
|
|
646
681
|
await ensureFirstAdminUserForProject(cwd, config, {
|
|
@@ -666,14 +701,56 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
666
701
|
const anonKey = signJwt({ ...jwtBase, role: "anon" }, LOCAL_JWT_SECRET)
|
|
667
702
|
const serviceRoleKey = signJwt({ ...jwtBase, role: "service_role" }, LOCAL_JWT_SECRET)
|
|
668
703
|
|
|
669
|
-
|
|
704
|
+
const devBrand = { intro: "Local development" }
|
|
705
|
+
const localServerImage = await ensureLocalServerDockerImage(cwd, config, devBrand)
|
|
706
|
+
|
|
707
|
+
ensureDevComposeEnv(cwd, config, anonKey, serviceRoleKey, kongPort, devDbPort, localServerImage)
|
|
670
708
|
|
|
671
709
|
console.log(`[supatype] provider: docker — starting self-host Compose stack (project ${project}, gateway :${kongPort})...`)
|
|
672
710
|
const paths = writeSelfHostCompose(cwd, config, { devLocal: true })
|
|
711
|
+
if (ensureDevApiConfig(cwd)) {
|
|
712
|
+
console.log("[supatype] API config written to .supatype/api-config.json")
|
|
713
|
+
}
|
|
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
|
+
|
|
673
750
|
await recoverStaleDevSession(cwd)
|
|
674
751
|
await handleComposeProjectRename(cwd, config.project.name, paths)
|
|
675
|
-
const devBrand = { intro: "Local development" }
|
|
676
752
|
|
|
753
|
+
console.log("[supatype] Bringing up Docker Compose services...")
|
|
677
754
|
const upStatus = runDockerCompose(paths.composePath, ["up", "-d"], cwd, project, {
|
|
678
755
|
quiet: true,
|
|
679
756
|
brand: devBrand,
|
|
@@ -695,8 +772,25 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
695
772
|
compose: { project, composePath: paths.composePath },
|
|
696
773
|
})
|
|
697
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
|
+
|
|
698
790
|
console.log("[supatype] Waiting for API gateway...")
|
|
699
791
|
await waitKongReady(kongPort, 120)
|
|
792
|
+
console.log("[supatype] Waiting for storage API...")
|
|
793
|
+
await waitStorageApiReady(kongPort, serviceRoleKey, 90)
|
|
700
794
|
|
|
701
795
|
writeLocalEnvironment(cwd, {
|
|
702
796
|
target: "local",
|
|
@@ -721,7 +815,9 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
721
815
|
const pidDir = join(homedir(), ".supatype", "projects", config.project.name, "pid")
|
|
722
816
|
mkdirSync(pidDir, { recursive: true })
|
|
723
817
|
|
|
724
|
-
|
|
818
|
+
startDevSession()
|
|
819
|
+
|
|
820
|
+
let studioProc: StudioProc = null
|
|
725
821
|
const studioOverride = config.overrides?.studio
|
|
726
822
|
if (studioOverride) {
|
|
727
823
|
studioProc = startStudioViteDevServer({
|
|
@@ -730,66 +826,55 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
730
826
|
pidDir,
|
|
731
827
|
serviceRoleKey,
|
|
732
828
|
proxyTarget: `http://localhost:${kongPort}`,
|
|
733
|
-
viteSupatypeUrl: `http://localhost:${
|
|
829
|
+
viteSupatypeUrl: `http://localhost:${STUDIO_DEV_PORT}`,
|
|
734
830
|
basePath: "/studio/",
|
|
735
831
|
})
|
|
736
832
|
studioProc?.start()
|
|
833
|
+
shutdownState.studioProc = studioProc
|
|
737
834
|
if (studioProc) {
|
|
738
|
-
console.log(
|
|
835
|
+
console.log(
|
|
836
|
+
`[supatype] Studio (overrides.studio) — live reload proxied at http://localhost:${kongPort}/studio/`,
|
|
837
|
+
)
|
|
739
838
|
}
|
|
740
839
|
}
|
|
741
840
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
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/` })
|
|
750
852
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
853
|
+
const hints: string[] = []
|
|
854
|
+
if (existsSync(join(cwd, "seed.ts"))) {
|
|
855
|
+
hints.push("Demo data: pnpm seed")
|
|
856
|
+
}
|
|
754
857
|
|
|
755
|
-
|
|
756
|
-
`)
|
|
858
|
+
publishDevReady({
|
|
859
|
+
title: `Services running (Docker · ${project})`,
|
|
860
|
+
links,
|
|
861
|
+
anonKey,
|
|
862
|
+
serviceRoleKey,
|
|
863
|
+
...(hints.length > 0 ? { hints } : {}),
|
|
864
|
+
})
|
|
757
865
|
|
|
758
866
|
const appProc = startProxyDevApp(cwd, config, pidDir)
|
|
759
|
-
|
|
760
|
-
let schemaWatcher: import("node:fs").FSWatcher | null = null
|
|
761
|
-
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
|
762
|
-
|
|
763
|
-
registerDevShutdown(async () => {
|
|
764
|
-
schemaWatcher?.close()
|
|
765
|
-
schemaWatcher = null
|
|
766
|
-
if (debounceTimer) {
|
|
767
|
-
clearTimeout(debounceTimer)
|
|
768
|
-
debounceTimer = null
|
|
769
|
-
}
|
|
770
|
-
console.log("[supatype] Shutting down compose...")
|
|
771
|
-
await studioProc?.stop()
|
|
772
|
-
await appProc?.stop()
|
|
773
|
-
const downStatus = runDockerCompose(paths.composePath, ["down"], cwd, project, { quiet: true })
|
|
774
|
-
if (downStatus === 0) {
|
|
775
|
-
console.log("[supatype] Compose stack stopped.")
|
|
776
|
-
} else {
|
|
777
|
-
console.warn(`[supatype] Compose down exited with status ${downStatus}.`)
|
|
778
|
-
}
|
|
779
|
-
}, {
|
|
780
|
-
cwd,
|
|
781
|
-
compose: { cwd, composePath: paths.composePath, composeProject: project },
|
|
782
|
-
})
|
|
867
|
+
shutdownState.appProc = appProc
|
|
783
868
|
|
|
784
869
|
if (opts.watch) {
|
|
785
870
|
const schemaDir = join(projectRootFromConfig(config, cwd), config.schema?.path ?? "schema/index.ts", "..")
|
|
786
871
|
console.log(`[supatype] Watching ${schemaDir} for changes...`)
|
|
787
872
|
const { watch } = await import("node:fs")
|
|
788
|
-
schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
|
|
873
|
+
shutdownState.schemaWatcher = watch(schemaDir, { recursive: true }, (_eventType, filename) => {
|
|
789
874
|
if (!filename?.endsWith(".ts")) return
|
|
790
|
-
if (debounceTimer) clearTimeout(debounceTimer)
|
|
791
|
-
debounceTimer = setTimeout(() => {
|
|
792
|
-
debounceTimer = null
|
|
875
|
+
if (shutdownState.debounceTimer) clearTimeout(shutdownState.debounceTimer)
|
|
876
|
+
shutdownState.debounceTimer = setTimeout(() => {
|
|
877
|
+
shutdownState.debounceTimer = null
|
|
793
878
|
console.log(`\n[supatype] Change detected in ${filename}, pushing schema...`)
|
|
794
879
|
runComposeSchemaPushQueued(cwd, config, paths, schemaPath, project)
|
|
795
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
|
package/src/dev-ports.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* availability so multiple projects and port collisions are surfaced clearly.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import { CLACK_CANCEL, isCancel, p } from "./ui/clack.js"
|
|
8
8
|
import { COMPOSE_DEV_KONG_PORT } from "./project-config.js"
|
|
9
9
|
import { isPortInUse } from "./postgres-ctl.js"
|
|
10
10
|
import { readEnvInt, upsertEnvFile } from "./env-file.js"
|
|
@@ -119,7 +119,7 @@ export async function promptKongPortChoice(): Promise<number> {
|
|
|
119
119
|
},
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
if (
|
|
122
|
+
if (isCancel(value)) {
|
|
123
123
|
p.cancel("Cancelled.")
|
|
124
124
|
process.exit(0)
|
|
125
125
|
}
|
|
@@ -154,7 +154,7 @@ async function promptPortConflictWithoutPersist(
|
|
|
154
154
|
],
|
|
155
155
|
})
|
|
156
156
|
|
|
157
|
-
if (
|
|
157
|
+
if (isCancel(choice) || choice === "cancel") {
|
|
158
158
|
p.cancel("Cancelled.")
|
|
159
159
|
process.exit(0)
|
|
160
160
|
}
|
|
@@ -171,7 +171,7 @@ async function promptPortConflictWithoutPersist(
|
|
|
171
171
|
},
|
|
172
172
|
})
|
|
173
173
|
|
|
174
|
-
if (
|
|
174
|
+
if (isCancel(custom)) {
|
|
175
175
|
p.cancel("Cancelled.")
|
|
176
176
|
process.exit(0)
|
|
177
177
|
}
|
|
@@ -194,19 +194,30 @@ async function promptPortConflictWithoutPersist(
|
|
|
194
194
|
|
|
195
195
|
const COMPOSE_DEV_DB_PORT = 54329
|
|
196
196
|
|
|
197
|
+
function devDbConnectionUrl(port: number): string {
|
|
198
|
+
return `postgresql://supatype_admin:postgres@localhost:${port}/supatype?sslmode=disable`
|
|
199
|
+
}
|
|
200
|
+
|
|
197
201
|
export async function ensureDevDbPort(cwd: string): Promise<number> {
|
|
198
202
|
const persisted = readEnvInt(cwd, "SUPATYPE_DEV_DB_PORT")
|
|
203
|
+
|
|
204
|
+
const persist = (port: number): number => {
|
|
205
|
+
upsertEnvFile(cwd, {
|
|
206
|
+
SUPATYPE_DEV_DB_PORT: String(port),
|
|
207
|
+
DATABASE_URL: devDbConnectionUrl(port),
|
|
208
|
+
})
|
|
209
|
+
return port
|
|
210
|
+
}
|
|
211
|
+
|
|
199
212
|
if (persisted !== null) {
|
|
200
213
|
if (!(await isPortInUse(persisted))) return persisted
|
|
201
214
|
const next = await findNextFreePort(persisted + 1)
|
|
202
|
-
|
|
203
|
-
SUPATYPE_DEV_DB_PORT: String(next),
|
|
204
|
-
DATABASE_URL: `postgresql://supatype_admin:postgres@localhost:${next}/supatype?sslmode=disable`,
|
|
205
|
-
})
|
|
206
|
-
return next
|
|
215
|
+
return persist(next)
|
|
207
216
|
}
|
|
208
217
|
|
|
209
218
|
let port = COMPOSE_DEV_DB_PORT
|
|
210
|
-
|
|
211
|
-
|
|
219
|
+
if (await isPortInUse(port)) {
|
|
220
|
+
port = await findNextFreePort(port + 1)
|
|
221
|
+
}
|
|
222
|
+
return persist(port)
|
|
212
223
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinned service URLs + dev keys for the Ink dashboard.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { appendStackOutput, getActiveDevSession } from "./dev-session.js"
|
|
6
|
+
|
|
7
|
+
export interface DevServiceLink {
|
|
8
|
+
label: string
|
|
9
|
+
url: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DevReadyPanel {
|
|
13
|
+
title: string
|
|
14
|
+
links: DevServiceLink[]
|
|
15
|
+
anonKey?: string
|
|
16
|
+
serviceRoleKey?: string
|
|
17
|
+
hints?: string[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Ink row budget for DevReadyPanelView (border, title, links, hints, keys, margin). */
|
|
21
|
+
export function devReadyPanelRowCount(panel: DevReadyPanel): number {
|
|
22
|
+
let rows = 2 // round border top + bottom
|
|
23
|
+
rows += 1 // title
|
|
24
|
+
rows += panel.links.length
|
|
25
|
+
for (const hint of panel.hints ?? []) {
|
|
26
|
+
if (hint.trim()) rows += 1
|
|
27
|
+
}
|
|
28
|
+
if (panel.anonKey) {
|
|
29
|
+
rows += 1 // "API keys (local dev)"
|
|
30
|
+
rows += 1 // anon
|
|
31
|
+
if (panel.serviceRoleKey) rows += 1 // service_role
|
|
32
|
+
}
|
|
33
|
+
rows += 1 // marginBottom on panel box
|
|
34
|
+
return rows
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function formatStreamBlock(panel: DevReadyPanel): string {
|
|
38
|
+
const lines = [`[supatype] ${panel.title}`]
|
|
39
|
+
for (const link of panel.links) {
|
|
40
|
+
lines.push(` ${link.label.padEnd(16)} ${link.url}`)
|
|
41
|
+
}
|
|
42
|
+
for (const hint of panel.hints ?? []) {
|
|
43
|
+
lines.push(` ${hint}`)
|
|
44
|
+
}
|
|
45
|
+
if (panel.anonKey) {
|
|
46
|
+
lines.push(" API keys (local dev only):")
|
|
47
|
+
lines.push(` anon key ${panel.anonKey}`)
|
|
48
|
+
lines.push(` service_role ${panel.serviceRoleKey ?? ""}`)
|
|
49
|
+
}
|
|
50
|
+
lines.push(" Press Ctrl+C to stop.")
|
|
51
|
+
return lines.join("\n")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Pin links in the TUI or print the classic block in stream mode. */
|
|
55
|
+
export function publishDevReady(panel: DevReadyPanel): void {
|
|
56
|
+
const session = getActiveDevSession()
|
|
57
|
+
if (session?.isTui()) {
|
|
58
|
+
session.bus.setReadyPanel(panel)
|
|
59
|
+
appendStackOutput("Services running.", "log")
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
console.log(formatStreamBlock(panel))
|
|
63
|
+
}
|
package/src/dev-session-lock.ts
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"
|
|
7
7
|
import { join, resolve } from "node:path"
|
|
8
8
|
import { spawnSync } from "node:child_process"
|
|
9
|
-
import * as p from "@clack/prompts"
|
|
10
9
|
import { runDockerCompose } from "./self-host-compose.js"
|
|
10
|
+
import { confirm as uiConfirm } from "./ui/confirm.js"
|
|
11
|
+
import { success, warn } from "./ui/messages.js"
|
|
11
12
|
import { isInteractive } from "./ui/interactive.js"
|
|
12
|
-
import { warn } from "./ui/messages.js"
|
|
13
13
|
|
|
14
14
|
const LOCK_VERSION = 1 as const
|
|
15
15
|
|
|
@@ -81,12 +81,9 @@ export async function recoverStaleDevSession(cwd: string): Promise<void> {
|
|
|
81
81
|
return
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const stop = await
|
|
85
|
-
message: `${message}\n\nStop the orphaned stack before starting?`,
|
|
86
|
-
initialValue: true,
|
|
87
|
-
})
|
|
84
|
+
const stop = await uiConfirm(`${message}\n\nStop the orphaned stack before starting?`, { default: true })
|
|
88
85
|
|
|
89
|
-
if (
|
|
86
|
+
if (!stop) {
|
|
90
87
|
warn(`Leaving "${lock.composeProject}" running.`)
|
|
91
88
|
return
|
|
92
89
|
}
|
|
@@ -94,7 +91,7 @@ export async function recoverStaleDevSession(cwd: string): Promise<void> {
|
|
|
94
91
|
const status = runDockerCompose(lock.composePath, ["down"], cwd, lock.composeProject, { quiet: true })
|
|
95
92
|
if (status === 0) {
|
|
96
93
|
clearDevSessionLock(cwd)
|
|
97
|
-
|
|
94
|
+
success(`Stopped orphaned stack "${lock.composeProject}".`)
|
|
98
95
|
} else {
|
|
99
96
|
warn(`Could not stop "${lock.composeProject}" (exit ${status}).`)
|
|
100
97
|
}
|