create-svc 0.1.24 → 0.1.25
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/package.json +3 -1
- package/src/post-scaffold.test.ts +10 -10
- package/src/post-scaffold.ts +4 -9
- package/src/scaffold.test.ts +42 -101
- package/src/scaffold.ts +10 -3
- package/{templates/shared/scripts → src/service-runtime}/authctl.ts +3 -3
- package/{templates/shared/scripts → src/service-runtime}/cloudrun/cleanup.ts +1 -1
- package/{templates/shared/scripts → src/service-runtime}/cloudrun/cli.ts +1 -1
- package/src/service-runtime/cloudrun/config.ts +55 -0
- package/src/service-runtime/runtime.ts +8 -0
- package/{templates/targets/workers/scripts → src/service-runtime}/workers/cli.ts +7 -6
- package/src/service.test.ts +0 -2
- package/src/service.ts +13 -19
- package/templates/shared/README.md +1 -1
- package/templates/shared/service.config.ts +31 -0
- package/templates/targets/workers/Makefile +1 -1
- package/templates/targets/workers/package.json +8 -11
- package/templates/variants/bun-connectrpc/Makefile +1 -1
- package/templates/variants/bun-connectrpc/package.json +7 -10
- package/templates/variants/bun-hono/Makefile +1 -1
- package/templates/variants/bun-hono/package.json +7 -10
- package/templates/variants/go-chi/Makefile +1 -1
- package/templates/variants/go-chi/go.mod +30 -1
- package/templates/variants/go-chi/package.json +7 -10
- package/templates/variants/go-connectrpc/Makefile +1 -1
- package/templates/variants/go-connectrpc/go.mod +30 -2
- package/templates/variants/go-connectrpc/package.json +7 -10
- package/templates/shared/scripts/cloudrun/config.ts +0 -62
- /package/{templates/shared/scripts → src/service-runtime}/cloudrun/bootstrap.ts +0 -0
- /package/{templates/shared/scripts → src/service-runtime}/cloudrun/deploy.ts +0 -0
- /package/{templates/shared/scripts → src/service-runtime}/cloudrun/lib.ts +0 -0
- /package/{templates/shared/scripts → src/service-runtime}/cloudrun/neon.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-svc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "Local microservice bootstrap CLI for Cloud Run and Workers services with Neon-backed data.",
|
|
5
5
|
"module": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
],
|
|
44
44
|
"packageManager": "bun@1.3.2",
|
|
45
45
|
"devDependencies": {
|
|
46
|
+
"@types/pg": "^8.16.0",
|
|
46
47
|
"@types/bun": "latest"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@clack/prompts": "^1.4.0",
|
|
53
54
|
"@neondatabase/api-client": "^2.7.1",
|
|
55
|
+
"pg": "^8.16.3",
|
|
54
56
|
"picocolors": "^1.1.1"
|
|
55
57
|
}
|
|
56
58
|
}
|
|
@@ -4,23 +4,23 @@ import { buildDeploymentVerificationCommands, buildPostScaffoldCommands } from "
|
|
|
4
4
|
describe("buildPostScaffoldCommands", () => {
|
|
5
5
|
test("runs create and deploy for HTTP services", () => {
|
|
6
6
|
expect(buildPostScaffoldCommands({ framework: "hono" })).toEqual([
|
|
7
|
-
{ command: "
|
|
8
|
-
{ command: "
|
|
7
|
+
{ command: "service", args: ["create"] },
|
|
8
|
+
{ command: "service", args: ["deploy"] },
|
|
9
9
|
]);
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
test("builds SDK artifacts before create and deploy for ConnectRPC services", () => {
|
|
13
13
|
expect(buildPostScaffoldCommands({ framework: "connectrpc" })).toEqual([
|
|
14
|
-
{ command: "
|
|
15
|
-
{ command: "
|
|
16
|
-
{ command: "
|
|
14
|
+
{ command: "service", args: ["sdk", "build"] },
|
|
15
|
+
{ command: "service", args: ["create"] },
|
|
16
|
+
{ command: "service", args: ["deploy"] },
|
|
17
17
|
]);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
test("uses the workers service CLI for workers services", () => {
|
|
21
21
|
expect(buildPostScaffoldCommands({ target: "workers", framework: "hono" })).toEqual([
|
|
22
|
-
{ command: "
|
|
23
|
-
{ command: "
|
|
22
|
+
{ command: "service", args: ["create"] },
|
|
23
|
+
{ command: "service", args: ["deploy"] },
|
|
24
24
|
]);
|
|
25
25
|
});
|
|
26
26
|
});
|
|
@@ -34,7 +34,7 @@ describe("buildDeploymentVerificationCommands", () => {
|
|
|
34
34
|
command: "sh",
|
|
35
35
|
args: [
|
|
36
36
|
"-c",
|
|
37
|
-
'TOKEN="$(
|
|
37
|
+
'TOKEN="$(service auth token)" && curl --fail --show-error --silent -H "Authorization: Bearer $TOKEN" "https://api.launch.anmho.com/v1/admin/waitlist?limit=1"',
|
|
38
38
|
],
|
|
39
39
|
},
|
|
40
40
|
]);
|
|
@@ -64,7 +64,7 @@ describe("buildDeploymentVerificationCommands", () => {
|
|
|
64
64
|
command: "sh",
|
|
65
65
|
args: [
|
|
66
66
|
"-c",
|
|
67
|
-
'TOKEN="$(
|
|
67
|
+
'TOKEN="$(service auth token)" && grpcurl -H "Authorization: Bearer $TOKEN" -d \'{"limit":1}\' -proto protos/waitlist/v1/waitlist.proto "api.launch.anmho.com:443" waitlist.v1.WaitlistService/ListWaitlistEntries',
|
|
68
68
|
],
|
|
69
69
|
});
|
|
70
70
|
});
|
|
@@ -81,7 +81,7 @@ describe("buildDeploymentVerificationCommands", () => {
|
|
|
81
81
|
command: "sh",
|
|
82
82
|
args: [
|
|
83
83
|
"-c",
|
|
84
|
-
'TOKEN="$(
|
|
84
|
+
'TOKEN="$(service auth token)" && curl --fail --show-error --silent -H "Authorization: Bearer $TOKEN" "https://api.launch.anmho.com/v1/admin/waitlist?limit=1"',
|
|
85
85
|
],
|
|
86
86
|
});
|
|
87
87
|
});
|
package/src/post-scaffold.ts
CHANGED
|
@@ -59,7 +59,7 @@ export function buildDeploymentVerificationCommands(
|
|
|
59
59
|
Partial<Pick<ScaffoldConfig, "target" | "serviceName" | "gcpProject" | "region">>
|
|
60
60
|
): PostScaffoldCommand[] {
|
|
61
61
|
const origin = verificationOrigin(config);
|
|
62
|
-
const tokenCommand =
|
|
62
|
+
const tokenCommand = 'TOKEN="$(service auth token)"';
|
|
63
63
|
return [
|
|
64
64
|
shellVerificationCommand(`curl --fail --show-error --silent "${origin}/"`),
|
|
65
65
|
shellVerificationCommand(`curl --fail --show-error --silent "${origin}/readyz"`),
|
|
@@ -148,18 +148,13 @@ function verificationHost(
|
|
|
148
148
|
export function buildPostScaffoldCommands(
|
|
149
149
|
config: Pick<ScaffoldConfig, "framework"> & Partial<Pick<ScaffoldConfig, "target">>
|
|
150
150
|
): PostScaffoldCommand[] {
|
|
151
|
-
const serviceCli = serviceCliPath(config);
|
|
152
151
|
return [
|
|
153
|
-
...(config.target !== "workers" && config.framework === "connectrpc" ? [{ command: "
|
|
154
|
-
{ command: "
|
|
155
|
-
{ command: "
|
|
152
|
+
...(config.target !== "workers" && config.framework === "connectrpc" ? [{ command: "service", args: ["sdk", "build"] }] : []),
|
|
153
|
+
{ command: "service", args: ["create"] },
|
|
154
|
+
{ command: "service", args: ["deploy"] },
|
|
156
155
|
];
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
function serviceCliPath(config: Partial<Pick<ScaffoldConfig, "target">>) {
|
|
160
|
-
return config.target === "workers" ? "./scripts/workers/cli.ts" : "./scripts/cloudrun/cli.ts";
|
|
161
|
-
}
|
|
162
|
-
|
|
163
158
|
function installProjectDependencies(cwd: string) {
|
|
164
159
|
requireCommand("bun");
|
|
165
160
|
run("bun", ["install"], { cwd });
|
package/src/scaffold.test.ts
CHANGED
|
@@ -54,63 +54,31 @@ test("scaffolds all runtime/framework variants with shared cloudrun config", asy
|
|
|
54
54
|
})
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
-
const configScript = await Bun.file(join(generatedRoot, "scripts", "cloudrun", "config.ts")).text();
|
|
58
57
|
const serviceConfig = await Bun.file(join(generatedRoot, "service.config.ts")).text();
|
|
59
58
|
expect(serviceConfig).toContain('service_id: "dns-api"');
|
|
60
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}"`);
|
|
61
65
|
expect(serviceConfig).toContain('module: "buf.build/anmho/dns-api"');
|
|
62
66
|
expect(serviceConfig).toContain('cloudflare_vault_path: "prod/providers/cloudflare"');
|
|
63
67
|
expect(serviceConfig).toContain('issuer: "https://auth.anmho.com/api/auth"');
|
|
64
68
|
expect(serviceConfig).toContain('audience: "api://dns-api"');
|
|
65
69
|
expect(serviceConfig).toContain('vault_path_prefix: "prod/apps/dns-api/server/oauth-clients"');
|
|
66
70
|
expect(serviceConfig).toContain('api_key_secret_name: "dns-api-temporal-api-key"');
|
|
67
|
-
expect(
|
|
68
|
-
expect(
|
|
69
|
-
expect(
|
|
70
|
-
expect(
|
|
71
|
-
expect(
|
|
72
|
-
expect(
|
|
73
|
-
expect(
|
|
74
|
-
expect(
|
|
75
|
-
expect(
|
|
76
|
-
expect(
|
|
77
|
-
expect(configScript).toContain('apiKeySecretName: "dns-api-temporal-api-key"');
|
|
78
|
-
expect(configScript).toContain('projectId: ""');
|
|
79
|
-
expect(configScript).toContain('baseBranchId: ""');
|
|
80
|
-
expect(configScript).toContain('baseBranchName: "main"');
|
|
81
|
-
expect(configScript).toContain('previewBranchPrefix: "dns-api-pr"');
|
|
82
|
-
expect(configScript).toContain('hostname: "api.dns-api.anmho.com"');
|
|
83
|
-
expect(configScript).toContain('cloudflareVaultPath: "prod/providers/cloudflare"');
|
|
84
|
-
expect(configScript).not.toContain("github:");
|
|
85
|
-
expect(configScript).not.toContain("attachmentBucket");
|
|
86
|
-
|
|
87
|
-
const deployScript = await Bun.file(join(generatedRoot, "scripts", "cloudrun", "lib.ts")).text();
|
|
88
|
-
expect(deployScript).toContain('--billing-project", config.project.quotaProjectId');
|
|
89
|
-
expect(deployScript).toContain('projectMode === "use_existing"');
|
|
90
|
-
expect(deployScript).toContain("serviceDomain");
|
|
91
|
-
expect(deployScript).toContain("ensureProductionDomainMapping");
|
|
92
|
-
expect(deployScript).toContain("ensureCloudflareDnsRecord");
|
|
93
|
-
expect(deployScript).toContain("gcloudWithRetry");
|
|
94
|
-
expect(deployScript).toContain("CLOUDFLARE_API_TOKEN");
|
|
95
|
-
expect(deployScript).toContain('"domain-mappings",');
|
|
96
|
-
expect(deployScript).toContain('"--region",');
|
|
97
|
-
expect(deployScript).toContain("assertProductionDomainAvailable");
|
|
98
|
-
expect(deployScript).toContain("assertServiceNameAvailable");
|
|
99
|
-
expect(deployScript).not.toContain("ensureStorageBucket");
|
|
100
|
-
|
|
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
|
+
expect(serviceConfig).not.toContain("github:");
|
|
80
|
+
expect(serviceConfig).not.toContain("attachmentBucket");
|
|
101
81
|
expect(await Bun.file(join(generatedRoot, "scripts", "cloudrun", "integrations.ts")).exists()).toBeFalse();
|
|
102
|
-
const destroyScript = await Bun.file(join(generatedRoot, "scripts", "cloudrun", "cleanup.ts")).text();
|
|
103
|
-
expect(destroyScript).toContain("assertOwnedResource");
|
|
104
|
-
expect(destroyScript).toContain("Planning resources to destroy");
|
|
105
|
-
expect(destroyScript).toContain("Resources selected for destroy");
|
|
106
|
-
expect(destroyScript).toContain("Destroy cannot continue until resource discovery succeeds");
|
|
107
|
-
expect(destroyScript).toContain("deleteAuthResourceServer");
|
|
108
|
-
expect(destroyScript).toContain("deleteGrafanaResources");
|
|
109
|
-
expect(destroyScript).toContain('gcx", ["resources", "delete"');
|
|
110
|
-
expect(destroyScript).toContain("config.temporal.apiKeySecretName");
|
|
111
|
-
const neonScript = await Bun.file(join(generatedRoot, "scripts", "cloudrun", "neon.ts")).text();
|
|
112
|
-
expect(neonScript).toContain("assertDatabaseOwned");
|
|
113
|
-
expect(neonScript).toContain("assertDisposableBranchName");
|
|
114
82
|
const seedScript = await Bun.file(join(generatedRoot, "scripts", "seed.ts")).text();
|
|
115
83
|
expect(seedScript).toContain("SEED_PROD=true");
|
|
116
84
|
expect(seedScript).toContain("waitlist_entries");
|
|
@@ -176,10 +144,11 @@ test("scaffolds all runtime/framework variants with shared cloudrun config", asy
|
|
|
176
144
|
const dockerfile = await Bun.file(join(generatedRoot, "Dockerfile")).text();
|
|
177
145
|
expect(dockerfile).toContain("COPY go.mod go.sum ./");
|
|
178
146
|
expect(packageJson).toContain('"dev": "make dev"');
|
|
179
|
-
expect(packageJson).toContain('"
|
|
180
|
-
expect(packageJson).toContain('"
|
|
181
|
-
expect(packageJson).toContain('"
|
|
182
|
-
expect(packageJson).toContain('"
|
|
147
|
+
expect(packageJson).toContain('"service": "service"');
|
|
148
|
+
expect(packageJson).toContain('"migrate": "service migrate"');
|
|
149
|
+
expect(packageJson).toContain('"create": "service create"');
|
|
150
|
+
expect(packageJson).toContain('"deploy": "service deploy"');
|
|
151
|
+
expect(packageJson).toContain('"destroy": "service destroy"');
|
|
183
152
|
|
|
184
153
|
const mainGo = await Bun.file(join(generatedRoot, "cmd", "server", "main.go")).text();
|
|
185
154
|
expect(mainGo).toContain("github.com/anmho/dns-api");
|
|
@@ -215,45 +184,26 @@ test("scaffolds all runtime/framework variants with shared cloudrun config", asy
|
|
|
215
184
|
const packageJson = await Bun.file(join(generatedRoot, "package.json")).text();
|
|
216
185
|
expect(packageJson).toContain('"@anmho/authctl": "0.1.1"');
|
|
217
186
|
expect(packageJson).toContain("@temporalio/worker");
|
|
218
|
-
expect(packageJson).toContain('"service": "./scripts/cloudrun/cli.ts"');
|
|
219
187
|
expect(packageJson).toContain('"dev": "bun run ./scripts/dev.ts bun run ./src/index.ts"');
|
|
220
188
|
expect(packageJson).toContain('"gen": "bun run ./scripts/codegen.ts"');
|
|
221
|
-
expect(packageJson).toContain('"
|
|
222
|
-
expect(packageJson).toContain('"
|
|
223
|
-
expect(packageJson).toContain('"
|
|
224
|
-
expect(packageJson).toContain('"
|
|
225
|
-
expect(packageJson).toContain('"
|
|
226
|
-
|
|
227
|
-
expect(
|
|
228
|
-
expect(
|
|
229
|
-
expect(
|
|
230
|
-
|
|
231
|
-
expect(
|
|
232
|
-
expect(
|
|
233
|
-
expect(
|
|
234
|
-
const cloudrunLib = await Bun.file(join(generatedRoot, "scripts", "cloudrun", "lib.ts")).text();
|
|
235
|
-
expect(cloudrunLib).toContain("resolveTemporalRuntimeConfig");
|
|
236
|
-
expect(cloudrunLib).toContain("TEMPORAL_API_KEY_ENV");
|
|
237
|
-
expect(cloudrunLib).toContain("value === undefined");
|
|
238
|
-
|
|
239
|
-
const authctlScript = await Bun.file(join(generatedRoot, "scripts", "authctl.ts")).text();
|
|
240
|
-
expect(authctlScript).toContain("authctl");
|
|
241
|
-
expect(authctlScript).toContain("resource-servers");
|
|
242
|
-
expect(authctlScript).toContain("clients");
|
|
243
|
-
expect(authctlScript).toContain("defaultClientTargetArgs");
|
|
244
|
-
expect(authctlScript).toContain("ensureAuthClient");
|
|
245
|
-
expect(authctlScript).toContain("mintAuthToken");
|
|
246
|
-
expect(authctlScript).toContain("clientVaultPath");
|
|
247
|
-
expect(authctlScript).toContain("deleteAuthResourceServer");
|
|
248
|
-
expect(authctlScript).toContain("readAuthctlAccessVaultField");
|
|
249
|
-
expect(authctlScript).toContain("prod/apps/auth/authctl/cloudflare-access");
|
|
250
|
-
expect(authctlScript).toContain('existsSync("./node_modules/.bin/authctl") ? "./node_modules/.bin/authctl" : Bun.which("authctl")');
|
|
251
|
-
expect(authctlScript).not.toContain('defaultAuthResourceServerArgs(), "--yes", "--json"');
|
|
189
|
+
expect(packageJson).toContain('"service": "service"');
|
|
190
|
+
expect(packageJson).toContain('"migrate": "service migrate"');
|
|
191
|
+
expect(packageJson).toContain('"create": "service create"');
|
|
192
|
+
expect(packageJson).toContain('"deploy": "service deploy"');
|
|
193
|
+
expect(packageJson).toContain('"dashboards": "service dashboards"');
|
|
194
|
+
expect(packageJson).toContain('"auth": "service auth"');
|
|
195
|
+
expect(packageJson).toContain('"destroy": "service destroy"');
|
|
196
|
+
expect(await Bun.file(join(generatedRoot, "scripts", "cloudrun", "cli.ts")).exists()).toBeFalse();
|
|
197
|
+
expect(await Bun.file(join(generatedRoot, "scripts", "authctl.ts")).exists()).toBeFalse();
|
|
198
|
+
const serviceConfig = await Bun.file(join(generatedRoot, "service.config.ts")).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"');
|
|
252
202
|
const authScript = await Bun.file(join(generatedRoot, "src", "auth.ts")).text();
|
|
253
203
|
expect(authScript).toContain('"Ed25519"');
|
|
254
204
|
|
|
255
205
|
const makefile = await Bun.file(join(generatedRoot, "Makefile")).text();
|
|
256
|
-
expect(makefile).toContain("
|
|
206
|
+
expect(makefile).toContain("SERVICE := service");
|
|
257
207
|
expect(makefile).toContain("dashboards:");
|
|
258
208
|
expect(makefile).toContain("auth:");
|
|
259
209
|
expect(makefile).toContain("bun run dev");
|
|
@@ -350,9 +300,9 @@ test("scaffolds the workers target with wrangler lifecycle commands", async () =
|
|
|
350
300
|
|
|
351
301
|
const packageJson = await Bun.file(join(generatedRoot, "package.json")).text();
|
|
352
302
|
expect(packageJson).toContain('"@anmho/authctl": "0.1.1"');
|
|
353
|
-
expect(packageJson).toContain('"service": "./scripts/workers/cli.ts"');
|
|
354
303
|
expect(packageJson).toContain('"dev": "wrangler dev"');
|
|
355
|
-
expect(packageJson).toContain('"
|
|
304
|
+
expect(packageJson).toContain('"service": "service"');
|
|
305
|
+
expect(packageJson).toContain('"auth": "service auth"');
|
|
356
306
|
expect(packageJson).toContain('"wrangler"');
|
|
357
307
|
expect(packageJson).toContain('"pg"');
|
|
358
308
|
|
|
@@ -374,28 +324,19 @@ test("scaffolds the workers target with wrangler lifecycle commands", async () =
|
|
|
374
324
|
expect(readme).toContain("Cloudflare Workers");
|
|
375
325
|
expect(readme).toContain("Hyperdrive binding for Neon-backed Postgres persistence");
|
|
376
326
|
expect(readme).not.toContain("Cloud Run");
|
|
377
|
-
const
|
|
378
|
-
expect(
|
|
379
|
-
expect(
|
|
380
|
-
expect(
|
|
381
|
-
expect(workerCli).toContain("ensureAuthClient");
|
|
382
|
-
expect(workerCli).toContain("auth token");
|
|
383
|
-
expect(workerCli).toContain("Workers database schema applied");
|
|
384
|
-
expect(workerCli).toContain("create table if not exists waitlist_entries");
|
|
385
|
-
expect(workerCli).toContain("DATABASE_URL or NEON_API_KEY is required to provision the Hyperdrive binding");
|
|
386
|
-
expect(workerCli).toContain("createProjectBranchDatabase");
|
|
387
|
-
expect(workerCli).toContain("deleteNeonDatabase");
|
|
388
|
-
expect(workerCli).toContain("deleteGrafanaResources");
|
|
389
|
-
expect(workerCli).toContain("hyperdrive\", \"delete");
|
|
327
|
+
const serviceConfig = await Bun.file(join(generatedRoot, "service.config.ts")).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"');
|
|
390
331
|
const makefile = await Bun.file(join(generatedRoot, "Makefile")).text();
|
|
391
332
|
expect(makefile).toContain('no generated code for workers');
|
|
392
333
|
expect(makefile).toContain("auth:");
|
|
393
334
|
expect(makefile).not.toContain("scripts/codegen.ts");
|
|
394
335
|
|
|
395
|
-
expect(await Bun.file(join(generatedRoot, "scripts", "authctl.ts")).exists()).
|
|
336
|
+
expect(await Bun.file(join(generatedRoot, "scripts", "authctl.ts")).exists()).toBeFalse();
|
|
396
337
|
expect(await Bun.file(join(generatedRoot, "src", "auth.ts")).exists()).toBeTrue();
|
|
397
338
|
expect(await Bun.file(join(generatedRoot, "src", "storage.ts")).exists()).toBeTrue();
|
|
398
|
-
expect(await Bun.file(join(generatedRoot, "scripts", "workers", "cli.ts")).exists()).
|
|
339
|
+
expect(await Bun.file(join(generatedRoot, "scripts", "workers", "cli.ts")).exists()).toBeFalse();
|
|
399
340
|
expect(await Bun.file(join(generatedRoot, "scripts", "cloudrun", "cli.ts")).exists()).toBeFalse();
|
|
400
341
|
expect(await Bun.file(join(generatedRoot, "scripts", "dev.ts")).exists()).toBeFalse();
|
|
401
342
|
expect(await Bun.file(join(generatedRoot, "scripts", "ensure-local-db.ts")).exists()).toBeFalse();
|
package/src/scaffold.ts
CHANGED
|
@@ -77,6 +77,14 @@ export async function scaffoldProject(config: ScaffoldConfig) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
function shouldSkipForTarget(target: DeployTarget, templateKind: "shared" | "variant" | "target", relativePath: string) {
|
|
80
|
+
if (
|
|
81
|
+
relativePath === "scripts/authctl.ts" ||
|
|
82
|
+
relativePath.startsWith("scripts/cloudrun/") ||
|
|
83
|
+
relativePath.startsWith("scripts/workers/")
|
|
84
|
+
) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
80
88
|
if (target === "workers") {
|
|
81
89
|
if (templateKind === "target") {
|
|
82
90
|
return false;
|
|
@@ -94,8 +102,7 @@ function shouldSkipForTarget(target: DeployTarget, templateKind: "shared" | "var
|
|
|
94
102
|
relativePath === "scripts/local-docker.ts" ||
|
|
95
103
|
relativePath === "scripts/local-env.ts" ||
|
|
96
104
|
relativePath === "scripts/seed.ts" ||
|
|
97
|
-
relativePath === "scripts/wait-for-db.ts"
|
|
98
|
-
relativePath.startsWith("scripts/cloudrun/")
|
|
105
|
+
relativePath === "scripts/wait-for-db.ts"
|
|
99
106
|
);
|
|
100
107
|
}
|
|
101
108
|
|
|
@@ -110,7 +117,7 @@ function shouldSkipForTarget(target: DeployTarget, templateKind: "shared" | "var
|
|
|
110
117
|
);
|
|
111
118
|
}
|
|
112
119
|
|
|
113
|
-
return relativePath
|
|
120
|
+
return relativePath === "wrangler.toml";
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
async function ensureTargetDirectory(targetDir: string) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import serviceConfig from "../service.config";
|
|
2
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { serviceConfig } from "./runtime";
|
|
3
3
|
|
|
4
4
|
type CommandResult = {
|
|
5
5
|
success: boolean;
|
|
@@ -47,7 +47,7 @@ export function defaultAuthResourceServerArgs() {
|
|
|
47
47
|
auth.resource_server.audience,
|
|
48
48
|
"--stage",
|
|
49
49
|
serviceConfig.stage_default,
|
|
50
|
-
...auth.resource_server.default_scopes.flatMap((scope) => ["--scope", scope]),
|
|
50
|
+
...(auth.resource_server.default_scopes as string[]).flatMap((scope: string) => ["--scope", scope]),
|
|
51
51
|
];
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -244,7 +244,7 @@ function defaultClientTargetArgs(rest: string[]) {
|
|
|
244
244
|
const hasScope = hasFlag(rest, "--scope");
|
|
245
245
|
return [
|
|
246
246
|
...(hasResourceServer ? [] : ["--resource-server", serviceConfig.auth.resource_server.id]),
|
|
247
|
-
...(hasScope ? [] : serviceConfig.auth.resource_server.default_scopes.flatMap((scope) => ["--scope", scope])),
|
|
247
|
+
...(hasScope ? [] : (serviceConfig.auth.resource_server.default_scopes as string[]).flatMap((scope: string) => ["--scope", scope])),
|
|
248
248
|
];
|
|
249
249
|
}
|
|
250
250
|
|
|
@@ -151,7 +151,7 @@ function planProductionDomainMapping(plan: DestroyPlan) {
|
|
|
151
151
|
return;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
const routeName = mapping.spec?.routeName;
|
|
154
|
+
const routeName = mapping.spec?.routeName ?? "";
|
|
155
155
|
if (routeName !== config.serviceName) {
|
|
156
156
|
plan.blockers.push(`${config.domain.hostname} maps to ${routeName || "an unknown service"}; refusing to delete ambiguous DNS mapping`);
|
|
157
157
|
return;
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
serviceOrigin,
|
|
24
24
|
} from "./lib";
|
|
25
25
|
|
|
26
|
-
async function main(argv = Bun.argv.slice(2)) {
|
|
26
|
+
export async function main(argv = Bun.argv.slice(2)) {
|
|
27
27
|
const [command, ...rest] = argv;
|
|
28
28
|
|
|
29
29
|
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { serviceConfig } from "../runtime";
|
|
2
|
+
|
|
3
|
+
const cloudrun = serviceConfig.cloudrun;
|
|
4
|
+
const dns = serviceConfig.dns;
|
|
5
|
+
const neon = serviceConfig.neon;
|
|
6
|
+
|
|
7
|
+
export const config = {
|
|
8
|
+
serviceName: serviceConfig.service_id,
|
|
9
|
+
profile: serviceConfig.profile,
|
|
10
|
+
example: serviceConfig.example,
|
|
11
|
+
runtime: serviceConfig.runtime,
|
|
12
|
+
framework: serviceConfig.framework,
|
|
13
|
+
region: cloudrun.region,
|
|
14
|
+
artifactRepository: cloudrun.artifact_repository,
|
|
15
|
+
runtimeServiceAccount: cloudrun.service_account,
|
|
16
|
+
project: {
|
|
17
|
+
mode: cloudrun.project_mode,
|
|
18
|
+
id: cloudrun.project_id,
|
|
19
|
+
name: cloudrun.project_name,
|
|
20
|
+
createIfMissing: cloudrun.create_if_missing,
|
|
21
|
+
billingAccount: cloudrun.billing_account,
|
|
22
|
+
quotaProjectId: cloudrun.quota_project_id,
|
|
23
|
+
},
|
|
24
|
+
domain: {
|
|
25
|
+
hostname: dns.hostname,
|
|
26
|
+
baseDomain: dns.base_domain,
|
|
27
|
+
cloudflareApiBaseUrl: dns.cloudflare_api_base_url,
|
|
28
|
+
cloudflareVaultPath: dns.cloudflare_vault_path,
|
|
29
|
+
cloudflareVaultField: dns.cloudflare_vault_field,
|
|
30
|
+
},
|
|
31
|
+
auth: {
|
|
32
|
+
issuer: serviceConfig.auth.issuer,
|
|
33
|
+
audience: serviceConfig.auth.resource_server.audience,
|
|
34
|
+
jwksUrl: serviceConfig.auth.jwks_url,
|
|
35
|
+
},
|
|
36
|
+
temporal: {
|
|
37
|
+
enabled: serviceConfig.temporal.enabled,
|
|
38
|
+
address: serviceConfig.temporal.address,
|
|
39
|
+
namespace: serviceConfig.temporal.namespace,
|
|
40
|
+
taskQueue: serviceConfig.temporal.task_queue,
|
|
41
|
+
apiKeySecretName: serviceConfig.temporal.api_key_secret_name,
|
|
42
|
+
},
|
|
43
|
+
neon: {
|
|
44
|
+
projectId: neon.project_id,
|
|
45
|
+
baseBranchId: neon.base_branch_id,
|
|
46
|
+
baseBranchName: neon.base_branch_name,
|
|
47
|
+
databaseName: neon.database_name,
|
|
48
|
+
roleName: neon.role_name,
|
|
49
|
+
previewBranchPrefix: neon.preview_branch_prefix,
|
|
50
|
+
personalBranchPrefix: neon.personal_branch_prefix,
|
|
51
|
+
},
|
|
52
|
+
requiredApis: cloudrun.required_apis,
|
|
53
|
+
} as const;
|
|
54
|
+
|
|
55
|
+
export type DeployEnvironment = "main" | "preview" | "personal";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
|
|
4
|
+
export const serviceRoot = process.env.CREATE_SVC_SERVICE_ROOT?.trim() || process.cwd();
|
|
5
|
+
|
|
6
|
+
export const serviceConfig = (
|
|
7
|
+
await import(pathToFileURL(join(serviceRoot, "service.config.ts")).href)
|
|
8
|
+
).default;
|
|
@@ -4,17 +4,18 @@ import { confirm, intro, isCancel, log, outro } from "@clack/prompts";
|
|
|
4
4
|
import { createApiClient } from "@neondatabase/api-client";
|
|
5
5
|
import { Client } from "pg";
|
|
6
6
|
import { ensureAuthClient, ensureAuthResourceServer, runAuthCommand, runAuthDoctor } from "../authctl";
|
|
7
|
+
import { serviceConfig } from "../runtime";
|
|
7
8
|
|
|
8
9
|
const config = {
|
|
9
|
-
serviceName:
|
|
10
|
-
hostname:
|
|
11
|
-
neonDatabaseName:
|
|
12
|
-
neonRoleName:
|
|
10
|
+
serviceName: serviceConfig.service_id,
|
|
11
|
+
hostname: serviceConfig.dns.hostname,
|
|
12
|
+
neonDatabaseName: serviceConfig.neon.database_name,
|
|
13
|
+
neonRoleName: serviceConfig.neon.role_name,
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
type DoctorStatus = "pass" | "warn" | "fail";
|
|
16
17
|
|
|
17
|
-
async function main(argv = Bun.argv.slice(2)) {
|
|
18
|
+
export async function main(argv = Bun.argv.slice(2)) {
|
|
18
19
|
const [command, ...rest] = argv;
|
|
19
20
|
|
|
20
21
|
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
@@ -255,7 +256,7 @@ async function deleteNeonDatabase() {
|
|
|
255
256
|
|
|
256
257
|
const payload = await neon.getProjectBranchDatabase(projectId, branchId, config.neonDatabaseName);
|
|
257
258
|
const database = (payload.data as { database?: { name?: string; owner_name?: string } } | undefined)?.database;
|
|
258
|
-
if (database
|
|
259
|
+
if (!database || database.name !== config.neonDatabaseName || (database.owner_name && database.owner_name !== config.neonRoleName)) {
|
|
259
260
|
throw new Error(`Refusing to delete Neon database ${database?.name ?? config.neonDatabaseName}; ownership metadata does not match`);
|
|
260
261
|
}
|
|
261
262
|
|
package/src/service.test.ts
CHANGED
|
@@ -20,10 +20,8 @@ test("findGeneratedServiceRoot detects generated service context from nested dir
|
|
|
20
20
|
const root = await mkdtemp(join(tmpdir(), "create-svc-service-root-"));
|
|
21
21
|
const serviceRoot = join(root, "generated-api");
|
|
22
22
|
const nested = join(serviceRoot, "src", "waitlist");
|
|
23
|
-
await mkdir(join(serviceRoot, "scripts", "cloudrun"), { recursive: true });
|
|
24
23
|
await mkdir(nested, { recursive: true });
|
|
25
24
|
await writeFile(join(serviceRoot, "service.config.ts"), "export default {}");
|
|
26
|
-
await writeFile(join(serviceRoot, "scripts", "cloudrun", "cli.ts"), "");
|
|
27
25
|
|
|
28
26
|
expect(findGeneratedServiceRoot(nested)).toBe(serviceRoot);
|
|
29
27
|
expect(findGeneratedServiceRoot(root)).toBeUndefined();
|
package/src/service.ts
CHANGED
|
@@ -7,7 +7,7 @@ const SCAFFOLD_COMMANDS = new Set(["create", "new", "init"]);
|
|
|
7
7
|
export async function runServiceCommand(argv: string[], cwd = process.cwd()) {
|
|
8
8
|
const serviceRoot = findGeneratedServiceRoot(cwd);
|
|
9
9
|
if (serviceRoot) {
|
|
10
|
-
delegateToGeneratedService(serviceRoot, argv);
|
|
10
|
+
await delegateToGeneratedService(serviceRoot, argv);
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -41,29 +41,23 @@ export function findGeneratedServiceRoot(start: string): string | undefined {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function isGeneratedServiceRoot(path: string) {
|
|
44
|
-
return (
|
|
45
|
-
existsSync(join(path, "service.config.ts")) &&
|
|
46
|
-
(existsSync(join(path, "scripts", "cloudrun", "cli.ts")) || existsSync(join(path, "scripts", "workers", "cli.ts")))
|
|
47
|
-
);
|
|
44
|
+
return existsSync(join(path, "service.config.ts"));
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
function delegateToGeneratedService(serviceRoot: string, argv: string[]) {
|
|
47
|
+
async function delegateToGeneratedService(serviceRoot: string, argv: string[]) {
|
|
51
48
|
ensureGeneratedDependencies(serviceRoot);
|
|
49
|
+
process.chdir(serviceRoot);
|
|
50
|
+
process.env.CREATE_SVC_SERVICE_ROOT = serviceRoot;
|
|
52
51
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
env: process.env,
|
|
59
|
-
stdin: "inherit",
|
|
60
|
-
stdout: "inherit",
|
|
61
|
-
stderr: "inherit",
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
if (!result.success) {
|
|
65
|
-
process.exit(result.exitCode || 1);
|
|
52
|
+
const serviceConfig = (await import(`${serviceRoot}/service.config.ts`)).default;
|
|
53
|
+
if (serviceConfig.target === "workers") {
|
|
54
|
+
const { main } = await import("./service-runtime/workers/cli");
|
|
55
|
+
await main(argv);
|
|
56
|
+
return;
|
|
66
57
|
}
|
|
58
|
+
|
|
59
|
+
const { main } = await import("./service-runtime/cloudrun/cli");
|
|
60
|
+
await main(argv);
|
|
67
61
|
}
|
|
68
62
|
|
|
69
63
|
export function generatedDependenciesInstalled(serviceRoot: string) {
|
|
@@ -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
|
|
62
|
+
The generated service config lives in [service.config.ts](service.config.ts).
|
|
63
63
|
|
|
64
64
|
Create, deploy, and destroy use:
|
|
65
65
|
|
|
@@ -3,7 +3,13 @@ export default {
|
|
|
3
3
|
target: "{{TARGET}}",
|
|
4
4
|
runtime: "{{RUNTIME}}",
|
|
5
5
|
framework: "{{FRAMEWORK}}",
|
|
6
|
+
profile: "{{PROFILE}}",
|
|
6
7
|
stage_default: "prod",
|
|
8
|
+
example: {
|
|
9
|
+
kind: "{{EXAMPLE_KIND}}",
|
|
10
|
+
domain: "{{EXAMPLE_DOMAIN}}",
|
|
11
|
+
label: "{{EXAMPLE_LABEL}}",
|
|
12
|
+
},
|
|
7
13
|
dns: {
|
|
8
14
|
hostname: "{{API_HOSTNAME}}",
|
|
9
15
|
base_domain: "{{API_BASE_DOMAIN}}",
|
|
@@ -47,13 +53,38 @@ export default {
|
|
|
47
53
|
temporal_path: "prod/providers/temporal",
|
|
48
54
|
},
|
|
49
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
|
+
},
|
|
50
65
|
buf: {
|
|
51
66
|
module: "buf.build/anmho/{{SERVICE_ID}}",
|
|
52
67
|
},
|
|
53
68
|
cloudrun: {
|
|
54
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}}",
|
|
55
75
|
region: "{{REGION}}",
|
|
76
|
+
artifact_repository: "cloud-run",
|
|
56
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
|
+
],
|
|
57
88
|
},
|
|
58
89
|
workers: {
|
|
59
90
|
script_name: "{{SERVICE_ID}}",
|
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
"name": "{{SERVICE_NAME}}",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"bin": {
|
|
6
|
-
"service": "./scripts/workers/cli.ts"
|
|
7
|
-
},
|
|
8
5
|
"scripts": {
|
|
9
6
|
"dev": "wrangler dev",
|
|
10
|
-
"service": "
|
|
11
|
-
"migrate": "
|
|
12
|
-
"seed": "
|
|
7
|
+
"service": "service",
|
|
8
|
+
"migrate": "service migrate",
|
|
9
|
+
"seed": "service seed",
|
|
13
10
|
"lint": "tsc --noEmit",
|
|
14
11
|
"test": "bun test",
|
|
15
|
-
"create": "
|
|
16
|
-
"deploy": "
|
|
17
|
-
"dashboards": "
|
|
18
|
-
"auth": "
|
|
19
|
-
"destroy": "
|
|
12
|
+
"create": "service create",
|
|
13
|
+
"deploy": "service deploy",
|
|
14
|
+
"dashboards": "service dashboards",
|
|
15
|
+
"auth": "service auth",
|
|
16
|
+
"destroy": "service destroy"
|
|
20
17
|
},
|
|
21
18
|
"dependencies": {
|
|
22
19
|
"@anmho/authctl": "0.1.1",
|
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
"name": "{{SERVICE_NAME}}",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"bin": {
|
|
6
|
-
"service": "./scripts/cloudrun/cli.ts"
|
|
7
|
-
},
|
|
8
5
|
"scripts": {
|
|
9
6
|
"dev": "bun run ./scripts/dev.ts bun run ./src/index.ts",
|
|
10
|
-
"service": "
|
|
11
|
-
"migrate": "
|
|
7
|
+
"service": "service",
|
|
8
|
+
"migrate": "service migrate",
|
|
12
9
|
"gen": "bun run ./scripts/codegen.ts",
|
|
13
10
|
"lint": "tsc --noEmit",
|
|
14
11
|
"test": "bun test",
|
|
15
|
-
"create": "
|
|
16
|
-
"deploy": "
|
|
17
|
-
"dashboards": "
|
|
18
|
-
"auth": "
|
|
19
|
-
"destroy": "
|
|
12
|
+
"create": "service create",
|
|
13
|
+
"deploy": "service deploy",
|
|
14
|
+
"dashboards": "service dashboards",
|
|
15
|
+
"auth": "service auth",
|
|
16
|
+
"destroy": "service destroy"
|
|
20
17
|
},
|
|
21
18
|
"dependencies": {
|
|
22
19
|
"@anmho/authctl": "0.1.1",
|
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
"name": "{{SERVICE_NAME}}",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"bin": {
|
|
6
|
-
"service": "./scripts/cloudrun/cli.ts"
|
|
7
|
-
},
|
|
8
5
|
"scripts": {
|
|
9
6
|
"dev": "bun run ./scripts/dev.ts bun run ./src/index.ts",
|
|
10
|
-
"service": "
|
|
11
|
-
"migrate": "
|
|
7
|
+
"service": "service",
|
|
8
|
+
"migrate": "service migrate",
|
|
12
9
|
"gen": "bun run ./scripts/codegen.ts",
|
|
13
10
|
"lint": "tsc --noEmit",
|
|
14
11
|
"test": "bun test",
|
|
15
|
-
"create": "
|
|
16
|
-
"deploy": "
|
|
17
|
-
"dashboards": "
|
|
18
|
-
"auth": "
|
|
19
|
-
"destroy": "
|
|
12
|
+
"create": "service create",
|
|
13
|
+
"deploy": "service deploy",
|
|
14
|
+
"dashboards": "service dashboards",
|
|
15
|
+
"auth": "service auth",
|
|
16
|
+
"destroy": "service destroy"
|
|
20
17
|
},
|
|
21
18
|
"dependencies": {
|
|
22
19
|
"@anmho/authctl": "0.1.1",
|
|
@@ -7,5 +7,34 @@ require (
|
|
|
7
7
|
github.com/jackc/pgx/v5 v5.7.5
|
|
8
8
|
github.com/jmoiron/sqlx v1.4.0
|
|
9
9
|
go.temporal.io/sdk v1.43.0
|
|
10
|
-
golang.org/x/net v0.
|
|
10
|
+
golang.org/x/net v0.49.0
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
require (
|
|
14
|
+
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
15
|
+
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
|
|
16
|
+
github.com/gogo/protobuf v1.3.2 // indirect
|
|
17
|
+
github.com/golang/mock v1.6.0 // indirect
|
|
18
|
+
github.com/google/uuid v1.6.0 // indirect
|
|
19
|
+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect
|
|
20
|
+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
|
21
|
+
github.com/jackc/pgpassfile v1.0.0 // indirect
|
|
22
|
+
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
|
23
|
+
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
|
24
|
+
github.com/nexus-rpc/sdk-go v0.6.0 // indirect
|
|
25
|
+
github.com/pmezard/go-difflib v1.0.0 // indirect
|
|
26
|
+
github.com/robfig/cron v1.2.0 // indirect
|
|
27
|
+
github.com/stretchr/objx v0.5.2 // indirect
|
|
28
|
+
github.com/stretchr/testify v1.10.0 // indirect
|
|
29
|
+
go.temporal.io/api v1.62.11 // indirect
|
|
30
|
+
golang.org/x/crypto v0.47.0 // indirect
|
|
31
|
+
golang.org/x/sync v0.19.0 // indirect
|
|
32
|
+
golang.org/x/sys v0.40.0 // indirect
|
|
33
|
+
golang.org/x/text v0.33.0 // indirect
|
|
34
|
+
golang.org/x/time v0.3.0 // indirect
|
|
35
|
+
google.golang.org/genproto/googleapis/api v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
|
36
|
+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
|
37
|
+
google.golang.org/grpc v1.79.3 // indirect
|
|
38
|
+
google.golang.org/protobuf v1.36.11 // indirect
|
|
39
|
+
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
11
40
|
)
|
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
"name": "{{SERVICE_NAME}}",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"bin": {
|
|
6
|
-
"service": "./scripts/cloudrun/cli.ts"
|
|
7
|
-
},
|
|
8
5
|
"scripts": {
|
|
9
6
|
"dev": "make dev",
|
|
10
|
-
"service": "
|
|
11
|
-
"migrate": "
|
|
7
|
+
"service": "service",
|
|
8
|
+
"migrate": "service migrate",
|
|
12
9
|
"gen": "make gen",
|
|
13
10
|
"lint": "make lint",
|
|
14
11
|
"test": "make test",
|
|
15
|
-
"create": "
|
|
16
|
-
"deploy": "
|
|
17
|
-
"auth": "
|
|
18
|
-
"dashboards": "
|
|
19
|
-
"destroy": "
|
|
12
|
+
"create": "service create",
|
|
13
|
+
"deploy": "service deploy",
|
|
14
|
+
"auth": "service auth",
|
|
15
|
+
"dashboards": "service dashboards",
|
|
16
|
+
"destroy": "service destroy"
|
|
20
17
|
},
|
|
21
18
|
"dependencies": {
|
|
22
19
|
"@anmho/authctl": "0.1.1",
|
|
@@ -9,6 +9,34 @@ require (
|
|
|
9
9
|
github.com/jackc/pgx/v5 v5.7.5
|
|
10
10
|
github.com/jmoiron/sqlx v1.4.0
|
|
11
11
|
go.temporal.io/sdk v1.43.0
|
|
12
|
-
golang.org/x/net v0.
|
|
13
|
-
google.golang.org/protobuf v1.36.
|
|
12
|
+
golang.org/x/net v0.49.0
|
|
13
|
+
google.golang.org/protobuf v1.36.11
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
require (
|
|
17
|
+
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
18
|
+
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
|
|
19
|
+
github.com/gogo/protobuf v1.3.2 // indirect
|
|
20
|
+
github.com/golang/mock v1.6.0 // indirect
|
|
21
|
+
github.com/google/uuid v1.6.0 // indirect
|
|
22
|
+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect
|
|
23
|
+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
|
24
|
+
github.com/jackc/pgpassfile v1.0.0 // indirect
|
|
25
|
+
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
|
26
|
+
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
|
27
|
+
github.com/nexus-rpc/sdk-go v0.6.0 // indirect
|
|
28
|
+
github.com/pmezard/go-difflib v1.0.0 // indirect
|
|
29
|
+
github.com/robfig/cron v1.2.0 // indirect
|
|
30
|
+
github.com/stretchr/objx v0.5.2 // indirect
|
|
31
|
+
github.com/stretchr/testify v1.10.0 // indirect
|
|
32
|
+
go.temporal.io/api v1.62.11 // indirect
|
|
33
|
+
golang.org/x/crypto v0.47.0 // indirect
|
|
34
|
+
golang.org/x/sync v0.19.0 // indirect
|
|
35
|
+
golang.org/x/sys v0.40.0 // indirect
|
|
36
|
+
golang.org/x/text v0.33.0 // indirect
|
|
37
|
+
golang.org/x/time v0.3.0 // indirect
|
|
38
|
+
google.golang.org/genproto/googleapis/api v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
|
39
|
+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
|
40
|
+
google.golang.org/grpc v1.79.3 // indirect
|
|
41
|
+
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
14
42
|
)
|
|
@@ -2,21 +2,18 @@
|
|
|
2
2
|
"name": "{{SERVICE_NAME}}",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"bin": {
|
|
6
|
-
"service": "./scripts/cloudrun/cli.ts"
|
|
7
|
-
},
|
|
8
5
|
"scripts": {
|
|
9
6
|
"dev": "make dev",
|
|
10
|
-
"service": "
|
|
11
|
-
"migrate": "
|
|
7
|
+
"service": "service",
|
|
8
|
+
"migrate": "service migrate",
|
|
12
9
|
"gen": "make gen",
|
|
13
10
|
"lint": "make lint",
|
|
14
11
|
"test": "make test",
|
|
15
|
-
"create": "
|
|
16
|
-
"deploy": "
|
|
17
|
-
"auth": "
|
|
18
|
-
"dashboards": "
|
|
19
|
-
"destroy": "
|
|
12
|
+
"create": "service create",
|
|
13
|
+
"deploy": "service deploy",
|
|
14
|
+
"auth": "service auth",
|
|
15
|
+
"dashboards": "service dashboards",
|
|
16
|
+
"destroy": "service destroy"
|
|
20
17
|
},
|
|
21
18
|
"dependencies": {
|
|
22
19
|
"@anmho/authctl": "0.1.1",
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
export const config = {
|
|
2
|
-
serviceName: "{{SERVICE_NAME}}",
|
|
3
|
-
profile: "{{PROFILE}}",
|
|
4
|
-
example: {
|
|
5
|
-
kind: "{{EXAMPLE_KIND}}",
|
|
6
|
-
domain: "{{EXAMPLE_DOMAIN}}",
|
|
7
|
-
label: "{{EXAMPLE_LABEL}}",
|
|
8
|
-
},
|
|
9
|
-
runtime: "{{RUNTIME}}",
|
|
10
|
-
framework: "{{FRAMEWORK}}",
|
|
11
|
-
region: "{{REGION}}",
|
|
12
|
-
artifactRepository: "cloud-run",
|
|
13
|
-
runtimeServiceAccount: "{{RUNTIME_SERVICE_ACCOUNT}}",
|
|
14
|
-
project: {
|
|
15
|
-
mode: "{{GCP_PROJECT_MODE}}",
|
|
16
|
-
id: "{{PROJECT_ID}}",
|
|
17
|
-
name: "{{PROJECT_NAME}}",
|
|
18
|
-
createIfMissing: {{PROJECT_CREATE_IF_MISSING}},
|
|
19
|
-
billingAccount: "{{BILLING_ACCOUNT}}",
|
|
20
|
-
quotaProjectId: "{{QUOTA_PROJECT_ID}}",
|
|
21
|
-
},
|
|
22
|
-
domain: {
|
|
23
|
-
hostname: "{{API_HOSTNAME}}",
|
|
24
|
-
baseDomain: "{{API_BASE_DOMAIN}}",
|
|
25
|
-
cloudflareApiBaseUrl: "https://api.cloudflare.com/client/v4",
|
|
26
|
-
cloudflareVaultPath: "prod/providers/cloudflare",
|
|
27
|
-
cloudflareVaultField: "api_token",
|
|
28
|
-
},
|
|
29
|
-
auth: {
|
|
30
|
-
issuer: "https://auth.anmho.com/api/auth",
|
|
31
|
-
audience: "api://{{SERVICE_ID}}",
|
|
32
|
-
jwksUrl: "https://auth.anmho.com/api/auth/jwks",
|
|
33
|
-
},
|
|
34
|
-
temporal: {
|
|
35
|
-
enabled: false,
|
|
36
|
-
address: "localhost:7233",
|
|
37
|
-
namespace: "default",
|
|
38
|
-
taskQueue: "{{SERVICE_ID}}",
|
|
39
|
-
apiKeySecretName: "{{SERVICE_ID}}-temporal-api-key",
|
|
40
|
-
},
|
|
41
|
-
neon: {
|
|
42
|
-
projectId: "{{NEON_PROJECT_ID}}",
|
|
43
|
-
baseBranchId: "{{NEON_BASE_BRANCH_ID}}",
|
|
44
|
-
baseBranchName: "{{NEON_BASE_BRANCH_NAME}}",
|
|
45
|
-
databaseName: "{{NEON_DATABASE_NAME}}",
|
|
46
|
-
roleName: "{{NEON_ROLE_NAME}}",
|
|
47
|
-
previewBranchPrefix: "{{NEON_PREVIEW_BRANCH_PREFIX}}",
|
|
48
|
-
personalBranchPrefix: "{{NEON_PERSONAL_BRANCH_PREFIX}}",
|
|
49
|
-
},
|
|
50
|
-
requiredApis: [
|
|
51
|
-
"run.googleapis.com",
|
|
52
|
-
"cloudbuild.googleapis.com",
|
|
53
|
-
"artifactregistry.googleapis.com",
|
|
54
|
-
"iam.googleapis.com",
|
|
55
|
-
"iamcredentials.googleapis.com",
|
|
56
|
-
"secretmanager.googleapis.com",
|
|
57
|
-
"serviceusage.googleapis.com",
|
|
58
|
-
"sts.googleapis.com",
|
|
59
|
-
],
|
|
60
|
-
} as const;
|
|
61
|
-
|
|
62
|
-
export type DeployEnvironment = "main" | "preview" | "personal";
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|