@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.
- package/CHANGELOG.md +107 -0
- package/README.md +70 -17
- package/dist/check.d.ts +2 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +16 -0
- package/dist/check.js.map +1 -1
- package/dist/choices.d.ts +22 -2
- package/dist/choices.d.ts.map +1 -1
- package/dist/choices.js +62 -0
- package/dist/choices.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/create-prompts.d.ts +6 -2
- package/dist/create-prompts.d.ts.map +1 -1
- package/dist/create-prompts.js +1 -1
- package/dist/create-prompts.js.map +1 -1
- package/dist/db.d.ts +5 -5
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +5 -5
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +386 -27
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +5 -0
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +805 -62
- package/dist/inspect.js.map +1 -1
- package/dist/make/inbox.d.ts.map +1 -1
- package/dist/make/inbox.js +5 -3
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.d.ts.map +1 -1
- package/dist/make/payments.js +58 -29
- package/dist/make/payments.js.map +1 -1
- package/dist/make/shared.d.ts +12 -3
- package/dist/make/shared.d.ts.map +1 -1
- package/dist/make/shared.js +52 -11
- package/dist/make/shared.js.map +1 -1
- package/dist/make/tenancy.d.ts.map +1 -1
- package/dist/make/tenancy.js +6 -4
- package/dist/make/tenancy.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +136 -65
- package/dist/make.js.map +1 -1
- package/dist/outbox.d.ts +114 -1
- package/dist/outbox.d.ts.map +1 -1
- package/dist/outbox.js +190 -0
- package/dist/outbox.js.map +1 -1
- package/dist/preflight.d.ts +90 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +423 -0
- package/dist/preflight.js.map +1 -0
- package/dist/provider-add.d.ts +10 -1
- package/dist/provider-add.d.ts.map +1 -1
- package/dist/provider-add.js +255 -16
- package/dist/provider-add.js.map +1 -1
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +2 -3
- package/dist/task.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +6 -3
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +5 -11
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +2 -0
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +10 -5
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +5 -1
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +13 -1
- package/dist/templates/shared.js.map +1 -1
- package/dist/templates/testing.d.ts +5 -0
- package/dist/templates/testing.d.ts.map +1 -0
- package/dist/templates/testing.js +542 -0
- package/dist/templates/testing.js.map +1 -0
- package/dist/templates/todos.js +2 -2
- package/package.json +3 -2
- package/skills/app-structure/SKILL.md +12 -4
- package/src/check.ts +23 -0
- package/src/choices.ts +84 -0
- package/src/config.ts +4 -0
- package/src/create-prompts.ts +8 -2
- package/src/db.ts +12 -12
- package/src/index.ts +592 -37
- package/src/inspect.ts +1253 -156
- package/src/make/inbox.ts +5 -3
- package/src/make/payments.ts +58 -29
- package/src/make/shared.ts +87 -13
- package/src/make/tenancy.ts +6 -4
- package/src/make.ts +179 -65
- package/src/outbox.ts +363 -0
- package/src/preflight.ts +596 -0
- package/src/provider-add.ts +270 -16
- package/src/task.ts +2 -3
- package/src/templates/agents.ts +6 -3
- package/src/templates/base.ts +5 -13
- package/src/templates/index.ts +2 -0
- package/src/templates/server.ts +10 -5
- package/src/templates/shared.ts +15 -1
- package/src/templates/testing.ts +545 -0
- package/src/templates/todos.ts +2 -2
- package/src/test-helpers/generated-app.ts +10 -6
package/src/index.ts
CHANGED
|
@@ -15,12 +15,13 @@ import {
|
|
|
15
15
|
} from "@stricli/core";
|
|
16
16
|
import {
|
|
17
17
|
type CompletionShell,
|
|
18
|
+
type CreateIntegrationName,
|
|
18
19
|
completionShellChoices,
|
|
20
|
+
createIntegrationChoices,
|
|
19
21
|
type DatabaseName,
|
|
20
22
|
databaseChoices,
|
|
21
23
|
databaseStartCommand,
|
|
22
24
|
type IntegrationName,
|
|
23
|
-
integrationChoices,
|
|
24
25
|
type MakeFeatureAddon,
|
|
25
26
|
type MakeFeatureRecipe,
|
|
26
27
|
makeFeatureAddonChoices,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
type ProviderPresetName,
|
|
30
31
|
packageManagerChoices,
|
|
31
32
|
providerPresetChoices,
|
|
33
|
+
splitCreateIntegrations,
|
|
32
34
|
type TemplateName,
|
|
33
35
|
templateChoices,
|
|
34
36
|
} from "./choices.js";
|
|
@@ -54,7 +56,7 @@ type CreateFlags = {
|
|
|
54
56
|
api?: boolean;
|
|
55
57
|
db?: DatabaseName;
|
|
56
58
|
packageManager?: PackageManager;
|
|
57
|
-
integrations?: readonly
|
|
59
|
+
integrations?: readonly CreateIntegrationName[];
|
|
58
60
|
yes?: boolean;
|
|
59
61
|
force?: boolean;
|
|
60
62
|
dryRun?: boolean;
|
|
@@ -108,6 +110,16 @@ type LintFlags = {
|
|
|
108
110
|
type CheckFlags = {
|
|
109
111
|
json?: boolean;
|
|
110
112
|
fix?: boolean;
|
|
113
|
+
preflight?: boolean;
|
|
114
|
+
cwd?: string;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
type PreflightFlags = {
|
|
118
|
+
json?: boolean;
|
|
119
|
+
envFile?: string;
|
|
120
|
+
envModule?: string;
|
|
121
|
+
connect?: boolean;
|
|
122
|
+
serverModule?: string;
|
|
111
123
|
cwd?: string;
|
|
112
124
|
};
|
|
113
125
|
|
|
@@ -131,7 +143,7 @@ const databaseSchemaTableChoices = [
|
|
|
131
143
|
"outbox",
|
|
132
144
|
] as const satisfies readonly DatabaseSchemaTable[];
|
|
133
145
|
|
|
134
|
-
type
|
|
146
|
+
type DbSchemaSyncFlags = DbFlags & {
|
|
135
147
|
dialect?: DatabaseSchemaDialect;
|
|
136
148
|
tables?: readonly DatabaseSchemaTable[];
|
|
137
149
|
output?: string;
|
|
@@ -150,6 +162,60 @@ type OutboxDrainFlags = {
|
|
|
150
162
|
batchSize?: number;
|
|
151
163
|
};
|
|
152
164
|
|
|
165
|
+
type OutboxMessageStatus = "pending" | "claimed" | "delivered" | "deadLettered";
|
|
166
|
+
|
|
167
|
+
type OutboxMessageKind = "event" | "job";
|
|
168
|
+
|
|
169
|
+
const outboxMessageStatusChoices = [
|
|
170
|
+
"pending",
|
|
171
|
+
"claimed",
|
|
172
|
+
"delivered",
|
|
173
|
+
"deadLettered",
|
|
174
|
+
] as const satisfies readonly OutboxMessageStatus[];
|
|
175
|
+
|
|
176
|
+
const outboxMessageKindChoices = [
|
|
177
|
+
"event",
|
|
178
|
+
"job",
|
|
179
|
+
] as const satisfies readonly OutboxMessageKind[];
|
|
180
|
+
|
|
181
|
+
type OutboxListFlags = {
|
|
182
|
+
json?: boolean;
|
|
183
|
+
module?: string;
|
|
184
|
+
status?: OutboxMessageStatus;
|
|
185
|
+
kind?: OutboxMessageKind;
|
|
186
|
+
name?: string;
|
|
187
|
+
limit?: number;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
type OutboxShowFlags = {
|
|
191
|
+
json?: boolean;
|
|
192
|
+
module?: string;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
type OutboxRequeueFlags = {
|
|
196
|
+
json?: boolean;
|
|
197
|
+
module?: string;
|
|
198
|
+
availableAt?: Date;
|
|
199
|
+
resetAttempts?: boolean;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
type OutboxPurgeFlags = {
|
|
203
|
+
json?: boolean;
|
|
204
|
+
module?: string;
|
|
205
|
+
before?: Date;
|
|
206
|
+
all?: boolean;
|
|
207
|
+
limit?: number;
|
|
208
|
+
dryRun?: boolean;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
type OutboxPruneFlags = {
|
|
212
|
+
json?: boolean;
|
|
213
|
+
module?: string;
|
|
214
|
+
before?: Date;
|
|
215
|
+
limit?: number;
|
|
216
|
+
dryRun?: boolean;
|
|
217
|
+
};
|
|
218
|
+
|
|
153
219
|
type ScheduleRunFlags = {
|
|
154
220
|
json?: boolean;
|
|
155
221
|
module?: string;
|
|
@@ -203,6 +269,13 @@ const parsePositiveInteger = (input: string): number => {
|
|
|
203
269
|
}
|
|
204
270
|
return value;
|
|
205
271
|
};
|
|
272
|
+
const parseDate = (input: string): Date => {
|
|
273
|
+
const value = new Date(input);
|
|
274
|
+
if (Number.isNaN(value.getTime())) {
|
|
275
|
+
throw new Error("Expected a valid date.");
|
|
276
|
+
}
|
|
277
|
+
return value;
|
|
278
|
+
};
|
|
206
279
|
|
|
207
280
|
const forceFlag = {
|
|
208
281
|
kind: "boolean",
|
|
@@ -218,6 +291,13 @@ const dryRunFlag = {
|
|
|
218
291
|
brief: "Preview generated changes without writing files.",
|
|
219
292
|
} as const;
|
|
220
293
|
|
|
294
|
+
const operationDryRunFlag = {
|
|
295
|
+
kind: "boolean",
|
|
296
|
+
optional: true,
|
|
297
|
+
withNegated: false,
|
|
298
|
+
brief: "Report matching records without deleting them.",
|
|
299
|
+
} as const;
|
|
300
|
+
|
|
221
301
|
const jsonFlag = {
|
|
222
302
|
kind: "boolean",
|
|
223
303
|
optional: true,
|
|
@@ -233,6 +313,14 @@ const parsedStringFlag = (brief: string) =>
|
|
|
233
313
|
brief,
|
|
234
314
|
}) as const;
|
|
235
315
|
|
|
316
|
+
const parsedDateFlag = (brief: string) =>
|
|
317
|
+
({
|
|
318
|
+
kind: "parsed",
|
|
319
|
+
parse: parseDate,
|
|
320
|
+
optional: true,
|
|
321
|
+
brief,
|
|
322
|
+
}) as const;
|
|
323
|
+
|
|
236
324
|
const cwdFlag = parsedStringFlag(
|
|
237
325
|
"App directory to inspect. Defaults to the current working directory.",
|
|
238
326
|
);
|
|
@@ -278,14 +366,14 @@ const dbFlagParameters = {
|
|
|
278
366
|
dryRun: dryRunFlag,
|
|
279
367
|
} satisfies FlagParametersForType<DbFlags, CliContext>;
|
|
280
368
|
|
|
281
|
-
const
|
|
369
|
+
const dbSchemaSyncFlagParameters = {
|
|
282
370
|
...dbFlagParameters,
|
|
283
371
|
dialect: {
|
|
284
372
|
kind: "enum",
|
|
285
373
|
values: databaseSchemaDialectChoices,
|
|
286
374
|
optional: true,
|
|
287
375
|
brief:
|
|
288
|
-
"Drizzle dialect to
|
|
376
|
+
"Drizzle dialect to sync. Inferred from server/providers.ts when omitted.",
|
|
289
377
|
},
|
|
290
378
|
tables: {
|
|
291
379
|
kind: "enum",
|
|
@@ -293,12 +381,12 @@ const dbSchemaGenerateFlagParameters = {
|
|
|
293
381
|
optional: true,
|
|
294
382
|
variadic: ",",
|
|
295
383
|
brief:
|
|
296
|
-
"Provider tables to
|
|
384
|
+
"Provider tables to sync as a comma-separated list. Defaults to audit,idempotency,outbox.",
|
|
297
385
|
},
|
|
298
386
|
output: parsedStringFlag(
|
|
299
|
-
"
|
|
387
|
+
"Synced schema file. Defaults to infra/db/schema/beignet.ts.",
|
|
300
388
|
),
|
|
301
|
-
} satisfies FlagParametersForType<
|
|
389
|
+
} satisfies FlagParametersForType<DbSchemaSyncFlags, CliContext>;
|
|
302
390
|
|
|
303
391
|
const taskRunFlagParameters = {
|
|
304
392
|
json: jsonFlag,
|
|
@@ -324,6 +412,95 @@ const outboxDrainFlagParameters = {
|
|
|
324
412
|
},
|
|
325
413
|
} satisfies FlagParametersForType<OutboxDrainFlags, CliContext>;
|
|
326
414
|
|
|
415
|
+
const outboxListFlagParameters = {
|
|
416
|
+
json: jsonFlag,
|
|
417
|
+
module: parsedStringFlag(
|
|
418
|
+
"Outbox registry module. Defaults to server/outbox.ts.",
|
|
419
|
+
),
|
|
420
|
+
status: {
|
|
421
|
+
kind: "enum",
|
|
422
|
+
values: outboxMessageStatusChoices,
|
|
423
|
+
optional: true,
|
|
424
|
+
brief: "Filter by outbox message status.",
|
|
425
|
+
},
|
|
426
|
+
kind: {
|
|
427
|
+
kind: "enum",
|
|
428
|
+
values: outboxMessageKindChoices,
|
|
429
|
+
optional: true,
|
|
430
|
+
brief: "Filter by outbox message kind.",
|
|
431
|
+
},
|
|
432
|
+
name: parsedStringFlag("Filter by event or job name."),
|
|
433
|
+
limit: {
|
|
434
|
+
kind: "parsed",
|
|
435
|
+
parse: parsePositiveInteger,
|
|
436
|
+
optional: true,
|
|
437
|
+
brief: "Maximum messages to return. Defaults to 50.",
|
|
438
|
+
},
|
|
439
|
+
} satisfies FlagParametersForType<OutboxListFlags, CliContext>;
|
|
440
|
+
|
|
441
|
+
const outboxShowFlagParameters = {
|
|
442
|
+
json: jsonFlag,
|
|
443
|
+
module: parsedStringFlag(
|
|
444
|
+
"Outbox registry module. Defaults to server/outbox.ts.",
|
|
445
|
+
),
|
|
446
|
+
} satisfies FlagParametersForType<OutboxShowFlags, CliContext>;
|
|
447
|
+
|
|
448
|
+
const outboxRequeueFlagParameters = {
|
|
449
|
+
json: jsonFlag,
|
|
450
|
+
module: parsedStringFlag(
|
|
451
|
+
"Outbox registry module. Defaults to server/outbox.ts.",
|
|
452
|
+
),
|
|
453
|
+
availableAt: parsedDateFlag(
|
|
454
|
+
"Earliest timestamp the requeued message may be claimed. Defaults to now.",
|
|
455
|
+
),
|
|
456
|
+
resetAttempts: {
|
|
457
|
+
kind: "boolean",
|
|
458
|
+
optional: true,
|
|
459
|
+
withNegated: false,
|
|
460
|
+
brief: "Reset attempts to zero before requeueing.",
|
|
461
|
+
},
|
|
462
|
+
} satisfies FlagParametersForType<OutboxRequeueFlags, CliContext>;
|
|
463
|
+
|
|
464
|
+
const outboxPurgeFlagParameters = {
|
|
465
|
+
json: jsonFlag,
|
|
466
|
+
module: parsedStringFlag(
|
|
467
|
+
"Outbox registry module. Defaults to server/outbox.ts.",
|
|
468
|
+
),
|
|
469
|
+
before: parsedDateFlag(
|
|
470
|
+
"Only purge dead-lettered messages last updated before this timestamp.",
|
|
471
|
+
),
|
|
472
|
+
all: {
|
|
473
|
+
kind: "boolean",
|
|
474
|
+
optional: true,
|
|
475
|
+
withNegated: false,
|
|
476
|
+
brief: "Purge every dead-lettered message when --before is omitted.",
|
|
477
|
+
},
|
|
478
|
+
limit: {
|
|
479
|
+
kind: "parsed",
|
|
480
|
+
parse: parsePositiveInteger,
|
|
481
|
+
optional: true,
|
|
482
|
+
brief: "Maximum messages to purge.",
|
|
483
|
+
},
|
|
484
|
+
dryRun: operationDryRunFlag,
|
|
485
|
+
} satisfies FlagParametersForType<OutboxPurgeFlags, CliContext>;
|
|
486
|
+
|
|
487
|
+
const outboxPruneFlagParameters = {
|
|
488
|
+
json: jsonFlag,
|
|
489
|
+
module: parsedStringFlag(
|
|
490
|
+
"Outbox registry module. Defaults to server/outbox.ts.",
|
|
491
|
+
),
|
|
492
|
+
before: parsedDateFlag(
|
|
493
|
+
"Prune delivered messages delivered before this timestamp.",
|
|
494
|
+
),
|
|
495
|
+
limit: {
|
|
496
|
+
kind: "parsed",
|
|
497
|
+
parse: parsePositiveInteger,
|
|
498
|
+
optional: true,
|
|
499
|
+
brief: "Maximum messages to prune.",
|
|
500
|
+
},
|
|
501
|
+
dryRun: operationDryRunFlag,
|
|
502
|
+
} satisfies FlagParametersForType<OutboxPruneFlags, CliContext>;
|
|
503
|
+
|
|
327
504
|
const scheduleRunFlagParameters = {
|
|
328
505
|
json: jsonFlag,
|
|
329
506
|
module: parsedStringFlag(
|
|
@@ -353,6 +530,17 @@ const namePositional = {
|
|
|
353
530
|
],
|
|
354
531
|
} as const;
|
|
355
532
|
|
|
533
|
+
const idPositional = {
|
|
534
|
+
kind: "tuple",
|
|
535
|
+
parameters: [
|
|
536
|
+
{
|
|
537
|
+
parse: parseString,
|
|
538
|
+
placeholder: "id",
|
|
539
|
+
brief: "Outbox message ID.",
|
|
540
|
+
},
|
|
541
|
+
],
|
|
542
|
+
} as const;
|
|
543
|
+
|
|
356
544
|
const providerPresetPositional = {
|
|
357
545
|
kind: "tuple",
|
|
358
546
|
parameters: [
|
|
@@ -400,7 +588,11 @@ and a shadcn UI shell. Pass --api for an API-only scaffold without the
|
|
|
400
588
|
UI shell, and --db to choose the database.
|
|
401
589
|
|
|
402
590
|
Available databases: ${databaseChoices.join(", ")}
|
|
403
|
-
Available integrations: ${
|
|
591
|
+
Available integrations: ${createIntegrationChoices.join(", ")}
|
|
592
|
+
|
|
593
|
+
--integrations accepts the starter template integrations plus the full
|
|
594
|
+
beignet providers add preset catalog; presets are applied to the scaffold
|
|
595
|
+
with the same machinery as beignet providers add.
|
|
404
596
|
|
|
405
597
|
Running create on an interactive terminal without selection flags opens a
|
|
406
598
|
prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
@@ -433,10 +625,11 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
433
625
|
},
|
|
434
626
|
integrations: {
|
|
435
627
|
kind: "enum",
|
|
436
|
-
values:
|
|
628
|
+
values: createIntegrationChoices,
|
|
437
629
|
optional: true,
|
|
438
630
|
variadic: ",",
|
|
439
|
-
brief:
|
|
631
|
+
brief:
|
|
632
|
+
"Add first-party integrations or provider presets as a comma-separated list.",
|
|
440
633
|
},
|
|
441
634
|
yes: {
|
|
442
635
|
kind: "boolean",
|
|
@@ -504,7 +697,18 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
504
697
|
|
|
505
698
|
const api = selections.api ?? false;
|
|
506
699
|
const database = selections.db ?? "sqlite";
|
|
507
|
-
const integrations =
|
|
700
|
+
const { integrations, presets } = splitCreateIntegrations(
|
|
701
|
+
uniqueValues([...(selections.integrations ?? [])]),
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
let presetsNeedEnv = false;
|
|
705
|
+
if (presets.length > 0) {
|
|
706
|
+
const { assertCompatibleCreatePresets, providerPresetNeedsEnv } =
|
|
707
|
+
await import("./provider-add.js");
|
|
708
|
+
assertCompatibleCreatePresets(presets, integrations);
|
|
709
|
+
presetsNeedEnv = presets.some(providerPresetNeedsEnv);
|
|
710
|
+
}
|
|
711
|
+
|
|
508
712
|
const result = await createProject({
|
|
509
713
|
name: selections.directory,
|
|
510
714
|
template: flags.template,
|
|
@@ -516,11 +720,24 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
516
720
|
dryRun: Boolean(flags.dryRun),
|
|
517
721
|
});
|
|
518
722
|
|
|
723
|
+
if (!flags.dryRun && presets.length > 0) {
|
|
724
|
+
const { addProviderPreset } = await import("./provider-add.js");
|
|
725
|
+
for (const preset of presets) {
|
|
726
|
+
await addProviderPreset({ name: preset, cwd: result.targetDir });
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
519
730
|
writeOutput(
|
|
520
731
|
this,
|
|
521
732
|
flags.json
|
|
522
|
-
? JSON.stringify(result, null, 2)
|
|
523
|
-
: nextSteps(result, {
|
|
733
|
+
? JSON.stringify({ ...result, providerPresets: presets }, null, 2)
|
|
734
|
+
: nextSteps(result, {
|
|
735
|
+
api,
|
|
736
|
+
integrations,
|
|
737
|
+
database,
|
|
738
|
+
presets,
|
|
739
|
+
presetsNeedEnv,
|
|
740
|
+
}),
|
|
524
741
|
);
|
|
525
742
|
};
|
|
526
743
|
},
|
|
@@ -622,6 +839,12 @@ const checkCommand = buildCommand<CheckFlags, [], CliContext>({
|
|
|
622
839
|
withNegated: false,
|
|
623
840
|
brief: "Apply low-risk doctor fixes before checking.",
|
|
624
841
|
},
|
|
842
|
+
preflight: {
|
|
843
|
+
kind: "boolean",
|
|
844
|
+
optional: true,
|
|
845
|
+
withNegated: false,
|
|
846
|
+
brief: "Append a beignet preflight step after doctor.",
|
|
847
|
+
},
|
|
625
848
|
cwd: cwdFlag,
|
|
626
849
|
} satisfies FlagParametersForType<CheckFlags, CliContext>,
|
|
627
850
|
},
|
|
@@ -635,6 +858,7 @@ const checkCommand = buildCommand<CheckFlags, [], CliContext>({
|
|
|
635
858
|
const result = await checkApp({
|
|
636
859
|
cwd: flags.cwd,
|
|
637
860
|
fix: flags.fix,
|
|
861
|
+
preflight: flags.preflight,
|
|
638
862
|
color,
|
|
639
863
|
...(flags.json
|
|
640
864
|
? {}
|
|
@@ -656,6 +880,64 @@ const checkCommand = buildCommand<CheckFlags, [], CliContext>({
|
|
|
656
880
|
},
|
|
657
881
|
});
|
|
658
882
|
|
|
883
|
+
const preflightCommand = buildCommand<PreflightFlags, [], CliContext>({
|
|
884
|
+
docs: {
|
|
885
|
+
brief: "Validate the deploy environment before shipping.",
|
|
886
|
+
fullDescription:
|
|
887
|
+
"Runtime production gate, unlike the static doctor checks: reads the actual environment the process runs with, verifies every env var installed provider manifests mark as required, flags values still matching .env.example or common placeholders on secret-like keys, and validates the app env schema by importing lib/env.ts. Run it in the deploy pipeline where production configuration is present. Exits 1 on any error finding.",
|
|
888
|
+
},
|
|
889
|
+
parameters: {
|
|
890
|
+
flags: {
|
|
891
|
+
json: jsonFlag,
|
|
892
|
+
envFile: parsedStringFlag(
|
|
893
|
+
"Dotenv-style file merged under the environment (existing env keys win) for local rehearsal.",
|
|
894
|
+
),
|
|
895
|
+
envModule: parsedStringFlag(
|
|
896
|
+
"App env module validated by importing it. Defaults to lib/env.ts.",
|
|
897
|
+
),
|
|
898
|
+
connect: {
|
|
899
|
+
kind: "boolean",
|
|
900
|
+
optional: true,
|
|
901
|
+
withNegated: false,
|
|
902
|
+
brief:
|
|
903
|
+
"Boot the app server and run every port's checkHealth(). Needs network and real credentials.",
|
|
904
|
+
},
|
|
905
|
+
serverModule: parsedStringFlag(
|
|
906
|
+
"Module exporting getServer, used by --connect. Defaults to server/index.ts.",
|
|
907
|
+
),
|
|
908
|
+
cwd: cwdFlag,
|
|
909
|
+
} satisfies FlagParametersForType<PreflightFlags, CliContext>,
|
|
910
|
+
},
|
|
911
|
+
loader: async () => {
|
|
912
|
+
const { formatPreflight, runPreflight } = await import("./preflight.js");
|
|
913
|
+
const path = await import("node:path");
|
|
914
|
+
|
|
915
|
+
return async function runPreflightCommand(
|
|
916
|
+
this: CliContext,
|
|
917
|
+
flags: PreflightFlags,
|
|
918
|
+
) {
|
|
919
|
+
const cwd = path.resolve(flags.cwd ?? process.cwd());
|
|
920
|
+
const result = await runPreflight({
|
|
921
|
+
cwd,
|
|
922
|
+
envFile: flags.envFile,
|
|
923
|
+
envModule: flags.envModule,
|
|
924
|
+
connect: flags.connect,
|
|
925
|
+
serverModule: flags.serverModule,
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
writeOutput(
|
|
929
|
+
this,
|
|
930
|
+
flags.json
|
|
931
|
+
? JSON.stringify({ schemaVersion: 1, cwd, ...result }, null, 2)
|
|
932
|
+
: formatPreflight(result, cwd),
|
|
933
|
+
);
|
|
934
|
+
if (result.findings.some((finding) => finding.severity === "error")) {
|
|
935
|
+
this.process.exitCode = 1;
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
},
|
|
939
|
+
});
|
|
940
|
+
|
|
659
941
|
const lintCommand = buildCommand<LintFlags, [], CliContext>({
|
|
660
942
|
docs: {
|
|
661
943
|
brief: "Check Beignet dependency direction conventions.",
|
|
@@ -819,27 +1101,23 @@ function databaseCommand(command: DatabaseCommandName) {
|
|
|
819
1101
|
});
|
|
820
1102
|
}
|
|
821
1103
|
|
|
822
|
-
const
|
|
823
|
-
DbSchemaGenerateFlags,
|
|
824
|
-
[],
|
|
825
|
-
CliContext
|
|
826
|
-
>({
|
|
1104
|
+
const dbSchemaSyncCommand = buildCommand<DbSchemaSyncFlags, [], CliContext>({
|
|
827
1105
|
docs: {
|
|
828
|
-
brief: "
|
|
1106
|
+
brief: "Sync app-owned re-exports of Beignet provider tables.",
|
|
829
1107
|
fullDescription:
|
|
830
|
-
"
|
|
1108
|
+
"Idempotently brings the app-owned schema file that re-exports Beignet provider tables in sync with the installed providers, then updates the schema index. Run beignet db generate afterward to let the app's Drizzle Kit script create migrations.",
|
|
831
1109
|
},
|
|
832
1110
|
parameters: {
|
|
833
|
-
flags:
|
|
1111
|
+
flags: dbSchemaSyncFlagParameters,
|
|
834
1112
|
},
|
|
835
1113
|
loader: async () => {
|
|
836
|
-
const {
|
|
1114
|
+
const { syncDatabaseSchema } = await import("./db.js");
|
|
837
1115
|
|
|
838
|
-
return async function
|
|
1116
|
+
return async function runDbSchemaSync(
|
|
839
1117
|
this: CliContext,
|
|
840
|
-
flags:
|
|
1118
|
+
flags: DbSchemaSyncFlags,
|
|
841
1119
|
) {
|
|
842
|
-
const result = await
|
|
1120
|
+
const result = await syncDatabaseSchema({
|
|
843
1121
|
dialect: flags.dialect,
|
|
844
1122
|
tables: flags.tables,
|
|
845
1123
|
output: flags.output,
|
|
@@ -850,7 +1128,7 @@ const dbSchemaGenerateCommand = buildCommand<
|
|
|
850
1128
|
this,
|
|
851
1129
|
flags.json
|
|
852
1130
|
? JSON.stringify(result, null, 2)
|
|
853
|
-
:
|
|
1131
|
+
: databaseSchemaSyncNextSteps(result),
|
|
854
1132
|
);
|
|
855
1133
|
};
|
|
856
1134
|
},
|
|
@@ -858,10 +1136,10 @@ const dbSchemaGenerateCommand = buildCommand<
|
|
|
858
1136
|
|
|
859
1137
|
const dbSchemaRoutes = buildRouteMap({
|
|
860
1138
|
docs: {
|
|
861
|
-
brief: "
|
|
1139
|
+
brief: "Sync app-owned Beignet provider schema exports.",
|
|
862
1140
|
},
|
|
863
1141
|
routes: {
|
|
864
|
-
|
|
1142
|
+
sync: dbSchemaSyncCommand,
|
|
865
1143
|
},
|
|
866
1144
|
});
|
|
867
1145
|
|
|
@@ -946,12 +1224,178 @@ const outboxDrainCommand = buildCommand<OutboxDrainFlags, [], CliContext>({
|
|
|
946
1224
|
},
|
|
947
1225
|
});
|
|
948
1226
|
|
|
1227
|
+
const outboxListCommand = buildCommand<OutboxListFlags, [], CliContext>({
|
|
1228
|
+
docs: {
|
|
1229
|
+
brief: "List outbox messages for operational inspection.",
|
|
1230
|
+
},
|
|
1231
|
+
parameters: {
|
|
1232
|
+
flags: outboxListFlagParameters,
|
|
1233
|
+
},
|
|
1234
|
+
loader: async () => {
|
|
1235
|
+
const { runOutboxList } = await import("./outbox.js");
|
|
1236
|
+
|
|
1237
|
+
return async function runList(this: CliContext, flags: OutboxListFlags) {
|
|
1238
|
+
const result = await runOutboxList({
|
|
1239
|
+
modulePath: flags.module,
|
|
1240
|
+
status: flags.status,
|
|
1241
|
+
kind: flags.kind,
|
|
1242
|
+
name: flags.name,
|
|
1243
|
+
limit: flags.limit,
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
writeOutput(
|
|
1247
|
+
this,
|
|
1248
|
+
flags.json
|
|
1249
|
+
? JSON.stringify(result, null, 2)
|
|
1250
|
+
: outboxListNextSteps(result),
|
|
1251
|
+
);
|
|
1252
|
+
};
|
|
1253
|
+
},
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
const outboxShowCommand = buildCommand<OutboxShowFlags, [string], CliContext>({
|
|
1257
|
+
docs: {
|
|
1258
|
+
brief: "Show one outbox message.",
|
|
1259
|
+
},
|
|
1260
|
+
parameters: {
|
|
1261
|
+
flags: outboxShowFlagParameters,
|
|
1262
|
+
positional: idPositional,
|
|
1263
|
+
},
|
|
1264
|
+
loader: async () => {
|
|
1265
|
+
const { runOutboxShow } = await import("./outbox.js");
|
|
1266
|
+
|
|
1267
|
+
return async function runShow(
|
|
1268
|
+
this: CliContext,
|
|
1269
|
+
flags: OutboxShowFlags,
|
|
1270
|
+
id: string,
|
|
1271
|
+
) {
|
|
1272
|
+
const result = await runOutboxShow({
|
|
1273
|
+
modulePath: flags.module,
|
|
1274
|
+
id,
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
writeOutput(
|
|
1278
|
+
this,
|
|
1279
|
+
flags.json
|
|
1280
|
+
? JSON.stringify(result, null, 2)
|
|
1281
|
+
: outboxShowNextSteps(result),
|
|
1282
|
+
);
|
|
1283
|
+
};
|
|
1284
|
+
},
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
const outboxRequeueCommand = buildCommand<
|
|
1288
|
+
OutboxRequeueFlags,
|
|
1289
|
+
[string],
|
|
1290
|
+
CliContext
|
|
1291
|
+
>({
|
|
1292
|
+
docs: {
|
|
1293
|
+
brief: "Return one dead-lettered outbox message to pending state.",
|
|
1294
|
+
},
|
|
1295
|
+
parameters: {
|
|
1296
|
+
flags: outboxRequeueFlagParameters,
|
|
1297
|
+
positional: idPositional,
|
|
1298
|
+
},
|
|
1299
|
+
loader: async () => {
|
|
1300
|
+
const { runOutboxRequeue } = await import("./outbox.js");
|
|
1301
|
+
|
|
1302
|
+
return async function runRequeue(
|
|
1303
|
+
this: CliContext,
|
|
1304
|
+
flags: OutboxRequeueFlags,
|
|
1305
|
+
id: string,
|
|
1306
|
+
) {
|
|
1307
|
+
const result = await runOutboxRequeue({
|
|
1308
|
+
modulePath: flags.module,
|
|
1309
|
+
id,
|
|
1310
|
+
availableAt: flags.availableAt,
|
|
1311
|
+
resetAttempts: Boolean(flags.resetAttempts),
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
writeOutput(
|
|
1315
|
+
this,
|
|
1316
|
+
flags.json
|
|
1317
|
+
? JSON.stringify(result, null, 2)
|
|
1318
|
+
: outboxRequeueNextSteps(result),
|
|
1319
|
+
);
|
|
1320
|
+
};
|
|
1321
|
+
},
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1324
|
+
const outboxPurgeCommand = buildCommand<OutboxPurgeFlags, [], CliContext>({
|
|
1325
|
+
docs: {
|
|
1326
|
+
brief: "Delete dead-lettered outbox messages.",
|
|
1327
|
+
},
|
|
1328
|
+
parameters: {
|
|
1329
|
+
flags: outboxPurgeFlagParameters,
|
|
1330
|
+
},
|
|
1331
|
+
loader: async () => {
|
|
1332
|
+
const { runOutboxPurge } = await import("./outbox.js");
|
|
1333
|
+
|
|
1334
|
+
return async function runPurge(this: CliContext, flags: OutboxPurgeFlags) {
|
|
1335
|
+
const result = await runOutboxPurge({
|
|
1336
|
+
modulePath: flags.module,
|
|
1337
|
+
before: flags.before,
|
|
1338
|
+
all: Boolean(flags.all),
|
|
1339
|
+
limit: flags.limit,
|
|
1340
|
+
dryRun: Boolean(flags.dryRun),
|
|
1341
|
+
});
|
|
1342
|
+
|
|
1343
|
+
writeOutput(
|
|
1344
|
+
this,
|
|
1345
|
+
flags.json
|
|
1346
|
+
? JSON.stringify(result, null, 2)
|
|
1347
|
+
: outboxDeleteNextSteps(
|
|
1348
|
+
"Purged dead-lettered outbox messages",
|
|
1349
|
+
result,
|
|
1350
|
+
),
|
|
1351
|
+
);
|
|
1352
|
+
};
|
|
1353
|
+
},
|
|
1354
|
+
});
|
|
1355
|
+
|
|
1356
|
+
const outboxPruneCommand = buildCommand<OutboxPruneFlags, [], CliContext>({
|
|
1357
|
+
docs: {
|
|
1358
|
+
brief: "Delete delivered outbox messages older than a retention cutoff.",
|
|
1359
|
+
},
|
|
1360
|
+
parameters: {
|
|
1361
|
+
flags: outboxPruneFlagParameters,
|
|
1362
|
+
},
|
|
1363
|
+
loader: async () => {
|
|
1364
|
+
const { runOutboxPrune } = await import("./outbox.js");
|
|
1365
|
+
|
|
1366
|
+
return async function runPrune(this: CliContext, flags: OutboxPruneFlags) {
|
|
1367
|
+
if (!flags.before) {
|
|
1368
|
+
throw new Error("Pass --before <date> to prune delivered messages.");
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
const result = await runOutboxPrune({
|
|
1372
|
+
modulePath: flags.module,
|
|
1373
|
+
before: flags.before,
|
|
1374
|
+
limit: flags.limit,
|
|
1375
|
+
dryRun: Boolean(flags.dryRun),
|
|
1376
|
+
});
|
|
1377
|
+
|
|
1378
|
+
writeOutput(
|
|
1379
|
+
this,
|
|
1380
|
+
flags.json
|
|
1381
|
+
? JSON.stringify(result, null, 2)
|
|
1382
|
+
: outboxDeleteNextSteps("Pruned delivered outbox messages", result),
|
|
1383
|
+
);
|
|
1384
|
+
};
|
|
1385
|
+
},
|
|
1386
|
+
});
|
|
1387
|
+
|
|
949
1388
|
const outboxRoutes = buildRouteMap({
|
|
950
1389
|
docs: {
|
|
951
1390
|
brief: "Run Beignet outbox operations.",
|
|
952
1391
|
},
|
|
953
1392
|
routes: {
|
|
954
1393
|
drain: outboxDrainCommand,
|
|
1394
|
+
list: outboxListCommand,
|
|
1395
|
+
show: outboxShowCommand,
|
|
1396
|
+
requeue: outboxRequeueCommand,
|
|
1397
|
+
purge: outboxPurgeCommand,
|
|
1398
|
+
prune: outboxPruneCommand,
|
|
955
1399
|
},
|
|
956
1400
|
});
|
|
957
1401
|
|
|
@@ -1557,6 +2001,7 @@ Run npm create beignet@latest (or bun create beignet) to scaffold a new app.`,
|
|
|
1557
2001
|
make: makeRoutes,
|
|
1558
2002
|
mcp: mcpCommand,
|
|
1559
2003
|
outbox: outboxRoutes,
|
|
2004
|
+
preflight: preflightCommand,
|
|
1560
2005
|
providers: providerRoutes,
|
|
1561
2006
|
routes: routesCommand,
|
|
1562
2007
|
schedule: scheduleRoutes,
|
|
@@ -1626,7 +2071,7 @@ type DatabaseCommandNextStepsResult = {
|
|
|
1626
2071
|
dryRun: boolean;
|
|
1627
2072
|
};
|
|
1628
2073
|
|
|
1629
|
-
type
|
|
2074
|
+
type DatabaseSchemaSyncNextStepsResult = {
|
|
1630
2075
|
cwd: string;
|
|
1631
2076
|
dialect: DatabaseSchemaDialect;
|
|
1632
2077
|
tables: DatabaseSchemaTable[];
|
|
@@ -1655,6 +2100,37 @@ type OutboxDrainNextStepsResult = {
|
|
|
1655
2100
|
};
|
|
1656
2101
|
};
|
|
1657
2102
|
|
|
2103
|
+
type OutboxAdminMessage = {
|
|
2104
|
+
id: string;
|
|
2105
|
+
kind: string;
|
|
2106
|
+
name: string;
|
|
2107
|
+
status: string;
|
|
2108
|
+
attempts: number;
|
|
2109
|
+
maxAttempts: number;
|
|
2110
|
+
availableAt: Date | string;
|
|
2111
|
+
deliveredAt: Date | string | null;
|
|
2112
|
+
updatedAt: Date | string;
|
|
2113
|
+
lastError: { name?: string; message: string } | null;
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
type OutboxListNextStepsResult = {
|
|
2117
|
+
durationMs: number;
|
|
2118
|
+
messages: readonly OutboxAdminMessage[];
|
|
2119
|
+
count: number;
|
|
2120
|
+
};
|
|
2121
|
+
|
|
2122
|
+
type OutboxMessageNextStepsResult = {
|
|
2123
|
+
durationMs: number;
|
|
2124
|
+
message: OutboxAdminMessage;
|
|
2125
|
+
};
|
|
2126
|
+
|
|
2127
|
+
type OutboxDeleteNextStepsResult = {
|
|
2128
|
+
durationMs: number;
|
|
2129
|
+
dryRun: boolean;
|
|
2130
|
+
matched: number;
|
|
2131
|
+
deleted: number;
|
|
2132
|
+
};
|
|
2133
|
+
|
|
1658
2134
|
type ScheduleRunNextStepsResult = {
|
|
1659
2135
|
name: string;
|
|
1660
2136
|
durationMs: number;
|
|
@@ -1691,6 +2167,69 @@ Result:
|
|
|
1691
2167
|
deadLettered: ${result.result.deadLettered}`;
|
|
1692
2168
|
}
|
|
1693
2169
|
|
|
2170
|
+
function formatOutboxDate(value: Date | string | null | undefined): string {
|
|
2171
|
+
if (!value) return "none";
|
|
2172
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
function outboxMessageLine(message: OutboxAdminMessage): string {
|
|
2176
|
+
return `${message.id} ${message.status} ${message.kind} ${message.name} attempts ${message.attempts}/${message.maxAttempts} updated ${formatOutboxDate(message.updatedAt)}`;
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
function outboxListNextSteps(result: OutboxListNextStepsResult): string {
|
|
2180
|
+
const messages =
|
|
2181
|
+
result.messages.length === 0
|
|
2182
|
+
? " none"
|
|
2183
|
+
: result.messages
|
|
2184
|
+
.map((message) => ` ${outboxMessageLine(message)}`)
|
|
2185
|
+
.join("\n");
|
|
2186
|
+
|
|
2187
|
+
return `Listed ${result.messages.length} of ${result.count} matching outbox messages in ${result.durationMs}ms
|
|
2188
|
+
|
|
2189
|
+
Messages:
|
|
2190
|
+
${messages}`;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
function outboxShowNextSteps(result: OutboxMessageNextStepsResult): string {
|
|
2194
|
+
const message = result.message;
|
|
2195
|
+
const error = message.lastError
|
|
2196
|
+
? `${message.lastError.name ?? "Error"}: ${message.lastError.message}`
|
|
2197
|
+
: "none";
|
|
2198
|
+
|
|
2199
|
+
return `Outbox message ${message.id} (${message.status}) in ${result.durationMs}ms
|
|
2200
|
+
|
|
2201
|
+
Message:
|
|
2202
|
+
kind: ${message.kind}
|
|
2203
|
+
name: ${message.name}
|
|
2204
|
+
attempts: ${message.attempts}/${message.maxAttempts}
|
|
2205
|
+
availableAt: ${formatOutboxDate(message.availableAt)}
|
|
2206
|
+
deliveredAt: ${formatOutboxDate(message.deliveredAt)}
|
|
2207
|
+
updatedAt: ${formatOutboxDate(message.updatedAt)}
|
|
2208
|
+
lastError: ${error}`;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
function outboxRequeueNextSteps(result: OutboxMessageNextStepsResult): string {
|
|
2212
|
+
return `Requeued outbox message ${result.message.id} in ${result.durationMs}ms
|
|
2213
|
+
|
|
2214
|
+
Message:
|
|
2215
|
+
status: ${result.message.status}
|
|
2216
|
+
attempts: ${result.message.attempts}/${result.message.maxAttempts}
|
|
2217
|
+
availableAt: ${formatOutboxDate(result.message.availableAt)}`;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
function outboxDeleteNextSteps(
|
|
2221
|
+
label: string,
|
|
2222
|
+
result: OutboxDeleteNextStepsResult,
|
|
2223
|
+
): string {
|
|
2224
|
+
const action = result.dryRun ? "Would delete" : "Deleted";
|
|
2225
|
+
|
|
2226
|
+
return `${label} in ${result.durationMs}ms
|
|
2227
|
+
|
|
2228
|
+
Result:
|
|
2229
|
+
matched: ${result.matched}
|
|
2230
|
+
${action}: ${result.deleted}`;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
1694
2233
|
function scheduleRunNextSteps(result: ScheduleRunNextStepsResult): string {
|
|
1695
2234
|
return `Ran schedule ${result.name} in ${result.durationMs}ms
|
|
1696
2235
|
|
|
@@ -1708,15 +2247,23 @@ function nextSteps(
|
|
|
1708
2247
|
api?: boolean;
|
|
1709
2248
|
integrations?: readonly IntegrationName[];
|
|
1710
2249
|
database?: DatabaseName;
|
|
2250
|
+
presets?: readonly ProviderPresetName[];
|
|
2251
|
+
presetsNeedEnv?: boolean;
|
|
1711
2252
|
} = {},
|
|
1712
2253
|
): string {
|
|
1713
2254
|
if (result.dryRun) {
|
|
1714
2255
|
const plannedFiles = result.files.map((file) => ` ${file}`).join("\n");
|
|
2256
|
+
const plannedPresets =
|
|
2257
|
+
options.presets && options.presets.length > 0
|
|
2258
|
+
? `\n\nProvider presets applied after scaffold (skipped in dry run):\n${options.presets
|
|
2259
|
+
.map((preset) => ` ${preset}`)
|
|
2260
|
+
.join("\n")}`
|
|
2261
|
+
: "";
|
|
1715
2262
|
|
|
1716
2263
|
return `Would create ${result.name} at ${result.targetDir}
|
|
1717
2264
|
|
|
1718
2265
|
Planned files:
|
|
1719
|
-
${plannedFiles}`;
|
|
2266
|
+
${plannedFiles}${plannedPresets}`;
|
|
1720
2267
|
}
|
|
1721
2268
|
|
|
1722
2269
|
const pm = result.packageManager;
|
|
@@ -1725,9 +2272,17 @@ ${plannedFiles}`;
|
|
|
1725
2272
|
const envRequiredIntegrations =
|
|
1726
2273
|
options.integrations?.filter(isEnvRequiredProviderIntegration) ?? [];
|
|
1727
2274
|
const envStep =
|
|
1728
|
-
envRequiredIntegrations.length > 0
|
|
2275
|
+
envRequiredIntegrations.length > 0 || options.presetsNeedEnv
|
|
1729
2276
|
? " Fill .env.local for selected provider integrations before starting the app.\n"
|
|
1730
2277
|
: "";
|
|
2278
|
+
const presetSection =
|
|
2279
|
+
options.presets && options.presets.length > 0
|
|
2280
|
+
? `\nProvider presets applied:\n${options.presets
|
|
2281
|
+
.map((preset) => ` ${preset}`)
|
|
2282
|
+
.join(
|
|
2283
|
+
"\n",
|
|
2284
|
+
)}\n See docs/integrations.md for setup notes and follow-up steps.\n`
|
|
2285
|
+
: "";
|
|
1731
2286
|
const openStep = options.api
|
|
1732
2287
|
? " open http://localhost:3000 for the API landing page"
|
|
1733
2288
|
: " open http://localhost:3000/sign-up";
|
|
@@ -1742,7 +2297,7 @@ ${plannedFiles}`;
|
|
|
1742
2297
|
: "";
|
|
1743
2298
|
|
|
1744
2299
|
return `Created ${result.name} at ${result.targetDir}
|
|
1745
|
-
|
|
2300
|
+
${presetSection}
|
|
1746
2301
|
Next steps:
|
|
1747
2302
|
cd ${result.targetDir}
|
|
1748
2303
|
${pm} install
|
|
@@ -1858,15 +2413,15 @@ Command:
|
|
|
1858
2413
|
${command}`;
|
|
1859
2414
|
}
|
|
1860
2415
|
|
|
1861
|
-
function
|
|
1862
|
-
result:
|
|
2416
|
+
function databaseSchemaSyncNextSteps(
|
|
2417
|
+
result: DatabaseSchemaSyncNextStepsResult,
|
|
1863
2418
|
): string {
|
|
1864
2419
|
const { changedFiles, skippedFiles } = changedFileLines({
|
|
1865
2420
|
createdFiles: result.createdFiles,
|
|
1866
2421
|
updatedFiles: result.updatedFiles,
|
|
1867
2422
|
skippedFiles: result.skippedFiles,
|
|
1868
2423
|
});
|
|
1869
|
-
const prefix = result.dryRun ? "Would
|
|
2424
|
+
const prefix = result.dryRun ? "Would sync" : "Synced";
|
|
1870
2425
|
const tables = result.tables.join(", ");
|
|
1871
2426
|
|
|
1872
2427
|
return `${prefix} Beignet ${result.dialect} database schema (${tables}) in ${result.cwd}
|
|
@@ -1984,7 +2539,7 @@ function makeOutboxNextSteps(result: MakeNextStepsResult): string {
|
|
|
1984
2539
|
function makeListenerNextSteps(result: MakeNextStepsResult): string {
|
|
1985
2540
|
return makeNextSteps(result, "listener", [
|
|
1986
2541
|
"Replace the starter handler with the event reaction.",
|
|
1987
|
-
"Register the listener collection from
|
|
2542
|
+
"Register the listener collection from server provider wiring.",
|
|
1988
2543
|
]);
|
|
1989
2544
|
}
|
|
1990
2545
|
|