@beignet/cli 0.0.38 → 0.0.40

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 (92) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +154 -102
  3. package/dist/choices.d.ts +17 -21
  4. package/dist/choices.d.ts.map +1 -1
  5. package/dist/choices.js +21 -67
  6. package/dist/choices.js.map +1 -1
  7. package/dist/config.d.ts +1 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +4 -2
  10. package/dist/config.js.map +1 -1
  11. package/dist/create-prompts.d.ts +5 -6
  12. package/dist/create-prompts.d.ts.map +1 -1
  13. package/dist/create-prompts.js +15 -15
  14. package/dist/create-prompts.js.map +1 -1
  15. package/dist/create.d.ts +11 -2
  16. package/dist/create.d.ts.map +1 -1
  17. package/dist/create.js +38 -28
  18. package/dist/create.js.map +1 -1
  19. package/dist/framework.d.ts +3 -0
  20. package/dist/framework.d.ts.map +1 -0
  21. package/dist/framework.js +6 -0
  22. package/dist/framework.js.map +1 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +149 -47
  25. package/dist/index.js.map +1 -1
  26. package/dist/inspect.d.ts +4 -2
  27. package/dist/inspect.d.ts.map +1 -1
  28. package/dist/inspect.js +174 -34
  29. package/dist/inspect.js.map +1 -1
  30. package/dist/lib.d.ts +1 -1
  31. package/dist/lib.d.ts.map +1 -1
  32. package/dist/make/inbox.js +3 -3
  33. package/dist/make/inbox.js.map +1 -1
  34. package/dist/make/payments.d.ts.map +1 -1
  35. package/dist/make/payments.js +5 -3
  36. package/dist/make/payments.js.map +1 -1
  37. package/dist/make/shared.d.ts +10 -3
  38. package/dist/make/shared.d.ts.map +1 -1
  39. package/dist/make/shared.js +7 -8
  40. package/dist/make/shared.js.map +1 -1
  41. package/dist/make.d.ts +3 -2
  42. package/dist/make.d.ts.map +1 -1
  43. package/dist/make.js +549 -186
  44. package/dist/make.js.map +1 -1
  45. package/dist/mcp.d.ts.map +1 -1
  46. package/dist/mcp.js +15 -11
  47. package/dist/mcp.js.map +1 -1
  48. package/dist/provider-add.d.ts +21 -3
  49. package/dist/provider-add.d.ts.map +1 -1
  50. package/dist/provider-add.js +101 -65
  51. package/dist/provider-add.js.map +1 -1
  52. package/dist/task.js +1 -1
  53. package/dist/task.js.map +1 -1
  54. package/dist/templates/base.d.ts +1 -1
  55. package/dist/templates/base.d.ts.map +1 -1
  56. package/dist/templates/base.js +15 -15
  57. package/dist/templates/base.js.map +1 -1
  58. package/dist/templates/index.d.ts +2 -2
  59. package/dist/templates/index.d.ts.map +1 -1
  60. package/dist/templates/index.js +5 -5
  61. package/dist/templates/index.js.map +1 -1
  62. package/dist/templates/server.d.ts.map +1 -1
  63. package/dist/templates/server.js +17 -13
  64. package/dist/templates/server.js.map +1 -1
  65. package/dist/templates/shadcn.js +1 -1
  66. package/dist/templates/shared.d.ts +4 -4
  67. package/dist/templates/shared.d.ts.map +1 -1
  68. package/dist/templates/shared.js +6 -6
  69. package/dist/templates/shared.js.map +1 -1
  70. package/package.json +2 -2
  71. package/skills/app-structure/SKILL.md +29 -9
  72. package/src/choices.ts +38 -88
  73. package/src/config.ts +7 -3
  74. package/src/create-prompts.ts +20 -21
  75. package/src/create.ts +54 -36
  76. package/src/framework.ts +13 -0
  77. package/src/index.ts +193 -65
  78. package/src/inspect.ts +290 -39
  79. package/src/lib.ts +1 -1
  80. package/src/make/inbox.ts +3 -3
  81. package/src/make/payments.ts +10 -3
  82. package/src/make/shared.ts +16 -10
  83. package/src/make.ts +720 -176
  84. package/src/mcp.ts +20 -13
  85. package/src/provider-add.ts +159 -79
  86. package/src/task.ts +1 -1
  87. package/src/templates/base.ts +16 -16
  88. package/src/templates/index.ts +6 -6
  89. package/src/templates/server.ts +17 -13
  90. package/src/templates/shadcn.ts +1 -1
  91. package/src/templates/shared.ts +10 -10
  92. package/src/test-helpers/generated-app.ts +2 -1
