@idevconn/create-icore 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/cli.js +832 -130
  2. package/dist/index.cjs +848 -149
  3. package/dist/index.d.cts +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +841 -142
  6. package/package.json +4 -4
  7. package/templates/.yarn/releases/{yarn-4.16.0.cjs → yarn-4.17.0.cjs} +326 -326
  8. package/templates/.yarnrc.yml +1 -1
  9. package/templates/apps/api/package.json +6 -6
  10. package/templates/apps/microservices/auth/package.json +4 -4
  11. package/templates/apps/microservices/jobs/package.json +5 -5
  12. package/templates/apps/microservices/notes/package.json +5 -5
  13. package/templates/apps/microservices/payment/package.json +4 -4
  14. package/templates/apps/microservices/upload/package.json +6 -6
  15. package/templates/apps/templates/client-antd/package.json +2 -2
  16. package/templates/apps/templates/client-mui/package.json +4 -4
  17. package/templates/apps/templates/client-shadcn/package.json +7 -7
  18. package/templates/apps/templates/client-shadcn/src/components/ui/button.tsx +1 -2
  19. package/templates/libs/auth-client/package.json +3 -3
  20. package/templates/libs/auth-strategies/firebase/package.json +4 -4
  21. package/templates/libs/auth-strategies/mongodb/package.json +4 -4
  22. package/templates/libs/auth-strategies/supabase/package.json +5 -5
  23. package/templates/libs/db-strategies/firestore/package.json +4 -4
  24. package/templates/libs/db-strategies/mongodb/package.json +3 -3
  25. package/templates/libs/db-strategies/supabase/package.json +5 -5
  26. package/templates/libs/firebase-admin/package.json +1 -1
  27. package/templates/libs/jobs-client/package.json +4 -4
  28. package/templates/libs/notes-client/package.json +3 -3
  29. package/templates/libs/payment-client/package.json +3 -3
  30. package/templates/libs/shared/package.json +2 -2
  31. package/templates/libs/storage-strategies/cloudinary/package.json +4 -4
  32. package/templates/libs/storage-strategies/firebase/package.json +4 -4
  33. package/templates/libs/storage-strategies/mongodb/package.json +3 -3
  34. package/templates/libs/storage-strategies/supabase/package.json +5 -5
  35. package/templates/libs/template-shared/package.json +8 -8
  36. package/templates/libs/upload-client/package.json +3 -3
  37. package/templates/libs/vite-plugins/package.json +3 -3
  38. package/templates/package.json +32 -32
  39. package/templates/tools/create-icore/_template-shell/package.json +32 -32
package/dist/index.cjs CHANGED
@@ -47,9 +47,9 @@ function pmRun(pm, script) {
47
47
  }
48
48
 
49
49
  // src/lib/scaffold.ts
50
- var import_promises8 = require("fs/promises");
50
+ var import_promises9 = require("fs/promises");
51
51
  var import_node_fs = require("fs");
52
- var import_node_path8 = require("path");
52
+ var import_node_path9 = require("path");
53
53
  var import_node_child_process = require("child_process");
54
54
 
55
55
  // src/lib/scaffold-env.ts
@@ -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) {
@@ -191,6 +215,9 @@ async function writeGatewayEnv(targetDir, opts) {
191
215
  for (const prefix of ["AUTH", "UPLOAD", "NOTES", "PAYMENT"]) {
192
216
  next = uncommentTransportEnv(next, prefix, opts.transport);
193
217
  }
218
+ if (opts.authProvider === "none") {
219
+ next = next.split("\n").filter((line) => !line.startsWith("AUTH_") && !line.startsWith("# AUTH_")).join("\n");
220
+ }
194
221
  await (0, import_promises.writeFile)((0, import_node_path.join)(targetDir, "apps/api/.env"), next);
195
222
  }
196
223
  async function writeRootEnv(targetDir, opts) {
@@ -272,59 +299,26 @@ async function removeFirebaseAdminLib(targetDir) {
272
299
  "@icore/firebase-admin"
273
300
  ]);
274
301
  }
275
- async function removeAuthStack(targetDir) {
276
- const rmPaths = [
277
- "apps/microservices/auth",
278
- "libs/auth-strategies",
279
- "libs/auth-client",
280
- "Dockerfile.ms-auth",
281
- "apps/api/src/app/auth",
282
- "apps/api/src/app/profile",
283
- "apps/api/src/app/abilities",
284
- "apps/client/src/components/auth",
285
- "apps/client/src/routes/login.tsx",
286
- "apps/client/src/routes/auth.callback.tsx",
287
- "apps/client/src/routes/auth.oauth.callback.tsx",
288
- "apps/client/src/routes/_dashboard/profile.tsx"
289
- ];
290
- for (const p2 of rmPaths) {
291
- await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, p2), { recursive: true, force: true });
292
- }
293
- const appModulePath = (0, import_node_path2.join)(targetDir, "apps/api/src/app/app.module.ts");
302
+ async function removeStrategiesLib(targetDir) {
303
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/strategies"), { recursive: true, force: true });
304
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/testing.ts"), { force: true });
305
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/transport.ts"), { force: true });
306
+ await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, "libs/shared/src/__tests__/transport.unit.test.ts"), { force: true });
307
+ const indexPath = (0, import_node_path2.join)(targetDir, "libs/shared/src/index.ts");
294
308
  try {
295
- const src = await (0, import_promises2.readFile)(appModulePath, "utf8");
296
- const next = src.replace(/^import \{ AuthModule \} from '\.\/auth\/auth\.module';\n/m, "").replace(/^import \{ ProfileModule \} from '\.\/profile\/profile\.module';\n/m, "").replace(/^import \{ AbilitiesModule \} from '\.\/abilities\/abilities\.module';\n/m, "").replace(/\bAuthModule,\s*/g, "").replace(/,\s*AuthModule\b/g, "").replace(/\bProfileModule,\s*/g, "").replace(/,\s*ProfileModule\b/g, "").replace(/\bAbilitiesModule,\s*/g, "").replace(/,\s*AbilitiesModule\b/g, "");
297
- await (0, import_promises2.writeFile)(appModulePath, next);
298
- } catch {
299
- }
300
- const dashboardPath = (0, import_node_path2.join)(targetDir, "apps/client/src/routes/_dashboard.tsx");
301
- try {
302
- const src = await (0, import_promises2.readFile)(dashboardPath, "utf8");
303
- const next = src.replace(/^import \{ useAuthStore \} from '@icore\/template-shared';\n/m, "").replace(/, redirect/g, "").replace(/\n {2}beforeLoad: \(\) => \{[\s\S]*?\n {2}\},/m, "");
304
- await (0, import_promises2.writeFile)(dashboardPath, next);
305
- } catch {
306
- }
307
- for (const alias of [
308
- "@icore/auth-client",
309
- "@icore/auth-supabase",
310
- "@icore/auth-firebase",
311
- "@icore/auth-mongodb"
312
- ]) {
313
- await stripTsconfigPath(targetDir, alias);
314
- }
315
- await stripDeps((0, import_node_path2.join)(targetDir, "apps/api/package.json"), ["@icore/auth-client"]);
316
- const gatewayEnv = (0, import_node_path2.join)(targetDir, "apps/api/.env");
317
- try {
318
- const env = await (0, import_promises2.readFile)(gatewayEnv, "utf8");
319
- const next = env.split("\n").filter((line) => !line.startsWith("AUTH_") && !line.startsWith("# AUTH_")).join("\n");
320
- await (0, import_promises2.writeFile)(gatewayEnv, next);
309
+ const src = await (0, import_promises2.readFile)(indexPath, "utf8");
310
+ await (0, import_promises2.writeFile)(
311
+ indexPath,
312
+ src.replace(/^export \* from '\.\/strategies';\n/m, "").replace(/^export \* from '\.\/transport';\n?/m, "")
313
+ );
321
314
  } catch {
322
315
  }
323
- const composePath = (0, import_node_path2.join)(targetDir, "docker-compose.yml");
316
+ const pkgPath = (0, import_node_path2.join)(targetDir, "libs/shared/package.json");
324
317
  try {
325
- const compose = await (0, import_promises2.readFile)(composePath, "utf8");
326
- const next = compose.replace(/\n {2}auth:[\s\S]+?(?=\n {2}\w|\nnetworks:)/m, "\n").replace(/\n {6}auth:\n {8}condition: service_started/g, "").replace(/\n {6}AUTH_TRANSPORT:[^\n]*/g, "").replace(/\n {6}AUTH_REDIS_URL:[^\n]*/g, "");
327
- await (0, import_promises2.writeFile)(composePath, next);
318
+ const pkg = JSON.parse(await (0, import_promises2.readFile)(pkgPath, "utf8"));
319
+ if (pkg.exports) delete pkg.exports["./testing"];
320
+ if (pkg.dependencies) delete pkg.dependencies["@nestjs/microservices"];
321
+ await (0, import_promises2.writeFile)(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
328
322
  } catch {
329
323
  }
330
324
  }
@@ -334,7 +328,8 @@ async function removeUploadStack(targetDir) {
334
328
  "apps/microservices/upload-e2e",
335
329
  "libs/storage-strategies",
336
330
  "libs/upload-client",
337
- "apps/api/src/app/storage"
331
+ "apps/api/src/app/storage",
332
+ "Dockerfile.ms-upload"
338
333
  ];
339
334
  for (const p2 of paths) {
340
335
  await (0, import_promises2.rm)((0, import_node_path2.join)(targetDir, p2), { recursive: true, force: true });
@@ -359,11 +354,683 @@ async function removeUploadStack(targetDir) {
359
354
  "@icore/upload-client",
360
355
  "@types/multer"
361
356
  ]);
