@idealyst/cli 1.0.45 → 1.0.48
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/dist/generators/fullstack.js +61 -3
- package/dist/generators/fullstack.js.map +1 -1
- package/dist/generators/native.js +12 -0
- package/dist/generators/native.js.map +1 -1
- package/dist/generators/utils.js +64 -31
- package/dist/generators/utils.js.map +1 -1
- package/dist/templates/api/README.md +207 -130
- package/dist/templates/api/package.json +5 -5
- package/dist/templates/api/src/controllers/TestController.ts +0 -0
- package/dist/templates/api/src/index.ts +2 -7
- package/dist/templates/api/src/lib/crud.ts +150 -0
- package/dist/templates/api/src/lib/database.ts +23 -0
- package/dist/templates/api/src/router/index.ts +104 -71
- package/dist/templates/api/src/routers/test.ts +59 -0
- package/dist/templates/api/src/routers/user.example.ts +83 -0
- package/dist/templates/api/src/server.ts +1 -1
- package/dist/templates/api/tsconfig.json +0 -1
- package/dist/templates/database/README.md +115 -1
- package/dist/templates/database/package.json +2 -0
- package/dist/templates/database/prisma/seed.ts +37 -1
- package/dist/templates/database/schema.prisma +11 -1
- package/dist/templates/native/index.js +1 -1
- package/dist/templates/native/metro.config.js +1 -1
- package/dist/templates/native/package.json +4 -0
- package/dist/templates/native/src/App.tsx +16 -0
- package/dist/templates/native/src/utils/trpc.ts +7 -127
- package/dist/templates/native/tsconfig.json +0 -2
- package/dist/templates/shared/README.md +31 -5
- package/dist/templates/shared/__tests__/shared.test.ts +17 -5
- package/dist/templates/shared/package.json +14 -30
- package/dist/templates/shared/src/components/App.tsx +57 -0
- package/dist/templates/shared/src/components/HelloWorld.tsx +307 -0
- package/dist/templates/shared/src/components/index.ts +1 -392
- package/dist/templates/shared/src/index.ts +9 -57
- package/dist/templates/shared/src/trpc/client.ts +39 -0
- package/dist/templates/shared/tsconfig.json +4 -7
- package/dist/templates/web/README.md +65 -8
- package/dist/templates/web/package.json +3 -3
- package/dist/templates/web/src/App-with-trpc-and-shared.tsx +11 -299
- package/dist/templates/web/src/components/TestDemo.tsx +164 -0
- package/dist/templates/web/src/utils/trpc.ts +7 -93
- package/dist/templates/web/tsconfig.json +0 -1
- package/dist/templates/workspace/.devcontainer/devcontainer.json +4 -9
- package/dist/templates/workspace/.devcontainer/docker-compose.yml +1 -2
- package/dist/templates/workspace/.devcontainer/setup.sh +1 -1
- package/dist/templates/workspace/.env.example +1 -1
- package/dist/templates/workspace/Dockerfile +4 -4
- package/dist/templates/workspace/docker/nginx/prod.conf +2 -2
- package/dist/templates/workspace/docker/nginx.conf +1 -1
- package/dist/templates/workspace/docker/prometheus/prometheus.yml +1 -1
- package/dist/templates/workspace/docker-compose.yml +4 -5
- package/dist/templates/workspace/tsconfig.json +0 -1
- package/package.json +1 -1
- package/templates/api/README.md +207 -130
- package/templates/api/package.json +5 -5
- package/templates/api/src/controllers/TestController.ts +0 -0
- package/templates/api/src/index.ts +2 -7
- package/templates/api/src/lib/crud.ts +150 -0
- package/templates/api/src/lib/database.ts +23 -0
- package/templates/api/src/router/index.ts +104 -71
- package/templates/api/src/routers/test.ts +59 -0
- package/templates/api/src/routers/user.example.ts +83 -0
- package/templates/api/src/server.ts +1 -1
- package/templates/api/tsconfig.json +0 -1
- package/templates/database/README.md +115 -1
- package/templates/database/package.json +2 -0
- package/templates/database/prisma/seed.ts +37 -1
- package/templates/database/schema.prisma +11 -1
- package/templates/native/index.js +1 -1
- package/templates/native/metro.config.js +1 -1
- package/templates/native/package.json +4 -0
- package/templates/native/src/App.tsx +16 -0
- package/templates/native/src/utils/trpc.ts +7 -127
- package/templates/native/tsconfig.json +0 -2
- package/templates/shared/README.md +31 -5
- package/templates/shared/__tests__/shared.test.ts +17 -5
- package/templates/shared/package.json +14 -30
- package/templates/shared/src/components/App.tsx +57 -0
- package/templates/shared/src/components/HelloWorld.tsx +307 -0
- package/templates/shared/src/components/index.ts +1 -392
- package/templates/shared/src/index.ts +9 -57
- package/templates/shared/src/trpc/client.ts +39 -0
- package/templates/shared/tsconfig.json +4 -7
- package/templates/web/README.md +65 -8
- package/templates/web/package.json +3 -3
- package/templates/web/src/App-with-trpc-and-shared.tsx +11 -299
- package/templates/web/src/components/TestDemo.tsx +164 -0
- package/templates/web/src/utils/trpc.ts +7 -93
- package/templates/web/tsconfig.json +0 -1
- package/templates/workspace/.devcontainer/devcontainer.json +4 -9
- package/templates/workspace/.devcontainer/docker-compose.yml +1 -2
- package/templates/workspace/.devcontainer/setup.sh +1 -1
- package/templates/workspace/.env.example +1 -1
- package/templates/workspace/Dockerfile +4 -4
- package/templates/workspace/docker/nginx/prod.conf +2 -2
- package/templates/workspace/docker/nginx.conf +1 -1
- package/templates/workspace/docker/prometheus/prometheus.yml +1 -1
- package/templates/workspace/docker-compose.yml +4 -5
- package/templates/workspace/tsconfig.json +0 -1
- package/dist/templates/api/src/controllers/UserController.ts +0 -102
- package/dist/templates/api/src/lib/controller.ts +0 -90
- package/dist/templates/api/src/lib/middleware.ts +0 -170
- package/dist/templates/api/src/middleware/auth.ts +0 -75
- package/dist/templates/api/src/middleware/common.ts +0 -103
- package/dist/templates/database/.env.example +0 -1
- package/dist/templates/native/App.tsx +0 -23
- package/dist/templates/native/src/App-with-trpc-and-shared.tsx +0 -266
- package/dist/templates/shared/rollup.config.js +0 -43
- package/dist/templates/shared/src/types/index.ts +0 -148
- package/dist/templates/shared/src/utils/index.ts +0 -278
- package/templates/api/src/controllers/UserController.ts +0 -102
- package/templates/api/src/lib/controller.ts +0 -90
- package/templates/api/src/lib/middleware.ts +0 -170
- package/templates/api/src/middleware/auth.ts +0 -75
- package/templates/api/src/middleware/common.ts +0 -103
- package/templates/database/.env.example +0 -1
- package/templates/native/App.tsx +0 -23
- package/templates/native/src/App-with-trpc-and-shared.tsx +0 -266
- package/templates/shared/rollup.config.js +0 -43
- package/templates/shared/src/types/index.ts +0 -148
- package/templates/shared/src/utils/index.ts +0 -278
|
@@ -1,304 +1,16 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
import { httpBatchLink } from '@trpc/client';
|
|
4
|
-
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
|
|
5
|
-
import { trpc } from './utils/trpc';
|
|
6
|
-
import { Screen, Text, View, Button, ScrollView } from '@idealyst/components';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { App } from '@{{workspaceScope}}/shared';
|
|
7
3
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
UserCard,
|
|
11
|
-
PostCard,
|
|
12
|
-
LoadingSpinner,
|
|
13
|
-
ErrorMessage,
|
|
14
|
-
FeatureCard,
|
|
15
|
-
DEMO_USERS,
|
|
16
|
-
DEMO_POSTS,
|
|
17
|
-
formatRelativeTime,
|
|
18
|
-
type User,
|
|
19
|
-
type Post,
|
|
20
|
-
type PostWithAuthor
|
|
21
|
-
} from '{{workspaceScope}}/shared';
|
|
22
|
-
|
|
23
|
-
// Create tRPC client
|
|
24
|
-
const queryClient = new QueryClient();
|
|
25
|
-
|
|
26
|
-
const trpcClient = trpc.createClient({
|
|
27
|
-
links: [
|
|
28
|
-
httpBatchLink({
|
|
29
|
-
url: 'http://localhost:3001/trpc', // Updated to match API port
|
|
30
|
-
// Optional: Add headers for authentication
|
|
31
|
-
// headers() {
|
|
32
|
-
// return {
|
|
33
|
-
// authorization: getAuthToken(),
|
|
34
|
-
// };
|
|
35
|
-
// },
|
|
36
|
-
}),
|
|
37
|
-
],
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Navigation Component
|
|
41
|
-
function Navigation() {
|
|
42
|
-
return (
|
|
43
|
-
<View style={{
|
|
44
|
-
flexDirection: 'row',
|
|
45
|
-
padding: 16,
|
|
46
|
-
backgroundColor: '#f8f9fa',
|
|
47
|
-
borderBottomWidth: 1,
|
|
48
|
-
borderBottomColor: '#e9ecef'
|
|
49
|
-
}}>
|
|
50
|
-
<Text variant="h2" style={{ marginRight: 24 }}>{{projectName}}</Text>
|
|
51
|
-
<View style={{ flexDirection: 'row', gap: 16 }}>
|
|
52
|
-
<Link to="/" style={{ textDecoration: 'none' }}>
|
|
53
|
-
<Text style={{ color: '#007bff' }}>Home</Text>
|
|
54
|
-
</Link>
|
|
55
|
-
<Link to="/users" style={{ textDecoration: 'none' }}>
|
|
56
|
-
<Text style={{ color: '#007bff' }}>Users</Text>
|
|
57
|
-
</Link>
|
|
58
|
-
<Link to="/posts" style={{ textDecoration: 'none' }}>
|
|
59
|
-
<Text style={{ color: '#007bff' }}>Posts</Text>
|
|
60
|
-
</Link>
|
|
61
|
-
</View>
|
|
62
|
-
</View>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Home Page Component
|
|
67
|
-
function HomePage() {
|
|
68
|
-
// Example tRPC usage
|
|
69
|
-
const { data: helloData, isLoading: helloLoading, error: helloError } = trpc.hello.useQuery({ name: 'Web User' });
|
|
70
|
-
const { data: usersData, isLoading: usersLoading } = trpc.users.getAll.useQuery();
|
|
71
|
-
const { data: postsData, isLoading: postsLoading } = trpc.posts.getAll.useQuery();
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<ScrollView style={{ flex: 1 }}>
|
|
75
|
-
<View style={{ padding: 20 }}>
|
|
76
|
-
{/* Welcome Section */}
|
|
77
|
-
<View style={{ marginBottom: 32, textAlign: 'center' }}>
|
|
78
|
-
<Text variant="h1" style={{ marginBottom: 16 }}>
|
|
79
|
-
Welcome to {{projectName}}! 🚀
|
|
80
|
-
</Text>
|
|
81
|
-
<Text variant="body" style={{ marginBottom: 16, fontSize: 18 }}>
|
|
82
|
-
A full-stack application built with the Idealyst Framework
|
|
83
|
-
</Text>
|
|
84
|
-
|
|
85
|
-
{/* tRPC Connection Test */}
|
|
86
|
-
<View style={{
|
|
87
|
-
padding: 16,
|
|
88
|
-
backgroundColor: '#e3f2fd',
|
|
89
|
-
borderRadius: 8,
|
|
90
|
-
marginBottom: 24
|
|
91
|
-
}}>
|
|
92
|
-
<Text variant="h3" style={{ marginBottom: 8 }}>🔗 API Connection:</Text>
|
|
93
|
-
{helloLoading && <Text>Testing connection...</Text>}
|
|
94
|
-
{helloError && <Text style={{ color: 'red' }}>Error: {helloError.message}</Text>}
|
|
95
|
-
{helloData && <Text style={{ color: 'green' }}>✅ {helloData.greeting}</Text>}
|
|
96
|
-
</View>
|
|
97
|
-
</View>
|
|
98
|
-
|
|
99
|
-
{/* Features Overview */}
|
|
100
|
-
<View style={{ marginBottom: 32 }}>
|
|
101
|
-
<Text variant="h2" style={{ marginBottom: 16 }}>🏗️ Architecture Overview</Text>
|
|
102
|
-
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 16 }}>
|
|
103
|
-
<FeatureCard
|
|
104
|
-
icon="🗄️"
|
|
105
|
-
title="Database Layer"
|
|
106
|
-
description="Prisma ORM with SQLite, user management, posts, and comments"
|
|
107
|
-
/>
|
|
108
|
-
<FeatureCard
|
|
109
|
-
icon="🚀"
|
|
110
|
-
title="API Server"
|
|
111
|
-
description="tRPC API with type-safe endpoints and real-time capabilities"
|
|
112
|
-
/>
|
|
113
|
-
<FeatureCard
|
|
114
|
-
icon="🌐"
|
|
115
|
-
title="Web Application"
|
|
116
|
-
description="React web app with Idealyst components and responsive design"
|
|
117
|
-
/>
|
|
118
|
-
<FeatureCard
|
|
119
|
-
icon="📱"
|
|
120
|
-
title="Mobile App"
|
|
121
|
-
description="React Native app with shared components and unified styling"
|
|
122
|
-
/>
|
|
123
|
-
<FeatureCard
|
|
124
|
-
icon="📦"
|
|
125
|
-
title="Shared Library"
|
|
126
|
-
description="Cross-platform components, utilities, and type definitions"
|
|
127
|
-
/>
|
|
128
|
-
<FeatureCard
|
|
129
|
-
icon="🔗"
|
|
130
|
-
title="Full Integration"
|
|
131
|
-
description="End-to-end type safety and unified development workflow"
|
|
132
|
-
/>
|
|
133
|
-
</View>
|
|
134
|
-
</View>
|
|
135
|
-
|
|
136
|
-
{/* Live Data Preview */}
|
|
137
|
-
<View style={{ marginBottom: 32 }}>
|
|
138
|
-
<Text variant="h2" style={{ marginBottom: 16 }}>📊 Live Data Preview</Text>
|
|
139
|
-
|
|
140
|
-
{/* Users Section */}
|
|
141
|
-
<View style={{ marginBottom: 24 }}>
|
|
142
|
-
<Text variant="h3" style={{ marginBottom: 12 }}>👥 Users ({usersLoading ? '...' : usersData?.length || DEMO_USERS.length})</Text>
|
|
143
|
-
{usersLoading ? (
|
|
144
|
-
<LoadingSpinner message="Loading users..." />
|
|
145
|
-
) : (
|
|
146
|
-
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 12 }}>
|
|
147
|
-
{(usersData || DEMO_USERS.slice(0, 3)).map((user: User) => (
|
|
148
|
-
<View key={user.id} style={{ width: '300px' }}>
|
|
149
|
-
<UserCard
|
|
150
|
-
user={user}
|
|
151
|
-
showBio={false}
|
|
152
|
-
onPress={() => console.log('View profile:', user.name)}
|
|
153
|
-
/>
|
|
154
|
-
</View>
|
|
155
|
-
))}
|
|
156
|
-
</View>
|
|
157
|
-
)}
|
|
158
|
-
</View>
|
|
159
|
-
|
|
160
|
-
{/* Posts Section */}
|
|
161
|
-
<View style={{ marginBottom: 24 }}>
|
|
162
|
-
<Text variant="h3" style={{ marginBottom: 12 }}>📝 Recent Posts ({postsLoading ? '...' : postsData?.length || DEMO_POSTS.length})</Text>
|
|
163
|
-
{postsLoading ? (
|
|
164
|
-
<LoadingSpinner message="Loading posts..." />
|
|
165
|
-
) : (
|
|
166
|
-
<View>
|
|
167
|
-
{(postsData || DEMO_POSTS.slice(0, 2)).map((post: Post) => {
|
|
168
|
-
const author = DEMO_USERS.find(u => u.id === post.authorId);
|
|
169
|
-
return (
|
|
170
|
-
<PostCard
|
|
171
|
-
key={post.id}
|
|
172
|
-
post={post}
|
|
173
|
-
author={author}
|
|
174
|
-
onPress={() => console.log('Read post:', post.title)}
|
|
175
|
-
onLike={() => console.log('Like post:', post.title)}
|
|
176
|
-
/>
|
|
177
|
-
);
|
|
178
|
-
})}
|
|
179
|
-
</View>
|
|
180
|
-
)}
|
|
181
|
-
</View>
|
|
182
|
-
</View>
|
|
183
|
-
|
|
184
|
-
{/* Quick Start Section */}
|
|
185
|
-
<View style={{
|
|
186
|
-
padding: 20,
|
|
187
|
-
backgroundColor: '#f8f9fa',
|
|
188
|
-
borderRadius: 8,
|
|
189
|
-
marginBottom: 24
|
|
190
|
-
}}>
|
|
191
|
-
<Text variant="h2" style={{ marginBottom: 16 }}>🚀 Quick Start</Text>
|
|
192
|
-
<Text variant="body" style={{ marginBottom: 12 }}>
|
|
193
|
-
Your full-stack workspace is ready! Here's what you can do:
|
|
194
|
-
</Text>
|
|
195
|
-
<View style={{ marginLeft: 16 }}>
|
|
196
|
-
<Text style={{ marginBottom: 4 }}>• 🗄️ Add your models in <code>packages/database/schema.prisma</code></Text>
|
|
197
|
-
<Text style={{ marginBottom: 4 }}>• 🚀 Create API endpoints in <code>packages/api/src/routers/</code></Text>
|
|
198
|
-
<Text style={{ marginBottom: 4 }}>• 📦 Build shared components in <code>packages/shared/src/</code></Text>
|
|
199
|
-
<Text style={{ marginBottom: 4 }}>• 🌐 Customize this web app in <code>packages/web/src/</code></Text>
|
|
200
|
-
<Text style={{ marginBottom: 4 }}>• 📱 Update the mobile app in <code>packages/mobile/src/</code></Text>
|
|
201
|
-
</View>
|
|
202
|
-
</View>
|
|
203
|
-
|
|
204
|
-
{/* Development Commands */}
|
|
205
|
-
<View style={{
|
|
206
|
-
padding: 20,
|
|
207
|
-
backgroundColor: '#e8f5e8',
|
|
208
|
-
borderRadius: 8,
|
|
209
|
-
marginBottom: 24
|
|
210
|
-
}}>
|
|
211
|
-
<Text variant="h3" style={{ marginBottom: 12 }}>💻 Development Commands</Text>
|
|
212
|
-
<View style={{ fontFamily: 'monospace', fontSize: 14 }}>
|
|
213
|
-
<Text style={{ marginBottom: 4 }}>yarn dev # Start all servers</Text>
|
|
214
|
-
<Text style={{ marginBottom: 4 }}>yarn web:dev # Start web app only</Text>
|
|
215
|
-
<Text style={{ marginBottom: 4 }}>yarn mobile:start # Start mobile bundler</Text>
|
|
216
|
-
<Text style={{ marginBottom: 4 }}>yarn api:dev # Start API server only</Text>
|
|
217
|
-
<Text style={{ marginBottom: 4 }}>yarn db:push # Update database schema</Text>
|
|
218
|
-
<Text style={{ marginBottom: 4 }}>yarn db:studio # Open database admin</Text>
|
|
219
|
-
</View>
|
|
220
|
-
</View>
|
|
221
|
-
</View>
|
|
222
|
-
</ScrollView>
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Users Page Component
|
|
227
|
-
function UsersPage() {
|
|
228
|
-
const { data: users, isLoading, error } = trpc.users.getAll.useQuery();
|
|
229
|
-
|
|
230
|
-
if (isLoading) return <LoadingSpinner message="Loading users..." />;
|
|
231
|
-
if (error) return <ErrorMessage message={error.message} />;
|
|
232
|
-
|
|
233
|
-
const allUsers = users || DEMO_USERS;
|
|
234
|
-
|
|
235
|
-
return (
|
|
236
|
-
<ScrollView style={{ flex: 1, padding: 20 }}>
|
|
237
|
-
<Text variant="h1" style={{ marginBottom: 20 }}>👥 Users ({allUsers.length})</Text>
|
|
238
|
-
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 16 }}>
|
|
239
|
-
{allUsers.map((user: User) => (
|
|
240
|
-
<View key={user.id} style={{ width: '400px' }}>
|
|
241
|
-
<UserCard
|
|
242
|
-
user={user}
|
|
243
|
-
showBio={true}
|
|
244
|
-
onPress={() => console.log('View profile:', user.name)}
|
|
245
|
-
/>
|
|
246
|
-
</View>
|
|
247
|
-
))}
|
|
248
|
-
</View>
|
|
249
|
-
</ScrollView>
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Posts Page Component
|
|
254
|
-
function PostsPage() {
|
|
255
|
-
const { data: posts, isLoading, error } = trpc.posts.getAll.useQuery();
|
|
256
|
-
|
|
257
|
-
if (isLoading) return <LoadingSpinner message="Loading posts..." />;
|
|
258
|
-
if (error) return <ErrorMessage message={error.message} />;
|
|
259
|
-
|
|
260
|
-
const allPosts = posts || DEMO_POSTS;
|
|
261
|
-
|
|
262
|
-
return (
|
|
263
|
-
<ScrollView style={{ flex: 1, padding: 20 }}>
|
|
264
|
-
<Text variant="h1" style={{ marginBottom: 20 }}>📝 Posts ({allPosts.length})</Text>
|
|
265
|
-
<View>
|
|
266
|
-
{allPosts.map((post: Post) => {
|
|
267
|
-
const author = DEMO_USERS.find(u => u.id === post.authorId);
|
|
268
|
-
return (
|
|
269
|
-
<PostCard
|
|
270
|
-
key={post.id}
|
|
271
|
-
post={post}
|
|
272
|
-
author={author}
|
|
273
|
-
showFullContent={false}
|
|
274
|
-
onPress={() => console.log('Read post:', post.title)}
|
|
275
|
-
onLike={() => console.log('Like post:', post.title)}
|
|
276
|
-
/>
|
|
277
|
-
);
|
|
278
|
-
})}
|
|
279
|
-
</View>
|
|
280
|
-
</ScrollView>
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Main App Component
|
|
285
|
-
function App() {
|
|
4
|
+
// Main App component using shared App wrapper
|
|
5
|
+
function AppWithTrpcAndShared() {
|
|
286
6
|
return (
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
<Route path="/" element={<HomePage />} />
|
|
294
|
-
<Route path="/users" element={<UsersPage />} />
|
|
295
|
-
<Route path="/posts" element={<PostsPage />} />
|
|
296
|
-
</Routes>
|
|
297
|
-
</Screen>
|
|
298
|
-
</BrowserRouter>
|
|
299
|
-
</QueryClientProvider>
|
|
300
|
-
</trpc.Provider>
|
|
7
|
+
<App
|
|
8
|
+
apiUrl="http://localhost:3000/trpc"
|
|
9
|
+
name="{{projectName}} Developer"
|
|
10
|
+
platform="web"
|
|
11
|
+
projectName="{{projectName}}"
|
|
12
|
+
/>
|
|
301
13
|
);
|
|
302
14
|
}
|
|
303
15
|
|
|
304
|
-
export default
|
|
16
|
+
export default AppWithTrpcAndShared;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { View, Text, Card, Button, Input } from '@idealyst/components';
|
|
3
|
+
import { trpc } from '../utils/trpc';
|
|
4
|
+
|
|
5
|
+
export const TestDemo: React.FC = () => {
|
|
6
|
+
const [newTestName, setNewTestName] = useState('');
|
|
7
|
+
const [newTestMessage, setNewTestMessage] = useState('');
|
|
8
|
+
|
|
9
|
+
// tRPC queries and mutations
|
|
10
|
+
const { data: tests, isLoading, refetch } = trpc.test.getAll.useQuery();
|
|
11
|
+
const createTestMutation = trpc.test.create.useMutation({
|
|
12
|
+
onSuccess: () => {
|
|
13
|
+
refetch();
|
|
14
|
+
setNewTestName('');
|
|
15
|
+
setNewTestMessage('');
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
const deleteTestMutation = trpc.test.delete.useMutation({
|
|
19
|
+
onSuccess: () => {
|
|
20
|
+
refetch();
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const handleCreateTest = async () => {
|
|
25
|
+
if (!newTestName || !newTestMessage) return;
|
|
26
|
+
|
|
27
|
+
await createTestMutation.mutateAsync({
|
|
28
|
+
name: newTestName,
|
|
29
|
+
message: newTestMessage,
|
|
30
|
+
status: 'active',
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleDeleteTest = async (id: string) => {
|
|
35
|
+
await deleteTestMutation.mutateAsync({ id });
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if (isLoading) {
|
|
39
|
+
return (
|
|
40
|
+
<Card variant="outlined" padding="large">
|
|
41
|
+
<Text size="medium">Loading tests...</Text>
|
|
42
|
+
</Card>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<View style={{ gap: 16 }}>
|
|
48
|
+
{/* Header */}
|
|
49
|
+
<Card variant="elevated" padding="large" intent="primary">
|
|
50
|
+
<View style={{ alignItems: 'center' }}>
|
|
51
|
+
<Text style={{ fontSize: 24, marginBottom: 8 }}>🧪</Text>
|
|
52
|
+
<Text size="large" weight="bold" style={{ marginBottom: 8, textAlign: 'center' }}>
|
|
53
|
+
tRPC + Database Test
|
|
54
|
+
</Text>
|
|
55
|
+
<Text size="medium" style={{ textAlign: 'center' }}>
|
|
56
|
+
This demonstrates end-to-end type-safe API calls from the web app to the database.
|
|
57
|
+
</Text>
|
|
58
|
+
</View>
|
|
59
|
+
</Card>
|
|
60
|
+
|
|
61
|
+
{/* Create Test Form */}
|
|
62
|
+
<Card variant="outlined" padding="large">
|
|
63
|
+
<Text size="medium" weight="bold" style={{ marginBottom: 16 }}>
|
|
64
|
+
Create New Test
|
|
65
|
+
</Text>
|
|
66
|
+
|
|
67
|
+
<View style={{ gap: 12 }}>
|
|
68
|
+
<Input
|
|
69
|
+
label="Test Name"
|
|
70
|
+
value={newTestName}
|
|
71
|
+
onChangeText={setNewTestName}
|
|
72
|
+
placeholder="Enter test name"
|
|
73
|
+
/>
|
|
74
|
+
<Input
|
|
75
|
+
label="Test Message"
|
|
76
|
+
value={newTestMessage}
|
|
77
|
+
onChangeText={setNewTestMessage}
|
|
78
|
+
placeholder="Enter test message"
|
|
79
|
+
multiline
|
|
80
|
+
/>
|
|
81
|
+
<Button
|
|
82
|
+
variant="contained"
|
|
83
|
+
intent="primary"
|
|
84
|
+
onPress={handleCreateTest}
|
|
85
|
+
disabled={!newTestName || !newTestMessage || createTestMutation.isPending}
|
|
86
|
+
>
|
|
87
|
+
{createTestMutation.isPending ? 'Creating...' : 'Create Test'}
|
|
88
|
+
</Button>
|
|
89
|
+
</View>
|
|
90
|
+
</Card>
|
|
91
|
+
|
|
92
|
+
{/* Test Results */}
|
|
93
|
+
<Card variant="outlined" padding="large">
|
|
94
|
+
<Text size="medium" weight="bold" style={{ marginBottom: 16 }}>
|
|
95
|
+
Test Entries ({tests?.count || 0})
|
|
96
|
+
</Text>
|
|
97
|
+
|
|
98
|
+
{tests?.data && tests.data.length > 0 ? (
|
|
99
|
+
<View style={{ gap: 12 }}>
|
|
100
|
+
{tests.data.map((test) => (
|
|
101
|
+
<Card key={test.id} variant="filled" padding="medium">
|
|
102
|
+
<View style={{
|
|
103
|
+
flexDirection: 'row',
|
|
104
|
+
justifyContent: 'space-between',
|
|
105
|
+
alignItems: 'flex-start',
|
|
106
|
+
gap: 12
|
|
107
|
+
}}>
|
|
108
|
+
<View style={{ flex: 1 }}>
|
|
109
|
+
<Text size="medium" weight="semibold" style={{ marginBottom: 4 }}>
|
|
110
|
+
{test.name}
|
|
111
|
+
</Text>
|
|
112
|
+
<Text size="small" style={{ marginBottom: 8, opacity: 0.8 }}>
|
|
113
|
+
{test.message}
|
|
114
|
+
</Text>
|
|
115
|
+
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
116
|
+
<Card
|
|
117
|
+
variant="filled"
|
|
118
|
+
padding="small"
|
|
119
|
+
intent={test.status === 'active' ? 'success' : 'neutral'}
|
|
120
|
+
>
|
|
121
|
+
<Text size="small" weight="semibold">
|
|
122
|
+
{test.status}
|
|
123
|
+
</Text>
|
|
124
|
+
</Card>
|
|
125
|
+
<Text size="small" style={{ opacity: 0.6 }}>
|
|
126
|
+
{new Date(test.createdAt).toLocaleDateString()}
|
|
127
|
+
</Text>
|
|
128
|
+
</View>
|
|
129
|
+
</View>
|
|
130
|
+
<Button
|
|
131
|
+
variant="outlined"
|
|
132
|
+
intent="error"
|
|
133
|
+
size="small"
|
|
134
|
+
onPress={() => handleDeleteTest(test.id)}
|
|
135
|
+
disabled={deleteTestMutation.isPending}
|
|
136
|
+
>
|
|
137
|
+
Delete
|
|
138
|
+
</Button>
|
|
139
|
+
</View>
|
|
140
|
+
</Card>
|
|
141
|
+
))}
|
|
142
|
+
</View>
|
|
143
|
+
) : (
|
|
144
|
+
<Card variant="filled" padding="medium" style={{ opacity: 0.6 }}>
|
|
145
|
+
<Text size="small" style={{ textAlign: 'center' }}>
|
|
146
|
+
No tests found. Create one above to get started!
|
|
147
|
+
</Text>
|
|
148
|
+
</Card>
|
|
149
|
+
)}
|
|
150
|
+
</Card>
|
|
151
|
+
|
|
152
|
+
{/* Type Safety Info */}
|
|
153
|
+
<Card variant="filled" intent="success" padding="medium">
|
|
154
|
+
<Text size="small" weight="semibold" style={{ marginBottom: 4 }}>
|
|
155
|
+
✨ Type Safety Features:
|
|
156
|
+
</Text>
|
|
157
|
+
<Text size="small">
|
|
158
|
+
• Full TypeScript types from database to frontend • tRPC ensures API type safety •
|
|
159
|
+
Prisma provides database schema validation • Real-time type checking across the stack
|
|
160
|
+
</Text>
|
|
161
|
+
</Card>
|
|
162
|
+
</View>
|
|
163
|
+
);
|
|
164
|
+
};
|
|
@@ -1,93 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type AppRouter = any;
|
|
9
|
-
|
|
10
|
-
// Create the tRPC React hooks
|
|
11
|
-
export const trpc = createTRPCReact<AppRouter>();
|
|
12
|
-
|
|
13
|
-
// Create a vanilla client (for use outside of React components)
|
|
14
|
-
export const trpcClient = createTRPCProxyClient<AppRouter>({
|
|
15
|
-
links: [
|
|
16
|
-
httpBatchLink({
|
|
17
|
-
url: 'http://localhost:3000/trpc', // Update this to match your API URL
|
|
18
|
-
// Optional: Add headers
|
|
19
|
-
// headers() {
|
|
20
|
-
// return {
|
|
21
|
-
// authorization: getAuthToken(),
|
|
22
|
-
// };
|
|
23
|
-
// },
|
|
24
|
-
}),
|
|
25
|
-
],
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
/*
|
|
29
|
-
Usage Examples:
|
|
30
|
-
|
|
31
|
-
1. First, install the required dependencies:
|
|
32
|
-
yarn add @trpc/client @trpc/react-query @tanstack/react-query
|
|
33
|
-
|
|
34
|
-
2. Replace the AppRouter type import above with your actual API router:
|
|
35
|
-
import type { AppRouter } from '@your-workspace/api';
|
|
36
|
-
|
|
37
|
-
3. Set up the tRPC provider in your App component:
|
|
38
|
-
|
|
39
|
-
```tsx
|
|
40
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
41
|
-
import { httpBatchLink } from '@trpc/client';
|
|
42
|
-
import { trpc } from './utils/trpc';
|
|
43
|
-
|
|
44
|
-
const queryClient = new QueryClient();
|
|
45
|
-
|
|
46
|
-
const trpcClient = trpc.createClient({
|
|
47
|
-
links: [
|
|
48
|
-
httpBatchLink({
|
|
49
|
-
url: 'http://localhost:3000/trpc',
|
|
50
|
-
}),
|
|
51
|
-
],
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
function App() {
|
|
55
|
-
return (
|
|
56
|
-
<trpc.Provider client={trpcClient} queryClient={queryClient}>
|
|
57
|
-
<QueryClientProvider client={queryClient}>
|
|
58
|
-
// Your app components
|
|
59
|
-
</QueryClientProvider>
|
|
60
|
-
</trpc.Provider>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
4. Use tRPC in your components:
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
import { trpc } from '../utils/trpc';
|
|
69
|
-
|
|
70
|
-
function UsersList() {
|
|
71
|
-
const { data: users, isLoading } = trpc.users.getAll.useQuery();
|
|
72
|
-
const createUser = trpc.users.create.useMutation();
|
|
73
|
-
|
|
74
|
-
if (isLoading) return <div>Loading...</div>;
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<div>
|
|
78
|
-
{users?.map(user => (
|
|
79
|
-
<div key={user.id}>{user.name}</div>
|
|
80
|
-
))}
|
|
81
|
-
<button
|
|
82
|
-
onClick={() => createUser.mutate({
|
|
83
|
-
email: 'test@example.com',
|
|
84
|
-
name: 'Test User'
|
|
85
|
-
})}
|
|
86
|
-
>
|
|
87
|
-
Create User
|
|
88
|
-
</button>
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
*/
|
|
1
|
+
// Import tRPC client utilities from shared package
|
|
2
|
+
export {
|
|
3
|
+
trpc,
|
|
4
|
+
createTRPCClient,
|
|
5
|
+
createVanillaTRPCClient
|
|
6
|
+
} from '@{{workspaceScope}}/shared';
|
|
7
|
+
export type { TRPCClientConfig, AppRouter } from '@{{workspaceScope}}/shared';
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
// Forward ports
|
|
8
8
|
"forwardPorts": [
|
|
9
|
-
3000, //
|
|
10
|
-
3001, // API server
|
|
9
|
+
3000, // Api server
|
|
11
10
|
5173, // Vite dev server
|
|
12
|
-
|
|
11
|
+
8081, // Metro Bundler
|
|
13
12
|
19006, // Expo dev tools
|
|
14
13
|
5432, // PostgreSQL
|
|
15
14
|
6379, // Redis
|
|
@@ -19,10 +18,6 @@
|
|
|
19
18
|
// Port attributes
|
|
20
19
|
"portsAttributes": {
|
|
21
20
|
"3000": {
|
|
22
|
-
"label": "Web App",
|
|
23
|
-
"onAutoForward": "openBrowser"
|
|
24
|
-
},
|
|
25
|
-
"3001": {
|
|
26
21
|
"label": "API Server",
|
|
27
22
|
"onAutoForward": "notify"
|
|
28
23
|
},
|
|
@@ -30,8 +25,8 @@
|
|
|
30
25
|
"label": "Vite Dev Server",
|
|
31
26
|
"onAutoForward": "openBrowser"
|
|
32
27
|
},
|
|
33
|
-
"
|
|
34
|
-
"label": "
|
|
28
|
+
"8081": {
|
|
29
|
+
"label": "Metro Bundler",
|
|
35
30
|
"onAutoForward": "notify"
|
|
36
31
|
},
|
|
37
32
|
"19006": {
|
|
@@ -45,13 +45,13 @@ COPY --from=builder /app/node_modules ./node_modules
|
|
|
45
45
|
COPY --from=builder /app/package.json ./
|
|
46
46
|
|
|
47
47
|
USER apiuser
|
|
48
|
-
EXPOSE
|
|
48
|
+
EXPOSE 3000
|
|
49
49
|
ENV NODE_ENV=production
|
|
50
|
-
ENV PORT=
|
|
50
|
+
ENV PORT=3000
|
|
51
51
|
|
|
52
52
|
# Health check for API
|
|
53
53
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
54
|
-
CMD node -e "require('http').get('http://localhost:
|
|
54
|
+
CMD node -e "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"
|
|
55
55
|
|
|
56
56
|
CMD ["node", "packages/api/dist/server.js"]
|
|
57
57
|
|
|
@@ -98,7 +98,7 @@ COPY --chown=devuser:devuser packages/web/package.json ./packages/web/
|
|
|
98
98
|
# Install dependencies including dev dependencies
|
|
99
99
|
RUN yarn install
|
|
100
100
|
|
|
101
|
-
EXPOSE 3000
|
|
101
|
+
EXPOSE 3000 5173 1 19006
|
|
102
102
|
|
|
103
103
|
CMD ["tail", "-f", "/dev/null"]
|
|
104
104
|
|