suparisma 1.1.1 → 1.2.1

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.
@@ -23,9 +23,13 @@ import { supabase } from './supabase-client';
23
23
  * @example
24
24
  * // Search for users with names containing "john"
25
25
  * const query = { field: "name", value: "john" };
26
+ *
27
+ * @example
28
+ * // Search across multiple fields
29
+ * const query = { field: "multi", value: "john" };
26
30
  */
27
31
  export type SearchQuery = {
28
- /** The field name to search in */
32
+ /** The field name to search in, or "multi" for multi-field search */
29
33
  field: string;
30
34
  /** The search term/value to look for */
31
35
  value: string;
@@ -34,6 +38,15 @@ export type SearchQuery = {
34
38
  // Define type for Supabase query builder
35
39
  export type SupabaseQueryBuilder = ReturnType<ReturnType<typeof supabase.from>['select']>;
36
40
 
41
+ /**
42
+ * Utility function to escape regex special characters for safe RegExp usage
43
+ * Prevents "Invalid regular expression" errors when search terms contain special characters
44
+ */
45
+ export function escapeRegexCharacters(str: string): string {
46
+ // Escape all special regex characters: ( ) [ ] { } + * ? ^ $ | . \\
47
+ return str.replace(/[()\\[\\]{}+*?^$|.\\\\]/g, '\\\\\\\\$&');
48
+ }
49
+
37
50
  /**
38
51
  * Advanced filter operators for complex queries
39
52
  * @example
@@ -162,10 +175,22 @@ export type ModelResult<T> = Promise<{
162
175
  * users.search.addQuery({ field: "name", value: "john" });
163
176
  *
164
177
  * @example
178
+ * // Search across multiple fields
179
+ * users.search.searchMultiField("john doe");
180
+ *
181
+ * @example
165
182
  * // Check if search is loading
166
183
  * if (users.search.loading) {
167
184
  * return <div>Searching...</div>;
168
185
  * }
186
+ *
187
+ * @example
188
+ * // Get current search terms for highlighting
189
+ * const searchTerms = users.search.getCurrentSearchTerms();
190
+ *
191
+ * @example
192
+ * // Safely escape regex characters
193
+ * const escaped = users.search.escapeRegex("user@example.com");
169
194
  */
170
195
  export type SearchState = {
171
196
  /** Current active search queries */
@@ -180,6 +205,14 @@ export type SearchState = {
180
205
  removeQuery: (field: string) => void;
181
206
  /** Clear all search queries and return to normal data fetching */
182
207
  clearQueries: () => void;
208
+ /** Search across multiple fields (convenience method) */
209
+ searchMultiField: (value: string) => void;
210
+ /** Search in a specific field (convenience method) */
211
+ searchField: (field: string, value: string) => void;
212
+ /** Get current search terms for custom highlighting */
213
+ getCurrentSearchTerms: () => string[];
214
+ /** Safely escape regex special characters */
215
+ escapeRegex: (text: string) => string;
183
216
  };
184
217
 
185
218
  /**
@@ -248,19 +281,23 @@ export function buildFilterString<T>(where?: T): string | undefined {
248
281
  }
249
282
 
250
283
  if ('gt' in advancedOps && advancedOps.gt !== undefined) {
251
- filters.push(\`\${key}=gt.\${advancedOps.gt}\`);
284
+ const value = advancedOps.gt instanceof Date ? advancedOps.gt.toISOString() : advancedOps.gt;
285
+ filters.push(\`\${key}=gt.\${value}\`);
252
286
  }
253
287
 
254
288
  if ('gte' in advancedOps && advancedOps.gte !== undefined) {
255
- filters.push(\`\${key}=gte.\${advancedOps.gte}\`);
289
+ const value = advancedOps.gte instanceof Date ? advancedOps.gte.toISOString() : advancedOps.gte;
290
+ filters.push(\`\${key}=gte.\${value}\`);
256
291
  }
257
292
 
258
293
  if ('lt' in advancedOps && advancedOps.lt !== undefined) {
259
- filters.push(\`\${key}=lt.\${advancedOps.lt}\`);
294
+ const value = advancedOps.lt instanceof Date ? advancedOps.lt.toISOString() : advancedOps.lt;
295
+ filters.push(\`\${key}=lt.\${value}\`);
260
296
  }
261
297
 
262
298
  if ('lte' in advancedOps && advancedOps.lte !== undefined) {
263
- filters.push(\`\${key}=lte.\${advancedOps.lte}\`);
299
+ const value = advancedOps.lte instanceof Date ? advancedOps.lte.toISOString() : advancedOps.lte;
300
+ filters.push(\`\${key}=lte.\${value}\`);
264
301
  }
265
302
 
266
303
  if ('in' in advancedOps && advancedOps.in?.length) {
@@ -345,23 +382,31 @@ function applyConditionGroup<T>(
345
382
  }
346
383
 
347
384
  if ('gt' in advancedOps && advancedOps.gt !== undefined) {
385
+ // Convert Date objects to ISO strings for Supabase
386
+ const value = advancedOps.gt instanceof Date ? advancedOps.gt.toISOString() : advancedOps.gt;
348
387
  // @ts-ignore: Supabase typing issue
349
- filteredQuery = filteredQuery.gt(key, advancedOps.gt);
388
+ filteredQuery = filteredQuery.gt(key, value);
350
389
  }
351
390
 
352
391
  if ('gte' in advancedOps && advancedOps.gte !== undefined) {
392
+ // Convert Date objects to ISO strings for Supabase
393
+ const value = advancedOps.gte instanceof Date ? advancedOps.gte.toISOString() : advancedOps.gte;
353
394
  // @ts-ignore: Supabase typing issue
354
- filteredQuery = filteredQuery.gte(key, advancedOps.gte);
395
+ filteredQuery = filteredQuery.gte(key, value);
355
396
  }
356
397
 
357
398
  if ('lt' in advancedOps && advancedOps.lt !== undefined) {
399
+ // Convert Date objects to ISO strings for Supabase
400
+ const value = advancedOps.lt instanceof Date ? advancedOps.lt.toISOString() : advancedOps.lt;
358
401
  // @ts-ignore: Supabase typing issue
359
- filteredQuery = filteredQuery.lt(key, advancedOps.lt);
402
+ filteredQuery = filteredQuery.lt(key, value);
360
403
  }
361
404
 
362
405
  if ('lte' in advancedOps && advancedOps.lte !== undefined) {
406
+ // Convert Date objects to ISO strings for Supabase
407
+ const value = advancedOps.lte instanceof Date ? advancedOps.lte.toISOString() : advancedOps.lte;
363
408
  // @ts-ignore: Supabase typing issue
364
- filteredQuery = filteredQuery.lte(key, advancedOps.lte);
409
+ filteredQuery = filteredQuery.lte(key, value);
365
410
  }
366
411
 
367
412
  if ('in' in advancedOps && advancedOps.in?.length) {
@@ -458,13 +503,17 @@ export function applyFilter<T>(
458
503
  } else if ('not' in advancedOps && advancedOps.not !== undefined) {
459
504
  orFilters.push(\`\${key}.neq.\${advancedOps.not}\`);
460
505
  } else if ('gt' in advancedOps && advancedOps.gt !== undefined) {
461
- orFilters.push(\`\${key}.gt.\${advancedOps.gt}\`);
506
+ const value = advancedOps.gt instanceof Date ? advancedOps.gt.toISOString() : advancedOps.gt;
507
+ orFilters.push(\`\${key}.gt.\${value}\`);
462
508
  } else if ('gte' in advancedOps && advancedOps.gte !== undefined) {
463
- orFilters.push(\`\${key}.gte.\${advancedOps.gte}\`);
509
+ const value = advancedOps.gte instanceof Date ? advancedOps.gte.toISOString() : advancedOps.gte;
510
+ orFilters.push(\`\${key}.gte.\${value}\`);
464
511
  } else if ('lt' in advancedOps && advancedOps.lt !== undefined) {
465
- orFilters.push(\`\${key}.lt.\${advancedOps.lt}\`);
512
+ const value = advancedOps.lt instanceof Date ? advancedOps.lt.toISOString() : advancedOps.lt;
513
+ orFilters.push(\`\${key}.lt.\${value}\`);
466
514
  } else if ('lte' in advancedOps && advancedOps.lte !== undefined) {
467
- orFilters.push(\`\${key}.lte.\${advancedOps.lte}\`);
515
+ const value = advancedOps.lte instanceof Date ? advancedOps.lte.toISOString() : advancedOps.lte;
516
+ orFilters.push(\`\${key}.lte.\${value}\`);
468
517
  } else if ('in' in advancedOps && advancedOps.in?.length) {
469
518
  orFilters.push(\`\${key}.in.(\${advancedOps.in.join(',')})\`);
470
519
  } else if ('contains' in advancedOps && advancedOps.contains !== undefined) {
@@ -528,6 +577,18 @@ function matchesFilter<T>(record: any, filter: T): boolean {
528
577
  }
529
578
  }
530
579
 
580
+ // Helper function to convert values to comparable format for date/time comparisons
581
+ const getComparableValue = (value: any): any => {
582
+ if (value instanceof Date) {
583
+ return value.getTime();
584
+ }
585
+ if (typeof value === 'string' && value.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)) {
586
+ // ISO date string
587
+ return new Date(value).getTime();
588
+ }
589
+ return value;
590
+ };
591
+
531
592
  // Helper function to check individual field conditions
532
593
  const checkFieldConditions = (conditions: any): boolean => {
533
594
  for (const [key, value] of Object.entries(conditions)) {
@@ -547,19 +608,27 @@ function matchesFilter<T>(record: any, filter: T): boolean {
547
608
  }
548
609
 
549
610
  if ('gt' in advancedOps && advancedOps.gt !== undefined) {
550
- if (!(recordValue > advancedOps.gt)) return false;
611
+ const recordComparable = getComparableValue(recordValue);
612
+ const filterComparable = getComparableValue(advancedOps.gt);
613
+ if (!(recordComparable > filterComparable)) return false;
551
614
  }
552
615
 
553
616
  if ('gte' in advancedOps && advancedOps.gte !== undefined) {
554
- if (!(recordValue >= advancedOps.gte)) return false;
617
+ const recordComparable = getComparableValue(recordValue);
618
+ const filterComparable = getComparableValue(advancedOps.gte);
619
+ if (!(recordComparable >= filterComparable)) return false;
555
620
  }
556
621
 
557
622
  if ('lt' in advancedOps && advancedOps.lt !== undefined) {
558
- if (!(recordValue < advancedOps.lt)) return false;
623
+ const recordComparable = getComparableValue(recordValue);
624
+ const filterComparable = getComparableValue(advancedOps.lt);
625
+ if (!(recordComparable < filterComparable)) return false;
559
626
  }
560
627
 
561
628
  if ('lte' in advancedOps && advancedOps.lte !== undefined) {
562
- if (!(recordValue <= advancedOps.lte)) return false;
629
+ const recordComparable = getComparableValue(recordValue);
630
+ const filterComparable = getComparableValue(advancedOps.lte);
631
+ if (!(recordComparable <= filterComparable)) return false;
563
632
  }
564
633
 
565
634
  if ('in' in advancedOps && advancedOps.in?.length) {
@@ -861,7 +930,39 @@ export function createSuparismaHook<
861
930
  setSearchQueries([]);
862
931
  isSearchingRef.current = false;
863
932
  findMany({ where, orderBy, take: limit, skip: offset });
864
- }, [where, orderBy, limit, offset])
933
+ }, [where, orderBy, limit, offset]),
934
+
935
+ // Search across multiple fields (convenience method)
936
+ searchMultiField: useCallback((value: string) => {
937
+ if (searchFields.length <= 1) {
938
+ console.warn('Multi-field search requires at least 2 searchable fields');
939
+ return;
940
+ }
941
+
942
+ setSearchQueries([{ field: 'multi', value }]);
943
+ executeSearch([{ field: 'multi', value }]);
944
+ }, [searchFields.length]),
945
+
946
+ // Search in a specific field (convenience method)
947
+ searchField: useCallback((field: string, value: string) => {
948
+ if (!searchFields.includes(field)) {
949
+ console.warn(\`Field "\${field}" is not searchable. Available fields: \${searchFields.join(', ')}\`);
950
+ return;
951
+ }
952
+
953
+ setSearchQueries([{ field, value }]);
954
+ executeSearch([{ field, value }]);
955
+ }, [searchFields]),
956
+
957
+ // Get current search terms for custom highlighting
958
+ getCurrentSearchTerms: useCallback(() => {
959
+ return searchQueries.map(q => q.value.trim());
960
+ }, [searchQueries]),
961
+
962
+ // Safely escape regex special characters
963
+ escapeRegex: useCallback((text: string) => {
964
+ return escapeRegexCharacters(text);
965
+ }, [])
865
966
  };
866
967
 
867
968
  // Execute search based on queries
@@ -884,13 +985,52 @@ export function createSuparismaHook<
884
985
  try {
885
986
  let results: TWithRelations[] = [];
886
987
 
988
+ // Validate search queries
989
+ const validQueries = queries.filter(query => {
990
+ if (!query.field || !query.value) {
991
+ console.warn('Invalid search query - missing field or value:', query);
992
+ return false;
993
+ }
994
+ // Allow "multi" as a special field for multi-field search
995
+ if (query.field === 'multi' && searchFields.length > 1) {
996
+ return true;
997
+ }
998
+ if (!searchFields.includes(query.field)) {
999
+ console.warn(\`Field "\${query.field}" is not searchable. Available fields: \${searchFields.join(', ')}, or "multi" for multi-field search\`);
1000
+ return false;
1001
+ }
1002
+ return true;
1003
+ });
1004
+
1005
+ if (validQueries.length === 0) {
1006
+ console.log('No valid search queries found');
1007
+ setData([]);
1008
+ setCount(0);
1009
+ return;
1010
+ }
1011
+
887
1012
  // Execute RPC function for each query using Promise.all
888
- const searchPromises = queries.map(query => {
889
- // Build function name: search_tablename_by_fieldname_prefix
890
- const functionName = \`search_\${tableName}_by_\${query.field}_prefix\`;
1013
+ const searchPromises = validQueries.map(query => {
1014
+ // Build function name based on field type
1015
+ const functionName = query.field === 'multi'
1016
+ ? \`search_\${tableName.toLowerCase()}_multi_field\`
1017
+ : \`search_\${tableName.toLowerCase()}_by_\${query.field.toLowerCase()}_prefix\`;
1018
+
1019
+ console.log(\`🔍 Executing search: \${functionName}(search_prefix: "\${query.value.trim()}")\`);
891
1020
 
892
- // Call RPC function
893
- return supabase.rpc(functionName, { prefix: query.value.trim() });
1021
+ // Call RPC function with proper error handling
1022
+ return Promise.resolve(supabase.rpc(functionName, { search_prefix: query.value.trim() }))
1023
+ .then((result: any) => ({
1024
+ ...result,
1025
+ queryField: query.field,
1026
+ queryValue: query.value
1027
+ }))
1028
+ .catch((error: any) => ({
1029
+ data: null,
1030
+ error: error,
1031
+ queryField: query.field,
1032
+ queryValue: query.value
1033
+ }));
894
1034
  });
895
1035
 
896
1036
  // Execute all search queries in parallel
@@ -898,82 +1038,88 @@ export function createSuparismaHook<
898
1038
 
899
1039
  // Combine and deduplicate results
900
1040
  const allResults: Record<string, TWithRelations> = {};
1041
+ let hasErrors = false;
901
1042
 
902
1043
  // Process each search result
903
- searchResults.forEach((result, index) => {
1044
+ searchResults.forEach((result: any, index: number) => {
904
1045
  if (result.error) {
905
- console.error(\`Search error for \${queries[index]?.field}:\`, result.error);
1046
+ console.error(\`🔍 Search error for field "\${result.queryField}" with value "\${result.queryValue}":\`, result.error);
1047
+ hasErrors = true;
906
1048
  return;
907
1049
  }
908
1050
 
909
- if (result.data) {
1051
+ if (result.data && Array.isArray(result.data)) {
1052
+ console.log(\`🔍 Search results for "\${result.queryField}": \${result.data.length} items\`);
1053
+
910
1054
  // Add each result, using id as key to deduplicate
911
1055
  for (const item of result.data as TWithRelations[]) {
912
1056
  // @ts-ignore: Assume item has an id property
913
- if (item.id) {
1057
+ if (item && typeof item === 'object' && 'id' in item && item.id) {
914
1058
  // @ts-ignore: Add to results using id as key
915
1059
  allResults[item.id] = item;
916
1060
  }
917
1061
  }
1062
+ } else if (result.data) {
1063
+ console.warn(\`🔍 Unexpected search result format for "\${result.queryField}":\`, typeof result.data);
918
1064
  }
919
1065
  });
920
1066
 
921
1067
  // Convert back to array
922
1068
  results = Object.values(allResults);
1069
+ console.log(\`🔍 Combined search results: \${results.length} unique items\`);
923
1070
 
924
- // Apply any where conditions client-side
1071
+ // Apply any where conditions client-side (now using the proper filter function)
925
1072
  if (where) {
926
- results = results.filter((item) => {
927
- for (const [key, value] of Object.entries(where)) {
928
- if (typeof value === 'object' && value !== null) {
929
- // Skip complex filters for now
930
- continue;
931
- }
932
-
933
- if (item[key as keyof typeof item] !== value) {
934
- return false;
935
- }
936
- }
937
- return true;
938
- });
1073
+ const originalCount = results.length;
1074
+ results = results.filter((item) => matchesFilter(item, where));
1075
+ console.log(\`🔍 After applying where filter: \${results.length}/\${originalCount} items\`);
939
1076
  }
940
1077
 
941
1078
  // Set count directly for search results
942
1079
  setCount(results.length);
943
1080
 
944
- // Apply ordering if needed
1081
+ // Apply ordering if needed (using the proper compare function)
945
1082
  if (orderBy) {
946
- const orderEntries = Object.entries(orderBy);
947
- if (orderEntries.length > 0) {
948
- const [orderField, direction] = orderEntries[0] || [];
1083
+ const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy];
949
1084
  results = [...results].sort((a, b) => {
950
- const aValue = a[orderField as keyof typeof a] ?? '';
951
- const bValue = b[orderField as keyof typeof b] ?? '';
1085
+ for (const orderByClause of orderByArray) {
1086
+ for (const [field, direction] of Object.entries(orderByClause)) {
1087
+ const aValue = a[field as keyof typeof a];
1088
+ const bValue = b[field as keyof typeof b];
952
1089
 
953
- if (direction === 'asc') {
954
- return aValue < bValue ? -1 : aValue > bValue ? 1 : 0;
955
- } else {
956
- return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;
1090
+ if (aValue === bValue) continue;
1091
+
1092
+ return compareValues(aValue, bValue, direction as 'asc' | 'desc');
957
1093
  }
958
- });
959
- }
1094
+ }
1095
+ return 0;
1096
+ });
960
1097
  }
961
1098
 
962
1099
  // Apply pagination if needed
963
1100
  let paginatedResults = results;
964
- if (limit && limit > 0) {
965
- paginatedResults = results.slice(0, limit);
966
- }
967
-
968
1101
  if (offset && offset > 0) {
969
1102
  paginatedResults = paginatedResults.slice(offset);
970
1103
  }
971
1104
 
1105
+ if (limit && limit > 0) {
1106
+ paginatedResults = paginatedResults.slice(0, limit);
1107
+ }
1108
+
1109
+ console.log(\`🔍 Final search results: \${paginatedResults.length} items (total: \${results.length})\`);
1110
+
972
1111
  // Update data with search results
973
1112
  setData(paginatedResults);
1113
+
1114
+ // Show error if there were issues but still show partial results
1115
+ if (hasErrors && results.length === 0) {
1116
+ setError(new Error('Search failed - please check if search functions are properly configured'));
1117
+ }
974
1118
  } catch (err) {
975
- console.error('Search error:', err);
1119
+ console.error('🔍 Search error:', err);
976
1120
  setError(err as Error);
1121
+ setData([]);
1122
+ setCount(0);
977
1123
  } finally {
978
1124
  setSearchLoading(false);
979
1125
  }
@@ -1518,7 +1664,20 @@ export function createSuparismaHook<
1518
1664
  setLoading(true);
1519
1665
  setError(null);
1520
1666
 
1521
- const now = new Date().toISOString();
1667
+ const now = new Date();
1668
+
1669
+ // Helper function to convert Date objects to ISO strings for database
1670
+ const convertDatesForDatabase = (obj: any): any => {
1671
+ const result: any = {};
1672
+ for (const [key, value] of Object.entries(obj)) {
1673
+ if (value instanceof Date) {
1674
+ result[key] = value.toISOString();
1675
+ } else {
1676
+ result[key] = value;
1677
+ }
1678
+ }
1679
+ return result;
1680
+ };
1522
1681
 
1523
1682
  // Apply default values from schema
1524
1683
  const appliedDefaults: Record<string, any> = {};
@@ -1529,7 +1688,7 @@ export function createSuparismaHook<
1529
1688
  if (!(field in data)) {
1530
1689
  // Parse the default value based on its type
1531
1690
  if (defaultValue.includes('now()') || defaultValue.includes('now')) {
1532
- appliedDefaults[field] = now;
1691
+ appliedDefaults[field] = now.toISOString(); // Database expects ISO string
1533
1692
  } else if (defaultValue.includes('uuid()') || defaultValue.includes('uuid')) {
1534
1693
  appliedDefaults[field] = crypto.randomUUID();
1535
1694
  } else if (defaultValue.includes('cuid()') || defaultValue.includes('cuid')) {
@@ -1550,13 +1709,13 @@ export function createSuparismaHook<
1550
1709
  }
1551
1710
  }
1552
1711
 
1553
- const itemWithDefaults = {
1712
+ const itemWithDefaults = convertDatesForDatabase({
1554
1713
  ...appliedDefaults, // Apply schema defaults first
1555
1714
  ...data, // Then user data (overrides defaults)
1556
- // Use the actual field names from Prisma
1557
- ...(hasCreatedAt ? { [createdAtField]: now } : {}),
1558
- ...(hasUpdatedAt ? { [updatedAtField]: now } : {})
1559
- };
1715
+ // Use the actual field names from Prisma - convert Date to ISO string for database
1716
+ ...(hasCreatedAt ? { [createdAtField]: now.toISOString() } : {}),
1717
+ ...(hasUpdatedAt ? { [updatedAtField]: now.toISOString() } : {})
1718
+ });
1560
1719
 
1561
1720
  const { data: result, error } = await supabase
1562
1721
  .from(tableName)
@@ -1624,17 +1783,30 @@ export function createSuparismaHook<
1624
1783
  throw new Error('A unique identifier is required');
1625
1784
  }
1626
1785
 
1627
- const now = new Date().toISOString();
1786
+ const now = new Date();
1787
+
1788
+ // Helper function to convert Date objects to ISO strings for database
1789
+ const convertDatesForDatabase = (obj: any): any => {
1790
+ const result: any = {};
1791
+ for (const [key, value] of Object.entries(obj)) {
1792
+ if (value instanceof Date) {
1793
+ result[key] = value.toISOString();
1794
+ } else {
1795
+ result[key] = value;
1796
+ }
1797
+ }
1798
+ return result;
1799
+ };
1628
1800
 
1629
1801
  // We do not apply default values for updates
1630
1802
  // Default values are only for creation, not for updates,
1631
1803
  // as existing records already have these values set
1632
1804
 
1633
- const itemWithDefaults = {
1805
+ const itemWithDefaults = convertDatesForDatabase({
1634
1806
  ...params.data,
1635
- // Use the actual updatedAt field name from Prisma
1636
- ...(hasUpdatedAt ? { [updatedAtField]: now } : {})
1637
- };
1807
+ // Use the actual updatedAt field name from Prisma - convert Date to ISO string for database
1808
+ ...(hasUpdatedAt ? { [updatedAtField]: now.toISOString() } : {})
1809
+ });
1638
1810
 
1639
1811
  const { data, error } = await supabase
1640
1812
  .from(tableName)
@@ -69,7 +69,7 @@ function generateModelTypesFile(model) {
69
69
  baseType = 'boolean';
70
70
  break;
71
71
  case 'DateTime':
72
- baseType = 'string'; // ISO date string
72
+ baseType = 'Date'; // Proper Date type for DateTime fields
73
73
  break;
74
74
  case 'Json':
75
75
  baseType = 'any'; // Or a more specific structured type if available
@@ -118,33 +118,16 @@ function generateModelTypesFile(model) {
118
118
  // Generate imports section for zod custom types
119
119
  let customImports = '';
120
120
  if (model.zodImports && model.zodImports.length > 0) {
121
- // Add zod import for type inference
122
- customImports = 'import { z } from \'zod\';\n';
123
- // Get the zod schemas file path from environment variable
124
- const zodSchemasPath = process.env.ZOD_SCHEMAS_FILE_PATH || '../commonTypes';
125
- // Add custom imports with environment variable path
126
- customImports += model.zodImports
127
- .map(zodImport => {
128
- // Extract the types from the original import statement
129
- const typeMatch = zodImport.importStatement.match(/import\s+{\s*([^}]+)\s*}\s+from/);
130
- if (typeMatch) {
131
- const types = typeMatch[1].trim();
132
- return `import { ${types} } from '${zodSchemasPath}'`;
133
- }
134
- // Fallback to original import if parsing fails
135
- return zodImport.importStatement;
136
- })
137
- .join('\n') + '\n\n';
138
- // Add type definitions for imported zod schemas if needed
139
- // This is a simplified approach - you might want to make this more sophisticated
121
+ // For projects without zod dependency, fallback to any types instead of importing zod
122
+ // This prevents TypeScript errors when zod is not installed
140
123
  const customTypeDefinitions = model.zodImports
141
124
  .flatMap(zodImport => zodImport.types)
142
125
  .filter((type, index, array) => array.indexOf(type) === index) // Remove duplicates
143
126
  .map(type => {
144
- // If it ends with 'Schema', create a corresponding type
127
+ // If it ends with 'Schema', create a corresponding type using any instead of zod
145
128
  if (type.endsWith('Schema')) {
146
129
  const typeName = type.replace('Schema', '');
147
- return `export type ${typeName} = z.infer<typeof ${type}>;`;
130
+ return `// Fallback type when zod is not available\nexport type ${typeName} = any;`;
148
131
  }
149
132
  return '';
150
133
  })