@@ -34,19 +34,25 @@ Use:
34
34
  ```bash
35
35
  beignet make feature projects
36
36
  beignet make feature projects --recipe full-slice
37
- beignet make resource projects/project --auth --tenant
38
- beignet make event posts/published
39
- beignet make listener posts/enqueue-published-email --event posts/published
40
- beignet make job billing/sync
41
- beignet make schedule billing/nightly --cron "0 2 * * *"
42
- beignet make task admin/backfill
43
- beignet make seed demo/users
44
- beignet make upload issues/attachment
37
+ beignet make resource projects --authorization --tenant-scoped
38
+ beignet make event posts.published
39
+ beignet make listener posts.enqueue-published-email --event posts.published
40
+ beignet make job billing.sync
41
+ beignet make schedule billing.nightly --cron "0 2 * * *"
42
+ beignet make task admin.backfill
43
+ beignet make seed demo.users
44
+ beignet make outbox
45
+ beignet make upload issues.attachment
46
+ beignet make upload issues.attachment --ui
45
47
  ```
46
48
 
47
49
  Generators place files under the owning feature, update central registries
48
50
  when possible, and keep `doctor` clean.
49
51
 
52
+ Use `make upload --ui` in full-stack apps when the upload should include a
53
+ shared client/server constraint manifest, typed React upload client, uploader,
54
+ and component test. Omit `--ui` for API-only or backend-only workflows.
55
+
50
56
  Use the `full-slice` recipe when you need a richer reference feature with
51
57
  policy, client helpers, workflow artifacts, events, listener registration,
52
58
  jobs, schedules, notifications, uploads, seeds, and outbox wiring. After
@@ -70,6 +76,12 @@ Hand-written files do not run until registered:
70
76
  every job worker or outbox registry that can receive it
71
77
  - seeds -> the app-owned seed entrypoint, usually `server/seed.ts`
72
78
 
79
+ For generated Next.js 15.1+ apps, `make outbox` also adds a server-local
80
+ provider that wraps the database Unit of Work with a push-assisted `after()`
81
+ trigger. Keep the generated cron route: it is the recovery path for missed
82
+ callbacks, delayed messages, retries, and additional batches. Older Next.js
83
+ apps remain cron-only.
84
+
73
85
  When an app opts into runtime integrity, keep `server/runtime-integrity.ts`
74
86
  aligned with those central registries. The boot check is pure and
75
87
  serverless-safe: it compares declared listeners, schedules, tasks, and outbox
@@ -84,7 +96,11 @@ low-risk route-group, schedule, task, outbox, and listener registry repair.
84
96
 
85
97
  ## Path Config
86
98
 
87
- `beignet.config.*` moves paths; it does not change architecture.
99
+ `beignet.config.*` selects the inspected server adapter and moves paths; it
100
+ does not change the application architecture. `framework: "next"` is the
101
+ default. Use `framework: "web"` for `@beignet/web` Fetch servers so `routes`
102
+ and `doctor` inspect the central `defineRoutes(...)` registry instead of
103
+ requiring Next.js `app/api/` handlers.
88
104
 
89
105
  Common `src/` apps configure:
90
106
 
@@ -102,6 +118,10 @@ export default defineConfig({
102
118
  });
103
119
  ```
104
120
 
121
+ Framework-neutral generators work in either profile. `make payments`,
122
+ `make upload`, `make outbox`, and `make schedule --route` still generate
123
+ Next.js handlers and reject the web profile before writing files.
124
+
105
125
  When `appContext` moves under `src/`, root client setup follows that source
106
126
  root at `src/client/index.ts`. Other registries and app-bound builders are not
107
127
  relocated implicitly; override each path the app has moved, such as
package/src/choices.ts CHANGED
@@ -14,18 +14,21 @@ export type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
14
14
  */
15
15
  export type TemplateName = "next";
16
16
  /**
17
- * Optional provider integrations that can be scaffolded into a new app.
17
+ * Optional providers rendered directly by the starter template.
18
18
  *
19
19
  * Better Auth, Drizzle/libSQL, and pino ship in every starter, so only
20
- * integrations that add an external service remain selectable.
20
+ * providers that add an external service remain selectable.
21
21
  */
22
- export type IntegrationName = "inngest" | "resend" | "upstash-rate-limit";
22
+ export type StarterProviderName =
23
+ | "jobs-inngest"
24
+ | "mail-resend"
25
+ | "rate-limit-upstash";
23
26
  /**
24
27
  * Databases supported by the starter's Drizzle persistence layer.
25
28
  */
26
29
  export type DatabaseName = "sqlite" | "postgres" | "mysql";
27
30
  /**
28
- * Provider setup presets supported by `beignet providers add`.
31
+ * Provider setup presets supported by `beignet provider add`.
29
32
  */
30
33
  export type ProviderPresetName =
31
34
  | "flags-openfeature"
@@ -35,13 +38,13 @@ export type ProviderPresetName =
35
38
  | "mail-smtp"
36
39
  | "payments-stripe"
37
40
  | "search-meilisearch"
38
- | "sentry"
39
- | "upstash-rate-limit"
40
- | "redis-cache"
41
+ | "error-reporting-sentry"
42
+ | "rate-limit-upstash"
43
+ | "cache-redis"
41
44
  | "event-bus-redis"
42
- | "redis-locks"
43
- | "s3-storage"
44
- | "vercel-blob-storage";
45
+ | "locks-redis"
46
+ | "storage-s3"
47
+ | "storage-vercel-blob";
45
48
 
46
49
  /**
47
50
  * Supported scaffold template choices.
@@ -61,13 +64,13 @@ export const packageManagerChoices = [
61
64
  ] as const satisfies readonly PackageManager[];
62
65
 
63
66
  /**
64
- * Supported scaffold integration choices.
67
+ * Supported providers rendered directly by the starter.
65
68
  */
66
- export const integrationChoices = [
67
- "inngest",
68
- "resend",
69
- "upstash-rate-limit",
70
- ] as const satisfies readonly IntegrationName[];
69
+ export const starterProviderChoices = [
70
+ "jobs-inngest",
71
+ "mail-resend",
72
+ "rate-limit-upstash",
73
+ ] as const satisfies readonly StarterProviderName[];
71
74
 
72
75
  /**
73
76
  * Supported scaffold database choices.
@@ -89,89 +92,45 @@ export const providerPresetChoices = [
89
92
  "mail-smtp",
90
93
  "payments-stripe",
91
94
  "search-meilisearch",
92
- "sentry",
93
- "upstash-rate-limit",
94
- "redis-cache",
95
+ "error-reporting-sentry",
96
+ "rate-limit-upstash",
97
+ "cache-redis",
95
98
  "event-bus-redis",
96
- "redis-locks",
97
- "s3-storage",
98
- "vercel-blob-storage",
99
+ "locks-redis",
100
+ "storage-s3",
101
+ "storage-vercel-blob",
99
102
  ] as const satisfies readonly ProviderPresetName[];
100
103
 
101
104
  /**
102
- * Values accepted by `beignet create --integrations`: the starter template
103
- * integrations plus the full `beignet providers add` preset catalog.
105
+ * Values accepted by `beignet create --providers`.
104
106
  */
105
- export type CreateIntegrationName = IntegrationName | ProviderPresetName;
107
+ export type CreateProviderName = ProviderPresetName;
106
108
 
107
109
  /**
108
- * Supported `beignet create --integrations` choices. Template integrations
109
- * come first; the rest of the provider preset catalog follows.
110
+ * Supported `beignet create --providers` choices.
110
111
  */
111
- export const createIntegrationChoices = [
112
- "inngest",
113
- "resend",
114
- "upstash-rate-limit",
115
- "flags-openfeature",
116
- "jobs-bullmq",
117
- "jobs-inngest",
118
- "mail-resend",
119
- "mail-smtp",
120
- "payments-stripe",
121
- "redis-cache",
122
- "event-bus-redis",
123
- "redis-locks",
124
- "s3-storage",
125
- "search-meilisearch",
126
- "sentry",
127
- "vercel-blob-storage",
128
- ] as const satisfies readonly CreateIntegrationName[];
129
-
130
- /**
131
- * Provider presets whose create-time wiring already ships as a starter
132
- * template integration. Selecting the preset name at create time scaffolds
133
- * the equivalent template integration, so preset and integration stay
134
- * consistent and `beignet providers add` remains a no-op afterwards.
135
- */
136
- const presetTemplateIntegrationAliases: Partial<
137
- Record<ProviderPresetName, IntegrationName>
138
- > = {
139
- "jobs-inngest": "inngest",
140
- "mail-resend": "resend",
141
- "upstash-rate-limit": "upstash-rate-limit",
142
- };
112
+ export const createProviderChoices = providerPresetChoices;
143
113
 
144
114
  /**
145
- * Split `--integrations` selections into starter template integrations and
146
- * provider presets applied with the `beignet providers add` machinery after
147
- * the scaffold is written. Preset names with a template equivalent are
148
- * normalized to the template integration; duplicates collapse.
115
+ * Split `--providers` selections into providers rendered directly by the
116
+ * starter and presets applied after the scaffold is written.
149
117
  */
150
- export function splitCreateIntegrations(
151
- values: readonly CreateIntegrationName[],
152
- ): {
153
- integrations: IntegrationName[];
118
+ export function splitCreateProviders(values: readonly CreateProviderName[]): {
119
+ starterProviders: StarterProviderName[];
154
120
  presets: ProviderPresetName[];
155
121
  } {
156
- const integrations = new Set<IntegrationName>();
122
+ const starterProviders = new Set<StarterProviderName>();
157
123
  const presets = new Set<ProviderPresetName>();
158
124
 
159
125
  for (const value of values) {
160
- if ((integrationChoices as readonly string[]).includes(value)) {
161
- integrations.add(value as IntegrationName);
162
- continue;
163
- }
164
-
165
- const preset = value as ProviderPresetName;
166
- const alias = presetTemplateIntegrationAliases[preset];
167
- if (alias) {
168
- integrations.add(alias);
126
+ if ((starterProviderChoices as readonly string[]).includes(value)) {
127
+ starterProviders.add(value as StarterProviderName);
169
128
  } else {
170
- presets.add(preset);
129
+ presets.add(value);
171
130
  }
172
131
  }
173
132
 
174
- return { integrations: [...integrations], presets: [...presets] };
133
+ return { starterProviders: [...starterProviders], presets: [...presets] };
175
134
  }
176
135
 
177
136
  /**
@@ -246,24 +205,15 @@ export const completionShellChoices = [
246
205
  export const makeFeatureAddonChoices = [
247
206
  "policy",
248
207
  "factory",
249
- "factories",
250
208
  "event",
251
- "events",
252
209
  "job",
253
- "jobs",
254
210
  "listener",
255
- "listeners",
256
211
  "notification",
257
- "notifications",
258
212
  "schedule",
259
- "schedules",
260
213
  "seed",
261
- "seeds",
262
214
  "task",
263
- "tasks",
264
215
  "ui",
265
216
  "upload",
266
- "uploads",
267
217
  ] as const;
268
218
 
269
219
  /**
package/src/config.ts CHANGED
@@ -6,7 +6,7 @@ import { createJiti } from "jiti";
6
6
  /**
7
7
  * Supported application framework targets for Beignet config.
8
8
  */
9
- export type BeignetFramework = "next";
9
+ export type BeignetFramework = "next" | "web";
10
10
 
11
11
  /**
12
12
  * Configurable app paths used by CLI generators, inspection, linting, and
@@ -306,11 +306,15 @@ function assertConfigObject(
306
306
  throw new Error(`${configFile} must export a Beignet config object.`);
307
307
  }
308
308
 
309
- if (config.framework !== undefined && config.framework !== "next") {
309
+ if (
310
+ config.framework !== undefined &&
311
+ config.framework !== "next" &&
312
+ config.framework !== "web"
313
+ ) {
310
314
  throw new Error(
311
315
  `${configFile} uses unsupported framework "${String(
