create-fullstack-scaffold 0.4.9 → 0.4.10

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 (127) hide show
  1. package/dist/cli/index.js +499 -100
  2. package/dist/cli/index.js.map +1 -1
  3. package/package.json +2 -2
  4. package/template/CLAUDE.md +18 -6
  5. package/template/drizzle/0004_add_merchants_products.sql +30 -0
  6. package/template/drizzle/meta/_journal.json +7 -0
  7. package/template/eslint-rules/module-boundary.js +6 -2
  8. package/template/eslint-rules/no-cross-module-service-import.js +105 -0
  9. package/template/eslint-rules/no-disable-type-safe-client.js +5 -0
  10. package/template/eslint.config.js +9 -0
  11. package/template/lint-scripts/config/project.config.ts +21 -0
  12. package/template/lint-scripts/validate-all.ts +48 -12
  13. package/template/lint-scripts/validators/index.ts +29 -0
  14. package/template/lint-scripts/validators/module-public-api.validator.ts +103 -0
  15. package/template/lint-scripts/validators/schema-uniqueness.validator.ts +147 -0
  16. package/template/modules.config.ts +2 -0
  17. package/template/package.json +2 -0
  18. package/template/playwright.config.ts +14 -0
  19. package/template/src/admin/App.tsx +40 -3
  20. package/template/src/admin/components/LanguageSwitcher.tsx +22 -0
  21. package/template/src/admin/components/NotificationDrawer.tsx +108 -38
  22. package/template/src/admin/components/StatsCard.tsx +3 -1
  23. package/template/src/admin/components/ThemeToggle.tsx +28 -0
  24. package/template/src/admin/hooks/useRoles.ts +2 -2
  25. package/template/src/admin/i18n/index.ts +18 -0
  26. package/template/src/admin/i18n/locales/en-US.json +381 -0
  27. package/template/src/admin/i18n/locales/zh-CN.json +381 -0
  28. package/template/src/admin/i18n/useLanguage.ts +21 -0
  29. package/template/src/admin/layouts/Header.tsx +37 -16
  30. package/template/src/admin/layouts/Layout.tsx +7 -3
  31. package/template/src/admin/layouts/Sidebar.tsx +70 -68
  32. package/template/src/admin/main.tsx +1 -0
  33. package/template/src/admin/pages/ContentPage.tsx +68 -56
  34. package/template/src/admin/pages/DashboardPage.tsx +82 -76
  35. package/template/src/admin/pages/DisputesPage.tsx +61 -53
  36. package/template/src/admin/pages/LoginPage.tsx +41 -33
  37. package/template/src/admin/pages/OrdersPage.tsx +69 -64
  38. package/template/src/admin/pages/PermissionsPage.tsx +10 -8
  39. package/template/src/admin/pages/PluginDashboardPage.tsx +3 -1
  40. package/template/src/admin/pages/PluginManagementPage.tsx +3 -1
  41. package/template/src/admin/pages/RegisterPage.tsx +18 -16
  42. package/template/src/admin/pages/RolesPage.tsx +51 -49
  43. package/template/src/admin/pages/SettingsPage.tsx +22 -22
  44. package/template/src/admin/pages/SystemLogsPage.tsx +32 -30
  45. package/template/src/admin/pages/TicketsPage.tsx +67 -59
  46. package/template/src/admin/pages/UsersPage.tsx +63 -53
  47. package/template/src/admin/pages/__tests__/RolesPage.test.tsx +2 -2
  48. package/template/src/admin/stores/themeStore.ts +32 -0
  49. package/template/src/client/index.css +73 -0
  50. package/template/src/merchant/App.tsx +2 -0
  51. package/template/src/merchant/components/MerchantGuard.tsx +2 -6
  52. package/template/src/merchant/components/__tests__/MerchantGuard.test.tsx +117 -0
  53. package/template/src/merchant/layouts/Header.tsx +2 -2
  54. package/template/src/merchant/pages/DashboardPage.tsx +2 -2
  55. package/template/src/merchant/pages/DisputesPage.tsx +14 -10
  56. package/template/src/merchant/pages/LoginPage.tsx +49 -0
  57. package/template/src/merchant/pages/OrdersPage.tsx +17 -10
  58. package/template/src/merchant/pages/ProductsPage.tsx +31 -8
  59. package/template/src/merchant/pages/SettingsPage.tsx +3 -7
  60. package/template/src/merchant/stores/__tests__/merchantStore.test.ts +317 -0
  61. package/template/src/merchant/stores/merchantStore.ts +24 -27
  62. package/template/src/server/db/schema/index.ts +2 -0
  63. package/template/src/server/db/schema/merchants.ts +26 -0
  64. package/template/src/server/db/schema/products.ts +25 -0
  65. package/template/src/server/db/test-setup.ts +237 -0
  66. package/template/src/server/middleware/__tests__/audit-log.test.ts +144 -0
  67. package/template/src/server/middleware/__tests__/cors.test.ts +84 -0
  68. package/template/src/server/middleware/__tests__/logger.test.ts +117 -0
  69. package/template/src/server/middleware/__tests__/rate-limit.test.ts +73 -0
  70. package/template/src/server/middleware/__tests__/realtime-env.test.ts +56 -0
  71. package/template/src/server/middleware/__tests__/tenant-isolation.test.ts +150 -0
  72. package/template/src/server/module-admin/__tests__/admin-routes.test.ts +1 -1
  73. package/template/src/server/module-admin/module.ts +4 -0
  74. package/template/src/server/module-admin/routes/admin-notification-routes.ts +3 -3
  75. package/template/src/server/module-admin/routes/user-management-routes.ts +2 -2
  76. package/template/src/server/module-auth/__tests__/auth-routes.test.ts +315 -0
  77. package/template/src/server/module-auth/__tests__/profile-routes.test.ts +83 -0
  78. package/template/src/server/module-auth/module.ts +2 -0
  79. package/template/src/server/module-content/module.ts +1 -0
  80. package/template/src/server/module-content/routes/content-routes.ts +2 -2
  81. package/template/src/server/module-dispute/module.ts +1 -0
  82. package/template/src/server/module-dispute/routes/dispute-routes.ts +2 -2
  83. package/template/src/server/module-merchant/__tests__/merchant-routes.test.ts +218 -0
  84. package/template/src/server/module-merchant/__tests__/merchant-service.test.ts +183 -0
  85. package/template/src/server/module-merchant/index.ts +10 -0
  86. package/template/src/server/module-merchant/module.ts +33 -0
  87. package/template/src/server/module-merchant/routes/merchant-routes.ts +138 -0
  88. package/template/src/server/module-merchant/services/merchant-service.ts +292 -0
  89. package/template/src/server/module-notifications/index.ts +18 -0
  90. package/template/src/server/module-notifications/module.ts +2 -0
  91. package/template/src/server/module-order/module.ts +1 -0
  92. package/template/src/server/module-order/routes/order-routes.ts +2 -2
  93. package/template/src/server/module-permission/routes/role-routes.ts +3 -3
  94. package/template/src/server/module-plugin/__tests__/admin-category-service.test.ts +181 -0
  95. package/template/src/server/module-plugin/__tests__/admin-plugin-service.test.ts +277 -0
  96. package/template/src/server/module-plugin/__tests__/admin-stats-service.test.ts +170 -0
  97. package/template/src/server/module-plugin/__tests__/plugin-review-service.test.ts +260 -0
  98. package/template/src/server/module-plugin/__tests__/plugin-seed-service.test.ts +170 -0
  99. package/template/src/server/module-plugin/module.ts +3 -0
  100. package/template/src/server/module-tenant/__tests__/tenant-routes.test.ts +142 -0
  101. package/template/src/server/module-tenant/__tests__/tenant-service.test.ts +152 -0
  102. package/template/src/server/module-tenant/module.ts +1 -0
  103. package/template/src/server/module-tenant/services/tenant-service.ts +1 -37
  104. package/template/src/server/module-ticket/module.ts +1 -0
  105. package/template/src/server/module-ticket/routes/ticket-routes.ts +2 -2
  106. package/template/src/server/module-todos/module.ts +3 -0
  107. package/template/src/server/route-registry.ts +4 -0
  108. package/template/src/server/utils/__tests__/date.test.ts +130 -0
  109. package/template/src/server/utils/__tests__/env.test.ts +25 -0
  110. package/template/src/server/utils/__tests__/generate.test.ts +82 -0
  111. package/template/src/server/utils/__tests__/id-helpers.test.ts +29 -0
  112. package/template/src/server/utils/__tests__/json.test.ts +49 -0
  113. package/template/src/server/utils/__tests__/permission-utils.test.ts +26 -0
  114. package/template/src/server/utils/__tests__/uuid.test.ts +25 -0
  115. package/template/src/shared/core/module-manifest.ts +15 -0
  116. package/template/src/shared/modules/admin/schemas.ts +1 -1
  117. package/template/src/shared/modules/content/schemas.ts +2 -2
  118. package/template/src/shared/modules/dispute/schemas.ts +2 -2
  119. package/template/src/shared/modules/index.ts +181 -1
  120. package/template/src/shared/modules/merchant/index.ts +12 -0
  121. package/template/src/shared/modules/merchant/schemas.ts +63 -0
  122. package/template/src/shared/modules/order/schemas.ts +2 -2
  123. package/template/src/shared/modules/permission/index.ts +1 -1
  124. package/template/src/shared/modules/permission/schemas.ts +1 -1
  125. package/template/src/shared/modules/role/schemas.ts +2 -2
  126. package/template/src/shared/modules/ticket/schemas.ts +2 -2
  127. package/template/src/shared/schemas/index.ts +74 -2
