@beignet/cli 0.0.35 → 0.0.37

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 (47) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +18 -0
  3. package/dist/config.d.ts +14 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +29 -0
  6. package/dist/config.js.map +1 -1
  7. package/dist/inspect.js +6 -2
  8. package/dist/inspect.js.map +1 -1
  9. package/dist/provider-audit.d.ts.map +1 -1
  10. package/dist/provider-audit.js +8 -3
  11. package/dist/provider-audit.js.map +1 -1
  12. package/dist/templates/base.d.ts.map +1 -1
  13. package/dist/templates/base.js +6 -1
  14. package/dist/templates/base.js.map +1 -1
  15. package/dist/templates/db/index.d.ts +1 -0
  16. package/dist/templates/db/index.d.ts.map +1 -1
  17. package/dist/templates/db/index.js.map +1 -1
  18. package/dist/templates/db/mysql.d.ts.map +1 -1
  19. package/dist/templates/db/mysql.js +16 -0
  20. package/dist/templates/db/mysql.js.map +1 -1
  21. package/dist/templates/db/postgres.d.ts.map +1 -1
  22. package/dist/templates/db/postgres.js +16 -0
  23. package/dist/templates/db/postgres.js.map +1 -1
  24. package/dist/templates/db/sqlite.d.ts.map +1 -1
  25. package/dist/templates/db/sqlite.js +16 -0
  26. package/dist/templates/db/sqlite.js.map +1 -1
  27. package/dist/templates/index.d.ts.map +1 -1
  28. package/dist/templates/index.js +2 -1
  29. package/dist/templates/index.js.map +1 -1
  30. package/dist/templates/server.d.ts +1 -1
  31. package/dist/templates/server.d.ts.map +1 -1
  32. package/dist/templates/server.js +51 -35
  33. package/dist/templates/server.js.map +1 -1
  34. package/dist/templates/shared.js +3 -3
  35. package/dist/templates/shared.js.map +1 -1
  36. package/package.json +2 -2
  37. package/src/config.ts +64 -0
  38. package/src/inspect.ts +16 -2
  39. package/src/provider-audit.ts +25 -8
  40. package/src/templates/base.ts +6 -1
  41. package/src/templates/db/index.ts +1 -0
  42. package/src/templates/db/mysql.ts +16 -0
  43. package/src/templates/db/postgres.ts +16 -0
  44. package/src/templates/db/sqlite.ts +16 -0
  45. package/src/templates/index.ts +2 -1
  46. package/src/templates/server.ts +51 -37
  47. package/src/templates/shared.ts +3 -3
@@ -18,6 +18,7 @@ export function serverProviders(ctx) {
18
18
  ? 'import { createUpstashRateLimitProvider } from "@beignet/provider-rate-limit-upstash";'
19
19
  : undefined,
20
20
  'import * as schema from "@/infra/db/schema";',
21
+ 'import { databaseClient } from "@/infra/db/client";',
21
22
  'import { starterDatabaseProvider } from "@/infra/db/provider";',
22
23
  'import { auth } from "@/lib/better-auth";',
23
24
  'import type { AuthSessionMetadata, AuthUser } from "@/ports/auth";',
@@ -38,7 +39,10 @@ export function serverProviders(ctx) {
38
39
  ].filter((entry) => Boolean(entry));
39
40
  return `${imports.join("\n")}
40
41
 
41
- const ${db.providerInstance} = ${db.providerFactory}({ schema });
42
+ const ${db.providerInstance} = ${db.providerFactory}({
43
+ schema,
44
+ client: databaseClient,
45
+ });
42
46
 
43
47
  export const providers = [
44
48
  ${entries.join("\n")}
@@ -138,7 +142,8 @@ export function env(ctx) {
138
142
  \t\tSQLITE_DB_AUTH_TOKEN: z.string().optional(),`
139
143
  : `\t\t${databaseDescriptor(ctx).urlEnvVar}: z
140
144
  \t\t\t.string()
141
- \t\t\t.default("${databaseLocalUrl(ctx.database, ctx.name)}"),`;
145
+ \t\t\t.default("${databaseLocalUrl(ctx.database, ctx.name)}"),
146
+ \t\t${ctx.database === "postgres" ? "POSTGRES" : "MYSQL"}_DB_POOL_MAX: z.coerce.number().int().positive().default(5),`;
142
147
  return `import { createEnv } from "@beignet/core/config";
143
148
  import { z } from "zod";
144
149
 
@@ -187,54 +192,45 @@ export const isDevtoolsEnabled =
187
192
  }
