@beignet/cli 0.0.31 → 0.0.33

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 (107) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +70 -17
  3. package/dist/check.d.ts +2 -0
  4. package/dist/check.d.ts.map +1 -1
  5. package/dist/check.js +16 -0
  6. package/dist/check.js.map +1 -1
  7. package/dist/choices.d.ts +22 -2
  8. package/dist/choices.d.ts.map +1 -1
  9. package/dist/choices.js +62 -0
  10. package/dist/choices.js.map +1 -1
  11. package/dist/config.d.ts +2 -0
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +2 -0
  14. package/dist/config.js.map +1 -1
  15. package/dist/create-prompts.d.ts +6 -2
  16. package/dist/create-prompts.d.ts.map +1 -1
  17. package/dist/create-prompts.js +1 -1
  18. package/dist/create-prompts.js.map +1 -1
  19. package/dist/db.d.ts +5 -5
  20. package/dist/db.d.ts.map +1 -1
  21. package/dist/db.js +5 -5
  22. package/dist/db.js.map +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +386 -27
  25. package/dist/index.js.map +1 -1
  26. package/dist/inspect.d.ts +5 -0
  27. package/dist/inspect.d.ts.map +1 -1
  28. package/dist/inspect.js +805 -62
  29. package/dist/inspect.js.map +1 -1
  30. package/dist/make/inbox.d.ts.map +1 -1
  31. package/dist/make/inbox.js +5 -3
  32. package/dist/make/inbox.js.map +1 -1
  33. package/dist/make/payments.d.ts.map +1 -1
  34. package/dist/make/payments.js +58 -29
  35. package/dist/make/payments.js.map +1 -1
  36. package/dist/make/shared.d.ts +12 -3
  37. package/dist/make/shared.d.ts.map +1 -1
  38. package/dist/make/shared.js +52 -11
  39. package/dist/make/shared.js.map +1 -1
  40. package/dist/make/tenancy.d.ts.map +1 -1
  41. package/dist/make/tenancy.js +6 -4
  42. package/dist/make/tenancy.js.map +1 -1
  43. package/dist/make.d.ts.map +1 -1
  44. package/dist/make.js +136 -65
  45. package/dist/make.js.map +1 -1
  46. package/dist/outbox.d.ts +114 -1
  47. package/dist/outbox.d.ts.map +1 -1
  48. package/dist/outbox.js +190 -0
  49. package/dist/outbox.js.map +1 -1
  50. package/dist/preflight.d.ts +90 -0
  51. package/dist/preflight.d.ts.map +1 -0
  52. package/dist/preflight.js +423 -0
  53. package/dist/preflight.js.map +1 -0
  54. package/dist/provider-add.d.ts +10 -1
  55. package/dist/provider-add.d.ts.map +1 -1
  56. package/dist/provider-add.js +255 -16
  57. package/dist/provider-add.js.map +1 -1
  58. package/dist/task.d.ts.map +1 -1
  59. package/dist/task.js +2 -3
  60. package/dist/task.js.map +1 -1
  61. package/dist/templates/agents.d.ts.map +1 -1
  62. package/dist/templates/agents.js +6 -3
  63. package/dist/templates/agents.js.map +1 -1
  64. package/dist/templates/base.d.ts.map +1 -1
  65. package/dist/templates/base.js +5 -11
  66. package/dist/templates/base.js.map +1 -1
  67. package/dist/templates/index.d.ts.map +1 -1
  68. package/dist/templates/index.js +2 -0
  69. package/dist/templates/index.js.map +1 -1
  70. package/dist/templates/server.d.ts.map +1 -1
  71. package/dist/templates/server.js +10 -5
  72. package/dist/templates/server.js.map +1 -1
  73. package/dist/templates/shared.d.ts +5 -1
  74. package/dist/templates/shared.d.ts.map +1 -1
  75. package/dist/templates/shared.js +13 -1
  76. package/dist/templates/shared.js.map +1 -1
  77. package/dist/templates/testing.d.ts +5 -0
  78. package/dist/templates/testing.d.ts.map +1 -0
  79. package/dist/templates/testing.js +542 -0
  80. package/dist/templates/testing.js.map +1 -0
  81. package/dist/templates/todos.js +2 -2
  82. package/package.json +3 -2
  83. package/skills/app-structure/SKILL.md +12 -4
  84. package/src/check.ts +23 -0
  85. package/src/choices.ts +84 -0
  86. package/src/config.ts +4 -0
  87. package/src/create-prompts.ts +8 -2
  88. package/src/db.ts +12 -12
  89. package/src/index.ts +592 -37
  90. package/src/inspect.ts +1253 -156
  91. package/src/make/inbox.ts +5 -3
  92. package/src/make/payments.ts +58 -29
  93. package/src/make/shared.ts +87 -13
  94. package/src/make/tenancy.ts +6 -4
  95. package/src/make.ts +179 -65
  96. package/src/outbox.ts +363 -0
  97. package/src/preflight.ts +596 -0
  98. package/src/provider-add.ts +270 -16
  99. package/src/task.ts +2 -3
  100. package/src/templates/agents.ts +6 -3
  101. package/src/templates/base.ts +5 -13
  102. package/src/templates/index.ts +2 -0
  103. package/src/templates/server.ts +10 -5
  104. package/src/templates/shared.ts +15 -1
  105. package/src/templates/testing.ts +545 -0
  106. package/src/templates/todos.ts +2 -2
  107. package/src/test-helpers/generated-app.ts +10 -6
