@idealyst/cli 1.2.31 → 1.2.33

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 (38) hide show
  1. package/dist/constants.js +5 -1
  2. package/dist/constants.js.map +1 -1
  3. package/dist/generators/core/shared.js +382 -4
  4. package/dist/generators/core/shared.js.map +1 -1
  5. package/dist/generators/extensions/graphql.js +112 -26
  6. package/dist/generators/extensions/graphql.js.map +1 -1
  7. package/dist/generators/extensions/prisma.js +105 -16
  8. package/dist/generators/extensions/prisma.js.map +1 -1
  9. package/dist/generators/extensions/trpc.js +137 -41
  10. package/dist/generators/extensions/trpc.js.map +1 -1
  11. package/dist/templates/core/api/src-graphql/builder.ts +25 -0
  12. package/dist/templates/core/api/src-graphql/schema.ts +217 -0
  13. package/dist/templates/core/api/src-trpc/context.ts +15 -0
  14. package/dist/templates/core/api/src-trpc/index.ts +6 -0
  15. package/dist/templates/core/api/src-trpc/lib/database.ts +4 -0
  16. package/dist/templates/core/api/src-trpc/router/index.ts +187 -0
  17. package/dist/templates/core/api/src-trpc/server.ts +63 -0
  18. package/dist/templates/core/api/src-trpc/trpc.ts +20 -0
  19. package/dist/templates/core/database/schema.prisma +22 -0
  20. package/dist/templates/core/shared/src/index.ts +1 -1
  21. package/dist/templates/core/shared/src-components/App.tsx +51 -0
  22. package/dist/templates/core/shared/src-graphql/client.ts +70 -0
  23. package/dist/templates/core/shared/{src/navigation → src-navigation}/AppRouter.tsx +34 -0
  24. package/dist/templates/core/shared/src-screens-graphql/GraphQLDemoScreen.tsx +354 -0
  25. package/dist/templates/core/shared/src-screens-trpc/TRPCDemoScreen.tsx +432 -0
  26. package/dist/templates/core/shared/src-trpc/client.ts +44 -0
  27. package/dist/types/constants.d.ts +9 -5
  28. package/package.json +1 -1
  29. package/dist/templates/core/shared/src/components/App.tsx +0 -13
  30. package/dist/templates/core/shared/src/screens/index.ts +0 -4
  31. /package/dist/templates/core/shared/src/{styles.ts → theme.ts} +0 -0
  32. /package/dist/templates/core/shared/{src/components → src-components}/index.ts +0 -0
  33. /package/dist/templates/core/shared/{src/layouts → src-layouts}/AppLayout.tsx +0 -0
  34. /package/dist/templates/core/shared/{src/navigation → src-navigation}/index.ts +0 -0
  35. /package/dist/templates/core/shared/{src/screens → src-screens}/ExploreScreen.tsx +0 -0
  36. /package/dist/templates/core/shared/{src/screens → src-screens}/HomeScreen.tsx +0 -0
  37. /package/dist/templates/core/shared/{src/screens → src-screens}/ProfileScreen.tsx +0 -0
  38. /package/dist/templates/core/shared/{src/screens → src-screens}/SettingsScreen.tsx +0 -0
@@ -7,6 +7,8 @@ import { HomeScreen } from '../screens/HomeScreen';
7
7
  import { ExploreScreen } from '../screens/ExploreScreen';
8
8
  import { ProfileScreen } from '../screens/ProfileScreen';
9
9
  import { SettingsScreen } from '../screens/SettingsScreen';
10
+ import { TRPCDemoScreen } from '../screens/TRPCDemoScreen';
11
+ import { GraphQLDemoScreen } from '../screens/GraphQLDemoScreen';
10
12
 
11
13
  // Custom Layouts
12
14
  import { AppTabLayout, AppStackLayout } from '../layouts/AppLayout';
@@ -68,6 +70,38 @@ const MainTabNavigator: NavigatorParam = {
68
70
  ),
69
71
  } as TabBarScreenOptions,
70
72
  },
