@idevconn/create-icore 0.6.3 → 0.7.1

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.
Files changed (87) hide show
  1. package/dist/cli.js +384 -276
  2. package/dist/index.cjs +385 -277
  3. package/dist/index.d.cts +3 -3
  4. package/dist/index.d.ts +3 -3
  5. package/dist/index.js +382 -274
  6. package/package.json +1 -1
  7. package/templates/.yarn/releases/yarn-4.16.0.cjs +944 -0
  8. package/templates/.yarnrc.yml +1 -1
  9. package/templates/apps/api/src/app/storage/storage.controller.ts +28 -0
  10. package/templates/apps/microservices/auth/src/app/app.module.ts +20 -2
  11. package/templates/apps/microservices/notes/src/app/app.module.ts +17 -2
  12. package/templates/apps/microservices/upload/src/app/app.module.ts +17 -2
  13. package/templates/apps/microservices/upload/src/app/storage.controller.ts +7 -0
  14. package/templates/apps/templates/client-antd/src/components/auth/AuthBrandPanel.tsx +59 -0
  15. package/templates/apps/templates/client-antd/src/components/auth/CheckEmailScreen.tsx +28 -0
  16. package/templates/apps/templates/client-antd/src/components/auth/LoginForm.tsx +116 -0
  17. package/templates/apps/templates/client-antd/src/components/auth/MagicLinkForm.tsx +95 -0
  18. package/templates/apps/templates/client-antd/src/components/auth/RegisterForm.tsx +98 -0
  19. package/templates/apps/templates/client-antd/src/globals.less +6 -0
  20. package/templates/apps/templates/client-antd/src/main.tsx +1 -1
  21. package/templates/apps/templates/client-antd/src/routes/login.tsx +45 -181
  22. package/templates/apps/templates/client-mui/src/components/auth/AuthBrandPanel.tsx +59 -0
  23. package/templates/apps/templates/client-mui/src/components/auth/CheckEmailScreen.tsx +28 -0
  24. package/templates/apps/templates/client-mui/src/components/auth/LoginForm.tsx +141 -0
  25. package/templates/apps/templates/client-mui/src/components/auth/MagicLinkForm.tsx +106 -0
  26. package/templates/apps/templates/client-mui/src/components/auth/RegisterForm.tsx +113 -0
  27. package/templates/apps/templates/client-mui/src/main.tsx +1 -1
  28. package/templates/apps/templates/client-mui/src/routes/login.tsx +50 -186
  29. package/templates/apps/templates/client-shadcn/src/components/auth/AuthBrandPanel.tsx +52 -0
  30. package/templates/apps/templates/client-shadcn/src/components/auth/CheckEmailScreen.tsx +29 -0
  31. package/templates/apps/templates/client-shadcn/src/components/auth/LoginForm.tsx +161 -0
  32. package/templates/apps/templates/client-shadcn/src/components/auth/MagicLinkForm.tsx +110 -0
  33. package/templates/apps/templates/client-shadcn/src/components/auth/RegisterForm.tsx +107 -0
  34. package/templates/apps/templates/client-shadcn/src/components/layout/LayoutHeader.tsx +31 -10
  35. package/templates/apps/templates/client-shadcn/src/components/layout/LayoutSider.tsx +22 -27
  36. package/templates/apps/templates/client-shadcn/src/components/ui/card.tsx +1 -1
  37. package/templates/apps/templates/client-shadcn/src/globals.css +39 -13
  38. package/templates/apps/templates/client-shadcn/src/routes/auth.callback.tsx +1 -1
  39. package/templates/apps/templates/client-shadcn/src/routes/login.tsx +55 -165
  40. package/templates/libs/auth-strategies/mongodb/CHANGELOG.md +8 -0
  41. package/templates/libs/auth-strategies/mongodb/README.md +11 -0
  42. package/templates/libs/auth-strategies/mongodb/eslint.config.mjs +19 -0
  43. package/templates/libs/auth-strategies/mongodb/jest.config.cts +10 -0
  44. package/templates/libs/auth-strategies/mongodb/package.json +16 -0
  45. package/templates/libs/auth-strategies/mongodb/project.json +19 -0
  46. package/templates/libs/auth-strategies/mongodb/src/index.ts +1 -0
  47. package/templates/libs/auth-strategies/mongodb/src/lib/__tests__/mongodb-auth.strategy.unit.test.ts +42 -0
  48. package/templates/libs/auth-strategies/mongodb/src/lib/auth-mongodb.spec.ts +7 -0
  49. package/templates/libs/auth-strategies/mongodb/src/lib/auth-mongodb.ts +3 -0
  50. package/templates/libs/auth-strategies/mongodb/src/lib/mongodb-auth.strategy.ts +188 -0
  51. package/templates/libs/auth-strategies/mongodb/tsconfig.json +23 -0
  52. package/templates/libs/auth-strategies/mongodb/tsconfig.lib.json +10 -0
  53. package/templates/libs/auth-strategies/mongodb/tsconfig.spec.json +16 -0
  54. package/templates/libs/db-strategies/mongodb/CHANGELOG.md +7 -0
  55. package/templates/libs/db-strategies/mongodb/README.md +11 -0
  56. package/templates/libs/db-strategies/mongodb/eslint.config.mjs +19 -0
  57. package/templates/libs/db-strategies/mongodb/jest.config.cts +10 -0
  58. package/templates/libs/db-strategies/mongodb/package.json +14 -0
  59. package/templates/libs/db-strategies/mongodb/project.json +19 -0
  60. package/templates/libs/db-strategies/mongodb/src/index.ts +1 -0
  61. package/templates/libs/db-strategies/mongodb/src/lib/__tests__/mongodb-db.strategy.unit.test.ts +38 -0
  62. package/templates/libs/db-strategies/mongodb/src/lib/mongodb-db.strategy.ts +108 -0
  63. package/templates/libs/db-strategies/mongodb/src/lib/mongodb.spec.ts +7 -0
  64. package/templates/libs/db-strategies/mongodb/src/lib/mongodb.ts +3 -0
  65. package/templates/libs/db-strategies/mongodb/tsconfig.json +23 -0
  66. package/templates/libs/db-strategies/mongodb/tsconfig.lib.json +10 -0
  67. package/templates/libs/db-strategies/mongodb/tsconfig.spec.json +16 -0
  68. package/templates/libs/shared/src/strategies/storage.ts +3 -0
  69. package/templates/libs/storage-strategies/mongodb/CHANGELOG.md +8 -0
  70. package/templates/libs/storage-strategies/mongodb/README.md +11 -0
  71. package/templates/libs/storage-strategies/mongodb/eslint.config.mjs +19 -0
  72. package/templates/libs/storage-strategies/mongodb/jest.config.cts +10 -0
  73. package/templates/libs/storage-strategies/mongodb/package.json +14 -0
  74. package/templates/libs/storage-strategies/mongodb/project.json +19 -0
  75. package/templates/libs/storage-strategies/mongodb/src/index.ts +1 -0
  76. package/templates/libs/storage-strategies/mongodb/src/lib/__tests__/mongodb-storage.strategy.unit.test.ts +38 -0
  77. package/templates/libs/storage-strategies/mongodb/src/lib/mongodb-storage.strategy.ts +93 -0
  78. package/templates/libs/storage-strategies/mongodb/src/lib/storage-mongodb.spec.ts +7 -0
  79. package/templates/libs/storage-strategies/mongodb/src/lib/storage-mongodb.ts +3 -0
  80. package/templates/libs/storage-strategies/mongodb/tsconfig.json +23 -0
  81. package/templates/libs/storage-strategies/mongodb/tsconfig.lib.json +10 -0
  82. package/templates/libs/storage-strategies/mongodb/tsconfig.spec.json +16 -0
  83. package/templates/libs/template-shared/src/lib/i18n/keys.ts +216 -56
  84. package/templates/libs/template-shared/src/lib/stores/theme.store.ts +1 -6
  85. package/templates/libs/upload-client/src/lib/upload-client.service.ts +7 -0
  86. package/templates/tsconfig.base.json +4 -1
  87. package/templates/.yarn/releases/yarn-4.15.0.cjs +0 -940
package/dist/cli.js CHANGED
@@ -124,7 +124,8 @@ Re-run with @latest to refresh:
124
124
  message: "Auth provider",
125
125
  options: [
126
126
  { value: "supabase", label: "Supabase" },
127
- { value: "firebase", label: "Firebase" }
127
+ { value: "firebase", label: "Firebase" },
128
+ { value: "mongodb", label: "MongoDB (Custom Auth)" }
128
129
  ]
129
130
  });
130
131
  if (p.isCancel(authProvider)) throw new Error("cancelled");
@@ -132,7 +133,8 @@ Re-run with @latest to refresh:
132
133
  message: "Database backend",
133
134
  options: [
134
135
  { value: "supabase", label: "Supabase Postgres" },
135
- { value: "firebase", label: "Firestore" }
136
+ { value: "firebase", label: "Firestore" },
137
+ { value: "mongodb", label: "MongoDB" }
136
138
  ],