package/src/choices.ts CHANGED
@@ -29,12 +29,16 @@ export type DatabaseName = "sqlite" | "postgres" | "mysql";
29
29
  */
30
30
  export type ProviderPresetName =
31
31
  | "flags-openfeature"
32
+ | "jobs-bullmq"
33
+ | "jobs-inngest"
32
34
  | "mail-resend"
33
35
  | "mail-smtp"
36
+ | "payments-stripe"
34
37
  | "search-meilisearch"
35
38
  | "sentry"
36
39
  | "upstash-rate-limit"
37
40
  | "redis-cache"
41
+ | "event-bus-redis"
38
42
  | "redis-locks"
39
43
  | "s3-storage"
40
44
  | "vercel-blob-storage";
@@ -79,17 +83,97 @@ export const databaseChoices = [
79
83
  */
80
84
  export const providerPresetChoices = [
81
85
  "flags-openfeature",
86
+ "jobs-bullmq",
87
+ "jobs-inngest",
82
88
  "mail-resend",
83
89
  "mail-smtp",
90
+ "payments-stripe",
84
91
  "search-meilisearch",
85
92
  "sentry",
86
93
  "upstash-rate-limit",
87
94
  "redis-cache",
95
+ "event-bus-redis",
88
96
  "redis-locks",
89
97
  "s3-storage",
90
98
  "vercel-blob-storage",
91
99
  ] as const satisfies readonly ProviderPresetName[];
92
100
 
101
+ /**
102
+ * Values accepted by `beignet create --integrations`: the starter template
103
+ * integrations plus the full `beignet providers add` preset catalog.
104
+ */
105
+ export type CreateIntegrationName = IntegrationName | ProviderPresetName;
106
+
107
+ /**
108
+ * Supported `beignet create --integrations` choices. Template integrations
109
+ * come first; the rest of the provider preset catalog follows.
110
+ */
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
+ };
143
+
144
+ /**
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.
149
+ */
150
+ export function splitCreateIntegrations(
151
+ values: readonly CreateIntegrationName[],
152
+ ): {
153
+ integrations: IntegrationName[];
154
+ presets: ProviderPresetName[];
155
+ } {
156
+ const integrations = new Set<IntegrationName>();
157
+ const presets = new Set<ProviderPresetName>();
158
+
159
+ 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);
169
+ } else {
170
+ presets.add(preset);
171
+ }
172
+ }
173
+
174
+ return { integrations: [...integrations], presets: [...presets] };
175
+ }
176
+
93
177
  /**
94
178
  * Local database name derived from the app name.
95
179
  *
package/src/config.ts CHANGED
@@ -16,6 +16,7 @@ export type BeignetPaths = {
16
16
  contracts: string;
17
17
  routes: string;
18
18
  server: string;
19
+ listeners: string;
19
20
  openapiRoute: string;
20
21
  tasks: string;
21
22
  outbox: string;
@@ -32,6 +33,7 @@ export type BeignetPaths = {
32
33
  schedulesBuilder: string;
33
34
  notificationsBuilder: string;
34
35
  tasksBuilder: string;
36
+ uploadsBuilder: string;
35
37
  tests: string;
36
38
  };
37
39
 
@@ -84,6 +86,7 @@ export const defaultBeignetConfig: ResolvedBeignetConfig = {
84
86
  contracts: "features",
85
87
  routes: "app/api",
86
88
  server: "server/index.ts",
89
+ listeners: "server/listeners.ts",
87
90
  openapiRoute: "app/api/openapi/route.ts",
88
91
  tasks: "server/tasks.ts",
89
92
  outbox: "server/outbox.ts",
@@ -100,6 +103,7 @@ export const defaultBeignetConfig: ResolvedBeignetConfig = {
100
103
  schedulesBuilder: "lib/schedules.ts",
101
104
  notificationsBuilder: "lib/notifications.ts",
102
105
  tasksBuilder: "lib/tasks.ts",
106
+ uploadsBuilder: "lib/uploads.ts",
103
107
  tests: "tests",
104
108
  },
105
109
  database: {
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import {
10
+ type CreateIntegrationName,
10
11
  type DatabaseName,
11
12
  databaseChoices,
12
13
  type IntegrationName,
@@ -16,12 +17,16 @@ import {
16
17
 
17
18
  /**
18
19
  * Selections shared by create flags and interactive prompt answers.
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.
19
24
  */
20
25
  export type CreateSelections = {
21
26
  directory?: string;
22
27
  api?: boolean;
23
28
  db?: DatabaseName;
24
- integrations?: readonly IntegrationName[];
29
+ integrations?: readonly CreateIntegrationName[];
25
30
  packageManager?: PackageManager;
26
31
  };
