@ram_28/kf-ai-sdk 1.0.20 → 1.0.22

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 (53) hide show
  1. package/dist/api/client.d.ts.map +1 -1
  2. package/dist/api/datetime.d.ts +59 -10
  3. package/dist/api/datetime.d.ts.map +1 -1
  4. package/dist/api/index.d.ts +3 -2
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api.cjs +1 -1
  7. package/dist/api.d.ts +1 -1
  8. package/dist/api.d.ts.map +1 -1
  9. package/dist/api.mjs +43 -21
  10. package/dist/api.types.d.ts +2 -1
  11. package/dist/api.types.d.ts.map +1 -1
  12. package/dist/auth/AuthProvider.d.ts.map +1 -1
  13. package/dist/auth.cjs +1 -1
  14. package/dist/auth.mjs +34 -34
  15. package/dist/base-types.d.ts +1 -1
  16. package/dist/base-types.d.ts.map +1 -1
  17. package/dist/client-BIkaIr2y.js +217 -0
  18. package/dist/client-DxjRcEtN.cjs +1 -0
  19. package/dist/components/hooks/useForm/apiClient.d.ts +45 -4
  20. package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -1
  21. package/dist/components/hooks/useForm/types.d.ts +8 -0
  22. package/dist/components/hooks/useForm/types.d.ts.map +1 -1
  23. package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
  24. package/dist/form.cjs +1 -1
  25. package/dist/form.mjs +1028 -1051
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/kanban.cjs +1 -1
  29. package/dist/kanban.mjs +1 -1
  30. package/dist/{metadata-0lZAfuTP.cjs → metadata-Bz8zJqC1.cjs} +1 -1
  31. package/dist/{metadata-B88D_pVS.js → metadata-VbQzyD2C.js} +1 -1
  32. package/dist/table.cjs +1 -1
  33. package/dist/table.mjs +1 -1
  34. package/dist/types/base-fields.d.ts +71 -17
  35. package/dist/types/base-fields.d.ts.map +1 -1
  36. package/dist/types/common.d.ts +0 -12
  37. package/dist/types/common.d.ts.map +1 -1
  38. package/package.json +1 -1
  39. package/sdk/api/client.ts +3 -41
  40. package/sdk/api/datetime.ts +98 -14
  41. package/sdk/api/index.ts +12 -6
  42. package/sdk/api.ts +6 -3
  43. package/sdk/api.types.ts +3 -4
  44. package/sdk/auth/AuthProvider.tsx +22 -24
  45. package/sdk/base-types.ts +2 -0
  46. package/sdk/components/hooks/useForm/apiClient.ts +118 -4
  47. package/sdk/components/hooks/useForm/types.ts +9 -0
  48. package/sdk/components/hooks/useForm/useForm.ts +79 -60
  49. package/sdk/index.ts +3 -0
  50. package/sdk/types/base-fields.ts +71 -17
  51. package/sdk/types/common.ts +2 -13
  52. package/dist/client-DgtkT50N.cjs +0 -1
  53. package/dist/client-V-WzUb8H.js +0 -237
