create-velox-app 0.6.29 → 0.6.51
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.
- package/CHANGELOG.md +132 -0
- package/GUIDE.md +230 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +14 -5
- package/dist/templates/auth.d.ts +0 -1
- package/dist/templates/auth.js +10 -1
- package/dist/templates/compiler.d.ts +0 -1
- package/dist/templates/compiler.js +0 -1
- package/dist/templates/index.d.ts +0 -1
- package/dist/templates/index.js +30 -2
- package/dist/templates/placeholders.d.ts +6 -1
- package/dist/templates/placeholders.js +55 -1
- package/dist/templates/rsc-auth.d.ts +12 -0
- package/dist/templates/rsc-auth.js +208 -0
- package/dist/templates/rsc.d.ts +0 -1
- package/dist/templates/rsc.js +40 -2
- package/dist/templates/shared/css-generator.d.ts +26 -0
- package/dist/templates/shared/css-generator.js +553 -0
- package/dist/templates/shared/index.d.ts +3 -1
- package/dist/templates/shared/index.js +3 -1
- package/dist/templates/shared/root.d.ts +0 -1
- package/dist/templates/shared/root.js +11 -2
- package/dist/templates/shared/rsc-styles.d.ts +54 -0
- package/dist/templates/shared/rsc-styles.js +68 -0
- package/dist/templates/shared/theme.d.ts +133 -0
- package/dist/templates/shared/theme.js +141 -0
- package/dist/templates/shared/web-base.d.ts +0 -1
- package/dist/templates/shared/web-base.js +0 -1
- package/dist/templates/shared/web-styles.d.ts +0 -1
- package/dist/templates/shared/web-styles.js +0 -1
- package/dist/templates/shared.d.ts +0 -1
- package/dist/templates/shared.js +0 -1
- package/dist/templates/spa.d.ts +0 -1
- package/dist/templates/spa.js +10 -1
- package/dist/templates/trpc.d.ts +0 -1
- package/dist/templates/trpc.js +10 -1
- package/dist/templates/types.d.ts +2 -2
- package/dist/templates/types.js +6 -1
- package/package.json +6 -3
- package/src/templates/source/api/config/database.ts +13 -32
- package/src/templates/source/api/docker-compose.yml +21 -0
- package/src/templates/source/root/CLAUDE.auth.md +6 -0
- package/src/templates/source/root/CLAUDE.default.md +6 -0
- package/src/templates/source/root/package.json +6 -6
- package/src/templates/source/rsc/CLAUDE.md +56 -2
- package/src/templates/source/rsc/app/actions/posts.ts +1 -1
- package/src/templates/source/rsc/app/actions/users.ts +111 -20
- package/src/templates/source/rsc/app/layouts/dashboard.tsx +21 -16
- package/src/templates/source/rsc/app/layouts/marketing.tsx +34 -0
- package/src/templates/source/rsc/app/layouts/minimal-content.tsx +21 -0
- package/src/templates/source/rsc/app/layouts/minimal.tsx +86 -5
- package/src/templates/source/rsc/app/layouts/root.tsx +148 -44
- package/src/templates/source/rsc/docker-compose.yml +21 -0
- package/src/templates/source/rsc/package.json +3 -3
- package/src/templates/source/rsc/src/api/database.ts +13 -32
- package/src/templates/source/rsc/src/api/handler.ts +1 -1
- package/src/templates/source/rsc/src/entry.client.tsx +65 -18
- package/src/templates/source/rsc-auth/CLAUDE.md +230 -0
- package/src/templates/source/rsc-auth/app/actions/auth.ts +112 -0
- package/src/templates/source/rsc-auth/app/actions/users.ts +289 -0
- package/src/templates/source/rsc-auth/app/layouts/dashboard.tsx +132 -0
- package/src/templates/source/rsc-auth/app/layouts/marketing.tsx +59 -0
- package/src/templates/source/rsc-auth/app/layouts/minimal-content.tsx +21 -0
- package/src/templates/source/rsc-auth/app/layouts/minimal.tsx +111 -0
- package/src/templates/source/rsc-auth/app/layouts/root.tsx +355 -0
- package/src/templates/source/rsc-auth/app/pages/_not-found.tsx +15 -0
- package/src/templates/source/rsc-auth/app/pages/auth/login.tsx +198 -0
- package/src/templates/source/rsc-auth/app/pages/auth/register.tsx +225 -0
- package/src/templates/source/rsc-auth/app/pages/dashboard/index.tsx +267 -0
- package/src/templates/source/rsc-auth/app/pages/index.tsx +83 -0
- package/src/templates/source/rsc-auth/app/pages/users.tsx +47 -0
- package/src/templates/source/rsc-auth/app.config.ts +12 -0
- package/src/templates/source/rsc-auth/docker-compose.yml +21 -0
- package/src/templates/source/rsc-auth/env.example +11 -0
- package/src/templates/source/rsc-auth/gitignore +34 -0
- package/src/templates/source/rsc-auth/package.json +44 -0
- package/src/templates/source/rsc-auth/prisma/schema.prisma +23 -0
- package/src/templates/source/rsc-auth/prisma.config.ts +22 -0
- package/src/templates/source/rsc-auth/public/favicon.svg +4 -0
- package/src/templates/source/rsc-auth/src/api/database.ts +129 -0
- package/src/templates/source/rsc-auth/src/api/handler.ts +85 -0
- package/src/templates/source/rsc-auth/src/api/procedures/auth.ts +262 -0
- package/src/templates/source/rsc-auth/src/api/procedures/health.ts +48 -0
- package/src/templates/source/rsc-auth/src/api/procedures/users.ts +87 -0
- package/src/templates/source/rsc-auth/src/api/schemas/auth.ts +79 -0
- package/src/templates/source/rsc-auth/src/api/schemas/user.ts +38 -0
- package/src/templates/source/rsc-auth/src/api/utils/auth.ts +157 -0
- package/src/templates/source/rsc-auth/src/entry.client.tsx +63 -0
- package/src/templates/source/rsc-auth/src/entry.server.tsx +262 -0
- package/src/templates/source/rsc-auth/tsconfig.json +24 -0
- package/src/templates/source/shared/scripts/check-client-imports.sh +75 -0
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/templates/auth.d.ts.map +0 -1
- package/dist/templates/auth.js.map +0 -1
- package/dist/templates/compiler.d.ts.map +0 -1
- package/dist/templates/compiler.js.map +0 -1
- package/dist/templates/default.d.ts +0 -12
- package/dist/templates/default.d.ts.map +0 -1
- package/dist/templates/default.js +0 -85
- package/dist/templates/default.js.map +0 -1
- package/dist/templates/fullstack.d.ts +0 -15
- package/dist/templates/fullstack.d.ts.map +0 -1
- package/dist/templates/fullstack.js +0 -110
- package/dist/templates/fullstack.js.map +0 -1
- package/dist/templates/index.d.ts.map +0 -1
- package/dist/templates/index.js.map +0 -1
- package/dist/templates/placeholders.d.ts.map +0 -1
- package/dist/templates/placeholders.js.map +0 -1
- package/dist/templates/rsc.d.ts.map +0 -1
- package/dist/templates/rsc.js.map +0 -1
- package/dist/templates/shared/index.d.ts.map +0 -1
- package/dist/templates/shared/index.js.map +0 -1
- package/dist/templates/shared/root.d.ts.map +0 -1
- package/dist/templates/shared/root.js.map +0 -1
- package/dist/templates/shared/web-base.d.ts.map +0 -1
- package/dist/templates/shared/web-base.js.map +0 -1
- package/dist/templates/shared/web-styles.d.ts.map +0 -1
- package/dist/templates/shared/web-styles.js.map +0 -1
- package/dist/templates/shared.d.ts.map +0 -1
- package/dist/templates/shared.js.map +0 -1
- package/dist/templates/source/api/config/app.d.ts +0 -13
- package/dist/templates/source/api/config/app.d.ts.map +0 -1
- package/dist/templates/source/api/config/app.js +0 -14
- package/dist/templates/source/api/config/app.js.map +0 -1
- package/dist/templates/source/api/config/auth.d.ts +0 -34
- package/dist/templates/source/api/config/auth.d.ts.map +0 -1
- package/dist/templates/source/api/config/auth.js +0 -165
- package/dist/templates/source/api/config/auth.js.map +0 -1
- package/dist/templates/source/api/config/index.auth.d.ts +0 -6
- package/dist/templates/source/api/config/index.auth.d.ts.map +0 -1
- package/dist/templates/source/api/config/index.auth.js +0 -6
- package/dist/templates/source/api/config/index.auth.js.map +0 -1
- package/dist/templates/source/api/config/index.default.d.ts +0 -5
- package/dist/templates/source/api/config/index.default.d.ts.map +0 -1
- package/dist/templates/source/api/config/index.default.js +0 -5
- package/dist/templates/source/api/config/index.default.js.map +0 -1
- package/dist/templates/source/api/database/index.d.ts +0 -9
- package/dist/templates/source/api/database/index.d.ts.map +0 -1
- package/dist/templates/source/api/database/index.js +0 -18
- package/dist/templates/source/api/database/index.js.map +0 -1
- package/dist/templates/source/api/index.auth.d.ts +0 -5
- package/dist/templates/source/api/index.auth.d.ts.map +0 -1
- package/dist/templates/source/api/index.auth.js +0 -59
- package/dist/templates/source/api/index.auth.js.map +0 -1
- package/dist/templates/source/api/index.default.d.ts +0 -5
- package/dist/templates/source/api/index.default.d.ts.map +0 -1
- package/dist/templates/source/api/index.default.js +0 -56
- package/dist/templates/source/api/index.default.js.map +0 -1
- package/dist/templates/source/api/prisma.config.d.ts +0 -9
- package/dist/templates/source/api/prisma.config.d.ts.map +0 -1
- package/dist/templates/source/api/prisma.config.js +0 -15
- package/dist/templates/source/api/prisma.config.js.map +0 -1
- package/dist/templates/source/api/procedures/auth.d.ts +0 -14
- package/dist/templates/source/api/procedures/auth.d.ts.map +0 -1
- package/dist/templates/source/api/procedures/auth.js +0 -221
- package/dist/templates/source/api/procedures/auth.js.map +0 -1
- package/dist/templates/source/api/procedures/health.d.ts +0 -5
- package/dist/templates/source/api/procedures/health.d.ts.map +0 -1
- package/dist/templates/source/api/procedures/health.js +0 -21
- package/dist/templates/source/api/procedures/health.js.map +0 -1
- package/dist/templates/source/api/procedures/index.auth.d.ts +0 -7
- package/dist/templates/source/api/procedures/index.auth.d.ts.map +0 -1
- package/dist/templates/source/api/procedures/index.auth.js +0 -7
- package/dist/templates/source/api/procedures/index.auth.js.map +0 -1
- package/dist/templates/source/api/procedures/index.default.d.ts +0 -6
- package/dist/templates/source/api/procedures/index.default.d.ts.map +0 -1
- package/dist/templates/source/api/procedures/index.default.js +0 -6
- package/dist/templates/source/api/procedures/index.default.js.map +0 -1
- package/dist/templates/source/api/procedures/users.auth.d.ts +0 -7
- package/dist/templates/source/api/procedures/users.auth.d.ts.map +0 -1
- package/dist/templates/source/api/procedures/users.auth.js +0 -111
- package/dist/templates/source/api/procedures/users.auth.js.map +0 -1
- package/dist/templates/source/api/procedures/users.default.d.ts +0 -5
- package/dist/templates/source/api/procedures/users.default.d.ts.map +0 -1
- package/dist/templates/source/api/procedures/users.default.js +0 -86
- package/dist/templates/source/api/procedures/users.default.js.map +0 -1
- package/dist/templates/source/api/schemas/index.d.ts +0 -5
- package/dist/templates/source/api/schemas/index.d.ts.map +0 -1
- package/dist/templates/source/api/schemas/index.js +0 -5
- package/dist/templates/source/api/schemas/index.js.map +0 -1
- package/dist/templates/source/api/schemas/user.d.ts +0 -11
- package/dist/templates/source/api/schemas/user.d.ts.map +0 -1
- package/dist/templates/source/api/schemas/user.js +0 -20
- package/dist/templates/source/api/schemas/user.js.map +0 -1
- package/dist/templates/source/api/tsup.config.d.ts +0 -3
- package/dist/templates/source/api/tsup.config.d.ts.map +0 -1
- package/dist/templates/source/api/tsup.config.js +0 -10
- package/dist/templates/source/api/tsup.config.js.map +0 -1
- package/dist/templates/source/web/main.d.ts +0 -9
- package/dist/templates/source/web/main.d.ts.map +0 -1
- package/dist/templates/source/web/main.js +0 -27
- package/dist/templates/source/web/main.js.map +0 -1
- package/dist/templates/source/web/routes/__root.d.ts +0 -2
- package/dist/templates/source/web/routes/__root.d.ts.map +0 -1
- package/dist/templates/source/web/routes/__root.js +0 -28
- package/dist/templates/source/web/routes/__root.js.map +0 -1
- package/dist/templates/source/web/routes/about.d.ts +0 -2
- package/dist/templates/source/web/routes/about.d.ts.map +0 -1
- package/dist/templates/source/web/routes/about.js +0 -33
- package/dist/templates/source/web/routes/about.js.map +0 -1
- package/dist/templates/source/web/routes/index.auth.d.ts +0 -2
- package/dist/templates/source/web/routes/index.auth.d.ts.map +0 -1
- package/dist/templates/source/web/routes/index.auth.js +0 -159
- package/dist/templates/source/web/routes/index.auth.js.map +0 -1
- package/dist/templates/source/web/routes/index.default.d.ts +0 -2
- package/dist/templates/source/web/routes/index.default.d.ts.map +0 -1
- package/dist/templates/source/web/routes/index.default.js +0 -60
- package/dist/templates/source/web/routes/index.default.js.map +0 -1
- package/dist/templates/source/web/vite.config.d.ts +0 -3
- package/dist/templates/source/web/vite.config.d.ts.map +0 -1
- package/dist/templates/source/web/vite.config.js +0 -22
- package/dist/templates/source/web/vite.config.js.map +0 -1
- package/dist/templates/spa.d.ts.map +0 -1
- package/dist/templates/spa.js.map +0 -1
- package/dist/templates/trpc.d.ts.map +0 -1
- package/dist/templates/trpc.js.map +0 -1
- package/dist/templates/types.d.ts.map +0 -1
- package/dist/templates/types.js.map +0 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Home Page
|
|
3
|
+
*
|
|
4
|
+
* A React Server Component that runs on the server at request time.
|
|
5
|
+
* For database access, use the API endpoints at /api/*.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export default function HomePage() {
|
|
9
|
+
return (
|
|
10
|
+
<div className="home-page">
|
|
11
|
+
<header className="hero">
|
|
12
|
+
<h1>Welcome to VeloxTS</h1>
|
|
13
|
+
<p className="tagline">Full-stack React Server Components with Authentication</p>
|
|
14
|
+
</header>
|
|
15
|
+
|
|
16
|
+
<section className="quick-links">
|
|
17
|
+
<h2>Quick Links</h2>
|
|
18
|
+
<ul>
|
|
19
|
+
<li>
|
|
20
|
+
<a href="/auth/login">Login</a>
|
|
21
|
+
</li>
|
|
22
|
+
<li>
|
|
23
|
+
<a href="/auth/register">Register</a>
|
|
24
|
+
</li>
|
|
25
|
+
<li>
|
|
26
|
+
<a href="/dashboard">Dashboard</a> (requires login)
|
|
27
|
+
</li>
|
|
28
|
+
<li>
|
|
29
|
+
<a href="/users">Users</a>
|
|
30
|
+
</li>
|
|
31
|
+
</ul>
|
|
32
|
+
</section>
|
|
33
|
+
|
|
34
|
+
<section className="api-endpoints">
|
|
35
|
+
<h2>API Endpoints</h2>
|
|
36
|
+
<ul>
|
|
37
|
+
<li>
|
|
38
|
+
<code>GET /api/health</code> - Health check
|
|
39
|
+
</li>
|
|
40
|
+
<li>
|
|
41
|
+
<code>POST /api/auth/register</code> - Create account
|
|
42
|
+
</li>
|
|
43
|
+
<li>
|
|
44
|
+
<code>POST /api/auth/login</code> - Get tokens
|
|
45
|
+
</li>
|
|
46
|
+
<li>
|
|
47
|
+
<code>GET /api/auth/me</code> - Current user (protected)
|
|
48
|
+
</li>
|
|
49
|
+
<li>
|
|
50
|
+
<code>GET /api/users</code> - List users
|
|
51
|
+
</li>
|
|
52
|
+
</ul>
|
|
53
|
+
</section>
|
|
54
|
+
|
|
55
|
+
<section className="features">
|
|
56
|
+
<h2>Features</h2>
|
|
57
|
+
<ul>
|
|
58
|
+
<li>
|
|
59
|
+
<strong>JWT Authentication</strong> - Access and refresh tokens
|
|
60
|
+
</li>
|
|
61
|
+
<li>
|
|
62
|
+
<strong>Rate Limiting</strong> - Built-in protection for auth endpoints
|
|
63
|
+
</li>
|
|
64
|
+
<li>
|
|
65
|
+
<strong>Password Validation</strong> - Strength requirements enforced
|
|
66
|
+
</li>
|
|
67
|
+
<li>
|
|
68
|
+
<strong>Role-Based Access</strong> - Authorization via guards
|
|
69
|
+
</li>
|
|
70
|
+
<li>
|
|
71
|
+
<strong>Server Actions</strong> - Type-safe with validated() helper
|
|
72
|
+
</li>
|
|
73
|
+
</ul>
|
|
74
|
+
</section>
|
|
75
|
+
|
|
76
|
+
<footer className="cta">
|
|
77
|
+
<p>
|
|
78
|
+
Edit <code>app/pages/index.tsx</code> to customize this page.
|
|
79
|
+
</p>
|
|
80
|
+
</footer>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Users Page (RSC)
|
|
3
|
+
*
|
|
4
|
+
* A React Server Component listing users.
|
|
5
|
+
* For database access, use the API endpoint at /api/users.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export default function UsersPage() {
|
|
9
|
+
return (
|
|
10
|
+
<div style={{ padding: '2rem', maxWidth: '800px', margin: '0 auto' }}>
|
|
11
|
+
<h1>Users</h1>
|
|
12
|
+
<p style={{ color: '#666' }}>
|
|
13
|
+
Fetch user data from the API at <code>/api/users</code>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<div
|
|
17
|
+
style={{ marginTop: '2rem', padding: '1rem', background: '#f5f5f5', borderRadius: '8px' }}
|
|
18
|
+
>
|
|
19
|
+
<h3>API Usage</h3>
|
|
20
|
+
<pre
|
|
21
|
+
style={{
|
|
22
|
+
background: '#1e1e1e',
|
|
23
|
+
color: '#d4d4d4',
|
|
24
|
+
padding: '1rem',
|
|
25
|
+
borderRadius: '4px',
|
|
26
|
+
overflow: 'auto',
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
{`// Fetch users from the API
|
|
30
|
+
const response = await fetch('/api/users');
|
|
31
|
+
const users = await response.json();
|
|
32
|
+
|
|
33
|
+
// Or use the typed client
|
|
34
|
+
import { createClient } from '@veloxts/client';
|
|
35
|
+
const client = createClient('/api');
|
|
36
|
+
const users = await client.users.list();`}
|
|
37
|
+
</pre>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<div style={{ marginTop: '2rem' }}>
|
|
41
|
+
<a href="/" style={{ color: '#007bff' }}>
|
|
42
|
+
← Back to Home
|
|
43
|
+
</a>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vinxi Application Configuration
|
|
3
|
+
*
|
|
4
|
+
* VeloxTS full-stack application with React Server Components.
|
|
5
|
+
* All options have sensible defaults - only specify what you need to change.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineVeloxApp } from '@veloxts/web';
|
|
9
|
+
|
|
10
|
+
export default defineVeloxApp({
|
|
11
|
+
port: __API_PORT__,
|
|
12
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
services:
|
|
2
|
+
postgres:
|
|
3
|
+
image: postgres:16-alpine
|
|
4
|
+
container_name: __PROJECT_NAME__-postgres
|
|
5
|
+
restart: unless-stopped
|
|
6
|
+
environment:
|
|
7
|
+
POSTGRES_USER: ${DATABASE_USER:-user}
|
|
8
|
+
POSTGRES_PASSWORD: ${DATABASE_PASSWORD:-password}
|
|
9
|
+
POSTGRES_DB: ${DATABASE_NAME:-__PROJECT_NAME__}
|
|
10
|
+
ports:
|
|
11
|
+
- "${DATABASE_PORT:-5432}:5432"
|
|
12
|
+
volumes:
|
|
13
|
+
- postgres_data:/var/lib/postgresql/data
|
|
14
|
+
healthcheck:
|
|
15
|
+
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USER:-user} -d ${DATABASE_NAME:-__PROJECT_NAME__}"]
|
|
16
|
+
interval: 10s
|
|
17
|
+
timeout: 5s
|
|
18
|
+
retries: 5
|
|
19
|
+
|
|
20
|
+
volumes:
|
|
21
|
+
postgres_data:
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Database
|
|
2
|
+
DATABASE_URL="__DATABASE_URL__"
|
|
3
|
+
|
|
4
|
+
# JWT Secrets (REQUIRED for production)
|
|
5
|
+
# Generate with: openssl rand -base64 64
|
|
6
|
+
JWT_SECRET="development-only-jwt-secret-at-least-64-characters-long-change-in-prod"
|
|
7
|
+
JWT_REFRESH_SECRET="development-only-refresh-secret-at-least-64-chars-long-change-prod"
|
|
8
|
+
|
|
9
|
+
# Server
|
|
10
|
+
NODE_ENV="development"
|
|
11
|
+
PORT=__API_PORT__
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Build output
|
|
5
|
+
dist/
|
|
6
|
+
.vinxi/
|
|
7
|
+
.output/
|
|
8
|
+
|
|
9
|
+
# Database
|
|
10
|
+
*.db
|
|
11
|
+
*.db-journal
|
|
12
|
+
|
|
13
|
+
# Environment
|
|
14
|
+
.env
|
|
15
|
+
.env.local
|
|
16
|
+
.env.*.local
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.vscode/
|
|
20
|
+
.idea/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
|
|
24
|
+
# OS
|
|
25
|
+
.DS_Store
|
|
26
|
+
Thumbs.db
|
|
27
|
+
|
|
28
|
+
# Logs
|
|
29
|
+
*.log
|
|
30
|
+
npm-debug.log*
|
|
31
|
+
pnpm-debug.log*
|
|
32
|
+
|
|
33
|
+
# TypeScript
|
|
34
|
+
*.tsbuildinfo
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vinxi dev --port __API_PORT__",
|
|
8
|
+
"build": "vinxi build",
|
|
9
|
+
"start": "vinxi start --port __API_PORT__",
|
|
10
|
+
"db:generate": "prisma generate",
|
|
11
|
+
"db:push": "prisma db push",
|
|
12
|
+
"db:migrate": "prisma migrate dev",
|
|
13
|
+
"db:studio": "prisma studio",
|
|
14
|
+
"type-check": "tsc --noEmit",
|
|
15
|
+
"lint:client": "./scripts/check-client-imports.sh"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@prisma/adapter-better-sqlite3": "7.2.0",
|
|
19
|
+
"@prisma/client": "7.2.0",
|
|
20
|
+
"@prisma/client-runtime-utils": "7.2.0",
|
|
21
|
+
"better-sqlite3": "12.5.0",
|
|
22
|
+
"@veloxts/auth": "__VELOXTS_VERSION__",
|
|
23
|
+
"@veloxts/core": "__VELOXTS_VERSION__",
|
|
24
|
+
"@veloxts/orm": "__VELOXTS_VERSION__",
|
|
25
|
+
"@veloxts/router": "__VELOXTS_VERSION__",
|
|
26
|
+
"@veloxts/validation": "__VELOXTS_VERSION__",
|
|
27
|
+
"@veloxts/web": "__VELOXTS_VERSION__",
|
|
28
|
+
"@vinxi/server-functions": "0.5.1",
|
|
29
|
+
"bcrypt": "6.0.0",
|
|
30
|
+
"dotenv": "17.2.3",
|
|
31
|
+
"react": "19.2.3",
|
|
32
|
+
"react-dom": "19.2.3",
|
|
33
|
+
"vinxi": "0.5.10",
|
|
34
|
+
"zod": "3.25.76"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/bcrypt": "5.0.2",
|
|
38
|
+
"@types/node": "25.0.3",
|
|
39
|
+
"@types/react": "19.2.7",
|
|
40
|
+
"@types/react-dom": "19.2.3",
|
|
41
|
+
"prisma": "7.2.0",
|
|
42
|
+
"typescript": "5.9.3"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Prisma Schema for VeloxTS RSC with Auth
|
|
2
|
+
// Database: __DATABASE_PROVIDER__
|
|
3
|
+
|
|
4
|
+
generator client {
|
|
5
|
+
provider = "prisma-client-js"
|
|
6
|
+
output = "../node_modules/.prisma/client"
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
datasource db {
|
|
10
|
+
provider = "__DATABASE_PROVIDER__"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
model User {
|
|
14
|
+
id String @id @default(uuid())
|
|
15
|
+
email String @unique
|
|
16
|
+
name String?
|
|
17
|
+
password String? // Hashed password (nullable for OAuth users)
|
|
18
|
+
roles String? @default("[\"user\"]") // JSON array of roles
|
|
19
|
+
createdAt DateTime @default(now())
|
|
20
|
+
updatedAt DateTime @updatedAt
|
|
21
|
+
|
|
22
|
+
@@map("users")
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
|
|
9
|
+
import { defineConfig } from 'prisma/config';
|
|
10
|
+
|
|
11
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
12
|
+
|
|
13
|
+
if (!databaseUrl) {
|
|
14
|
+
throw new Error('DATABASE_URL environment variable is required');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default defineConfig({
|
|
18
|
+
schema: './prisma/schema.prisma',
|
|
19
|
+
datasource: {
|
|
20
|
+
url: databaseUrl,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
2
|
+
<rect width="32" height="32" rx="6" fill="#6366f1"/>
|
|
3
|
+
<text x="50%" y="50%" dominant-baseline="central" text-anchor="middle" fill="white" font-family="system-ui" font-weight="bold" font-size="18">V</text>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Configuration
|
|
3
|
+
*
|
|
4
|
+
* Prisma client instance for database access.
|
|
5
|
+
* Uses Laravel-style `db` export for consistency.
|
|
6
|
+
*
|
|
7
|
+
* Note: Prisma 7 requires using driver adapters for direct database connections.
|
|
8
|
+
* We explicitly load dotenv here because Vite's SSR module evaluation
|
|
9
|
+
* doesn't always have access to .env variables.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createRequire } from 'node:module';
|
|
13
|
+
import { dirname, resolve } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
|
|
16
|
+
/* @if sqlite */
|
|
17
|
+
// Type imports (erased at runtime, safe for ESM)
|
|
18
|
+
import type { PrismaBetterSqlite3 as PrismaBetterSqlite3Type } from '@prisma/adapter-better-sqlite3';
|
|
19
|
+
/* @endif sqlite */
|
|
20
|
+
/* @if postgresql */
|
|
21
|
+
// Type imports (erased at runtime, safe for ESM)
|
|
22
|
+
import type { PrismaPg as PrismaPgType } from '@prisma/adapter-pg';
|
|
23
|
+
/* @endif postgresql */
|
|
24
|
+
import type { PrismaClient as PrismaClientType } from '@prisma/client';
|
|
25
|
+
import dotenv from 'dotenv';
|
|
26
|
+
|
|
27
|
+
// Runtime imports using createRequire for Node.js v24+ CJS interop
|
|
28
|
+
const require = createRequire(import.meta.url);
|
|
29
|
+
/* @if sqlite */
|
|
30
|
+
const { PrismaBetterSqlite3 } = require('@prisma/adapter-better-sqlite3') as {
|
|
31
|
+
PrismaBetterSqlite3: typeof PrismaBetterSqlite3Type;
|
|
32
|
+
};
|
|
33
|
+
/* @endif sqlite */
|
|
34
|
+
/* @if postgresql */
|
|
35
|
+
const { PrismaPg } = require('@prisma/adapter-pg') as {
|
|
36
|
+
PrismaPg: typeof PrismaPgType;
|
|
37
|
+
};
|
|
38
|
+
/* @endif postgresql */
|
|
39
|
+
const { PrismaClient } = require('@prisma/client') as {
|
|
40
|
+
PrismaClient: typeof PrismaClientType;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Get the project root directory (2 levels up from src/api/)
|
|
44
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
45
|
+
const projectRoot = resolve(__dirname, '..', '..');
|
|
46
|
+
|
|
47
|
+
// Load .env file explicitly for Vite SSR compatibility
|
|
48
|
+
// Use project root for reliable path resolution
|
|
49
|
+
dotenv.config({ path: resolve(projectRoot, '.env') });
|
|
50
|
+
|
|
51
|
+
declare global {
|
|
52
|
+
// Allow global `var` declarations for hot reload in development
|
|
53
|
+
// eslint-disable-next-line no-var
|
|
54
|
+
var __db: PrismaClient | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* @if sqlite */
|
|
58
|
+
/**
|
|
59
|
+
* Create a Prisma client instance using the SQLite adapter.
|
|
60
|
+
*
|
|
61
|
+
* Prisma 7 Breaking Change:
|
|
62
|
+
* - `datasourceUrl` and `datasources` options removed from PrismaClient
|
|
63
|
+
* - Must use driver adapters for direct database connections
|
|
64
|
+
* - Validates that DATABASE_URL is set before creating the client
|
|
65
|
+
*/
|
|
66
|
+
function createPrismaClient(): PrismaClient {
|
|
67
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
68
|
+
|
|
69
|
+
if (!databaseUrl) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
'[VeloxTS] DATABASE_URL environment variable is not set. ' +
|
|
72
|
+
'Ensure .env file exists in project root with DATABASE_URL defined.'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Prisma 7 requires driver adapters for direct connections
|
|
77
|
+
const adapter = new PrismaBetterSqlite3({ url: databaseUrl });
|
|
78
|
+
return new PrismaClient({ adapter });
|
|
79
|
+
}
|
|
80
|
+
/* @endif sqlite */
|
|
81
|
+
/* @if postgresql */
|
|
82
|
+
/**
|
|
83
|
+
* Create a Prisma client instance using the PostgreSQL adapter.
|
|
84
|
+
*
|
|
85
|
+
* Prisma 7 Breaking Change:
|
|
86
|
+
* - PrismaPg now takes connectionString directly (not a Pool instance)
|
|
87
|
+
* - Pool management is handled internally by the adapter
|
|
88
|
+
*/
|
|
89
|
+
function createPrismaClient(): PrismaClient {
|
|
90
|
+
const connectionString = process.env.DATABASE_URL;
|
|
91
|
+
|
|
92
|
+
if (!connectionString) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
'[VeloxTS] DATABASE_URL environment variable is not set. ' +
|
|
95
|
+
'Ensure .env file exists in project root with DATABASE_URL defined.'
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Prisma 7: Pass connectionString directly to PrismaPg (not a Pool)
|
|
100
|
+
const adapter = new PrismaPg({ connectionString });
|
|
101
|
+
return new PrismaClient({ adapter });
|
|
102
|
+
}
|
|
103
|
+
/* @endif postgresql */
|
|
104
|
+
|
|
105
|
+
/* @if sqlite */
|
|
106
|
+
// Use global singleton for hot reload in development
|
|
107
|
+
export const db = globalThis.__db ?? createPrismaClient();
|
|
108
|
+
|
|
109
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
110
|
+
globalThis.__db = db;
|
|
111
|
+
}
|
|
112
|
+
/* @endif sqlite */
|
|
113
|
+
/* @if postgresql */
|
|
114
|
+
// Use global singleton for hot reload in development
|
|
115
|
+
export const db = globalThis.__db ?? createPrismaClient();
|
|
116
|
+
|
|
117
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
118
|
+
globalThis.__db = db;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Graceful shutdown - disconnect Prisma on process exit
|
|
122
|
+
const shutdown = async () => {
|
|
123
|
+
await db.$disconnect();
|
|
124
|
+
process.exit(0);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
process.on('SIGTERM', shutdown);
|
|
128
|
+
process.on('SIGINT', shutdown);
|
|
129
|
+
/* @endif postgresql */
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Handler with Authentication
|
|
3
|
+
*
|
|
4
|
+
* This creates the Fastify API handler that gets embedded in Vinxi.
|
|
5
|
+
* All routes under /api/* are handled by this Fastify instance.
|
|
6
|
+
* Includes JWT authentication via @veloxts/auth.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { authPlugin } from '@veloxts/auth';
|
|
10
|
+
import { veloxApp } from '@veloxts/core';
|
|
11
|
+
import { databasePlugin } from '@veloxts/orm';
|
|
12
|
+
import { rest } from '@veloxts/router';
|
|
13
|
+
import { createH3ApiHandler } from '@veloxts/web/adapters';
|
|
14
|
+
|
|
15
|
+
import { db } from './database.js';
|
|
16
|
+
import { authProcedures } from './procedures/auth.js';
|
|
17
|
+
import { healthProcedures } from './procedures/health.js';
|
|
18
|
+
import { userProcedures } from './procedures/users.js';
|
|
19
|
+
import { getJwtSecrets, parseUserRoles, tokenStore } from './utils/auth.js';
|
|
20
|
+
|
|
21
|
+
// Export router type for frontend type safety
|
|
22
|
+
const router = { health: healthProcedures, users: userProcedures, auth: authProcedures };
|
|
23
|
+
export type AppRouter = typeof router;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create auth configuration for the embedded API.
|
|
27
|
+
*/
|
|
28
|
+
function createAuthConfig() {
|
|
29
|
+
const { jwtSecret, refreshSecret } = getJwtSecrets();
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
jwt: {
|
|
33
|
+
secret: jwtSecret,
|
|
34
|
+
refreshSecret: refreshSecret,
|
|
35
|
+
accessTokenExpiry: '15m',
|
|
36
|
+
refreshTokenExpiry: '7d',
|
|
37
|
+
issuer: 'velox-app',
|
|
38
|
+
audience: 'velox-app-client',
|
|
39
|
+
},
|
|
40
|
+
userLoader: async (userId: string) => {
|
|
41
|
+
const user = await db.user.findUnique({
|
|
42
|
+
where: { id: userId },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!user) return null;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
id: user.id,
|
|
49
|
+
email: user.email,
|
|
50
|
+
name: user.name,
|
|
51
|
+
roles: parseUserRoles(user.roles),
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
isTokenRevoked: async (jti: string) => tokenStore.isRevoked(jti),
|
|
55
|
+
rateLimit: {
|
|
56
|
+
max: 100,
|
|
57
|
+
windowMs: 60000,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Export the h3 event handler for Vinxi embedding.
|
|
64
|
+
*/
|
|
65
|
+
export default createH3ApiHandler({
|
|
66
|
+
app: async () => {
|
|
67
|
+
const app = await veloxApp();
|
|
68
|
+
|
|
69
|
+
// Register database plugin
|
|
70
|
+
await app.register(databasePlugin({ client: db }));
|
|
71
|
+
|
|
72
|
+
// Register auth plugin for JWT verification
|
|
73
|
+
await app.register(authPlugin(createAuthConfig()));
|
|
74
|
+
|
|
75
|
+
// Register REST routes from procedures
|
|
76
|
+
app.routes(
|
|
77
|
+
rest([healthProcedures, userProcedures, authProcedures], {
|
|
78
|
+
prefix: '', // No prefix - Vinxi handles /api/*
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return app.server;
|
|
83
|
+
},
|
|
84
|
+
basePath: '/api',
|
|
85
|
+
});
|