@osdk/client 2.7.1 → 2.7.2

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 (83) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/browser/Client.js +1 -1
  3. package/build/browser/Client.js.map +1 -1
  4. package/build/browser/observable/ObservableClient.js.map +1 -1
  5. package/build/browser/observable/internal/BulkObjectLoader.js +71 -9
  6. package/build/browser/observable/internal/BulkObjectLoader.js.map +1 -1
  7. package/build/browser/observable/internal/BulkObjectLoader.test.js +79 -0
  8. package/build/browser/observable/internal/BulkObjectLoader.test.js.map +1 -1
  9. package/build/browser/observable/internal/ObservableClientImpl.js +104 -17
  10. package/build/browser/observable/internal/ObservableClientImpl.js.map +1 -1
  11. package/build/browser/observable/internal/PivotCanonicalizer.js +4 -4
  12. package/build/browser/observable/internal/PivotCanonicalizer.js.map +1 -1
  13. package/build/browser/observable/internal/Store.test.js +185 -1
  14. package/build/browser/observable/internal/Store.test.js.map +1 -1
  15. package/build/browser/observable/internal/list/InterfaceListQuery.js +49 -3
  16. package/build/browser/observable/internal/list/InterfaceListQuery.js.map +1 -1
  17. package/build/browser/observable/internal/list/ListQuery.test.js +154 -0
  18. package/build/browser/observable/internal/list/ListQuery.test.js.map +1 -1
  19. package/build/browser/observable/internal/list/ListsHelper.js +1 -1
  20. package/build/browser/observable/internal/list/ListsHelper.js.map +1 -1
  21. package/build/browser/observable/internal/list/ObjectListQuery.js +22 -21
  22. package/build/browser/observable/internal/list/ObjectListQuery.js.map +1 -1
  23. package/build/browser/observable/internal/object/ObjectQuery.js +23 -6
  24. package/build/browser/observable/internal/object/ObjectQuery.js.map +1 -1
  25. package/build/browser/observable/internal/object/ObjectsHelper.js +3 -1
  26. package/build/browser/observable/internal/object/ObjectsHelper.js.map +1 -1
  27. package/build/browser/util/UserAgent.js +2 -2
  28. package/build/browser/util/interfaceUtils.js +7 -0
  29. package/build/browser/util/interfaceUtils.js.map +1 -1
  30. package/build/cjs/{chunk-OZNDU7AU.cjs → chunk-R6UWEIUJ.cjs} +2 -2
  31. package/build/cjs/{chunk-OZNDU7AU.cjs.map → chunk-R6UWEIUJ.cjs.map} +1 -1
  32. package/build/cjs/{chunk-OVZCGOMG.cjs → chunk-YFQRCAZX.cjs} +69 -65
  33. package/build/cjs/chunk-YFQRCAZX.cjs.map +1 -0
  34. package/build/cjs/index.cjs +8 -8
  35. package/build/cjs/public/internal.cjs +8 -8
  36. package/build/cjs/public/unstable-do-not-use.cjs +323 -112
  37. package/build/cjs/public/unstable-do-not-use.cjs.map +1 -1
  38. package/build/cjs/public/unstable-do-not-use.d.cts +9 -9
  39. package/build/esm/Client.js +1 -1
  40. package/build/esm/Client.js.map +1 -1
  41. package/build/esm/observable/ObservableClient.js.map +1 -1
  42. package/build/esm/observable/internal/BulkObjectLoader.js +71 -9
  43. package/build/esm/observable/internal/BulkObjectLoader.js.map +1 -1
  44. package/build/esm/observable/internal/BulkObjectLoader.test.js +79 -0
  45. package/build/esm/observable/internal/BulkObjectLoader.test.js.map +1 -1
  46. package/build/esm/observable/internal/ObservableClientImpl.js +104 -17
  47. package/build/esm/observable/internal/ObservableClientImpl.js.map +1 -1
  48. package/build/esm/observable/internal/PivotCanonicalizer.js +4 -4
  49. package/build/esm/observable/internal/PivotCanonicalizer.js.map +1 -1
  50. package/build/esm/observable/internal/Store.test.js +185 -1
  51. package/build/esm/observable/internal/Store.test.js.map +1 -1
  52. package/build/esm/observable/internal/list/InterfaceListQuery.js +49 -3
  53. package/build/esm/observable/internal/list/InterfaceListQuery.js.map +1 -1
  54. package/build/esm/observable/internal/list/ListQuery.test.js +154 -0
  55. package/build/esm/observable/internal/list/ListQuery.test.js.map +1 -1
  56. package/build/esm/observable/internal/list/ListsHelper.js +1 -1
  57. package/build/esm/observable/internal/list/ListsHelper.js.map +1 -1
  58. package/build/esm/observable/internal/list/ObjectListQuery.js +22 -21
  59. package/build/esm/observable/internal/list/ObjectListQuery.js.map +1 -1
  60. package/build/esm/observable/internal/object/ObjectQuery.js +23 -6
  61. package/build/esm/observable/internal/object/ObjectQuery.js.map +1 -1
  62. package/build/esm/observable/internal/object/ObjectsHelper.js +3 -1
  63. package/build/esm/observable/internal/object/ObjectsHelper.js.map +1 -1
  64. package/build/esm/util/UserAgent.js +2 -2
  65. package/build/esm/util/interfaceUtils.js +7 -0
  66. package/build/esm/util/interfaceUtils.js.map +1 -1
  67. package/build/types/Client.d.ts +1 -1
  68. package/build/types/observable/ObservableClient.d.ts +12 -12
  69. package/build/types/observable/ObservableClient.d.ts.map +1 -1
  70. package/build/types/observable/internal/BulkObjectLoader.d.ts +2 -1
  71. package/build/types/observable/internal/BulkObjectLoader.d.ts.map +1 -1
  72. package/build/types/observable/internal/PivotCanonicalizer.d.ts +2 -2
  73. package/build/types/observable/internal/PivotCanonicalizer.d.ts.map +1 -1
  74. package/build/types/observable/internal/Store.test.d.ts.map +1 -1
  75. package/build/types/observable/internal/list/InterfaceListQuery.d.ts.map +1 -1
  76. package/build/types/observable/internal/list/ObjectListQuery.d.ts.map +1 -1
  77. package/build/types/observable/internal/object/ObjectQuery.d.ts +2 -1
  78. package/build/types/observable/internal/object/ObjectQuery.d.ts.map +1 -1
  79. package/build/types/observable/internal/object/ObjectsHelper.d.ts.map +1 -1
  80. package/build/types/util/interfaceUtils.d.ts +2 -1
  81. package/build/types/util/interfaceUtils.d.ts.map +1 -1
  82. package/package.json +5 -5
  83. package/build/cjs/chunk-OVZCGOMG.cjs.map +0 -1
