create-fullstack-scaffold 0.5.6 → 0.6.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 (54) hide show
  1. package/dist/cli/index.js +80 -22
  2. package/dist/cli/index.js.map +1 -1
  3. package/package.json +12 -12
  4. package/template/package.json +10 -14
  5. package/template/src/cli/modules/tenant/index.ts +89 -0
  6. package/template/src/client/entry-server.tsx +7 -1
  7. package/template/src/client/main.tsx +0 -8
  8. package/template/src/client/pages/ContentDetailPage.tsx +1 -1
  9. package/template/src/client/pages/ContentListPage.tsx +1 -1
  10. package/template/src/client/pages/TodoPage.tsx +20 -4
  11. package/template/src/client/ssr-pages.ts +10 -21
  12. package/template/src/server/db/init.ts +0 -52
  13. package/template/src/server/db/schema/index.ts +3 -0
  14. package/template/src/server/db/schema/tenant-invitations.ts +33 -0
  15. package/template/src/server/db/schema/tenant-members.ts +38 -0
  16. package/template/src/server/db/schema/tenant-roles.ts +32 -0
  17. package/template/src/server/db/schema/todos.ts +4 -0
  18. package/template/src/server/db/test-setup.ts +128 -0
  19. package/template/src/server/entries/node.ts +38 -19
  20. package/template/src/server/index.ts +12 -0
  21. package/template/src/server/middleware/__tests__/tenant-isolation.test.ts +55 -9
  22. package/template/src/server/middleware/auth.ts +17 -19
  23. package/template/src/server/middleware/tenant-isolation.ts +4 -2
  24. package/template/src/server/module-auth/module.ts +2 -1
  25. package/template/src/server/module-auth/services/auth-service.ts +39 -0
  26. package/template/src/server/module-tenant/__tests__/tenant-routes.test.ts +97 -0
  27. package/template/src/server/module-tenant/__tests__/tenant-service.test.ts +201 -22
  28. package/template/src/server/module-tenant/module.ts +1 -1
  29. package/template/src/server/module-tenant/routes/tenant-routes.ts +339 -2
  30. package/template/src/server/module-tenant/services/tenant-service.ts +581 -17
  31. package/template/src/server/module-todos/routes/todos-routes.ts +10 -2
  32. package/template/src/server/module-todos/services/todo-service.ts +12 -2
  33. package/template/src/server/ssr-bridge.ts +10 -0
  34. package/template/src/server/utils/__tests__/captcha.test.ts +6 -4
  35. package/template/src/server/utils/id-helpers.ts +13 -0
  36. package/template/src/shared/modules/index.ts +29 -6
  37. package/template/src/shared/modules/tenant/index.ts +30 -0
  38. package/template/src/shared/modules/tenant/permissions.ts +54 -0
  39. package/template/src/shared/modules/tenant/role-templates.ts +66 -0
  40. package/template/src/shared/modules/tenant/schemas.ts +113 -1
  41. package/template/src/shared/modules/todos/schemas.ts +1 -0
  42. package/template/src/shared/schemas/index.ts +28 -0
  43. package/template/src/tenant/App.tsx +30 -23
  44. package/template/src/tenant/components/TenantGuard.tsx +12 -2
  45. package/template/src/tenant/layouts/Header.tsx +6 -2
  46. package/template/src/tenant/pages/InviteAcceptPage.tsx +97 -0
  47. package/template/src/tenant/pages/LoginPage.tsx +82 -0
  48. package/template/src/tenant/pages/SubscriptionPage.tsx +32 -55
  49. package/template/src/tenant/pages/UsersPage.tsx +134 -88
  50. package/template/src/tenant/services/tenantApi.ts +61 -0
  51. package/template/src/tenant/stores/tenantStore.ts +172 -49
  52. package/template/src/test/setup-db-path.ts +20 -0
  53. package/template/vite.config.ts +4 -73
  54. package/template/vitest.config.ts +3 -1