188
193
  export function betterAuth(ctx) {
189
194
  const connectionByDatabase = {
190
- sqlite: `import { createClient } from "@libsql/client";
191
- import { betterAuth } from "better-auth";
195
+ sqlite: `import { betterAuth } from "better-auth";
192
196
  import { drizzleAdapter } from "better-auth/adapters/drizzle";
193
197
  import { drizzle } from "drizzle-orm/libsql";
198
+ import { databaseClient } from "@/infra/db/client";
194
199
  import { ensureDatabaseReady } from "@/infra/db/database-ready";
195
200
  import * as schema from "@/infra/db/schema";
196
201
  import { env } from "@/lib/env";
197
202
 
198
- const client = createClient({
199
- url: env.SQLITE_DB_URL,
200
- authToken: env.SQLITE_DB_AUTH_TOKEN,
201
- });
202
-
203
203
  // Auth routes can be the first thing to touch the database, before any
204
204
  // Beignet provider boots, so readiness is enforced here too.
205
- await ensureDatabaseReady(client);
205
+ await ensureDatabaseReady(databaseClient);
206
206
 
207
- const db = drizzle(client, { schema });`,
207
+ const db = drizzle(databaseClient, { schema });`,
208
208
  postgres: `import { betterAuth } from "better-auth";
209
209
  import { drizzleAdapter } from "better-auth/adapters/drizzle";
210
210
  import { drizzle } from "drizzle-orm/node-postgres";
211
- import pg from "pg";
211
+ import { databaseClient } from "@/infra/db/client";
212
212
  import { ensureDatabaseReady } from "@/infra/db/database-ready";
213
213
  import * as schema from "@/infra/db/schema";
214
214
  import { env } from "@/lib/env";
215
215
 
216
- const pool = new pg.Pool({ connectionString: env.POSTGRES_DB_URL });
217
-
218
216
  // Auth routes can be the first thing to touch the database, before any
219
217
  // Beignet provider boots, so readiness is enforced here too.
220
- await ensureDatabaseReady(pool);
218
+ await ensureDatabaseReady(databaseClient);
221
219
 
222
- const db = drizzle(pool, { schema });`,
220
+ const db = drizzle(databaseClient, { schema });`,
223
221
  mysql: `import { betterAuth } from "better-auth";
224
222
  import { drizzleAdapter } from "better-auth/adapters/drizzle";
225
223
  import { drizzle } from "drizzle-orm/mysql2";
226
- import mysql from "mysql2/promise";
224
+ import { databaseClient } from "@/infra/db/client";
227
225
  import { ensureDatabaseReady } from "@/infra/db/database-ready";
228
226
  import * as schema from "@/infra/db/schema";
229
227
  import { env } from "@/lib/env";
230
228
 
231
- const pool = mysql.createPool({ uri: env.MYSQL_DB_URL });
232
-
233
229
  // Auth routes can be the first thing to touch the database, before any
234
230
  // Beignet provider boots, so readiness is enforced here too.
235
- await ensureDatabaseReady(pool);
231
+ await ensureDatabaseReady(databaseClient);
236
232
 
237
- const db = drizzle(pool, { schema, mode: "default" });`,
233
+ const db = drizzle(databaseClient, { schema, mode: "default" });`,
238
234
  };
239
235
  return `${connectionByDatabase[ctx.database]}
240
236
 
@@ -268,16 +264,7 @@ export const auth = betterAuth({
268
264
  });
269
265
  `;
270
266
  }
