@osdk/react 0.10.0-beta.1 → 0.10.0-beta.10

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/AGENTS.md +46 -221
  2. package/CHANGELOG.md +132 -0
  3. package/build/browser/new/makeExternalStore.js +61 -0
  4. package/build/browser/new/makeExternalStore.js.map +1 -1
  5. package/build/browser/new/useLinks.js +11 -4
  6. package/build/browser/new/useLinks.js.map +1 -1
  7. package/build/browser/new/useObjectSet.js +42 -18
  8. package/build/browser/new/useObjectSet.js.map +1 -1
  9. package/build/browser/new/useOsdkAction.js +2 -2
  10. package/build/browser/new/useOsdkAction.js.map +1 -1
  11. package/build/browser/new/useOsdkAggregation.js +65 -27
  12. package/build/browser/new/useOsdkAggregation.js.map +1 -1
  13. package/build/browser/new/useOsdkFunction.js +17 -12
  14. package/build/browser/new/useOsdkFunction.js.map +1 -1
  15. package/build/browser/new/useOsdkObject.js +44 -26
  16. package/build/browser/new/useOsdkObject.js.map +1 -1
  17. package/build/browser/new/useOsdkObjects.js +28 -19
  18. package/build/browser/new/useOsdkObjects.js.map +1 -1
  19. package/build/browser/{intellisense.test.helpers/useOsdkObjectsWithPivot.js → public/experimental/admin.js} +4 -19
  20. package/build/browser/public/experimental/admin.js.map +1 -0
  21. package/build/browser/public/experimental.js +0 -3
  22. package/build/browser/public/experimental.js.map +1 -1
  23. package/build/browser/useOsdkMetadata.js.map +1 -1
  24. package/build/cjs/{chunk-V32JHU3O.cjs → chunk-OVBG5VXE.cjs} +3 -8
  25. package/build/cjs/chunk-OVBG5VXE.cjs.map +1 -0
  26. package/build/cjs/chunk-SVVMLSKN.cjs +111 -0
  27. package/build/cjs/chunk-SVVMLSKN.cjs.map +1 -0
  28. package/build/cjs/index.cjs +4 -4
  29. package/build/cjs/index.d.cts +1 -1
  30. package/build/cjs/public/experimental/admin.cjs +146 -0
  31. package/build/cjs/public/experimental/admin.cjs.map +1 -0
  32. package/build/cjs/public/experimental/admin.d.cts +118 -0
  33. package/build/cjs/public/experimental.cjs +253 -492
  34. package/build/cjs/public/experimental.cjs.map +1 -1
  35. package/build/cjs/public/experimental.d.cts +106 -138
  36. package/build/cjs/useOsdkMetadata-BElt3F5s.d.cts +15 -0
  37. package/build/esm/new/makeExternalStore.js +61 -0
  38. package/build/esm/new/makeExternalStore.js.map +1 -1
  39. package/build/esm/new/useLinks.js +11 -4
  40. package/build/esm/new/useLinks.js.map +1 -1
  41. package/build/esm/new/useObjectSet.js +42 -18
  42. package/build/esm/new/useObjectSet.js.map +1 -1
  43. package/build/esm/new/useOsdkAction.js +2 -2
  44. package/build/esm/new/useOsdkAction.js.map +1 -1
  45. package/build/esm/new/useOsdkAggregation.js +65 -27
  46. package/build/esm/new/useOsdkAggregation.js.map +1 -1
  47. package/build/esm/new/useOsdkFunction.js +17 -12
  48. package/build/esm/new/useOsdkFunction.js.map +1 -1
  49. package/build/esm/new/useOsdkObject.js +44 -26
  50. package/build/esm/new/useOsdkObject.js.map +1 -1
  51. package/build/esm/new/useOsdkObjects.js +28 -19
  52. package/build/esm/new/useOsdkObjects.js.map +1 -1
  53. package/build/esm/{intellisense.test.helpers/useOsdkObjectsWithPivot.js → public/experimental/admin.js} +4 -19
  54. package/build/esm/public/experimental/admin.js.map +1 -0
  55. package/build/esm/public/experimental.js +0 -3
  56. package/build/esm/public/experimental.js.map +1 -1
  57. package/build/esm/useOsdkMetadata.js.map +1 -1
  58. package/build/types/new/makeExternalStore.d.ts +11 -0
  59. package/build/types/new/makeExternalStore.d.ts.map +1 -1
  60. package/build/types/new/useLinks.d.ts +19 -0
  61. package/build/types/new/useLinks.d.ts.map +1 -1
  62. package/build/types/new/useObjectSet.d.ts +10 -4
  63. package/build/types/new/useObjectSet.d.ts.map +1 -1
  64. package/build/types/new/useOsdkAggregation.d.ts +41 -3
  65. package/build/types/new/useOsdkAggregation.d.ts.map +1 -1
  66. package/build/types/new/useOsdkFunction.d.ts +11 -5
  67. package/build/types/new/useOsdkFunction.d.ts.map +1 -1
  68. package/build/types/new/useOsdkObject.d.ts +18 -7
  69. package/build/types/new/useOsdkObject.d.ts.map +1 -1
  70. package/build/types/new/useOsdkObjects.d.ts +26 -2
  71. package/build/types/new/useOsdkObjects.d.ts.map +1 -1
  72. package/build/types/public/experimental/admin.d.ts +3 -0
  73. package/build/types/public/experimental/admin.d.ts.map +1 -0
  74. package/build/types/public/experimental.d.ts +0 -3
  75. package/build/types/public/experimental.d.ts.map +1 -1
  76. package/build/types/useOsdkMetadata.d.ts +5 -4
  77. package/build/types/useOsdkMetadata.d.ts.map +1 -1
  78. package/docs/querying-data.md +19 -0
  79. package/{build/esm/intellisense.test.helpers/useOsdkObjectsWithProperties.js → experimental/admin.d.ts} +1 -18
  80. package/package.json +29 -8
  81. package/build/browser/intellisense.test.helpers/useOsdkObjectsWithPivot.js.map +0 -1
  82. package/build/browser/intellisense.test.helpers/useOsdkObjectsWithProperties.js +0 -34
  83. package/build/browser/intellisense.test.helpers/useOsdkObjectsWithProperties.js.map +0 -1
  84. package/build/browser/intellisense.test.js +0 -148
  85. package/build/browser/intellisense.test.js.map +0 -1
  86. package/build/cjs/chunk-V32JHU3O.cjs.map +0 -1
  87. package/build/cjs/useOsdkMetadata-DFZhnhGZ.d.cts +0 -14
  88. package/build/esm/intellisense.test.helpers/useOsdkObjectsWithPivot.js.map +0 -1
  89. package/build/esm/intellisense.test.helpers/useOsdkObjectsWithProperties.js.map +0 -1
  90. package/build/esm/intellisense.test.js +0 -148
  91. package/build/esm/intellisense.test.js.map +0 -1
  92. package/build/types/intellisense.test.d.ts +0 -1
  93. package/build/types/intellisense.test.d.ts.map +0 -1
  94. package/build/types/intellisense.test.helpers/useOsdkObjectsWithPivot.d.ts +0 -1
  95. package/build/types/intellisense.test.helpers/useOsdkObjectsWithPivot.d.ts.map +0 -1
  96. package/build/types/intellisense.test.helpers/useOsdkObjectsWithProperties.d.ts +0 -1
  97. package/build/types/intellisense.test.helpers/useOsdkObjectsWithProperties.d.ts.map +0 -1
