create-svc 0.1.10 → 0.1.11

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.
Files changed (168) hide show
  1. package/README.md +46 -43
  2. package/bin/create-service.mjs +2 -0
  3. package/package.json +12 -9
  4. package/src/cli.test.ts +28 -10
  5. package/src/cli.ts +195 -30
  6. package/src/git-bootstrap.test.ts +40 -0
  7. package/src/git-bootstrap.ts +110 -0
  8. package/src/naming.test.ts +1 -0
  9. package/src/naming.ts +23 -0
  10. package/src/post-scaffold.test.ts +19 -0
  11. package/src/post-scaffold.ts +17 -4
  12. package/src/profiles.ts +2 -5
  13. package/src/scaffold.test.ts +231 -40
  14. package/src/scaffold.ts +84 -29
  15. package/src/vault.test.ts +61 -1
  16. package/src/vault.ts +77 -15
  17. package/templates/shared/.github/workflows/ci.yml +2 -1
  18. package/templates/shared/.github/workflows/deploy.yml +2 -0
  19. package/templates/shared/README.md +124 -47
  20. package/templates/shared/grafana/alerts.yaml +54 -0
  21. package/templates/shared/grafana/waitlist-dashboard.json +63 -0
  22. package/templates/shared/scripts/authctl.ts +231 -0
  23. package/templates/shared/scripts/cloudrun/bootstrap.ts +14 -5
  24. package/templates/shared/scripts/cloudrun/cleanup.ts +64 -4
  25. package/templates/shared/scripts/cloudrun/cli.ts +324 -7
  26. package/templates/shared/scripts/cloudrun/config.ts +11 -4
  27. package/templates/shared/scripts/cloudrun/deploy.ts +0 -4
  28. package/templates/shared/scripts/cloudrun/lib.ts +174 -41
  29. package/templates/shared/scripts/cloudrun/neon.ts +45 -0
  30. package/templates/shared/scripts/dev.ts +22 -0
  31. package/templates/shared/scripts/ensure-local-db.ts +3 -0
  32. package/templates/shared/scripts/local-docker.ts +63 -0
  33. package/templates/shared/scripts/local-env.ts +27 -0
  34. package/templates/shared/scripts/seed.ts +73 -0
  35. package/templates/shared/scripts/wait-for-db.ts +32 -0
  36. package/templates/shared/service.config.ts +59 -0
  37. package/templates/shared/service.yaml +24 -44
  38. package/templates/targets/workers/.github/workflows/ci.yml +19 -0
  39. package/templates/targets/workers/.github/workflows/deploy.yml +19 -0
  40. package/templates/targets/workers/Makefile +33 -0
  41. package/templates/targets/workers/README.md +75 -0
  42. package/templates/targets/workers/package.json +35 -0
  43. package/templates/targets/workers/scripts/workers/cli.ts +397 -0
  44. package/templates/targets/workers/src/auth.ts +178 -0
  45. package/templates/targets/workers/src/index.ts +198 -0
  46. package/templates/targets/workers/src/storage.ts +370 -0
  47. package/templates/targets/workers/test/app.test.ts +108 -0
  48. package/templates/targets/workers/tsconfig.json +11 -0
  49. package/templates/targets/workers/wrangler.toml +24 -0
  50. package/templates/variants/bun-connectrpc/Makefile +14 -8
  51. package/templates/variants/bun-connectrpc/gen/protos/waitlist/v1/waitlist_pb.ts +424 -0
  52. package/templates/variants/bun-connectrpc/migrations/0000_init.sql +12 -55
  53. package/templates/variants/bun-connectrpc/package.json +12 -5
  54. package/templates/variants/bun-connectrpc/protos/waitlist/v1/waitlist.proto +91 -0
  55. package/templates/variants/bun-connectrpc/scripts/codegen.ts +1 -1
  56. package/templates/variants/bun-connectrpc/scripts/migrate.ts +4 -1
  57. package/templates/variants/bun-connectrpc/src/auth.ts +200 -0
  58. package/templates/variants/bun-connectrpc/src/db/repository.ts +67 -420
  59. package/templates/variants/bun-connectrpc/src/db/schema.ts +15 -64
  60. package/templates/variants/bun-connectrpc/src/index.ts +76 -176
  61. package/templates/variants/bun-connectrpc/src/temporal/activities.ts +14 -0
  62. package/templates/variants/bun-connectrpc/src/temporal/worker.ts +38 -0
  63. package/templates/variants/bun-connectrpc/src/temporal/workflows.ts +10 -0
  64. package/templates/variants/bun-connectrpc/src/waitlist/service.ts +172 -0
  65. package/templates/variants/bun-connectrpc/src/waitlist/types.ts +45 -0
  66. package/templates/variants/bun-connectrpc/test/app.test.ts +4 -4
  67. package/templates/variants/bun-connectrpc/test/waitlist.integration.test.ts +71 -0
  68. package/templates/variants/bun-hono/Makefile +14 -8
  69. package/templates/variants/bun-hono/migrations/0000_init.sql +12 -55
  70. package/templates/variants/bun-hono/package.json +12 -5
  71. package/templates/variants/bun-hono/scripts/migrate.ts +4 -1
  72. package/templates/variants/bun-hono/src/auth.ts +181 -0
  73. package/templates/variants/bun-hono/src/db/repository.ts +68 -421
  74. package/templates/variants/bun-hono/src/db/schema.ts +15 -64
  75. package/templates/variants/bun-hono/src/index.ts +65 -180
  76. package/templates/variants/bun-hono/src/temporal/activities.ts +14 -0
  77. package/templates/variants/bun-hono/src/temporal/worker.ts +38 -0
  78. package/templates/variants/bun-hono/src/temporal/workflows.ts +10 -0
  79. package/templates/variants/bun-hono/src/waitlist/service.ts +166 -0
  80. package/templates/variants/bun-hono/src/waitlist/types.ts +50 -0
  81. package/templates/variants/bun-hono/test/app.test.ts +72 -41
  82. package/templates/variants/bun-hono/test/waitlist.integration.test.ts +102 -0
  83. package/templates/variants/go-chi/Makefile +27 -11
  84. package/templates/variants/go-chi/atlas.hcl +8 -0
  85. package/templates/variants/go-chi/cmd/server/main.go +21 -10
  86. package/templates/variants/go-chi/go.mod +1 -3
  87. package/templates/variants/go-chi/internal/app/service.go +202 -685
  88. package/templates/variants/go-chi/internal/auth/middleware.go +289 -0
  89. package/templates/variants/go-chi/internal/auth/middleware_test.go +38 -0
  90. package/templates/variants/go-chi/internal/config/config.go +27 -11
  91. package/templates/variants/go-chi/internal/httpapi/routes.go +78 -157
  92. package/templates/variants/go-chi/internal/httpapi/waitlist_integration_test.go +199 -0
  93. package/templates/variants/go-chi/internal/temporal/activities.go +27 -0
  94. package/templates/variants/go-chi/internal/temporal/worker.go +42 -0
  95. package/templates/variants/go-chi/internal/temporal/workflows.go +18 -0
  96. package/templates/variants/go-chi/migrations/0000_init.sql +12 -55
  97. package/templates/variants/go-chi/migrations/atlas.sum +2 -0
  98. package/templates/variants/go-chi/package.json +7 -1
  99. package/templates/variants/go-connectrpc/Makefile +26 -9
  100. package/templates/variants/go-connectrpc/atlas.hcl +8 -0
  101. package/templates/variants/go-connectrpc/buf.gen.yaml +2 -2
  102. package/templates/variants/go-connectrpc/cmd/server/main.go +23 -12
  103. package/templates/variants/go-connectrpc/gen/waitlist/v1/waitlist.pb.go +960 -0
  104. package/templates/variants/go-connectrpc/gen/waitlist/v1/waitlistv1connect/waitlist.connect.go +283 -0
  105. package/templates/variants/go-connectrpc/go.mod +1 -1
  106. package/templates/variants/go-connectrpc/internal/app/service.go +202 -685
  107. package/templates/variants/go-connectrpc/internal/auth/middleware.go +289 -0
  108. package/templates/variants/go-connectrpc/internal/auth/middleware_test.go +38 -0
  109. package/templates/variants/go-connectrpc/internal/config/config.go +27 -11
  110. package/templates/variants/go-connectrpc/internal/connectapi/handler.go +78 -201
  111. package/templates/variants/go-connectrpc/internal/connectapi/waitlist_integration_test.go +122 -0
  112. package/templates/variants/go-connectrpc/internal/httpapi/routes.go +147 -9
  113. package/templates/variants/go-connectrpc/internal/temporal/activities.go +27 -0
  114. package/templates/variants/go-connectrpc/internal/temporal/worker.go +42 -0
  115. package/templates/variants/go-connectrpc/internal/temporal/workflows.go +18 -0
  116. package/templates/variants/go-connectrpc/migrations/0000_init.sql +12 -55
  117. package/templates/variants/go-connectrpc/migrations/atlas.sum +2 -0
  118. package/templates/variants/go-connectrpc/package.json +7 -1
  119. package/templates/variants/go-connectrpc/protos/waitlist/v1/waitlist.proto +93 -0
  120. package/templates/root/.github/workflows/buf-publish.yml +0 -19
  121. package/templates/root/.github/workflows/ci.yml +0 -26
  122. package/templates/root/.github/workflows/deploy.yml +0 -22
  123. package/templates/root/Dockerfile +0 -23
  124. package/templates/root/README.md +0 -69
  125. package/templates/root/buf.gen.yaml +0 -10
  126. package/templates/root/buf.yaml +0 -9
  127. package/templates/root/cmd/server/main.go +0 -44
  128. package/templates/root/gen/dns/v1/dns.pb.go +0 -623
  129. package/templates/root/gen/dns/v1/dnsv1connect/dns.connect.go +0 -192
  130. package/templates/root/go.mod +0 -10
  131. package/templates/root/internal/app/service.go +0 -152
  132. package/templates/root/internal/app/token_source.go +0 -50
  133. package/templates/root/internal/cloudflare/client.go +0 -160
  134. package/templates/root/internal/config/config.go +0 -55
  135. package/templates/root/internal/connectapi/handler.go +0 -79
  136. package/templates/root/internal/httpapi/routes.go +0 -93
  137. package/templates/root/internal/vault/client.go +0 -148
  138. package/templates/root/package.json +0 -12
  139. package/templates/root/protos/dns/v1/dns.proto +0 -58
  140. package/templates/root/scripts/cloudrun/bootstrap.ts +0 -65
  141. package/templates/root/scripts/cloudrun/config.ts +0 -50
  142. package/templates/root/scripts/cloudrun/deploy.ts +0 -41
  143. package/templates/root/scripts/cloudrun/lib.ts +0 -244
  144. package/templates/root/service.yaml +0 -50
  145. package/templates/root/test/go.test.ts +0 -19
  146. package/templates/shared/scripts/cloudrun/integrations.ts +0 -111
  147. package/templates/variants/bun-connectrpc/gen/protos/chat/v1/chat_pb.ts +0 -1078
  148. package/templates/variants/bun-connectrpc/protos/chat/v1/chat.proto +0 -228
  149. package/templates/variants/bun-connectrpc/src/chat/service.ts +0 -384
  150. package/templates/variants/bun-connectrpc/src/chat/types.ts +0 -142
  151. package/templates/variants/bun-connectrpc/src/storage.ts +0 -72
  152. package/templates/variants/bun-connectrpc/src/webhooks.ts +0 -35
  153. package/templates/variants/bun-connectrpc/test/list-messages.integration.test.ts +0 -182
  154. package/templates/variants/bun-hono/src/chat/service.ts +0 -384
  155. package/templates/variants/bun-hono/src/chat/types.ts +0 -142
  156. package/templates/variants/bun-hono/src/storage.ts +0 -72
  157. package/templates/variants/bun-hono/src/webhooks.ts +0 -35
  158. package/templates/variants/bun-hono/test/list-messages.integration.test.ts +0 -256
  159. package/templates/variants/go-chi/buf.gen.yaml +0 -12
  160. package/templates/variants/go-chi/buf.yaml +0 -9
  161. package/templates/variants/go-chi/cmd/migrate/main.go +0 -101
  162. package/templates/variants/go-chi/internal/httpapi/list_messages_integration_test.go +0 -298
  163. package/templates/variants/go-chi/protos/chat/v1/chat.proto +0 -219
  164. package/templates/variants/go-connectrpc/cmd/migrate/main.go +0 -101
  165. package/templates/variants/go-connectrpc/gen/chat/v1/chat.pb.go +0 -2512
  166. package/templates/variants/go-connectrpc/gen/chat/v1/chatv1connect/chat.connect.go +0 -571
  167. package/templates/variants/go-connectrpc/internal/connectapi/list_messages_integration_test.go +0 -216
  168. package/templates/variants/go-connectrpc/protos/chat/v1/chat.proto +0 -232