73
+ {
74
+ path: 'trpc',
75
+ type: 'screen',
76
+ component: TRPCDemoScreen,
77
+ options: {
78
+ title: 'tRPC',
79
+ tabBarLabel: 'tRPC',
80
+ tabBarIcon: ({ focused, color, size }) => (
81
+ <Icon
82
+ name={focused ? 'api' : 'api'}
83
+ color={color}
84
+ size={size}
85
+ />
86
+ ),
87
+ } as TabBarScreenOptions,
88
+ },
89
+ {
90
+ path: 'graphql',
91
+ type: 'screen',
92
+ component: GraphQLDemoScreen,
93
+ options: {
94
+ title: 'GraphQL',
95
+ tabBarLabel: 'GraphQL',
96
+ tabBarIcon: ({ focused, color, size }) => (
97
+ <Icon
98
+ name={focused ? 'graphql' : 'graphql'}
99
+ color={color}
100
+ size={size}
101
+ />
102
+ ),
103
+ } as TabBarScreenOptions,
104
+ },
71
105
  ],
72
106
  };
73
107
 
@@ -0,0 +1,354 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ Screen,
4
+ View,
5
+ Text,
6
+ Card,
7
+ Button,
8
+ Icon,
9
+ Badge,
10
+ ActivityIndicator,
11
+ Alert,
12
+ TextInput,
13
+ } from '@idealyst/components';
14
+ import { useQuery, useMutation, gql } from '../graphql/client';
15
+
16
+ // GraphQL Queries
17
+ const GET_ITEMS = gql`
18
+ query GetItems {
19
+ items {
20
+ id
21
+ title
22
+ description
23
+ completed
24
+ createdAt
25
+ }
26
+ }
27
+ `;
28
+
29
+ const GET_ITEM_STATS = gql`
30
+ query GetItemStats {
31
+ itemStats {
32
+ total
33
+ completed
34
+ pending
35
+ }
36
+ }
37
+ `;
38
+
39
+ // GraphQL Mutations
40
+ const CREATE_ITEM = gql`
41
+ mutation CreateItem($input: CreateItemInput!) {
42
+ createItem(input: $input) {
43
+ id
44
+ title
45
+ description
46
+ completed
47
+ }
48
+ }
49
+ `;
50
+
51
+ const TOGGLE_ITEM = gql`
52
+ mutation ToggleItem($id: String!) {
53
+ toggleItem(id: $id) {
54
+ id
55
+ completed
56
+ }
57
+ }
58
+ `;
59
+
60
+ const DELETE_ITEM = gql`
61
+ mutation DeleteItem($id: String!) {
62
+ deleteItem(id: $id) {
63
+ id
64
+ }
65
+ }
66
+ `;
67
+
68
+ interface Item {
69
+ id: string;
70
+ title: string;
71
+ description: string | null;
72
+ completed: boolean;
73
+ createdAt: string;
74
+ }
75
+
76
+ interface ItemStats {
77
+ total: number;
78
+ completed: number;
79
+ pending: number;
80
+ }
81
+
82
+ export const GraphQLDemoScreen: React.FC = () => {
83
+ const [newItemTitle, setNewItemTitle] = useState('');
84
+
85
+ // Queries
86
+ const {
87
+ data: itemsData,
88
+ loading: itemsLoading,
89
+ error: itemsError,
90
+ refetch: refetchItems,
91
+ } = useQuery<{ items: Item[] }>(GET_ITEMS);
92
+
93
+ const {
94
+ data: statsData,
95
+ loading: statsLoading,
96
+ error: statsError,
97
+ refetch: refetchStats,
98
+ } = useQuery<{ itemStats: ItemStats }>(GET_ITEM_STATS);
99
+
100
+ // Mutations
101
+ const [createItem, { loading: createLoading }] = useMutation(CREATE_ITEM, {
102
+ onCompleted: () => {
103
+ refetchItems();
104
+ refetchStats();
105
+ setNewItemTitle('');
106
+ },
107
+ });
108
+
109
+ const [toggleItem] = useMutation(TOGGLE_ITEM, {
110
+ onCompleted: () => {
111
+ refetchItems();
112
+ refetchStats();
113
+ },
114
+ });
115
+
116
+ const [deleteItem] = useMutation(DELETE_ITEM, {
117
+ onCompleted: () => {
118
+ refetchItems();
119
+ refetchStats();
120
+ },
121
+ });
122
+
123
+ const isLoading = itemsLoading || statsLoading;
124
+ const hasError = itemsError || statsError;
125
+
126
+ const handleCreateItem = () => {
127
+ if (newItemTitle.trim()) {
128
+ createItem({ variables: { input: { title: newItemTitle.trim() } } });
129
+ }
130
+ };
131
+
132
+ return (
133
+ <Screen background="primary" padding="lg" scrollable>
134
+ <View gap="lg">
135
+ {/* Header */}
136
+ <View gap="sm">
137
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
138
+ <Icon name="graphql" size={28} intent="danger" />
139
+ <Text typography="h3">GraphQL Demo</Text>
140
+ </View>
141
+ <Text color="secondary">
142
+ Flexible queries and mutations with Apollo Client
143
+ </Text>
144
+ </View>
145
+
146
+ {/* Loading State */}
147
+ {isLoading && (
148
+ <Card type="outlined" padding="lg">
149
+ <View style={{ alignItems: 'center', gap: 12 }}>
150
+ <ActivityIndicator size="lg" intent="danger" />
151
+ <Text color="secondary">Fetching GraphQL data...</Text>
152
+ </View>
153
+ </Card>
154
+ )}
155
+
156
+ {/* Error State */}
157
+ {hasError && (
158
+ <Alert intent="danger" title="GraphQL Error">
159
+ Could not fetch data. Make sure the API server is running and the
160
+ database is set up.
161
+ </Alert>
162
+ )}
163
+
164
+ {/* Stats */}
165
+ {statsData?.itemStats && (
166
+ <Card type="elevated" padding="md" gap="md">
167
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
168
+ <Icon name="chart-pie" size={20} intent="danger" />
169
+ <Text weight="semibold">Item Statistics</Text>
170
+ </View>
171
+
172
+ <View style={{ flexDirection: 'row', gap: 12 }}>
173
+ <View
174
+ background="secondary"
175
+ padding="md"
176
+ radius="md"
177
+ style={{ flex: 1, alignItems: 'center' }}
178
+ >
179
+ <Text typography="h4">{statsData.itemStats.total}</Text>
180
+ <Text typography="caption" color="secondary">
181
+ Total
182
+ </Text>
183
+ </View>
184
+ <View
185
+ background="secondary"
186
+ padding="md"
187
+ radius="md"
188
+ style={{ flex: 1, alignItems: 'center' }}
189
+ >
190
+ <Text typography="h4" intent="success">
191
+ {statsData.itemStats.completed}
192
+ </Text>
193
+ <Text typography="caption" color="secondary">
194
+ Completed
195
+ </Text>
196
+ </View>
197
+ <View
198
+ background="secondary"
199
+ padding="md"
200
+ radius="md"
201
+ style={{ flex: 1, alignItems: 'center' }}
202
+ >
203
+ <Text typography="h4" intent="warning">
204
+ {statsData.itemStats.pending}
205
+ </Text>
206
+ <Text typography="caption" color="secondary">
207
+ Pending
208
+ </Text>
209
+ </View>
210
+ </View>
211
+
212
+ <View background="secondary" padding="sm" radius="sm">
213
+ <Text typography="caption" style={{ fontFamily: 'monospace' }}>
214
+ {`query { itemStats { total completed pending } }`}
215
+ </Text>
216
+ </View>
217
+ </Card>
218
+ )}
219
+
220
+ {/* Create Item */}
221
+ <Card type="elevated" padding="md" gap="md">
222
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
223
+ <Icon name="plus-circle" size={20} intent="success" />
224
+ <Text weight="semibold">Create Item</Text>
225
+ </View>
226
+
227
+ <TextInput
228
+ placeholder="Enter item title..."
229
+ value={newItemTitle}
230
+ onChangeText={setNewItemTitle}
231
+ />
232
+
233
+ <Button
234
+ intent="danger"
235
+ leftIcon="plus"
236
+ onPress={handleCreateItem}
237
+ disabled={!newItemTitle.trim() || createLoading}
238
+ >
239
+ {createLoading ? 'Creating...' : 'Add Item (GraphQL)'}
240
+ </Button>
241
+
242
+ <View background="secondary" padding="sm" radius="sm">
243
+ <Text typography="caption" style={{ fontFamily: 'monospace' }}>
244
+ {`mutation { createItem(input: { title: "..." }) { id } }`}
245
+ </Text>
246
+ </View>
247
+ </Card>
248
+
249
+ {/* Items List */}
250
+ {itemsData?.items && itemsData.items.length > 0 && (
251
+ <Card type="outlined" padding="md" gap="md">
252
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
253
+ <Icon name="format-list-checks" size={20} intent="danger" />
254
+ <Text weight="semibold">Items</Text>
255
+ <Badge intent="danger" size="sm">
256
+ {itemsData.items.length}
257
+ </Badge>
258
+ </View>
259
+
260
+ <View gap="sm">
261
+ {itemsData.items.map((item) => (
262
+ <View
263
+ key={item.id}
264
+ background="secondary"
265
+ padding="sm"
266
+ radius="sm"
267
+ style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}
268
+ >
269
+ <Button
270
+ size="sm"
271
+ intent={item.completed ? 'success' : 'neutral'}
272
+ leftIcon={item.completed ? 'check-circle' : 'circle-outline'}
273
+ onPress={() => toggleItem({ variables: { id: item.id } })}
274
+ />
275
+ <View style={{ flex: 1 }}>
276
+ <Text
277
+ weight="medium"
278
+ style={{
279
+ textDecorationLine: item.completed ? 'line-through' : 'none',
280
+ opacity: item.completed ? 0.6 : 1,
281
+ }}
282
+ >
283
+ {item.title}
284
+ </Text>
285
+ {item.description && (
286
+ <Text typography="caption" color="secondary">
287
+ {item.description}
288
+ </Text>
289
+ )}
290
+ </View>
291
+ <Button
292
+ size="sm"
293
+ intent="danger"
294
+ leftIcon="delete"
295
+ onPress={() => deleteItem({ variables: { id: item.id } })}
296
+ />
297
+ </View>
298
+ ))}
299
+ </View>
300
+ </Card>
301
+ )}
302
+
303
+ {/* Empty State */}
304
+ {itemsData?.items && itemsData.items.length === 0 && (
305
+ <Card type="outlined" padding="lg">
306
+ <View style={{ alignItems: 'center', gap: 8 }}>
307
+ <Icon name="inbox-outline" size={48} textColor="secondary" />
308
+ <Text color="secondary">No items yet. Create one above!</Text>
309
+ </View>
310
+ </Card>
311
+ )}
312
+
313
+ {/* Refetch Button */}
314
+ <Button
315
+ intent="danger"
316
+ leftIcon="refresh"
317
+ onPress={() => {
318
+ refetchItems();
319
+ refetchStats();
320
+ }}
321
+ >
322
+ Refetch All Queries
323
+ </Button>
324
+
325
+ {/* GraphQL Benefits */}
326
+ <Card type="elevated" padding="md" gap="sm">
327
+ <Text weight="semibold">GraphQL Benefits</Text>
328
+ <View gap="xs">
329
+ <View style={{ flexDirection: 'row', gap: 8 }}>
330
+ <Icon name="check-circle" size={16} intent="success" />
331
+ <Text typography="caption">Request only the fields you need</Text>
332
+ </View>
333
+ <View style={{ flexDirection: 'row', gap: 8 }}>
334
+ <Icon name="check-circle" size={16} intent="success" />
335
+ <Text typography="caption">Single endpoint for all operations</Text>
336
+ </View>
337
+ <View style={{ flexDirection: 'row', gap: 8 }}>
338
+ <Icon name="check-circle" size={16} intent="success" />
339
+ <Text typography="caption">
340
+ Built-in GraphiQL playground at /graphql
341
+ </Text>
342
+ </View>
343
+ <View style={{ flexDirection: 'row', gap: 8 }}>
344
+ <Icon name="check-circle" size={16} intent="success" />
345
+ <Text typography="caption">Strong typing with schema</Text>
346
+ </View>
347
+ </View>
348
+ </Card>
349
+ </View>
350
+ </Screen>
351
+ );
352
+ };
353
+
354
+ export default GraphQLDemoScreen;