@ram_28/kf-ai-sdk 2.0.2 → 2.0.4

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 (97) hide show
  1. package/dist/BaseField-B6da88U7.js +40 -0
  2. package/dist/BaseField-Drp0-OxL.cjs +1 -0
  3. package/dist/api/client.d.ts +7 -0
  4. package/dist/api/client.d.ts.map +1 -1
  5. package/dist/api/index.d.ts +1 -1
  6. package/dist/api/index.d.ts.map +1 -1
  7. package/dist/api.cjs +1 -1
  8. package/dist/api.mjs +3 -3
  9. package/dist/auth.cjs +1 -1
  10. package/dist/auth.mjs +2 -2
  11. package/dist/bdo/core/BaseBdo.d.ts +4 -0
  12. package/dist/bdo/core/BaseBdo.d.ts.map +1 -1
  13. package/dist/bdo.cjs +1 -1
  14. package/dist/bdo.mjs +91 -118
  15. package/dist/client-BULEEaCP.js +222 -0
  16. package/dist/client-DtPpfJc1.cjs +1 -0
  17. package/dist/components/hooks/useForm/index.d.ts +1 -1
  18. package/dist/components/hooks/useForm/index.d.ts.map +1 -1
  19. package/dist/components/hooks/useForm/types.d.ts +15 -2
  20. package/dist/components/hooks/useForm/types.d.ts.map +1 -1
  21. package/dist/components/hooks/useForm/useDraftInteraction.d.ts +26 -0
  22. package/dist/components/hooks/useForm/useDraftInteraction.d.ts.map +1 -0
  23. package/dist/components/hooks/useForm/useForm.d.ts +1 -0
  24. package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
  25. package/dist/{constants-CM9xOACN.js → constants-BQrBcCON.js} +5 -5
  26. package/dist/error-handling-CAoD0Kwb.cjs +1 -0
  27. package/dist/error-handling-CrhTtD88.js +14 -0
  28. package/dist/filter.mjs +1 -1
  29. package/dist/form.cjs +1 -1
  30. package/dist/form.mjs +313 -1187
  31. package/dist/form.types.d.ts +1 -1
  32. package/dist/form.types.d.ts.map +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.esm-Cj63v5ny.js +1014 -0
  36. package/dist/index.esm-DuwT11sx.cjs +1 -0
  37. package/dist/{metadata-BN57S6W9.cjs → metadata-BJWukIqS.cjs} +1 -1
  38. package/dist/{metadata-P7DGCgIG.js → metadata-CJuFxytC.js} +1 -1
  39. package/dist/table.cjs +1 -1
  40. package/dist/table.mjs +83 -93
  41. package/dist/types/constants.d.ts +2 -2
  42. package/dist/types/constants.d.ts.map +1 -1
  43. package/dist/workflow/Activity.d.ts +85 -0
  44. package/dist/workflow/Activity.d.ts.map +1 -0
  45. package/dist/workflow/ActivityInstance.d.ts +96 -0
  46. package/dist/workflow/ActivityInstance.d.ts.map +1 -0
  47. package/dist/workflow/client.d.ts +39 -0
  48. package/dist/workflow/client.d.ts.map +1 -0
  49. package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts +16 -0
  50. package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +1 -0
  51. package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts +22 -0
  52. package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts.map +1 -0
  53. package/dist/workflow/components/useActivityForm/index.d.ts +3 -0
  54. package/dist/workflow/components/useActivityForm/index.d.ts.map +1 -0
  55. package/dist/workflow/components/useActivityForm/types.d.ts +80 -0
  56. package/dist/workflow/components/useActivityForm/types.d.ts.map +1 -0
  57. package/dist/workflow/components/useActivityForm/useActivityForm.d.ts +4 -0
  58. package/dist/workflow/components/useActivityForm/useActivityForm.d.ts.map +1 -0
  59. package/dist/workflow/index.d.ts +8 -0
  60. package/dist/workflow/index.d.ts.map +1 -0
  61. package/dist/workflow/types.d.ts +53 -0
  62. package/dist/workflow/types.d.ts.map +1 -0
  63. package/dist/workflow.cjs +1 -0
  64. package/dist/workflow.d.ts +8 -0
  65. package/dist/workflow.d.ts.map +1 -0
  66. package/dist/workflow.mjs +565 -0
  67. package/dist/workflow.types.cjs +1 -0
  68. package/dist/workflow.types.d.ts +2 -0
  69. package/dist/workflow.types.d.ts.map +1 -0
  70. package/dist/workflow.types.mjs +1 -0
  71. package/docs/workflow.md +703 -0
  72. package/package.json +21 -1
  73. package/sdk/api/client.ts +85 -52
  74. package/sdk/api/index.ts +1 -0
  75. package/sdk/api/metadata.ts +4 -4
  76. package/sdk/bdo/core/BaseBdo.ts +10 -0
  77. package/sdk/components/hooks/useForm/index.ts +1 -0
  78. package/sdk/components/hooks/useForm/types.ts +17 -3
  79. package/sdk/components/hooks/useForm/useDraftInteraction.ts +251 -0
  80. package/sdk/components/hooks/useForm/useForm.ts +115 -24
  81. package/sdk/form.types.ts +1 -0
  82. package/sdk/index.ts +6 -0
  83. package/sdk/types/constants.ts +2 -2
  84. package/sdk/workflow/Activity.ts +181 -0
  85. package/sdk/workflow/ActivityInstance.ts +339 -0
  86. package/sdk/workflow/client.ts +208 -0
  87. package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +126 -0
  88. package/sdk/workflow/components/useActivityForm/createActivityResolver.ts +61 -0
  89. package/sdk/workflow/components/useActivityForm/index.ts +5 -0
  90. package/sdk/workflow/components/useActivityForm/types.ts +166 -0
  91. package/sdk/workflow/components/useActivityForm/useActivityForm.ts +386 -0
  92. package/sdk/workflow/index.ts +20 -0
  93. package/sdk/workflow/types.ts +84 -0
  94. package/sdk/workflow.ts +25 -0
  95. package/sdk/workflow.types.ts +11 -0
  96. package/dist/client-Bo-RLKJi.cjs +0 -1
  97. package/dist/client-eA4VvNTo.js +0 -178