@@ -1,17 +1,43 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
+ import { mkdir } from "node:fs/promises";
4
+ import { ensureAuthResourceServer, runAuthCommand, runAuthDoctor } from "../authctl";
3
5
  import { bootstrap } from "./bootstrap";
4
6
  import { cleanup } from "./cleanup";
5
7
  import { deploy } from "./deploy";
6
- import { runMain } from "./lib";
8
+ import { config } from "./config";
9
+ import {
10
+ accessSecretVersion,
11
+ assertProductionDomainAvailable,
12
+ assertServiceNameAvailable,
13
+ describeProductionDomainMapping,
14
+ formatError,
15
+ gcloud,
16
+ ensureProductionDomainMapping,
17
+ requireCommand,
18
+ requireGcloudAuth,
19
+ resolveDeploymentTarget,
20
+ run,
21
+ runMain,
22
+ runStep,
23
+ serviceOrigin,
24
+ } from "./lib";
7
25
 
8
26
  async function main(argv = Bun.argv.slice(2)) {
9
27
  const [command, ...rest] = argv;
10
28
 
11
- if (command === "bootstrap") {
12
- await runMain("Bootstrap", async () => {
29
+ if (command === "create") {
30
+ await runMain("Create", async () => {
31
+ assertServiceNameAvailable(config.serviceName);
32
+ assertProductionDomainAvailable(config.serviceName);
33
+ await runStep("Registering auth resource server", () => ensureAuthResourceServer());
13
34
  await bootstrap();
14
- return "Bootstrap finished";
35
+ const target = resolveDeploymentTarget("main");
36
+ const databaseUrl = await runStep("Reading production database URL", () => accessSecretVersion(target.databaseSecretName));
37
+ await runStep("Applying production migrations", () => runLanguageTask("migrate", { DATABASE_URL: databaseUrl }));
38
+ const origin = await deploy(["--ci"]);
39
+ await runOptionalBunScript("seed", { DATABASE_URL: databaseUrl });
40
+ return `Created ${origin}`;
15
41
  });
16
42
  return;
17
43
  }
@@ -21,12 +47,303 @@ async function main(argv = Bun.argv.slice(2)) {
21
47
  return;
22
48
  }
23
49
 
24
- if (command === "cleanup") {
25
- await runMain("Cleanup", () => cleanup(rest));
50
+ if (command === "migrate") {
51
+ await runMain("Migrate", () => runLanguageTask("migrate"));
26
52
  return;
27
53
  }
28
54
 
29
- throw new Error("Usage: svc-cloudrun <bootstrap|deploy|cleanup> [args]");
55
+ if (command === "seed") {
56
+ await runMain("Seed", () => runOptionalBunScript("seed"));
57
+ return;
58
+ }
59
+
60
+ if (command === "dashboards") {
61
+ await runMain("Dashboards", () => runDashboards());
62
+ return;
63
+ }
64
+
65
+ if (command === "dns") {
66
+ await runMain("DNS", () => repairDns());
67
+ return;
68
+ }
69
+
70
+ if (command === "doctor") {
71
+ await runMain("Doctor", () => runDoctor());
72
+ return;
73
+ }
74
+
75
+ if (command === "auth") {
76
+ await runMain("Auth", () => runAuthCommand(rest));
77
+ return;
78
+ }
79
+
80
+ if (command === "destroy") {
81
+ await runMain("Destroy", () => cleanup(rest));
82
+ return;
83
+ }
84
+
85
+ if (command === "sdk") {
86
+ await runMain("SDK", () => runSdk(rest));
87
+ return;
88
+ }
89
+
90
+ throw new Error("Usage: service <create|deploy|migrate|seed|dashboards|dns|doctor|destroy|auth|sdk> [args]");
91
+ }
92
+
93
+ function runLanguageTask(task: "migrate", env?: Record<string, string | undefined>) {
94
+ if (config.runtime === "bun") {
95
+ run("bun", ["run", `./scripts/${task}.ts`], { env });
96
+ return `${task} finished`;
97
+ }
98
+
99
+ if (task === "migrate") {
100
+ run("make", ["migrate"], { env });
101
+ return `${task} finished`;
102
+ }
103
+
104
+ throw new Error(`${task} is not available for ${config.runtime}`);
105
+ }
106
+
107
+ async function runOptionalBunScript(name: string, env?: Record<string, string | undefined>) {
108
+ const scriptPath = `./scripts/${name}.ts`;
109
+ if (!(await Bun.file(scriptPath).exists())) {
110
+ return `${name} script is not configured`;
111
+ }
112
+
113
+ run("bun", ["run", scriptPath], { env });
114
+ return `${name} finished`;
115
+ }
116
+
117
+ function runDashboards() {
118
+ requireCommand("gcx");
119
+ run("gcx", ["dev", "lint", "run", "./grafana", "-o", "compact"]);
120
+ run("gcx", ["resources", "push", "--path", "./grafana"]);
121
+ return "Dashboards pushed";
122
+ }
123
+
124
+ function repairDns() {
125
+ ensureProductionDomainMapping(config.serviceName);
126
+ return `DNS mapping ready for https://${config.domain.hostname}`;
127
+ }
128
+
129
+ async function runDoctor() {
130
+ const results: Array<{ name: string; status: "pass" | "warn" | "fail"; detail: string }> = [];
131
+ const target = resolveDeploymentTarget("main");
132
+
133
+ await record(results, "bun CLI", "fail", () => checkCommand("bun"));
134
+ await record(results, "gcloud CLI", "fail", () => checkCommand("gcloud"));
135
+ await record(results, "gcloud auth", "fail", () => {
136
+ requireGcloudAuth();
137
+ return "active account available";
138
+ });
139
+ await record(results, "GCP project", "fail", () => {
140
+ gcloud(["projects", "describe", config.project.id, "--format=value(projectId)"]);
141
+ return config.project.id;
142
+ });
143
+ await record(results, "Cloud Run service", "fail", () => {
144
+ const serviceName = gcloud([
145
+ "run",
146
+ "services",
147
+ "describe",
148
+ target.serviceName,
149
+ "--project",
150
+ config.project.id,
151
+ "--region",
152
+ config.region,
153
+ "--format=value(metadata.name)",
154
+ ]).stdout;
155
+ return serviceName || target.serviceName;
156
+ });
157
+ await record(results, "runtime database secret", "fail", () => {
158
+ const value = accessSecretVersion(target.databaseSecretName);
159
+ if (!value.startsWith("postgres://") && !value.startsWith("postgresql://")) {
160
+ throw new Error(`${target.databaseSecretName} does not look like a Postgres URL`);
161
+ }
162
+ return target.databaseSecretName;
163
+ });
164
+ await record(results, "DNS mapping", "fail", () => {
165
+ const mapping = describeProductionDomainMapping();
166
+ const mappedService = mapping?.spec?.routeName;
167
+ if (mappedService !== target.serviceName) {
168
+ throw new Error(`${config.domain.hostname} maps to ${mappedService || "nothing"}, expected ${target.serviceName}`);
169
+ }
170
+ return `${config.domain.hostname} -> ${target.serviceName}`;
171
+ });
172
+ await record(results, "deployment health", "fail", async () => {
173
+ const response = await fetchWithTimeout(`${serviceOrigin(target)}/healthz`, 5_000);
174
+ if (!response.ok) {
175
+ throw new Error(`GET /healthz returned ${response.status}`);
176
+ }
177
+ return "GET /healthz ok";
178
+ });
179
+ await record(results, "migration assets", "fail", async () => {
180
+ if (!(await Bun.file("./migrations/0000_init.sql").exists())) {
181
+ throw new Error("missing migrations/0000_init.sql");
182
+ }
183
+ return "migrations/0000_init.sql";
184
+ });
185
+ if ((config.runtime as string) === "go") {
186
+ await record(results, "Atlas CLI", "fail", () => checkCommand("atlas"));
187
+ await record(results, "Atlas config", "fail", async () => {
188
+ if (!(await Bun.file("./atlas.hcl").exists())) {
189
+ throw new Error("missing atlas.hcl");
190
+ }
191
+ return "atlas.hcl";
192
+ });
193
+ }
194
+ await record(results, "dashboard tooling", "warn", () => {
195
+ if (!Bun.which("gcx")) {
196
+ throw new Error("gcx is not installed");
197
+ }
198
+ return "gcx available";
199
+ });
200
+ await record(results, "dashboard artifacts", "warn", async () => {
201
+ if (!(await Bun.file("./grafana").exists()) && !(await Bun.file("./dashboards").exists())) {
202
+ throw new Error("no grafana/ or dashboards/ directory found");
203
+ }
204
+ return "dashboard directory found";
205
+ });
206
+ await record(results, "authctl", "warn", () => runAuthDoctor().detail);
207
+ await record(results, "Temporal/Cron", "warn", async () => {
208
+ const hasBunTemporal = await Bun.file("./src/temporal/worker.ts").exists();
209
+ const hasGoTemporal = await Bun.file("./internal/temporal/worker.go").exists();
210
+ if (!hasBunTemporal && !hasGoTemporal) {
211
+ throw new Error("Temporal worker config is not present in this scaffold yet");
212
+ }
213
+ return "Temporal worker config present";
214
+ });
215
+
216
+ if ((config.framework as string) === "connectrpc") {
217
+ await record(results, "ConnectRPC proto", "fail", async () => {
218
+ if (!(await Bun.file("./buf.yaml").exists())) {
219
+ throw new Error("missing buf.yaml");
220
+ }
221
+ if (!(await Bun.file("./protos/waitlist/v1/waitlist.proto").exists())) {
222
+ throw new Error("missing waitlist proto");
223
+ }
224
+ return "waitlist proto present";
225
+ });
226
+ await record(results, "Buf CLI", "warn", () => checkCommand("buf"));
227
+ await record(results, "generated SDK artifacts", "warn", async () => {
228
+ const bunGen = await Bun.file("./gen/protos/waitlist/v1/waitlist_pb.ts").exists();
229
+ const goGen = await Bun.file("./gen/waitlist/v1/waitlist.pb.go").exists();
230
+ if (!bunGen && !goGen) {
231
+ throw new Error("generated SDK artifacts are missing; run service sdk build");
232
+ }
233
+ return "local generated artifacts present";
234
+ });
235
+ await record(results, "SDK mode", "warn", async () => {
236
+ const text = await Bun.file(".service/sdk.json").text();
237
+ const state = JSON.parse(text) as { mode?: string; module?: string };
238
+ if (state.mode !== "local" && state.mode !== "remote") {
239
+ throw new Error("SDK mode must be local or remote");
240
+ }
241
+ return `${state.mode}: ${state.module || bufModule()}`;
242
+ });
243
+ }
244
+
245
+ const output = results.map(formatDoctorResult).join("\n");
246
+ const failures = results.filter((result) => result.status === "fail");
247
+ if (failures.length > 0) {
248
+ throw new Error(`Doctor found ${failures.length} failing check(s)\n${output}`);
249
+ }
250
+ return output;
251
+ }
252
+
253
+ async function record(
254
+ results: Array<{ name: string; status: "pass" | "warn" | "fail"; detail: string }>,
255
+ name: string,
256
+ failureStatus: "warn" | "fail",
257
+ check: () => string | Promise<string>
258
+ ) {
259
+ try {
260
+ results.push({ name, status: "pass", detail: await check() });
261
+ } catch (error) {
262
+ results.push({ name, status: failureStatus, detail: formatError(error) });
263
+ }
264
+ }
265
+
266
+ function checkCommand(name: string) {
267
+ const path = Bun.which(name);
268
+ if (!path) {
269
+ throw new Error(`${name} is not installed`);
270
+ }
271
+ return path;
272
+ }
273
+
274
+ async function fetchWithTimeout(url: string, timeoutMs: number) {
275
+ return await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
276
+ }
277
+
278
+ function formatDoctorResult(result: { name: string; status: "pass" | "warn" | "fail"; detail: string }) {
279
+ const marker = result.status === "pass" ? "PASS" : result.status === "warn" ? "WARN" : "FAIL";
280
+ return `[${marker}] ${result.name}: ${result.detail}`;
281
+ }
282
+
283
+ async function runSdk(args: string[]) {
284
+ if ((config.framework as string) !== "connectrpc") {
285
+ throw new Error("SDK commands are only available for ConnectRPC services");
286
+ }
287
+
288
+ const [subcommand] = args;
289
+ if (subcommand === "publish") {
290
+ requireCommand("buf");
291
+ run("buf", ["push"]);
292
+ return "Schema pushed to Buf Schema Registry";
293
+ }
294
+
295
+ if (subcommand === "build") {
296
+ if (config.runtime === "bun") {
297
+ run("bun", ["run", "gen"]);
298
+ } else {
299
+ run("make", ["gen"]);
300
+ }
301
+ await writeSdkMode("local");
302
+ return "Local SDK artifacts generated and selected";
303
+ }
304
+
305
+ if (subcommand === "use-local") {
306
+ await assertLocalSdkArtifacts();
307
+ await writeSdkMode("local");
308
+ return "Local SDK artifacts selected";
309
+ }
310
+
311
+ if (subcommand === "use-remote") {
312
+ await writeSdkMode("remote");
313
+ return `Remote Buf SDK selected: ${bufModule()}`;
314
+ }
315
+
316
+ throw new Error("Usage: service sdk <build|publish|use-local|use-remote>");
317
+ }
318
+
319
+ async function assertLocalSdkArtifacts() {
320
+ const bunArtifacts = await Bun.file("./gen/protos/waitlist/v1/waitlist_pb.ts").exists();
321
+ const goArtifacts = await Bun.file("./gen/waitlist/v1/waitlist.pb.go").exists();
322
+ if (!bunArtifacts && !goArtifacts) {
323
+ throw new Error("Local SDK artifacts are missing. Run `service sdk build` first.");
324
+ }
325
+ }
326
+
327
+ async function writeSdkMode(mode: "local" | "remote") {
328
+ await mkdir(".service", { recursive: true });
329
+ const localPath = config.runtime === "bun" ? "./gen/protos/waitlist/v1" : "./gen/waitlist/v1";
330
+ await Bun.write(
331
+ ".service/sdk.json",
332
+ `${JSON.stringify(
333
+ {
334
+ mode,
335
+ module: bufModule(),
336
+ localPath,
337
+ updatedAt: new Date().toISOString(),
338
+ },
339
+ null,
340
+ 2
341
+ )}\n`
342
+ );
343
+ }
344
+
345
+ function bufModule() {
346
+ return `buf.build/anmho/${config.serviceName}`;
30
347
  }
31
348
 
32
349
  if (import.meta.main) {
@@ -23,9 +23,17 @@ export const config = {
23
23
  hostname: "{{API_HOSTNAME}}",
24
24
  baseDomain: "{{API_BASE_DOMAIN}}",
25
25
  },
26
- storage: {
27
- attachmentBucket: "{{ATTACHMENT_BUCKET}}",
28
- attachmentPublicBaseUrl: "{{ATTACHMENT_PUBLIC_BASE_URL}}",
26
+ auth: {
27
+ issuer: "https://auth.anmho.com/api/auth",
28
+ audience: "api://{{SERVICE_ID}}",
29
+ jwksUrl: "https://auth.anmho.com/api/auth/jwks",
30
+ },
31
+ temporal: {
32
+ enabled: false,
33
+ address: "localhost:7233",
34
+ namespace: "default",
35
+ taskQueue: "{{SERVICE_ID}}",
36
+ apiKeySecretName: "{{SERVICE_ID}}-temporal-api-key",
29
37
  },
30
38
  neon: {
31
39
  projectId: "{{NEON_PROJECT_ID}}",
@@ -44,7 +52,6 @@ export const config = {
44
52
  "iamcredentials.googleapis.com",
45
53
  "secretmanager.googleapis.com",
46
54
  "serviceusage.googleapis.com",
47
- "storage.googleapis.com",
48
55
  "sts.googleapis.com",
49
56
  ],
50
57
  } as const;
@@ -1,6 +1,5 @@
1
1
  import { config } from "./config";
2
2
  import { bootstrap } from "./bootstrap";
3
- import { publishProviderRuntimeSecrets } from "./integrations";
4
3
  import { deleteBranch, ensureBranch, ensureDatabase, getConnectionUri, listBranches, resolveNeonConfig } from "./neon";
5
4
  import {
6
5
  addSecretVersion,
@@ -63,9 +62,6 @@ export async function deploy(args = Bun.argv.slice(2)) {
63
62
  addSecretVersion(target.databaseSecretName, connectionUri);
64
63
  ensureSecretAccessor(target.databaseSecretName, `serviceAccount:${config.runtimeServiceAccount}`);
65
64
  });
66
-
67
- await runStep("Publishing environment provider secrets", () => publishProviderRuntimeSecrets(target));
68
-
69
65
  const image = imageUrl();
70
66
  await runStep("Building container image", () =>
71
67
  gcloud(["builds", "submit", "--project", config.project.id, "--region", config.region, "--tag", image])