@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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useRef } from "react"
|
|
2
|
+
import { render } from "ink"
|
|
3
|
+
import { isInteractive } from "../interactive.js"
|
|
4
|
+
import { createClackApi, type ClackApi } from "../clack-api.js"
|
|
5
|
+
import { FlowApp } from "../flows/FlowApp.js"
|
|
6
|
+
|
|
7
|
+
interface RunClackFlowRootProps {
|
|
8
|
+
run: (api: ClackApi) => Promise<unknown>
|
|
9
|
+
onComplete: (value: unknown) => void
|
|
10
|
+
onError: (err: unknown) => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function RunClackFlowRoot({ run, onComplete, onError }: RunClackFlowRootProps): React.ReactElement {
|
|
14
|
+
const started = useRef(false)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<FlowApp
|
|
18
|
+
bind={(controller) => {
|
|
19
|
+
if (started.current) return
|
|
20
|
+
started.current = true
|
|
21
|
+
void run(createClackApi(controller))
|
|
22
|
+
.then(onComplete)
|
|
23
|
+
.catch(onError)
|
|
24
|
+
}}
|
|
25
|
+
/>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Mount a single Ink flow session (init wizard, standalone confirm, etc.). */
|
|
30
|
+
export async function runClackFlow<T>(run: (api: ClackApi) => Promise<T>): Promise<T> {
|
|
31
|
+
if (!isInteractive()) {
|
|
32
|
+
throw new Error("Interactive Ink flow requires a TTY.")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return new Promise<T>((resolve, reject) => {
|
|
36
|
+
const instance = render(
|
|
37
|
+
<RunClackFlowRoot
|
|
38
|
+
run={run as (api: ClackApi) => Promise<unknown>}
|
|
39
|
+
onComplete={(value) => {
|
|
40
|
+
instance.unmount()
|
|
41
|
+
resolve(value as T)
|
|
42
|
+
}}
|
|
43
|
+
onError={(err) => {
|
|
44
|
+
instance.unmount()
|
|
45
|
+
reject(err)
|
|
46
|
+
}}
|
|
47
|
+
/>,
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { CLACK_CANCEL } from "./cancel.js"
|
package/src/ui/theme.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supatype terminal design tokens — shared by Ink components and plain CI output.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export const RESET = "\x1b[0m"
|
|
6
|
+
export const DIM = "\x1b[2m"
|
|
7
|
+
export const BOLD = "\x1b[1m"
|
|
8
|
+
|
|
9
|
+
export const theme = {
|
|
10
|
+
brand: "magenta" as const,
|
|
11
|
+
brandHex: "#c084fc",
|
|
12
|
+
info: "cyan" as const,
|
|
13
|
+
warn: "yellow" as const,
|
|
14
|
+
error: "red" as const,
|
|
15
|
+
success: "green" as const,
|
|
16
|
+
dim: "gray" as const,
|
|
17
|
+
muted: "gray" as const,
|
|
18
|
+
} as const
|
|
19
|
+
|
|
20
|
+
/** Legacy ANSI exports used by dev-logo / dev-task-colors. */
|
|
21
|
+
export const BRAND_COLOR = "\x1b[35m"
|
|
22
|
+
|
|
23
|
+
export function brandStyle(text: string): string {
|
|
24
|
+
return `${BRAND_COLOR}${BOLD}${text}${RESET}`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function plainInfo(message: string): string {
|
|
28
|
+
return `${theme.info === "cyan" ? "\x1b[36m" : ""}ℹ ${message}${RESET}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function plainWarn(message: string): string {
|
|
32
|
+
return `\x1b[33m⚠ ${message}${RESET}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function plainError(message: string): string {
|
|
36
|
+
return `\x1b[31m✗ ${message}${RESET}`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function plainSuccess(message: string): string {
|
|
40
|
+
return `\x1b[32m✓ ${message}${RESET}`
|
|
41
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight Valkey container for native `supatype dev` (REST response cache).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from "node:child_process"
|
|
6
|
+
import { createConnection } from "node:net"
|
|
7
|
+
|
|
8
|
+
const DEFAULT_HOST = "127.0.0.1"
|
|
9
|
+
const DEFAULT_PORT = 6379
|
|
10
|
+
const IMAGE = "valkey/valkey:8-alpine"
|
|
11
|
+
|
|
12
|
+
function containerName(projectName: string): string {
|
|
13
|
+
const safe = projectName.replace(/[^a-zA-Z0-9_-]/g, "-").slice(0, 48)
|
|
14
|
+
return `supatype-valkey-dev-${safe}`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function dockerAvailable(): boolean {
|
|
18
|
+
const r = spawnSync("docker", ["info"], { stdio: "ignore" })
|
|
19
|
+
return r.status === 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isAddrReachable(host: string, port: number, timeoutMs = 800): boolean {
|
|
23
|
+
try {
|
|
24
|
+
const r = spawnSync(
|
|
25
|
+
process.execPath,
|
|
26
|
+
[
|
|
27
|
+
"-e",
|
|
28
|
+
`const n=require('net');const s=n.createConnection({host:${JSON.stringify(host)},port:${port}});` +
|
|
29
|
+
`s.on('connect',()=>{s.end();process.exit(0)});s.on('error',()=>process.exit(1));` +
|
|
30
|
+
`setTimeout(()=>process.exit(1),${timeoutMs})`,
|
|
31
|
+
],
|
|
32
|
+
{ stdio: "ignore" },
|
|
33
|
+
)
|
|
34
|
+
return r.status === 0
|
|
35
|
+
} catch {
|
|
36
|
+
return false
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function sleepMs(ms: number): void {
|
|
41
|
+
const end = Date.now() + ms
|
|
42
|
+
while (Date.now() < end) {
|
|
43
|
+
/* spin */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ValkeySidecarResult {
|
|
48
|
+
addr: string
|
|
49
|
+
containerName: string | null
|
|
50
|
+
started: boolean
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Ensure Valkey is reachable at 127.0.0.1:6379 for native dev.
|
|
55
|
+
* Starts a named Docker container when Docker is available and nothing is listening.
|
|
56
|
+
*/
|
|
57
|
+
export function ensureValkeySidecar(projectName: string): ValkeySidecarResult {
|
|
58
|
+
const envAddr = process.env["SUPATYPE_VALKEY_ADDR"]?.trim()
|
|
59
|
+
if (envAddr) {
|
|
60
|
+
return { addr: envAddr, containerName: null, started: false }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const addr = `${DEFAULT_HOST}:${DEFAULT_PORT}`
|
|
64
|
+
|
|
65
|
+
if (isAddrReachable(DEFAULT_HOST, DEFAULT_PORT)) {
|
|
66
|
+
return { addr, containerName: null, started: false }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!dockerAvailable()) {
|
|
70
|
+
console.warn(
|
|
71
|
+
"[supatype] ⚠ Valkey not available (Docker not running). " +
|
|
72
|
+
"REST server cache (`cache({ server: true })`) will bypass until Valkey is reachable.",
|
|
73
|
+
)
|
|
74
|
+
return { addr: "", containerName: null, started: false }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const name = containerName(projectName)
|
|
78
|
+
spawnSync("docker", ["rm", "-f", name], { stdio: "ignore" })
|
|
79
|
+
|
|
80
|
+
const run = spawnSync(
|
|
81
|
+
"docker",
|
|
82
|
+
["run", "-d", "--name", name, "-p", `${DEFAULT_PORT}:6379`, IMAGE],
|
|
83
|
+
{ encoding: "utf8" },
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if (run.status !== 0) {
|
|
87
|
+
const detail = (run.stderr || run.stdout || "").trim()
|
|
88
|
+
console.warn(
|
|
89
|
+
`[supatype] ⚠ Could not start Valkey sidecar: ${detail || `exit ${run.status}`}\n` +
|
|
90
|
+
" REST server cache will bypass until Valkey is available.",
|
|
91
|
+
)
|
|
92
|
+
return { addr: "", containerName: null, started: false }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < 30; i++) {
|
|
96
|
+
if (isAddrReachable(DEFAULT_HOST, DEFAULT_PORT)) {
|
|
97
|
+
console.log(`[supatype] Valkey sidecar running (${addr})`)
|
|
98
|
+
return { addr, containerName: name, started: true }
|
|
99
|
+
}
|
|
100
|
+
sleepMs(100)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.warn("[supatype] ⚠ Valkey sidecar started but not reachable yet — cache may bypass initially.")
|
|
104
|
+
return { addr, containerName: name, started: true }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function stopValkeySidecar(containerName: string | null): void {
|
|
108
|
+
if (!containerName) return
|
|
109
|
+
spawnSync("docker", ["rm", "-f", containerName], { stdio: "ignore" })
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** @internal Test helper — probe without subprocess. */
|
|
113
|
+
export function probeTcp(host: string, port: number): Promise<boolean> {
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
const s = createConnection({ host, port })
|
|
116
|
+
s.once("connect", () => {
|
|
117
|
+
s.destroy()
|
|
118
|
+
resolve(true)
|
|
119
|
+
})
|
|
120
|
+
s.once("error", () => resolve(false))
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
s.destroy()
|
|
123
|
+
resolve(false)
|
|
124
|
+
}, 800)
|
|
125
|
+
})
|
|
126
|
+
}
|
|
@@ -98,7 +98,7 @@ describe("VERSION_PIN_LOCAL + resolveBinary", () => {
|
|
|
98
98
|
|
|
99
99
|
it("throws when versions.engine is local without overrides.engine", async () => {
|
|
100
100
|
const cfg = baseConfig()
|
|
101
|
-
cfg.versions
|
|
101
|
+
cfg.versions!.engine = VERSION_PIN_LOCAL
|
|
102
102
|
await expect(resolveBinary("engine", cfg)).rejects.toThrow(/overrides\.engine/)
|
|
103
103
|
})
|
|
104
104
|
|
|
@@ -106,7 +106,7 @@ describe("VERSION_PIN_LOCAL + resolveBinary", () => {
|
|
|
106
106
|
const fakeBin = join(tmp, "supatype-engine-local")
|
|
107
107
|
writeFileSync(fakeBin, "#")
|
|
108
108
|
const cfg = baseConfig({ engine: fakeBin })
|
|
109
|
-
cfg.versions
|
|
109
|
+
cfg.versions!.engine = VERSION_PIN_LOCAL
|
|
110
110
|
const p = await resolveBinary("engine", cfg)
|
|
111
111
|
expect(p.replace(/\\/g, "/")).toContain("supatype-engine-local")
|
|
112
112
|
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, expect, it, beforeEach, afterEach } from "vitest"
|
|
2
|
+
import { existsSync, mkdirSync, rmSync } from "node:fs"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
import { tmpdir } from "node:os"
|
|
5
|
+
import {
|
|
6
|
+
tryAcquireDownloadLock,
|
|
7
|
+
releaseDownloadLock,
|
|
8
|
+
isDownloadInProgress,
|
|
9
|
+
clearDownloadLock,
|
|
10
|
+
} from "../src/binary-download-lock.js"
|
|
11
|
+
import { cachePath } from "../src/binary-cache.js"
|
|
12
|
+
|
|
13
|
+
const VERSION = "9.9.9-test"
|
|
14
|
+
|
|
15
|
+
describe("binary-download-lock", () => {
|
|
16
|
+
let dir: string
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
dir = cachePath("deno", VERSION)
|
|
20
|
+
if (existsSync(dir)) rmSync(dir, { recursive: true, force: true })
|
|
21
|
+
mkdirSync(dir, { recursive: true })
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
clearDownloadLock("deno", VERSION)
|
|
26
|
+
if (existsSync(dir)) rmSync(dir, { recursive: true, force: true })
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it("acquires and releases a download lock", () => {
|
|
30
|
+
expect(tryAcquireDownloadLock("deno", VERSION)).toBe(true)
|
|
31
|
+
expect(isDownloadInProgress("deno", VERSION)).toBe(true)
|
|
32
|
+
releaseDownloadLock("deno", VERSION)
|
|
33
|
+
expect(isDownloadInProgress("deno", VERSION)).toBe(false)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("rejects a second acquire while the lock is held", () => {
|
|
37
|
+
expect(tryAcquireDownloadLock("deno", VERSION)).toBe(true)
|
|
38
|
+
expect(tryAcquireDownloadLock("deno", VERSION)).toBe(false)
|
|
39
|
+
releaseDownloadLock("deno", VERSION)
|
|
40
|
+
})
|
|
41
|
+
})
|
package/tests/cli-help.test.ts
CHANGED
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { describe, it, expect } from "vitest"
|
|
6
6
|
import { spawnSync } from "node:child_process"
|
|
7
|
-
import {
|
|
7
|
+
import { readFileSync } from "node:fs"
|
|
8
|
+
import { resolve, dirname, join } from "node:path"
|
|
8
9
|
import { fileURLToPath } from "node:url"
|
|
9
10
|
|
|
10
11
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
11
12
|
const CLI_BIN = resolve(__dirname, "../bin/supatype.js")
|
|
12
|
-
const
|
|
13
|
+
const PACKAGE_VERSION = (
|
|
14
|
+
JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf8")) as { version: string }
|
|
15
|
+
).version
|
|
13
16
|
|
|
14
17
|
function runCli(args: string[]): { stdout: string; stderr: string; exitCode: number } {
|
|
15
18
|
const result = spawnSync(process.execPath, [CLI_BIN, ...args], {
|
|
@@ -51,10 +54,10 @@ describe("CLI binary (requires built dist/)", () => {
|
|
|
51
54
|
}
|
|
52
55
|
})
|
|
53
56
|
|
|
54
|
-
it("--version prints
|
|
57
|
+
it("--version prints package.json version", () => {
|
|
55
58
|
const { stdout, exitCode } = runCli(["--version"])
|
|
56
59
|
expect(exitCode).toBe(0)
|
|
57
|
-
expect(stdout.trim()).
|
|
60
|
+
expect(stdout.trim()).toBe(PACKAGE_VERSION)
|
|
58
61
|
})
|
|
59
62
|
|
|
60
63
|
it("self-update --help describes the command", () => {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import { readFileSync } from "node:fs"
|
|
3
|
+
import { join, dirname } from "node:path"
|
|
4
|
+
import { fileURLToPath } from "node:url"
|
|
5
|
+
import { cliPackageVersion } from "../src/cli-package-version.js"
|
|
6
|
+
|
|
7
|
+
const packageJson = JSON.parse(
|
|
8
|
+
readFileSync(join(dirname(fileURLToPath(import.meta.url)), "../package.json"), "utf8"),
|
|
9
|
+
) as { version: string }
|
|
10
|
+
|
|
11
|
+
describe("cliPackageVersion", () => {
|
|
12
|
+
it("matches packages/cli/package.json version", () => {
|
|
13
|
+
expect(cliPackageVersion()).toBe(packageJson.version)
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Command } from "commander"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
import { registerInit } from "../src/commands/init.js"
|
|
4
|
+
import { registerDev } from "../src/commands/dev.js"
|
|
5
|
+
import { registerCache } from "../src/commands/cache.js"
|
|
6
|
+
import { registerSelfUpdate } from "../src/commands/self-update.js"
|
|
7
|
+
import { registerUpdate } from "../src/commands/update.js"
|
|
8
|
+
import { registerPg } from "../src/commands/pg.js"
|
|
9
|
+
import { registerPush } from "../src/commands/push.js"
|
|
10
|
+
import { registerDiff } from "../src/commands/diff.js"
|
|
11
|
+
import { registerPull } from "../src/commands/pull.js"
|
|
12
|
+
import { registerDoctor } from "../src/commands/doctor.js"
|
|
13
|
+
import { registerIntrospect } from "../src/commands/introspect.js"
|
|
14
|
+
import { registerAdopt } from "../src/commands/adopt.js"
|
|
15
|
+
import { registerGenerate } from "../src/commands/generate.js"
|
|
16
|
+
import { registerMigrate } from "../src/commands/migrate.js"
|
|
17
|
+
import { registerSeed } from "../src/commands/seed.js"
|
|
18
|
+
import { registerKeys } from "../src/commands/keys.js"
|
|
19
|
+
import { registerApp } from "../src/commands/app.js"
|
|
20
|
+
import { registerAdd } from "../src/commands/add.js"
|
|
21
|
+
import { registerSelfHost } from "../src/commands/self-host.js"
|
|
22
|
+
import { registerCloud } from "../src/commands/cloud.js"
|
|
23
|
+
import { registerEngine } from "../src/commands/engine.js"
|
|
24
|
+
import { registerDb } from "../src/commands/db.js"
|
|
25
|
+
import { registerDeploy } from "../src/commands/deploy.js"
|
|
26
|
+
import { registerStatus } from "../src/commands/status.js"
|
|
27
|
+
import { registerLogs } from "../src/commands/logs.js"
|
|
28
|
+
import { registerAdmin } from "../src/commands/admin.js"
|
|
29
|
+
import { registerFunctions } from "../src/commands/functions.js"
|
|
30
|
+
import { registerPlugins } from "../src/commands/plugins.js"
|
|
31
|
+
import { registerTypes } from "../src/commands/types.js"
|
|
32
|
+
import { registerMigrateFromV1 } from "../src/commands/migrate-from-v1.js"
|
|
33
|
+
import {
|
|
34
|
+
shouldExcludeCommandChrome,
|
|
35
|
+
wrapProgramActionsWithChrome,
|
|
36
|
+
} from "../src/ui/runtime/command-chrome.js"
|
|
37
|
+
|
|
38
|
+
type CommandWithAction = Command & {
|
|
39
|
+
parent?: Command | null
|
|
40
|
+
_actionHandler?: ((args: unknown) => unknown) | null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function commandPath(cmd: CommandWithAction, root: Command): string {
|
|
44
|
+
const segments: string[] = []
|
|
45
|
+
let current: CommandWithAction | null = cmd
|
|
46
|
+
while (current && current !== root) {
|
|
47
|
+
segments.unshift(current.name())
|
|
48
|
+
current = current.parent ?? null
|
|
49
|
+
}
|
|
50
|
+
return segments.join(" ")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function collectActionCommands(cmd: CommandWithAction, root: Command): CommandWithAction[] {
|
|
54
|
+
const out: CommandWithAction[] = []
|
|
55
|
+
if (cmd._actionHandler) out.push(cmd)
|
|
56
|
+
for (const sub of cmd.commands) {
|
|
57
|
+
out.push(...collectActionCommands(sub as CommandWithAction, root))
|
|
58
|
+
}
|
|
59
|
+
return out
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildProgram(): Command {
|
|
63
|
+
const program = new Command().name("supatype")
|
|
64
|
+
registerInit(program)
|
|
65
|
+
registerDev(program)
|
|
66
|
+
registerCache(program)
|
|
67
|
+
registerSelfUpdate(program)
|
|
68
|
+
registerUpdate(program)
|
|
69
|
+
registerPg(program)
|
|
70
|
+
registerPush(program)
|
|
71
|
+
registerDiff(program)
|
|
72
|
+
registerPull(program)
|
|
73
|
+
registerDoctor(program)
|
|
74
|
+
registerIntrospect(program)
|
|
75
|
+
registerAdopt(program)
|
|
76
|
+
registerGenerate(program)
|
|
77
|
+
registerMigrate(program)
|
|
78
|
+
registerSeed(program)
|
|
79
|
+
registerKeys(program)
|
|
80
|
+
registerApp(program)
|
|
81
|
+
registerAdd(program)
|
|
82
|
+
registerSelfHost(program)
|
|
83
|
+
registerCloud(program)
|
|
84
|
+
registerEngine(program)
|
|
85
|
+
registerDb(program)
|
|
86
|
+
registerDeploy(program)
|
|
87
|
+
registerStatus(program)
|
|
88
|
+
registerLogs(program)
|
|
89
|
+
registerAdmin(program)
|
|
90
|
+
registerFunctions(program)
|
|
91
|
+
registerPlugins(program)
|
|
92
|
+
registerTypes(program)
|
|
93
|
+
registerMigrateFromV1(program)
|
|
94
|
+
wrapProgramActionsWithChrome(program)
|
|
95
|
+
return program
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
describe("CLI command chrome coverage", () => {
|
|
99
|
+
it("wraps every non-excluded leaf command", () => {
|
|
100
|
+
const program = buildProgram()
|
|
101
|
+
const root = program as CommandWithAction
|
|
102
|
+
const commands = collectActionCommands(root, program)
|
|
103
|
+
|
|
104
|
+
expect(commands.length).toBeGreaterThan(50)
|
|
105
|
+
|
|
106
|
+
const excluded: string[] = []
|
|
107
|
+
const wrapped: string[] = []
|
|
108
|
+
|
|
109
|
+
for (const cmd of commands) {
|
|
110
|
+
const path = commandPath(cmd, program)
|
|
111
|
+
const handlerBefore = cmd._actionHandler
|
|
112
|
+
// Re-wrap is idempotent only when already wrapped; detect first-wrap by path policy.
|
|
113
|
+
if (shouldExcludeCommandChrome(path)) {
|
|
114
|
+
excluded.push(path)
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
wrapped.push(path)
|
|
118
|
+
expect(handlerBefore, `${path} should be wrapped`).toBeDefined()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
expect(excluded).toEqual(
|
|
122
|
+
expect.arrayContaining([
|
|
123
|
+
"dev",
|
|
124
|
+
"init",
|
|
125
|
+
"link",
|
|
126
|
+
"add domain",
|
|
127
|
+
"logs",
|
|
128
|
+
"pg psql",
|
|
129
|
+
"functions serve",
|
|
130
|
+
"self-host compose logs",
|
|
131
|
+
]),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
expect(wrapped).toEqual(
|
|
135
|
+
expect.arrayContaining([
|
|
136
|
+
"push",
|
|
137
|
+
"diff",
|
|
138
|
+
"doctor",
|
|
139
|
+
"pull",
|
|
140
|
+
"cache list",
|
|
141
|
+
"cache rest list",
|
|
142
|
+
"deploy",
|
|
143
|
+
"deploy rollback",
|
|
144
|
+
"keys",
|
|
145
|
+
"generate",
|
|
146
|
+
]),
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Command } from "commander"
|
|
2
|
+
import { describe, expect, it, vi } from "vitest"
|
|
3
|
+
import {
|
|
4
|
+
shouldExcludeCommandChrome,
|
|
5
|
+
wrapProgramActionsWithChrome,
|
|
6
|
+
} from "../src/ui/runtime/command-chrome.js"
|
|
7
|
+
|
|
8
|
+
describe("shouldExcludeCommandChrome", () => {
|
|
9
|
+
it("excludes wizard and streaming commands", () => {
|
|
10
|
+
expect(shouldExcludeCommandChrome("dev")).toBe(true)
|
|
11
|
+
expect(shouldExcludeCommandChrome("init")).toBe(true)
|
|
12
|
+
expect(shouldExcludeCommandChrome("link")).toBe(true)
|
|
13
|
+
expect(shouldExcludeCommandChrome("add domain")).toBe(true)
|
|
14
|
+
expect(shouldExcludeCommandChrome("logs")).toBe(true)
|
|
15
|
+
expect(shouldExcludeCommandChrome("pg psql")).toBe(true)
|
|
16
|
+
expect(shouldExcludeCommandChrome("functions serve")).toBe(true)
|
|
17
|
+
expect(shouldExcludeCommandChrome("self-host compose logs")).toBe(true)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("includes one-shot commands", () => {
|
|
21
|
+
expect(shouldExcludeCommandChrome("push")).toBe(false)
|
|
22
|
+
expect(shouldExcludeCommandChrome("doctor")).toBe(false)
|
|
23
|
+
expect(shouldExcludeCommandChrome("cache rest list")).toBe(false)
|
|
24
|
+
expect(shouldExcludeCommandChrome("deploy rollback")).toBe(false)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe("wrapProgramActionsWithChrome", () => {
|
|
29
|
+
it("wraps leaf actions but skips excluded paths", () => {
|
|
30
|
+
const program = new Command()
|
|
31
|
+
const pushFn = vi.fn()
|
|
32
|
+
const devFn = vi.fn()
|
|
33
|
+
|
|
34
|
+
program.command("push").action(pushFn)
|
|
35
|
+
program.command("dev").action(devFn)
|
|
36
|
+
|
|
37
|
+
type CommandWithAction = Command & {
|
|
38
|
+
_actionHandler?: ((args: unknown) => unknown) | null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const pushCmd = program.commands.find((c) => c.name() === "push") as CommandWithAction
|
|
42
|
+
const devCmd = program.commands.find((c) => c.name() === "dev") as CommandWithAction
|
|
43
|
+
const pushHandlerBefore = pushCmd._actionHandler
|
|
44
|
+
const devHandlerBefore = devCmd._actionHandler
|
|
45
|
+
|
|
46
|
+
wrapProgramActionsWithChrome(program)
|
|
47
|
+
|
|
48
|
+
expect(pushCmd._actionHandler).not.toBe(pushHandlerBefore)
|
|
49
|
+
expect(devCmd._actionHandler).toBe(devHandlerBefore)
|
|
50
|
+
})
|
|
51
|
+
})
|
package/tests/config.test.ts
CHANGED
|
@@ -176,7 +176,7 @@ describe("loadConfig()", () => {
|
|
|
176
176
|
})}`,
|
|
177
177
|
)
|
|
178
178
|
const cfg = loadConfig(tmpDir)
|
|
179
|
-
expect(cfg.versions
|
|
179
|
+
expect(cfg.versions!.engine).toBe("0.4.2")
|
|
180
180
|
expect(cfg.schema?.path).toBe("./a.ts")
|
|
181
181
|
})
|
|
182
182
|
})
|
|
@@ -207,7 +207,9 @@ describe("mergeProjectConfig()", () => {
|
|
|
207
207
|
...minimalProject("p"),
|
|
208
208
|
email: { provider: "smtp", smtp: { host: "h1", port: 587, user: "u0" } },
|
|
209
209
|
})
|
|
210
|
-
const merged = mergeProjectConfig(base, {
|
|
210
|
+
const merged = mergeProjectConfig(base, {
|
|
211
|
+
email: { smtp: { host: "h2", pass: "x" } },
|
|
212
|
+
} as Partial<typeof base>)
|
|
211
213
|
expect(merged.email?.provider).toBe("smtp")
|
|
212
214
|
expect(merged.email?.smtp?.host).toBe("h2")
|
|
213
215
|
expect(merged.email?.smtp?.port).toBe(587)
|
|
@@ -222,7 +224,7 @@ describe("mergeProjectConfig()", () => {
|
|
|
222
224
|
})
|
|
223
225
|
const merged = mergeProjectConfig(base, {
|
|
224
226
|
email: { send_email_hook_secrets: "v1,whsec_customsecret0000000000000000" },
|
|
225
|
-
})
|
|
227
|
+
} as Partial<typeof base>)
|
|
226
228
|
expect(merged.email?.send_email_hook).toBe(true)
|
|
227
229
|
expect(merged.email?.send_email_hook_uri).toBe("http://old/hook")
|
|
228
230
|
expect(merged.email?.send_email_hook_secrets).toBe("v1,whsec_customsecret0000000000000000")
|
|
@@ -233,7 +235,9 @@ describe("mergeProjectConfig()", () => {
|
|
|
233
235
|
...minimalProject("p"),
|
|
234
236
|
app: { mode: "static", static_dir: "./dist", vite_dev_url: "http://127.0.0.1:1111" },
|
|
235
237
|
})
|
|
236
|
-
const merged = mergeProjectConfig(base, {
|
|
238
|
+
const merged = mergeProjectConfig(base, {
|
|
239
|
+
app: { vite_dev_url: "http://127.0.0.1:5173" },
|
|
240
|
+
} as Partial<typeof base>)
|
|
237
241
|
expect(merged.app?.vite_dev_url).toBe("http://127.0.0.1:5173")
|
|
238
242
|
})
|
|
239
243
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import { devReadyPanelRowCount } from "../src/dev-ready-panel.js"
|
|
3
|
+
|
|
4
|
+
describe("devReadyPanelRowCount", () => {
|
|
5
|
+
it("accounts for border, keys block, and hints", () => {
|
|
6
|
+
const rows = devReadyPanelRowCount({
|
|
7
|
+
title: "Services running",
|
|
8
|
+
links: [
|
|
9
|
+
{ label: "API", url: "http://localhost:1" },
|
|
10
|
+
{ label: "Studio", url: "http://localhost:1/studio/" },
|
|
11
|
+
],
|
|
12
|
+
hints: ["Demo data: pnpm seed"],
|
|
13
|
+
anonKey: "anon-jwt",
|
|
14
|
+
serviceRoleKey: "svc-jwt",
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
// border(2) + title(1) + links(2) + hint(1) + keys header(1) + anon(1) + svc(1) + margin(1)
|
|
18
|
+
expect(rows).toBe(10)
|
|
19
|
+
})
|
|
20
|
+
})
|
package/tests/dev-ui.test.ts
CHANGED
|
@@ -2,9 +2,13 @@ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
|
|
|
2
2
|
import { mkdtempSync, writeFileSync } from "node:fs"
|
|
3
3
|
import { join } from "node:path"
|
|
4
4
|
import { tmpdir } from "node:os"
|
|
5
|
+
|
|
6
|
+
vi.mock("ink", () => ({
|
|
7
|
+
render: vi.fn(() => ({ unmount: vi.fn() })),
|
|
8
|
+
}))
|
|
5
9
|
import { DevLogBus } from "../src/dev-log-bus.js"
|
|
6
|
-
import { filterDevSubprocessLine, formatConsoleArgs, stripAnsi } from "../src/dev-log-filter.js"
|
|
7
|
-
import { appendDevTaskLog, beginDevSession, endDevSession, resolveDevUiMode } from "../src/dev-session.js"
|
|
10
|
+
import { filterCommandLogLine, filterDevSubprocessLine, filterStackLogLine, formatConsoleArgs, stripAnsi } from "../src/dev-log-filter.js"
|
|
11
|
+
import { appendDevTaskLog, beginDevSession, endDevSession, getActiveDevSession, resolveDevUiMode, withDevSessionSuspended } from "../src/dev-session.js"
|
|
8
12
|
import {
|
|
9
13
|
layoutLogoBlock,
|
|
10
14
|
logoRowCount,
|
|
@@ -25,6 +29,28 @@ describe("filterDevSubprocessLine()", () => {
|
|
|
25
29
|
})
|
|
26
30
|
})
|
|
27
31
|
|
|
32
|
+
describe("filterStackLogLine()", () => {
|
|
33
|
+
it("drops docker build progress but keeps supatype messages", () => {
|
|
34
|
+
expect(filterStackLogLine("#1 [internal] load build definition from Dockerfile")).toBe(false)
|
|
35
|
+
expect(filterStackLogLine(" Container supatype-demo-db-1 Running")).toBe(false)
|
|
36
|
+
expect(filterStackLogLine("[supatype] Waiting for Postgres (compose)...")).toBe(true)
|
|
37
|
+
expect(filterStackLogLine("Services running.")).toBe(true)
|
|
38
|
+
expect(filterStackLogLine(" API (Kong) http://localhost:18473")).toBe(true)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it("keeps override banner lines", () => {
|
|
42
|
+
expect(filterStackLogLine(" engine → ../supatype-schema-engine/bin/engine")).toBe(true)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe("filterCommandLogLine()", () => {
|
|
47
|
+
it("keeps diff output but drops docker container progress", () => {
|
|
48
|
+
expect(filterCommandLogLine(" [+] add_column users.email")).toBe(true)
|
|
49
|
+
expect(filterCommandLogLine(" Container supatype-demo-db-1 Running")).toBe(false)
|
|
50
|
+
expect(filterCommandLogLine("[supatype] Schema pushed.")).toBe(true)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
28
54
|
describe("stripAnsi()", () => {
|
|
29
55
|
it("removes colour codes", () => {
|
|
30
56
|
expect(stripAnsi("\x1b[33mhello\x1b[0m")).toBe("hello")
|
|
@@ -78,6 +104,20 @@ describe("appendDevTaskLog()", () => {
|
|
|
78
104
|
expect(session.bus.getTask("app")?.lines).toEqual(["Proxy mode: running npm run vite (/tmp/app)"])
|
|
79
105
|
expect(session.bus.getTask("stack")?.lines ?? []).toEqual([])
|
|
80
106
|
})
|
|
107
|
+
|
|
108
|
+
it("captures console.log to the bus before ink mounts", () => {
|
|
109
|
+
beginDevSession("tui")
|
|
110
|
+
console.log("[supatype] bootstrap line")
|
|
111
|
+
expect(getActiveDevSession()?.bus.getTask("stack")?.lines).toEqual(["bootstrap line"])
|
|
112
|
+
expect(getActiveDevSession()?.isInkMounted()).toBe(true)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it("withDevSessionSuspended is a no-op during bootstrap", async () => {
|
|
116
|
+
beginDevSession("tui")
|
|
117
|
+
await withDevSessionSuspended(async () => "ok")
|
|
118
|
+
expect(getActiveDevSession()?.isConsoleCaptured()).toBe(true)
|
|
119
|
+
expect(getActiveDevSession()?.isInkMounted()).toBe(true)
|
|
120
|
+
})
|
|
81
121
|
})
|
|
82
122
|
|
|
83
123
|
describe("dev-logo", () => {
|