137
139
  initialValue: authProvider
138
140
  });
@@ -143,6 +145,7 @@ Re-run with @latest to refresh:
143
145
  { value: "supabase", label: "Supabase Storage" },
144
146
  { value: "firebase", label: "Firebase Cloud Storage" },
145
147
  { value: "cloudinary", label: "Cloudinary" },
148
+ { value: "mongodb", label: "MongoDB GridFS" },
146
149
  { value: "none", label: "None \u2014 skip the upload microservice" }
147
150
  ]
148
151
  });
@@ -233,41 +236,14 @@ Re-run with @latest to refresh:
233
236
  }
234
237
 
235
238
  // src/lib/scaffold.ts
236
- import { copyFile, mkdir, readdir, readFile as readFile2, stat, writeFile, rm } from "fs/promises";
239
+ import { copyFile, mkdir as mkdir2, readdir as readdir2, readFile as readFile5, stat, writeFile as writeFile4, rm as rm2 } from "fs/promises";
237
240
  import { readFileSync } from "fs";
238
- import { join as join2 } from "path";
241
+ import { join as join5 } from "path";
239
242
  import { spawnSync } from "child_process";
240
243
 
241
- // src/lib/options.ts
242
- function pmRun(pm, script) {
243
- return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
244
- }
245
-
246
- // src/lib/scaffold.ts
247
- var IGNORE_TOP = /* @__PURE__ */ new Set([
248
- ".git",
249
- "node_modules",
250
- ".yarn/cache",
251
- ".yarn/unplugged",
252
- ".yarn/install-state.gz",
253
- ".nx",
254
- "dist",
255
- "tmp",
256
- "coverage",
257
- ".idea",
258
- ".vscode"
259
- ]);
260
- async function copyTree(src, dest) {
261
- await mkdir(dest, { recursive: true });
262
- const entries = await readdir(src, { withFileTypes: true });
263
- for (const entry of entries) {
264
- if (IGNORE_TOP.has(entry.name)) continue;
265
- const s = join2(src, entry.name);
266
- const d = join2(dest, entry.name);
267
- if (entry.isDirectory()) await copyTree(s, d);
268
- else if (entry.isFile()) await copyFile(s, d);
269
- }
270
- }
244
+ // src/lib/scaffold-env.ts
245
+ import { readFile as readFile2, writeFile } from "fs/promises";
246
+ import { join as join2 } from "path";
271
247
  var TRANSPORT_ENV_TOKEN = {
272
248
  redis: "REDIS",
273
249
  nats: "NATS",
@@ -281,11 +257,28 @@ var TRANSPORT_DEPS = {
281
257
  rmq: { amqplib: "^2.0.1", "amqp-connection-manager": "^5.0.0" },
282
258
  kafka: { kafkajs: "^2.2.4" }
283
259
  };
260
+ var MONGODB_DEPS = {
261
+ mongoose: "^9.6.3",
262
+ "@nestjs/mongoose": "^11.0.4",
263
+ bcrypt: "^6.0.0",
264
+ jsonwebtoken: "^9.0.3"
265
+ };
284
266
  function uncommentTransportEnv(text2, prefix, transport) {
285
267
  const token = TRANSPORT_ENV_TOKEN[transport];
286
268
  if (!token) return text2;
287
269
  return text2.replace(new RegExp(`^# (${prefix}_${token}_[A-Z0-9_]*=)`, "gm"), "$1");
288
270
  }
271
+ async function stripGatewayTransport(targetDir, prefix) {
272
+ const gatewayEnv = join2(targetDir, "apps/api/.env");
273
+ try {
274
+ const env = await readFile2(gatewayEnv, "utf8");
275
+ const next = env.split("\n").filter(
276
+ (line) => !line.startsWith(`${prefix}_`) && !line.startsWith(`# ${prefix}_`) && !line.includes(`${prefix} MS transport`)
277
+ ).join("\n");
278
+ await writeFile(gatewayEnv, next);
279
+ } catch {
280
+ }
281
+ }
289
282
  async function rewriteRootPackageJson(targetDir, opts) {
290
283
  const pkgPath = join2(targetDir, "package.json");
291
284
  const raw = await readFile2(pkgPath, "utf8");
@@ -299,6 +292,10 @@ async function rewriteRootPackageJson(targetDir, opts) {
299
292
  const deps = pkg["dependencies"] ??= {};
300
293
  Object.assign(deps, transportDeps);
301
294
  }
295
+ if (opts.authProvider === "mongodb" || opts.dbProvider === "mongodb" || opts.upload === "mongodb") {
296
+ const deps = pkg["dependencies"] ??= {};
297
+ Object.assign(deps, MONGODB_DEPS);
298
+ }
302
299
  if (opts.packageManager !== "yarn") {
303
300
  delete pkg.packageManager;
304
301
  } else {
@@ -319,6 +316,9 @@ async function writeAuthEnv(targetDir, opts) {
319
316
  const env = await readFile2(envExample, "utf8");
320
317
  let next = env.replace(/^AUTH_PROVIDER=.*$/m, `AUTH_PROVIDER=${opts.authProvider}`).replace(/^AUTH_TRANSPORT=.*$/m, `AUTH_TRANSPORT=${opts.transport}`);
321
318
  next = uncommentTransportEnv(next, "AUTH", opts.transport);
319
+ if (opts.authProvider === "mongodb") {
320
+ next += "\nMONGODB_URI=mongodb://localhost:27017/icore-auth\nJWT_SECRET=change-me-in-production\n";
321
+ }
322
322
  await writeFile(join2(targetDir, "apps/microservices/auth/.env"), next);
323
323
  }
324
324
  async function writeUploadEnv(targetDir, opts) {
@@ -327,6 +327,9 @@ async function writeUploadEnv(targetDir, opts) {
327
327
  const env = await readFile2(envExample, "utf8");
328
328
  let next = env.replace(/^STORAGE_PROVIDER=.*$/m, `STORAGE_PROVIDER=${opts.upload}`).replace(/^UPLOAD_TRANSPORT=.*$/m, `UPLOAD_TRANSPORT=${opts.transport}`);
329
329
  next = uncommentTransportEnv(next, "UPLOAD", opts.transport);
330
+ if (opts.upload === "mongodb") {
331
+ next += "\nMONGODB_URI=mongodb://localhost:27017/icore-upload\n";
332
+ }
330
333
  await writeFile(join2(targetDir, "apps/microservices/upload/.env"), next);
331
334
  }
332
335
  async function writeNotesEnv(targetDir, opts) {
@@ -356,18 +359,11 @@ async function writeRootEnv(targetDir, opts) {
356
359
  `DB_PROVIDER=${opts.dbProvider}`,
357
360
  ``
358
361
  ];
359
- await writeFile(join2(targetDir, ".env"), lines.join("\n"));
360
- }
361
- async function stripGatewayTransport(targetDir, prefix) {
362
- const gatewayEnv = join2(targetDir, "apps/api/.env");
363
- try {
364
- const env = await readFile2(gatewayEnv, "utf8");
365
- const next = env.split("\n").filter(
366
- (line) => !line.startsWith(`${prefix}_`) && !line.startsWith(`# ${prefix}_`) && !line.includes(`${prefix} MS transport`)
367
- ).join("\n");
368
- await writeFile(gatewayEnv, next);
369
- } catch {
362
+ if (opts.dbProvider === "mongodb") {
363
+ lines.push(`MONGODB_URI=mongodb://localhost:27017/icore-data`);
364
+ lines.push(``);
370
365
  }
366
+ await writeFile(join2(targetDir, ".env"), lines.join("\n"));
371
367
  }
372
368
  async function writeClientEnv(targetDir) {
373
369
  const envExample = join2(targetDir, "apps/client/.env.example");
@@ -388,15 +384,37 @@ async function writePaymentEnv(targetDir, opts) {
388
384
  } catch {
389
385
  }
390
386
  }
387
+
388
+ // src/lib/scaffold-strip.ts
389
+ import { readFile as readFile3, writeFile as writeFile2, rm } from "fs/promises";
390
+ import { join as join3 } from "path";
391
391
  async function stripDeps(pkgPath, names) {
392
392
  try {
393
- const raw = await readFile2(pkgPath, "utf8");
393
+ const raw = await readFile3(pkgPath, "utf8");
394
394
  const pkg = JSON.parse(raw);
395
395
  for (const n of names) {
396
396
  if (pkg.dependencies) delete pkg.dependencies[n];
397
397
  if (pkg.devDependencies) delete pkg.devDependencies[n];
398
398
  }
399
- await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
399
+ await writeFile2(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
400
+ } catch {
401
+ }
402
+ }
403
+ async function stripTsconfigPath(targetDir, alias) {
404
+ const tsconfigPath = join3(targetDir, "tsconfig.base.json");
405
+ try {
406
+ const src = await readFile3(tsconfigPath, "utf8");
407
+ const escaped = alias.replace(/[@/]/g, (c) => c === "@" ? "@" : "\\/");
408
+ const pretty = src.replace(new RegExp(`^\\s*"${escaped}": \\[[^\\]]*\\],?\\n`, "m"), "");
409
+ if (pretty !== src) {
410
+ await writeFile2(tsconfigPath, pretty);
411
+ return;
412
+ }
413
+ const parsed = JSON.parse(src);
414
+ if (parsed.compilerOptions?.paths) {
415
+ delete parsed.compilerOptions.paths[alias];
416
+ }
417
+ await writeFile2(tsconfigPath, JSON.stringify(parsed));
400
418
  } catch {
401
419
  }
402
420
  }
@@ -408,25 +426,25 @@ async function removeJobsStack(targetDir) {
408
426
  "Dockerfile.ms-jobs"
409
427
  ];
410
428
  for (const p3 of paths) {
411
- await rm(join2(targetDir, p3), { recursive: true, force: true });
429
+ await rm(join3(targetDir, p3), { recursive: true, force: true });
412
430
  }
413
- const appModulePath = join2(targetDir, "apps/api/src/app/app.module.ts");
431
+ const appModulePath = join3(targetDir, "apps/api/src/app/app.module.ts");
414
432
  try {
415
- const appModule = await readFile2(appModulePath, "utf8");
433
+ const appModule = await readFile3(appModulePath, "utf8");
416
434
  const next = appModule.replace(/^import \{ AdminModule \} from '\.\/admin\/admin\.module';\n/m, "").replace(/,\s*AdminModule/g, "");
417
- await writeFile(appModulePath, next);
435
+ await writeFile2(appModulePath, next);
418
436
  } catch {
419
437
  }
420
- await stripDeps(join2(targetDir, "apps/api/package.json"), [
438
+ await stripDeps(join3(targetDir, "apps/api/package.json"), [
421
439
  "@icore/jobs-client",
422
440
  "@bull-board/api",
423
441
  "@bull-board/express"
424
442
  ]);
425
- const composePath = join2(targetDir, "docker-compose.yml");
443
+ const composePath = join3(targetDir, "docker-compose.yml");
426
444
  try {
427
- const compose = await readFile2(composePath, "utf8");
445
+ const compose = await readFile3(composePath, "utf8");
428
446
  const next = compose.replace(/\n {2}jobs:[\s\S]+?(?=\n {2}\w+:|\nnetworks:)/m, "\n").replace(/\n {6}jobs:\n {8}condition: service_started/g, "").replace(/\n {6}JOBS_REDIS_URL:[^\n]*/g, "");
429
- await writeFile(composePath, next);
447
+ await writeFile2(composePath, next);
430
448
  } catch {
431
449
  }
432
450
  }
@@ -438,25 +456,25 @@ async function removePaymentStack(targetDir) {
438
456
  "apps/api/src/app/payment"
439
457
  ];
440
458
  for (const p3 of paths) {
441
- await rm(join2(targetDir, p3), { recursive: true, force: true });
459
+ await rm(join3(targetDir, p3), { recursive: true, force: true });
442
460
  }
443
- const appModulePath = join2(targetDir, "apps/api/src/app/app.module.ts");
461
+ const appModulePath = join3(targetDir, "apps/api/src/app/app.module.ts");
444
462
  try {
445
- const appModule = await readFile2(appModulePath, "utf8");
463
+ const appModule = await readFile3(appModulePath, "utf8");
446
464
  const next = appModule.replace(/^import \{ PaymentModule \} from '\.\/payment\/payment\.module';\n/m, "").replace(/,\s*PaymentModule/g, "");
447
- await writeFile(appModulePath, next);
465
+ await writeFile2(appModulePath, next);
448
466
  } catch {
449
467
  }
450
- await stripDeps(join2(targetDir, "apps/api/package.json"), [
468
+ await stripDeps(join3(targetDir, "apps/api/package.json"), [
451
469
  "@icore/payment-client",
452
470
  "@idevconn/payment"
453
471
  ]);
454
472
  await stripGatewayTransport(targetDir, "PAYMENT");
455
- const mainTsPath = join2(targetDir, "apps/api/src/main.ts");
473
+ const mainTsPath = join3(targetDir, "apps/api/src/main.ts");
456
474
  try {
457
- const src = await readFile2(mainTsPath, "utf8");
475
+ const src = await readFile3(mainTsPath, "utf8");
458
476
  const next = src.replace(/\n\s*\{ name: 'payment', prefix: 'PAYMENT' \},/, "");
459
- await writeFile(mainTsPath, next);
477
+ await writeFile2(mainTsPath, next);
460
478
  } catch {
461
479
  }
462
480
  }
@@ -468,39 +486,39 @@ async function removeNotesStack(targetDir) {
468
486
  "apps/api/src/app/notes",
469
487
  "apps/client/src/components/notes"
470
488
  ]) {
471
- await rm(join2(targetDir, p3), { recursive: true, force: true });
489
+ await rm(join3(targetDir, p3), { recursive: true, force: true });
472
490
  }
473
- await rm(join2(targetDir, "apps/client/src/routes/_dashboard/notes.tsx"), { force: true });
474
- await rm(join2(targetDir, "apps/client/src/queries/notes.ts"), { force: true });
475
- const appModulePath = join2(targetDir, "apps/api/src/app/app.module.ts");
491
+ await rm(join3(targetDir, "apps/client/src/routes/_dashboard/notes.tsx"), { force: true });
492
+ await rm(join3(targetDir, "apps/client/src/queries/notes.ts"), { force: true });
493
+ const appModulePath = join3(targetDir, "apps/api/src/app/app.module.ts");
476
494
  try {
477
- const src = await readFile2(appModulePath, "utf8");
495
+ const src = await readFile3(appModulePath, "utf8");
478
496
  const next = src.replace(/^import \{ NotesModule \} from '\.\/notes\/notes\.module';\n/m, "").replace(/,\s*NotesModule/g, "");
479
- await writeFile(appModulePath, next);
497
+ await writeFile2(appModulePath, next);
480
498
  } catch {
481
499
  }
482
- await stripDeps(join2(targetDir, "apps/api/package.json"), [
500
+ await stripDeps(join3(targetDir, "apps/api/package.json"), [
483
501
  "@icore/notes-client",
484
502
  "@casl/ability"
485
503
  ]);
486
504
  await stripGatewayTransport(targetDir, "NOTES");
487
- const mainTsPath = join2(targetDir, "apps/api/src/main.ts");
505
+ const mainTsPath = join3(targetDir, "apps/api/src/main.ts");
488
506
  try {
489
- const src = await readFile2(mainTsPath, "utf8");
507
+ const src = await readFile3(mainTsPath, "utf8");
490
508
  const next = src.replace(/\n\s*\{ name: 'notes', prefix: 'NOTES' \},/, "");
491
- await writeFile(mainTsPath, next);
509
+ await writeFile2(mainTsPath, next);
492
510
  } catch {
493
511
  }
494
- const tsconfigPath = join2(targetDir, "tsconfig.base.json");
512
+ const tsconfigPath = join3(targetDir, "tsconfig.base.json");
495
513
  try {
496
- const src = await readFile2(tsconfigPath, "utf8");
514
+ const src = await readFile3(tsconfigPath, "utf8");
497
515
  const next = src.replace(/^\s*"@icore\/notes-client": \[[^\]]*\],?\n/m, "");
498
- await writeFile(tsconfigPath, next);
516
+ await writeFile2(tsconfigPath, next);
499
517
  } catch {
500
518
  }
501
- const siderPath = join2(targetDir, "apps/client/src/components/layout/LayoutSider.tsx");
519
+ const siderPath = join3(targetDir, "apps/client/src/components/layout/LayoutSider.tsx");
502
520
  try {
503
- const src = await readFile2(siderPath, "utf8");
521
+ const src = await readFile3(siderPath, "utf8");
504
522
  const next = src.replace(", StickyNote", "").replace(/\n {8}<Link\n {10}to="\/(?:_dashboard\/)?notes"[\s\S]*?<\/Link>/, "").replace(", FileTextOutlined", "").replace(
505
523
  "const selectedKey = pathname.includes('/notes')\n ? 'notes'\n : pathname.includes('/profile')",
506
524
  "const selectedKey = pathname.includes('/profile')"
@@ -511,159 +529,213 @@ async function removeNotesStack(targetDir) {
511
529
  /\n {8}<ListItemButton\n {10}component=\{Link\}\n {10}to="\/(?:_dashboard\/)?notes"[\s\S]*?<\/ListItemButton>/,
512
530
  ""
513
531
  ).replace(/\n\s*<Link to="\/(?:_dashboard\/)?notes">[\s\S]*?<\/Link>/m, "");
514
- await writeFile(siderPath, next);
532
+ await writeFile2(siderPath, next);
515
533
  } catch {
516
534
  }
517
- const keysPath = join2(targetDir, "libs/template-shared/src/lib/i18n/keys.ts");
535
+ const keysPath = join3(targetDir, "libs/template-shared/src/lib/i18n/keys.ts");
518
536
  try {
519
- const src = await readFile2(keysPath, "utf8");
537
+ const src = await readFile3(keysPath, "utf8");
520
538
  const next = src.replace(/^\s{4}notes: \{\n(?:\s+.*\n)*?\s{4}\},\n/m, "");
521
- await writeFile(keysPath, next);
522
- } catch {
523
- }
524
- }
525
- async function stripTsconfigPath(targetDir, alias) {
526
- const tsconfigPath = join2(targetDir, "tsconfig.base.json");
527
- try {
528
- const src = await readFile2(tsconfigPath, "utf8");
529
- const escaped = alias.replace(/[@/]/g, (c) => c === "@" ? "@" : "\\/");
530
- const pretty = src.replace(new RegExp(`^\\s*"${escaped}": \\[[^\\]]*\\],?\\n`, "m"), "");
531
- if (pretty !== src) {
532
- await writeFile(tsconfigPath, pretty);
533
- return;
534
- }
535
- const parsed = JSON.parse(src);
536
- if (parsed.compilerOptions?.paths) {
537
- delete parsed.compilerOptions.paths[alias];
538
- }
539
- await writeFile(tsconfigPath, JSON.stringify(parsed));
539
+ await writeFile2(keysPath, next);
540
540
  } catch {
541
541
  }
542
542
  }
543
543
  async function removeUnusedAuthStrategies(targetDir, authProvider) {
544
- const modulePath = join2(targetDir, "apps/microservices/auth/src/app/app.module.ts");
545
- const AUTH_BRANCH = /if \(provider === 'supabase'\) return makeSupabaseAuth\(cfg\);\n\s*return makeFirebaseAuth\(cfg\);/m;
544
+ const modulePath = join3(targetDir, "apps/microservices/auth/src/app/app.module.ts");
545
+ const AUTH_BRANCH = /if \(provider === 'supabase'\) return makeSupabaseAuth\(cfg\);\n\s*if \(provider === 'mongodb'\) return makeMongoDbAuth\(connection, cfg\);\n\s*return makeFirebaseAuth\(cfg\);/m;
546
546
  if (authProvider === "supabase") {
547
- await rm(join2(targetDir, "libs/auth-strategies/firebase"), { recursive: true, force: true });
548
- await stripDeps(join2(targetDir, "apps/microservices/auth/package.json"), [
547
+ await rm(join3(targetDir, "libs/auth-strategies/firebase"), { recursive: true, force: true });
548
+ await rm(join3(targetDir, "libs/auth-strategies/mongodb"), { recursive: true, force: true });
549
+ await stripDeps(join3(targetDir, "apps/microservices/auth/package.json"), [
549
550
  "@icore/auth-firebase",
550
- "@icore/firebase-admin"
551
+ "@icore/firebase-admin",
552
+ "@icore/auth-mongodb"
551
553
  ]);
552
554
  await stripTsconfigPath(targetDir, "@icore/auth-firebase");
555
+ await stripTsconfigPath(targetDir, "@icore/auth-mongodb");
553
556
  try {
554
- const src = await readFile2(modulePath, "utf8");
555
- const next = src.replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/m, "").replace(/^import \{[^}]*FirebaseAuthStrategy[^}]*\} from '@icore\/auth-firebase';\n/m, "").replace(/^ {2}firebase: \[[^\]]*\],\n/m, "").replace(/\nfunction makeFirebaseAuth[\s\S]*?\n}\n/m, "").replace(AUTH_BRANCH, "return makeSupabaseAuth(cfg);");
556
- await writeFile(modulePath, next);
557
+ const src = await readFile3(modulePath, "utf8");
558
+ const next = src.replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/gm, "").replace(/^import \{[^}]*FirebaseAuthStrategy[^}]*\} from '@icore\/auth-firebase';\n/gm, "").replace(/^import \{[^}]*MongoDbAuthStrategy[^}]*\} from '@icore\/auth-mongodb';\n/gm, "").replace(
559
+ /^import \{ MongooseModule, getConnectionToken \} from '@nestjs\/mongoose';\n/gm,
560
+ ""
561
+ ).replace(/^import \{ Connection \} from 'mongoose';\n/gm, "").replace(/^ {2}firebase: \[[^\]]*\],\n/gm, "").replace(/^ {2}mongodb: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeFirebaseAuth[\s\S]*?\n}\n/gm, "").replace(/\nfunction makeMongoDbAuth[\s\S]*?\n}\n/gm, "").replace(/^ {4}MongooseModule\.forRootAsync[\s\S]*?\n {4}\}\),\n/gm, "").replace(AUTH_BRANCH, "return makeSupabaseAuth(cfg);").replace(/, connection: Connection/, "").replace(/, getConnectionToken\(\)/, "");
562
+ await writeFile2(modulePath, next);
557
563
  } catch {
558
564
  }