357
+ const uploadComposePath = (0, import_node_path2.join)(targetDir, "docker-compose.yml");
358
+ try {
359
+ const compose = await (0, import_promises2.readFile)(uploadComposePath, "utf8");
360
+ 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, "");
361
+ await (0, import_promises2.writeFile)(uploadComposePath, next);
362
+ } catch {
363
+ }
364
+ }
365
+
366
+ // src/lib/scaffold-auth-none.ts
367
+ var import_promises3 = require("fs/promises");
368
+ var import_node_path3 = require("path");
369
+ async function stripDeps2(pkgPath, names) {
370
+ try {
371
+ const raw = await (0, import_promises3.readFile)(pkgPath, "utf8");
372
+ const pkg = JSON.parse(raw);
373
+ for (const n of names) {
374
+ if (pkg.dependencies) delete pkg.dependencies[n];
375
+ if (pkg.devDependencies) delete pkg.devDependencies[n];
376
+ }
377
+ await (0, import_promises3.writeFile)(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
378
+ } catch {
379
+ }
380
+ }
381
+ var AUTH_ONLY_PATHS = [
382
+ "apps/microservices/auth",
383
+ "libs/auth-strategies",
384
+ "libs/auth-client",
385
+ "Dockerfile.ms-auth",
386
+ "apps/api/src/app/auth",
387
+ "apps/api/src/app/profile",
388
+ "apps/api/src/app/abilities",
389
+ "libs/shared/src/abilities",
390
+ "apps/client/src/components/auth",
391
+ "apps/client/src/routes/login.tsx",
392
+ "apps/client/src/routes/auth.callback.tsx",
393
+ "apps/client/src/routes/auth.oauth.callback.tsx",
394
+ "apps/client/src/routes/_dashboard/profile.tsx",
395
+ "libs/template-shared/src/lib/abilities"
396
+ ];
397
+ async function removeAuthOnlyPaths(targetDir) {
398
+ for (const p2 of AUTH_ONLY_PATHS) {
399
+ await (0, import_promises3.rm)((0, import_node_path3.join)(targetDir, p2), { recursive: true, force: true });
400
+ }
401
+ await stripDeps2((0, import_node_path3.join)(targetDir, "apps/api/package.json"), [
402
+ "@icore/auth-client",
403
+ "cookie-parser"
404
+ ]);
405
+ }
406
+ async function stripTsconfigPath2(targetDir, alias) {
407
+ const tsconfigPath = (0, import_node_path3.join)(targetDir, "tsconfig.base.json");
408
+ try {
409
+ const src = await (0, import_promises3.readFile)(tsconfigPath, "utf8");
410
+ const escaped = alias.replace(/[@/]/g, (c) => c === "@" ? "@" : "\\/");
411
+ const pretty = src.replace(new RegExp(`^\\s*"${escaped}": \\[[^\\]]*\\],?\\n`, "m"), "");
412
+ if (pretty !== src) {
413
+ await (0, import_promises3.writeFile)(tsconfigPath, pretty);
414
+ return;
415
+ }
416
+ const parsed = JSON.parse(src);
417
+ if (parsed.compilerOptions?.paths) delete parsed.compilerOptions.paths[alias];
418
+ await (0, import_promises3.writeFile)(tsconfigPath, JSON.stringify(parsed));
419
+ } catch {
420
+ }
421
+ }
422
+ async function removeAuthTsconfigPaths(targetDir) {
423
+ for (const alias of [
424
+ "@icore/auth-client",
425
+ "@icore/auth-supabase",
426
+ "@icore/auth-firebase",
427
+ "@icore/auth-mongodb"
428
+ ]) {
429
+ await stripTsconfigPath2(targetDir, alias);
430
+ }
431
+ }
432
+ async function removeDockerComposeAuthService(targetDir) {
433
+ const composePath = (0, import_node_path3.join)(targetDir, "docker-compose.yml");
434
+ try {
435
+ const compose = await (0, import_promises3.readFile)(composePath, "utf8");
436
+ const next = compose.replace(/\n {2}auth:[\s\S]+?(?=\n {2}\w|\nnetworks:)/m, "\n").replace(/\n {6}auth:\n {8}condition: service_started/g, "").replace(/\n {6}AUTH_TRANSPORT:[^\n]*/g, "").replace(/\n {6}AUTH_REDIS_URL:[^\n]*/g, "");
437
+ await (0, import_promises3.writeFile)(composePath, next);
438
+ } catch {
439
+ }
440
+ }
441
+ var GATEWAY_MAIN_TS = `import { Logger } from '@nestjs/common';
442
+ import { NestFactory } from '@nestjs/core';
443
+ import { NestExpressApplication } from '@nestjs/platform-express';
444
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
445
+ import { formatGatewayBanner } from '@icore/shared';
446
+ import { AppModule } from './app/app.module';
447
+ import { GATEWAY_SERVICES } from './app/gateway-services';
448
+ import pkg from '@icore/package.json';
449
+
450
+ const DEFAULT_PORT = 3001;
451
+
452
+ async function bootstrap() {
453
+ const app = await NestFactory.create<NestExpressApplication>(AppModule);
454
+ app.setGlobalPrefix('api');
455
+
456
+ const swaggerConfig = new DocumentBuilder()
457
+ .setTitle('iCore API')
458
+ .setDescription('iCore Gateway HTTP surface')
459
+ .setVersion(pkg.version)
460
+ .addBearerAuth()
461
+ .build();
462
+ const document = SwaggerModule.createDocument(app, swaggerConfig);
463
+ SwaggerModule.setup('api/docs', app, document);
464
+
465
+ const port = Number(process.env.API_PORT ?? DEFAULT_PORT);
466
+ await app.listen(port);
467
+ }
468
+
469
+ bootstrap()
470
+ .then(() => {
471
+ const origin = process.env.API_ORIGIN ?? 'http://localhost';
472
+ const port = Number(process.env.API_PORT ?? DEFAULT_PORT);
473
+ new Logger('API-Bootstrap').log(
474
+ formatGatewayBanner({ port, origin, services: GATEWAY_SERVICES }),
475
+ );
476
+ })
477
+ .catch((err) => {
478
+ new Logger('API-Bootstrap').error(
479
+ 'Gateway bootstrap failed',
480
+ err instanceof Error ? err.stack : err,
481
+ );
482
+ process.exit(1);
483
+ });
484
+ `;
485
+ var GATEWAY_APP_MODULE_TS = `import { join } from 'node:path';
486
+ import { Module } from '@nestjs/common';
487
+ import { ConfigModule } from '@nestjs/config';
488
+ import { ThrottlerModule, seconds } from '@nestjs/throttler';
489
+ import { StorageModule } from './storage/storage.module';
490
+ import { FeaturesModule } from './features.module';
491
+
492
+ @Module({
493
+ imports: [
494
+ ConfigModule.forRoot({
495
+ isGlobal: true,
496
+ envFilePath: [join(process.cwd(), 'apps/api/.env'), join(process.cwd(), '.env')],
497
+ }),
498
+ ThrottlerModule.forRoot([{ name: 'auth-burst', ttl: seconds(60), limit: 10 }]),
499
+ StorageModule,
500
+ FeaturesModule,
501
+ ],
502
+ })
503
+ export class AppModule {}
504
+ `;
505
+ var SHARED_CLIENT_TS = `// Browser-safe subset of @icore/shared.
506
+ // Import from '@icore/shared/client' in client-side code to avoid pulling
507
+ // in NestJS / Node.js-only modules (transport, strategies, contracts).
508
+ export * from './types';
509
+ `;
510
+ var SHARED_INDEX_TS = `export * from './env';
511
+ export * from './bootstrap';
512
+ export * from './jobs';
513
+ export * from './strategies';
514
+ export * from './transport';
515
+ export * from './types';
516
+ `;
517
+ var TEMPLATE_SHARED_INDEX_TS = `export * from './lib/api/create-api.js';
518
+ export * from './lib/stores/auth.store.js';
519
+ export * from './lib/stores/loading.store.js';
520
+ export * from './lib/i18n/create-i18n.js';
521
+ export * from './lib/i18n/keys.js';
522
+ export * from './lib/notify/use-notify.js';
523
+ export * from './lib/draft/index.js';
524
+ export * from './lib/landing/LandingPage.js';
525
+ export * from './lib/stores/theme.store.js';
526
+ `;
527
+ var SHADCN_MAIN_TSX = `import './globals.css';
528
+ import { StrictMode } from 'react';
529
+ import { createRoot } from 'react-dom/client';
530
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
531
+ import { RouterProvider, createRouter } from '@tanstack/react-router';
532
+ import {
533
+ createIcoreApi,
534
+ createIcoreI18n,
535
+ ICORE_LOCALES,
536
+ useThemeStore,
537
+ } from '@icore/template-shared';
538
+ import { I18nextProvider } from 'react-i18next';
539
+ import { Toaster } from 'sonner';
540
+ import { routeTree } from './routeTree.gen';
541
+ import { wireShadcnNotifier } from './lib/notify';
542
+
543
+ const queryClient = new QueryClient({
544
+ defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false } },
545
+ });
546
+
547
+ const router = createRouter({ routeTree, context: { queryClient } });
548
+
549
+ declare module '@tanstack/react-router' {
550
+ interface Register {
551
+ router: typeof router;
552
+ }
553
+ }
554
+
555
+ const i18n = createIcoreI18n({ resources: ICORE_LOCALES });
556
+
557
+ // Single shared API instance \u2014 used by every query in src/queries/
558
+ export const api = createIcoreApi({
559
+ baseUrl: import.meta.env.VITE_API_URL ?? '/api',
560
+ });
561
+
562
+ wireShadcnNotifier();
563
+
564
+ // Apply the theme class before React mounts so the first paint is correct
565
+ const applyTheme = (mode: 'light' | 'dark') => {
566
+ document.documentElement.classList.toggle('dark', mode === 'dark');
567
+ };
568
+ applyTheme(useThemeStore.getState().mode);
569
+ useThemeStore.subscribe((s) => applyTheme(s.mode));
570
+
571
+ createRoot(document.getElementById('root')!).render(
572
+ <StrictMode>
573
+ <I18nextProvider i18n={i18n}>
574
+ <QueryClientProvider client={queryClient}>
575
+ <RouterProvider router={router} />
576
+ <Toaster richColors />
577
+ </QueryClientProvider>
578
+ </I18nextProvider>
579
+ </StrictMode>,
580
+ );
581
+ `;
582
+ var SHADCN_DASHBOARD_TSX = `import { createFileRoute, Outlet } from '@tanstack/react-router';
583
+ import { MainLayout } from '../layouts/MainLayout';
584
+
585
+ export const Route = createFileRoute('/_dashboard')({
586
+ component: () => (
587
+ <MainLayout>
588
+ <Outlet />
589
+ </MainLayout>
590
+ ),
591
+ });
592
+ `;
593
+ var SHADCN_INDEX_TSX = `import { createFileRoute } from '@tanstack/react-router';
594
+ import { LandingPage } from '@icore/template-shared';
595
+
596
+ // All version strings are injected at build time by vite.config.mts
597
+ // (reads root package.json via fs.readFileSync so they stay accurate
598
+ // even when workspace packages are bumped independently).
599
+ const APP_VERSION = (import.meta.env.VITE_APP_VERSION as string | undefined) ?? '0.0.0-dev';
600
+
601
+ export const Route = createFileRoute('/')({
602
+ component: () => (
603
+ <LandingPage
604
+ coreVersion={APP_VERSION}
605
+ uiLibrary="shadcn"
606
+ deps={[
607
+ { name: 'react', version: (import.meta.env.VITE_DEP_REACT as string) ?? '?' },
608
+ { name: 'vite', version: (import.meta.env.VITE_DEP_VITE as string) ?? '?' },
609
+ { name: 'tailwindcss', version: (import.meta.env.VITE_DEP_TAILWINDCSS as string) ?? '?' },
610
+ {
611
+ name: '@tanstack/react-router',
612
+ version: (import.meta.env.VITE_DEP_TANSTACK_ROUTER as string) ?? '?',
613
+ },
614
+ {
615
+ name: '@tanstack/react-query',
616
+ version: (import.meta.env.VITE_DEP_TANSTACK_QUERY as string) ?? '?',
617
+ },
618
+ { name: 'zustand', version: (import.meta.env.VITE_DEP_ZUSTAND as string) ?? '?' },
619
+ { name: '@casl/ability', version: (import.meta.env.VITE_DEP_CASL as string) ?? '?' },
620
+ ]}
621
+ ctaHref="/dashboard"
622
+ ctaLabel="Dashboard \u2192"
623
+ />
624
+ ),
625
+ });
626
+ `;
627
+ var SHADCN_LAYOUT_HEADER_TSX = `import { setStoredLocale, type IcoreLocale } from '@icore/template-shared';
628
+ import { ThemeToggle } from '../ThemeToggle';
629
+
630
+ const LOCALES: { code: IcoreLocale; label: string }[] = [
631
+ { code: 'en', label: 'EN' },
632
+ { code: 'ru', label: 'RU' },
633
+ { code: 'he', label: 'HE' },
634
+ ];
635
+
636
+ export function LayoutHeader() {
637
+ function handleLocale(code: IcoreLocale) {
638
+ setStoredLocale(code);
639
+ window.location.reload();
640
+ }
641
+
642
+ return (
643
+ <header className="sticky top-0 z-30 flex h-14 items-center justify-between border-b border-[--color-border] bg-[--color-background]/80 px-4 backdrop-blur-sm">
644
+ <div className="flex items-center gap-2">
645
+ <div className="flex h-6 w-6 items-center justify-center rounded bg-[--color-primary]">
646
+ <span className="text-xs font-bold text-[--color-primary-foreground]">i</span>
647
+ </div>
648
+ <span className="text-sm font-semibold tracking-tight">iCore</span>
649
+ </div>
650
+
651
+ <div className="flex items-center gap-1">
652
+ <div className="flex items-center rounded-md border border-[--color-border] overflow-hidden mr-2">
653
+ {LOCALES.map(({ code, label }) => (
654
+ <button
655
+ key={code}
656
+ type="button"
657
+ onClick={() => handleLocale(code)}
658
+ className="px-2.5 py-1 text-xs text-[--color-muted-foreground] hover:bg-[--color-muted] hover:text-[--color-foreground] transition-colors cursor-pointer"
659
+ >
660
+ {label}
661
+ </button>
662
+ ))}
663
+ </div>
664
+
665
+ <ThemeToggle />
666
+ </div>
667
+ </header>
668
+ );
669
+ }
670
+ `;
671
+ var ANTD_MAIN_TSX = `import './globals.less';
672
+ import { StrictMode } from 'react';
673
+ import { createRoot } from 'react-dom/client';
674
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
675
+ import { RouterProvider, createRouter } from '@tanstack/react-router';
676
+ import { ConfigProvider, App as AntApp, theme } from 'antd';
677
+ import { I18nextProvider } from 'react-i18next';
678
+ import {
679
+ createIcoreApi,
680
+ createIcoreI18n,
681
+ ICORE_LOCALES,
682
+ useThemeStore,
683
+ } from '@icore/template-shared';
684
+ import { routeTree } from './routeTree.gen';
685
+
686
+ const queryClient = new QueryClient({
687
+ defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false } },
688
+ });
689
+
690
+ const router = createRouter({ routeTree, context: { queryClient } });
691
+
692
+ declare module '@tanstack/react-router' {
693
+ interface Register {
694
+ router: typeof router;
695
+ }
696
+ }
697
+
698
+ const i18n = createIcoreI18n({ resources: ICORE_LOCALES });
699
+
700
+ // Single shared API instance \u2014 used by every query in src/queries/
701
+ export const api = createIcoreApi({
702
+ baseUrl: import.meta.env.VITE_API_URL ?? '/api',
703
+ });
704
+
705
+ function Root() {
706
+ const mode = useThemeStore((s) => s.mode);
707
+ const algorithm = mode === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm;
708
+ return (
709
+ <ConfigProvider theme={{ algorithm, token: { colorPrimary: '#22c55e', colorLink: '#22c55e' } }}>
710
+ <AntApp>
711
+ <QueryClientProvider client={queryClient}>
712
+ <RouterProvider router={router} />
713
+ </QueryClientProvider>
714
+ </AntApp>
715
+ </ConfigProvider>
716
+ );
717
+ }
718
+
719
+ createRoot(document.getElementById('root')!).render(
720
+ <StrictMode>
721
+ <I18nextProvider i18n={i18n}>
722
+ <Root />
723
+ </I18nextProvider>
724
+ </StrictMode>,
725
+ );
726
+ `;
727
+ var ANTD_DASHBOARD_TSX = `import { createFileRoute, Outlet } from '@tanstack/react-router';
728
+ import { MainLayout } from '../layouts/MainLayout';
729
+
730
+ export const Route = createFileRoute('/_dashboard')({
731
+ component: () => (
732
+ <MainLayout>
733
+ <Outlet />
734
+ </MainLayout>
735
+ ),
736
+ });
737
+ `;
738
+ var ANTD_INDEX_TSX = `import { createFileRoute, Link } from '@tanstack/react-router';
739
+ import { LandingPage } from '@icore/template-shared';
740
+
741
+ // All version strings are injected at build time by vite.config.mts
742
+ // (reads root package.json via fs.readFileSync so they stay accurate
743
+ // even when workspace packages are bumped independently).
744
+ const APP_VERSION = (import.meta.env.VITE_APP_VERSION as string | undefined) ?? '0.0.0-dev';
745
+
746
+ export const Route = createFileRoute('/')({
747
+ component: () => (
748
+ <LandingPage
749
+ coreVersion={APP_VERSION}
750
+ uiLibrary="antd"
751
+ deps={[
752
+ { name: 'react', version: (import.meta.env.VITE_DEP_REACT as string) ?? '?' },
753
+ { name: 'antd', version: (import.meta.env.VITE_DEP_ANTD as string) ?? '?' },
754
+ { name: 'vite', version: (import.meta.env.VITE_DEP_VITE as string) ?? '?' },
755
+ {
756
+ name: '@tanstack/react-router',
757
+ version: (import.meta.env.VITE_DEP_TANSTACK_ROUTER as string) ?? '?',
758
+ },
759
+ {
760
+ name: '@tanstack/react-query',
761
+ version: (import.meta.env.VITE_DEP_TANSTACK_QUERY as string) ?? '?',
762
+ },
763
+ { name: 'zustand', version: (import.meta.env.VITE_DEP_ZUSTAND as string) ?? '?' },
764
+ { name: '@casl/ability', version: (import.meta.env.VITE_DEP_CASL as string) ?? '?' },
765
+ ]}
766
+ ctaHref="/dashboard"
767
+ ctaLabel={<Link to="/dashboard">Dashboard \u2192</Link>}
768
+ />
769
+ ),
770
+ });
771
+ `;
772
+ var ANTD_LAYOUT_HEADER_TSX = `import { Button, Layout, Space } from 'antd';
773
+ import { setStoredLocale, type IcoreLocale } from '@icore/template-shared';
774
+ import { ThemeToggle } from '../ThemeToggle';
775
+
776
+ const APP_VERSION = (import.meta.env.VITE_APP_VERSION as string | undefined) ?? '0.0.0-dev';
777
+
778
+ const LOCALES: { code: IcoreLocale; label: string }[] = [
779
+ { code: 'en', label: 'EN' },
780
+ { code: 'ru', label: 'RU' },
781
+ { code: 'he', label: 'HE' },
782
+ ];
783
+
784
+ export function LayoutHeader() {
785
+ function handleLocale(code: IcoreLocale) {
786
+ setStoredLocale(code);
787
+ window.location.reload();
788
+ }
789
+
790
+ return (
791
+ <Layout.Header
792
+ style={{
793
+ display: 'flex',
794
+ alignItems: 'center',
795
+ justifyContent: 'space-between',
796
+ padding: '0 24px',
797
+ }}
798
+ >
799
+ <Space>
800
+ <span style={{ color: '#fff', fontWeight: 600, fontSize: 16 }}>iCore</span>
801
+ <span
802
+ style={{
803
+ color: 'rgba(255,255,255,0.45)',
804
+ fontSize: 11,
805
+ background: 'rgba(255,255,255,0.1)',
806
+ padding: '1px 6px',
807
+ borderRadius: 4,
808
+ }}
809
+ >
810
+ v{APP_VERSION}
811
+ </span>
812
+ </Space>
813
+
814
+ <Space size="middle">
815
+ <Space size={4}>
816
+ {LOCALES.map(({ code, label }) => (
817
+ <Button
818
+ key={code}
819
+ size="small"
820
+ type="text"
821
+ style={{ color: 'rgba(255,255,255,0.65)' }}
822
+ onClick={() => handleLocale(code)}
823
+ >
824
+ {label}
825
+ </Button>
826
+ ))}
827
+ </Space>
828
+
829
+ <ThemeToggle />
830
+ </Space>
831
+ </Layout.Header>
832
+ );
833
+ }
834
+ `;
835
+ var MUI_MAIN_TSX = `import './globals.css';
836
+ import { StrictMode, useMemo } from 'react';
837
+ import { createRoot } from 'react-dom/client';
838
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
839
+ import { RouterProvider, createRouter } from '@tanstack/react-router';
840
+ import { CssBaseline, ThemeProvider, createTheme } from '@mui/material';
841
+ import { I18nextProvider } from 'react-i18next';
842
+ import {
843
+ createIcoreApi,
844
+ createIcoreI18n,
845
+ ICORE_LOCALES,
846
+ useThemeStore,
847
+ } from '@icore/template-shared';
848
+ import { routeTree } from './routeTree.gen';
849
+ import { wireMuiNotifier } from './lib/notify';
850
+
851
+ const queryClient = new QueryClient({
852
+ defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false } },
853
+ });
854
+
855
+ const router = createRouter({ routeTree, context: { queryClient } });
856
+
857
+ declare module '@tanstack/react-router' {
858
+ interface Register {
859
+ router: typeof router;
860
+ }
861
+ }
862
+
863
+ const i18n = createIcoreI18n({ resources: ICORE_LOCALES });
864
+
865
+ export const api = createIcoreApi({
866
+ baseUrl: import.meta.env.VITE_API_URL ?? '/api',
867
+ });
868
+
869
+ wireMuiNotifier();
870
+
871
+ function Root() {
872
+ const mode = useThemeStore((s) => s.mode);
873
+ const theme = useMemo(
874
+ () => createTheme({ palette: { mode, primary: { main: '#22c55e' } } }),
875
+ [mode],
876
+ );
877
+ return (
878
+ <ThemeProvider theme={theme}>
879
+ <CssBaseline />
880
+ <QueryClientProvider client={queryClient}>
881
+ <RouterProvider router={router} />
882
+ </QueryClientProvider>
883
+ </ThemeProvider>
884
+ );
885
+ }
886
+
887
+ createRoot(document.getElementById('root')!).render(
888
+ <StrictMode>
889
+ <I18nextProvider i18n={i18n}>
890
+ <Root />
891
+ </I18nextProvider>
892
+ </StrictMode>,
893
+ );
894
+ `;
895
+ var MUI_DASHBOARD_TSX = `import { createFileRoute, Outlet } from '@tanstack/react-router';
896
+ import { MainLayout } from '../layouts/MainLayout';
897
+
898
+ export const Route = createFileRoute('/_dashboard')({
899
+ component: () => (
900
+ <MainLayout>
901
+ <Outlet />
902
+ </MainLayout>
903
+ ),
904
+ });
905
+ `;
906
+ var MUI_INDEX_TSX = `import { createFileRoute, Link } from '@tanstack/react-router';
907
+ import { LandingPage } from '@icore/template-shared';
908
+
909
+ // All version strings are injected at build time by vite.config.mts
910
+ // (reads root package.json via fs.readFileSync so they stay accurate
911
+ // even when workspace packages are bumped independently).
912
+ const APP_VERSION = (import.meta.env.VITE_APP_VERSION as string | undefined) ?? '0.0.0-dev';
913
+
914
+ export const Route = createFileRoute('/')({
915
+ component: () => (
916
+ <LandingPage
917
+ coreVersion={APP_VERSION}
918
+ uiLibrary="mui"
919
+ deps={[
920
+ { name: 'react', version: (import.meta.env.VITE_DEP_REACT as string) ?? '?' },
921
+ { name: '@mui/material', version: (import.meta.env.VITE_DEP_MUI as string) ?? '?' },
922
+ { name: 'vite', version: (import.meta.env.VITE_DEP_VITE as string) ?? '?' },
923
+ {
924
+ name: '@tanstack/react-router',
925
+ version: (import.meta.env.VITE_DEP_TANSTACK_ROUTER as string) ?? '?',
926
+ },
927
+ {
928
+ name: '@tanstack/react-query',
929
+ version: (import.meta.env.VITE_DEP_TANSTACK_QUERY as string) ?? '?',
930
+ },
931
+ { name: 'zustand', version: (import.meta.env.VITE_DEP_ZUSTAND as string) ?? '?' },
932
+ { name: '@casl/ability', version: (import.meta.env.VITE_DEP_CASL as string) ?? '?' },
933
+ ]}
934
+ ctaHref="/dashboard"
935
+ ctaLabel={<Link to="/dashboard">Dashboard \u2192</Link>}
936
+ />
937
+ ),
938
+ });
939
+ `;
940
+ var MUI_LAYOUT_HEADER_TSX = `import { AppBar, Box, Button, Toolbar, Typography } from '@mui/material';
941
+ import { useTranslation } from 'react-i18next';
942
+ import { setStoredLocale, type IcoreLocale } from '@icore/template-shared';
943
+ import { ThemeToggle } from '../ThemeToggle';
944
+
945
+ const APP_VERSION = (import.meta.env.VITE_APP_VERSION as string | undefined) ?? '0.0.0-dev';
946
+
947
+ const LOCALES: { code: IcoreLocale; label: string }[] = [
948
+ { code: 'en', label: 'EN' },
949
+ { code: 'ru', label: 'RU' },
950
+ { code: 'he', label: 'HE' },
951
+ ];
952
+
953
+ export function LayoutHeader() {
954
+ const { i18n } = useTranslation();
955
+ const currentLocale = i18n.language as IcoreLocale;
956
+
957
+ function handleLocale(code: IcoreLocale) {
958
+ setStoredLocale(code);
959
+ window.location.reload();
960
+ }
961
+
962
+ return (
963
+ <AppBar position="sticky" color="default" elevation={1}>
964
+ <Toolbar sx={{ justifyContent: 'space-between' }}>
965
+ <Typography variant="h6" component="div" fontWeight={600}>
966
+ iCore{' '}
967
+ <span style={{ opacity: 0.6, fontSize: '0.75em', fontWeight: 400 }}>v{APP_VERSION}</span>
968
+ </Typography>
969
+
970
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
971
+ <Box sx={{ display: 'flex', gap: 0.5 }}>
972
+ {LOCALES.map(({ code, label }) => (
973
+ <Button
974
+ key={code}
975
+ size="small"
976
+ variant={currentLocale === code ? 'contained' : 'text'}
977
+ onClick={() => handleLocale(code)}
978
+ >
979
+ {label}
980
+ </Button>
981
+ ))}
982
+ </Box>
983
+
984
+ <ThemeToggle />
985
+ </Box>
986
+ </Toolbar>
987
+ </AppBar>
988
+ );
989
+ }
990
+ `;
991
+ var COMMON_VARIANTS = {
992
+ "apps/api/src/main.ts": GATEWAY_MAIN_TS,
993
+ "apps/api/src/app/app.module.ts": GATEWAY_APP_MODULE_TS,
994
+ "libs/shared/src/client.ts": SHARED_CLIENT_TS,
995
+ "libs/shared/src/index.ts": SHARED_INDEX_TS,
996
+ "libs/template-shared/src/index.ts": TEMPLATE_SHARED_INDEX_TS
997
+ };
998
+ var UI_VARIANTS = {
999
+ shadcn: {
1000
+ "apps/client/src/main.tsx": SHADCN_MAIN_TSX,
1001
+ "apps/client/src/routes/_dashboard.tsx": SHADCN_DASHBOARD_TSX,
1002
+ "apps/client/src/routes/index.tsx": SHADCN_INDEX_TSX,
1003
+ "apps/client/src/components/layout/LayoutHeader.tsx": SHADCN_LAYOUT_HEADER_TSX
1004
+ },
1005
+ antd: {
1006
+ "apps/client/src/main.tsx": ANTD_MAIN_TSX,
1007
+ "apps/client/src/routes/_dashboard.tsx": ANTD_DASHBOARD_TSX,
1008
+ "apps/client/src/routes/index.tsx": ANTD_INDEX_TSX,
1009
+ "apps/client/src/components/layout/LayoutHeader.tsx": ANTD_LAYOUT_HEADER_TSX
1010
+ },
1011
+ mui: {
1012
+ "apps/client/src/main.tsx": MUI_MAIN_TSX,
1013
+ "apps/client/src/routes/_dashboard.tsx": MUI_DASHBOARD_TSX,
1014
+ "apps/client/src/routes/index.tsx": MUI_INDEX_TSX,
1015
+ "apps/client/src/components/layout/LayoutHeader.tsx": MUI_LAYOUT_HEADER_TSX
1016
+ }
1017
+ };
1018
+ async function applyAuthNoneVariants(targetDir, ui) {
1019
+ const uiFiles = UI_VARIANTS[ui] ?? UI_VARIANTS["shadcn"];
1020
+ const all = { ...COMMON_VARIANTS, ...uiFiles };
1021
+ for (const [rel, content] of Object.entries(all)) {
1022
+ const dest = (0, import_node_path3.join)(targetDir, rel);
1023
+ try {
1024
+ await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(dest), { recursive: true });
1025
+ await (0, import_promises3.writeFile)(dest, content);
1026
+ } catch {
1027
+ }
1028
+ }
362
1029
  }
