@osdk/react 0.14.0 → 0.14.1-main-5835d51d99a51882d5cb42d4e9bf5b5fbe4f6bca
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/CHANGELOG.md +6 -0
- package/build/browser/new/shapes/derivedLinksStore.js +359 -0
- package/build/browser/new/shapes/derivedLinksStore.js.map +1 -0
- package/build/browser/new/shapes/index.js +18 -0
- package/build/browser/new/shapes/index.js.map +1 -0
- package/build/browser/new/shapes/types.js +96 -0
- package/build/browser/new/shapes/types.js.map +1 -0
- package/build/browser/new/shapes/useShape.js +23 -0
- package/build/browser/new/shapes/useShape.js.map +1 -0
- package/build/browser/new/shared/storeUtils.js +71 -0
- package/build/browser/new/shared/storeUtils.js.map +1 -0
- package/build/browser/util/UserAgent.js +1 -1
- package/build/browser/util/UserAgent.js.map +1 -1
- package/build/cjs/public/experimental.cjs +1 -1
- package/build/cjs/public/experimental.cjs.map +1 -1
- package/build/esm/new/shapes/derivedLinksStore.js +359 -0
- package/build/esm/new/shapes/derivedLinksStore.js.map +1 -0
- package/build/esm/new/shapes/index.js +18 -0
- package/build/esm/new/shapes/index.js.map +1 -0
- package/build/esm/new/shapes/types.js +96 -0
- package/build/esm/new/shapes/types.js.map +1 -0
- package/build/esm/new/shapes/useShape.js +23 -0
- package/build/esm/new/shapes/useShape.js.map +1 -0
- package/build/esm/new/shared/storeUtils.js +71 -0
- package/build/esm/new/shared/storeUtils.js.map +1 -0
- package/build/esm/util/UserAgent.js +1 -1
- package/build/esm/util/UserAgent.js.map +1 -1
- package/build/types/new/shapes/derivedLinksStore.d.ts +27 -0
- package/build/types/new/shapes/derivedLinksStore.d.ts.map +1 -0
- package/build/types/new/shapes/index.d.ts +2 -0
- package/build/types/new/shapes/index.d.ts.map +1 -0
- package/build/types/new/shapes/types.d.ts +53 -0
- package/build/types/new/shapes/types.d.ts.map +1 -0
- package/build/types/new/shapes/useShape.d.ts +44 -0
- package/build/types/new/shapes/useShape.d.ts.map +1 -0
- package/build/types/new/shared/storeUtils.d.ts +8 -0
- package/build/types/new/shared/storeUtils.d.ts.map +1 -0
- package/package.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Store layer for one source object's derived links on a given shape. Owns
|
|
19
|
+
* one `LinkEntry` per top-level derived link. If a link's target shape has
|
|
20
|
+
* its own derived links, also owns one `LinkEntry` per (pk, nestedLinkName)
|
|
21
|
+
* under the parent's `nestedByPk`. Feeds `useSyncExternalStore` via
|
|
22
|
+
* `subscribe` / `getSnapShot`. Teardown is one-way via `destroy`.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { applyShapeTransformationsToArray, buildObjectSetFromLinkDefByType, getLinkQueryOptions } from "@osdk/client/unstable-do-not-use";
|
|
26
|
+
import { createCachingNotifier, createStoreSubscribe, createVersionedCache, wrapError } from "../shared/storeUtils.js";
|
|
27
|
+
import { buildDataWithNestedLinks, cleanupNestedMap, createLinkEntry, violationsToError } from "./types.js";
|
|
28
|
+
export { buildDataWithNestedLinks, cleanupNestedMap, createEmptyDerivedLinksStore, isBatchableLink, NOOP_FETCH_MORE, violationsToError } from "./types.js";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Debounce window before starting newly-queued nested link observations.
|
|
32
|
+
* When a parent list resolves, each item needs its own nested link
|
|
33
|
+
* subscriptions. If the parent observer emits a few times in quick
|
|
34
|
+
* succession (e.g. streamUpdates), we collapse those into one
|
|
35
|
+
* `startLinksInBatch` call instead of kicking off subscriptions per
|
|
36
|
+
* emission. 25ms is a guess: small enough to feel instant, large enough
|
|
37
|
+
* to coalesce sync-ish bursts. Not tuned against real workloads.
|
|
38
|
+
*/
|
|
39
|
+
const NESTED_FLUSH_DELAY_MS = 25;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Removes nested entries for pks that are no longer in the parent's result
|
|
43
|
+
* set. `cleanupNestedMap` recursively unsubscribes each entry and marks it
|
|
44
|
+
* `cleaned`, which allows any already-queued flushes for those entries to
|
|
45
|
+
* no-op gracefully.
|
|
46
|
+
*/
|
|
47
|
+
function pruneStaleNestedEntries(nestedByPk, currentPks) {
|
|
48
|
+
for (const [pk, nestedMap] of nestedByPk) {
|
|
49
|
+
if (!currentPks.has(pk)) {
|
|
50
|
+
cleanupNestedMap(nestedMap);
|
|
51
|
+
nestedByPk.delete(pk);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Creates a store that observes all derived links for a single source
|
|
58
|
+
* object against the given shape. Returned methods:
|
|
59
|
+
*
|
|
60
|
+
* - `subscribe(notify)`: add a listener. First subscribe kicks off
|
|
61
|
+
* observation of all non-deferred top-level links. Last unsubscribe
|
|
62
|
+
* triggers `destroy`.
|
|
63
|
+
* - `getSnapShot()`: read a cached snapshot of all link data + statuses.
|
|
64
|
+
* - `loadDeferred(linkName)`: start a link configured with `defer: true`.
|
|
65
|
+
* - `retry(linkName?)`: restart error-state entries.
|
|
66
|
+
* - `destroy()`: one-way teardown; cascades through nested subscriptions.
|
|
67
|
+
*/
|
|
68
|
+
export function createDerivedLinksStore(shape, sourceObject, observableClient, client, linkConfig) {
|
|
69
|
+
const linkEntries = new Map();
|
|
70
|
+
const derivedLinks = shape.__derivedLinks;
|
|
71
|
+
for (const linkDef of derivedLinks) {
|
|
72
|
+
const config = linkConfig[linkDef.name];
|
|
73
|
+
linkEntries.set(linkDef.name, createLinkEntry(linkDef, sourceObject, config?.defer));
|
|
74
|
+
}
|
|
75
|
+
const subscribers = new Set();
|
|
76
|
+
const cache = createVersionedCache();
|
|
77
|
+
const notifySubscribers = createCachingNotifier(subscribers, cache);
|
|
78
|
+
const pendingNestedEntries = [];
|
|
79
|
+
let nestedFlushTimer;
|
|
80
|
+
let isDestroyed = false;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Schedules a single flush of `pendingNestedEntries` after the debounce
|
|
84
|
+
* window. An entry can be pruned (via `cleanupNestedMap` setting `cleaned`)
|
|
85
|
+
* between being queued and the flush firing, so we filter those out here
|
|
86
|
+
* instead of trying to remove them from the queue at prune time.
|
|
87
|
+
*/
|
|
88
|
+
function scheduleNestedFlush() {
|
|
89
|
+
if (nestedFlushTimer != null) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
nestedFlushTimer = setTimeout(() => {
|
|
93
|
+
nestedFlushTimer = undefined;
|
|
94
|
+
if (isDestroyed) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const batch = pendingNestedEntries.splice(0).filter(({
|
|
98
|
+
entry
|
|
99
|
+
}) => !entry.cleaned);
|
|
100
|
+
if (batch.length > 0) {
|
|
101
|
+
startLinksInBatch(batch);
|
|
102
|
+
}
|
|
103
|
+
}, NESTED_FLUSH_DELAY_MS);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* For each raw object in a parent's result set, ensure a nested `LinkEntry`
|
|
108
|
+
* exists for every nested derived link the target shape declares. New entries
|
|
109
|
+
* with status `"init"` are queued for batched startup; returns the set of
|
|
110
|
+
* pks seen so the caller can prune entries whose pks disappeared.
|
|
111
|
+
*/
|
|
112
|
+
function trackNestedLinksForObjects(parentEntry, rawObjects) {
|
|
113
|
+
const nestedDerivedLinks = parentEntry.linkDef.targetShape.__derivedLinks;
|
|
114
|
+
const currentPks = new Set();
|
|
115
|
+
for (const rawObj of rawObjects) {
|
|
116
|
+
const pk = rawObj.$primaryKey;
|
|
117
|
+
currentPks.add(pk);
|
|
118
|
+
let nestedMap = parentEntry.nestedByPk.get(pk);
|
|
119
|
+
if (!nestedMap) {
|
|
120
|
+
nestedMap = new Map();
|
|
121
|
+
parentEntry.nestedByPk.set(pk, nestedMap);
|
|
122
|
+
}
|
|
123
|
+
for (const nestedLinkDef of nestedDerivedLinks) {
|
|
124
|
+
if (!nestedMap.has(nestedLinkDef.name)) {
|
|
125
|
+
const nestedEntry = createLinkEntry(nestedLinkDef, rawObj);
|
|
126
|
+
nestedMap.set(nestedLinkDef.name, nestedEntry);
|
|
127
|
+
if (nestedEntry.status === "init") {
|
|
128
|
+
pendingNestedEntries.push({
|
|
129
|
+
entry: nestedEntry,
|
|
130
|
+
sourceType: parentEntry.linkDef.targetShape.__baseType
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return currentPks;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Called every time a parent link's observer emits. Three steps:
|
|
141
|
+
* 1. Ensure nested entries exist for each raw object (and queue new ones).
|
|
142
|
+
* 2. Prune nested entries for pks no longer in the result set.
|
|
143
|
+
* 3. If new entries were queued, schedule the debounced flush to start them.
|
|
144
|
+
*/
|
|
145
|
+
function handleNestedLinks(parentEntry, rawObjects) {
|
|
146
|
+
const nestedDerivedLinks = parentEntry.linkDef.targetShape.__derivedLinks;
|
|
147
|
+
if (nestedDerivedLinks.length === 0) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const pendingBefore = pendingNestedEntries.length;
|
|
151
|
+
const currentPks = trackNestedLinksForObjects(parentEntry, rawObjects);
|
|
152
|
+
pruneStaleNestedEntries(parentEntry.nestedByPk, currentPks);
|
|
153
|
+
if (pendingNestedEntries.length > pendingBefore) {
|
|
154
|
+
scheduleNestedFlush();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Moves a batch of entries to `"loading"` in one pass, notifies subscribers
|
|
160
|
+
* once for the bulk status change, and then kicks off each entry's async
|
|
161
|
+
* observation. Errors from `startLinkObservationInternal` flip the entry
|
|
162
|
+
* to `"error"` individually.
|
|
163
|
+
*/
|
|
164
|
+
function startLinksInBatch(entries) {
|
|
165
|
+
for (const {
|
|
166
|
+
entry
|
|
167
|
+
} of entries) {
|
|
168
|
+
entry.status = "loading";
|
|
169
|
+
entry.error = undefined;
|
|
170
|
+
}
|
|
171
|
+
notifySubscribers();
|
|
172
|
+
for (const {
|
|
173
|
+
entry,
|
|
174
|
+
sourceType
|
|
175
|
+
} of entries) {
|
|
176
|
+
startLinkObservationInternal(entry, sourceType).catch(err => {
|
|
177
|
+
entry.status = "error";
|
|
178
|
+
entry.error = wrapError(err);
|
|
179
|
+
notifySubscribers();
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Skips links already loading/loaded, otherwise marks as loading and starts observation. */
|
|
185
|
+
function startLinkObservation(entry, sourceType) {
|
|
186
|
+
if (entry.status === "loading" || entry.status === "loaded") {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
startLinksInBatch([{
|
|
190
|
+
entry,
|
|
191
|
+
sourceType
|
|
192
|
+
}]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Observer used for `observeObjectSet` on each link entry. On `next` it
|
|
197
|
+
* applies shape transformations, updates entry state, recurses into nested
|
|
198
|
+
* link handling, and rebuilds the entry's data with any nested link data
|
|
199
|
+
* attached. On `error` it flips the entry to `"error"`.
|
|
200
|
+
*/
|
|
201
|
+
function createLinkObserver(entry) {
|
|
202
|
+
return {
|
|
203
|
+
next: payload => {
|
|
204
|
+
if (isDestroyed) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const resolved = payload.resolvedList ?? [];
|
|
208
|
+
const transformResult = applyShapeTransformationsToArray(entry.linkDef.targetShape, resolved);
|
|
209
|
+
entry.status = payload.status === "loading" ? "loading" : "loaded";
|
|
210
|
+
entry.hasMore = payload.hasMore;
|
|
211
|
+
entry.fetchMore = payload.fetchMore;
|
|
212
|
+
entry.error = violationsToError(entry.linkDef.targetShape, transformResult.violations);
|
|
213
|
+
handleNestedLinks(entry, resolved);
|
|
214
|
+
entry.data = buildDataWithNestedLinks(entry, transformResult.data);
|
|
215
|
+
notifySubscribers();
|
|
216
|
+
},
|
|
217
|
+
error: err => {
|
|
218
|
+
if (isDestroyed) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
entry.status = "error";
|
|
222
|
+
entry.error = wrapError(err);
|
|
223
|
+
notifySubscribers();
|
|
224
|
+
},
|
|
225
|
+
complete: () => {}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
async function startLinkObservationInternal(entry, sourceType) {
|
|
229
|
+
const objectSet = await buildObjectSetFromLinkDefByType(client, sourceType, entry.sourceObject.$primaryKey, entry.linkDef.objectSetDef);
|
|
230
|
+
if (isDestroyed) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const config = linkEntries.has(entry.linkDef.name) ? linkConfig[entry.linkDef.name] : undefined;
|
|
234
|
+
const queryOptions = getLinkQueryOptions(entry.linkDef.objectSetDef, entry.sourceObject, config?.pageSize);
|
|
235
|
+
const subscription = observableClient.observeObjectSet(objectSet, {
|
|
236
|
+
where: queryOptions.where,
|
|
237
|
+
orderBy: queryOptions.orderBy,
|
|
238
|
+
pageSize: queryOptions.pageSize,
|
|
239
|
+
autoFetchMore: config?.autoFetchMore,
|
|
240
|
+
streamUpdates: config?.streamUpdates
|
|
241
|
+
}, createLinkObserver(entry));
|
|
242
|
+
if (isDestroyed) {
|
|
243
|
+
subscription.unsubscribe();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
entry.subscription = subscription;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* One-way teardown. Order matters: set `isDestroyed` first so in-flight
|
|
250
|
+
* async work (observer next/error, startLinkObservationInternal) no-ops.
|
|
251
|
+
* Then clear the flush timer, drop the pending queue, unsubscribe every
|
|
252
|
+
* entry, and cascade through `nestedByPk`.
|
|
253
|
+
*/
|
|
254
|
+
function destroy() {
|
|
255
|
+
isDestroyed = true;
|
|
256
|
+
if (nestedFlushTimer != null) {
|
|
257
|
+
clearTimeout(nestedFlushTimer);
|
|
258
|
+
nestedFlushTimer = undefined;
|
|
259
|
+
}
|
|
260
|
+
pendingNestedEntries.length = 0;
|
|
261
|
+
for (const entry of linkEntries.values()) {
|
|
262
|
+
entry.subscription?.unsubscribe();
|
|
263
|
+
for (const nestedMap of entry.nestedByPk.values()) {
|
|
264
|
+
cleanupNestedMap(nestedMap);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
linkEntries.clear();
|
|
268
|
+
}
|
|
269
|
+
const subscribe = createStoreSubscribe(subscribers, () => {
|
|
270
|
+
const entriesToStart = [];
|
|
271
|
+
for (const entry of linkEntries.values()) {
|
|
272
|
+
if (entry.status === "init") {
|
|
273
|
+
entriesToStart.push({
|
|
274
|
+
entry,
|
|
275
|
+
sourceType: shape.__baseType
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (entriesToStart.length > 0) {
|
|
280
|
+
startLinksInBatch(entriesToStart);
|
|
281
|
+
}
|
|
282
|
+
}, destroy);
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Starts observation for a link that was configured with `defer: true`.
|
|
286
|
+
* No-op for unknown link names or links not in the `deferred` state.
|
|
287
|
+
*/
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Resets error-state entries back to `"init"` and restarts observation.
|
|
291
|
+
* With a `linkName`, scopes to a single entry; otherwise retries all links.
|
|
292
|
+
* No-op for entries not currently in `"error"`.
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
subscribe,
|
|
297
|
+
getSnapShot: function buildSnapshot() {
|
|
298
|
+
return cache.get(() => {
|
|
299
|
+
const links = {};
|
|
300
|
+
const linkStatus = {};
|
|
301
|
+
let anyLoading = false;
|
|
302
|
+
let anyError = false;
|
|
303
|
+
for (const [name, entry] of linkEntries) {
|
|
304
|
+
links[name] = entry.data;
|
|
305
|
+
const isLoadingOrInit = entry.status === "loading" || entry.status === "init";
|
|
306
|
+
if (isLoadingOrInit) {
|
|
307
|
+
anyLoading = true;
|
|
308
|
+
}
|
|
309
|
+
if (entry.status === "error") {
|
|
310
|
+
anyError = true;
|
|
311
|
+
}
|
|
312
|
+
linkStatus[name] = {
|
|
313
|
+
isLoading: isLoadingOrInit,
|
|
314
|
+
error: entry.error,
|
|
315
|
+
hasMore: entry.hasMore,
|
|
316
|
+
fetchMore: entry.fetchMore
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
links,
|
|
321
|
+
linkStatus: linkStatus,
|
|
322
|
+
anyLoading,
|
|
323
|
+
anyError
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
loadDeferred: function loadDeferred(linkName) {
|
|
328
|
+
const entry = linkEntries.get(String(linkName));
|
|
329
|
+
if (!entry || entry.status !== "deferred") {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
startLinkObservation(entry, shape.__baseType);
|
|
333
|
+
},
|
|
334
|
+
retry: function retry(linkName) {
|
|
335
|
+
const retryEntry = entry => {
|
|
336
|
+
if (entry.status !== "error") {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
entry.subscription?.unsubscribe();
|
|
340
|
+
entry.status = "init";
|
|
341
|
+
entry.error = undefined;
|
|
342
|
+
entry.subscription = undefined;
|
|
343
|
+
startLinkObservation(entry, shape.__baseType);
|
|
344
|
+
};
|
|
345
|
+
if (linkName) {
|
|
346
|
+
const entry = linkEntries.get(String(linkName));
|
|
347
|
+
if (entry) {
|
|
348
|
+
retryEntry(entry);
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
for (const entry of linkEntries.values()) {
|
|
352
|
+
retryEntry(entry);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
destroy
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=derivedLinksStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derivedLinksStore.js","names":["applyShapeTransformationsToArray","buildObjectSetFromLinkDefByType","getLinkQueryOptions","createCachingNotifier","createStoreSubscribe","createVersionedCache","wrapError","buildDataWithNestedLinks","cleanupNestedMap","createLinkEntry","violationsToError","createEmptyDerivedLinksStore","isBatchableLink","NOOP_FETCH_MORE","NESTED_FLUSH_DELAY_MS","pruneStaleNestedEntries","nestedByPk","currentPks","pk","nestedMap","has","delete","createDerivedLinksStore","shape","sourceObject","observableClient","client","linkConfig","linkEntries","Map","derivedLinks","__derivedLinks","linkDef","config","name","set","defer","subscribers","Set","cache","notifySubscribers","pendingNestedEntries","nestedFlushTimer","isDestroyed","scheduleNestedFlush","setTimeout","undefined","batch","splice","filter","entry","cleaned","length","startLinksInBatch","trackNestedLinksForObjects","parentEntry","rawObjects","nestedDerivedLinks","targetShape","rawObj","$primaryKey","add","get","nestedLinkDef","nestedEntry","status","push","sourceType","__baseType","handleNestedLinks","pendingBefore","entries","error","startLinkObservationInternal","catch","err","startLinkObservation","createLinkObserver","next","payload","resolved","resolvedList","transformResult","hasMore","fetchMore","violations","data","complete","objectSet","objectSetDef","queryOptions","pageSize","subscription","observeObjectSet","where","orderBy","autoFetchMore","streamUpdates","unsubscribe","destroy","clearTimeout","values","clear","subscribe","entriesToStart","getSnapShot","buildSnapshot","links","linkStatus","anyLoading","anyError","isLoadingOrInit","isLoading","loadDeferred","linkName","String","retry","retryEntry"],"sources":["derivedLinksStore.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\n/**\n * Store layer for one source object's derived links on a given shape. Owns\n * one `LinkEntry` per top-level derived link. If a link's target shape has\n * its own derived links, also owns one `LinkEntry` per (pk, nestedLinkName)\n * under the parent's `nestedByPk`. Feeds `useSyncExternalStore` via\n * `subscribe` / `getSnapShot`. Teardown is one-way via `destroy`.\n */\n\nimport type {\n ObjectOrInterfaceDefinition,\n ObjectSet,\n ObjectTypeDefinition,\n Osdk,\n} from \"@osdk/api\";\nimport type { ShapeDerivedLinkDef } from \"@osdk/api/shapes-internal\";\nimport type {\n LinkLoadConfig,\n LinkStatus,\n ShapeBaseType,\n ShapeDefinition,\n ShapeDerivedLinks,\n} from \"@osdk/api/unstable\";\nimport type { Client } from \"@osdk/client\";\nimport {\n applyShapeTransformationsToArray,\n buildObjectSetFromLinkDefByType,\n getLinkQueryOptions,\n} from \"@osdk/client/unstable-do-not-use\";\nimport type {\n ObservableClient,\n Observer,\n} from \"@osdk/client/unstable-do-not-use\";\nimport {\n createCachingNotifier,\n createStoreSubscribe,\n createVersionedCache,\n wrapError,\n} from \"../shared/storeUtils.js\";\nimport type {\n AnyShapeInstance,\n DerivedLinksPayload,\n DerivedLinksStore,\n LinkEntry,\n ListObserverPayload,\n} from \"./types.js\";\nimport {\n buildDataWithNestedLinks,\n cleanupNestedMap,\n createLinkEntry,\n violationsToError,\n} from \"./types.js\";\n\nexport type {\n AnyShapeInstance,\n DerivedLinksPayload,\n DerivedLinksStore,\n} from \"./types.js\";\nexport {\n buildDataWithNestedLinks,\n cleanupNestedMap,\n createEmptyDerivedLinksStore,\n isBatchableLink,\n NOOP_FETCH_MORE,\n violationsToError,\n} from \"./types.js\";\n\n/**\n * Debounce window before starting newly-queued nested link observations.\n * When a parent list resolves, each item needs its own nested link\n * subscriptions. If the parent observer emits a few times in quick\n * succession (e.g. streamUpdates), we collapse those into one\n * `startLinksInBatch` call instead of kicking off subscriptions per\n * emission. 25ms is a guess: small enough to feel instant, large enough\n * to coalesce sync-ish bursts. Not tuned against real workloads.\n */\nconst NESTED_FLUSH_DELAY_MS = 25;\n\n/**\n * Removes nested entries for pks that are no longer in the parent's result\n * set. `cleanupNestedMap` recursively unsubscribes each entry and marks it\n * `cleaned`, which allows any already-queued flushes for those entries to\n * no-op gracefully.\n */\nfunction pruneStaleNestedEntries(\n nestedByPk: Map<string | number, Map<string, LinkEntry>>,\n currentPks: Set<string | number>,\n): void {\n for (const [pk, nestedMap] of nestedByPk) {\n if (!currentPks.has(pk)) {\n cleanupNestedMap(nestedMap);\n nestedByPk.delete(pk);\n }\n }\n}\n\n/**\n * Creates a store that observes all derived links for a single source\n * object against the given shape. Returned methods:\n *\n * - `subscribe(notify)`: add a listener. First subscribe kicks off\n * observation of all non-deferred top-level links. Last unsubscribe\n * triggers `destroy`.\n * - `getSnapShot()`: read a cached snapshot of all link data + statuses.\n * - `loadDeferred(linkName)`: start a link configured with `defer: true`.\n * - `retry(linkName?)`: restart error-state entries.\n * - `destroy()`: one-way teardown; cascades through nested subscriptions.\n */\nexport function createDerivedLinksStore<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n>(\n shape: S,\n sourceObject: Osdk.Instance<ShapeBaseType<S>>,\n observableClient: ObservableClient,\n client: Client,\n linkConfig: Partial<Record<keyof ShapeDerivedLinks<S>, LinkLoadConfig>>,\n): DerivedLinksStore<S> {\n const castSource = sourceObject as Osdk.Instance<ObjectOrInterfaceDefinition>;\n const linkEntries = new Map<string, LinkEntry>();\n const derivedLinks = shape.__derivedLinks as readonly ShapeDerivedLinkDef[];\n for (const linkDef of derivedLinks) {\n const config = (linkConfig as Partial<Record<string, LinkLoadConfig>>)[\n linkDef.name\n ];\n linkEntries.set(\n linkDef.name,\n createLinkEntry(linkDef, castSource, config?.defer),\n );\n }\n const subscribers = new Set<() => void>();\n const cache = createVersionedCache<DerivedLinksPayload<S>>();\n const notifySubscribers = createCachingNotifier(subscribers, cache);\n\n const pendingNestedEntries: Array<\n { entry: LinkEntry; sourceType: ObjectOrInterfaceDefinition }\n > = [];\n let nestedFlushTimer: ReturnType<typeof setTimeout> | undefined;\n let isDestroyed = false;\n\n /**\n * Schedules a single flush of `pendingNestedEntries` after the debounce\n * window. An entry can be pruned (via `cleanupNestedMap` setting `cleaned`)\n * between being queued and the flush firing, so we filter those out here\n * instead of trying to remove them from the queue at prune time.\n */\n function scheduleNestedFlush(): void {\n if (nestedFlushTimer != null) {\n return;\n }\n nestedFlushTimer = setTimeout(() => {\n nestedFlushTimer = undefined;\n if (isDestroyed) {\n return;\n }\n const batch = pendingNestedEntries.splice(0).filter(({ entry }) =>\n !entry.cleaned\n );\n if (batch.length > 0) {\n startLinksInBatch(batch);\n }\n }, NESTED_FLUSH_DELAY_MS);\n }\n\n /**\n * For each raw object in a parent's result set, ensure a nested `LinkEntry`\n * exists for every nested derived link the target shape declares. New entries\n * with status `\"init\"` are queued for batched startup; returns the set of\n * pks seen so the caller can prune entries whose pks disappeared.\n */\n function trackNestedLinksForObjects(\n parentEntry: LinkEntry,\n rawObjects: Osdk.Instance<ObjectOrInterfaceDefinition>[],\n ): Set<string | number> {\n const nestedDerivedLinks = parentEntry.linkDef.targetShape\n .__derivedLinks as readonly ShapeDerivedLinkDef[];\n const currentPks = new Set<string | number>();\n\n for (const rawObj of rawObjects) {\n const pk = rawObj.$primaryKey;\n currentPks.add(pk);\n\n let nestedMap = parentEntry.nestedByPk.get(pk);\n if (!nestedMap) {\n nestedMap = new Map();\n parentEntry.nestedByPk.set(pk, nestedMap);\n }\n\n for (const nestedLinkDef of nestedDerivedLinks) {\n if (!nestedMap.has(nestedLinkDef.name)) {\n const nestedEntry = createLinkEntry(nestedLinkDef, rawObj);\n nestedMap.set(nestedLinkDef.name, nestedEntry);\n if (nestedEntry.status === \"init\") {\n pendingNestedEntries.push({\n entry: nestedEntry,\n sourceType: parentEntry.linkDef.targetShape.__baseType,\n });\n }\n }\n }\n }\n\n return currentPks;\n }\n\n /**\n * Called every time a parent link's observer emits. Three steps:\n * 1. Ensure nested entries exist for each raw object (and queue new ones).\n * 2. Prune nested entries for pks no longer in the result set.\n * 3. If new entries were queued, schedule the debounced flush to start them.\n */\n function handleNestedLinks(\n parentEntry: LinkEntry,\n rawObjects: Osdk.Instance<ObjectOrInterfaceDefinition>[],\n ): void {\n const nestedDerivedLinks = parentEntry.linkDef.targetShape\n .__derivedLinks as readonly ShapeDerivedLinkDef[];\n if (nestedDerivedLinks.length === 0) {\n return;\n }\n\n const pendingBefore = pendingNestedEntries.length;\n const currentPks = trackNestedLinksForObjects(parentEntry, rawObjects);\n pruneStaleNestedEntries(parentEntry.nestedByPk, currentPks);\n\n if (pendingNestedEntries.length > pendingBefore) {\n scheduleNestedFlush();\n }\n }\n\n /**\n * Moves a batch of entries to `\"loading\"` in one pass, notifies subscribers\n * once for the bulk status change, and then kicks off each entry's async\n * observation. Errors from `startLinkObservationInternal` flip the entry\n * to `\"error\"` individually.\n */\n function startLinksInBatch(\n entries: Array<\n { entry: LinkEntry; sourceType: ObjectOrInterfaceDefinition }\n >,\n ): void {\n for (const { entry } of entries) {\n entry.status = \"loading\";\n entry.error = undefined;\n }\n notifySubscribers();\n for (const { entry, sourceType } of entries) {\n startLinkObservationInternal(entry, sourceType).catch((err) => {\n entry.status = \"error\";\n entry.error = wrapError(err);\n notifySubscribers();\n });\n }\n }\n\n /** Skips links already loading/loaded, otherwise marks as loading and starts observation. */\n function startLinkObservation(\n entry: LinkEntry,\n sourceType: ObjectOrInterfaceDefinition,\n ): void {\n if (entry.status === \"loading\" || entry.status === \"loaded\") {\n return;\n }\n startLinksInBatch([{ entry, sourceType }]);\n }\n\n /**\n * Observer used for `observeObjectSet` on each link entry. On `next` it\n * applies shape transformations, updates entry state, recurses into nested\n * link handling, and rebuilds the entry's data with any nested link data\n * attached. On `error` it flips the entry to `\"error\"`.\n */\n function createLinkObserver(\n entry: LinkEntry,\n ): Observer<ListObserverPayload> {\n return {\n next: (payload) => {\n if (isDestroyed) {\n return;\n }\n const resolved = payload.resolvedList ?? [];\n const transformResult = applyShapeTransformationsToArray(\n entry.linkDef.targetShape,\n resolved,\n );\n\n entry.status = payload.status === \"loading\" ? \"loading\" : \"loaded\";\n entry.hasMore = payload.hasMore;\n entry.fetchMore = payload.fetchMore;\n entry.error = violationsToError(\n entry.linkDef.targetShape,\n transformResult.violations,\n );\n\n handleNestedLinks(entry, resolved);\n entry.data = buildDataWithNestedLinks(entry, transformResult.data);\n\n notifySubscribers();\n },\n error: (err) => {\n if (isDestroyed) {\n return;\n }\n entry.status = \"error\";\n entry.error = wrapError(err);\n notifySubscribers();\n },\n complete: () => {},\n };\n }\n\n async function startLinkObservationInternal(\n entry: LinkEntry,\n sourceType: ObjectOrInterfaceDefinition,\n ): Promise<void> {\n const objectSet = await buildObjectSetFromLinkDefByType(\n client,\n sourceType,\n entry.sourceObject.$primaryKey,\n entry.linkDef.objectSetDef,\n );\n\n if (isDestroyed) {\n return;\n }\n\n const config = linkEntries.has(entry.linkDef.name)\n ? linkConfig[entry.linkDef.name as keyof ShapeDerivedLinks<S>]\n : undefined;\n\n const queryOptions = getLinkQueryOptions(\n entry.linkDef.objectSetDef,\n entry.sourceObject,\n config?.pageSize,\n );\n\n const subscription = observableClient.observeObjectSet(\n objectSet as ObjectSet<ObjectTypeDefinition>,\n {\n where: queryOptions.where,\n orderBy: queryOptions.orderBy,\n pageSize: queryOptions.pageSize,\n autoFetchMore: config?.autoFetchMore,\n streamUpdates: config?.streamUpdates,\n },\n createLinkObserver(entry),\n );\n\n if (isDestroyed) {\n subscription.unsubscribe();\n return;\n }\n entry.subscription = subscription;\n }\n\n function buildSnapshot(): DerivedLinksPayload<S> {\n return cache.get(() => {\n const links: Record<string, AnyShapeInstance[]> = {};\n const linkStatus: Record<string, LinkStatus> = {};\n let anyLoading = false;\n let anyError = false;\n\n for (const [name, entry] of linkEntries) {\n links[name] = entry.data;\n const isLoadingOrInit = entry.status === \"loading\"\n || entry.status === \"init\";\n if (isLoadingOrInit) {\n anyLoading = true;\n }\n if (entry.status === \"error\") {\n anyError = true;\n }\n linkStatus[name] = {\n isLoading: isLoadingOrInit,\n error: entry.error,\n hasMore: entry.hasMore,\n fetchMore: entry.fetchMore,\n };\n }\n\n return {\n links,\n linkStatus: linkStatus as Partial<\n { [K in keyof ShapeDerivedLinks<S>]: LinkStatus }\n >,\n anyLoading,\n anyError,\n };\n });\n }\n\n /**\n * One-way teardown. Order matters: set `isDestroyed` first so in-flight\n * async work (observer next/error, startLinkObservationInternal) no-ops.\n * Then clear the flush timer, drop the pending queue, unsubscribe every\n * entry, and cascade through `nestedByPk`.\n */\n function destroy(): void {\n isDestroyed = true;\n if (nestedFlushTimer != null) {\n clearTimeout(nestedFlushTimer);\n nestedFlushTimer = undefined;\n }\n pendingNestedEntries.length = 0;\n for (const entry of linkEntries.values()) {\n entry.subscription?.unsubscribe();\n for (const nestedMap of entry.nestedByPk.values()) {\n cleanupNestedMap(nestedMap);\n }\n }\n linkEntries.clear();\n }\n\n const subscribe = createStoreSubscribe(\n subscribers,\n () => {\n const entriesToStart: Array<\n { entry: LinkEntry; sourceType: ObjectOrInterfaceDefinition }\n > = [];\n for (const entry of linkEntries.values()) {\n if (entry.status === \"init\") {\n entriesToStart.push({ entry, sourceType: shape.__baseType });\n }\n }\n if (entriesToStart.length > 0) {\n startLinksInBatch(entriesToStart);\n }\n },\n destroy,\n );\n\n /**\n * Starts observation for a link that was configured with `defer: true`.\n * No-op for unknown link names or links not in the `deferred` state.\n */\n function loadDeferred(\n linkName: keyof ShapeDerivedLinks<S>,\n ): void {\n const entry = linkEntries.get(String(linkName));\n if (!entry || entry.status !== \"deferred\") {\n return;\n }\n startLinkObservation(entry, shape.__baseType);\n }\n\n /**\n * Resets error-state entries back to `\"init\"` and restarts observation.\n * With a `linkName`, scopes to a single entry; otherwise retries all links.\n * No-op for entries not currently in `\"error\"`.\n */\n function retry(linkName?: keyof ShapeDerivedLinks<S>): void {\n const retryEntry = (entry: LinkEntry) => {\n if (entry.status !== \"error\") {\n return;\n }\n entry.subscription?.unsubscribe();\n entry.status = \"init\";\n entry.error = undefined;\n entry.subscription = undefined;\n startLinkObservation(entry, shape.__baseType);\n };\n\n if (linkName) {\n const entry = linkEntries.get(String(linkName));\n if (entry) {\n retryEntry(entry);\n }\n } else {\n for (const entry of linkEntries.values()) {\n retryEntry(entry);\n }\n }\n }\n\n return {\n subscribe,\n getSnapShot: buildSnapshot,\n loadDeferred,\n retry,\n destroy,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export { useShapeList, useShapeSingle } from "./useShape.js";
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["useShapeList","useShapeSingle"],"sources":["index.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\nexport type {\n PerItemLinkStatus,\n UseShapeListOptions,\n UseShapeListResult,\n UseShapeResult,\n} from \"./useShape.js\";\n\nexport { useShapeList, useShapeSingle } from \"./useShape.js\";\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AASA,SAASA,YAAY,EAAEC,cAAc,QAAQ,eAAe","ignoreList":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { ShapeNullabilityError } from "@osdk/api/unstable";
|
|
18
|
+
export const NOOP_FETCH_MORE = async () => {};
|
|
19
|
+
export function violationsToError(shape, violations) {
|
|
20
|
+
if (violations.some(v => v.constraint === "require")) {
|
|
21
|
+
return new ShapeNullabilityError(shape, violations);
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
export function createLinkEntry(linkDef, sourceObject, configDefer) {
|
|
26
|
+
const isDeferred = linkDef.config.defer ?? configDefer ?? false;
|
|
27
|
+
return {
|
|
28
|
+
linkDef,
|
|
29
|
+
sourceObject,
|
|
30
|
+
status: isDeferred ? "deferred" : "init",
|
|
31
|
+
data: [],
|
|
32
|
+
error: undefined,
|
|
33
|
+
hasMore: false,
|
|
34
|
+
fetchMore: NOOP_FETCH_MORE,
|
|
35
|
+
subscription: undefined,
|
|
36
|
+
nestedByPk: new Map(),
|
|
37
|
+
cleaned: false
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function createEmptyDerivedLinksStore() {
|
|
41
|
+
const emptyPayload = {
|
|
42
|
+
links: {},
|
|
43
|
+
linkStatus: {},
|
|
44
|
+
anyLoading: false,
|
|
45
|
+
anyError: false
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
subscribe: () => () => {},
|
|
49
|
+
getSnapShot: () => emptyPayload,
|
|
50
|
+
loadDeferred: () => {},
|
|
51
|
+
retry: () => {},
|
|
52
|
+
destroy: () => {}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function cleanupNestedMap(map) {
|
|
56
|
+
for (const entry of map.values()) {
|
|
57
|
+
entry.cleaned = true;
|
|
58
|
+
entry.subscription?.unsubscribe();
|
|
59
|
+
for (const nestedMap of entry.nestedByPk.values()) {
|
|
60
|
+
cleanupNestedMap(nestedMap);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function buildDataWithNestedLinks(entry, transformedData) {
|
|
65
|
+
const targetShape = entry.linkDef.targetShape;
|
|
66
|
+
if (targetShape.__derivedLinks.length === 0) {
|
|
67
|
+
return transformedData;
|
|
68
|
+
}
|
|
69
|
+
return transformedData.map(obj => {
|
|
70
|
+
const pk = obj.$primaryKey;
|
|
71
|
+
const nestedMap = entry.nestedByPk.get(pk);
|
|
72
|
+
if (!nestedMap || nestedMap.size === 0) {
|
|
73
|
+
return obj;
|
|
74
|
+
}
|
|
75
|
+
const nestedLinks = {};
|
|
76
|
+
for (const [linkName, nestedEntry] of nestedMap) {
|
|
77
|
+
nestedLinks[linkName] = buildDataWithNestedLinks(nestedEntry, nestedEntry.data);
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
...obj,
|
|
81
|
+
...nestedLinks
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A link is batchable when it can use observeLinks (one API call for all source
|
|
88
|
+
* objects) instead of per-object observeObjectSet calls. This requires a simple
|
|
89
|
+
* single-hop pivotTo with no filters, ordering, limits, or set operations,
|
|
90
|
+
* since observeLinks doesn't support those query features.
|
|
91
|
+
*/
|
|
92
|
+
export function isBatchableLink(linkDef) {
|
|
93
|
+
const def = linkDef.objectSetDef;
|
|
94
|
+
return def.segments.length === 1 && def.segments[0].type === "pivotTo" && (!def.setOperations || def.setOperations.length === 0) && !def.where && !def.orderBy && def.limit == null && !def.distinct;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","names":["ShapeNullabilityError","NOOP_FETCH_MORE","violationsToError","shape","violations","some","v","constraint","undefined","createLinkEntry","linkDef","sourceObject","configDefer","isDeferred","config","defer","status","data","error","hasMore","fetchMore","subscription","nestedByPk","Map","cleaned","createEmptyDerivedLinksStore","emptyPayload","links","linkStatus","anyLoading","anyError","subscribe","getSnapShot","loadDeferred","retry","destroy","cleanupNestedMap","map","entry","values","unsubscribe","nestedMap","buildDataWithNestedLinks","transformedData","targetShape","__derivedLinks","length","obj","pk","$primaryKey","get","size","nestedLinks","linkName","nestedEntry","isBatchableLink","def","objectSetDef","segments","type","setOperations","where","orderBy","limit","distinct"],"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 { ObjectOrInterfaceDefinition, Osdk } from \"@osdk/api\";\nimport type { ShapeDerivedLinkDef } from \"@osdk/api/shapes-internal\";\nimport type {\n LinkStatus,\n ShapeDefinition,\n ShapeDerivedLinks,\n ShapeInstance,\n} from \"@osdk/api/unstable\";\nimport { ShapeNullabilityError } from \"@osdk/api/unstable\";\nimport type { Unsubscribable } from \"@osdk/client/unstable-do-not-use\";\n\nexport type AnyShapeInstance = ShapeInstance<\n ShapeDefinition<ObjectOrInterfaceDefinition>\n>;\n\nexport type ListObserverPayload = {\n resolvedList: Osdk.Instance<ObjectOrInterfaceDefinition>[] | undefined;\n hasMore: boolean;\n fetchMore: () => Promise<void>;\n status: string;\n isOptimistic: boolean;\n};\n\nexport const NOOP_FETCH_MORE = async (): Promise<void> => {};\n\nexport function violationsToError(\n shape: ShapeDefinition<ObjectOrInterfaceDefinition>,\n violations: readonly { property: string; constraint: string }[],\n): Error | undefined {\n if (violations.some(v => v.constraint === \"require\")) {\n return new ShapeNullabilityError(\n shape,\n violations as readonly {\n property: string;\n primaryKey: unknown;\n constraint: \"require\" | \"dropIfNull\" | \"transformError\";\n }[],\n );\n }\n return undefined;\n}\n\nexport interface LinkEntry {\n linkDef: ShapeDerivedLinkDef;\n sourceObject: Osdk.Instance<ObjectOrInterfaceDefinition>;\n status: \"init\" | \"loading\" | \"loaded\" | \"error\" | \"deferred\";\n data: AnyShapeInstance[];\n error?: Error;\n hasMore: boolean;\n fetchMore: () => Promise<void>;\n subscription?: Unsubscribable;\n nestedByPk: Map<string | number, Map<string, LinkEntry>>;\n cleaned: boolean;\n}\n\nexport function createLinkEntry(\n linkDef: ShapeDerivedLinkDef,\n sourceObject: Osdk.Instance<ObjectOrInterfaceDefinition>,\n configDefer?: boolean,\n): LinkEntry {\n const isDeferred = linkDef.config.defer ?? configDefer ?? false;\n return {\n linkDef,\n sourceObject,\n status: isDeferred ? \"deferred\" : \"init\",\n data: [],\n error: undefined,\n hasMore: false,\n fetchMore: NOOP_FETCH_MORE,\n subscription: undefined,\n nestedByPk: new Map(),\n cleaned: false,\n };\n}\n\nexport interface DerivedLinksPayload<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n> {\n links: Record<string, AnyShapeInstance[]>;\n linkStatus: Partial<{ [K in keyof ShapeDerivedLinks<S>]: LinkStatus }>;\n anyLoading: boolean;\n anyError: boolean;\n}\n\nexport interface DerivedLinksStore<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n> {\n subscribe: (notifyUpdate: () => void) => () => void;\n getSnapShot: () => DerivedLinksPayload<S>;\n loadDeferred: (linkName: keyof ShapeDerivedLinks<S>) => void;\n retry: (linkName?: keyof ShapeDerivedLinks<S>) => void;\n destroy: () => void;\n}\n\nexport function createEmptyDerivedLinksStore<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n>(): DerivedLinksStore<S> {\n const emptyPayload: DerivedLinksPayload<S> = {\n links: {},\n linkStatus: {},\n anyLoading: false,\n anyError: false,\n };\n\n return {\n subscribe: () => () => {},\n getSnapShot: () => emptyPayload,\n loadDeferred: () => {},\n retry: () => {},\n destroy: () => {},\n };\n}\n\nexport function cleanupNestedMap(map: Map<string, LinkEntry>): void {\n for (const entry of map.values()) {\n entry.cleaned = true;\n entry.subscription?.unsubscribe();\n for (const nestedMap of entry.nestedByPk.values()) {\n cleanupNestedMap(nestedMap);\n }\n }\n}\n\nexport function buildDataWithNestedLinks(\n entry: LinkEntry,\n transformedData: AnyShapeInstance[],\n): AnyShapeInstance[] {\n const targetShape = entry.linkDef.targetShape;\n if (targetShape.__derivedLinks.length === 0) {\n return transformedData;\n }\n\n return transformedData.map((obj) => {\n const pk = obj.$primaryKey;\n const nestedMap = entry.nestedByPk.get(pk);\n if (!nestedMap || nestedMap.size === 0) {\n return obj;\n }\n\n const nestedLinks: Record<string, AnyShapeInstance[]> = {};\n for (const [linkName, nestedEntry] of nestedMap) {\n nestedLinks[linkName] = buildDataWithNestedLinks(\n nestedEntry,\n nestedEntry.data,\n );\n }\n\n return { ...obj, ...nestedLinks } as AnyShapeInstance;\n });\n}\n\n/**\n * A link is batchable when it can use observeLinks (one API call for all source\n * objects) instead of per-object observeObjectSet calls. This requires a simple\n * single-hop pivotTo with no filters, ordering, limits, or set operations,\n * since observeLinks doesn't support those query features.\n */\nexport function isBatchableLink(linkDef: ShapeDerivedLinkDef): boolean {\n const def = linkDef.objectSetDef;\n return (\n def.segments.length === 1\n && def.segments[0].type === \"pivotTo\"\n && (!def.setOperations || def.setOperations.length === 0)\n && !def.where\n && !def.orderBy\n && def.limit == null\n && !def.distinct\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export function useShapeSingle() {
|
|
18
|
+
throw new Error("useShapeSingle is not implemented yet");
|
|
19
|
+
}
|
|
20
|
+
export function useShapeList() {
|
|
21
|
+
throw new Error("useShapeList is not implemented yet");
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=useShape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useShape.js","names":["useShapeSingle","Error","useShapeList"],"sources":["useShape.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 ObjectOrInterfaceDefinition,\n PrimaryKeyType,\n PropertyKeys,\n WhereClause,\n} from \"@osdk/api\";\nimport type {\n LinkLoadConfig,\n LinkStatus,\n NullabilityViolation,\n ShapeBaseType,\n ShapeDefinition,\n ShapeDerivedLinks,\n ShapeInstance,\n} from \"@osdk/api/unstable\";\n\nexport interface UseShapeResult<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n> {\n data: ShapeInstance<S> | undefined;\n isLoading: boolean;\n error: Error | undefined;\n isOptimistic: boolean;\n droppedDueToNullability: boolean;\n nullabilityViolations: readonly NullabilityViolation[];\n linkStatus: Partial<{ [K in keyof ShapeDerivedLinks<S>]: LinkStatus }>;\n loadDeferred: (linkName: keyof ShapeDerivedLinks<S>) => void;\n retry: (linkName?: keyof ShapeDerivedLinks<S>) => void;\n invalidate: (linkName?: keyof ShapeDerivedLinks<S>) => void;\n}\n\nexport interface UseShapeListOptions<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n> {\n where?: WhereClause<ShapeBaseType<S>>;\n pageSize?: number;\n orderBy?: { [K in PropertyKeys<ShapeBaseType<S>>]?: \"asc\" | \"desc\" };\n autoFetchMore?: boolean | number;\n dedupeIntervalMs?: number;\n streamUpdates?: boolean;\n enabled?: boolean;\n links?: Partial<{ [K in keyof ShapeDerivedLinks<S>]: LinkLoadConfig }>;\n}\n\nexport type PerItemLinkStatus<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n> = Map<\n string | number,\n Partial<{ [K in keyof ShapeDerivedLinks<S>]: LinkStatus }>\n>;\n\nexport interface UseShapeListResult<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n> {\n data: ShapeInstance<S>[] | undefined;\n isLoading: boolean;\n error: Error | undefined;\n isOptimistic: boolean;\n fetchMore: (() => Promise<void>) | undefined;\n droppedCount: number;\n nullabilityViolations: readonly NullabilityViolation[];\n itemLinkStatus: PerItemLinkStatus<S>;\n linkStatus: Partial<{ [K in keyof ShapeDerivedLinks<S>]: LinkStatus }>;\n loadDeferred: (\n primaryKey: string | number,\n linkName: keyof ShapeDerivedLinks<S>,\n ) => void;\n retry: (\n primaryKey?: string | number,\n linkName?: keyof ShapeDerivedLinks<S>,\n ) => void;\n invalidate: (linkName?: keyof ShapeDerivedLinks<S>) => void;\n}\n\nexport function useShapeSingle<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n>(\n _shape: S,\n _primaryKey: PrimaryKeyType<ShapeBaseType<S>>,\n _options?: {\n enabled?: boolean;\n links?: Partial<{ [K in keyof ShapeDerivedLinks<S>]: LinkLoadConfig }>;\n },\n): UseShapeResult<S> {\n throw new Error(\"useShapeSingle is not implemented yet\");\n}\n\nexport function useShapeList<\n S extends ShapeDefinition<ObjectOrInterfaceDefinition>,\n>(\n _shape: S,\n _options: UseShapeListOptions<S>,\n): UseShapeListResult<S> {\n throw new Error(\"useShapeList is not implemented yet\");\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AA4EA,OAAO,SAASA,cAAcA,CAAA,EAST;EACnB,MAAM,IAAIC,KAAK,CAAC,uCAAuC,CAAC;AAC1D;AAEA,OAAO,SAASC,YAAYA,CAAA,EAKH;EACvB,MAAM,IAAID,KAAK,CAAC,qCAAqC,CAAC;AACxD","ignoreList":[]}
|