package/dist/cli/index.js CHANGED
@@ -287,6 +287,7 @@ function getGeneratedFiles(resolved) {
287
287
  "src/server/isr-modules.ts",
288
288
  "src/client/stores/entry-stores.ts",
289
289
  "src/client/ssr-pages.ts",
290
+ "src/server/ssr-bridge.ts",
290
291
  "src/server/db/schema/index.ts",
291
292
  "src/shared/modules/index.ts",
292
293
  "src/shared/schemas/index.ts",
@@ -1582,6 +1583,7 @@ function generateServerApp(resolved) {
1582
1583
  const useRealtime = resolved.hasSSE || resolved.hasWebSocket;
1583
1584
  const useAuditLog = resolved.hasPermission;
1584
1585
  const useCaptcha = resolved.hasCaptcha;
1586
+ const useTenantIsolation = resolved.modules.has("tenant");
1585
1587
  const standaloneRoutes = getStandaloneRoutes(resolved);
1586
1588
  const imports = [
1587
1589
  `import { OpenAPIHono } from '@hono/zod-openapi'`,
@@ -1603,6 +1605,9 @@ function generateServerApp(resolved) {
1603
1605
  if (useCaptcha) {
1604
1606
  imports.push(`import { captchaMiddleware } from './middleware/captcha'`);
1605
1607
  }
1608
+ if (useTenantIsolation) {
1609
+ imports.push(`import { tenantIsolationMiddleware } from './middleware/tenant-isolation'`);
1610
+ }
1606
1611
  imports.push(
1607
1612
  `import { createModuleLoggerSync } from './utils/logger'`,
1608
1613
  `import { adminApiRoutes, clientApiRoutes } from './route-registry'`
@@ -1642,6 +1647,9 @@ function generateServerApp(resolved) {
1642
1647
  )`
1643
1648
  );
1644
1649
  }
1650
+ if (useTenantIsolation) {
1651
+ middlewareChain.push(`.use('/api/*', tenantIsolationMiddleware())`);
1652
+ }
1645
1653
  const routes = [`.route('/', clientApiRoutes)`, `.route('/', adminApiRoutes)`];
1646
1654
  for (const sr of standaloneRoutes) {
1647
1655
  routes.push(`.route('${sr.mountPath}', ${sr.localName})`);
@@ -1914,6 +1922,24 @@ var MODULE_EXPORTS = {
1914
1922
  "TenantListResponseSchema",
1915
1923
  "TenantQuerySchema",
1916
1924
  "TenantIdResponseSchema",
1925
+ "TenantRoleSchema",
1926
+ "CreateTenantRoleSchema",
1927
+ "UpdateTenantRoleSchema",
1928
+ "TenantMemberSchema",
1929
+ "UpdateMemberRoleSchema",
1930
+ "TenantInvitationSchema",
1931
+ "InviteMemberSchema",
1932
+ "PublicInvitationSchema",
1933
+ "StringIdResponseSchema",
1934
+ "TenantArrayResponseSchema",
1935
+ "TenantRoleArrayResponseSchema",
1936
+ "TenantMemberArrayResponseSchema",
1937
+ "TenantPermission",
1938
+ "TENANT_PERMISSION_VALUES",
1939
+ "TENANT_PERMISSION_LABELS",
1940
+ "TenantRoleCode",
1941
+ "TENANT_ROLE_TEMPLATES",
1942
+ "PLAN_ROLE_LIMITS",
1917
1943
  "type Tenant",
1918
1944
  "type TenantStatus",
1919
1945
  "type TenantPlan",
@@ -1924,7 +1950,17 @@ var MODULE_EXPORTS = {
1924
1950
  "type TenantSlug",
1925
1951
  "type TenantListResponse",
1926
1952
  "type TenantQuery",
1927
- "type TenantIdResponse"
1953
+ "type TenantIdResponse",
1954
+ "type TenantRole",
1955
+ "type CreateTenantRoleInput",
1956
+ "type UpdateTenantRoleInput",
1957
+ "type TenantMember",
1958
+ "type UpdateMemberRoleInput",
1959
+ "type TenantInvitation",
1960
+ "type InviteMemberInput",
1961
+ "type PublicInvitation",
1962
+ "type StringIdResponse",
1963
+ "type TenantRoleTemplate"
1928
1964
  ]
1929
1965
  },
1930
1966
  order: {
@@ -2485,6 +2521,24 @@ var MODULE_EXPORTS2 = {
2485
2521
  "TenantListResponseSchema",
2486
2522
  "TenantQuerySchema",
2487
2523
  "TenantIdResponseSchema",
2524
+ "TenantRoleSchema",
2525
+ "CreateTenantRoleSchema",
2526
+ "UpdateTenantRoleSchema",
2527
+ "TenantMemberSchema",
2528
+ "UpdateMemberRoleSchema",
2529
+ "TenantInvitationSchema",
2530
+ "InviteMemberSchema",
2531
+ "PublicInvitationSchema",
2532
+ "StringIdResponseSchema",
2533
+ "TenantArrayResponseSchema",
2534
+ "TenantRoleArrayResponseSchema",
2535
+ "TenantMemberArrayResponseSchema",
2536
+ "TenantPermission",
2537
+ "TENANT_PERMISSION_VALUES",
2538
+ "TENANT_PERMISSION_LABELS",
2539
+ "TenantRoleCode",
2540
+ "TENANT_ROLE_TEMPLATES",
2541
+ "PLAN_ROLE_LIMITS",
2488
2542
  "type Tenant",
2489
2543
  "type TenantStatus",
2490
2544
  "type TenantPlan",
@@ -2495,7 +2549,17 @@ var MODULE_EXPORTS2 = {
2495
2549
  "type TenantSlug",
2496
2550
  "type TenantListResponse",
2497
2551
  "type TenantQuery",
2498
- "type TenantIdResponse"
2552
+ "type TenantIdResponse",
2553
+ "type TenantRole",
2554
+ "type CreateTenantRoleInput",
2555
+ "type UpdateTenantRoleInput",
2556
+ "type TenantMember",
2557
+ "type UpdateMemberRoleInput",
2558
+ "type TenantInvitation",
2559
+ "type InviteMemberInput",
2560
+ "type PublicInvitation",
2561
+ "type StringIdResponse",
2562
+ "type TenantRoleTemplate"
2499
2563
  ]
2500
2564
  },
2501
2565
  dispute: {
@@ -3179,10 +3243,6 @@ var CLIENT_DEV_PACKAGES = [
3179
3243
  "autoprefixer",
3180
3244
  "@playwright/test",
3181
3245
  "playwright",
3182
- "@prerenderer/renderer-jsdom",
3183
- "@prerenderer/renderer-puppeteer",
3184
- "puppeteer",
3185
- "@prerenderer/rollup-plugin",
3186
3246
  "eventsource"
3187
3247
  ];
3188
3248
  var CLIENT_TYPE_PACKAGES = ["@types/react", "@types/react-dom"];
@@ -3970,14 +4030,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
3970
4030
  <RootApp />
3971
4031
  </React.StrictMode>,
3972
4032
  )
3973
-
3974
- if (typeof window !== 'undefined') {
3975
- requestAnimationFrame(() => {
3976
- setTimeout(() => {
3977
- document.dispatchEvent(new CustomEvent('prerender-ready'))
3978
- }, 100)
3979
- })
3980
- }
3981
4033
  `;
3982
4034
  }
3983
4035
  return `import React from 'react'
@@ -4001,14 +4053,6 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
4001
4053
  <RootApp />
4002
4054
  </React.StrictMode>,
4003
4055
  )
4004
-
4005
- if (typeof window !== 'undefined') {
4006
- requestAnimationFrame(() => {
4007
- setTimeout(() => {
4008
- document.dispatchEvent(new CustomEvent('prerender-ready'))
4009
- }, 100)
4010
- })
4011
- }
4012
4056
  `;
4013
4057
  }
4014
4058
 
@@ -4304,6 +4348,20 @@ async function createProject(projectNameOrOptions, useCurrentDir = false, preset
4304
4348
  (name) => fs.existsSync(path.join(targetDir, "src/client/pages", `${name}.tsx`))
4305
4349
  );
4306
4350
  await fs.writeFile(path.join(targetDir, "src/client/ssr-pages.ts"), ssrPagesContent);
4351
+ const ssrBridgePath = path.join(targetDir, "src/server/ssr-bridge.ts");
4352
+ const hasClientDir = fs.existsSync(path.join(targetDir, "src/client/entry-server.tsx"));
4353
+ const bridge = hasClientDir ? "import { renderSSR as renderSSRImpl } from '@client/entry-server'\n\n// data \u7531 ISR registry fetch \u63D0\u4F9B\uFF0CrenderSSRImpl \u5185\u90E8\u81EA\u53D6\u6240\u9700\u5B57\u6BB5\nexport function renderSSR(pathname: string, data: unknown): { html: string } | null {\n return renderSSRImpl(pathname, data as Parameters<typeof renderSSRImpl>[1])\n}\n" : "export function renderSSR(...args: unknown[]): { html: string } | null {\n return null\n}\n";
4354
+ await fs.writeFile(ssrBridgePath, bridge);
4355
+ } else {
4356
+ await fs.writeFile(
4357
+ path.join(targetDir, "src/server/ssr-bridge.ts"),
4358
+ "export const renderSSR: ((pathname: string, data: unknown) => { html: string } | null) | null = null\n"
4359
+ );
4360
+ await fs.ensureDir(path.join(targetDir, "src/client"));
4361
+ await fs.writeFile(
4362
+ path.join(targetDir, "src/client/ssr-pages.ts"),
4363
+ "// \u672C preset \u65E0 client \u9875\u9762\u2014\u2014SSR \u8F93\u51FA\u5E03\u5C40\u58F3 + meta\nexport function getSsrPage(_pathname: string): null {\n return null\n}\n"
4364
+ );
4307
4365
  }
4308
4366
  const dbSchemaContent = generateDbSchemaBarrel(resolved);
4309
4367
  await fs.writeFile(path.join(targetDir, "src/server/db/schema/index.ts"), dbSchemaContent);