create-svc 0.1.65 → 0.1.67

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-svc",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
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",
@@ -194,6 +194,8 @@ test("scaffolds all runtime/framework variants with shared cloudrun config", asy
194
194
  expect(goMod).toContain("connectrpc.com/connect");
195
195
  expect(mainGo).toContain("NewWaitlistService");
196
196
  expect(mainGo).toContain("WaitlistServiceName");
197
+ const bufConfig = await Bun.file(join(generatedRoot, "buf.yaml")).text();
198
+ expect(bufConfig).toContain("name: buf.build/anmho/dns-api");
197
199
  } else {
198
200
  expect(goMod).not.toContain("connectrpc.com/connect");
199
201
  expect(mainGo).toContain("NewWaitlistService");
@@ -325,6 +327,9 @@ test("scaffolds a backend package cleanly into a nested monorepo-style directory
325
327
  expect(readme).toContain("GCP_DEPLOYER_SERVICE_ACCOUNT");
326
328
  expect(readme).toContain("NEON_API_KEY");
327
329
  expect(readme).toContain("CLOUDFLARE_API_TOKEN");
330
+ expect(readme).toContain("ConnectRPC service builds import the generated bindings checked into this repo");
331
+ expect(readme).toContain("does not rewrite this");
332
+ expect(readme).toContain("service's Go imports away from local generated packages");
328
333
 
329
334
  const packageJson = await Bun.file(join(generatedRoot, "package.json")).text();
330
335
  expect(packageJson).toContain('"hono"');
@@ -350,7 +350,8 @@ async function runSdk(args: string[]) {
350
350
  if (subcommand === "publish") {
351
351
  requireCommand("buf");
352
352
  run("buf", ["push"]);
353
- return "Schema pushed to Buf Schema Registry";
353
+ await writeSdkMode("remote");
354
+ return "Schema pushed to Buf Schema Registry and recorded for consumers";
354
355
  }
355
356
 
356
357
  if (subcommand === "build") {
@@ -360,18 +361,18 @@ async function runSdk(args: string[]) {
360
361
  run("make", ["gen"]);
361
362
  }
362
363
  await writeSdkMode("local");
363
- return "Local SDK artifacts generated and selected";
364
+ return "Local SDK artifacts generated and recorded";
364
365
  }
365
366
 
366
367
  if (subcommand === "use-local") {
367
368
  await assertLocalSdkArtifacts();
368
369
  await writeSdkMode("local");
369
- return "Local SDK artifacts selected";
370
+ return "Local SDK artifacts recorded";
370
371
  }
371
372
 
372
373
  if (subcommand === "use-remote") {
373
374
  await writeSdkMode("remote");
374
- return `Remote Buf SDK selected: ${bufModule()}`;
375
+ return `Remote Buf SDK recorded for consumers: ${bufModule()}`;
375
376
  }
376
377
 
377
378
  throw new Error("Usage: service sdk <build|publish|use-local|use-remote>");
@@ -0,0 +1,107 @@
1
+ import { expect, test } from "bun:test";
2
+ import { chmod, mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { scaffoldProject, type ScaffoldConfig } from "../../scaffold";
6
+
7
+ function baseConfig(directory: string): ScaffoldConfig {
8
+ return {
9
+ directory,
10
+ serviceName: "sdk-proof",
11
+ modulePath: "github.com/anmho/sdk-proof",
12
+ target: "cloudrun",
13
+ runtime: "go",
14
+ framework: "connectrpc",
15
+ region: "us-west1",
16
+ gcpProjectMode: "use_existing",
17
+ gcpProject: "anmho-services",
18
+ gcpProjectName: "services",
19
+ billingAccount: "",
20
+ quotaProjectId: "anmho-infra-prod",
21
+ profile: "microservice",
22
+ git: {
23
+ enabled: false,
24
+ owner: "anmho",
25
+ repository: "sdk-proof",
26
+ },
27
+ neonDatabaseName: "sdk_proof",
28
+ apiHostname: "api.sdk-proof.anmho.com",
29
+ generatorRoot: join(import.meta.dir, "..", "..", ".."),
30
+ autoDeploy: false,
31
+ };
32
+ }
33
+
34
+ test("service sdk publish pushes the named Buf module and selects remote SDK mode", async () => {
35
+ const root = await mkdtemp(join(tmpdir(), "create-svc-sdk-"));
36
+ const generatedRoot = join(root, "sdk-proof");
37
+ const fakeBin = join(root, "bin");
38
+ const bufLog = join(root, "buf.log");
39
+
40
+ await scaffoldProject(baseConfig(generatedRoot));
41
+ await mkdir(join(generatedRoot, "node_modules"));
42
+ await mkdir(fakeBin);
43
+ await writeFile(
44
+ join(fakeBin, "buf"),
45
+ ["#!/bin/sh", `echo "$@" > "${bufLog}"`, "exit 0", ""].join("\n")
46
+ );
47
+ await chmod(join(fakeBin, "buf"), 0o755);
48
+
49
+ const result = Bun.spawnSync(["bun", join(import.meta.dir, "..", "..", "..", "index.ts"), "sdk", "publish"], {
50
+ cwd: generatedRoot,
51
+ env: { ...process.env, PATH: `${fakeBin}:${process.env.PATH ?? ""}` },
52
+ stdout: "pipe",
53
+ stderr: "pipe",
54
+ });
55
+
56
+ expect(result.success, [result.stdout.toString(), result.stderr.toString()].join("\n")).toBeTrue();
57
+ expect(result.stdout.toString()).toContain("recorded for consumers");
58
+ expect((await readFile(bufLog, "utf8")).trim()).toBe("push");
59
+ const sdkState = JSON.parse(await Bun.file(join(generatedRoot, ".service", "sdk.json")).text());
60
+ expect(sdkState).toMatchObject({
61
+ mode: "remote",
62
+ module: "buf.build/anmho/sdk-proof",
63
+ localPath: "./gen/waitlist/v1",
64
+ });
65
+ const bufConfig = await Bun.file(join(generatedRoot, "buf.yaml")).text();
66
+ expect(bufConfig).toContain("name: buf.build/anmho/sdk-proof");
67
+ });
68
+
69
+ test("service sdk publish leaves local SDK mode when Buf push fails", async () => {
70
+ const root = await mkdtemp(join(tmpdir(), "create-svc-sdk-"));
71
+ const generatedRoot = join(root, "sdk-proof");
72
+ const fakeBin = join(root, "bin");
73
+
74
+ await scaffoldProject(baseConfig(generatedRoot));
75
+ await mkdir(join(generatedRoot, "node_modules"));
76
+ await mkdir(fakeBin);
77
+ await mkdir(join(generatedRoot, ".service"));
78
+ await Bun.write(
79
+ join(generatedRoot, ".service", "sdk.json"),
80
+ `${JSON.stringify(
81
+ {
82
+ mode: "local",
83
+ module: "buf.build/anmho/sdk-proof",
84
+ localPath: "./gen/waitlist/v1",
85
+ updatedAt: "2026-05-25T00:00:00.000Z",
86
+ },
87
+ null,
88
+ 2
89
+ )}\n`
90
+ );
91
+ await writeFile(join(fakeBin, "buf"), ["#!/bin/sh", "echo denied >&2", "exit 1", ""].join("\n"));
92
+ await chmod(join(fakeBin, "buf"), 0o755);
93
+
94
+ const before = JSON.parse(await Bun.file(join(generatedRoot, ".service", "sdk.json")).text());
95
+ expect(before.mode).toBe("local");
96
+
97
+ const result = Bun.spawnSync(["bun", join(import.meta.dir, "..", "..", "..", "index.ts"), "sdk", "publish"], {
98
+ cwd: generatedRoot,
99
+ env: { ...process.env, PATH: `${fakeBin}:${process.env.PATH ?? ""}` },
100
+ stdout: "pipe",
101
+ stderr: "pipe",
102
+ });
103
+
104
+ expect(result.success).toBeFalse();
105
+ const after = JSON.parse(await Bun.file(join(generatedRoot, ".service", "sdk.json")).text());
106
+ expect(after.mode).toBe("local");
107
+ });
@@ -258,6 +258,18 @@ secrets only when you add a provider adapter. A generic adapter can honor:
258
258
 
259
259
  - `WEBHOOK_<PROVIDER>_SECRET`
260
260
 
261
+ ## ConnectRPC SDK publishing
262
+
263
+ ConnectRPC service builds import the generated bindings checked into this repo
264
+ under `gen/`. That keeps the API and worker images self-contained and does not
265
+ change when SDK metadata changes.
266
+
267
+ Use `service sdk build` after editing protobufs to regenerate local
268
+ bindings for this service. Use `service sdk publish` to push the
269
+ schema to the Buf Schema Registry for external consumers. A successful publish
270
+ records the remote module in `.service/sdk.json`; it does not rewrite this
271
+ service's Go imports away from local generated packages.
272
+
261
273
  ## GitHub Actions deployment
262
274
 
263
275
  The scaffold emits a minimal deployment workflow slice for Cloud Run:
@@ -1,6 +1,7 @@
1
1
  version: v2
2
2
  modules:
3
3
  - path: protos
4
+ name: buf.build/anmho/{{SERVICE_ID}}
4
5
  lint:
5
6
  use:
6
7
  - STANDARD