@ram_28/kf-ai-sdk 2.0.28 → 2.0.29

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.
@@ -25,6 +25,26 @@ import type { ListOptionsType } from "@ram_28/kf-ai-sdk/api/types";
25
25
  ```typescript
26
26
  const product = useMemo(() => new AdminProduct(), []);
27
27
  ```
28
+ 5. **`Filter` must be `ConditionGroupType`** — Always wrap conditions in `{ Operator: "And", Condition: [...] }`. Never pass a flat condition:
29
+ ```typescript
30
+ // ❌ WRONG — flat ConditionType causes TS2322
31
+ await product.list({ Filter: { Operator: "EQ", LHSField: "Category", RHSValue: "Electronics" } });
32
+ // ✅ CORRECT — ConditionGroupType wrapper
33
+ await product.list({ Filter: { Operator: "And", Condition: [
34
+ { Operator: "EQ", LHSField: "Category", RHSValue: "Electronics", RHSType: "Constant" }
35
+ ] } });
36
+ ```
37
+ 6. **Use `PageSize` and `Page`, not `Take` or `Limit`** — `ListOptionsType` uses `PageSize` (number of items per page) and `Page` (1-indexed page number).
38
+ 7. **Never spread ItemType proxies.** `list()`, `get()`, and `create()` return proxied `ItemType` objects. Spreading `{ ...item, extraProp }` copies enumerable keys but destroys the proxy — `.get()` and `.set()` stop working. Instead, wrap in a container object:
39
+ ```typescript
40
+ // ❌ WRONG — proxy is destroyed, .get() fails at runtime
41
+ const enriched = items.map(item => ({ ...item, extra: fetchedData }));
42
+ enriched[0].Title.get(); // TypeError: get is not a function
43
+
44
+ // ✅ CORRECT — proxy preserved in container
45
+ const enriched = items.map(item => ({ entry: item, extra: fetchedData }));
46
+ enriched[0].entry.Title.get(); // works
47
+ ```
28
48
 
29
49
  ## Quick Start
30
50
 
