create-svc 0.1.48 → 0.1.50

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.48",
3
+ "version": "0.1.50",
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",
@@ -42,6 +42,7 @@ describe("buildLocalPreparationCommands", () => {
42
42
  test("starts local Postgres before migrating Workers dev", () => {
43
43
  expect(buildLocalPreparationCommands({ target: "workers" })).toEqual([
44
44
  { command: "bun", args: ["run", "./scripts/ensure-local-db.ts"] },
45
+ { command: "bun", args: ["run", "./scripts/wait-for-db.ts"] },
45
46
  { command: "bun", args: ["run", "migrate"] },
46
47
  ]);
47
48
  });
@@ -78,6 +78,7 @@ export function buildLocalPreparationCommands(config: Pick<ScaffoldConfig, "targ
78
78
  if (config.target === "workers") {
79
79
  return [
80
80
  { command: "bun", args: ["run", "./scripts/ensure-local-db.ts"] },
81
+ { command: "bun", args: ["run", "./scripts/wait-for-db.ts"] },
81
82
  { command: "bun", args: ["run", "migrate"] },
82
83
  ];
83
84
  }
@@ -348,13 +348,13 @@ test("scaffolds the workers target with wrangler lifecycle commands", async () =
348
348
  expect(await Bun.file(join(generatedRoot, "src", "storage.ts")).exists()).toBeTrue();
349
349
  expect(await Bun.file(join(generatedRoot, "scripts", "workers", "cli.ts")).exists()).toBeFalse();
350
350
  expect(await Bun.file(join(generatedRoot, "scripts", "cloudrun", "cli.ts")).exists()).toBeFalse();
351
- expect(await Bun.file(join(generatedRoot, "scripts", "dev.ts")).exists()).toBeFalse();
352
- expect(await Bun.file(join(generatedRoot, "scripts", "ensure-local-db.ts")).exists()).toBeFalse();
353
- expect(await Bun.file(join(generatedRoot, "scripts", "local-docker.ts")).exists()).toBeFalse();
354
- expect(await Bun.file(join(generatedRoot, "scripts", "wait-for-db.ts")).exists()).toBeFalse();
351
+ expect(await Bun.file(join(generatedRoot, "scripts", "dev.ts")).exists()).toBeTrue();
352
+ expect(await Bun.file(join(generatedRoot, "scripts", "ensure-local-db.ts")).exists()).toBeTrue();
353
+ expect(await Bun.file(join(generatedRoot, "scripts", "local-docker.ts")).exists()).toBeTrue();
354
+ expect(await Bun.file(join(generatedRoot, "scripts", "wait-for-db.ts")).exists()).toBeTrue();
355
355
  expect(await Bun.file(join(generatedRoot, "service.yaml")).exists()).toBeFalse();
356
356
  expect(await Bun.file(join(generatedRoot, "Dockerfile")).exists()).toBeFalse();
357
- expect(await Bun.file(join(generatedRoot, "docker-compose.yml")).exists()).toBeFalse();
357
+ expect(await Bun.file(join(generatedRoot, "docker-compose.yml")).exists()).toBeTrue();
358
358
  expect(await Bun.file(join(generatedRoot, "src", "db", "repository.ts")).exists()).toBeFalse();
359
359
  expect(await Bun.file(join(generatedRoot, "src", "temporal", "worker.ts")).exists()).toBeFalse();
360
360
  expect(await Bun.file(join(generatedRoot, "scripts", "codegen.ts")).exists()).toBeFalse();
package/src/scaffold.ts CHANGED
@@ -90,20 +90,12 @@ function shouldSkipForTarget(target: DeployTarget, templateKind: "shared" | "var
90
90
  return false;
91
91
  }
92
92
 
93
- if (relativePath === "Dockerfile" || relativePath === "docker-compose.yml") {
93
+ if (relativePath === "Dockerfile") {
94
94
  return true;
95
95
  }
96
96
 
97
97
  if (templateKind === "shared") {
98
- return (
99
- relativePath === "service.yaml" ||
100
- relativePath === "scripts/dev.ts" ||
101
- relativePath === "scripts/ensure-local-db.ts" ||
102
- relativePath === "scripts/local-docker.ts" ||
103
- relativePath === "scripts/local-env.ts" ||
104
- relativePath === "scripts/seed.ts" ||
105
- relativePath === "scripts/wait-for-db.ts"
106
- );
98
+ return relativePath === "service.yaml";
107
99
  }
108
100
 
109
101
  return (
@@ -4,8 +4,9 @@ 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 { manualGitHubDeleteCommand } from "../../git-bootstrap";
7
- import { ensureAuthClient, ensureAuthResourceServer, runAuthCommand, runAuthDoctor } from "../authctl";
7
+ import { deleteAuthResourceServer, ensureAuthClient, ensureAuthResourceServer, runAuthCommand, runAuthDoctor } from "../authctl";
8
8
  import { stopLocalDev } from "../local-dev";
9
+ import { runParallelTasks, type ParallelTask } from "../parallel-tasks";
9
10
  import { serviceConfig } from "../runtime";
10
11
  import { isLocalDatabaseUrl, isMissingDatabaseError, resolveCommandPath } from "./lib";
11
12
 
@@ -78,7 +79,7 @@ export async function main(argv = Bun.argv.slice(2)) {
78
79
  if (rest[0] !== "down") {
79
80
  throw new Error(`Unknown dev command: ${rest[0] || ""}\n\n${formatHelp()}`);
80
81
  }
81
- return runMain("Dev", () => stopLocalDev({ dockerCompose: false }));
82
+ return runMain("Dev", () => stopLocalDev({ dockerCompose: true, removeVolumes: false }));
82
83
  }
83
84
 
84
85
  if (command === "doctor") {
@@ -97,14 +98,45 @@ export async function main(argv = Bun.argv.slice(2)) {
97
98
  return runMain("Destroy", async () => {
98
99
  await requireDestroyConfirmation(rest.includes("--force"));
99
100
  const wranglerArgs = rest.filter((arg) => arg !== "--force");
100
- await stopLocalDev({ dockerCompose: false });
101
+ const tasks: ParallelTask[] = [
102
+ {
103
+ label: "Stopping local dev resources",
104
+ task: () => stopLocalDev({ dockerCompose: true, removeVolumes: true }),
105
+ },
106
+ {
107
+ label: `Deleting auth resource server ${config.serviceName}`,
108
+ task: () => deleteAuthResourceServer(),
109
+ },
110
+ {
111
+ label: "Deleting Hyperdrive",
112
+ task: () => deleteHyperdrive(),
113
+ },
114
+ {
115
+ label: `Deleting Worker ${config.serviceName}`,
116
+ task: () => run("wrangler", ["delete", "--name", config.serviceName, "--force", ...wranglerArgs]),
117
+ },
118
+ {
119
+ label: "Deleting Neon database",
120
+ task: () => deleteNeonDatabase(),
121
+ },
122
+ {
123
+ label: "Deleting Grafana resources",
124
+ task: () => deleteGrafanaResources(),
125
+ },
126
+ ];
127
+
101
128
  if (await confirmGitHubRepositoryDeletion(rest.includes("--force"))) {
102
- deleteGitHubRepositoryIfOwned();
129
+ tasks.push({
130
+ label: `Deleting GitHub repository ${config.git.owner}/${config.git.repository}`,
131
+ task: () => deleteGitHubRepositoryIfOwned(),
132
+ });
103
133
  }
104
- await deleteHyperdrive();
105
- run("wrangler", ["delete", "--name", config.serviceName, "--force", ...wranglerArgs]);
106
- await deleteNeonDatabase();
107
- await deleteGrafanaResources();
134
+
135
+ log.step(`Deleting ${tasks.length} resource groups in parallel`);
136
+ await runParallelTasks(tasks, {
137
+ onSuccess: (label) => log.step(`${label}: done`),
138
+ onFailure: (label, error) => log.error(`${label} failed\n${error instanceof Error ? error.message : String(error)}`),
139
+ });
108
140
  return `Destroyed ${config.serviceName}`;
109
141
  });
110
142
  }
@@ -129,7 +161,7 @@ function formatHelp() {
129
161
  " doctor Check local tools and cloud access",
130
162
  " auth Manage auth resource server and clients",
131
163
  " auth token Mint a bearer token for protected API checks",
132
- " dev down Stop local dev",
164
+ " dev down Stop local dev and Docker Compose containers",
133
165
  " dns Show Workers custom-domain configuration",
134
166
  " dashboards Publish Grafana resources",
135
167
  " destroy Remove service-managed Worker resources",
@@ -32,9 +32,10 @@ bun install
32
32
  bun run dev
33
33
  ```
34
34
 
35
- The Workers target starts with an HTTP waitlist API. Local unit tests use an
36
- in-memory store. Deployed Workers use the `HYPERDRIVE` binding and create the
37
- small waitlist/trigger schema on first use.
35
+ The Workers target starts with an HTTP waitlist API. Local dev starts Docker
36
+ Compose Postgres and passes it to Wrangler as the local Hyperdrive connection.
37
+ Local unit tests use an in-memory store. Deployed Workers use the `HYPERDRIVE`
38
+ binding and create the small waitlist/trigger schema on first use.
38
39
 
39
40
  ## API
40
41