package/AGENTS.md CHANGED
@@ -1,21 +1,20 @@
1
- # @osdk/react - AI Agent Instructions
1
+ # @osdk/react
2
2
 
3
- ## Critical Rules
3
+ ## Rules
4
4
 
5
- 1. **Use `OsdkProvider2`** - Not `OsdkProvider`. All modern hooks require `OsdkProvider2`.
6
- 2. **Import from `@osdk/react/experimental`** - Not `@osdk/react`. The main entry point only has legacy hooks.
7
- 3. **Never conditionally call hooks** - Use the `enabled` option instead.
8
- 4. **Keep rendering during loading** - No early returns like `if (isLoading) return <Spinner />`. Show loading indicators while rendering existing data.
5
+ 1. **Use `OsdkProvider2`**, not `OsdkProvider`. All modern hooks require it.
6
+ 2. **Import from `@osdk/react/experimental`**, not `@osdk/react`. Main entry only has legacy hooks.
7
+ 3. **Never conditionally call hooks.** Use the `enabled` option instead.
8
+ 4. **Keep rendering during loading.** No early returns like `if (isLoading) return <Spinner />`. Show loading indicators alongside existing data to prevent UI flashing. Exception: `if (!data && isLoading)` is acceptable for initial load.
9
+ 5. **`useOsdkObject` `enabled` is positional**, not in an options object: `useOsdkObject(Type, id, false)`.
9
10
 
10
11
  ## Exports
11
12
 
12
- **Stable** (`@osdk/react`):
13
+ **Stable** (`@osdk/react`): `OsdkProvider` (legacy), `useOsdkClient`, `useOsdkMetadata`
13
14
 
14
- - `OsdkProvider` - Legacy provider
15
- - `useOsdkClient` - Access client
16
- - `useOsdkMetadata` - Fetch metadata
15
+ **Experimental** (`@osdk/react/experimental`): `OsdkProvider2`, `useOsdkObjects`, `useOsdkObject`, `useOsdkAction`, `useLinks`, `useObjectSet`, `useOsdkAggregation`, `useOsdkFunction`, `useDebouncedCallback`, `useCurrentFoundryUser`, `useFoundryUser`, `useFoundryUsersList`
17
16
 
18
- **Experimental** (`@osdk/react/experimental`):
17
+ ## Hook Options
19
18
 
20
19
  - `OsdkProvider2` - Modern provider (use this)
21
20
  - `useOsdkObjects` - Query lists of objects
@@ -24,230 +23,56 @@
24
23
  - `useLinks` - Navigate object relationships
25
24
  - `useObjectSet` - Advanced set operations (union, intersect, subtract, pivot)
26
25
  - `useOsdkAggregation` - Server-side aggregations with groupBy/select
27
- - `useCurrentFoundryUser`, `useFoundryUser`, `useFoundryUsersList` - Platform APIs
28
26
  - `useOsdkClient`, `useOsdkMetadata` - Also available from experimental
29
27
 
30
- ## Correct Patterns
31
-
32
- ### Loading States
33
-
34
- ```tsx
35
- import { Todo } from "@my/osdk";
36
- import { useOsdkObjects } from "@osdk/react/experimental";
37
-
38
- function TodoList() {
39
- const { data, isLoading, error } = useOsdkObjects(Todo);
40
-
41
- return (
42
- <div>
43
- {isLoading && <LoadingIndicator />}
44
- {error && <ErrorMessage error={error} />}
45
- {data?.map(todo => <TodoItem key={todo.$primaryKey} todo={todo} />)}
46
- </div>
47
- );
48
- }
49
- ```
28
+ **Experimental Admin** (`@osdk/react/experimental/admin`):
50
29
 
51
- ### Single Object (useOsdkObject)
52
-
53
- ```tsx
54
- import { Employee } from "@my/osdk";
55
- import { useOsdkObject } from "@osdk/react/experimental";
56
-
57
- // By type + primary key (enabled is 3rd positional param)
58
- const { object, isLoading, error, isOptimistic } = useOsdkObject(
59
- Employee,
60
- "employee-123",
61
- true, // enabled (optional, defaults to true)
62
- );
63
-
64
- // By existing instance (enabled is 2nd positional param)
65
- const { object: refreshed } = useOsdkObject(existingEmployee, true);
66
- ```
67
-
68
- ### Conditional Fetching
69
-
70
- ```tsx
71
- // useOsdkObjects uses options object
72
- const { data: reports } = useOsdkObjects(Employee, {
73
- where: { managerId: selectedManagerId },
74
- enabled: !!selectedManagerId,
75
- });
76
-
77
- // useOsdkObject uses positional enabled parameter
78
- const { object: manager } = useOsdkObject(Employee, managerId, !!managerId);
79
- ```
30
+ - `useCurrentFoundryUser`, `useFoundryUser`, `useFoundryUsersList` - Platform APIs (requires `@osdk/foundry.admin`)
80
31
 
81
- ### Actions (useOsdkAction)
32
+ ## Correct Patterns
82
33
 