559
565
  }
560
566
  if (authProvider === "firebase") {
561
- await rm(join2(targetDir, "libs/auth-strategies/supabase"), { recursive: true, force: true });
562
- await stripDeps(join2(targetDir, "apps/microservices/auth/package.json"), [
563
- "@icore/auth-supabase"
567
+ await rm(join3(targetDir, "libs/auth-strategies/supabase"), { recursive: true, force: true });
568
+ await rm(join3(targetDir, "libs/auth-strategies/mongodb"), { recursive: true, force: true });
569
+ await stripDeps(join3(targetDir, "apps/microservices/auth/package.json"), [
570
+ "@icore/auth-supabase",
571
+ "@icore/auth-mongodb"
572
+ ]);
573
+ await stripTsconfigPath(targetDir, "@icore/auth-supabase");
574
+ await stripTsconfigPath(targetDir, "@icore/auth-mongodb");
575
+ try {
576
+ const src = await readFile3(modulePath, "utf8");
577
+ const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/gm, "").replace(/^import \{[^}]*SupabaseAuthStrategy[^}]*\} from '@icore\/auth-supabase';\n/gm, "").replace(/^import \{[^}]*MongoDbAuthStrategy[^}]*\} from '@icore\/auth-mongodb';\n/gm, "").replace(
578
+ /^import \{ MongooseModule, getConnectionToken \} from '@nestjs\/mongoose';\n/gm,
579
+ ""
580
+ ).replace(/^import \{ Connection \} from 'mongoose';\n/gm, "").replace(/^ {2}supabase: \[[^\]]*\],\n/gm, "").replace(/^ {2}mongodb: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeSupabaseAuth[\s\S]*?\n}\n/gm, "").replace(/\nfunction makeMongoDbAuth[\s\S]*?\n}\n/gm, "").replace(/^ {4}MongooseModule\.forRootAsync[\s\S]*?\n {4}\}\),\n/gm, "").replace(AUTH_BRANCH, "return makeFirebaseAuth(cfg);").replace(/, connection: Connection/, "").replace(/, getConnectionToken\(\)/, "");
581
+ await writeFile2(modulePath, next);
582
+ } catch {
583
+ }
584
+ }
585
+ if (authProvider === "mongodb") {
586
+ await rm(join3(targetDir, "libs/auth-strategies/supabase"), { recursive: true, force: true });
587
+ await rm(join3(targetDir, "libs/auth-strategies/firebase"), { recursive: true, force: true });
588
+ await stripDeps(join3(targetDir, "apps/microservices/auth/package.json"), [
589
+ "@icore/auth-supabase",
590
+ "@icore/auth-firebase",
591
+ "@icore/firebase-admin"
564
592
  ]);
565
593
  await stripTsconfigPath(targetDir, "@icore/auth-supabase");
594
+ await stripTsconfigPath(targetDir, "@icore/auth-firebase");
566
595
  try {
567
- const src = await readFile2(modulePath, "utf8");
568
- const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/m, "").replace(/^import \{[^}]*SupabaseAuthStrategy[^}]*\} from '@icore\/auth-supabase';\n/m, "").replace(/\nfunction makeSupabaseAuth[\s\S]*?\n}\n/m, "").replace(AUTH_BRANCH, "return makeFirebaseAuth(cfg);");
569
- await writeFile(modulePath, next);
596
+ const src = await readFile3(modulePath, "utf8");
597
+ const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/gm, "").replace(/^import \{[^}]*SupabaseAuthStrategy[^}]*\} from '@icore\/auth-supabase';\n/gm, "").replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/gm, "").replace(/^import \{[^}]*FirebaseAuthStrategy[^}]*\} from '@icore\/auth-firebase';\n/gm, "").replace(/^ {2}supabase: \[[^\]]*\],\n/gm, "").replace(/^ {2}firebase: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeSupabaseAuth[\s\S]*?\n}\n/gm, "").replace(/\nfunction makeFirebaseAuth[\s\S]*?\n}\n/gm, "").replace(AUTH_BRANCH, "return makeMongoDbAuth(connection, cfg);");
598
+ await writeFile2(modulePath, next);
570
599
  } catch {
571
600
  }
572
601
  }
573
602
  }
574
603
  async function removeUnusedStorageStrategies(targetDir, uploadProvider) {
575
604
  if (uploadProvider === "none") return;
576
- const modulePath = join2(targetDir, "apps/microservices/upload/src/app/app.module.ts");
605
+ const modulePath = join3(targetDir, "apps/microservices/upload/src/app/app.module.ts");
606
+ const STORAGE_BRANCH = /if \(provider === 'supabase'\) return makeSupabaseStorage\(cfg\);\n\s*if \(provider === 'firebase'\) return makeFirebaseStorage\(cfg\);\n\s*if \(provider === 'mongodb'\) return makeMongoDbStorage\(connection\);\n\s*return makeCloudinaryStorage\(cfg\);/m;
577
607
  if (uploadProvider !== "firebase") {
578
- await rm(join2(targetDir, "libs/storage-strategies/firebase"), { recursive: true, force: true });
579
- await stripDeps(join2(targetDir, "apps/microservices/upload/package.json"), [
608
+ await rm(join3(targetDir, "libs/storage-strategies/firebase"), { recursive: true, force: true });
609
+ await stripDeps(join3(targetDir, "apps/microservices/upload/package.json"), [
580
610
  "@icore/storage-firebase",
581
611
  "@icore/firebase-admin"
582
612
  ]);
583
613
  await stripTsconfigPath(targetDir, "@icore/storage-firebase");
584
614
  }
585
615
  if (uploadProvider !== "cloudinary") {
586
- await rm(join2(targetDir, "libs/storage-strategies/cloudinary"), {
616
+ await rm(join3(targetDir, "libs/storage-strategies/cloudinary"), {
587
617
  recursive: true,
588
618
  force: true
589
619
  });
590
- await stripDeps(join2(targetDir, "apps/microservices/upload/package.json"), [
620
+ await stripDeps(join3(targetDir, "apps/microservices/upload/package.json"), [
591
621
  "@icore/storage-cloudinary"
592
622
  ]);
593
623
  await stripTsconfigPath(targetDir, "@icore/storage-cloudinary");
594
624
  }
595
625
  if (uploadProvider !== "supabase") {
596
- await rm(join2(targetDir, "libs/storage-strategies/supabase"), { recursive: true, force: true });
597
- await stripDeps(join2(targetDir, "apps/microservices/upload/package.json"), [
626
+ await rm(join3(targetDir, "libs/storage-strategies/supabase"), { recursive: true, force: true });
627
+ await stripDeps(join3(targetDir, "apps/microservices/upload/package.json"), [
598
628
  "@icore/storage-supabase"
599
629
  ]);
600
630
  await stripTsconfigPath(targetDir, "@icore/storage-supabase");
601
631
  }
632
+ if (uploadProvider !== "mongodb") {
633
+ await rm(join3(targetDir, "libs/storage-strategies/mongodb"), { recursive: true, force: true });
634
+ await stripDeps(join3(targetDir, "apps/microservices/upload/package.json"), [
635
+ "@icore/storage-mongodb"
636
+ ]);
637
+ await stripTsconfigPath(targetDir, "@icore/storage-mongodb");
638
+ }
602
639
  try {
603
- let src = await readFile2(modulePath, "utf8");
640
+ let src = await readFile3(modulePath, "utf8");
604
641
  if (uploadProvider !== "firebase") {
605
- src = src.replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/m, "").replace(
606
- /^import \{[^}]*FirebaseStorageStrategy[^}]*\} from '@icore\/storage-firebase';\n/m,
642
+ src = src.replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/gm, "").replace(
643
+ /^import \{[^}]*FirebaseStorageStrategy[^}]*\} from '@icore\/storage-firebase';\n/gm,
607
644
  ""
608
- ).replace(/^ {2}firebase: \[[^\]]*\],\n/m, "").replace(/\nfunction makeFirebaseStorage[\s\S]*?\n}\n/m, "");
645
+ ).replace(/^ {2}firebase: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeFirebaseStorage[\s\S]*?\n}\n/gm, "");
609
646
  }
610
647
  if (uploadProvider !== "cloudinary") {
611
- src = src.replace(/^import \{ v2 as cloudinary \} from 'cloudinary';\n/m, "").replace(
612
- /^import \{[^}]*CloudinaryStorageStrategy[^}]*\} from '@icore\/storage-cloudinary';\n/m,
648
+ src = src.replace(/^import \{ v2 as cloudinary \} from 'cloudinary';\n/gm, "").replace(
649
+ /^import \{[^}]*CloudinaryStorageStrategy[^}]*\} from '@icore\/storage-cloudinary';\n/gm,
613
650
  ""
