create-velox-app 0.4.2 → 0.4.4

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 (174) hide show
  1. package/dist/cli.js +0 -0
  2. package/dist/index.js +21 -14
  3. package/dist/index.js.map +1 -1
  4. package/dist/templates/auth.d.ts +6 -3
  5. package/dist/templates/auth.d.ts.map +1 -1
  6. package/dist/templates/auth.js +56 -1110
  7. package/dist/templates/auth.js.map +1 -1
  8. package/dist/templates/compiler.d.ts +68 -0
  9. package/dist/templates/compiler.d.ts.map +1 -0
  10. package/dist/templates/compiler.js +149 -0
  11. package/dist/templates/compiler.js.map +1 -0
  12. package/dist/templates/default.d.ts +5 -2
  13. package/dist/templates/default.d.ts.map +1 -1
  14. package/dist/templates/default.js +51 -508
  15. package/dist/templates/default.js.map +1 -1
  16. package/dist/templates/index.d.ts.map +1 -1
  17. package/dist/templates/index.js +19 -10
  18. package/dist/templates/index.js.map +1 -1
  19. package/dist/templates/placeholders.d.ts +70 -0
  20. package/dist/templates/placeholders.d.ts.map +1 -0
  21. package/dist/templates/placeholders.js +145 -0
  22. package/dist/templates/placeholders.js.map +1 -0
  23. package/dist/templates/shared/index.d.ts +9 -0
  24. package/dist/templates/shared/index.d.ts.map +1 -0
  25. package/dist/templates/shared/index.js +9 -0
  26. package/dist/templates/shared/index.js.map +1 -0
  27. package/dist/templates/shared/root.d.ts +14 -0
  28. package/dist/templates/shared/root.d.ts.map +1 -0
  29. package/dist/templates/shared/root.js +43 -0
  30. package/dist/templates/shared/root.js.map +1 -0
  31. package/dist/templates/shared/web-base.d.ts +18 -0
  32. package/dist/templates/shared/web-base.d.ts.map +1 -0
  33. package/dist/templates/shared/web-base.js +63 -0
  34. package/dist/templates/shared/web-base.js.map +1 -0
  35. package/dist/templates/shared/web-styles.d.ts +10 -0
  36. package/dist/templates/shared/web-styles.d.ts.map +1 -0
  37. package/dist/templates/shared/web-styles.js +26 -0
  38. package/dist/templates/shared/web-styles.js.map +1 -0
  39. package/dist/templates/shared.d.ts +3 -14
  40. package/dist/templates/shared.d.ts.map +1 -1
  41. package/dist/templates/shared.js +7 -290
  42. package/dist/templates/shared.js.map +1 -1
  43. package/dist/templates/source/api/config/app.d.ts +13 -0
  44. package/dist/templates/source/api/config/app.d.ts.map +1 -0
  45. package/dist/templates/source/api/config/app.js +14 -0
  46. package/dist/templates/source/api/config/app.js.map +1 -0
  47. package/dist/templates/source/api/config/auth.d.ts +34 -0
  48. package/dist/templates/source/api/config/auth.d.ts.map +1 -0
  49. package/dist/templates/source/api/config/auth.js +165 -0
  50. package/dist/templates/source/api/config/auth.js.map +1 -0
  51. package/dist/templates/source/api/config/index.auth.d.ts +6 -0
  52. package/dist/templates/source/api/config/index.auth.d.ts.map +1 -0
  53. package/dist/templates/source/api/config/index.auth.js +6 -0
  54. package/dist/templates/source/api/config/index.auth.js.map +1 -0
  55. package/dist/templates/source/api/config/index.default.d.ts +5 -0
  56. package/dist/templates/source/api/config/index.default.d.ts.map +1 -0
  57. package/dist/templates/source/api/config/index.default.js +5 -0
  58. package/dist/templates/source/api/config/index.default.js.map +1 -0
  59. package/dist/templates/source/api/database/index.d.ts +9 -0
  60. package/dist/templates/source/api/database/index.d.ts.map +1 -0
  61. package/dist/templates/source/api/database/index.js +18 -0
  62. package/dist/templates/source/api/database/index.js.map +1 -0
  63. package/dist/templates/source/api/index.auth.d.ts +5 -0
  64. package/dist/templates/source/api/index.auth.d.ts.map +1 -0
  65. package/dist/templates/source/api/index.auth.js +59 -0
  66. package/dist/templates/source/api/index.auth.js.map +1 -0
  67. package/dist/templates/source/api/index.default.d.ts +5 -0
  68. package/dist/templates/source/api/index.default.d.ts.map +1 -0
  69. package/dist/templates/source/api/index.default.js +56 -0
  70. package/dist/templates/source/api/index.default.js.map +1 -0
  71. package/dist/templates/source/api/prisma.config.d.ts +9 -0
  72. package/dist/templates/source/api/prisma.config.d.ts.map +1 -0
  73. package/dist/templates/source/api/prisma.config.js +15 -0
  74. package/dist/templates/source/api/prisma.config.js.map +1 -0
  75. package/dist/templates/source/api/procedures/auth.d.ts +14 -0
  76. package/dist/templates/source/api/procedures/auth.d.ts.map +1 -0
  77. package/dist/templates/source/api/procedures/auth.js +221 -0
  78. package/dist/templates/source/api/procedures/auth.js.map +1 -0
  79. package/dist/templates/source/api/procedures/health.d.ts +5 -0
  80. package/dist/templates/source/api/procedures/health.d.ts.map +1 -0
  81. package/dist/templates/source/api/procedures/health.js +21 -0
  82. package/dist/templates/source/api/procedures/health.js.map +1 -0
  83. package/dist/templates/source/api/procedures/index.auth.d.ts +7 -0
  84. package/dist/templates/source/api/procedures/index.auth.d.ts.map +1 -0
  85. package/dist/templates/source/api/procedures/index.auth.js +7 -0
  86. package/dist/templates/source/api/procedures/index.auth.js.map +1 -0
  87. package/dist/templates/source/api/procedures/index.default.d.ts +6 -0
  88. package/dist/templates/source/api/procedures/index.default.d.ts.map +1 -0
  89. package/dist/templates/source/api/procedures/index.default.js +6 -0
  90. package/dist/templates/source/api/procedures/index.default.js.map +1 -0
  91. package/dist/templates/source/api/procedures/users.auth.d.ts +7 -0
  92. package/dist/templates/source/api/procedures/users.auth.d.ts.map +1 -0
  93. package/dist/templates/source/api/procedures/users.auth.js +111 -0
  94. package/dist/templates/source/api/procedures/users.auth.js.map +1 -0
  95. package/dist/templates/source/api/procedures/users.default.d.ts +5 -0
  96. package/dist/templates/source/api/procedures/users.default.d.ts.map +1 -0
  97. package/dist/templates/source/api/procedures/users.default.js +86 -0
  98. package/dist/templates/source/api/procedures/users.default.js.map +1 -0
  99. package/dist/templates/source/api/schemas/index.d.ts +5 -0
  100. package/dist/templates/source/api/schemas/index.d.ts.map +1 -0
  101. package/dist/templates/source/api/schemas/index.js +5 -0
  102. package/dist/templates/source/api/schemas/index.js.map +1 -0
  103. package/dist/templates/source/api/schemas/user.d.ts +11 -0
  104. package/dist/templates/source/api/schemas/user.d.ts.map +1 -0
  105. package/dist/templates/source/api/schemas/user.js +20 -0
  106. package/dist/templates/source/api/schemas/user.js.map +1 -0
  107. package/dist/templates/source/api/tsup.config.d.ts +3 -0
  108. package/dist/templates/source/api/tsup.config.d.ts.map +1 -0
  109. package/dist/templates/source/api/tsup.config.js +10 -0
  110. package/dist/templates/source/api/tsup.config.js.map +1 -0
  111. package/dist/templates/source/web/main.d.ts +9 -0
  112. package/dist/templates/source/web/main.d.ts.map +1 -0
  113. package/dist/templates/source/web/main.js +27 -0
  114. package/dist/templates/source/web/main.js.map +1 -0
  115. package/dist/templates/source/web/routes/__root.d.ts +2 -0
  116. package/dist/templates/source/web/routes/__root.d.ts.map +1 -0
  117. package/dist/templates/source/web/routes/__root.js +28 -0
  118. package/dist/templates/source/web/routes/__root.js.map +1 -0
  119. package/dist/templates/source/web/routes/about.d.ts +2 -0
  120. package/dist/templates/source/web/routes/about.d.ts.map +1 -0
  121. package/dist/templates/source/web/routes/about.js +33 -0
  122. package/dist/templates/source/web/routes/about.js.map +1 -0
  123. package/dist/templates/source/web/routes/index.auth.d.ts +2 -0
  124. package/dist/templates/source/web/routes/index.auth.d.ts.map +1 -0
  125. package/dist/templates/source/web/routes/index.auth.js +159 -0
  126. package/dist/templates/source/web/routes/index.auth.js.map +1 -0
  127. package/dist/templates/source/web/routes/index.default.d.ts +2 -0
  128. package/dist/templates/source/web/routes/index.default.d.ts.map +1 -0
  129. package/dist/templates/source/web/routes/index.default.js +60 -0
  130. package/dist/templates/source/web/routes/index.default.js.map +1 -0
  131. package/dist/templates/source/web/vite.config.d.ts +3 -0
  132. package/dist/templates/source/web/vite.config.d.ts.map +1 -0
  133. package/dist/templates/source/web/vite.config.js +22 -0
  134. package/dist/templates/source/web/vite.config.js.map +1 -0
  135. package/package.json +11 -9
  136. package/src/templates/source/api/config/app.ts +13 -0
  137. package/src/templates/source/api/config/auth.ts +202 -0
  138. package/src/templates/source/api/config/database.ts +22 -0
  139. package/src/templates/source/api/env.auth +22 -0
  140. package/src/templates/source/api/env.default +13 -0
  141. package/src/templates/source/api/index.auth.ts +30 -0
  142. package/src/templates/source/api/index.default.ts +27 -0
  143. package/src/templates/source/api/package.auth.json +40 -0
  144. package/src/templates/source/api/package.default.json +38 -0
  145. package/src/templates/source/api/prisma/schema.auth.prisma +30 -0
  146. package/src/templates/source/api/prisma/schema.default.prisma +28 -0
  147. package/src/templates/source/api/prisma.config.ts +15 -0
  148. package/src/templates/source/api/procedures/auth.ts +285 -0
  149. package/src/templates/source/api/procedures/health.ts +24 -0
  150. package/src/templates/source/api/procedures/users.auth.ts +170 -0
  151. package/src/templates/source/api/procedures/users.default.ts +119 -0
  152. package/src/templates/source/api/schemas/user.ts +29 -0
  153. package/src/templates/source/api/tsconfig.json +12 -0
  154. package/src/templates/source/api/tsup.config.ts +10 -0
  155. package/src/templates/source/root/CLAUDE.auth.md +148 -0
  156. package/src/templates/source/root/CLAUDE.default.md +128 -0
  157. package/src/templates/source/root/README.md +72 -0
  158. package/src/templates/source/root/gitignore +37 -0
  159. package/src/templates/source/root/package.json +17 -0
  160. package/src/templates/source/root/pnpm-workspace.yaml +2 -0
  161. package/src/templates/source/root/tsconfig.json +19 -0
  162. package/src/templates/source/web/App.module.css +282 -0
  163. package/src/templates/source/web/favicon.svg +12 -0
  164. package/src/templates/source/web/index.html +13 -0
  165. package/src/templates/source/web/main.tsx +38 -0
  166. package/src/templates/source/web/package.json +26 -0
  167. package/src/templates/source/web/routes/__root.tsx +31 -0
  168. package/src/templates/source/web/routes/about.tsx +36 -0
  169. package/src/templates/source/web/routes/index.auth.tsx +230 -0
  170. package/src/templates/source/web/routes/index.default.tsx +79 -0
  171. package/src/templates/source/web/styles/global.css +90 -0
  172. package/src/templates/source/web/tsconfig.json +24 -0
  173. package/src/templates/source/web/vite.config.ts +22 -0
  174. package/LICENSE +0 -21
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+ import { TanStackRouterVite } from '@tanstack/router-plugin/vite';
4
+ import path from 'node:path';
5
+ export default defineConfig({
6
+ plugins: [TanStackRouterVite(), react()],
7
+ resolve: {
8
+ alias: {
9
+ '@': path.resolve(__dirname, './src'),
10
+ },
11
+ },
12
+ server: {
13
+ port: __WEB_PORT__,
14
+ proxy: {
15
+ '/api': {
16
+ target: 'http://localhost:__API_PORT__',
17
+ changeOrigin: true,
18
+ },
19
+ },
20
+ },
21
+ });
22
+ //# sourceMappingURL=vite.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.config.js","sourceRoot":"","sources":["../../../../src/templates/source/web/vite.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,MAAM,sBAAsB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,eAAe,YAAY,CAAC;IAC1B,OAAO,EAAE,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,CAAC;IACxC,OAAO,EAAE;QACP,KAAK,EAAE;YACL,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC;SACtC;KACF;IACD,MAAM,EAAE;QACN,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE;YACL,MAAM,EAAE;gBACN,MAAM,EAAE,+BAA+B;gBACvC,YAAY,EAAE,IAAI;aACnB;SACF;KACF;CACF,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-velox-app",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Project scaffolder for VeloxTS framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,8 +16,17 @@
16
16
  },
