create-svc 0.1.66 → 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.66",
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",
@@ -327,6 +327,9 @@ test("scaffolds a backend package cleanly into a nested monorepo-style directory
327
327
  expect(readme).toContain("GCP_DEPLOYER_SERVICE_ACCOUNT");
328
328
  expect(readme).toContain("NEON_API_KEY");
329
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");
330
333
 
331
334
  const packageJson = await Bun.file(join(generatedRoot, "package.json")).text();
332
335
  expect(packageJson).toContain('"hono"');
@@ -351,7 +351,7 @@ async function runSdk(args: string[]) {
351
351
  requireCommand("buf");
352
352
  run("buf", ["push"]);
353
353
  await writeSdkMode("remote");
354
- return "Schema pushed to Buf Schema Registry";
354
+ return "Schema pushed to Buf Schema Registry and recorded for consumers";
355
355
  }
356
356
 
357
357
  if (subcommand === "build") {
@@ -361,18 +361,18 @@ async function runSdk(args: string[]) {
361
361
  run("make", ["gen"]);
362
362
  }
363
363
  await writeSdkMode("local");
364
- return "Local SDK artifacts generated and selected";
364
+ return "Local SDK artifacts generated and recorded";
365
365
  }
366
366
 
367
367
  if (subcommand === "use-local") {
368
368
  await assertLocalSdkArtifacts();
369
369
  await writeSdkMode("local");
370
- return "Local SDK artifacts selected";
370
+ return "Local SDK artifacts recorded";
371
371
  }
372
372
 
373
373
  if (subcommand === "use-remote") {
374
374
  await writeSdkMode("remote");
375
- return `Remote Buf SDK selected: ${bufModule()}`;
375
+ return `Remote Buf SDK recorded for consumers: ${bufModule()}`;
376
376
  }
377
377
 
378
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: