@beignet/cli 0.0.37 → 0.0.39

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 (113) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +138 -101
  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 +1 -1
  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/index.d.ts.map +1 -1
  20. package/dist/index.js +149 -47
  21. package/dist/index.js.map +1 -1
  22. package/dist/inspect.js +69 -16
  23. package/dist/inspect.js.map +1 -1
  24. package/dist/lib.d.ts +1 -1
  25. package/dist/lib.d.ts.map +1 -1
  26. package/dist/lint.d.ts.map +1 -1
  27. package/dist/lint.js +27 -6
  28. package/dist/lint.js.map +1 -1
  29. package/dist/make/inbox.js +10 -10
  30. package/dist/make/inbox.js.map +1 -1
  31. package/dist/make/payments.d.ts +2 -1
  32. package/dist/make/payments.d.ts.map +1 -1
  33. package/dist/make/payments.js +18 -14
  34. package/dist/make/payments.js.map +1 -1
  35. package/dist/make/shared.d.ts +11 -4
  36. package/dist/make/shared.d.ts.map +1 -1
  37. package/dist/make/shared.js +56 -45
  38. package/dist/make/shared.js.map +1 -1
  39. package/dist/make/tenancy.js +8 -8
  40. package/dist/make/tenancy.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 +481 -200
  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/operational-error-reporting.d.ts +15 -0
  49. package/dist/operational-error-reporting.d.ts.map +1 -0
  50. package/dist/operational-error-reporting.js +42 -0
  51. package/dist/operational-error-reporting.js.map +1 -0
  52. package/dist/outbox.d.ts.map +1 -1
  53. package/dist/outbox.js +73 -0
  54. package/dist/outbox.js.map +1 -1
  55. package/dist/provider-add.d.ts +21 -3
  56. package/dist/provider-add.d.ts.map +1 -1
  57. package/dist/provider-add.js +117 -81
  58. package/dist/provider-add.js.map +1 -1
  59. package/dist/provider-audit.js +3 -3
  60. package/dist/provider-audit.js.map +1 -1
  61. package/dist/schedule.d.ts.map +1 -1
  62. package/dist/schedule.js +28 -1
  63. package/dist/schedule.js.map +1 -1
  64. package/dist/task.d.ts.map +1 -1
  65. package/dist/task.js +38 -5
  66. package/dist/task.js.map +1 -1
  67. package/dist/templates/base.d.ts +1 -1
  68. package/dist/templates/base.d.ts.map +1 -1
  69. package/dist/templates/base.js +15 -15
  70. package/dist/templates/base.js.map +1 -1
  71. package/dist/templates/index.d.ts +2 -2
  72. package/dist/templates/index.d.ts.map +1 -1
  73. package/dist/templates/index.js +7 -7
  74. package/dist/templates/index.js.map +1 -1
  75. package/dist/templates/server.d.ts +1 -1
  76. package/dist/templates/server.d.ts.map +1 -1
  77. package/dist/templates/server.js +22 -18
  78. package/dist/templates/server.js.map +1 -1
  79. package/dist/templates/shared.d.ts +4 -4
  80. package/dist/templates/shared.d.ts.map +1 -1
  81. package/dist/templates/shared.js +6 -6
  82. package/dist/templates/shared.js.map +1 -1
  83. package/dist/templates/testing.js +1 -1
  84. package/dist/templates/todos.js +6 -6
  85. package/package.json +4 -4
  86. package/skills/app-structure/SKILL.md +13 -8
  87. package/src/choices.ts +38 -88
  88. package/src/config.ts +2 -2
  89. package/src/create-prompts.ts +20 -21
  90. package/src/create.ts +54 -36
  91. package/src/index.ts +193 -65
  92. package/src/inspect.ts +116 -18
  93. package/src/lib.ts +1 -1
  94. package/src/lint.ts +35 -4
  95. package/src/make/inbox.ts +10 -10
  96. package/src/make/payments.ts +26 -18
  97. package/src/make/shared.ts +72 -50
  98. package/src/make/tenancy.ts +8 -8
  99. package/src/make.ts +607 -191
  100. package/src/mcp.ts +20 -13
  101. package/src/operational-error-reporting.ts +60 -0
  102. package/src/outbox.ts +77 -0
  103. package/src/provider-add.ts +179 -95
  104. package/src/provider-audit.ts +3 -3
  105. package/src/schedule.ts +32 -1
  106. package/src/task.ts +42 -5
  107. package/src/templates/base.ts +16 -16
  108. package/src/templates/index.ts +8 -8
  109. package/src/templates/server.ts +22 -18
  110. package/src/templates/shared.ts +10 -10
  111. package/src/templates/testing.ts +1 -1
  112. package/src/templates/todos.ts +6 -6
  113. package/src/test-helpers/generated-app.ts +1 -0
@@ -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 {