83
- ```tsx
84
- import { $Actions } from "@my/osdk";
85
- import { useOsdkAction } from "@osdk/react/experimental";
86
-
87
- function CompleteTodoButton({ todo }) {
88
- const {
89
- applyAction,
90
- validateAction,
91
- isPending,
92
- isValidating,
93
- error,
94
- data,
95
- validationResult,
96
- } = useOsdkAction($Actions.completeTodo);
97
-
98
- // Validate before applying
99
- const handleValidate = async () => {
100
- const result = await validateAction({ todo, isComplete: true });
101
- };
102
-
103
- // Apply the action
104
- const handleComplete = async () => {
105
- await applyAction({ todo, isComplete: true });
106
- };
107
-
108
- // With optimistic update (use $ prefix for client options)
109
- const handleOptimistic = async () => {
110
- await applyAction({
111
- todo,
112
- isComplete: true,
113
- $optimisticUpdate: (ctx) => {
114
- ctx.updateObject(todo, { isComplete: true });
115
- },
116
- });
117
- };
118
-
119
- return (
120
- <button onClick={handleComplete} disabled={isPending}>
121
- Complete
122
- </button>
123
- );
124
- }
125
- ```
34
+ | Hook | Key Options |
35
+ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
36
+ | `useOsdkObjects` | `where`, `orderBy`, `pageSize`, `withProperties`, `enabled`, `autoFetchMore`, `dedupeIntervalMs`, `streamUpdates`, `intersectWith`, `pivotTo` |
37
+ | `useObjectSet` | Same as above plus `union`, `intersect`, `subtract`. Use when you need set operations. |
38
+ | `useOsdkObject` | `enabled` is **positional** (2nd param for instance, 3rd for type+key) |
39
+ | `useLinks` | `where`, `pageSize`, `enabled`, `mode` (`"force"` / `"offline"`), `dedupeIntervalMs`. Accepts single object or array. |
40
+ | `useOsdkAction` | Returns `applyAction`, `validateAction`, `isPending`, `error`, `validationResult`. Pass `$optimisticUpdate` with `$` prefix in action params. |
41
+ | `useOsdkAggregation` | `where`, `aggregate: { $groupBy, $select }`. Metrics: `$count`, `sum`, `avg`, `min`, `max`, `exactDistinct`, `approximateDistinct`. |
42
+ | `useOsdkFunction` | `params`, `dependsOn` (object types), `dependsOnObjects` (instances), `enabled`, `dedupeIntervalMs` |
126
43
 
127
- ### Links (useLinks)
44
+ ## Text Search Filters
128
45
 
129
- ```tsx
130
- import { useLinks } from "@osdk/react/experimental";
131
-
132
- // Single object
133
- const { links, isLoading, hasMore, fetchMore, error } = useLinks(
134
- employee,
135
- "directReports",
136
- { pageSize: 20 },
137
- );
138
-
139
- // Multiple objects (returns all linked objects)
140
- const { links: allReports } = useLinks(
141
- [employee1, employee2],
142
- "directReports",
143
- );
144
- ```
46
+ `$startsWith`, `$containsAnyTerm`, `$containsAllTerms`, `$containsAllTermsInOrder`. All support `{ term, fuzzySearch: true }`.
145
47
 
146
- ### Object Set Operations (useObjectSet)
48
+ ## useOsdkObjects vs useObjectSet
147
49
 
148
- ```tsx
149
- import { Employee } from "@my/osdk";
150
- import { useObjectSet } from "@osdk/react/experimental";
151
-
152
- const { data, isLoading, fetchMore, objectSet } = useObjectSet(
153
- Employee.all(),
154
- {
155
- where: { department: "Engineering" },
156
- orderBy: { hireDate: "desc" },
157
- pageSize: 50,
158
- union: [otherObjectSet],
159
- intersect: [anotherObjectSet],
160
- autoFetchMore: 100, // fetch until 100 items
161
- streamUpdates: true,
162
- enabled: true,
163
- },
164
- );
165
- ```
50
+ Use `useOsdkObjects` by default (more optimized). Use `useObjectSet` only when you need `union`/`intersect`/`subtract` set operations.
166
51
 
167
- ### Aggregations (useOsdkAggregation)
52
+ ## Cache
168
53
 
169
- ```tsx
170
- import { Employee } from "@my/osdk";
171
- import { useOsdkAggregation } from "@osdk/react/experimental";
172
-
173
- const { data, isLoading, error, refetch } = useOsdkAggregation(Employee, {
174
- where: { department: "Engineering" },
175
- aggregate: {
176
- groupBy: { department: "exact" },
177
- select: {
178
- avgSalary: { $avg: "salary" },
179
- count: { $count: {} },
180
- },
181
- },
182
- });
183
- ```
54
+ The `ObservableClient` maintains a normalized cache. Objects update automatically after actions. For manual invalidation: `observableClient.invalidateObjects()`, `.invalidateObjectType()`, `.invalidateFunction()`, `.invalidateAll()`.
184
55
 
185
56
  ## Anti-Patterns
186
57
 
187
- ### Wrong: Conditional Hook Call
188
-
189
- ```tsx
190
- if (shouldLoad) {
191
- const { data } = useOsdkObjects(Todo); // NEVER do this
192
- }
193
- ```
194
-
195
- ### Wrong: Early Return During Loading
196
-
197
- ```tsx
198
- if (isLoading) return <Spinner />; // Causes UI flashing
199
- if (!data) return null; // Loses state
200
- ```
201
-
202
- ### Wrong: Importing from Main Entry
203
-
204
- ```tsx
205
- import { useOsdkObjects } from "@osdk/react"; // WRONG - doesn't exist here
206
- ```
207
-
208
- ### Wrong: Using OsdkProvider Instead of OsdkProvider2
209
-
210
58
  ```tsx
211
- <OsdkProvider client={client}> // WRONG - new hooks won't work
212
- ```
213
-
214
- ### Wrong: Using options object for useOsdkObject enabled
215
-
216
- ```tsx
217
- // WRONG - enabled is positional, not in options
218
- const { object } = useOsdkObject(Employee, id, { enabled: false });
219
-
59
+ // WRONG: conditional hook
60
+ if (x) { useOsdkObjects(Todo); }
61
+ // CORRECT: use enabled
62
+ useOsdkObjects(Todo, { enabled: x });
63
+
64
+ // WRONG: early return
65
+ if (isLoading) return <Spinner />;
66
+ // CORRECT: render together
67
+ <div>{isLoading && <Spinner />}{data?.map(...)}</div>
68
+
69
+ // WRONG: import from main entry
70
+ import { useOsdkObjects } from "@osdk/react";
220
71
  // CORRECT
221
- const { object } = useOsdkObject(Employee, id, false);
222
- ```
223
-
224
- ## Hook Options Reference
225
-
226
- **useOsdkObjects / useObjectSet:**
227
-
228
- - `where` - Filter conditions
229
- - `orderBy` - Sort order (`{ field: "asc" | "desc" }`)
230
- - `pageSize` - Results per page
231
- - `withProperties` - Derived properties
232
- - `enabled` - Enable/disable query
233
- - `autoFetchMore` - Auto-pagination (`true` | `number`)
234
- - `dedupeIntervalMs` - Request deduplication
235
- - `streamUpdates` - WebSocket updates
236
-
237
- **useObjectSet additional:**
238
-
239
- - `union`, `intersect`, `subtract` - Set operations
240
- - `pivotTo` - Pivot to linked type
241
-
242
- **useOsdkObject:**
243
-
244
- - `enabled` is a **positional parameter**, not in options
245
-
246
- **useLinks:**
247
-
248
- - `where`, `pageSize`, `enabled`
249
- - `mode` - `"force"` | `"offline"`
250
-
251
- **useOsdkAction:**
72
+ import { useOsdkObjects } from "@osdk/react/experimental";
252
73
 