614
- ).replace(/\nfunction makeCloudinaryStorage[\s\S]*?\n}\n/m, "");
651
+ ).replace(/\nfunction makeCloudinaryStorage[\s\S]*?\n}\n/gm, "");
615
652
  }
616
653
  if (uploadProvider !== "supabase") {
617
- src = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/m, "").replace(
618
- /^import \{[^}]*SupabaseStorageStrategy[^}]*\} from '@icore\/storage-supabase';\n/m,
654
+ src = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/gm, "").replace(
655
+ /^import \{[^}]*SupabaseStorageStrategy[^}]*\} from '@icore\/storage-supabase';\n/gm,
619
656
  ""
620
- ).replace(/\nfunction makeSupabaseStorage[\s\S]*?\n}\n/m, "");
657
+ ).replace(/\nfunction makeSupabaseStorage[\s\S]*?\n}\n/gm, "");
621
658
  }
622
- const STORAGE_BRANCH = /if \(provider === 'supabase'\) return makeSupabaseStorage\(cfg\);\n\s*if \(provider === 'firebase'\) return makeFirebaseStorage\(cfg\);\n\s*return makeCloudinaryStorage\(cfg\);/m;
623
- const chosenReturn = `return make${uploadProvider.charAt(0).toUpperCase() + uploadProvider.slice(1)}Storage(cfg);`;
659
+ if (uploadProvider !== "mongodb") {
660
+ src = src.replace(
661
+ /^import \{[^}]*MongoDbStorageStrategy[^}]*\} from '@icore\/storage-mongodb';\n/gm,
662
+ ""
663
+ ).replace(
664
+ /^import \{ MongooseModule, getConnectionToken \} from '@nestjs\/mongoose';\n/gm,
665
+ ""
666
+ ).replace(/^import \{ Connection \} from 'mongoose';\n/gm, "").replace(/^ {2}mongodb: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeMongoDbStorage[\s\S]*?\n}\n/gm, "").replace(/^ {4}MongooseModule\.forRootAsync[\s\S]*?\n {4}\}\),\n/gm, "");
667
+ }
668
+ const chosenReturn = uploadProvider === "mongodb" ? `return makeMongoDbStorage(connection);` : `return make${uploadProvider.charAt(0).toUpperCase() + uploadProvider.slice(1)}Storage(cfg);`;
624
669
  src = src.replace(STORAGE_BRANCH, chosenReturn);
625
- await writeFile(modulePath, src);
670
+ if (uploadProvider !== "mongodb") {
671
+ src = src.replace(/, connection: Connection/, "").replace(/, getConnectionToken\(\)/, "");
672
+ }
673
+ await writeFile2(modulePath, src);
626
674
  } catch {
627
675
  }
628
676
  }
629
677
  async function removeUnusedDbStrategies(targetDir, dbProvider) {
630
- const modulePath = join2(targetDir, "apps/microservices/notes/src/app/app.module.ts");
678
+ const modulePath = join3(targetDir, "apps/microservices/notes/src/app/app.module.ts");
679
+ const DB_BRANCH = /if \(provider === 'supabase'\) return makeSupabaseDB\(cfg\);\n\s*if \(provider === 'mongodb'\) return makeMongoDb\(connection\);\n\s*return makeFirestoreDB\(cfg\);/m;
631
680
  if (dbProvider === "supabase") {
632
- await rm(join2(targetDir, "libs/db-strategies/firestore"), { recursive: true, force: true });
633
- await stripDeps(join2(targetDir, "apps/microservices/notes/package.json"), [
681
+ await rm(join3(targetDir, "libs/db-strategies/firestore"), { recursive: true, force: true });
682
+ await rm(join3(targetDir, "libs/db-strategies/mongodb"), { recursive: true, force: true });
683
+ await stripDeps(join3(targetDir, "apps/microservices/notes/package.json"), [
634
684
  "@icore/db-firestore",
635
- "@icore/firebase-admin"
685
+ "@icore/firebase-admin",
686
+ "@icore/db-mongodb"
636
687
  ]);
637
688
  await stripTsconfigPath(targetDir, "@icore/db-firestore");
689
+ await stripTsconfigPath(targetDir, "@icore/db-mongodb");
638
690
  try {
639
- const src = await readFile2(modulePath, "utf8");
640
- const next = src.replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/m, "").replace(/^import \{[^}]*FirestoreDBStrategy[^}]*\} from '@icore\/db-firestore';\n/m, "").replace(/^ {2}firestore: \[[^\]]*\],\n/m, "").replace(/^ {2}firebase: \[[^\]]*\],\n/m, "").replace(/\nfunction makeFirestoreDB[\s\S]*?\n}\n/m, "").replace(
641
- /if \(provider === 'supabase'\) return makeSupabaseDB\(cfg\);\n\s*return makeFirestoreDB\(cfg\);/m,
642
- "return makeSupabaseDB(cfg);"
643
- );
644
- await writeFile(modulePath, next);
691
+ const src = await readFile3(modulePath, "utf8");
692
+ const next = src.replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/gm, "").replace(/^import \{[^}]*FirestoreDBStrategy[^}]*\} from '@icore\/db-firestore';\n/gm, "").replace(/^import \{[^}]*MongoDbDBStrategy[^}]*\} from '@icore\/db-mongodb';\n/gm, "").replace(
693
+ /^import \{ MongooseModule, getConnectionToken \} from '@nestjs\/mongoose';\n/gm,
694
+ ""
695
+ ).replace(/^import \{ Connection \} from 'mongoose';\n/gm, "").replace(/^ {2}firestore: \[[^\]]*\],\n/gm, "").replace(/^ {2}firebase: \[[^\]]*\],\n/gm, "").replace(/^ {2}mongodb: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeFirestoreDB[\s\S]*?\n}\n/gm, "").replace(/\nfunction makeMongoDb[\s\S]*?\n}\n/gm, "").replace(/^ {4}MongooseModule\.forRootAsync[\s\S]*?\n {4}\}\),\n/gm, "").replace(DB_BRANCH, "return makeSupabaseDB(cfg);").replace(/, connection: Connection/, "").replace(/, getConnectionToken\(\)/, "");
696
+ await writeFile2(modulePath, next);
645
697
  } catch {
646
698
  }
