@osdk/react 0.9.0-beta.5 → 0.9.0-beta.7

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 (72) hide show
  1. package/AGENTS.md +253 -0
  2. package/CHANGELOG.md +31 -0
  3. package/build/browser/intellisense.test.js +1 -1
  4. package/build/browser/intellisense.test.js.map +1 -1
  5. package/build/browser/new/platform-apis/admin/useCurrentFoundryUser.js +2 -2
  6. package/build/browser/new/platform-apis/admin/useCurrentFoundryUser.js.map +1 -1
  7. package/build/browser/new/platform-apis/admin/useFoundryUser.js +2 -2
  8. package/build/browser/new/platform-apis/admin/useFoundryUser.js.map +1 -1
  9. package/build/browser/new/platform-apis/admin/useFoundryUsersList.js +2 -2
  10. package/build/browser/new/platform-apis/admin/useFoundryUsersList.js.map +1 -1
  11. package/build/browser/new/useLinks.js +1 -1
  12. package/build/browser/new/useLinks.js.map +1 -1
  13. package/build/browser/new/useOsdkAggregation.js +1 -1
  14. package/build/browser/new/useOsdkAggregation.js.map +1 -1
  15. package/build/browser/new/useOsdkFunction.js +101 -0
  16. package/build/browser/new/useOsdkFunction.js.map +1 -0
  17. package/build/browser/new/useOsdkObject.js +1 -1
  18. package/build/browser/new/useOsdkObject.js.map +1 -1
  19. package/build/browser/new/useOsdkObjects.js +1 -1
  20. package/build/browser/new/useOsdkObjects.js.map +1 -1
  21. package/build/browser/public/experimental.js +1 -0
  22. package/build/browser/public/experimental.js.map +1 -1
  23. package/build/browser/utils/usePlatformQuery.js +1 -1
  24. package/build/browser/utils/usePlatformQuery.js.map +1 -1
  25. package/build/cjs/public/experimental.cjs +77 -379
  26. package/build/cjs/public/experimental.cjs.map +1 -1
  27. package/build/cjs/public/experimental.d.cts +139 -27
  28. package/build/esm/intellisense.test.js +1 -1
  29. package/build/esm/intellisense.test.js.map +1 -1
  30. package/build/esm/new/platform-apis/admin/useCurrentFoundryUser.js +2 -2
  31. package/build/esm/new/platform-apis/admin/useCurrentFoundryUser.js.map +1 -1
  32. package/build/esm/new/platform-apis/admin/useFoundryUser.js +2 -2
  33. package/build/esm/new/platform-apis/admin/useFoundryUser.js.map +1 -1
  34. package/build/esm/new/platform-apis/admin/useFoundryUsersList.js +2 -2
  35. package/build/esm/new/platform-apis/admin/useFoundryUsersList.js.map +1 -1
  36. package/build/esm/new/useLinks.js +1 -1
  37. package/build/esm/new/useLinks.js.map +1 -1
  38. package/build/esm/new/useOsdkAggregation.js +1 -1
  39. package/build/esm/new/useOsdkAggregation.js.map +1 -1
  40. package/build/esm/new/useOsdkFunction.js +101 -0
  41. package/build/esm/new/useOsdkFunction.js.map +1 -0
  42. package/build/esm/new/useOsdkObject.js +1 -1
  43. package/build/esm/new/useOsdkObject.js.map +1 -1
  44. package/build/esm/new/useOsdkObjects.js +1 -1
  45. package/build/esm/new/useOsdkObjects.js.map +1 -1
  46. package/build/esm/public/experimental.js +1 -0
  47. package/build/esm/public/experimental.js.map +1 -1
  48. package/build/esm/utils/usePlatformQuery.js +1 -1
  49. package/build/esm/utils/usePlatformQuery.js.map +1 -1
  50. package/build/types/new/platform-apis/admin/useCurrentFoundryUser.d.ts +2 -2
  51. package/build/types/new/platform-apis/admin/useCurrentFoundryUser.d.ts.map +1 -1
  52. package/build/types/new/platform-apis/admin/useFoundryUser.d.ts +4 -4
  53. package/build/types/new/platform-apis/admin/useFoundryUser.d.ts.map +1 -1
  54. package/build/types/new/platform-apis/admin/useFoundryUsersList.d.ts +4 -4
  55. package/build/types/new/platform-apis/admin/useFoundryUsersList.d.ts.map +1 -1
  56. package/build/types/new/useLinks.d.ts +5 -5
  57. package/build/types/new/useLinks.d.ts.map +1 -1
  58. package/build/types/new/useOsdkAggregation.d.ts +4 -5
  59. package/build/types/new/useOsdkAggregation.d.ts.map +1 -1
  60. package/build/types/new/useOsdkFunction.d.ts +112 -0
  61. package/build/types/new/useOsdkFunction.d.ts.map +1 -0
  62. package/build/types/new/useOsdkObjects.d.ts +5 -5
  63. package/build/types/new/useOsdkObjects.d.ts.map +1 -1
  64. package/build/types/public/experimental.d.ts +2 -0
  65. package/build/types/public/experimental.d.ts.map +1 -1
  66. package/docs/actions.md +414 -0
  67. package/docs/advanced-queries.md +657 -0
  68. package/docs/cache-management.md +213 -0
  69. package/docs/getting-started.md +382 -0
  70. package/docs/platform-apis.md +203 -0
  71. package/docs/querying-data.md +648 -0
  72. package/package.json +9 -6