17
17
  "files": [
18
18
  "dist",
19
+ "src/templates/source",
19
20
  "README.md"
20
21
  ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "type-check": "tsc --noEmit",
26
+ "check:templates": "tsc -p tsconfig.templates.json --noEmit || true",
27
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
28
+ "smoke-test": "./scripts/smoke-test.sh"
29
+ },
21
30
  "dependencies": {
22
31
  "@clack/prompts": "0.11.0",
23
32
  "ora": "8.1.1",
@@ -45,12 +54,5 @@
45
54
  },
46
55
  "publishConfig": {
47
56
  "access": "public"
48
- },
49
- "scripts": {
50
- "build": "tsc",
51
- "dev": "tsc --watch",
52
- "type-check": "tsc --noEmit",
53
- "clean": "rm -rf dist tsconfig.tsbuildinfo",
54
- "smoke-test": "./scripts/smoke-test.sh"
55
57
  }
56
- }
58
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Application Configuration
3
+ */
4
+
5
+ export const config = {
6
+ port: Number(process.env.PORT) || __API_PORT__,
7
+ host: process.env.HOST || '0.0.0.0',
8
+ logger: process.env.LOG_LEVEL !== 'silent',
9
+ apiPrefix: process.env.API_PREFIX || '/api',
10
+ env: (process.env.NODE_ENV || 'development') as 'development' | 'production' | 'test',
11
+ } as const;
12
+
13
+ export type AppConfig = typeof config;
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Authentication Configuration
3
+ *
4
+ * JWT-based authentication configuration.
5
+ *
6
+ * SECURITY: JWT secrets are required from environment variables.
7
+ * The app will fail to start in production without them.
8
+ */
9
+
10
+ import type { AuthPluginOptions } from '@veloxts/velox';
11
+
12
+ import { prisma } from './database.js';
13
+
14
+ // ============================================================================
15
+ // Environment Variable Validation
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Gets required JWT secrets from environment variables.
20
+ * Throws a clear error in production if secrets are not configured.
21
+ */
22
+ function getRequiredSecrets(): { jwtSecret: string; refreshSecret: string } {
23
+ const jwtSecret = process.env.JWT_SECRET;
24
+ const refreshSecret = process.env.JWT_REFRESH_SECRET;
25
+
26
+ const isDevelopment = process.env.NODE_ENV !== 'production';
27
+
28
+ if (!jwtSecret || !refreshSecret) {
29
+ if (isDevelopment) {
30
+ console.warn(
31
+ '\n' +
32
+ '='.repeat(70) +
33
+ '\n' +
34
+ ' WARNING: JWT secrets not configured!\n' +
35
+ ' Using temporary development secrets. DO NOT USE IN PRODUCTION!\n' +
36
+ '\n' +
37
+ ' To configure secrets, add to .env:\n' +
38
+ ' JWT_SECRET=<generate with: openssl rand -base64 64>\n' +
39
+ ' JWT_REFRESH_SECRET=<generate with: openssl rand -base64 64>\n' +
40
+ '='.repeat(70) +
41
+ '\n'
42
+ );
43
+ return {
44
+ jwtSecret:
45
+ jwtSecret || `dev-only-jwt-secret-${Math.random().toString(36).substring(2).repeat(4)}`,
46
+ refreshSecret:
47
+ refreshSecret ||
48
+ `dev-only-refresh-secret-${Math.random().toString(36).substring(2).repeat(4)}`,
49
+ };
50
+ }
51
+
52
+ throw new Error(
53
+ '\n' +
54
+ 'CRITICAL: JWT secrets are required but not configured.\n' +
55
+ '\n' +
56
+ 'Required environment variables:\n' +
57
+ ' - JWT_SECRET: Secret for signing access tokens (64+ characters)\n' +
58
+ ' - JWT_REFRESH_SECRET: Secret for signing refresh tokens (64+ characters)\n' +
59
+ '\n' +
60
+ 'Generate secure secrets with:\n' +
61
+ ' openssl rand -base64 64\n' +
62
+ '\n' +
63
+ 'Add them to your environment or .env file before starting the server.\n'
64
+ );
65
+ }
66
+
67
+ return { jwtSecret, refreshSecret };
68
+ }
69
+
70
+ // ============================================================================
71
+ // Token Revocation Store
72
+ // ============================================================================
73
+
74
+ /**
75
+ * In-memory token revocation store.
76
+ *
77
+ * PRODUCTION NOTE: Replace with Redis or database-backed store for:
78
+ * - Persistence across server restarts
79
+ * - Horizontal scaling (multiple server instances)
80
+ */
81
+ class InMemoryTokenStore {
82
+ private revokedTokens: Map<string, number> = new Map();
83
+ private usedRefreshTokens: Map<string, string> = new Map();
84
+ private cleanupInterval: NodeJS.Timeout | null = null;
85
+
86
+ constructor() {
87
+ this.cleanupInterval = setInterval(() => this.cleanup(), 5 * 60 * 1000);
88
+ }
89
+
90
+ revoke(jti: string, expiresInMs: number = 7 * 24 * 60 * 60 * 1000): void {
91
+ this.revokedTokens.set(jti, Date.now() + expiresInMs);
92
+ }
93
+
94
+ isRevoked(jti: string): boolean {
95
+ const expiry = this.revokedTokens.get(jti);
96
+ if (!expiry) return false;
97
+ if (Date.now() > expiry) {
98
+ this.revokedTokens.delete(jti);
99
+ return false;
100
+ }
101
+ return true;
102
+ }
103
+
104
+ markRefreshTokenUsed(jti: string, userId: string): void {
105
+ this.usedRefreshTokens.set(jti, userId);
106
+ setTimeout(() => this.usedRefreshTokens.delete(jti), 7 * 24 * 60 * 60 * 1000);
107
+ }
108
+
109
+ isRefreshTokenUsed(jti: string): string | undefined {
110
+ return this.usedRefreshTokens.get(jti);
111
+ }
112
+
113
+ revokeAllUserTokens(userId: string): void {
114
+ console.warn(
115
+ `[Security] Token reuse detected for user ${userId}. ` +
116
+ 'All tokens should be revoked. Implement proper user->token mapping for production.'
117
+ );
118
+ }
119
+
120
+ private cleanup(): void {
121
+ const now = Date.now();
122
+ for (const [jti, expiry] of this.revokedTokens.entries()) {
123
+ if (now > expiry) {
124
+ this.revokedTokens.delete(jti);
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ export const tokenStore = new InMemoryTokenStore();
131
+
132
+ // ============================================================================
133
+ // Role Parsing
134
+ // ============================================================================
135
+
136
+ const ALLOWED_ROLES = ['user', 'admin', 'moderator', 'editor'] as const;
137
+
138
+ export function parseUserRoles(rolesJson: string | null): string[] {
139
+ if (!rolesJson) return ['user'];
140
+
141
+ try {
142
+ const parsed: unknown = JSON.parse(rolesJson);
143
+
144
+ if (!Array.isArray(parsed)) {
145
+ return ['user'];
146
+ }
147
+
148
+ const validRoles = parsed
149
+ .filter((role): role is string => typeof role === 'string')
150
+ .filter((role) => ALLOWED_ROLES.includes(role as (typeof ALLOWED_ROLES)[number]));
151
+
152
+ return validRoles.length > 0 ? validRoles : ['user'];
153
+ } catch {
154
+ return ['user'];
155
+ }
156
+ }
157
+
158
+ // ============================================================================
159
+ // User Loader
160
+ // ============================================================================
161
+
162
+ async function userLoader(userId: string) {
163
+ const user = await prisma.user.findUnique({
164
+ where: { id: userId },
165
+ });
166
+
167
+ if (!user) return null;
168
+
169
+ return {
170
+ id: user.id,
171
+ email: user.email,
172
+ name: user.name,
173
+ roles: parseUserRoles(user.roles),
174
+ };
175
+ }
176
+
177
+ // ============================================================================
178
+ // Auth Configuration
179
+ // ============================================================================
180
+
181
+ export function createAuthConfig(): AuthPluginOptions {
182
+ const { jwtSecret, refreshSecret } = getRequiredSecrets();
183
+
184
+ return {
185
+ jwt: {
186
+ secret: jwtSecret,
187
+ refreshSecret: refreshSecret,
188
+ accessTokenExpiry: '15m',
189
+ refreshTokenExpiry: '7d',
190
+ issuer: 'velox-app',
191
+ audience: 'velox-app-client',
192
+ },
193
+ userLoader,
194
+ isTokenRevoked: async (jti: string) => tokenStore.isRevoked(jti),
195
+ rateLimit: {
196
+ max: 100,
197
+ windowMs: 60000,
198
+ },
199
+ };
200
+ }
201
+
202
+ export const authConfig = createAuthConfig();
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Database Client (Prisma 7.x)
3
+ *
4
+ * Prisma 7 requires:
5
+ * - Generated client from custom output path
6
+ * - Driver adapter for database connections
7
+ */
8
+
9
+ import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3';
10
+
11
+ import { PrismaClient } from '../generated/prisma/client.js';
12
+
13
+ // Validate DATABASE_URL is set
14
+ if (!process.env.DATABASE_URL) {
15
+ throw new Error('DATABASE_URL environment variable is required');
16
+ }
17
+
18
+ // Create SQLite adapter with database URL from environment
19
+ const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL });
20
+
21
+ // Export configured Prisma client
22
+ export const prisma = new PrismaClient({ adapter });
@@ -0,0 +1,22 @@
1
+ # Database URL
2
+ # SQLite (local development):
3
+ DATABASE_URL="file:./dev.db"
4
+ # PostgreSQL (production):
5
+ # DATABASE_URL="postgresql://user:password@localhost:5432/myapp"
6
+
7
+ # Server Configuration
8
+ PORT=__API_PORT__
9
+ HOST=0.0.0.0
10
+ NODE_ENV=development
11
+
12
+ # API Configuration
13
+ API_PREFIX=/api
14
+
15
+ # ============================================================================
16
+ # Authentication (REQUIRED for production)
17
+ # ============================================================================
18
+ # Generate new secrets with: openssl rand -base64 64
19
+ #
20
+ # IMPORTANT: Replace these development secrets before deploying to production!
21
+ JWT_SECRET=development-only-jwt-secret-replace-in-production-must-be-64-chars-or-longer
22
+ JWT_REFRESH_SECRET=development-only-refresh-secret-replace-in-production-must-be-64-chars
@@ -0,0 +1,13 @@
1
+ # Database URL
2
+ # SQLite (local development):
3
+ DATABASE_URL="file:./dev.db"
4
+ # PostgreSQL (production):
5
+ # DATABASE_URL="postgresql://user:password@localhost:5432/myapp"
6
+
7
+ # Server Configuration
8
+ PORT=__API_PORT__
9
+ HOST=0.0.0.0
10
+ NODE_ENV=development
11
+
12
+ # API Configuration
13
+ API_PREFIX=/api
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Application Entry Point
3
+ */
4
+
5
+ import 'dotenv/config';
6
+
7
+ import { veloxApp, databasePlugin, authPlugin, rest } from '@veloxts/velox';
8
+ import { config } from './config/app.js';
9
+ import { authConfig } from './config/auth.js';
10
+ import { prisma } from './config/database.js';
11
+ import { authProcedures } from './procedures/auth.js';
12
+ import { healthProcedures } from './procedures/health.js';
13
+ import { userProcedures } from './procedures/users.js';
14
+
15
+ const app = await veloxApp({
16
+ port: config.port,
17
+ host: config.host,
18
+ logger: config.logger,
19
+ });
20
+
21
+ await app.register(databasePlugin({ client: prisma }));
22
+ await app.register(authPlugin(authConfig));
23
+
24
+ app.routes(
25
+ rest([healthProcedures, authProcedures, userProcedures], {
26
+ prefix: config.apiPrefix,
27
+ })
28
+ );
29
+
30
+ await app.start();
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Application Entry Point
3
+ */
4
+
5
+ import 'dotenv/config';
6
+
7
+ import { veloxApp, databasePlugin, rest } from '@veloxts/velox';
8
+ import { config } from './config/app.js';
9
+ import { prisma } from './config/database.js';
10
+ import { healthProcedures } from './procedures/health.js';
11
+ import { userProcedures } from './procedures/users.js';
12
+
13
+ const app = await veloxApp({
14
+ port: config.port,
15
+ host: config.host,
16
+ logger: config.logger,
17
+ });
18
+
19
+ await app.register(databasePlugin({ client: prisma }));
20
+
21
+ app.routes(
22
+ rest([healthProcedures, userProcedures], {
23
+ prefix: config.apiPrefix,
24
+ })
25
+ );
26
+
27
+ await app.start();
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "api",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "build": "tsup",
9
+ "start": "node dist/index.js",
10
+ "dev": "tsx watch src/index.ts",
11
+ "dev:hmr": "velox dev --hmr",
12
+ "type-check": "tsc --noEmit",
13
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true});require('fs').rmSync('tsconfig.tsbuildinfo',{force:true})\"",
14
+ "db:generate": "prisma generate",
15
+ "db:push": "prisma db push",
16
+ "db:studio": "prisma studio",
17
+ "postinstall": "prisma generate"
18
+ },
19
+ "dependencies": {
20
+ "@prisma/adapter-better-sqlite3": "7.1.0",
21
+ "@prisma/client": "7.1.0",
22
+ "@veloxts/velox": "__VELOXTS_VERSION__",
23
+ "bcrypt": "5.1.1",
24
+ "better-sqlite3": "12.5.0",
25
+ "dotenv": "17.2.3",
26
+ "zod": "3.24.4"
27
+ },
28
+ "devDependencies": {
29
+ "@types/bcrypt": "5.0.2",
30
+ "@veloxts/cli": "__VELOXTS_VERSION__",
31
+ "hot-hook": "0.4.0",
32
+ "prisma": "7.1.0",
33
+ "tsup": "8.5.1",
34
+ "tsx": "4.21.0",
35
+ "typescript": "5.9.3"
36
+ },
37
+ "hotHook": {
38
+ "boundaries": ["./src/procedures/**/*.ts", "./src/schemas/**/*.ts", "./src/handlers/**/*.ts"]
39
+ }
40
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "api",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "scripts": {
8
+ "build": "tsup",
9
+ "start": "node dist/index.js",
10
+ "dev": "tsx watch src/index.ts",
11
+ "dev:hmr": "velox dev --hmr",
12
+ "type-check": "tsc --noEmit",
13
+ "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true});require('fs').rmSync('tsconfig.tsbuildinfo',{force:true})\"",
14
+ "db:generate": "prisma generate",
15
+ "db:push": "prisma db push",
16
+ "db:studio": "prisma studio",
17
+ "postinstall": "prisma generate"
18
+ },
19
+ "dependencies": {
20
+ "@prisma/adapter-better-sqlite3": "7.1.0",
21
+ "@prisma/client": "7.1.0",
22
+ "@veloxts/velox": "__VELOXTS_VERSION__",
23
+ "better-sqlite3": "12.5.0",
24
+ "dotenv": "17.2.3",
25
+ "zod": "3.24.4"
26
+ },
27
+ "devDependencies": {
28
+ "@veloxts/cli": "__VELOXTS_VERSION__",
29
+ "hot-hook": "0.4.0",
30
+ "prisma": "7.1.0",
31
+ "tsup": "8.5.1",
32
+ "tsx": "4.21.0",
33
+ "typescript": "5.9.3"
34
+ },
35
+ "hotHook": {
36
+ "boundaries": ["./src/procedures/**/*.ts", "./src/schemas/**/*.ts", "./src/handlers/**/*.ts"]
37
+ }
38
+ }
@@ -0,0 +1,30 @@
1
+ // Prisma Schema
2
+ //
3
+ // This schema defines the database structure with authentication support.
4
+ // Using SQLite for simplicity - easily swap to PostgreSQL for production.
5
+
6
+ generator client {
7
+ provider = "prisma-client"
8
+ output = "../src/generated/prisma"
9
+ }
10
+
11
+ datasource db {
12
+ provider = "sqlite"
13
+ }
14
+
15
+ // ============================================================================
16
+ // User Model
17
+ // ============================================================================
18
+
19
+ /// User model with authentication support
20
+ model User {
21
+ id String @id @default(uuid())
22
+ name String
23
+ email String @unique
24
+ password String? // Hashed password (optional for social auth)
25
+ roles String @default("[\"user\"]") // JSON array of roles
26
+ createdAt DateTime @default(now())
27
+ updatedAt DateTime @updatedAt
28
+
29
+ @@map("users")
30
+ }
@@ -0,0 +1,28 @@
1
+ // Prisma Schema
2
+ //
3
+ // This schema defines the database structure.
4
+ // Using SQLite for simplicity - easily swap to PostgreSQL for production.
5
+
6
+ generator client {
7
+ provider = "prisma-client"
8
+ output = "../src/generated/prisma"
9
+ }
10
+
11
+ datasource db {
12
+ provider = "sqlite"
13
+ }
14
+
15
+ // ============================================================================
16
+ // User Model
17
+ // ============================================================================
18
+
19
+ /// User model for basic CRUD demonstration
20
+ model User {
21
+ id String @id @default(uuid())
22
+ name String
23
+ email String @unique
24
+ createdAt DateTime @default(now())
25
+ updatedAt DateTime @updatedAt
26
+
27
+ @@map("users")
28
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Prisma Configuration (Prisma 7.x)
3
+ *
4
+ * Database URL is configured here instead of schema.prisma.
5
+ */
6
+
7
+ import 'dotenv/config';
8
+ import { defineConfig } from 'prisma/config';
9
+
10
+ export default defineConfig({
11
+ schema: './prisma/schema.prisma',
12
+ datasource: {
13
+ url: process.env.DATABASE_URL!,
14
+ },
15
+ });