363
1030
 
364
1031
  // src/manifest/wire-features.ts
365
- var import_promises4 = require("fs/promises");
366
- var import_node_path4 = require("path");
1032
+ var import_promises5 = require("fs/promises");
1033
+ var import_node_path5 = require("path");
367
1034
 
368
1035
  // src/manifest/index.ts
369
1036
  var EMPTY = { libDirs: [], deps: {}, tsPaths: {} };
@@ -523,8 +1190,8 @@ var MANIFEST = {
523
1190
  };
524
1191
 
525
1192
  // src/manifest/wire-provider.ts
526
- var import_promises3 = require("fs/promises");
527
- var import_node_path3 = require("path");
1193
+ var import_promises4 = require("fs/promises");
1194
+ var import_node_path4 = require("path");
528
1195
  async function writeProvider(targetDir, axis, provider) {
529
1196
  const nestModule = axis.section[provider]?.nestModule;
530
1197
  if (!nestModule) throw new Error(`provider "${provider}" has no nestModule in the manifest`);
@@ -535,27 +1202,27 @@ const ENV_PATH = '${axis.envPath}';
535
1202
 
536
1203
  export const ${axis.exportConst} = ${symbol}.forRoot(ENV_PATH);
537
1204
  `;
538
- await (0, import_promises3.writeFile)((0, import_node_path3.join)(targetDir, axis.providerFile), content);
1205
+ await (0, import_promises4.writeFile)((0, import_node_path4.join)(targetDir, axis.providerFile), content);
539
1206
  }
540
1207
  async function stripJsonKeys(path, drop) {
541
1208
  try {
542
- const pkg = JSON.parse(await (0, import_promises3.readFile)(path, "utf8"));
1209
+ const pkg = JSON.parse(await (0, import_promises4.readFile)(path, "utf8"));
543
1210
  for (const field of ["dependencies", "devDependencies"]) {
544
1211
  const deps = pkg[field];
545
1212
  if (!deps) continue;
546
1213
  for (const k of Object.keys(deps)) if (drop(k)) delete deps[k];
547
1214
  }
548
- await (0, import_promises3.writeFile)(path, JSON.stringify(pkg, null, 2) + "\n");
1215
+ await (0, import_promises4.writeFile)(path, JSON.stringify(pkg, null, 2) + "\n");
549
1216
  } catch {
550
1217
  }
551
1218
  }
552
1219
  async function stripTsconfigKeys(targetDir, aliases) {
553
- const path = (0, import_node_path3.join)(targetDir, "tsconfig.base.json");
1220
+ const path = (0, import_node_path4.join)(targetDir, "tsconfig.base.json");
554
1221
  try {
555
- const parsed = JSON.parse(await (0, import_promises3.readFile)(path, "utf8"));
1222
+ const parsed = JSON.parse(await (0, import_promises4.readFile)(path, "utf8"));
556
1223
  const paths = parsed.compilerOptions?.paths;
557
1224
  if (paths) for (const a of aliases) delete paths[a];
558
- await (0, import_promises3.writeFile)(path, JSON.stringify(parsed, null, 2) + "\n");
1225
+ await (0, import_promises4.writeFile)(path, JSON.stringify(parsed, null, 2) + "\n");
559
1226
  } catch {
560
1227
  }
561
1228
  }
@@ -564,10 +1231,10 @@ async function cleanupUnusedAxis(targetDir, axis, chosen) {
564
1231
  if (provider === chosen) continue;
565
1232
  const unit = axis.section[provider];
566
1233
  for (const dir of unit.libDirs)
567
- await (0, import_promises3.rm)((0, import_node_path3.join)(targetDir, dir), { recursive: true, force: true });
568
- for (const t of unit.appTests ?? []) await (0, import_promises3.rm)((0, import_node_path3.join)(targetDir, t), { force: true });
1234
+ await (0, import_promises4.rm)((0, import_node_path4.join)(targetDir, dir), { recursive: true, force: true });
1235
+ for (const t of unit.appTests ?? []) await (0, import_promises4.rm)((0, import_node_path4.join)(targetDir, t), { force: true });
569
1236
  const dropKeys = /* @__PURE__ */ new Set([...Object.keys(unit.tsPaths), ...Object.keys(unit.deps)]);
570
- await stripJsonKeys((0, import_node_path3.join)(targetDir, axis.msPackageJson), (k) => dropKeys.has(k));
1237
+ await stripJsonKeys((0, import_node_path4.join)(targetDir, axis.msPackageJson), (k) => dropKeys.has(k));
571
1238
  await stripTsconfigKeys(targetDir, Object.keys(unit.tsPaths));
572
1239
  }
573
1240
  }
@@ -596,7 +1263,7 @@ async function writeFeaturesWiring(targetDir, opts) {
596
1263
  })
597
1264
  export class FeaturesModule {}
598
1265
  `;
599
- await (0, import_promises4.writeFile)((0, import_node_path4.join)(targetDir, FEATURES_MODULE), featuresModule);
1266
+ await (0, import_promises5.writeFile)((0, import_node_path5.join)(targetDir, FEATURES_MODULE), featuresModule);
600
1267
  const services = [];
601
1268
  if (opts.authProvider !== "none") services.push({ name: "auth", prefix: "AUTH" });
602
1269
  if (opts.upload !== "none") services.push({ name: "upload", prefix: "UPLOAD" });
@@ -610,14 +1277,14 @@ export const GATEWAY_SERVICES = [
610
1277
  ${entries}
611
1278
  ];
612
1279
  `;
613
- await (0, import_promises4.writeFile)((0, import_node_path4.join)(targetDir, GATEWAY_SERVICES), gatewayServices);
1280
+ await (0, import_promises5.writeFile)((0, import_node_path5.join)(targetDir, GATEWAY_SERVICES), gatewayServices);
614
1281
  }
615
1282
  async function stripJobsDockerCompose(targetDir) {
616
- const composePath = (0, import_node_path4.join)(targetDir, "docker-compose.yml");
1283
+ const composePath = (0, import_node_path5.join)(targetDir, "docker-compose.yml");
617
1284
  try {
618
- const compose = await (0, import_promises4.readFile)(composePath, "utf8");
1285
+ const compose = await (0, import_promises5.readFile)(composePath, "utf8");
619
1286
  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, "");
620
- await (0, import_promises4.writeFile)(composePath, next);
1287
+ await (0, import_promises5.writeFile)(composePath, next);
621
1288
  } catch {
622
1289
  }
623
1290
  }
@@ -627,18 +1294,38 @@ async function cleanupUnusedFeatures(targetDir, opts) {
627
1294
  if (chosen.has(key)) continue;
628
1295
  const unit = FEATURES[key];
629
1296
  for (const dir of unit.libDirs)
630
- await (0, import_promises4.rm)((0, import_node_path4.join)(targetDir, dir), { recursive: true, force: true });
1297
+ await (0, import_promises5.rm)((0, import_node_path5.join)(targetDir, dir), { recursive: true, force: true });
631
1298
  const dropKeys = /* @__PURE__ */ new Set([...Object.keys(unit.tsPaths), ...Object.keys(unit.deps)]);
632
- await stripJsonKeys((0, import_node_path4.join)(targetDir, API_PKG), (k) => dropKeys.has(k));
1299
+ await stripJsonKeys((0, import_node_path5.join)(targetDir, API_PKG), (k) => dropKeys.has(k));
633
1300
  await stripTsconfigKeys(targetDir, Object.keys(unit.tsPaths));
634
1301
  if (unit.gatewayService) await stripGatewayTransport(targetDir, unit.gatewayService.prefix);
635
1302
  if (unit.dockerService === "jobs") await stripJobsDockerCompose(targetDir);
1303
+ if (key === "jobs") {
1304
+ try {
1305
+ await (0, import_promises5.unlink)((0, import_node_path5.join)(targetDir, "libs/shared/src/jobs.ts"));
1306
+ } catch {
1307
+ }
1308
+ try {
1309
+ await (0, import_promises5.unlink)((0, import_node_path5.join)(targetDir, "libs/shared/src/__tests__/jobs.unit.test.ts"));
1310
+ } catch {
1311
+ }
1312
+ const sharedIdx = (0, import_node_path5.join)(targetDir, "libs/shared/src/index.ts");
1313
+ try {
1314
+ const src = await (0, import_promises5.readFile)(sharedIdx, "utf8");
1315
+ await (0, import_promises5.writeFile)(sharedIdx, src.replace(/^export \* from '\.\/jobs';\n/m, ""));
1316
+ } catch {
1317
+ }
1318
+ }
1319
+ }
1320
+ try {
1321
+ await (0, import_promises5.rmdir)((0, import_node_path5.join)(targetDir, "apps/client/src/queries"));
1322
+ } catch {
636
1323
  }
637
1324
  }
638
1325
 
639
1326
  // src/manifest/wire-client.ts
640
- var import_promises5 = require("fs/promises");
641
- var import_node_path5 = require("path");
1327
+ var import_promises6 = require("fs/promises");
1328
+ var import_node_path6 = require("path");
642
1329
  var NAV_CONFIG_FILE = "apps/client/src/nav.config.ts";
643
1330
  var BASE_NAV = [
644
1331
  { to: "/dashboard", labelKey: "nav.dashboard", iconName: "dashboard", exact: true }
@@ -676,12 +1363,12 @@ export const NAV_CONFIG: NavItem[] = [
676
1363
  ` + entries.map(renderEntry).join("\n") + `
677
1364
  ];
678
1365
  `;
679
- await (0, import_promises5.writeFile)((0, import_node_path5.join)(targetDir, NAV_CONFIG_FILE), content);
1366
+ await (0, import_promises6.writeFile)((0, import_node_path6.join)(targetDir, NAV_CONFIG_FILE), content);
680
1367
  }
