@tanstack/create 0.61.4 → 0.61.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 +17 -0
- package/dist/create-app.js +64 -3
- package/dist/custom-add-ons/add-on.js +59 -1
- package/dist/custom-add-ons/starter.js +5 -1
- package/dist/frameworks/react/add-ons/clerk/info.json +9 -0
- package/dist/frameworks/react/add-ons/convex/info.json +16 -0
- package/dist/frameworks.js +1 -0
- package/dist/index.js +1 -1
- package/dist/types/custom-add-ons/add-on.d.ts +9 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +192 -0
- package/dist/types.js +10 -0
- package/package.json +1 -1
- package/src/create-app.ts +77 -3
- package/src/custom-add-ons/add-on.ts +72 -1
- package/src/custom-add-ons/starter.ts +7 -1
- package/src/frameworks/react/add-ons/clerk/info.json +9 -0
- package/src/frameworks/react/add-ons/convex/info.json +16 -0
- package/src/frameworks.ts +1 -0
- package/src/index.ts +1 -1
- package/src/types.ts +14 -0
- package/tests/custom-add-ons/starter.test.ts +29 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @tanstack/create
|
|
2
2
|
|
|
3
|
+
## 0.61.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add a continuous development workflow for custom add-on authors. ([`b3cc585`](https://github.com/TanStack/cli/commit/b3cc5851d2b81613e3b024eb7981c440ee5183af))
|
|
8
|
+
|
|
9
|
+
- Add `tanstack add-on dev` to watch project files and continuously refresh `.add-on` outputs.
|
|
10
|
+
- Rebuild `.add-on` assets and `add-on.json` automatically when source files change.
|
|
11
|
+
- Document the new add-on development loop in the custom add-on guide.
|
|
12
|
+
|
|
13
|
+
- Improve scaffold customization and custom add-on authoring flow. ([`5fbf262`](https://github.com/TanStack/cli/commit/5fbf262fe3a0d070e6a78fa2f2a920b176b84480))
|
|
14
|
+
|
|
15
|
+
- Add `--examples` / `--no-examples` support to include or omit demo/example pages during app creation.
|
|
16
|
+
- Prompt for add-on-declared environment variables during interactive create and seed entered values into generated `.env.local`.
|
|
17
|
+
- Ensure custom add-on/starter metadata consistently includes a `version`, with safe backfill for older metadata files.
|
|
18
|
+
- Align bundled starter/example metadata and docs with current Start/file-router behavior.
|
|
19
|
+
|
|
3
20
|
## 0.61.4
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/create-app.js
CHANGED
|
@@ -8,6 +8,42 @@ import { createTemplateFile } from './template-file.js';
|
|
|
8
8
|
import { installShadcnComponents } from './integrations/shadcn.js';
|
|
9
9
|
import { setupGit } from './integrations/git.js';
|
|
10
10
|
import { runSpecialSteps } from './special-steps/index.js';
|
|
11
|
+
function isDemoRoutePath(path) {
|
|
12
|
+
if (!path)
|
|
13
|
+
return false;
|
|
14
|
+
const normalized = path.replace(/\\/g, '/');
|
|
15
|
+
return (normalized.includes('/routes/demo/') ||
|
|
16
|
+
normalized.includes('/routes/demo.') ||
|
|
17
|
+
normalized.includes('/routes/example/') ||
|
|
18
|
+
normalized.includes('/routes/example.'));
|
|
19
|
+
}
|
|
20
|
+
function stripExamplesFromOptions(options) {
|
|
21
|
+
if (options.includeExamples !== false) {
|
|
22
|
+
return options;
|
|
23
|
+
}
|
|
24
|
+
const chosenAddOns = options.chosenAddOns
|
|
25
|
+
.filter((addOn) => addOn.type !== 'example')
|
|
26
|
+
.map((addOn) => {
|
|
27
|
+
const filteredRoutes = (addOn.routes || []).filter((route) => !isDemoRoutePath(route.path) &&
|
|
28
|
+
!(route.url && route.url.startsWith('/demo')));
|
|
29
|
+
return {
|
|
30
|
+
...addOn,
|
|
31
|
+
routes: filteredRoutes,
|
|
32
|
+
getFiles: async () => {
|
|
33
|
+
const files = await addOn.getFiles();
|
|
34
|
+
return files.filter((file) => !isDemoRoutePath(file));
|
|
35
|
+
},
|
|
36
|
+
getDeletedFiles: async () => {
|
|
37
|
+
const deletedFiles = await addOn.getDeletedFiles();
|
|
38
|
+
return deletedFiles.filter((file) => !isDemoRoutePath(file));
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
...options,
|
|
44
|
+
chosenAddOns,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
11
47
|
async function writeFiles(environment, options) {
|
|
12
48
|
const templateFileFromContent = createTemplateFile(environment, options);
|
|
13
49
|
async function writeFileBundle(bundle) {
|
|
@@ -170,6 +206,29 @@ async function runCommandsAndInstallDependencies(environment, options) {
|
|
|
170
206
|
}
|
|
171
207
|
await installShadcnComponents(environment, options.targetDir, options);
|
|
172
208
|
}
|
|
209
|
+
async function seedEnvValues(environment, options) {
|
|
210
|
+
const envVarValues = options.envVarValues || {};
|
|
211
|
+
const entries = Object.entries(envVarValues);
|
|
212
|
+
if (entries.length === 0)
|
|
213
|
+
return;
|
|
214
|
+
const envLocalPath = resolve(options.targetDir, '.env.local');
|
|
215
|
+
if (!environment.exists(envLocalPath)) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
let envContents = await environment.readFile(envLocalPath);
|
|
219
|
+
for (const [key, value] of entries) {
|
|
220
|
+
const escapedValue = value.replace(/\n/g, '\\n');
|
|
221
|
+
const nextLine = `${key}=${escapedValue}`;
|
|
222
|
+
const pattern = new RegExp(`^${key}=.*$`, 'm');
|
|
223
|
+
if (pattern.test(envContents)) {
|
|
224
|
+
envContents = envContents.replace(pattern, nextLine);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
envContents += `${envContents.endsWith('\n') ? '' : '\n'}${nextLine}\n`;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
await environment.writeFile(envLocalPath, envContents);
|
|
231
|
+
}
|
|
173
232
|
function report(environment, options) {
|
|
174
233
|
const warnings = [];
|
|
175
234
|
for (const addOn of options.chosenAddOns) {
|
|
@@ -207,9 +266,11 @@ ${cdInstruction}% ${formatCommand(getPackageManagerScriptCommand(options.package
|
|
|
207
266
|
Please read the README.md file for information on testing, styling, adding routes, etc.${errorStatement}`);
|
|
208
267
|
}
|
|
209
268
|
export async function createApp(environment, options) {
|
|
269
|
+
const effectiveOptions = stripExamplesFromOptions(options);
|
|
210
270
|
environment.startRun();
|
|
211
|
-
await writeFiles(environment,
|
|
212
|
-
await
|
|
271
|
+
await writeFiles(environment, effectiveOptions);
|
|
272
|
+
await seedEnvValues(environment, effectiveOptions);
|
|
273
|
+
await runCommandsAndInstallDependencies(environment, effectiveOptions);
|
|
213
274
|
environment.finishRun();
|
|
214
|
-
report(environment,
|
|
275
|
+
report(environment, effectiveOptions);
|
|
215
276
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
1
|
+
import { readFile, watch } from 'node:fs/promises';
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { basename, dirname, resolve } from 'node:path';
|
|
4
4
|
import { AddOnCompiledSchema } from '../types.js';
|
|
@@ -15,6 +15,19 @@ export const ADD_ON_IGNORE_FILES = [
|
|
|
15
15
|
const INFO_FILE = '.add-on/info.json';
|
|
16
16
|
const COMPILED_FILE = 'add-on.json';
|
|
17
17
|
const ASSETS_DIR = 'assets';
|
|
18
|
+
const ADD_ON_DEV_IGNORE_PREFIXES = [
|
|
19
|
+
'.add-on/',
|
|
20
|
+
'.git/',
|
|
21
|
+
'node_modules/',
|
|
22
|
+
'.turbo/',
|
|
23
|
+
'dist/',
|
|
24
|
+
];
|
|
25
|
+
function shouldIgnoreDevPath(path) {
|
|
26
|
+
const normalized = path.replace(/\\/g, '/');
|
|
27
|
+
if (normalized === COMPILED_FILE)
|
|
28
|
+
return true;
|
|
29
|
+
return ADD_ON_DEV_IGNORE_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
30
|
+
}
|
|
18
31
|
export function camelCase(str) {
|
|
19
32
|
return str
|
|
20
33
|
.split(/(\.|-|\/)/)
|
|
@@ -78,6 +91,9 @@ export async function readOrGenerateAddOnInfo(options) {
|
|
|
78
91
|
},
|
|
79
92
|
dependsOn: options.chosenAddOns,
|
|
80
93
|
};
|
|
94
|
+
if (!info.version) {
|
|
95
|
+
info.version = '0.0.1';
|
|
96
|
+
}
|
|
81
97
|
return info;
|
|
82
98
|
}
|
|
83
99
|
export async function generateProject(persistedOptions) {
|
|
@@ -136,6 +152,48 @@ export async function initAddOn(environment) {
|
|
|
136
152
|
await updateAddOnInfo(environment);
|
|
137
153
|
await compileAddOn(environment);
|
|
138
154
|
}
|
|
155
|
+
export async function devAddOn(environment) {
|
|
156
|
+
await initAddOn(environment);
|
|
157
|
+
environment.info('Add-on dev mode is running.', 'Watching project files and recompiling add-on output on changes. Press Ctrl+C to stop.');
|
|
158
|
+
const abortController = new AbortController();
|
|
159
|
+
let debounceTimeout;
|
|
160
|
+
const rerun = async () => {
|
|
161
|
+
try {
|
|
162
|
+
await updateAddOnInfo(environment);
|
|
163
|
+
await compileAddOn(environment);
|
|
164
|
+
environment.info('Add-on updated.', 'Compiled add-on.json and refreshed .add-on');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
168
|
+
environment.error('Failed to rebuild add-on.', message);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
process.once('SIGINT', () => {
|
|
172
|
+
abortController.abort();
|
|
173
|
+
});
|
|
174
|
+
try {
|
|
175
|
+
for await (const event of watch(process.cwd(), {
|
|
176
|
+
recursive: true,
|
|
177
|
+
signal: abortController.signal,
|
|
178
|
+
})) {
|
|
179
|
+
const file = event.filename?.toString();
|
|
180
|
+
if (!file || shouldIgnoreDevPath(file))
|
|
181
|
+
continue;
|
|
182
|
+
if (debounceTimeout) {
|
|
183
|
+
clearTimeout(debounceTimeout);
|
|
184
|
+
}
|
|
185
|
+
debounceTimeout = setTimeout(() => {
|
|
186
|
+
void rerun();
|
|
187
|
+
}, 200);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
192
|
+
if (!message.includes('aborted')) {
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
139
197
|
export async function loadRemoteAddOn(url) {
|
|
140
198
|
const response = await fetch(url);
|
|
141
199
|
const jsonContent = await response.json();
|
|
@@ -7,7 +7,7 @@ import { compareFilesRecursively, createAppOptionsFromPersisted, createPackageAd
|
|
|
7
7
|
const INFO_FILE = 'starter-info.json';
|
|
8
8
|
const COMPILED_FILE = 'starter.json';
|
|
9
9
|
export async function readOrGenerateStarterInfo(options) {
|
|
10
|
-
|
|
10
|
+
const info = existsSync(INFO_FILE)
|
|
11
11
|
? JSON.parse((await readFile(INFO_FILE)).toString())
|
|
12
12
|
: {
|
|
13
13
|
id: `${options.projectName}-starter`,
|
|
@@ -31,6 +31,10 @@ export async function readOrGenerateStarterInfo(options) {
|
|
|
31
31
|
dependsOn: options.chosenAddOns,
|
|
32
32
|
typescript: true,
|
|
33
33
|
};
|
|
34
|
+
if (!info.version) {
|
|
35
|
+
info.version = '0.0.1';
|
|
36
|
+
}
|
|
37
|
+
return info;
|
|
34
38
|
}
|
|
35
39
|
async function loadCurrentStarterInfo(environment) {
|
|
36
40
|
const persistedOptions = await readCurrentProjectOptions(environment);
|
|
@@ -28,5 +28,14 @@
|
|
|
28
28
|
"jsName": "ClerkProvider",
|
|
29
29
|
"path": "src/integrations/clerk/provider.tsx"
|
|
30
30
|
}
|
|
31
|
+
],
|
|
32
|
+
"envVars": [
|
|
33
|
+
{
|
|
34
|
+
"name": "VITE_CLERK_PUBLISHABLE_KEY",
|
|
35
|
+
"description": "Clerk publishable key",
|
|
36
|
+
"required": true,
|
|
37
|
+
"secret": false,
|
|
38
|
+
"file": ".env.local"
|
|
39
|
+
}
|
|
31
40
|
]
|
|
32
41
|
}
|
|
@@ -23,5 +23,21 @@
|
|
|
23
23
|
"path": "src/integrations/convex/provider.tsx",
|
|
24
24
|
"jsName": "ConvexProvider"
|
|
25
25
|
}
|
|
26
|
+
],
|
|
27
|
+
"envVars": [
|
|
28
|
+
{
|
|
29
|
+
"name": "CONVEX_DEPLOYMENT",
|
|
30
|
+
"description": "Convex deployment name",
|
|
31
|
+
"required": false,
|
|
32
|
+
"secret": false,
|
|
33
|
+
"file": ".env.local"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "VITE_CONVEX_URL",
|
|
37
|
+
"description": "Convex deployment URL",
|
|
38
|
+
"required": true,
|
|
39
|
+
"secret": false,
|
|
40
|
+
"file": ".env.local"
|
|
41
|
+
}
|
|
26
42
|
]
|
|
27
43
|
}
|
package/dist/frameworks.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ export { writeConfigFileToEnvironment, readConfigFileFromEnvironment, readConfig
|
|
|
17
17
|
export { cleanUpFiles, cleanUpFileArray, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, toCleanPath, } from './file-helpers.js';
|
|
18
18
|
export { formatCommand, handleSpecialURL } from './utils.js';
|
|
19
19
|
export { initStarter, compileStarter } from './custom-add-ons/starter.js';
|
|
20
|
-
export { initAddOn, compileAddOn } from './custom-add-ons/add-on.js';
|
|
20
|
+
export { initAddOn, compileAddOn, devAddOn } from './custom-add-ons/add-on.js';
|
|
21
21
|
export { createAppOptionsFromPersisted, createSerializedOptionsFromPersisted, } from './custom-add-ons/shared.js';
|
|
22
22
|
export { createSerializedOptions } from './options.js';
|
|
23
23
|
export { getRawRegistry, getRegistry, getRegistryAddOns, getRegistryStarters, } from './registry.js';
|
|
@@ -61,6 +61,14 @@ export declare function generateProject(persistedOptions: PersistedOptions): Pro
|
|
|
61
61
|
addOnSpecialSteps?: string[] | undefined;
|
|
62
62
|
createSpecialSteps?: string[] | undefined;
|
|
63
63
|
postInitSpecialSteps?: string[] | undefined;
|
|
64
|
+
envVars?: {
|
|
65
|
+
name: string;
|
|
66
|
+
file?: ".env" | ".env.local" | undefined;
|
|
67
|
+
description?: string | undefined;
|
|
68
|
+
default?: string | undefined;
|
|
69
|
+
required?: boolean | undefined;
|
|
70
|
+
secret?: boolean | undefined;
|
|
71
|
+
}[] | undefined;
|
|
64
72
|
integrations?: {
|
|
65
73
|
type?: string | undefined;
|
|
66
74
|
code?: string | undefined;
|
|
@@ -79,4 +87,5 @@ export declare function buildAssetsDirectory(output: {
|
|
|
79
87
|
export declare function updateAddOnInfo(environment: Environment): Promise<void>;
|
|
80
88
|
export declare function compileAddOn(environment: Environment): Promise<void>;
|
|
81
89
|
export declare function initAddOn(environment: Environment): Promise<void>;
|
|
90
|
+
export declare function devAddOn(environment: Environment): Promise<void>;
|
|
82
91
|
export declare function loadRemoteAddOn(url: string): Promise<AddOn>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { writeConfigFileToEnvironment, readConfigFileFromEnvironment, readConfig
|
|
|
12
12
|
export { cleanUpFiles, cleanUpFileArray, readFileHelper, getBinaryFile, recursivelyGatherFiles, relativePath, toCleanPath, } from './file-helpers.js';
|
|
13
13
|
export { formatCommand, handleSpecialURL } from './utils.js';
|
|
14
14
|
export { initStarter, compileStarter } from './custom-add-ons/starter.js';
|
|
15
|
-
export { initAddOn, compileAddOn } from './custom-add-ons/add-on.js';
|
|
15
|
+
export { initAddOn, compileAddOn, devAddOn } from './custom-add-ons/add-on.js';
|
|
16
16
|
export { createAppOptionsFromPersisted, createSerializedOptionsFromPersisted, } from './custom-add-ons/shared.js';
|
|
17
17
|
export { createSerializedOptions } from './options.js';
|
|
18
18
|
export { getRawRegistry, getRegistry, getRegistryAddOns, getRegistryStarters, } from './registry.js';
|
package/dist/types/types.d.ts
CHANGED
|
@@ -198,6 +198,28 @@ export declare const AddOnBaseSchema: z.ZodObject<{
|
|
|
198
198
|
default: string;
|
|
199
199
|
description?: string | undefined;
|
|
200
200
|
}>]>>>;
|
|
201
|
+
envVars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
202
|
+
name: z.ZodString;
|
|
203
|
+
description: z.ZodOptional<z.ZodString>;
|
|
204
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
205
|
+
default: z.ZodOptional<z.ZodString>;
|
|
206
|
+
secret: z.ZodOptional<z.ZodBoolean>;
|
|
207
|
+
file: z.ZodOptional<z.ZodEnum<[".env", ".env.local"]>>;
|
|
208
|
+
}, "strip", z.ZodTypeAny, {
|
|
209
|
+
name: string;
|
|
210
|
+
file?: ".env" | ".env.local" | undefined;
|
|
211
|
+
description?: string | undefined;
|
|
212
|
+
default?: string | undefined;
|
|
213
|
+
required?: boolean | undefined;
|
|
214
|
+
secret?: boolean | undefined;
|
|
215
|
+
}, {
|
|
216
|
+
name: string;
|
|
217
|
+
file?: ".env" | ".env.local" | undefined;
|
|
218
|
+
description?: string | undefined;
|
|
219
|
+
default?: string | undefined;
|
|
220
|
+
required?: boolean | undefined;
|
|
221
|
+
secret?: boolean | undefined;
|
|
222
|
+
}>, "many">>;
|
|
201
223
|
default: z.ZodOptional<z.ZodBoolean>;
|
|
202
224
|
}, "strip", z.ZodTypeAny, {
|
|
203
225
|
type: "add-on" | "example" | "starter" | "toolchain" | "deployment";
|
|
@@ -247,6 +269,14 @@ export declare const AddOnBaseSchema: z.ZodObject<{
|
|
|
247
269
|
addOnSpecialSteps?: string[] | undefined;
|
|
248
270
|
createSpecialSteps?: string[] | undefined;
|
|
249
271
|
postInitSpecialSteps?: string[] | undefined;
|
|
272
|
+
envVars?: {
|
|
273
|
+
name: string;
|
|
274
|
+
file?: ".env" | ".env.local" | undefined;
|
|
275
|
+
description?: string | undefined;
|
|
276
|
+
default?: string | undefined;
|
|
277
|
+
required?: boolean | undefined;
|
|
278
|
+
secret?: boolean | undefined;
|
|
279
|
+
}[] | undefined;
|
|
250
280
|
}, {
|
|
251
281
|
type: "add-on" | "example" | "starter" | "toolchain" | "deployment";
|
|
252
282
|
description: string;
|
|
@@ -295,6 +325,14 @@ export declare const AddOnBaseSchema: z.ZodObject<{
|
|
|
295
325
|
addOnSpecialSteps?: string[] | undefined;
|
|
296
326
|
createSpecialSteps?: string[] | undefined;
|
|
297
327
|
postInitSpecialSteps?: string[] | undefined;
|
|
328
|
+
envVars?: {
|
|
329
|
+
name: string;
|
|
330
|
+
file?: ".env" | ".env.local" | undefined;
|
|
331
|
+
description?: string | undefined;
|
|
332
|
+
default?: string | undefined;
|
|
333
|
+
required?: boolean | undefined;
|
|
334
|
+
secret?: boolean | undefined;
|
|
335
|
+
}[] | undefined;
|
|
298
336
|
}>;
|
|
299
337
|
export declare const StarterSchema: z.ZodObject<{
|
|
300
338
|
id: z.ZodString;
|
|
@@ -391,6 +429,28 @@ export declare const StarterSchema: z.ZodObject<{
|
|
|
391
429
|
default: string;
|
|
392
430
|
description?: string | undefined;
|
|
393
431
|
}>]>>>;
|
|
432
|
+
envVars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
433
|
+
name: z.ZodString;
|
|
434
|
+
description: z.ZodOptional<z.ZodString>;
|
|
435
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
436
|
+
default: z.ZodOptional<z.ZodString>;
|
|
437
|
+
secret: z.ZodOptional<z.ZodBoolean>;
|
|
438
|
+
file: z.ZodOptional<z.ZodEnum<[".env", ".env.local"]>>;
|
|
439
|
+
}, "strip", z.ZodTypeAny, {
|
|
440
|
+
name: string;
|
|
441
|
+
file?: ".env" | ".env.local" | undefined;
|
|
442
|
+
description?: string | undefined;
|
|
443
|
+
default?: string | undefined;
|
|
444
|
+
required?: boolean | undefined;
|
|
445
|
+
secret?: boolean | undefined;
|
|
446
|
+
}, {
|
|
447
|
+
name: string;
|
|
448
|
+
file?: ".env" | ".env.local" | undefined;
|
|
449
|
+
description?: string | undefined;
|
|
450
|
+
default?: string | undefined;
|
|
451
|
+
required?: boolean | undefined;
|
|
452
|
+
secret?: boolean | undefined;
|
|
453
|
+
}>, "many">>;
|
|
394
454
|
default: z.ZodOptional<z.ZodBoolean>;
|
|
395
455
|
} & {
|
|
396
456
|
framework: z.ZodString;
|
|
@@ -448,6 +508,14 @@ export declare const StarterSchema: z.ZodObject<{
|
|
|
448
508
|
addOnSpecialSteps?: string[] | undefined;
|
|
449
509
|
createSpecialSteps?: string[] | undefined;
|
|
450
510
|
postInitSpecialSteps?: string[] | undefined;
|
|
511
|
+
envVars?: {
|
|
512
|
+
name: string;
|
|
513
|
+
file?: ".env" | ".env.local" | undefined;
|
|
514
|
+
description?: string | undefined;
|
|
515
|
+
default?: string | undefined;
|
|
516
|
+
required?: boolean | undefined;
|
|
517
|
+
secret?: boolean | undefined;
|
|
518
|
+
}[] | undefined;
|
|
451
519
|
banner?: string | undefined;
|
|
452
520
|
}, {
|
|
453
521
|
type: "add-on" | "example" | "starter" | "toolchain" | "deployment";
|
|
@@ -500,6 +568,14 @@ export declare const StarterSchema: z.ZodObject<{
|
|
|
500
568
|
addOnSpecialSteps?: string[] | undefined;
|
|
501
569
|
createSpecialSteps?: string[] | undefined;
|
|
502
570
|
postInitSpecialSteps?: string[] | undefined;
|
|
571
|
+
envVars?: {
|
|
572
|
+
name: string;
|
|
573
|
+
file?: ".env" | ".env.local" | undefined;
|
|
574
|
+
description?: string | undefined;
|
|
575
|
+
default?: string | undefined;
|
|
576
|
+
required?: boolean | undefined;
|
|
577
|
+
secret?: boolean | undefined;
|
|
578
|
+
}[] | undefined;
|
|
503
579
|
banner?: string | undefined;
|
|
504
580
|
}>;
|
|
505
581
|
export declare const StarterCompiledSchema: z.ZodObject<{
|
|
@@ -597,6 +673,28 @@ export declare const StarterCompiledSchema: z.ZodObject<{
|
|
|
597
673
|
default: string;
|
|
598
674
|
description?: string | undefined;
|
|
599
675
|
}>]>>>;
|
|
676
|
+
envVars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
677
|
+
name: z.ZodString;
|
|
678
|
+
description: z.ZodOptional<z.ZodString>;
|
|
679
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
680
|
+
default: z.ZodOptional<z.ZodString>;
|
|
681
|
+
secret: z.ZodOptional<z.ZodBoolean>;
|
|
682
|
+
file: z.ZodOptional<z.ZodEnum<[".env", ".env.local"]>>;
|
|
683
|
+
}, "strip", z.ZodTypeAny, {
|
|
684
|
+
name: string;
|
|
685
|
+
file?: ".env" | ".env.local" | undefined;
|
|
686
|
+
description?: string | undefined;
|
|
687
|
+
default?: string | undefined;
|
|
688
|
+
required?: boolean | undefined;
|
|
689
|
+
secret?: boolean | undefined;
|
|
690
|
+
}, {
|
|
691
|
+
name: string;
|
|
692
|
+
file?: ".env" | ".env.local" | undefined;
|
|
693
|
+
description?: string | undefined;
|
|
694
|
+
default?: string | undefined;
|
|
695
|
+
required?: boolean | undefined;
|
|
696
|
+
secret?: boolean | undefined;
|
|
697
|
+
}>, "many">>;
|
|
600
698
|
default: z.ZodOptional<z.ZodBoolean>;
|
|
601
699
|
} & {
|
|
602
700
|
framework: z.ZodString;
|
|
@@ -659,6 +757,14 @@ export declare const StarterCompiledSchema: z.ZodObject<{
|
|
|
659
757
|
addOnSpecialSteps?: string[] | undefined;
|
|
660
758
|
createSpecialSteps?: string[] | undefined;
|
|
661
759
|
postInitSpecialSteps?: string[] | undefined;
|
|
760
|
+
envVars?: {
|
|
761
|
+
name: string;
|
|
762
|
+
file?: ".env" | ".env.local" | undefined;
|
|
763
|
+
description?: string | undefined;
|
|
764
|
+
default?: string | undefined;
|
|
765
|
+
required?: boolean | undefined;
|
|
766
|
+
secret?: boolean | undefined;
|
|
767
|
+
}[] | undefined;
|
|
662
768
|
banner?: string | undefined;
|
|
663
769
|
}, {
|
|
664
770
|
type: "add-on" | "example" | "starter" | "toolchain" | "deployment";
|
|
@@ -713,6 +819,14 @@ export declare const StarterCompiledSchema: z.ZodObject<{
|
|
|
713
819
|
addOnSpecialSteps?: string[] | undefined;
|
|
714
820
|
createSpecialSteps?: string[] | undefined;
|
|
715
821
|
postInitSpecialSteps?: string[] | undefined;
|
|
822
|
+
envVars?: {
|
|
823
|
+
name: string;
|
|
824
|
+
file?: ".env" | ".env.local" | undefined;
|
|
825
|
+
description?: string | undefined;
|
|
826
|
+
default?: string | undefined;
|
|
827
|
+
required?: boolean | undefined;
|
|
828
|
+
secret?: boolean | undefined;
|
|
829
|
+
}[] | undefined;
|
|
716
830
|
banner?: string | undefined;
|
|
717
831
|
}>;
|
|
718
832
|
export declare const IntegrationSchema: z.ZodObject<{
|
|
@@ -829,6 +943,28 @@ export declare const AddOnInfoSchema: z.ZodObject<{
|
|
|
829
943
|
default: string;
|
|
830
944
|
description?: string | undefined;
|
|
831
945
|
}>]>>>;
|
|
946
|
+
envVars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
947
|
+
name: z.ZodString;
|
|
948
|
+
description: z.ZodOptional<z.ZodString>;
|
|
949
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
950
|
+
default: z.ZodOptional<z.ZodString>;
|
|
951
|
+
secret: z.ZodOptional<z.ZodBoolean>;
|
|
952
|
+
file: z.ZodOptional<z.ZodEnum<[".env", ".env.local"]>>;
|
|
953
|
+
}, "strip", z.ZodTypeAny, {
|
|
954
|
+
name: string;
|
|
955
|
+
file?: ".env" | ".env.local" | undefined;
|
|
956
|
+
description?: string | undefined;
|
|
957
|
+
default?: string | undefined;
|
|
958
|
+
required?: boolean | undefined;
|
|
959
|
+
secret?: boolean | undefined;
|
|
960
|
+
}, {
|
|
961
|
+
name: string;
|
|
962
|
+
file?: ".env" | ".env.local" | undefined;
|
|
963
|
+
description?: string | undefined;
|
|
964
|
+
default?: string | undefined;
|
|
965
|
+
required?: boolean | undefined;
|
|
966
|
+
secret?: boolean | undefined;
|
|
967
|
+
}>, "many">>;
|
|
832
968
|
default: z.ZodOptional<z.ZodBoolean>;
|
|
833
969
|
} & {
|
|
834
970
|
modes: z.ZodArray<z.ZodString, "many">;
|
|
@@ -904,6 +1040,14 @@ export declare const AddOnInfoSchema: z.ZodObject<{
|
|
|
904
1040
|
addOnSpecialSteps?: string[] | undefined;
|
|
905
1041
|
createSpecialSteps?: string[] | undefined;
|
|
906
1042
|
postInitSpecialSteps?: string[] | undefined;
|
|
1043
|
+
envVars?: {
|
|
1044
|
+
name: string;
|
|
1045
|
+
file?: ".env" | ".env.local" | undefined;
|
|
1046
|
+
description?: string | undefined;
|
|
1047
|
+
default?: string | undefined;
|
|
1048
|
+
required?: boolean | undefined;
|
|
1049
|
+
secret?: boolean | undefined;
|
|
1050
|
+
}[] | undefined;
|
|
907
1051
|
integrations?: {
|
|
908
1052
|
type?: string | undefined;
|
|
909
1053
|
code?: string | undefined;
|
|
@@ -963,6 +1107,14 @@ export declare const AddOnInfoSchema: z.ZodObject<{
|
|
|
963
1107
|
addOnSpecialSteps?: string[] | undefined;
|
|
964
1108
|
createSpecialSteps?: string[] | undefined;
|
|
965
1109
|
postInitSpecialSteps?: string[] | undefined;
|
|
1110
|
+
envVars?: {
|
|
1111
|
+
name: string;
|
|
1112
|
+
file?: ".env" | ".env.local" | undefined;
|
|
1113
|
+
description?: string | undefined;
|
|
1114
|
+
default?: string | undefined;
|
|
1115
|
+
required?: boolean | undefined;
|
|
1116
|
+
secret?: boolean | undefined;
|
|
1117
|
+
}[] | undefined;
|
|
966
1118
|
integrations?: {
|
|
967
1119
|
type?: string | undefined;
|
|
968
1120
|
code?: string | undefined;
|
|
@@ -1068,6 +1220,28 @@ export declare const AddOnCompiledSchema: z.ZodObject<{
|
|
|
1068
1220
|
default: string;
|
|
1069
1221
|
description?: string | undefined;
|
|
1070
1222
|
}>]>>>;
|
|
1223
|
+
envVars: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1224
|
+
name: z.ZodString;
|
|
1225
|
+
description: z.ZodOptional<z.ZodString>;
|
|
1226
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
1227
|
+
default: z.ZodOptional<z.ZodString>;
|
|
1228
|
+
secret: z.ZodOptional<z.ZodBoolean>;
|
|
1229
|
+
file: z.ZodOptional<z.ZodEnum<[".env", ".env.local"]>>;
|
|
1230
|
+
}, "strip", z.ZodTypeAny, {
|
|
1231
|
+
name: string;
|
|
1232
|
+
file?: ".env" | ".env.local" | undefined;
|
|
1233
|
+
description?: string | undefined;
|
|
1234
|
+
default?: string | undefined;
|
|
1235
|
+
required?: boolean | undefined;
|
|
1236
|
+
secret?: boolean | undefined;
|
|
1237
|
+
}, {
|
|
1238
|
+
name: string;
|
|
1239
|
+
file?: ".env" | ".env.local" | undefined;
|
|
1240
|
+
description?: string | undefined;
|
|
1241
|
+
default?: string | undefined;
|
|
1242
|
+
required?: boolean | undefined;
|
|
1243
|
+
secret?: boolean | undefined;
|
|
1244
|
+
}>, "many">>;
|
|
1071
1245
|
default: z.ZodOptional<z.ZodBoolean>;
|
|
1072
1246
|
} & {
|
|
1073
1247
|
modes: z.ZodArray<z.ZodString, "many">;
|
|
@@ -1149,6 +1323,14 @@ export declare const AddOnCompiledSchema: z.ZodObject<{
|
|
|
1149
1323
|
addOnSpecialSteps?: string[] | undefined;
|
|
1150
1324
|
createSpecialSteps?: string[] | undefined;
|
|
1151
1325
|
postInitSpecialSteps?: string[] | undefined;
|
|
1326
|
+
envVars?: {
|
|
1327
|
+
name: string;
|
|
1328
|
+
file?: ".env" | ".env.local" | undefined;
|
|
1329
|
+
description?: string | undefined;
|
|
1330
|
+
default?: string | undefined;
|
|
1331
|
+
required?: boolean | undefined;
|
|
1332
|
+
secret?: boolean | undefined;
|
|
1333
|
+
}[] | undefined;
|
|
1152
1334
|
integrations?: {
|
|
1153
1335
|
type?: string | undefined;
|
|
1154
1336
|
code?: string | undefined;
|
|
@@ -1211,6 +1393,14 @@ export declare const AddOnCompiledSchema: z.ZodObject<{
|
|
|
1211
1393
|
addOnSpecialSteps?: string[] | undefined;
|
|
1212
1394
|
createSpecialSteps?: string[] | undefined;
|
|
1213
1395
|
postInitSpecialSteps?: string[] | undefined;
|
|
1396
|
+
envVars?: {
|
|
1397
|
+
name: string;
|
|
1398
|
+
file?: ".env" | ".env.local" | undefined;
|
|
1399
|
+
description?: string | undefined;
|
|
1400
|
+
default?: string | undefined;
|
|
1401
|
+
required?: boolean | undefined;
|
|
1402
|
+
secret?: boolean | undefined;
|
|
1403
|
+
}[] | undefined;
|
|
1214
1404
|
integrations?: {
|
|
1215
1405
|
type?: string | undefined;
|
|
1216
1406
|
code?: string | undefined;
|
|
@@ -1275,6 +1465,8 @@ export interface Options {
|
|
|
1275
1465
|
addOnOptions: Record<string, Record<string, any>>;
|
|
1276
1466
|
starter?: Starter | undefined;
|
|
1277
1467
|
routerOnly?: boolean;
|
|
1468
|
+
includeExamples?: boolean;
|
|
1469
|
+
envVarValues?: Record<string, string>;
|
|
1278
1470
|
}
|
|
1279
1471
|
export type SerializedOptions = Omit<Options, 'chosenAddOns' | 'starter' | 'framework'> & {
|
|
1280
1472
|
chosenAddOns: Array<string>;
|
package/dist/types.js
CHANGED
|
@@ -75,6 +75,16 @@ export const AddOnBaseSchema = z.object({
|
|
|
75
75
|
createSpecialSteps: z.array(z.string()).optional(),
|
|
76
76
|
postInitSpecialSteps: z.array(z.string()).optional(),
|
|
77
77
|
options: AddOnOptionsSchema.optional(),
|
|
78
|
+
envVars: z
|
|
79
|
+
.array(z.object({
|
|
80
|
+
name: z.string(),
|
|
81
|
+
description: z.string().optional(),
|
|
82
|
+
required: z.boolean().optional(),
|
|
83
|
+
default: z.string().optional(),
|
|
84
|
+
secret: z.boolean().optional(),
|
|
85
|
+
file: z.enum(['.env', '.env.local']).optional(),
|
|
86
|
+
}))
|
|
87
|
+
.optional(),
|
|
78
88
|
default: z.boolean().optional(),
|
|
79
89
|
});
|
|
80
90
|
export const StarterSchema = AddOnBaseSchema.extend({
|
package/package.json
CHANGED
package/src/create-app.ts
CHANGED
|
@@ -16,6 +16,51 @@ import { runSpecialSteps } from './special-steps/index.js'
|
|
|
16
16
|
|
|
17
17
|
import type { Environment, FileBundleHandler, Options } from './types.js'
|
|
18
18
|
|
|
19
|
+
function isDemoRoutePath(path?: string) {
|
|
20
|
+
if (!path) return false
|
|
21
|
+
const normalized = path.replace(/\\/g, '/')
|
|
22
|
+
return (
|
|
23
|
+
normalized.includes('/routes/demo/') ||
|
|
24
|
+
normalized.includes('/routes/demo.') ||
|
|
25
|
+
normalized.includes('/routes/example/') ||
|
|
26
|
+
normalized.includes('/routes/example.')
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function stripExamplesFromOptions(options: Options): Options {
|
|
31
|
+
if (options.includeExamples !== false) {
|
|
32
|
+
return options
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const chosenAddOns = options.chosenAddOns
|
|
36
|
+
.filter((addOn) => addOn.type !== 'example')
|
|
37
|
+
.map((addOn) => {
|
|
38
|
+
const filteredRoutes = (addOn.routes || []).filter(
|
|
39
|
+
(route) =>
|
|
40
|
+
!isDemoRoutePath(route.path) &&
|
|
41
|
+
!(route.url && route.url.startsWith('/demo')),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
...addOn,
|
|
46
|
+
routes: filteredRoutes,
|
|
47
|
+
getFiles: async () => {
|
|
48
|
+
const files = await addOn.getFiles()
|
|
49
|
+
return files.filter((file) => !isDemoRoutePath(file))
|
|
50
|
+
},
|
|
51
|
+
getDeletedFiles: async () => {
|
|
52
|
+
const deletedFiles = await addOn.getDeletedFiles()
|
|
53
|
+
return deletedFiles.filter((file) => !isDemoRoutePath(file))
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
...options,
|
|
60
|
+
chosenAddOns,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
19
64
|
async function writeFiles(environment: Environment, options: Options) {
|
|
20
65
|
const templateFileFromContent = createTemplateFile(environment, options)
|
|
21
66
|
|
|
@@ -235,6 +280,32 @@ async function runCommandsAndInstallDependencies(
|
|
|
235
280
|
await installShadcnComponents(environment, options.targetDir, options)
|
|
236
281
|
}
|
|
237
282
|
|
|
283
|
+
async function seedEnvValues(environment: Environment, options: Options) {
|
|
284
|
+
const envVarValues = options.envVarValues || {}
|
|
285
|
+
const entries = Object.entries(envVarValues)
|
|
286
|
+
if (entries.length === 0) return
|
|
287
|
+
|
|
288
|
+
const envLocalPath = resolve(options.targetDir, '.env.local')
|
|
289
|
+
if (!environment.exists(envLocalPath)) {
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
let envContents = await environment.readFile(envLocalPath)
|
|
294
|
+
for (const [key, value] of entries) {
|
|
295
|
+
const escapedValue = value.replace(/\n/g, '\\n')
|
|
296
|
+
const nextLine = `${key}=${escapedValue}`
|
|
297
|
+
const pattern = new RegExp(`^${key}=.*$`, 'm')
|
|
298
|
+
|
|
299
|
+
if (pattern.test(envContents)) {
|
|
300
|
+
envContents = envContents.replace(pattern, nextLine)
|
|
301
|
+
} else {
|
|
302
|
+
envContents += `${envContents.endsWith('\n') ? '' : '\n'}${nextLine}\n`
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
await environment.writeFile(envLocalPath, envContents)
|
|
307
|
+
}
|
|
308
|
+
|
|
238
309
|
function report(environment: Environment, options: Options) {
|
|
239
310
|
const warnings: Array<string> = []
|
|
240
311
|
for (const addOn of options.chosenAddOns) {
|
|
@@ -282,10 +353,13 @@ Please read the README.md file for information on testing, styling, adding route
|
|
|
282
353
|
}
|
|
283
354
|
|
|
284
355
|
export async function createApp(environment: Environment, options: Options) {
|
|
356
|
+
const effectiveOptions = stripExamplesFromOptions(options)
|
|
357
|
+
|
|
285
358
|
environment.startRun()
|
|
286
|
-
await writeFiles(environment,
|
|
287
|
-
await
|
|
359
|
+
await writeFiles(environment, effectiveOptions)
|
|
360
|
+
await seedEnvValues(environment, effectiveOptions)
|
|
361
|
+
await runCommandsAndInstallDependencies(environment, effectiveOptions)
|
|
288
362
|
environment.finishRun()
|
|
289
363
|
|
|
290
|
-
report(environment,
|
|
364
|
+
report(environment, effectiveOptions)
|
|
291
365
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises'
|
|
1
|
+
import { readFile, watch } from 'node:fs/promises'
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
3
3
|
import { basename, dirname, resolve } from 'node:path'
|
|
4
4
|
|
|
@@ -36,6 +36,22 @@ const COMPILED_FILE = 'add-on.json'
|
|
|
36
36
|
|
|
37
37
|
const ASSETS_DIR = 'assets'
|
|
38
38
|
|
|
39
|
+
const ADD_ON_DEV_IGNORE_PREFIXES = [
|
|
40
|
+
'.add-on/',
|
|
41
|
+
'.git/',
|
|
42
|
+
'node_modules/',
|
|
43
|
+
'.turbo/',
|
|
44
|
+
'dist/',
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
function shouldIgnoreDevPath(path: string) {
|
|
48
|
+
const normalized = path.replace(/\\/g, '/')
|
|
49
|
+
if (normalized === COMPILED_FILE) return true
|
|
50
|
+
return ADD_ON_DEV_IGNORE_PREFIXES.some((prefix) =>
|
|
51
|
+
normalized.startsWith(prefix),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
39
55
|
export function camelCase(str: string) {
|
|
40
56
|
return str
|
|
41
57
|
.split(/(\.|-|\/)/)
|
|
@@ -122,6 +138,11 @@ export async function readOrGenerateAddOnInfo(
|
|
|
122
138
|
},
|
|
123
139
|
dependsOn: options.chosenAddOns,
|
|
124
140
|
} as AddOnInfo)
|
|
141
|
+
|
|
142
|
+
if (!info.version) {
|
|
143
|
+
info.version = '0.0.1'
|
|
144
|
+
}
|
|
145
|
+
|
|
125
146
|
return info
|
|
126
147
|
}
|
|
127
148
|
|
|
@@ -213,6 +234,56 @@ export async function initAddOn(environment: Environment) {
|
|
|
213
234
|
await compileAddOn(environment)
|
|
214
235
|
}
|
|
215
236
|
|
|
237
|
+
export async function devAddOn(environment: Environment) {
|
|
238
|
+
await initAddOn(environment)
|
|
239
|
+
|
|
240
|
+
environment.info(
|
|
241
|
+
'Add-on dev mode is running.',
|
|
242
|
+
'Watching project files and recompiling add-on output on changes. Press Ctrl+C to stop.',
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
const abortController = new AbortController()
|
|
246
|
+
let debounceTimeout: ReturnType<typeof setTimeout> | undefined
|
|
247
|
+
|
|
248
|
+
const rerun = async () => {
|
|
249
|
+
try {
|
|
250
|
+
await updateAddOnInfo(environment)
|
|
251
|
+
await compileAddOn(environment)
|
|
252
|
+
environment.info('Add-on updated.', 'Compiled add-on.json and refreshed .add-on')
|
|
253
|
+
} catch (error) {
|
|
254
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
255
|
+
environment.error('Failed to rebuild add-on.', message)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
process.once('SIGINT', () => {
|
|
260
|
+
abortController.abort()
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
for await (const event of watch(process.cwd(), {
|
|
265
|
+
recursive: true,
|
|
266
|
+
signal: abortController.signal,
|
|
267
|
+
})) {
|
|
268
|
+
const file = event.filename?.toString()
|
|
269
|
+
if (!file || shouldIgnoreDevPath(file)) continue
|
|
270
|
+
|
|
271
|
+
if (debounceTimeout) {
|
|
272
|
+
clearTimeout(debounceTimeout)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
debounceTimeout = setTimeout(() => {
|
|
276
|
+
void rerun()
|
|
277
|
+
}, 200)
|
|
278
|
+
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
281
|
+
if (!message.includes('aborted')) {
|
|
282
|
+
throw error
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
216
287
|
export async function loadRemoteAddOn(url: string): Promise<AddOn> {
|
|
217
288
|
const response = await fetch(url)
|
|
218
289
|
const jsonContent = await response.json()
|
|
@@ -27,7 +27,7 @@ const COMPILED_FILE = 'starter.json'
|
|
|
27
27
|
export async function readOrGenerateStarterInfo(
|
|
28
28
|
options: PersistedOptions,
|
|
29
29
|
): Promise<StarterInfo> {
|
|
30
|
-
|
|
30
|
+
const info = existsSync(INFO_FILE)
|
|
31
31
|
? JSON.parse((await readFile(INFO_FILE)).toString())
|
|
32
32
|
: {
|
|
33
33
|
id: `${options.projectName}-starter`,
|
|
@@ -51,6 +51,12 @@ export async function readOrGenerateStarterInfo(
|
|
|
51
51
|
dependsOn: options.chosenAddOns,
|
|
52
52
|
typescript: true,
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
if (!info.version) {
|
|
56
|
+
info.version = '0.0.1'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return info
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
async function loadCurrentStarterInfo(environment: Environment) {
|
|
@@ -28,5 +28,14 @@
|
|
|
28
28
|
"jsName": "ClerkProvider",
|
|
29
29
|
"path": "src/integrations/clerk/provider.tsx"
|
|
30
30
|
}
|
|
31
|
+
],
|
|
32
|
+
"envVars": [
|
|
33
|
+
{
|
|
34
|
+
"name": "VITE_CLERK_PUBLISHABLE_KEY",
|
|
35
|
+
"description": "Clerk publishable key",
|
|
36
|
+
"required": true,
|
|
37
|
+
"secret": false,
|
|
38
|
+
"file": ".env.local"
|
|
39
|
+
}
|
|
31
40
|
]
|
|
32
41
|
}
|
|
@@ -23,5 +23,21 @@
|
|
|
23
23
|
"path": "src/integrations/convex/provider.tsx",
|
|
24
24
|
"jsName": "ConvexProvider"
|
|
25
25
|
}
|
|
26
|
+
],
|
|
27
|
+
"envVars": [
|
|
28
|
+
{
|
|
29
|
+
"name": "CONVEX_DEPLOYMENT",
|
|
30
|
+
"description": "Convex deployment name",
|
|
31
|
+
"required": false,
|
|
32
|
+
"secret": false,
|
|
33
|
+
"file": ".env.local"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "VITE_CONVEX_URL",
|
|
37
|
+
"description": "Convex deployment URL",
|
|
38
|
+
"required": true,
|
|
39
|
+
"secret": false,
|
|
40
|
+
"file": ".env.local"
|
|
41
|
+
}
|
|
26
42
|
]
|
|
27
43
|
}
|
package/src/frameworks.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -61,7 +61,7 @@ export {
|
|
|
61
61
|
export { formatCommand, handleSpecialURL } from './utils.js'
|
|
62
62
|
|
|
63
63
|
export { initStarter, compileStarter } from './custom-add-ons/starter.js'
|
|
64
|
-
export { initAddOn, compileAddOn } from './custom-add-ons/add-on.js'
|
|
64
|
+
export { initAddOn, compileAddOn, devAddOn } from './custom-add-ons/add-on.js'
|
|
65
65
|
export {
|
|
66
66
|
createAppOptionsFromPersisted,
|
|
67
67
|
createSerializedOptionsFromPersisted,
|
package/src/types.ts
CHANGED
|
@@ -92,6 +92,18 @@ export const AddOnBaseSchema = z.object({
|
|
|
92
92
|
createSpecialSteps: z.array(z.string()).optional(),
|
|
93
93
|
postInitSpecialSteps: z.array(z.string()).optional(),
|
|
94
94
|
options: AddOnOptionsSchema.optional(),
|
|
95
|
+
envVars: z
|
|
96
|
+
.array(
|
|
97
|
+
z.object({
|
|
98
|
+
name: z.string(),
|
|
99
|
+
description: z.string().optional(),
|
|
100
|
+
required: z.boolean().optional(),
|
|
101
|
+
default: z.string().optional(),
|
|
102
|
+
secret: z.boolean().optional(),
|
|
103
|
+
file: z.enum(['.env', '.env.local']).optional(),
|
|
104
|
+
}),
|
|
105
|
+
)
|
|
106
|
+
.optional(),
|
|
95
107
|
default: z.boolean().optional(),
|
|
96
108
|
})
|
|
97
109
|
|
|
@@ -207,6 +219,8 @@ export interface Options {
|
|
|
207
219
|
addOnOptions: Record<string, Record<string, any>>
|
|
208
220
|
starter?: Starter | undefined
|
|
209
221
|
routerOnly?: boolean
|
|
222
|
+
includeExamples?: boolean
|
|
223
|
+
envVarValues?: Record<string, string>
|
|
210
224
|
}
|
|
211
225
|
|
|
212
226
|
export type SerializedOptions = Omit<
|
|
@@ -55,4 +55,33 @@ describe('readOrGenerateStarterInfo', () => {
|
|
|
55
55
|
})
|
|
56
56
|
expect(starterInfo.name).toEqual('test-starter')
|
|
57
57
|
})
|
|
58
|
+
|
|
59
|
+
it('should backfill version when missing', async () => {
|
|
60
|
+
fs.mkdirSync(process.cwd(), { recursive: true })
|
|
61
|
+
fs.writeFileSync(
|
|
62
|
+
'starter-info.json',
|
|
63
|
+
JSON.stringify({
|
|
64
|
+
framework: 'test',
|
|
65
|
+
chosenAddOns: [],
|
|
66
|
+
starter: undefined,
|
|
67
|
+
name: 'test-starter',
|
|
68
|
+
mode: 'code-router',
|
|
69
|
+
typescript: true,
|
|
70
|
+
tailwind: true,
|
|
71
|
+
git: true,
|
|
72
|
+
}),
|
|
73
|
+
)
|
|
74
|
+
const starterInfo = await readOrGenerateStarterInfo({
|
|
75
|
+
framework: 'test',
|
|
76
|
+
version: 1,
|
|
77
|
+
chosenAddOns: [],
|
|
78
|
+
starter: undefined,
|
|
79
|
+
projectName: 'test',
|
|
80
|
+
mode: 'code-router',
|
|
81
|
+
typescript: true,
|
|
82
|
+
tailwind: true,
|
|
83
|
+
git: true,
|
|
84
|
+
})
|
|
85
|
+
expect(starterInfo.version).toEqual('0.0.1')
|
|
86
|
+
})
|
|
58
87
|
})
|