647
699
  }
648
700
  if (dbProvider === "firebase") {
649
- await rm(join2(targetDir, "libs/db-strategies/supabase"), { recursive: true, force: true });
650
- await stripDeps(join2(targetDir, "apps/microservices/notes/package.json"), [
651
- "@icore/db-supabase"
701
+ await rm(join3(targetDir, "libs/db-strategies/supabase"), { recursive: true, force: true });
702
+ await rm(join3(targetDir, "libs/db-strategies/mongodb"), { recursive: true, force: true });
703
+ await stripDeps(join3(targetDir, "apps/microservices/notes/package.json"), [
704
+ "@icore/db-supabase",
705
+ "@icore/db-mongodb"
652
706
  ]);
653
707
  await stripTsconfigPath(targetDir, "@icore/db-supabase");
708
+ await stripTsconfigPath(targetDir, "@icore/db-mongodb");
654
709
  try {
655
- const src = await readFile2(modulePath, "utf8");
656
- const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/m, "").replace(/^import \{[^}]*SupabaseDBStrategy[^}]*\} from '@icore\/db-supabase';\n/m, "").replace(/\nfunction makeSupabaseDB[\s\S]*?\n}\n/m, "").replace(/\nfunction requireEnv[\s\S]*?\n}\n/m, "").replace(
657
- /if \(provider === 'supabase'\) return makeSupabaseDB\(cfg\);\n\s*return makeFirestoreDB\(cfg\);/m,
658
- "return makeFirestoreDB(cfg);"
659
- );
660
- await writeFile(modulePath, next);
710
+ const src = await readFile3(modulePath, "utf8");
711
+ const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/gm, "").replace(/^import \{[^}]*SupabaseDBStrategy[^}]*\} from '@icore\/db-supabase';\n/gm, "").replace(/^import \{[^}]*MongoDbDBStrategy[^}]*\} from '@icore\/db-mongodb';\n/gm, "").replace(
712
+ /^import \{ MongooseModule, getConnectionToken \} from '@nestjs\/mongoose';\n/gm,
713
+ ""
714
+ ).replace(/^import \{ Connection \} from 'mongoose';\n/gm, "").replace(/^ {2}supabase: \[[^\]]*\],\n/gm, "").replace(/^ {2}mongodb: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeSupabaseDB[\s\S]*?\n}\n/gm, "").replace(/\nfunction makeMongoDb[\s\S]*?\n}\n/gm, "").replace(/^ {4}MongooseModule\.forRootAsync[\s\S]*?\n {4}\}\),\n/gm, "").replace(/\nfunction requireEnv[\s\S]*?\n}\n/gm, "").replace(DB_BRANCH, "return makeFirestoreDB(cfg);").replace(/, connection: Connection/, "").replace(/, getConnectionToken\(\)/, "");
715
+ await writeFile2(modulePath, next);
716
+ } catch {
717
+ }
718
+ }
719
+ if (dbProvider === "mongodb") {
720
+ await rm(join3(targetDir, "libs/db-strategies/supabase"), { recursive: true, force: true });
721
+ await rm(join3(targetDir, "libs/db-strategies/firestore"), { recursive: true, force: true });
722
+ await stripDeps(join3(targetDir, "apps/microservices/notes/package.json"), [
723
+ "@icore/db-supabase",
724
+ "@icore/db-firestore",
725
+ "@icore/firebase-admin"
726
+ ]);
727
+ await stripTsconfigPath(targetDir, "@icore/db-supabase");
728
+ await stripTsconfigPath(targetDir, "@icore/db-firestore");
729
+ try {
730
+ const src = await readFile3(modulePath, "utf8");
731
+ const next = src.replace(/^import \{ createClient \} from '@supabase\/supabase-js';\n/gm, "").replace(/^import \{[^}]*SupabaseDBStrategy[^}]*\} from '@icore\/db-supabase';\n/gm, "").replace(/^import \{[^}]*\} from '@icore\/firebase-admin';\n/gm, "").replace(/^import \{[^}]*FirestoreDBStrategy[^}]*\} from '@icore\/db-firestore';\n/gm, "").replace(/^ {2}supabase: \[[^\]]*\],\n/gm, "").replace(/^ {2}firestore: \[[^\]]*\],\n/gm, "").replace(/^ {2}firebase: \[[^\]]*\],\n/gm, "").replace(/\nfunction makeSupabaseDB[\s\S]*?\n}\n/gm, "").replace(/\nfunction makeFirestoreDB[\s\S]*?\n}\n/gm, "").replace(/\nfunction requireEnv[\s\S]*?\n}\n/gm, "").replace(DB_BRANCH, "return makeMongoDb(connection);");
732
+ await writeFile2(modulePath, next);
661
733
  } catch {
662
734
  }
663
735
  }
664
736
  }
665
737
  async function removeFirebaseAdminLib(targetDir) {
666
- await rm(join2(targetDir, "libs/firebase-admin"), { recursive: true, force: true });
738
+ await rm(join3(targetDir, "libs/firebase-admin"), { recursive: true, force: true });
667
739
  await stripTsconfigPath(targetDir, "@icore/firebase-admin");
668
740
  }
