everything-dev 1.20.0 → 1.22.0
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/dist/cli/init.cjs +163 -80
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.d.cts +12 -6
- package/dist/cli/init.d.cts.map +1 -1
- package/dist/cli/init.d.mts +12 -6
- package/dist/cli/init.d.mts.map +1 -1
- package/dist/cli/init.mjs +163 -81
- package/dist/cli/init.mjs.map +1 -1
- package/dist/cli/parse.cjs +9 -0
- package/dist/cli/parse.cjs.map +1 -1
- package/dist/cli/parse.mjs +9 -0
- package/dist/cli/parse.mjs.map +1 -1
- package/dist/cli/prompts.cjs +44 -13
- package/dist/cli/prompts.cjs.map +1 -1
- package/dist/cli/prompts.mjs +44 -13
- package/dist/cli/prompts.mjs.map +1 -1
- package/dist/cli/sync.cjs +6 -0
- package/dist/cli/sync.cjs.map +1 -1
- package/dist/cli/sync.mjs +6 -0
- package/dist/cli/sync.mjs.map +1 -1
- package/dist/cli.cjs +3 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +3 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/contract.cjs +9 -1
- package/dist/contract.cjs.map +1 -1
- package/dist/contract.d.cts +33 -4
- package/dist/contract.d.cts.map +1 -1
- package/dist/contract.d.mts +33 -4
- package/dist/contract.d.mts.map +1 -1
- package/dist/contract.meta.cjs +2 -2
- package/dist/contract.meta.cjs.map +1 -1
- package/dist/contract.meta.d.cts +3 -3
- package/dist/contract.meta.d.mts +3 -3
- package/dist/contract.meta.mjs +2 -2
- package/dist/contract.meta.mjs.map +1 -1
- package/dist/contract.mjs +9 -2
- package/dist/contract.mjs.map +1 -1
- package/dist/fastkv.cjs +4 -1
- package/dist/fastkv.cjs.map +1 -1
- package/dist/fastkv.mjs +4 -1
- package/dist/fastkv.mjs.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/plugin.cjs +43 -20
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +13 -2
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +13 -2
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +44 -21
- package/dist/plugin.mjs.map +1 -1
- package/package.json +1 -1
- package/src/cli/init.ts +252 -95
- package/src/cli/parse.ts +17 -0
- package/src/cli/prompts.ts +45 -28
- package/src/cli/sync.ts +1 -0
- package/src/cli.ts +8 -1
- package/src/contract.meta.ts +6 -2
- package/src/contract.ts +5 -1
- package/src/fastkv.ts +6 -1
- package/src/plugin.ts +58 -18
package/src/cli/init.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
15
15
|
import { pipeline } from "node:stream/promises";
|
|
16
16
|
import { execa } from "execa";
|
|
17
17
|
import { glob } from "glob";
|
|
18
|
+
import type { OverrideSection } from "../contract";
|
|
18
19
|
import { fetchBosConfigFromFastKv } from "../fastkv";
|
|
19
20
|
import {
|
|
20
21
|
loadManifestNormalizationSpec,
|
|
@@ -27,6 +28,17 @@ import { writeSnapshot } from "./snapshot";
|
|
|
27
28
|
|
|
28
29
|
const require = createRequire(import.meta.url);
|
|
29
30
|
|
|
31
|
+
const FRAMEWORK_PACKAGES = ["every-plugin", "everything-dev"] as const;
|
|
32
|
+
|
|
33
|
+
const _DEFAULT_OVERRIDES: OverrideSection[] = ["ui", "api"];
|
|
34
|
+
|
|
35
|
+
const OVERRIDE_WORKSPACE_MAP: Record<OverrideSection, string[]> = {
|
|
36
|
+
ui: ["ui"],
|
|
37
|
+
api: ["api"],
|
|
38
|
+
host: ["host"],
|
|
39
|
+
plugins: [],
|
|
40
|
+
};
|
|
41
|
+
|
|
30
42
|
interface SourceResult {
|
|
31
43
|
sourceDir: string;
|
|
32
44
|
parentConfig: BosConfig;
|
|
@@ -124,6 +136,32 @@ export async function resolveRepositoryViaExtendsChain(
|
|
|
124
136
|
}
|
|
125
137
|
}
|
|
126
138
|
|
|
139
|
+
export async function detectGitRemoteUrl(directory: string): Promise<string | undefined> {
|
|
140
|
+
try {
|
|
141
|
+
const { stdout } = await execa("git", ["remote", "get-url", "origin"], {
|
|
142
|
+
cwd: directory,
|
|
143
|
+
stdio: "pipe",
|
|
144
|
+
});
|
|
145
|
+
const url = stdout.trim();
|
|
146
|
+
if (!url) return undefined;
|
|
147
|
+
return normalizeGitUrl(url);
|
|
148
|
+
} catch {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function normalizeGitUrl(url: string): string | undefined {
|
|
154
|
+
const sshMatch = url.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
155
|
+
if (sshMatch) {
|
|
156
|
+
return `https://github.com/${sshMatch[1]}/${sshMatch[2]}`;
|
|
157
|
+
}
|
|
158
|
+
const httpsMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/.*)?$/);
|
|
159
|
+
if (httpsMatch) {
|
|
160
|
+
return `https://github.com/${httpsMatch[1]}/${httpsMatch[2]}`;
|
|
161
|
+
}
|
|
162
|
+
return url.endsWith(".git") ? url.slice(0, -4) : url;
|
|
163
|
+
}
|
|
164
|
+
|
|
127
165
|
export async function downloadTarball(
|
|
128
166
|
repoUrl: string,
|
|
129
167
|
): Promise<{ dir: string; cleanup: () => Promise<void> }> {
|
|
@@ -191,19 +229,51 @@ function parseGitHubUrl(url: string): { owner: string; repo: string; branch: str
|
|
|
191
229
|
return null;
|
|
192
230
|
}
|
|
193
231
|
|
|
232
|
+
function filterPatternsByOverrides(
|
|
233
|
+
patterns: string[],
|
|
234
|
+
overrides: OverrideSection[],
|
|
235
|
+
_plugins?: string[],
|
|
236
|
+
): string[] {
|
|
237
|
+
const has = (section: OverrideSection) => overrides.includes(section);
|
|
238
|
+
let filtered = [...patterns];
|
|
239
|
+
|
|
240
|
+
if (!has("host")) {
|
|
241
|
+
filtered = filtered.filter((p) => !p.startsWith("host/") && p !== "host/**");
|
|
242
|
+
}
|
|
243
|
+
if (!has("ui")) {
|
|
244
|
+
filtered = filtered.filter((p) => !p.startsWith("ui/") && p !== "ui/**");
|
|
245
|
+
}
|
|
246
|
+
if (!has("api")) {
|
|
247
|
+
filtered = filtered.filter((p) => !p.startsWith("api/") && p !== "api/**");
|
|
248
|
+
}
|
|
249
|
+
if (!has("plugins")) {
|
|
250
|
+
filtered = filtered.filter((p) => !p.startsWith("plugins/") && p !== "plugins/**");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return filtered;
|
|
254
|
+
}
|
|
255
|
+
|
|
194
256
|
export async function copyFilteredFiles(
|
|
195
257
|
sourceDir: string,
|
|
196
258
|
destination: string,
|
|
197
259
|
patterns: string[],
|
|
198
|
-
options: {
|
|
260
|
+
options: {
|
|
261
|
+
overrides: OverrideSection[];
|
|
262
|
+
plugins?: string[];
|
|
263
|
+
pluginRoutes?: Record<string, string[]>;
|
|
264
|
+
},
|
|
199
265
|
): Promise<number> {
|
|
200
266
|
if (patterns.length === 0) {
|
|
201
267
|
return 0;
|
|
202
268
|
}
|
|
203
269
|
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
270
|
+
const has = (section: OverrideSection) => options.overrides.includes(section);
|
|
271
|
+
|
|
272
|
+
const effectivePatterns = filterPatternsByOverrides(patterns, options.overrides, options.plugins);
|
|
273
|
+
|
|
274
|
+
if (has("host") && !effectivePatterns.some((p) => p.startsWith("host/") || p === "host/**")) {
|
|
275
|
+
effectivePatterns.push("host/**");
|
|
276
|
+
}
|
|
207
277
|
|
|
208
278
|
const excludedRoutePatterns: string[] = [];
|
|
209
279
|
if (options.pluginRoutes) {
|
|
@@ -276,6 +346,13 @@ export async function copyFilteredFiles(
|
|
|
276
346
|
return count;
|
|
277
347
|
}
|
|
278
348
|
|
|
349
|
+
function stripProductionFields(entry: Record<string, unknown>): void {
|
|
350
|
+
delete entry.production;
|
|
351
|
+
delete entry.integrity;
|
|
352
|
+
delete entry.ssr;
|
|
353
|
+
delete entry.ssrIntegrity;
|
|
354
|
+
}
|
|
355
|
+
|
|
279
356
|
export async function personalizeConfig(
|
|
280
357
|
destination: string,
|
|
281
358
|
opts: {
|
|
@@ -284,13 +361,16 @@ export async function personalizeConfig(
|
|
|
284
361
|
account?: string;
|
|
285
362
|
domain?: string;
|
|
286
363
|
plugins?: string[];
|
|
364
|
+
overrides: OverrideSection[];
|
|
287
365
|
pluginRoutes?: Record<string, string[]>;
|
|
288
366
|
workspaceOpts?: { localOverrides?: boolean; sourceDir?: string };
|
|
289
367
|
mode?: "init" | "sync";
|
|
290
|
-
|
|
368
|
+
repository?: string;
|
|
291
369
|
},
|
|
292
370
|
): Promise<void> {
|
|
293
371
|
const isInit = opts.mode !== "sync";
|
|
372
|
+
const has = (section: OverrideSection) => opts.overrides.includes(section);
|
|
373
|
+
|
|
294
374
|
const configPath = join(destination, "bos.config.json");
|
|
295
375
|
if (existsSync(configPath)) {
|
|
296
376
|
const config = JSON.parse(readFileSync(configPath, "utf-8")) as Record<string, unknown>;
|
|
@@ -303,53 +383,62 @@ export async function personalizeConfig(
|
|
|
303
383
|
if (opts.domain) {
|
|
304
384
|
config.domain = opts.domain;
|
|
305
385
|
}
|
|
386
|
+
if (opts.repository) {
|
|
387
|
+
config.repository = opts.repository;
|
|
388
|
+
}
|
|
306
389
|
|
|
307
390
|
if (isInit && config.app && typeof config.app === "object") {
|
|
308
391
|
const app = config.app as Record<string, unknown>;
|
|
309
392
|
|
|
310
393
|
for (const entryKey of Object.keys(app)) {
|
|
394
|
+
if (
|
|
395
|
+
!has(entryKey as OverrideSection) &&
|
|
396
|
+
(entryKey === "host" || entryKey === "ui" || entryKey === "api" || entryKey === "auth")
|
|
397
|
+
) {
|
|
398
|
+
delete app[entryKey];
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
311
401
|
const entry = app[entryKey];
|
|
312
402
|
if (entry && typeof entry === "object") {
|
|
313
|
-
|
|
314
|
-
delete e.production;
|
|
315
|
-
delete e.integrity;
|
|
316
|
-
delete e.ssr;
|
|
317
|
-
delete e.ssrIntegrity;
|
|
403
|
+
stripProductionFields(entry as Record<string, unknown>);
|
|
318
404
|
}
|
|
319
405
|
}
|
|
320
406
|
}
|
|
321
407
|
|
|
322
|
-
if (
|
|
323
|
-
|
|
408
|
+
if (has("plugins")) {
|
|
409
|
+
if (config.plugins && typeof config.plugins === "object") {
|
|
410
|
+
const plugins = config.plugins as Record<string, unknown>;
|
|
324
411
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
412
|
+
if (opts.plugins !== undefined) {
|
|
413
|
+
for (const pluginKey of Object.keys(plugins)) {
|
|
414
|
+
if (!opts.plugins.includes(pluginKey)) {
|
|
415
|
+
delete plugins[pluginKey];
|
|
416
|
+
}
|
|
329
417
|
}
|
|
330
418
|
}
|
|
331
|
-
}
|
|
332
419
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
420
|
+
for (const pluginKey of Object.keys(plugins)) {
|
|
421
|
+
const plugin = plugins[pluginKey];
|
|
422
|
+
let pluginObj: Record<string, unknown>;
|
|
423
|
+
|
|
424
|
+
if (typeof plugin === "string") {
|
|
425
|
+
pluginObj = { extends: plugin };
|
|
426
|
+
plugins[pluginKey] = pluginObj;
|
|
427
|
+
} else if (plugin && typeof plugin === "object") {
|
|
428
|
+
pluginObj = { ...(plugin as Record<string, unknown>) };
|
|
429
|
+
} else {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
336
432
|
|
|
337
|
-
|
|
338
|
-
pluginObj = { extends: plugin };
|
|
339
|
-
plugins[pluginKey] = pluginObj;
|
|
340
|
-
} else if (plugin && typeof plugin === "object") {
|
|
341
|
-
pluginObj = { ...(plugin as Record<string, unknown>) };
|
|
342
|
-
} else {
|
|
343
|
-
continue;
|
|
433
|
+
stripProductionFields(pluginObj);
|
|
344
434
|
}
|
|
345
435
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if (Object.keys(plugins).length === 0) {
|
|
351
|
-
config.plugins = {};
|
|
436
|
+
if (Object.keys(plugins).length === 0) {
|
|
437
|
+
config.plugins = {};
|
|
438
|
+
}
|
|
352
439
|
}
|
|
440
|
+
} else {
|
|
441
|
+
delete config.plugins;
|
|
353
442
|
}
|
|
354
443
|
|
|
355
444
|
await saveBosConfig(destination, config);
|
|
@@ -364,10 +453,11 @@ export async function personalizeConfig(
|
|
|
364
453
|
if (Array.isArray(ws.packages)) {
|
|
365
454
|
ws.packages = ws.packages.filter((p: string) => {
|
|
366
455
|
if (p.startsWith("packages/")) return false;
|
|
367
|
-
if (p === "host") return
|
|
368
|
-
if (p === "plugins/*") return (opts.plugins?.length ?? 0) > 0;
|
|
456
|
+
if (p === "host") return has("host");
|
|
457
|
+
if (p === "plugins/*") return has("plugins") && (opts.plugins?.length ?? 0) > 0;
|
|
369
458
|
const pluginMatch = p.match(/^plugins\/([^/]+)/);
|
|
370
|
-
if (pluginMatch)
|
|
459
|
+
if (pluginMatch)
|
|
460
|
+
return has("plugins") && (opts.plugins?.includes(pluginMatch[1]) ?? true);
|
|
371
461
|
return true;
|
|
372
462
|
});
|
|
373
463
|
}
|
|
@@ -395,7 +485,7 @@ export async function personalizeConfig(
|
|
|
395
485
|
scripts.typecheck = scripts.typecheck
|
|
396
486
|
.replace("bun run types:gen && ", "")
|
|
397
487
|
.replace(/bun run --cwd packages\/everything-dev typecheck & ?/, "");
|
|
398
|
-
if (!
|
|
488
|
+
if (!has("host")) {
|
|
399
489
|
scripts.typecheck = scripts.typecheck.replace(/bun run --cwd host tsc --noEmit & ?/, "");
|
|
400
490
|
}
|
|
401
491
|
}
|
|
@@ -451,27 +541,34 @@ export async function personalizeConfig(
|
|
|
451
541
|
|
|
452
542
|
await resolveWorkspaceRefs(destination, opts.workspaceOpts);
|
|
453
543
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
544
|
+
if (has("ui")) {
|
|
545
|
+
const genContractPath = join(destination, "ui", "src", "lib", "api-types.gen.ts");
|
|
546
|
+
if (!existsSync(genContractPath)) {
|
|
547
|
+
mkdirSync(dirname(genContractPath), { recursive: true });
|
|
548
|
+
writeFileSync(genContractPath, `export type ApiContract = Record<string, never>;\n`);
|
|
549
|
+
}
|
|
458
550
|
}
|
|
459
551
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
552
|
+
if (has("api")) {
|
|
553
|
+
const pluginsClientGenPath = join(destination, "api", "src", "lib", "plugins-types.gen.ts");
|
|
554
|
+
if (!existsSync(pluginsClientGenPath)) {
|
|
555
|
+
mkdirSync(dirname(pluginsClientGenPath), { recursive: true });
|
|
556
|
+
writeFileSync(
|
|
557
|
+
pluginsClientGenPath,
|
|
558
|
+
`import type { ContractRouterClient, AnyContractRouter } from "@orpc/contract";\ntype ClientFactory<C extends AnyContractRouter> = (context?: Record<string, unknown>) => ContractRouterClient<C>;\nexport type PluginsClient = Record<string, never>;\n`,
|
|
559
|
+
);
|
|
560
|
+
}
|
|
467
561
|
}
|
|
468
562
|
|
|
469
563
|
const authTypesContent = generateAuthTypesTemplate();
|
|
470
|
-
const authTypesPaths = [
|
|
471
|
-
|
|
472
|
-
join(destination, "
|
|
473
|
-
|
|
474
|
-
if (
|
|
564
|
+
const authTypesPaths: string[] = [];
|
|
565
|
+
if (has("ui")) {
|
|
566
|
+
authTypesPaths.push(join(destination, "ui", "src", "lib", "auth-types.gen.ts"));
|
|
567
|
+
}
|
|
568
|
+
if (has("api")) {
|
|
569
|
+
authTypesPaths.push(join(destination, "api", "src", "lib", "auth-types.gen.ts"));
|
|
570
|
+
}
|
|
571
|
+
if (has("host") && existsSync(join(destination, "host", "src"))) {
|
|
475
572
|
authTypesPaths.push(join(destination, "host", "src", "lib", "auth-types.gen.ts"));
|
|
476
573
|
}
|
|
477
574
|
for (const authTypesGenPath of authTypesPaths) {
|
|
@@ -534,15 +631,15 @@ export interface AuthServices {
|
|
|
534
631
|
}
|
|
535
632
|
|
|
536
633
|
export async function runBunInstall(destination: string): Promise<void> {
|
|
537
|
-
await execCommand("bun", ["install", "--ignore-scripts"], destination);
|
|
634
|
+
await execCommand("bun", ["install", "--ignore-scripts"], destination, { stdio: "inherit" });
|
|
538
635
|
}
|
|
539
636
|
|
|
540
637
|
export async function runTypesGen(destination: string): Promise<void> {
|
|
541
|
-
await execCommand("node_modules/.bin/bos", ["types", "gen"], destination);
|
|
638
|
+
await execCommand("node_modules/.bin/bos", ["types", "gen"], destination, { stdio: "inherit" });
|
|
542
639
|
}
|
|
543
640
|
|
|
544
641
|
export async function runDockerComposeUp(destination: string): Promise<void> {
|
|
545
|
-
await execCommand("docker", ["compose", "up", "-d", "--wait"], destination);
|
|
642
|
+
await execCommand("docker", ["compose", "up", "-d", "--wait"], destination, { stdio: "inherit" });
|
|
546
643
|
}
|
|
547
644
|
|
|
548
645
|
const WORKSPACE_LOCAL_PATHS: Record<string, string> = {
|
|
@@ -550,6 +647,20 @@ const WORKSPACE_LOCAL_PATHS: Record<string, string> = {
|
|
|
550
647
|
"every-plugin": "packages/every-plugin",
|
|
551
648
|
};
|
|
552
649
|
|
|
650
|
+
function resolveFrameworkCatalog(): Record<string, string> {
|
|
651
|
+
const catalog: Record<string, string> = {};
|
|
652
|
+
for (const packageName of FRAMEWORK_PACKAGES) {
|
|
653
|
+
try {
|
|
654
|
+
const resolved = require.resolve(`${packageName}/package.json`);
|
|
655
|
+
const pkg = JSON.parse(readFileSync(resolved, "utf-8")) as { version?: string };
|
|
656
|
+
if (pkg.version) {
|
|
657
|
+
catalog[packageName] = `^${pkg.version}`;
|
|
658
|
+
}
|
|
659
|
+
} catch {}
|
|
660
|
+
}
|
|
661
|
+
return catalog;
|
|
662
|
+
}
|
|
663
|
+
|
|
553
664
|
export async function scaffoldMinimalProject(
|
|
554
665
|
destination: string,
|
|
555
666
|
parentConfig: BosConfigInput,
|
|
@@ -559,55 +670,51 @@ export async function scaffoldMinimalProject(
|
|
|
559
670
|
account?: string;
|
|
560
671
|
domain?: string;
|
|
561
672
|
plugins?: string[];
|
|
562
|
-
|
|
673
|
+
overrides: OverrideSection[];
|
|
674
|
+
repository?: string;
|
|
563
675
|
},
|
|
564
676
|
): Promise<number> {
|
|
565
677
|
mkdirSync(destination, { recursive: true });
|
|
566
678
|
|
|
679
|
+
const has = (section: OverrideSection) => opts.overrides.includes(section);
|
|
680
|
+
|
|
567
681
|
const config: Record<string, unknown> = {
|
|
568
682
|
extends: `bos://${opts.extendsAccount}/${opts.extendsGateway}`,
|
|
569
683
|
account: opts.account || opts.extendsAccount,
|
|
570
684
|
...(opts.domain ? { domain: opts.domain } : {}),
|
|
685
|
+
...(opts.repository ? { repository: opts.repository } : {}),
|
|
571
686
|
};
|
|
572
687
|
|
|
573
688
|
if (parentConfig.app && typeof parentConfig.app === "object") {
|
|
574
689
|
const app: Record<string, unknown> = {};
|
|
575
690
|
const parentApp = parentConfig.app as Record<string, Record<string, unknown>>;
|
|
576
691
|
|
|
577
|
-
if (parentApp.host) {
|
|
692
|
+
if (has("host") && parentApp.host) {
|
|
578
693
|
app.host = { ...parentApp.host };
|
|
579
|
-
|
|
580
|
-
delete host.production;
|
|
581
|
-
delete host.integrity;
|
|
694
|
+
stripProductionFields(app.host as Record<string, unknown>);
|
|
582
695
|
}
|
|
583
696
|
|
|
584
|
-
if (parentApp.ui) {
|
|
697
|
+
if (has("ui") && parentApp.ui) {
|
|
585
698
|
app.ui = { ...parentApp.ui };
|
|
586
|
-
|
|
587
|
-
delete ui.production;
|
|
588
|
-
delete ui.integrity;
|
|
589
|
-
delete ui.ssr;
|
|
590
|
-
delete ui.ssrIntegrity;
|
|
699
|
+
stripProductionFields(app.ui as Record<string, unknown>);
|
|
591
700
|
}
|
|
592
701
|
|
|
593
|
-
if (parentApp.api) {
|
|
702
|
+
if (has("api") && parentApp.api) {
|
|
594
703
|
app.api = { ...parentApp.api };
|
|
595
|
-
|
|
596
|
-
delete api.production;
|
|
597
|
-
delete api.integrity;
|
|
704
|
+
stripProductionFields(app.api as Record<string, unknown>);
|
|
598
705
|
}
|
|
599
706
|
|
|
600
|
-
if (parentApp.auth) {
|
|
707
|
+
if (has("plugins") && parentApp.auth) {
|
|
601
708
|
app.auth = { ...parentApp.auth };
|
|
602
|
-
|
|
603
|
-
delete auth.production;
|
|
604
|
-
delete auth.integrity;
|
|
709
|
+
stripProductionFields(app.auth as Record<string, unknown>);
|
|
605
710
|
}
|
|
606
711
|
|
|
607
|
-
|
|
712
|
+
if (Object.keys(app).length > 0) {
|
|
713
|
+
config.app = app;
|
|
714
|
+
}
|
|
608
715
|
}
|
|
609
716
|
|
|
610
|
-
if (opts.plugins && opts.plugins.length > 0 && parentConfig.plugins) {
|
|
717
|
+
if (has("plugins") && opts.plugins && opts.plugins.length > 0 && parentConfig.plugins) {
|
|
611
718
|
const plugins: Record<string, unknown> = {};
|
|
612
719
|
for (const key of opts.plugins) {
|
|
613
720
|
const parentPlugin = (parentConfig.plugins as Record<string, unknown>)?.[key];
|
|
@@ -616,8 +723,7 @@ export async function scaffoldMinimalProject(
|
|
|
616
723
|
plugins[key] = { extends: parentPlugin };
|
|
617
724
|
} else {
|
|
618
725
|
const pluginCopy = { ...(parentPlugin as Record<string, unknown>) };
|
|
619
|
-
|
|
620
|
-
delete pluginCopy.integrity;
|
|
726
|
+
stripProductionFields(pluginCopy);
|
|
621
727
|
plugins[key] = pluginCopy;
|
|
622
728
|
}
|
|
623
729
|
}
|
|
@@ -627,6 +733,18 @@ export async function scaffoldMinimalProject(
|
|
|
627
733
|
|
|
628
734
|
await saveBosConfig(destination, config);
|
|
629
735
|
|
|
736
|
+
const workspacePackages: string[] = [];
|
|
737
|
+
for (const section of opts.overrides) {
|
|
738
|
+
workspacePackages.push(...OVERRIDE_WORKSPACE_MAP[section]);
|
|
739
|
+
}
|
|
740
|
+
if (has("plugins") && opts.plugins) {
|
|
741
|
+
for (const plugin of opts.plugins) {
|
|
742
|
+
workspacePackages.push(`plugins/${plugin}`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
const catalog = resolveFrameworkCatalog();
|
|
747
|
+
|
|
630
748
|
const pkg: Record<string, unknown> = {
|
|
631
749
|
name: opts.domain || opts.extendsGateway,
|
|
632
750
|
private: true,
|
|
@@ -649,13 +767,13 @@ export async function scaffoldMinimalProject(
|
|
|
649
767
|
},
|
|
650
768
|
devDependencies: {},
|
|
651
769
|
workspaces: {
|
|
652
|
-
packages:
|
|
653
|
-
catalog
|
|
770
|
+
packages: workspacePackages,
|
|
771
|
+
catalog,
|
|
654
772
|
},
|
|
655
773
|
};
|
|
656
774
|
writeFileSync(join(destination, "package.json"), `${JSON.stringify(pkg, null, 2)}\n`);
|
|
657
775
|
|
|
658
|
-
const envExample = generateEnvExample(parentConfig);
|
|
776
|
+
const envExample = generateEnvExample(parentConfig, opts.overrides);
|
|
659
777
|
if (envExample) {
|
|
660
778
|
writeFileSync(join(destination, ".env.example"), envExample);
|
|
661
779
|
}
|
|
@@ -714,11 +832,18 @@ export async function writeInitSnapshot(
|
|
|
714
832
|
extendsGateway: string,
|
|
715
833
|
sourceDir: string,
|
|
716
834
|
patterns: string[],
|
|
717
|
-
options: {
|
|
835
|
+
options: {
|
|
836
|
+
overrides: OverrideSection[];
|
|
837
|
+
plugins?: string[];
|
|
838
|
+
pluginRoutes?: Record<string, string[]>;
|
|
839
|
+
},
|
|
718
840
|
): Promise<void> {
|
|
719
|
-
const effectivePatterns = options.
|
|
720
|
-
|
|
721
|
-
|
|
841
|
+
const effectivePatterns = filterPatternsByOverrides(patterns, options.overrides, options.plugins);
|
|
842
|
+
|
|
843
|
+
const has = (section: OverrideSection) => options.overrides.includes(section);
|
|
844
|
+
if (has("host") && !effectivePatterns.some((p) => p.startsWith("host/") || p === "host/**")) {
|
|
845
|
+
effectivePatterns.push("host/**");
|
|
846
|
+
}
|
|
722
847
|
|
|
723
848
|
const excludedRoutePatterns: string[] = [];
|
|
724
849
|
if (options.pluginRoutes) {
|
|
@@ -813,14 +938,34 @@ export async function generateDatabaseMigrations(destination: string): Promise<v
|
|
|
813
938
|
}
|
|
814
939
|
}
|
|
815
940
|
|
|
816
|
-
|
|
817
|
-
|
|
941
|
+
const COMMAND_TIMEOUTS: Record<string, number> = {
|
|
942
|
+
bun: 5 * 60_000,
|
|
943
|
+
docker: 5 * 60_000,
|
|
944
|
+
node_modules: 2 * 60_000,
|
|
945
|
+
tar: 60_000,
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
export async function execCommand(
|
|
949
|
+
command: string,
|
|
950
|
+
args: string[],
|
|
951
|
+
cwd?: string,
|
|
952
|
+
options?: { stdio?: "pipe" | "inherit" },
|
|
953
|
+
): Promise<void> {
|
|
954
|
+
const timeout = COMMAND_TIMEOUTS[command] ?? 2 * 60_000;
|
|
955
|
+
await execa(command, args, { cwd, stdio: options?.stdio ?? "pipe", timeout });
|
|
818
956
|
}
|
|
819
957
|
|
|
820
|
-
function generateEnvExample(config: BosConfigInput): string {
|
|
958
|
+
function generateEnvExample(config: BosConfigInput, overrides: OverrideSection[]): string {
|
|
959
|
+
const has = (section: OverrideSection) => overrides.includes(section);
|
|
960
|
+
|
|
821
961
|
const lines: string[] = ["# Environment variables"];
|
|
822
|
-
const collectSecrets = (
|
|
962
|
+
const collectSecrets = (
|
|
963
|
+
obj: Record<string, unknown>,
|
|
964
|
+
includeSection: boolean,
|
|
965
|
+
prefix = "",
|
|
966
|
+
): void => {
|
|
823
967
|
for (const [key, value] of Object.entries(obj)) {
|
|
968
|
+
if (!includeSection) continue;
|
|
824
969
|
if (key === "secrets" && Array.isArray(value)) {
|
|
825
970
|
for (const secret of value) {
|
|
826
971
|
if (typeof secret === "string") {
|
|
@@ -834,16 +979,28 @@ function generateEnvExample(config: BosConfigInput): string {
|
|
|
834
979
|
}
|
|
835
980
|
}
|
|
836
981
|
} else if (isPlainObject(value) && key !== "extends") {
|
|
837
|
-
collectSecrets(value as Record<string, unknown>, `${prefix}${key}.`);
|
|
982
|
+
collectSecrets(value as Record<string, unknown>, includeSection, `${prefix}${key}.`);
|
|
838
983
|
}
|
|
839
984
|
}
|
|
840
985
|
};
|
|
841
986
|
|
|
842
987
|
if (config.app && typeof config.app === "object") {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
collectSecrets(
|
|
988
|
+
const app = config.app as Record<string, unknown>;
|
|
989
|
+
collectSecrets(app, has("host"), "host.");
|
|
990
|
+
collectSecrets(app, has("ui"), "ui.");
|
|
991
|
+
collectSecrets(app, has("api"), "api.");
|
|
992
|
+
collectSecrets(app, has("plugins"), "auth.");
|
|
993
|
+
}
|
|
994
|
+
if (has("plugins") && config.plugins && typeof config.plugins === "object") {
|
|
995
|
+
for (const [pluginKey, pluginVal] of Object.entries(
|
|
996
|
+
config.plugins as Record<string, unknown>,
|
|
997
|
+
)) {
|
|
998
|
+
if (isPlainObject(pluginVal)) {
|
|
999
|
+
collectSecrets(pluginVal as Record<string, unknown>, true);
|
|
1000
|
+
} else if (typeof pluginVal === "string") {
|
|
1001
|
+
lines.push(`# Plugin '${pluginKey}' extends ${pluginVal}`);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
847
1004
|
}
|
|
848
1005
|
|
|
849
1006
|
lines.push("BETTER_AUTH_SECRET=generate-a-secret-here");
|
package/src/cli/parse.ts
CHANGED
|
@@ -29,6 +29,10 @@ function isBooleanSchema(schema: SchemaLike): boolean {
|
|
|
29
29
|
return unwrap(schema)._def?.type === "boolean";
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function isArraySchema(schema: SchemaLike): boolean {
|
|
33
|
+
return unwrap(schema)._def?.type === "array";
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
function coerceValue(raw: string, schema: SchemaLike): unknown {
|
|
33
37
|
const inner = unwrap(schema);
|
|
34
38
|
switch (inner._def?.type) {
|
|
@@ -100,6 +104,19 @@ export function parseCommandInput(descriptor: CommandDescriptor, argv: string[])
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
const next = inline ?? argv[i + 1];
|
|
107
|
+
|
|
108
|
+
if (isArraySchema(fieldSchema)) {
|
|
109
|
+
if (next === undefined || next.startsWith("--")) {
|
|
110
|
+
throw new Error(`Missing value for ${flag}`);
|
|
111
|
+
}
|
|
112
|
+
input[fieldName] = next
|
|
113
|
+
.split(",")
|
|
114
|
+
.map((s: string) => s.trim())
|
|
115
|
+
.filter(Boolean);
|
|
116
|
+
if (!inline) i += 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
103
120
|
if (next === undefined || next.startsWith("--")) {
|
|
104
121
|
throw new Error(`Missing value for ${flag}`);
|
|
105
122
|
}
|