@supatype/cli 0.1.0-alpha.9 → 0.1.0
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 +2 -2
- package/.turbo/turbo-test.log +270 -65
- package/.turbo/turbo-typecheck.log +1 -1
- package/assets/supatype-logo-wordmark.ascii.txt +6 -0
- package/bin/dev-entry.ts +2 -1
- package/dist/app/framework.js +1 -3
- package/dist/app/framework.js.map +1 -1
- package/dist/app/proxy-dev-app.d.ts +14 -0
- package/dist/app/proxy-dev-app.d.ts.map +1 -1
- package/dist/app/proxy-dev-app.js +110 -6
- package/dist/app/proxy-dev-app.js.map +1 -1
- package/dist/app-config.d.ts +10 -0
- package/dist/app-config.d.ts.map +1 -1
- package/dist/app-config.js +72 -0
- package/dist/app-config.js.map +1 -1
- package/dist/assets/supatype-logo-wordmark.ascii.txt +6 -0
- package/dist/binary-cache.d.ts +19 -7
- package/dist/binary-cache.d.ts.map +1 -1
- package/dist/binary-cache.js +92 -46
- package/dist/binary-cache.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +17 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +86 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +39 -53
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/adopt.d.ts +3 -0
- package/dist/commands/adopt.d.ts.map +1 -0
- package/dist/commands/adopt.js +55 -0
- package/dist/commands/adopt.js.map +1 -0
- package/dist/commands/app.d.ts.map +1 -1
- package/dist/commands/app.js +20 -17
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/cache.d.ts.map +1 -1
- package/dist/commands/cache.js +11 -10
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/cloud.d.ts +4 -9
- package/dist/commands/cloud.d.ts.map +1 -1
- package/dist/commands/cloud.js +75 -125
- package/dist/commands/cloud.js.map +1 -1
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +37 -58
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +140 -96
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +72 -39
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +39 -39
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +78 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +5 -4
- package/dist/commands/engine.js.map +1 -1
- package/dist/commands/functions.d.ts.map +1 -1
- package/dist/commands/functions.js +172 -119
- package/dist/commands/functions.js.map +1 -1
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +5 -4
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts +30 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +814 -107
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/introspect.d.ts +3 -0
- package/dist/commands/introspect.d.ts.map +1 -0
- package/dist/commands/introspect.js +35 -0
- package/dist/commands/introspect.js.map +1 -0
- package/dist/commands/keys.d.ts +15 -1
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +46 -10
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/link-helpers.d.ts +15 -0
- package/dist/commands/link-helpers.d.ts.map +1 -0
- package/dist/commands/link-helpers.js +225 -0
- package/dist/commands/link-helpers.js.map +1 -0
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +5 -4
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/migrate-from-v1.d.ts.map +1 -1
- package/dist/commands/migrate-from-v1.js +3 -2
- package/dist/commands/migrate-from-v1.js.map +1 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +119 -26
- package/dist/commands/migrate.js.map +1 -1
- package/dist/commands/pg.d.ts.map +1 -1
- package/dist/commands/pg.js +11 -12
- package/dist/commands/pg.js.map +1 -1
- package/dist/commands/plugins.d.ts.map +1 -1
- package/dist/commands/plugins.js +55 -46
- package/dist/commands/plugins.js.map +1 -1
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +33 -5
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +110 -137
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/seed.d.ts.map +1 -1
- package/dist/commands/seed.js +4 -3
- package/dist/commands/seed.js.map +1 -1
- package/dist/commands/self-host.d.ts +2 -2
- package/dist/commands/self-host.d.ts.map +1 -1
- package/dist/commands/self-host.js +65 -50
- package/dist/commands/self-host.js.map +1 -1
- package/dist/commands/self-update.d.ts.map +1 -1
- package/dist/commands/self-update.js +3 -2
- package/dist/commands/self-update.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +95 -29
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js +3 -2
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +54 -21
- package/dist/commands/update.js.map +1 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/dev-compose.d.ts +26 -0
- package/dist/dev-compose.d.ts.map +1 -1
- package/dist/dev-compose.js +328 -34
- package/dist/dev-compose.js.map +1 -1
- package/dist/dev-log-bus.d.ts +30 -0
- package/dist/dev-log-bus.d.ts.map +1 -0
- package/dist/dev-log-bus.js +87 -0
- package/dist/dev-log-bus.js.map +1 -0
- package/dist/dev-log-filter.d.ts +10 -0
- package/dist/dev-log-filter.d.ts.map +1 -0
- package/dist/dev-log-filter.js +36 -0
- package/dist/dev-log-filter.js.map +1 -0
- package/dist/dev-logo.d.ts +12 -0
- package/dist/dev-logo.d.ts.map +1 -0
- package/dist/dev-logo.js +56 -0
- package/dist/dev-logo.js.map +1 -0
- package/dist/dev-session.d.ts +26 -0
- package/dist/dev-session.d.ts.map +1 -0
- package/dist/dev-session.js +106 -0
- package/dist/dev-session.js.map +1 -0
- package/dist/dev-shutdown.d.ts +9 -0
- package/dist/dev-shutdown.d.ts.map +1 -0
- package/dist/dev-shutdown.js +50 -0
- package/dist/dev-shutdown.js.map +1 -0
- package/dist/dev-task-colors.d.ts +13 -0
- package/dist/dev-task-colors.d.ts.map +1 -0
- package/dist/dev-task-colors.js +43 -0
- package/dist/dev-task-colors.js.map +1 -0
- package/dist/dev-tui.d.ts +24 -0
- package/dist/dev-tui.d.ts.map +1 -0
- package/dist/dev-tui.js +188 -0
- package/dist/dev-tui.js.map +1 -0
- package/dist/diff-output.d.ts +5 -1
- package/dist/diff-output.d.ts.map +1 -1
- package/dist/diff-output.js +69 -0
- package/dist/diff-output.js.map +1 -1
- package/dist/docker-runtime.d.ts +30 -0
- package/dist/docker-runtime.d.ts.map +1 -0
- package/dist/docker-runtime.js +118 -0
- package/dist/docker-runtime.js.map +1 -0
- package/dist/engine-client.d.ts +10 -1
- package/dist/engine-client.d.ts.map +1 -1
- package/dist/engine-client.js +76 -17
- package/dist/engine-client.js.map +1 -1
- package/dist/engine-push-output.d.ts +17 -0
- package/dist/engine-push-output.d.ts.map +1 -0
- package/dist/engine-push-output.js +64 -0
- package/dist/engine-push-output.js.map +1 -0
- package/dist/ensure-binary.js +2 -2
- package/dist/ensure-binary.js.map +1 -1
- package/dist/gitignore.d.ts +8 -0
- package/dist/gitignore.d.ts.map +1 -0
- package/dist/gitignore.js +41 -0
- package/dist/gitignore.js.map +1 -0
- package/dist/kong-config.d.ts +9 -0
- package/dist/kong-config.d.ts.map +1 -1
- package/dist/kong-config.js +18 -1
- package/dist/kong-config.js.map +1 -1
- package/dist/link.d.ts +66 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +160 -0
- package/dist/link.js.map +1 -0
- package/dist/process-manager.d.ts +8 -0
- package/dist/process-manager.d.ts.map +1 -1
- package/dist/process-manager.js +53 -9
- package/dist/process-manager.js.map +1 -1
- package/dist/project-config.d.ts +30 -3
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +37 -4
- package/dist/project-config.js.map +1 -1
- package/dist/prompts.d.ts +3 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +3 -0
- package/dist/prompts.js.map +1 -0
- package/dist/pull-utils.d.ts +50 -14
- package/dist/pull-utils.d.ts.map +1 -1
- package/dist/pull-utils.js +152 -12
- package/dist/pull-utils.js.map +1 -1
- package/dist/resolve-target.d.ts +86 -0
- package/dist/resolve-target.d.ts.map +1 -0
- package/dist/resolve-target.js +291 -0
- package/dist/resolve-target.js.map +1 -0
- package/dist/restore-system-relation-targets.d.ts +3 -0
- package/dist/restore-system-relation-targets.d.ts.map +1 -0
- package/dist/restore-system-relation-targets.js +45 -0
- package/dist/restore-system-relation-targets.js.map +1 -0
- package/dist/runtime-routes.d.ts.map +1 -1
- package/dist/runtime-routes.js +7 -0
- package/dist/runtime-routes.js.map +1 -1
- package/dist/schema-ast-v2.d.ts +1 -1
- package/dist/schema-ast-v2.d.ts.map +1 -1
- package/dist/schema-ast-v2.js +2 -2
- package/dist/schema-ast-v2.js.map +1 -1
- package/dist/schema-sources.d.ts +40 -0
- package/dist/schema-sources.d.ts.map +1 -0
- package/dist/schema-sources.js +183 -0
- package/dist/schema-sources.js.map +1 -0
- package/dist/scripts/postinstall.js +5 -1
- package/dist/scripts/postinstall.js.map +1 -1
- package/dist/self-host-compose.d.ts +37 -1
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +233 -43
- package/dist/self-host-compose.js.map +1 -1
- package/dist/storage-provision.d.ts +4 -0
- package/dist/storage-provision.d.ts.map +1 -1
- package/dist/storage-provision.js +24 -2
- package/dist/storage-provision.js.map +1 -1
- package/dist/supatype-eval-1781522769253.d.mts +2 -0
- package/dist/supatype-eval-1781522769253.d.mts.map +1 -0
- package/dist/supatype-eval-1781522769253.mjs +3 -0
- package/dist/supatype-eval-1781522769253.mjs.map +1 -0
- package/dist/systemd.js +2 -2
- package/dist/systemd.js.map +1 -1
- package/dist/target-client.d.ts +10 -0
- package/dist/target-client.d.ts.map +1 -0
- package/dist/target-client.js +22 -0
- package/dist/target-client.js.map +1 -0
- package/dist/type-extractor.d.ts +11 -0
- package/dist/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor.js +95 -8
- package/dist/type-extractor.js.map +1 -1
- package/dist/ui/brand.d.ts +9 -0
- package/dist/ui/brand.d.ts.map +1 -0
- package/dist/ui/brand.js +11 -0
- package/dist/ui/brand.js.map +1 -0
- package/dist/ui/confirm.d.ts +12 -0
- package/dist/ui/confirm.d.ts.map +1 -0
- package/dist/ui/confirm.js +28 -0
- package/dist/ui/confirm.js.map +1 -0
- package/dist/ui/fatal.d.ts +10 -0
- package/dist/ui/fatal.d.ts.map +1 -0
- package/dist/ui/fatal.js +34 -0
- package/dist/ui/fatal.js.map +1 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +9 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/interactive.d.ts +3 -0
- package/dist/ui/interactive.d.ts.map +1 -0
- package/dist/ui/interactive.js +5 -0
- package/dist/ui/interactive.js.map +1 -0
- package/dist/ui/messages.d.ts +10 -0
- package/dist/ui/messages.d.ts.map +1 -0
- package/dist/ui/messages.js +35 -0
- package/dist/ui/messages.js.map +1 -0
- package/dist/ui/next-steps.d.ts +3 -0
- package/dist/ui/next-steps.d.ts.map +1 -0
- package/dist/ui/next-steps.js +10 -0
- package/dist/ui/next-steps.js.map +1 -0
- package/dist/ui/progress.d.ts +5 -0
- package/dist/ui/progress.d.ts.map +1 -0
- package/dist/ui/progress.js +24 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/prompts.d.ts +14 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +34 -0
- package/dist/ui/prompts.js.map +1 -0
- package/package.json +3 -2
- package/src/app/framework.ts +1 -3
- package/src/app/proxy-dev-app.ts +114 -6
- package/src/app-config.ts +80 -0
- package/src/binary-cache.ts +102 -52
- package/src/cli.ts +16 -2
- package/src/commands/add.ts +97 -0
- package/src/commands/admin.ts +39 -73
- package/src/commands/adopt.ts +82 -0
- package/src/commands/app.ts +20 -17
- package/src/commands/cache.ts +11 -10
- package/src/commands/cloud.ts +91 -142
- package/src/commands/db.ts +40 -63
- package/src/commands/deploy.ts +186 -126
- package/src/commands/dev.ts +95 -55
- package/src/commands/diff.ts +52 -43
- package/src/commands/doctor.ts +103 -0
- package/src/commands/engine.ts +5 -4
- package/src/commands/functions.ts +187 -123
- package/src/commands/generate.ts +5 -4
- package/src/commands/init.ts +996 -105
- package/src/commands/introspect.ts +48 -0
- package/src/commands/keys.ts +56 -14
- package/src/commands/link-helpers.ts +273 -0
- package/src/commands/logs.ts +5 -4
- package/src/commands/migrate-from-v1.ts +3 -2
- package/src/commands/migrate.ts +167 -27
- package/src/commands/pg.ts +13 -18
- package/src/commands/plugins.ts +55 -46
- package/src/commands/pull.ts +38 -9
- package/src/commands/push.ts +147 -174
- package/src/commands/seed.ts +5 -4
- package/src/commands/self-host.ts +85 -54
- package/src/commands/self-update.ts +3 -2
- package/src/commands/status.ts +102 -33
- package/src/commands/types.ts +3 -2
- package/src/commands/update.ts +59 -23
- package/src/config.ts +2 -1
- package/src/dev-compose.ts +426 -34
- package/src/dev-log-bus.ts +101 -0
- package/src/dev-log-filter.ts +32 -0
- package/src/dev-logo.ts +61 -0
- package/src/dev-session.ts +130 -0
- package/src/dev-shutdown.ts +54 -0
- package/src/dev-task-colors.ts +47 -0
- package/src/dev-tui.ts +232 -0
- package/src/diff-output.ts +79 -1
- package/src/docker-runtime.ts +151 -0
- package/src/engine-client.ts +81 -17
- package/src/engine-push-output.ts +75 -0
- package/src/ensure-binary.ts +2 -2
- package/src/gitignore.ts +48 -0
- package/src/kong-config.ts +24 -1
- package/src/link.ts +243 -0
- package/src/process-manager.ts +66 -10
- package/src/project-config.ts +62 -7
- package/src/prompts.ts +2 -0
- package/src/pull-utils.ts +217 -23
- package/src/resolve-target.ts +419 -0
- package/src/restore-system-relation-targets.ts +45 -0
- package/src/runtime-routes.ts +7 -0
- package/src/schema-ast-v2.ts +2 -1
- package/src/schema-sources.ts +248 -0
- package/src/scripts/postinstall.ts +7 -1
- package/src/self-host-compose.ts +261 -46
- package/src/storage-provision.ts +33 -1
- package/src/supatype-eval-1781522769253.mts +1 -0
- package/src/systemd.ts +2 -2
- package/src/target-client.ts +40 -0
- package/src/type-extractor.ts +124 -11
- package/src/ui/README.md +17 -0
- package/src/ui/brand.ts +12 -0
- package/src/ui/confirm.ts +38 -0
- package/src/ui/fatal.ts +43 -0
- package/src/ui/index.ts +8 -0
- package/src/ui/interactive.ts +4 -0
- package/src/ui/messages.ts +43 -0
- package/src/ui/next-steps.ts +10 -0
- package/src/ui/progress.ts +28 -0
- package/src/ui/prompts.ts +40 -0
- package/tests/cli-help.test.ts +27 -2
- package/tests/config.test.ts +29 -2
- package/tests/dev-ui.test.ts +139 -0
- package/tests/docker-runtime.test.ts +236 -0
- package/tests/engine-push-output.test.ts +67 -0
- package/tests/init.test.ts +197 -18
- package/tests/link.test.ts +148 -0
- package/tests/minisign.test.ts +102 -0
- package/tests/proxy-dev-app.test.ts +45 -1
- package/tests/pull-utils.test.ts +5 -4
- package/tests/runtime-contract.test.ts +186 -2
- package/tests/schema-sources.test.ts +119 -0
- package/tests/storage-provision.test.ts +100 -0
- package/tests/ui-confirm.test.ts +41 -0
- package/tests/ui-messages.test.ts +66 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/diff-output.ts
CHANGED
|
@@ -1,4 +1,44 @@
|
|
|
1
|
-
import type { DiffResult } from "./engine-client.js"
|
|
1
|
+
import type { DiffResult, Operation } from "./engine-client.js"
|
|
2
|
+
|
|
3
|
+
/** Human-readable label for a single schema operation. */
|
|
4
|
+
export function formatOperation(op: Operation): string {
|
|
5
|
+
if (typeof op.description === "string" && op.description.trim().length > 0) {
|
|
6
|
+
return op.description
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const kind = typeof op.type === "string" ? op.type : typeof op.kind === "string" ? op.kind : "operation"
|
|
10
|
+
const raw = op as unknown as Record<string, unknown>
|
|
11
|
+
const table = raw["table"]
|
|
12
|
+
const column = raw["column"]
|
|
13
|
+
const index = raw["index"]
|
|
14
|
+
const sql = typeof op.sql === "string" ? op.sql.trim() : ""
|
|
15
|
+
|
|
16
|
+
if (kind === "add_unique_constraint" || kind === "drop_unique_constraint") {
|
|
17
|
+
const constraint = typeof raw["constraint"] === "string" ? raw["constraint"] : null
|
|
18
|
+
if (typeof table === "string" && constraint) return `${kind} ${table}.${constraint}`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (kind === "create_index" || kind === "drop_index" || kind === "add_index") {
|
|
22
|
+
const indexName = typeof index === "string" ? index : typeof raw["name"] === "string" ? raw["name"] : null
|
|
23
|
+
const fields = Array.isArray(raw["fields"]) ? raw["fields"].join(", ") : null
|
|
24
|
+
if (indexName && fields) return `${kind} ${table}.${indexName} (${fields})`
|
|
25
|
+
if (indexName) return `${kind} ${table}.${indexName}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (typeof table === "string" && typeof column === "string") {
|
|
29
|
+
return `${kind} ${table}.${column}`
|
|
30
|
+
}
|
|
31
|
+
if (typeof table === "string") {
|
|
32
|
+
return `${kind} ${table}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (sql) {
|
|
36
|
+
const oneLine = sql.replace(/\s+/g, " ").slice(0, 120)
|
|
37
|
+
return `${kind}: ${oneLine}${sql.length > 120 ? "…" : ""}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return kind
|
|
41
|
+
}
|
|
2
42
|
|
|
3
43
|
/** Print engine diff warnings before the operation list. */
|
|
4
44
|
export function printDiffWarnings(diff: DiffResult): void {
|
|
@@ -10,3 +50,41 @@ export function printDiffWarnings(diff: DiffResult): void {
|
|
|
10
50
|
}
|
|
11
51
|
console.log()
|
|
12
52
|
}
|
|
53
|
+
|
|
54
|
+
const RISK_SYMBOL: Record<NonNullable<DiffResult["operations"][number]["risk"]>, string> = {
|
|
55
|
+
safe: "+",
|
|
56
|
+
warn: "~",
|
|
57
|
+
cautious: "~",
|
|
58
|
+
danger: "!",
|
|
59
|
+
destructive: "!",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const RISK_LEGEND: Record<NonNullable<DiffResult["operations"][number]["risk"]>, string> = {
|
|
63
|
+
safe: "safe",
|
|
64
|
+
warn: "caution",
|
|
65
|
+
cautious: "caution",
|
|
66
|
+
danger: "DANGER",
|
|
67
|
+
destructive: "DANGER",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Print planned schema operations from a diff result. */
|
|
71
|
+
export function printDiffOperations(diff: DiffResult): void {
|
|
72
|
+
const ops = diff.operations ?? []
|
|
73
|
+
if (ops.length === 0) {
|
|
74
|
+
console.log("No changes.")
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log(`\n${ops.length} change(s):\n`)
|
|
79
|
+
for (const op of ops) {
|
|
80
|
+
const r = op.risk ?? "safe"
|
|
81
|
+
const label = op.warning ?? formatOperation(op)
|
|
82
|
+
console.log(` [${RISK_SYMBOL[r]}] ${label} (${RISK_LEGEND[r]})`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const dangerous = ops.filter((o) => o.risk === "danger").length
|
|
86
|
+
if (dangerous > 0) {
|
|
87
|
+
console.log(`\n ${dangerous} dangerous operation(s). Review before pushing.`)
|
|
88
|
+
}
|
|
89
|
+
console.log()
|
|
90
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker daemon availability — used before `docker compose` and other docker CLI calls.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from "node:child_process"
|
|
6
|
+
import { platform } from "node:os"
|
|
7
|
+
import { endDevSession, getActiveDevSession } from "./dev-session.js"
|
|
8
|
+
import { isInteractive } from "./ui/interactive.js"
|
|
9
|
+
import { error, plain } from "./ui/messages.js"
|
|
10
|
+
import { clack as p, printLogo } from "./ui/prompts.js"
|
|
11
|
+
|
|
12
|
+
export type DockerDaemonProbe =
|
|
13
|
+
| { ok: true }
|
|
14
|
+
| { ok: false; reason: "cli_missing" | "daemon_unavailable"; detail?: string }
|
|
15
|
+
|
|
16
|
+
export type DockerBrandOptions = {
|
|
17
|
+
intro: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type DockerReportOptions = {
|
|
21
|
+
/** Logo + Clack intro before the error (e.g. `supatype dev` entry). */
|
|
22
|
+
brand?: DockerBrandOptions
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function dockerSpawn(args: string[]) {
|
|
26
|
+
return spawnSync("docker", args, {
|
|
27
|
+
encoding: "utf8",
|
|
28
|
+
stdio: "pipe",
|
|
29
|
+
shell: process.platform === "win32",
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Returns whether the Docker CLI is on PATH and the daemon accepts connections. */
|
|
34
|
+
export function probeDockerDaemon(): DockerDaemonProbe {
|
|
35
|
+
const version = dockerSpawn(["version", "--format", "{{.Client.Version}}"])
|
|
36
|
+
if (version.error && "code" in version.error && version.error.code === "ENOENT") {
|
|
37
|
+
return { ok: false, reason: "cli_missing" }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const clientVersion = (version.stdout ?? "").trim()
|
|
41
|
+
const versionStderr = (version.stderr ?? "").trim()
|
|
42
|
+
const versionDetail = `${versionStderr}${version.stdout ?? ""}`.trim()
|
|
43
|
+
|
|
44
|
+
// No client version — CLI missing or broken.
|
|
45
|
+
if (!clientVersion) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
reason: "cli_missing",
|
|
49
|
+
...(versionDetail ? { detail: versionDetail } : {}),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Client is present but daemon refused (paused/stopped). `docker info` can hang
|
|
54
|
+
// while paused on Docker Desktop — use the version stderr and skip info.
|
|
55
|
+
if (version.status !== 0 && versionStderr) {
|
|
56
|
+
return { ok: false, reason: "daemon_unavailable", detail: versionStderr }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const info = dockerSpawn(["info"])
|
|
60
|
+
if (info.status === 0) return { ok: true }
|
|
61
|
+
|
|
62
|
+
const infoDetail = `${info.stderr ?? ""}${info.stdout ?? ""}`.trim()
|
|
63
|
+
const detail = infoDetail || versionDetail
|
|
64
|
+
return { ok: false, reason: "daemon_unavailable", ...(detail ? { detail } : {}) }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function shouldShowDockerDetail(probe: Extract<DockerDaemonProbe, { ok: false }>): boolean {
|
|
68
|
+
if (!probe.detail) return false
|
|
69
|
+
const lower = probe.detail.toLowerCase()
|
|
70
|
+
if (probe.reason !== "daemon_unavailable") return true
|
|
71
|
+
// Skip raw daemon stderr when we already print a clearer hint.
|
|
72
|
+
return !lower.includes("paused") && !lower.includes("cannot connect")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function dockerUnavailableHeadline(probe: Extract<DockerDaemonProbe, { ok: false }>): string {
|
|
76
|
+
if (probe.reason === "cli_missing") {
|
|
77
|
+
return "Docker is not installed or not on your PATH."
|
|
78
|
+
}
|
|
79
|
+
return "Docker is installed but the daemon is not running."
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function dockerUnavailableHints(probe: Extract<DockerDaemonProbe, { ok: false }>): string[] {
|
|
83
|
+
const hints: string[] = []
|
|
84
|
+
|
|
85
|
+
if (probe.reason === "cli_missing") {
|
|
86
|
+
hints.push(
|
|
87
|
+
"Install Docker Desktop (https://www.docker.com/products/docker-desktop/) or add the docker CLI to PATH.",
|
|
88
|
+
)
|
|
89
|
+
} else if (probe.detail?.toLowerCase().includes("paused")) {
|
|
90
|
+
hints.push("Unpause Docker Desktop from the whale menu or Dashboard, then try again.")
|
|
91
|
+
} else if (platform() === "win32" || platform() === "darwin") {
|
|
92
|
+
hints.push("Start Docker Desktop, then try again.")
|
|
93
|
+
} else {
|
|
94
|
+
hints.push("Start the Docker daemon (e.g. sudo systemctl start docker), then try again.")
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
hints.push('To develop without Docker, set provider: "native" in supatype.config.ts.')
|
|
98
|
+
|
|
99
|
+
if (shouldShowDockerDetail(probe)) {
|
|
100
|
+
const firstLine = probe.detail!.split(/\r?\n/).find((line) => line.trim().length > 0)
|
|
101
|
+
if (firstLine) hints.push(`docker: ${firstLine.trim()}`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return hints
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** @deprecated Tests only — use `reportDockerUnavailable`. */
|
|
108
|
+
export function formatDockerUnavailableMessage(
|
|
109
|
+
probe: Extract<DockerDaemonProbe, { ok: false }>,
|
|
110
|
+
): string {
|
|
111
|
+
const lines: string[] = [dockerUnavailableHeadline(probe), ...dockerUnavailableHints(probe)]
|
|
112
|
+
return lines.join("\n")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Print Docker-unavailable guidance via the shared CLI message layer. */
|
|
116
|
+
export function reportDockerUnavailable(
|
|
117
|
+
probe: Extract<DockerDaemonProbe, { ok: false }>,
|
|
118
|
+
opts?: DockerReportOptions,
|
|
119
|
+
): void {
|
|
120
|
+
if (opts?.brand && isInteractive()) {
|
|
121
|
+
printLogo()
|
|
122
|
+
p.intro(opts.brand.intro)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const headline = dockerUnavailableHeadline(probe)
|
|
126
|
+
const hints = dockerUnavailableHints(probe)
|
|
127
|
+
|
|
128
|
+
error(headline)
|
|
129
|
+
|
|
130
|
+
if (isInteractive()) {
|
|
131
|
+
p.note(hints.join("\n\n"))
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const hint of hints) {
|
|
136
|
+
plain()
|
|
137
|
+
plain(` ${hint}`)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Exit 1 with a friendly message when Docker is not usable. */
|
|
142
|
+
export function requireDockerDaemon(opts?: DockerReportOptions): void {
|
|
143
|
+
const probe = probeDockerDaemon()
|
|
144
|
+
if (probe.ok) return
|
|
145
|
+
// Dev TUI patches console — restore stderr before printing a fatal message.
|
|
146
|
+
if (getActiveDevSession()) {
|
|
147
|
+
endDevSession()
|
|
148
|
+
}
|
|
149
|
+
reportDockerUnavailable(probe, opts)
|
|
150
|
+
process.exit(1)
|
|
151
|
+
}
|
package/src/engine-client.ts
CHANGED
|
@@ -13,21 +13,25 @@ import { mkdirSync, writeFileSync, unlinkSync, existsSync, readdirSync } from "n
|
|
|
13
13
|
import { tmpdir, homedir } from "node:os"
|
|
14
14
|
import { join } from "node:path"
|
|
15
15
|
import { loadConfig } from "./config.js"
|
|
16
|
-
import {
|
|
16
|
+
import { currentPlatform, cachePath } from "./binary-cache.js"
|
|
17
|
+
import { ensureBinary } from "./ensure-binary.js"
|
|
17
18
|
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Types (kept for backward compatibility with existing callers)
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
21
22
|
|
|
22
23
|
export interface Operation {
|
|
23
|
-
kind: "create_table" | "alter_table" | "drop_table" | "create_index" | "drop_index" |
|
|
24
|
-
"create_policy" | "drop_policy" | "add_column" | "drop_column" | "alter_column" |
|
|
25
|
-
"recreate_column"
|
|
26
24
|
type?: string
|
|
25
|
+
kind?: string
|
|
27
26
|
description?: string
|
|
28
27
|
risk?: "safe" | "warn" | "danger" | "cautious" | "destructive"
|
|
29
28
|
warning?: string
|
|
30
29
|
sql?: string
|
|
30
|
+
table?: string
|
|
31
|
+
column?: string
|
|
32
|
+
constraint?: string
|
|
33
|
+
index_name?: string
|
|
34
|
+
index?: { fields?: string[]; name?: string; unique?: boolean }
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export interface DiffResult {
|
|
@@ -83,10 +87,16 @@ async function getEngineBin(): Promise<string> {
|
|
|
83
87
|
|
|
84
88
|
try {
|
|
85
89
|
const config = loadConfig(cwd)
|
|
86
|
-
|
|
90
|
+
// Download-on-miss (with retry) so a fresh machine or a failed postinstall
|
|
91
|
+
// self-heals on first use instead of silently skipping type/admin refresh.
|
|
92
|
+
_engineBin = await ensureBinary("engine", config)
|
|
87
93
|
return _engineBin
|
|
88
|
-
} catch {
|
|
89
|
-
//
|
|
94
|
+
} catch (err) {
|
|
95
|
+
// A real download/verification failure must surface, not fall back to a
|
|
96
|
+
// possibly-stale cached binary from a different version.
|
|
97
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
98
|
+
if (message.includes("Failed to download")) throw err
|
|
99
|
+
// Otherwise (no valid project config) fall through to default cache scan.
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
// No config found — scan the cache for any available engine binary.
|
|
@@ -146,24 +156,40 @@ export async function engineRequest<T = unknown>(
|
|
|
146
156
|
): Promise<T> {
|
|
147
157
|
const bin = await getEngineBin()
|
|
148
158
|
|
|
149
|
-
// Write request to a temp file.
|
|
150
|
-
// For CLI-mode endpoints the engine reads the input file as a raw SchemaAst,
|
|
151
|
-
// so we extract the `ast` field when present, otherwise write the full body.
|
|
152
159
|
const tmpDir = join(tmpdir(), "supatype-engine")
|
|
153
160
|
mkdirSync(tmpDir, { recursive: true })
|
|
161
|
+
const cleanup: string[] = []
|
|
154
162
|
const reqFile = join(tmpDir, `req-${Date.now()}.json`)
|
|
155
163
|
const inputPayload = body["ast"] !== undefined ? body["ast"] : body
|
|
156
164
|
writeFileSync(reqFile, JSON.stringify(inputPayload))
|
|
165
|
+
cleanup.push(reqFile)
|
|
166
|
+
|
|
167
|
+
let gzPath: string | undefined
|
|
168
|
+
let manifestPath: string | undefined
|
|
169
|
+
if (typeof body["schema_sources_gz_base64"] === "string") {
|
|
170
|
+
gzPath = join(tmpDir, `sources-${Date.now()}.gz`)
|
|
171
|
+
writeFileSync(gzPath, Buffer.from(body["schema_sources_gz_base64"], "base64"))
|
|
172
|
+
cleanup.push(gzPath)
|
|
173
|
+
}
|
|
174
|
+
if (body["schema_sources_manifest"] !== undefined) {
|
|
175
|
+
manifestPath = join(tmpDir, `manifest-${Date.now()}.json`)
|
|
176
|
+
writeFileSync(manifestPath, JSON.stringify(body["schema_sources_manifest"]))
|
|
177
|
+
cleanup.push(manifestPath)
|
|
178
|
+
}
|
|
157
179
|
|
|
158
|
-
const args = endpointToArgs(endpoint, body, reqFile
|
|
180
|
+
const args = endpointToArgs(endpoint, body, reqFile, {
|
|
181
|
+
...(gzPath !== undefined ? { gzPath } : {}),
|
|
182
|
+
...(manifestPath !== undefined ? { manifestPath } : {}),
|
|
183
|
+
})
|
|
159
184
|
|
|
160
185
|
const result = spawnSync(bin, args, {
|
|
161
186
|
encoding: "utf8",
|
|
162
187
|
cwd: process.cwd(),
|
|
163
188
|
})
|
|
164
189
|
|
|
165
|
-
|
|
166
|
-
|
|
190
|
+
for (const f of cleanup) {
|
|
191
|
+
try { unlinkSync(f) } catch { /* ignore */ }
|
|
192
|
+
}
|
|
167
193
|
|
|
168
194
|
if (result.status !== 0) {
|
|
169
195
|
const stderr = result.stderr?.trim() || "(no output)"
|
|
@@ -195,6 +221,7 @@ function endpointToArgs(
|
|
|
195
221
|
endpoint: string,
|
|
196
222
|
body: Record<string, unknown>,
|
|
197
223
|
reqFile: string,
|
|
224
|
+
sources?: { gzPath?: string; manifestPath?: string },
|
|
198
225
|
): string[] {
|
|
199
226
|
const dbUrl = (body["database_url"] as string | undefined) ?? ""
|
|
200
227
|
const schema = (body["schema"] as string | undefined) ?? "public"
|
|
@@ -206,8 +233,26 @@ function endpointToArgs(
|
|
|
206
233
|
case "/diff":
|
|
207
234
|
return ["diff", "--input", reqFile, "--database-url", dbUrl, "--schema", schema]
|
|
208
235
|
|
|
209
|
-
case "/push":
|
|
210
|
-
|
|
236
|
+
case "/push": {
|
|
237
|
+
const sourceArgs: string[] = []
|
|
238
|
+
if (sources?.gzPath) sourceArgs.push("--schema-sources-gz", sources.gzPath)
|
|
239
|
+
if (sources?.manifestPath) sourceArgs.push("--schema-sources-manifest", sources.manifestPath)
|
|
240
|
+
return [
|
|
241
|
+
"push",
|
|
242
|
+
"--input",
|
|
243
|
+
reqFile,
|
|
244
|
+
"--database-url",
|
|
245
|
+
dbUrl,
|
|
246
|
+
"--schema",
|
|
247
|
+
schema,
|
|
248
|
+
...force,
|
|
249
|
+
...nonInteractive,
|
|
250
|
+
...sourceArgs,
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
case "/rollback":
|
|
255
|
+
return ["rollback", "--database-url", dbUrl, "--schema", schema]
|
|
211
256
|
|
|
212
257
|
case "/parse":
|
|
213
258
|
return ["parse", "--input", reqFile]
|
|
@@ -220,6 +265,18 @@ function endpointToArgs(
|
|
|
220
265
|
case "/introspect":
|
|
221
266
|
return ["introspect", "--database-url", dbUrl, "--schema", schema]
|
|
222
267
|
|
|
268
|
+
case "/doctor": {
|
|
269
|
+
const strict = body["strict"] ? ["--strict"] : []
|
|
270
|
+
const noCache = body["no_cache"] ? ["--no-cache"] : []
|
|
271
|
+
return ["doctor", "--input", reqFile, "--database-url", dbUrl, "--schema", schema, ...strict, ...noCache]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
case "/adopt": {
|
|
275
|
+
const yes = body["yes"] ? ["--yes"] : []
|
|
276
|
+
const noCache = body["no_cache"] ? ["--no-cache"] : []
|
|
277
|
+
return ["adopt", "--input", reqFile, "--database-url", dbUrl, "--schema", schema, ...yes, ...noCache]
|
|
278
|
+
}
|
|
279
|
+
|
|
223
280
|
case "/validate":
|
|
224
281
|
return ["validate", "--input", reqFile]
|
|
225
282
|
|
|
@@ -227,9 +284,16 @@ function endpointToArgs(
|
|
|
227
284
|
return ["admin", "--input", reqFile]
|
|
228
285
|
|
|
229
286
|
default:
|
|
230
|
-
if (endpoint.startsWith("/migrations")) {
|
|
287
|
+
if (endpoint === "/migrations" || endpoint.startsWith("/migrations")) {
|
|
231
288
|
const action = (body["action"] as string | undefined) ?? "list"
|
|
232
|
-
|
|
289
|
+
if (action === "rollback") {
|
|
290
|
+
return ["rollback", "--database-url", dbUrl, "--schema", schema]
|
|
291
|
+
}
|
|
292
|
+
const name = body["name"] as string | undefined
|
|
293
|
+
if (name) {
|
|
294
|
+
return ["migrations", "--database-url", dbUrl, "--name", name]
|
|
295
|
+
}
|
|
296
|
+
return ["migrations", "--database-url", dbUrl]
|
|
233
297
|
}
|
|
234
298
|
return [endpoint.replace(/^\//, ""), "--input", reqFile]
|
|
235
299
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse and format schema-engine push output (compose subprocess or HTTP).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface EnginePushResult {
|
|
6
|
+
status?: string
|
|
7
|
+
operations?: number
|
|
8
|
+
admin_refreshed?: boolean
|
|
9
|
+
message?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Extract the engine JSON object from mixed docker compose stdout/stderr. */
|
|
13
|
+
export function parseEngineJsonOutput<T>(output: string): T | null {
|
|
14
|
+
const trimmed = output.trim()
|
|
15
|
+
if (!trimmed) return null
|
|
16
|
+
|
|
17
|
+
for (const line of trimmed.split(/\r?\n/)) {
|
|
18
|
+
const candidate = line.trim()
|
|
19
|
+
if (!candidate.startsWith("{") || !candidate.endsWith("}")) continue
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(candidate) as T
|
|
22
|
+
} catch {
|
|
23
|
+
/* try next line */
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (trimmed.startsWith("{")) {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(trimmed) as T
|
|
30
|
+
} catch {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function parseEnginePushOutput(output: string): EnginePushResult | null {
|
|
39
|
+
return parseEngineJsonOutput<EnginePushResult>(output)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Human-readable one-liner for successful push (matches `supatype push` tone). */
|
|
43
|
+
export function formatEnginePushMessage(result: EnginePushResult): string {
|
|
44
|
+
if (result.status === "up_to_date") {
|
|
45
|
+
if (result.admin_refreshed) {
|
|
46
|
+
return "Schema up to date — Studio metadata synced."
|
|
47
|
+
}
|
|
48
|
+
return "Schema up to date."
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const ops = result.operations
|
|
52
|
+
if (typeof ops === "number" && ops > 0) {
|
|
53
|
+
return `Applied ${ops} operation(s).`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result.message?.trim() || "Schema applied."
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const COMPOSE_PROGRESS_LINE =
|
|
60
|
+
/^Container\s+.+\s+(Running|Waiting|Healthy|Created|Starting|Started|Exited|Stopped)\s*$/i
|
|
61
|
+
|
|
62
|
+
/** Drop docker compose progress noise; keep engine JSON and real errors. */
|
|
63
|
+
export function filterComposeNoise(output: string): string {
|
|
64
|
+
return output
|
|
65
|
+
.split(/\r?\n/)
|
|
66
|
+
.map((line) => line.trimEnd())
|
|
67
|
+
.filter((line) => {
|
|
68
|
+
const t = line.trim()
|
|
69
|
+
if (!t) return false
|
|
70
|
+
if (COMPOSE_PROGRESS_LINE.test(t)) return false
|
|
71
|
+
return true
|
|
72
|
+
})
|
|
73
|
+
.join("\n")
|
|
74
|
+
.trim()
|
|
75
|
+
}
|
package/src/ensure-binary.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
resolveBinary,
|
|
7
7
|
download,
|
|
8
8
|
currentPlatform,
|
|
9
|
-
|
|
9
|
+
resolveVersionFor,
|
|
10
10
|
type Component,
|
|
11
11
|
} from "./binary-cache.js"
|
|
12
12
|
import type { SupatypeProjectConfig } from "./project-config.js"
|
|
@@ -24,5 +24,5 @@ export async function ensureBinary(
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
return download(component,
|
|
27
|
+
return download(component, await resolveVersionFor(component, config), currentPlatform())
|
|
28
28
|
}
|
package/src/gitignore.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { resolve } from "node:path"
|
|
3
|
+
|
|
4
|
+
export const SUPATYPE_GITIGNORE_MARKER = "# Supatype — local runtime (contains secrets in link.json)"
|
|
5
|
+
export const SUPATYPE_GITIGNORE_BLOCK = `${SUPATYPE_GITIGNORE_MARKER}
|
|
6
|
+
.env
|
|
7
|
+
.supatype/
|
|
8
|
+
supatype.local.config.ts
|
|
9
|
+
supatype.local.config.js
|
|
10
|
+
supatype.local.config.mjs
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
export function isSupatypeGitignored(cwd: string): boolean {
|
|
14
|
+
const gitignorePath = resolve(cwd, ".gitignore")
|
|
15
|
+
if (!existsSync(gitignorePath)) return false
|
|
16
|
+
const content = readFileSync(gitignorePath, "utf8")
|
|
17
|
+
return /\.supatype\/?(\/|\s|$)/m.test(content) || content.includes(".supatype/")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function ensureSupatypeGitignore(cwd: string, opts?: { silent?: boolean }): boolean {
|
|
21
|
+
const gitignorePath = resolve(cwd, ".gitignore")
|
|
22
|
+
if (isSupatypeGitignored(cwd)) return true
|
|
23
|
+
|
|
24
|
+
if (existsSync(gitignorePath)) {
|
|
25
|
+
const content = readFileSync(gitignorePath, "utf8")
|
|
26
|
+
const next = content.endsWith("\n") ? content : `${content}\n`
|
|
27
|
+
writeFileSync(gitignorePath, `${next}\n${SUPATYPE_GITIGNORE_BLOCK}`, "utf8")
|
|
28
|
+
} else {
|
|
29
|
+
writeFileSync(
|
|
30
|
+
gitignorePath,
|
|
31
|
+
`.env\nnode_modules/\ndist/\n${SUPATYPE_GITIGNORE_BLOCK}`,
|
|
32
|
+
"utf8",
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!opts?.silent) {
|
|
37
|
+
console.warn("Added .supatype/ to .gitignore (link.json contains secrets — never commit).")
|
|
38
|
+
}
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function warnIfLinkNotGitignored(cwd: string): void {
|
|
43
|
+
if (isSupatypeGitignored(cwd)) return
|
|
44
|
+
console.warn(
|
|
45
|
+
"\n⚠ Warning: .supatype/ is not in .gitignore — link.json contains tokens and must not be committed.",
|
|
46
|
+
)
|
|
47
|
+
console.warn(" Run with link --fix-gitignore to append the Supatype block.\n")
|
|
48
|
+
}
|
package/src/kong-config.ts
CHANGED
|
@@ -18,6 +18,11 @@ export interface KongDeclarativeOptions {
|
|
|
18
18
|
studioServiceUrl?: string | undefined
|
|
19
19
|
/** See {@link RuntimeRouteOptions.studioStripPath}. */
|
|
20
20
|
studioStripPath?: boolean | undefined
|
|
21
|
+
/**
|
|
22
|
+
* When set, append a global Kong `acme` plugin (Let's Encrypt) with Redis/Valkey
|
|
23
|
+
* storage so the self-host gateway provisions and renews TLS automatically.
|
|
24
|
+
*/
|
|
25
|
+
acme?: { email: string; domain: string; redisHost: string } | undefined
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
/** Escape a string for use inside YAML double quotes. */
|
|
@@ -85,9 +90,27 @@ ${route.paths.map((path) => ` - ${path}`).join("\n")}
|
|
|
85
90
|
${protocols}${routePlugins}${graphqlPlugins}`
|
|
86
91
|
}).join("\n")
|
|
87
92
|
|
|
93
|
+
const acme = opts.acme
|
|
94
|
+
const pluginsBlock = acme
|
|
95
|
+
? `
|
|
96
|
+
plugins:
|
|
97
|
+
- name: acme
|
|
98
|
+
config:
|
|
99
|
+
account_email: ${yamlQuotedString(acme.email)}
|
|
100
|
+
tos_accepted: true
|
|
101
|
+
domains:
|
|
102
|
+
- ${yamlQuotedString(acme.domain)}
|
|
103
|
+
storage: redis
|
|
104
|
+
storage_config:
|
|
105
|
+
redis:
|
|
106
|
+
host: ${yamlQuotedString(acme.redisHost)}
|
|
107
|
+
port: 6379
|
|
108
|
+
`
|
|
109
|
+
: ""
|
|
110
|
+
|
|
88
111
|
return `_format_version: "3.0"
|
|
89
112
|
${consumersBlock}
|
|
90
113
|
services:
|
|
91
114
|
${servicesBlock}
|
|
92
|
-
`
|
|
115
|
+
${pluginsBlock}`
|
|
93
116
|
}
|