@@ -0,0 +1,703 @@
1
+ # Workflow SDK API
2
+
3
+ The Workflow SDK provides a type-safe client for orchestrating business processes (workflows). Each workflow has typed Activity classes with field definitions, and a React hook (`useActivityForm`) for building forms bound to activity input fields.
4
+
5
+ ## Imports
6
+
7
+ ```typescript
8
+ // Runtime exports
9
+ import {
10
+ Workflow,
11
+ Activity,
12
+ ActivityInstance,
13
+ useActivityForm,
14
+ } from "@ram_28/kf-ai-sdk/workflow";
15
+
16
+ // Type-only exports
17
+ import type {
18
+ ActivityInstanceFieldsType,
19
+ ActivityProgressType,
20
+ WorkflowStartResponseType,
21
+ UseActivityFormOptions,
22
+ UseActivityFormReturn,
23
+ } from "@ram_28/kf-ai-sdk/workflow";
24
+
25
+ // Field classes (for defining Activity fields)
26
+ import {
27
+ StringField,
28
+ NumberField,
29
+ BooleanField,
30
+ DateTimeField,
31
+ SelectField,
32
+ ReferenceField,
33
+ } from "@ram_28/kf-ai-sdk/bdo/fields";
34
+
35
+ // Field types (for entity type definitions)
36
+ import type {
37
+ StringFieldType,
38
+ NumberFieldType,
39
+ BooleanFieldType,
40
+ DateFieldType,
41
+ DateTimeFieldType,
42
+ SelectFieldType,
43
+ ReferenceFieldType,
44
+ } from "@ram_28/kf-ai-sdk/types";
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Type Definitions
50
+
51
+ ### WorkflowStartResponseType
52
+
53
+ ```typescript
54
+ interface WorkflowStartResponseType {
55
+ activityId: string; // First activity ID in the workflow
56
+ activityInstanceId: string; // Instance ID for the started activity
57
+ }
58
+ ```
59
+
60
+ ### ActivityProgressType
61
+
62
+ ```typescript
63
+ interface ActivityProgressType {
64
+ Stage?: string;
65
+ Progress?: number;
66
+ [key: string]: any;
67
+ }
68
+ ```
69
+
70
+ ### ActivityInstanceFieldsType
71
+
72
+ System fields present on every activity instance. Returned alongside activity-specific fields from `getInstanceList()`.
73
+
74
+ ```typescript
75
+ type ActivityInstanceFieldsType = {
76
+ _id: StringFieldType;
77
+ Status: SelectFieldType<"InProgress" | "Completed">;
78
+ AssignedTo: ReferenceFieldType<{ _id: StringFieldType; username: StringFieldType }>;
79
+ CompletedAt: DateTimeFieldType;
80
+ };
81
+ ```
82
+
83
+ ### UseActivityFormOptions\<A\>
84
+
85
+ ```typescript
86
+ interface UseActivityFormOptions<A extends Activity<any, any, any>> {
87
+ /** Activity instance identifier (from wf.start() or getInstanceList()) */
88
+ activity_instance_id: string;
89
+
90
+ /** Default form values */
91
+ defaultValues?: Partial<ExtractActivityEditable<A>>;
92
+
93
+ /** Validation mode (default: "onBlur") */
94
+ mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
95
+
96
+ /** Whether to load activity data on mount (default: true) */
97
+ enabled?: boolean;
98
+ }
99
+ ```
100
+
101
+ ### UseActivityFormReturn\<A\>
102
+
103
+ ```typescript
104
+ interface UseActivityFormReturn<A extends Activity<any, any, any>> {
105
+ // Core
106
+ item: FormItemType<EditableFields, ReadonlyFields>;
107
+ activity: A;
108
+ register: FormRegisterType<EditableFields, ReadonlyFields>;
109
+ handleSubmit: HandleSubmitType; // Save the activity form
110
+ handleComplete: HandleSubmitType; // Complete the activity
111
+
112
+ // RHF methods
113
+ watch: UseFormWatch;
114
+ setValue: UseFormSetValue;
115
+ getValues: UseFormGetValues;
116
+ reset: UseFormReset;
117
+ trigger: UseFormTrigger;
118
+ control: Control;
119
+
120
+ // Form state
121
+ errors: FieldErrors;
122
+ isValid: boolean;
123
+ isDirty: boolean;
124
+ isSubmitting: boolean;
125
+ isSubmitSuccessful: boolean;
126
+
127
+ // Loading
128
+ isLoading: boolean;
129
+ loadError: Error | null;
130
+ hasError: boolean;
131
+
132
+ // Operations
133
+ clearErrors: () => void;
134
+ }
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Generated Workflow SDK
140
+
141
+ Each workflow generates a TypeScript SDK with typed Activity classes and a Workflow class. These are defined in `src/bdo/workflows/` and should never be created manually.
142
+
143
+ ### Example: SimpleLeaveProcess SDK
144
+
145
+ ```typescript
146
+ // --- Activity classes ---
147
+
148
+ export type EmployeeInputEntityType = {
149
+ StartDate: DateFieldType;
150
+ EndDate: DateFieldType;
151
+ LeaveType: SelectFieldType<"PTO" | "Sick" | "Parental">;
152
+ LeaveDays: NumberFieldType;
153
+ };
154
+
155
+ export type EmployeeInputEditable = Omit<EmployeeInputEntityType, "LeaveDays">;
156
+ export type EmployeeInputReadonly = Pick<EmployeeInputEntityType, "LeaveDays">;
157
+
158
+ export class EmployeeInputActivity extends Activity<
159
+ EmployeeInputEntityType,
160
+ EmployeeInputEditable,
161
+ EmployeeInputReadonly
162
+ > {
163
+ readonly meta = {
164
+ businessProcessId: "SimpleLeaveProcess",
165
+ activityId: "EMPLOYEE_INPUT",
166
+ };
167
+
168
+ readonly StartDate = new DateTimeField({ id: "StartDate", label: "Start Date" });
169
+ readonly EndDate = new DateTimeField({ id: "EndDate", label: "End Date" });
170
+ readonly LeaveType = new SelectField<"PTO" | "Sick" | "Parental">({
171
+ id: "LeaveType", label: "Leave Type",
172
+ options: [
173
+ { value: "PTO", label: "PTO" },
174
+ { value: "Sick", label: "Sick" },
175
+ { value: "Parental", label: "Parental" },
176
+ ],
177
+ });
178
+ readonly LeaveDays = new NumberField({ id: "LeaveDays", label: "Leave Days", editable: false });
179
+ }
180
+
181
+ export type ManagerApprovalEntityType = {
182
+ ManagerApproved: BooleanFieldType;
183
+ ManagerReason: StringFieldType;
184
+ };
185
+
186
+ export class ManagerApprovalActivity extends Activity<
187
+ ManagerApprovalEntityType,
188
+ ManagerApprovalEntityType,
189
+ {}
190
+ > {
191
+ readonly meta = {
192
+ businessProcessId: "SimpleLeaveProcess",
193
+ activityId: "MANAGER_APPROVAL",
194
+ };
195
+
196
+ readonly ManagerApproved = new BooleanField({ id: "ManagerApproved", label: "Manager Approved" });
197
+ readonly ManagerReason = new StringField({ id: "ManagerReason", label: "Manager's Reason" });
198
+ }
199
+
200
+ // --- Workflow class ---
201
+
202
+ export class SimpleLeaveProcess {
203
+ async start(): Promise<WorkflowStartResponseType>;
204
+
205
+ employeeInputActivity(): EmployeeInputActivity;
206
+ managerApprovalActivity(): ManagerApprovalActivity;
207
+ }
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Activity Class
213
+
214
+ Each Activity class provides methods to query and access activity instances.
215
+
216
+ ```typescript
217
+ const activity = wf.employeeInputActivity();
218
+ ```
219
+
220
+ ### getInstanceList(options?)
221
+
222
+ List activity instances with optional filtering and pagination.
223
+
224
+ ```typescript
225
+ const result = await activity.getInstanceList({
226
+ Page: 1,
227
+ PageSize: 20,
228
+ Filter: {
229
+ Operator: "And",
230
+ Condition: [
231
+ { LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
232
+ ],
233
+ },
234
+ });
235
+
236
+ for (const item of result.Data) {
237
+ console.log(item._id, item.Status, item.StartDate);
238
+ }
239
+ ```
240
+
241
+ ### instanceMetrics(options)
242
+
243
+ Get aggregated metrics for activity instances.
244
+
245
+ ```typescript
246
+ const metrics = await activity.instanceMetrics({
247
+ Metric: [{ Field: "Status", Function: "Count" }],
248
+ });
249
+ ```
250
+
251
+ ### getInstance(instanceId)
252
+
253
+ Get a typed ActivityInstance with field accessors and persistence methods.
254
+
255
+ ```typescript
256
+ const instance = await activity.getInstance("inst_abc123");
257
+
258
+ // Field accessors (BDO Item pattern)
259
+ instance._id; // "inst_abc123"
260
+ instance.StartDate.get(); // read value (typed)
261
+ instance.StartDate.set("2026-03-01"); // set value (editable fields only)
262
+ instance.StartDate.meta; // { id: "StartDate", label: "Start Date", ... }
263
+ instance.LeaveDays.get(); // read computed/readonly field
264
+ // instance.LeaveDays.set(...) // NOT available — readonly, no set()
265
+
266
+ // Utility methods
267
+ instance.toJSON(); // convert to plain object
268
+ instance.validate(); // validate all fields
269
+
270
+ // Persistence methods
271
+ await instance.update({ StartDate: "2026-03-01" }); // update fields
272
+ await instance.save({ StartDate: "2026-03-01" }); // save and commit
273
+ await instance.complete(); // complete the activity
274
+ const progress = await instance.progress(); // get progress
275
+ ```
276
+
277
+ ---
278
+
279
+ ## useActivityForm Hook
280
+
281
+ React hook for building forms bound to workflow activity input fields. Integrates with `react-hook-form`.
282
+
283
+ ### Options
284
+
285
+ | Property | Type | Default | Description |
286
+ |----------|------|---------|-------------|
287
+ | `activity_instance_id` | `string` | *required* | Activity instance ID (from `wf.start()` or `getInstanceList()`) |
288
+ | `defaultValues` | `Partial<Editable>` | `{}` | Initial form values |
289
+ | `mode` | `"onBlur" \| "onChange" \| "onSubmit" \| "onTouched" \| "all"` | `"onBlur"` | Validation timing |
290
+ | `enabled` | `boolean` | `true` | Whether to load activity data on mount |
291
+
292
+ ### Lifecycle
293
+
294
+ ```
295
+ Mount
296
+ |
297
+ |-> Load activity instance data -> populate form
298
+ |
299
+ v
300
+ User edits field -> blurs
301
+ |
302
+ |-> Field validation (BaseField.validate)
303
+ |-> If valid + readonly fields exist -> update computed fields
304
+ |
305
+ v
306
+ User clicks Save
307
+ |
308
+ |-> handleSubmit -> save activity data
309
+ |
310
+ v
311
+ User clicks Complete
312
+ |
313
+ |-> handleComplete -> complete activity
314
+ ```
315
+
316
+ ### Return Value
317
+
318
+ | Property | Type | Description |
319
+ |----------|------|-------------|
320
+ | `item` | `FormItemType` | Proxy with typed field accessors (`.get()`, `.set()`, `.meta`) |
321
+ | `activity` | `A` | The Activity instance |
322
+ | `register` | `FormRegisterType` | Smart register (auto-disables readonly fields) |
323
+ | `handleSubmit` | `HandleSubmitType` | Save activity data |
324
+ | `handleComplete` | `HandleSubmitType` | Complete the activity |
325
+ | `watch` | `UseFormWatch` | Watch field values |
326
+ | `setValue` | `UseFormSetValue` | Set field value programmatically |
327
+ | `getValues` | `UseFormGetValues` | Get current field values |
328
+ | `reset` | `UseFormReset` | Reset form to default values |
329
+ | `trigger` | `UseFormTrigger` | Trigger validation |
330
+ | `control` | `Control` | RHF control (for Controller components) |
331
+ | `errors` | `FieldErrors` | Validation errors |
332
+ | `isValid` | `boolean` | Form is valid |
333
+ | `isDirty` | `boolean` | Form has been modified |
334
+ | `isSubmitting` | `boolean` | Currently submitting |
335
+ | `isSubmitSuccessful` | `boolean` | Last submission succeeded |
336
+ | `isLoading` | `boolean` | Loading activity data |
337
+ | `loadError` | `Error \| null` | Load error |
338
+ | `hasError` | `boolean` | Any error active |
339
+ | `clearErrors` | `() => void` | Clear all form errors |
340
+
341
+ ---
342
+
343
+ ## Use Case: Employee Creating Leave
344
+
345
+ ### Step 1 — Start the workflow
346
+
347
+ ```typescript
348
+ import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
349
+ import type { WorkflowStartResponseType } from "@ram_28/kf-ai-sdk/workflow";
350
+
351
+ const wf = new SimpleLeaveProcess();
352
+ const { activityId, activityInstanceId }: WorkflowStartResponseType = await wf.start();
353
+ ```
354
+
355
+ ### Step 2 — React component with useActivityForm
356
+
357
+ ```tsx
358
+ import { useMemo } from "react";
359
+ import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
360
+ import type { UseActivityFormOptions } from "@ram_28/kf-ai-sdk/workflow";
361
+ import type { FieldErrors } from "react-hook-form";
362
+ import { SimpleLeaveProcess, EmployeeInputActivity } from "@/bdo/workflows/SimpleLeaveProcess";
363
+
364
+ interface LeaveRequestFormProps {
365
+ activityInstanceId: string;
366
+ onComplete: () => void;
367
+ }
368
+
369
+ function LeaveRequestForm({ activityInstanceId, onComplete }: LeaveRequestFormProps) {
370
+ // 1. Get the typed activity from the workflow
371
+ const activity = useMemo(() => new SimpleLeaveProcess().employeeInputActivity(), []);
372
+
373
+ // 2. Hook options
374
+ const options: UseActivityFormOptions<EmployeeInputActivity> = {
375
+ activity_instance_id: activityInstanceId,
376
+ defaultValues: {
377
+ StartDate: undefined,
378
+ EndDate: undefined,
379
+ LeaveType: undefined,
380
+ },
381
+ mode: "onBlur",
382
+ };
383
+
384
+ // 3. Initialize hook
385
+ const {
386
+ register,
387
+ handleSubmit,
388
+ handleComplete,
389
+ item,
390
+ errors,
391
+ isLoading,
392
+ isSubmitting,
393
+ loadError,
394
+ } = useActivityForm(activity, options);
395
+
396
+ if (isLoading) return <div>Loading...</div>;
397
+ if (loadError) return <div>Error: {loadError.message}</div>;
398
+
399
+ // 4. Handlers
400
+ const onSaveSuccess = (): void => {
401
+ console.log("Saved!");
402
+ };
403
+
404
+ const onCompleteSuccess = (): void => {
405
+ console.log("Leave request submitted!");
406
+ onComplete();
407
+ };
408
+
409
+ const onError = (error: FieldErrors | Error): void => {
410
+ if (error instanceof Error) {
411
+ console.error("API Error:", error.message);
412
+ } else {
413
+ console.error("Validation errors:", error);
414
+ }
415
+ };
416
+
417
+ return (
418
+ <form>
419
+ <h2>Leave Request</h2>
420
+
421
+ {/* Start Date */}
422
+ <div>
423
+ <label>{activity.StartDate.meta.label}</label>
424
+ <input type="date" {...register(activity.StartDate.meta.id)} />
425
+ {errors.StartDate && <span>{errors.StartDate.message}</span>}
426
+ </div>
427
+
428
+ {/* End Date */}
429
+ <div>
430
+ <label>{activity.EndDate.meta.label}</label>
431
+ <input type="date" {...register(activity.EndDate.meta.id)} />
432
+ {errors.EndDate && <span>{errors.EndDate.message}</span>}
433
+ </div>
434
+
435
+ {/* Leave Type */}
436
+ <div>
437
+ <label>{activity.LeaveType.meta.label}</label>
438
+ <select {...register(activity.LeaveType.meta.id)}>
439
+ <option value="">Select type</option>
440
+ <option value="PTO">PTO</option>
441
+ <option value="Sick">Sick</option>
442
+ <option value="Parental">Parental</option>
443
+ </select>
444
+ {errors.LeaveType && <span>{errors.LeaveType.message}</span>}
445
+ </div>
446
+
447
+ {/* Leave Days (readonly — auto-disabled, computed by server) */}
448
+ <div>
449
+ <label>{activity.LeaveDays.meta.label}</label>
450
+ <input type="number" {...register(activity.LeaveDays.meta.id)} />
451
+ </div>
452
+
453
+ {/* Actions */}
454
+ <div>
455
+ <button type="button" onClick={handleSubmit(onSaveSuccess, onError)}>
456
+ {isSubmitting ? "Saving..." : "Save Draft"}
457
+ </button>
458
+ <button type="button" onClick={handleComplete(onCompleteSuccess, onError)}>
459
+ {isSubmitting ? "Submitting..." : "Submit Leave Request"}
460
+ </button>
461
+ </div>
462
+ </form>
463
+ );
464
+ }
465
+ ```
466
+
467
+ ### Full flow orchestration
468
+
469
+ ```tsx
470
+ import { useState } from "react";
471
+ import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
472
+ import type { WorkflowStartResponseType } from "@ram_28/kf-ai-sdk/workflow";
473
+
474
+ function LeaveRequestPage() {
475
+ const [instanceId, setInstanceId] = useState<string | null>(null);
476
+
477
+ const startLeaveRequest = async () => {
478
+ const wf = new SimpleLeaveProcess();
479
+ const result: WorkflowStartResponseType = await wf.start();
480
+ setInstanceId(result.activityInstanceId);
481
+ };
482
+
483
+ if (!instanceId) {
484
+ return <button onClick={startLeaveRequest}>New Leave Request</button>;
485
+ }
486
+
487
+ return (
488
+ <LeaveRequestForm
489
+ activityInstanceId={instanceId}
490
+ onComplete={() => setInstanceId(null)}
491
+ />
492
+ );
493
+ }
494
+ ```
495
+
496
+ ---
497
+
498
+ ## Use Case: Manager Approving Leave
499
+
500
+ ### Step 1 — List in-progress items
501
+
502
+ ```typescript
503
+ import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
504
+
505
+ const wf = new SimpleLeaveProcess();
506
+ const activity = wf.managerApprovalActivity();
507
+
508
+ const result = await activity.getInstanceList({
509
+ Filter: {
510
+ Operator: "And",
511
+ Condition: [
512
+ { LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
513
+ ],
514
+ },
515
+ Page: 1,
516
+ PageSize: 20,
517
+ });
518
+
519
+ for (const item of result.Data) {
520
+ console.log(item._id, item.Status, item.AssignedTo.username);
521
+ }
522
+ ```
523
+
524
+ ### Step 2 — Approval form component
525
+
526
+ ```tsx
527
+ import { useMemo } from "react";
528
+ import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
529
+ import type { UseActivityFormOptions } from "@ram_28/kf-ai-sdk/workflow";
530
+ import type { FieldErrors } from "react-hook-form";
531
+ import { SimpleLeaveProcess, ManagerApprovalActivity } from "@/bdo/workflows/SimpleLeaveProcess";
532
+
533
+ interface ApprovalFormProps {
534
+ activityInstanceId: string;
535
+ onComplete: () => void;
536
+ }
537
+
538
+ function ApprovalForm({ activityInstanceId, onComplete }: ApprovalFormProps) {
539
+ const activity = useMemo(() => new SimpleLeaveProcess().managerApprovalActivity(), []);
540
+
541
+ const options: UseActivityFormOptions<ManagerApprovalActivity> = {
542
+ activity_instance_id: activityInstanceId,
543
+ defaultValues: {
544
+ ManagerApproved: false,
545
+ ManagerReason: "",
546
+ },
547
+ mode: "onBlur",
548
+ };
549
+
550
+ const {
551
+ register,
552
+ handleComplete,
553
+ errors,
554
+ isLoading,
555
+ isSubmitting,
556
+ loadError,
557
+ } = useActivityForm(activity, options);
558
+
559
+ if (isLoading) return <div>Loading...</div>;
560
+ if (loadError) return <div>Error: {loadError.message}</div>;
561
+
562
+ const onSuccess = (): void => {
563
+ console.log("Approval submitted!");
564
+ onComplete();
565
+ };
566
+
567
+ const onError = (error: FieldErrors | Error): void => {
568
+ if (error instanceof Error) console.error("API Error:", error.message);
569
+ };
570
+
571
+ return (
572
+ <form>
573
+ <h2>Leave Approval</h2>
574
+
575
+ <div>
576
+ <label>
577
+ <input type="checkbox" {...register(activity.ManagerApproved.meta.id)} />
578
+ {activity.ManagerApproved.meta.label}
579
+ </label>
580
+ </div>
581
+
582
+ <div>
583
+ <label>{activity.ManagerReason.meta.label}</label>
584
+ <textarea {...register(activity.ManagerReason.meta.id)} rows={4} />
585
+ </div>
586
+
587
+ <button type="button" onClick={handleComplete(onSuccess, onError)}>
588
+ {isSubmitting ? "Submitting..." : "Submit Decision"}
589
+ </button>
590
+ </form>
591
+ );
592
+ }
593
+ ```
594
+
595
+ ---
596
+
597
+ ## Use Case: Programmatic ActivityInstance
598
+
599
+ For non-form scenarios (scripts, server-side, batch processing):
600
+
601
+ ```typescript
602
+ import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
603
+
604
+ const wf = new SimpleLeaveProcess();
605
+ const activity = wf.employeeInputActivity();
606
+
607
+ // Get a typed instance
608
+ const instance = await activity.getInstance("inst_abc123");
609
+
610
+ // Read fields
611
+ console.log(instance.StartDate.get()); // "2026-02-01"
612
+ console.log(instance.LeaveType.get()); // "PTO"
613
+ console.log(instance.LeaveDays.get()); // 5 (computed)
614
+
615
+ // Write editable fields
616
+ instance.StartDate.set("2026-03-01");
617
+ instance.EndDate.set("2026-03-05");
618
+
619
+ // Field metadata
620
+ console.log(instance.StartDate.meta.label); // "Start Date"
621
+
622
+ // Persist changes
623
+ await instance.update({ StartDate: "2026-03-01", EndDate: "2026-03-05" });
624
+
625
+ // Save and commit
626
+ await instance.save({ StartDate: "2026-03-01", EndDate: "2026-03-05" });
627
+
628
+ // Complete activity
629
+ await instance.complete();
630
+
631
+ // Check progress
632
+ const progress = await instance.progress();
633
+ ```
634
+
635
+ ---
636
+
637
+ ## Filtering Reference
638
+
639
+ ### In-progress items
640
+
641
+ ```typescript
642
+ const result = await activity.getInstanceList({
643
+ Filter: {
644
+ Operator: "And",
645
+ Condition: [
646
+ { LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
647
+ ],
648
+ },
649
+ });
650
+ ```
651
+
652
+ ### Completed items
653
+
654
+ ```typescript
655
+ const result = await activity.getInstanceList({
656
+ Filter: {
657
+ Operator: "And",
658
+ Condition: [
659
+ { LHSField: "Status", Operator: "EQ", RHSValue: "Completed", RHSType: "Constant" },
660
+ ],
661
+ },
662
+ });
663
+ ```
664
+
665
+ ### Assigned to a specific user
666
+
667
+ ```typescript
668
+ const result = await activity.getInstanceList({
669
+ Filter: {
670
+ Operator: "And",
671
+ Condition: [
672
+ { LHSField: "AssignedTo._id", Operator: "EQ", RHSValue: userId, RHSType: "Constant" },
673
+ ],
674
+ },
675
+ });
676
+ ```
677
+
678
+ ### Combined: In-progress + assigned to user
679
+
680
+ ```typescript
681
+ const result = await activity.getInstanceList({
682
+ Filter: {
683
+ Operator: "And",
684
+ Condition: [
685
+ { LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
686
+ { LHSField: "AssignedTo._id", Operator: "EQ", RHSValue: userId, RHSType: "Constant" },
687
+ ],
688
+ },
689
+ });
690
+ ```
691
+
692
+ ---
693
+
694
+ ## ActivityInstance System Fields Reference
695
+
696
+ | Field | Type | Description |
697
+ |-------|------|-------------|
698
+ | `_id` | `StringFieldType` | Unique activity instance identifier |
699
+ | `Status` | `SelectFieldType<"InProgress" \| "Completed">` | Current status |
700
+ | `AssignedTo` | `ReferenceFieldType<UserRefType>` | Assigned user (has `._id` and `.username`) |
701
+ | `CompletedAt` | `DateTimeFieldType` | Completion timestamp (`"YYYY-MM-DDTHH:MM:SS"`) |
702
+
703
+ ---