@digilogiclabs/create-saas-app 1.17.1 → 1.18.0

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 (45) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cli/commands/create.d.ts.map +1 -1
  4. package/dist/cli/commands/create.js +6 -2
  5. package/dist/cli/commands/create.js.map +1 -1
  6. package/dist/cli/index.js +1 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/generators/template-generator.d.ts.map +1 -1
  9. package/dist/generators/template-generator.js +13 -7
  10. package/dist/generators/template-generator.js.map +1 -1
  11. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
  12. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
  13. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
  14. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
  15. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
  16. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
  17. package/dist/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
  18. package/dist/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
  19. package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
  20. package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
  21. package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
  22. package/dist/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
  23. package/dist/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
  24. package/dist/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
  25. package/dist/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
  26. package/dist/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
  27. package/dist/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
  28. package/package.json +1 -1
  29. package/src/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
  30. package/src/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
  31. package/src/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
  32. package/src/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
  33. package/src/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
  34. package/src/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
  35. package/src/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
  36. package/src/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
  37. package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
  38. package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
  39. package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
  40. package/src/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
  41. package/src/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
  42. package/src/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
  43. package/src/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
  44. package/src/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
  45. package/src/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
@@ -0,0 +1,346 @@
1
+ import { useState, useEffect, useCallback, useRef } from 'react';
2
+ import { AppState } from 'react-native';
3
+ import AsyncStorage from '@react-native-async-storage/async-storage';
4
+ import NetInfo from '@react-native-community/netinfo';
5
+ import { RAGSystem } from '@digilogiclabs/saas-factory-ai';
6
+ import type {
7
+ RAGQuery,
8
+ RAGResponse,
9
+ RAGDocument,
10
+ RAGSearchResult,
11
+ RAGDocumentSchema
12
+ } from '@digilogiclabs/saas-factory-ai-types';
13
+ import { getRAGConfigForDomain, mobileRAGOptions } from '../lib/rag/config';
14
+
15
+ interface UseRAGSystemOptions {
16
+ domain?: string;
17
+ enableOffline?: boolean;
18
+ autoSync?: boolean;
19
+ cacheResults?: boolean;
20
+ }
21
+
22
+ interface RAGState {
23
+ isInitialized: boolean;
24
+ isOnline: boolean;
25
+ isLoading: boolean;
26
+ lastSyncAt: Date | null;
27
+ cachedQueries: number;
28
+ error: string | null;
29
+ }
30
+
31
+ export function useRAGSystem<TSchema extends RAGDocumentSchema>(
32
+ options: UseRAGSystemOptions = {}
33
+ ) {
34
+ const {
35
+ domain = 'generic',
36
+ enableOffline = true,
37
+ autoSync = true,
38
+ cacheResults = true
39
+ } = options;
40
+
41
+ const [ragSystem, setRAGSystem] = useState<RAGSystem<TSchema> | null>(null);
42
+ const [state, setState] = useState<RAGState>({
43
+ isInitialized: false,
44
+ isOnline: true,
45
+ isLoading: false,
46
+ lastSyncAt: null,
47
+ cachedQueries: 0,
48
+ error: null
49
+ });
50
+
51
+ const [recentQueries, setRecentQueries] = useState<RAGQuery[]>([]);
52
+ const [cachedResponses, setCachedResponses] = useState<Map<string, RAGResponse>>(new Map());
53
+ const offlineQueueRef = useRef<RAGQuery[]>([]);
54
+
55
+ // Initialize RAG system
56
+ useEffect(() => {
57
+ const initRAG = async () => {
58
+ try {
59
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
60
+
61
+ const config = getRAGConfigForDomain(domain);
62
+ const system = new RAGSystem<TSchema>(config);
63
+
64
+ await system.initialize();
65
+ setRAGSystem(system);
66
+
67
+ // Load cached data
68
+ if (enableOffline) {
69
+ await loadCachedData();
70
+ }
71
+
72
+ setState(prev => ({
73
+ ...prev,
74
+ isInitialized: true,
75
+ isLoading: false,
76
+ lastSyncAt: new Date()
77
+ }));
78
+
79
+ } catch (error) {
80
+ console.error('RAG initialization error:', error);
81
+ setState(prev => ({
82
+ ...prev,
83
+ error: error instanceof Error ? error.message : 'Initialization failed',
84
+ isLoading: false
85
+ }));
86
+ }
87
+ };
88
+
89
+ initRAG();
90
+ }, [domain, enableOffline]);
91
+
92
+ // Network state monitoring
93
+ useEffect(() => {
94
+ const unsubscribe = NetInfo.addEventListener(state => {
95
+ setState(prev => ({ ...prev, isOnline: state.isConnected ?? false }));
96
+
97
+ // Process offline queue when back online
98
+ if (state.isConnected && offlineQueueRef.current.length > 0) {
99
+ processOfflineQueue();
100
+ }
101
+ });
102
+
103
+ return unsubscribe;
104
+ }, []);
105
+
106
+ // App state handling for sync
107
+ useEffect(() => {
108
+ if (!autoSync) return;
109
+
110
+ const handleAppStateChange = (nextAppState: string) => {
111
+ if (nextAppState === 'active' && ragSystem && state.isOnline) {
112
+ syncKnowledgeBase();
113
+ }
114
+ };
115
+
116
+ const subscription = AppState.addEventListener('change', handleAppStateChange);
117
+ return () => subscription?.remove();
118
+ }, [ragSystem, state.isOnline, autoSync]);
119
+
120
+ // Query function with caching and offline support
121
+ const query = useCallback(async (queryText: string, options?: {
122
+ category?: string;
123
+ maxResults?: number;
124
+ includeMetadata?: boolean;
125
+ }): Promise<RAGResponse> => {
126
+ if (!ragSystem) {
127
+ throw new Error('RAG system not initialized');
128
+ }
129
+
130
+ const ragQuery: RAGQuery = {
131
+ query: queryText,
132
+ category: options?.category,
133
+ maxResults: options?.maxResults || 5,
134
+ includeMetadata: options?.includeMetadata ?? true,
135
+ timestamp: new Date()
136
+ };
137
+
138
+ // Check cache first
139
+ const cacheKey = getCacheKey(ragQuery);
140
+ if (cacheResults && cachedResponses.has(cacheKey)) {
141
+ const cached = cachedResponses.get(cacheKey)!;
142
+ return { ...cached, fromCache: true };
143
+ }
144
+
145
+ // Handle offline mode
146
+ if (!state.isOnline && enableOffline) {
147
+ return handleOfflineQuery(ragQuery);
148
+ }
149
+
150
+ try {
151
+ setState(prev => ({ ...prev, isLoading: true }));
152
+
153
+ const response = await ragSystem.query(ragQuery);
154
+
155
+ // Cache successful responses
156
+ if (cacheResults && response.confidence > 0.5) {
157
+ const newCache = new Map(cachedResponses);
158
+ newCache.set(cacheKey, response);
159
+ setCachedResponses(newCache);
160
+
161
+ // Persist to local storage
162
+ await cacheResponseLocally(cacheKey, response);
163
+ }
164
+
165
+ // Update recent queries
166
+ setRecentQueries(prev => [ragQuery, ...prev.slice(0, 9)]);
167
+
168
+ setState(prev => ({ ...prev, isLoading: false }));
169
+ return response;
170
+
171
+ } catch (error) {
172
+ setState(prev => ({ ...prev, isLoading: false }));
173
+
174
+ if (enableOffline) {
175
+ return handleOfflineQuery(ragQuery);
176
+ }
177
+
178
+ throw error;
179
+ }
180
+ }, [ragSystem, state.isOnline, cacheResults, enableOffline, cachedResponses]);
181
+
182
+ // Search knowledge base
183
+ const searchKnowledge = useCallback(async (
184
+ searchText: string,
185
+ filters?: { category?: string; limit?: number }
186
+ ): Promise<RAGSearchResult[]> => {
187
+ if (!ragSystem) return [];
188
+
189
+ try {
190
+ return await ragSystem.searchDocuments(searchText, filters);
191
+ } catch (error) {
192
+ console.error('Knowledge search error:', error);
193
+ return [];
194
+ }
195
+ }, [ragSystem]);
196
+
197
+ // Add document to knowledge base
198
+ const addKnowledge = useCallback(async (
199
+ document: Omit<RAGDocument<TSchema>, 'id' | 'createdAt' | 'updatedAt'>
200
+ ): Promise<string | null> => {
201
+ if (!ragSystem || !state.isOnline) return null;
202
+
203
+ try {
204
+ return await ragSystem.addDocument(document as RAGDocument<TSchema>);
205
+ } catch (error) {
206
+ console.error('Add knowledge error:', error);
207
+ return null;
208
+ }
209
+ }, [ragSystem, state.isOnline]);
210
+
211
+ // Update document
212
+ const updateKnowledge = useCallback(async (
213
+ id: string,
214
+ updates: Partial<RAGDocument<TSchema>>
215
+ ): Promise<boolean> => {
216
+ if (!ragSystem || !state.isOnline) return false;
217
+
218
+ try {
219
+ await ragSystem.updateDocument(id, updates);
220
+ return true;
221
+ } catch (error) {
222
+ console.error('Update knowledge error:', error);
223
+ return false;
224
+ }
225
+ }, [ragSystem, state.isOnline]);
226
+
227
+ // Sync knowledge base
228
+ const syncKnowledgeBase = useCallback(async (): Promise<void> => {
229
+ if (!ragSystem || !state.isOnline) return;
230
+
231
+ try {
232
+ setState(prev => ({ ...prev, isLoading: true }));
233
+
234
+ // Implement incremental sync based on lastSyncAt
235
+ await ragSystem.sync(state.lastSyncAt);
236
+
237
+ setState(prev => ({
238
+ ...prev,
239
+ lastSyncAt: new Date(),
240
+ isLoading: false
241
+ }));
242
+ } catch (error) {
243
+ console.error('Sync error:', error);
244
+ setState(prev => ({ ...prev, isLoading: false }));
245
+ }
246
+ }, [ragSystem, state.isOnline, state.lastSyncAt]);
247
+
248
+ // Clear cache
249
+ const clearCache = useCallback(async () => {
250
+ setCachedResponses(new Map());
251
+ setRecentQueries([]);
252
+ await AsyncStorage.multiRemove(['rag_cache', 'rag_recent_queries']);
253
+ setState(prev => ({ ...prev, cachedQueries: 0 }));
254
+ }, []);
255
+
256
+ // Helper functions
257
+ const getCacheKey = (query: RAGQuery): string => {
258
+ return `${query.query}:${query.category || 'all'}:${query.maxResults}`;
259
+ };
260
+
261
+ const handleOfflineQuery = async (query: RAGQuery): Promise<RAGResponse> => {
262
+ // Add to offline queue
263
+ offlineQueueRef.current.push(query);
264
+
265
+ // Return fallback response
266
+ return {
267
+ query: query.query,
268
+ response: "I'm currently offline. Your query has been saved and I'll respond when connection is restored.",
269
+ sources: [],
270
+ confidence: 0,
271
+ metadata: { offline: true },
272
+ timestamp: new Date()
273
+ };
274
+ };
275
+
276
+ const processOfflineQueue = async () => {
277
+ if (!ragSystem || offlineQueueRef.current.length === 0) return;
278
+
279
+ const queue = [...offlineQueueRef.current];
280
+ offlineQueueRef.current = [];
281
+
282
+ for (const query of queue) {
283
+ try {
284
+ await ragSystem.query(query);
285
+ } catch (error) {
286
+ console.error('Offline queue processing error:', error);
287
+ // Re-add failed queries to queue
288
+ offlineQueueRef.current.push(query);
289
+ }
290
+ }
291
+ };
292
+
293
+ const loadCachedData = async () => {
294
+ try {
295
+ const [cacheData, recentData] = await AsyncStorage.multiGet([
296
+ 'rag_cache',
297
+ 'rag_recent_queries'
298
+ ]);
299
+
300
+ if (cacheData[1]) {
301
+ const cache = JSON.parse(cacheData[1]);
302
+ setCachedResponses(new Map(cache));
303
+ setState(prev => ({ ...prev, cachedQueries: cache.length }));
304
+ }
305
+
306
+ if (recentData[1]) {
307
+ const recent = JSON.parse(recentData[1]);
308
+ setRecentQueries(recent);
309
+ }
310
+ } catch (error) {
311
+ console.error('Cache loading error:', error);
312
+ }
313
+ };
314
+
315
+ const cacheResponseLocally = async (key: string, response: RAGResponse) => {
316
+ try {
317
+ const current = await AsyncStorage.getItem('rag_cache');
318
+ const cache = current ? JSON.parse(current) : {};
319
+ cache[key] = response;
320
+
321
+ await AsyncStorage.setItem('rag_cache', JSON.stringify(cache));
322
+ } catch (error) {
323
+ console.error('Cache storage error:', error);
324
+ }
325
+ };
326
+
327
+ return {
328
+ // State
329
+ ...state,
330
+ ragSystem,
331
+ recentQueries,
332
+ offlineQueueSize: offlineQueueRef.current.length,
333
+
334
+ // Actions
335
+ query,
336
+ searchKnowledge,
337
+ addKnowledge,
338
+ updateKnowledge,
339
+ syncKnowledgeBase,
340
+ clearCache,
341
+
342
+ // Utilities
343
+ isReady: state.isInitialized && !state.isLoading,
344
+ canQuery: state.isInitialized && (state.isOnline || enableOffline),
345
+ };
346
+ }
@@ -0,0 +1,180 @@
1
+ import {
2
+ createGenericRAGConfig,
3
+ createPlantCareRAGConfig,
4
+ createEcommerceRAGConfig,
5
+ createEducationRAGConfig
6
+ } from '@digilogiclabs/saas-factory-ai';
7
+ import type {
8
+ RAGConfig,
9
+ GenericRAGDocumentSchema,
10
+ PlantKnowledgeSchema,
11
+ EcommerceKnowledgeSchema,
12
+ EducationKnowledgeSchema
13
+ } from '@digilogiclabs/saas-factory-ai-types';
14
+ import Constants from 'expo-constants';
15
+
16
+ // Environment configuration
17
+ const supabaseConfig = {
18
+ url: Constants.expoConfig?.extra?.supabaseUrl || process.env.EXPO_PUBLIC_SUPABASE_URL,
19
+ anonKey: Constants.expoConfig?.extra?.supabaseAnonKey || process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY,
20
+ serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY, // Server-only for embeddings
21
+ };
22
+
23
+ const openAIKey = Constants.expoConfig?.extra?.openaiApiKey || process.env.EXPO_PUBLIC_OPENAI_API_KEY;
24
+
25
+ // RAG Configuration Templates
26
+ export const createRAGConfigs = () => {
27
+ const baseNamespace = '{{packageName}}';
28
+
29
+ return {
30
+ // Generic AI Assistant
31
+ generic: createGenericRAGConfig<GenericRAGDocumentSchema>(
32
+ baseNamespace,
33
+ supabaseConfig,
34
+ openAIKey,
35
+ {
36
+ retrieval: {
37
+ topK: 5,
38
+ confidenceThreshold: 0.75,
39
+ hybridSearchWeight: { vector: 0.7, text: 0.3 }
40
+ },
41
+ generation: {
42
+ systemPrompt: `You are an intelligent AI assistant for the ${baseNamespace} app.
43
+ Use the provided knowledge base to give accurate, helpful responses.
44
+ If information isn't in the knowledge base, say so clearly and provide general guidance.
45
+ Keep responses concise and actionable for mobile users.`,
46
+ temperature: 0.3,
47
+ maxTokens: 500,
48
+ },
49
+ mobile: {
50
+ caching: true,
51
+ offlineMode: true,
52
+ syncStrategy: 'incremental'
53
+ }
54
+ }
55
+ ),
56
+
57
+ // Plant Care Assistant
58
+ plantCare: createPlantCareRAGConfig(
59
+ `${baseNamespace}-plants`,
60
+ supabaseConfig,
61
+ openAIKey,
62
+ {
63
+ retrieval: {
64
+ topK: 4,
65
+ confidenceThreshold: 0.8,
66
+ hybridSearchWeight: { vector: 0.8, text: 0.2 }
67
+ },
68
+ generation: {
69
+ systemPrompt: `You are a botanical expert assistant helping users care for their plants.
70
+ Use the plant knowledge base to provide specific care instructions, diagnose issues, and suggest solutions.
71
+ Always consider the user's location, season, and plant type when giving advice.
72
+ Focus on practical, actionable guidance.`,
73
+ temperature: 0.2,
74
+ maxTokens: 400,
75
+ }
76
+ }
77
+ ),
78
+
79
+ // E-commerce Assistant
80
+ ecommerce: createEcommerceRAGConfig(
81
+ `${baseNamespace}-store`,
82
+ supabaseConfig,
83
+ openAIKey,
84
+ {
85
+ retrieval: {
86
+ topK: 6,
87
+ confidenceThreshold: 0.7,
88
+ hybridSearchWeight: { vector: 0.6, text: 0.4 }
89
+ },
90
+ generation: {
91
+ systemPrompt: `You are a helpful shopping assistant for the ${baseNamespace} store.
92
+ Help users find products, answer questions about specifications, pricing, and availability.
93
+ Provide personalized recommendations based on their needs and preferences.
94
+ Always mention stock status and current promotions if available.`,
95
+ temperature: 0.4,
96
+ maxTokens: 350,
97
+ }
98
+ }
99
+ ),
100
+
101
+ // Education Assistant
102
+ education: createEducationRAGConfig(
103
+ `${baseNamespace}-learning`,
104
+ supabaseConfig,
105
+ openAIKey,
106
+ {
107
+ retrieval: {
108
+ topK: 5,
109
+ confidenceThreshold: 0.8,
110
+ hybridSearchWeight: { vector: 0.75, text: 0.25 }
111
+ },
112
+ generation: {
113
+ systemPrompt: `You are an educational tutor assistant for the ${baseNamespace} learning platform.
114
+ Help students understand concepts, answer questions, and provide study guidance.
115
+ Adapt your explanations to the appropriate grade level and learning style.
116
+ Encourage critical thinking and provide examples when helpful.`,
117
+ temperature: 0.3,
118
+ maxTokens: 600,
119
+ }
120
+ }
121
+ )
122
+ };
123
+ };
124
+
125
+ // Default configuration selector
126
+ export const getRAGConfigForDomain = (domain: string): RAGConfig<any> => {
127
+ const configs = createRAGConfigs();
128
+
129
+ switch (domain.toLowerCase()) {
130
+ case 'plants':
131
+ case 'plant-care':
132
+ case 'gardening':
133
+ return configs.plantCare;
134
+
135
+ case 'store':
136
+ case 'shop':
137
+ case 'ecommerce':
138
+ case 'products':
139
+ return configs.ecommerce;
140
+
141
+ case 'education':
142
+ case 'learning':
143
+ case 'courses':
144
+ case 'study':
145
+ return configs.education;
146
+
147
+ default:
148
+ return configs.generic;
149
+ }
150
+ };
151
+
152
+ // Mobile-specific optimizations
153
+ export const mobileRAGOptions = {
154
+ // Cache frequently accessed documents locally
155
+ enableLocalCache: true,
156
+ maxCacheSize: 100, // Max cached documents
157
+
158
+ // Offline mode settings
159
+ offlineMode: {
160
+ enabled: true,
161
+ fallbackResponses: true,
162
+ queueQueries: true,
163
+ },
164
+
165
+ // Performance settings
166
+ performance: {
167
+ debounceMs: 300, // Debounce search queries
168
+ maxConcurrentRequests: 2,
169
+ timeout: 10000, // 10 second timeout
170
+ },
171
+
172
+ // Mobile UX settings
173
+ ui: {
174
+ showTypingIndicator: true,
175
+ showConfidenceScores: false, // Hide on mobile for simplicity
176
+ showSources: true,
177
+ maxDisplaySources: 3,
178
+ compactMode: true,
179
+ }
180
+ };
@@ -0,0 +1,113 @@
1
+ {
2
+ "name": "{{packageName}}",
3
+ "version": "1.0.0",
4
+ "description": "{{description}} - Mobile AI App with RAG Knowledge Base, UI, Auth, Payments, and AI Generation",
5
+ "main": "node_modules/expo/AppEntry.js",
6
+ "scripts": {
7
+ "start": "expo start",
8
+ "dev": "expo start --dev-client",
9
+ "android": "expo start --android",
10
+ "ios": "expo start --ios",
11
+ "web": "expo start --web",
12
+ "build": "eas build",
13
+ "build:android": "eas build --platform android",
14
+ "build:ios": "eas build --platform ios",
15
+ "preview": "eas build --profile preview",
16
+ "submit": "eas submit",
17
+ "test": "jest",
18
+ "lint": "expo lint",
19
+ "type-check": "tsc --noEmit",
20
+ "setup:rag": "node scripts/setup-rag.js",
21
+ "seed:knowledge": "node scripts/seed-knowledge.js",
22
+ "db:types": "supabase gen types --local > types/supabase.ts"
23
+ },
24
+ "dependencies": {
25
+ "expo": "~50.0.0",
26
+ "react": "18.2.0",
27
+ "react-native": "0.73.4",
28
+
29
+ "@expo/vector-icons": "^14.0.0",
30
+ "@expo/config-plugins": "~7.8.0",
31
+
32
+ "@react-navigation/native": "^6.1.9",
33
+ "@react-navigation/stack": "^6.3.20",
34
+ "@react-navigation/bottom-tabs": "^6.5.11",
35
+ "@react-navigation/drawer": "^6.6.6",
36
+ "react-native-screens": "~3.29.0",
37
+ "react-native-safe-area-context": "4.8.2",
38
+ "react-native-gesture-handler": "~2.14.0",
39
+ "react-native-reanimated": "~3.6.2",
40
+
41
+ "@digilogiclabs/saas-factory-ui": "^0.22.0",
42
+ "@digilogiclabs/saas-factory-auth": "^1.0.1",
43
+ "@digilogiclabs/saas-factory-payments": "^1.1.0",
44
+ "@digilogiclabs/saas-factory-ai": "^4.0.0",
45
+ "@digilogiclabs/saas-factory-ai-types": "^4.0.0",
46
+
47
+ "@supabase/supabase-js": "^2.39.0",
48
+ "@react-native-async-storage/async-storage": "1.21.0",
49
+
50
+ "@stripe/stripe-react-native": "0.37.2",
51
+
52
+ "expo-router": "~3.4.0",
53
+ "expo-font": "~11.10.0",
54
+ "expo-linking": "~6.2.2",
55
+ "expo-constants": "~15.4.0",
56
+ "expo-status-bar": "~1.11.1",
57
+ "expo-splash-screen": "~0.26.4",
58
+ "expo-system-ui": "~2.9.3",
59
+ "expo-web-browser": "~12.8.2",
60
+ "expo-haptics": "~12.8.1",
61
+ "expo-device": "~5.9.3",
62
+ "expo-location": "~16.5.3",
63
+ "expo-image-picker": "~14.7.1",
64
+ "expo-camera": "~14.1.3",
65
+ "expo-barcode-scanner": "~12.9.3",
66
+ "expo-notifications": "~0.27.6",
67
+ "expo-secure-store": "~12.8.1",
68
+ "expo-file-system": "~16.0.6",
69
+ "expo-updates": "~0.24.11",
70
+ "expo-linear-gradient": "~12.7.2",
71
+ "expo-blur": "~12.9.2",
72
+ "expo-speech": "~11.7.0",
73
+ "expo-av": "~13.10.4",
74
+
75
+ "@react-native-community/netinfo": "11.2.1",
76
+ "react-native-mmkv": "^2.12.2",
77
+ "react-native-svg": "14.1.0",
78
+ "react-native-url-polyfill": "^2.0.0",
79
+
80
+ "zustand": "^4.4.7",
81
+ "react-hook-form": "^7.48.2",
82
+ "@hookform/resolvers": "^3.3.2",
83
+ "zod": "^3.22.4",
84
+ "date-fns": "^3.0.6",
85
+ "react-native-heroicons": "^4.0.0"
86
+ },
87
+ "devDependencies": {
88
+ "@babel/core": "^7.23.6",
89
+ "@types/react": "~18.2.45",
90
+ "@types/react-native": "~0.73.0",
91
+ "typescript": "~5.3.3",
92
+ "jest": "^29.7.0",
93
+ "@testing-library/react-native": "^12.4.2",
94
+ "@testing-library/jest-native": "^5.4.3",
95
+ "babel-plugin-module-resolver": "^5.0.0",
96
+ "eslint": "^8.57.0",
97
+ "eslint-config-expo": "^7.0.0",
98
+ "prettier": "^3.1.1"
99
+ },
100
+ "jest": {
101
+ "preset": "jest-expo",
102
+ "setupFilesAfterEnv": ["<rootDir>/jest-setup.ts"],
103
+ "transformIgnorePatterns": [
104
+ "node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)"
105
+ ]
106
+ },
107
+ "private": true,
108
+ "expo": {
109
+ "install": {
110
+ "exclude": ["react-native-safe-area-context"]
111
+ }
112
+ }
113
+ }