create-velox-app 0.4.14 → 0.6.25

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 (113) hide show
  1. package/README.md +2 -43
  2. package/dist/cli.js +23 -13
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +26 -8
  5. package/dist/index.js.map +1 -1
  6. package/dist/templates/auth.d.ts.map +1 -1
  7. package/dist/templates/auth.js +24 -0
  8. package/dist/templates/auth.js.map +1 -1
  9. package/dist/templates/fullstack.d.ts +15 -0
  10. package/dist/templates/fullstack.d.ts.map +1 -0
  11. package/dist/templates/fullstack.js +110 -0
  12. package/dist/templates/fullstack.js.map +1 -0
  13. package/dist/templates/index.d.ts +1 -1
  14. package/dist/templates/index.d.ts.map +1 -1
  15. package/dist/templates/index.js +27 -5
  16. package/dist/templates/index.js.map +1 -1
  17. package/dist/templates/placeholders.d.ts +6 -1
  18. package/dist/templates/placeholders.d.ts.map +1 -1
  19. package/dist/templates/placeholders.js +15 -5
  20. package/dist/templates/placeholders.js.map +1 -1
  21. package/dist/templates/rsc.d.ts +15 -0
  22. package/dist/templates/rsc.d.ts.map +1 -0
  23. package/dist/templates/rsc.js +192 -0
  24. package/dist/templates/rsc.js.map +1 -0
  25. package/dist/templates/shared/root.d.ts +1 -0
  26. package/dist/templates/shared/root.d.ts.map +1 -1
  27. package/dist/templates/shared/root.js +4 -0
  28. package/dist/templates/shared/root.js.map +1 -1
  29. package/dist/templates/spa.d.ts +12 -0
  30. package/dist/templates/spa.d.ts.map +1 -0
  31. package/dist/templates/spa.js +101 -0
  32. package/dist/templates/spa.js.map +1 -0
  33. package/dist/templates/trpc.d.ts.map +1 -1
  34. package/dist/templates/trpc.js +16 -0
  35. package/dist/templates/trpc.js.map +1 -1
  36. package/dist/templates/types.d.ts +14 -1
  37. package/dist/templates/types.d.ts.map +1 -1
  38. package/dist/templates/types.js +35 -10
  39. package/dist/templates/types.js.map +1 -1
  40. package/package.json +3 -3
  41. package/src/templates/source/api/config/auth.ts +2 -2
  42. package/src/templates/source/api/config/database.ts +44 -10
  43. package/src/templates/source/api/index.auth.ts +10 -16
  44. package/src/templates/source/api/index.default.ts +10 -9
  45. package/src/templates/source/api/index.trpc.ts +9 -28
  46. package/src/templates/source/api/package.auth.json +7 -6
  47. package/src/templates/source/api/package.default.json +5 -4
  48. package/src/templates/source/api/prisma/schema.auth.prisma +3 -2
  49. package/src/templates/source/api/prisma/schema.default.prisma +3 -2
  50. package/src/templates/source/api/prisma.config.ts +7 -1
  51. package/src/templates/source/api/procedures/auth.ts +38 -66
  52. package/src/templates/source/api/procedures/health.ts +4 -9
  53. package/src/templates/source/api/procedures/users.auth.ts +7 -11
  54. package/src/templates/source/api/procedures/users.default.ts +7 -11
  55. package/src/templates/source/api/router.auth.ts +31 -0
  56. package/src/templates/source/api/router.default.ts +29 -0
  57. package/src/templates/source/api/router.trpc.ts +37 -0
  58. package/src/templates/source/api/router.types.auth.ts +88 -0
  59. package/src/templates/source/api/router.types.default.ts +73 -0
  60. package/src/templates/source/api/router.types.trpc.ts +73 -0
  61. package/src/templates/source/api/routes.auth.ts +66 -0
  62. package/src/templates/source/api/routes.default.ts +53 -0
  63. package/src/templates/source/api/schemas/auth.ts +79 -0
  64. package/src/templates/source/api/schemas/health.ts +21 -0
  65. package/src/templates/source/api/schemas/user.ts +62 -12
  66. package/src/templates/source/api/utils/auth.ts +157 -0
  67. package/src/templates/source/root/.cursorrules +187 -0
  68. package/src/templates/source/root/CLAUDE.auth.md +264 -0
  69. package/src/templates/source/root/CLAUDE.default.md +185 -0
  70. package/src/templates/source/root/package.json +7 -1
  71. package/src/templates/source/rsc/CLAUDE.md +104 -0
  72. package/src/templates/source/rsc/app/actions/posts.ts +93 -0
  73. package/src/templates/source/rsc/app/actions/users.ts +83 -0
  74. package/src/templates/source/rsc/app/layouts/dashboard.tsx +127 -0
  75. package/src/templates/source/rsc/app/layouts/marketing.tsx +25 -0
  76. package/src/templates/source/rsc/app/layouts/minimal.tsx +30 -0
  77. package/src/templates/source/rsc/app/layouts/root.tsx +241 -0
  78. package/src/templates/source/rsc/app/pages/(dashboard)/profile.tsx +71 -0
  79. package/src/templates/source/rsc/app/pages/(dashboard)/settings.tsx +104 -0
  80. package/src/templates/source/rsc/app/pages/(marketing)/about.tsx +52 -0
  81. package/src/templates/source/rsc/app/pages/_not-found.tsx +149 -0
  82. package/src/templates/source/rsc/app/pages/docs/[...slug].tsx +211 -0
  83. package/src/templates/source/rsc/app/pages/index.tsx +50 -0
  84. package/src/templates/source/rsc/app/pages/print.tsx +80 -0
  85. package/src/templates/source/rsc/app/pages/users/[id]/posts/[postId].tsx +89 -0
  86. package/src/templates/source/rsc/app/pages/users/[id]/posts/index.tsx +76 -0
  87. package/src/templates/source/rsc/app/pages/users/[id]/posts/new.tsx +79 -0
  88. package/src/templates/source/rsc/app/pages/users/[id].tsx +64 -0
  89. package/src/templates/source/rsc/app/pages/users/_layout.tsx +104 -0
  90. package/src/templates/source/rsc/app/pages/users.tsx +44 -0
  91. package/src/templates/source/rsc/app.config.ts +12 -0
  92. package/src/templates/source/rsc/env.example +6 -0
  93. package/src/templates/source/rsc/gitignore +34 -0
  94. package/src/templates/source/rsc/package.json +41 -0
  95. package/src/templates/source/rsc/prisma/schema.prisma +34 -0
  96. package/src/templates/source/rsc/prisma.config.ts +22 -0
  97. package/src/templates/source/rsc/public/favicon.svg +4 -0
  98. package/src/templates/source/rsc/src/api/database.ts +72 -0
  99. package/src/templates/source/rsc/src/api/handler.ts +53 -0
  100. package/src/templates/source/rsc/src/api/procedures/health.ts +48 -0
  101. package/src/templates/source/rsc/src/api/procedures/posts.ts +151 -0
  102. package/src/templates/source/rsc/src/api/procedures/users.ts +87 -0
  103. package/src/templates/source/rsc/src/api/schemas/post.ts +53 -0
  104. package/src/templates/source/rsc/src/api/schemas/user.ts +38 -0
  105. package/src/templates/source/rsc/src/entry.client.tsx +28 -0
  106. package/src/templates/source/rsc/src/entry.server.tsx +304 -0
  107. package/src/templates/source/rsc/tsconfig.json +24 -0
  108. package/src/templates/source/web/App.module.css +1 -1
  109. package/src/templates/source/web/api.ts +8 -1
  110. package/src/templates/source/web/main.tsx +4 -4
  111. package/src/templates/source/web/package.json +6 -6
  112. package/src/templates/source/web/routes/__root.tsx +2 -2
  113. package/src/templates/source/web/routes/index.auth.tsx +3 -0
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/templates/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2C;IACvE,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,sDAAsD;KAC7D;IACD,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,kDAAkD;QACxD,QAAQ,EAAE,IAAI;KACf;IACD,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,6CAA6C;QACnD,QAAQ,EAAE,IAAI;KACf;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,IAAI,iBAAiB,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAsB;IACxD,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AA8CD,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2C;IACvE,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,oCAAoC;QACjD,IAAI,EAAE,wCAAwC;KAC/C;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,0DAA0D;QACvE,IAAI,EAAE,0DAA0D;KACjE;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,aAAa;QACpB,WAAW,EAAE,oDAAoD;QACjE,IAAI,EAAE,oDAAoD;KAC3D;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,IAAI,iBAAiB,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/templates/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgBH;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAiC;IAC5D,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,KAAK;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,IAAI,QAAQ,IAAI,gBAAgB,EAAE,CAAC;QACjC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,QAAwB,CAAC;IAClC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAiBD;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2C;IACvE,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,sDAAsD;KAC7D;IACD,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,kDAAkD;QACxD,QAAQ,EAAE,IAAI;KACf;IACD,KAAK,EAAE;QACL,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,6CAA6C;QACnD,QAAQ,EAAE,IAAI;KACf;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,IAAI,iBAAiB,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAsB;IACxD,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AA8CD,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2C;IACvE,GAAG,EAAE;QACH,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,iDAAiD;QAC9D,IAAI,EAAE,2DAA2D;KAClE;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,yDAAyD;QACtE,IAAI,EAAE,0DAA0D;KACjE;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,gDAAgD;QAC7D,IAAI,EAAE,2DAA2D;KAClE;IACD,GAAG,EAAE;QACH,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,uDAAuD;QACpE,IAAI,EAAE,6DAA6D;KACpE;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,IAAI,iBAAiB,CAAC;AACvC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-velox-app",
3
- "version": "0.4.14",
3
+ "version": "0.6.25",
4
4
  "description": "Project scaffolder for VeloxTS framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,11 +21,11 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "@clack/prompts": "0.11.0",