package/sdk/base-types.ts CHANGED
@@ -25,6 +25,8 @@ export type {
25
25
  CurrencyValueType,
26
26
  JSONFieldType,
27
27
  ReferenceFieldType,
28
+ ExtractReferenceType,
29
+ ExtractFetchFieldType,
28
30
 
29
31
  // JSON types
30
32
  JSONValueType,
@@ -135,7 +135,62 @@ export async function submitFormData<T = any>(
135
135
  // ============================================================
136
136
 
137
137
  /**
138
- * Fetch reference field data
138
+ * Fetch reference field data using the fetchField API
139
+ * This correctly uses instance context for filter evaluation
140
+ */
141
+ export async function fetchReferenceFieldData(
142
+ boId: string,
143
+ instanceId: string,
144
+ fieldId: string
145
+ ): Promise<Array<{ Value: string; Label: string }>> {
146
+ try {
147
+ // Calls GET /{boId}/{instanceId}/field/{fieldId}/fetch
148
+ return await api(boId).fetchField(instanceId, fieldId);
149
+ } catch (error) {
150
+ console.error(`Reference data fetch error for ${fieldId}:`, error);
151
+ return [];
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Fetch all reference data for a form
157
+ * @param boId - The Business Object ID
158
+ * @param instanceId - The instance ID (draftId for create, recordId for update)
159
+ * @param referenceFieldIds - Array of reference field IDs to fetch
160
+ */
161
+ export async function fetchAllReferenceFieldData(
162
+ boId: string,
163
+ instanceId: string,
164
+ referenceFieldIds: string[]
165
+ ): Promise<Record<string, Array<{ Value: string; Label: string }>>> {
166
+ const referenceData: Record<string, Array<{ Value: string; Label: string }>> = {};
167
+
168
+ // Fetch all reference data in parallel
169
+ const fetchPromises = referenceFieldIds.map(async (fieldId) => {
170
+ try {
171
+ const data = await fetchReferenceFieldData(boId, instanceId, fieldId);
172
+ return [fieldId, data] as const;
173
+ } catch (error) {
174
+ console.warn(`Failed to fetch reference data for ${fieldId}:`, error);
175
+ return [fieldId, []] as const;
176
+ }
177
+ });
178
+
179
+ const results = await Promise.allSettled(fetchPromises);
180
+
181
+ results.forEach((result) => {
182
+ if (result.status === "fulfilled") {
183
+ const [fieldId, data] = result.value;
184
+ referenceData[fieldId] = [...data];
185
+ }
186
+ });
187
+
188
+ return referenceData;
189
+ }
190
+
191
+ /**
192
+ * @deprecated Use fetchReferenceFieldData instead
193
+ * Legacy function that fetches reference data using list() API
139
194
  */
140
195
  export async function fetchReferenceData(
141
196
  businessObject: string,
@@ -171,7 +226,8 @@ export async function fetchReferenceData(
171
226
  }
172
227
 
173
228
  /**
174
- * Fetch all reference data for a schema
229
+ * @deprecated Use fetchAllReferenceFieldData instead
230
+ * Legacy function that fetches all reference data using list() API
175
231
  */
176
232
  export async function fetchAllReferenceData(
177
233
  referenceFields: Record<string, any>
@@ -239,18 +295,26 @@ export function validateFormData<T>(
239
295
  * Clean form data before submission
240
296
  * - For create: returns all non-computed, non-undefined fields
241
297
  * - For update: returns only fields that changed from originalData
298
+ * - Transforms Reference fields to JSON format expected by backend
299
+ *
300
+ * @param data - Form data to clean
301
+ * @param computedFields - Array of computed field names to exclude
302
+ * @param operation - "create" or "update"
303
+ * @param originalData - Original data for comparison (update only)
304
+ * @param fieldTypes - Map of field names to their BDO types (e.g., { "SupplierInfo": "Reference" })
242
305
  */
243
306
  export function cleanFormData<T>(
244
307
  data: Partial<T>,
245
308
  computedFields: string[],
246
309
  operation: FormOperationType = "create",
247
- originalData?: Partial<T>
310
+ originalData?: Partial<T>,
311
+ fieldTypes?: Record<string, string>
248
312
  ): Partial<T> {
249
313
  const cleanedData: Partial<T> = {};
250
314
 
251
315
  Object.keys(data).forEach((key) => {
252
316
  const fieldKey = key as keyof T;
253
- const value = data[fieldKey];
317
+ let value = data[fieldKey];
254
318
 
255
319
  // Skip computed fields
256
320
  if (computedFields.includes(key)) {
@@ -262,6 +326,12 @@ export function cleanFormData<T>(
262
326
  return;
263
327
  }
264
328
 
329
+ // Transform Reference fields to JSON format expected by backend
330
+ // Backend expects: {"_id": "...", "_name": "..."} or a JSON string that parses to this
331
+ if (fieldTypes?.[key] === "Reference" && value !== null) {
332
+ value = transformReferenceValue(value) as any;
333
+ }
334
+
265
335
  // For create: include all non-computed, non-undefined fields
266
336
  if (operation === "create") {
267
337
  cleanedData[fieldKey] = value;
@@ -289,6 +359,50 @@ export function cleanFormData<T>(
289
359
  return cleanedData;
290
360
  }
291
361
 
362
+ /**
363
+ * Transform a Reference/Lookup field value to the format expected by backend
364
+ *
365
+ * Backend expects Reference fields as either:
366
+ * - A dict with at minimum {"_id": "..."}
367
+ * - For Lookup fields, the full referenced record can be passed
368
+ * - A JSON string that parses to this format
369
+ *
370
+ * This function handles various input formats:
371
+ * - Plain string ID: "SUPP-001" → {"_id": "SUPP-001"}
372
+ * - Object with _id: preserves ALL properties (for lookup fields with full data)
373
+ * - JSON string: '{"_id": "..."}' → parsed and validated
374
+ */
375
+ export function transformReferenceValue(value: any): Record<string, any> | null {
376
+ if (value === null || value === undefined || value === "") {
377
+ return null;
378
+ }
379
+
380
+ // Already an object with _id - preserve ALL properties (for lookup fields with full data)
381
+ if (typeof value === "object" && value._id) {
382
+ return { ...value };
383
+ }
384
+
385
+ // String value - could be plain ID or JSON string
386
+ if (typeof value === "string") {
387
+ // Try to parse as JSON first
388
+ try {
389
+ const parsed = JSON.parse(value);
390
+ if (typeof parsed === "object" && parsed._id) {
391
+ return { ...parsed };
392
+ }
393
+ // Parsed but not a valid reference object - treat original as ID
394
+ } catch {
395
+ // Not valid JSON - treat as plain ID string
396
+ }
397
+
398
+ // Plain string ID
399
+ return { _id: value };
400
+ }
401
+
402
+ // Unknown format - return as-is (let backend handle/reject it)
403
+ return value;
404
+ }
405
+
292
406
  // ============================================================
293
407
  // ERROR HANDLING
294
408
  // ============================================================
@@ -304,6 +304,15 @@ export interface UseFormOptionsType<
304
304
  * @default "interactive"
305
305
  */
306
306
  interactionMode?: InteractionModeType;
307
+
308
+ /**
309
+ * Enable draft API calls in update mode
310
+ * When false (default), no draft API calls (e.g., /instance_id/draft) are made during
311
+ * field blur in update mode. The update API is only called on form submission.
312
+ * When true, draft API calls are made on blur for computed field dependencies.
313
+ * @default false
314
+ */
315
+ enableDraftInUpdateMode?: boolean;
307
316
  }
308
317
 
309
318
  // ============================================================
@@ -16,14 +16,14 @@ import type {
16
16
  FormFieldConfigType,
17
17
  } from "./types";
18
18
 
19
- import { processSchema, extractReferenceFields } from "./schemaParser.utils";
19
+ import { processSchema } from "./schemaParser.utils";
20
20
 
21
21
  import {
22
22
  fetchFormSchemaWithCache,
23
23
  fetchRecord,
24
24
  submitFormData,
25
- fetchAllReferenceData,
26
25
  cleanFormData,
26
+ transformReferenceValue,
27
27
  } from "./apiClient";
28
28
 
29
29
  import { api } from "../../../api";
@@ -40,7 +40,7 @@ import {
40
40
  // ============================================================
41
41
 
42
42
  export function useForm<T extends Record<string, any> = Record<string, any>>(
43
- options: UseFormOptionsType<T>
43
+ options: UseFormOptionsType<T>,
44
44
  ): UseFormReturnType<T> {
45
45
  const {
46
46
  source,
@@ -54,6 +54,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
54
54
  skipSchemaFetch = false,
55
55
  schema: manualSchema,
56
56
  interactionMode = "interactive",
57
+ enableDraftInUpdateMode = false,
57
58
  } = options;
58
59
 
59
60
  // Derived interaction mode flags
@@ -63,9 +64,13 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
63
64
  // STATE MANAGEMENT
64
65
  // ============================================================
65
66
 
66
- const [schemaConfig, setSchemaConfig] =
67
- useState<FormSchemaConfigType | null>(null);
68
- const [referenceData, setReferenceData] = useState<Record<string, any[]>>({});
67
+ const [schemaConfig, setSchemaConfig] = useState<FormSchemaConfigType | null>(
68
+ null,
69
+ );
70
+ // Reference data for cross-field validation - populated lazily by UI components if needed
71
+ const [referenceData, _setReferenceData] = useState<Record<string, any[]>>(
72
+ {},
73
+ );
69
74
  const [isSubmitting, setIsSubmitting] = useState(false);
70
75
  const [lastFormValues] = useState<Partial<T>>({});
71
76
 
@@ -176,22 +181,11 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
176
181
  const processed = processSchema(
177
182
  schema as any,
178
183
  {}, // Pass empty object - validation functions get live values from react-hook-form
179
- userRole
184
+ userRole,
180
185
  );
181
186
  setSchemaConfig(processed);
182
-
183
- // Fetch reference data for reference fields
184
- const refFields = extractReferenceFields(processed);
185
- if (Object.keys(refFields).length > 0) {
186
- fetchAllReferenceData(refFields)
187
- .then(setReferenceData)
188
- .catch((err) => {
189
- const error = toError(err);
190
- console.warn("Failed to fetch reference data:", error);
191
- // Notify via callback but don't block form - reference data is non-critical
192
- onSchemaErrorRef.current?.(error);
193
- });
194
- }
187
+ // Reference data is fetched lazily by UI components when dropdowns are opened
188
+ // using the fetchField API with proper instance context (draftId/recordId)
195
189
  } catch (error) {
196
190
  console.error("Schema processing failed:", error);
197
191
  onSchemaErrorRef.current?.(toError(error));
@@ -219,7 +213,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
219
213
  !schemaConfig ||
220
214
  !enabled ||
221
215
  draftId ||
222
- draftCreationStartedRef.current // Prevent duplicate calls in React strict mode
216
+ draftCreationStartedRef.current // Prevent duplicate calls in React strict mode
223
217
  ) {
224
218
  return;
225
219
  }
@@ -321,7 +315,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
321
315
  const field = schemaConfig.fields[fieldName];
322
316
  if (field._bdoField.Formula) {
323
317
  const fieldDeps = getFieldDependencies(
324
- field._bdoField.Formula.ExpressionTree
318
+ field._bdoField.Formula.ExpressionTree,
325
319
  );
326
320
  fieldDeps.forEach((dep) => {
327
321
  // Only add non-computed fields as dependencies
@@ -353,14 +347,20 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
353
347
  return;
354
348
  }
355
349
 
356
- // Determine if draft should be triggered based on interaction mode
357
- // For update mode, always behave as non-interactive (only trigger for computed deps)
350
+ // Determine if draft should be triggered based on interaction mode and configuration
351
+ // For update mode: skip draft API calls unless explicitly enabled via enableDraftInUpdateMode
358
352
  // Interactive mode (create only): Always trigger draft API on blur
359
353
  // Non-interactive mode: Only trigger for computed field dependencies
360
- const shouldTrigger = (isInteractiveMode && operation !== "update")
361
- ? true // Interactive mode (create only): always trigger
362
- : (computedFieldDependencies.length > 0 &&
363
- computedFieldDependencies.includes(fieldName as Path<T>));
354
+ if (operation === "update" && !enableDraftInUpdateMode) {
355
+ // Skip draft API calls in update mode when enableDraftInUpdateMode is false (default)
356
+ return;
357
+ }
358
+
359
+ const shouldTrigger =
360
+ isInteractiveMode && operation !== "update"
361
+ ? true // Interactive mode (create only): always trigger
362
+ : computedFieldDependencies.length > 0 &&
363
+ computedFieldDependencies.includes(fieldName as Path<T>);
364
364
 
365
365
  if (!shouldTrigger) {
366
366
  return;
@@ -422,7 +422,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
422
422
 
423
423
  // Get computed field names to exclude from payload
424
424
  const computedFieldNames = new Set(
425
- schemaConfig.computedFields || []
425
+ schemaConfig.computedFields || [],
426
426
  );
427
427
 
428
428
  // Find fields that changed from baseline (excluding computed fields)
@@ -430,7 +430,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
430
430
  // Skip _id and computed fields
431
431
  if (key === "_id" || computedFieldNames.has(key)) return;
432
432
 
433
- const currentValue = (currentValues as any)[key];
433
+ let currentValue = (currentValues as any)[key];
434
434
  const baselineValue = (baseline as any)[key];
435
435
 
436
436
  // Include if value has changed (using JSON.stringify for deep comparison)
@@ -443,6 +443,11 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
443
443
  currentValue !== undefined;
444
444
 
445
445
  if (hasChanged && isNonEmpty) {
446
+ // Transform Reference fields to format expected by backend
447
+ const fieldConfig = schemaConfig.fields[key];
448
+ if (fieldConfig?._bdoField?.Type === "Reference") {
449
+ currentValue = transformReferenceValue(currentValue);
450
+ }
446
451
  (changedFields as any)[key] = currentValue;
447
452
  }
448
453
  });
@@ -470,7 +475,10 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
470
475
  let computedFieldsResponse;
471
476
  if (operation === "update" && recordId) {
472
477
  // Update mode: use draftPatch (both interactive and non-interactive)
473
- computedFieldsResponse = await client.draftPatch(recordId, payload);
478
+ computedFieldsResponse = await client.draftPatch(
479
+ recordId,
480
+ payload,
481
+ );
474
482
  } else if (isInteractiveMode && draftId) {
475
483
  // Interactive create: use draftInteraction with _id
476
484
  computedFieldsResponse = await client.draftInteraction(payload);
@@ -493,7 +501,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
493
501
  shouldValidate: false,
494
502
  });
495
503
  }
496
- }
504
+ },
497
505
  );
498
506
 
499
507
  // Update baseline with computed fields from successful API response
@@ -502,7 +510,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
502
510
  if (computedFieldNames.has(fieldName)) {
503
511
  (lastSyncedValuesRef.current as any)[fieldName] = value;
504
512
  }
505
- }
513
+ },
506
514
  );
507
515
  }
508
516
  } catch (error) {
@@ -531,7 +539,8 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
531
539
  computedFieldDependencies,
532
540
  isInteractiveMode,
533
541
  draftId,
534
- ]
542
+ enableDraftInUpdateMode,
543
+ ],
535
544
  );
536
545
 
537
546
  // ============================================================
@@ -553,18 +562,16 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
553
562
 
554
563
  // Cross-field validation
555
564
  // Transform ValidationRule[] to the format expected by validateCrossField
556
- const transformedRules = schemaConfig.crossFieldValidation.map(
557
- (rule) => ({
558
- Id: rule.Id,
559
- Condition: { ExpressionTree: rule.ExpressionTree },
560
- Message: rule.Message || `Validation failed for ${rule.Name}`,
561
- })
562
- );
565
+ const transformedRules = schemaConfig.crossFieldValidation.map((rule) => ({
566
+ Id: rule.Id,
567
+ Condition: { ExpressionTree: rule.ExpressionTree },
568
+ Message: rule.Message || `Validation failed for ${rule.Name}`,
569
+ }));
563
570
 
564
571
  const crossFieldErrors = validateCrossField(
565
572
  transformedRules,
566
573
  values as any,
567
- referenceData
574
+ referenceData,
568
575
  );
569
576
 
570
577
  if (crossFieldErrors.length > 0) {
@@ -603,11 +610,14 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
603
610
  */
604
611
  const handleSubmit = useCallback(
605
612
  (
606
- onSuccess?: (data: T, e?: React.BaseSyntheticEvent) => void | Promise<void>,
613
+ onSuccess?: (
614
+ data: T,
615
+ e?: React.BaseSyntheticEvent,
616
+ ) => void | Promise<void>,
607
617
  onError?: (
608
618
  error: import("react-hook-form").FieldErrors<T> | Error,
609
- e?: React.BaseSyntheticEvent
610
- ) => void | Promise<void>
619
+ e?: React.BaseSyntheticEvent,
620
+ ) => void | Promise<void>,
611
621
  ) => {
612
622
  return rhfForm.handleSubmit(
613
623
  // RHF onValid handler - validation passed, now do cross-field + API
@@ -627,13 +637,13 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
627
637
  Id: rule.Id,
628
638
  Condition: { ExpressionTree: rule.ExpressionTree },
629
639
  Message: rule.Message || `Validation failed for ${rule.Name}`,
630
- })
640
+ }),
631
641
  );
