@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
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { cliPackageVersion } from "./cli-package-version.js"
|
|
2
|
+
|
|
3
|
+
export interface InitDependencyVersions {
|
|
4
|
+
cli: string
|
|
5
|
+
types: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type NpmRegistryPackage = {
|
|
9
|
+
versions?: Record<string, unknown>
|
|
10
|
+
"dist-tags"?: { latest?: string }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Fallback when the registry is unreachable (offline / tests). */
|
|
14
|
+
export function initDependencyVersionsFallback(): InitDependencyVersions {
|
|
15
|
+
const version = cliPackageVersion()
|
|
16
|
+
return { cli: version, types: version }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function fetchNpmPackage(name: string): Promise<NpmRegistryPackage | null> {
|
|
20
|
+
const url = `https://registry.npmjs.org/${encodeURIComponent(name)}`
|
|
21
|
+
try {
|
|
22
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(10_000) })
|
|
23
|
+
if (!resp.ok) return null
|
|
24
|
+
return (await resp.json()) as NpmRegistryPackage
|
|
25
|
+
} catch {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function versionPublishedOnNpm(meta: NpmRegistryPackage | null, version: string): boolean {
|
|
31
|
+
return Boolean(meta?.versions?.[version])
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function latestPublishedOnNpm(meta: NpmRegistryPackage | null): string | null {
|
|
35
|
+
const latest = meta?.["dist-tags"]?.latest
|
|
36
|
+
return typeof latest === "string" && latest.trim() !== "" ? latest.trim() : null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolvePackageVersion(
|
|
40
|
+
meta: NpmRegistryPackage | null,
|
|
41
|
+
preferred: string,
|
|
42
|
+
): string {
|
|
43
|
+
if (versionPublishedOnNpm(meta, preferred)) return preferred
|
|
44
|
+
const latest = latestPublishedOnNpm(meta)
|
|
45
|
+
if (latest) return latest
|
|
46
|
+
return preferred
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pick @supatype/cli and @supatype/types versions that exist on npm.
|
|
51
|
+
* The running CLI may be a local dev build ahead of the registry (e.g. 0.1.3
|
|
52
|
+
* while types is only published at 0.1.1).
|
|
53
|
+
*/
|
|
54
|
+
export async function resolveInitDependencyVersions(): Promise<InitDependencyVersions> {
|
|
55
|
+
const runningCli = cliPackageVersion()
|
|
56
|
+
const [cliMeta, typesMeta] = await Promise.all([
|
|
57
|
+
fetchNpmPackage("@supatype/cli"),
|
|
58
|
+
fetchNpmPackage("@supatype/types"),
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
if (!cliMeta && !typesMeta) {
|
|
62
|
+
return initDependencyVersionsFallback()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
cli: resolvePackageVersion(cliMeta, runningCli),
|
|
67
|
+
types: resolvePackageVersion(typesMeta, runningCli),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { InitDependencyVersions } from "./init-dependency-versions.js"
|
|
2
|
+
|
|
3
|
+
export interface MergePackageJsonOptions {
|
|
4
|
+
projectName: string
|
|
5
|
+
app: { viteDevUrl?: string; mode: string }
|
|
6
|
+
helloFunction: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
type PackageJson = {
|
|
10
|
+
name?: string
|
|
11
|
+
private?: boolean
|
|
12
|
+
type?: string
|
|
13
|
+
scripts?: Record<string, string>
|
|
14
|
+
dependencies?: Record<string, string>
|
|
15
|
+
devDependencies?: Record<string, string>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const CORE_SCRIPTS = {
|
|
19
|
+
dev: "supatype dev",
|
|
20
|
+
push: "supatype push",
|
|
21
|
+
seed: "tsx seed.ts",
|
|
22
|
+
} as const
|
|
23
|
+
|
|
24
|
+
/** Merge Supatype deps/scripts into an existing package.json object. */
|
|
25
|
+
export function mergeSupatypePackageJson(
|
|
26
|
+
pkg: PackageJson,
|
|
27
|
+
opts: MergePackageJsonOptions,
|
|
28
|
+
deps: InitDependencyVersions,
|
|
29
|
+
): PackageJson {
|
|
30
|
+
const next: PackageJson = { ...pkg }
|
|
31
|
+
|
|
32
|
+
if (!next.name) next.name = opts.projectName
|
|
33
|
+
if (next.private === undefined) next.private = true
|
|
34
|
+
if (!next.type) next.type = "module"
|
|
35
|
+
|
|
36
|
+
const scripts = { ...(next.scripts ?? {}) }
|
|
37
|
+
for (const [key, value] of Object.entries(CORE_SCRIPTS)) {
|
|
38
|
+
if (scripts[key] === undefined) scripts[key] = value
|
|
39
|
+
}
|
|
40
|
+
if (scripts.dev !== CORE_SCRIPTS.dev && scripts["supatype:dev"] === undefined) {
|
|
41
|
+
scripts["supatype:dev"] = CORE_SCRIPTS.dev
|
|
42
|
+
}
|
|
43
|
+
if (opts.app.viteDevUrl && scripts.vite === undefined) {
|
|
44
|
+
scripts.vite = "vite"
|
|
45
|
+
}
|
|
46
|
+
if (opts.helloFunction && scripts.functions === undefined) {
|
|
47
|
+
scripts.functions = "supatype functions serve"
|
|
48
|
+
}
|
|
49
|
+
next.scripts = scripts
|
|
50
|
+
|
|
51
|
+
const dependencies = { ...(next.dependencies ?? {}) }
|
|
52
|
+
if (dependencies["@supatype/cli"] === undefined) dependencies["@supatype/cli"] = `^${deps.cli}`
|
|
53
|
+
if (dependencies["@supatype/types"] === undefined) dependencies["@supatype/types"] = `^${deps.types}`
|
|
54
|
+
next.dependencies = dependencies
|
|
55
|
+
|
|
56
|
+
const devDependencies = { ...(next.devDependencies ?? {}) }
|
|
57
|
+
if (devDependencies.tsx === undefined) devDependencies.tsx = "^4.19.2"
|
|
58
|
+
if (devDependencies.typescript === undefined) devDependencies.typescript = "^5"
|
|
59
|
+
if (opts.app.viteDevUrl && devDependencies.vite === undefined) devDependencies.vite = "^6"
|
|
60
|
+
next.devDependencies = devDependencies
|
|
61
|
+
|
|
62
|
+
return next
|
|
63
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs"
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
|
|
4
|
+
const VITE_CONFIG_NAMES = [
|
|
5
|
+
"vite.config.ts",
|
|
6
|
+
"vite.config.js",
|
|
7
|
+
"vite.config.mjs",
|
|
8
|
+
"vite.config.cjs",
|
|
9
|
+
] as const
|
|
10
|
+
|
|
11
|
+
const SUPATYPE_CONFIG_NAMES = [
|
|
12
|
+
"supatype.config.ts",
|
|
13
|
+
"supatype.config.js",
|
|
14
|
+
"supatype.config.mjs",
|
|
15
|
+
] as const
|
|
16
|
+
|
|
17
|
+
export interface DetectedProjectSetup {
|
|
18
|
+
/** Directory has files other than `.git`. */
|
|
19
|
+
hasExistingFiles: boolean
|
|
20
|
+
hasSupatypeConfig: boolean
|
|
21
|
+
hasVite: boolean
|
|
22
|
+
hasViteConfig: boolean
|
|
23
|
+
viteDevUrl: string
|
|
24
|
+
staticDir: string
|
|
25
|
+
/** Human-readable bullets for the init wizard. */
|
|
26
|
+
summaryLines: string[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hasPackageVite(cwd: string): boolean {
|
|
30
|
+
const pkgPath = join(cwd, "package.json")
|
|
31
|
+
if (!existsSync(pkgPath)) return false
|
|
32
|
+
try {
|
|
33
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as {
|
|
34
|
+
dependencies?: Record<string, string>
|
|
35
|
+
devDependencies?: Record<string, string>
|
|
36
|
+
}
|
|
37
|
+
return Boolean(pkg.devDependencies?.["vite"] ?? pkg.dependencies?.["vite"])
|
|
38
|
+
} catch {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function readVitePort(cwd: string): number {
|
|
44
|
+
for (const name of VITE_CONFIG_NAMES) {
|
|
45
|
+
const path = join(cwd, name)
|
|
46
|
+
if (!existsSync(path)) continue
|
|
47
|
+
const src = readFileSync(path, "utf8")
|
|
48
|
+
const portMatch = src.match(/port:\s*(\d+)/)
|
|
49
|
+
if (portMatch?.[1]) {
|
|
50
|
+
const port = Number.parseInt(portMatch[1], 10)
|
|
51
|
+
if (Number.isInteger(port) && port > 0) return port
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return 5173
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function detectStaticDir(cwd: string): string {
|
|
58
|
+
if (existsSync(join(cwd, "dist", "index.html"))) return "./dist"
|
|
59
|
+
if (existsSync(join(cwd, "public", "index.html"))) return "./public"
|
|
60
|
+
if (existsSync(join(cwd, "dist"))) return "./dist"
|
|
61
|
+
if (existsSync(join(cwd, "public"))) return "./public"
|
|
62
|
+
return "./public"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Inspect `cwd` before init prompts — Vite, static dir, existing Supatype config. */
|
|
66
|
+
export function detectProjectSetup(cwd: string): DetectedProjectSetup {
|
|
67
|
+
let entries: string[] = []
|
|
68
|
+
try {
|
|
69
|
+
entries = readdirSync(cwd).filter((entry) => entry !== ".git")
|
|
70
|
+
} catch {
|
|
71
|
+
entries = []
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const hasExistingFiles = entries.length > 0
|
|
75
|
+
const hasViteConfig = VITE_CONFIG_NAMES.some((name) => existsSync(join(cwd, name)))
|
|
76
|
+
const hasVite = hasViteConfig || hasPackageVite(cwd)
|
|
77
|
+
const viteDevUrl = `http://127.0.0.1:${readVitePort(cwd)}`
|
|
78
|
+
const staticDir = detectStaticDir(cwd)
|
|
79
|
+
const hasSupatypeConfig = SUPATYPE_CONFIG_NAMES.some((name) => existsSync(join(cwd, name)))
|
|
80
|
+
|
|
81
|
+
const summaryLines: string[] = []
|
|
82
|
+
if (hasSupatypeConfig) summaryLines.push("supatype.config already present")
|
|
83
|
+
if (hasViteConfig) summaryLines.push(`Vite config found (${viteDevUrl})`)
|
|
84
|
+
else if (hasVite) summaryLines.push(`Vite dependency in package.json (${viteDevUrl})`)
|
|
85
|
+
if (existsSync(join(cwd, staticDir.replace(/^\.\//, "")))) {
|
|
86
|
+
summaryLines.push(`static assets in ${staticDir}`)
|
|
87
|
+
}
|
|
88
|
+
if (existsSync(join(cwd, "package.json"))) summaryLines.push("package.json present")
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
hasExistingFiles,
|
|
92
|
+
hasSupatypeConfig,
|
|
93
|
+
hasVite,
|
|
94
|
+
hasViteConfig,
|
|
95
|
+
viteDevUrl,
|
|
96
|
+
staticDir,
|
|
97
|
+
summaryLines,
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/postgres-ctl.ts
CHANGED
|
@@ -148,7 +148,8 @@ export async function isPortInUse(port: number): Promise<boolean> {
|
|
|
148
148
|
return new Promise((resolve) => {
|
|
149
149
|
const server = createServer()
|
|
150
150
|
server.once("error", (err: NodeJS.ErrnoException) => {
|
|
151
|
-
|
|
151
|
+
// EADDRINUSE — something is listening. EACCES — Windows excluded/reserved port range.
|
|
152
|
+
resolve(err.code === "EADDRINUSE" || err.code === "EACCES")
|
|
152
153
|
})
|
|
153
154
|
server.once("listening", () => {
|
|
154
155
|
server.close(() => resolve(false))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which CDN-cached host binaries a project needs (native vs docker).
|
|
3
|
+
*
|
|
4
|
+
* Docker runs Postgres, API, and schema push in Compose, but the CLI still uses a
|
|
5
|
+
* host engine binary for type generation and admin-config refresh after push.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync } from "node:fs"
|
|
9
|
+
import type { Component } from "./components.js"
|
|
10
|
+
import {
|
|
11
|
+
functionsPathCandidatesFromProject,
|
|
12
|
+
resolveRuntimeProvider,
|
|
13
|
+
type SupatypeProjectConfig,
|
|
14
|
+
} from "./project-config.js"
|
|
15
|
+
|
|
16
|
+
export function requiredHostComponents(
|
|
17
|
+
config: SupatypeProjectConfig,
|
|
18
|
+
cwd: string = process.cwd(),
|
|
19
|
+
): Component[] {
|
|
20
|
+
const provider = resolveRuntimeProvider(config)
|
|
21
|
+
|
|
22
|
+
if (provider === "docker") {
|
|
23
|
+
return ["engine"]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const components: Component[] = ["engine", "server", "postgres"]
|
|
27
|
+
const hasFunctions = functionsPathCandidatesFromProject(config, cwd).some((dir) =>
|
|
28
|
+
existsSync(dir),
|
|
29
|
+
)
|
|
30
|
+
if (hasFunctions) components.push("deno")
|
|
31
|
+
return components
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function describeRequiredHostComponents(components: readonly Component[]): string {
|
|
35
|
+
if (components.length === 0) return ""
|
|
36
|
+
return components.join(", ")
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the project API base URL (Kong gateway or direct server) for CLI HTTP calls.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { loadConfig } from "./config.js"
|
|
6
|
+
import { readEnvValue } from "./env-file.js"
|
|
7
|
+
import { serverBaseUrl } from "./project-config.js"
|
|
8
|
+
|
|
9
|
+
const API_URL_ENV_KEYS = [
|
|
10
|
+
"SUPATYPE_URL",
|
|
11
|
+
"SUPATYPE_API_URL",
|
|
12
|
+
"PUBLIC_SUPATYPE_URL",
|
|
13
|
+
"NEXT_PUBLIC_SUPATYPE_URL",
|
|
14
|
+
"SITE_URL",
|
|
15
|
+
"API_EXTERNAL_URL",
|
|
16
|
+
] as const
|
|
17
|
+
|
|
18
|
+
/** Kong or server origin without a trailing slash. */
|
|
19
|
+
export function resolveProjectApiUrl(cwd: string): string {
|
|
20
|
+
for (const key of API_URL_ENV_KEYS) {
|
|
21
|
+
const value = readEnvValue(cwd, key, "").trim()
|
|
22
|
+
if (value) {
|
|
23
|
+
return value.replace(/\/+$/, "")
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const kongPort = readEnvValue(cwd, "SUPATYPE_KONG_PORT", "").trim()
|
|
28
|
+
if (kongPort) {
|
|
29
|
+
return `http://localhost:${kongPort}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const fromConfig = serverBaseUrl(loadConfig(cwd))
|
|
34
|
+
if (fromConfig) {
|
|
35
|
+
return fromConfig.replace(/\/+$/, "")
|
|
36
|
+
}
|
|
37
|
+
} catch {
|
|
38
|
+
// No supatype.config — fall through to PORT default.
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const port = readEnvValue(cwd, "PORT", "54321").trim() || "54321"
|
|
42
|
+
return `http://localhost:${port}`
|
|
43
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin REST cache API client for CLI commands.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { readEnvValue } from "./env-file.js"
|
|
6
|
+
import { resolveProjectApiUrl } from "./resolve-api-url.js"
|
|
7
|
+
|
|
8
|
+
export interface RestCacheEntrySummary {
|
|
9
|
+
key: string
|
|
10
|
+
table?: string
|
|
11
|
+
scope?: string
|
|
12
|
+
method?: string
|
|
13
|
+
path?: string
|
|
14
|
+
raw_query?: string
|
|
15
|
+
ttl_seconds: number
|
|
16
|
+
size_bytes: number
|
|
17
|
+
cached_at?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface RestCacheListResponse {
|
|
21
|
+
entries: RestCacheEntrySummary[]
|
|
22
|
+
cursor: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RestCacheDetail extends RestCacheEntrySummary {
|
|
26
|
+
status_code: number
|
|
27
|
+
content_type?: string
|
|
28
|
+
body_preview?: string
|
|
29
|
+
body_json?: unknown
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function serviceRoleKey(cwd: string): string {
|
|
33
|
+
const key =
|
|
34
|
+
readEnvValue(cwd, "SUPATYPE_SERVICE_ROLE_KEY", "").trim() ||
|
|
35
|
+
readEnvValue(cwd, "SERVICE_ROLE_KEY", "").trim()
|
|
36
|
+
if (!key) {
|
|
37
|
+
throw new Error("SERVICE_ROLE_KEY not found in .env — run supatype dev or supatype keys")
|
|
38
|
+
}
|
|
39
|
+
return key.trim()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function adminHeaders(cwd: string): Record<string, string> {
|
|
43
|
+
const key = serviceRoleKey(cwd)
|
|
44
|
+
return {
|
|
45
|
+
Authorization: `Bearer ${key}`,
|
|
46
|
+
apikey: key,
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function formatCacheApiError(
|
|
52
|
+
operation: string,
|
|
53
|
+
status: number,
|
|
54
|
+
body: string,
|
|
55
|
+
baseUrl: string,
|
|
56
|
+
): string {
|
|
57
|
+
const trimmed = body.trim()
|
|
58
|
+
if (status === 404) {
|
|
59
|
+
return (
|
|
60
|
+
`${operation} failed (404): ${trimmed || "not found"}\n` +
|
|
61
|
+
` API: ${baseUrl}/admin/v1/cache\n` +
|
|
62
|
+
" Start the stack with `supatype dev`, or check SUPATYPE_URL / PUBLIC_SUPATYPE_URL in .env."
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
if (status === 403 && trimmed.includes("rest_cache_not_available")) {
|
|
66
|
+
return "REST server cache is not available on this plan or deployment."
|
|
67
|
+
}
|
|
68
|
+
if (status === 503 && trimmed.includes("valkey")) {
|
|
69
|
+
return "Valkey is not configured — server-side REST cache requires Valkey (supatype dev with docker)."
|
|
70
|
+
}
|
|
71
|
+
return `${operation} failed (${status}): ${trimmed || "(empty body)"}`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizeListResponse(data: RestCacheListResponse): RestCacheListResponse {
|
|
75
|
+
return {
|
|
76
|
+
entries: data.entries ?? [],
|
|
77
|
+
cursor: data.cursor ?? "0",
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function listRestCacheEntries(
|
|
82
|
+
cwd: string,
|
|
83
|
+
opts?: { table?: string | undefined; cursor?: string | undefined; limit?: number | undefined },
|
|
84
|
+
): Promise<RestCacheListResponse> {
|
|
85
|
+
const baseUrl = resolveProjectApiUrl(cwd)
|
|
86
|
+
const params = new URLSearchParams()
|
|
87
|
+
if (opts?.table) params.set("table", opts.table)
|
|
88
|
+
if (opts?.cursor) params.set("cursor", opts.cursor)
|
|
89
|
+
if (opts?.limit !== undefined) params.set("limit", String(opts.limit))
|
|
90
|
+
const qs = params.toString()
|
|
91
|
+
const url = `${baseUrl}/admin/v1/cache${qs ? `?${qs}` : ""}`
|
|
92
|
+
const res = await fetch(url, { headers: adminHeaders(cwd) })
|
|
93
|
+
if (!res.ok) {
|
|
94
|
+
const body = await res.text()
|
|
95
|
+
throw new Error(formatCacheApiError("list cache", res.status, body, baseUrl))
|
|
96
|
+
}
|
|
97
|
+
const data = (await res.json()) as RestCacheListResponse
|
|
98
|
+
return normalizeListResponse(data)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function getRestCacheEntry(cwd: string, key: string): Promise<RestCacheDetail> {
|
|
102
|
+
const baseUrl = resolveProjectApiUrl(cwd)
|
|
103
|
+
const enc = Buffer.from(key, "utf8").toString("base64url")
|
|
104
|
+
const url = `${baseUrl}/admin/v1/cache/entries/${encodeURIComponent(enc)}`
|
|
105
|
+
const res = await fetch(url, { headers: adminHeaders(cwd) })
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
const body = await res.text()
|
|
108
|
+
throw new Error(formatCacheApiError("get cache entry", res.status, body, baseUrl))
|
|
109
|
+
}
|
|
110
|
+
return res.json() as Promise<RestCacheDetail>
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export async function deleteRestCacheEntry(cwd: string, key: string): Promise<void> {
|
|
114
|
+
const baseUrl = resolveProjectApiUrl(cwd)
|
|
115
|
+
const enc = Buffer.from(key, "utf8").toString("base64url")
|
|
116
|
+
const url = `${baseUrl}/admin/v1/cache/entries/${encodeURIComponent(enc)}`
|
|
117
|
+
const res = await fetch(url, { method: "DELETE", headers: adminHeaders(cwd) })
|
|
118
|
+
if (!res.ok) {
|
|
119
|
+
const body = await res.text()
|
|
120
|
+
throw new Error(formatCacheApiError("delete cache entry", res.status, body, baseUrl))
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function flushRestCache(cwd: string, table?: string): Promise<void> {
|
|
125
|
+
const baseUrl = resolveProjectApiUrl(cwd)
|
|
126
|
+
const params = new URLSearchParams()
|
|
127
|
+
if (table) params.set("table", table)
|
|
128
|
+
const qs = params.toString()
|
|
129
|
+
const url = `${baseUrl}/admin/v1/cache${qs ? `?${qs}` : ""}`
|
|
130
|
+
const res = await fetch(url, { method: "DELETE", headers: adminHeaders(cwd) })
|
|
131
|
+
if (!res.ok) {
|
|
132
|
+
const body = await res.text()
|
|
133
|
+
throw new Error(formatCacheApiError("flush cache", res.status, body, baseUrl))
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -1,57 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Postinstall script —
|
|
2
|
+
* Postinstall script — @supatype/cli global/project install.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Failures are non-fatal: an installation message is printed and the user
|
|
8
|
-
* can run `supatype update` manually to retry.
|
|
4
|
+
* Host binaries (engine, server, postgres, deno) are downloaded on demand:
|
|
5
|
+
* - native provider: first supatype dev / supatype update
|
|
6
|
+
* - docker provider: Compose images on first supatype dev
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
|
-
import { download, currentPlatform, fetchAllLatestVersions, type Component } from "../binary-cache.js"
|
|
12
|
-
|
|
13
9
|
async function main() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
versions = await fetchAllLatestVersions()
|
|
20
|
-
} catch (err) {
|
|
21
|
-
console.error(`[supatype] Failed to fetch latest versions: ${(err as Error).message}`)
|
|
22
|
-
console.error("[supatype] Run 'supatype update' to download component binaries.")
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.log(`[supatype] Downloading component binaries for ${platform.os}/${platform.arch}...`)
|
|
27
|
-
|
|
28
|
-
const components = Object.entries(versions) as [Component, string][]
|
|
29
|
-
|
|
30
|
-
let anyFailed = false
|
|
31
|
-
for (const [component, version] of components) {
|
|
32
|
-
try {
|
|
33
|
-
await download(component, version, platform)
|
|
34
|
-
} catch (err) {
|
|
35
|
-
console.error(`[supatype] Failed to download ${component} v${version}: ${(err as Error).message}`)
|
|
36
|
-
anyFailed = true
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (anyFailed) {
|
|
41
|
-
// npm hides postinstall output unless --foreground-scripts, so don't rely on
|
|
42
|
-
// this being seen: the CLI re-attempts the download (with retry) on first use.
|
|
43
|
-
console.error(
|
|
44
|
-
"[supatype] Some component binaries failed to download. " +
|
|
45
|
-
"They will be re-downloaded automatically on first use; " +
|
|
46
|
-
"run 'supatype update' to retry now.",
|
|
47
|
-
)
|
|
48
|
-
} else {
|
|
49
|
-
console.log("[supatype] All component binaries downloaded successfully.")
|
|
50
|
-
}
|
|
10
|
+
console.log(
|
|
11
|
+
"[supatype] CLI installed. " +
|
|
12
|
+
"Runtime components download automatically on first use " +
|
|
13
|
+
"(supatype dev or supatype update).",
|
|
14
|
+
)
|
|
51
15
|
}
|
|
52
16
|
|
|
53
17
|
main().catch((err) => {
|
|
54
|
-
// Non-fatal — postinstall failures should not break npm install.
|
|
55
18
|
console.error("[supatype] Postinstall failed:", err)
|
|
56
19
|
process.exit(0)
|
|
57
20
|
})
|
package/src/self-host-compose.ts
CHANGED
|
@@ -292,9 +292,7 @@ ${studioService}
|
|
|
292
292
|
? ` - "80:8000"
|
|
293
293
|
- "443:8443"`
|
|
294
294
|
: ` - "\${SUPATYPE_KONG_PORT:-18473}:8000"`
|
|
295
|
-
const
|
|
296
|
-
const valkeyBlock = tlsEnabled
|
|
297
|
-
? `
|
|
295
|
+
const valkeyBlock = `
|
|
298
296
|
valkey:
|
|
299
297
|
image: \${SUPATYPE_VALKEY_IMAGE:-valkey/valkey:8-alpine}
|
|
300
298
|
command: ["valkey-server", "--appendonly", "yes"]
|
|
@@ -303,23 +301,18 @@ ${studioService}
|
|
|
303
301
|
volumes:
|
|
304
302
|
- valkey-data:/data
|
|
305
303
|
`
|
|
306
|
-
|
|
304
|
+
const kongValkeyDepends = "\n - valkey"
|
|
307
305
|
const tlsHintComment = tlsEnabled
|
|
308
306
|
? ""
|
|
309
307
|
: ` # HTTPS is off. To enable automatic TLS (Let's Encrypt) for production, set in supatype.config.ts:
|
|
310
308
|
# server: { mode: "standalone", domain: "your.domain", tls: { email: "you@example.com" } }
|
|
311
309
|
# then re-run \`supatype self-host compose up -d\`. Kong publishes :80/:443 and provisions certs automatically.
|
|
312
310
|
`
|
|
313
|
-
const volumesBlock =
|
|
314
|
-
? `volumes:
|
|
311
|
+
const volumesBlock = `volumes:
|
|
315
312
|
db-data:
|
|
316
313
|
minio-data:
|
|
317
314
|
valkey-data:
|
|
318
315
|
`
|
|
319
|
-
: `volumes:
|
|
320
|
-
db-data:
|
|
321
|
-
minio-data:
|
|
322
|
-
`
|
|
323
316
|
|
|
324
317
|
return `# Generated by supatype self-host compose
|
|
325
318
|
# Kong → supatype-server (unified gateway) → internal PostgREST / storage / etc.
|
|
@@ -431,6 +424,7 @@ ${serverPorts} volumes:
|
|
|
431
424
|
SUPATYPE_DENO_FUNCTIONS_DIR: /project/functions
|
|
432
425
|
SUPATYPE_FUNCTIONS_WORKER_URL: http://functions-worker:8001
|
|
433
426
|
SUPATYPE_CONTROL_PLANE_URL: http://control-plane:8080
|
|
427
|
+
SUPATYPE_VALKEY_ADDR: valkey:6379
|
|
434
428
|
${appEnv}
|
|
435
429
|
GOTRUE_API_HOST: 0.0.0.0
|
|
436
430
|
GOTRUE_API_PORT: 9999
|
|
@@ -450,6 +444,8 @@ ${devLocal ? " STUDIO_OPEN_DEV: \"1\"\n" : ""}
|
|
|
450
444
|
depends_on:
|
|
451
445
|
db:
|
|
452
446
|
condition: service_healthy
|
|
447
|
+
valkey:
|
|
448
|
+
condition: service_started
|
|
453
449
|
postgrest:
|
|
454
450
|
condition: service_started
|
|
455
451
|
storage:
|
|
@@ -492,7 +488,7 @@ ${kongTlsEnv} volumes:
|
|
|
492
488
|
ports:
|
|
493
489
|
${kongPorts}
|
|
494
490
|
depends_on:
|
|
495
|
-
${kongDependsOn}${
|
|
491
|
+
${kongDependsOn}${kongValkeyDepends}
|
|
496
492
|
|
|
497
493
|
${volumesBlock}`
|
|
498
494
|
}
|
|
@@ -594,7 +590,21 @@ export function runDockerCompose(
|
|
|
594
590
|
? { ...process.env, COMPOSE_PROGRESS: "quiet" }
|
|
595
591
|
: process.env
|
|
596
592
|
const stdio = options?.quiet ? "pipe" : "inherit"
|
|
597
|
-
const result = spawnSync("docker", composeArgs, {
|
|
593
|
+
const result = spawnSync("docker", composeArgs, {
|
|
594
|
+
stdio,
|
|
595
|
+
cwd: projectRoot,
|
|
596
|
+
env,
|
|
597
|
+
...(options?.quiet ? { encoding: "utf8" as const } : {}),
|
|
598
|
+
})
|
|
599
|
+
if (options?.quiet && result.status !== 0) {
|
|
600
|
+
const detail = [result.stderr, result.stdout]
|
|
601
|
+
.filter((s): s is string => typeof s === "string" && s.trim() !== "")
|
|
602
|
+
.join("\n")
|
|
603
|
+
.trim()
|
|
604
|
+
if (detail) {
|
|
605
|
+
console.error(`[supatype] docker compose: ${detail}`)
|
|
606
|
+
}
|
|
607
|
+
}
|
|
598
608
|
return result.status ?? 1
|
|
599
609
|
}
|
|
600
610
|
|
package/src/studio-dev-server.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { existsSync } from "node:fs"
|
|
|
2
2
|
import { join, resolve } from "node:path"
|
|
3
3
|
import { ProcessManager } from "./process-manager.js"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/** Vite dev server port when `overrides.studio` is set. */
|
|
6
|
+
export const STUDIO_DEV_PORT = 3002
|
|
6
7
|
|
|
7
8
|
export interface StudioDevServerOptions {
|
|
8
9
|
cwd: string
|
|
@@ -15,8 +16,8 @@ export interface StudioDevServerOptions {
|
|
|
15
16
|
*/
|
|
16
17
|
proxyTarget: string
|
|
17
18
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* Browser API base URL. Must match the Vite dev origin (`http://localhost:3002`)
|
|
20
|
+
* so fetches hit the Vite proxy (SUPATYPE_PROXY_TARGET) and avoid CORS.
|
|
20
21
|
*/
|
|
21
22
|
viteSupatypeUrl: string
|
|
22
23
|
/** Vite `base` — `/studio/` when behind Kong at `/studio/`; `/` for native dev on :3002. */
|
|
@@ -35,7 +36,7 @@ export function startStudioViteDevServer(opts: StudioDevServerOptions): ProcessM
|
|
|
35
36
|
const basePath = opts.basePath ?? "/"
|
|
36
37
|
return new ProcessManager(
|
|
37
38
|
process.execPath,
|
|
38
|
-
[viteJs, "--port", String(
|
|
39
|
+
[viteJs, "--port", String(STUDIO_DEV_PORT), "--strictPort", "--host"],
|
|
39
40
|
{
|
|
40
41
|
label: "studio",
|
|
41
42
|
pidDir: opts.pidDir,
|
package/src/ui/README.md
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
# CLI terminal UI (`packages/cli/src/ui/`)
|
|
2
2
|
|
|
3
|
-
Shared
|
|
3
|
+
Shared Ink-based design system for the Supatype CLI.
|
|
4
4
|
|
|
5
5
|
| Module | Use for |
|
|
6
6
|
|--------|---------|
|
|
7
|
-
| `
|
|
8
|
-
| `
|
|
9
|
-
| `
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
7
|
+
| `theme.ts` | Brand + semantic colours (Ink + plain ANSI) |
|
|
8
|
+
| `messages.ts` | `info` / `warn` / `error` / `success`, `file`, `step`, `plain` |
|
|
9
|
+
| `fatal.ts` | `fatalError`, `reportCliFatal` |
|
|
10
|
+
| `confirm.ts` | Yes/no prompts (Ink overlay in dev, Ink flow in TTY) |
|
|
11
|
+
| `progress.ts` | `withSpinner` + `runCommandChrome` for one-shot commands |
|
|
12
|
+
| `runtime/command-chrome.ts` | Ink shell (logo, logs, spinner) — applied globally via `wrapProgramActionsWithChrome` in `cli.ts` |
|
|
13
|
+
| `prompts.ts` | Logo, `promptText`, `promptPassword`, `ensureNotCancelled` |
|
|
14
|
+
| `clack.ts` | Clack-compatible `p.*` API + `runClackFlow()` for wizards |
|
|
15
|
+
| `flows/` | Ink flow shell + prompt fields |
|
|
16
|
+
| `dev/DevDashboard.tsx` | `supatype dev` task list + log pane + prompt overlay |
|
|
12
17
|
| `next-steps.ts` | Bulleted follow-up commands |
|
|
13
|
-
| `brand.ts` | ANSI colours + logo styling (shared with dev TUI) |
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
**Convention:** interactive wizards use `runClackFlow(async (p) => …)` (`init`, `link`, `add domain`); one-shot commands get branded chrome automatically in `cli.ts` via `wrapProgramActionsWithChrome`. **`supatype dev`** keeps a persistent Ink dashboard (excluded from auto-wrap).
|
|
16
20
|
|
|
17
|
-
**
|
|
21
|
+
**Plain profile:** when `!isInteractive()` (CI, pipes), helpers fall back to `[supatype]`-prefixed lines.
|