@supatype/cli 0.1.1 → 0.1.3
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 +126 -99
- 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 +12 -0
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +116 -26
- 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 +296 -121
- 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/config.d.ts.map +1 -1
- package/dist/config.js +12 -1
- package/dist/config.js.map +1 -1
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +113 -56
- 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 +16 -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 +21 -0
- package/dist/dev-ready-panel.d.ts.map +1 -0
- package/dist/dev-ready-panel.js +67 -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/init-project-detect.d.ts +14 -0
- package/dist/init-project-detect.d.ts.map +1 -0
- package/dist/init-project-detect.js +89 -0
- package/dist/init-project-detect.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 +158 -0
- package/dist/ui/dev/DevDashboard.js.map +1 -0
- package/dist/ui/dev/DevReadyPanelView.d.ts +8 -0
- package/dist/ui/dev/DevReadyPanelView.d.ts.map +1 -0
- package/dist/ui/dev/DevReadyPanelView.js +48 -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 +44 -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 +92 -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 +46 -0
- package/dist/ui/runtime/run-clack-flow.js.map +1 -0
- package/dist/ui/runtime/stdin-after-ink.d.ts +3 -0
- package/dist/ui/runtime/stdin-after-ink.d.ts.map +1 -0
- package/dist/ui/runtime/stdin-after-ink.js +16 -0
- package/dist/ui/runtime/stdin-after-ink.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 +156 -29
- package/src/commands/cache.ts +105 -5
- package/src/commands/dev.ts +26 -21
- package/src/commands/init.ts +473 -247
- 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/config.ts +13 -1
- package/src/dev-compose.ts +139 -54
- package/src/dev-log-bus.ts +20 -0
- package/src/dev-log-filter.ts +42 -0
- package/src/dev-ports.ts +22 -11
- package/src/dev-ready-panel.ts +80 -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/init-project-detect.ts +99 -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 +223 -0
- package/src/ui/dev/DevReadyPanelView.tsx +134 -0
- package/src/ui/fatal.ts +5 -10
- package/src/ui/flows/FlowApp.tsx +69 -0
- package/src/ui/flows/prompt-fields.tsx +198 -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 +65 -0
- package/src/ui/runtime/stdin-after-ink.ts +18 -0
- package/src/ui/theme.ts +41 -0
- package/src/valkey-sidecar.ts +126 -0
- package/tests/admin-ensure.test.ts +80 -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 +27 -4
- package/tests/dev-ready-panel.test.ts +37 -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-project-detect.test.ts +53 -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/stdin-after-ink.test.ts +8 -0
- 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
|
@@ -12,7 +12,7 @@ import { targetFetch } from "../target-client.js"
|
|
|
12
12
|
import { error, info, plain } from "../ui/messages.js"
|
|
13
13
|
import { nextSteps } from "../ui/next-steps.js"
|
|
14
14
|
import { isInteractive } from "../ui/interactive.js"
|
|
15
|
-
import { ensureNotCancelled,
|
|
15
|
+
import { ensureNotCancelled, p, runClackFlow } from "../ui/prompts.js"
|
|
16
16
|
|
|
17
17
|
function resolveLinkToken(opts: {
|
|
18
18
|
token?: string
|
|
@@ -145,35 +145,36 @@ export async function runLinkAction(opts: {
|
|
|
145
145
|
let url = opts.url
|
|
146
146
|
|
|
147
147
|
if (isInteractive() && !project && !url) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}),
|
|
158
|
-
)
|
|
159
|
-
if (targetKind === "cloud") {
|
|
160
|
-
project = ensureNotCancelled(
|
|
161
|
-
await p.text({
|
|
162
|
-
message: "Cloud project slug",
|
|
163
|
-
placeholder: projectRef,
|
|
164
|
-
defaultValue: projectRef,
|
|
148
|
+
await runClackFlow(async () => {
|
|
149
|
+
p.intro("Link this project")
|
|
150
|
+
const targetKind = ensureNotCancelled(
|
|
151
|
+
await p.select<"cloud" | "self-host">({
|
|
152
|
+
message: "Link target",
|
|
153
|
+
options: [
|
|
154
|
+
{ value: "cloud", label: "Supatype Cloud", hint: "managed project on supatype.com" },
|
|
155
|
+
{ value: "self-host", label: "Self-host", hint: "your Kong gateway URL" },
|
|
156
|
+
],
|
|
165
157
|
}),
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
158
|
+
)
|
|
159
|
+
if (targetKind === "cloud") {
|
|
160
|
+
project = ensureNotCancelled(
|
|
161
|
+
await p.text({
|
|
162
|
+
message: "Cloud project slug",
|
|
163
|
+
placeholder: projectRef,
|
|
164
|
+
defaultValue: projectRef,
|
|
165
|
+
}),
|
|
166
|
+
).trim()
|
|
167
|
+
} else {
|
|
168
|
+
url = ensureNotCancelled(
|
|
169
|
+
await p.text({
|
|
170
|
+
message: "Kong gateway URL",
|
|
171
|
+
placeholder: "https://api.example.com",
|
|
172
|
+
defaultValue: "http://localhost:18473",
|
|
173
|
+
}),
|
|
174
|
+
).trim()
|
|
175
|
+
}
|
|
176
|
+
p.outro("Linking...")
|
|
177
|
+
})
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
const token = resolveLinkToken(opts)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync } from "node:fs"
|
|
2
|
+
import { dirname, isAbsolute, join, resolve } from "node:path"
|
|
3
|
+
import { spawnSync } from "node:child_process"
|
|
4
|
+
import { VERSION_PIN_LOCAL } from "./binary-cache.js"
|
|
5
|
+
import { appendStackOutput, getActiveDevSession } from "./dev-session.js"
|
|
6
|
+
import { requireDockerDaemon } from "./docker-runtime.js"
|
|
7
|
+
import type { SupatypeProjectConfig } from "./project-config.js"
|
|
8
|
+
|
|
9
|
+
/** Docker tag for compose dev when `versions.server` is `local`. */
|
|
10
|
+
export const LOCAL_SERVER_DOCKER_IMAGE = "supatype/server:local-dev"
|
|
11
|
+
|
|
12
|
+
/** Find the server repo root (directory containing `Dockerfile`) from an overrides.server binary path. */
|
|
13
|
+
export function resolveServerSourceRoot(serverOverride: string, cwd: string): string | null {
|
|
14
|
+
const binaryPath = isAbsolute(serverOverride) ? serverOverride : resolve(cwd, serverOverride)
|
|
15
|
+
let dir = dirname(binaryPath)
|
|
16
|
+
for (let depth = 0; depth < 5; depth++) {
|
|
17
|
+
if (existsSync(join(dir, "Dockerfile"))) return dir
|
|
18
|
+
const parent = dirname(dir)
|
|
19
|
+
if (parent === dir) break
|
|
20
|
+
dir = parent
|
|
21
|
+
}
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* When `versions.server` is `local`, build a Linux server image from the source tree
|
|
27
|
+
* next to `overrides.server` so compose dev matches the contributor's binary.
|
|
28
|
+
*/
|
|
29
|
+
export async function ensureLocalServerDockerImage(
|
|
30
|
+
cwd: string,
|
|
31
|
+
config: SupatypeProjectConfig,
|
|
32
|
+
brand?: { intro?: string },
|
|
33
|
+
): Promise<string | undefined> {
|
|
34
|
+
if (config.versions?.server !== VERSION_PIN_LOCAL) return undefined
|
|
35
|
+
|
|
36
|
+
const override = config.overrides?.server?.trim()
|
|
37
|
+
if (!override) return undefined
|
|
38
|
+
|
|
39
|
+
const root = resolveServerSourceRoot(override, cwd)
|
|
40
|
+
if (!root) {
|
|
41
|
+
console.warn(
|
|
42
|
+
`[supatype] ⚠ versions.server is "local" but no Dockerfile found near ${override}. ` +
|
|
43
|
+
"Compose will use the default supatype/server:latest image.",
|
|
44
|
+
)
|
|
45
|
+
return undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
requireDockerDaemon(brand?.intro ? { brand: { intro: brand.intro } } : undefined)
|
|
49
|
+
const dockerfile = join(root, "Dockerfile")
|
|
50
|
+
console.log(`[supatype] Building local server Docker image from ${root}…`)
|
|
51
|
+
const result = spawnSync(
|
|
52
|
+
"docker",
|
|
53
|
+
["build", "--progress=plain", "-t", LOCAL_SERVER_DOCKER_IMAGE, "-f", dockerfile, root],
|
|
54
|
+
{ encoding: "utf8", stdio: "pipe" },
|
|
55
|
+
)
|
|
56
|
+
const tui = getActiveDevSession()?.isTui() ?? false
|
|
57
|
+
if (!tui) {
|
|
58
|
+
appendStackOutput(result.stdout, "log")
|
|
59
|
+
appendStackOutput(result.stderr, result.status === 0 ? "log" : "error")
|
|
60
|
+
} else if (result.status !== 0) {
|
|
61
|
+
appendStackOutput(result.stderr || result.stdout || "docker build failed", "error")
|
|
62
|
+
}
|
|
63
|
+
if (result.status !== 0) {
|
|
64
|
+
throw new Error(`docker build failed for local server (exit ${result.status ?? "unknown"})`)
|
|
65
|
+
}
|
|
66
|
+
console.log(`[supatype] Local server image ready: ${LOCAL_SERVER_DOCKER_IMAGE}`)
|
|
67
|
+
return LOCAL_SERVER_DOCKER_IMAGE
|
|
68
|
+
}
|
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/config.ts
CHANGED
|
@@ -158,7 +158,7 @@ process.stdout.write(JSON.stringify(config))
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
const failure = result.stderr || result.stdout
|
|
161
|
-
if (!failure
|
|
161
|
+
if (!shouldStripCliImportOnLoadFailure(failure)) {
|
|
162
162
|
throw new Error(`Failed to load ${candidate}:\n${failure}`)
|
|
163
163
|
}
|
|
164
164
|
|
|
@@ -169,6 +169,18 @@ process.stdout.write(JSON.stringify(config))
|
|
|
169
169
|
return null
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
/** When @supatype/cli is not installed yet (e.g. during `supatype init`), strip its import. */
|
|
173
|
+
function shouldStripCliImportOnLoadFailure(failure: string): boolean {
|
|
174
|
+
if (failure.includes("ERR_PACKAGE_PATH_NOT_EXPORTED")) return true
|
|
175
|
+
if (!failure.includes("@supatype/cli")) return false
|
|
176
|
+
return (
|
|
177
|
+
failure.includes("ERR_MODULE_NOT_FOUND") ||
|
|
178
|
+
failure.includes("MODULE_NOT_FOUND") ||
|
|
179
|
+
failure.includes("Cannot find module '@supatype/cli'") ||
|
|
180
|
+
failure.includes('Cannot find package \'@supatype/cli\'')
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
172
184
|
function loadTsConfigWithoutCliImport(
|
|
173
185
|
configPath: string,
|
|
174
186
|
cwd: string,
|
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,
|
|
@@ -691,12 +768,29 @@ export async function runDevCompose(cwd: string, config: SupatypeProjectConfig,
|
|
|
691
768
|
console.error("[supatype] Initial schema push failed:", (e as Error).message),
|
|
692
769
|
)
|
|
693
770
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
771
|
+
if (localServerImage !== undefined) {
|
|
772
|
+
console.log("[supatype] Recreating server with local image...")
|
|
773
|
+
const recreateStatus = runDockerCompose(
|
|
774
|
+
paths.composePath,
|
|
775
|
+
["up", "-d", "--force-recreate", "--no-deps", "server"],
|
|
776
|
+
cwd,
|
|
777
|
+
project,
|
|
778
|
+
{ quiet: true, brand: devBrand },
|
|
779
|
+
)
|
|
780
|
+
if (recreateStatus !== 0) {
|
|
781
|
+
endDevSession()
|
|
782
|
+
exitComposeFailed(recreateStatus, "Could not recreate the server container with the local image.", devBrand)
|
|
783
|
+
}
|
|
784
|
+
}
|
|
697
785
|
|
|
698
786
|
console.log("[supatype] Waiting for API gateway...")
|
|
699
787
|
await waitKongReady(kongPort, 120)
|
|
788
|
+
console.log("[supatype] Waiting for storage API...")
|
|
789
|
+
await waitStorageApiReady(kongPort, serviceRoleKey, 90)
|
|
790
|
+
|
|
791
|
+
await ensureFirstAdminUserForProject(cwd, config, {
|
|
792
|
+
compose: { project, composePath: paths.composePath },
|
|
793
|
+
})
|
|
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 { devReadyPanelCompactRowCount, 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,22 @@ 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(compact = false): number {
|
|
83
|
+
if (!this.readyPanel) return 0
|
|
84
|
+
return compact
|
|
85
|
+
? devReadyPanelCompactRowCount(this.readyPanel)
|
|
86
|
+
: devReadyPanelRowCount(this.readyPanel)
|
|
87
|
+
}
|
|
88
|
+
|
|
69
89
|
append(taskId: string, line: string, level: DevLogLevel = "log"): void {
|
|
70
90
|
this.ensureTask(taskId, taskId)
|
|
71
91
|
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
|