@osdk/react 0.9.0-beta.1 → 0.9.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.
- package/AGENTS.md +253 -0
- package/CHANGELOG.md +118 -0
- package/build/browser/intellisense.test.js +1 -1
- package/build/browser/intellisense.test.js.map +1 -1
- package/build/browser/new/makeExternalStore.js +2 -2
- package/build/browser/new/makeExternalStore.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useCurrentFoundryUser.js +44 -0
- package/build/browser/new/platform-apis/admin/useCurrentFoundryUser.js.map +1 -0
- package/build/browser/new/platform-apis/admin/useFoundryUser.js +50 -0
- package/build/browser/new/platform-apis/admin/useFoundryUser.js.map +1 -0
- package/build/browser/new/platform-apis/admin/useFoundryUsersList.js +54 -0
- package/build/browser/new/platform-apis/admin/useFoundryUsersList.js.map +1 -0
- package/build/browser/new/useLinks.js +15 -8
- package/build/browser/new/useLinks.js.map +1 -1
- package/build/browser/new/useObjectSet.js +20 -4
- package/build/browser/new/useObjectSet.js.map +1 -1
- package/build/browser/new/useOsdkAction.js.map +1 -1
- package/build/browser/new/useOsdkAggregation.js +1 -1
- package/build/browser/new/useOsdkAggregation.js.map +1 -1
- package/build/browser/new/useOsdkFunction.js +101 -0
- package/build/browser/new/useOsdkFunction.js.map +1 -0
- package/build/browser/new/useOsdkObject.js +1 -1
- package/build/browser/new/useOsdkObject.js.map +1 -1
- package/build/browser/new/useOsdkObjects.js +4 -3
- package/build/browser/new/useOsdkObjects.js.map +1 -1
- package/build/browser/public/experimental.js +4 -0
- package/build/browser/public/experimental.js.map +1 -1
- package/build/browser/utils/usePlatformQuery.js +74 -0
- package/build/browser/utils/usePlatformQuery.js.map +1 -0
- package/build/cjs/{chunk-OVBG5VXE.cjs → chunk-V32JHU3O.cjs} +8 -3
- package/build/cjs/chunk-V32JHU3O.cjs.map +1 -0
- package/build/cjs/index.cjs +4 -4
- package/build/cjs/public/experimental.cjs +413 -67
- package/build/cjs/public/experimental.cjs.map +1 -1
- package/build/cjs/public/experimental.d.cts +279 -32
- package/build/esm/intellisense.test.js +1 -1
- package/build/esm/intellisense.test.js.map +1 -1
- package/build/esm/new/makeExternalStore.js +2 -2
- package/build/esm/new/makeExternalStore.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useCurrentFoundryUser.js +44 -0
- package/build/esm/new/platform-apis/admin/useCurrentFoundryUser.js.map +1 -0
- package/build/esm/new/platform-apis/admin/useFoundryUser.js +50 -0
- package/build/esm/new/platform-apis/admin/useFoundryUser.js.map +1 -0
- package/build/esm/new/platform-apis/admin/useFoundryUsersList.js +54 -0
- package/build/esm/new/platform-apis/admin/useFoundryUsersList.js.map +1 -0
- package/build/esm/new/useLinks.js +15 -8
- package/build/esm/new/useLinks.js.map +1 -1
- package/build/esm/new/useObjectSet.js +20 -4
- package/build/esm/new/useObjectSet.js.map +1 -1
- package/build/esm/new/useOsdkAction.js.map +1 -1
- package/build/esm/new/useOsdkAggregation.js +1 -1
- package/build/esm/new/useOsdkAggregation.js.map +1 -1
- package/build/esm/new/useOsdkFunction.js +101 -0
- package/build/esm/new/useOsdkFunction.js.map +1 -0
- package/build/esm/new/useOsdkObject.js +1 -1
- package/build/esm/new/useOsdkObject.js.map +1 -1
- package/build/esm/new/useOsdkObjects.js +4 -3
- package/build/esm/new/useOsdkObjects.js.map +1 -1
- package/build/esm/public/experimental.js +4 -0
- package/build/esm/public/experimental.js.map +1 -1
- package/build/esm/utils/usePlatformQuery.js +74 -0
- package/build/esm/utils/usePlatformQuery.js.map +1 -0
- package/build/types/new/makeExternalStore.d.ts +1 -1
- package/build/types/new/makeExternalStore.d.ts.map +1 -1
- package/build/types/new/platform-apis/admin/useCurrentFoundryUser.d.ts +28 -0
- package/build/types/new/platform-apis/admin/useCurrentFoundryUser.d.ts.map +1 -0
- package/build/types/new/platform-apis/admin/useFoundryUser.d.ts +36 -0
- package/build/types/new/platform-apis/admin/useFoundryUser.d.ts.map +1 -0
- package/build/types/new/platform-apis/admin/useFoundryUsersList.d.ts +52 -0
- package/build/types/new/platform-apis/admin/useFoundryUsersList.d.ts.map +1 -0
- package/build/types/new/useLinks.d.ts +5 -5
- package/build/types/new/useLinks.d.ts.map +1 -1
- package/build/types/new/useObjectSet.d.ts +4 -0
- package/build/types/new/useObjectSet.d.ts.map +1 -1
- package/build/types/new/useOsdkAction.d.ts +3 -3
- package/build/types/new/useOsdkAction.d.ts.map +1 -1
- package/build/types/new/useOsdkAggregation.d.ts +10 -12
- package/build/types/new/useOsdkAggregation.d.ts.map +1 -1
- package/build/types/new/useOsdkFunction.d.ts +112 -0
- package/build/types/new/useOsdkFunction.d.ts.map +1 -0
- package/build/types/new/useOsdkObjects.d.ts +31 -13
- package/build/types/new/useOsdkObjects.d.ts.map +1 -1
- package/build/types/public/experimental.d.ts +5 -0
- package/build/types/public/experimental.d.ts.map +1 -1
- package/build/types/utils/usePlatformQuery.d.ts +25 -0
- package/build/types/utils/usePlatformQuery.d.ts.map +1 -0
- package/docs/actions.md +414 -0
- package/docs/advanced-queries.md +663 -0
- package/docs/cache-management.md +213 -0
- package/docs/getting-started.md +382 -0
- package/docs/platform-apis.md +203 -0
- package/docs/querying-data.md +648 -0
- package/package.json +8 -4
- package/build/browser/new/types.js +0 -2
- package/build/browser/new/types.js.map +0 -1
- package/build/cjs/chunk-OVBG5VXE.cjs.map +0 -1
- package/build/esm/new/types.js +0 -2
- package/build/esm/new/types.js.map +0 -1
- package/build/types/new/types.d.ts +0 -5
- package/build/types/new/types.d.ts.map +0 -1
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 2
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Querying Data
|
|
6
|
+
|
|
7
|
+
This guide covers all the ways to fetch data from the server using OSDK React hooks.
|
|
8
|
+
|
|
9
|
+
## useOsdkObjects
|
|
10
|
+
|
|
11
|
+
*Experimental - import from `@osdk/react/experimental`*
|
|
12
|
+
|
|
13
|
+
Retrieve and observe collections of objects with automatic cache management.
|
|
14
|
+
|
|
15
|
+
### Basic Usage
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Todo } from "@my/osdk";
|
|
19
|
+
import {
|
|
20
|
+
type UseOsdkListResult,
|
|
21
|
+
useOsdkObjects,
|
|
22
|
+
} from "@osdk/react/experimental";
|
|
23
|
+
|
|
24
|
+
function TodoList() {
|
|
25
|
+
const {
|
|
26
|
+
data,
|
|
27
|
+
isLoading,
|
|
28
|
+
isOptimistic,
|
|
29
|
+
error,
|
|
30
|
+
fetchMore,
|
|
31
|
+
}: UseOsdkListResult<typeof Todo> = useOsdkObjects(Todo);
|
|
32
|
+
|
|
33
|
+
if (!data && isLoading) {
|
|
34
|
+
return "Loading...";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div>
|
|
39
|
+
{isLoading && <div>Refreshing data</div>}
|
|
40
|
+
{data.map(todo => <TodoView key={todo.$primaryKey} todo={todo} />)}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Return Values
|
|
47
|
+
|
|
48
|
+
- `data` - Array of objects matching the query (undefined while initially loading)
|
|
49
|
+
- `isLoading` - True while fetching data from server (can be true while `data` exists during revalidation)
|
|
50
|
+
- `isOptimistic` - True if the list order is affected by optimistic updates (see note below)
|
|
51
|
+
- `fetchMore` - Function to load next page (undefined when no more pages available)
|
|
52
|
+
- `error` - Error object if fetch failed
|
|
53
|
+
|
|
54
|
+
:::note About isOptimistic
|
|
55
|
+
`isOptimistic` refers to whether the **ordered list of objects** (considering only primary keys) is optimistic. To check if individual object contents are optimistic, use `useOsdkObject` on each object.
|
|
56
|
+
:::
|
|
57
|
+
|
|
58
|
+
### Filtering with `where`
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const { data, isLoading } = useOsdkObjects(Todo, {
|
|
62
|
+
where: { text: { $startsWith: "cool " } },
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Text Search Filters
|
|
67
|
+
|
|
68
|
+
OSDK provides several text search operators for string properties. Understanding the differences helps you choose the right one for your use case.
|
|
69
|
+
|
|
70
|
+
#### `$startsWith`
|
|
71
|
+
|
|
72
|
+
Matches strings that begin with the specified prefix.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const { data } = useOsdkObjects(Employee, {
|
|
76
|
+
where: { fullName: { $startsWith: "John" } },
|
|
77
|
+
});
|
|
78
|
+
// Matches: "John Smith", "Johnny Appleseed"
|
|
79
|
+
// Does NOT match: "Mary Johnson"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### `$containsAnyTerm`
|
|
83
|
+
|
|
84
|
+
Matches if the property contains **any** of the search terms. Terms are space-separated. Useful for broad searches where matching any word is sufficient.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const { data } = useOsdkObjects(Article, {
|
|
88
|
+
where: { content: { $containsAnyTerm: "react typescript javascript" } },
|
|
89
|
+
});
|
|
90
|
+
// Matches articles containing "react" OR "typescript" OR "javascript"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
With fuzzy matching enabled, minor typos are tolerated:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const { data } = useOsdkObjects(Article, {
|
|
97
|
+
where: { content: { $containsAnyTerm: { term: "react", fuzzySearch: true } } },
|
|
98
|
+
});
|
|
99
|
+
// Fuzzy matching handles common typos automatically
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### `$containsAllTerms`
|
|
103
|
+
|
|
104
|
+
Matches if the property contains **all** of the search terms, in any order. Use this for more precise searches where all keywords must be present.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const { data } = useOsdkObjects(Article, {
|
|
108
|
+
where: { content: { $containsAllTerms: "react hooks tutorial" } },
|
|
109
|
+
});
|
|
110
|
+
// Matches: "This tutorial covers React hooks in depth"
|
|
111
|
+
// Matches: "Learn hooks - a React tutorial"
|
|
112
|
+
// Does NOT match: "React components guide" (missing "hooks" and "tutorial")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
With fuzzy matching:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const { data } = useOsdkObjects(Article, {
|
|
119
|
+
where: { content: { $containsAllTerms: { term: "react hooks", fuzzySearch: true } } },
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `$containsAllTermsInOrder`
|
|
124
|
+
|
|
125
|
+
Matches if the property contains all terms **in the exact order specified**. Use this for phrase matching.
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const { data } = useOsdkObjects(Document, {
|
|
129
|
+
where: { title: { $containsAllTermsInOrder: "quarterly sales report" } },
|
|
130
|
+
});
|
|
131
|
+
// Matches: "Q4 Quarterly Sales Report 2024"
|
|
132
|
+
// Does NOT match: "Sales Report - Quarterly" (wrong order)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Search Filter Comparison
|
|
136
|
+
|
|
137
|
+
| Filter | Match Requirement | Use Case |
|
|
138
|
+
|--------|-------------------|----------|
|
|
139
|
+
| `$startsWith` | Begins with prefix | Autocomplete, prefix search |
|
|
140
|
+
| `$containsAnyTerm` | Any term present | Broad keyword search |
|
|
141
|
+
| `$containsAllTerms` | All terms present (any order) | Precise multi-keyword search |
|
|
142
|
+
| `$containsAllTermsInOrder` | All terms in exact order | Phrase/exact match search |
|
|
143
|
+
|
|
144
|
+
#### Search Example: Building a Search Box
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
import { Article } from "@my/osdk";
|
|
148
|
+
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
149
|
+
import { useState } from "react";
|
|
150
|
+
|
|
151
|
+
function ArticleSearch() {
|
|
152
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
153
|
+
|
|
154
|
+
const { data, isLoading } = useOsdkObjects(Article, {
|
|
155
|
+
where: searchQuery
|
|
156
|
+
? { title: { $containsAnyTerm: { term: searchQuery, fuzzySearch: true } } }
|
|
157
|
+
: undefined,
|
|
158
|
+
enabled: searchQuery.length >= 2,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<div>
|
|
163
|
+
<input
|
|
164
|
+
type="text"
|
|
165
|
+
placeholder="Search articles..."
|
|
166
|
+
value={searchQuery}
|
|
167
|
+
onChange={e => setSearchQuery(e.target.value)}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
{isLoading && <div>Searching...</div>}
|
|
171
|
+
|
|
172
|
+
{data?.map(article => (
|
|
173
|
+
<div key={article.$primaryKey}>{article.title}</div>
|
|
174
|
+
))}
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Sorting with `orderBy`
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
const { data } = useOsdkObjects(Todo, {
|
|
184
|
+
orderBy: { createdAt: "desc" },
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Pagination
|
|
189
|
+
|
|
190
|
+
Control page size and load more results:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
function TodoList() {
|
|
194
|
+
const { data, isLoading, fetchMore } = useOsdkObjects(Todo, {
|
|
195
|
+
pageSize: 10,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<div>
|
|
200
|
+
{data?.map(todo => <TodoView key={todo.$primaryKey} todo={todo} />)}
|
|
201
|
+
|
|
202
|
+
{fetchMore && (
|
|
203
|
+
<button onClick={() => fetchMore()} disabled={isLoading}>
|
|
204
|
+
{isLoading ? "Loading..." : "Load More"}
|
|
205
|
+
</button>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Auto-Fetching Pages
|
|
213
|
+
|
|
214
|
+
By default, only the first page is fetched. Use `autoFetchMore` to load more automatically:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
// Fetch all pages automatically
|
|
218
|
+
const { data, isLoading } = useOsdkObjects(Todo, {
|
|
219
|
+
autoFetchMore: true,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Fetch at least 100 items
|
|
223
|
+
const { data, isLoading, fetchMore } = useOsdkObjects(Todo, {
|
|
224
|
+
autoFetchMore: 100,
|
|
225
|
+
pageSize: 25, // Will load 4 pages
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
:::warning Performance Warning
|
|
230
|
+
Using `autoFetchMore: true` on large datasets may cause long load times and high memory usage. Prefer `autoFetchMore: N` with a specific number.
|
|
231
|
+
:::
|
|
232
|
+
|
|
233
|
+
### Conditional Queries with `enabled`
|
|
234
|
+
|
|
235
|
+
Control when a query executes:
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
import { Todo } from "@my/osdk";
|
|
239
|
+
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
240
|
+
import { useState } from "react";
|
|
241
|
+
|
|
242
|
+
function ConditionalTodoFetch() {
|
|
243
|
+
const [shouldFetch, setShouldFetch] = useState(false);
|
|
244
|
+
|
|
245
|
+
const { data, isLoading } = useOsdkObjects(Todo, {
|
|
246
|
+
where: { isComplete: false },
|
|
247
|
+
enabled: shouldFetch, // Only fetch when true
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<div>
|
|
252
|
+
<button onClick={() => setShouldFetch(!shouldFetch)}>
|
|
253
|
+
{shouldFetch ? "Hide" : "Show"} Incomplete Todos
|
|
254
|
+
</button>
|
|
255
|
+
|
|
256
|
+
{shouldFetch && isLoading && !data && <div>Loading...</div>}
|
|
257
|
+
{data?.map(todo => <div key={todo.$primaryKey}>{todo.title}</div>)}
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Real-time Updates with `streamUpdates`
|
|
264
|
+
|
|
265
|
+
Enable WebSocket-based real-time updates:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
import { Todo } from "@my/osdk";
|
|
269
|
+
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
270
|
+
|
|
271
|
+
function LiveTodoList() {
|
|
272
|
+
const { data, isLoading } = useOsdkObjects(Todo, {
|
|
273
|
+
where: { isComplete: false },
|
|
274
|
+
orderBy: { createdAt: "desc" },
|
|
275
|
+
streamUpdates: true,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Data automatically updates when:
|
|
279
|
+
// - New todos matching the where clause are created
|
|
280
|
+
// - Existing todos are modified and still match
|
|
281
|
+
// - Todos are deleted or no longer match
|
|
282
|
+
|
|
283
|
+
if (isLoading && !data) {
|
|
284
|
+
return <div>Loading todos...</div>;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<div>
|
|
289
|
+
<h2>Live Todo List ({data?.length})</h2>
|
|
290
|
+
{data?.map(todo => (
|
|
291
|
+
<div key={todo.$primaryKey}>
|
|
292
|
+
<span>{todo.title}</span>
|
|
293
|
+
{isLoading && <span style={{ fontSize: "0.8em" }}>(Updating...)</span>}
|
|
294
|
+
</div>
|
|
295
|
+
))}
|
|
296
|
+
</div>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Set Intersections with `intersectWith`
|
|
302
|
+
|
|
303
|
+
Find objects matching multiple where clauses:
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
import { Employee } from "@my/osdk";
|
|
307
|
+
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
308
|
+
|
|
309
|
+
function EmployeesIntersection() {
|
|
310
|
+
const { data, isLoading } = useOsdkObjects(Employee, {
|
|
311
|
+
where: { department: "Engineering" },
|
|
312
|
+
intersectWith: [
|
|
313
|
+
{ where: { salary: { $gte: 100000 } } },
|
|
314
|
+
{ where: { yearsExperience: { $gte: 5 } } },
|
|
315
|
+
],
|
|
316
|
+
orderBy: { fullName: "asc" },
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
if (isLoading && !data) {
|
|
320
|
+
return <div>Loading...</div>;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return (
|
|
324
|
+
<div>
|
|
325
|
+
<h3>Senior Engineers with High Salary ({data?.length})</h3>
|
|
326
|
+
{data?.map(employee => (
|
|
327
|
+
<div key={employee.$primaryKey}>{employee.fullName}</div>
|
|
328
|
+
))}
|
|
329
|
+
</div>
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Pivot to Related Objects with `pivotTo`
|
|
335
|
+
|
|
336
|
+
Traverse relationships and return linked objects:
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
import { Employee } from "@my/osdk";
|
|
340
|
+
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
341
|
+
|
|
342
|
+
function ManagerReports() {
|
|
343
|
+
const { data, isLoading } = useOsdkObjects(Employee, {
|
|
344
|
+
where: { fullName: "John Smith" },
|
|
345
|
+
pivotTo: "reports", // Changes return type from Employee[] to Report[]
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
if (isLoading && !data) {
|
|
349
|
+
return <div>Loading...</div>;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return (
|
|
353
|
+
<div>
|
|
354
|
+
<h3>John Smith's Direct Reports ({data?.length})</h3>
|
|
355
|
+
{data?.map(report => (
|
|
356
|
+
<div key={report.$primaryKey}>{report.fullName}</div>
|
|
357
|
+
))}
|
|
358
|
+
</div>
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### All Options
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const { data, isLoading, isOptimistic, fetchMore, error } = useOsdkObjects(
|
|
367
|
+
Todo,
|
|
368
|
+
{
|
|
369
|
+
where: { isComplete: false },
|
|
370
|
+
pageSize: 20,
|
|
371
|
+
orderBy: { createdAt: "desc" },
|
|
372
|
+
dedupeIntervalMs: 5000,
|
|
373
|
+
streamUpdates: true,
|
|
374
|
+
autoFetchMore: 100,
|
|
375
|
+
enabled: true,
|
|
376
|
+
intersectWith: [{ where: { priority: "high" } }],
|
|
377
|
+
pivotTo: "assignee",
|
|
378
|
+
withProperties: { /* see advanced-queries */ },
|
|
379
|
+
},
|
|
380
|
+
);
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## useOsdkObject
|
|
386
|
+
|
|
387
|
+
*Experimental - import from `@osdk/react/experimental`*
|
|
388
|
+
|
|
389
|
+
Retrieve and observe a single object.
|
|
390
|
+
|
|
391
|
+
### Tracking an Existing Instance
|
|
392
|
+
|
|
393
|
+
Pass an object instance to track its loading and optimistic state:
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
import { Todo } from "@my/osdk";
|
|
397
|
+
import { useOsdkObject } from "@osdk/react/experimental";
|
|
398
|
+
|
|
399
|
+
function TodoView({ todo }: { todo: Todo.OsdkInstance }) {
|
|
400
|
+
const { object, isLoading, isOptimistic, error } = useOsdkObject(todo);
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<div>
|
|
404
|
+
{object?.title || todo.title}
|
|
405
|
+
{isLoading && " (Loading)"}
|
|
406
|
+
{isOptimistic && " (Optimistic)"}
|
|
407
|
+
{error && <div>Error: {error.message}</div>}
|
|
408
|
+
</div>
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Loading by Primary Key
|
|
414
|
+
|
|
415
|
+
Fetch an object by its type and primary key:
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
import { Todo } from "@my/osdk";
|
|
419
|
+
import { useOsdkObject } from "@osdk/react/experimental";
|
|
420
|
+
|
|
421
|
+
function TodoLoader({ todoId }: { todoId: string }) {
|
|
422
|
+
const { object, isLoading, error } = useOsdkObject(Todo, todoId);
|
|
423
|
+
|
|
424
|
+
if (isLoading && !object) {
|
|
425
|
+
return <div>Loading todo...</div>;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (error) {
|
|
429
|
+
return <div>Error loading todo: {error.message}</div>;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (!object) {
|
|
433
|
+
return <div>Todo not found</div>;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return <TodoView todo={object} />;
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Return Values
|
|
441
|
+
|
|
442
|
+
- `object` - The object instance (may be undefined while loading)
|
|
443
|
+
- `isLoading` - True while fetching from server
|
|
444
|
+
- `isOptimistic` - True if object has optimistic updates applied
|
|
445
|
+
- `error` - Error object if fetch failed
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## useLinks
|
|
450
|
+
|
|
451
|
+
*Experimental - import from `@osdk/react/experimental`*
|
|
452
|
+
|
|
453
|
+
Observe and navigate relationships between objects.
|
|
454
|
+
|
|
455
|
+
### Basic Usage
|
|
456
|
+
|
|
457
|
+
```tsx
|
|
458
|
+
import { Employee } from "@my/osdk";
|
|
459
|
+
import { useLinks } from "@osdk/react/experimental";
|
|
460
|
+
|
|
461
|
+
function EmployeeReports({ employee }: { employee: Employee.OsdkInstance }) {
|
|
462
|
+
const { links, isLoading, fetchMore, hasMore } = useLinks(
|
|
463
|
+
employee,
|
|
464
|
+
"reports",
|
|
465
|
+
{
|
|
466
|
+
pageSize: 10,
|
|
467
|
+
orderBy: { name: "asc" },
|
|
468
|
+
where: { isActive: true },
|
|
469
|
+
},
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
if (isLoading && !links) {
|
|
473
|
+
return <div>Loading reports...</div>;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return (
|
|
477
|
+
<div>
|
|
478
|
+
<h3>Reports ({links?.length})</h3>
|
|
479
|
+
{links?.map(report => <div key={report.$primaryKey}>{report.name}</div>)}
|
|
480
|
+
|
|
481
|
+
{hasMore && (
|
|
482
|
+
<button onClick={() => fetchMore?.()} disabled={isLoading}>
|
|
483
|
+
Load More
|
|
484
|
+
</button>
|
|
485
|
+
)}
|
|
486
|
+
</div>
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Multiple Source Objects
|
|
492
|
+
|
|
493
|
+
Load links from multiple objects at once:
|
|
494
|
+
|
|
495
|
+
```tsx
|
|
496
|
+
function TeamMembers({ employees }: { employees: Employee.OsdkInstance[] }) {
|
|
497
|
+
const { links, isLoading } = useLinks(employees, "reports");
|
|
498
|
+
|
|
499
|
+
return (
|
|
500
|
+
<div>
|
|
501
|
+
<h3>All Team Reports</h3>
|
|
502
|
+
{links?.map(report => <div key={report.$primaryKey}>{report.name}</div>)}
|
|
503
|
+
</div>
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Lazy Loading with `enabled`
|
|
509
|
+
|
|
510
|
+
```tsx
|
|
511
|
+
import { Employee } from "@my/osdk";
|
|
512
|
+
import { useLinks } from "@osdk/react/experimental";
|
|
513
|
+
import { useState } from "react";
|
|
514
|
+
|
|
515
|
+
function OptionalReportsList({ employee }: { employee: Employee.OsdkInstance }) {
|
|
516
|
+
const [showReports, setShowReports] = useState(false);
|
|
517
|
+
|
|
518
|
+
const { links, isLoading } = useLinks(employee, "reports", {
|
|
519
|
+
enabled: showReports,
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
return (
|
|
523
|
+
<div>
|
|
524
|
+
<button onClick={() => setShowReports(!showReports)}>
|
|
525
|
+
{showReports ? "Hide" : "Show"} Reports
|
|
526
|
+
</button>
|
|
527
|
+
|
|
528
|
+
{showReports && isLoading && !links && <div>Loading...</div>}
|
|
529
|
+
{links?.map(report => <div key={report.$primaryKey}>{report.name}</div>)}
|
|
530
|
+
</div>
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### Options
|
|
536
|
+
|
|
537
|
+
- `where` - Filter linked objects
|
|
538
|
+
- `pageSize` - Number of links per page
|
|
539
|
+
- `orderBy` - Sort order for linked objects
|
|
540
|
+
- `mode` - Fetch mode: `"force"` (always fetch), `"offline"` (cache only), or undefined (default)
|
|
541
|
+
- `enabled` - Enable/disable the query (default: true)
|
|
542
|
+
|
|
543
|
+
### Return Values
|
|
544
|
+
|
|
545
|
+
- `links` - Array of linked objects
|
|
546
|
+
- `isLoading` - True while fetching
|
|
547
|
+
- `isOptimistic` - True if links affected by optimistic updates
|
|
548
|
+
- `fetchMore` - Function to load next page
|
|
549
|
+
- `hasMore` - True if more pages available
|
|
550
|
+
- `error` - Error object if fetch failed
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
## useOsdkClient
|
|
555
|
+
|
|
556
|
+
*Stable - available from both `@osdk/react` and `@osdk/react/experimental`*
|
|
557
|
+
|
|
558
|
+
Access the OSDK client directly for custom queries.
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
import { Todo } from "@my/osdk";
|
|
562
|
+
import { useOsdkClient } from "@osdk/react";
|
|
563
|
+
|
|
564
|
+
function MyComponent() {
|
|
565
|
+
const client = useOsdkClient();
|
|
566
|
+
|
|
567
|
+
const loadTodos = async () => {
|
|
568
|
+
const todos = await client(Todo).fetchPage();
|
|
569
|
+
// ...
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
return <button onClick={loadTodos}>Load Todos</button>;
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Use this when you need to perform queries outside the reactive hook system, such as in event handlers or effects where you manage state manually.
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## Error Handling
|
|
581
|
+
|
|
582
|
+
All hooks return an `error` field. A basic pattern:
|
|
583
|
+
|
|
584
|
+
```tsx
|
|
585
|
+
import { Todo } from "@my/osdk";
|
|
586
|
+
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
587
|
+
|
|
588
|
+
function TodoList() {
|
|
589
|
+
const { data, isLoading, error } = useOsdkObjects(Todo);
|
|
590
|
+
|
|
591
|
+
if (error) {
|
|
592
|
+
return (
|
|
593
|
+
<div>
|
|
594
|
+
<h2>Error loading todos</h2>
|
|
595
|
+
<p>{JSON.stringify(error)}</p>
|
|
596
|
+
<button onClick={() => window.location.reload()}>Retry</button>
|
|
597
|
+
</div>
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (isLoading && !data) {
|
|
602
|
+
return <div>Loading todos...</div>;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return (
|
|
606
|
+
<div>
|
|
607
|
+
{data?.map(todo => <TodoView key={todo.$primaryKey} todo={todo} />)}
|
|
608
|
+
</div>
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## Combining Multiple Hooks
|
|
616
|
+
|
|
617
|
+
A common pattern is using multiple hooks together:
|
|
618
|
+
|
|
619
|
+
```tsx
|
|
620
|
+
import { Todo } from "@my/osdk";
|
|
621
|
+
import { useLinks, useOsdkObject } from "@osdk/react/experimental";
|
|
622
|
+
|
|
623
|
+
function TodoWithDetails({ todoId }: { todoId: string }) {
|
|
624
|
+
const { object: todo, isLoading: todoLoading } = useOsdkObject(Todo, todoId);
|
|
625
|
+
|
|
626
|
+
const { links: comments, isLoading: commentsLoading } = useLinks(
|
|
627
|
+
todo,
|
|
628
|
+
"comments",
|
|
629
|
+
{ orderBy: { createdAt: "desc" } },
|
|
630
|
+
);
|
|
631
|
+
|
|
632
|
+
if (todoLoading) return <div>Loading...</div>;
|
|
633
|
+
if (!todo) return <div>Todo not found</div>;
|
|
634
|
+
|
|
635
|
+
return (
|
|
636
|
+
<div>
|
|
637
|
+
<h2>{todo.title}</h2>
|
|
638
|
+
<p>{todo.description}</p>
|
|
639
|
+
|
|
640
|
+
<h3>Comments ({comments?.length || 0})</h3>
|
|
641
|
+
{commentsLoading && <div>Loading comments...</div>}
|
|
642
|
+
{comments?.map(comment => (
|
|
643
|
+
<div key={comment.$primaryKey}>{comment.text}</div>
|
|
644
|
+
))}
|
|
645
|
+
</div>
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@osdk/react",
|
|
3
|
-
"version": "0.9.0-beta.
|
|
3
|
+
"version": "0.9.0-beta.10",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
"react-dom": "^17 || ^18 || ^19"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
+
"@osdk/foundry.admin": "2.45.0",
|
|
47
|
+
"@osdk/foundry.core": "2.45.0",
|
|
46
48
|
"@testing-library/react": "^16.3.0",
|
|
47
49
|
"@types/react": "^18.3.24",
|
|
48
50
|
"find-up": "^8.0.0",
|
|
@@ -55,16 +57,18 @@
|
|
|
55
57
|
"react": "^18.3.1",
|
|
56
58
|
"tiny-invariant": "^1.3.3",
|
|
57
59
|
"typescript": "~5.5.4",
|
|
58
|
-
"@osdk/api": "2.7.0-beta.
|
|
59
|
-
"@osdk/client": "2.7.0-beta.
|
|
60
|
-
"@osdk/client.test.ontology": "2.7.0-beta.1",
|
|
60
|
+
"@osdk/api": "2.7.0-beta.14",
|
|
61
|
+
"@osdk/client": "2.7.0-beta.14",
|
|
61
62
|
"@osdk/monorepo.api-extractor": "~0.6.0-beta.1",
|
|
63
|
+
"@osdk/client.test.ontology": "2.7.0-beta.14",
|
|
62
64
|
"@osdk/monorepo.tsconfig": "~0.6.0-beta.1"
|
|
63
65
|
},
|
|
64
66
|
"publishConfig": {
|
|
65
67
|
"access": "public"
|
|
66
68
|
},
|
|
67
69
|
"files": [
|
|
70
|
+
"AGENTS.md",
|
|
71
|
+
"docs",
|
|
68
72
|
"build/cjs",
|
|
69
73
|
"build/esm",
|
|
70
74
|
"build/browser",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["types.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 DerivedProperty,\n InterfaceDefinition,\n ObjectTypeDefinition,\n} from \"@osdk/api\";\n\nexport type InferRdpTypes<\n Q extends ObjectTypeDefinition | InterfaceDefinition,\n WP extends DerivedProperty.Clause<Q> | undefined,\n> = WP extends DerivedProperty.Clause<Q> ? {\n [K in keyof WP]: WP[K] extends DerivedProperty.Creator<Q, infer T> ? T\n : never;\n }\n : {};\n"],"mappings":"","ignoreList":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/OsdkContext.ts","../../src/useOsdkClient.ts","../../src/useOsdkMetadata.ts"],"names":["React","error"],"mappings":";;;;;;;;;AAiBA,SAAS,gBAAgB,KAAO,EAAA;AAC9B,EAAM,MAAA,IAAI,MAAM,sEAAsE,CAAA;AACxF;AACA,IAAM,UAAA,GAAa,MAAO,CAAA,MAAA,CAAO,YAAc,EAAA;AAAA,EAC7C,aAAe,EAAA;AACjB,CAAC,CAAA;AACY,IAAA,WAAA,2CAAiC,aAAc,CAAA;AAAA,EAC1D,MAAQ,EAAA;AACV,CAAC;;;ACPM,SAAS,aAAgB,GAAA;AAC9B,EAAOA,OAAAA,uBAAAA,CAAM,UAAW,CAAA,WAAW,CAAE,CAAA,MAAA;AACvC;ACFO,SAAS,gBAAgB,IAAM,EAAA;AACpC,EAAA,MAAM,SAAS,aAAc,EAAA;AAC7B,EAAA,MAAM,CAAC,QAAU,EAAA,WAAW,CAAIA,GAAAA,uBAAAA,CAAM,SAAS,MAAS,CAAA;AACxD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,wBAAM,QAAS,EAAA;AACzC,EAAI,IAAA,CAAC,QAAY,IAAA,CAAC,KAAO,EAAA;AACvB,IAAA,MAAA,CAAO,aAAc,CAAA,IAAI,CAAE,CAAA,IAAA,CAAK,CAAmB,eAAA,KAAA;AACjD,MAAA,WAAA,CAAY,eAAe,CAAA;AAAA,KAC5B,CAAA,CAAE,KAAM,CAAA,CAAAC,MAAS,KAAA;AAChB,MAAA,MAAM,eAAeA,MAAiB,YAAA,KAAA,GAAQA,MAAM,CAAA,OAAA,GAAU,OAAOA,MAAK,CAAA;AAC1E,MAAA,QAAA,CAAS,YAAY,CAAA;AAAA,KACtB,CAAA;AACD,IAAO,OAAA;AAAA,MACL,OAAS,EAAA;AAAA,KACX;AAAA;AAEF,EAAO,OAAA;AAAA,IACL,OAAS,EAAA,KAAA;AAAA,IACT,QAAA;AAAA,IACA;AAAA,GACF;AACF","file":"chunk-OVBG5VXE.cjs","sourcesContent":["/*\n * Copyright 2024 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 React from \"react\";\nfunction fakeClientFn(..._args) {\n throw new Error(\"This is not a real client. Did you forget to <OsdkContext.Provider>?\");\n}\nconst fakeClient = Object.assign(fakeClientFn, {\n fetchMetadata: fakeClientFn\n});\nexport const OsdkContext = /*#__PURE__*/React.createContext({\n client: fakeClient\n});","/*\n * Copyright 2024 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 React from \"react\";\nimport { OsdkContext } from \"./OsdkContext.js\";\nexport function useOsdkClient() {\n return React.useContext(OsdkContext).client;\n}","/*\n * Copyright 2024 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 React from \"react\";\nimport { useOsdkClient } from \"./useOsdkClient.js\";\nexport function useOsdkMetadata(type) {\n const client = useOsdkClient();\n const [metadata, setMetadata] = React.useState(undefined);\n const [error, setError] = React.useState();\n if (!metadata && !error) {\n client.fetchMetadata(type).then(fetchedMetadata => {\n setMetadata(fetchedMetadata);\n }).catch(error => {\n const errorMessage = error instanceof Error ? error.message : String(error);\n setError(errorMessage);\n });\n return {\n loading: true\n };\n }\n return {\n loading: false,\n metadata,\n error\n };\n}"]}
|
package/build/esm/new/types.js
DELETED