@idevconn/create-icore 0.9.1 → 0.9.3

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.js CHANGED
@@ -336,7 +336,7 @@ Re-run with @latest to refresh:
336
336
  }
337
337
 
338
338
  // src/lib/scaffold.ts
339
- import { copyFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile8, stat, writeFile as writeFile8, rm as rm4 } from "fs/promises";
339
+ import { copyFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile8, rmdir as rmdir2, stat, writeFile as writeFile8, rm as rm4 } from "fs/promises";
340
340
  import { readFileSync } from "fs";
341
341
  import { join as join9 } from "path";
342
342
  import { spawnSync } from "child_process";
@@ -439,6 +439,30 @@ async function rewriteRootPackageJson(targetDir, opts) {
439
439
  }
440
440
  }
441
441
  delete pkg.pnpm;
442
+ const noMs = opts.authProvider === "none" && opts.upload === "none" && opts.payment === "none" && opts.jobs === "none" && opts.example === "none";
443
+ const ws = pkg.workspaces;
444
+ if (ws) {
445
+ pkg.workspaces = ws.filter((entry) => {
446
+ if (entry === "apps/templates/*") return false;
447
+ if (entry === "apps/microservices/*" && noMs) return false;
448
+ if (entry === "libs/auth-strategies/*" && opts.authProvider === "none") return false;
449
+ if (entry === "libs/storage-strategies/*" && opts.upload === "none") return false;
450
+ if (entry === "libs/db-strategies/*" && opts.dbProvider === "none") return false;
451
+ return true;
452
+ });
453
+ }
454
+ const rootDeps = pkg.dependencies ?? {};
455
+ const rootDevDeps = pkg.devDependencies ?? {};
456
+ if (opts.authProvider === "none") {
457
+ delete rootDeps["cookie-parser"];
458
+ delete rootDevDeps["@types/cookie-parser"];
459
+ }
460
+ if (opts.upload === "none") {
461
+ delete rootDevDeps["@types/multer"];
462
+ }
463
+ if (noMs) {
464
+ delete rootDeps["@nestjs/microservices"];
465
+ }
442
466
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
443
467
  }
444
468
  async function writeAuthEnv(targetDir, opts) {
@@ -561,6 +585,28 @@ async function removeFirebaseAdminLib(targetDir) {
561
585
  "@icore/firebase-admin"
562
586
  ]);
563
587
  }