632
642
 
633
643
  const crossFieldErrors = validateCrossField(
634
644
  transformedRules,
635
645
  data as any,
636
- referenceData
646
+ referenceData,
637
647
  );
638
648
 
639
649
  if (crossFieldErrors.length > 0) {
@@ -649,12 +659,21 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
649
659
  return;
650
660
  }
651
661
 
662
+ // Extract field types from schema for Reference field transformation
663
+ const fieldTypes: Record<string, string> = {};
664
+ Object.entries(schemaConfig.fields).forEach(
665
+ ([fieldName, field]) => {
666
+ fieldTypes[fieldName] = field._bdoField.Type;
667
+ },
668
+ );
669
+
652
670
  // Clean data for submission
653
671
  const cleanedData = cleanFormData(
654
672
  data as any,
655
673
  schemaConfig.computedFields,
656
674
  operation,
657
- recordData as Partial<T> | undefined
675
+ recordData as Partial<T> | undefined,
676
+ fieldTypes,
658
677
  );
659
678
 
660
679
  let result;
@@ -667,7 +686,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
667
686
  // Interactive create: must have draftId
668
687
  if (!draftId) {
669
688
  throw new Error(
670
- "Interactive create mode requires a draft ID. Draft creation may have failed."
689
+ "Interactive create mode requires a draft ID. Draft creation may have failed.",
671
690
  );
672
691
  }