312
316
  config.framework,
313
- )}". Supported framework: "next".`,
317
+ )}". Supported frameworks: "next", "web".`,
314
318
  );
315
319
  }
316
320
 
@@ -7,26 +7,25 @@
7
7
  */
8
8
 
9
9
  import {
10
- type CreateIntegrationName,
10
+ type CreateProviderName,
11
11
  type DatabaseName,
12
12
  databaseChoices,
13
- type IntegrationName,
14
- integrationChoices,
15
13
  type PackageManager,
14
+ type StarterProviderName,
15
+ starterProviderChoices,
16
16
  } from "./choices.js";
17
17
 
18
18
  /**
19
19
  * Selections shared by create flags and interactive prompt answers.
20
20
  *
21
- * `integrations` accepts the starter template integrations plus the full
22
- * `beignet providers add` preset catalog; the interactive prompt shows the
23
- * curated template list and points at the wider catalog.
21
+ * `providers` accepts the full `beignet provider add` preset catalog; the
22
+ * interactive prompt shows the providers rendered directly by the starter.
24
23
  */
25
24
  export type CreateSelections = {
26
25
  directory?: string;
27
26
  api?: boolean;
28
27
  db?: DatabaseName;
29
- integrations?: readonly CreateIntegrationName[];
28
+ providers?: readonly CreateProviderName[];
30
29
  packageManager?: PackageManager;
31
30
  };
