@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.
Files changed (121) hide show
  1. package/dist/generators/fullstack.js +61 -3
  2. package/dist/generators/fullstack.js.map +1 -1
  3. package/dist/generators/native.js +12 -0
  4. package/dist/generators/native.js.map +1 -1
  5. package/dist/generators/utils.js +64 -31
  6. package/dist/generators/utils.js.map +1 -1
  7. package/dist/templates/api/README.md +207 -130
  8. package/dist/templates/api/package.json +5 -5
  9. package/dist/templates/api/src/controllers/TestController.ts +0 -0
  10. package/dist/templates/api/src/index.ts +2 -7
  11. package/dist/templates/api/src/lib/crud.ts +150 -0
  12. package/dist/templates/api/src/lib/database.ts +23 -0
  13. package/dist/templates/api/src/router/index.ts +104 -71
  14. package/dist/templates/api/src/routers/test.ts +59 -0
  15. package/dist/templates/api/src/routers/user.example.ts +83 -0
  16. package/dist/templates/api/src/server.ts +1 -1
  17. package/dist/templates/api/tsconfig.json +0 -1
  18. package/dist/templates/database/README.md +115 -1
  19. package/dist/templates/database/package.json +2 -0
  20. package/dist/templates/database/prisma/seed.ts +37 -1
  21. package/dist/templates/database/schema.prisma +11 -1
  22. package/dist/templates/native/index.js +1 -1
  23. package/dist/templates/native/metro.config.js +1 -1
  24. package/dist/templates/native/package.json +4 -0
  25. package/dist/templates/native/src/App.tsx +16 -0
  26. package/dist/templates/native/src/utils/trpc.ts +7 -127
  27. package/dist/templates/native/tsconfig.json +0 -2
  28. package/dist/templates/shared/README.md +31 -5
  29. package/dist/templates/shared/__tests__/shared.test.ts +17 -5
  30. package/dist/templates/shared/package.json +14 -30
  31. package/dist/templates/shared/src/components/App.tsx +57 -0
  32. package/dist/templates/shared/src/components/HelloWorld.tsx +307 -0
  33. package/dist/templates/shared/src/components/index.ts +1 -392
  34. package/dist/templates/shared/src/index.ts +9 -57
  35. package/dist/templates/shared/src/trpc/client.ts +39 -0
  36. package/dist/templates/shared/tsconfig.json +4 -7
  37. package/dist/templates/web/README.md +65 -8
  38. package/dist/templates/web/package.json +3 -3
  39. package/dist/templates/web/src/App-with-trpc-and-shared.tsx +11 -299
  40. package/dist/templates/web/src/components/TestDemo.tsx +164 -0
  41. package/dist/templates/web/src/utils/trpc.ts +7 -93
  42. package/dist/templates/web/tsconfig.json +0 -1
  43. package/dist/templates/workspace/.devcontainer/devcontainer.json +4 -9
  44. package/dist/templates/workspace/.devcontainer/docker-compose.yml +1 -2
  45. package/dist/templates/workspace/.devcontainer/setup.sh +1 -1
  46. package/dist/templates/workspace/.env.example +1 -1
  47. package/dist/templates/workspace/Dockerfile +4 -4
  48. package/dist/templates/workspace/docker/nginx/prod.conf +2 -2
  49. package/dist/templates/workspace/docker/nginx.conf +1 -1
  50. package/dist/templates/workspace/docker/prometheus/prometheus.yml +1 -1
  51. package/dist/templates/workspace/docker-compose.yml +4 -5
  52. package/dist/templates/workspace/tsconfig.json +0 -1
  53. package/package.json +1 -1
  54. package/templates/api/README.md +207 -130
  55. package/templates/api/package.json +5 -5
  56. package/templates/api/src/controllers/TestController.ts +0 -0
  57. package/templates/api/src/index.ts +2 -7
  58. package/templates/api/src/lib/crud.ts +150 -0
  59. package/templates/api/src/lib/database.ts +23 -0
  60. package/templates/api/src/router/index.ts +104 -71
  61. package/templates/api/src/routers/test.ts +59 -0
  62. package/templates/api/src/routers/user.example.ts +83 -0
  63. package/templates/api/src/server.ts +1 -1
  64. package/templates/api/tsconfig.json +0 -1
  65. package/templates/database/README.md +115 -1
  66. package/templates/database/package.json +2 -0
  67. package/templates/database/prisma/seed.ts +37 -1
  68. package/templates/database/schema.prisma +11 -1
  69. package/templates/native/index.js +1 -1
  70. package/templates/native/metro.config.js +1 -1
  71. package/templates/native/package.json +4 -0
  72. package/templates/native/src/App.tsx +16 -0
  73. package/templates/native/src/utils/trpc.ts +7 -127
  74. package/templates/native/tsconfig.json +0 -2
  75. package/templates/shared/README.md +31 -5
  76. package/templates/shared/__tests__/shared.test.ts +17 -5
  77. package/templates/shared/package.json +14 -30
  78. package/templates/shared/src/components/App.tsx +57 -0
  79. package/templates/shared/src/components/HelloWorld.tsx +307 -0
  80. package/templates/shared/src/components/index.ts +1 -392
  81. package/templates/shared/src/index.ts +9 -57
  82. package/templates/shared/src/trpc/client.ts +39 -0
  83. package/templates/shared/tsconfig.json +4 -7
  84. package/templates/web/README.md +65 -8
  85. package/templates/web/package.json +3 -3
  86. package/templates/web/src/App-with-trpc-and-shared.tsx +11 -299
  87. package/templates/web/src/components/TestDemo.tsx +164 -0
  88. package/templates/web/src/utils/trpc.ts +7 -93
  89. package/templates/web/tsconfig.json +0 -1
  90. package/templates/workspace/.devcontainer/devcontainer.json +4 -9
  91. package/templates/workspace/.devcontainer/docker-compose.yml +1 -2
  92. package/templates/workspace/.devcontainer/setup.sh +1 -1
  93. package/templates/workspace/.env.example +1 -1
  94. package/templates/workspace/Dockerfile +4 -4
  95. package/templates/workspace/docker/nginx/prod.conf +2 -2
  96. package/templates/workspace/docker/nginx.conf +1 -1
  97. package/templates/workspace/docker/prometheus/prometheus.yml +1 -1
  98. package/templates/workspace/docker-compose.yml +4 -5
  99. package/templates/workspace/tsconfig.json +0 -1
  100. package/dist/templates/api/src/controllers/UserController.ts +0 -102
  101. package/dist/templates/api/src/lib/controller.ts +0 -90
  102. package/dist/templates/api/src/lib/middleware.ts +0 -170
  103. package/dist/templates/api/src/middleware/auth.ts +0 -75
  104. package/dist/templates/api/src/middleware/common.ts +0 -103
  105. package/dist/templates/database/.env.example +0 -1
  106. package/dist/templates/native/App.tsx +0 -23
  107. package/dist/templates/native/src/App-with-trpc-and-shared.tsx +0 -266
  108. package/dist/templates/shared/rollup.config.js +0 -43
  109. package/dist/templates/shared/src/types/index.ts +0 -148
  110. package/dist/templates/shared/src/utils/index.ts +0 -278
  111. package/templates/api/src/controllers/UserController.ts +0 -102
  112. package/templates/api/src/lib/controller.ts +0 -90
  113. package/templates/api/src/lib/middleware.ts +0 -170
  114. package/templates/api/src/middleware/auth.ts +0 -75
  115. package/templates/api/src/middleware/common.ts +0 -103
  116. package/templates/database/.env.example +0 -1
  117. package/templates/native/App.tsx +0 -23
  118. package/templates/native/src/App-with-trpc-and-shared.tsx +0 -266
  119. package/templates/shared/rollup.config.js +0 -43
  120. package/templates/shared/src/types/index.ts +0 -148
  121. package/templates/shared/src/utils/index.ts +0 -278
