@beignet/cli 0.0.4 → 0.0.5
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 +14 -0
- package/dist/choices.d.ts +5 -28
- package/dist/choices.d.ts.map +1 -1
- package/dist/choices.js +0 -35
- package/dist/choices.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 +19 -77
- package/dist/create-prompts.js.map +1 -1
- package/dist/create.d.ts +6 -4
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +15 -24
- package/dist/create.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -39
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +153 -1
- package/dist/make.js.map +1 -1
- package/dist/templates/base.d.ts +13 -0
- package/dist/templates/base.d.ts.map +1 -0
- package/dist/templates/base.js +300 -0
- package/dist/templates/base.js.map +1 -0
- package/dist/templates/db.d.ts +14 -0
- package/dist/templates/db.d.ts.map +1 -0
- package/dist/templates/db.js +962 -0
- package/dist/templates/db.js.map +1 -0
- package/dist/templates/index.d.ts +14 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +123 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/server.d.ts +26 -0
- package/dist/templates/server.d.ts.map +1 -0
- package/dist/templates/server.js +520 -0
- package/dist/templates/server.js.map +1 -0
- package/dist/templates/shadcn.d.ts +5 -0
- package/dist/templates/shadcn.d.ts.map +1 -0
- package/dist/templates/shadcn.js +555 -0
- package/dist/templates/shadcn.js.map +1 -0
- package/dist/templates/shared.d.ts +49 -0
- package/dist/templates/shared.d.ts.map +1 -0
- package/dist/templates/shared.js +57 -0
- package/dist/templates/shared.js.map +1 -0
- package/dist/templates/shell.d.ts +5 -0
- package/dist/templates/shell.d.ts.map +1 -0
- package/dist/templates/shell.js +1190 -0
- package/dist/templates/shell.js.map +1 -0
- package/dist/templates/todos.d.ts +17 -0
- package/dist/templates/todos.d.ts.map +1 -0
- package/dist/templates/todos.js +607 -0
- package/dist/templates/todos.js.map +1 -0
- package/package.json +2 -2
- package/src/choices.ts +4 -58
- package/src/create-prompts.ts +20 -88
- package/src/create.ts +21 -38
- package/src/index.ts +39 -45
- package/src/lib.ts +1 -1
- package/src/make.ts +208 -1
- package/src/templates/base.ts +377 -0
- package/src/templates/db.ts +963 -0
- package/src/templates/index.ts +148 -0
- package/src/templates/server.ts +528 -0
- package/src/templates/shadcn.ts +570 -0
- package/src/templates/shared.ts +90 -0
- package/src/templates/shell.ts +1219 -0
- package/src/templates/todos.ts +607 -0
- package/dist/templates.d.ts +0 -26
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js +0 -3995
- package/dist/templates.js.map +0 -1
- package/src/templates.ts +0 -4280
package/src/choices.ts
CHANGED
|
@@ -8,28 +8,17 @@
|
|
|
8
8
|
* Package managers supported by the app template generator.
|
|
9
9
|
*/
|
|
10
10
|
export type PackageManager = "bun" | "npm" | "pnpm" | "yarn";
|
|
11
|
-
/**
|
|
12
|
-
* Starter presets supported by the app template generator.
|
|
13
|
-
*/
|
|
14
|
-
export type PresetName = "minimal" | "standard";
|
|
15
11
|
/**
|
|
16
12
|
* Application templates supported by the app template generator.
|
|
17
13
|
*/
|
|
18
14
|
export type TemplateName = "next";
|
|
19
|
-
/**
|
|
20
|
-
* Optional first-party features that can be scaffolded into a new app.
|
|
21
|
-
*/
|
|
22
|
-
export type FeatureName = "client" | "react-query" | "forms" | "openapi";
|
|
23
15
|
/**
|
|
24
16
|
* Optional provider integrations that can be scaffolded into a new app.
|
|
17
|
+
*
|
|
18
|
+
* Better Auth, Drizzle/libSQL, and pino ship in every starter, so only
|
|
19
|
+
* integrations that add an external service remain selectable.
|
|
25
20
|
*/
|
|
26
|
-
export type IntegrationName =
|
|
27
|
-
| "better-auth"
|
|
28
|
-
| "drizzle-turso"
|
|
29
|
-
| "inngest"
|
|
30
|
-
| "pino"
|
|
31
|
-
| "resend"
|
|
32
|
-
| "upstash-rate-limit";
|
|
21
|
+
export type IntegrationName = "inngest" | "resend" | "upstash-rate-limit";
|
|
33
22
|
|
|
34
23
|
/**
|
|
35
24
|
* Supported scaffold template choices.
|
|
@@ -48,58 +37,15 @@ export const packageManagerChoices = [
|
|
|
48
37
|
"yarn",
|
|
49
38
|
] as const satisfies readonly PackageManager[];
|
|
50
39
|
|
|
51
|
-
/**
|
|
52
|
-
* Supported scaffold feature choices.
|
|
53
|
-
*/
|
|
54
|
-
export const featureChoices = [
|
|
55
|
-
"client",
|
|
56
|
-
"react-query",
|
|
57
|
-
"forms",
|
|
58
|
-
"openapi",
|
|
59
|
-
] as const satisfies readonly FeatureName[];
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Supported scaffold preset choices.
|
|
63
|
-
*/
|
|
64
|
-
export const presetChoices = [
|
|
65
|
-
"minimal",
|
|
66
|
-
"standard",
|
|
67
|
-
] as const satisfies readonly PresetName[];
|
|
68
|
-
|
|
69
40
|
/**
|
|
70
41
|
* Supported scaffold integration choices.
|
|
71
42
|
*/
|
|
72
43
|
export const integrationChoices = [
|
|
73
|
-
"better-auth",
|
|
74
|
-
"drizzle-turso",
|
|
75
44
|
"inngest",
|
|
76
|
-
"pino",
|
|
77
45
|
"resend",
|
|
78
46
|
"upstash-rate-limit",
|
|
79
47
|
] as const satisfies readonly IntegrationName[];
|
|
80
48
|
|
|
81
|
-
/**
|
|
82
|
-
* Features included by each starter preset before explicit `--features`
|
|
83
|
-
* selections are added.
|
|
84
|
-
*/
|
|
85
|
-
export const presetFeatureDefaults: Record<PresetName, readonly FeatureName[]> =
|
|
86
|
-
{
|
|
87
|
-
minimal: [],
|
|
88
|
-
standard: featureChoices,
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Integrations included by each starter preset before explicit
|
|
93
|
-
* `--integrations` selections are added.
|
|
94
|
-
*/
|
|
95
|
-
export const presetIntegrationDefaults: Record<
|
|
96
|
-
PresetName,
|
|
97
|
-
readonly IntegrationName[]
|
|
98
|
-
> = {
|
|
99
|
-
minimal: [],
|
|
100
|
-
standard: ["better-auth", "drizzle-turso", "pino"],
|
|
101
|
-
};
|
|
102
|
-
|
|
103
49
|
/**
|
|
104
50
|
* Shells supported by `beignet completion install` and `uninstall`.
|
|
105
51
|
*/
|
package/src/create-prompts.ts
CHANGED
|
@@ -7,14 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
type FeatureName,
|
|
11
|
-
featureChoices,
|
|
12
10
|
type IntegrationName,
|
|
13
11
|
integrationChoices,
|
|
14
12
|
type PackageManager,
|
|
15
|
-
type PresetName,
|
|
16
|
-
packageManagerChoices,
|
|
17
|
-
presetIntegrationDefaults,
|
|
18
13
|
} from "./choices.js";
|
|
19
14
|
|
|
20
15
|
/**
|
|
@@ -22,8 +17,7 @@ import {
|
|
|
22
17
|
*/
|
|
23
18
|
export type CreateSelections = {
|
|
24
19
|
directory?: string;
|
|
25
|
-
|
|
26
|
-
features?: readonly FeatureName[];
|
|
20
|
+
api?: boolean;
|
|
27
21
|
integrations?: readonly IntegrationName[];
|
|
28
22
|
packageManager?: PackageManager;
|
|
29
23
|
};
|
|
@@ -41,9 +35,9 @@ type CreatePromptTty = {
|
|
|
41
35
|
* Decide whether `beignet create` should run the interactive prompt flow.
|
|
42
36
|
*
|
|
43
37
|
* Prompts run only on a full TTY, only when `--yes` is absent, and only when
|
|
44
|
-
* no selection flag was passed. Any explicit
|
|
45
|
-
*
|
|
46
|
-
*
|
|
38
|
+
* no selection flag was passed. Any explicit api, integration, or package
|
|
39
|
+
* manager selection means the invocation is scripted, so the non-interactive
|
|
40
|
+
* path stays byte-identical for agents and CI.
|
|
47
41
|
*/
|
|
48
42
|
export function shouldPromptInteractively(
|
|
49
43
|
flags: CreatePromptFlags,
|
|
@@ -53,26 +47,15 @@ export function shouldPromptInteractively(
|
|
|
53
47
|
if (flags.yes) return false;
|
|
54
48
|
|
|
55
49
|
const selectionFlagPassed =
|
|
56
|
-
flags.
|
|
57
|
-
(flags.features?.length ?? 0) > 0 ||
|
|
50
|
+
flags.api !== undefined ||
|
|
58
51
|
(flags.integrations?.length ?? 0) > 0 ||
|
|
59
52
|
flags.packageManager !== undefined;
|
|
60
53
|
|
|
61
54
|
return !selectionFlagPassed;
|
|
62
55
|
}
|
|
63
56
|
|
|
64
|
-
const featureHints: Record<FeatureName, string> = {
|
|
65
|
-
client: "Typed Beignet HTTP client",
|
|
66
|
-
"react-query": "TanStack Query helpers for contracts",
|
|
67
|
-
forms: "React Hook Form wired to contract bodies",
|
|
68
|
-
openapi: "OpenAPI document route generated from contracts",
|
|
69
|
-
};
|
|
70
|
-
|
|
71
57
|
const integrationHints: Record<IntegrationName, string> = {
|
|
72
|
-
"better-auth": "Better Auth routes and auth provider wiring",
|
|
73
|
-
"drizzle-turso": "Drizzle/libSQL persistence with Turso-ready config",
|
|
74
58
|
inngest: "Inngest-backed background jobs",
|
|
75
|
-
pino: "Pino logger provider",
|
|
76
59
|
resend: "Resend-backed mail provider",
|
|
77
60
|
"upstash-rate-limit": "Upstash-backed rate limiting",
|
|
78
61
|
};
|
|
@@ -103,80 +86,29 @@ export async function promptCreateSelections(
|
|
|
103
86
|
directory = answer;
|
|
104
87
|
}
|
|
105
88
|
|
|
106
|
-
const
|
|
107
|
-
message: "
|
|
108
|
-
|
|
109
|
-
{
|
|
110
|
-
value: "standard",
|
|
111
|
-
label: "standard",
|
|
112
|
-
hint: "Full app layout with auth, database, jobs, and devtools",
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
value: "minimal",
|
|
116
|
-
label: "minimal",
|
|
117
|
-
hint: "Smallest contract/server/use-case loop",
|
|
118
|
-
},
|
|
119
|
-
],
|
|
120
|
-
initialValue: "standard",
|
|
89
|
+
const api = await prompts.confirm({
|
|
90
|
+
message: "API-only app (no UI shell)?",
|
|
91
|
+
initialValue: false,
|
|
121
92
|
});
|
|
122
|
-
if (prompts.isCancel(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
options: featureChoices.map((feature) => ({
|
|
131
|
-
value: feature,
|
|
132
|
-
label: feature,
|
|
133
|
-
hint: featureHints[feature],
|
|
134
|
-
})),
|
|
135
|
-
required: false,
|
|
136
|
-
});
|
|
137
|
-
if (prompts.isCancel(answer)) return undefined;
|
|
138
|
-
features = answer;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const presetIntegrations = new Set(presetIntegrationDefaults[preset]);
|
|
142
|
-
const integrationOptions = integrationChoices.filter(
|
|
143
|
-
(integration) => !presetIntegrations.has(integration),
|
|
144
|
-
);
|
|
145
|
-
let integrations: readonly IntegrationName[] | undefined;
|
|
146
|
-
if (integrationOptions.length > 0) {
|
|
147
|
-
const answer = await prompts.multiselect<IntegrationName>({
|
|
148
|
-
message:
|
|
149
|
-
presetIntegrations.size > 0
|
|
150
|
-
? "Add provider integrations beyond the preset defaults? (press enter to skip)"
|
|
151
|
-
: "Add provider integrations? (press enter to skip)",
|
|
152
|
-
options: integrationOptions.map((integration) => ({
|
|
153
|
-
value: integration,
|
|
154
|
-
label: integration,
|
|
155
|
-
hint: integrationHints[integration],
|
|
156
|
-
})),
|
|
157
|
-
required: false,
|
|
158
|
-
});
|
|
159
|
-
if (prompts.isCancel(answer)) return undefined;
|
|
160
|
-
integrations = answer;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const packageManager = await prompts.select<PackageManager>({
|
|
164
|
-
message: "Which package manager?",
|
|
165
|
-
options: packageManagerChoices.map((manager) => ({
|
|
166
|
-
value: manager,
|
|
167
|
-
label: manager,
|
|
93
|
+
if (prompts.isCancel(api)) return undefined;
|
|
94
|
+
|
|
95
|
+
const integrations = await prompts.multiselect<IntegrationName>({
|
|
96
|
+
message: "Add provider integrations? (press enter to skip)",
|
|
97
|
+
options: integrationChoices.map((integration) => ({
|
|
98
|
+
value: integration,
|
|
99
|
+
label: integration,
|
|
100
|
+
hint: integrationHints[integration],
|
|
168
101
|
})),
|
|
169
|
-
|
|
102
|
+
required: false,
|
|
170
103
|
});
|
|
171
|
-
if (prompts.isCancel(
|
|
104
|
+
if (prompts.isCancel(integrations)) return undefined;
|
|
172
105
|
|
|
173
106
|
prompts.outro(`Creating ${directory}`);
|
|
174
107
|
|
|
175
108
|
return {
|
|
176
109
|
directory,
|
|
177
|
-
|
|
178
|
-
features,
|
|
110
|
+
api,
|
|
179
111
|
integrations,
|
|
180
|
-
packageManager,
|
|
112
|
+
packageManager: initial.packageManager,
|
|
181
113
|
};
|
|
182
114
|
}
|
package/src/create.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { mkdir, readdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { presetFeatureDefaults, presetIntegrationDefaults } from "./choices.js";
|
|
4
3
|
import {
|
|
5
|
-
type FeatureName,
|
|
6
|
-
featureChoices,
|
|
7
4
|
getTemplateFiles,
|
|
8
5
|
type IntegrationName,
|
|
9
6
|
integrationChoices,
|
|
10
7
|
type PackageManager,
|
|
11
|
-
type PresetName,
|
|
12
8
|
type TemplateName,
|
|
13
|
-
} from "./templates.js";
|
|
9
|
+
} from "./templates/index.js";
|
|
14
10
|
import { getCliVersion } from "./version.js";
|
|
15
11
|
|
|
16
12
|
/**
|
|
@@ -20,8 +16,10 @@ export type CreateOptions = {
|
|
|
20
16
|
name: string;
|
|
21
17
|
cwd?: string;
|
|
22
18
|
template?: TemplateName;
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Scaffold an API-only app without the UI shell.
|
|
21
|
+
*/
|
|
22
|
+
api?: boolean;
|
|
25
23
|
packageManager?: PackageManager;
|
|
26
24
|
integrations?: IntegrationName[];
|
|
27
25
|
force?: boolean;
|
|
@@ -42,7 +40,7 @@ export type CreateResult = {
|
|
|
42
40
|
};
|
|
43
41
|
|
|
44
42
|
/**
|
|
45
|
-
* Create a Beignet app from
|
|
43
|
+
* Create a Beignet app from the starter template.
|
|
46
44
|
*/
|
|
47
45
|
export async function createProject(
|
|
48
46
|
options: CreateOptions,
|
|
@@ -52,9 +50,8 @@ export async function createProject(
|
|
|
52
50
|
const targetDir = path.resolve(cwd, options.name);
|
|
53
51
|
const packageManager = options.packageManager ?? "bun";
|
|
54
52
|
const template = options.template ?? "next";
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const integrations = resolveIntegrations(preset, options.integrations ?? []);
|
|
53
|
+
const api = Boolean(options.api);
|
|
54
|
+
const integrations = resolveIntegrations(options.integrations ?? []);
|
|
58
55
|
|
|
59
56
|
if (template !== "next") {
|
|
60
57
|
throw new Error(
|
|
@@ -70,8 +67,7 @@ export async function createProject(
|
|
|
70
67
|
name,
|
|
71
68
|
packageManager,
|
|
72
69
|
beignetVersion: options.beignetVersion ?? getDefaultBeignetVersion(),
|
|
73
|
-
|
|
74
|
-
features,
|
|
70
|
+
api,
|
|
75
71
|
integrations,
|
|
76
72
|
});
|
|
77
73
|
|
|
@@ -95,38 +91,25 @@ export async function createProject(
|
|
|
95
91
|
};
|
|
96
92
|
}
|
|
97
93
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
for (const feature of explicitFeatures) {
|
|
105
|
-
features.add(feature);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (features.has("forms")) {
|
|
109
|
-
features.add("react-query");
|
|
110
|
-
}
|
|
111
|
-
if (features.has("react-query")) {
|
|
112
|
-
features.add("client");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return featureChoices.filter((feature) => features.has(feature));
|
|
116
|
-
}
|
|
94
|
+
/**
|
|
95
|
+
* Providers that ship in every starter. They used to be `--integrations`
|
|
96
|
+
* choices, so passing them gets a pointed error instead of a generic one.
|
|
97
|
+
*/
|
|
98
|
+
const baseProviderNames = new Set(["better-auth", "drizzle-turso", "pino"]);
|
|
117
99
|
|
|
118
100
|
function resolveIntegrations(
|
|
119
|
-
preset: PresetName,
|
|
120
101
|
explicitIntegrations: IntegrationName[],
|
|
121
102
|
): IntegrationName[] {
|
|
122
|
-
const integrations = new Set<IntegrationName>(
|
|
123
|
-
presetIntegrationDefaults[preset],
|
|
124
|
-
);
|
|
125
|
-
|
|
126
103
|
for (const integration of explicitIntegrations) {
|
|
127
|
-
|
|
104
|
+
if (baseProviderNames.has(integration)) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`${integration} is part of every Beignet starter and no longer an --integrations choice.`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
128
109
|
}
|
|
129
110
|
|
|
111
|
+
const integrations = new Set<IntegrationName>(explicitIntegrations);
|
|
112
|
+
|
|
130
113
|
return integrationChoices.filter((integration) =>
|
|
131
114
|
integrations.has(integration),
|
|
132
115
|
);
|
package/src/index.ts
CHANGED
|
@@ -16,16 +16,12 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
type CompletionShell,
|
|
18
18
|
completionShellChoices,
|
|
19
|
-
type FeatureName,
|
|
20
|
-
featureChoices,
|
|
21
19
|
type IntegrationName,
|
|
22
20
|
integrationChoices,
|
|
23
21
|
type MakeFeatureAddon,
|
|
24
22
|
makeFeatureAddonChoices,
|
|
25
23
|
type PackageManager,
|
|
26
|
-
type PresetName,
|
|
27
24
|
packageManagerChoices,
|
|
28
|
-
presetChoices,
|
|
29
25
|
type TemplateName,
|
|
30
26
|
templateChoices,
|
|
31
27
|
} from "./choices.js";
|
|
@@ -47,9 +43,8 @@ const outputFormatChoices = [
|
|
|
47
43
|
|
|
48
44
|
type CreateFlags = {
|
|
49
45
|
template: TemplateName;
|
|
50
|
-
|
|
46
|
+
api?: boolean;
|
|
51
47
|
packageManager?: PackageManager;
|
|
52
|
-
features?: readonly FeatureName[];
|
|
53
48
|
integrations?: readonly IntegrationName[];
|
|
54
49
|
yes?: boolean;
|
|
55
50
|
force?: boolean;
|
|
@@ -286,7 +281,10 @@ const createCommand = buildCommand<
|
|
|
286
281
|
>({
|
|
287
282
|
docs: {
|
|
288
283
|
brief: "Create a new Beignet app.",
|
|
289
|
-
fullDescription: `
|
|
284
|
+
fullDescription: `Scaffolds a full-stack Beignet starter: typed contracts, Better Auth,
|
|
285
|
+
Drizzle/libSQL persistence with checked-in migrations, pino logging,
|
|
286
|
+
devtools, and a shadcn UI shell. Pass --api for an API-only scaffold
|
|
287
|
+
without the UI shell.
|
|
290
288
|
|
|
291
289
|
Available integrations: ${integrationChoices.join(", ")}
|
|
292
290
|
|
|
@@ -301,11 +299,11 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
301
299
|
default: "next",
|
|
302
300
|
brief: "Template to use.",
|
|
303
301
|
},
|
|
304
|
-
|
|
305
|
-
kind: "
|
|
306
|
-
values: presetChoices,
|
|
302
|
+
api: {
|
|
303
|
+
kind: "boolean",
|
|
307
304
|
optional: true,
|
|
308
|
-
|
|
305
|
+
withNegated: false,
|
|
306
|
+
brief: "Scaffold an API-only app without the UI shell.",
|
|
309
307
|
},
|
|
310
308
|
packageManager: {
|
|
311
309
|
kind: "enum",
|
|
@@ -313,13 +311,6 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
313
311
|
optional: true,
|
|
314
312
|
brief: "Package manager to use in next-step commands.",
|
|
315
313
|
},
|
|
316
|
-
features: {
|
|
317
|
-
kind: "enum",
|
|
318
|
-
values: featureChoices,
|
|
319
|
-
optional: true,
|
|
320
|
-
variadic: ",",
|
|
321
|
-
brief: "Add starter features as a comma-separated list.",
|
|
322
|
-
},
|
|
323
314
|
integrations: {
|
|
324
315
|
kind: "enum",
|
|
325
316
|
values: integrationChoices,
|
|
@@ -362,8 +353,7 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
362
353
|
) {
|
|
363
354
|
let selections: CreateSelections = {
|
|
364
355
|
directory,
|
|
365
|
-
|
|
366
|
-
features: flags.features,
|
|
356
|
+
api: flags.api,
|
|
367
357
|
integrations: flags.integrations,
|
|
368
358
|
packageManager: flags.packageManager,
|
|
369
359
|
};
|
|
@@ -391,12 +381,12 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
391
381
|
);
|
|
392
382
|
}
|
|
393
383
|
|
|
384
|
+
const api = selections.api ?? false;
|
|
394
385
|
const integrations = uniqueValues([...(selections.integrations ?? [])]);
|
|
395
386
|
const result = await createProject({
|
|
396
387
|
name: selections.directory,
|
|
397
388
|
template: flags.template,
|
|
398
|
-
|
|
399
|
-
features: uniqueValues([...(selections.features ?? [])]),
|
|
389
|
+
api,
|
|
400
390
|
packageManager: selections.packageManager,
|
|
401
391
|
integrations,
|
|
402
392
|
force: Boolean(flags.force),
|
|
@@ -407,7 +397,7 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
|
|
|
407
397
|
this,
|
|
408
398
|
flags.json
|
|
409
399
|
? JSON.stringify(result, null, 2)
|
|
410
|
-
: nextSteps(result, { integrations }),
|
|
400
|
+
: nextSteps(result, { api, integrations }),
|
|
411
401
|
);
|
|
412
402
|
};
|
|
413
403
|
},
|
|
@@ -1020,7 +1010,7 @@ const makeScheduleCommand = buildCommand<
|
|
|
1020
1010
|
this,
|
|
1021
1011
|
flags.json
|
|
1022
1012
|
? JSON.stringify(result, null, 2)
|
|
1023
|
-
: makeScheduleNextSteps(result),
|
|
1013
|
+
: makeScheduleNextSteps(result, { route: Boolean(flags.route) }),
|
|
1024
1014
|
);
|
|
1025
1015
|
};
|
|
1026
1016
|
},
|
|
@@ -1245,7 +1235,10 @@ Run:
|
|
|
1245
1235
|
|
|
1246
1236
|
function nextSteps(
|
|
1247
1237
|
result: CreateNextStepsResult,
|
|
1248
|
-
options: {
|
|
1238
|
+
options: {
|
|
1239
|
+
api?: boolean;
|
|
1240
|
+
integrations?: readonly IntegrationName[];
|
|
1241
|
+
} = {},
|
|
1249
1242
|
): string {
|
|
1250
1243
|
if (result.dryRun) {
|
|
1251
1244
|
const plannedFiles = result.files.map((file) => ` ${file}`).join("\n");
|
|
@@ -1259,37 +1252,29 @@ ${plannedFiles}`;
|
|
|
1259
1252
|
const pm = result.packageManager;
|
|
1260
1253
|
const run = pm === "npm" ? "npm run" : `${pm} run`;
|
|
1261
1254
|
const cli = packageRunnerFromPackageManager(pm);
|
|
1262
|
-
const envFileStep = result.files.includes(".env.example")
|
|
1263
|
-
? " cp .env.example .env.local\n"
|
|
1264
|
-
: "";
|
|
1265
1255
|
const envRequiredIntegrations =
|
|
1266
1256
|
options.integrations?.filter(isEnvRequiredProviderIntegration) ?? [];
|
|
1267
1257
|
const envStep =
|
|
1268
1258
|
envRequiredIntegrations.length > 0
|
|
1269
1259
|
? " Fill .env.local for selected provider integrations before starting the app.\n"
|
|
1270
1260
|
: "";
|
|
1271
|
-
const
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
Prepare the database:
|
|
1275
|
-
${cli} db generate
|
|
1276
|
-
${cli} db migrate
|
|
1277
|
-
`
|
|
1278
|
-
: "";
|
|
1279
|
-
const featureDatabaseSteps = hasDatabase
|
|
1280
|
-
? `
|
|
1281
|
-
${cli} db generate
|
|
1282
|
-
${cli} db migrate`
|
|
1283
|
-
: "";
|
|
1261
|
+
const openStep = options.api
|
|
1262
|
+
? " open http://localhost:3000 for the API landing page"
|
|
1263
|
+
: " open http://localhost:3000/sign-up";
|
|
1284
1264
|
|
|
1285
1265
|
return `Created ${result.name} at ${result.targetDir}
|
|
1286
1266
|
|
|
1287
1267
|
Next steps:
|
|
1288
1268
|
cd ${result.targetDir}
|
|
1289
1269
|
${pm} install
|
|
1290
|
-
|
|
1270
|
+
cp .env.example .env.local
|
|
1271
|
+
${envStep}
|
|
1272
|
+
Prepare the database:
|
|
1273
|
+
${cli} db migrate
|
|
1274
|
+
|
|
1291
1275
|
Start the app:
|
|
1292
1276
|
${run} dev
|
|
1277
|
+
${openStep}
|
|
1293
1278
|
|
|
1294
1279
|
Inspect the app:
|
|
1295
1280
|
${cli} routes
|
|
@@ -1297,7 +1282,9 @@ Inspect the app:
|
|
|
1297
1282
|
${cli} doctor
|
|
1298
1283
|
|
|
1299
1284
|
Generate a feature:
|
|
1300
|
-
${cli} make feature projects
|
|
1285
|
+
${cli} make feature projects
|
|
1286
|
+
${cli} db generate
|
|
1287
|
+
${cli} db migrate
|
|
1301
1288
|
${run} test
|
|
1302
1289
|
${run} typecheck
|
|
1303
1290
|
${cli} lint
|
|
@@ -1477,10 +1464,17 @@ function makeListenerNextSteps(result: MakeNextStepsResult): string {
|
|
|
1477
1464
|
]);
|
|
1478
1465
|
}
|
|
1479
1466
|
|
|
1480
|
-
function makeScheduleNextSteps(
|
|
1467
|
+
function makeScheduleNextSteps(
|
|
1468
|
+
result: MakeNextStepsResult,
|
|
1469
|
+
options: { route?: boolean } = {},
|
|
1470
|
+
): string {
|
|
1481
1471
|
return makeNextSteps(result, "schedule", [
|
|
1482
1472
|
"Replace the starter payload and handler with the scheduled workflow.",
|
|
1483
|
-
|
|
1473
|
+
...(options.route
|
|
1474
|
+
? [
|
|
1475
|
+
"Set CRON_SECRET in your deployment and configure a scheduled request with Authorization: Bearer $CRON_SECRET.",
|
|
1476
|
+
]
|
|
1477
|
+
: ["Trigger it from a cron route, worker, or provider adapter."]),
|
|
1484
1478
|
]);
|
|
1485
1479
|
}
|
|
1486
1480
|
|
package/src/lib.ts
CHANGED
|
@@ -42,4 +42,4 @@ export {
|
|
|
42
42
|
export { runOutboxDrain } from "./outbox.js";
|
|
43
43
|
export { runAppSchedule } from "./schedule.js";
|
|
44
44
|
export { runAppTask } from "./task.js";
|
|
45
|
-
export type { IntegrationName } from "./templates.js";
|
|
45
|
+
export type { IntegrationName } from "./templates/index.js";
|