@@ -1,7 +1,7 @@
1
- import type { DerivedProperty, InterfaceDefinition, LinkedType, LinkNames, ObjectTypeDefinition, Osdk, PropertyKeys, SimplePropertyDef, WhereClause } from "@osdk/api";
1
+ import type { DerivedProperty, LinkedType, LinkNames, ObjectOrInterfaceDefinition, Osdk, PropertyKeys, SimplePropertyDef, WhereClause } from "@osdk/api";
2
2
  import type { InferRdpTypes } from "./types.js";
3
3
  export interface UseOsdkObjectsOptions<
4
- T extends ObjectTypeDefinition | InterfaceDefinition,
4
+ T extends ObjectOrInterfaceDefinition,
5
5
  WithProps extends DerivedProperty.Clause<T> | undefined = undefined
6
6
  > {
7
7
  /**
@@ -107,7 +107,7 @@ export interface UseOsdkObjectsOptions<
107
107
  enabled?: boolean;
108
108
  }
109
109
  export interface UseOsdkListResult<
110
- T extends ObjectTypeDefinition | InterfaceDefinition,
110
+ T extends ObjectOrInterfaceDefinition,
111
111
  RDPs extends Record<string, SimplePropertyDef> = {}
112
112
  > {
113
113
  fetchMore: (() => Promise<void>) | undefined;
@@ -124,12 +124,12 @@ export interface UseOsdkListResult<
124
124
  isOptimistic: boolean;
125
125
  }
126
126
  export declare function useOsdkObjects<
127
- Q extends ObjectTypeDefinition,
127
+ Q extends ObjectOrInterfaceDefinition,
128
128
  L extends LinkNames<Q>
129
129
  >(type: Q, options: UseOsdkObjectsOptions<Q> & {
130
130
  pivotTo: L
131
131
  }): UseOsdkListResult<LinkedType<Q, L>>;
132
132
  export declare function useOsdkObjects<
133
- Q extends ObjectTypeDefinition | InterfaceDefinition,
133
+ Q extends ObjectOrInterfaceDefinition,
134
134
  WP extends DerivedProperty.Clause<Q> | undefined
135
135
  >(type: Q, options?: UseOsdkObjectsOptions<Q, WP>): UseOsdkListResult<Q, InferRdpTypes<Q, WP>>;
@@ -1 +1 @@
1
- {"mappings":"AAgBA,cACE,iBACA,qBACA,YACA,WACA,sBACA,MACA,cACA,mBACA,mBACK,WAAY;AAKnB,cAAc,qBAAqB,YAAa;AAEhD,iBAAiB;CACf,UAAU,uBAAuB;CACjC,kBAAkB,gBAAgB,OAAO;EACzC;;;;CAIA,QAAQ,YAAY,GAAG,cAAc,GAAG;;;;CAKxC;;CAGA,aACG,KAAK,aAAa,OAAM,QAAQ;;;;;CAOnC,iBAAiB;;;;;;CAOjB,gBAAgB,MAAM;EACpB,OAAO,YAAY,GAAG,cAAc,GAAG;CACxC;;;;;CAMD,UAAU,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA0BpB;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BA;CAEA;;;;;;;;;;;;;;;;;;;;;CAsBA;AACD;AAED,iBAAiB;CACf,UAAU,uBAAuB;CACjC,aAAa,eAAe,qBAAqB,CAAE;EACnD;CACA,kBAAkB;CAClB,MACI,KAAK,SAAS,GAAG,sBAAsB,aAAa,IAAI;CAE5D;CAEA,OAAO;;;;;;;;CASP;AACD;AAQD,OAAO,iBAAS;CACd,UAAU;CACV,UAAU,UAAU;EAEpBA,MAAM,GACNC,SAAS,sBAAsB,KAAK;CAAE,SAAS;AAAG,IACjD,kBAAkB,WAAW,GAAG;AAEnC,OAAO,iBAAS;CACd,UAAU,uBAAuB;CACjC,WAAW,gBAAgB,OAAO;EAElCD,MAAM,GACNE,UAAU,sBAAsB,GAAG,MAClC,kBAAkB,GAAG,cAAc,GAAG","names":["type: Q","options: UseOsdkObjectsOptions<Q> & { pivotTo: L }","options?: UseOsdkObjectsOptions<Q, WP>"],"sources":["../../../src/new/useOsdkObjects.ts"],"version":3,"file":"useOsdkObjects.d.ts"}
1
+ {"mappings":"AAgBA,cACE,iBACA,YACA,WACA,6BACA,MACA,cACA,mBACA,mBACK,WAAY;AAKnB,cAAc,qBAAqB,YAAa;AAEhD,iBAAiB;CACf,UAAU;CACV,kBAAkB,gBAAgB,OAAO;EACzC;;;;CAIA,QAAQ,YAAY,GAAG,cAAc,GAAG;;;;CAKxC;;CAGA,aACG,KAAK,aAAa,OAAM,QAAQ;;;;;CAOnC,iBAAiB;;;;;;CAOjB,gBAAgB,MAAM;EACpB,OAAO,YAAY,GAAG,cAAc,GAAG;CACxC;;;;;CAMD,UAAU,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;CA0BpB;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BA;CAEA;;;;;;;;;;;;;;;;;;;;;CAsBA;AACD;AAED,iBAAiB;CACf,UAAU;CACV,aAAa,eAAe,qBAAqB,CAAE;EACnD;CACA,kBAAkB;CAClB,MACI,KAAK,SAAS,GAAG,sBAAsB,aAAa,IAAI;CAE5D;CAEA,OAAO;;;;;;;;CASP;AACD;AAQD,OAAO,iBAAS;CACd,UAAU;CACV,UAAU,UAAU;EAEpBA,MAAM,GACNC,SAAS,sBAAsB,KAAK;CAAE,SAAS;AAAG,IACjD,kBAAkB,WAAW,GAAG;AAEnC,OAAO,iBAAS;CACd,UAAU;CACV,WAAW,gBAAgB,OAAO;EAElCD,MAAM,GACNE,UAAU,sBAAsB,GAAG,MAClC,kBAAkB,GAAG,cAAc,GAAG","names":["type: Q","options: UseOsdkObjectsOptions<Q> & { pivotTo: L }","options?: UseOsdkObjectsOptions<Q, WP>"],"sources":["../../../src/new/useOsdkObjects.ts"],"version":3,"file":"useOsdkObjects.d.ts"}
@@ -7,6 +7,8 @@ export { useObjectSet } from "../new/useObjectSet.js";
7
7
  export { useOsdkAction } from "../new/useOsdkAction.js";
8
8
  export type { UseOsdkAggregationResult } from "../new/useOsdkAggregation.js";
9
9
  export { useOsdkAggregation } from "../new/useOsdkAggregation.js";
10
+ export type { UseOsdkFunctionOptions, UseOsdkFunctionResult } from "../new/useOsdkFunction.js";
11
+ export { useOsdkFunction } from "../new/useOsdkFunction.js";
10
12
  export { useOsdkObject } from "../new/useOsdkObject.js";
11
13
  export type { UseOsdkListResult } from "../new/useOsdkObjects.js";
12
14
  export { useOsdkObjects } from "../new/useOsdkObjects.js";
@@ -1 +1 @@
1
- {"mappings":"AAgBA,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,cAAc,gCAAgC;AAC9C,SAAS,0BAA0B;AACnC,SAAS,qBAAqB;AAC9B,cAAc,yBAAyB;AACvC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,cAAc,6BAA6B;AAC3C,SAAS,4BAA4B","names":[],"sources":["../../../src/public/experimental.ts"],"version":3,"file":"experimental.d.ts"}
1
+ {"mappings":"AAgBA,SAAS,qBAAqB;AAC9B,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AACpC,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,cAAc,gCAAgC;AAC9C,SAAS,0BAA0B;AACnC,cACE,wBACA,6BACK;AACP,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,cAAc,yBAAyB;AACvC,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,cAAc,6BAA6B;AAC3C,SAAS,4BAA4B","names":[],"sources":["../../../src/public/experimental.ts"],"version":3,"file":"experimental.d.ts"}
@@ -0,0 +1,414 @@
1
+ ---
2
+ sidebar_position: 3
3
+ ---
4
+
5
+ # Actions
6
+
7
+ This guide covers executing actions, validation, optimistic updates, and debouncing patterns.
8
+
9
+ ## useOsdkAction
10
+
11
+ *Experimental - import from `@osdk/react/experimental`*
12
+
13
+ Execute and validate actions with automatic state management.
14
+
15
+ ### Basic Usage
16
+
17
+ ```tsx
18
+ import { $Actions, Todo } from "@my/osdk";
19
+ import { useOsdkAction, useOsdkObject } from "@osdk/react/experimental";
20
+ import { useCallback } from "react";
21
+
22
+ function TodoView({ todo }: { todo: Todo.OsdkInstance }) {
23
+ const { isLoading } = useOsdkObject(todo);
24
+ const { applyAction, data, error, isPending } = useOsdkAction(
25
+ $Actions.completeTodo,
26
+ );
27
+
28
+ const onClick = useCallback(() => {
29
+ applyAction({
30
+ todo: todo,
31
+ isComplete: true,
32
+ });
33
+ }, [applyAction, todo]);
34
+
35
+ return (
36
+ <div>
37
+ <div>
38
+ {todo.title}
39
+ {todo.isComplete === false && (
40
+ <button onClick={onClick} disabled={isPending}>
41
+ Mark Complete
42
+ </button>
43
+ )}
44
+ {isPending && "(Applying)"}
45
+ {data && "(Action completed successfully)"}
46
+ </div>
47
+ {error && (
48
+ <div>
49
+ An error occurred:
50
+ <pre>{JSON.stringify(error, null, 2)}</pre>
51
+ </div>
52
+ )}
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### Return Values
59
+
60
+ - `applyAction` - Function to execute the action (accepts single args object or array for batch)
61
+ - `data` - Return value from the last successful action execution
62
+ - `error` - Error object (see error handling below)
63
+ - `isPending` - True while action is executing
64
+ - `isValidating` - True while validation is in progress
65
+ - `validateAction` - Function to validate without executing
66
+ - `validationResult` - Result of last validation
67
+
68
+ ---
69
+
70
+ ## Error Handling
71
+
72
+ The `error` object has the following structure:
73
+
74
+ ```ts
75
+ {
76
+ actionValidation?: ActionValidationError;
77
+ unknown?: unknown;
78
+ }
79
+ ```
80
+
81
+ `ActionValidationError` extends `Error` and has:
82
+ - `message` - Error message string
83
+ - `validation` - Full validation response from server
84
+
85
+ Example:
86
+
87
+ ```tsx
88
+ import { $Actions, Todo } from "@my/osdk";
89
+ import { useOsdkAction } from "@osdk/react/experimental";
90
+
91
+ function TodoActionWithErrorHandling({ todo }: { todo: Todo.OsdkInstance }) {
92
+ const { applyAction, error, isPending } = useOsdkAction($Actions.completeTodo);
93
+
94
+ const onClick = async () => {
95
+ try {
96
+ await applyAction({ todo, isComplete: true });
97
+ } catch (e) {
98
+ console.error("Action failed", e);
99
+ }
100
+ };
101
+
102
+ return (
103
+ <div>
104
+ <button onClick={onClick} disabled={isPending}>
105
+ Complete Todo
106
+ </button>
107
+
108
+ {error?.actionValidation && (
109
+ <div style={{ color: "red" }}>
110
+ Validation failed: {JSON.stringify(error.actionValidation.validation)}
111
+ </div>
112
+ )}
113
+
114
+ {error?.unknown && (
115
+ <div style={{ color: "red" }}>
116
+ An unexpected error occurred: {String(error.unknown)}
117
+ </div>
118
+ )}
119
+ </div>
120
+ );
121
+ }
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Validation
127
+
128
+ Validate action parameters without executing using `validateAction`.
129
+
130
+ ```tsx
131
+ import { $Actions } from "@my/osdk";
132
+ import { useOsdkAction } from "@osdk/react/experimental";
133
+ import { useState } from "react";
134
+
135
+ function TodoForm() {
136
+ const [title, setTitle] = useState("");
137
+ const [assignee, setAssignee] = useState("");
138
+
139
+ const {
140
+ applyAction,
141
+ validateAction,
142
+ isValidating,
143
+ validationResult,
144
+ isPending,
145
+ error,
146
+ } = useOsdkAction($Actions.createTodo);
147
+
148
+ const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
149
+ const newTitle = e.target.value;
150
+ setTitle(newTitle);
151
+ validateAction({ title: newTitle, assignee });
152
+ };
153
+
154
+ const handleAssigneeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
155
+ const newAssignee = e.target.value;
156
+ setAssignee(newAssignee);
157
+ validateAction({ title, assignee: newAssignee });
158
+ };
159
+
160
+ const handleSubmit = async (e: React.FormEvent) => {
161
+ e.preventDefault();
162
+ if (validationResult?.result === "VALID") {
163
+ await applyAction({ title, assignee });
164
+ }
165
+ };
166
+
167
+ return (
168
+ <form onSubmit={handleSubmit}>
169
+ <input
170
+ type="text"
171
+ value={title}
172
+ onChange={handleTitleChange}
173
+ placeholder="Todo title"
174
+ />
175
+ <input
176
+ type="text"
177
+ value={assignee}
178
+ onChange={handleAssigneeChange}
179
+ placeholder="Assignee"
180
+ />
181
+
182
+ {isValidating && <span>Validating...</span>}
183
+
184
+ {validationResult?.result === "INVALID" && (
185
+ <div style={{ color: "red" }}>
186
+ Invalid: {JSON.stringify(validationResult)}
187
+ </div>
188
+ )}
189
+
190
+ <button
191
+ type="submit"
192
+ disabled={isPending || isValidating || validationResult?.result !== "VALID"}
193
+ >
194
+ Create Todo
195
+ </button>
196
+
197
+ {error?.actionValidation && (
198
+ <div style={{ color: "red" }}>
199
+ Validation error: {error.actionValidation.message}
200
+ </div>
201
+ )}
202
+ </form>
203
+ );
204
+ }
205
+ ```
206
+
207
+ Key features:
208
+
209
+ - `validateAction` - Validates action parameters without executing
210
+ - `isValidating` - True while validation is in progress
211
+ - `validationResult` - Contains `{ result: "VALID" | "INVALID", ... }`
212
+ - Calling `validateAction` while a previous validation is in progress cancels the previous one
213
+ - Validation and execution are mutually exclusive
214
+
215
+ ---
216
+
217
+ ## Batch Actions
218
+
219
+ Apply the same action to multiple items in a single call:
220
+
221
+ ```tsx
222
+ import { $Actions, Todo } from "@my/osdk";
223
+ import { useOsdkAction } from "@osdk/react/experimental";
224
+ import { useCallback } from "react";
225
+
226
+ function BulkCompleteButton({ todos }: { todos: Todo.OsdkInstance[] }) {
227
+ const { applyAction, isPending } = useOsdkAction($Actions.completeTodo);
228
+
229
+ const onClick = useCallback(() => {
230
+ applyAction(
231
+ todos.map(todo => ({
232
+ todo: todo,
233
+ isComplete: true,
234
+ })),
235
+ );
236
+ }, [applyAction, todos]);
237
+
238
+ return (
239
+ <button onClick={onClick} disabled={isPending}>
240
+ Complete All ({todos.length})
241
+ </button>
242
+ );
243
+ }
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Optimistic Updates
249
+
250
+ Apply changes to the cache immediately while waiting for the server response.
251
+
252
+ ```tsx
253
+ import { $Actions, Todo } from "@my/osdk";
254
+ import { useOsdkAction, useOsdkObject } from "@osdk/react/experimental";
255
+ import { useCallback } from "react";
256
+
257
+ function TodoView({ todo }: { todo: Todo.OsdkInstance }) {
258
+ const { isLoading, isOptimistic } = useOsdkObject(todo);
259
+ const { applyAction, error, isPending } = useOsdkAction($Actions.completeTodo);
260
+
261
+ const onClick = useCallback(() => {
262
+ applyAction({
263
+ todo: todo,
264
+ isComplete: true,
265
+
266
+ $optimisticUpdate: (ou) => {
267
+ ou.updateObject(todo.$clone({ isComplete: true }));
268
+ },
269
+ });
270
+ }, [applyAction, todo]);
271
+
272
+ return (
273
+ <div>
274
+ {todo.title}
275
+ {todo.isComplete === false && !isOptimistic && (
276
+ <button onClick={onClick} disabled={isPending}>Mark Complete</button>
277
+ )}
278
+ {isPending && "(Saving)"}
279
+ {isLoading && "(Loading)"}
280
+ {isOptimistic && "(Optimistic)"}
281
+ {error && (
282
+ <div style={{ color: "red" }}>
283
+ {error.actionValidation?.message ?? String(error.unknown)}
284
+ </div>
285
+ )}
286
+ </div>
287
+ );
288
+ }
289
+ ```
290
+
291
+ ### How Optimistic Updates Work
292
+
293
+ 1. When you call `applyAction` with `$optimisticUpdate`, the cache is updated immediately
294
+ 2. The UI shows the optimistic state (tracked via `isOptimistic`)
295
+ 3. If the action succeeds, the cache is refreshed with server data
296
+ 4. If the action fails, the optimistic changes are rolled back automatically
297
+
298
+ ### Optimistic Update API
299
+
300
+ The `$optimisticUpdate` callback receives an object with the following methods:
301
+
302
+ ```tsx
303
+ $optimisticUpdate: (ou) => {
304
+ ou.updateObject(todo.$clone({ isComplete: true }));
305
+ ou.updateObject(anotherObject.$clone({ ... }));
306
+ }
307
+ ```
308
+
309
+ :::note The `$clone` method
310
+ Every OSDK object instance has a `$clone()` method that creates a new object with modified properties. This is essential for optimistic updates because OSDK objects are immutable.
311
+
312
+ ```tsx
313
+ // Create a modified copy without mutating the original
314
+ const completedTodo = todo.$clone({ isComplete: true });
315
+
316
+ // Clone with multiple property changes
317
+ const updatedTodo = todo.$clone({
318
+ title: "New Title",
319
+ priority: "high",
320
+ });
321
+ ```
322
+ :::
323
+
324
+ ---
325
+
326
+ ## useDebouncedCallback
327
+
328
+ *Experimental - import from `@osdk/react/experimental`*
329
+
330
+ Debounce callback functions for auto-save patterns or expensive operations.
331
+
332
+ ### Basic Usage
333
+
334
+ ```tsx
335
+ import { useDebouncedCallback } from "@osdk/react/experimental";
336
+ import { useState } from "react";
337
+
338
+ function SearchableList({ onSearch }: { onSearch: (query: string) => void }) {
339
+ const [query, setQuery] = useState("");
340
+
341
+ const debouncedSearch = useDebouncedCallback((q: string) => {
342
+ onSearch(q);
343
+ }, 500);
344
+
345
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
346
+ const value = e.target.value;
347
+ setQuery(value);
348
+ debouncedSearch(value);
349
+ };
350
+
351
+ return (
352
+ <input
353
+ value={query}
354
+ onChange={handleChange}
355
+ placeholder="Search..."
356
+ />
357
+ );
358
+ }
359
+ ```
360
+
361
+ ### Auto-Save Pattern
362
+
363
+ Combine with actions for auto-saving:
364
+
365
+ ```tsx
366
+ import { $Actions, Todo } from "@my/osdk";
367
+ import { useDebouncedCallback, useOsdkAction } from "@osdk/react/experimental";
368
+ import { useState } from "react";
369
+
370
+ function AutoSaveTodo({ todo }: { todo: Todo.OsdkInstance }) {
371
+ const [title, setTitle] = useState(todo.title);
372
+ const { applyAction } = useOsdkAction($Actions.updateTodo);
373
+
374
+ const debouncedSave = useDebouncedCallback((newTitle: string) => {
375
+ applyAction({
376
+ todo,
377
+ title: newTitle,
378
+ $optimisticUpdate: (ou) => {
379
+ ou.updateObject(todo.$clone({ title: newTitle }));
380
+ },
381
+ });
382
+ }, 1000);
383
+
384
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
385
+ const newTitle = e.target.value;
386
+ setTitle(newTitle);
387
+ debouncedSave(newTitle);
388
+ };
389
+
390
+ return (
391
+ <input
392
+ value={title}
393
+ onChange={handleChange}
394
+ placeholder="Click to edit title..."
395
+ />
396
+ );
397
+ }
398
+ ```
399
+
400
+ ### Debounced Callback Methods
401
+
402
+ The returned function has utility methods:
403
+
404
+ ```tsx
405
+ import { useDebouncedCallback } from "@osdk/react/experimental";
406
+
407
+ const debouncedFn = useDebouncedCallback((value: string) => {
408
+ console.log("Called with:", value);
409
+ }, 500);
410
+
411
+ debouncedFn("hello");
412
+ debouncedFn.cancel();
413
+ debouncedFn.flush();
414
+ ```