271
- export function server(ctx) {
272
- const db = databaseDescriptor(ctx);
273
- const providerConfigEntries = ctx.database === "sqlite"
274
- ? `\t\t"drizzle-sqlite": {
275
- \t\t\tDB_URL: env.SQLITE_DB_URL,
276
- \t\t\tDB_AUTH_TOKEN: env.SQLITE_DB_AUTH_TOKEN,
277
- \t\t},`
278
- : `\t\t"${db.providerName}": {
279
- \t\t\tDB_URL: env.${db.urlEnvVar},
280
- \t\t},`;
267
+ export function server() {
281
268
  return `import "@beignet/core/server-only";
282
269
  import { createNextServer, createNextServerLoader } from "@beignet/next";
283
270
  import {
@@ -287,6 +274,7 @@ import {
287
274
  } from "@beignet/core/server";
288
275
  import type { AppContext } from "@/app-context";
289
276
  import { appPorts } from "@/infra/app-ports";
277
+ import { closeDatabaseClient } from "@/infra/db/client";
290
278
  import { env } from "@/lib/env";
291
279
  import { appContext } from "./context";
292
280
  import { routes } from "./routes";
@@ -294,12 +282,9 @@ import { routes } from "./routes";
294
282
  export const getServer = createNextServerLoader(async () => {
295
283
  const { providers } = await import("./providers");
296
284
 
297
- return createNextServer({
285
+ const server = await createNextServer({
298
286
  ports: appPorts,
299
287
  providers,
300
- providerConfig: {
301
- ${providerConfigEntries}
302
- },
303
288
  hooks: [
304
289
  createSecurityHeadersHooks<AppContext>(),
305
290
  createErrorReportingHooks<AppContext>(),
@@ -324,7 +309,38 @@ ${providerConfigEntries}
324
309
  };
325
310
  },
326
311
  });
312
+ let stopPromise: Promise<void> | undefined;
313
+
314
+ return {
315
+ ...server,
316
+ stop() {
317
+ stopPromise ??= stopServerAndDatabase(server);
318
+ return stopPromise;
319
+ },
320
+ };
327
321
  });
322
+
323
+ async function stopServerAndDatabase(server: {
324
+ stop(): Promise<void>;
325
+ }): Promise<void> {
326
+ const errors: unknown[] = [];
327
+ try {
328
+ await server.stop();
329
+ } catch (error) {
330
+ errors.push(error);
331
+ }
332
+
333
+ try {
334
+ await closeDatabaseClient();
335
+ } catch (error) {
336
+ errors.push(error);
337
+ }
338
+
339
+ if (errors.length === 1) throw errors[0];
340
+ if (errors.length > 1) {
341
+ throw new AggregateError(errors, "Server and database shutdown failed");
342
+ }
343
+ }
328
344
  `;
329
345
  }
330
346
  const files = {
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/templates/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EACL,kBAAkB,EAClB,cAAc,GAEf,MAAM,aAAa,CAAC;AAErB,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,MAAM,EAAE,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG;QACd,qCAAqC;QACrC,6DAA6D;QAC7D,gFAAgF;QAChF,YAAY,EAAE,CAAC,eAAe,yCAAyC,EAAE,CAAC,OAAO,IAAI;QACrF,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC;YAC5B,CAAC,CAAC,6EAA6E;YAC/E,CAAC,CAAC,SAAS;QACb,2EAA2E;QAC3E,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC;YAC3B,CAAC,CAAC,2EAA2E;YAC7E,CAAC,CAAC,SAAS;QACb,cAAc,CAAC,GAAG,EAAE,oBAAoB,CAAC;YACvC,CAAC,CAAC,wFAAwF;YAC1F,CAAC,CAAC,SAAS;QACb,8CAA8C;QAC9C,gEAAgE;QAChE,2CAA2C;QAC3C,oEAAoE;KACrE,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAElD,MAAM,OAAO,GAAG;QACd,6BAA6B;QAC7B,kEAAkE;QAClE,+BAA+B;QAC/B,KAAK,EAAE,CAAC,gBAAgB,GAAG;QAC3B,4BAA4B;QAC5B,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC;YAC5B,CAAC,CAAC,gCAAgC;YAClC,CAAC,CAAC,SAAS;QACb,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,SAAS;QAC3E,cAAc,CAAC,GAAG,EAAE,oBAAoB,CAAC;YACvC,CAAC,CAAC,qCAAqC;YACvC,CAAC,CAAC,SAAS;KACd,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAErD,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;QAEtB,EAAE,CAAC,gBAAgB,MAAM,EAAE,CAAC,eAAe;;;EAGjD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;CAEnB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAoB;IACxC,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAG;QAClB,cAAc;QACd,aAAa;QACb,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,eAAe;QACf,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,mBAAmB;KACpB,CAAC;IACF,MAAM,UAAU,GAAG,UAAU;QAC3B,CAAC,CAAC,yDAAyD;QAC3D,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;EAEP,UAAU;EACV,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;EAkBtB,WAAW,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,EAAE;EACjD,UAAU,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,EAAE;;;CAGjG,CAAC;AACF,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAoB;IACtD,MAAM,QAAQ,GAAG;QACf,aAAa;QACb,oBAAoB;QACpB,cAAc,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS;QAC1D,eAAe;QACf,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;QAC3D,cAAc,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS;QAC1E,cAAc;QACd,YAAY;KACb,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAErD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BP,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;;;CAGpB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,GAAoB;IACtC,MAAM,gBAAgB,GACpB,GAAG,CAAC,QAAQ,KAAK,QAAQ;QACvB,CAAC,CAAC;iDACyC;QAC3C,CAAC,CAAC,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,SAAS;;kBAE9B,gBAAgB,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;IAE9D,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BP,gBAAgB;;;;;;;;;;;;;;CAcjB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAoB;IAC7C,MAAM,oBAAoB,GAAG;QAC3B,MAAM,EAAE;;;;;;;;;;;;;;;;;wCAiB4B;QACpC,QAAQ,EAAE;;;;;;;;;;;;;;sCAcwB;QAClC,KAAK,EAAE;;;;;;;;;;;;;;uDAc4C;KAC3C,CAAC;IAEX,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;eAe/B,kBAAkB,CAAC,GAAG,CAAC,CAAC,kBAAkB;;;;;;;;;;;;;;;CAexD,CAAC;AACF,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAoB;IACzC,MAAM,EAAE,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,qBAAqB,GACzB,GAAG,CAAC,QAAQ,KAAK,QAAQ;QACvB,CAAC,CAAC;;;OAGD;QACD,CAAC,CAAC,QAAQ,EAAE,CAAC,YAAY;oBACX,EAAE,CAAC,SAAS;OACzB,CAAC;IAEN,OAAO;;;;;;;;;;;;;;;;;;;;EAoBP,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BtB,CAAC;AACF,CAAC;AAED,MAAM,KAAK,GAAG;IACZ,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;CAoBb;IACC,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;CAqBf;IACC,cAAc,EAAE;;;;;CAKjB;IACC,aAAa,EAAE;;;;;CAKhB;IACC,WAAW,EAAE;;;;;;;;;;;;;;;CAed;IACC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCX;IACC,YAAY,EAAE;;;;;;;;;CASf;IACC,aAAa,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8DhB;IACC,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Cf;IACC,gBAAgB,EAAE;;;;;CAKnB;IACC,WAAW,EAAE;;;;;;;;;;;;;;;;CAgBd;IACC,UAAU,EAAE;;;;;;;;;;;;;;CAcb;IACC,aAAa,EAAE;;;;;;;;;;;CAWhB;IACC,YAAY,EAAE;;;;;;;;;CASf;IACC,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;CAqBZ;IACC,2EAA2E;IAC3E,wEAAwE;IACxE,4EAA4E;IAC5E,SAAS,EAAE;;;;;;;;;;;;;;;;;;;;;;;CAuBZ;IACC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BV;IACC,cAAc,EAAE;;;;;CAKjB;CACA,CAAC;AAEF,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/templates/server.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export const externalVersions = {
2
2
  biome: "^2.4.14",
3
- next: "^16.2.4",
3
+ next: "^16.2.10",
4
4
  react: "^19.2.5",
5
5
  reactDom: "^19.2.5",
6
6
  tsx: "^4.22.4",
@@ -16,7 +16,7 @@ export const externalVersions = {
16
16
  bullmq: "^5.0.0",
17
17
  drizzleKit: "^0.31.10",
18
18
  drizzleOrm: "^0.45.2",
19
- inngest: "^3.0.0",
19
+ inngest: "^3.54.0",
20
20
  libsqlClient: "^0.14.0",
21
21
  vercelBlob: "^2.5.0",
22
22
  mysql2: "^3.12.0",
@@ -26,7 +26,7 @@ export const externalVersions = {
26
26
  resend: "^6.14.0",
27
27
  sentryNode: "^10.58.0",
28
28
  stripe: "^22.2.1",
29
- nodemailer: "^8.0.5",
29
+ nodemailer: "^9.0.1",
30
30
  openFeatureServerSdk: "^1.22.0",
31
31
  typesPg: "^8.11.0",
32
32
  ioredis: "^5.0.0",
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/templates/shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/templates/shared.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beignet/cli",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "type": "module",
5
5
  "description": "CLI for creating and maintaining Beignet apps.",
6
6
  "main": "./dist/lib.js",
@@ -70,7 +70,7 @@
70
70
  "typescript": "^5.3.0"
71
71
  },
72
72
  "dependencies": {
73
- "@beignet/core": "^0.0.35",
73
+ "@beignet/core": "^0.0.37",
74
74
  "@clack/prompts": "^1.5.1",
75
75
  "@modelcontextprotocol/sdk": "^1.29.0",
76
76
  "@stricli/core": "^1.2.7",
package/src/config.ts CHANGED
@@ -56,6 +56,17 @@ export type BeignetDatabaseConfig = {
56
56
  schemaSources?: string[];
57
57
  };
58
58
 
59
+ /**
60
+ * Explicit exceptions for static provider package requirements.
61
+ */
62
+ export type BeignetProviderAuditConfig = {
63
+ /**
64
+ * Environment variables supplied through another mechanism, such as an
65
+ * injected platform client, and therefore not required in app env files.
66
+ */
67
+ ignoreRequiredEnv?: string[];
68
+ };
69
+
59
70
  /**
60
71
  * User-authored Beignet CLI config.
61
72
  */
@@ -63,6 +74,7 @@ export type BeignetConfig = {
63
74
  framework?: BeignetFramework;
64
75
  paths?: Partial<BeignetPaths>;
65
76
  database?: BeignetDatabaseConfig;
77
+ providerAudit?: BeignetProviderAuditConfig;
66
78
  };
67
79
 
68
80
  /**
@@ -75,6 +87,9 @@ export type ResolvedBeignetConfig = {
75
87
  tables: BeignetDatabaseTables;
76
88
  schemaSources: string[];
77
89
  };
90
+ providerAudit: {
91
+ ignoreRequiredEnv: string[];
92
+ };
78
93
  configFile?: string;
79
94
  };
80
95
 
@@ -116,6 +131,9 @@ export const defaultBeignetConfig: ResolvedBeignetConfig = {
116
131
  },
117
132
  schemaSources: [],
118
133
  },
134
+ providerAudit: {
135
+ ignoreRequiredEnv: [],
136
+ },
119
137
  };
120
138
 
121
139
  /**
@@ -145,11 +163,17 @@ export function resolveConfig(
145
163
  config.database?.schemaSources ??
146
164
  defaultBeignetConfig.database.schemaSources,
147
165
  };
166
+ const providerAudit = {
167
+ ignoreRequiredEnv:
168
+ config.providerAudit?.ignoreRequiredEnv ??
169
+ defaultBeignetConfig.providerAudit.ignoreRequiredEnv,
170
+ };
148
171
 
149
172
  return {
150
173
  framework: config.framework ?? defaultBeignetConfig.framework,
151
174
  paths: normalizeConfigPaths(paths),
152
175
  database: normalizeDatabaseConfig(database),
176
+ providerAudit: normalizeProviderAuditConfig(providerAudit),
153
177
  configFile,
154
178
  };
155
179
  }
@@ -298,6 +322,20 @@ function assertConfigObject(
298
322
  throw new Error(`${configFile} database must be an object.`);
299
323
  }
300
324
 
325
+ if (config.providerAudit !== undefined && !isRecord(config.providerAudit)) {
326
+ throw new Error(`${configFile} providerAudit must be an object.`);
327
+ }
328
+
329
+ if (
330
+ config.providerAudit !== undefined &&
331
+ config.providerAudit.ignoreRequiredEnv !== undefined &&
332
+ !Array.isArray(config.providerAudit.ignoreRequiredEnv)
333
+ ) {
334
+ throw new Error(
335
+ `${configFile} providerAudit.ignoreRequiredEnv must be an array.`,
336
+ );
337
+ }
338
+
301
339
  if (
302
340
  config.database !== undefined &&
303
341
  config.database.tables !== undefined &&
@@ -385,6 +423,32 @@ function normalizeDatabaseSchemaSource(index: number, value: string): string {
385
423
  return value.trim();
386
424
  }
387
425
 
426
+ function normalizeProviderAuditConfig(config: {
427
+ ignoreRequiredEnv: string[];
428
+ }): {
429
+ ignoreRequiredEnv: string[];
430
+ } {
431
+ return {
432
+ ignoreRequiredEnv: [
433
+ ...new Set(
434
+ config.ignoreRequiredEnv.map((value, index) =>
435
+ normalizeIgnoredRequiredEnv(index, value),
436
+ ),
437
+ ),
438
+ ],
439
+ };
440
+ }
441
+
442
+ function normalizeIgnoredRequiredEnv(index: number, value: string): string {
443
+ if (typeof value !== "string" || value.trim() === "") {
444
+ throw new Error(
445
+ `Beignet config providerAudit.ignoreRequiredEnv[${index}] must be a string.`,
446
+ );
447
+ }
448
+
449
+ return value.trim();
450
+ }
451
+
388
452
  function isRecord(value: unknown): value is Record<string, unknown> {
389
453
  return typeof value === "object" && value !== null && !Array.isArray(value);
390
454
  }
package/src/inspect.ts CHANGED
@@ -2228,7 +2228,10 @@ async function inspectProductionReadiness(
2228
2228
  provider.variants,
2229
2229
  providerEntries,
2230
2230
  )) {
2231
- for (const envVar of variant.requiredEnv) {
2231
+ for (const envVar of configuredProviderRequiredEnv(
2232
+ variant.requiredEnv,
2233
+ config,
2234
+ )) {
2232
2235
  if (
2233
2236
  await providerRequiredEnvExists(
2234
2237
  targetDir,
@@ -2275,7 +2278,10 @@ async function inspectProductionReadiness(
2275
2278
  continue;
2276
2279
  }
2277
2280
 
2278
- for (const envVar of provider.requiredEnv ?? []) {
2281
+ for (const envVar of configuredProviderRequiredEnv(
2282
+ provider.requiredEnv ?? [],
2283
+ config,
2284
+ )) {
2279
2285
  if (
2280
2286
  await providerRequiredEnvExists(
2281
2287
  targetDir,
@@ -5539,6 +5545,14 @@ function configuredProviderRequiredTables(
5539
5545
  );
5540
5546
  }
5541
5547
 
5548
+ function configuredProviderRequiredEnv(
5549
+ envVars: readonly string[],
5550
+ config: ResolvedBeignetConfig,
5551
+ ): string[] {
5552
+ const ignored = new Set(config.providerAudit.ignoreRequiredEnv);
5553
+ return envVars.filter((envVar) => !ignored.has(envVar));
5554
+ }
5555
+
5542
5556
  function configuredProviderRequiredTable(
5543
5557
  tableName: string,
5544
5558
  config: ResolvedBeignetConfig,
@@ -1015,6 +1015,14 @@ function isRecord(value: unknown): value is Record<string, unknown> {
1015
1015
  return typeof value === "object" && value !== null && !Array.isArray(value);
1016
1016
  }
1017
1017
 
1018
+ function configuredProviderRequiredEnv(
1019
+ envVars: readonly string[],
1020
+ config: ResolvedBeignetConfig,
1021
+ ): string[] {
1022
+ const ignored = new Set(config.providerAudit.ignoreRequiredEnv);
1023
+ return envVars.filter((envVar) => !ignored.has(envVar));
1024
+ }
1025
+
1018
1026
  function configuredProviderRequiredTables(
1019
1027
  tableNames: readonly string[],
1020
1028
  config: ResolvedBeignetConfig,
@@ -1140,13 +1148,18 @@ async function providerAuditEntryForRule(options: {
1140
1148
  const requiredEnv =
1141
1149
  options.rule.variants !== undefined
1142
1150
  ? aggregateVariantRequirement(variants, "requiredEnv")
1143
- : await requirementAudit(options.rule.requiredEnv ?? [], (envVar) =>
1144
- providerRequiredEnvExists(
1145
- options.targetDir,
1146
- options.configFiles,
1147
- envVar,
1148
- options.sourceCache,
1151
+ : await requirementAudit(
1152
+ configuredProviderRequiredEnv(
1153
+ options.rule.requiredEnv ?? [],
1154
+ options.config,
1149
1155
  ),
1156
+ (envVar) =>
1157
+ providerRequiredEnvExists(
1158
+ options.targetDir,
1159
+ options.configFiles,
1160
+ envVar,
1161
+ options.sourceCache,
1162
+ ),
1150
1163
  );
1151
1164
 
1152
1165
  const requiredTables =
@@ -1222,12 +1235,16 @@ async function providerVariantAudit(options: {
1222
1235
  variant: ProviderDoctorVariantRule;
1223
1236
  registered: boolean;
1224
1237
  }): Promise<ProviderVariantAudit> {
1238
+ const requiredEnv = configuredProviderRequiredEnv(
1239
+ options.variant.requiredEnv,
1240
+ options.config,
1241
+ );
1225
1242
  if (!options.registered) {
1226
1243
  return {
1227
1244
  name: options.variant.name,
1228
1245
  displayName: options.variant.displayName,
1229
1246
  registration: "inactive",
1230
- requiredEnv: inactiveRequirement(options.variant.requiredEnv),
1247
+ requiredEnv: inactiveRequirement(requiredEnv),
1231
1248
  requiredTables: inactiveRequirement(options.variant.requiredTables),
1232
1249
  };
1233
1250
  }
@@ -1240,7 +1257,7 @@ async function providerVariantAudit(options: {
1240
1257
  options.variant.registrationSeverity,
1241
1258
  options.providerEntries,
1242
1259
  ),
1243
- requiredEnv: await requirementAudit(options.variant.requiredEnv, (envVar) =>
1260
+ requiredEnv: await requirementAudit(requiredEnv, (envVar) =>
1244
1261
  providerRequiredEnvExists(
1245
1262
  options.targetDir,
1246
1263
  options.configFiles,
@@ -314,7 +314,7 @@ Use \`${cli} make feature projects --recipe full-slice\` when you want a richer
314
314
  - \`features/shared/errors.ts\` keeps application errors and route-owned error schemas together.
315
315
  - \`ports/\` defines app-owned dependencies.
316
316
  - \`infra/\` implements ports for the selected runtime.
317
- - \`infra/db/schema/\` contains the Drizzle schema, \`drizzle/\` contains the checked-in migrations, and \`infra/todos/\` contains the durable todo repository adapter.
317
+ - \`infra/db/client.ts\` owns the process-wide database client shared by Better Auth and the Beignet provider; the public server \`stop()\` closes it after provider shutdown. \`infra/db/schema/\` contains the Drizzle schema, \`drizzle/\` contains the checked-in migrations, and \`infra/todos/\` contains the durable todo repository adapter.
318
318
  - \`server/routes.ts\` keeps the central route registry and OpenAPI contract list.
319
319
  - \`server/context.ts\` declares the context blueprint shared by the server and route tests.
320
320
  - \`server/providers.ts\` wires devtools, Better Auth, pino, ${
@@ -342,6 +342,7 @@ ${optionalAuthRedirects}
342
342
  cli +
343
343
  " db migrate` against it before starting the app."
344
344
  }
345
+ - Size the process-wide database client for the deployment. Postgres and MySQL use the generated pool-limit environment variable; count web, worker, preview, and task processes against the database connection limit, and keep writable SQLite files on one host.
345
346
  - Run \`${cli} db generate\` and \`${cli} db migrate\` after changing the Drizzle schema.
346
347
  - Run \`${cli} db reset\` to rebuild a local ${
347
348
  ctx.database === "sqlite"
@@ -438,11 +439,15 @@ export function envExample(ctx: TemplateContext): string {
438
439
  "# Local Postgres matching the docker one-liner below; point at your own server in production.",
439
440
  `# ${databaseStartCommand("postgres", ctx.name)}`,
440
441
  `POSTGRES_DB_URL=${databaseLocalUrl("postgres", ctx.name)}`,
442
+ "# Maximum connections opened by each running app process.",
443
+ "POSTGRES_DB_POOL_MAX=5",
441
444
  ]
442
445
  : [
443
446
  "# Local MySQL matching the docker one-liner below; point at your own server in production.",
444
447
  `# ${databaseStartCommand("mysql", ctx.name)}`,
445
448
  `MYSQL_DB_URL=${databaseLocalUrl("mysql", ctx.name)}`,
449
+ "# Maximum connections opened by each running app process.",
450
+ "MYSQL_DB_POOL_MAX=5",
446
451
  ];
447
452
 
448
453
  const lines = [
@@ -10,6 +10,7 @@ import { sqliteDbFiles } from "./sqlite.js";
10
10
  */
11
11
  export type DbTemplateFiles = {
12
12
  drizzleConfig: string;
13
+ dbClient: string;
13
14
  dbSchema: string;
14
15
  drizzleTodoRepository: string;
15
16
  dbRepositories: string;
@@ -36,6 +36,22 @@ export function mysqlDbFiles(ctx: TemplateContext): DbTemplateFiles {
36
36
  url: process.env.MYSQL_DB_URL ?? "${databaseLocalUrl("mysql", ctx.name)}",
37
37
  },
38
38
  };
39
+ `,
40
+ dbClient: `import "@beignet/core/server-only";
41
+ import mysql from "mysql2/promise";
42
+ import { env } from "@/lib/env";
43
+
44
+ export const databaseClient = mysql.createPool({
45
+ uri: env.MYSQL_DB_URL,
46
+ connectionLimit: env.MYSQL_DB_POOL_MAX,
47
+ });
48
+
49
+ let closePromise: Promise<void> | undefined;
50
+
51
+ export function closeDatabaseClient(): Promise<void> {
52
+ closePromise ??= Promise.resolve().then(() => databaseClient.end());
53
+ return closePromise;
54
+ }
39
55
  `,
40
56
  dbSchema: `import {
41
57
  boolean,
@@ -33,6 +33,22 @@ export function postgresDbFiles(ctx: TemplateContext): DbTemplateFiles {
33
33
  url: process.env.POSTGRES_DB_URL ?? "${databaseLocalUrl("postgres", ctx.name)}",
34
34
  },
35
35
  };
36
+ `,
37
+ dbClient: `import "@beignet/core/server-only";
38
+ import pg from "pg";
39
+ import { env } from "@/lib/env";
40
+
41
+ export const databaseClient = new pg.Pool({
42
+ connectionString: env.POSTGRES_DB_URL,
43
+ max: env.POSTGRES_DB_POOL_MAX,
44
+ });
45
+
46
+ let closePromise: Promise<void> | undefined;
47
+
48
+ export function closeDatabaseClient(): Promise<void> {
49
+ closePromise ??= Promise.resolve().then(() => databaseClient.end());
50
+ return closePromise;
51
+ }
36
52
  `,
37
53
  dbSchema: `import { boolean, index, pgTable, text, timestamp } from "drizzle-orm/pg-core";
38
54
 
@@ -24,6 +24,22 @@ const files = {
24
24
  authToken: process.env.SQLITE_DB_AUTH_TOKEN,
25
25
  },
26
26
  };
27
+ `,
28
+ dbClient: `import "@beignet/core/server-only";
29
+ import { createClient } from "@libsql/client";
30
+ import { env } from "@/lib/env";
31
+
32
+ export const databaseClient = createClient({
33
+ url: env.SQLITE_DB_URL,
34
+ authToken: env.SQLITE_DB_AUTH_TOKEN,
35
+ });
36
+
37
+ let closePromise: Promise<void> | undefined;
38
+
39
+ export function closeDatabaseClient(): Promise<void> {
40
+ closePromise ??= Promise.resolve().then(() => databaseClient.close());
41
+ return closePromise;
42
+ }
27
43
  `,
28
44
  dbSchema: `import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
29
45
 
@@ -110,6 +110,7 @@ export function getTemplateFiles(ctx: TemplateContext): TemplateFile[] {
110
110
  { path: "ports/index.ts", content: ports(ctx) },
111
111
  { path: "ports/auth.ts", content: serverFiles.authPort },
112
112
  { path: "infra/app-ports.ts", content: infrastructurePorts(ctx) },
113
+ { path: "infra/db/client.ts", content: db.dbClient },
113
114
  { path: "infra/db/database-ready.ts", content: db.databaseReady },
114
115
  { path: "infra/db/provider.ts", content: db.dbProvider },
115
116
  { path: "infra/db/repositories.ts", content: db.dbRepositories },
@@ -137,7 +138,7 @@ export function getTemplateFiles(ctx: TemplateContext): TemplateFile[] {
137
138
  ...testSupportTemplateFiles,
138
139
  { path: "lib/use-case.ts", content: serverFiles.useCaseBuilder },
139
140
  { path: "lib/routes.ts", content: serverFiles.routesBuilder },
140
- { path: "server/index.ts", content: server(ctx) },
141
+ { path: "server/index.ts", content: server() },
141
142
  { path: "server/context.ts", content: serverFiles.serverContext },
142
143
  { path: "server/routes.ts", content: serverFiles.serverRoutes },
143
144
  { path: "server/providers.ts", content: serverProviders(ctx) },