253
- - `$optimisticUpdate` - Passed to action with `$` prefix
74
+ // WRONG: useOsdkObject enabled in options
75
+ useOsdkObject(Employee, id, { enabled: false });
76
+ // CORRECT: positional
77
+ useOsdkObject(Employee, id, false);
78
+ ```
package/CHANGELOG.md CHANGED
@@ -1,5 +1,137 @@
1
1
  # @osdkkit/react
2
2
 
3
+ ## 0.10.0-beta.10
4
+
5
+ ### Minor Changes
6
+
7
+ - dbbfb6f: Add experimental ActionForm component with field renderers, form state hook, and tests
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [cbfa135]
12
+ - Updated dependencies [f4604c2]
13
+ - @osdk/client@2.8.0-beta.22
14
+ - @osdk/api@2.8.0-beta.22
15
+
16
+ ## 0.10.0-beta.9
17
+
18
+ ### Minor Changes
19
+
20
+ - c40444b: Add linkedObjectsBySourcePrimaryKey to link observation responses
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [c40444b]
25
+ - Updated dependencies [dda14be]
26
+ - @osdk/client@2.8.0-beta.21
27
+ - @osdk/api@2.8.0-beta.21
28
+
29
+ ## 0.10.0-beta.8
30
+
31
+ ### Minor Changes
32
+
33
+ - 9720083: Add AGENTS.md files for AI IDE context
34
+ - 09e5659: add $select support to observable client and react hooks
35
+ - 8a82492: Move admin hooks to @osdk/react/experimental/admin subpath to avoid bundler crash when @osdk/foundry.admin is not installed
36
+ - 2ebe62c: package and bundle size optimizations
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [09e5659]
41
+ - Updated dependencies [2ebe62c]
42
+ - @osdk/client@2.8.0-beta.16
43
+ - @osdk/api@2.8.0-beta.16
44
+
45
+ ## 0.10.0-beta.7
46
+
47
+ ### Minor Changes
48
+
49
+ - 9156827: Preserve object set data between loads
50
+ - 35f2f1a: Add Media inputs/outputs for Queries
51
+ - 71e28ef: Allow interface object sets in useObjectSet
52
+
53
+ ### Patch Changes
54
+
55
+ - Updated dependencies [e64bf0b]
56
+ - Updated dependencies [baba327]
57
+ - Updated dependencies [d1ad4d1]
58
+ - Updated dependencies [35f2f1a]
59
+ - Updated dependencies [71e28ef]
60
+ - @osdk/client@2.8.0-beta.14
61
+ - @osdk/api@2.8.0-beta.14
62
+
63
+ ## 0.10.0-beta.6
64
+
65
+ ### Minor Changes
66
+
67
+ - 993c023: ObjectTable supports objectSet input
68
+
69
+ ### Patch Changes
70
+
71
+ - Updated dependencies [8825f8c]
72
+ - @osdk/client@2.8.0-beta.12
73
+ - @osdk/api@2.8.0-beta.12
74
+
75
+ ## 0.10.0-beta.5
76
+
77
+ ### Minor Changes
78
+
79
+ - 525f277: update useOsdkAggregation to support composed object sets, async
80
+ - d80c234: add interface support to useOsdkObject
81
+ - 996d8e4: memoize hook responses
82
+
83
+ ### Patch Changes
84
+
85
+ - Updated dependencies [642be5f]
86
+ - Updated dependencies [525f277]
87
+ - Updated dependencies [f5f95e2]
88
+ - Updated dependencies [d80c234]
89
+ - @osdk/client@2.8.0-beta.11
90
+ - @osdk/api@2.8.0-beta.11
91
+
92
+ ## 0.10.0-beta.4
93
+
94
+ ### Minor Changes
95
+
96
+ - 727fd0e: fix dual @types/react version mismatch
97
+
98
+ ### Patch Changes
99
+
100
+ - Updated dependencies [8c60682]
101
+ - Updated dependencies [15e1686]
102
+ - Updated dependencies [c9d954d]
103
+ - Updated dependencies [044eb80]
104
+ - Updated dependencies [9d234b9]
105
+ - @osdk/client@2.8.0-beta.6
106
+ - @osdk/api@2.8.0-beta.6
107
+
108
+ ## 0.10.0-beta.3
109
+
110
+ ### Minor Changes
111
+
112
+ - 73e617e: expose dedupeInterval on useLinks and fix forced revalidation bypassing dedupeInterval
113
+ - a027f3c: stabilize subscription deps in useOsdkObjects and useOsdkAggregation
114
+
115
+ ### Patch Changes
116
+
117
+ - Updated dependencies [73e617e]
118
+ - Updated dependencies [5848e3c]
119
+ - @osdk/client@2.8.0-beta.4
120
+ - @osdk/api@2.8.0-beta.4
121
+
122
+ ## 0.10.0-beta.2
123
+
124
+ ### Minor Changes
125
+
126
+ - 0d174a2: useOsdkFunction typing updates
127
+
128
+ ### Patch Changes
129
+
130
+ - Updated dependencies [26cec61]
131
+ - Updated dependencies [0d174a2]
132
+ - @osdk/client@2.8.0-beta.3
133
+ - @osdk/api@2.8.0-beta.3
134
+
3
135
  ## 0.9.0-beta.10
4
136
 
5
137
  ### Minor Changes
@@ -42,4 +42,65 @@ export function makeExternalStore(createObservation, _name, initialValue) {
42
42
  getSnapShot
43
43
  };
44
44
  }
45
+
46
+ /**
47
+ * Like makeExternalStore but for async subscription creation.
48
+ *
49
+ * Uses an isActive flag to handle race conditions:
50
+ * If cleanup runs before promise resolves, the stale subscription is
51
+ * immediately unsubscribed when it eventually resolves
52
+ */
53
+ export function makeExternalStoreAsync(createObservation, _name, initialValue) {
54
+ let lastResult = initialValue;
55
+ function getSnapShot() {
56
+ return lastResult;
57
+ }
58
+ function subscribe(notifyUpdate) {
59
+ let isActive = true;
60
+ let currentSubscription;
61
+ const subscriptionPromise = createObservation({
62
+ next: payload => {
63
+ if (isActive) {
64
+ lastResult = payload;
65
+ notifyUpdate();
66
+ }
67
+ },
68
+ error: error => {
69
+ if (isActive) {
70
+ lastResult = {
71
+ ...(lastResult ?? {}),
72
+ error: error instanceof Error ? error : new Error(String(error))
73
+ };
74
+ notifyUpdate();
75
+ }
76
+ },
77
+ complete: () => {}
78
+ });
79
+ subscriptionPromise.then(sub => {
80
+ if (isActive) {
81
+ currentSubscription = sub;
82
+ } else {
83
+ sub.unsubscribe();
84
+ }
85
+ }).catch(error => {
86
+ if (isActive) {
87
+ lastResult = {
88
+ ...(lastResult ?? {}),
89
+ error: error instanceof Error ? error : new Error(String(error))
90
+ };
91
+ notifyUpdate();
92
+ }
93
+ });
94
+ return () => {
95
+ isActive = false;
96
+ if (currentSubscription) {
97
+ currentSubscription.unsubscribe();
98
+ }
99
+ };
100
+ }
101
+ return {
102
+ subscribe,
103
+ getSnapShot
104
+ };
105
+ }
45
106
  //# sourceMappingURL=makeExternalStore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"makeExternalStore.js","names":["makeExternalStore","createObservation","_name","initialValue","lastResult","getSnapShot","subscribe","notifyUpdate","obs","next","payload","error","Error","String","complete","unsubscribe"],"sources":["makeExternalStore.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n Observer,\n Unsubscribable,\n} from \"@osdk/client/unstable-do-not-use\";\n\nexport type Snapshot<X> =\n | X & { error?: Error }\n | (Partial<X> & { error?: Error })\n | undefined;\n\nexport function makeExternalStore<X>(\n createObservation: (callback: Observer<X | undefined>) => Unsubscribable,\n _name?: string,\n initialValue?: Snapshot<X>,\n): {\n subscribe: (notifyUpdate: () => void) => () => void;\n getSnapShot: () => Snapshot<X>;\n} {\n let lastResult: Snapshot<X> = initialValue;\n\n function getSnapShot(): Snapshot<X> {\n return lastResult;\n }\n\n function subscribe(notifyUpdate: () => void) {\n const obs = createObservation({\n next: (payload) => {\n lastResult = payload as Snapshot<X>;\n notifyUpdate();\n },\n error: (error: unknown) => {\n lastResult = {\n ...(lastResult ?? {}),\n error: error instanceof Error ? error : new Error(String(error)),\n } as Snapshot<X>;\n notifyUpdate();\n },\n complete: () => {},\n });\n\n return (): void => {\n obs.unsubscribe();\n };\n }\n\n return {\n subscribe,\n getSnapShot,\n };\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAYA,OAAO,SAASA,iBAAiBA,CAC/BC,iBAAwE,EACxEC,KAAc,EACdC,YAA0B,EAI1B;EACA,IAAIC,UAAuB,GAAGD,YAAY;EAE1C,SAASE,WAAWA,CAAA,EAAgB;IAClC,OAAOD,UAAU;EACnB;EAuBA,OAAO;IACLE,SAAS,EAtBX,SAASA,SAASA,CAACC,YAAwB,EAAE;MAC3C,MAAMC,GAAG,GAAGP,iBAAiB,CAAC;QAC5BQ,IAAI,EAAGC,OAAO,IAAK;UACjBN,UAAU,GAAGM,OAAsB;UACnCH,YAAY,CAAC,CAAC;QAChB,CAAC;QACDI,KAAK,EAAGA,KAAc,IAAK;UACzBP,UAAU,GAAG;YACX,IAAIA,UAAU,IAAI,CAAC,CAAC,CAAC;YACrBO,KAAK,EAAEA,KAAK,YAAYC,KAAK,GAAGD,KAAK,GAAG,IAAIC,KAAK,CAACC,MAAM,CAACF,KAAK,CAAC;UACjE,CAAgB;UAChBJ,YAAY,CAAC,CAAC;QAChB,CAAC;QACDO,QAAQ,EAAEA,CAAA,KAAM,CAAC;MACnB,CAAC,CAAC;MAEF,OAAO,MAAY;QACjBN,GAAG,CAACO,WAAW,CAAC,CAAC;MACnB,CAAC;IACH,CAGW;IACTV;EACF,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"makeExternalStore.js","names":["makeExternalStore","createObservation","_name","initialValue","lastResult","getSnapShot","subscribe","notifyUpdate","obs","next","payload","error","Error","String","complete","unsubscribe","makeExternalStoreAsync","isActive","currentSubscription","subscriptionPromise","then","sub","catch"],"sources":["makeExternalStore.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n Observer,\n Unsubscribable,\n} from \"@osdk/client/unstable-do-not-use\";\n\nexport type Snapshot<X> =\n | X & { error?: Error }\n | (Partial<X> & { error?: Error })\n | undefined;\n\nexport function makeExternalStore<X>(\n createObservation: (callback: Observer<X | undefined>) => Unsubscribable,\n _name?: string,\n initialValue?: Snapshot<X>,\n): {\n subscribe: (notifyUpdate: () => void) => () => void;\n getSnapShot: () => Snapshot<X>;\n} {\n let lastResult: Snapshot<X> = initialValue;\n\n function getSnapShot(): Snapshot<X> {\n return lastResult;\n }\n\n function subscribe(notifyUpdate: () => void) {\n const obs = createObservation({\n next: (payload) => {\n lastResult = payload as Snapshot<X>;\n notifyUpdate();\n },\n error: (error: unknown) => {\n lastResult = {\n ...(lastResult ?? {}),\n error: error instanceof Error ? error : new Error(String(error)),\n } as Snapshot<X>;\n notifyUpdate();\n },\n complete: () => {},\n });\n\n return (): void => {\n obs.unsubscribe();\n };\n }\n\n return {\n subscribe,\n getSnapShot,\n };\n}\n\n/**\n * Like makeExternalStore but for async subscription creation.\n *\n * Uses an isActive flag to handle race conditions:\n * If cleanup runs before promise resolves, the stale subscription is\n * immediately unsubscribed when it eventually resolves\n */\nexport function makeExternalStoreAsync<X>(\n createObservation: (\n callback: Observer<X | undefined>,\n ) => Promise<Unsubscribable>,\n _name?: string,\n initialValue?: Snapshot<X>,\n): {\n subscribe: (notifyUpdate: () => void) => () => void;\n getSnapShot: () => Snapshot<X>;\n} {\n let lastResult: Snapshot<X> = initialValue;\n\n function getSnapShot(): Snapshot<X> {\n return lastResult;\n }\n\n function subscribe(notifyUpdate: () => void) {\n let isActive = true;\n let currentSubscription: Unsubscribable | undefined;\n\n const subscriptionPromise = createObservation({\n next: (payload) => {\n if (isActive) {\n lastResult = payload as Snapshot<X>;\n notifyUpdate();\n }\n },\n error: (error: unknown) => {\n if (isActive) {\n lastResult = {\n ...(lastResult ?? {}),\n error: error instanceof Error ? error : new Error(String(error)),\n } as Snapshot<X>;\n notifyUpdate();\n }\n },\n complete: () => {},\n });\n\n subscriptionPromise.then((sub) => {\n if (isActive) {\n currentSubscription = sub;\n } else {\n sub.unsubscribe();\n }\n }).catch((error: unknown) => {\n if (isActive) {\n lastResult = {\n ...(lastResult ?? {}),\n error: error instanceof Error ? error : new Error(String(error)),\n } as Snapshot<X>;\n notifyUpdate();\n }\n });\n\n return (): void => {\n isActive = false;\n if (currentSubscription) {\n currentSubscription.unsubscribe();\n }\n };\n }\n\n return {\n subscribe,\n getSnapShot,\n };\n}\n"],"mappings":"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","ignoreList":[]}
@@ -18,6 +18,7 @@ import React from "react";
18
18
  import { makeExternalStore } from "./makeExternalStore.js";
19
19
  import { OsdkContext2 } from "./OsdkContext2.js";
20
20
  const emptyArray = Object.freeze([]);
21
+ const emptyMap = new Map();
21
22
 
22
23
  /**
23
24
  * Hook to observe links from an object or array of objects.
@@ -37,6 +38,7 @@ export function useLinks(objects, linkName, options = {}) {
37
38
  } = options;
38
39
  const stableWhere = React.useMemo(() => otherOptions.where, [JSON.stringify(otherOptions.where)]);
39
40
  const stableOrderBy = React.useMemo(() => otherOptions.orderBy, [JSON.stringify(otherOptions.orderBy)]);
41
+ const stableSelect = React.useMemo(() => otherOptions.$select, [JSON.stringify(otherOptions.$select)]);
40
42
  const objectsKey = React.useMemo(() => {
41
43
  if (objects === undefined) return "";
42
44
  const arr = Array.isArray(objects) ? objects : [objects];
@@ -61,17 +63,22 @@ export function useLinks(objects, linkName, options = {}) {
61
63
  where: stableWhere,
62
64
  pageSize: otherOptions.pageSize,
63
65
  orderBy: stableOrderBy,
64
- mode: otherOptions.mode
66
+ mode: otherOptions.mode,
67
+ dedupeInterval: otherOptions.dedupeIntervalMs ?? 2_000,
68
+ ...(stableSelect ? {
69
+ select: stableSelect
70
+ } : {})
65
71
  }, observer), `links ${linkName} for ${objectsKey}`);
66
- }, [enabled, observableClient, objectsArray, objectsKey, linkName, stableWhere, otherOptions.pageSize, stableOrderBy, otherOptions.mode]);
72
+ }, [enabled, observableClient, objectsArray, objectsKey, linkName, stableWhere, otherOptions.pageSize, stableOrderBy, otherOptions.mode, otherOptions.dedupeIntervalMs, stableSelect]);
67
73
  const payload = React.useSyncExternalStore(subscribe, getSnapShot);
68
- return {
74
+ return React.useMemo(() => ({
69
75
  links: payload?.resolvedList,
76
+ linkedObjectsBySourcePrimaryKey: payload?.linkedObjectsBySourcePrimaryKey ?? emptyMap,
70
77
  isLoading: enabled ? payload?.status === "loading" || payload?.status === "init" || !payload : false,
71
78
  isOptimistic: payload?.isOptimistic ?? false,
72
79
  error: payload?.error,
73
80
  fetchMore: payload?.hasMore ? payload?.fetchMore : undefined,
74
81
  hasMore: payload?.hasMore ?? false
75
- };
82
+ }), [payload, enabled]);
76
83
  }
77
84
  //# sourceMappingURL=useLinks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLinks.js","names":["React","makeExternalStore","OsdkContext2","emptyArray","Object","freeze","useLinks","objects","linkName","options","observableClient","useContext","enabled","otherOptions","stableWhere","useMemo","where","JSON","stringify","stableOrderBy","orderBy","objectsKey","undefined","arr","Array","isArray","map","obj","$apiName","$primaryKey","join","objectsArray","subscribe","getSnapShot","unsubscribe","observer","observeLinks","pageSize","mode","payload","useSyncExternalStore","links","resolvedList","isLoading","status","isOptimistic","error","fetchMore","hasMore"],"sources":["useLinks.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n LinkedType,\n LinkNames,\n ObjectOrInterfaceDefinition,\n} from \"@osdk/api\";\nimport type { Osdk, PropertyKeys, WhereClause } from \"@osdk/client\";\nimport type { ObserveLinks } from \"@osdk/client/unstable-do-not-use\";\nimport React from \"react\";\nimport { makeExternalStore } from \"./makeExternalStore.js\";\nimport { OsdkContext2 } from \"./OsdkContext2.js\";\n\nexport interface UseLinksOptions<\n T extends ObjectOrInterfaceDefinition,\n> {\n /**\n * Standard OSDK Where clause for filtering linked objects\n */\n where?: WhereClause<T>;\n\n /**\n * The preferred page size for the links list.\n */\n pageSize?: number;\n\n /** Sorting options for the linked objects */\n orderBy?: {\n [K in PropertyKeys<T>]?: \"asc\" | \"desc\";\n };\n\n /**\n * The mode to use for fetching data.\n * - undefined: Fetch data if not already in cache\n * - \"force\": Always fetch fresh data\n * - \"offline\": Only use cached data, don't make network requests\n */\n mode?: \"force\" | \"offline\";\n\n /**\n * Enable or disable the query.\n *\n * When `false`, the query will not automatically execute. It will still\n * return any cached data, but will not fetch from the server.\n *\n * This is useful for:\n * - Lazy/on-demand queries that should wait for user interaction\n * - Dependent queries that need data from another query first\n * - Conditional queries based on component state\n *\n * @default true\n * @example\n * // Dependent query - wait for employee data\n * const { object: employee } = useOsdkObject(Employee, employeeId);\n * const { links: reports } = useLinks(employee, \"reports\", {\n * enabled: !!employee\n * });\n */\n enabled?: boolean;\n}\n\nexport interface UseLinksResult<\n Q extends ObjectOrInterfaceDefinition,\n> {\n links: Osdk.Instance<Q>[] | undefined;\n isLoading: boolean;\n error: Error | undefined;\n\n /**\n * Refers to whether the links are optimistic or not.\n */\n isOptimistic: boolean;\n\n /**\n * Fetch more linked objects if pagination is supported\n */\n fetchMore: (() => Promise<unknown>) | undefined;\n\n /**\n * Indicates if there are more linked objects available to fetch\n */\n hasMore: boolean;\n}\n\nconst emptyArray = Object.freeze([]);\n\n/**\n * Hook to observe links from an object or array of objects.\n *\n * @param objects The source object(s) to observe links from\n * @param linkName The name of the link to observe\n * @param options Optional configuration for the link query\n * @returns UseLinksResult with links data and metadata\n */\nexport function useLinks<\n T extends ObjectOrInterfaceDefinition,\n L extends LinkNames<T>,\n>(\n objects: Osdk.Instance<T> | Array<Osdk.Instance<T>> | undefined,\n linkName: L,\n options: UseLinksOptions<LinkedType<T, L>> = {},\n): UseLinksResult<LinkedType<T, L>> {\n const { observableClient } = React.useContext(OsdkContext2);\n\n const { enabled = true, ...otherOptions } = options;\n\n const stableWhere = React.useMemo(\n () => otherOptions.where,\n [JSON.stringify(otherOptions.where)],\n );\n\n const stableOrderBy = React.useMemo(\n () => otherOptions.orderBy,\n [JSON.stringify(otherOptions.orderBy)],\n );\n\n const objectsKey = React.useMemo(() => {\n if (objects === undefined) return \"\";\n const arr = Array.isArray(objects) ? objects : [objects];\n return arr.map(obj => `${obj.$apiName}:${obj.$primaryKey}`).join(\",\");\n }, [objects]);\n\n // Convert single object to array for consistent handling\n const objectsArray: ReadonlyArray<Osdk.Instance<T>> = React.useMemo(() => {\n return objects === undefined\n ? emptyArray\n : Array.isArray(objects)\n ? objects\n : [objects];\n }, [objectsKey, objects]);\n\n const { subscribe, getSnapShot } = React.useMemo(\n () => {\n if (!enabled) {\n return makeExternalStore<ObserveLinks.CallbackArgs<T>>(\n () => ({ unsubscribe: () => {} }),\n `links ${linkName} for ${objectsKey} [DISABLED]`,\n );\n }\n return makeExternalStore<ObserveLinks.CallbackArgs<T>>(\n (observer) =>\n observableClient.observeLinks(\n objectsArray,\n linkName,\n {\n linkName,\n where: stableWhere,\n pageSize: otherOptions.pageSize,\n orderBy: stableOrderBy,\n mode: otherOptions.mode,\n },\n observer,\n ),\n `links ${linkName} for ${objectsKey}`,\n );\n },\n [\n enabled,\n observableClient,\n objectsArray,\n objectsKey,\n linkName,\n stableWhere,\n otherOptions.pageSize,\n stableOrderBy,\n otherOptions.mode,\n ],\n );\n\n const payload = React.useSyncExternalStore(\n subscribe,\n getSnapShot,\n );\n\n return {\n links: payload?.resolvedList,\n isLoading: enabled\n ? (payload?.status === \"loading\" || payload?.status === \"init\"\n || !payload)\n : false,\n isOptimistic: payload?.isOptimistic ?? false,\n error: payload?.error,\n fetchMore: payload?.hasMore ? payload?.fetchMore : undefined,\n hasMore: payload?.hasMore ?? false,\n };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"useLinks.js","names":["React","makeExternalStore","OsdkContext2","emptyArray","Object","freeze","emptyMap","Map","useLinks","objects","linkName","options","observableClient","useContext","enabled","otherOptions","stableWhere","useMemo","where","JSON","stringify","stableOrderBy","orderBy","stableSelect","$select","objectsKey","undefined","arr","Array","isArray","map","obj","$apiName","$primaryKey","join","objectsArray","subscribe","getSnapShot","unsubscribe","observer","observeLinks","pageSize","mode","dedupeInterval","dedupeIntervalMs","select","payload","useSyncExternalStore","links","resolvedList","linkedObjectsBySourcePrimaryKey","isLoading","status","isOptimistic","error","fetchMore","hasMore"],"sources":["useLinks.ts"],"sourcesContent":["/*\n * Copyright 2025 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n LinkedType,\n LinkNames,\n ObjectOrInterfaceDefinition,\n} from \"@osdk/api\";\nimport type { Osdk, PropertyKeys, WhereClause } from \"@osdk/client\";\nimport type { ObserveLinks } from \"@osdk/client/unstable-do-not-use\";\nimport React from \"react\";\nimport { makeExternalStore } from \"./makeExternalStore.js\";\nimport { OsdkContext2 } from \"./OsdkContext2.js\";\n\nexport interface UseLinksOptions<\n T extends ObjectOrInterfaceDefinition,\n> {\n /**\n * Standard OSDK Where clause for filtering linked objects\n */\n where?: WhereClause<T>;\n\n /**\n * The preferred page size for the links list.\n */\n pageSize?: number;\n\n /** Sorting options for the linked objects */\n orderBy?: {\n [K in PropertyKeys<T>]?: \"asc\" | \"desc\";\n };\n\n /**\n * Restrict which properties are returned for each linked object.\n * When provided, only the specified properties will be fetched,\n * reducing payload sizes for list views.\n */\n $select?: readonly PropertyKeys<T>[];\n\n /**\n * The mode to use for fetching data.\n * - undefined: Fetch data if not already in cache\n * - \"force\": Always fetch fresh data\n * - \"offline\": Only use cached data, don't make network requests\n */\n mode?: \"force\" | \"offline\";\n\n /**\n * The number of milliseconds to wait after the last observed link change.\n *\n * Two uses of `useLinks` with the same parameters will only trigger one\n * network request if the second is within `dedupeIntervalMs`.\n */\n dedupeIntervalMs?: number;\n\n /**\n * Enable or disable the query.\n *\n * When `false`, the query will not automatically execute. It will still\n * return any cached data, but will not fetch from the server.\n *\n * This is useful for:\n * - Lazy/on-demand queries that should wait for user interaction\n * - Dependent queries that need data from another query first\n * - Conditional queries based on component state\n *\n * @default true\n * @example\n * // Dependent query - wait for employee data\n * const { object: employee } = useOsdkObject(Employee, employeeId);\n * const { links: reports } = useLinks(employee, \"reports\", {\n * enabled: !!employee\n * });\n */\n enabled?: boolean;\n}\n\nexport interface UseLinksResult<\n Q extends ObjectOrInterfaceDefinition,\n> {\n links: Osdk.Instance<Q>[] | undefined;\n\n /**\n * Maps each source object's primary key to its linked object instances.\n * Useful when observing links from multiple source objects to determine\n * which source links to which targets.\n */\n linkedObjectsBySourcePrimaryKey: ReadonlyMap<\n string | number,\n ReadonlyArray<Osdk.Instance<Q>>\n >;\n\n isLoading: boolean;\n error: Error | undefined;\n\n /**\n * Refers to whether the links are optimistic or not.\n */\n isOptimistic: boolean;\n\n /**\n * Fetch more linked objects if pagination is supported\n */\n fetchMore: (() => Promise<unknown>) | undefined;\n\n /**\n * Indicates if there are more linked objects available to fetch\n */\n hasMore: boolean;\n}\n\nconst emptyArray = Object.freeze([]);\nconst emptyMap: ReadonlyMap<string | number, ReadonlyArray<never>> = new Map();\n\n/**\n * Hook to observe links from an object or array of objects.\n *\n * @param objects The source object(s) to observe links from\n * @param linkName The name of the link to observe\n * @param options Optional configuration for the link query\n * @returns UseLinksResult with links data and metadata\n */\nexport function useLinks<\n T extends ObjectOrInterfaceDefinition,\n L extends LinkNames<T>,\n>(\n objects: Osdk.Instance<T> | Array<Osdk.Instance<T>> | undefined,\n linkName: L,\n options: UseLinksOptions<LinkedType<T, L>> = {},\n): UseLinksResult<LinkedType<T, L>> {\n const { observableClient } = React.useContext(OsdkContext2);\n\n const { enabled = true, ...otherOptions } = options;\n\n const stableWhere = React.useMemo(\n () => otherOptions.where,\n [JSON.stringify(otherOptions.where)],\n );\n\n const stableOrderBy = React.useMemo(\n () => otherOptions.orderBy,\n [JSON.stringify(otherOptions.orderBy)],\n );\n\n const stableSelect = React.useMemo(\n () => otherOptions.$select,\n [JSON.stringify(otherOptions.$select)],\n );\n\n const objectsKey = React.useMemo(() => {\n if (objects === undefined) return \"\";\n const arr = Array.isArray(objects) ? objects : [objects];\n return arr.map(obj => `${obj.$apiName}:${obj.$primaryKey}`).join(\",\");\n }, [objects]);\n\n // Convert single object to array for consistent handling\n const objectsArray: ReadonlyArray<Osdk.Instance<T>> = React.useMemo(() => {\n return objects === undefined\n ? emptyArray\n : Array.isArray(objects)\n ? objects\n : [objects];\n }, [objectsKey, objects]);\n\n const { subscribe, getSnapShot } = React.useMemo(\n () => {\n if (!enabled) {\n return makeExternalStore<ObserveLinks.CallbackArgs<T>>(\n () => ({ unsubscribe: () => {} }),\n `links ${linkName} for ${objectsKey} [DISABLED]`,\n );\n }\n return makeExternalStore<ObserveLinks.CallbackArgs<T>>(\n (observer) =>\n observableClient.observeLinks(\n objectsArray,\n linkName,\n {\n linkName,\n where: stableWhere,\n pageSize: otherOptions.pageSize,\n orderBy: stableOrderBy,\n mode: otherOptions.mode,\n dedupeInterval: otherOptions.dedupeIntervalMs ?? 2_000,\n ...(stableSelect ? { select: stableSelect } : {}),\n },\n observer,\n ),\n `links ${linkName} for ${objectsKey}`,\n );\n },\n [\n enabled,\n observableClient,\n objectsArray,\n objectsKey,\n linkName,\n stableWhere,\n otherOptions.pageSize,\n stableOrderBy,\n otherOptions.mode,\n otherOptions.dedupeIntervalMs,\n stableSelect,\n ],\n );\n\n const payload = React.useSyncExternalStore(\n subscribe,\n getSnapShot,\n );\n\n return React.useMemo(() => ({\n links: payload?.resolvedList,\n linkedObjectsBySourcePrimaryKey: payload?.linkedObjectsBySourcePrimaryKey\n ?? emptyMap,\n isLoading: enabled\n ? (payload?.status === \"loading\" || payload?.status === \"init\"\n || !payload)\n : false,\n isOptimistic: payload?.isOptimistic ?? false,\n error: payload?.error,\n fetchMore: payload?.hasMore ? payload?.fetchMore : undefined,\n hasMore: payload?.hasMore ?? false,\n }), [payload, enabled]);\n}\n"],"mappings":"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","ignoreList":[]}