@@ -64,8 +64,11 @@ This applies to ALL field types: `StringField.get()` → `string | undefined`, `
64
64
  2. **`.get()` returns `T | undefined`** — Always null-guard before passing to `new Date()`, `format()`, template literals, or typed function parameters. See section above.
65
65
  3. **Don't confuse `StringField` (class) with `StringFieldType` (type alias)** — Different modules.
66
66
  4. **`fetchOptions()` requires a parent BDO** — Standalone fields will throw.
67
- 5. **SelectField meta `Type` is `"String"`** — `Constraint.Enum` differentiates it.
67
+ 5. **SelectField meta `Type` is `"String"`** — `Constraint.Enum` differentiates it. Only `SelectField` has the `.options` getter. `StringField` (even with an enum constraint) does NOT have `.options` — you must hardcode the enum values from the BDO file.
68
68
  6. **Always use pre-built components for File/Image** — `<FileUpload>`, `<ImageUpload>`, `<FilePreview>`, `<ImageThumbnail>`.
69
+ 7. **`<ImageUpload>` / `<FileUpload>` ONLY work with `ImageField` / `FileField`** — Never use them for `TextField` or `StringField`, even if the field name contains "image" or "file". A `TextField` named `image_urls` is still a text field — render it with `<Textarea>` or `<Input>`, not `<ImageUpload>`. Determine the component from the **field class** in the BDO file, not the field name.
70
+ 8. **`<ImageUpload>` / `<FileUpload>` `field` prop MUST be `item.Field`, NOT `bdo.Field`** — The `upload()` and `deleteAttachment()` methods live on the form item accessor (created by the Item proxy), not on the BDO field class. Passing `bdo.Field` causes silent upload failures.
71
+ 9. **BooleanField: use `watch()` + `setValue()`, never `register()`** — `<Switch>` and `<Checkbox>` components don't fire native change events. Using `register()` means the value never updates on toggle.
69
72
 
70
73
  ## Quick Start
71
74
 
@@ -242,3 +242,4 @@ item.StartDate.readOnly; // is readonly?
242
242
  - **Don't call `activity.update()` or `activity.complete()` manually.** `handleSubmit` handles the API calls. Calling them yourself will double-submit.
243
243
  - **Don't render the form before `isLoading` is false.** The activity data and metadata are being fetched. Guard with `if (isLoading) return <Loading />`.
244
244
  - **Don't forget `activity_instance_id` is required.** This is the activity instance ID (from `workflow.start()` or `getInProgressList()`), not a BDO record ID.
245
+ - **Don't pass a single options object.** `useActivityForm` takes 2 arguments: `useActivityForm(activity, { activity_instance_id })`. This is different from `useActivityTable` which takes a single object `useActivityTable({ activity, status })`. Passing `useActivityForm({ activity, activity_instance_id })` causes a type error.
@@ -261,3 +261,5 @@ This is the standard pattern after any mutation (complete, update, save) that sh
261
261
  - **Don't use 0-indexed pagination.** Pages start at 1. Passing `pageNo: 0` will produce incorrect results.
262
262
  - **Don't forget to guard on `isLoading` before rendering rows.** While loading, `rows` is an empty array. Guard with `if (table.isLoading) return <Loading />` to avoid rendering an empty table.
263
263
  - **Don't hardcode field names as strings.** Use the activity field IDs (`activity.StartDate.id`) instead of raw strings (`"StartDate"`). This keeps your code type-safe and resilient to field renames.
264
+ - **Don't use `table.data`** — the property is `table.rows`, same as `useBDOTable`.
265
+ - **`initialState.sort` format is `[{ fieldName: "ASC" }]`** — NOT `{ field, direction }`. Write `sort: [{ StartDate: "DESC" }]`, not `sort: [{ field: "StartDate", direction: "desc" }]`.
@@ -170,6 +170,32 @@ item.Title.readOnly; // is readonly?
170
170
  - **Don't forget `useMemo` on the BDO.** `new BdoClass()` must be wrapped in `useMemo(() => ..., [])`. Re-creating the instance on every render breaks the hook.
171
171
  - **Don't set date `defaultValues` to empty string.** Use `undefined` instead. Empty strings cause type validation errors for Date and DateTime fields.
172
172
  - **Don't mix `register()` and `watch()`+`setValue()` for the same field.** Pick one approach per field. `register()` for native inputs, `watch()`+`setValue()` for custom components.
173
- - **Don't use `register()` for select, checkbox, or reference components.** They don't fire native change events. Use `watch()` + `setValue()`.
173
+ - **Don't use `register()` for select, checkbox, switch, or reference components.** They don't fire native change events. Use `watch()` + `setValue()`.
174
174
  - **Don't call `bdo.create()` or `bdo.update()` manually.** `handleSubmit` handles the API call. Calling them yourself will double-submit.
175
+ - **`handleSubmit` is curried — pass it directly to `onSubmit`, don't call it inside a handler.** It takes `(onSuccess, onError)` and returns an event handler. Write `<form onSubmit={handleSubmit(onSuccess, onError)}>`. NEVER write `<form onSubmit={(e) => handleSubmit(data)}>` or `await handleSubmit(data)` — this passes the wrong argument and the API call never fires.
176
+ ```tsx
177
+ // ❌ WRONG — handleSubmit receives FormEvent, not form data. API never fires.
178
+ const onSubmit = async (data) => { await handleSubmit(data); };
179
+ <form onSubmit={onSubmit}>
180
+
181
+ // ✅ CORRECT — handleSubmit wraps your callback, validates, calls API, then invokes onSuccess
182
+ <form onSubmit={handleSubmit(
183
+ (result) => { toast.success("Created"); navigate("/products"); },
184
+ (error) => { toast.error("Failed"); }
185
+ )}>
186
+ ```
175
187
  - **Don't render the form before `isLoading` is false.** In create mode, the draft is being allocated. In update mode, the record is being fetched. Guard with `if (isLoading) return <Loading />`.
188
+ - **There is no `operation` field.** Create vs. update mode is determined solely by `recordId`: absent = create, present = update. Never pass `operation: "create"` or `operation: "update"`.
189
+ - **Guard `loadError` in edit forms.** After the `isLoading` check, add `if (loadError) return <ErrorMessage />` before rendering the form. Without this, `item` may be undefined in update mode.
190
+ ```tsx
191
+ if (isLoading) return <Loading />;
192
+ if (loadError) return <p>Error: {loadError.message}</p>;
193
+ ```
194
+ - **Don't pass `operation` even though the SDK type supports it.** The SDK has `UseBDOFormAutoOptionsType` that auto-infers create/update from `recordId`. Passing `operation: "update"` requires `recordId: string` (not `string | undefined`), causing TS errors with `useParams()`. Omit `operation` entirely:
195
+ ```tsx
196
+ // ❌ WRONG — TS2345 when id is string | undefined from useParams
197
+ useBDOForm({ bdo, recordId: id, operation: "update" })
198
+
199
+ // ✅ CORRECT — auto mode handles string | undefined
200
+ useBDOForm({ bdo, recordId: id })
201
+ ```
@@ -237,7 +237,17 @@ This is the standard pattern after any mutation (create, update, delete) that sh
237
237
  ## Common Mistakes
238
238
 
239
239
  - **Don't forget `useMemo` on the BDO.** `new BdoClass()` must be wrapped in `useMemo(() => ..., [])`. Re-creating the instance on every render causes infinite refetching.
240
+ - **Don't use `table.data`** — the property is `table.rows`. Other table libraries use `data`, but this SDK uses `rows`.
241
+ - **Don't use `table.setSearch()`** — the correct API is `table.search.set(field, query)` with two arguments: field ID and query string.
240
242
  - **Don't access row fields directly.** `row.Title` is an accessor object, not the value. Use `row.Title.get()` to read the value.
241
243
  - **Don't use 0-indexed pagination.** Pages start at 1. Passing `pageNo: 0` will produce incorrect results.
242
244
  - **Don't forget to guard on `isLoading` before rendering rows.** While loading, `rows` is an empty array. Guard with `if (table.isLoading) return <Loading />` to avoid rendering an empty table.
243
245
  - **Don't hardcode field names as strings.** Use the BDO field IDs (`product.Title.id`) instead of raw strings (`"Title"`). This keeps your code type-safe and resilient to field renames.
246
+ - **`initialState.sort` format is `[{ fieldName: "ASC" }]`** — a single-key object, NOT `{ field, direction }`. Other libraries use `{ field: "Title", direction: "asc" }` but this SDK uses `[{ Title: "ASC" }]`. Note: the direction is uppercase `"ASC"` or `"DESC"`.
247
+ ```tsx
248
+ // ❌ WRONG — { field, direction } format from other libraries
249
+ initialState: { sort: [{ field: product.Title.id, direction: "desc" }] }
250
+ // ✅ CORRECT — single-key object with uppercase direction
251
+ initialState: { sort: [{ Title: "DESC" }] }
252
+ ```
253
+ - **Don't pass `bdo.field` where `bdo.field.id` is expected.** `bdo.Title` is a `StringField` object, not a string. Use `bdo.Title.id` to get the field ID string. Passing the field object causes TS2322 (`StringField` not assignable to `string`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ram_28/kf-ai-sdk",
3
- "version": "2.0.28",
3
+ "version": "2.0.29",
4
4
  "description": "Type-safe, AI-driven SDK for building modern web applications with role-based access control",
5
5
  "author": "Ramprasad",
6
6
  "license": "MIT",