27
32
 
@@ -114,7 +119,8 @@ export async function promptCreateSelections(
114
119
  if (prompts.isCancel(db)) return undefined;
115
120
 
116
121
  const integrations = await prompts.multiselect<IntegrationName>({
117
- message: "Add provider integrations? (press enter to skip)",
122
+ message:
123
+ "Add provider integrations? (press enter to skip; the full preset catalog is available via --integrations or beignet providers add)",
118
124
  options: integrationChoices.map((integration) => ({
119
125
  value: integration,
120
126
  label: integration,
package/src/db.ts CHANGED
@@ -36,7 +36,7 @@ export type RunDatabaseCommandResult = {
36
36
  export type DatabaseSchemaDialect = "sqlite" | "postgres" | "mysql";
37
37
  export type DatabaseSchemaTable = "audit" | "idempotency" | "outbox";
38
38
 
39
- export type GenerateDatabaseSchemaOptions = {
39
+ export type SyncDatabaseSchemaOptions = {
40
40
  cwd?: string;
41
41
  dialect?: DatabaseSchemaDialect;
42
42
  tables?: readonly DatabaseSchemaTable[];
@@ -44,9 +44,9 @@ export type GenerateDatabaseSchemaOptions = {
44
44
  dryRun?: boolean;
45
45
  };
46
46
 
47
- export type GenerateDatabaseSchemaResult = {
47
+ export type SyncDatabaseSchemaResult = {
48
48
  schemaVersion: 1;
49
- command: "schema:generate";
49
+ command: "schema:sync";
50
50
  cwd: string;
51
51
  dialect: DatabaseSchemaDialect;
52
52
  tables: DatabaseSchemaTable[];
@@ -132,15 +132,15 @@ export async function runDatabaseCommand(
132
132
  }
133
133
 
134
134
  /**
135
- * Generate the app-owned Drizzle schema entrypoint for Beignet provider tables.
135
+ * Sync the app-owned Drizzle schema entrypoint for Beignet provider tables.
136
136
  *
137
137
  * This only writes schema source. The app still owns SQL migration generation
138
138
  * through `beignet db generate` and migration application through
139
139
  * `beignet db migrate`.
140
140
  */
141
- export async function generateDatabaseSchema(
142
- options: GenerateDatabaseSchemaOptions = {},
143
- ): Promise<GenerateDatabaseSchemaResult> {
141
+ export async function syncDatabaseSchema(
142
+ options: SyncDatabaseSchemaOptions = {},
143
+ ): Promise<SyncDatabaseSchemaResult> {
144
144
  const cwd = path.resolve(options.cwd ?? process.cwd());
145
145
  const dialect = await resolveDatabaseSchemaDialect(cwd, options.dialect);
146
146
  const tables = uniqueSchemaTables(options.tables ?? allDatabaseSchemaTables);
@@ -159,9 +159,9 @@ export async function generateDatabaseSchema(
159
159
  throw new Error("Schema output must not be the schema index file.");
160
160
  }
161
161
 
162
- const result: GenerateDatabaseSchemaResult = {
162
+ const result: SyncDatabaseSchemaResult = {
163
163
  schemaVersion: 1,
164
- command: "schema:generate",
164
+ command: "schema:sync",
165
165
  cwd,
166
166
  dialect,
167
167
  tables,
@@ -345,7 +345,7 @@ function renderDatabaseSchema(
345
345
  const tableNames = selectedTables.map((table) => table.tableName);
346
346
  const exportNames = selectedTables.map((table) => table.exportName).sort();
347
347
 
348
- return `// Generated by beignet db schema generate.
348
+ return `// Managed by beignet db schema sync.
349
349
  // Required tables: ${tableNames.join(", ")}.
350
350
  // Re-run this command after upgrading @beignet/provider-db-drizzle.
351
351
 
@@ -437,7 +437,7 @@ async function readTextIfExists(file: string): Promise<string | undefined> {
437
437
  }
438
438
 
439
439
  function recordFileStatus(
440
- result: GenerateDatabaseSchemaResult,
440
+ result: SyncDatabaseSchemaResult,
441
441
  file: string,
442
442
  status: FileWriteStatus,
443
443
  ): void {
@@ -464,7 +464,7 @@ function missingDatabaseScriptMessage(
464
464
 
465
465
  const entrypoint =
466
466
  command === "seed" ? "server/seed.ts" : "infra/db/reset.ts";
467
- return `Missing package.json script "${script}". Standard Drizzle apps use "${script}": "bun ${entrypoint}" so beignet db ${command} can run the app-owned ${command} entrypoint.`;
467
+ return `Missing package.json script "${script}". Standard Drizzle apps use "${script}": "tsx ${entrypoint}" so beignet db ${command} can run the app-owned ${command} entrypoint.`;
468
468
  }
469
469
 
470
470
  async function readPackageJson(cwd: string): Promise<PackageJson> {