@warp-drive-mirror/json-api 5.10.0-alpha.7 → 5.10.0-alpha.8

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.
@@ -912,7 +912,7 @@ function validateResourceDocument(reporter, doc) {
912
912
  }
913
913
 
914
914
  //#endregion
915
- //#region ../../node_modules/.pnpm/@embroider+macros@1.20.7/node_modules/@embroider/macros/src/addon/runtime.js
915
+ //#region ../../node_modules/.pnpm/@embroider+macros@1.21.1/node_modules/@embroider/macros/src/addon/runtime.js
916
916
  function config(packageRoot) {
917
917
  return runtimeConfig.packages[packageRoot];
918
918
  }
@@ -2216,20 +2216,89 @@ function getDefaultValue(schema, identifier, store) {
2216
2216
  if (transform?.defaultValue) return transform.defaultValue(options || null, identifier);
2217
2217
  }
2218
2218
  }
2219
- function calculateChangedKeys(cached, updates, fields) {
2220
- const changedKeys = /* @__PURE__ */ new Set();
2221
- const keys = Object.keys(updates);
2222
- const length = keys.length;
2223
- const localAttrs = cached.localAttrs;
2224
- const original = Object.assign(Object.create(null), cached.remoteAttrs, cached.inflightAttrs);
2225
- for (let i = 0; i < length; i++) {
2219
+ /**
2220
+ * Narrow `subset` to the members that survived {@link patchLocalAttributes}' pruning. Only called
2221
+ * when that pruning actually removed something, so the allocation is skipped on the common path
2222
+ * where a resource has no local edits at all.
2223
+ */
2224
+ function retainSurviving(subset, survivors) {
2225
+ if (!subset?.size) return subset;
2226
+ const result = /* @__PURE__ */ new Set();
2227
+ for (const key of subset) if (survivors.has(key)) result.add(key);
2228
+ return result.size ? result : void 0;
2229
+ }
2230
+ /**
2231
+ * Which projection each changed key moved, so the caller can notify on the matching channel:
2232
+ * `localOnly` and `remoteOnly` on theirs, `both` unscoped. `remoteChanged` is the union
2233
+ * {@link patchLocalAttributes} reconciles against.
2234
+ *
2235
+ * `undefined` rather than empty Sets: this runs on every `upsert`, and a resource where nothing
2236
+ * moved should cost no allocation.
2237
+ */
2238
+ const NO_PROJECTION_CHANGES = Object.freeze({
2239
+ localOnly: void 0,
2240
+ remoteOnly: void 0,
2241
+ both: void 0,
2242
+ remoteChanged: void 0
2243
+ });
2244
+ /**
2245
+ * The keys a merge could move: everything the payload carries, plus anything being promoted that
2246
+ * the payload did not mention. `null` when there is nothing to examine.
2247
+ *
2248
+ * `upsert` promotes nothing, so it gets the `Object.keys` array back unchanged. Only a commit
2249
+ * carrying both a payload and promoted attrs pays for a copy, and that is once per save rather
2250
+ * than once per resource in a document.
2251
+ */
2252
+ function candidateKeys(updates, promoted) {
2253
+ const updateKeys = updates ? Object.keys(updates) : null;
2254
+ const promotedKeys = promoted ? Object.keys(promoted) : null;
2255
+ if (!promotedKeys?.length) return updateKeys?.length ? updateKeys : null;
2256
+ if (!updateKeys?.length) return promotedKeys;
2257
+ const keys = updateKeys.slice();
2258
+ for (let i = 0; i < promotedKeys.length; i++) if (!(promotedKeys[i] in updates)) keys.push(promotedKeys[i]);
2259
+ return keys;
2260
+ }
2261
+ /**
2262
+ * Partition the keys an incoming payload touches by which projection each one moves.
2263
+ *
2264
+ * Takes the values rather than the `CachedResource` so it cannot observe the merge it is
2265
+ * describing: `prevRemote` is the remote state as it stands *before* `promoted` and `updates` are
2266
+ * applied, and the two callers merge different things. Reading them off `cached` would make the
2267
+ * result depend on whether the caller had already mutated it.
2268
+ */
2269
+ function calculateChangedKeys(prevRemote, localAttrs, updates, promoted, fields) {
2270
+ const keys = candidateKeys(updates, promoted);
2271
+ if (keys === null) return NO_PROJECTION_CHANGES;
2272
+ let localOnly;
2273
+ let remoteOnly;
2274
+ let both;
2275
+ let remoteChanged;
2276
+ for (let i = 0; i < keys.length; i++) {
2226
2277
  const key = keys[i];
2227
- if (!fields.has(key)) continue;
2228
- const value = updates[key];
2229
- if (localAttrs && localAttrs[key] !== void 0) continue;
2230
- if (original[key] !== value) changedKeys.add(key);
2231
- }
2232
- return changedKeys;
2278
+ const field = fields.get(key);
2279
+ if (!field || isRelationship(field)) continue;
2280
+ const isPromoted = promoted !== null && key in promoted;
2281
+ const isUpdated = updates !== void 0 && key in updates;
2282
+ const wasRemote = prevRemote ? prevRemote[key] : void 0;
2283
+ const nowRemote = isUpdated ? updates[key] : isPromoted ? promoted[key] : wasRemote;
2284
+ const localEdit = localAttrs ? localAttrs[key] : void 0;
2285
+ const isEdited = localEdit !== void 0;
2286
+ const wasLocal = isEdited ? localEdit : isPromoted ? promoted[key] : wasRemote;
2287
+ const nowLocal = isEdited ? localEdit : nowRemote;
2288
+ const remoteMoved = wasRemote !== nowRemote;
2289
+ const localMoved = wasLocal !== nowLocal;
2290
+ if (remoteMoved) {
2291
+ (remoteChanged ??= /* @__PURE__ */ new Set()).add(key);
2292
+ if (localMoved) (both ??= /* @__PURE__ */ new Set()).add(key);
2293
+ else (remoteOnly ??= /* @__PURE__ */ new Set()).add(key);
2294
+ } else if (localMoved) (localOnly ??= /* @__PURE__ */ new Set()).add(key);
2295
+ }
2296
+ return remoteChanged || localOnly ? {
2297
+ localOnly,
2298
+ remoteOnly,
2299
+ both,
2300
+ remoteChanged
2301
+ } : NO_PROJECTION_CHANGES;
2233
2302
  }
2234
2303
  function cacheIsEmpty(cached) {
2235
2304
  return !cached || cached.remoteAttrs === null && cached.inflightAttrs === null && cached.localAttrs === null;
@@ -2401,7 +2470,7 @@ function cacheUpsert(cache, identifier, data, calculateChanges) {
2401
2470
  cache._capabilities.notifyChange(identifier, "state", null);
2402
2471
  }
2403
2472
  const fields = getCacheFields(cache, identifier);
2404
- if (calculateChanges && existed && data.attributes) changedKeys = calculateChangedKeys(cached, data.attributes, fields);
2473
+ if (calculateChanges && existed && data.attributes) changedKeys = calculateChangedKeys(cached.remoteAttrs, cached.localAttrs, data.attributes, null, fields).remoteChanged;
2405
2474
  cached.remoteAttrs = Object.assign(cached.remoteAttrs || Object.create(null), data.attributes);
2406
2475
  if (cached.localAttrs) {
2407
2476
  if (patchLocalAttributes(cached, changedKeys)) cache._capabilities.notifyChange(identifier, "state", null);
@@ -2569,15 +2638,21 @@ function didCommit(cache, committedIdentifier, data, op) {
2569
2638
  }
2570
2639
  newCanonicalAttributes = data.attributes;
2571
2640
  }
2572
- const changedKeys = newCanonicalAttributes && calculateChangedKeys(cached, newCanonicalAttributes, fields);
2641
+ const changes = calculateChangedKeys(cached.remoteAttrs, cached.localAttrs, newCanonicalAttributes, cached.inflightAttrs, fields);
2573
2642
  cached.remoteAttrs = Object.assign(cached.remoteAttrs || Object.create(null), cached.inflightAttrs, newCanonicalAttributes);
2574
2643
  cached.inflightAttrs = null;
2575
- patchLocalAttributes(cached, changedKeys);
2644
+ const pruned = patchLocalAttributes(cached, changes.remoteChanged);
2576
2645
  if (cached.errors) {
2577
2646
  cached.errors = null;
2578
2647
  cache._capabilities.notifyChange(identifier, "errors", null);
2579
2648
  }
2580
- if (changedKeys?.size) cache._capabilities.notifyChange(identifier, "attributes", changedKeys);
2649
+ const { remoteChanged, localOnly } = changes;
2650
+ const reprune = pruned && remoteChanged !== void 0;
2651
+ const both = reprune ? retainSurviving(changes.both, remoteChanged) : changes.both;
2652
+ const remoteOnly = reprune ? retainSurviving(changes.remoteOnly, remoteChanged) : changes.remoteOnly;
2653
+ if (both?.size) cache._capabilities.notifyChange(identifier, "attributes", both);
2654
+ if (remoteOnly?.size) cache._capabilities.notifyChange(identifier, "attributes", remoteOnly, "remote");
2655
+ if (localOnly?.size) cache._capabilities.notifyChange(identifier, "attributes", localOnly, "local");
2581
2656
  cache._capabilities.notifyChange(identifier, "state", null);
2582
2657
  }
2583
2658
  function willCommit(cache, identifier) {