@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.
- package/CHANGELOG.md +26 -0
- package/README.md +138 -101
- package/dist/choices.d.ts +17 -21
- package/dist/choices.d.ts.map +1 -1
- package/dist/choices.js +21 -67
- package/dist/choices.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/create-prompts.d.ts +5 -6
- package/dist/create-prompts.d.ts.map +1 -1
- package/dist/create-prompts.js +15 -15
- package/dist/create-prompts.js.map +1 -1
- package/dist/create.d.ts +11 -2
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +38 -28
- package/dist/create.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +149 -47
- package/dist/index.js.map +1 -1
- package/dist/inspect.js +69 -16
- package/dist/inspect.js.map +1 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +27 -6
- package/dist/lint.js.map +1 -1
- package/dist/make/inbox.js +10 -10
- package/dist/make/inbox.js.map +1 -1
- package/dist/make/payments.d.ts +2 -1
- package/dist/make/payments.d.ts.map +1 -1
- package/dist/make/payments.js +18 -14
- package/dist/make/payments.js.map +1 -1
- package/dist/make/shared.d.ts +11 -4
- package/dist/make/shared.d.ts.map +1 -1
- package/dist/make/shared.js +56 -45
- package/dist/make/shared.js.map +1 -1
- package/dist/make/tenancy.js +8 -8
- package/dist/make/tenancy.js.map +1 -1
- package/dist/make.d.ts +3 -2
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +481 -200
- package/dist/make.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +15 -11
- package/dist/mcp.js.map +1 -1
- package/dist/operational-error-reporting.d.ts +15 -0
- package/dist/operational-error-reporting.d.ts.map +1 -0
- package/dist/operational-error-reporting.js +42 -0
- package/dist/operational-error-reporting.js.map +1 -0
- package/dist/outbox.d.ts.map +1 -1
- package/dist/outbox.js +73 -0
- package/dist/outbox.js.map +1 -1
- package/dist/provider-add.d.ts +21 -3
- package/dist/provider-add.d.ts.map +1 -1
- package/dist/provider-add.js +117 -81
- package/dist/provider-add.js.map +1 -1
- package/dist/provider-audit.js +3 -3
- package/dist/provider-audit.js.map +1 -1
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +28 -1
- package/dist/schedule.js.map +1 -1
- package/dist/task.d.ts.map +1 -1
- package/dist/task.js +38 -5
- package/dist/task.js.map +1 -1
- package/dist/templates/base.d.ts +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +15 -15
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/index.d.ts +2 -2
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +7 -7
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/server.d.ts +1 -1
- package/dist/templates/server.d.ts.map +1 -1
- package/dist/templates/server.js +22 -18
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/shared.d.ts +4 -4
- package/dist/templates/shared.d.ts.map +1 -1
- package/dist/templates/shared.js +6 -6
- package/dist/templates/shared.js.map +1 -1
- package/dist/templates/testing.js +1 -1
- package/dist/templates/todos.js +6 -6
- package/package.json +4 -4
- package/skills/app-structure/SKILL.md +13 -8
- package/src/choices.ts +38 -88
- package/src/config.ts +2 -2
- package/src/create-prompts.ts +20 -21
- package/src/create.ts +54 -36
- package/src/index.ts +193 -65
- package/src/inspect.ts +116 -18
- package/src/lib.ts +1 -1
- package/src/lint.ts +35 -4
- package/src/make/inbox.ts +10 -10
- package/src/make/payments.ts +26 -18
- package/src/make/shared.ts +72 -50
- package/src/make/tenancy.ts +8 -8
- package/src/make.ts +607 -191
- package/src/mcp.ts +20 -13
- package/src/operational-error-reporting.ts +60 -0
- package/src/outbox.ts +77 -0
- package/src/provider-add.ts +179 -95
- package/src/provider-audit.ts +3 -3
- package/src/schedule.ts +32 -1
- package/src/task.ts +42 -5
- package/src/templates/base.ts +16 -16
- package/src/templates/index.ts +8 -8
- package/src/templates/server.ts +22 -18
- package/src/templates/shared.ts +10 -10
- package/src/templates/testing.ts +1 -1
- package/src/templates/todos.ts +6 -6
- package/src/test-helpers/generated-app.ts +1 -0
package/src/schedule.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import type { ErrorReporterPort } from "@beignet/core/error-reporting";
|
|
3
4
|
import type { ProviderInstrumentationPort } from "@beignet/core/providers";
|
|
4
5
|
import type {
|
|
5
6
|
ScheduleDef,
|
|
@@ -8,6 +9,10 @@ import type {
|
|
|
8
9
|
} from "@beignet/core/schedules";
|
|
9
10
|
import { createJiti } from "jiti";
|
|
10
11
|
import { loadBeignetConfig, normalizePath } from "./config.js";
|
|
12
|
+
import {
|
|
13
|
+
flushOperationalErrorReporter,
|
|
14
|
+
reportOperationalFailure,
|
|
15
|
+
} from "./operational-error-reporting.js";
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Options for running one app-owned schedule.
|
|
@@ -56,6 +61,7 @@ type ScheduleContext = {
|
|
|
56
61
|
logger?: ScheduleLogger;
|
|
57
62
|
devtools?: ProviderInstrumentationPort;
|
|
58
63
|
instrumentation?: ProviderInstrumentationPort;
|
|
64
|
+
errorReporter?: ErrorReporterPort;
|
|
59
65
|
};
|
|
60
66
|
};
|
|
61
67
|
|
|
@@ -131,7 +137,31 @@ export async function runAppSchedule(
|
|
|
131
137
|
},
|
|
132
138
|
});
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
try {
|
|
141
|
+
await runner.run(schedule, runOptions);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
await reportOperationalFailure({
|
|
144
|
+
ctx: scheduleContext,
|
|
145
|
+
error,
|
|
146
|
+
reportOptions: {
|
|
147
|
+
level: "error",
|
|
148
|
+
mechanism: "beignet.schedule.cli",
|
|
149
|
+
handled: false,
|
|
150
|
+
tags: {
|
|
151
|
+
"beignet.kind": "schedule",
|
|
152
|
+
"beignet.schedule": schedule.name,
|
|
153
|
+
},
|
|
154
|
+
contexts: {
|
|
155
|
+
schedule: {
|
|
156
|
+
name: schedule.name,
|
|
157
|
+
source: runOptions.source ?? "beignet-cli",
|
|
158
|
+
attempt: runOptions.attempt ?? null,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
135
165
|
|
|
136
166
|
return {
|
|
137
167
|
schemaVersion: 1,
|
|
@@ -148,6 +178,7 @@ export async function runAppSchedule(
|
|
|
148
178
|
durationMs: Math.round(performance.now() - startedAt),
|
|
149
179
|
};
|
|
150
180
|
} finally {
|
|
181
|
+
await flushOperationalErrorReporter(scheduleContext);
|
|
151
182
|
await scheduleModule.stopScheduleContext?.(ctx, contextArgs);
|
|
152
183
|
}
|
|
153
184
|
}
|
package/src/task.ts
CHANGED
|
@@ -3,6 +3,11 @@ import path from "node:path";
|
|
|
3
3
|
import type { TaskDef, TaskRunContextArgs } from "@beignet/core/tasks";
|
|
4
4
|
import { createJiti } from "jiti";
|
|
5
5
|
import { loadBeignetConfig, normalizePath } from "./config.js";
|
|
6
|
+
import {
|
|
7
|
+
flushOperationalErrorReporter,
|
|
8
|
+
type OperationalErrorReportingContext,
|
|
9
|
+
reportOperationalFailure,
|
|
10
|
+
} from "./operational-error-reporting.js";
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* Options for running an app-owned operational task.
|
|
@@ -63,10 +68,35 @@ export async function runAppTask(
|
|
|
63
68
|
: {};
|
|
64
69
|
|
|
65
70
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
let output: unknown;
|
|
72
|
+
try {
|
|
73
|
+
output = await runTask(task, {
|
|
74
|
+
input: parsedInput,
|
|
75
|
+
ctx,
|
|
76
|
+
});
|
|
77
|
+
} catch (error) {
|
|
78
|
+
await reportOperationalFailure({
|
|
79
|
+
ctx: toOperationalContext(ctx),
|
|
80
|
+
error,
|
|
81
|
+
reportOptions: {
|
|
82
|
+
level: "error",
|
|
83
|
+
mechanism: "beignet.task.cli",
|
|
84
|
+
handled: false,
|
|
85
|
+
tags: {
|
|
86
|
+
"beignet.kind": "task",
|
|
87
|
+
"beignet.task": task.name,
|
|
88
|
+
},
|
|
89
|
+
contexts: {
|
|
90
|
+
task: {
|
|
91
|
+
name: task.name,
|
|
92
|
+
tenant: options.tenant ?? null,
|
|
93
|
+
source: "beignet-cli",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
70
100
|
|
|
71
101
|
return {
|
|
72
102
|
schemaVersion: 1,
|
|
@@ -79,10 +109,17 @@ export async function runAppTask(
|
|
|
79
109
|
durationMs: Math.round(performance.now() - startedAt),
|
|
80
110
|
};
|
|
81
111
|
} finally {
|
|
112
|
+
await flushOperationalErrorReporter(toOperationalContext(ctx));
|
|
82
113
|
await taskModule.stopTaskContext?.(ctx, contextArgs);
|
|
83
114
|
}
|
|
84
115
|
}
|
|
85
116
|
|
|
117
|
+
function toOperationalContext(ctx: unknown): OperationalErrorReportingContext {
|
|
118
|
+
return typeof ctx === "object" && ctx !== null
|
|
119
|
+
? (ctx as OperationalErrorReportingContext)
|
|
120
|
+
: {};
|
|
121
|
+
}
|
|
122
|
+
|
|
86
123
|
function parseTaskInputFlag(input: RunAppTaskOptions["input"]): unknown {
|
|
87
124
|
if (input === undefined) return {};
|
|
88
125
|
if (typeof input !== "string") return input;
|
|
@@ -105,7 +142,7 @@ async function loadTaskModule(
|
|
|
105
142
|
await stat(absolutePath);
|
|
106
143
|
} catch {
|
|
107
144
|
throw new Error(
|
|
108
|
-
`Could not find app task registry at ${modulePath}. Create it with beignet make task <feature
|
|
145
|
+
`Could not find app task registry at ${modulePath}. Create it with beignet make task <feature.name> or configure paths.tasks in beignet.config.ts.`,
|
|
109
146
|
);
|
|
110
147
|
}
|
|
111
148
|
|
package/src/templates/base.ts
CHANGED
|
@@ -2,10 +2,10 @@ import { databaseLocalUrl, databaseStartCommand } from "../choices.js";
|
|
|
2
2
|
import { shadcnDependencies, shadcnDevDependencies } from "./shadcn.js";
|
|
3
3
|
import {
|
|
4
4
|
externalVersions,
|
|
5
|
-
|
|
6
|
-
integrationDeps,
|
|
5
|
+
hasStarterProvider,
|
|
7
6
|
json,
|
|
8
7
|
packageRunner,
|
|
8
|
+
starterProviderDeps,
|
|
9
9
|
type TemplateContext,
|
|
10
10
|
} from "./shared.js";
|
|
11
11
|
import { shellDependencies, shellDevDependencies } from "./shell.js";
|
|
@@ -55,9 +55,9 @@ export function packageJson(ctx: TemplateContext): string {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
for (const
|
|
58
|
+
for (const provider of ctx.providers) {
|
|
59
59
|
for (const [name, version] of Object.entries(
|
|
60
|
-
|
|
60
|
+
starterProviderDeps[provider],
|
|
61
61
|
)) {
|
|
62
62
|
dependencies[name] = version || ctx.beignetVersion;
|
|
63
63
|
}
|
|
@@ -356,10 +356,10 @@ ${optionalAuthRedirects}
|
|
|
356
356
|
: "; it refuses non-local hosts unless `BEIGNET_ALLOW_DATABASE_RESET=true`"
|
|
357
357
|
}.
|
|
358
358
|
- Remove \`DEVTOOLS_ENABLED=true\` in production unless you add authentication and stricter redaction.
|
|
359
|
-
- Set \`APP_URL\`, \`BETTER_AUTH_SECRET\`, \`LOG_LEVEL\`, and
|
|
359
|
+
- Set \`APP_URL\`, \`BETTER_AUTH_SECRET\`, \`LOG_LEVEL\`, and provider-specific variables in your hosting environment.
|
|
360
360
|
- Set \`BETTER_AUTH_TRUSTED_ORIGINS\` before serving auth across multiple origins.
|
|
361
361
|
- Review the starter authorization policy before exposing user-owned data.
|
|
362
|
-
${ctx.
|
|
362
|
+
${ctx.providers.length > 0 ? "\nSee `docs/providers.md` for setup notes.\n" : ""}`;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
function intentRunner(ctx: TemplateContext): string {
|
|
@@ -375,16 +375,16 @@ function intentRunner(ctx: TemplateContext): string {
|
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
-
export function
|
|
378
|
+
export function providersDoc(ctx: TemplateContext): string {
|
|
379
379
|
const lines = [
|
|
380
|
-
"#
|
|
380
|
+
"# Providers",
|
|
381
381
|
"",
|
|
382
|
-
"The starter app added dependencies for the
|
|
382
|
+
"The starter app added dependencies for the providers you selected. Runtime providers are wired in `server/providers.ts` when Beignet can do so safely; providers that need app-owned setup list their follow-up steps below.",
|
|
383
383
|
"",
|
|
384
384
|
];
|
|
385
385
|
|
|
386
|
-
for (const
|
|
387
|
-
if (
|
|
386
|
+
for (const provider of ctx.providers) {
|
|
387
|
+
if (provider === "jobs-inngest") {
|
|
388
388
|
lines.push(
|
|
389
389
|
"## Inngest jobs",
|
|
390
390
|
"",
|
|
@@ -398,7 +398,7 @@ export function integrationsDoc(ctx: TemplateContext): string {
|
|
|
398
398
|
);
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
-
if (
|
|
401
|
+
if (provider === "mail-resend") {
|
|
402
402
|
lines.push(
|
|
403
403
|
"## Resend mail",
|
|
404
404
|
"",
|
|
@@ -410,7 +410,7 @@ export function integrationsDoc(ctx: TemplateContext): string {
|
|
|
410
410
|
);
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
if (
|
|
413
|
+
if (provider === "rate-limit-upstash") {
|
|
414
414
|
lines.push(
|
|
415
415
|
"## Upstash rate limit",
|
|
416
416
|
"",
|
|
@@ -470,11 +470,11 @@ export function envExample(ctx: TemplateContext): string {
|
|
|
470
470
|
"",
|
|
471
471
|
];
|
|
472
472
|
|
|
473
|
-
if (
|
|
473
|
+
if (hasStarterProvider(ctx, "jobs-inngest")) {
|
|
474
474
|
lines.push("INNGEST_APP_NAME=beignet-app", "# INNGEST_EVENT_KEY=", "");
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
if (
|
|
477
|
+
if (hasStarterProvider(ctx, "mail-resend")) {
|
|
478
478
|
lines.push(
|
|
479
479
|
"# Dev placeholders keep the app bootable; set real Resend values before sending mail.",
|
|
480
480
|
"RESEND_API_KEY=dev-placeholder-change-me",
|
|
@@ -483,7 +483,7 @@ export function envExample(ctx: TemplateContext): string {
|
|
|
483
483
|
);
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
-
if (
|
|
486
|
+
if (hasStarterProvider(ctx, "rate-limit-upstash")) {
|
|
487
487
|
lines.push(
|
|
488
488
|
"# Dev placeholders keep the app bootable; set real Upstash values before rate limiting.",
|
|
489
489
|
"UPSTASH_REDIS_REST_URL=https://dev-placeholder.upstash.io",
|
package/src/templates/index.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
export type {
|
|
2
2
|
DatabaseName,
|
|
3
|
-
IntegrationName,
|
|
4
3
|
PackageManager,
|
|
4
|
+
StarterProviderName,
|
|
5
5
|
TemplateName,
|
|
6
6
|
} from "../choices.js";
|
|
7
|
-
export { databaseChoices,
|
|
7
|
+
export { databaseChoices, starterProviderChoices } from "../choices.js";
|
|
8
8
|
export type { TemplateContext, TemplateFile } from "./shared.js";
|
|
9
9
|
|
|
10
10
|
import { agentsMd, mcpJson } from "./agents.js";
|
|
11
11
|
import {
|
|
12
12
|
baseFiles,
|
|
13
13
|
envExample,
|
|
14
|
-
integrationsDoc,
|
|
15
14
|
packageJson,
|
|
15
|
+
providersDoc,
|
|
16
16
|
readme,
|
|
17
17
|
} from "./base.js";
|
|
18
18
|
import { dbFiles } from "./db/index.js";
|
|
19
19
|
import {
|
|
20
20
|
betterAuth,
|
|
21
21
|
env,
|
|
22
|
-
infrastructurePorts,
|
|
23
22
|
ports,
|
|
23
|
+
portWiring,
|
|
24
24
|
server,
|
|
25
25
|
serverFiles,
|
|
26
26
|
serverProviders,
|
|
@@ -109,7 +109,7 @@ export function getTemplateFiles(ctx: TemplateContext): TemplateFile[] {
|
|
|
109
109
|
},
|
|
110
110
|
{ path: "ports/index.ts", content: ports(ctx) },
|
|
111
111
|
{ path: "ports/auth.ts", content: serverFiles.authPort },
|
|
112
|
-
{ path: "infra/
|
|
112
|
+
{ path: "infra/port-wiring.ts", content: portWiring(ctx) },
|
|
113
113
|
{ path: "infra/db/client.ts", content: db.dbClient },
|
|
114
114
|
{ path: "infra/db/database-ready.ts", content: db.databaseReady },
|
|
115
115
|
{ path: "infra/db/provider.ts", content: db.dbProvider },
|
|
@@ -154,10 +154,10 @@ export function getTemplateFiles(ctx: TemplateContext): TemplateFile[] {
|
|
|
154
154
|
templateFiles.push(...shadcnTemplateFiles(), ...shellTemplateFiles(ctx));
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
if (ctx.
|
|
157
|
+
if (ctx.providers.length > 0) {
|
|
158
158
|
templateFiles.push({
|
|
159
|
-
path: "docs/
|
|
160
|
-
content:
|
|
159
|
+
path: "docs/providers.md",
|
|
160
|
+
content: providersDoc(ctx),
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
163
|
|
package/src/templates/server.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { databaseLocalUrl } from "../choices.js";
|
|
2
2
|
import {
|
|
3
3
|
databaseDescriptor,
|
|
4
|
-
|
|
4
|
+
hasStarterProvider,
|
|
5
5
|
type TemplateContext,
|
|
6
6
|
} from "./shared.js";
|
|
7
7
|
|
|
@@ -12,14 +12,14 @@ export function serverProviders(ctx: TemplateContext): string {
|
|
|
12
12
|
'import { createDevtoolsProvider } from "@beignet/devtools";',
|
|
13
13
|
'import { createBetterAuthProvider } from "@beignet/provider-auth-better-auth";',
|
|
14
14
|
`import { ${db.providerFactory} } from "@beignet/provider-db-drizzle/${db.subpath}";`,
|
|
15
|
-
|
|
15
|
+
hasStarterProvider(ctx, "jobs-inngest")
|
|
16
16
|
? 'import { createInngestJobsProvider } from "@beignet/provider-jobs-inngest";'
|
|
17
17
|
: undefined,
|
|
18
18
|
'import { createPinoLoggerProvider } from "@beignet/provider-logger-pino";',
|
|
19
|
-
|
|
19
|
+
hasStarterProvider(ctx, "mail-resend")
|
|
20
20
|
? 'import { createResendMailProvider } from "@beignet/provider-mail-resend";'
|
|
21
21
|
: undefined,
|
|
22
|
-
|
|
22
|
+
hasStarterProvider(ctx, "rate-limit-upstash")
|
|
23
23
|
? 'import { createUpstashRateLimitProvider } from "@beignet/provider-rate-limit-upstash";'
|
|
24
24
|
: undefined,
|
|
25
25
|
'import * as schema from "@/infra/db/schema";',
|
|
@@ -35,11 +35,13 @@ export function serverProviders(ctx: TemplateContext): string {
|
|
|
35
35
|
"\tcreatePinoLoggerProvider(),",
|
|
36
36
|
`\t${db.providerInstance},`,
|
|
37
37
|
"\tstarterDatabaseProvider,",
|
|
38
|
-
|
|
38
|
+
hasStarterProvider(ctx, "jobs-inngest")
|
|
39
39
|
? "\tcreateInngestJobsProvider(),"
|
|
40
40
|
: undefined,
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
hasStarterProvider(ctx, "mail-resend")
|
|
42
|
+
? "\tcreateResendMailProvider(),"
|
|
43
|
+
: undefined,
|
|
44
|
+
hasStarterProvider(ctx, "rate-limit-upstash")
|
|
43
45
|
? "\tcreateUpstashRateLimitProvider(),"
|
|
44
46
|
: undefined,
|
|
45
47
|
].filter((entry): entry is string => Boolean(entry));
|
|
@@ -58,9 +60,9 @@ ${entries.join("\n")}
|
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
export function ports(ctx: TemplateContext): string {
|
|
61
|
-
const usesInngest =
|
|
62
|
-
const usesResend =
|
|
63
|
-
const usesUpstash =
|
|
63
|
+
const usesInngest = hasStarterProvider(ctx, "jobs-inngest");
|
|
64
|
+
const usesResend = hasStarterProvider(ctx, "mail-resend");
|
|
65
|
+
const usesUpstash = hasStarterProvider(ctx, "rate-limit-upstash");
|
|
64
66
|
const coreImports = [
|
|
65
67
|
"\tBoundGate,",
|
|
66
68
|
"\tGatePort,",
|
|
@@ -101,14 +103,16 @@ ${usesResend ? "\tmailer: MailerPort;\n" : ""}${usesUpstash ? "\trateLimit: Rate
|
|
|
101
103
|
`;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
export function
|
|
106
|
+
export function portWiring(ctx: TemplateContext): string {
|
|
105
107
|
const deferred = [
|
|
106
108
|
'\t\t"auth",',
|
|
107
109
|
'\t\t"idempotency",',
|
|
108
|
-
|
|
110
|
+
hasStarterProvider(ctx, "jobs-inngest") ? '\t\t"jobs",' : undefined,
|
|
109
111
|
'\t\t"logger",',
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
hasStarterProvider(ctx, "mail-resend") ? '\t\t"mailer",' : undefined,
|
|
113
|
+
hasStarterProvider(ctx, "rate-limit-upstash")
|
|
114
|
+
? '\t\t"rateLimit",'
|
|
115
|
+
: undefined,
|
|
112
116
|
'\t\t"todos",',
|
|
113
117
|
'\t\t"uow",',
|
|
114
118
|
].filter((entry): entry is string => Boolean(entry));
|
|
@@ -130,13 +134,13 @@ const gate = createGate({
|
|
|
130
134
|
});
|
|
131
135
|
|
|
132
136
|
/**
|
|
133
|
-
*
|
|
137
|
+
* Initial port values the server boots with.
|
|
134
138
|
*
|
|
135
139
|
* Bound ports are app-owned. Every deferred key is contributed by a provider
|
|
136
140
|
* in server/providers.ts during startup; createNextServer(...) fails boot if
|
|
137
141
|
* any of them is still unbound after providers have started.
|
|
138
142
|
*/
|
|
139
|
-
export const
|
|
143
|
+
export const initialPorts = definePorts<AppPorts>()({
|
|
140
144
|
bound: {
|
|
141
145
|
errorReporter: createNoopErrorReporter(),
|
|
142
146
|
gate,
|
|
@@ -290,7 +294,7 @@ import {
|
|
|
290
294
|
createSecurityHeadersHooks,
|
|
291
295
|
} from "@beignet/core/server";
|
|
292
296
|
import type { AppContext } from "@/app-context";
|
|
293
|
-
import {
|
|
297
|
+
import { initialPorts } from "@/infra/port-wiring";
|
|
294
298
|
import { closeDatabaseClient } from "@/infra/db/client";
|
|
295
299
|
import { env } from "@/lib/env";
|
|
296
300
|
import { appContext } from "./context";
|
|
@@ -300,7 +304,7 @@ export const getServer = createNextServerLoader(async () => {
|
|
|
300
304
|
const { providers } = await import("./providers");
|
|
301
305
|
|
|
302
306
|
const server = await createNextServer({
|
|
303
|
-
ports:
|
|
307
|
+
ports: initialPorts,
|
|
304
308
|
providers,
|
|
305
309
|
hooks: [
|
|
306
310
|
createSecurityHeadersHooks<AppContext>(),
|
package/src/templates/shared.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
DatabaseName,
|
|
3
|
-
IntegrationName,
|
|
4
3
|
PackageManager,
|
|
4
|
+
StarterProviderName,
|
|
5
5
|
} from "../choices.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -23,7 +23,7 @@ export type TemplateContext = {
|
|
|
23
23
|
* When true, scaffold an API-only app without the UI shell.
|
|
24
24
|
*/
|
|
25
25
|
api: boolean;
|
|
26
|
-
|
|
26
|
+
providers: StarterProviderName[];
|
|
27
27
|
/**
|
|
28
28
|
* Database backing the starter's Drizzle persistence layer.
|
|
29
29
|
*/
|
|
@@ -169,30 +169,30 @@ export function packageRunner(ctx: TemplateContext): string {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
export const
|
|
173
|
-
|
|
172
|
+
export const starterProviderDeps: Record<
|
|
173
|
+
StarterProviderName,
|
|
174
174
|
Record<string, string>
|
|
175
175
|
> = {
|
|
176
|
-
inngest: {
|
|
176
|
+
"jobs-inngest": {
|
|
177
177
|
"@beignet/provider-jobs-inngest": "",
|
|
178
178
|
inngest: externalVersions.inngest,
|
|
179
179
|
},
|
|
180
|
-
resend: {
|
|
180
|
+
"mail-resend": {
|
|
181
181
|
"@beignet/provider-mail-resend": "",
|
|
182
182
|
resend: externalVersions.resend,
|
|
183
183
|
},
|
|
184
|
-
"
|
|
184
|
+
"rate-limit-upstash": {
|
|
185
185
|
"@beignet/provider-rate-limit-upstash": "",
|
|
186
186
|
"@upstash/ratelimit": externalVersions.upstashRateLimit,
|
|
187
187
|
"@upstash/redis": externalVersions.upstashRedis,
|
|
188
188
|
},
|
|
189
189
|
};
|
|
190
190
|
|
|
191
|
-
export function
|
|
191
|
+
export function hasStarterProvider(
|
|
192
192
|
ctx: TemplateContext,
|
|
193
|
-
|
|
193
|
+
provider: StarterProviderName,
|
|
194
194
|
): boolean {
|
|
195
|
-
return ctx.
|
|
195
|
+
return ctx.providers.includes(provider);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
export function json(value: unknown): string {
|
package/src/templates/testing.ts
CHANGED
|
@@ -536,7 +536,7 @@ async function configuredRoots(cwd: string): Promise<string[]> {
|
|
|
536
536
|
paths.features,
|
|
537
537
|
parentPath(paths.routes),
|
|
538
538
|
parentPath(paths.server),
|
|
539
|
-
parentPath(paths.
|
|
539
|
+
parentPath(paths.portWiring),
|
|
540
540
|
parentPath(paths.ports),
|
|
541
541
|
parentPath(paths.useCaseBuilder),
|
|
542
542
|
parentPath(paths.routesBuilder),
|
package/src/templates/todos.ts
CHANGED
|
@@ -368,7 +368,7 @@ import {
|
|
|
368
368
|
import { createInMemoryDevtools } from "@beignet/devtools";
|
|
369
369
|
import type { AppContext } from "@/app-context";
|
|
370
370
|
import type { TodoRepository } from "@/features/todos/ports";
|
|
371
|
-
import {
|
|
371
|
+
import { initialPorts } from "@/infra/port-wiring";
|
|
372
372
|
import type { AppTransactionPorts } from "@/ports";
|
|
373
373
|
import {
|
|
374
374
|
createTodoUseCase,
|
|
@@ -388,9 +388,9 @@ function createTester(userId: string, todos: TodoRepository) {
|
|
|
388
388
|
session: { id: \`session_\${userId}\` },
|
|
389
389
|
};
|
|
390
390
|
const testFixture = createTestPorts<AppContext["ports"], AppTransactionPorts>({
|
|
391
|
-
base:
|
|
391
|
+
base: initialPorts,
|
|
392
392
|
overrides: {
|
|
393
|
-
gate:
|
|
393
|
+
gate: initialPorts.gate,
|
|
394
394
|
todos,
|
|
395
395
|
devtools: createInMemoryDevtools(),
|
|
396
396
|
},
|
|
@@ -483,7 +483,7 @@ import { createInMemoryDevtools } from "@beignet/devtools";
|
|
|
483
483
|
import { createTestApp, createTestRequester } from "@beignet/web/testing";
|
|
484
484
|
import type { AppContext } from "@/app-context";
|
|
485
485
|
import type { TodoRepository } from "@/features/todos/ports";
|
|
486
|
-
import {
|
|
486
|
+
import { initialPorts } from "@/infra/port-wiring";
|
|
487
487
|
import type { AppPorts, AppTransactionPorts } from "@/ports";
|
|
488
488
|
import type { AuthRequest, AuthSessionMetadata, AuthUser } from "@/ports/auth";
|
|
489
489
|
import { type AppServiceContextInput, appContext } from "@/server/context";
|
|
@@ -507,9 +507,9 @@ async function createTodosTestApp(
|
|
|
507
507
|
) {
|
|
508
508
|
const todos = options.todos ?? createTestTodoRepository();
|
|
509
509
|
const fixture = createTestPorts<AppContext["ports"], AppTransactionPorts>({
|
|
510
|
-
base:
|
|
510
|
+
base: initialPorts,
|
|
511
511
|
overrides: {
|
|
512
|
-
gate:
|
|
512
|
+
gate: initialPorts.gate,
|
|
513
513
|
todos,
|
|
514
514
|
devtools: createInMemoryDevtools(),
|
|
515
515
|
auth: options.auth ?? createSignedOutAuth(),
|