create-svc 0.1.25 → 0.1.27
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/README.md +1 -1
- package/package.json +1 -1
- package/src/jsonc.ts +63 -0
- package/src/post-scaffold.ts +10 -1
- package/src/scaffold.test.ts +30 -30
- package/src/service-runtime/cloudrun/lib.ts +3 -1
- package/src/service-runtime/runtime.ts +11 -4
- package/src/service.test.ts +1 -1
- package/src/service.ts +3 -2
- package/templates/shared/README.md +1 -1
- package/templates/shared/service.jsonc +106 -0
- package/templates/shared/service.config.ts +0 -94
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- Go or Bun runtime choices where the target supports them
|
|
8
8
|
- HTTP frameworks (`chi` or `hono`) and ConnectRPC variants
|
|
9
9
|
- standalone package output that does not assume repo bootstrap
|
|
10
|
-
- a generated `service.
|
|
10
|
+
- a generated `service.jsonc` manifest
|
|
11
11
|
- one `service` CLI for scaffold, create, deploy, migrate, seed, dashboards, doctor, and destroy
|
|
12
12
|
- local Docker Compose Postgres for first-run development
|
|
13
13
|
- Neon-backed remote environments
|
package/package.json
CHANGED
package/src/jsonc.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export function parseJsonc(text: string): unknown {
|
|
2
|
+
return JSON.parse(stripTrailingCommas(stripJsonComments(text)));
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function stripJsonComments(text: string) {
|
|
6
|
+
let output = "";
|
|
7
|
+
let inString = false;
|
|
8
|
+
let quote = "";
|
|
9
|
+
let escaped = false;
|
|
10
|
+
|
|
11
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
12
|
+
const char = text[index] ?? "";
|
|
13
|
+
const next = text[index + 1] ?? "";
|
|
14
|
+
|
|
15
|
+
if (inString) {
|
|
16
|
+
output += char;
|
|
17
|
+
if (escaped) {
|
|
18
|
+
escaped = false;
|
|
19
|
+
} else if (char === "\\") {
|
|
20
|
+
escaped = true;
|
|
21
|
+
} else if (char === quote) {
|
|
22
|
+
inString = false;
|
|
23
|
+
quote = "";
|
|
24
|
+
}
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (char === '"' || char === "'") {
|
|
29
|
+
inString = true;
|
|
30
|
+
quote = char;
|
|
31
|
+
output += char;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (char === "/" && next === "/") {
|
|
36
|
+
while (index < text.length && text[index] !== "\n") {
|
|
37
|
+
index += 1;
|
|
38
|
+
}
|
|
39
|
+
output += "\n";
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (char === "/" && next === "*") {
|
|
44
|
+
index += 2;
|
|
45
|
+
while (index < text.length && !(text[index] === "*" && text[index + 1] === "/")) {
|
|
46
|
+
if (text[index] === "\n") {
|
|
47
|
+
output += "\n";
|
|
48
|
+
}
|
|
49
|
+
index += 1;
|
|
50
|
+
}
|
|
51
|
+
index += 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
output += char;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return output;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function stripTrailingCommas(text: string) {
|
|
62
|
+
return text.replace(/,\s*([}\]])/g, "$1");
|
|
63
|
+
}
|
package/src/post-scaffold.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ScaffoldConfig } from "./scaffold";
|
|
2
|
+
import { dirname } from "node:path";
|
|
2
3
|
|
|
3
4
|
type CommandOptions = {
|
|
4
5
|
cwd: string;
|
|
@@ -169,7 +170,7 @@ function requireCommand(name: string) {
|
|
|
169
170
|
function run(command: string, args: string[], options: CommandOptions): CommandResult {
|
|
170
171
|
const result = Bun.spawnSync([command, ...args], {
|
|
171
172
|
cwd: options.cwd,
|
|
172
|
-
env:
|
|
173
|
+
env: postScaffoldEnv(),
|
|
173
174
|
stdin: options.input === undefined ? undefined : encoder.encode(options.input),
|
|
174
175
|
stdout: options.allowFailure || options.quiet ? "pipe" : "inherit",
|
|
175
176
|
stderr: options.allowFailure || options.quiet ? "pipe" : "inherit",
|
|
@@ -188,3 +189,11 @@ function run(command: string, args: string[], options: CommandOptions): CommandR
|
|
|
188
189
|
stderr,
|
|
189
190
|
};
|
|
190
191
|
}
|
|
192
|
+
|
|
193
|
+
function postScaffoldEnv() {
|
|
194
|
+
const currentBinDir = dirname(Bun.argv[1] ?? "");
|
|
195
|
+
return {
|
|
196
|
+
...process.env,
|
|
197
|
+
PATH: currentBinDir ? `${currentBinDir}:${process.env.PATH ?? ""}` : process.env.PATH,
|
|
198
|
+
};
|
|
199
|
+
}
|
package/src/scaffold.test.ts
CHANGED
|
@@ -54,28 +54,28 @@ test("scaffolds all runtime/framework variants with shared cloudrun config", asy
|
|
|
54
54
|
})
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
-
const serviceConfig = await Bun.file(join(generatedRoot, "service.
|
|
58
|
-
expect(serviceConfig).toContain('service_id: "dns-api"');
|
|
59
|
-
expect(serviceConfig).toContain('target: "cloudrun"');
|
|
60
|
-
expect(serviceConfig).toContain('profile: "microservice"');
|
|
61
|
-
expect(serviceConfig).toContain('domain: "waitlist"');
|
|
62
|
-
expect(serviceConfig).toContain('kind: "microservice"');
|
|
63
|
-
expect(serviceConfig).toContain(`runtime: "${variant.runtime}"`);
|
|
64
|
-
expect(serviceConfig).toContain(`framework: "${variant.framework}"`);
|
|
65
|
-
expect(serviceConfig).toContain('module: "buf.build/anmho/dns-api"');
|
|
66
|
-
expect(serviceConfig).toContain('cloudflare_vault_path: "prod/providers/cloudflare"');
|
|
67
|
-
expect(serviceConfig).toContain('issuer: "https://auth.anmho.com/api/auth"');
|
|
68
|
-
expect(serviceConfig).toContain('audience: "api://dns-api"');
|
|
69
|
-
expect(serviceConfig).toContain('vault_path_prefix: "prod/apps/dns-api/server/oauth-clients"');
|
|
70
|
-
expect(serviceConfig).toContain('api_key_secret_name: "dns-api-temporal-api-key"');
|
|
71
|
-
expect(serviceConfig).toContain('project_mode: "create_new"');
|
|
72
|
-
expect(serviceConfig).toContain('quota_project_id: "anmho-infra-prod"');
|
|
73
|
-
expect(serviceConfig).toContain('jwks_url: "https://auth.anmho.com/api/auth/jwks"');
|
|
74
|
-
expect(serviceConfig).toContain('project_id: ""');
|
|
75
|
-
expect(serviceConfig).toContain('base_branch_id: ""');
|
|
76
|
-
expect(serviceConfig).toContain('base_branch_name: "main"');
|
|
77
|
-
expect(serviceConfig).toContain('preview_branch_prefix: "dns-api-pr"');
|
|
78
|
-
expect(serviceConfig).toContain('hostname: "api.dns-api.anmho.com"');
|
|
57
|
+
const serviceConfig = await Bun.file(join(generatedRoot, "service.jsonc")).text();
|
|
58
|
+
expect(serviceConfig).toContain('"service_id": "dns-api"');
|
|
59
|
+
expect(serviceConfig).toContain('"target": "cloudrun"');
|
|
60
|
+
expect(serviceConfig).toContain('"profile": "microservice"');
|
|
61
|
+
expect(serviceConfig).toContain('"domain": "waitlist"');
|
|
62
|
+
expect(serviceConfig).toContain('"kind": "microservice"');
|
|
63
|
+
expect(serviceConfig).toContain(`"runtime": "${variant.runtime}"`);
|
|
64
|
+
expect(serviceConfig).toContain(`"framework": "${variant.framework}"`);
|
|
65
|
+
expect(serviceConfig).toContain('"module": "buf.build/anmho/dns-api"');
|
|
66
|
+
expect(serviceConfig).toContain('"cloudflare_vault_path": "prod/providers/cloudflare"');
|
|
67
|
+
expect(serviceConfig).toContain('"issuer": "https://auth.anmho.com/api/auth"');
|
|
68
|
+
expect(serviceConfig).toContain('"audience": "api://dns-api"');
|
|
69
|
+
expect(serviceConfig).toContain('"vault_path_prefix": "prod/apps/dns-api/server/oauth-clients"');
|
|
70
|
+
expect(serviceConfig).toContain('"api_key_secret_name": "dns-api-temporal-api-key"');
|
|
71
|
+
expect(serviceConfig).toContain('"project_mode": "create_new"');
|
|
72
|
+
expect(serviceConfig).toContain('"quota_project_id": "anmho-infra-prod"');
|
|
73
|
+
expect(serviceConfig).toContain('"jwks_url": "https://auth.anmho.com/api/auth/jwks"');
|
|
74
|
+
expect(serviceConfig).toContain('"project_id": ""');
|
|
75
|
+
expect(serviceConfig).toContain('"base_branch_id": ""');
|
|
76
|
+
expect(serviceConfig).toContain('"base_branch_name": "main"');
|
|
77
|
+
expect(serviceConfig).toContain('"preview_branch_prefix": "dns-api-pr"');
|
|
78
|
+
expect(serviceConfig).toContain('"hostname": "api.dns-api.anmho.com"');
|
|
79
79
|
expect(serviceConfig).not.toContain("github:");
|
|
80
80
|
expect(serviceConfig).not.toContain("attachmentBucket");
|
|
81
81
|
expect(await Bun.file(join(generatedRoot, "scripts", "cloudrun", "integrations.ts")).exists()).toBeFalse();
|
|
@@ -195,10 +195,10 @@ test("scaffolds all runtime/framework variants with shared cloudrun config", asy
|
|
|
195
195
|
expect(packageJson).toContain('"destroy": "service destroy"');
|
|
196
196
|
expect(await Bun.file(join(generatedRoot, "scripts", "cloudrun", "cli.ts")).exists()).toBeFalse();
|
|
197
197
|
expect(await Bun.file(join(generatedRoot, "scripts", "authctl.ts")).exists()).toBeFalse();
|
|
198
|
-
const serviceConfig = await Bun.file(join(generatedRoot, "service.
|
|
199
|
-
expect(serviceConfig).toContain('service_id: "dns-api"');
|
|
200
|
-
expect(serviceConfig).toContain('project_id: "anmho-dns-api"');
|
|
201
|
-
expect(serviceConfig).toContain('database_name: "dns_api"');
|
|
198
|
+
const serviceConfig = await Bun.file(join(generatedRoot, "service.jsonc")).text();
|
|
199
|
+
expect(serviceConfig).toContain('"service_id": "dns-api"');
|
|
200
|
+
expect(serviceConfig).toContain('"project_id": "anmho-dns-api"');
|
|
201
|
+
expect(serviceConfig).toContain('"database_name": "dns_api"');
|
|
202
202
|
const authScript = await Bun.file(join(generatedRoot, "src", "auth.ts")).text();
|
|
203
203
|
expect(authScript).toContain('"Ed25519"');
|
|
204
204
|
|
|
@@ -324,10 +324,10 @@ test("scaffolds the workers target with wrangler lifecycle commands", async () =
|
|
|
324
324
|
expect(readme).toContain("Cloudflare Workers");
|
|
325
325
|
expect(readme).toContain("Hyperdrive binding for Neon-backed Postgres persistence");
|
|
326
326
|
expect(readme).not.toContain("Cloud Run");
|
|
327
|
-
const serviceConfig = await Bun.file(join(generatedRoot, "service.
|
|
328
|
-
expect(serviceConfig).toContain('target: "workers"');
|
|
329
|
-
expect(serviceConfig).toContain('hostname: "api.dns-api.anmho.com"');
|
|
330
|
-
expect(serviceConfig).toContain('database_name: "dns_api"');
|
|
327
|
+
const serviceConfig = await Bun.file(join(generatedRoot, "service.jsonc")).text();
|
|
328
|
+
expect(serviceConfig).toContain('"target": "workers"');
|
|
329
|
+
expect(serviceConfig).toContain('"hostname": "api.dns-api.anmho.com"');
|
|
330
|
+
expect(serviceConfig).toContain('"database_name": "dns_api"');
|
|
331
331
|
const makefile = await Bun.file(join(generatedRoot, "Makefile")).text();
|
|
332
332
|
expect(makefile).toContain('no generated code for workers');
|
|
333
333
|
expect(makefile).toContain("auth:");
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { intro, log, outro, spinner } from "@clack/prompts";
|
|
2
|
+
import { join } from "node:path";
|
|
2
3
|
import { config } from "./config";
|
|
4
|
+
import { serviceRoot } from "../runtime";
|
|
3
5
|
|
|
4
6
|
type CommandOptions = {
|
|
5
7
|
allowFailure?: boolean;
|
|
@@ -422,7 +424,7 @@ export function resolveDeploymentTarget(environment: DeployArgs["environment"],
|
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
export async function renderManifest(image: string, target: DeploymentTarget) {
|
|
425
|
-
const template = await Bun.file(
|
|
427
|
+
const template = await Bun.file(join(serviceRoot, "service.yaml")).text();
|
|
426
428
|
const temporal = resolveTemporalRuntimeConfig();
|
|
427
429
|
const values = {
|
|
428
430
|
SERVICE_NAME: target.serviceName,
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { parseJsonc } from "../jsonc";
|
|
3
3
|
|
|
4
4
|
export const serviceRoot = process.env.CREATE_SVC_SERVICE_ROOT?.trim() || process.cwd();
|
|
5
5
|
|
|
6
|
-
export const serviceConfig = (
|
|
7
|
-
|
|
8
|
-
)
|
|
6
|
+
export const serviceConfig = await readServiceConfig(serviceRoot);
|
|
7
|
+
|
|
8
|
+
async function readServiceConfig(root: string) {
|
|
9
|
+
const configPath = join(root, "service.jsonc");
|
|
10
|
+
const parsed = parseJsonc(await Bun.file(configPath).text());
|
|
11
|
+
if (!parsed || typeof parsed !== "object") {
|
|
12
|
+
throw new Error(`${configPath} must contain a JSON object`);
|
|
13
|
+
}
|
|
14
|
+
return parsed as any;
|
|
15
|
+
}
|
package/src/service.test.ts
CHANGED
|
@@ -21,7 +21,7 @@ test("findGeneratedServiceRoot detects generated service context from nested dir
|
|
|
21
21
|
const serviceRoot = join(root, "generated-api");
|
|
22
22
|
const nested = join(serviceRoot, "src", "waitlist");
|
|
23
23
|
await mkdir(nested, { recursive: true });
|
|
24
|
-
await writeFile(join(serviceRoot, "service.
|
|
24
|
+
await writeFile(join(serviceRoot, "service.jsonc"), "{}");
|
|
25
25
|
|
|
26
26
|
expect(findGeneratedServiceRoot(nested)).toBe(serviceRoot);
|
|
27
27
|
expect(findGeneratedServiceRoot(root)).toBeUndefined();
|
package/src/service.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { run as runScaffoldCli } from "./cli";
|
|
4
|
+
import { parseJsonc } from "./jsonc";
|
|
4
5
|
|
|
5
6
|
const SCAFFOLD_COMMANDS = new Set(["create", "new", "init"]);
|
|
6
7
|
|
|
@@ -41,7 +42,7 @@ export function findGeneratedServiceRoot(start: string): string | undefined {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
function isGeneratedServiceRoot(path: string) {
|
|
44
|
-
return existsSync(join(path, "service.
|
|
45
|
+
return existsSync(join(path, "service.jsonc"));
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
async function delegateToGeneratedService(serviceRoot: string, argv: string[]) {
|
|
@@ -49,7 +50,7 @@ async function delegateToGeneratedService(serviceRoot: string, argv: string[]) {
|
|
|
49
50
|
process.chdir(serviceRoot);
|
|
50
51
|
process.env.CREATE_SVC_SERVICE_ROOT = serviceRoot;
|
|
51
52
|
|
|
52
|
-
const serviceConfig = (await
|
|
53
|
+
const serviceConfig = parseJsonc(await Bun.file(join(serviceRoot, "service.jsonc")).text()) as { target?: string };
|
|
53
54
|
if (serviceConfig.target === "workers") {
|
|
54
55
|
const { main } = await import("./service-runtime/workers/cli");
|
|
55
56
|
await main(argv);
|
|
@@ -59,7 +59,7 @@ No cloud credentials are required for local HTTP development after Docker and Po
|
|
|
59
59
|
|
|
60
60
|
## Remote provisioning
|
|
61
61
|
|
|
62
|
-
The generated service config lives in [service.
|
|
62
|
+
The generated service config lives in [service.jsonc](service.jsonc).
|
|
63
63
|
|
|
64
64
|
Create, deploy, and destroy use:
|
|
65
65
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
// The installed `service` CLI reads this file to choose Cloud Run vs Workers
|
|
3
|
+
// operations for this generated repo.
|
|
4
|
+
"service_id": "{{SERVICE_ID}}",
|
|
5
|
+
"target": "{{TARGET}}",
|
|
6
|
+
"runtime": "{{RUNTIME}}",
|
|
7
|
+
"framework": "{{FRAMEWORK}}",
|
|
8
|
+
"profile": "{{PROFILE}}",
|
|
9
|
+
"stage_default": "prod",
|
|
10
|
+
|
|
11
|
+
"example": {
|
|
12
|
+
"kind": "{{EXAMPLE_KIND}}",
|
|
13
|
+
"domain": "{{EXAMPLE_DOMAIN}}",
|
|
14
|
+
"label": "{{EXAMPLE_LABEL}}"
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
"dns": {
|
|
18
|
+
"hostname": "{{API_HOSTNAME}}",
|
|
19
|
+
"base_domain": "{{API_BASE_DOMAIN}}",
|
|
20
|
+
"cloudflare_api_base_url": "https://api.cloudflare.com/client/v4",
|
|
21
|
+
"cloudflare_vault_path": "prod/providers/cloudflare",
|
|
22
|
+
"cloudflare_vault_field": "api_token"
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
"ownership": {
|
|
26
|
+
"managed_by": "create-service",
|
|
27
|
+
"service_id": "{{SERVICE_ID}}"
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
"auth": {
|
|
31
|
+
"issuer": "{{AUTH_ISSUER}}",
|
|
32
|
+
"token_endpoint": "https://auth.anmho.com/api/auth/oauth2/token",
|
|
33
|
+
"jwks_url": "https://auth.anmho.com/api/auth/jwks",
|
|
34
|
+
"resource_server": {
|
|
35
|
+
"id": "{{SERVICE_ID}}",
|
|
36
|
+
"audience": "api://{{SERVICE_ID}}",
|
|
37
|
+
"default_scopes": ["{{SERVICE_ID}}:read", "{{SERVICE_ID}}:write"]
|
|
38
|
+
},
|
|
39
|
+
"client": {
|
|
40
|
+
"app_id": "{{SERVICE_ID}}",
|
|
41
|
+
"identity": "server",
|
|
42
|
+
"vault_path_prefix": "prod/apps/{{SERVICE_ID}}/server/oauth-clients"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"temporal": {
|
|
47
|
+
"enabled": false,
|
|
48
|
+
"address": "localhost:7233",
|
|
49
|
+
"namespace": "default",
|
|
50
|
+
"task_queue": "{{SERVICE_ID}}",
|
|
51
|
+
"api_key_secret_name": "{{SERVICE_ID}}-temporal-api-key"
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
"providers": {
|
|
55
|
+
"vault": {
|
|
56
|
+
"mount": "secret",
|
|
57
|
+
"neon_path": "prod/providers/neon",
|
|
58
|
+
"cloudflare_path": "prod/providers/cloudflare",
|
|
59
|
+
"grafana_path": "prod/providers/grafana",
|
|
60
|
+
"clerk_m2m_path": "prod/providers/clerk-m2m",
|
|
61
|
+
"temporal_path": "prod/providers/temporal"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
"neon": {
|
|
66
|
+
"project_id": "{{NEON_PROJECT_ID}}",
|
|
67
|
+
"base_branch_id": "{{NEON_BASE_BRANCH_ID}}",
|
|
68
|
+
"base_branch_name": "{{NEON_BASE_BRANCH_NAME}}",
|
|
69
|
+
"database_name": "{{NEON_DATABASE_NAME}}",
|
|
70
|
+
"role_name": "{{NEON_ROLE_NAME}}",
|
|
71
|
+
"preview_branch_prefix": "{{NEON_PREVIEW_BRANCH_PREFIX}}",
|
|
72
|
+
"personal_branch_prefix": "{{NEON_PERSONAL_BRANCH_PREFIX}}"
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
"buf": {
|
|
76
|
+
"module": "buf.build/anmho/{{SERVICE_ID}}"
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
"cloudrun": {
|
|
80
|
+
"project_id": "{{PROJECT_ID}}",
|
|
81
|
+
"project_name": "{{PROJECT_NAME}}",
|
|
82
|
+
"project_mode": "{{GCP_PROJECT_MODE}}",
|
|
83
|
+
"create_if_missing": {{PROJECT_CREATE_IF_MISSING}},
|
|
84
|
+
"billing_account": "{{BILLING_ACCOUNT}}",
|
|
85
|
+
"quota_project_id": "{{QUOTA_PROJECT_ID}}",
|
|
86
|
+
"region": "{{REGION}}",
|
|
87
|
+
"artifact_repository": "cloud-run",
|
|
88
|
+
"service_account": "{{RUNTIME_SERVICE_ACCOUNT}}",
|
|
89
|
+
"required_apis": [
|
|
90
|
+
"run.googleapis.com",
|
|
91
|
+
"cloudbuild.googleapis.com",
|
|
92
|
+
"artifactregistry.googleapis.com",
|
|
93
|
+
"iam.googleapis.com",
|
|
94
|
+
"iamcredentials.googleapis.com",
|
|
95
|
+
"secretmanager.googleapis.com",
|
|
96
|
+
"serviceusage.googleapis.com",
|
|
97
|
+
"sts.googleapis.com"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
"workers": {
|
|
102
|
+
"script_name": "{{SERVICE_ID}}",
|
|
103
|
+
"hyperdrive_binding": "HYPERDRIVE",
|
|
104
|
+
"cron": "*/15 * * * *"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
service_id: "{{SERVICE_ID}}",
|
|
3
|
-
target: "{{TARGET}}",
|
|
4
|
-
runtime: "{{RUNTIME}}",
|
|
5
|
-
framework: "{{FRAMEWORK}}",
|
|
6
|
-
profile: "{{PROFILE}}",
|
|
7
|
-
stage_default: "prod",
|
|
8
|
-
example: {
|
|
9
|
-
kind: "{{EXAMPLE_KIND}}",
|
|
10
|
-
domain: "{{EXAMPLE_DOMAIN}}",
|
|
11
|
-
label: "{{EXAMPLE_LABEL}}",
|
|
12
|
-
},
|
|
13
|
-
dns: {
|
|
14
|
-
hostname: "{{API_HOSTNAME}}",
|
|
15
|
-
base_domain: "{{API_BASE_DOMAIN}}",
|
|
16
|
-
cloudflare_api_base_url: "https://api.cloudflare.com/client/v4",
|
|
17
|
-
cloudflare_vault_path: "prod/providers/cloudflare",
|
|
18
|
-
cloudflare_vault_field: "api_token",
|
|
19
|
-
},
|
|
20
|
-
ownership: {
|
|
21
|
-
managed_by: "create-service",
|
|
22
|
-
service_id: "{{SERVICE_ID}}",
|
|
23
|
-
},
|
|
24
|
-
auth: {
|
|
25
|
-
issuer: "{{AUTH_ISSUER}}",
|
|
26
|
-
token_endpoint: "https://auth.anmho.com/api/auth/oauth2/token",
|
|
27
|
-
jwks_url: "https://auth.anmho.com/api/auth/jwks",
|
|
28
|
-
resource_server: {
|
|
29
|
-
id: "{{SERVICE_ID}}",
|
|
30
|
-
audience: "api://{{SERVICE_ID}}",
|
|
31
|
-
default_scopes: ["{{SERVICE_ID}}:read", "{{SERVICE_ID}}:write"],
|
|
32
|
-
},
|
|
33
|
-
client: {
|
|
34
|
-
app_id: "{{SERVICE_ID}}",
|
|
35
|
-
identity: "server",
|
|
36
|
-
vault_path_prefix: "prod/apps/{{SERVICE_ID}}/server/oauth-clients",
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
temporal: {
|
|
40
|
-
enabled: false,
|
|
41
|
-
address: "localhost:7233",
|
|
42
|
-
namespace: "default",
|
|
43
|
-
task_queue: "{{SERVICE_ID}}",
|
|
44
|
-
api_key_secret_name: "{{SERVICE_ID}}-temporal-api-key",
|
|
45
|
-
},
|
|
46
|
-
providers: {
|
|
47
|
-
vault: {
|
|
48
|
-
mount: "secret",
|
|
49
|
-
neon_path: "prod/providers/neon",
|
|
50
|
-
cloudflare_path: "prod/providers/cloudflare",
|
|
51
|
-
grafana_path: "prod/providers/grafana",
|
|
52
|
-
clerk_m2m_path: "prod/providers/clerk-m2m",
|
|
53
|
-
temporal_path: "prod/providers/temporal",
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
neon: {
|
|
57
|
-
project_id: "{{NEON_PROJECT_ID}}",
|
|
58
|
-
base_branch_id: "{{NEON_BASE_BRANCH_ID}}",
|
|
59
|
-
base_branch_name: "{{NEON_BASE_BRANCH_NAME}}",
|
|
60
|
-
database_name: "{{NEON_DATABASE_NAME}}",
|
|
61
|
-
role_name: "{{NEON_ROLE_NAME}}",
|
|
62
|
-
preview_branch_prefix: "{{NEON_PREVIEW_BRANCH_PREFIX}}",
|
|
63
|
-
personal_branch_prefix: "{{NEON_PERSONAL_BRANCH_PREFIX}}",
|
|
64
|
-
},
|
|
65
|
-
buf: {
|
|
66
|
-
module: "buf.build/anmho/{{SERVICE_ID}}",
|
|
67
|
-
},
|
|
68
|
-
cloudrun: {
|
|
69
|
-
project_id: "{{PROJECT_ID}}",
|
|
70
|
-
project_name: "{{PROJECT_NAME}}",
|
|
71
|
-
project_mode: "{{GCP_PROJECT_MODE}}",
|
|
72
|
-
create_if_missing: {{PROJECT_CREATE_IF_MISSING}},
|
|
73
|
-
billing_account: "{{BILLING_ACCOUNT}}",
|
|
74
|
-
quota_project_id: "{{QUOTA_PROJECT_ID}}",
|
|
75
|
-
region: "{{REGION}}",
|
|
76
|
-
artifact_repository: "cloud-run",
|
|
77
|
-
service_account: "{{RUNTIME_SERVICE_ACCOUNT}}",
|
|
78
|
-
required_apis: [
|
|
79
|
-
"run.googleapis.com",
|
|
80
|
-
"cloudbuild.googleapis.com",
|
|
81
|
-
"artifactregistry.googleapis.com",
|
|
82
|
-
"iam.googleapis.com",
|
|
83
|
-
"iamcredentials.googleapis.com",
|
|
84
|
-
"secretmanager.googleapis.com",
|
|
85
|
-
"serviceusage.googleapis.com",
|
|
86
|
-
"sts.googleapis.com",
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
workers: {
|
|
90
|
-
script_name: "{{SERVICE_ID}}",
|
|
91
|
-
hyperdrive_binding: "HYPERDRIVE",
|
|
92
|
-
cron: "*/15 * * * *",
|
|
93
|
-
},
|
|
94
|
-
} as const;
|