673
692
  // POST /{bdo_id}/draft with _id in payload
@@ -687,7 +706,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
687
706
  source,
688
707
  operation,
689
708
  cleanedData,
690
- recordId
709
+ recordId,
691
710
  );
692
711
 
693
712
  if (!result.success) {
@@ -716,7 +735,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
716
735
  // RHF onInvalid handler - validation failed
717
736
  (errors, event) => {
718
737
  onError?.(errors, event);
719
- }
738
+ },
720
739
  );
721
740
  },
722
741
  [
@@ -729,7 +748,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
729
748
  recordData,
730
749
  isInteractiveMode,
731
750
  draftId,
732
- ]
751
+ ],
733
752
  );
734
753
 
735
754
  // ============================================================
@@ -740,7 +759,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
740
759
  <K extends keyof T>(fieldName: K): FormFieldConfigType | null => {
741
760
  return schemaConfig?.fields[fieldName as string] || null;
742
761
  },
743
- [schemaConfig]
762
+ [schemaConfig],
744
763
  );
745
764
 
746
765
  const getFields = useCallback((): Record<keyof T, FormFieldConfigType> => {
@@ -758,7 +777,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
758
777
  <K extends keyof T>(fieldName: K): boolean => {
759
778
  return !!schemaConfig?.fields[fieldName as string];
760
779
  },
761
- [schemaConfig]
780
+ [schemaConfig],
762
781
  );
763
782
 
764
783
  const isFieldRequired = useCallback(
@@ -767,7 +786,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
767
786
  schemaConfig?.requiredFields.includes(fieldName as string) || false
768
787
  );
769
788
  },