package/dist/cli/index.js CHANGED
@@ -189,18 +189,11 @@ function getExcludePatterns(resolved, allManifests) {
189
189
  excludes.push(`src/server/middleware/__tests__/${mw.name}.test.ts`);
190
190
  }
191
191
  }
192
- if (name === "notifications") {
193
- excludes.push("src/cli/modules/notification");
194
- }
195
192
  if (name === "todos") {
196
- excludes.push("src/cli/modules/todo");
197
193
  excludes.push("src/server/__tests__/integration/todos-api.test.ts");
198
194
  }
199
- if (name === "auth") {
200
- excludes.push("src/cli/modules/auth");
201
- }
202
- if (name === "plugin") {
203
- excludes.push("src/cli/modules/plugin");
195
+ if (manifest.cliModule) {
196
+ excludes.push(`src/cli/modules/${manifest.cliModule.dir}`);
204
197
  }
205
198
  }
206
199
  if (!resolved.modules.has("admin")) {
@@ -213,6 +206,8 @@ function getExcludePatterns(resolved, allManifests) {
213
206
  excludes.push("tenant.html");
214
207
  excludes.push("src/merchant");
215
208
  excludes.push("merchant.html");
209
+ excludes.push("src/server/middleware/tenant-isolation.ts");
210
+ excludes.push("src/server/middleware/__tests__/tenant-isolation.test.ts");
216
211
  }
217
212
  if (!resolved.hasClient) {
218
213
  excludes.push("src/client");
@@ -235,12 +230,14 @@ function getExcludePatterns(resolved, allManifests) {
235
230
  excludes.push("src/client/preset-ui-config.ts");
236
231
  if (!resolved.hasPermission && !resolved.modules.has("auth")) {
237
232
  excludes.push("src/server/utils/permission-utils.ts");
233
+ excludes.push("src/server/utils/__tests__/permission-utils.test.ts");
238
234
  excludes.push("src/server/middleware/__tests__/auth-simple.test.ts");
239
235
  excludes.push("src/server/middleware/__tests__/auth.test.ts");
240
236
  excludes.push("src/server/middleware/__tests__/error-response-format.test.ts");
241
237
  excludes.push("src/server/utils/__tests__/auth.test.ts");
242
238
  } else if (!resolved.hasPermission && resolved.modules.has("auth")) {
243
239
  excludes.push("src/server/utils/permission-utils.ts");
240
+ excludes.push("src/server/utils/__tests__/permission-utils.test.ts");
244
241
  excludes.push("src/server/middleware/__tests__/auth-simple.test.ts");
245
242
  excludes.push("src/server/middleware/__tests__/auth.test.ts");
246
243
  excludes.push("src/server/middleware/__tests__/error-response-format.test.ts");
@@ -305,25 +302,34 @@ function generateRouteRegistry(resolved) {
305
302
  const clientRoutes = [];
306
303
  const adminRoutes = [];
307
304
  const moduleEntries = [...resolved.modules.entries()];
305
+ const usedNames = /* @__PURE__ */ new Set();
308
306
  for (const [name, manifest] of moduleEntries) {
309
307
  const moduleDir = `module-${name}`;
310
308
  if (manifest.routes.client) {
311
309
  const clientRouteList = Array.isArray(manifest.routes.client) ? manifest.routes.client : [manifest.routes.client];
312
310
  for (const route of clientRouteList) {
313
311
  const { importPath, exportName } = route;
314
- imports.push(
315
- `import { ${exportName} } from './${moduleDir}/${importPath.replace(/^\.\//, "")}'`
316
- );
317
- clientRoutes.push(` .route('/api', ${exportName})`);
312
+ const localName = usedNames.has(exportName) ? `${name}${exportName.charAt(0).toUpperCase()}${exportName.slice(1)}` : exportName;
313
+ usedNames.add(localName);
314
+ const importStmt = localName === exportName ? `import { ${exportName} } from './${moduleDir}/${importPath.replace(/^\.\//, "")}'` : `import { ${exportName} as ${localName} } from './${moduleDir}/${importPath.replace(
315
+ /^\.\//,
316
+ ""
317
+ )}'`;
318
+ imports.push(importStmt);
319
+ clientRoutes.push(` .route('/api', ${localName})`);
318
320
  }
319
321
  }
320
322
  if (manifest.routes.admin) {
321
323
  for (const route of manifest.routes.admin) {
322
324
  const { importPath, exportName } = route;
323
- imports.push(
324
- `import { ${exportName} } from './${moduleDir}/${importPath.replace(/^\.\//, "")}'`
325
- );
326
- adminRoutes.push(` .route('/api', ${exportName})`);
325
+ const localName = usedNames.has(exportName) ? `${name}${exportName.charAt(0).toUpperCase()}${exportName.slice(1)}` : exportName;
326
+ usedNames.add(localName);
327
+ const importStmt = localName === exportName ? `import { ${exportName} } from './${moduleDir}/${importPath.replace(/^\.\//, "")}'` : `import { ${exportName} as ${localName} } from './${moduleDir}/${importPath.replace(
328
+ /^\.\//,
329
+ ""
330
+ )}'`;
331
+ imports.push(importStmt);
332
+ adminRoutes.push(` .route('/api', ${localName})`);
327
333
  }
328
334
  }
329
335
  }
@@ -371,6 +377,19 @@ function generateRouteRegistry(resolved) {
371
377
  `;
372
378
  return content;
373
379
  }
380
+ function getStandaloneRoutes(resolved) {
381
+ const routes = [];
382
+ const usedNames = /* @__PURE__ */ new Set();
383
+ for (const [name, manifest] of resolved.modules) {
384
+ if (manifest.routes.standalone) {
385
+ const { exportName, mountPath } = manifest.routes.standalone;
386
+ const localName = usedNames.has(exportName) ? `${name}${exportName.charAt(0).toUpperCase()}${exportName.slice(1)}` : exportName;
387
+ usedNames.add(localName);
388
+ routes.push({ localName, mountPath });
389
+ }
390
+ }
391
+ return routes;
392
+ }
374
393
 
375
394
  // src/generators/client-navigation.ts
376
395
  var DEFAULT_ICON = "Circle";
@@ -704,43 +723,6 @@ function generateDbSchemaBarrel(resolved) {
704
723
  }
705
724
 
706
725
  // src/generators/db-init.ts
707
- var SEED_MODULES = [
708
- {
709
- module: "todos",
710
- importLine: "",
711
- call: "import('../module-todos/services/todo-service').then(m => m.seedTodosIfEmpty())"
712
- },
713
- {
714
- module: "order",
715
- importLine: "",
716
- call: "import('../module-order/services/order-service').then(m => m.seedOrdersIfEmpty())"
717
- },
718
- {
719
- module: "ticket",
720
- importLine: "",
721
- call: "import('../module-ticket/services/ticket-service').then(m => m.seedTicketsIfEmpty())"
722
- },
723
- {
724
- module: "dispute",
725
- importLine: "",
726
- call: "import('../module-dispute/services/dispute-service').then(m => m.seedDisputesIfEmpty())"
727
- },
728
- {
729
- module: "content",
730
- importLine: "",
731
- call: "import('../module-content/services/content-service').then(m => m.seedContentsIfEmpty())"
732
- },
733
- {
734
- module: "tenant",
735
- importLine: "",
736
- call: "import('../module-tenant/services/tenant-service').then(m => m.seedTenantsIfEmpty())"
737
- },
738
- {
739
- module: "plugin",
740
- importLine: "",
741
- call: "import('../module-plugin/services/plugin-seed-service').then(m => m.seedPluginsIfEmpty())"
742
- }
743
- ];
744
726
  var INITIAL_PERMISSIONS = `const initialPermissions = [
745
727
  {
746
728
  id: 'perm_user_view',
@@ -1086,14 +1068,23 @@ var INITIAL_ROLE_PERMISSIONS = `const initialRolePermissions = [
1086
1068
  { roleId: 'role_user', permissionId: 'perm_order_view' },
1087
1069
  ]`;
1088
1070
  function generateDbInit(resolved) {
1089
- const activeSeeds = SEED_MODULES.filter((s) => resolved.modules.has(s.module));
1071
+ const activeSeeds = [];
1072
+ for (const [name, manifest] of resolved.modules) {
1073
+ if (manifest.dbSchemas?.hasSeed && manifest.dbSchemas.seed) {
1074
+ activeSeeds.push({
1075
+ moduleDir: `module-${name}`,
1076
+ serviceFile: manifest.dbSchemas.seed.serviceFile,
1077
+ functionName: manifest.dbSchemas.seed.functionName
1078
+ });
1079
+ }
1080
+ }
1090
1081
  if (!resolved.hasPermission) {
1091
1082
  return generateMinimalDbInit(activeSeeds);
1092
1083
  }
1093
1084
  return generateFullDbInit(activeSeeds);
1094
1085
  }
1095
1086
  function generateMinimalDbInit(activeSeeds) {
1096
- const seedCalls = activeSeeds.map((s) => ` ${s.call},`).join("\n");
1087
+ const seedCalls = activeSeeds.map((s) => ` import('../${s.moduleDir}/services/${s.serviceFile}').then(m => m.${s.functionName}()),`).join("\n");
1097
1088
  const seedBlock = activeSeeds.length > 0 ? `
1098
1089
  log.info({}, 'Seeding module data...')
1099
1090
  await Promise.all([
@@ -1115,7 +1106,7 @@ export async function initializeDatabase() {
1115
1106
  `;
1116
1107
  }
1117
1108
  function generateFullDbInit(activeSeeds) {
1118
- const seedCalls = activeSeeds.map((s) => ` ${s.call},`).join("\n");
1109
+ const seedCalls = activeSeeds.map((s) => ` import('../${s.moduleDir}/services/${s.serviceFile}').then(m => m.${s.functionName}()),`).join("\n");
1119
1110
  const seedBlock = activeSeeds.length > 0 ? `
1120
1111
  log.info({}, 'Seeding module data...')
1121
1112
  await Promise.all([
@@ -1188,7 +1179,7 @@ function generateServerApp(resolved) {
1188
1179
  const useRealtime = resolved.hasSSE || resolved.hasWebSocket;
1189
1180
  const useAuditLog = resolved.hasPermission;
1190
1181
  const useCaptcha = resolved.hasCaptcha;
1191
- const useFileRoutes = resolved.modules.has("file");
1182
+ const standaloneRoutes = getStandaloneRoutes(resolved);
1192
1183
  const imports = [
1193
1184
  `import { OpenAPIHono } from '@hono/zod-openapi'`,
1194
1185
  ``,
@@ -1213,8 +1204,18 @@ function generateServerApp(resolved) {
1213
1204
  `import { createModuleLoggerSync } from './utils/logger'`,
1214
1205
  `import { adminApiRoutes, clientApiRoutes } from './route-registry'`
1215
1206
  );
1216
- if (useFileRoutes) {
1217
- imports.push(`import { fileRoutes } from './module-file/routes/file-routes'`);
1207
+ const standaloneImportSet = /* @__PURE__ */ new Set();
1208
+ for (const [name, manifest] of resolved.modules) {
1209
+ if (manifest.routes.standalone) {
1210
+ const { importPath, exportName } = manifest.routes.standalone;
1211
+ const moduleDir = `module-${name}`;
1212
+ const relPath = importPath.replace(/^\.\//, "");
1213
+ const stmt = `import { ${exportName} } from './${moduleDir}/${relPath}'`;
1214
+ if (!standaloneImportSet.has(stmt)) {
1215
+ standaloneImportSet.add(stmt);
1216
+ imports.push(stmt);
1217
+ }
1218
+ }
1218
1219
  }
1219
1220
  const middlewareChain = [
1220
1221
  `.use('*', errorHandlerMiddleware())`,
@@ -1239,8 +1240,8 @@ function generateServerApp(resolved) {
1239
1240
  );
1240
1241
  }
1241
1242
  const routes = [`.route('/', clientApiRoutes)`, `.route('/', adminApiRoutes)`];
1242
- if (useFileRoutes) {
1243
- routes.push(`.route('/files', fileRoutes)`);
1243
+ for (const sr of standaloneRoutes) {
1244
+ routes.push(`.route('${sr.mountPath}', ${sr.localName})`);
1244
1245
  }
1245
1246
  const indent = " ";
1246
1247
  const chain = [...middlewareChain, ...routes].join(`
@@ -1401,7 +1402,7 @@ var MODULE_EXPORTS = {
1401
1402
  "hasPermission",
1402
1403
  "hasAnyPermission",
1403
1404
  "hasAllPermissions",
1404
- "type RoleType",
1405
+ "type PermissionRoleType",
1405
1406
  "type RoleInfo",
1406
1407
  "type PermissionInfo",
1407
1408
  "type UserPermissions"
@@ -1451,6 +1452,210 @@ var MODULE_EXPORTS = {
1451
1452
  "type AdminDashboardStats",
1452
1453
  "type PluginListQuery"
1453
1454
  ]
1455
+ },
1456
+ merchant: {
1457
+ namedExports: [
1458
+ "ProductSchema",
1459
+ "CreateProductSchema",
1460
+ "UpdateProductSchema",
1461
+ "ProductListSchema",
1462
+ "type Product",
1463
+ "type CreateProductInput",
1464
+ "type UpdateProductInput"
1465
+ ]
1466
+ },
1467
+ tenant: {
1468
+ namedExports: [
1469
+ "TenantSchema",
1470
+ "TenantStatusSchema",
1471
+ "TenantPlanSchema",
1472
+ "TenantSettingsSchema",
1473
+ "CreateTenantSchema",
1474
+ "UpdateTenantSchema",
1475
+ "TenantIdSchema",
1476
+ "TenantSlugSchema",
1477
+ "TenantListResponseSchema",
1478
+ "TenantQuerySchema",
1479
+ "TenantIdResponseSchema",
1480
+ "type Tenant",
1481
+ "type TenantStatus",
1482
+ "type TenantPlan",
1483
+ "type TenantSettings",
1484
+ "type CreateTenantInput",
1485
+ "type UpdateTenantInput",
1486
+ "type TenantId",
1487
+ "type TenantSlug",
1488
+ "type TenantListResponse",
1489
+ "type TenantQuery",
1490
+ "type TenantIdResponse"
1491
+ ]
1492
+ },
1493
+ order: {
1494
+ namedExports: [
1495
+ "OrderStatusSchema",
1496
+ "OrderSchema",
1497
+ "CreateOrderSchema",
1498
+ "UpdateOrderSchema",
1499
+ "OrderListSchema",
1500
+ "OrderQuerySchema",
1501
+ "OrderDeleteResultSchema",
1502
+ "ProcessOrderSchema",
1503
+ "CancelOrderSchema",
1504
+ "RemoveCartItemResponseSchema",
1505
+ "ECommerceProductSchema",
1506
+ "ECommerceOrderStatusSchema",
1507
+ "ECommerceOrderSchema",
1508
+ "ECommerceOrderListSchema",
1509
+ "type OrderStatus",
1510
+ "type Order",
1511
+ "type CreateOrderInput",
1512
+ "type UpdateOrderInput",
1513
+ "type OrderDeleteResult",
1514
+ "type ProcessOrderInput",
1515
+ "type CancelOrderInput",
1516
+ "type OrderQueryInput",
1517
+ "type RemoveCartItemResponse",
1518
+ "type ECommerceProduct",
1519
+ "type ECommerceOrderStatus",
1520
+ "type ECommerceOrder"
1521
+ ]
1522
+ },
1523
+ ticket: {
1524
+ namedExports: [
1525
+ "TicketStatusSchema",
1526
+ "TicketPrioritySchema",
1527
+ "TicketCategorySchema",
1528
+ "TicketReplySchema",
1529
+ "TicketSchema",
1530
+ "CreateTicketSchema",
1531
+ "UpdateTicketSchema",
1532
+ "ReplyTicketSchema",
1533
+ "TicketListSchema",
1534
+ "TicketDeleteResultSchema",
1535
+ "type TicketStatus",
1536
+ "type TicketPriority",
1537
+ "type TicketCategory",
1538
+ "type TicketReply",
1539
+ "type Ticket",
1540
+ "type CreateTicketInput",
1541
+ "type UpdateTicketInput",
1542
+ "type ReplyTicketInput",
1543
+ "type TicketDeleteResult"
1544
+ ]
1545
+ },
1546
+ dispute: {
1547
+ namedExports: [
1548
+ "DisputeTypeSchema",
1549
+ "DisputeStatusSchema",
1550
+ "DisputeSchema",
1551
+ "CreateDisputeSchema",
1552
+ "UpdateDisputeSchema",
1553
+ "ResolveDisputeSchema",
1554
+ "DisputeListSchema",
1555
+ "DisputeDeleteResultSchema",
1556
+ "type DisputeType",
1557
+ "type DisputeStatus",
1558
+ "type Dispute",
1559
+ "type CreateDisputeInput",
1560
+ "type UpdateDisputeInput",
1561
+ "type ResolveDisputeInput",
1562
+ "type DisputeDeleteResult"
1563
+ ]
1564
+ },
1565
+ content: {
1566
+ namedExports: [
1567
+ "ContentCategorySchema",
1568
+ "ContentStatusSchema",
1569
+ "ContentSchema",
1570
+ "CreateContentSchema",
1571
+ "UpdateContentSchema",
1572
+ "ContentListSchema",
1573
+ "ContentDeleteResultSchema",
1574
+ "type ContentCategory",
1575
+ "type ContentStatus",
1576
+ "type Content",
1577
+ "type CreateContentInput",
1578
+ "type UpdateContentInput",
1579
+ "type ContentDeleteResult"
1580
+ ]
1581
+ },
1582
+ captcha: {
1583
+ namedExports: [
1584
+ "CaptchaResponseSchema",
1585
+ "VerifyCaptchaRequestSchema",
1586
+ "CaptchaVerifyResponseSchema",
1587
+ "type CaptchaResponse",
1588
+ "type VerifyCaptchaRequest",
1589
+ "type CaptchaVerifyResponse"
1590
+ ]
1591
+ },
1592
+ dashboard: {
1593
+ namedExports: [
1594
+ "DashboardStatSchema",
1595
+ "RevenueDataSchema",
1596
+ "ActivityStatusSchema",
1597
+ "ActivitySchema",
1598
+ "DashboardResponseSchema",
1599
+ "type DashboardStat",
1600
+ "type RevenueData",
1601
+ "type ActivityStatus",
1602
+ "type Activity",
1603
+ "type DashboardResponse"
1604
+ ]
1605
+ },
1606
+ cart: {
1607
+ namedExports: [
1608
+ "CartItemSchema",
1609
+ "CartSummarySchema",
1610
+ "CartResponseSchema",
1611
+ "AddCartItemSchema",
1612
+ "CartItemIdSchema",
1613
+ "type CartItem",
1614
+ "type CartSummary",
1615
+ "type CartResponse",
1616
+ "type AddCartItemInput"
1617
+ ]
1618
+ },
1619
+ community: {
1620
+ namedExports: [
1621
+ "TopicStatusSchema",
1622
+ "TopicTagSchema",
1623
+ "TopicAuthorSchema",
1624
+ "TopicSchema",
1625
+ "TopicsResponseSchema",
1626
+ "ProfileStatsSchema",
1627
+ "ActivityTypeSchema",
1628
+ "ProfileActivitySchema",
1629
+ "ProfileResponseSchema",
1630
+ "type TopicStatus",
1631
+ "type TopicTag",
1632
+ "type TopicAuthor",
1633
+ "type Topic",
1634
+ "type ProfileStats",
1635
+ "type ActivityType",
1636
+ "type ProfileActivity",
1637
+ "type ProfileResponse"
1638
+ ]
1639
+ },
1640
+ audit: {
1641
+ namedExports: [
1642
+ "ResourceTypeSchema",
1643
+ "ActionTypeSchema",
1644
+ "AuditLogSchema",
1645
+ "type AuditLogType"
1646
+ ]
1647
+ },
1648
+ role: {
1649
+ namedExports: [
1650
+ "RoleSchema",
1651
+ "CreateRoleSchema",
1652
+ "UpdateRoleSchema",
1653
+ "UpdateRolePermissionsSchema",
1654
+ "RoleSuccessSchema",
1655
+ "type RoleDataType",
1656
+ "type CreateRoleType",
1657
+ "type UpdateRoleType"
1658
+ ]
1454
1659
  }
1455
1660
  };
1456
1661
  function generateSharedModulesIndex(resolved) {
@@ -1463,8 +1668,16 @@ function generateSharedModulesIndex(resolved) {
1463
1668
  "admin",
1464
1669
  "permission",
1465
1670
  "auth",
1466
- "plugin"
1671
+ "plugin",
1672
+ "merchant",
1673
+ "tenant",
1674
+ "order",
1675
+ "ticket",
1676
+ "dispute",
1677
+ "content",
1678
+ "captcha"
1467
1679
  ];
1680
+ const standaloneModules = ["dashboard", "cart", "community"];
1468
1681
  for (const moduleName of moduleOrder2) {
1469
1682
  if (!resolved.modules.has(moduleName)) continue;
1470
1683
  const manifest = resolved.modules.get(moduleName);
@@ -1475,6 +1688,31 @@ function generateSharedModulesIndex(resolved) {
1475
1688
  ${exports.namedExports.join(",\n ")},
1476
1689
  } from './${exportKey}'`);
1477
1690
  }
1691
+ const additionalExported = /* @__PURE__ */ new Set();
1692
+ for (const moduleName of moduleOrder2) {
1693
+ if (!resolved.modules.has(moduleName)) continue;
1694
+ const manifest = resolved.modules.get(moduleName);
1695
+ if (manifest.sharedSchemas?.additionalPaths) {
1696
+ for (const extra of manifest.sharedSchemas.additionalPaths) {
1697
+ if (additionalExported.has(extra)) continue;
1698
+ additionalExported.add(extra);
1699
+ const exports = MODULE_EXPORTS[extra];
1700
+ if (!exports) continue;
1701
+ lines.push(`export {
1702
+ ${exports.namedExports.join(",\n ")},
1703
+ } from './${extra}'`);
1704
+ }
1705
+ }
1706
+ }
1707
+ if (resolved.hasClient) {
1708
+ for (const moduleName of standaloneModules) {
1709
+ const exports = MODULE_EXPORTS[moduleName];
1710
+ if (!exports) continue;
1711
+ lines.push(`export {
1712
+ ${exports.namedExports.join(",\n ")},
1713
+ } from './${moduleName}'`);
1714
+ }
1715
+ }
1478
1716
  return lines.join("\n") + "\n";
1479
1717
  }
1480
1718
 
@@ -1624,7 +1862,7 @@ var MODULE_EXPORTS2 = {
1624
1862
  "UpdateUserRequestSchema",
1625
1863
  "CreateUserRequestSchema",
1626
1864
  "ClearTodosResultSchema",
1627
- "SuccessSchema",
1865
+ "AdminSuccessSchema",
1628
1866
  "DownloadTokenSchema",
1629
1867
  "type SystemStats",
1630
1868
  "type HealthCheck",
@@ -1694,13 +1932,13 @@ var MODULE_EXPORTS2 = {
1694
1932
  "CreateContentSchema",
1695
1933
  "UpdateContentSchema",
1696
1934
  "ContentListSchema",
1697
- "DeleteResultSchema",
1935
+ "ContentDeleteResultSchema",
1698
1936
  "type ContentCategory",
1699
1937
  "type ContentStatus",
1700
1938
  "type Content",
1701
1939
  "type CreateContentInput",
1702
1940
  "type UpdateContentInput",
1703
- "type DeleteResult"
1941
+ "type ContentDeleteResult"
1704
1942
  ]
1705
1943
  },
1706
1944
  dashboard: {
@@ -1717,6 +1955,55 @@ var MODULE_EXPORTS2 = {
1717
1955
  "type DashboardResponse"
1718
1956
  ]
1719
1957
  },
1958
+ merchant: {
1959
+ namedExports: [
1960
+ "MerchantSchema",
1961
+ "MerchantLoginSchema",
1962
+ "MerchantLoginResponseSchema",
1963
+ "MerchantStatsSchema",
1964
+ "ProductSchema",
1965
+ "CreateProductSchema",
1966
+ "UpdateProductSchema",
1967
+ "ProductListSchema",
1968
+ "ProductListResponseSchema",
1969
+ "ProductQuerySchema",
1970
+ "type Merchant",
1971
+ "type MerchantLoginInput",
1972
+ "type MerchantLoginResponse",
1973
+ "type MerchantStats",
1974
+ "type Product",
1975
+ "type CreateProductInput",
1976
+ "type UpdateProductInput",
1977
+ "type ProductListResponse",
1978
+ "type ProductQuery"
1979
+ ]
1980
+ },
1981
+ tenant: {
1982
+ namedExports: [
1983
+ "TenantSchema",
1984
+ "TenantStatusSchema",
1985
+ "TenantPlanSchema",
1986
+ "TenantSettingsSchema",
1987
+ "CreateTenantSchema",
1988
+ "UpdateTenantSchema",
1989
+ "TenantIdSchema",
1990
+ "TenantSlugSchema",
1991
+ "TenantListResponseSchema",
1992
+ "TenantQuerySchema",
1993
+ "TenantIdResponseSchema",
1994
+ "type Tenant",
1995
+ "type TenantStatus",
1996
+ "type TenantPlan",
1997
+ "type TenantSettings",
1998
+ "type CreateTenantInput",
1999
+ "type UpdateTenantInput",
2000
+ "type TenantId",
2001
+ "type TenantSlug",
2002
+ "type TenantListResponse",
2003
+ "type TenantQuery",
2004
+ "type TenantIdResponse"
2005
+ ]
2006
+ },
1720
2007
  dispute: {
1721
2008
  namedExports: [
1722
2009
  "DisputeTypeSchema",
@@ -1726,14 +2013,14 @@ var MODULE_EXPORTS2 = {
1726
2013
  "UpdateDisputeSchema",
1727
2014
  "ResolveDisputeSchema",
1728
2015
  "DisputeListSchema",
1729
- "DeleteResultSchema",
2016
+ "DisputeDeleteResultSchema",
1730
2017
  "type DisputeType",
1731
2018
  "type DisputeStatus",
1732
2019
  "type Dispute",
1733
2020
  "type CreateDisputeInput",
1734
2021
  "type UpdateDisputeInput",
1735
2022
  "type ResolveDisputeInput",
1736
- "type DeleteResult"
2023
+ "type DisputeDeleteResult"
1737
2024
  ]
1738
2025
  },
1739
2026
  order: {
@@ -1744,7 +2031,7 @@ var MODULE_EXPORTS2 = {
1744
2031
  "UpdateOrderSchema",
1745
2032
  "OrderListSchema",
1746
2033
  "OrderQuerySchema",
1747
- "DeleteResultSchema",
2034
+ "OrderDeleteResultSchema",
1748
2035
  "ProcessOrderSchema",
1749
2036
  "CancelOrderSchema",
1750
2037
  "RemoveCartItemResponseSchema",
@@ -1756,7 +2043,7 @@ var MODULE_EXPORTS2 = {
1756
2043
  "type Order",
1757
2044
  "type CreateOrderInput",
1758
2045
  "type UpdateOrderInput",
1759
- "type DeleteResult",
2046
+ "type OrderDeleteResult",
1760
2047
  "type ProcessOrderInput",
1761
2048
  "type CancelOrderInput",
1762
2049
  "type OrderQueryInput",
@@ -1785,7 +2072,7 @@ var MODULE_EXPORTS2 = {
1785
2072
  "RoleLabelsSchema",
1786
2073
  "PermissionLabelsSchema",
1787
2074
  "PermissionInitSchema",
1788
- "type RoleType",
2075
+ "type PermissionRoleType",
1789
2076
  "type PermissionType",
1790
2077
  "type RoleInfo",
1791
2078
  "type PermissionInfo",
@@ -1813,8 +2100,8 @@ var MODULE_EXPORTS2 = {
1813
2100
  "CreateRoleSchema",
1814
2101
  "UpdateRoleSchema",
1815
2102
  "UpdateRolePermissionsSchema",
1816
- "SuccessSchema",
1817
- "type RoleType",
2103
+ "RoleSuccessSchema",
2104
+ "type RoleDataType",
1818
2105
  "type CreateRoleType",
1819
2106
  "type UpdateRoleType"
1820
2107
  ]
@@ -1830,7 +2117,7 @@ var MODULE_EXPORTS2 = {
1830
2117
  "UpdateTicketSchema",
1831
2118
  "ReplyTicketSchema",
1832
2119
  "TicketListSchema",
1833
- "DeleteResultSchema",
2120
+ "TicketDeleteResultSchema",
1834
2121
  "type TicketStatus",
1835
2122
  "type TicketPriority",
1836
2123
  "type TicketCategory",
@@ -1839,7 +2126,7 @@ var MODULE_EXPORTS2 = {
1839
2126
  "type CreateTicketInput",
1840
2127
  "type UpdateTicketInput",
1841
2128
  "type ReplyTicketInput",
1842
- "type DeleteResult"
2129
+ "type TicketDeleteResult"
1843
2130
  ]
1844
2131
  }
1845
2132
  };
@@ -1862,9 +2149,11 @@ var moduleOrder = [
1862
2149
  "content",
1863
2150
  "dashboard",
1864
2151
  "dispute",
2152
+ "merchant",
1865
2153
  "order",
1866
2154
  "permission",
1867
2155
  "role",
2156
+ "tenant",
1868
2157
  "ticket"
1869
2158
  ];
1870
2159
  function generateSharedSchemasIndex(resolved) {
@@ -1893,14 +2182,21 @@ export {
1893
2182
  `;
1894
2183
  const moduleLines = [];
1895
2184
  const exportedNames = /* @__PURE__ */ new Set();
2185
+ const firstSeenModule = /* @__PURE__ */ new Map();
2186
+ const droppedExports = [];
1896
2187
  for (const moduleName of moduleOrder) {
1897
2188
  const exports = MODULE_EXPORTS2[moduleName];
1898
2189
  if (!exports) continue;
1899
2190
  const shouldInclude = shouldIncludeModule(moduleName, resolved);
1900
2191
  if (!shouldInclude) continue;
1901
2192
  const uniqueExports = exports.namedExports.filter((name) => {
1902
- if (exportedNames.has(name)) return false;
2193
+ if (exportedNames.has(name)) {
2194
+ const originalModule = firstSeenModule.get(name) ?? "unknown";
2195
+ droppedExports.push({ name, moduleName, originalModule });
2196
+ return false;
2197
+ }
1903
2198
  exportedNames.add(name);
2199
+ firstSeenModule.set(name, moduleName);
1904
2200
  return true;
1905
2201
  });
1906
2202
  if (uniqueExports.length === 0) continue;
@@ -1911,6 +2207,11 @@ export {
1911
2207
  } from '../modules/${importPath}'`
1912
2208
  );
1913
2209
  }
2210
+ for (const { name, moduleName, originalModule } of droppedExports) {
2211
+ console.warn(
2212
+ `\u26A0\uFE0F Schema collision: "${name}" defined in both ${originalModule} and ${moduleName}. Using ${originalModule}'s version. Rename to avoid ambiguity.`
2213
+ );
2214
+ }
1914
2215
  return header + moduleLines.join("\n") + "\n";
1915
2216
  }
1916
2217
  function shouldIncludeModule(moduleName, resolved) {
@@ -2263,27 +2564,22 @@ function generateClientComponentsIndex(resolved) {
2263
2564
  }
2264
2565
 
2265
2566
  // src/generators/cli-modules-index.ts
2567
+ var ALWAYS_INCLUDED = {
2568
+ dir: "config",
2569
+ registerFunction: "registerConfigCommands"
2570
+ };
2266
2571
  function generateCliModulesIndex(resolved) {
2267
2572
  const modules = [];
2268
2573
  const registrations = [];
2269
- if (resolved.modules.has("todos")) {
2270
- modules.push("import { registerTodoCommands } from './todo'");
2271
- registrations.push("registerTodoCommands(site)");
2272
- }
2273
- if (resolved.modules.has("notifications")) {
2274
- modules.push("import { registerNotificationCommands } from './notification'");
2275
- registrations.push("registerNotificationCommands(site)");
2276
- }
2277
- if (resolved.modules.has("auth")) {
2278
- modules.push("import { registerAuthCommands } from './auth'");
2279
- registrations.push("registerAuthCommands(site)");
2280
- }
2281
- if (resolved.modules.has("plugin")) {
2282
- modules.push("import { registerPluginCommands } from './plugin'");
2283
- registrations.push("registerPluginCommands(site)");
2574
+ for (const [, manifest] of resolved.modules) {
2575
+ if (manifest.cliModule) {
2576
+ const { dir, registerFunction } = manifest.cliModule;
2577
+ modules.push(`import { ${registerFunction} } from './${dir}'`);
2578
+ registrations.push(`${registerFunction}(site)`);
2579
+ }
2284
2580
  }
2285
- modules.push("import { registerConfigCommands } from './config'");
2286
- registrations.push("registerConfigCommands(site)");
2581
+ modules.push(`import { ${ALWAYS_INCLUDED.registerFunction} } from './${ALWAYS_INCLUDED.dir}'`);
2582
+ registrations.push(`${ALWAYS_INCLUDED.registerFunction}(site)`);
2287
2583
  const exports = modules.map((m) => {
2288
2584
  const match = m.match(/\{ (\w+) \}/);
2289
2585
  return match ? match[1] : "";
@@ -2433,13 +2729,19 @@ function generateViteConfig(resolved, templateDir) {
2433
2729
  aliasesToRemove.push("@tenant", "@merchant");
2434
2730
  }
2435
2731
  for (const name of entriesToRemove) {
2436
- const re = new RegExp(`^\\s*${name}:\\s*path\\.resolve\\(__dirname,\\s*['"]${name}\\.html['"]\\),\\s*$\\n?`, "gm");
2732
+ const re = new RegExp(
2733
+ `^\\s*${name}:\\s*path\\.resolve\\(__dirname,\\s*['"]${name}\\.html['"]\\),\\s*$\\n?`,
2734
+ "gm"
2735
+ );
2437
2736
  content = content.replace(re, "");
2438
2737
  }
2439
2738
  for (const alias of aliasesToRemove) {
2440
2739
  const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2441
2740
  const dirName = alias.replace("@", "");
2442
- const re = new RegExp(`^\\s*'${escapedAlias}':\\s*path\\.resolve\\(__dirname,\\s*['"]src\\/${dirName}['"]\\),\\s*$\\n?`, "gm");
2741
+ const re = new RegExp(
2742
+ `^\\s*'${escapedAlias}':\\s*path\\.resolve\\(__dirname,\\s*['"]src\\/${dirName}['"]\\),\\s*$\\n?`,
2743
+ "gm"
2744
+ );
2443
2745
  content = content.replace(re, "");
2444
2746
  }
2445
2747
  return content;
@@ -2513,6 +2815,20 @@ function getThemeForPresetType(presetType) {
2513
2815
  borderRadius: '8px',
2514
2816
  logoText: 'AdminPanel',
2515
2817
  fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
2818
+ }`
2819
+ },
2820
+ community: {
2821
+ constName: "COMMUNITY_THEME",
2822
+ theme: `{
2823
+ primaryColor: '#f97316',
2824
+ primaryHover: '#ea580c',
2825
+ bgColor: '#ffffff',
2826
+ textColor: '#111827',
2827
+ secondaryBg: '#fff7ed',
2828
+ borderColor: '#fed7aa',
2829
+ borderRadius: '12px',
2830
+ logoText: 'CommunityHub',
2831
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
2516
2832
  }`
2517
2833
  }
2518
2834
  };
@@ -2706,6 +3022,67 @@ function getRoutesForPreset(presetType, resolved) {
2706
3022
  routes.push(...maybeAuthRoutes);
2707
3023
  return routes;
2708
3024
  }
3025
+ case "community": {
3026
+ const routes = [];
3027
+ if (hasModule("content")) {
3028
+ routes.push(
3029
+ {
3030
+ path: "/",
3031
+ importPath: "./pages/ContentListPage",
3032
+ componentName: "ContentListPage",
3033
+ label: "Home"
3034
+ },
3035
+ {
3036
+ path: "/topics",
3037
+ importPath: "./pages/ContentListPage",
3038
+ componentName: "ContentListPage",
3039
+ label: "Topics"
3040
+ },
3041
+ {
3042
+ path: "/topics/:id",
3043
+ importPath: "./pages/ContentDetailPage",
3044
+ componentName: "ContentDetailPage",
3045
+ label: "Topic Detail"
3046
+ },
3047
+ {
3048
+ path: "/popular",
3049
+ importPath: "./pages/ContentListPage",
3050
+ componentName: "ContentListPage",
3051
+ label: "Popular"
3052
+ },
3053
+ {
3054
+ path: "/content",
3055
+ importPath: "./pages/ContentListPage",
3056
+ componentName: "ContentListPage",
3057
+ label: "Content"
3058
+ },
3059
+ {
3060
+ path: "/content/:id",
3061
+ importPath: "./pages/ContentDetailPage",
3062
+ componentName: "ContentDetailPage",
3063
+ label: "Content Detail"
3064
+ }
3065
+ );
3066
+ }
3067
+ if (hasModule("chat")) {
3068
+ routes.push({
3069
+ path: "/websocket",
3070
+ importPath: "./pages/WebSocketPage",
3071
+ componentName: "WebSocketPage",
3072
+ label: "WebSocket"
3073
+ });
3074
+ }
3075
+ if (hasModule("notifications")) {
3076
+ routes.push({
3077
+ path: "/notifications",
3078
+ importPath: "./pages/NotificationPage",
3079
+ componentName: "NotificationPage",
3080
+ label: "Notifications"
3081
+ });
3082
+ }
3083
+ routes.push(...maybeAuthRoutes);
3084
+ return routes;
3085
+ }
2709
3086
  default:
2710
3087
  return [...maybeAuthRoutes];
2711
3088
  }
@@ -2791,6 +3168,28 @@ function getNavConfigForPreset(presetType, hasAuth) {
2791
3168
  ],
2792
3169
  defaultRoute: "/dashboard"
2793
3170
  };
3171
+ case "community":
3172
+ return {
3173
+ name: "Community Forum",
3174
+ appType: "client",
3175
+ layout: "top-nav",
3176
+ navigationObj: "{ visible: true, showLogo: true, showSearch: true, showCart: false, authStyle: 'text-link', navItems: 'desktop' }",
3177
+ desktopNav: [
3178
+ "{ label: 'Home', icon: 'Home', path: '/' }",
3179
+ "{ label: 'Topics', icon: 'MessageSquare', path: '/topics' }",
3180
+ "{ label: 'Popular', icon: 'Flame', path: '/popular' }",
3181
+ "{ label: 'Profile', icon: 'User', path: '/profile' }",
3182
+ "{ label: 'Chat', icon: 'MessageCircle', path: '/websocket' }"
3183
+ ],
3184
+ mobileTabs: [
3185
+ "{ label: 'Home', icon: 'Home', path: '/' }",
3186
+ "{ label: 'Topics', icon: 'MessageSquare', path: '/topics' }",
3187
+ "{ label: 'Popular', icon: 'Flame', path: '/popular' }",
3188
+ "{ label: 'Profile', icon: 'User', path: '/profile' }",
3189
+ "{ label: 'Chat', icon: 'MessageCircle', path: '/websocket' }"
3190
+ ],
3191
+ defaultRoute: "/"
3192
+ };
2794
3193
  default:
2795
3194
  return {
2796
3195
  name: "App",
@@ -3424,12 +3823,12 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
3424
3823
  // src/index.ts
3425
3824
  var __filename2 = fileURLToPath(import.meta.url);
3426
3825
  var __dirname2 = path.dirname(__filename2);
3427
- var rootDir = __dirname2.endsWith(path.join("src")) || __dirname2.endsWith(path.join("dist")) ? path.resolve(__dirname2, "..") : path.resolve(__dirname2, "..", "..");
3826
+ var rootDir = __dirname2.endsWith(path.join("src")) ? path.resolve(__dirname2, "..") : __dirname2.endsWith(path.join("dist", "cli")) ? path.resolve(__dirname2, "..", "..") : path.resolve(__dirname2, "..", "..");
3428
3827
  var packageJson = JSON.parse(readFileSync(path.join(rootDir, "package.json"), "utf-8"));
3429
3828
  var program = new Command();
3430
3829
  program.name("create-fullstack-scaffold").description("Create a new full-stack scaffold app with Todo List example").version(packageJson.version).argument("[project-name]", "Name of your project").option("-c, --current-dir", "Create project in current directory").option(
3431
3830
  "-p, --preset <preset>",
3432
- "Template preset to use (fullstack-admin, todo-app, cli-only, minimal)"
3831
+ "Template preset to use (fullstack-admin, todo-app, ecommerce, xbrowser-marketplace, forum, cli-only, minimal, saas)"
3433
3832
  ).option("-o, --output-dir <path>", "Output directory (defaults to project name)").option("--dry-run", "Show what would be generated without creating files").action(
3434
3833
  async (projectName = "my-fullstack-app", options) => {
3435
3834
  console.log("");
@@ -3440,7 +3839,7 @@ program.name("create-fullstack-scaffold").description("Create a new full-stack s
3440
3839
  console.log("");
3441
3840
  let preset = options.preset;
3442
3841
  if (!preset && process.stdin.isTTY) {
3443
- const templateDir = path.join(__dirname2, "../template");
3842
+ const templateDir = path.join(rootDir, "template");
3444
3843
  const presets = await loadPresets(templateDir);
3445
3844
  preset = await select({
3446
3845
  message: "Choose a template preset:",
@@ -3471,7 +3870,7 @@ program.name("create-fullstack-scaffold").description("Create a new full-stack s
3471
3870
  }
3472
3871
  );
3473
3872
  program.command("presets").description("List available template presets").action(async () => {
3474
- const templateDir = path.join(__dirname2, "../template");
3873
+ const templateDir = path.join(rootDir, "template");
3475
3874
  const presets = await loadPresets(templateDir);
3476
3875
  console.log(chalk.cyan("\nAvailable presets:\n"));
3477
3876
  for (const preset of presets) {