24
- "ora": "8.1.1",
24
+ "ora": "9.0.0",
25
25
  "picocolors": "1.1.1"
26
26
  },
27
27
  "devDependencies": {
28
- "@types/node": "25.0.0",
28
+ "@types/node": "25.0.3",
29
29
  "typescript": "5.9.3"
30
30
  },
31
31
  "keywords": [
@@ -9,7 +9,7 @@
9
9
 
10
10
  import type { AuthPluginOptions } from '@veloxts/velox';
11
11
 
12
- import { prisma } from './database.js';
12
+ import { db } from './database.js';
13
13
 
14
14
  // ============================================================================
15
15
  // Environment Variable Validation
@@ -167,7 +167,7 @@ export function parseUserRoles(rolesJson: string | null): string[] {
167
167
  // ============================================================================
168
168
 
169
169
  async function userLoader(userId: string) {
170
- const user = await prisma.user.findUnique({
170
+ const user = await db.user.findUnique({
171
171
  where: { id: userId },
172
172
  });
173
173
 
@@ -2,21 +2,55 @@
2
2
  * Database Client (Prisma 7.x)
3
3
  *
4
4
  * Prisma 7 requires:
5
- * - Generated client from custom output path
6
5
  * - Driver adapter for database connections
6
+ * - Uses standard @prisma/client import path
7
+ *
8
+ * Uses Laravel-style `db` export for consistency.
7
9
  */
8
10
 
9
- import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3';
11
+ // Runtime imports using createRequire for Node.js v24+ CJS interop
12
+ import { createRequire } from 'node:module';
13
+
14
+ // Type imports (erased at runtime, safe for ESM)
15
+ import type { PrismaBetterSqlite3 as PrismaBetterSqlite3Type } from '@prisma/adapter-better-sqlite3';
16
+ import type { PrismaClient as PrismaClientType } from '@prisma/client';
10
17
 
11
- import { PrismaClient } from '../generated/prisma/client.js';
18
+ const require = createRequire(import.meta.url);
19
+ const { PrismaBetterSqlite3 } = require('@prisma/adapter-better-sqlite3') as {
20
+ PrismaBetterSqlite3: typeof PrismaBetterSqlite3Type;
21
+ };
22
+ const { PrismaClient } = require('@prisma/client') as {
23
+ PrismaClient: typeof PrismaClientType;
24
+ };
12
25
 
13
- // Validate DATABASE_URL is set
14
- if (!process.env.DATABASE_URL) {
15
- throw new Error('DATABASE_URL environment variable is required');
26
+ declare global {
27
+ // Allow global `var` declarations for hot reload in development
28
+ // eslint-disable-next-line no-var
29
+ var __db: PrismaClient | undefined;
16
30
  }
17
31
 
18
- // Create SQLite adapter with database URL from environment
19
- const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL });
32
+ /**
33
+ * Create a Prisma client instance using the SQLite adapter.
34
+ * Validates that DATABASE_URL is set before creating the client.
35
+ */
36
+ function createPrismaClient(): PrismaClient {
37
+ const databaseUrl = process.env.DATABASE_URL;
38
+
39
+ if (!databaseUrl) {
40
+ throw new Error(
41
+ '[VeloxTS] DATABASE_URL environment variable is not set. ' +
42
+ 'Ensure .env file exists with DATABASE_URL defined.'
43
+ );
44
+ }
20
45
 
21
- // Export configured Prisma client
22
- export const prisma = new PrismaClient({ adapter });
46
+ // Prisma 7 requires driver adapters for direct connections
47
+ const adapter = new PrismaBetterSqlite3({ url: databaseUrl });
48
+ return new PrismaClient({ adapter });
49
+ }
50
+
51
+ // Use global singleton for hot reload in development
52
+ export const db = globalThis.__db ?? createPrismaClient();
53
+
54
+ if (process.env.NODE_ENV !== 'production') {
55
+ globalThis.__db = db;
56
+ }
@@ -4,24 +4,18 @@
4
4
 
5
5
  import 'dotenv/config';
6
6
 
7
- import { authPlugin, databasePlugin, extractRoutes, rest, veloxApp } from '@veloxts/velox';
7
+ import { authPlugin, databasePlugin, rest, veloxApp } from '@veloxts/velox';
8
8
 
9
9
  import { config } from './config/app.js';
10
10
  import { authConfig } from './config/auth.js';
11
- import { prisma } from './config/database.js';
12
- import { authProcedures } from './procedures/auth.js';
13
- import { healthProcedures } from './procedures/health.js';
14
- import { userProcedures } from './procedures/users.js';
11
+ import { db } from './config/database.js';
12
+ // Import router definition (type-only safe for frontend imports)
13
+ import { collections } from './router.js';
15
14
 
16
- // Procedure collections for routing
17
- const collections = [healthProcedures, authProcedures, userProcedures];
18
-
19
- // Router type for frontend type safety
20
- const router = { auth: authProcedures, health: healthProcedures, users: userProcedures };
21
- export type AppRouter = typeof router;
22
-
23
- // Route mappings for frontend client - imported directly, no manual duplication needed
24
- export const routes = extractRoutes(collections);
15
+ // Re-export AppRouter and routes for backward compatibility
16
+ // Frontend should import from ./router.js directly for type safety
17
+ export type { AppRouter } from './router.js';
18
+ export { routes } from './router.js';
25
19
 
26
20
  const app = await veloxApp({
27
21
  port: config.port,
@@ -29,7 +23,7 @@ const app = await veloxApp({
29
23
  logger: config.logger,
30
24
  });
31
25
 
32
- await app.register(databasePlugin({ client: prisma }));
26
+ await app.register(databasePlugin({ client: db }));
33
27
  await app.register(authPlugin(authConfig));
34
28
 
35
29
  app.routes(
@@ -54,7 +48,7 @@ const shutdown = async () => {
54
48
  isShuttingDown = true;
55
49
 
56
50
  try {
57
- await prisma.$disconnect();
51
+ await db.$disconnect();
58
52
  } catch {
59
53
  // Ignore disconnect errors during shutdown
60
54
  }
@@ -7,13 +7,14 @@ import 'dotenv/config';
7
7
  import { databasePlugin, rest, veloxApp } from '@veloxts/velox';
8
8
 
9
9
  import { config } from './config/app.js';
10
- import { prisma } from './config/database.js';
11
- import { healthProcedures } from './procedures/health.js';
12
- import { userProcedures } from './procedures/users.js';
10
+ import { db } from './config/database.js';
11
+ // Import router definition (type-only safe for frontend imports)
12
+ import { collections } from './router.js';
13
13
 
14
- // Router type for frontend type safety
15
- const router = { health: healthProcedures, users: userProcedures };
16
- export type AppRouter = typeof router;
14
+ // Re-export AppRouter and routes for backward compatibility
15
+ // Frontend should import from ./router.js directly for type safety
16
+ export type { AppRouter } from './router.js';
17
+ export { routes } from './router.js';
17
18
 
18
19
  const app = await veloxApp({
19
20
  port: config.port,
@@ -21,10 +22,10 @@ const app = await veloxApp({
21
22
  logger: config.logger,
22
23
  });
23
24
 
24
- await app.register(databasePlugin({ client: prisma }));
25
+ await app.register(databasePlugin({ client: db }));
25
26
 
26
27
  app.routes(
27
- rest([healthProcedures, userProcedures], {
28
+ rest(collections, {
28
29
  prefix: config.apiPrefix,
29
30
  })
30
31
  );
@@ -45,7 +46,7 @@ const shutdown = async () => {
45
46
  isShuttingDown = true;
46
47
 
47
48
  try {
48
- await prisma.$disconnect();
49
+ await db.$disconnect();
49
50
  } catch {
50
51
  // Ignore disconnect errors during shutdown
51
52
  }
@@ -13,32 +13,13 @@ import 'dotenv/config';
13
13
  import { databasePlugin, serve, veloxApp } from '@veloxts/velox';
14
14
 
15
15
  import { config } from './config/app.js';
16
- import { prisma } from './config/database.js';
17
- import { healthProcedures } from './procedures/health.js';
18
- import { userProcedures } from './procedures/users.js';
16
+ import { db } from './config/database.js';
17
+ // Import router definition (type-only safe for frontend imports)
18
+ import { collections } from './router.js';
19
19
 
20
- // ============================================================================
21
- // Type Exports for Frontend
22
- // ============================================================================
23
-
24
- /**
25
- * AppRouter type for frontend type safety
26
- *
27
- * Constructed from procedure collections to preserve full type information.
28
- * This enables type-safe API calls with full autocomplete.
29
- *
30
- * @example
31
- * ```typescript
32
- * import type { AppRouter } from '../../api/src';
33
- * import { createVeloxHooks } from '@veloxts/client/react';
34
- *
35
- * export const api = createVeloxHooks<AppRouter>();
36
- * ```
37
- */
38
- export type AppRouter = {
39
- health: typeof healthProcedures;
40
- users: typeof userProcedures;
41
- };
20
+ // Re-export AppRouter for backward compatibility
21
+ // Frontend should import from ./router.js directly for type safety
22
+ export type { AppRouter } from './router.js';
42
23
 
43
24
  // ============================================================================
44
25
  // Application Bootstrap
@@ -50,7 +31,7 @@ const app = await veloxApp({
50
31
  logger: config.logger,
51
32
  });
52
33
 
53
- await app.register(databasePlugin({ client: prisma }));
34
+ await app.register(databasePlugin({ client: db }));
54
35
 
55
36
  // ============================================================================
56
37
  // API Registration
@@ -62,7 +43,7 @@ await app.register(databasePlugin({ client: prisma }));
62
43
  * - REST: /api/users, /api/health
63
44
  * - tRPC: /trpc/users.getUser, /trpc/health.getHealth
64
45
  */
65
- await serve(app, [healthProcedures, userProcedures], {
46
+ await serve(app, collections, {
66
47
  api: config.apiPrefix,
67
48
  rpc: '/trpc',
68
49
  });
@@ -83,7 +64,7 @@ const shutdown = async () => {
83
64
  isShuttingDown = true;
84
65
 
85
66
  try {
86
- await prisma.$disconnect();
67
+ await db.$disconnect();
87
68
  } catch {
88
69
  // Ignore disconnect errors during shutdown
89
70
  }
@@ -17,21 +17,22 @@
17
17
  "postinstall": "prisma generate"
18
18
  },
19
19
  "dependencies": {
20
- "@prisma/adapter-better-sqlite3": "7.1.0",
21
- "@prisma/client": "7.1.0",
20
+ "@prisma/adapter-better-sqlite3": "7.2.0",
21
+ "@prisma/client": "7.2.0",
22
+ "@prisma/client-runtime-utils": "7.2.0",
22
23
  "@veloxts/velox": "__VELOXTS_VERSION__",
23
- "bcrypt": "5.1.1",
24
+ "bcrypt": "6.0.0",
24
25
  "better-sqlite3": "12.5.0",
25
26
  "dotenv": "17.2.3",
26
27
  "file-uri-to-path": "2.0.0",
27
- "zod": "3.24.4"
28
+ "zod": "3.25.76"
28
29
  },
29
30
  "devDependencies": {
30
- "@types/bcrypt": "5.0.2",
31
+ "@types/bcrypt": "6.0.0",
31
32
  "@types/node": "25.0.2",
32
33
  "@veloxts/cli": "__VELOXTS_VERSION__",
33
34
  "hot-hook": "0.4.0",
34
- "prisma": "7.1.0",
35
+ "prisma": "7.2.0",
35
36
  "tsup": "8.5.1",
36
37
  "tsx": "4.21.0",
37
38
  "typescript": "5.9.3"
@@ -17,19 +17,20 @@
17
17
  "postinstall": "prisma generate"
18
18
  },
19
19
  "dependencies": {
20
- "@prisma/adapter-better-sqlite3": "7.1.0",
21
- "@prisma/client": "7.1.0",
20
+ "@prisma/adapter-better-sqlite3": "7.2.0",
21
+ "@prisma/client": "7.2.0",
22
+ "@prisma/client-runtime-utils": "7.2.0",
22
23
  "@veloxts/velox": "__VELOXTS_VERSION__",
23
24
  "better-sqlite3": "12.5.0",
24
25
  "dotenv": "17.2.3",
25
26
  "file-uri-to-path": "2.0.0",
26
- "zod": "3.24.4"
27
+ "zod": "3.25.76"
27
28
  },
28
29
  "devDependencies": {
29
30
  "@types/node": "25.0.2",
30
31
  "@veloxts/cli": "__VELOXTS_VERSION__",
31
32
  "hot-hook": "0.4.0",
32
- "prisma": "7.1.0",
33
+ "prisma": "7.2.0",
33
34
  "tsup": "8.5.1",
34
35
  "tsx": "4.21.0",
35
36
  "typescript": "5.9.3"
@@ -4,8 +4,9 @@
4
4
  // Using SQLite for simplicity - easily swap to PostgreSQL for production.
5
5
 
6
6
  generator client {
7
- provider = "prisma-client"
8
- output = "../src/generated/prisma"
7
+ provider = "prisma-client-js"
8
+ // Generate to root node_modules for workspace compatibility
9
+ output = "../../../node_modules/.prisma/client"
9
10
  }
10
11
 
11
12
  datasource db {
@@ -4,8 +4,9 @@
4
4
  // Using SQLite for simplicity - easily swap to PostgreSQL for production.
5
5
 
6
6
  generator client {
7
- provider = "prisma-client"
8
- output = "../src/generated/prisma"
7
+ provider = "prisma-client-js"
8
+ // Generate to root node_modules for workspace compatibility
9
+ output = "../../../node_modules/.prisma/client"
9
10
  }
10
11
 
11
12
  datasource db {
@@ -8,9 +8,15 @@ import 'dotenv/config';
8
8
 
9
9
  import { defineConfig } from 'prisma/config';
10
10
 
11
+ const databaseUrl = process.env.DATABASE_URL;
12
+
13
+ if (!databaseUrl) {
14
+ throw new Error('DATABASE_URL environment variable is required');
15
+ }
16
+
11
17
  export default defineConfig({
12
18
  schema: './prisma/schema.prisma',
13
19
  datasource: {
14
- url: process.env.DATABASE_URL!,
20
+ url: databaseUrl,
15
21
  },
16
22
  });
@@ -20,11 +20,17 @@ import {
20
20
  jwtManager,
21
21
  procedure,
22
22
  verifyPassword,
23
- z,
24
23
  } from '@veloxts/velox';
25
24
 
26
- import { authConfig, parseUserRoles, tokenStore } from '../config/auth.js';
27
- import { prisma } from '../config/database.js';
25
+ import {
26
+ LoginInput,
27
+ LogoutResponse,
28
+ RefreshInput,
29
+ RegisterInput,
30
+ TokenResponse,
31
+ UserResponse,
32
+ } from '../schemas/auth.js';
33
+ import { getJwtSecrets, parseUserRoles, tokenStore } from '../utils/auth.js';
28
34
 
29
35
  // ============================================================================
30
36
  // Rate Limiter
@@ -50,7 +56,7 @@ const rateLimiter = createAuthRateLimiter({
50
56
  });
51
57
 
52
58
  // ============================================================================
53
- // Password Blacklist
59
+ // Password Blacklist (runtime-only, not in type chain)
54
60
  // ============================================================================
55
61
 
56
62
  const COMMON_PASSWORDS = new Set([
@@ -64,66 +70,32 @@ const COMMON_PASSWORDS = new Set([
64
70
  'admin123',
65
71
  ]);
66
72
 
67
- // ============================================================================
68
- // Schemas
69
- // ============================================================================
70
-
71
- const PasswordSchema = z
72
- .string()
73
- .min(12, 'Password must be at least 12 characters')
74
- .max(128, 'Password must not exceed 128 characters')
75
- .refine((pwd) => /[a-z]/.test(pwd), 'Password must contain at least one lowercase letter')
76
- .refine((pwd) => /[A-Z]/.test(pwd), 'Password must contain at least one uppercase letter')
77
- .refine((pwd) => /[0-9]/.test(pwd), 'Password must contain at least one number')
78
- .refine(
79
- (pwd) => !COMMON_PASSWORDS.has(pwd.toLowerCase()),
80
- 'Password is too common. Please choose a stronger password.'
81
- );
82
-
83
- const EmailSchema = z
84
- .string()
85
- .email('Invalid email address')
86
- .transform((email) => email.toLowerCase().trim());
87
-
88
- const RegisterInput = z.object({
89
- name: z.string().min(2).max(100).trim(),
90
- email: EmailSchema,
91
- password: PasswordSchema,
92
- });
93
-
94
- const LoginInput = z.object({
95
- email: EmailSchema,
96
- password: z.string().min(1),
97
- });
98
-
99
- const RefreshInput = z.object({
100
- refreshToken: z.string(),
101
- });
102
-
103
- const TokenResponse = z.object({
104
- accessToken: z.string(),
105
- refreshToken: z.string(),
106
- expiresIn: z.number(),
107
- tokenType: z.literal('Bearer'),
108
- });
109
-
110
- const UserResponse = z.object({
111
- id: z.string(),
112
- name: z.string(),
113
- email: z.string(),
114
- roles: z.array(z.string()),
115
- });
116
-
117
- const LogoutResponse = z.object({
118
- success: z.boolean(),
119
- message: z.string(),
73
+ // Enhanced password validation with common password check
74
+ const EnhancedRegisterInput = RegisterInput.extend({
75
+ password: RegisterInput.shape.password
76
+ .refine((pwd) => /[a-z]/.test(pwd), 'Password must contain at least one lowercase letter')
77
+ .refine((pwd) => /[A-Z]/.test(pwd), 'Password must contain at least one uppercase letter')
78
+ .refine((pwd) => /[0-9]/.test(pwd), 'Password must contain at least one number')
79
+ .refine(
80
+ (pwd) => !COMMON_PASSWORDS.has(pwd.toLowerCase()),
81
+ 'Password is too common. Please choose a stronger password.'
82
+ ),
120
83
  });
121
84
 
122
85
  // ============================================================================
123
86
  // JWT Manager
124
87
  // ============================================================================
125
88
 
126
- const jwt = jwtManager(authConfig.jwt);
89
+ const { jwtSecret, refreshSecret } = getJwtSecrets();
90
+
91
+ const jwt = jwtManager({
92
+ secret: jwtSecret,
93
+ refreshSecret: refreshSecret,
94
+ accessTokenExpiry: '15m',
95
+ refreshTokenExpiry: '7d',
96
+ issuer: 'velox-app',
97
+ audience: 'velox-app-client',
98
+ });
127
99
 
128
100
  // Dummy hash for timing attack prevention
129
101
  const DUMMY_HASH = '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4.uy7dPSSXB5G6Uy';
@@ -136,12 +108,12 @@ export const authProcedures = defineProcedures('auth', {
136
108
  createAccount: procedure()
137
109
  .rest({ method: 'POST', path: '/auth/register' })
138
110
  .use(rateLimiter.register())
139
- .input(RegisterInput)
111
+ .input(EnhancedRegisterInput)
140
112
  .output(TokenResponse)
141
- .mutation(async ({ input }) => {
113
+ .mutation(async ({ input, ctx }) => {
142
114
  const normalizedEmail = input.email.toLowerCase().trim();
143
115
 
144
- const existing = await prisma.user.findUnique({
116
+ const existing = await ctx.db.user.findUnique({
145
117
  where: { email: normalizedEmail },
146
118
  });
147
119
 
@@ -155,7 +127,7 @@ export const authProcedures = defineProcedures('auth', {
155
127
 
156
128
  const hashedPassword = await hashPassword(input.password);
157
129
 
158
- const user = await prisma.user.create({
130
+ const user = await ctx.db.user.create({
159
131
  data: {
160
132
  name: input.name.trim(),
161
133
  email: normalizedEmail,
@@ -181,10 +153,10 @@ export const authProcedures = defineProcedures('auth', {
181
153
  )
182
154
  .input(LoginInput)
183
155
  .output(TokenResponse)
184
- .mutation(async ({ input }) => {
156
+ .mutation(async ({ input, ctx }) => {
185
157
  const normalizedEmail = input.email.toLowerCase().trim();
186
158
 
187
- const user = await prisma.user.findUnique({
159
+ const user = await ctx.db.user.findUnique({
188
160
  where: { email: normalizedEmail },
189
161
  });
190
162
 
@@ -209,7 +181,7 @@ export const authProcedures = defineProcedures('auth', {
209
181
  .use(rateLimiter.refresh())
210
182
  .input(RefreshInput)
211
183
  .output(TokenResponse)
212
- .mutation(async ({ input }) => {
184
+ .mutation(async ({ input, ctx }) => {
213
185
  try {
214
186
  const payload = jwt.verifyToken(input.refreshToken);
215
187
 
@@ -234,7 +206,7 @@ export const authProcedures = defineProcedures('auth', {
234
206
  tokenStore.markRefreshTokenUsed(payload.jti, payload.sub);
235
207
  }
236
208
 
237
- const user = await prisma.user.findUnique({
209
+ const user = await ctx.db.user.findUnique({
238
210
  where: { id: payload.sub },
239
211
  });
240
212
 
@@ -2,19 +2,14 @@
2
2
  * Health Check Procedures
3
3
  */
4
4
 
5
- import { defineProcedures, procedure, VELOX_VERSION, z } from '@veloxts/velox';
5
+ import { defineProcedures, procedure, VELOX_VERSION } from '@veloxts/velox';
6
+
7
+ import { HealthResponse } from '../schemas/health.js';
6
8
 
7
9
  export const healthProcedures = defineProcedures('health', {
8
10
  getHealth: procedure()
9
11
  .rest({ method: 'GET', path: '/health' })
10
- .output(
11
- z.object({
12
- status: z.literal('ok'),
13
- version: z.string(),
14
- timestamp: z.string().datetime(),
15
- uptime: z.number(),
16
- })
17
- )
12
+ .output(HealthResponse)
18
13
  .query(async () => ({
19
14
  status: 'ok' as const,
20
15
  version: VELOX_VERSION,
@@ -20,7 +20,12 @@ import {
20
20
  z,
21
21
  } from '@veloxts/velox';
22
22
 
23
- import { CreateUserInput, UpdateUserInput, UserSchema } from '../schemas/user.js';
23
+ import {
24
+ CreateUserInput,
25
+ ListUsersResponse,
26
+ UpdateUserInput,
27
+ UserSchema,
28
+ } from '../schemas/user.js';
24
29
 
25
30
  // ============================================================================
26
31
  // User Procedures
@@ -41,16 +46,7 @@ export const userProcedures = defineProcedures('users', {
41
46
 
42
47
  listUsers: procedure()
43
48
  .input(paginationInputSchema.optional())
44
- .output(
45
- z.object({
46
- data: z.array(UserSchema),
47
- meta: z.object({
48
- page: z.number(),
49
- limit: z.number(),
50
- total: z.number(),
51
- }),
52
- })
53
- )
49
+ .output(ListUsersResponse)
54
50
  .query(async ({ input, ctx }) => {
55
51
  const page = input?.page ?? 1;
56
52
  const limit = input?.limit ?? 10;
@@ -15,7 +15,12 @@ import {
15
15
  z,
16
16
  } from '@veloxts/velox';
17
17
 
18
- import { CreateUserInput, UpdateUserInput, UserSchema } from '../schemas/user.js';
18
+ import {
19
+ CreateUserInput,
20
+ ListUsersResponse,
21
+ UpdateUserInput,
22
+ UserSchema,
23
+ } from '../schemas/user.js';
19
24
 
20
25
  export const userProcedures = defineProcedures('users', {
21
26
  getUser: procedure()
@@ -32,16 +37,7 @@ export const userProcedures = defineProcedures('users', {
32
37
 
33
38
  listUsers: procedure()
34
39
  .input(paginationInputSchema.optional())
35
- .output(
36
- z.object({
37
- data: z.array(UserSchema),
38
- meta: z.object({
39
- page: z.number(),
40
- limit: z.number(),
41
- total: z.number(),
42
- }),
43
- })
44
- )
40
+ .output(ListUsersResponse)
45
41
  .query(async ({ input, ctx }) => {
46
42
  const page = input?.page ?? 1;
47
43
  const limit = input?.limit ?? 10;