@supatype/cli 0.1.0-alpha.13 → 0.1.0-alpha.15
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 +209 -92
- package/.turbo/turbo-typecheck.log +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/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- 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 +83 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/app.js +2 -2
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/init.d.ts +29 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +569 -90
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +15 -1
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +39 -4
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/self-host.d.ts.map +1 -1
- package/dist/commands/self-host.js +5 -5
- package/dist/commands/self-host.js.map +1 -1
- 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/project-config.d.ts +16 -0
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +34 -0
- package/dist/project-config.js.map +1 -1
- package/dist/prompts.d.ts +8 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +20 -0
- package/dist/prompts.js.map +1 -0
- package/dist/self-host-compose.d.ts.map +1 -1
- package/dist/self-host-compose.js +62 -17
- package/dist/self-host-compose.js.map +1 -1
- package/package.json +2 -1
- package/src/app-config.ts +80 -0
- package/src/cli.ts +2 -0
- package/src/commands/add.ts +94 -0
- package/src/commands/app.ts +2 -2
- package/src/commands/init.ts +738 -88
- package/src/commands/keys.ts +49 -4
- package/src/commands/self-host.ts +25 -5
- package/src/kong-config.ts +24 -1
- package/src/project-config.ts +45 -0
- package/src/prompts.ts +21 -0
- package/src/self-host-compose.ts +62 -17
- package/tests/config.test.ts +26 -0
- package/tests/init.test.ts +128 -15
- package/tests/runtime-contract.test.ts +111 -1
- package/tsconfig.tsbuildinfo +1 -1
package/tests/init.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest"
|
|
|
2
2
|
import { mkdirSync, rmSync, existsSync, readFileSync, writeFileSync } from "node:fs"
|
|
3
3
|
import { join } from "node:path"
|
|
4
4
|
import { tmpdir } from "node:os"
|
|
5
|
-
import { scaffold } from "../src/commands/init.js"
|
|
5
|
+
import { scaffold, defaultScaffoldOptions } from "../src/commands/init.js"
|
|
6
6
|
|
|
7
7
|
let tmpRoot: string
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ afterEach(() => {
|
|
|
17
17
|
|
|
18
18
|
describe("scaffold()", () => {
|
|
19
19
|
it("creates all expected files", () => {
|
|
20
|
-
scaffold(tmpRoot, "my-app")
|
|
20
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
21
21
|
|
|
22
22
|
const expected = [
|
|
23
23
|
"package.json",
|
|
@@ -35,7 +35,7 @@ describe("scaffold()", () => {
|
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
it("supatype.config.ts embeds the project name and exports defineConfig", () => {
|
|
38
|
-
scaffold(tmpRoot, "blog-app")
|
|
38
|
+
scaffold(tmpRoot, defaultScaffoldOptions("blog-app"))
|
|
39
39
|
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
40
40
|
expect(content).toContain("blog-app")
|
|
41
41
|
expect(content).toContain("defineConfig")
|
|
@@ -46,7 +46,7 @@ describe("scaffold()", () => {
|
|
|
46
46
|
})
|
|
47
47
|
|
|
48
48
|
it("package.json includes @supatype/cli and @supatype/types", () => {
|
|
49
|
-
scaffold(tmpRoot, "pkg-app")
|
|
49
|
+
scaffold(tmpRoot, defaultScaffoldOptions("pkg-app"))
|
|
50
50
|
const content = readFileSync(join(tmpRoot, "package.json"), "utf8")
|
|
51
51
|
expect(content).toContain("@supatype/cli")
|
|
52
52
|
expect(content).toContain("@supatype/types")
|
|
@@ -56,18 +56,18 @@ describe("scaffold()", () => {
|
|
|
56
56
|
it("skips package.json when it already exists", () => {
|
|
57
57
|
const pkgPath = join(tmpRoot, "package.json")
|
|
58
58
|
writeFileSync(pkgPath, '{"name":"existing"}', "utf8")
|
|
59
|
-
scaffold(tmpRoot, "my-app")
|
|
59
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
60
60
|
expect(readFileSync(pkgPath, "utf8")).toBe('{"name":"existing"}')
|
|
61
61
|
})
|
|
62
62
|
|
|
63
63
|
it("supatype.config.ts documents self-host workflow", () => {
|
|
64
|
-
scaffold(tmpRoot, "my-app")
|
|
64
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
65
65
|
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
66
66
|
expect(content).toContain("self-host")
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
it(".env contains DATABASE_URL, JWT_SECRET, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB", () => {
|
|
70
|
-
scaffold(tmpRoot, "my-app")
|
|
70
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
71
71
|
const content = readFileSync(join(tmpRoot, ".env"), "utf8")
|
|
72
72
|
expect(content).toContain("DATABASE_URL=")
|
|
73
73
|
expect(content).toContain("JWT_SECRET=")
|
|
@@ -77,23 +77,24 @@ describe("scaffold()", () => {
|
|
|
77
77
|
})
|
|
78
78
|
|
|
79
79
|
it(".env contains ANON_KEY, SERVICE_ROLE_KEY, and SITE_URL placeholders", () => {
|
|
80
|
-
scaffold(tmpRoot, "my-app")
|
|
80
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
81
81
|
const content = readFileSync(join(tmpRoot, ".env"), "utf8")
|
|
82
82
|
expect(content).toContain("ANON_KEY=")
|
|
83
83
|
expect(content).toContain("SERVICE_ROLE_KEY=")
|
|
84
84
|
expect(content).toContain("SITE_URL=")
|
|
85
85
|
})
|
|
86
86
|
|
|
87
|
-
it("schema/index.ts exports a
|
|
88
|
-
scaffold(tmpRoot, "my-app")
|
|
87
|
+
it("schema/index.ts exports a Profile model using RFC v2 Model<>", () => {
|
|
88
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
89
89
|
const content = readFileSync(join(tmpRoot, "schema/index.ts"), "utf8")
|
|
90
|
-
expect(content).toContain("export type
|
|
90
|
+
expect(content).toContain("export type Profile")
|
|
91
|
+
expect(content).toContain("display_name")
|
|
91
92
|
expect(content).toContain("Model<")
|
|
92
93
|
expect(content).toContain("access:")
|
|
93
94
|
})
|
|
94
95
|
|
|
95
96
|
it(".gitignore excludes .env, node_modules, and engine binary", () => {
|
|
96
|
-
scaffold(tmpRoot, "my-app")
|
|
97
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app"))
|
|
97
98
|
const content = readFileSync(join(tmpRoot, ".gitignore"), "utf8")
|
|
98
99
|
expect(content).toContain(".env")
|
|
99
100
|
expect(content).toContain("node_modules/")
|
|
@@ -102,19 +103,19 @@ describe("scaffold()", () => {
|
|
|
102
103
|
})
|
|
103
104
|
|
|
104
105
|
it("seed.ts references the project name", () => {
|
|
105
|
-
scaffold(tmpRoot, "acme")
|
|
106
|
+
scaffold(tmpRoot, defaultScaffoldOptions("acme"))
|
|
106
107
|
const content = readFileSync(join(tmpRoot, "seed.ts"), "utf8")
|
|
107
108
|
expect(content).toContain("acme")
|
|
108
109
|
})
|
|
109
110
|
|
|
110
111
|
it("different project names produce different config bodies", () => {
|
|
111
|
-
scaffold(tmpRoot, "alpha")
|
|
112
|
+
scaffold(tmpRoot, defaultScaffoldOptions("alpha"))
|
|
112
113
|
const alpha = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
113
114
|
|
|
114
115
|
const tmp2 = join(tmpdir(), `dt-init-test2-${Date.now()}`)
|
|
115
116
|
mkdirSync(tmp2, { recursive: true })
|
|
116
117
|
try {
|
|
117
|
-
scaffold(tmp2, "beta")
|
|
118
|
+
scaffold(tmp2, defaultScaffoldOptions("beta"))
|
|
118
119
|
const beta = readFileSync(join(tmp2, "supatype.config.ts"), "utf8")
|
|
119
120
|
expect(alpha).toContain("alpha")
|
|
120
121
|
expect(beta).toContain("beta")
|
|
@@ -124,4 +125,116 @@ describe("scaffold()", () => {
|
|
|
124
125
|
rmSync(tmp2, { recursive: true, force: true })
|
|
125
126
|
}
|
|
126
127
|
})
|
|
128
|
+
|
|
129
|
+
it("self-host target emits standalone mode + domain and a local override", () => {
|
|
130
|
+
scaffold(tmpRoot, { ...defaultScaffoldOptions("my-app", "self-host"), domain: "api.example.com" })
|
|
131
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
132
|
+
expect(content).toContain('mode: "standalone"')
|
|
133
|
+
expect(content).toContain('domain: "api.example.com"')
|
|
134
|
+
expect(content).toContain('environments: { default: "production" }')
|
|
135
|
+
expect(existsSync(join(tmpRoot, "supatype.local.config.ts"))).toBe(true)
|
|
136
|
+
const local = readFileSync(join(tmpRoot, "supatype.local.config.ts"), "utf8")
|
|
137
|
+
expect(local).toContain('mode: "dev"')
|
|
138
|
+
expect(local).toContain("Partial<SupatypeConfig>")
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it("self-host with a TLS email emits an active tls block", () => {
|
|
142
|
+
scaffold(tmpRoot, {
|
|
143
|
+
...defaultScaffoldOptions("my-app", "self-host"),
|
|
144
|
+
domain: "api.example.com",
|
|
145
|
+
tlsEmail: "ops@example.com",
|
|
146
|
+
})
|
|
147
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
148
|
+
expect(content).toContain('tls: { email: "ops@example.com" }')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it("self-host without a TLS email emits a commented tls hint", () => {
|
|
152
|
+
scaffold(tmpRoot, { ...defaultScaffoldOptions("my-app", "self-host"), domain: "api.example.com" })
|
|
153
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
154
|
+
expect(content).toContain('// tls: { email: "you@example.com" }')
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it("cloud target emits managed mode + environments and a local override", () => {
|
|
158
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app", "cloud"))
|
|
159
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
160
|
+
expect(content).toContain('mode: "managed"')
|
|
161
|
+
expect(content).toContain('environments: { default: "production" }')
|
|
162
|
+
expect(existsSync(join(tmpRoot, "supatype.local.config.ts"))).toBe(true)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it("later target stays in dev mode with no local override", () => {
|
|
166
|
+
scaffold(tmpRoot, defaultScaffoldOptions("my-app", "later"))
|
|
167
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
168
|
+
expect(content).toContain('mode: "dev"')
|
|
169
|
+
expect(content).not.toContain("environments:")
|
|
170
|
+
expect(existsSync(join(tmpRoot, "supatype.local.config.ts"))).toBe(false)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it("static app mode writes the static dir and config block", () => {
|
|
174
|
+
scaffold(tmpRoot, {
|
|
175
|
+
...defaultScaffoldOptions("my-app"),
|
|
176
|
+
app: { mode: "static", staticDir: "./dist" },
|
|
177
|
+
})
|
|
178
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
179
|
+
expect(content).toContain('mode: "static"')
|
|
180
|
+
expect(content).toContain('static_dir: "./dist"')
|
|
181
|
+
expect(existsSync(join(tmpRoot, "dist/.gitkeep"))).toBe(true)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it("proxy app mode writes upstream and start in the config", () => {
|
|
185
|
+
scaffold(tmpRoot, {
|
|
186
|
+
...defaultScaffoldOptions("my-app"),
|
|
187
|
+
app: { mode: "proxy", upstream: "http://localhost:4000", start: "dev" },
|
|
188
|
+
})
|
|
189
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
190
|
+
expect(content).toContain('mode: "proxy"')
|
|
191
|
+
expect(content).toContain('upstream: "http://localhost:4000"')
|
|
192
|
+
expect(content).toContain('start: "dev"')
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it("hello-world function scaffolds function files and a functions script", () => {
|
|
196
|
+
scaffold(tmpRoot, { ...defaultScaffoldOptions("my-app"), helloFunction: true })
|
|
197
|
+
expect(existsSync(join(tmpRoot, "functions/hello/index.ts"))).toBe(true)
|
|
198
|
+
expect(existsSync(join(tmpRoot, "functions/_shared/README.md"))).toBe(true)
|
|
199
|
+
expect(existsSync(join(tmpRoot, "functions/.env.local"))).toBe(true)
|
|
200
|
+
const pkg = readFileSync(join(tmpRoot, "package.json"), "utf8")
|
|
201
|
+
expect(pkg).toContain("supatype functions serve")
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it("custom schema path is honored", () => {
|
|
205
|
+
scaffold(tmpRoot, { ...defaultScaffoldOptions("my-app"), schemaPath: "db/schema.ts" })
|
|
206
|
+
expect(existsSync(join(tmpRoot, "db/schema.ts"))).toBe(true)
|
|
207
|
+
const content = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
208
|
+
expect(content).toContain('path: "db/schema.ts"')
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it("s3 storage and resend email reflect in config and .env", () => {
|
|
212
|
+
scaffold(tmpRoot, {
|
|
213
|
+
...defaultScaffoldOptions("my-app"),
|
|
214
|
+
email: "resend",
|
|
215
|
+
storageLocal: "s3",
|
|
216
|
+
storageProduction: "s3",
|
|
217
|
+
})
|
|
218
|
+
const config = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
219
|
+
expect(config).toContain('email: { provider: "resend" }')
|
|
220
|
+
expect(config).toContain('storage: { provider: "s3" }')
|
|
221
|
+
const env = readFileSync(join(tmpRoot, ".env"), "utf8")
|
|
222
|
+
expect(env).toContain("RESEND_API_KEY=")
|
|
223
|
+
expect(env).toContain("S3_BUCKET=")
|
|
224
|
+
expect(env).toContain("local development and production")
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it("mixed local dev and s3 production writes both storage sections", () => {
|
|
228
|
+
scaffold(tmpRoot, {
|
|
229
|
+
...defaultScaffoldOptions("my-app"),
|
|
230
|
+
storageLocal: "local",
|
|
231
|
+
storageProduction: "s3",
|
|
232
|
+
})
|
|
233
|
+
const config = readFileSync(join(tmpRoot, "supatype.config.ts"), "utf8")
|
|
234
|
+
expect(config).toContain('provider: "local"')
|
|
235
|
+
expect(config).toContain("Production storage: external S3")
|
|
236
|
+
const env = readFileSync(join(tmpRoot, ".env"), "utf8")
|
|
237
|
+
expect(env).toContain("local development — MinIO")
|
|
238
|
+
expect(env).toContain("production — external bucket")
|
|
239
|
+
})
|
|
127
240
|
})
|
|
@@ -5,7 +5,7 @@ import { tmpdir } from "node:os"
|
|
|
5
5
|
import { runtimeRouteSpec } from "../src/runtime-routes.js"
|
|
6
6
|
import { buildKongDeclarative } from "../src/kong-config.js"
|
|
7
7
|
import { composeDockerImageEnv, composePullNeedsIgnoreFailures, hasLocalVersionPins, isRegistryPullableImageRef, renderSelfHostCompose, writeSelfHostCompose } from "../src/self-host-compose.js"
|
|
8
|
-
import { updateAppConfigInProject } from "../src/app-config.js"
|
|
8
|
+
import { updateAppConfigInProject, updateServerConfigInProject } from "../src/app-config.js"
|
|
9
9
|
import type { SupatypeProjectConfig } from "../src/project-config.js"
|
|
10
10
|
import { DENO_RELEASE_PIN } from "../src/release-pins.js"
|
|
11
11
|
|
|
@@ -376,6 +376,60 @@ export default defineConfig({
|
|
|
376
376
|
}
|
|
377
377
|
})
|
|
378
378
|
|
|
379
|
+
it("server config updater sets standalone mode, domain, and tls (preserving other keys)", () => {
|
|
380
|
+
const dir = mkdtempSync(join(tmpdir(), "supatype-server-config-"))
|
|
381
|
+
try {
|
|
382
|
+
const configPath = join(dir, "supatype.config.ts")
|
|
383
|
+
writeFileSync(
|
|
384
|
+
configPath,
|
|
385
|
+
`import { defineConfig } from "@supatype/cli"
|
|
386
|
+
|
|
387
|
+
export default defineConfig({
|
|
388
|
+
project: { name: "x" },
|
|
389
|
+
database: { provider: "docker" },
|
|
390
|
+
server: { mode: "dev", port: 54321 },
|
|
391
|
+
app: { mode: "none" },
|
|
392
|
+
})
|
|
393
|
+
`,
|
|
394
|
+
"utf8",
|
|
395
|
+
)
|
|
396
|
+
updateServerConfigInProject(dir, { domain: "demo.supatype.com", tlsEmail: "hello@supatype.com" })
|
|
397
|
+
const next = readFileSync(configPath, "utf8")
|
|
398
|
+
expect(next).toContain(`mode: "standalone"`)
|
|
399
|
+
expect(next).toContain(`domain: "demo.supatype.com"`)
|
|
400
|
+
expect(next).toContain(`tls: { email: "hello@supatype.com", provider: "kong" }`)
|
|
401
|
+
expect(next).toContain(`port: 54321`)
|
|
402
|
+
} finally {
|
|
403
|
+
rmSync(dir, { recursive: true, force: true })
|
|
404
|
+
}
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it("server config updater is idempotent and overwrites a prior domain/email", () => {
|
|
408
|
+
const dir = mkdtempSync(join(tmpdir(), "supatype-server-config-"))
|
|
409
|
+
try {
|
|
410
|
+
const configPath = join(dir, "supatype.config.ts")
|
|
411
|
+
writeFileSync(
|
|
412
|
+
configPath,
|
|
413
|
+
`export default {
|
|
414
|
+
project: { name: "x" },
|
|
415
|
+
database: { provider: "docker" },
|
|
416
|
+
server: { mode: "standalone", domain: "old.example.com", tls: { email: "old@example.com", provider: "kong" } },
|
|
417
|
+
app: { mode: "none" },
|
|
418
|
+
}
|
|
419
|
+
`,
|
|
420
|
+
"utf8",
|
|
421
|
+
)
|
|
422
|
+
updateServerConfigInProject(dir, { domain: "new.supatype.com", tlsEmail: "new@supatype.com" })
|
|
423
|
+
const next = readFileSync(configPath, "utf8")
|
|
424
|
+
expect(next).toContain(`domain: "new.supatype.com"`)
|
|
425
|
+
expect(next).toContain(`email: "new@supatype.com"`)
|
|
426
|
+
expect(next).not.toContain("old.example.com")
|
|
427
|
+
expect(next).not.toContain("old@example.com")
|
|
428
|
+
} finally {
|
|
429
|
+
rmSync(dir, { recursive: true, force: true })
|
|
430
|
+
}
|
|
431
|
+
})
|
|
432
|
+
|
|
379
433
|
it("writes self-host compose artifacts under .supatype/self-host", () => {
|
|
380
434
|
const dir = mkdtempSync(join(tmpdir(), "supatype-compose-"))
|
|
381
435
|
try {
|
|
@@ -399,6 +453,62 @@ export default defineConfig({
|
|
|
399
453
|
}
|
|
400
454
|
})
|
|
401
455
|
|
|
456
|
+
const tlsConfig: SupatypeProjectConfig = {
|
|
457
|
+
...baseConfig,
|
|
458
|
+
server: { mode: "standalone", domain: "api.example.com", tls: { email: "ops@example.com" } },
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
it("self-host compose renders Kong TLS + Valkey when standalone domain + email are set", () => {
|
|
462
|
+
const compose = renderSelfHostCompose(tlsConfig)
|
|
463
|
+
expect(compose).toContain("\n valkey:\n")
|
|
464
|
+
expect(compose).toContain("valkey/valkey:8-alpine")
|
|
465
|
+
expect(compose).toContain('- "80:8000"')
|
|
466
|
+
expect(compose).toContain('- "443:8443"')
|
|
467
|
+
expect(compose).toContain("KONG_PROXY_LISTEN")
|
|
468
|
+
expect(compose).toContain("- valkey")
|
|
469
|
+
expect(compose).toContain("https://api.example.com")
|
|
470
|
+
expect(compose).toMatch(/^\s{2}valkey-data:/m)
|
|
471
|
+
expect(compose).not.toContain("HTTPS is off")
|
|
472
|
+
})
|
|
473
|
+
|
|
474
|
+
it("self-host compose stays plain HTTP with a discoverable hint when TLS is off", () => {
|
|
475
|
+
const compose = renderSelfHostCompose(baseConfig)
|
|
476
|
+
expect(compose).not.toContain("\n valkey:\n")
|
|
477
|
+
expect(compose).not.toContain('- "443:8443"')
|
|
478
|
+
expect(compose).toContain("${SUPATYPE_KONG_PORT:-18473}:8000")
|
|
479
|
+
expect(compose).toContain("HTTPS is off")
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
it("self-host compose does not enable TLS for a domain without an ACME email", () => {
|
|
483
|
+
const compose = renderSelfHostCompose({
|
|
484
|
+
...baseConfig,
|
|
485
|
+
server: { mode: "standalone", domain: "api.example.com" },
|
|
486
|
+
})
|
|
487
|
+
expect(compose).not.toContain("\n valkey:\n")
|
|
488
|
+
expect(compose).not.toContain('- "443:8443"')
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
it("writeSelfHostCompose emits a Kong acme plugin backed by Valkey when TLS is on", () => {
|
|
492
|
+
const dir = mkdtempSync(join(tmpdir(), "supatype-tls-"))
|
|
493
|
+
try {
|
|
494
|
+
const out = writeSelfHostCompose(dir, tlsConfig)
|
|
495
|
+
const kong = readFileSync(out.kongPath, "utf8")
|
|
496
|
+
expect(kong).toContain("name: acme")
|
|
497
|
+
expect(kong).toContain('account_email: "ops@example.com"')
|
|
498
|
+
expect(kong).toContain("tos_accepted: true")
|
|
499
|
+
expect(kong).toContain('- "api.example.com"')
|
|
500
|
+
expect(kong).toContain("storage: redis")
|
|
501
|
+
expect(kong).toContain('host: "valkey"')
|
|
502
|
+
} finally {
|
|
503
|
+
rmSync(dir, { recursive: true, force: true })
|
|
504
|
+
}
|
|
505
|
+
})
|
|
506
|
+
|
|
507
|
+
it("kong declarative omits the acme plugin when no acme options are provided", () => {
|
|
508
|
+
const kong = buildKongDeclarative({ unifiedGateway: true })
|
|
509
|
+
expect(kong).not.toContain("name: acme")
|
|
510
|
+
})
|
|
511
|
+
|
|
402
512
|
it("writes default manifest when missing for compose", () => {
|
|
403
513
|
const dir = mkdtempSync(join(tmpdir(), "supatype-manifest-"))
|
|
404
514
|
try {
|