@@ -63,24 +63,9 @@ export class ObservableClientImpl {
63
63
  }, subFn);
64
64
  };
65
65
  observeLinks = (objects, linkName, options, subFn) => {
66
- // Convert to array if single object provided
67
66
  const objectsArray = Array.isArray(objects) ? objects : [objects];
68
- const parentSub = new Subscription();
69
- for (const obj of objectsArray) {
70
- const querySubscription = this.__experimentalStore.links.observe({
71
- ...options,
72
- srcType: {
73
- type: "object",
74
- apiName: obj.$objectType ?? obj.$apiName
75
- },
76
- linkName,
77
- pk: obj.$primaryKey
78
- },
79
- // cast to cross typed to untyped barrier
80
- subFn);
81
- parentSub.add(querySubscription);
82
- }
83
- return new UnsubscribableWrapper(parentSub);
67
+ const observer = subFn;
68
+ return objectsArray.length <= 1 ? observeSingleLink(this.__experimentalStore, objectsArray, linkName, options, observer) : observeMultiLinks(this.__experimentalStore, objectsArray, linkName, options, observer);
84
69
  };
85
70
  observeObjectSet(baseObjectSet, options, subFn) {
86
71
  return this.__experimentalStore.objectSets.observe({
@@ -109,4 +94,106 @@ export class ObservableClientImpl {
109
94
  return this.__experimentalStore.whereCanonicalizer.canonicalize(where);
110
95
  }
111
96
  }
97
+ function observeSingleLink(store, objectsArray, linkName, options, observer) {
98
+ if (objectsArray.length === 0) {
99
+ observer.next({
100
+ resolvedList: [],
101
+ isOptimistic: false,
102
+ lastUpdated: 0,
103
+ fetchMore: () => Promise.resolve(),
104
+ hasMore: false,
105
+ status: "loaded",
106
+ totalCount: "0"
107
+ });
108
+ return new UnsubscribableWrapper(new Subscription());
109
+ }
110
+ const parentSub = new Subscription();
111
+ for (const obj of objectsArray) {
112
+ parentSub.add(store.links.observe({
113
+ ...options,
114
+ srcType: {
115
+ type: "object",
116
+ apiName: obj.$objectType ?? obj.$apiName
117
+ },
118
+ linkName,
119
+ pk: obj.$primaryKey
120
+ }, observer));
121
+ }
122
+ return new UnsubscribableWrapper(parentSub);
123
+ }
124
+ function observeMultiLinks(store, objectsArray, linkName, options, observer) {
125
+ const parentSub = new Subscription();
126
+ const totalExpected = objectsArray.length;
127
+ const perObjectResults = new Map();
128
+ let errored = false;
129
+ function mergeAndEmit() {
130
+ if (errored) {
131
+ return;
132
+ }
133
+ const seen = new Map();
134
+ const fetchMores = [];
135
+ let latestUpdated = 0;
136
+ let hasMore = false;
137
+ let isOptimistic = false;
138
+ for (const payload of perObjectResults.values()) {
139
+ for (const obj of payload.resolvedList) {
140
+ seen.set(`${obj.$objectType}:${obj.$primaryKey}`, obj);
141
+ }
142
+ if (payload.lastUpdated > latestUpdated) {
143
+ latestUpdated = payload.lastUpdated;
144
+ }
145
+ if (payload.isOptimistic) {
146
+ isOptimistic = true;
147
+ }
148
+ if (payload.hasMore) {
149
+ hasMore = true;
150
+ fetchMores.push(payload.fetchMore);
151
+ }
152
+ }
153
+ const payloads = [...perObjectResults.values()];
154
+ const loading = perObjectResults.size < totalExpected || payloads.some(p => p.status === "init" || p.status === "loading");
155
+ observer.next({
156
+ resolvedList: Array.from(seen.values()),
157
+ isOptimistic,
158
+ lastUpdated: latestUpdated,
159
+ fetchMore: hasMore ? () => Promise.all(fetchMores.map(fn => fn())).then(() => {}) : () => Promise.resolve(),
160
+ hasMore,
161
+ status: loading ? "loading" : payloads.some(p => p.status === "error") ? "error" : "loaded",
162
+ ...(!hasMore ? {
163
+ totalCount: String(seen.size)
164
+ } : {})
165
+ });
166
+ }
167
+ for (const obj of objectsArray) {
168
+ const objKey = `${obj.$objectType ?? obj.$apiName}:${obj.$primaryKey}`;
169
+ parentSub.add(store.links.observe({
170
+ ...options,
171
+ srcType: {
172
+ type: "object",
173
+ apiName: obj.$objectType ?? obj.$apiName
174
+ },
175
+ linkName,
176
+ pk: obj.$primaryKey
177
+ }, {
178
+ next: payload => {
179
+ if (errored) {
180
+ return;
181
+ }
182
+ perObjectResults.set(objKey, payload);
183
+ mergeAndEmit();
184
+ },
185
+ error: err => {
186
+ if (errored) {
187
+ return;
188
+ }
189
+ errored = true;
190
+ parentSub.unsubscribe();
191
+ observer.error(err);
192
+ },
193
+ // store link queries are long-lived and do not complete
194
+ complete: () => {}
195
+ }));
196
+ }
197
+ return new UnsubscribableWrapper(parentSub);
198
+ }
112
199
  //# sourceMappingURL=ObservableClientImpl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ObservableClientImpl.js","names":["Subscription","UnsubscribableWrapper","ObservableClientImpl","constructor","store","__experimentalStore","applyAction","bind","validateAction","observeObject","apiName","pk","options","subFn","objects","observe","observeList","lists","observeAggregation","aggregations","observeFunction","queryDef","params","dependsOn","map","dep","dependsOnObjects","obj","$apiName","$objectType","$primaryKey","functions","observeLinks","linkName","objectsArray","Array","isArray","parentSub","querySubscription","links","srcType","type","add","observeObjectSet","baseObjectSet","objectSets","invalidateAll","invalidateObjects","invalidateObjectType","undefined","invalidateFunction","invalidateFunctionsByObject","primaryKey","canonicalizeWhereClause","where","whereCanonicalizer","canonicalize"],"sources":["ObservableClientImpl.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 ActionDefinition,\n ActionEditResponse,\n ActionValidationResponse,\n AggregateOpts,\n CompileTimeMetadata,\n InterfaceDefinition,\n ObjectOrInterfaceDefinition,\n ObjectSet,\n ObjectTypeDefinition,\n Osdk,\n PrimaryKeyType,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n WirePropertyTypes,\n} from \"@osdk/api\";\nimport { Subscription } from \"rxjs\";\nimport type { ActionSignatureFromDef } from \"../../actions/applyAction.js\";\nimport type { FunctionPayload } from \"../FunctionPayload.js\";\nimport type { SpecificLinkPayload } from \"../LinkPayload.js\";\nimport type { ListPayload } from \"../ListPayload.js\";\nimport type { ObjectPayload } from \"../ObjectPayload.js\";\nimport type { ObjectSetPayload } from \"../ObjectSetPayload.js\";\nimport type {\n ObservableClient,\n ObserveAggregationArgs,\n ObserveAggregationOptions,\n ObserveFunctionCallbackArgs,\n ObserveFunctionOptions,\n ObserveListOptions,\n ObserveObjectCallbackArgs,\n ObserveObjectOptions,\n ObserveObjectsCallbackArgs,\n ObserveObjectSetArgs,\n Unsubscribable,\n} from \"../ObservableClient.js\";\nimport type { Observer } from \"../ObservableClient/common.js\";\nimport type { ObserveLinks } from \"../ObservableClient/ObserveLink.js\";\nimport type { AggregationPayloadBase } from \"./aggregation/AggregationQuery.js\";\nimport type { Canonical } from \"./Canonical.js\";\nimport type { ObserveObjectSetOptions } from \"./objectset/ObjectSetQueryOptions.js\";\nimport type { Store } from \"./Store.js\";\nimport { UnsubscribableWrapper } from \"./UnsubscribableWrapper.js\";\n\n/**\n * Implementation of the public ObservableClient interface.\n * - Delegates all operations to the Store for consistency\n * - Serves as the entry point for reactive data management\n * - Ensures proper method binding and API exposure\n *\n * @internal\n */\nexport class ObservableClientImpl implements ObservableClient {\n __experimentalStore: Store;\n\n constructor(store: Store) {\n this.__experimentalStore = store;\n\n this.applyAction = store.applyAction.bind(store);\n this.validateAction = store.validateAction.bind(store);\n }\n\n public observeObject: <T extends ObjectTypeDefinition>(\n apiName: T[\"apiName\"] | T,\n pk: PrimaryKeyType<T>,\n options: Omit<ObserveObjectOptions<T>, \"apiName\" | \"pk\">,\n subFn: Observer<ObserveObjectCallbackArgs<T>>,\n ) => Unsubscribable = (apiName, pk, options, subFn) => {\n return this.__experimentalStore.objects.observe(\n {\n ...options,\n apiName,\n pk,\n },\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<ObjectPayload>,\n );\n };\n\n public observeList: <\n T extends ObjectTypeDefinition | InterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(\n options: ObserveListOptions<T, RDPs>,\n subFn: Observer<ObserveObjectsCallbackArgs<T, RDPs>>,\n ) => Unsubscribable = (options, subFn) => {\n return this.__experimentalStore.lists.observe(\n options,\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<ListPayload>,\n );\n };\n\n public observeAggregation: <\n T extends ObjectOrInterfaceDefinition,\n A extends AggregateOpts<T>,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(\n options: ObserveAggregationOptions<T, A, RDPs>,\n subFn: Observer<ObserveAggregationArgs<T, A>>,\n ) => Unsubscribable = <\n T extends ObjectOrInterfaceDefinition,\n A extends AggregateOpts<T>,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(\n options: ObserveAggregationOptions<T, A, RDPs>,\n subFn: Observer<ObserveAggregationArgs<T, A>>,\n ) => {\n return this.__experimentalStore.aggregations.observe(\n options,\n subFn as Observer<AggregationPayloadBase>,\n );\n };\n\n public observeFunction: <Q extends QueryDefinition<unknown>>(\n queryDef: Q,\n params: Record<string, unknown> | undefined,\n options: ObserveFunctionOptions,\n subFn: Observer<ObserveFunctionCallbackArgs<Q>>,\n ) => Unsubscribable = (queryDef, params, options, subFn) => {\n const dependsOn = options.dependsOn?.map(dep =>\n typeof dep === \"string\" ? dep : dep.apiName\n );\n const dependsOnObjects = options.dependsOnObjects?.map(obj => ({\n $apiName: obj.$objectType ?? obj.$apiName,\n $primaryKey: obj.$primaryKey,\n }));\n\n return this.__experimentalStore.functions.observe(\n {\n ...options,\n queryDef,\n params,\n dependsOn,\n dependsOnObjects,\n },\n subFn as unknown as Observer<FunctionPayload>,\n );\n };\n\n public observeLinks: <\n T extends ObjectTypeDefinition | InterfaceDefinition,\n L extends keyof CompileTimeMetadata<T>[\"links\"] & string,\n >(\n objects: Osdk.Instance<T> | Array<Osdk.Instance<T>>,\n linkName: L,\n options: ObserveLinks.Options<T, L>,\n subFn: Observer<\n ObserveLinks.CallbackArgs<\n CompileTimeMetadata<T>[\"links\"][L][\"targetType\"]\n >\n >,\n ) => Unsubscribable = (objects, linkName, options, subFn) => {\n // Convert to array if single object provided\n const objectsArray = Array.isArray(objects) ? objects : [objects];\n\n const parentSub = new Subscription();\n\n for (const obj of objectsArray) {\n const querySubscription = this.__experimentalStore.links\n .observe(\n {\n ...options,\n srcType: {\n type: \"object\",\n apiName: obj.$objectType ?? obj.$apiName,\n },\n linkName,\n pk: obj.$primaryKey,\n },\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<SpecificLinkPayload>,\n );\n\n parentSub.add(querySubscription);\n }\n\n return new UnsubscribableWrapper(parentSub);\n };\n\n public applyAction: <Q extends ActionDefinition<any>>(\n action: Q,\n args: Parameters<ActionSignatureFromDef<Q>[\"applyAction\"]>[0],\n opts?: ObservableClient.ApplyActionOptions,\n ) => Promise<ActionEditResponse>;\n\n public validateAction: <Q extends ActionDefinition<any>>(\n action: Q,\n args: Parameters<ActionSignatureFromDef<Q>[\"applyAction\"]>[0],\n ) => Promise<ActionValidationResponse>;\n\n public observeObjectSet<\n T extends ObjectTypeDefinition,\n RDPs extends Record<\n string,\n WirePropertyTypes | undefined | Array<WirePropertyTypes>\n > = {},\n >(\n baseObjectSet: ObjectSet<T>,\n options: ObserveObjectSetOptions<T, RDPs>,\n subFn: Observer<ObserveObjectSetArgs<T, RDPs>>,\n ): Unsubscribable {\n return this.__experimentalStore.objectSets.observe(\n { baseObjectSet, ...options },\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<ObjectSetPayload>,\n );\n }\n\n public invalidateAll(): Promise<void> {\n return this.__experimentalStore.invalidateAll();\n }\n\n public invalidateObjects(\n objects:\n | Osdk.Instance<ObjectTypeDefinition>\n | ReadonlyArray<Osdk.Instance<ObjectTypeDefinition>>,\n ): Promise<void> {\n return this.__experimentalStore.invalidateObjects(objects);\n }\n\n public invalidateObjectType<T extends ObjectTypeDefinition>(\n type: T | T[\"apiName\"],\n ): Promise<void> {\n return this.__experimentalStore.invalidateObjectType(type, undefined);\n }\n\n public invalidateFunction(\n apiName: string | QueryDefinition<unknown>,\n params?: Record<string, unknown>,\n ): Promise<void> {\n return this.__experimentalStore.invalidateFunction(apiName, params);\n }\n\n public invalidateFunctionsByObject(\n apiName: string,\n primaryKey: string | number,\n ): Promise<void> {\n return this.__experimentalStore.invalidateFunctionsByObject(\n apiName,\n primaryKey,\n );\n }\n\n public canonicalizeWhereClause<\n T extends ObjectTypeDefinition | InterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(where: WhereClause<T, RDPs>): Canonical<WhereClause<T, RDPs>> {\n return this.__experimentalStore.whereCanonicalizer\n .canonicalize(where) as Canonical<WhereClause<T, RDPs>>;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"ObservableClientImpl.js","names":["Subscription","UnsubscribableWrapper","ObservableClientImpl","constructor","store","__experimentalStore","applyAction","bind","validateAction","observeObject","apiName","pk","options","subFn","objects","observe","observeList","lists","observeAggregation","aggregations","observeFunction","queryDef","params","dependsOn","map","dep","dependsOnObjects","obj","$apiName","$objectType","$primaryKey","functions","observeLinks","linkName","objectsArray","Array","isArray","observer","length","observeSingleLink","observeMultiLinks","observeObjectSet","baseObjectSet","objectSets","invalidateAll","invalidateObjects","invalidateObjectType","type","undefined","invalidateFunction","invalidateFunctionsByObject","primaryKey","canonicalizeWhereClause","where","whereCanonicalizer","canonicalize","next","resolvedList","isOptimistic","lastUpdated","fetchMore","Promise","resolve","hasMore","status","totalCount","parentSub","add","links","srcType","totalExpected","perObjectResults","Map","errored","mergeAndEmit","seen","fetchMores","latestUpdated","payload","values","set","push","payloads","loading","size","some","p","from","all","fn","then","String","objKey","error","err","unsubscribe","complete"],"sources":["ObservableClientImpl.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 ActionDefinition,\n ActionEditResponse,\n ActionValidationResponse,\n AggregateOpts,\n CompileTimeMetadata,\n InterfaceDefinition,\n ObjectOrInterfaceDefinition,\n ObjectSet,\n ObjectTypeDefinition,\n Osdk,\n PrimaryKeyType,\n QueryDefinition,\n SimplePropertyDef,\n WhereClause,\n WirePropertyTypes,\n} from \"@osdk/api\";\nimport { Subscription } from \"rxjs\";\nimport type { ActionSignatureFromDef } from \"../../actions/applyAction.js\";\nimport type { FunctionPayload } from \"../FunctionPayload.js\";\nimport type { SpecificLinkPayload } from \"../LinkPayload.js\";\nimport type { ListPayload } from \"../ListPayload.js\";\nimport type { ObjectPayload } from \"../ObjectPayload.js\";\nimport type { ObjectSetPayload } from \"../ObjectSetPayload.js\";\nimport type {\n ObservableClient,\n ObserveAggregationArgs,\n ObserveAggregationOptions,\n ObserveFunctionCallbackArgs,\n ObserveFunctionOptions,\n ObserveListOptions,\n ObserveObjectCallbackArgs,\n ObserveObjectOptions,\n ObserveObjectsCallbackArgs,\n ObserveObjectSetArgs,\n Unsubscribable,\n} from \"../ObservableClient.js\";\nimport type { Observer } from \"../ObservableClient/common.js\";\nimport type { ObserveLinks } from \"../ObservableClient/ObserveLink.js\";\nimport type { AggregationPayloadBase } from \"./aggregation/AggregationQuery.js\";\nimport type { Canonical } from \"./Canonical.js\";\nimport type { ObserveObjectSetOptions } from \"./objectset/ObjectSetQueryOptions.js\";\nimport type { Store } from \"./Store.js\";\nimport { UnsubscribableWrapper } from \"./UnsubscribableWrapper.js\";\n\n/**\n * Implementation of the public ObservableClient interface.\n * - Delegates all operations to the Store for consistency\n * - Serves as the entry point for reactive data management\n * - Ensures proper method binding and API exposure\n *\n * @internal\n */\nexport class ObservableClientImpl implements ObservableClient {\n __experimentalStore: Store;\n\n constructor(store: Store) {\n this.__experimentalStore = store;\n\n this.applyAction = store.applyAction.bind(store);\n this.validateAction = store.validateAction.bind(store);\n }\n\n public observeObject: <T extends ObjectOrInterfaceDefinition>(\n apiName: T[\"apiName\"] | T,\n pk: PrimaryKeyType<T>,\n options: Omit<ObserveObjectOptions<T>, \"apiName\" | \"pk\">,\n subFn: Observer<ObserveObjectCallbackArgs<T>>,\n ) => Unsubscribable = (apiName, pk, options, subFn) => {\n return this.__experimentalStore.objects.observe(\n {\n ...options,\n apiName,\n pk,\n },\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<ObjectPayload>,\n );\n };\n\n public observeList: <\n T extends ObjectTypeDefinition | InterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(\n options: ObserveListOptions<T, RDPs>,\n subFn: Observer<ObserveObjectsCallbackArgs<T, RDPs>>,\n ) => Unsubscribable = (options, subFn) => {\n return this.__experimentalStore.lists.observe(\n options,\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<ListPayload>,\n );\n };\n\n public observeAggregation: <\n T extends ObjectOrInterfaceDefinition,\n A extends AggregateOpts<T>,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(\n options: ObserveAggregationOptions<T, A, RDPs>,\n subFn: Observer<ObserveAggregationArgs<T, A>>,\n ) => Unsubscribable = <\n T extends ObjectOrInterfaceDefinition,\n A extends AggregateOpts<T>,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(\n options: ObserveAggregationOptions<T, A, RDPs>,\n subFn: Observer<ObserveAggregationArgs<T, A>>,\n ) => {\n return this.__experimentalStore.aggregations.observe(\n options,\n subFn as Observer<AggregationPayloadBase>,\n );\n };\n\n public observeFunction: <Q extends QueryDefinition<unknown>>(\n queryDef: Q,\n params: Record<string, unknown> | undefined,\n options: ObserveFunctionOptions,\n subFn: Observer<ObserveFunctionCallbackArgs<Q>>,\n ) => Unsubscribable = (queryDef, params, options, subFn) => {\n const dependsOn = options.dependsOn?.map(dep =>\n typeof dep === \"string\" ? dep : dep.apiName\n );\n const dependsOnObjects = options.dependsOnObjects?.map(obj => ({\n $apiName: obj.$objectType ?? obj.$apiName,\n $primaryKey: obj.$primaryKey,\n }));\n\n return this.__experimentalStore.functions.observe(\n {\n ...options,\n queryDef,\n params,\n dependsOn,\n dependsOnObjects,\n },\n subFn as unknown as Observer<FunctionPayload>,\n );\n };\n\n public observeLinks: <\n T extends ObjectOrInterfaceDefinition,\n L extends keyof CompileTimeMetadata<T>[\"links\"] & string,\n >(\n objects: Osdk.Instance<T> | Array<Osdk.Instance<T>>,\n linkName: L,\n options: ObserveLinks.Options<T, L>,\n subFn: Observer<\n ObserveLinks.CallbackArgs<\n CompileTimeMetadata<T>[\"links\"][L][\"targetType\"]\n >\n >,\n ) => Unsubscribable = (objects, linkName, options, subFn) => {\n const objectsArray = Array.isArray(objects) ? objects : [objects];\n const observer = subFn as unknown as Observer<SpecificLinkPayload>;\n\n return objectsArray.length <= 1\n ? observeSingleLink(\n this.__experimentalStore,\n objectsArray,\n linkName,\n options,\n observer,\n )\n : observeMultiLinks(\n this.__experimentalStore,\n objectsArray,\n linkName,\n options,\n observer,\n );\n };\n\n public applyAction: <Q extends ActionDefinition<any>>(\n action: Q,\n args: Parameters<ActionSignatureFromDef<Q>[\"applyAction\"]>[0],\n opts?: ObservableClient.ApplyActionOptions,\n ) => Promise<ActionEditResponse>;\n\n public validateAction: <Q extends ActionDefinition<any>>(\n action: Q,\n args: Parameters<ActionSignatureFromDef<Q>[\"applyAction\"]>[0],\n ) => Promise<ActionValidationResponse>;\n\n public observeObjectSet<\n T extends ObjectTypeDefinition,\n RDPs extends Record<\n string,\n WirePropertyTypes | undefined | Array<WirePropertyTypes>\n > = {},\n >(\n baseObjectSet: ObjectSet<T>,\n options: ObserveObjectSetOptions<T, RDPs>,\n subFn: Observer<ObserveObjectSetArgs<T, RDPs>>,\n ): Unsubscribable {\n return this.__experimentalStore.objectSets.observe(\n { baseObjectSet, ...options },\n // cast to cross typed to untyped barrier\n subFn as unknown as Observer<ObjectSetPayload>,\n );\n }\n\n public invalidateAll(): Promise<void> {\n return this.__experimentalStore.invalidateAll();\n }\n\n public invalidateObjects(\n objects:\n | Osdk.Instance<ObjectTypeDefinition>\n | ReadonlyArray<Osdk.Instance<ObjectTypeDefinition>>,\n ): Promise<void> {\n return this.__experimentalStore.invalidateObjects(objects);\n }\n\n public invalidateObjectType<T extends ObjectTypeDefinition>(\n type: T | T[\"apiName\"],\n ): Promise<void> {\n return this.__experimentalStore.invalidateObjectType(type, undefined);\n }\n\n public invalidateFunction(\n apiName: string | QueryDefinition<unknown>,\n params?: Record<string, unknown>,\n ): Promise<void> {\n return this.__experimentalStore.invalidateFunction(apiName, params);\n }\n\n public invalidateFunctionsByObject(\n apiName: string,\n primaryKey: string | number,\n ): Promise<void> {\n return this.__experimentalStore.invalidateFunctionsByObject(\n apiName,\n primaryKey,\n );\n }\n\n public canonicalizeWhereClause<\n T extends ObjectTypeDefinition | InterfaceDefinition,\n RDPs extends Record<string, SimplePropertyDef> = {},\n >(where: WhereClause<T, RDPs>): Canonical<WhereClause<T, RDPs>> {\n return this.__experimentalStore.whereCanonicalizer\n .canonicalize(where) as Canonical<WhereClause<T, RDPs>>;\n }\n}\n\nfunction observeSingleLink(\n store: Store,\n objectsArray: ReadonlyArray<Osdk.Instance<ObjectOrInterfaceDefinition>>,\n linkName: string,\n options: ObserveLinks.Options<ObjectOrInterfaceDefinition, string>,\n observer: Observer<SpecificLinkPayload>,\n): Unsubscribable {\n if (objectsArray.length === 0) {\n observer.next({\n resolvedList: [],\n isOptimistic: false,\n lastUpdated: 0,\n fetchMore: () => Promise.resolve(),\n hasMore: false,\n status: \"loaded\",\n totalCount: \"0\",\n });\n return new UnsubscribableWrapper(new Subscription());\n }\n\n const parentSub = new Subscription();\n\n for (const obj of objectsArray) {\n parentSub.add(\n store.links.observe(\n {\n ...options,\n srcType: {\n type: \"object\",\n apiName: obj.$objectType ?? obj.$apiName,\n },\n linkName,\n pk: obj.$primaryKey,\n },\n observer,\n ),\n );\n }\n\n return new UnsubscribableWrapper(parentSub);\n}\n\nfunction observeMultiLinks(\n store: Store,\n objectsArray: ReadonlyArray<Osdk.Instance<ObjectOrInterfaceDefinition>>,\n linkName: string,\n options: ObserveLinks.Options<ObjectOrInterfaceDefinition, string>,\n observer: Observer<SpecificLinkPayload>,\n): Unsubscribable {\n const parentSub = new Subscription();\n const totalExpected = objectsArray.length;\n const perObjectResults = new Map<string, SpecificLinkPayload>();\n let errored = false;\n\n function mergeAndEmit() {\n if (errored) {\n return;\n }\n\n const seen = new Map<string, SpecificLinkPayload[\"resolvedList\"][number]>();\n const fetchMores: Array<() => Promise<void>> = [];\n let latestUpdated = 0;\n let hasMore = false;\n let isOptimistic = false;\n\n for (const payload of perObjectResults.values()) {\n for (const obj of payload.resolvedList) {\n seen.set(`${obj.$objectType}:${obj.$primaryKey}`, obj);\n }\n if (payload.lastUpdated > latestUpdated) {\n latestUpdated = payload.lastUpdated;\n }\n if (payload.isOptimistic) {\n isOptimistic = true;\n }\n if (payload.hasMore) {\n hasMore = true;\n fetchMores.push(payload.fetchMore);\n }\n }\n\n const payloads = [...perObjectResults.values()];\n const loading = perObjectResults.size < totalExpected\n || payloads.some(p => p.status === \"init\" || p.status === \"loading\");\n\n observer.next({\n resolvedList: Array.from(seen.values()),\n isOptimistic,\n lastUpdated: latestUpdated,\n fetchMore: hasMore\n ? () => Promise.all(fetchMores.map(fn => fn())).then(() => {})\n : () => Promise.resolve(),\n hasMore,\n status: loading\n ? \"loading\"\n : payloads.some(p => p.status === \"error\")\n ? \"error\"\n : \"loaded\",\n ...(!hasMore ? { totalCount: String(seen.size) } : {}),\n });\n }\n\n for (const obj of objectsArray) {\n const objKey = `${obj.$objectType ?? obj.$apiName}:${obj.$primaryKey}`;\n\n parentSub.add(\n store.links.observe(\n {\n ...options,\n srcType: {\n type: \"object\",\n apiName: obj.$objectType ?? obj.$apiName,\n },\n linkName,\n pk: obj.$primaryKey,\n },\n {\n next: (payload: SpecificLinkPayload) => {\n if (errored) {\n return;\n }\n perObjectResults.set(objKey, payload);\n mergeAndEmit();\n },\n error: (err: unknown) => {\n if (errored) {\n return;\n }\n errored = true;\n parentSub.unsubscribe();\n observer.error(err);\n },\n // store link queries are long-lived and do not complete\n complete: () => {},\n },\n ),\n );\n }\n\n return new UnsubscribableWrapper(parentSub);\n}\n"],"mappings":"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","ignoreList":[]}
@@ -16,14 +16,14 @@
16
16
 
17
17
  export class PivotCanonicalizer {
18
18
  #cache = new Map();
19
- canonicalize(sourceType, linkName) {
20
- const key = `${sourceType}::${linkName}`;
19
+ canonicalize(sourceType, sourceTypeKind, linkName) {
20
+ const key = `${sourceTypeKind}:${sourceType}::${linkName}`;
21
21
  let canonical = this.#cache.get(key);
22
22
  if (!canonical) {
23
23
  canonical = {
24
24
  sourceType,
25
- linkName,
26
- targetType: "<targetType>"
25
+ sourceTypeKind,
26
+ linkName
27
27
  };
28
28
  this.#cache.set(key, canonical);
29
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PivotCanonicalizer.js","names":["PivotCanonicalizer","cache","Map","canonicalize","sourceType","linkName","key","canonical","get","targetType","set"],"sources":["PivotCanonicalizer.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 { Canonical } from \"./Canonical.js\";\n\nexport interface PivotInfo {\n sourceType: string;\n linkName: string;\n targetType: string;\n}\n\nexport class PivotCanonicalizer {\n #cache = new Map<string, Canonical<PivotInfo>>();\n\n canonicalize(sourceType: string, linkName: string): Canonical<PivotInfo> {\n const key = `${sourceType}::${linkName}`;\n\n let canonical = this.#cache.get(key);\n\n if (!canonical) {\n canonical = {\n sourceType,\n linkName,\n targetType: \"<targetType>\",\n } as Canonical<PivotInfo>;\n this.#cache.set(key, canonical);\n }\n\n return canonical;\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUA,OAAO,MAAMA,kBAAkB,CAAC;EAC9B,CAACC,KAAK,GAAG,IAAIC,GAAG,CAA+B,CAAC;EAEhDC,YAAYA,CAACC,UAAkB,EAAEC,QAAgB,EAAwB;IACvE,MAAMC,GAAG,GAAG,GAAGF,UAAU,KAAKC,QAAQ,EAAE;IAExC,IAAIE,SAAS,GAAG,IAAI,CAAC,CAACN,KAAK,CAACO,GAAG,CAACF,GAAG,CAAC;IAEpC,IAAI,CAACC,SAAS,EAAE;MACdA,SAAS,GAAG;QACVH,UAAU;QACVC,QAAQ;QACRI,UAAU,EAAE;MACd,CAAyB;MACzB,IAAI,CAAC,CAACR,KAAK,CAACS,GAAG,CAACJ,GAAG,EAAEC,SAAS,CAAC;IACjC;IAEA,OAAOA,SAAS;EAClB;AACF","ignoreList":[]}
1
+ {"version":3,"file":"PivotCanonicalizer.js","names":["PivotCanonicalizer","cache","Map","canonicalize","sourceType","sourceTypeKind","linkName","key","canonical","get","set"],"sources":["PivotCanonicalizer.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 { Canonical } from \"./Canonical.js\";\n\nexport interface PivotInfo {\n sourceType: string;\n sourceTypeKind: \"object\" | \"interface\";\n linkName: string;\n}\n\nexport class PivotCanonicalizer {\n #cache = new Map<string, Canonical<PivotInfo>>();\n\n canonicalize(\n sourceType: string,\n sourceTypeKind: \"object\" | \"interface\",\n linkName: string,\n ): Canonical<PivotInfo> {\n const key = `${sourceTypeKind}:${sourceType}::${linkName}`;\n\n let canonical = this.#cache.get(key);\n\n if (!canonical) {\n canonical = {\n sourceType,\n sourceTypeKind,\n linkName,\n } as Canonical<PivotInfo>;\n this.#cache.set(key, canonical);\n }\n\n return canonical;\n }\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUA,OAAO,MAAMA,kBAAkB,CAAC;EAC9B,CAACC,KAAK,GAAG,IAAIC,GAAG,CAA+B,CAAC;EAEhDC,YAAYA,CACVC,UAAkB,EAClBC,cAAsC,EACtCC,QAAgB,EACM;IACtB,MAAMC,GAAG,GAAG,GAAGF,cAAc,IAAID,UAAU,KAAKE,QAAQ,EAAE;IAE1D,IAAIE,SAAS,GAAG,IAAI,CAAC,CAACP,KAAK,CAACQ,GAAG,CAACF,GAAG,CAAC;IAEpC,IAAI,CAACC,SAAS,EAAE;MACdA,SAAS,GAAG;QACVJ,UAAU;QACVC,cAAc;QACdC;MACF,CAAyB;MACzB,IAAI,CAAC,CAACL,KAAK,CAACS,GAAG,CAACH,GAAG,EAAEC,SAAS,CAAC;IACjC;IAEA,OAAOA,SAAS;EAClB;AACF","ignoreList":[]}
@@ -24,9 +24,10 @@ import { ActionValidationError } from "../../actions/ActionValidationError.js";
24
24
  import { createClient } from "../../createClient.js";
25
25
  import { TestLogger } from "../../logger/TestLogger.js";
26
26
  import { runOptimisticJob } from "./actions/OptimisticJob.js";
27
+ import { ObservableClientImpl } from "./ObservableClientImpl.js";
27
28
  import { createOptimisticId } from "./OptimisticId.js";
28
29
  import { Store } from "./Store.js";
29
- import { applyCustomMatchers, createClientMockHelper, createDefer, expectNoMoreCalls, expectSingleLinkCallAndClear, expectSingleListCallAndClear, expectSingleObjectCallAndClear, getObject, mockListSubCallback, mockObserver, mockSingleSubCallback, objectPayloadContaining, updateList, updateObject, waitForCall } from "./testUtils.js";
30
+ import { applyCustomMatchers, createClientMockHelper, createDefer, expectNoMoreCalls, expectSingleLinkCallAndClear, expectSingleListCallAndClear, expectSingleObjectCallAndClear, getObject, mockLinkSubCallback, mockListSubCallback, mockObserver, mockSingleSubCallback, objectPayloadContaining, updateList, updateObject, waitForCall } from "./testUtils.js";
30
31
  import { invalidateList } from "./testUtils/invalidateList.js";
31
32
  import { expectStandardObserveLink } from "./testUtils/observeLink/expectStandardObserveLink.js";
32
33
  import { expectStandardObserveObject } from "./testUtils/observeObject/expectStandardObserveObject.js";
@@ -300,6 +301,189 @@ describe(Store, () => {
300
301
  expect(empSubFn.next).not.toHaveBeenCalled();
301
302
  expect(officeSubFn.next).not.toHaveBeenCalled();
302
303
  });
304
+ describe("multi-object observeLinks", () => {
305
+ function getLastPayload(subFn) {
306
+ const calls = subFn.next.mock.calls;
307
+ return calls[calls.length - 1][0];
308
+ }
309
+ async function waitForLoaded(subFn) {
310
+ await vi.waitFor(() => {
311
+ expect(getLastPayload(subFn)?.status).toBe("loaded");
312
+ }, {
313
+ interval: 0
314
+ });
315
+ }
316
+ it("returns linked objects from all source objects", async () => {
317
+ const observableClient = new ObservableClientImpl(cache);
318
+ const {
319
+ payload: emp1Payload
320
+ } = await expectStandardObserveObject({
321
+ cache,
322
+ type: Employee,
323
+ primaryKey: 1
324
+ });
325
+ const emp1 = emp1Payload?.object;
326
+ !emp1 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
327
+ const {
328
+ payload: emp2Payload
329
+ } = await expectStandardObserveObject({
330
+ cache,
331
+ type: Employee,
332
+ primaryKey: 2
333
+ });
334
+ const emp2 = emp2Payload?.object;
335
+ !emp2 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
336
+ const linkSubFn = mockLinkSubCallback();
337
+ defer(observableClient.observeLinks([emp1, emp2], "officeLink", {
338
+ linkName: "officeLink"
339
+ },
340
+ // @ts-expect-error crossing typed/untyped barrier for test
341
+ linkSubFn));
342
+ await waitForLoaded(linkSubFn);
343
+ const lastPayload = getLastPayload(linkSubFn);
344
+ expect(lastPayload.resolvedList).toHaveLength(2);
345
+ expect(lastPayload.resolvedList).toEqual(expect.arrayContaining([expect.objectContaining({
346
+ $primaryKey: "101"
347
+ }), expect.objectContaining({
348
+ $primaryKey: "102"
349
+ })]));
350
+ expect(lastPayload.totalCount).toBe("2");
351
+ });
352
+ it("deduplicates when multiple sources link to the same target", async () => {
353
+ const dataStore = fauxFoundry.getDefaultDataStore();
354
+
355
+ // emp1 already links to office1; add emp3 -> office1 too
356
+ dataStore.registerLink({
357
+ __apiName: "Employee",
358
+ __primaryKey: 3
359
+ }, "officeLink", {
360
+ __apiName: "Office",
361
+ __primaryKey: "101"
362
+ }, "occupants");
363
+ try {
364
+ const observableClient = new ObservableClientImpl(cache);
365
+ const {
366
+ payload: emp1Payload
367
+ } = await expectStandardObserveObject({
368
+ cache,
369
+ type: Employee,
370
+ primaryKey: 1
371
+ });
372
+ const emp1 = emp1Payload?.object;
373
+ !emp1 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
374
+ const {
375
+ payload: emp3Payload
376
+ } = await expectStandardObserveObject({
377
+ cache,
378
+ type: Employee,
379
+ primaryKey: 3
380
+ });
381
+ const emp3 = emp3Payload?.object;
382
+ !emp3 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
383
+ const linkSubFn = mockLinkSubCallback();
384
+ defer(observableClient.observeLinks([emp1, emp3], "officeLink", {
385
+ linkName: "officeLink"
386
+ },
387
+ // @ts-expect-error crossing typed/untyped barrier for test
388
+ linkSubFn));
389
+ await waitForLoaded(linkSubFn);
390
+ const lastPayload = getLastPayload(linkSubFn);
391
+ expect(lastPayload.resolvedList).toHaveLength(1);
392
+ expect(lastPayload.resolvedList[0].$primaryKey).toBe("101");
393
+ expect(lastPayload.totalCount).toBe("1");
394
+ } finally {
395
+ dataStore.unregisterLink({
396
+ __apiName: "Employee",
397
+ __primaryKey: 3
398
+ }, "officeLink", {
399
+ __apiName: "Office",
400
+ __primaryKey: "101"
401
+ }, "occupants");
402
+ }
403
+ });
404
+ it("leaves totalCount undefined when sub-queries are still paginating", async () => {
405
+ const dataStore = fauxFoundry.getDefaultDataStore();
406
+
407
+ // Ensure emp1 has at least 2 peeps links (MANY cardinality).
408
+ // Prior tests may have removed the original johnDoe peep,
409
+ // so we register two fresh links to guarantee pagination with pageSize=1.
410
+ dataStore.registerLink({
411
+ __apiName: "Employee",
412
+ __primaryKey: 1
413
+ }, "peeps", {
414
+ __apiName: "Employee",
415
+ __primaryKey: 3
416
+ }, "lead");
417
+ dataStore.registerLink({
418
+ __apiName: "Employee",
419
+ __primaryKey: 1
420
+ }, "peeps", {
421
+ __apiName: "Employee",
422
+ __primaryKey: 4
423
+ }, "lead");
424
+ const observableClient = new ObservableClientImpl(cache);
425
+ const {
426
+ payload: emp1Payload
427
+ } = await expectStandardObserveObject({
428
+ cache,
429
+ type: Employee,
430
+ primaryKey: 1
431
+ });
432
+ const emp1 = emp1Payload?.object;
433
+ !emp1 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
434
+ const {
435
+ payload: emp2Payload
436
+ } = await expectStandardObserveObject({
437
+ cache,
438
+ type: Employee,
439
+ primaryKey: 2
440
+ });
441
+ const emp2 = emp2Payload?.object;
442
+ !emp2 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
443
+ const linkSubFn = mockLinkSubCallback();
444
+
445
+ // emp1 has 2 peeps but pageSize=1, so emp1's query has hasMore=true.
446
+ // emp2 has 0 peeps, so its query finishes immediately.
447
+ defer(observableClient.observeLinks([emp1, emp2], "peeps", {
448
+ linkName: "peeps",
449
+ pageSize: 1
450
+ },
451
+ // @ts-expect-error crossing typed/untyped barrier for test
452
+ linkSubFn));
453
+ await waitForLoaded(linkSubFn);
454
+ const lastPayload = getLastPayload(linkSubFn);
455
+ expect(lastPayload.hasMore).toBe(true);
456
+ expect(lastPayload.totalCount).toBeUndefined();
457
+ });
458
+ it("single object fast path still works", async () => {
459
+ const observableClient = new ObservableClientImpl(cache);
460
+ const {
461
+ payload: emp1Payload
462
+ } = await expectStandardObserveObject({
463
+ cache,
464
+ type: Employee,
465
+ primaryKey: 1
466
+ });
467
+ const emp1 = emp1Payload?.object;
468
+ !emp1 ? process.env.NODE_ENV !== "production" ? invariant(false) : invariant(false) : void 0;
469
+ const linkSubFn = mockLinkSubCallback();
470
+ defer(observableClient.observeLinks(emp1, "officeLink", {
471
+ linkName: "officeLink"
472
+ },
473
+ // @ts-expect-error crossing typed/untyped barrier for test
474
+ linkSubFn));
475
+ await waitForCall(linkSubFn);
476
+ expectSingleLinkCallAndClear(linkSubFn, [], {
477
+ status: "loading"
478
+ });
479
+ await waitForCall(linkSubFn);
480
+ expectSingleLinkCallAndClear(linkSubFn, [expect.objectContaining({
481
+ $primaryKey: "101"
482
+ })], {
483
+ status: "loaded"
484
+ });
485
+ });
486
+ });
303
487
  });
304
488
  describe("with mock server", () => {
305
489
  let client;