@@ -1,103 +0,0 @@
1
- import type { Context } from '../context.js';
2
- import type { MiddlewareFn } from '../lib/controller.js';
3
-
4
- // Logging middleware
5
- export const logger: MiddlewareFn = async ({ ctx, next }) => {
6
- const start = Date.now();
7
- const { method, url } = ctx.req;
8
-
9
- console.log(`📝 ${method} ${url} - ${new Date().toISOString()}`);
10
-
11
- try {
12
- const result = await next();
13
- const duration = Date.now() - start;
14
- console.log(`✅ Request completed in ${duration}ms`);
15
- return result;
16
- } catch (error) {
17
- const duration = Date.now() - start;
18
- console.log(`❌ Request failed in ${duration}ms:`, error);
19
- throw error;
20
- }
21
- };
22
-
23
- // Simple rate limiting middleware (in-memory)
24
- const requestCounts = new Map<string, { count: number; resetTime: number }>();
25
-
26
- export const rateLimit = (maxRequests: number = 100, windowMs: number = 15 * 60 * 1000): MiddlewareFn => {
27
- return async ({ ctx, next }) => {
28
- const clientId = ctx.req.ip || ctx.req.socket.remoteAddress || 'unknown';
29
- const now = Date.now();
30
-
31
- const clientData = requestCounts.get(clientId);
32
-
33
- if (!clientData || now > clientData.resetTime) {
34
- // Reset or initialize
35
- requestCounts.set(clientId, {
36
- count: 1,
37
- resetTime: now + windowMs,
38
- });
39
- } else {
40
- clientData.count++;
41
-
42
- if (clientData.count > maxRequests) {
43
- throw new Error('Rate limit exceeded');
44
- }
45
- }
46
-
47
- return next();
48
- };
49
- };
50
-
51
- // CORS middleware (though this should typically be handled at Express level)
52
- export const cors: MiddlewareFn = async ({ ctx, next }) => {
53
- // Set CORS headers (note: this is just for demonstration)
54
- // In practice, use the cors Express middleware
55
- ctx.res.setHeader('Access-Control-Allow-Origin', '*');
56
- ctx.res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
57
- ctx.res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
58
-
59
- return next();
60
- };
61
-
62
- // Error handling middleware
63
- export const errorHandler: MiddlewareFn = async ({ ctx, next }) => {
64
- try {
65
- return await next();
66
- } catch (error) {
67
- // Log the error
68
- console.error('❌ API Error:', error);
69
-
70
- // Re-throw the error (tRPC will handle it properly)
71
- throw error;
72
- }
73
- };
74
-
75
- // Response time header middleware
76
- export const responseTime: MiddlewareFn = async ({ ctx, next }) => {
77
- const start = Date.now();
78
-
79
- const result = await next();
80
-
81
- const duration = Date.now() - start;
82
- ctx.res.setHeader('X-Response-Time', `${duration}ms`);
83
-
84
- return result;
85
- };
86
-
87
- // Request ID middleware
88
- export const requestId: MiddlewareFn = async ({ ctx, next }) => {
89
- const id = Math.random().toString(36).substring(2, 15);
90
-
91
- // Add request ID to context
92
- const newCtx = {
93
- ...ctx,
94
- requestId: id,
95
- };
96
-
97
- // Set response header
98
- ctx.res.setHeader('X-Request-ID', id);
99
-
100
- return next({
101
- ctx: newCtx,
102
- });
103
- };
@@ -1 +0,0 @@
1
- DATABASE_URL="sqlite:./dev.db"
@@ -1,23 +0,0 @@
1
- import React from 'react';
2
- import {
3
- SafeAreaView,
4
- } from 'react-native';
5
-
6
- import { ExampleStackRouter } from '@idealyst/navigation/examples';
7
- import { NavigatorProvider } from '@idealyst/navigation';
8
-
9
-
10
- function App() {
11
-
12
- const backgroundStyle = {
13
- flex: 1,
14
- };
15
-
16
- return (
17
- <SafeAreaView style={backgroundStyle}>
18
- <NavigatorProvider route={ExampleStackRouter} />
19
- </SafeAreaView>
20
- );
21
- }
22
-
23
- export default App;
@@ -1,266 +0,0 @@
1
- import React, { useState } from 'react';
2
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
- import { httpBatchLink } from '@trpc/client';
4
- import { Screen, Text, View, Button, ScrollView } from '@idealyst/components';
5
- import { trpc } from './utils/trpc';
6
-
7
- // Import shared components and utilities
8
- import {
9
- UserCard,
10
- PostCard,
11
- LoadingSpinner,
12
- ErrorMessage,
13
- FeatureCard,
14
- TabButton,
15
- DEMO_USERS,
16
- DEMO_POSTS,
17
- formatRelativeTime,
18
- type User,
19
- type Post
20
- } from '{{workspaceScope}}/shared';
21
-
22
- // Create tRPC client
23
- const queryClient = new QueryClient();
24
-
25
- const trpcClient = trpc.createClient({
26
- links: [
27
- httpBatchLink({
28
- url: 'http://localhost:3001/trpc', // Update this to your API URL
29
- // For device testing, you might need: 'http://192.168.1.xxx:3001/trpc'
30
- // Optional: Add headers for authentication
31
- // headers() {
32
- // return {
33
- // authorization: getAuthToken(),
34
- // };
35
- // },
36
- }),
37
- ],
38
- });
39
-
40
- function App() {
41
- const [currentTab, setCurrentTab] = useState<'home' | 'users' | 'posts'>('home');
42
-
43
- // Example tRPC usage
44
- const { data: helloData, isLoading: helloLoading, error: helloError } = trpc.hello.useQuery({ name: 'Mobile User' });
45
- const { data: usersData, isLoading: usersLoading } = trpc.users.getAll.useQuery();
46
- const { data: postsData, isLoading: postsLoading } = trpc.posts.getAll.useQuery();
47
-
48
- const renderHome = () => (
49
- <ScrollView style={{ flex: 1 }}>
50
- <View style={{ padding: 20 }}>
51
- {/* Welcome Section */}
52
- <View style={{ marginBottom: 32, alignItems: 'center' }}>
53
- <Text variant="h1" style={{ textAlign: 'center', marginBottom: 16 }}>
54
- Welcome to {{appName}}! 📱
55
- </Text>
56
- <Text variant="body" style={{ textAlign: 'center', marginBottom: 16, fontSize: 18 }}>
57
- A cross-platform mobile app built with React Native and the Idealyst Framework
58
- </Text>
59
-
60
- {/* tRPC Connection Test */}
61
- <View style={{
62
- padding: 16,
63
- backgroundColor: '#e3f2fd',
64
- borderRadius: 8,
65
- marginBottom: 24,
66
- width: '100%'
67
- }}>
68
- <Text variant="h3" style={{ marginBottom: 8, textAlign: 'center' }}>🔗 API Connection</Text>
69
- {helloLoading && <Text style={{ textAlign: 'center' }}>Testing connection...</Text>}
70
- {helloError && <Text style={{ color: 'red', textAlign: 'center' }}>Error: {helloError.message}</Text>}
71
- {helloData && <Text style={{ color: 'green', textAlign: 'center' }}>✅ {helloData.greeting}</Text>}
72
- </View>
73
- </View>
74
-
75
- {/* Features Overview */}
76
- <View style={{ marginBottom: 32 }}>
77
- <Text variant="h2" style={{ marginBottom: 16, textAlign: 'center' }}>🏗️ What's Included</Text>
78
- <FeatureCard
79
- icon="🔗"
80
- title="Full Integration"
81
- description="Connected to your database and API with end-to-end type safety"
82
- />
83
- <FeatureCard
84
- icon="📦"
85
- title="Shared Components"
86
- description="Cross-platform UI components that work on web and mobile"
87
- />
88
- <FeatureCard
89
- icon="🎨"
90
- title="Idealyst Design"
91
- description="Beautiful, consistent styling with the Idealyst component library"
92
- />
93
- <FeatureCard
94
- icon="⚡"
95
- title="Real-time Updates"
96
- description="tRPC provides instant synchronization with your backend"
97
- />
98
- </View>
99
-
100
- {/* Quick Data Preview */}
101
- <View style={{ marginBottom: 32 }}>
102
- <Text variant="h2" style={{ marginBottom: 16, textAlign: 'center' }}>📊 Live Data</Text>
103
-
104
- {/* Users Preview */}
105
- <View style={{ marginBottom: 20 }}>
106
- <Text variant="h3" style={{ marginBottom: 12 }}>👥 Users ({usersLoading ? '...' : usersData?.length || DEMO_USERS.length})</Text>
107
- {usersLoading ? (
108
- <LoadingSpinner message="Loading users..." />
109
- ) : (
110
- <View>
111
- {(usersData || DEMO_USERS.slice(0, 2)).map((user: User) => (
112
- <UserCard
113
- key={user.id}
114
- user={user}
115
- showBio={false}
116
- onPress={() => console.log('View profile:', user.name)}
117
- />
118
- ))}
119
- </View>
120
- )}
121
- </View>
122
-
123
- {/* Posts Preview */}
124
- <View style={{ marginBottom: 20 }}>
125
- <Text variant="h3" style={{ marginBottom: 12 }}>📝 Recent Posts ({postsLoading ? '...' : postsData?.length || DEMO_POSTS.length})</Text>
126
- {postsLoading ? (
127
- <LoadingSpinner message="Loading posts..." />
128
- ) : (
129
- <View>
130
- {(postsData || DEMO_POSTS.slice(0, 1)).map((post: Post) => {
131
- const author = DEMO_USERS.find(u => u.id === post.authorId);
132
- return (
133
- <PostCard
134
- key={post.id}
135
- post={post}
136
- author={author}
137
- onPress={() => console.log('Read post:', post.title)}
138
- onLike={() => console.log('Like post:', post.title)}
139
- />
140
- );
141
- })}
142
- </View>
143
- )}
144
- </View>
145
- </View>
146
-
147
- {/* Development Info */}
148
- <View style={{
149
- padding: 20,
150
- backgroundColor: '#f8f9fa',
151
- borderRadius: 8,
152
- marginBottom: 24
153
- }}>
154
- <Text variant="h3" style={{ marginBottom: 12, textAlign: 'center' }}>🚀 Development</Text>
155
- <Text variant="body" style={{ textAlign: 'center', marginBottom: 12 }}>
156
- This app is part of your full-stack workspace. Make changes to see them reflected instantly!
157
- </Text>
158
- <Text variant="caption" style={{ textAlign: 'center', fontStyle: 'italic' }}>
159
- Edit packages/mobile/src/App.tsx to customize this screen
160
- </Text>
161
- </View>
162
- </View>
163
- </ScrollView>
164
- );
165
-
166
- const renderUsers = () => {
167
- const { data: users, isLoading, error } = trpc.users.getAll.useQuery();
168
-
169
- if (isLoading) return <LoadingSpinner message="Loading users..." />;
170
- if (error) return <ErrorMessage message={error.message} />;
171
-
172
- const allUsers = users || DEMO_USERS;
173
-
174
- return (
175
- <ScrollView style={{ flex: 1, padding: 20 }}>
176
- <Text variant="h1" style={{ marginBottom: 20, textAlign: 'center' }}>👥 All Users ({allUsers.length})</Text>
177
- <View>
178
- {allUsers.map((user: User) => (
179
- <UserCard
180
- key={user.id}
181
- user={user}
182
- showBio={true}
183
- onPress={() => console.log('View profile:', user.name)}
184
- />
185
- ))}
186
- </View>
187
- </ScrollView>
188
- );
189
- };
190
-
191
- const renderPosts = () => {
192
- const { data: posts, isLoading, error } = trpc.posts.getAll.useQuery();
193
-
194
- if (isLoading) return <LoadingSpinner message="Loading posts..." />;
195
- if (error) return <ErrorMessage message={error.message} />;
196
-
197
- const allPosts = posts || DEMO_POSTS;
198
-
199
- return (
200
- <ScrollView style={{ flex: 1, padding: 20 }}>
201
- <Text variant="h1" style={{ marginBottom: 20, textAlign: 'center' }}>📝 All Posts ({allPosts.length})</Text>
202
- <View>
203
- {allPosts.map((post: Post) => {
204
- const author = DEMO_USERS.find(u => u.id === post.authorId);
205
- return (
206
- <PostCard
207
- key={post.id}
208
- post={post}
209
- author={author}
210
- showFullContent={false}
211
- onPress={() => console.log('Read post:', post.title)}
212
- onLike={() => console.log('Like post:', post.title)}
213
- />
214
- );
215
- })}
216
- </View>
217
- </ScrollView>
218
- );
219
- };
220
-
221
- const renderTabBar = () => (
222
- <View style={{
223
- flexDirection: 'row',
224
- backgroundColor: '#f8f9fa',
225
- borderTopWidth: 1,
226
- borderTopColor: '#e9ecef',
227
- paddingVertical: 10
228
- }}>
229
- <TabButton
230
- title="Home"
231
- icon="🏠"
232
- active={currentTab === 'home'}
233
- onPress={() => setCurrentTab('home')}
234
- />
235
- <TabButton
236
- title="Users"
237
- icon="👥"
238
- active={currentTab === 'users'}
239
- onPress={() => setCurrentTab('users')}
240
- />
241
- <TabButton
242
- title="Posts"
243
- icon="📝"
244
- active={currentTab === 'posts'}
245
- onPress={() => setCurrentTab('posts')}
246
- />
247
- </View>
248
- );
249
-
250
- return (
251
- <trpc.Provider client={trpcClient} queryClient={queryClient}>
252
- <QueryClientProvider client={queryClient}>
253
- <Screen>
254
- <View style={{ flex: 1 }}>
255
- {currentTab === 'home' && renderHome()}
256
- {currentTab === 'users' && renderUsers()}
257
- {currentTab === 'posts' && renderPosts()}
258
- {renderTabBar()}
259
- </View>
260
- </Screen>
261
- </QueryClientProvider>
262
- </trpc.Provider>
263
- );
264
- }
265
-
266
- export default App;
@@ -1,43 +0,0 @@
1
- const typescript = require('rollup-plugin-typescript2');
2
-
3
- module.exports = {
4
- input: 'src/index.ts',
5
- output: [
6
- {
7
- file: 'dist/index.js',
8
- format: 'cjs',
9
- exports: 'named',
10
- sourcemap: true,
11
- },
12
- {
13
- file: 'dist/index.esm.js',
14
- format: 'esm',
15
- exports: 'named',
16
- sourcemap: true,
17
- },
18
- ],
19
- plugins: [
20
- typescript({
21
- typescript: require('typescript'),
22
- tsconfig: './tsconfig.json',
23
- exclude: ['**/*.test.ts', '**/*.test.tsx', '**/*.native.ts', '**/*.native.tsx'],
24
- declaration: true,
25
- declarationDir: 'dist',
26
- rootDir: 'src',
27
- clean: true,
28
- }),
29
- ],
30
- external: [
31
- 'react',
32
- 'react-dom',
33
- 'react-native',
34
- 'react-native-unistyles',
35
- '@react-native/normalize-colors',
36
- 'react-native-edge-to-edge',
37
- 'react-native-nitro-modules',
38
- '@react-native-vector-icons/common',
39
- '@react-native-vector-icons/material-design-icons',
40
- '@mdi/js',
41
- '@mdi/react',
42
- ],
43
- };
@@ -1,148 +0,0 @@
1
- import { z } from 'zod';
2
-
3
- // User related schemas and types
4
- export const UserSchema = z.object({
5
- id: z.string(),
6
- email: z.string().email(),
7
- name: z.string().nullable(),
8
- avatar: z.string().url().nullable(),
9
- bio: z.string().nullable(),
10
- location: z.string().nullable(),
11
- website: z.string().url().nullable(),
12
- createdAt: z.date(),
13
- updatedAt: z.date(),
14
- });
15
-
16
- export const CreateUserSchema = z.object({
17
- email: z.string().email(),
18
- name: z.string().min(1, 'Name is required'),
19
- avatar: z.string().url().optional(),
20
- bio: z.string().optional(),
21
- location: z.string().optional(),
22
- website: z.string().url().optional(),
23
- });
24
-
25
- export const UpdateUserSchema = CreateUserSchema.partial();
26
-
27
- // Post related schemas and types
28
- export const PostSchema = z.object({
29
- id: z.string(),
30
- title: z.string(),
31
- content: z.string(),
32
- excerpt: z.string().nullable(),
33
- published: z.boolean(),
34
- tags: z.array(z.string()),
35
- authorId: z.string(),
36
- views: z.number(),
37
- likes: z.number(),
38
- createdAt: z.date(),
39
- updatedAt: z.date(),
40
- });
41
-
42
- export const CreatePostSchema = z.object({
43
- title: z.string().min(1, 'Title is required'),
44
- content: z.string().min(1, 'Content is required'),
45
- excerpt: z.string().optional(),
46
- published: z.boolean().default(false),
47
- tags: z.array(z.string()).default([]),
48
- });
49
-
50
- export const UpdatePostSchema = CreatePostSchema.partial();
51
-
52
- // Comment related schemas and types
53
- export const CommentSchema = z.object({
54
- id: z.string(),
55
- content: z.string(),
56
- authorId: z.string(),
57
- postId: z.string(),
58
- parentId: z.string().nullable(),
59
- createdAt: z.date(),
60
- updatedAt: z.date(),
61
- });
62
-
63
- export const CreateCommentSchema = z.object({
64
- content: z.string().min(1, 'Comment cannot be empty'),
65
- postId: z.string(),
66
- parentId: z.string().optional(),
67
- });
68
-
69
- // User settings schemas and types
70
- export const UserSettingsSchema = z.object({
71
- id: z.string(),
72
- theme: z.enum(['light', 'dark', 'auto']),
73
- notifications: z.boolean(),
74
- emailUpdates: z.boolean(),
75
- publicProfile: z.boolean(),
76
- userId: z.string(),
77
- createdAt: z.date(),
78
- updatedAt: z.date(),
79
- });
80
-
81
- export const UpdateUserSettingsSchema = z.object({
82
- theme: z.enum(['light', 'dark', 'auto']).optional(),
83
- notifications: z.boolean().optional(),
84
- emailUpdates: z.boolean().optional(),
85
- publicProfile: z.boolean().optional(),
86
- });
87
-
88
- // Inferred TypeScript types
89
- export type User = z.infer<typeof UserSchema>;
90
- export type CreateUser = z.infer<typeof CreateUserSchema>;
91
- export type UpdateUser = z.infer<typeof UpdateUserSchema>;
92
-
93
- export type Post = z.infer<typeof PostSchema>;
94
- export type CreatePost = z.infer<typeof CreatePostSchema>;
95
- export type UpdatePost = z.infer<typeof UpdatePostSchema>;
96
-
97
- export type Comment = z.infer<typeof CommentSchema>;
98
- export type CreateComment = z.infer<typeof CreateCommentSchema>;
99
-
100
- export type UserSettings = z.infer<typeof UserSettingsSchema>;
101
- export type UpdateUserSettings = z.infer<typeof UpdateUserSettingsSchema>;
102
-
103
- // Extended types with relations for UI components
104
- export type UserWithPosts = User & {
105
- posts: Post[];
106
- settings?: UserSettings;
107
- };
108
-
109
- export type PostWithAuthor = Post & {
110
- author: User;
111
- comments: CommentWithAuthor[];
112
- };
113
-
114
- export type CommentWithAuthor = Comment & {
115
- author: User;
116
- children?: CommentWithAuthor[];
117
- };
118
-
119
- // API Response types
120
- export type ApiResponse<T> = {
121
- data: T;
122
- success: boolean;
123
- message?: string;
124
- };
125
-
126
- export type PaginatedResponse<T> = ApiResponse<{
127
- items: T[];
128
- total: number;
129
- page: number;
130
- pageSize: number;
131
- hasMore: boolean;
132
- }>;
133
-
134
- // Common utility types
135
- export type Theme = 'light' | 'dark' | 'auto';
136
-
137
- export interface LoadingState {
138
- isLoading: boolean;
139
- error?: string;
140
- }
141
-
142
- export interface PaginationParams {
143
- page?: number;
144
- pageSize?: number;
145
- sortBy?: string;
146
- sortOrder?: 'asc' | 'desc';
147
- search?: string;
148
- }