681
1368
 
682
1369
  // src/manifest/blueprint.ts
683
- var import_promises6 = require("fs/promises");
684
- var import_node_path6 = require("path");
1370
+ var import_promises7 = require("fs/promises");
1371
+ var import_node_path7 = require("path");
685
1372
  async function writeBlueprintJson(targetDir, opts) {
686
1373
  const blueprint = {
687
1374
  schemaVersion: 1,
@@ -696,10 +1383,10 @@ async function writeBlueprintJson(targetDir, opts) {
696
1383
  transport: opts.transport,
697
1384
  packageManager: opts.packageManager
698
1385
  };
699
- await (0, import_promises6.writeFile)((0, import_node_path6.join)(targetDir, "blueprint.json"), JSON.stringify(blueprint, null, 2) + "\n");
1386
+ await (0, import_promises7.writeFile)((0, import_node_path7.join)(targetDir, "blueprint.json"), JSON.stringify(blueprint, null, 2) + "\n");
700
1387
  }
701
1388
  async function writeJson(targetDir, rel, data) {
702
- await (0, import_promises6.writeFile)((0, import_node_path6.join)(targetDir, rel, "blueprint.json"), JSON.stringify(data, null, 2) + "\n");
1389
+ await (0, import_promises7.writeFile)((0, import_node_path7.join)(targetDir, rel, "blueprint.json"), JSON.stringify(data, null, 2) + "\n");
703
1390
  }
704
1391
  async function writeServiceBlueprints(targetDir, opts) {
705
1392
  const t = opts.transport;
@@ -793,11 +1480,11 @@ var writeDbProvider = (targetDir, provider) => writeProvider(targetDir, DB, prov
793
1480
  var cleanupUnusedDb = (targetDir, chosen) => cleanupUnusedAxis(targetDir, DB, chosen);
794
1481
 
795
1482
  // src/lib/scaffold-pkg.ts
796
- var import_promises7 = require("fs/promises");
797
- var import_node_path7 = require("path");
1483
+ var import_promises8 = require("fs/promises");
1484
+ var import_node_path8 = require("path");
798
1485
  async function writePnpmWorkspace(targetDir) {
799
- const pkgPath = (0, import_node_path7.join)(targetDir, "package.json");
800
- const pkg = JSON.parse(await (0, import_promises7.readFile)(pkgPath, "utf8"));
1486
+ const pkgPath = (0, import_node_path8.join)(targetDir, "package.json");
1487
+ const pkg = JSON.parse(await (0, import_promises8.readFile)(pkgPath, "utf8"));
801
1488
  const workspaces = pkg.workspaces ?? [];
802
1489
  const packagesBlock = workspaces.map((p2) => ` - '${p2}'`).join("\n");
803
1490
  const allowBuilds = [
@@ -820,22 +1507,22 @@ ${packagesBlock}
820
1507
  allowBuilds:
821
1508
  ${allowBuilds}
822
1509
  `;
823
- await (0, import_promises7.writeFile)((0, import_node_path7.join)(targetDir, "pnpm-workspace.yaml"), content);
1510
+ await (0, import_promises8.writeFile)((0, import_node_path8.join)(targetDir, "pnpm-workspace.yaml"), content);
824
1511
  }
825
1512
  async function rewritePnpmWorkspaceDeps(targetDir) {
826
1513
  async function walk2(dir) {
827
1514
  const found = [];
828
1515
  let entries;
829
1516
  try {
830
- entries = await (0, import_promises7.readdir)(dir, { withFileTypes: true });
1517
+ entries = await (0, import_promises8.readdir)(dir, { withFileTypes: true });
831
1518
  } catch {
832
1519
  return found;
833
1520
  }
834
1521
  for (const e of entries) {
835
1522
  if (e.isDirectory() && e.name !== "node_modules") {
836
- found.push(...await walk2((0, import_node_path7.join)(dir, e.name)));
1523
+ found.push(...await walk2((0, import_node_path8.join)(dir, e.name)));
837
1524
  } else if (e.isFile() && e.name === "package.json") {
838
- found.push((0, import_node_path7.join)(dir, e.name));
1525
+ found.push((0, import_node_path8.join)(dir, e.name));
839
1526
  }
840
1527
  }
841
1528
  return found;
@@ -843,17 +1530,17 @@ async function rewritePnpmWorkspaceDeps(targetDir) {
843
1530
  const pkgFiles = await walk2(targetDir);
844
1531
  for (const f of pkgFiles) {
845
1532
  try {
846
- const raw = await (0, import_promises7.readFile)(f, "utf8");
1533
+ const raw = await (0, import_promises8.readFile)(f, "utf8");
847
1534
  const next = raw.replace(/"(@icore\/[^"]+)":\s*"\*"/g, '"$1": "workspace:*"');
848
- if (next !== raw) await (0, import_promises7.writeFile)(f, next);
1535
+ if (next !== raw) await (0, import_promises8.writeFile)(f, next);
849
1536
  } catch {
850
1537
  }
851
1538
  }
852
1539
  }
853
1540
  async function patchGitignoreForPm(targetDir, pm) {
854
- const giPath = (0, import_node_path7.join)(targetDir, ".gitignore");
1541
+ const giPath = (0, import_node_path8.join)(targetDir, ".gitignore");
855
1542
  try {
856
- let src = await (0, import_promises7.readFile)(giPath, "utf8");
1543
+ let src = await (0, import_promises8.readFile)(giPath, "utf8");
857
1544
  src = src.replace(/^# Build artifacts.*\ntools\/create-icore\/templates\/\s*\n/m, "");
858
1545
  if (pm !== "yarn") {
859
1546
  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, "");
@@ -868,7 +1555,7 @@ async function patchGitignoreForPm(targetDir, pm) {
868
1555
  src += "\n# npm\nnpm-debug.log*\n";
869
1556
  }
870
1557
  }
871
- await (0, import_promises7.writeFile)(giPath, src);
1558
+ await (0, import_promises8.writeFile)(giPath, src);
872
1559
  } catch {
873
1560
  }
874
1561
  }
@@ -876,14 +1563,15 @@ async function writeAiFiles(targetDir, opts) {
876
1563
  const pm = opts.packageManager;
877
1564
  const nx = pm === "npm" ? "npx nx" : `${pm} nx`;
878
1565
  const devCmd = pmRun(pm, "dev");
879
- const activeMSes = ["auth (port 4001)"];
1566
+ const activeMSes = [];
1567
+ if (opts.authProvider !== "none") activeMSes.push("auth (port 4001)");
880
1568
  if (opts.upload !== "none") activeMSes.push(`upload (port 4002)`);
881
1569
  if (opts.payment !== "none") activeMSes.push(`payment (port 4003)`);
882
1570
  if (opts.example !== "none") activeMSes.push(`notes (port 4004)`);
883
1571
  if (opts.jobs !== "none") activeMSes.push(`jobs (standalone)`);
884
1572
  const usesSupabase = opts.authProvider === "supabase" || opts.dbProvider === "supabase" || opts.upload === "supabase";
885
1573
  const usesFirebase = opts.authProvider === "firebase" || opts.dbProvider === "firebase" || opts.upload === "firebase";
886
- await (0, import_promises7.writeFile)((0, import_node_path7.join)(targetDir, "CLAUDE.md"), "@AGENTS.md\n");
1574
+ await (0, import_promises8.writeFile)((0, import_node_path8.join)(targetDir, "CLAUDE.md"), "@AGENTS.md\n");
887
1575
  const uiLabel = { shadcn: "shadcn/ui + Tailwind", antd: "Ant Design 6", mui: "MUI 6" }[opts.ui];
888
1576
  const readme = `# ${opts.projectName}
889
1577
 
@@ -905,9 +1593,7 @@ async function writeAiFiles(targetDir, opts) {
905
1593
 
906
1594
  \`\`\`bash
907
1595
  # 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)
1596
+ ${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
1597
 
912
1598
  # 2. Start everything
913
1599
  ${devCmd}
@@ -933,7 +1619,7 @@ ${pm === "yarn" ? "yarn remove-notes" : pm === "pnpm" ? "pnpm remove-notes" : "n
933
1619
 
934
1620
  Apache-2.0
935
1621
  `;
936
- await (0, import_promises7.writeFile)((0, import_node_path7.join)(targetDir, "README.md"), readme);
1622
+ await (0, import_promises8.writeFile)((0, import_node_path8.join)(targetDir, "README.md"), readme);
937
1623
  const agents = `# ${opts.projectName} \u2014 Agent Instructions
938
1624
 
939
1625
  ## Stack snapshot
@@ -1003,10 +1689,10 @@ ${nx} g @nx/nest:resource # generate NestJS resource
1003
1689
 
1004
1690
  | File | Key vars |
1005
1691
  |------|----------|
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) |
1692
+ ${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`"} |
1693
+ ` : ""}${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PROVIDER=${opts.upload}\`, provider creds |
1694
+ ` : ""}${opts.example !== "none" ? `| \`apps/microservices/notes/.env\` | \`DB_PROVIDER=${opts.dbProvider}\`, DB creds |
1695
+ ` : ""}| \`apps/client/.env\` | \`VITE_API_URL=/api\` (proxied to :3001 in dev) |
1010
1696
 
1011
1697
  ## Testing
1012
1698
 
@@ -1014,8 +1700,8 @@ ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PRO
1014
1700
  - Test behaviour, not implementation. Fake strategies from \`@icore/shared\` (FakeAuthStrategy etc.) serve as test doubles.
1015
1701
  - Run: \`${nx} test <project>\`
1016
1702
  `;
1017
- await (0, import_promises7.writeFile)((0, import_node_path7.join)(targetDir, "AGENTS.md"), agents);
1018
- await (0, import_promises7.mkdir)((0, import_node_path7.join)(targetDir, ".claude"), { recursive: true });
1703
+ await (0, import_promises8.writeFile)((0, import_node_path8.join)(targetDir, "AGENTS.md"), agents);
1704
+ await (0, import_promises8.mkdir)((0, import_node_path8.join)(targetDir, ".claude"), { recursive: true });
1019
1705
  const mcpServers = {
1020
1706
  nx: {
1021
1707
  command: "npx",
@@ -1056,8 +1742,8 @@ ${opts.upload !== "none" ? `| \`apps/microservices/upload/.env\` | \`STORAGE_PRO
1056
1742
  ]
1057
1743
  }
1058
1744
  };
1059
- await (0, import_promises7.writeFile)(
1060
- (0, import_node_path7.join)(targetDir, ".claude", "settings.json"),
1745
+ await (0, import_promises8.writeFile)(
1746
+ (0, import_node_path8.join)(targetDir, ".claude", "settings.json"),
1061
1747
  JSON.stringify(settings, null, 2) + "\n"
1062
1748
  );
1063
1749
  }
@@ -1077,30 +1763,30 @@ var IGNORE_TOP = /* @__PURE__ */ new Set([
1077
1763
  ".vscode"
1078
1764
  ]);
1079
1765
  async function copyTree(src, dest) {
1080
- await (0, import_promises8.mkdir)(dest, { recursive: true });
1081
- const entries = await (0, import_promises8.readdir)(src, { withFileTypes: true });
1766
+ await (0, import_promises9.mkdir)(dest, { recursive: true });
1767
+ const entries = await (0, import_promises9.readdir)(src, { withFileTypes: true });
1082
1768
  for (const entry of entries) {
1083
1769
  if (IGNORE_TOP.has(entry.name)) continue;
1084
- const s = (0, import_node_path8.join)(src, entry.name);
1085
- const d = (0, import_node_path8.join)(dest, entry.name);
1770
+ const s = (0, import_node_path9.join)(src, entry.name);
1771
+ const d = (0, import_node_path9.join)(dest, entry.name);
1086
1772
  if (entry.isDirectory()) await copyTree(s, d);
1087
- else if (entry.isFile()) await (0, import_promises8.copyFile)(s, d);
1773
+ else if (entry.isFile()) await (0, import_promises9.copyFile)(s, d);
1088
1774
  }
1089
1775
  }
1090
1776
  async function selectClientTemplate(targetDir, opts) {
1091
- const templatesRoot = (0, import_node_path8.join)(targetDir, "apps/templates");
1092
- const chosen = (0, import_node_path8.join)(templatesRoot, `client-${opts.ui}`);
1093
- const destClient = (0, import_node_path8.join)(targetDir, "apps/client");
1777
+ const templatesRoot = (0, import_node_path9.join)(targetDir, "apps/templates");
1778
+ const chosen = (0, import_node_path9.join)(templatesRoot, `client-${opts.ui}`);
1779
+ const destClient = (0, import_node_path9.join)(targetDir, "apps/client");
1094
1780
  let chosenUi = opts.ui;
1095
1781
  try {
1096
- const s = await (0, import_promises8.stat)(chosen);
1782
+ const s = await (0, import_promises9.stat)(chosen);
1097
1783
  if (!s.isDirectory()) throw new Error("not a dir");
1098
1784
  await copyTree(chosen, destClient);
1099
1785
  } catch {
1100
1786
  chosenUi = "shadcn";
1101
- await copyTree((0, import_node_path8.join)(templatesRoot, "client-shadcn"), destClient);
1787
+ await copyTree((0, import_node_path9.join)(templatesRoot, "client-shadcn"), destClient);
1102
1788
  }
1103
- await (0, import_promises8.rm)(templatesRoot, { recursive: true, force: true });
1789
+ await (0, import_promises9.rm)(templatesRoot, { recursive: true, force: true });
1104
1790
  await rewriteClientPaths(destClient, chosenUi);
1105
1791
  }
1106
1792
  async function rewriteClientPaths(clientDir, ui) {
@@ -1113,11 +1799,11 @@ async function rewriteClientPaths(clientDir, ui) {
1113
1799
  "eslint.config.mjs"
1114
1800
  ];
1115
1801
  for (const rel of candidates) {
1116
- const path = (0, import_node_path8.join)(clientDir, rel);
1802
+ const path = (0, import_node_path9.join)(clientDir, rel);
1117
1803
  try {
1118
- const raw = await (0, import_promises8.readFile)(path, "utf8");
1804
+ const raw = await (0, import_promises9.readFile)(path, "utf8");
1119
1805
  const next = raw.replaceAll("../../../", "../../").replaceAll(`apps/templates/client-${ui}`, "apps/client").replaceAll(`client-${ui}`, "client");
1120
- if (next !== raw) await (0, import_promises8.writeFile)(path, next);
1806
+ if (next !== raw) await (0, import_promises9.writeFile)(path, next);
1121
1807
  } catch {
1122
1808
  }
1123
1809
  }
@@ -1133,12 +1819,12 @@ function gitInit(cwd, projectName) {
1133
1819
  }
1134
1820
  function resolveYarnBin(cwd) {
1135
1821
  try {
1136
- const yarnrc = (0, import_node_fs.readFileSync)((0, import_node_path8.join)(cwd, ".yarnrc.yml"), "utf8");
1822
+ const yarnrc = (0, import_node_fs.readFileSync)((0, import_node_path9.join)(cwd, ".yarnrc.yml"), "utf8");
1137
1823
  const match = yarnrc.match(/^yarnPath:\s*(.+)$/m);
1138
- if (match?.[1]) return (0, import_node_path8.join)(cwd, match[1].trim());
1824
+ if (match?.[1]) return (0, import_node_path9.join)(cwd, match[1].trim());
1139
1825
  } catch {
1140
1826
  }
1141
- return (0, import_node_path8.join)(cwd, ".yarn", "releases", "yarn-4.5.0.cjs");
1827
+ return (0, import_node_path9.join)(cwd, ".yarn", "releases", "yarn-4.5.0.cjs");
1142
1828
  }
1143
1829
  function runInstall(cwd, pm) {
1144
1830
  if (pm === "yarn") {
@@ -1149,7 +1835,8 @@ function runInstall(cwd, pm) {
1149
1835
  (0, import_node_child_process.spawnSync)("pnpm", ["install"], { cwd, stdio: "inherit" });
1150
1836
  }
1151
1837
  }
1152
- async function scaffold(opts, templatesDir) {
1838
+ async function scaffold(rawOpts, templatesDir) {
1839
+ const opts = rawOpts.authProvider === "none" && rawOpts.example !== "none" ? { ...rawOpts, example: "none" } : rawOpts;
1153
1840
  await copyTree(templatesDir, opts.targetDir);
1154
1841
  await rewriteRootPackageJson(opts.targetDir, opts);
1155
1842
  if (opts.authProvider !== "none") await writeAuthEnv(opts.targetDir, opts);
@@ -1160,6 +1847,10 @@ async function scaffold(opts, templatesDir) {
1160
1847
  await writeRootEnv(opts.targetDir, opts);
1161
1848
  await selectClientTemplate(opts.targetDir, opts);
1162
1849
  await writeClientEnv(opts.targetDir);
1850
+ if (opts.authProvider === "none") {
1851
+ await removeAuthOnlyPaths(opts.targetDir);
1852
+ await applyAuthNoneVariants(opts.targetDir, opts.ui);
1853
+ }
1163
1854
  if (opts.upload === "none") await removeUploadStack(opts.targetDir);
1164
1855
  await cleanupUnusedFeatures(opts.targetDir, opts);
1165
1856
  await writeFeaturesWiring(opts.targetDir, opts);
@@ -1168,7 +1859,8 @@ async function scaffold(opts, templatesDir) {
1168
1859
  await cleanupUnusedAuth(opts.targetDir, opts.authProvider);
1169
1860
  await writeAuthProvider(opts.targetDir, opts.authProvider);
1170
1861
  } else {
1171
- await removeAuthStack(opts.targetDir);
1862
+ await removeAuthTsconfigPaths(opts.targetDir);
1863
+ await removeDockerComposeAuthService(opts.targetDir);
1172
1864
  }
1173
1865
  if (opts.upload !== "none") {
1174
1866
  await cleanupUnusedStorage(opts.targetDir, opts.upload);
@@ -1181,13 +1873,20 @@ async function scaffold(opts, templatesDir) {
1181
1873
  await writeDbProvider(opts.targetDir, opts.dbProvider);
1182
1874
  }
1183
1875
  await pruneRootProviderDeps(opts.targetDir, opts);
1876
+ if (opts.authProvider === "none" && opts.upload === "none" && opts.dbProvider === "none" && opts.payment === "none") {
1877
+ await removeStrategiesLib(opts.targetDir);
1878
+ }
1879
+ try {
1880
+ await (0, import_promises9.rmdir)((0, import_node_path9.join)(opts.targetDir, "apps/microservices"));
1881
+ } catch {
1882
+ }
1184
1883
  await writeBlueprintJson(opts.targetDir, opts);
1185
1884
  await writeServiceBlueprints(opts.targetDir, opts);
1186
1885
  if (opts.packageManager === "yarn") {
1187
- await (0, import_promises8.writeFile)((0, import_node_path8.join)(opts.targetDir, "yarn.lock"), "");
1886
+ await (0, import_promises9.writeFile)((0, import_node_path9.join)(opts.targetDir, "yarn.lock"), "");
1188
1887
  } else {
1189
- await (0, import_promises8.rm)((0, import_node_path8.join)(opts.targetDir, ".yarn"), { recursive: true, force: true });
1190
- await (0, import_promises8.rm)((0, import_node_path8.join)(opts.targetDir, ".yarnrc.yml"), { force: true });
1888
+ await (0, import_promises9.rm)((0, import_node_path9.join)(opts.targetDir, ".yarn"), { recursive: true, force: true });
1889
+ await (0, import_promises9.rm)((0, import_node_path9.join)(opts.targetDir, ".yarnrc.yml"), { force: true });
1191
1890
  }
1192
1891
  if (opts.packageManager === "pnpm") {
1193
1892
  await writePnpmWorkspace(opts.targetDir);
@@ -1201,13 +1900,13 @@ async function scaffold(opts, templatesDir) {
1201
1900
 
1202
1901
  // src/lib/prompts.ts
1203
1902
  var p = __toESM(require("@clack/prompts"), 1);
1204
- var import_node_path9 = require("path");
1205
- var import_promises10 = require("fs/promises");
1206
1903
  var import_node_path10 = require("path");
1904
+ var import_promises11 = require("fs/promises");
1905
+ var import_node_path11 = require("path");
1207
1906
  var import_node_url = require("url");
1208
1907
 
1209
1908
  // src/lib/config.ts
1210
- var import_promises9 = require("fs/promises");
1909
+ var import_promises10 = require("fs/promises");
1211
1910
  var ConfigFileError = class extends Error {
1212
1911
  constructor(message) {
1213
1912
  super(message);
@@ -1278,7 +1977,7 @@ function validateConfig(raw) {
1278
1977
  async function loadConfig(filePath) {
1279
1978
  let raw;
1280
1979
  try {
1281
- raw = await (0, import_promises9.readFile)(filePath, "utf8");
1980
+ raw = await (0, import_promises10.readFile)(filePath, "utf8");
1282
1981
  } catch {
1283
1982
  throw new ConfigFileError(`config file not found: ${filePath}`);
1284
1983
  }
@@ -1303,8 +2002,8 @@ function detectPackageManager() {
1303
2002
  }
1304
2003
  async function readSelfVersion() {
1305
2004
  try {
1306
- const here = (0, import_node_path10.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
1307
- const pkgRaw = await (0, import_promises10.readFile)((0, import_node_path10.join)(here, "..", "package.json"), "utf8");
2005
+ const here = (0, import_node_path11.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
2006
+ const pkgRaw = await (0, import_promises11.readFile)((0, import_node_path11.join)(here, "..", "package.json"), "utf8");
1308
2007
  const pkg = JSON.parse(pkgRaw);
1309
2008
  return pkg.version ?? null;
1310
2009
  } catch {
@@ -1512,7 +2211,7 @@ Re-run with @latest to refresh:
1512
2211
  }) === false;
1513
2212
  return {
1514
2213
  projectName,
1515
- targetDir: (0, import_node_path9.resolve)(cwd, projectName),
2214
+ targetDir: (0, import_node_path10.resolve)(cwd, projectName),
1516
2215
  authProvider,
1517
2216
  dbProvider,
1518
2217
  upload,
@@ -1528,23 +2227,23 @@ Re-run with @latest to refresh:
1528
2227
  }
1529
2228
 
1530
2229
  // src/manifest/audit.ts
1531
- var import_promises11 = require("fs/promises");
1532
- var import_node_path11 = require("path");
2230
+ var import_promises12 = require("fs/promises");
2231
+ var import_node_path12 = require("path");
1533
2232
  var IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".nx"]);
1534
2233
  async function walk(dir, out = []) {
1535
- const entries = await (0, import_promises11.readdir)(dir, { withFileTypes: true });
2234
+ const entries = await (0, import_promises12.readdir)(dir, { withFileTypes: true });
1536
2235
  for (const e of entries) {
1537
2236
  if (e.isDirectory()) {
1538
- if (!IGNORE_DIRS.has(e.name)) await walk((0, import_node_path11.join)(dir, e.name), out);
2237
+ if (!IGNORE_DIRS.has(e.name)) await walk((0, import_node_path12.join)(dir, e.name), out);
1539
2238
  } else if (/\.(ts|tsx|mjs)$/.test(e.name)) {
1540
- out.push((0, import_node_path11.join)(dir, e.name));
2239
+ out.push((0, import_node_path12.join)(dir, e.name));
1541
2240
  }
1542
2241
  }
1543
2242
  return out;
1544
2243
  }
1545
2244
  async function tsconfigAliases(dir) {
1546
2245
  try {
1547
- const raw = await (0, import_promises11.readFile)((0, import_node_path11.join)(dir, "tsconfig.base.json"), "utf8");
2246
+ const raw = await (0, import_promises12.readFile)((0, import_node_path12.join)(dir, "tsconfig.base.json"), "utf8");
1548
2247
  const aliases = /* @__PURE__ */ new Set();
1549
2248
  for (const m of raw.matchAll(/"(@icore\/[a-z0-9.-]+)"\s*:/g)) {
1550
2249
  if (m[1]) aliases.add(m[1]);
@@ -1562,7 +2261,7 @@ var PROVIDER_SDKS = {
1562
2261
  };
1563
2262
  async function readBlueprint(dir) {
1564
2263
  try {
1565
- return JSON.parse(await (0, import_promises11.readFile)((0, import_node_path11.join)(dir, "blueprint.json"), "utf8"));
2264
+ return JSON.parse(await (0, import_promises12.readFile)((0, import_node_path12.join)(dir, "blueprint.json"), "utf8"));
1566
2265
  } catch {
1567
2266
  return null;
1568
2267
  }
@@ -1579,29 +2278,29 @@ function forbiddenFromBlueprint(bp) {
1579
2278
  }
1580
2279
  async function allPackageJsons(dir) {
1581
2280
  const out = [];
1582
- const root = (0, import_node_path11.join)(dir, "package.json");
2281
+ const root = (0, import_node_path12.join)(dir, "package.json");
1583
2282
  out.push(root);
1584
2283
  async function walk2(d) {
1585
2284
  let entries;
1586
2285
  try {
1587
- entries = await (0, import_promises11.readdir)(d, { withFileTypes: true });
2286
+ entries = await (0, import_promises12.readdir)(d, { withFileTypes: true });
1588
2287
  } catch {
1589
2288
  return;
1590
2289
  }
1591
2290
  for (const e of entries) {
1592
2291
  if (e.isDirectory()) {
1593
- if (!IGNORE_DIRS.has(e.name)) await walk2((0, import_node_path11.join)(d, e.name));
2292
+ if (!IGNORE_DIRS.has(e.name)) await walk2((0, import_node_path12.join)(d, e.name));
1594
2293
  } else if (e.name === "package.json") {
1595
- out.push((0, import_node_path11.join)(d, e.name));
2294
+ out.push((0, import_node_path12.join)(d, e.name));
1596
2295
  }
1597
2296
  }
1598
2297
  }
1599
- await walk2((0, import_node_path11.join)(dir, "apps"));
2298
+ await walk2((0, import_node_path12.join)(dir, "apps"));
1600
2299
  return out;
1601
2300
  }
1602
2301
  async function depKeys(pkgPath) {
1603
2302
  try {
1604
- const pkg = JSON.parse(await (0, import_promises11.readFile)(pkgPath, "utf8"));
2303
+ const pkg = JSON.parse(await (0, import_promises12.readFile)(pkgPath, "utf8"));
1605
2304
  return /* @__PURE__ */ new Set([
1606
2305
  ...Object.keys(pkg.dependencies ?? {}),
1607
2306
  ...Object.keys(pkg.devDependencies ?? {})
@@ -1615,7 +2314,7 @@ async function auditProject(dir, opts = {}) {
1615
2314
  const violations = [];
1616
2315
  const aliases = await tsconfigAliases(dir);
1617
2316
  for (const file of await walk(dir)) {
1618
- const src = await (0, import_promises11.readFile)(file, "utf8");
2317
+ const src = await (0, import_promises12.readFile)(file, "utf8");
1619
2318
  for (const m of src.matchAll(ICORE_IMPORT)) {
1620
2319
  const alias = m[1];
1621
2320
  if (alias && !aliases.has(alias)) {