@ram_28/kf-ai-sdk 2.0.4 → 2.0.5

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 (66) hide show
  1. package/dist/api.mjs +1 -1
  2. package/dist/auth.mjs +1 -1
  3. package/dist/bdo/core/Item.d.ts.map +1 -1
  4. package/dist/bdo/core/types.d.ts +1 -0
  5. package/dist/bdo/core/types.d.ts.map +1 -1
  6. package/dist/bdo.cjs +1 -1
  7. package/dist/bdo.mjs +91 -86
  8. package/dist/components/hooks/useForm/createItemProxy.d.ts.map +1 -1
  9. package/dist/components/hooks/useForm/index.d.ts +1 -1
  10. package/dist/components/hooks/useForm/index.d.ts.map +1 -1
  11. package/dist/components/hooks/useForm/types.d.ts +6 -16
  12. package/dist/components/hooks/useForm/types.d.ts.map +1 -1
  13. package/dist/components/hooks/useForm/useForm.d.ts +0 -1
  14. package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
  15. package/dist/components/hooks/useTable/types.d.ts +2 -2
  16. package/dist/components/hooks/useTable/useTable.d.ts.map +1 -1
  17. package/dist/{constants-BQrBcCON.js → constants-CYJih7y4.js} +2 -2
  18. package/dist/filter.mjs +1 -1
  19. package/dist/form.cjs +1 -1
  20. package/dist/form.mjs +158 -283
  21. package/dist/form.types.d.ts +1 -1
  22. package/dist/form.types.d.ts.map +1 -1
  23. package/dist/table.cjs +1 -1
  24. package/dist/table.mjs +65 -65
  25. package/dist/types/constants.d.ts +11 -11
  26. package/dist/types/constants.d.ts.map +1 -1
  27. package/dist/utils/api/buildListOptions.d.ts +1 -1
  28. package/dist/utils/api/buildListOptions.d.ts.map +1 -1
  29. package/dist/workflow/Activity.d.ts +14 -5
  30. package/dist/workflow/Activity.d.ts.map +1 -1
  31. package/dist/workflow/ActivityInstance.d.ts +1 -1
  32. package/dist/workflow/ActivityInstance.d.ts.map +1 -1
  33. package/dist/workflow/client.d.ts +14 -4
  34. package/dist/workflow/client.d.ts.map +1 -1
  35. package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +1 -1
  36. package/dist/workflow/types.d.ts +26 -9
  37. package/dist/workflow/types.d.ts.map +1 -1
  38. package/dist/workflow.cjs +1 -1
  39. package/dist/workflow.mjs +296 -240
  40. package/docs/bdo.md +63 -0
  41. package/docs/useAuth.md +27 -0
  42. package/docs/useFilter.md +67 -0
  43. package/docs/useForm.md +59 -0
  44. package/docs/useTable.md +106 -13
  45. package/docs/workflow.md +93 -49
  46. package/package.json +2 -2
  47. package/sdk/bdo/core/Item.ts +8 -0
  48. package/sdk/bdo/core/types.ts +1 -0
  49. package/sdk/components/hooks/useForm/createItemProxy.ts +8 -0
  50. package/sdk/components/hooks/useForm/index.ts +0 -1
  51. package/sdk/components/hooks/useForm/types.ts +7 -18
  52. package/sdk/components/hooks/useForm/useForm.ts +23 -109
  53. package/sdk/components/hooks/useTable/types.ts +2 -2
  54. package/sdk/components/hooks/useTable/useTable.llm.txt +7 -7
  55. package/sdk/components/hooks/useTable/useTable.ts +9 -8
  56. package/sdk/form.types.ts +0 -1
  57. package/sdk/types/constants.ts +11 -11
  58. package/sdk/utils/api/buildListOptions.ts +2 -3
  59. package/sdk/workflow/Activity.ts +31 -10
  60. package/sdk/workflow/ActivityInstance.ts +1 -1
  61. package/sdk/workflow/client.ts +73 -10
  62. package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +4 -0
  63. package/sdk/workflow/types.ts +22 -9
  64. package/dist/components/hooks/useForm/useDraftInteraction.d.ts +0 -26
  65. package/dist/components/hooks/useForm/useDraftInteraction.d.ts.map +0 -1
  66. package/sdk/components/hooks/useForm/useDraftInteraction.ts +0 -251