770
- [schemaConfig]
789
+ [schemaConfig],
771
790
  );
772
791
 
773
792
  const isFieldComputed = useCallback(
@@ -776,7 +795,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
776
795
  schemaConfig?.computedFields.includes(fieldName as string) || false
777
796
  );
778
797
  },
779
- [schemaConfig]
798
+ [schemaConfig],
780
799
  );
781
800
 
782
801
  // ============================================================
@@ -806,12 +825,12 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
806
825
 
807
826
  const computedFields = useMemo<Array<keyof T>>(
808
827
  () => (schemaConfig?.computedFields as Array<keyof T>) || [],
809
- [schemaConfig]
828
+ [schemaConfig],
810
829
  );
811
830
 
812
831
  const requiredFields = useMemo<Array<keyof T>>(
813
832
  () => (schemaConfig?.requiredFields as Array<keyof T>) || [],
814
- [schemaConfig]
833
+ [schemaConfig],
815
834
  );
816
835
 
817
836
  // ============================================================
@@ -864,7 +883,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
864
883
  value,
865
884
  [rule],
866
885
  currentValues,
867
- lastFormValues as T | undefined
886
+ lastFormValues as T | undefined,
868
887
  );
869
888
  if (!result.isValid) {
870
889
  return result.message || rule.Message || "Invalid value";
@@ -936,7 +955,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
936
955
  onBlur: enhancedOnBlur,
937
956
  });
938
957
  },
939
- [rhfForm, validationRules, triggerComputationAfterValidation, mode]
958
+ [rhfForm, validationRules, triggerComputationAfterValidation, mode],
940
959
  );
941
960
 
942
961
  return {
package/sdk/index.ts CHANGED
@@ -92,6 +92,9 @@ export type {
92
92
  LookupFieldType,
93
93
  ArrayFieldType,
94
94
  JSONFieldType,
95
+ ReferenceFieldType,
96
+ ExtractReferenceType,
97
+ ExtractFetchFieldType,
95
98
  } from './types/base-fields';
96
99
 
97
100
  // ============================================================