32
31
 
@@ -43,7 +42,7 @@ type CreatePromptTty = {
43
42
  * Decide whether `beignet create` should run the interactive prompt flow.
44
43
  *
45
44
  * Prompts run only on a full TTY, only when `--yes` is absent, and only when
46
- * no selection flag was passed. Any explicit api, database, integration, or
45
+ * no selection flag was passed. Any explicit api, database, provider, or
47
46
  * package manager selection means the invocation is scripted, so the
48
47
  * non-interactive path stays byte-identical for agents and CI.
49
48
  */
@@ -57,16 +56,16 @@ export function shouldPromptInteractively(
57
56
  const selectionFlagPassed =
58
57
  flags.api !== undefined ||
59
58
  flags.db !== undefined ||
60
- (flags.integrations?.length ?? 0) > 0 ||
59
+ (flags.providers?.length ?? 0) > 0 ||
61
60
  flags.packageManager !== undefined;
62
61
 
63
62
  return !selectionFlagPassed;
64
63
  }
65
64
 
66
- const integrationHints: Record<IntegrationName, string> = {
67
- inngest: "Inngest-backed background jobs",
68
- resend: "Resend-backed mail provider",
69
- "upstash-rate-limit": "Upstash-backed rate limiting",
65
+ const providerHints: Record<StarterProviderName, string> = {
66
+ "jobs-inngest": "Inngest-backed background jobs",
67
+ "mail-resend": "Resend-backed mail provider",
68
+ "rate-limit-upstash": "Upstash-backed rate limiting",
70
69
  };
71
70
 
72
71
  const databaseHints: Record<DatabaseName, string> = {
@@ -118,17 +117,17 @@ export async function promptCreateSelections(
118
117
  });
119
118
  if (prompts.isCancel(db)) return undefined;
120
119
 
121
- const integrations = await prompts.multiselect<IntegrationName>({
120
+ const providers = await prompts.multiselect<StarterProviderName>({
122
121
  message:
123
- "Add provider integrations? (press enter to skip; the full preset catalog is available via --integrations or beignet providers add)",
124
- options: integrationChoices.map((integration) => ({
125
- value: integration,
126
- label: integration,
127
- hint: integrationHints[integration],
122
+ "Add providers? (press enter to skip; the full catalog is available via --providers or beignet provider add)",
123
+ options: starterProviderChoices.map((provider) => ({
124
+ value: provider,
125
+ label: provider,
126
+ hint: providerHints[provider],
128
127
  })),
129
128
  required: false,
130
129
  });
131
- if (prompts.isCancel(integrations)) return undefined;
130
+ if (prompts.isCancel(providers)) return undefined;
132
131
 
133
132
  prompts.outro(`Creating ${directory}`);
134
133
 
@@ -136,7 +135,7 @@ export async function promptCreateSelections(
136
135
  directory,
137
136
  api,
138
137
  db,
139
- integrations,
138
+ providers,
140
139
  packageManager: initial.packageManager,
141
140
  };
142
141
  }
package/src/create.ts CHANGED
@@ -4,9 +4,10 @@ import {
4
4
  type DatabaseName,
5
5
  databaseChoices,
6
6
  getTemplateFiles,
7
- type IntegrationName,
8
- integrationChoices,
9
7
  type PackageManager,
8
+ type StarterProviderName,
9
+ starterProviderChoices,
10
+ type TemplateFile,
10
11
  type TemplateName,
11
12
  } from "./templates/index.js";
12
13
  import { getCliVersion } from "./version.js";
@@ -23,7 +24,7 @@ export type CreateOptions = {
23
24
  */
24
25
  api?: boolean;
25
26
  packageManager?: PackageManager;
26
- integrations?: IntegrationName[];
27
+ providers?: StarterProviderName[];
27
28
  /**
28
29
  * Database backing the starter's Drizzle persistence layer.
29
30
  * Defaults to "sqlite".
@@ -47,19 +48,46 @@ export type CreateResult = {
47
48
  database: DatabaseName;
48
49
  };
49
50
 
51
+ export type CreateProjectPlan = {
52
+ result: CreateResult;
53
+ files: TemplateFile[];
54
+ };
55
+
50
56
  /**
51
57
  * Create a Beignet app from the starter template.
52
58
  */
53
59
  export async function createProject(
54
60
  options: CreateOptions,
55
61
  ): Promise<CreateResult> {
62
+ const plan = await planCreateProject(options);
63
+
64
+ if (!plan.result.dryRun) {
65
+ await mkdir(plan.result.targetDir, { recursive: true });
66
+
67
+ for (const file of plan.files) {
68
+ const destination = path.join(plan.result.targetDir, file.path);
69
+ await mkdir(path.dirname(destination), { recursive: true });
70
+ await writeFile(destination, file.content);
71
+ }
72
+ }
73
+
74
+ return plan.result;
75
+ }
76
+
77
+ /**
78
+ * Render a scaffold without writing it so create-time provider presets can
79
+ * compose against the exact same file contents as a real create.
80
+ */
81
+ export async function planCreateProject(
82
+ options: CreateOptions,
83
+ ): Promise<CreateProjectPlan> {
56
84
  const cwd = options.cwd ?? process.cwd();
57
85
  const name = normalizeProjectName(options.name);
58
86
  const targetDir = path.resolve(cwd, options.name);
59
87
  const packageManager = options.packageManager ?? "bun";
60
88
  const template = options.template ?? "next";
61
89
  const api = Boolean(options.api);
62
- const integrations = resolveIntegrations(options.integrations ?? []);
90
+ const providers = resolveStarterProviders(options.providers ?? []);
63
91
  const database = options.db ?? "sqlite";
64
92
 
65
93
  if (template !== "next") {
@@ -83,58 +111,48 @@ export async function createProject(
83
111
  packageManager,
84
112
  beignetVersion: options.beignetVersion ?? getDefaultBeignetVersion(),
85
113
  api,
86
- integrations,
114
+ providers,
87
115
  database,
88
116
  });
89
117
 
90
- if (!dryRun) {
91
- await mkdir(targetDir, { recursive: true });
92
-
93
- for (const file of files) {
94
- const destination = path.join(targetDir, file.path);
95
- await mkdir(path.dirname(destination), { recursive: true });
96
- await writeFile(destination, file.content);
97
- }
98
- }
99
-
100
118
  return {
101
- schemaVersion: 1,
102
- name,
103
- targetDir,
104
- dryRun,
105
- files: files.map((file) => file.path),
106
- packageManager,
107
- database,
119
+ result: {
120
+ schemaVersion: 1,
121
+ name,
122
+ targetDir,
123
+ dryRun,
124
+ files: files.map((file) => file.path),
125
+ packageManager,
126
+ database,
127
+ },
128
+ files,
108
129
  };
109
130
  }
110
131
 
111
132
  /**
112
- * Providers that ship in every starter. They used to be `--integrations`
113
- * choices, so passing them gets a pointed error instead of a generic one.
133
+ * Providers that ship in every starter are not selectable additions.
114
134
  */
115
135
  const baseProviderNames = new Set(["better-auth", "drizzle-sqlite", "pino"]);
116
136
 
117
- function resolveIntegrations(
118
- explicitIntegrations: IntegrationName[],
119
- ): IntegrationName[] {
120
- for (const integration of explicitIntegrations) {
121
- const integrationName: string = integration;
122
- if (baseProviderNames.has(integrationName)) {
137
+ function resolveStarterProviders(
138
+ explicitProviders: StarterProviderName[],
139
+ ): StarterProviderName[] {
140
+ for (const provider of explicitProviders) {
141
+ const providerName: string = provider;
142
+ if (baseProviderNames.has(providerName)) {
123
143
  const databaseHint =
124
- integrationName === "drizzle-sqlite"
144
+ providerName === "drizzle-sqlite"
125
145
  ? " Choose the starter database with --db sqlite|postgres|mysql instead."
126
146
  : "";
127
147
  throw new Error(
128
- `${integration} is part of every Beignet starter and no longer an --integrations choice.${databaseHint}`,
148
+ `${provider} is part of every Beignet starter and is not a --providers choice.${databaseHint}`,
129
149
  );
130
150
  }
131
151
  }
132
152
 
133
- const integrations = new Set<IntegrationName>(explicitIntegrations);
153
+ const providers = new Set<StarterProviderName>(explicitProviders);
134
154
 
135
- return integrationChoices.filter((integration) =>
136
- integrations.has(integration),
137
- );
155
+ return starterProviderChoices.filter((provider) => providers.has(provider));
138
156
  }
139
157
 
140
158
  function getDefaultBeignetVersion(): string {
@@ -0,0 +1,13 @@
1
+ import type { ResolvedBeignetConfig } from "./config.js";
2
+
3
+ export function assertNextFramework(
4
+ config: ResolvedBeignetConfig,
5
+ command: string,
6
+ generatedSurface: string,
7
+ ): void {
8
+ if (config.framework === "next") return;
9
+
10
+ throw new Error(
11
+ `${command} currently supports framework: "next" because it generates ${generatedSurface}. For framework: "web", define the framework-neutral artifact directly and mount its HTTP entrypoint through @beignet/web.`,
12
+ );
13
+ }