@@ -41,9 +41,14 @@ import type {
41
41
  * await act.draftEnd("inst_123", data);
42
42
  * await act.complete("inst_123");
43
43
  *
44
- * // List operations
45
- * await act.list({ Page: 1, PageSize: 10 });
46
- * await act.metric({ Metric: [...] });
44
+ * // List operations (by status)
45
+ * await act.inProgressList({ Page: 1, PageSize: 10 });
46
+ * await act.completedList({ Page: 1, PageSize: 10 });
47
+ * await act.inProgressMetric({ Metric: [...] });
48
+ * await act.completedMetric({ Metric: [...] });
49
+ *
50
+ * // Global process progress
51
+ * const progress = await wf.progress();
47
52
  * ```
48
53
  */
49
54
  export class Workflow<T = any> {
@@ -72,6 +77,26 @@ export class Workflow<T = any> {
72
77
  return response.json();
73
78
  }
74
79
 
80
+ /**
81
+ * Get global progress across the entire business process.
82
+ * Returns a list of progress entries for each stage/activity.
83
+ */
84
+ async progress(): Promise<ActivityProgressType[]> {
85
+ const response = await fetch(
86
+ `${getApiBaseUrl()}/api/app/process/${this.bp_id}/progress`,
87
+ {
88
+ method: "GET",
89
+ headers: getDefaultHeaders(),
90
+ }
91
+ );
92
+
93
+ if (!response.ok) {
94
+ throw new Error(`Failed to get process progress: ${response.statusText}`);
95
+ }
96
+
97
+ return response.json();
98
+ }
99
+
75
100
  /**
76
101
  * Get all operations for a specific activity
77
102
  * @param activity_id - Activity identifier
@@ -82,39 +107,77 @@ export class Workflow<T = any> {
82
107
  return {
83
108
  // ── List-level ────────────────────────────────────────────
84
109
 
85
- async list(options?: ListOptionsType): Promise<ListResponseType<ActivityInstanceFieldsType & T>> {
110
+ async inProgressList(options?: ListOptionsType): Promise<ListResponseType<ActivityInstanceFieldsType & T>> {
86
111
  const requestBody: ListOptionsType = {
87
112
  Type: "List",
88
113
  ...options,
89
114
  };
90
115
 
91
- const response = await fetch(`${getApiBaseUrl()}${base}/list`, {
116
+ const response = await fetch(`${getApiBaseUrl()}${base}/inprogress/list`, {
117
+ method: "POST",
118
+ headers: getDefaultHeaders(),
119
+ body: JSON.stringify(requestBody),
120
+ });
121
+
122
+ if (!response.ok) {
123
+ throw new Error(`Failed to list in-progress activities: ${response.statusText}`);
124
+ }
125
+
126
+ return response.json();
127
+ },
128
+
129
+ async completedList(options?: ListOptionsType): Promise<ListResponseType<ActivityInstanceFieldsType & T>> {
130
+ const requestBody: ListOptionsType = {
131
+ Type: "List",
132
+ ...options,
133
+ };
134
+
135
+ const response = await fetch(`${getApiBaseUrl()}${base}/completed/list`, {
136
+ method: "POST",
137
+ headers: getDefaultHeaders(),
138
+ body: JSON.stringify(requestBody),
139
+ });
140
+
141
+ if (!response.ok) {
142
+ throw new Error(`Failed to list completed activities: ${response.statusText}`);
143
+ }
144
+
145
+ return response.json();
146
+ },
147
+
148
+ async inProgressMetric(options: Omit<MetricOptionsType, "Type">): Promise<MetricResponseType> {
149
+ const requestBody: MetricOptionsType = {
150
+ Type: "Metric",
151
+ ...options,
152
+ };
153
+
154
+ const response = await fetch(`${getApiBaseUrl()}${base}/inprogress/metric`, {
92
155
  method: "POST",
93
156
  headers: getDefaultHeaders(),
94
157
  body: JSON.stringify(requestBody),
95
158
  });
96
159
 
97
160
  if (!response.ok) {
98
- throw new Error(`Failed to list activities: ${response.statusText}`);
161
+ throw new Error(`Failed to get in-progress activity metrics: ${response.statusText}`);
99
162
  }
100
163
 
101
164
  return response.json();
102
165
  },
103
166
 
104
- async metric(options: Omit<MetricOptionsType, "Type">): Promise<MetricResponseType> {
167
+ async completedMetric(options: Omit<MetricOptionsType, "Type">): Promise<MetricResponseType> {
105
168
  const requestBody: MetricOptionsType = {
106
169
  Type: "Metric",
107
170
  ...options,
108
171
  };
109
172
 
110
- const response = await fetch(`${getApiBaseUrl()}${base}/metric`, {
173
+ const response = await fetch(`${getApiBaseUrl()}${base}/completed/metric`, {
111
174
  method: "POST",
112
175
  headers: getDefaultHeaders(),
113
176
  body: JSON.stringify(requestBody),
114
177
  });
115
178
 
116
179
  if (!response.ok) {
117
- throw new Error(`Failed to get activity metrics: ${response.statusText}`);
180
+ throw new Error(`Failed to get completed activity metrics: ${response.statusText}`);
118
181
  }
119
182
 
120
183
  return response.json();
@@ -191,7 +254,7 @@ export class Workflow<T = any> {
191
254
  return response.json();
192
255
  },
193
256
 
194
- async progress(instanceId: string): Promise<ActivityProgressType> {
257
+ async progress(instanceId: string): Promise<ActivityProgressType[]> {
195
258
  const response = await fetch(`${getApiBaseUrl()}${base}/${instanceId}/progress`, {
196
259
  method: "GET",
197
260
  headers: getDefaultHeaders(),
@@ -80,6 +80,8 @@ export function createActivityItemProxy<A extends Activity<any, any, any>>(
80
80
  defaultValue: bdoField?.defaultValue,
81
81
  meta: fieldMeta,
82
82
  get: () => form.getValues(prop as Path<FieldValues>),
83
+ getOrDefault: (fallback: unknown) =>
84
+ form.getValues(prop as Path<FieldValues>) ?? fallback,
83
85
  set: (value: unknown) => {
84
86
  form.setValue(prop as Path<FieldValues>, value as any, {
85
87
  shouldDirty: true,
@@ -99,6 +101,8 @@ export function createActivityItemProxy<A extends Activity<any, any, any>>(
99
101
  defaultValue: bdoField?.defaultValue,
100
102
  meta: fieldMeta,
101
103
  get: () => form.getValues(prop as Path<FieldValues>),
104
+ getOrDefault: (fallback: unknown) =>
105
+ form.getValues(prop as Path<FieldValues>) ?? fallback,
102
106
  validate,
103
107
  };
104
108
  return accessor;
@@ -28,12 +28,19 @@ export interface WorkflowStartResponseType {
28
28
  }
29
29
 
30
30
  /**
31
- * Response from the activity progress endpoint
31
+ * Response from the activity progress endpoint.
32
+ * Both global (Workflow.progress()) and instance-level (ActivityInstance.progress())
33
+ * return ActivityProgressType[].
32
34
  */
33
35
  export interface ActivityProgressType {
34
- Stage?: string;
35
- Progress?: number;
36
- [key: string]: any;
36
+ ActivityId: string;
37
+ ActivityInstanceId: string;
38
+ ActivityType: string;
39
+ AssignedTo: { Type: string; _id: string }[];
40
+ CompletedAt: string | null;
41
+ CompletedBy: { _id: string; _name: string } | null;
42
+ Status: "COMPLETED" | "IN_PROGRESS";
43
+ _name: string;
37
44
  }
38
45
 
39
46
  /**
@@ -56,11 +63,17 @@ export type ActivityInstanceFieldsType = {
56
63
  export interface ActivityOperations<T> {
57
64
  // ── List-level ──────────────────────────────────────────────
58
65
 
59
- /** List activity instances (POST .../list) */
60
- list(options?: ListOptionsType): Promise<ListResponseType<ActivityInstanceFieldsType & T>>;
66
+ /** List in-progress activity instances (POST .../inprogress/list) */
67
+ inProgressList(options?: ListOptionsType): Promise<ListResponseType<ActivityInstanceFieldsType & T>>;
61
68
 
62
- /** Get activity metrics (POST .../metric) */
63
- metric(options: Omit<MetricOptionsType, "Type">): Promise<MetricResponseType>;
69
+ /** List completed activity instances (POST .../completed/list) */
70
+ completedList(options?: ListOptionsType): Promise<ListResponseType<ActivityInstanceFieldsType & T>>;
71
+
72
+ /** Get in-progress activity metrics (POST .../inprogress/metric) */
73
+ inProgressMetric(options: Omit<MetricOptionsType, "Type">): Promise<MetricResponseType>;
74
+
75
+ /** Get completed activity metrics (POST .../completed/metric) */
76
+ completedMetric(options: Omit<MetricOptionsType, "Type">): Promise<MetricResponseType>;
64
77
 
65
78
  // ── Instance-level ──────────────────────────────────────────
66
79
 
@@ -80,5 +93,5 @@ export interface ActivityOperations<T> {
80
93
  complete(instanceId: string): Promise<CreateUpdateResponseType>;
81
94
 
82
95
  /** Get activity progress (GET .../progress) */
83
- progress(instanceId: string): Promise<ActivityProgressType>;
96
+ progress(instanceId: string): Promise<ActivityProgressType[]>;
84
97
  }
@@ -1,26 +0,0 @@
1
- import type { UseFormReturn, FieldValues } from "react-hook-form";
2
- import type { BaseField } from "../../../bdo/fields/BaseField";
3
- import type { InteractiveCreatableBdo } from "./types";
4
- interface UseDraftInteractionOptions {
5
- /** The BDO instance — must expose interactive draft methods */
6
- bdo: InteractiveCreatableBdo;
7
- /** RHF form instance */
8
- form: UseFormReturn<FieldValues>;
9
- /** RHF validation mode */
10
- mode: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
11
- /** BDO field definitions (for determining dirty fields) */
12
- fields: Record<string, BaseField<unknown>>;
13
- /** Whether interactive mode is enabled */
14
- enabled: boolean;
15
- }
16
- interface UseDraftInteractionReturn {
17
- draftId: string | undefined;
18
- isInitializingDraft: boolean;
19
- isInteracting: boolean;
20
- interactionError: Error | null;
21
- triggerInteraction: () => void;
22
- commitDraft: (dirtyData: Record<string, unknown>) => Promise<unknown>;
23
- }
24
- export declare function useDraftInteraction(options: UseDraftInteractionOptions): UseDraftInteractionReturn;
25
- export {};
26
- //# sourceMappingURL=useDraftInteraction.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useDraftInteraction.d.ts","sourceRoot":"","sources":["../../../../sdk/components/hooks/useForm/useDraftInteraction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAMvD,UAAU,0BAA0B;IAClC,+DAA+D;IAC/D,GAAG,EAAE,uBAAuB,CAAC;IAC7B,wBAAwB;IACxB,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACjC,0BAA0B;IAC1B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,KAAK,CAAC;IAC/D,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,0CAA0C;IAC1C,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,KAAK,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAYD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,yBAAyB,CA+M3B"}
@@ -1,251 +0,0 @@
1
- import { useState, useEffect, useCallback, useRef } from "react";
2
- import type { UseFormReturn, FieldValues } from "react-hook-form";
3
- import type { BaseField } from "../../../bdo/fields/BaseField";
4
- import type { InteractiveCreatableBdo } from "./types";
5
-
6
- // ============================================================
7
- // TYPES
8
- // ============================================================
9
-
10
- interface UseDraftInteractionOptions {
11
- /** The BDO instance — must expose interactive draft methods */
12
- bdo: InteractiveCreatableBdo;
13
- /** RHF form instance */
14
- form: UseFormReturn<FieldValues>;
15
- /** RHF validation mode */
16
- mode: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
17
- /** BDO field definitions (for determining dirty fields) */
18
- fields: Record<string, BaseField<unknown>>;
19
- /** Whether interactive mode is enabled */
20
- enabled: boolean;
21
- }
22
-
23
- interface UseDraftInteractionReturn {
24
- draftId: string | undefined;
25
- isInitializingDraft: boolean;
26
- isInteracting: boolean;
27
- interactionError: Error | null;
28
- triggerInteraction: () => void;
29
- commitDraft: (dirtyData: Record<string, unknown>) => Promise<unknown>;
30
- }
31
-
32
- // ============================================================
33
- // DEBOUNCE DELAY
34
- // ============================================================
35
-
36
- const DEBOUNCE_MS = 300;
37
-
38
- // ============================================================
39
- // HOOK
40
- // ============================================================
41
-
42
- export function useDraftInteraction(
43
- options: UseDraftInteractionOptions,
44
- ): UseDraftInteractionReturn {
45
- const { bdo, form, mode, fields, enabled } = options;
46
-
47
- // ============================================================
48
- // STATE
49
- // ============================================================
50
-
51
- const [draftId, setDraftId] = useState<string | undefined>(undefined);
52
- const [isInitializingDraft, setIsInitializingDraft] = useState(false);
53
- const [isInteracting, setIsInteracting] = useState(false);
54
- const [interactionError, setInteractionError] = useState<Error | null>(null);
55
-
56
- // ============================================================
57
- // REFS (for concurrency control & loop prevention)
58
- // ============================================================
59
-
60
- /** Tracks the latest interaction call — stale responses are discarded */
61
- const interactionCounterRef = useRef(0);
62
-
63
- /** Prevents re-trigger when applying computed values via setValue */
64
- const isApplyingComputedRef = useRef(false);
65
-
66
- /** Debounce timer for onChange mode */
67
- const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
68
-
69
- /** AbortController for cleanup on unmount */
70
- const abortControllerRef = useRef<AbortController | null>(null);
71
-
72
- // ============================================================
73
- // DRAFT INITIALIZATION (Create mode only)
74
- // ============================================================
75
-
76
- useEffect(() => {
77
- if (!enabled) return;
78
-
79
- let cancelled = false;
80
- setIsInitializingDraft(true);
81
-
82
- const controller = new AbortController();
83
- abortControllerRef.current = controller;
84
-
85
- bdo
86
- .draftInteraction({})
87
- .then((response) => {
88
- if (cancelled || controller.signal.aborted) return;
89
- const id = response._id;
90
- setDraftId(id);
91
- // Set _id into form without marking dirty
92
- form.setValue("_id" as any, id, { shouldDirty: false });
93
- setInteractionError(null);
94
- })
95
- .catch((error) => {
96
- if (cancelled || controller.signal.aborted) return;
97
- setInteractionError(error instanceof Error ? error : new Error(String(error)));
98
- })
99
- .finally(() => {
100
- if (!cancelled) setIsInitializingDraft(false);
101
- });
102
-
103
- return () => {
104
- cancelled = true;
105
- controller.abort();
106
- };
107
- }, [enabled, bdo, form]);
108
-
109
- // ============================================================
110
- // CORE INTERACTION LOGIC
111
- // ============================================================
112
-
113
- const executeInteraction = useCallback(async () => {
114
- if (!enabled || !draftId) return;
115
- if (isApplyingComputedRef.current) return;
116
-
117
- // Build payload from dirty fields
118
- const dirtyFields = form.formState.dirtyFields;
119
- const allValues = form.getValues();
120
- const payload: Record<string, unknown> = {};
121
-
122
- for (const [key, isDirty] of Object.entries(dirtyFields)) {
123
- if (isDirty && fields[key] && !fields[key].readOnly) {
124
- payload[key] = allValues[key];
125
- }
126
- }
127
-
128
- // Skip if nothing changed
129
- if (Object.keys(payload).length === 0) return;
130
-
131
- // Increment counter for concurrency control
132
- const currentCounter = ++interactionCounterRef.current;
133
-
134
- setIsInteracting(true);
135
-
136
- try {
137
- const response = await bdo.draftInteraction({
138
- _id: draftId,
139
- ...payload,
140
- } as any);
141
-
142
- // Only apply if this is still the latest interaction
143
- if (currentCounter !== interactionCounterRef.current) return;
144
-
145
- // Apply computed values back to form
146
- isApplyingComputedRef.current = true;
147
- try {
148
- for (const [key, value] of Object.entries(response)) {
149
- // Skip _id and fields the user has dirty (don't overwrite user input)
150
- if (key === "_id") continue;
151
- if (dirtyFields[key]) continue;
152
-
153
- form.setValue(key as any, value, {
154
- shouldDirty: false,
155
- shouldValidate: false,
156
- });
157
- }
158
- } finally {
159
- // Reset flag after React settles
160
- // Using setTimeout(0) ensures setValue batch is complete
161
- setTimeout(() => {
162
- isApplyingComputedRef.current = false;
163
- }, 0);
164
- }
165
-
166
- setInteractionError(null);
167
- } catch (error) {
168
- // Only set error if this is still the latest interaction
169
- if (currentCounter !== interactionCounterRef.current) return;
170
- setInteractionError(error instanceof Error ? error : new Error(String(error)));
171
- } finally {
172
- if (currentCounter === interactionCounterRef.current) {
173
- setIsInteracting(false);
174
- }
175
- }
176
- }, [enabled, draftId, form, fields, bdo]);
177
-
178
- // ============================================================
179
- // TRIGGER INTERACTION (with optional debounce)
180
- // ============================================================
181
-
182
- const triggerInteraction = useCallback(() => {
183
- if (!enabled) return;
184
-
185
- // For onChange/all modes, debounce the interaction
186
- if (mode === "onChange" || mode === "all") {
187
- if (debounceTimerRef.current) {
188
- clearTimeout(debounceTimerRef.current);
189
- }
190
- debounceTimerRef.current = setTimeout(() => {
191
- executeInteraction();
192
- }, DEBOUNCE_MS);
193
- } else {
194
- // For onBlur/onTouched/onSubmit, trigger immediately
195
- executeInteraction();
196
- }
197
- }, [enabled, mode, executeInteraction]);
198
-
199
- // ============================================================
200
- // COMMIT DRAFT (for handleSubmit)
201
- // ============================================================
202
-
203
- const commitDraft = useCallback(
204
- async (dirtyData: Record<string, unknown>): Promise<unknown> => {
205
- return bdo.draft({
206
- _id: draftId,
207
- ...dirtyData,
208
- } as any);
209
- },
210
- [bdo, draftId],
211
- );
212
-
213
- // ============================================================
214
- // CLEANUP
215
- // ============================================================
216
-
217
- useEffect(() => {
218
- return () => {
219
- if (debounceTimerRef.current) {
220
- clearTimeout(debounceTimerRef.current);
221
- }
222
- abortControllerRef.current?.abort();
223
- };
224
- }, []);
225
-
226
- // ============================================================
227
- // DISABLED MODE (return no-ops)
228
- // ============================================================
229
-
230
- if (!enabled) {
231
- return {
232
- draftId: undefined,
233
- isInitializingDraft: false,
234
- isInteracting: false,
235
- interactionError: null,
236
- triggerInteraction: () => {},
237
- commitDraft: async () => {
238
- throw new Error("Draft interaction is not enabled");
239
- },
240
- };
241
- }
242
-
243
- return {
244
- draftId,
245
- isInitializingDraft,
246
- isInteracting,
247
- interactionError,
248
- triggerInteraction,
249
- commitDraft,
250
- };
251
- }