588
+ async function removeStrategiesLib(targetDir) {
589
+ await rm(join3(targetDir, "libs/shared/src/strategies"), { recursive: true, force: true });
590
+ await rm(join3(targetDir, "libs/shared/src/testing.ts"), { force: true });
591
+ await rm(join3(targetDir, "libs/shared/src/transport.ts"), { force: true });
592
+ const indexPath = join3(targetDir, "libs/shared/src/index.ts");
593
+ try {
594
+ const src = await readFile4(indexPath, "utf8");
595
+ await writeFile2(
596
+ indexPath,
597
+ src.replace(/^export \* from '\.\/strategies';\n/m, "").replace(/^export \* from '\.\/transport';\n?/m, "")
598
+ );
599
+ } catch {
600
+ }
601
+ const pkgPath = join3(targetDir, "libs/shared/package.json");
602
+ try {
603
+ const pkg = JSON.parse(await readFile4(pkgPath, "utf8"));
604
+ if (pkg.exports) delete pkg.exports["./testing"];
605
+ if (pkg.dependencies) delete pkg.dependencies["@nestjs/microservices"];
606
+ await writeFile2(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
607
+ } catch {
608
+ }
609
+ }
564
610
  async function removeAuthStack(targetDir) {
565
611
  const rmPaths = [
566
612
  "apps/microservices/auth",
@@ -570,6 +616,7 @@ async function removeAuthStack(targetDir) {
570
616
  "apps/api/src/app/auth",
571
617
  "apps/api/src/app/profile",
572
618
  "apps/api/src/app/abilities",
619
+ "libs/shared/src/abilities",
573
620
  "apps/client/src/components/auth",
574
621
  "apps/client/src/routes/login.tsx",
575
622
  "apps/client/src/routes/auth.callback.tsx",
@@ -601,7 +648,17 @@ async function removeAuthStack(targetDir) {
601
648
  ]) {
602
649
  await stripTsconfigPath(targetDir, alias);
603
650
  }
604
- await stripDeps(join3(targetDir, "apps/api/package.json"), ["@icore/auth-client"]);
651
+ await stripDeps(join3(targetDir, "apps/api/package.json"), [
652
+ "@icore/auth-client",
653
+ "cookie-parser"
654
+ ]);
655
+ const gatewayMainPath = join3(targetDir, "apps/api/src/main.ts");
656
+ try {
657
+ const src = await readFile4(gatewayMainPath, "utf8");
658
+ const next = src.replace(/^import cookieParser from 'cookie-parser';\n/m, "").replace(/^\s*app\.use\(cookieParser\(\)\);\n/m, "");
659
+ await writeFile2(gatewayMainPath, next);
660
+ } catch {
661
+ }
605
662
  const gatewayEnv = join3(targetDir, "apps/api/.env");
606
663
  try {
607
664
  const env = await readFile4(gatewayEnv, "utf8");
@@ -616,6 +673,55 @@ async function removeAuthStack(targetDir) {
616
673
  await writeFile2(composePath, next);
617
674
  } catch {
618
675
  }
676
+ for (const rel of ["libs/shared/src/index.ts", "libs/shared/src/client.ts"]) {
677
+ const sharedIndexPath = join3(targetDir, rel);
678
+ try {
679
+ const src = await readFile4(sharedIndexPath, "utf8");
680
+ await writeFile2(sharedIndexPath, src.replace(/^export \* from '\.\/abilities';\n?/m, ""));
681
+ } catch {
682
+ }
683
+ }
684
+ const routesIndexPath = join3(targetDir, "apps/client/src/routes/index.tsx");
685
+ try {
686
+ const src = await readFile4(routesIndexPath, "utf8");
687
+ await writeFile2(
688
+ routesIndexPath,
689
+ src.replace(/ctaHref="\/login"/, 'ctaHref="/dashboard"').replace(/ctaLabel="Log in →"/, 'ctaLabel="Dashboard \u2192"')
690
+ );
691
+ } catch {
692
+ }
693
+ const mainTsxPath = join3(targetDir, "apps/client/src/main.tsx");
694
+ try {
695
+ const src = await readFile4(mainTsxPath, "utf8");
696
+ const next = src.replace(/\n {2}onUnauthorized: \(\) => router\.navigate\(\{ to: '\/login' \}\),/, "").replace(/^\s*AbilityProvider,\n/m, "").replace(/^\s*<AbilityProvider>\n/m, "").replace(/^\s*<\/AbilityProvider>\n/m, "");
697
+ await writeFile2(mainTsxPath, next);
698
+ } catch {
699
+ }
700
+ await rm(join3(targetDir, "libs/template-shared/src/lib/abilities"), {
701
+ recursive: true,
702
+ force: true
703
+ });
704
+ const templateSharedIndexPath = join3(targetDir, "libs/template-shared/src/index.ts");
705
+ try {
706
+ const src = await readFile4(templateSharedIndexPath, "utf8");
707
+ await writeFile2(
708
+ templateSharedIndexPath,
709
+ src.replace(/^export \* from '\.\/lib\/abilities\/ability-provider\.js';\n/m, "")
710
+ );
711
+ } catch {
712
+ }
713
+ const headerPath = join3(targetDir, "apps/client/src/components/layout/LayoutHeader.tsx");
714
+ try {
715
+ const src = await readFile4(headerPath, "utf8");
716
+ await writeFile2(
717
+ headerPath,
718
+ src.replace(/^import \{ useTranslation \} from 'react-i18next';\n/m, "").replace(/^import \{ useNavigate \} from '@tanstack\/react-router';\n/m, "").replace(/^import \{ LogOut \} from 'lucide-react';\n/m, "").replace(/^import \{ Button \} from '\.\.\/ui\/button';\n/m, "").replace(
719
+ /import \{ useAuthStore, setStoredLocale, type IcoreLocale \} from '@icore\/template-shared';/,
720
+ "import { setStoredLocale, type IcoreLocale } from '@icore/template-shared';"
721
+ ).replace(/^ {2}const \{ t \} = useTranslation\(\);\n/m, "").replace(/^ {2}const navigate = useNavigate\(\);\n/m, "").replace(/^ {2}const user = useAuthStore\(\(s\) => s\.user\);\n/m, "").replace(/^ {2}const logout = useAuthStore\(\(s\) => s\.logout\);\n/m, "").replace(/\n {2}function handleLogout\(\) \{[\s\S]*?\n {2}\}\n(?=\n {2}return)/m, "\n").replace(/\n {8}<div className="hidden sm:flex[\s\S]*?\n {8}<\/div>\n/m, "\n").replace(/\n {8}<Button[\s\S]*?sm:hidden[\s\S]*?\n {8}<\/Button>\n/m, "\n")
722
+ );
723
+ } catch {
724
+ }
619
725
  }
620
726
  async function removeUploadStack(targetDir) {
621
727
  const paths = [
@@ -623,7 +729,8 @@ async function removeUploadStack(targetDir) {
623
729
  "apps/microservices/upload-e2e",
624
730
  "libs/storage-strategies",
625
731
  "libs/upload-client",
626
- "apps/api/src/app/storage"
732
+ "apps/api/src/app/storage",
733
+ "Dockerfile.ms-upload"
627
734
  ];
628
735
  for (const p3 of paths) {
629
736
  await rm(join3(targetDir, p3), { recursive: true, force: true });
@@ -648,10 +755,17 @@ async function removeUploadStack(targetDir) {
648
755
  "@icore/upload-client",
649
756
  "@types/multer"
650
757
  ]);
758
+ const uploadComposePath = join3(targetDir, "docker-compose.yml");
759
+ try {
760
+ const compose = await readFile4(uploadComposePath, "utf8");
761
+ const next = compose.replace(/\n {2}upload:[\s\S]+?(?=\n {2}\w|\nnetworks:)/m, "\n").replace(/\n {6}upload:\n {8}condition: service_started/g, "").replace(/\n {6}UPLOAD_TRANSPORT:[^\n]*/g, "").replace(/\n {6}UPLOAD_REDIS_URL:[^\n]*/g, "");
762
+ await writeFile2(uploadComposePath, next);
763
+ } catch {
764
+ }
651
765
  }
652
766
 
653
767
  // src/manifest/wire-features.ts
654
- import { readFile as readFile6, writeFile as writeFile4, rm as rm3 } from "fs/promises";
768
+ import { readFile as readFile6, writeFile as writeFile4, rm as rm3, rmdir, unlink } from "fs/promises";
655
769
  import { join as join5 } from "path";
656
770
 
657
771
  // src/manifest/index.ts
@@ -922,6 +1036,22 @@ async function cleanupUnusedFeatures(targetDir, opts) {
922
1036
  await stripTsconfigKeys(targetDir, Object.keys(unit.tsPaths));
923
1037
  if (unit.gatewayService) await stripGatewayTransport(targetDir, unit.gatewayService.prefix);
924
1038
  if (unit.dockerService === "jobs") await stripJobsDockerCompose(targetDir);
1039
+ if (key === "jobs") {
1040
+ try {
1041
+ await unlink(join5(targetDir, "libs/shared/src/jobs.ts"));
1042
+ } catch {
1043
+ }
1044
+ const sharedIdx = join5(targetDir, "libs/shared/src/index.ts");
1045
+ try {
1046
+ const src = await readFile6(sharedIdx, "utf8");
1047
+ await writeFile4(sharedIdx, src.replace(/^export \* from '\.\/jobs';\n/m, ""));
1048
+ } catch {
1049
+ }
1050
+ }
1051
+ }
1052
+ try {
1053
+ await rmdir(join5(targetDir, "apps/client/src/queries"));
1054
+ } catch {
925
1055
  }
926
1056
  }
927
1057
 
@@ -1172,7 +1302,8 @@ async function writeAiFiles(targetDir, opts) {
1172
1302
  const pm = opts.packageManager;
1173
1303
  const nx = pm === "npm" ? "npx nx" : `${pm} nx`;
1174
1304
  const devCmd = pmRun(pm, "dev");
1175
- const activeMSes = ["auth (port 4001)"];
1305
+ const activeMSes = [];
1306
+ if (opts.authProvider !== "none") activeMSes.push("auth (port 4001)");
1176
1307
  if (opts.upload !== "none") activeMSes.push(`upload (port 4002)`);
1177
1308
  if (opts.payment !== "none") activeMSes.push(`payment (port 4003)`);
1178
1309
  if (opts.example !== "none") activeMSes.push(`notes (port 4004)`);
@@ -1201,9 +1332,7 @@ async function writeAiFiles(targetDir, opts) {
1201
1332
 
1202
1333
  \`\`\`bash
1203
1334
  # 1. Fill in provider credentials
1204
- # apps/microservices/auth/.env
1205
- # apps/microservices/upload/.env (if upload is enabled)
1206
- # apps/client/.env (VITE_API_URL \u2014 already defaults to /api)
1335
+ ${opts.authProvider !== "none" ? "# apps/microservices/auth/.env\n" : ""}${opts.upload !== "none" ? "# apps/microservices/upload/.env\n" : ""}# apps/client/.env (VITE_API_URL \u2014 already defaults to /api)
1207
1336
 
1208
1337
  # 2. Start everything
1209
1338
  ${devCmd}
@@ -1299,10 +1428,10 @@ ${nx} g @nx/nest:resource # generate NestJS resource
1299
1428
 
1300
1429
  | File | Key vars |
1301
1430
  |------|----------|
1302
- | \`apps/microservices/auth/.env\` | \`AUTH_PROVIDER=${opts.authProvider}\`, ${opts.authProvider === "supabase" ? "`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`" : "`FB_ADMIN_*`, `FIREBASE_WEB_API_KEY`"} |
1303
- ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
1304
- ` : ""}| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
1305
- | \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
1431
+ ${opts.authProvider !== "none" ? `| \`apps/microservices/auth/.env\` | \`AUTH_PROVIDER=${opts.authProvider}\`, ${opts.authProvider === "supabase" ? "`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`" : "`FB_ADMIN_*`, `FIREBASE_WEB_API_KEY`"} |
1432
+ ` : ""}${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
1433
+ ` : ""}${opts.example !== "none" ? `| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
1434
+ ` : ""}| \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
1306
1435
 
1307
1436
  ## Testing
1308
1437
 
@@ -1445,7 +1574,8 @@ function runInstall(cwd, pm) {
1445
1574
  spawnSync("pnpm", ["install"], { cwd, stdio: "inherit" });
1446
1575
  }
1447
1576
  }
1448
- async function scaffold(opts, templatesDir2) {
1577
+ async function scaffold(rawOpts, templatesDir2) {
1578
+ const opts = rawOpts.authProvider === "none" && rawOpts.example !== "none" ? { ...rawOpts, example: "none" } : rawOpts;
1449
1579
  await copyTree(templatesDir2, opts.targetDir);
1450
1580
  await rewriteRootPackageJson(opts.targetDir, opts);
1451
1581
  if (opts.authProvider !== "none") await writeAuthEnv(opts.targetDir, opts);
@@ -1477,6 +1607,13 @@ async function scaffold(opts, templatesDir2) {
1477
1607
  await writeDbProvider(opts.targetDir, opts.dbProvider);
1478
1608
  }
1479
1609
  await pruneRootProviderDeps(opts.targetDir, opts);
1610
+ if (opts.authProvider === "none" && opts.upload === "none" && opts.dbProvider === "none") {
1611
+ await removeStrategiesLib(opts.targetDir);
1612
+ }
1613
+ try {
1614
+ await rmdir2(join9(opts.targetDir, "apps/microservices"));
1615
+ } catch {
1616
+ }
1480
1617
  await writeBlueprintJson(opts.targetDir, opts);
1481
1618
  await writeServiceBlueprints(opts.targetDir, opts);
1482
1619
  if (opts.packageManager === "yarn") {
@@ -1525,11 +1662,14 @@ async function main() {
1525
1662
  p2.log.info(`Next:`);
1526
1663
  p2.log.info(` cd ${opts.projectName}`);
1527
1664
  if (!opts.install) p2.log.info(` ${opts.packageManager} install`);
1528
- p2.log.info(
1529
- ` ${pmRun(opts.packageManager, "dev")} # gateway + auth MS + upload MS + client`
1530
- );
1665
+ const services = ["gateway", "client"];
1666
+ if (opts.authProvider !== "none") services.splice(1, 0, "auth MS");
1667
+ if (opts.upload !== "none") services.splice(-1, 0, "upload MS");
1668
+ p2.log.info(` ${pmRun(opts.packageManager, "dev")} # ${services.join(" + ")}`);
1531
1669
  p2.log.info(` open http://localhost:4200`);
1532
- p2.log.info(` edit apps/microservices/auth/.env to plug in real ${opts.authProvider} creds`);
1670
+ if (opts.authProvider !== "none") {
1671
+ p2.log.info(` edit apps/microservices/auth/.env to plug in real ${opts.authProvider} creds`);
1672
+ }
1533
1673
  }
1534
1674
  main().catch((err) => {
1535
1675
  p2.log.error(err instanceof Error ? err.message : String(err));
package/dist/index.cjs CHANGED
@@ -150,6 +150,30 @@ async function rewriteRootPackageJson(targetDir, opts) {
150
150
  }
151
151
  }
152
152
  delete pkg.pnpm;
153
+ const noMs = opts.authProvider === "none" && opts.upload === "none" && opts.payment === "none" && opts.jobs === "none" && opts.example === "none";
154
+ const ws = pkg.workspaces;
155
+ if (ws) {
156
+ pkg.workspaces = ws.filter((entry) => {
157
+ if (entry === "apps/templates/*") return false;
158
+ if (entry === "apps/microservices/*" && noMs) return false;
159
+ if (entry === "libs/auth-strategies/*" && opts.authProvider === "none") return false;
160
+ if (entry === "libs/storage-strategies/*" && opts.upload === "none") return false;
161
+ if (entry === "libs/db-strategies/*" && opts.dbProvider === "none") return false;
162
+ return true;
163
+ });
164
+ }
165
+ const rootDeps = pkg.dependencies ?? {};
166
+ const rootDevDeps = pkg.devDependencies ?? {};
167
+ if (opts.authProvider === "none") {
168
+ delete rootDeps["cookie-parser"];
169
+ delete rootDevDeps["@types/cookie-parser"];
170
+ }
171
+ if (opts.upload === "none") {
172
+ delete rootDevDeps["@types/multer"];
173
+ }
174
+ if (noMs) {
175
+ delete rootDeps["@nestjs/microservices"];
176
+ }
153
177
  await (0, import_promises.writeFile)(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
154
178
  }
155
179
  async function writeAuthEnv(targetDir, opts) {
@@ -272,6 +296,28 @@ async function removeFirebaseAdminLib(targetDir) {
272
296
  "@icore/firebase-admin"
273
297
  ]);
274
298
  }
299
+ async function removeStrategiesLib(targetDir) {
300
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/strategies"), { recursive: true, force: true });
301
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/testing.ts"), { force: true });
302
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/transport.ts"), { force: true });
303
+ const indexPath = (0, import_node_path2.join)(targetDir, "libs/shared/src/index.ts");
304
+ try {
305
+ const src = await (0, import_promises2.readFile)(indexPath, "utf8");
306
+ await (0, import_promises2.writeFile)(
307
+ indexPath,
308
+ src.replace(/^export \* from '\.\/strategies';\n/m, "").replace(/^export \* from '\.\/transport';\n?/m, "")
309
+ );
310
+ } catch {
311
+ }
312
+ const pkgPath = (0, import_node_path2.join)(targetDir, "libs/shared/package.json");
313
+ try {
314
+ const pkg = JSON.parse(await (0, import_promises2.readFile)(pkgPath, "utf8"));
315
+ if (pkg.exports) delete pkg.exports["./testing"];
316
+ if (pkg.dependencies) delete pkg.dependencies["@nestjs/microservices"];
317
+ await (0, import_promises2.writeFile)(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
318
+ } catch {
319
+ }
320
+ }
275
321
  async function removeAuthStack(targetDir) {
276
322
  const rmPaths = [
277
323
  "apps/microservices/auth",
@@ -281,6 +327,7 @@ async function removeAuthStack(targetDir) {
281
327
  "apps/api/src/app/auth",
282
328
  "apps/api/src/app/profile",
283
329
  "apps/api/src/app/abilities",
330
+ "libs/shared/src/abilities",
284
331
  "apps/client/src/components/auth",
285
332
  "apps/client/src/routes/login.tsx",
286
333
  "apps/client/src/routes/auth.callback.tsx",
@@ -312,7 +359,17 @@ async function removeAuthStack(targetDir) {
312
359
  ]) {
313
360
  await stripTsconfigPath(targetDir, alias);
314
361
  }
315
- await stripDeps((0, import_node_path2.join)(targetDir, "apps/api/package.json"), ["@icore/auth-client"]);
362
+ await stripDeps((0, import_node_path2.join)(targetDir, "apps/api/package.json"), [
363
+ "@icore/auth-client",
364
+ "cookie-parser"
365
+ ]);
366
+ const gatewayMainPath = (0, import_node_path2.join)(targetDir, "apps/api/src/main.ts");
367
+ try {
368
+ const src = await (0, import_promises2.readFile)(gatewayMainPath, "utf8");
369
+ const next = src.replace(/^import cookieParser from 'cookie-parser';\n/m, "").replace(/^\s*app\.use\(cookieParser\(\)\);\n/m, "");
370
+ await (0, import_promises2.writeFile)(gatewayMainPath, next);
371
+ } catch {
372
+ }
316
373
  const gatewayEnv = (0, import_node_path2.join)(targetDir, "apps/api/.env");
317
374
  try {
318
375
  const env = await (0, import_promises2.readFile)(gatewayEnv, "utf8");
@@ -327,6 +384,55 @@ async function removeAuthStack(targetDir) {
327
384
  await (0, import_promises2.writeFile)(composePath, next);
328
385
  } catch {
329
386
  }
387
+ for (const rel of ["libs/shared/src/index.ts", "libs/shared/src/client.ts"]) {
388
+ const sharedIndexPath = (0, import_node_path2.join)(targetDir, rel);
389
+ try {
390
+ const src = await (0, import_promises2.readFile)(sharedIndexPath, "utf8");
391
+ await (0, import_promises2.writeFile)(sharedIndexPath, src.replace(/^export \* from '\.\/abilities';\n?/m, ""));
392
+ } catch {
393
+ }
394
+ }
395
+ const routesIndexPath = (0, import_node_path2.join)(targetDir, "apps/client/src/routes/index.tsx");
396
+ try {
397
+ const src = await (0, import_promises2.readFile)(routesIndexPath, "utf8");
398
+ await (0, import_promises2.writeFile)(
399
+ routesIndexPath,
400
+ src.replace(/ctaHref="\/login"/, 'ctaHref="/dashboard"').replace(/ctaLabel="Log in →"/, 'ctaLabel="Dashboard \u2192"')
401
+ );
402
+ } catch {
403
+ }
404
+ const mainTsxPath = (0, import_node_path2.join)(targetDir, "apps/client/src/main.tsx");
405
+ try {
406
+ const src = await (0, import_promises2.readFile)(mainTsxPath, "utf8");
407
+ const next = src.replace(/\n {2}onUnauthorized: \(\) => router\.navigate\(\{ to: '\/login' \}\),/, "").replace(/^\s*AbilityProvider,\n/m, "").replace(/^\s*<AbilityProvider>\n/m, "").replace(/^\s*<\/AbilityProvider>\n/m, "");
408
+ await (0, import_promises2.writeFile)(mainTsxPath, next);
409
+ } catch {
410
+ }
411
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/template-shared/src/lib/abilities"), {
412
+ recursive: true,
413
+ force: true
414
+ });
415
+ const templateSharedIndexPath = (0, import_node_path2.join)(targetDir, "libs/template-shared/src/index.ts");
416
+ try {
417
+ const src = await (0, import_promises2.readFile)(templateSharedIndexPath, "utf8");
418
+ await (0, import_promises2.writeFile)(
419
+ templateSharedIndexPath,
420
+ src.replace(/^export \* from '\.\/lib\/abilities\/ability-provider\.js';\n/m, "")
421
+ );
422
+ } catch {
423
+ }
424
+ const headerPath = (0, import_node_path2.join)(targetDir, "apps/client/src/components/layout/LayoutHeader.tsx");
425
+ try {
426
+ const src = await (0, import_promises2.readFile)(headerPath, "utf8");
427
+ await (0, import_promises2.writeFile)(
428
+ headerPath,
429
+ src.replace(/^import \{ useTranslation \} from 'react-i18next';\n/m, "").replace(/^import \{ useNavigate \} from '@tanstack\/react-router';\n/m, "").replace(/^import \{ LogOut \} from 'lucide-react';\n/m, "").replace(/^import \{ Button \} from '\.\.\/ui\/button';\n/m, "").replace(
430
+ /import \{ useAuthStore, setStoredLocale, type IcoreLocale \} from '@icore\/template-shared';/,
431
+ "import { setStoredLocale, type IcoreLocale } from '@icore/template-shared';"
432
+ ).replace(/^ {2}const \{ t \} = useTranslation\(\);\n/m, "").replace(/^ {2}const navigate = useNavigate\(\);\n/m, "").replace(/^ {2}const user = useAuthStore\(\(s\) => s\.user\);\n/m, "").replace(/^ {2}const logout = useAuthStore\(\(s\) => s\.logout\);\n/m, "").replace(/\n {2}function handleLogout\(\) \{[\s\S]*?\n {2}\}\n(?=\n {2}return)/m, "\n").replace(/\n {8}<div className="hidden sm:flex[\s\S]*?\n {8}<\/div>\n/m, "\n").replace(/\n {8}<Button[\s\S]*?sm:hidden[\s\S]*?\n {8}<\/Button>\n/m, "\n")
433
+ );
434
+ } catch {
435
+ }
330
436
  }
331
437
  async function removeUploadStack(targetDir) {
332
438
  const paths = [
@@ -334,7 +440,8 @@ async function removeUploadStack(targetDir) {
334
440
  "apps/microservices/upload-e2e",
335
441
  "libs/storage-strategies",
336
442
  "libs/upload-client",
337
- "apps/api/src/app/storage"
443
+ "apps/api/src/app/storage",
444
+ "Dockerfile.ms-upload"
338
445
  ];
339
446
  for (const p2 of paths) {
340
447
  await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, p2), { recursive: true, force: true });
@@ -359,6 +466,13 @@ async function removeUploadStack(targetDir) {
359
466
  "@icore/upload-client",
360
467
  "@types/multer"
361
468
  ]);
469
+ const uploadComposePath = (0, import_node_path2.join)(targetDir, "docker-compose.yml");
470
+ try {
471
+ const compose = await (0, import_promises2.readFile)(uploadComposePath, "utf8");
472
+ const next = compose.replace(/\n {2}upload:[\s\S]+?(?=\n {2}\w|\nnetworks:)/m, "\n").replace(/\n {6}upload:\n {8}condition: service_started/g, "").replace(/\n {6}UPLOAD_TRANSPORT:[^\n]*/g, "").replace(/\n {6}UPLOAD_REDIS_URL:[^\n]*/g, "");
473
+ await (0, import_promises2.writeFile)(uploadComposePath, next);
474
+ } catch {
475
+ }
362
476
  }
363
477
 
364
478
  // src/manifest/wire-features.ts
@@ -633,6 +747,22 @@ async function cleanupUnusedFeatures(targetDir, opts) {
633
747
  await stripTsconfigKeys(targetDir, Object.keys(unit.tsPaths));
634
748
  if (unit.gatewayService) await stripGatewayTransport(targetDir, unit.gatewayService.prefix);
635
749
  if (unit.dockerService === "jobs") await stripJobsDockerCompose(targetDir);
750
+ if (key === "jobs") {
751
+ try {
752
+ await (0, import_promises4.unlink)((0, import_node_path4.join)(targetDir, "libs/shared/src/jobs.ts"));
753
+ } catch {
754
+ }
755
+ const sharedIdx = (0, import_node_path4.join)(targetDir, "libs/shared/src/index.ts");
756
+ try {
757
+ const src = await (0, import_promises4.readFile)(sharedIdx, "utf8");
758
+ await (0, import_promises4.writeFile)(sharedIdx, src.replace(/^export \* from '\.\/jobs';\n/m, ""));
759
+ } catch {
760
+ }
761
+ }
762
+ }
763
+ try {
764
+ await (0, import_promises4.rmdir)((0, import_node_path4.join)(targetDir, "apps/client/src/queries"));
765
+ } catch {
636
766
  }
637
767
  }
638
768
 
@@ -876,7 +1006,8 @@ async function writeAiFiles(targetDir, opts) {
876
1006
  const pm = opts.packageManager;
877
1007
  const nx = pm === "npm" ? "npx nx" : `${pm} nx`;
878
1008
  const devCmd = pmRun(pm, "dev");
879
- const activeMSes = ["auth (port 4001)"];
1009
+ const activeMSes = [];
1010
+ if (opts.authProvider !== "none") activeMSes.push("auth (port 4001)");
880
1011
  if (opts.upload !== "none") activeMSes.push(`upload (port 4002)`);
881
1012
  if (opts.payment !== "none") activeMSes.push(`payment (port 4003)`);
882
1013
  if (opts.example !== "none") activeMSes.push(`notes (port 4004)`);
@@ -905,9 +1036,7 @@ async function writeAiFiles(targetDir, opts) {
905
1036
 
906
1037
  \`\`\`bash
907
1038
  # 1. Fill in provider credentials
908
- # apps/microservices/auth/.env
909
- # apps/microservices/upload/.env (if upload is enabled)
910
- # apps/client/.env (VITE_API_URL \u2014 already defaults to /api)
1039
+ ${opts.authProvider !== "none" ? "# apps/microservices/auth/.env\n" : ""}${opts.upload !== "none" ? "# apps/microservices/upload/.env\n" : ""}# apps/client/.env (VITE_API_URL \u2014 already defaults to /api)
911
1040
 
912
1041
  # 2. Start everything
913
1042
  ${devCmd}
@@ -1003,10 +1132,10 @@ ${nx} g @nx/nest:resource # generate NestJS resource
1003
1132
 
1004
1133
  | File | Key vars |
1005
1134
  |------|----------|
1006
- | \`apps/microservices/auth/.env\` | \`AUTH_PROVIDER=${opts.authProvider}\`, ${opts.authProvider === "supabase" ? "`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`" : "`FB_ADMIN_*`, `FIREBASE_WEB_API_KEY`"} |
1007
- ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
1008
- ` : ""}| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
1009
- | \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
1135
+ ${opts.authProvider !== "none" ? `| \`apps/microservices/auth/.env\` | \`AUTH_PROVIDER=${opts.authProvider}\`, ${opts.authProvider === "supabase" ? "`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`" : "`FB_ADMIN_*`, `FIREBASE_WEB_API_KEY`"} |
1136
+ ` : ""}${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
1137
+ ` : ""}${opts.example !== "none" ? `| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
1138
+ ` : ""}| \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
1010
1139
 
1011
1140
  ## Testing
1012
1141
 
@@ -1149,7 +1278,8 @@ function runInstall(cwd, pm) {
1149
1278
  (0, import_node_child_process.spawnSync)("pnpm", ["install"], { cwd, stdio: "inherit" });
1150
1279
  }
1151
1280
  }
1152
- async function scaffold(opts, templatesDir) {
1281
+ async function scaffold(rawOpts, templatesDir) {
1282
+ const opts = rawOpts.authProvider === "none" && rawOpts.example !== "none" ? { ...rawOpts, example: "none" } : rawOpts;
1153
1283
  await copyTree(templatesDir, opts.targetDir);
1154
1284
  await rewriteRootPackageJson(opts.targetDir, opts);
1155
1285
  if (opts.authProvider !== "none") await writeAuthEnv(opts.targetDir, opts);
@@ -1181,6 +1311,13 @@ async function scaffold(opts, templatesDir) {
1181
1311
  await writeDbProvider(opts.targetDir, opts.dbProvider);
1182
1312
  }
1183
1313
  await pruneRootProviderDeps(opts.targetDir, opts);
1314
+ if (opts.authProvider === "none" && opts.upload === "none" && opts.dbProvider === "none") {
1315
+ await removeStrategiesLib(opts.targetDir);
1316
+ }
1317
+ try {
1318
+ await (0, import_promises8.rmdir)((0, import_node_path8.join)(opts.targetDir, "apps/microservices"));
1319
+ } catch {
1320
+ }
1184
1321
  await writeBlueprintJson(opts.targetDir, opts);
1185
1322
  await writeServiceBlueprints(opts.targetDir, opts);
1186
1323
  if (opts.packageManager === "yarn") {
package/dist/index.d.cts CHANGED
@@ -30,7 +30,7 @@ interface CreateIcoreOptions {
30
30
  install: boolean;
31
31
  }
32
32
 
33
- declare function scaffold(opts: CreateIcoreOptions, templatesDir: string): Promise<void>;
33
+ declare function scaffold(rawOpts: CreateIcoreOptions, templatesDir: string): Promise<void>;
34
34
 
35
35
  interface PromptInput {
36
36
  argv: string[];
package/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ interface CreateIcoreOptions {
30
30
  install: boolean;
31
31
  }
32
32
 
33
- declare function scaffold(opts: CreateIcoreOptions, templatesDir: string): Promise<void>;
33
+ declare function scaffold(rawOpts: CreateIcoreOptions, templatesDir: string): Promise<void>;
34
34
 
35
35
  interface PromptInput {
36
36
  argv: string[];
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ function pmRun(pm, script) {
4
4
  }
5
5
 
6
6
  // src/lib/scaffold.ts
7
- import { copyFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile6, stat, writeFile as writeFile8, rm as rm4 } from "fs/promises";
7
+ import { copyFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile6, rmdir as rmdir2, stat, writeFile as writeFile8, rm as rm4 } from "fs/promises";
8
8
  import { readFileSync } from "fs";
9
9
  import { join as join8 } from "path";
10
10
  import { spawnSync } from "child_process";
@@ -107,6 +107,30 @@ async function rewriteRootPackageJson(targetDir, opts) {
107
107
  }
108
108
  }
109
109
  delete pkg.pnpm;
110
+ const noMs = opts.authProvider === "none" && opts.upload === "none" && opts.payment === "none" && opts.jobs === "none" && opts.example === "none";
111
+ const ws = pkg.workspaces;
112
+ if (ws) {
113
+ pkg.workspaces = ws.filter((entry) => {
114
+ if (entry === "apps/templates/*") return false;
115
+ if (entry === "apps/microservices/*" && noMs) return false;
116
+ if (entry === "libs/auth-strategies/*" && opts.authProvider === "none") return false;
117
+ if (entry === "libs/storage-strategies/*" && opts.upload === "none") return false;
118
+ if (entry === "libs/db-strategies/*" && opts.dbProvider === "none") return false;
119
+ return true;
120
+ });
121
+ }
122
+ const rootDeps = pkg.dependencies ?? {};
123
+ const rootDevDeps = pkg.devDependencies ?? {};
124
+ if (opts.authProvider === "none") {
125
+ delete rootDeps["cookie-parser"];
126
+ delete rootDevDeps["@types/cookie-parser"];
127
+ }
128
+ if (opts.upload === "none") {
129
+ delete rootDevDeps["@types/multer"];
130
+ }
131
+ if (noMs) {
132
+ delete rootDeps["@nestjs/microservices"];
133
+ }
110
134
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
111
135
  }
112
136
  async function writeAuthEnv(targetDir, opts) {
@@ -229,6 +253,28 @@ async function removeFirebaseAdminLib(targetDir) {
229
253
  "@icore/firebase-admin"
230
254
  ]);
231
255
  }
256
+ async function removeStrategiesLib(targetDir) {
257
+ await rm(join2(targetDir, "libs/shared/src/strategies"), { recursive: true, force: true });
258
+ await rm(join2(targetDir, "libs/shared/src/testing.ts"), { force: true });
259
+ await rm(join2(targetDir, "libs/shared/src/transport.ts"), { force: true });
260
+ const indexPath = join2(targetDir, "libs/shared/src/index.ts");
261
+ try {
262
+ const src = await readFile2(indexPath, "utf8");
263
+ await writeFile2(
264
+ indexPath,
265
+ src.replace(/^export \* from '\.\/strategies';\n/m, "").replace(/^export \* from '\.\/transport';\n?/m, "")
266
+ );
267
+ } catch {
268
+ }
269
+ const pkgPath = join2(targetDir, "libs/shared/package.json");
270
+ try {
271
+ const pkg = JSON.parse(await readFile2(pkgPath, "utf8"));
272
+ if (pkg.exports) delete pkg.exports["./testing"];
273
+ if (pkg.dependencies) delete pkg.dependencies["@nestjs/microservices"];
274
+ await writeFile2(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
275
+ } catch {
276
+ }
277
+ }
232
278
  async function removeAuthStack(targetDir) {
233
279
  const rmPaths = [
234
280
  "apps/microservices/auth",
@@ -238,6 +284,7 @@ async function removeAuthStack(targetDir) {
238
284
  "apps/api/src/app/auth",
239
285
  "apps/api/src/app/profile",
240
286
  "apps/api/src/app/abilities",
287
+ "libs/shared/src/abilities",
241
288
  "apps/client/src/components/auth",
242
289
  "apps/client/src/routes/login.tsx",
243
290
  "apps/client/src/routes/auth.callback.tsx",
@@ -269,7 +316,17 @@ async function removeAuthStack(targetDir) {
269
316
  ]) {
270
317
  await stripTsconfigPath(targetDir, alias);
271
318
  }
272
- await stripDeps(join2(targetDir, "apps/api/package.json"), ["@icore/auth-client"]);
319
+ await stripDeps(join2(targetDir, "apps/api/package.json"), [
320
+ "@icore/auth-client",
321
+ "cookie-parser"
322
+ ]);
323
+ const gatewayMainPath = join2(targetDir, "apps/api/src/main.ts");
324
+ try {
325
+ const src = await readFile2(gatewayMainPath, "utf8");
326
+ const next = src.replace(/^import cookieParser from 'cookie-parser';\n/m, "").replace(/^\s*app\.use\(cookieParser\(\)\);\n/m, "");
327
+ await writeFile2(gatewayMainPath, next);
328
+ } catch {
329
+ }
273
330
  const gatewayEnv = join2(targetDir, "apps/api/.env");
274
331
  try {
275
332
  const env = await readFile2(gatewayEnv, "utf8");
@@ -284,6 +341,55 @@ async function removeAuthStack(targetDir) {
284
341
  await writeFile2(composePath, next);
285
342
  } catch {
286
343
  }
344
+ for (const rel of ["libs/shared/src/index.ts", "libs/shared/src/client.ts"]) {
345
+ const sharedIndexPath = join2(targetDir, rel);
346
+ try {
347
+ const src = await readFile2(sharedIndexPath, "utf8");
348
+ await writeFile2(sharedIndexPath, src.replace(/^export \* from '\.\/abilities';\n?/m, ""));
349
+ } catch {
350
+ }
351
+ }
352
+ const routesIndexPath = join2(targetDir, "apps/client/src/routes/index.tsx");
353
+ try {
354
+ const src = await readFile2(routesIndexPath, "utf8");
355
+ await writeFile2(
356
+ routesIndexPath,
357
+ src.replace(/ctaHref="\/login"/, 'ctaHref="/dashboard"').replace(/ctaLabel="Log in →"/, 'ctaLabel="Dashboard \u2192"')
358
+ );
359
+ } catch {
360
+ }
361
+ const mainTsxPath = join2(targetDir, "apps/client/src/main.tsx");
362
+ try {
363
+ const src = await readFile2(mainTsxPath, "utf8");
364
+ const next = src.replace(/\n {2}onUnauthorized: \(\) => router\.navigate\(\{ to: '\/login' \}\),/, "").replace(/^\s*AbilityProvider,\n/m, "").replace(/^\s*<AbilityProvider>\n/m, "").replace(/^\s*<\/AbilityProvider>\n/m, "");
365
+ await writeFile2(mainTsxPath, next);
366
+ } catch {
367
+ }
368
+ await rm(join2(targetDir, "libs/template-shared/src/lib/abilities"), {
369
+ recursive: true,
370
+ force: true
371
+ });
372
+ const templateSharedIndexPath = join2(targetDir, "libs/template-shared/src/index.ts");
373
+ try {
374
+ const src = await readFile2(templateSharedIndexPath, "utf8");
375
+ await writeFile2(
376
+ templateSharedIndexPath,
377
+ src.replace(/^export \* from '\.\/lib\/abilities\/ability-provider\.js';\n/m, "")
378
+ );
379
+ } catch {
380
+ }
381
+ const headerPath = join2(targetDir, "apps/client/src/components/layout/LayoutHeader.tsx");
382
+ try {
383
+ const src = await readFile2(headerPath, "utf8");
384
+ await writeFile2(
385
+ headerPath,
386
+ src.replace(/^import \{ useTranslation \} from 'react-i18next';\n/m, "").replace(/^import \{ useNavigate \} from '@tanstack\/react-router';\n/m, "").replace(/^import \{ LogOut \} from 'lucide-react';\n/m, "").replace(/^import \{ Button \} from '\.\.\/ui\/button';\n/m, "").replace(
387
+ /import \{ useAuthStore, setStoredLocale, type IcoreLocale \} from '@icore\/template-shared';/,
388
+ "import { setStoredLocale, type IcoreLocale } from '@icore/template-shared';"
389
+ ).replace(/^ {2}const \{ t \} = useTranslation\(\);\n/m, "").replace(/^ {2}const navigate = useNavigate\(\);\n/m, "").replace(/^ {2}const user = useAuthStore\(\(s\) => s\.user\);\n/m, "").replace(/^ {2}const logout = useAuthStore\(\(s\) => s\.logout\);\n/m, "").replace(/\n {2}function handleLogout\(\) \{[\s\S]*?\n {2}\}\n(?=\n {2}return)/m, "\n").replace(/\n {8}<div className="hidden sm:flex[\s\S]*?\n {8}<\/div>\n/m, "\n").replace(/\n {8}<Button[\s\S]*?sm:hidden[\s\S]*?\n {8}<\/Button>\n/m, "\n")
390
+ );
391
+ } catch {
392
+ }
287
393
  }
288
394
  async function removeUploadStack(targetDir) {
289
395
  const paths = [
@@ -291,7 +397,8 @@ async function removeUploadStack(targetDir) {
291
397
  "apps/microservices/upload-e2e",
292
398
  "libs/storage-strategies",
293
399
  "libs/upload-client",
294
- "apps/api/src/app/storage"
400
+ "apps/api/src/app/storage",
401
+ "Dockerfile.ms-upload"
295
402
  ];
296
403
  for (const p2 of paths) {
297
404
  await rm(join2(targetDir, p2), { recursive: true, force: true });
@@ -316,10 +423,17 @@ async function removeUploadStack(targetDir) {
316
423
  "@icore/upload-client",
317
424
  "@types/multer"
318
425
  ]);
426
+ const uploadComposePath = join2(targetDir, "docker-compose.yml");
427
+ try {
428
+ const compose = await readFile2(uploadComposePath, "utf8");
429
+ const next = compose.replace(/\n {2}upload:[\s\S]+?(?=\n {2}\w|\nnetworks:)/m, "\n").replace(/\n {6}upload:\n {8}condition: service_started/g, "").replace(/\n {6}UPLOAD_TRANSPORT:[^\n]*/g, "").replace(/\n {6}UPLOAD_REDIS_URL:[^\n]*/g, "");
430
+ await writeFile2(uploadComposePath, next);
431
+ } catch {
432
+ }
319
433
  }
320
434
 
321
435
  // src/manifest/wire-features.ts
322
- import { readFile as readFile4, writeFile as writeFile4, rm as rm3 } from "fs/promises";
436
+ import { readFile as readFile4, writeFile as writeFile4, rm as rm3, rmdir, unlink } from "fs/promises";
323
437
  import { join as join4 } from "path";
324
438
 
325
439
  // src/manifest/index.ts
@@ -590,6 +704,22 @@ async function cleanupUnusedFeatures(targetDir, opts) {
590
704
  await stripTsconfigKeys(targetDir, Object.keys(unit.tsPaths));
591
705
  if (unit.gatewayService) await stripGatewayTransport(targetDir, unit.gatewayService.prefix);
592
706
  if (unit.dockerService === "jobs") await stripJobsDockerCompose(targetDir);
707
+ if (key === "jobs") {
708
+ try {
709
+ await unlink(join4(targetDir, "libs/shared/src/jobs.ts"));
710
+ } catch {
711
+ }
712
+ const sharedIdx = join4(targetDir, "libs/shared/src/index.ts");
713
+ try {
714
+ const src = await readFile4(sharedIdx, "utf8");
715
+ await writeFile4(sharedIdx, src.replace(/^export \* from '\.\/jobs';\n/m, ""));
716
+ } catch {
717
+ }
718
+ }
719
+ }
720
+ try {
721
+ await rmdir(join4(targetDir, "apps/client/src/queries"));
722
+ } catch {
593
723
  }
594
724
  }
595
725
 
@@ -833,7 +963,8 @@ async function writeAiFiles(targetDir, opts) {
833
963
  const pm = opts.packageManager;
834
964
  const nx = pm === "npm" ? "npx nx" : `${pm} nx`;
835
965
  const devCmd = pmRun(pm, "dev");
836
- const activeMSes = ["auth (port 4001)"];
966
+ const activeMSes = [];
967
+ if (opts.authProvider !== "none") activeMSes.push("auth (port 4001)");
837
968
  if (opts.upload !== "none") activeMSes.push(`upload (port 4002)`);
838
969
  if (opts.payment !== "none") activeMSes.push(`payment (port 4003)`);
839
970
  if (opts.example !== "none") activeMSes.push(`notes (port 4004)`);
@@ -862,9 +993,7 @@ async function writeAiFiles(targetDir, opts) {
862
993
 
863
994
  \`\`\`bash
864
995
  # 1. Fill in provider credentials
865
- # apps/microservices/auth/.env
866
- # apps/microservices/upload/.env (if upload is enabled)
867
- # apps/client/.env (VITE_API_URL \u2014 already defaults to /api)
996
+ ${opts.authProvider !== "none" ? "# apps/microservices/auth/.env\n" : ""}${opts.upload !== "none" ? "# apps/microservices/upload/.env\n" : ""}# apps/client/.env (VITE_API_URL \u2014 already defaults to /api)
868
997
 
869
998
  # 2. Start everything
870
999
  ${devCmd}
@@ -960,10 +1089,10 @@ ${nx} g @nx/nest:resource # generate NestJS resource
960
1089
 
961
1090
  | File | Key vars |
962
1091
  |------|----------|
963
- | \`apps/microservices/auth/.env\` | \`AUTH_PROVIDER=${opts.authProvider}\`, ${opts.authProvider === "supabase" ? "`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`" : "`FB_ADMIN_*`, `FIREBASE_WEB_API_KEY`"} |
964
- ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
965
- ` : ""}| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
966
- | \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
1092
+ ${opts.authProvider !== "none" ? `| \`apps/microservices/auth/.env\` | \`AUTH_PROVIDER=${opts.authProvider}\`, ${opts.authProvider === "supabase" ? "`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`" : "`FB_ADMIN_*`, `FIREBASE_WEB_API_KEY`"} |
1093
+ ` : ""}${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
1094
+ ` : ""}${opts.example !== "none" ? `| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
1095
+ ` : ""}| \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
967
1096
 
968
1097
  ## Testing
969
1098
 
@@ -1106,7 +1235,8 @@ function runInstall(cwd, pm) {
1106
1235
  spawnSync("pnpm", ["install"], { cwd, stdio: "inherit" });
1107
1236
  }
1108
1237
  }
1109
- async function scaffold(opts, templatesDir) {
1238
+ async function scaffold(rawOpts, templatesDir) {
1239
+ const opts = rawOpts.authProvider === "none" && rawOpts.example !== "none" ? { ...rawOpts, example: "none" } : rawOpts;
1110
1240
  await copyTree(templatesDir, opts.targetDir);
1111
1241
  await rewriteRootPackageJson(opts.targetDir, opts);
1112
1242
  if (opts.authProvider !== "none") await writeAuthEnv(opts.targetDir, opts);
@@ -1138,6 +1268,13 @@ async function scaffold(opts, templatesDir) {
1138
1268
  await writeDbProvider(opts.targetDir, opts.dbProvider);
1139
1269
  }
1140
1270
  await pruneRootProviderDeps(opts.targetDir, opts);
1271
+ if (opts.authProvider === "none" && opts.upload === "none" && opts.dbProvider === "none") {
1272
+ await removeStrategiesLib(opts.targetDir);
1273
+ }
1274
+ try {
1275
+ await rmdir2(join8(opts.targetDir, "apps/microservices"));
1276
+ } catch {
1277
+ }
1141
1278
  await writeBlueprintJson(opts.targetDir, opts);
1142
1279
  await writeServiceBlueprints(opts.targetDir, opts);
1143
1280
  if (opts.packageManager === "yarn") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idevconn/create-icore",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Bootstrap a new project from the iCore scaffold (Nx + NestJS + React + Vite + shadcn/Tailwind, swappable auth + storage providers).",
5
5
  "license": "Apache-2.0",
6
6
  "author": "iDEVconn",
@@ -3,16 +3,20 @@
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
5
  "type": "commonjs",
6
- "main": "./src/index.js",
6
+ "main": "./src/index.ts",
7
7
  "types": "./src/index.ts",
8
8
  "exports": {
9
9
  ".": {
10
- "require": "./src/index.js",
10
+ "default": "./src/index.ts",
11
11
  "types": "./src/index.ts"
12
12
  },
13
13
  "./client": {
14
- "require": "./src/client.js",
14
+ "default": "./src/client.ts",
15
15
  "types": "./src/client.ts"
16
+ },
17
+ "./testing": {
18
+ "default": "./src/testing.ts",
19
+ "types": "./src/testing.ts"
16
20
  }
17
21
  },
18
22
  "dependencies": {