669
741
  async function removeUploadStack(targetDir) {
@@ -675,129 +747,43 @@ async function removeUploadStack(targetDir) {
675
747
  "apps/api/src/app/storage"
676
748
  ];
677
749
  for (const p3 of paths) {
678
- await rm(join2(targetDir, p3), { recursive: true, force: true });
750
+ await rm(join3(targetDir, p3), { recursive: true, force: true });
679
751
  }
680
- const appModulePath = join2(targetDir, "apps/api/src/app/app.module.ts");
752
+ const appModulePath = join3(targetDir, "apps/api/src/app/app.module.ts");
681
753
  try {
682
- const appModule = await readFile2(appModulePath, "utf8");
754
+ const appModule = await readFile3(appModulePath, "utf8");
683
755
  const next = appModule.replace(/^import \{ StorageModule \} from '\.\/storage\/storage\.module';\n/m, "").replace(/,\s*StorageModule/g, "");
684
- await writeFile(appModulePath, next);
756
+ await writeFile2(appModulePath, next);
685
757
  } catch {
686
758
  }
687
- const gatewayEnv = join2(targetDir, "apps/api/.env");
759
+ const gatewayEnv = join3(targetDir, "apps/api/.env");
688
760
  try {
689
- const env = await readFile2(gatewayEnv, "utf8");
761
+ const env = await readFile3(gatewayEnv, "utf8");
690
762
  const next = env.split("\n").filter(
691
763
  (line) => !line.startsWith("UPLOAD_") && !line.startsWith("# UPLOAD_") && !line.startsWith("MAX_FILE_SIZE_KB")
692
764
  ).join("\n");
693
- await writeFile(gatewayEnv, next);
765
+ await writeFile2(gatewayEnv, next);
694
766
  } catch {
695
767
  }
696
- await stripDeps(join2(targetDir, "apps/api/package.json"), [
768
+ await stripDeps(join3(targetDir, "apps/api/package.json"), [
697
769
  "@icore/upload-client",
698
770
  "@types/multer"
699
771
  ]);
700
772
  }
701
- async function selectClientTemplate(targetDir, opts) {
702
- const templatesRoot = join2(targetDir, "apps/templates");
703
- const chosen = join2(templatesRoot, `client-${opts.ui}`);
704
- const destClient = join2(targetDir, "apps/client");
705
- let chosenUi = opts.ui;
706
- try {
707
- const s = await stat(chosen);
708
- if (!s.isDirectory()) throw new Error("not a dir");
709
- await copyTree(chosen, destClient);
710
- } catch {
711
- chosenUi = "shadcn";
712
- await copyTree(join2(templatesRoot, "client-shadcn"), destClient);
713
- }
714
- await rm(templatesRoot, { recursive: true, force: true });
715
- await rewriteClientPaths(destClient, chosenUi);
716
- }
717
- async function rewriteClientPaths(clientDir, ui) {
718
- const candidates = [
719
- "vite.config.mts",
720
- "tsconfig.json",
721
- "tsconfig.app.json",
722
- "tsconfig.spec.json",
723
- "project.json",
724
- "eslint.config.mjs"
725
- ];
726
- for (const rel of candidates) {
727
- const path = join2(clientDir, rel);
728
- try {
729
- const raw = await readFile2(path, "utf8");
730
- const next = raw.replaceAll("../../../", "../../").replaceAll(`apps/templates/client-${ui}`, "apps/client").replaceAll(`client-${ui}`, "client");
731
- if (next !== raw) await writeFile(path, next);
732
- } catch {
733
- }
734
- }
735
- }
736
- function gitInit(cwd, projectName) {
737
- spawnSync("git", ["init"], { cwd, stdio: "inherit" });
738
- spawnSync("git", ["add", "."], { cwd, stdio: "inherit" });
739
- spawnSync(
740
- "git",
741
- ["commit", "-m", `chore: bootstrap ${projectName} from @idevconn/create-icore`],
742
- { cwd, stdio: "inherit" }
743
- );
744
- }
745
- function resolveYarnBin(cwd) {
746
- try {
747
- const yarnrc = readFileSync(join2(cwd, ".yarnrc.yml"), "utf8");
748
- const match = yarnrc.match(/^yarnPath:\s*(.+)$/m);
749
- if (match?.[1]) return join2(cwd, match[1].trim());
750
- } catch {
751
- }
752
- return join2(cwd, ".yarn", "releases", "yarn-4.5.0.cjs");
753
- }
754
- function runInstall(cwd, pm) {
755
- if (pm === "yarn") {
756
- spawnSync("node", [resolveYarnBin(cwd), "install"], { cwd, stdio: "inherit" });
757
- } else if (pm === "npm") {
758
- spawnSync("npm", ["install"], { cwd, stdio: "inherit" });
759
- } else {
760
- spawnSync("pnpm", ["install"], { cwd, stdio: "inherit" });
761
- }
762
- }
763
- async function scaffold(opts, templatesDir2) {
764
- await copyTree(templatesDir2, opts.targetDir);
765
- await rewriteRootPackageJson(opts.targetDir, opts);
766
- await writeAuthEnv(opts.targetDir, opts);
767
- await writeUploadEnv(opts.targetDir, opts);
768
- await writeNotesEnv(opts.targetDir, opts);
769
- await writePaymentEnv(opts.targetDir, opts);
770
- await writeGatewayEnv(opts.targetDir, opts);
771
- await writeRootEnv(opts.targetDir, opts);
772
- await selectClientTemplate(opts.targetDir, opts);
773
- await writeClientEnv(opts.targetDir);
774
- if (opts.upload === "none") await removeUploadStack(opts.targetDir);
775
- if (opts.payment === "none") await removePaymentStack(opts.targetDir);
776
- if (opts.jobs === "none") await removeJobsStack(opts.targetDir);
777
- if (opts.example === "none") await removeNotesStack(opts.targetDir);
778
- await removeUnusedAuthStrategies(opts.targetDir, opts.authProvider);
779
- await removeUnusedStorageStrategies(opts.targetDir, opts.upload);
780
- await removeUnusedDbStrategies(opts.targetDir, opts.dbProvider);
781
- const firebaseUsed = opts.authProvider === "firebase" || opts.dbProvider === "firebase" || opts.upload === "firebase";
782
- if (!firebaseUsed) await removeFirebaseAdminLib(opts.targetDir);
783
- if (opts.packageManager === "yarn") {
784
- await writeFile(join2(opts.targetDir, "yarn.lock"), "");
785
- } else {
786
- await rm(join2(opts.targetDir, ".yarn"), { recursive: true, force: true });
787
- await rm(join2(opts.targetDir, ".yarnrc.yml"), { force: true });
788
- }
789
- if (opts.packageManager === "pnpm") {
790
- await writePnpmWorkspace(opts.targetDir);
791
- await rewritePnpmWorkspaceDeps(opts.targetDir);
792
- }
793
- await patchGitignoreForPm(opts.targetDir, opts.packageManager);
794
- await writeAiFiles(opts.targetDir, opts);
795
- if (opts.install) runInstall(opts.targetDir, opts.packageManager);
796
- if (opts.initGit) gitInit(opts.targetDir, opts.projectName);
773
+
774
+ // src/lib/scaffold-pkg.ts
775
+ import { readFile as readFile4, writeFile as writeFile3, mkdir, readdir } from "fs/promises";
776
+ import { join as join4 } from "path";
777
+
778
+ // src/lib/options.ts
779
+ function pmRun(pm, script) {
780
+ return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
797
781
  }
782
+
783
+ // src/lib/scaffold-pkg.ts
798
784
  async function writePnpmWorkspace(targetDir) {
799
- const pkgPath = join2(targetDir, "package.json");
800
- const pkg = JSON.parse(await readFile2(pkgPath, "utf8"));
785
+ const pkgPath = join4(targetDir, "package.json");
786
+ const pkg = JSON.parse(await readFile4(pkgPath, "utf8"));
801
787
  const workspaces = pkg.workspaces ?? [];
802
788
  const packagesBlock = workspaces.map((p3) => ` - '${p3}'`).join("\n");
803
789
  const allowBuilds = [
@@ -818,23 +804,22 @@ ${packagesBlock}
818
804
  allowBuilds:
819
805
  ${allowBuilds}
820
806
  `;
821
- await writeFile(join2(targetDir, "pnpm-workspace.yaml"), content);
807
+ await writeFile3(join4(targetDir, "pnpm-workspace.yaml"), content);
822
808
  }
823
809
  async function rewritePnpmWorkspaceDeps(targetDir) {
824
- const { readdir: rd } = await import("fs/promises");
825
810
  async function walk(dir) {
826
811
  const found = [];
827
812
  let entries;
828
813
  try {
829
- entries = await rd(dir, { withFileTypes: true });
814
+ entries = await readdir(dir, { withFileTypes: true });
830
815
  } catch {
831
816
  return found;
832
817
  }
833
818
  for (const e of entries) {
834
819
  if (e.isDirectory() && e.name !== "node_modules") {
835
- found.push(...await walk(join2(dir, e.name)));
820
+ found.push(...await walk(join4(dir, e.name)));
836
821
  } else if (e.isFile() && e.name === "package.json") {
837
- found.push(join2(dir, e.name));
822
+ found.push(join4(dir, e.name));
838
823
  }
839
824
  }
840
825
  return found;
@@ -842,17 +827,17 @@ async function rewritePnpmWorkspaceDeps(targetDir) {
842
827
  const pkgFiles = await walk(targetDir);
843
828
  for (const f of pkgFiles) {
844
829
  try {
845
- const raw = await readFile2(f, "utf8");
830
+ const raw = await readFile4(f, "utf8");
846
831
  const next = raw.replace(/"(@icore\/[^"]+)":\s*"\*"/g, '"$1": "workspace:*"');
847
- if (next !== raw) await writeFile(f, next);
832
+ if (next !== raw) await writeFile3(f, next);
848
833
  } catch {
849
834
  }
850
835
  }
851
836
  }
852
837
  async function patchGitignoreForPm(targetDir, pm) {
853
- const giPath = join2(targetDir, ".gitignore");
838
+ const giPath = join4(targetDir, ".gitignore");
854
839
  try {
855
- let src = await readFile2(giPath, "utf8");
840
+ let src = await readFile4(giPath, "utf8");
856
841
  src = src.replace(/^# Build artifacts.*\ntools\/create-icore\/templates\/\s*\n/m, "");
857
842
  if (pm !== "yarn") {
858
843
  src = src.replace(/^\.yarn\/\*\s*\n/m, "").replace(/^!\.yarn\/patches\s*\n/m, "").replace(/^!\.yarn\/plugins\s*\n/m, "").replace(/^!\.yarn\/releases\s*\n/m, "").replace(/^!\.yarn\/sdks\s*\n/m, "").replace(/^!\.yarn\/versions\s*\n/m, "").replace(/^\.pnp\.\*\s*\n/m, "");
@@ -867,7 +852,7 @@ async function patchGitignoreForPm(targetDir, pm) {
867
852
  src += "\n# npm\nnpm-debug.log*\n";
868
853
  }
869
854
  }
870
- await writeFile(giPath, src);
855
+ await writeFile3(giPath, src);
871
856
  } catch {
872
857
  }
873
858
  }
@@ -882,7 +867,7 @@ async function writeAiFiles(targetDir, opts) {
882
867
  if (opts.jobs !== "none") activeMSes.push(`jobs (standalone)`);
883
868
  const usesSupabase = opts.authProvider === "supabase" || opts.dbProvider === "supabase" || opts.upload === "supabase";
884
869
  const usesFirebase = opts.authProvider === "firebase" || opts.dbProvider === "firebase" || opts.upload === "firebase";
885
- await writeFile(join2(targetDir, "CLAUDE.md"), "@AGENTS.md\n");
870
+ await writeFile3(join4(targetDir, "CLAUDE.md"), "@AGENTS.md\n");
886
871
  const uiLabel = { shadcn: "shadcn/ui + Tailwind", antd: "Ant Design 6", mui: "MUI 6" }[opts.ui];
887
872
  const readme = `# ${opts.projectName}
888
873
 
@@ -932,7 +917,7 @@ ${pm === "yarn" ? "yarn remove-notes" : pm === "pnpm" ? "pnpm remove-notes" : "n
932
917
 
933
918
  Apache-2.0
934
919
  `;
935
- await writeFile(join2(targetDir, "README.md"), readme);
920
+ await writeFile3(join4(targetDir, "README.md"), readme);
936
921
  const agents = `# ${opts.projectName} \u2014 Agent Instructions
937
922
 
938
923
  ## Stack snapshot
@@ -1013,8 +998,8 @@ ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PRO
1013
998
  - Test behaviour, not implementation. Fake strategies from \`@icore/shared\` (FakeAuthStrategy etc.) serve as test doubles.
1014
999
  - Run: \`${nx} test <project>\`
1015
1000
  `;
1016
- await writeFile(join2(targetDir, "AGENTS.md"), agents);
1017
- await mkdir(join2(targetDir, ".claude"), { recursive: true });
1001
+ await writeFile3(join4(targetDir, "AGENTS.md"), agents);
1002
+ await mkdir(join4(targetDir, ".claude"), { recursive: true });
1018
1003
  const mcpServers = {
1019
1004
  nx: {
1020
1005
  command: "npx",
@@ -1055,12 +1040,135 @@ ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PRO
1055
1040
  ]
1056
1041
  }
1057
1042
  };
1058
- await writeFile(
1059
- join2(targetDir, ".claude", "settings.json"),
1043
+ await writeFile3(
1044
+ join4(targetDir, ".claude", "settings.json"),
1060
1045
  JSON.stringify(settings, null, 2) + "\n"
1061
1046
  );
1062
1047
  }
1063
1048
 
1049
+ // src/lib/scaffold.ts
1050
+ var IGNORE_TOP = /* @__PURE__ */ new Set([
1051
+ ".git",
1052
+ "node_modules",
1053
+ ".yarn/cache",
1054
+ ".yarn/unplugged",
1055
+ ".yarn/install-state.gz",
1056
+ ".nx",
1057
+ "dist",
1058
+ "tmp",
1059
+ "coverage",
1060
+ ".idea",
1061
+ ".vscode"
1062
+ ]);
1063
+ async function copyTree(src, dest) {
1064
+ await mkdir2(dest, { recursive: true });
1065
+ const entries = await readdir2(src, { withFileTypes: true });
1066
+ for (const entry of entries) {
1067
+ if (IGNORE_TOP.has(entry.name)) continue;
1068
+ const s = join5(src, entry.name);
1069
+ const d = join5(dest, entry.name);
1070
+ if (entry.isDirectory()) await copyTree(s, d);
1071
+ else if (entry.isFile()) await copyFile(s, d);
1072
+ }
1073
+ }
1074
+ async function selectClientTemplate(targetDir, opts) {
1075
+ const templatesRoot = join5(targetDir, "apps/templates");
1076
+ const chosen = join5(templatesRoot, `client-${opts.ui}`);
1077
+ const destClient = join5(targetDir, "apps/client");
1078
+ let chosenUi = opts.ui;
1079
+ try {
1080
+ const s = await stat(chosen);
1081
+ if (!s.isDirectory()) throw new Error("not a dir");
1082
+ await copyTree(chosen, destClient);
1083
+ } catch {
1084
+ chosenUi = "shadcn";
1085
+ await copyTree(join5(templatesRoot, "client-shadcn"), destClient);
1086
+ }
1087
+ await rm2(templatesRoot, { recursive: true, force: true });
1088
+ await rewriteClientPaths(destClient, chosenUi);
1089
+ }
1090
+ async function rewriteClientPaths(clientDir, ui) {
1091
+ const candidates = [
1092
+ "vite.config.mts",
1093
+ "tsconfig.json",
1094
+ "tsconfig.app.json",
1095
+ "tsconfig.spec.json",
1096
+ "project.json",
1097
+ "eslint.config.mjs"
1098
+ ];
1099
+ for (const rel of candidates) {
1100
+ const path = join5(clientDir, rel);
1101
+ try {
1102
+ const raw = await readFile5(path, "utf8");
1103
+ const next = raw.replaceAll("../../../", "../../").replaceAll(`apps/templates/client-${ui}`, "apps/client").replaceAll(`client-${ui}`, "client");
1104
+ if (next !== raw) await writeFile4(path, next);
1105
+ } catch {
1106
+ }
1107
+ }
1108
+ }
1109
+ function gitInit(cwd, projectName) {
1110
+ spawnSync("git", ["init"], { cwd, stdio: "inherit" });
1111
+ spawnSync("git", ["add", "."], { cwd, stdio: "inherit" });
1112
+ spawnSync(
1113
+ "git",
1114
+ ["commit", "-m", `chore: bootstrap ${projectName} from @idevconn/create-icore`],
1115
+ { cwd, stdio: "inherit" }
1116
+ );
1117
+ }
1118
+ function resolveYarnBin(cwd) {
1119
+ try {
1120
+ const yarnrc = readFileSync(join5(cwd, ".yarnrc.yml"), "utf8");
1121
+ const match = yarnrc.match(/^yarnPath:\s*(.+)$/m);
1122
+ if (match?.[1]) return join5(cwd, match[1].trim());
1123
+ } catch {
1124
+ }
1125
+ return join5(cwd, ".yarn", "releases", "yarn-4.5.0.cjs");
1126
+ }
1127
+ function runInstall(cwd, pm) {
1128
+ if (pm === "yarn") {
1129
+ spawnSync("node", [resolveYarnBin(cwd), "install"], { cwd, stdio: "inherit" });
1130
+ } else if (pm === "npm") {
1131
+ spawnSync("npm", ["install"], { cwd, stdio: "inherit" });
1132
+ } else {
1133
+ spawnSync("pnpm", ["install"], { cwd, stdio: "inherit" });
1134
+ }
1135
+ }
1136
+ async function scaffold(opts, templatesDir2) {
1137
+ await copyTree(templatesDir2, opts.targetDir);
1138
+ await rewriteRootPackageJson(opts.targetDir, opts);
1139
+ await writeAuthEnv(opts.targetDir, opts);
1140
+ await writeUploadEnv(opts.targetDir, opts);
1141
+ await writeNotesEnv(opts.targetDir, opts);
1142
+ await writePaymentEnv(opts.targetDir, opts);
1143
+ await writeGatewayEnv(opts.targetDir, opts);
1144
+ await writeRootEnv(opts.targetDir, opts);
1145
+ await selectClientTemplate(opts.targetDir, opts);
1146
+ await writeClientEnv(opts.targetDir);
1147
+ if (opts.upload === "none") await removeUploadStack(opts.targetDir);
1148
+ if (opts.payment === "none") await removePaymentStack(opts.targetDir);
1149
+ if (opts.jobs === "none") await removeJobsStack(opts.targetDir);
1150
+ if (opts.example === "none") await removeNotesStack(opts.targetDir);
1151
+ await removeUnusedAuthStrategies(opts.targetDir, opts.authProvider);
1152
+ await removeUnusedStorageStrategies(opts.targetDir, opts.upload);
1153
+ await removeUnusedDbStrategies(opts.targetDir, opts.dbProvider);
1154
+ const firebaseUsed = opts.authProvider === "firebase" || opts.dbProvider === "firebase" || opts.upload === "firebase";
1155
+ if (!firebaseUsed) await removeFirebaseAdminLib(opts.targetDir);
1156
+ if (opts.packageManager === "yarn") {
1157
+ await writeFile4(join5(opts.targetDir, "yarn.lock"), "");
1158
+ } else {
1159
+ await rm2(join5(opts.targetDir, ".yarn"), { recursive: true, force: true });
1160
+ await rm2(join5(opts.targetDir, ".yarnrc.yml"), { force: true });
1161
+ }
1162
+ if (opts.packageManager === "pnpm") {
1163
+ await writePnpmWorkspace(opts.targetDir);
1164
+ await rewritePnpmWorkspaceDeps(opts.targetDir);
1165
+ }
1166
+ await patchGitignoreForPm(opts.targetDir, opts.packageManager);
1167
+ await writeAiFiles(opts.targetDir, opts);
1168
+ if (opts.install) runInstall(opts.targetDir, opts.packageManager);
1169
+ if (opts.initGit) gitInit(opts.targetDir, opts.projectName);
1170
+ }
1171
+
1064
1172
  // src/cli.ts
1065
1173
  var [nodeMajor] = process.versions.node.split(".").map(Number);
1066
1174
  if (nodeMajor < 22) {