@salesforce/lds-worker-api 1.454.0 → 1.456.0

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.
@@ -4276,7 +4276,7 @@ function withDefaultLuvio(callback) {
4276
4276
  }
4277
4277
  callbacks.push(callback);
4278
4278
  }
4279
- // version: 1.454.0-4223ab4365
4279
+ // version: 1.456.0-cef836b978
4280
4280
 
4281
4281
  // TODO [TD-0081508]: once that TD is fulfilled we can probably change this file
4282
4282
  function instrumentAdapter$1(createFunction, _metadata) {
@@ -5320,7 +5320,7 @@ function createGraphQLWireAdapterConstructor(luvio, adapter, metadata, astResolv
5320
5320
  const { apiFamily, name } = metadata;
5321
5321
  return createGraphQLWireAdapterConstructor$1(adapter, `${apiFamily}.${name}`, luvio, astResolver);
5322
5322
  }
5323
- // version: 1.454.0-4223ab4365
5323
+ // version: 1.456.0-cef836b978
5324
5324
 
5325
5325
  function isSupportedEntity(_objectApiName) {
5326
5326
  return true;
@@ -5430,7 +5430,7 @@ var TypeCheckShapes;
5430
5430
 
5431
5431
  const { keys: ObjectKeys$4, create: ObjectCreate$4 } = Object;
5432
5432
 
5433
- const { assign: assign$7, create: create$9, freeze: freeze$6, isFrozen: isFrozen$4, keys: keys$a } = Object;
5433
+ const { assign: assign$7, create: create$9, freeze: freeze$6, getPrototypeOf: getPrototypeOf$3, isFrozen: isFrozen$4, keys: keys$a } = Object;
5434
5434
 
5435
5435
  /**
5436
5436
  * Defines configuration for the module with a default value which can be overridden by the runtime environment.
@@ -6065,7 +6065,7 @@ function buildAdapterValidationConfig$3(displayName, paramsMeta) {
6065
6065
  }
6066
6066
  const keyPrefix$3 = 'UiApi';
6067
6067
 
6068
- const { assign: assign$6, create: create$8, freeze: freeze$5, isFrozen: isFrozen$3, keys: keys$9 } = Object;
6068
+ const { assign: assign$6, create: create$8, freeze: freeze$5, getPrototypeOf: getPrototypeOf$2, isFrozen: isFrozen$3, keys: keys$9 } = Object;
6069
6069
  const { hasOwnProperty: hasOwnProperty$5 } = Object.prototype;
6070
6070
  const { split: split$1, endsWith: endsWith$1 } = String.prototype;
6071
6071
  const { isArray: isArray$8 } = Array;
@@ -32547,7 +32547,7 @@ withDefaultLuvio((luvio) => {
32547
32547
  throttle(60, 60000, setupNotifyAllListRecordUpdateAvailable(luvio));
32548
32548
  throttle(60, 60000, setupNotifyAllListInfoSummaryUpdateAvailable(luvio));
32549
32549
  });
32550
- // version: 1.454.0-761808c4e9
32550
+ // version: 1.456.0-6ed480b93c
32551
32551
 
32552
32552
  var draftQueueMaxRetryAttemptsGate = {
32553
32553
  isOpen: function (e) {
@@ -47849,16 +47849,18 @@ class LdsAbortController {
47849
47849
  }
47850
47850
 
47851
47851
  class AsyncWorkerPool {
47852
- constructor(concurrency) {
47852
+ constructor(concurrency, onWorkTiming) {
47853
47853
  this.queue = [];
47854
47854
  this.activeWork = [];
47855
47855
  this.concurrency = concurrency;
47856
+ this.onWorkTiming = onWorkTiming;
47856
47857
  }
47857
47858
  push(work) {
47858
47859
  return new Promise((resolve, reject) => {
47859
47860
  this.queue.push({
47860
47861
  ...work,
47861
47862
  workFn: (abortController) => work.workFn(abortController).then(resolve).catch(reject),
47863
+ enqueuedAt: Date.now(),
47862
47864
  });
47863
47865
  this.doWork();
47864
47866
  });
@@ -47901,10 +47903,30 @@ class AsyncWorkerPool {
47901
47903
  const abortController = new LdsAbortController();
47902
47904
  const newWork = { ...work, abortController };
47903
47905
  this.activeWork.push(newWork);
47904
- const { workFn } = work;
47906
+ const { workFn, enqueuedAt } = work;
47907
+ const onWorkTiming = this.onWorkTiming;
47908
+ let startedAt = 0;
47909
+ let waitMs = 0;
47910
+ let queueDepthAtStart = 0;
47911
+ if (onWorkTiming !== undefined) {
47912
+ startedAt = Date.now();
47913
+ waitMs = startedAt - enqueuedAt;
47914
+ // depth AFTER this unit was shifted off — units still waiting behind it.
47915
+ queueDepthAtStart = this.queue.length;
47916
+ }
47905
47917
  workFn(abortController).finally(() => {
47906
- this.activeWork = this.activeWork.filter((w) => w !== newWork);
47907
- this.doWork();
47918
+ try {
47919
+ if (onWorkTiming !== undefined) {
47920
+ onWorkTiming(waitMs, Date.now() - startedAt, queueDepthAtStart);
47921
+ }
47922
+ }
47923
+ catch {
47924
+ // Instrumentation must not prevent the pool from releasing the worker slot.
47925
+ }
47926
+ finally {
47927
+ this.activeWork = this.activeWork.filter((w) => w !== newWork);
47928
+ this.doWork();
47929
+ }
47908
47930
  });
47909
47931
  }
47910
47932
  }
@@ -48234,6 +48256,25 @@ const DRAFT_SEGMENT = 'DRAFT';
48234
48256
  */
48235
48257
  const DRAFT_ACTION_RETRY_COUNT_METADATA_KEY = 'retryCount';
48236
48258
  class DurableDraftQueue {
48259
+ // Instrumentation is strictly measure-only: a broken sink must never change queue behavior.
48260
+ // Pass the sink into the callback so methods are invoked through their owning object and retain
48261
+ // their receiver (some sinks use `this` to reach their metric registry).
48262
+ emitInstrumentation(emit) {
48263
+ const { instrumentation } = this;
48264
+ if (instrumentation === undefined) {
48265
+ return;
48266
+ }
48267
+ try {
48268
+ emit(instrumentation);
48269
+ }
48270
+ catch {
48271
+ // Telemetry failures must not interrupt draft processing.
48272
+ }
48273
+ }
48274
+ resetDrainCycle() {
48275
+ this.drainCycleStart = undefined;
48276
+ this.drainCycleBatchCount = 0;
48277
+ }
48237
48278
  getHandler(id) {
48238
48279
  const handler = this.handlers[id];
48239
48280
  if (handler === undefined) {
@@ -48256,9 +48297,19 @@ class DurableDraftQueue {
48256
48297
  ? __nimbus.plugins.JSLoggerPlugin
48257
48298
  : undefined;
48258
48299
  this.handlers = {};
48300
+ // Drain-wait attribution state. uploadStartTimes stamps when each action first began
48301
+ // uploading (keyed by action id) so actionCompleted/failed can emit its end-to-end drain time,
48302
+ // including automatic retries/backoff. actionQueueWaitEmittedIds ensures those retries do not
48303
+ // report the original enqueue wait more than once. drainCycleStart/BatchCount track one full
48304
+ // idle->empty sweep. All measure-only; when no instrumentation is injected these stay untouched.
48305
+ this.uploadStartTimes = new Map();
48306
+ this.actionQueueWaitEmittedIds = new Set();
48307
+ this.drainCycleBatchCount = 0;
48259
48308
  this.draftStore = draftStore;
48260
- this.workerPool = new AsyncWorkerPool(1);
48261
48309
  this.instrumentation = instrumentation;
48310
+ this.workerPool = new AsyncWorkerPool(1, instrumentation?.onWorkerTiming !== undefined
48311
+ ? (waitMs, holdMs, queueDepth) => this.emitInstrumentation((sink) => sink.onWorkerTiming?.(waitMs, holdMs, queueDepth))
48312
+ : undefined);
48262
48313
  }
48263
48314
  addHandler(handler) {
48264
48315
  const id = handler.handlerId;
@@ -48346,6 +48397,9 @@ class DurableDraftQueue {
48346
48397
  clearTimeout(this.timeoutHandler);
48347
48398
  this.timeoutHandler = undefined;
48348
48399
  }
48400
+ // A stop/user edit breaks the current sweep. A later restart starts a fresh cycle rather
48401
+ // than attributing stopped time to an offline drain.
48402
+ this.resetDrainCycle();
48349
48403
  this.state = DraftQueueState.Stopped;
48350
48404
  }
48351
48405
  async getQueueActions() {
@@ -48376,7 +48430,7 @@ class DurableDraftQueue {
48376
48430
  }
48377
48431
  return aTime - bTime;
48378
48432
  });
48379
- instrumentation?.onGetQueueActions?.(Date.now() - start, sorted.length);
48433
+ this.emitInstrumentation((sink) => sink.onGetQueueActions?.(Date.now() - start, sorted.length));
48380
48434
  return sorted;
48381
48435
  }
48382
48436
  async enqueue(handlerId, data, observabilityContext) {
@@ -48420,6 +48474,13 @@ class DurableDraftQueue {
48420
48474
  await handler.handleActionCompleted(action, queueOperations, values$2(this.handlers));
48421
48475
  this.retryIntervalMilliseconds = 0;
48422
48476
  this.uploadingActionId = undefined;
48477
+ // The action finished draining — emit its end-to-end drain time and
48478
+ // count it toward the current drain-cycle batch. Measure-only.
48479
+ this.emitActionDrainDuration(action.id, action.handler);
48480
+ this.actionQueueWaitEmittedIds.delete(action.id);
48481
+ if (this.drainCycleStart !== undefined) {
48482
+ this.drainCycleBatchCount += 1;
48483
+ }
48423
48484
  await this.notifyChangedListeners({
48424
48485
  type: DraftQueueEventType.ActionCompleted,
48425
48486
  action,
@@ -48431,6 +48492,16 @@ class DurableDraftQueue {
48431
48492
  },
48432
48493
  });
48433
48494
  }
48495
+ // Read+clear the action's upload-start stamp and emit its drain duration. Safe to
48496
+ // call when instrumentation is absent or the id was never stamped (no-op). Never emits the id.
48497
+ emitActionDrainDuration(id, handlerId) {
48498
+ const start = this.uploadStartTimes.get(id);
48499
+ if (start === undefined) {
48500
+ return;
48501
+ }
48502
+ this.uploadStartTimes.delete(id);
48503
+ this.emitInstrumentation((sink) => sink.onActionDrainDuration?.(handlerId, Date.now() - start));
48504
+ }
48434
48505
  async actionFailed(action, retry, retryDelayInMs, actionDataChanged) {
48435
48506
  if (actionDataChanged === true) {
48436
48507
  await this.draftStore.writeAction({
@@ -48440,14 +48511,24 @@ class DurableDraftQueue {
48440
48511
  }
48441
48512
  this.uploadingActionId = undefined;
48442
48513
  if (retry && this.state !== DraftQueueState.Stopped) {
48514
+ // A retry means this action is NOT done draining. Keep its first-upload stamp and the
48515
+ // open cycle so the eventual outcome includes network time and retry/backoff.
48443
48516
  this.state = DraftQueueState.Waiting;
48444
48517
  return retryDelayInMs !== undefined
48445
48518
  ? this.scheduleRetryWithSpecifiedDelay(retryDelayInMs)
48446
48519
  : this.scheduleRetry();
48447
48520
  }
48448
48521
  else if (isDraftError(action)) {
48522
+ // Terminal failure — this action is done draining. Emit its drain time.
48523
+ this.emitActionDrainDuration(action.id, action.handler);
48524
+ // This was not a clean drain-to-empty. Discard the sweep before user intervention so a
48525
+ // later manual retry/removal cannot inherit its elapsed time or completed batch count.
48526
+ this.resetDrainCycle();
48449
48527
  return this.handleServerError(action, action.error);
48450
48528
  }
48529
+ // Any other terminal path — ensure no stale start stamp lingers.
48530
+ this.emitActionDrainDuration(action.id, action.handler);
48531
+ this.resetDrainCycle();
48451
48532
  }
48452
48533
  handle(action) {
48453
48534
  const handler = this.getHandler(action.handler);
@@ -48467,12 +48548,22 @@ class DurableDraftQueue {
48467
48548
  this.state = DraftQueueState.Started;
48468
48549
  }
48469
48550
  this.processingAction = undefined;
48551
+ // The queue drained empty — close the drain-cycle window if one was open.
48552
+ if (this.drainCycleStart !== undefined) {
48553
+ const durationMs = Date.now() - this.drainCycleStart;
48554
+ const batchSize = this.drainCycleBatchCount;
48555
+ this.resetDrainCycle();
48556
+ this.emitInstrumentation((sink) => sink.onDrainCycle?.(durationMs, batchSize));
48557
+ }
48470
48558
  return ProcessActionResult.NO_ACTION_TO_PROCESS;
48471
48559
  }
48472
48560
  const { status, id } = action;
48473
48561
  if (status === DraftActionStatus.Error) {
48474
48562
  this.state = DraftQueueState.Error;
48475
48563
  this.processingAction = undefined;
48564
+ // The sweep is blocked on an errored action, not a clean drain-to-empty —
48565
+ // discard the open drain-cycle window so it doesn't inflate a later cycle's duration.
48566
+ this.resetDrainCycle();
48476
48567
  await this.notifyChangedListeners({
48477
48568
  type: DraftQueueEventType.ActionFailed,
48478
48569
  action: action,
@@ -48490,6 +48581,31 @@ class DurableDraftQueue {
48490
48581
  if (this.state === DraftQueueState.Waiting) {
48491
48582
  this.state = DraftQueueState.Started;
48492
48583
  }
48584
+ // The action is now leaving the queue to upload. Emit head-of-line FIFO wait
48585
+ // (enqueue -> upload start), stamp its drain-start for end-to-end timing on completion, and
48586
+ // open a drain-cycle window if the queue was previously idle. All measure-only.
48587
+ const { instrumentation } = this;
48588
+ if (instrumentation !== undefined) {
48589
+ const now = Date.now();
48590
+ const { timestamp } = action;
48591
+ if (instrumentation.onActionQueueWait !== undefined &&
48592
+ !this.actionQueueWaitEmittedIds.has(id) &&
48593
+ typeof timestamp === 'number' &&
48594
+ timestamp > 0) {
48595
+ // Mark before invoking the sink: even a throwing callback must not make a retry
48596
+ // report the same action's enqueue wait again.
48597
+ this.actionQueueWaitEmittedIds.add(id);
48598
+ this.emitInstrumentation((sink) => sink.onActionQueueWait?.(action.handler, now - timestamp));
48599
+ }
48600
+ if (instrumentation.onActionDrainDuration !== undefined &&
48601
+ !this.uploadStartTimes.has(id)) {
48602
+ this.uploadStartTimes.set(id, now);
48603
+ }
48604
+ if (instrumentation.onDrainCycle !== undefined && this.drainCycleStart === undefined) {
48605
+ this.drainCycleStart = now;
48606
+ this.drainCycleBatchCount = 0;
48607
+ }
48608
+ }
48493
48609
  await this.notifyChangedListeners({
48494
48610
  type: DraftQueueEventType.ActionUploading,
48495
48611
  action: { ...action, status: DraftActionStatus.Uploading },
@@ -48527,7 +48643,7 @@ class DurableDraftQueue {
48527
48643
  results.push(listener(event));
48528
48644
  }
48529
48645
  // W-23515682: listener fan-out per event type. Measure-only.
48530
- this.instrumentation?.onNotifyChangedListeners?.(event.type, draftQueueLen);
48646
+ this.emitInstrumentation((sink) => sink.onNotifyChangedListeners?.(event.type, draftQueueLen));
48531
48647
  await Promise.all(results);
48532
48648
  }
48533
48649
  /**
@@ -48556,9 +48672,17 @@ class DurableDraftQueue {
48556
48672
  const shouldDeleteRelated = handler.shouldDeleteActionByTagOnRemoval(action);
48557
48673
  if (shouldDeleteRelated) {
48558
48674
  await this.draftStore.deleteByTag(action.tag);
48675
+ queue.forEach((queuedAction) => {
48676
+ if (queuedAction.tag === action.tag) {
48677
+ this.uploadStartTimes.delete(queuedAction.id);
48678
+ this.actionQueueWaitEmittedIds.delete(queuedAction.id);
48679
+ }
48680
+ });
48559
48681
  }
48560
48682
  else {
48561
48683
  await this.draftStore.deleteDraft(action.id);
48684
+ this.uploadStartTimes.delete(action.id);
48685
+ this.actionQueueWaitEmittedIds.delete(action.id);
48562
48686
  }
48563
48687
  await handler.handleActionRemoved(action, queue.filter((x) => x.id !== actionId));
48564
48688
  await this.notifyChangedListeners({
@@ -80190,6 +80314,20 @@ const DRAFT_QUEUE_GET_QUEUE_ACTIONS_DURATION = 'draft-queue-get-queue-actions-du
80190
80314
  const DRAFT_QUEUE_NOTIFY_CHANGED_LISTENERS_COUNT = 'draft-queue-notify-changed-listeners-count';
80191
80315
  const DRAFT_QUEUE_DURABLE_OP_COUNT = 'draft-queue-durable-op-count';
80192
80316
  const DRAFT_QUEUE_DURABLE_OP_DURATION = 'draft-queue-durable-op-duration';
80317
+ // Drain-wait attribution telemetry: the wall-clock spine of where an offline drain actually spends
80318
+ // WAITING. Operational counts/durations/depths only — no draft content, field values, or server
80319
+ // record ids (matching the existing draft-queue privacy stance).
80320
+ const DRAFT_QUEUE_WORKER_WAIT_DURATION = 'draft-queue-worker-wait-duration';
80321
+ const DRAFT_QUEUE_WORKER_HOLD_DURATION = 'draft-queue-worker-hold-duration';
80322
+ const DRAFT_QUEUE_ACTION_QUEUE_WAIT_DURATION = 'draft-queue-action-queue-wait-duration';
80323
+ const DRAFT_QUEUE_ACTION_DRAIN_DURATION = 'draft-queue-action-drain-duration';
80324
+ const DRAFT_QUEUE_DRAIN_CYCLE_DURATION = 'draft-queue-drain-cycle-duration';
80325
+ const DRAFT_QUEUE_DRAIN_CYCLE_BATCH_SIZE = 'draft-queue-drain-cycle-batch-size';
80326
+ const DRAFT_QUEUE_ACTION_NETWORK_DURATION = 'draft-queue-action-network-duration';
80327
+ const DRAFT_QUEUE_ACTION_RETRY_ATTEMPT = 'draft-queue-action-retry-attempt';
80328
+ const DRAFT_QUEUE_SIDEEFFECT_OP_DURATION = 'draft-queue-sideeffect-op-duration';
80329
+ const DRAFT_QUEUE_SIDEEFFECT_MAP_SIZE = 'draft-queue-sideeffect-map-size';
80330
+ const DRAFT_QUEUE_SIDEEFFECT_REGION_DURATION = 'draft-queue-sideeffect-region-duration';
80193
80331
  /** Content Document */
80194
80332
  const CREATE_CONTENT_DOCUMENT_AND_VERSION_TOTAL_SYNTHESIZE_CALLS = 'content-document-version-total-synthesize-calls';
80195
80333
  const CREATE_CONTENT_DOCUMENT_AND_VERSION_DRAFT_SYNTHESIZE_ERROR = 'create-content-document-version-draft-synthesize-error';
@@ -80309,6 +80447,134 @@ function reportDraftQueueDurableOperation(op, segment, durationMs) {
80309
80447
  });
80310
80448
  ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DURABLE_OP_DURATION, durationMs);
80311
80449
  }
80450
+ const DRAIN_DURATION_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000, 30000];
80451
+ const WORKER_DEPTH_BUCKETS = [1, 2, 5, 10, 20, 50, 100, 250, 500];
80452
+ // Handler ids are extensible through DraftManager, so only retain the fixed mobile handlers in
80453
+ // metric tags. Everything else shares one bounded bucket rather than creating an unbounded series.
80454
+ function draftQueueHandlerTagOf(handlerId) {
80455
+ switch (handlerId) {
80456
+ case 'LDS_ACTION_HANDLER':
80457
+ case 'ContentDocumentCompositeRepresentationActionHandler':
80458
+ case 'QUICK_ACTION_HANDLER':
80459
+ case 'UPDATE_RECORD_QUICK_ACTION_HANDLER':
80460
+ return handlerId;
80461
+ default:
80462
+ return 'custom';
80463
+ }
80464
+ }
80465
+ // Coarse, bounded-cardinality label for the pool depth a unit saw when it began, so the
80466
+ // wait/hold durations can be sliced BY backlog size without emitting depth as a free integer tag.
80467
+ function workerDepthBucketOf(queueDepth) {
80468
+ if (queueDepth <= 0) {
80469
+ return '0';
80470
+ }
80471
+ if (queueDepth <= 2) {
80472
+ return '1-2';
80473
+ }
80474
+ if (queueDepth <= 10) {
80475
+ return '3-10';
80476
+ }
80477
+ if (queueDepth <= 50) {
80478
+ return '11-50';
80479
+ }
80480
+ if (queueDepth <= 250) {
80481
+ return '51-250';
80482
+ }
80483
+ return '250+';
80484
+ }
80485
+ /**
80486
+ * Per-unit lifecycle split for the AsyncWorkerPool(1) serial queue, emitted once when a unit settles
80487
+ * so the two halves are a JOINED event (rather than shipping wait and depth as unrelated aggregates).
80488
+ * Isolates WHERE the time goes:
80489
+ * waitMs — enqueue -> work began (waiting on the serial queue before any logic runs).
80490
+ * holdMs — work began -> work settled (the critical section's own O(N) service time).
80491
+ * Both are additionally tagged by a depthBucket so "does per-unit cost scale with backlog depth"
80492
+ * (the O(N^2) signature) survives aggregation. queueDepth itself is also tracked. Operational only.
80493
+ */
80494
+ function reportDraftQueueWorkerTiming(waitMs, holdMs, queueDepth) {
80495
+ const depthBucket = workerDepthBucketOf(queueDepth);
80496
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_WORKER_WAIT_DURATION, waitMs, undefined, {
80497
+ depthBucket,
80498
+ });
80499
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_WORKER_HOLD_DURATION, holdMs, undefined, {
80500
+ depthBucket,
80501
+ });
80502
+ ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_WORKER_WAIT_DURATION + '-depth', queueDepth, WORKER_DEPTH_BUCKETS);
80503
+ }
80504
+ /**
80505
+ * Head-of-line FIFO wait for one draft (enqueue -> upload start), bucketed so the
80506
+ * "does wait grow with backlog depth" (O(N^2)) signal is visible per handler type. Custom handler
80507
+ * ids are normalized to one bounded tag so caller-defined values never become metric dimensions.
80508
+ */
80509
+ function reportDraftQueueActionQueueWait(handlerId, waitMs) {
80510
+ ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_ACTION_QUEUE_WAIT_DURATION, waitMs, DRAIN_DURATION_BUCKETS, undefined, { handlerId: draftQueueHandlerTagOf(handlerId) });
80511
+ }
80512
+ /**
80513
+ * End-to-end drain time for one action (first upload attempt -> completed/failed), including
80514
+ * retry/backoff. Compare it with network-duration and retry-attempt signals to understand the
80515
+ * non-request portion of the drain interval.
80516
+ */
80517
+ function reportDraftQueueActionDrainDuration(handlerId, durationMs) {
80518
+ ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_ACTION_DRAIN_DURATION, durationMs, DRAIN_DURATION_BUCKETS, undefined, { handlerId: draftQueueHandlerTagOf(handlerId) });
80519
+ }
80520
+ /**
80521
+ * One full drain sweep — first action starts uploading -> queue empties. Both raw values share a
80522
+ * bounded batch-size cohort so aggregate duration remains sliceable by the number of actions drained.
80523
+ */
80524
+ function reportDraftQueueDrainCycle(durationMs, batchSize) {
80525
+ const batchSizeBucket = workerDepthBucketOf(batchSize);
80526
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DRAIN_CYCLE_DURATION, durationMs, undefined, {
80527
+ batchSizeBucket,
80528
+ });
80529
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DRAIN_CYCLE_BATCH_SIZE, batchSize, undefined, {
80530
+ batchSizeBucket,
80531
+ });
80532
+ }
80533
+ /**
80534
+ * Server round-trip duration for one upload. Isolates slow-network from CPU-bound
80535
+ * quadratic work — today only a THROWN error is captured, so a slow-but-successful (or slow 4xx/5xx)
80536
+ * response is invisible. Tags: handler type, HTTP method, and a bucketed status class ('2xx'/'4xx'/
80537
+ * '5xx'/'0'). No URL, body, or record id.
80538
+ */
80539
+ function reportDraftQueueActionNetworkDuration(handlerId, method, statusBucket, durationMs) {
80540
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_ACTION_NETWORK_DURATION, durationMs, undefined, {
80541
+ handlerId: draftQueueHandlerTagOf(handlerId),
80542
+ method,
80543
+ statusBucket,
80544
+ });
80545
+ }
80546
+ /**
80547
+ * Retry event count. Repeated events identify actions cycling through the drain even when the retry
80548
+ * cap is disabled and an exact attempt number is not persisted. cappedOut marks cap exhaustion.
80549
+ */
80550
+ function reportDraftQueueActionRetryAttempt(handlerId, cappedOut) {
80551
+ ldsMobileInstrumentation$2.incrementCounter(DRAFT_QUEUE_ACTION_RETRY_ATTEMPT, 1, undefined, {
80552
+ handlerId: draftQueueHandlerTagOf(handlerId),
80553
+ cappedOut: String(cappedOut),
80554
+ });
80555
+ }
80556
+ /**
80557
+ * SideEffectStore operation duration + map size. The incremental map sped up the by-KEY lookup but
80558
+ * getEffectsByTag still linearly scans all effects — this measures whether that residual scan is
80559
+ * silently quadratic during churn. op is 'add'|'remove'|'getByTag'; incremental flags the fast path;
80560
+ * mapSize is an integer effect count. No record keys, field names, or field values.
80561
+ */
80562
+ function reportDraftQueueSideEffectOp(op, incremental, durationMs, mapSize) {
80563
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_OP_DURATION, durationMs, undefined, {
80564
+ op,
80565
+ incremental: String(incremental),
80566
+ });
80567
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_MAP_SIZE, mapSize, undefined, {
80568
+ op,
80569
+ });
80570
+ }
80571
+ /**
80572
+ * Broad side-effect lifecycle duration. The fixed region and lifecycle tags identify which part of
80573
+ * serialized draft processing is slow without emitting record keys, action ids, or field data.
80574
+ */
80575
+ function reportDraftQueueSideEffectRegionDuration(region, lifecycle, durationMs) {
80576
+ ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_REGION_DURATION, durationMs, undefined, { region, lifecycle });
80577
+ }
80312
80578
  /**
80313
80579
  * Reports an exception thrown while uploading a draft action. The thrown error is
80314
80580
  * otherwise swallowed by the upload handler's retry path, leaving the failure
@@ -80516,8 +80782,16 @@ class AbstractResourceRequestActionHandler {
80516
80782
  const dispatchOptions = action.observabilityContext !== undefined
80517
80783
  ? { requestCorrelator: { observabilityContext: action.observabilityContext } }
80518
80784
  : {};
80785
+ const method = request?.method?.toUpperCase() ?? 'UNKNOWN';
80786
+ const networkStart = Date.now();
80787
+ let responseReceived = false;
80519
80788
  try {
80520
80789
  const response = await this.networkAdapter(request, dispatchOptions);
80790
+ responseReceived = true;
80791
+ // Time the round-trip regardless of outcome (ok, retryable HTTP error, or non-ok
80792
+ // terminal error) — today only a THROWN error is visible; a slow-but-successful or
80793
+ // slow 4xx/5xx response is not.
80794
+ this.reportNetworkDuration(method, statusBucketOf(response.status), networkStart);
80521
80795
  if (response.ok) {
80522
80796
  await actionCompleted({
80523
80797
  ...action,
@@ -80673,6 +80947,11 @@ class AbstractResourceRequestActionHandler {
80673
80947
  const error = normalizeError$1(e);
80674
80948
  const attempt = this.getUploadRetryCount(action) + 1;
80675
80949
  reportDraftActionUploadError(error, this.handlerId, attempt);
80950
+ // A thrown network call still has a round-trip duration worth surfacing — a slow
80951
+ // FAILING call is otherwise as invisible as a slow successful one.
80952
+ if (!responseReceived) {
80953
+ this.reportNetworkDuration(method, 'error', networkStart);
80954
+ }
80676
80955
  await this.retryOrCap(action, error, actionErrored);
80677
80956
  return ProcessActionResult.NETWORK_ERROR;
80678
80957
  }
@@ -80708,12 +80987,17 @@ class AbstractResourceRequestActionHandler {
80708
80987
  */
80709
80988
  async retryOrCap(action, lastFailure, actionErrored, retryDelayInMs, actionDataChanged) {
80710
80989
  if (!draftQueueMaxRetryAttemptsGate.isOpen({ fallback: false })) {
80711
- // Gate closed: preserve the pre-existing unbounded-retry behavior exactly.
80990
+ // Gate closed: preserve the pre-existing unbounded-retry behavior exactly. The
80991
+ // metric is still emitted (measure-only) so retry attempts are visible even with
80992
+ // the cap gate closed — cappedOut is always false here since nothing ever caps
80993
+ // out on this path.
80994
+ this.reportRetryAttempt(false);
80712
80995
  await actionErrored(action, true, retryDelayInMs, actionDataChanged);
80713
80996
  return;
80714
80997
  }
80715
80998
  const attempt = this.getUploadRetryCount(action) + 1;
80716
80999
  if (attempt >= MAX_RETRY_ATTEMPTS) {
81000
+ this.reportRetryAttempt(true);
80717
81001
  await actionErrored({
80718
81002
  ...action,
80719
81003
  error: buildMaxRetryError(lastFailure),
@@ -80721,6 +81005,7 @@ class AbstractResourceRequestActionHandler {
80721
81005
  }, false);
80722
81006
  return;
80723
81007
  }
81008
+ this.reportRetryAttempt(false);
80724
81009
  // Persist the incremented attempt count so it survives restarts. Forcing
80725
81010
  // actionDataChanged ensures the queue writes the updated metadata before the
80726
81011
  // action is rescheduled for retry.
@@ -80734,12 +81019,12 @@ class AbstractResourceRequestActionHandler {
80734
81019
  await actionErrored(retryingAction, true, retryDelayInMs, true);
80735
81020
  }
80736
81021
  async handleActionEnqueued(action) {
80737
- const impactedKeys = await this.recordService.setSideEffectsForActions([action]);
80738
- await this.recordService.reapplyRecordSideEffects(impactedKeys);
81022
+ const impactedKeys = await this.recordService.setSideEffectsForActions([action], 'enqueued');
81023
+ await this.recordService.reapplyRecordSideEffects(impactedKeys, 'enqueued');
80739
81024
  }
80740
81025
  async handleActionRemoved(action) {
80741
81026
  const impactedKeys = await this.recordService.removeSideEffectsForAction(action);
80742
- await this.recordService.reapplyRecordSideEffects(impactedKeys);
81027
+ await this.recordService.reapplyRecordSideEffects(impactedKeys, 'removed');
80743
81028
  }
80744
81029
  async handleActionReplaced(target, source) {
80745
81030
  // remove both the siden effects from the actions being merged before we
@@ -80747,10 +81032,10 @@ class AbstractResourceRequestActionHandler {
80747
81032
  const impactedKeysFromRemove = await this.recordService.removeSideEffectsForAction(source);
80748
81033
  const removedSideEffectFromSet = await this.recordService.removeSideEffectsForAction(target);
80749
81034
  // revert the values in the DEFAULT store back to what it was before the removed side effects
80750
- await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]));
81035
+ await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]), 'replaced-remove');
80751
81036
  // set the new side effect values for the merged action
80752
- const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target]);
80753
- await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromSet]));
81037
+ const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target], 'replaced-set');
81038
+ await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromSet]), 'replaced-set');
80754
81039
  }
80755
81040
  async handleActionCompleted(action, queueOperations) {
80756
81041
  const { data: request, tag } = action;
@@ -80784,8 +81069,8 @@ class AbstractResourceRequestActionHandler {
80784
81069
  actionsNeedingReplay.push(qo.action);
80785
81070
  }
80786
81071
  });
80787
- const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay);
80788
- await this.recordService.reapplyRecordSideEffects(impactedKeys);
81072
+ const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay, 'completed-replay');
81073
+ await this.recordService.reapplyRecordSideEffects(impactedKeys, 'completed-replay');
80789
81074
  }
80790
81075
  getQueueOperationsForCompletingDrafts(queue, action) {
80791
81076
  const queueOperations = [];
@@ -81111,6 +81396,39 @@ class AbstractResourceRequestActionHandler {
81111
81396
  return new StoreKeyMap();
81112
81397
  });
81113
81398
  }
81399
+ reportNetworkDuration(method, statusBucket, startedAt) {
81400
+ try {
81401
+ reportDraftQueueActionNetworkDuration(this.handlerId, method, statusBucket, Date.now() - startedAt);
81402
+ }
81403
+ catch {
81404
+ // Telemetry must not change upload processing behavior.
81405
+ }
81406
+ }
81407
+ reportRetryAttempt(cappedOut) {
81408
+ try {
81409
+ reportDraftQueueActionRetryAttempt(this.handlerId, cappedOut);
81410
+ }
81411
+ catch {
81412
+ // Telemetry must not change retry or cap behavior.
81413
+ }
81414
+ }
81415
+ }
81416
+ // Classifies an HTTP status into a small, greppable tag set for the network-duration metric —
81417
+ // never the raw status, to keep the metric's tag cardinality bounded.
81418
+ function statusBucketOf(status) {
81419
+ if (status === 0) {
81420
+ return '0';
81421
+ }
81422
+ if (status >= 200 && status <= 299) {
81423
+ return '2xx';
81424
+ }
81425
+ if (status >= 400 && status <= 499) {
81426
+ return '4xx';
81427
+ }
81428
+ if (status >= 500) {
81429
+ return '5xx';
81430
+ }
81431
+ return 'other';
81114
81432
  }
81115
81433
  function actionsForTag(tag, queue) {
81116
81434
  return queue.filter((action) => action.tag === tag);
@@ -81474,10 +81792,16 @@ class UiApiDraftRecordService {
81474
81792
  }
81475
81793
  // calculates the side effects for a given set of actions
81476
81794
  // and returns a set of impacted record keys
81477
- async setSideEffectsForActions(changedActions) {
81478
- const operations = await this.recalculateForChangedActions(changedActions);
81479
- await this.sideEffectStore.addEffects(operations);
81480
- return new Set(operations.map((o) => o.key));
81795
+ async setSideEffectsForActions(changedActions, lifecycle) {
81796
+ const startedAt = Date.now();
81797
+ try {
81798
+ const operations = await this.recalculateForChangedActions(changedActions);
81799
+ await this.sideEffectStore.addEffects(operations);
81800
+ return new Set(operations.map((o) => o.key));
81801
+ }
81802
+ finally {
81803
+ this.reportSideEffectRegionDuration('set', lifecycle, startedAt);
81804
+ }
81481
81805
  }
81482
81806
  // removes the associated side effects for a given action and returns
81483
81807
  // a set of impacted record keys
@@ -81488,31 +81812,45 @@ class UiApiDraftRecordService {
81488
81812
  }
81489
81813
  // reads a set of records out of the durable store, re-applies current side
81490
81814
  // effects and persists the changed record
81491
- async reapplyRecordSideEffects(recordKeys) {
81492
- const luvio = this.getLuvio();
81493
- const keys = Array.from(recordKeys);
81494
- const recordEntries = await this.durableRecordStore.getRecordsWithMetadata(keys);
81495
- keys.forEach((key) => {
81496
- let record;
81497
- const metadata = {
81498
- namespace: 'UiApi',
81499
- representationName: 'RecordRepresentation',
81500
- version: VERSION$1v$1,
81501
- ingestionTimestamp: Date.now(),
81502
- ttl: Number.MAX_SAFE_INTEGER,
81503
- };
81504
- const recordEntry = recordEntries.get(key);
81505
- if (recordEntry) {
81506
- record = recordEntry.record;
81507
- if (recordEntry.metadata) {
81508
- metadata.ingestionTimestamp = recordEntry.metadata.ingestionTimestamp;
81509
- metadata.ttl = TTL$z;
81815
+ async reapplyRecordSideEffects(recordKeys, lifecycle) {
81816
+ const startedAt = Date.now();
81817
+ try {
81818
+ const luvio = this.getLuvio();
81819
+ const keys = Array.from(recordKeys);
81820
+ const recordEntries = await this.durableRecordStore.getRecordsWithMetadata(keys);
81821
+ keys.forEach((key) => {
81822
+ let record;
81823
+ const metadata = {
81824
+ namespace: 'UiApi',
81825
+ representationName: 'RecordRepresentation',
81826
+ version: VERSION$1v$1,
81827
+ ingestionTimestamp: Date.now(),
81828
+ ttl: Number.MAX_SAFE_INTEGER,
81829
+ };
81830
+ const recordEntry = recordEntries.get(key);
81831
+ if (recordEntry) {
81832
+ record = recordEntry.record;
81833
+ if (recordEntry.metadata) {
81834
+ metadata.ingestionTimestamp = recordEntry.metadata.ingestionTimestamp;
81835
+ metadata.ttl = TTL$z;
81836
+ }
81510
81837
  }
81511
- }
81512
- luvio.storePublish(key, record);
81513
- luvio.publishStoreMetadata(key, metadata);
81514
- });
81515
- await luvio.storeBroadcast();
81838
+ luvio.storePublish(key, record);
81839
+ luvio.publishStoreMetadata(key, metadata);
81840
+ });
81841
+ await luvio.storeBroadcast();
81842
+ }
81843
+ finally {
81844
+ this.reportSideEffectRegionDuration('reapply', lifecycle, startedAt);
81845
+ }
81846
+ }
81847
+ reportSideEffectRegionDuration(region, lifecycle, startedAt) {
81848
+ try {
81849
+ reportDraftQueueSideEffectRegionDuration(region, lifecycle, Date.now() - startedAt);
81850
+ }
81851
+ catch {
81852
+ // Telemetry must not change draft processing behavior.
81853
+ }
81516
81854
  }
81517
81855
  async synthesizeId(apiName) {
81518
81856
  const objectInfo = await this.objectInfoService.getObjectInfo(apiName);
@@ -81748,7 +82086,7 @@ class UpdateRecordQuickActionExecutionRepresentationHandler extends AbstractQuic
81748
82086
  // since we don't ingest a record from the response, we need to manually trigger a re-apply here to ensure we
81749
82087
  // re-ingest the record without effects applied
81750
82088
  await this.recordService.removeSideEffectsForAction(action);
81751
- await this.recordService.reapplyRecordSideEffects(new Set([action.tag]));
82089
+ await this.recordService.reapplyRecordSideEffects(new Set([action.tag]), 'quick-action-completed');
81752
82090
  // notify luvio that record is now changed and needs to be refreshed
81753
82091
  await luvio.notifyStoreUpdateAvailable([action.tag]);
81754
82092
  }
@@ -90428,6 +90766,18 @@ const draftQueueInstrumentation = {
90428
90766
  onDurableOperation(op, segment, durationMs) {
90429
90767
  reportDraftQueueDurableOperation(op, segment, durationMs);
90430
90768
  },
90769
+ onWorkerTiming(waitMs, holdMs, queueDepth) {
90770
+ reportDraftQueueWorkerTiming(waitMs, holdMs, queueDepth);
90771
+ },
90772
+ onActionQueueWait(handlerId, waitMs) {
90773
+ reportDraftQueueActionQueueWait(handlerId, waitMs);
90774
+ },
90775
+ onActionDrainDuration(handlerId, durationMs) {
90776
+ reportDraftQueueActionDrainDuration(handlerId, durationMs);
90777
+ },
90778
+ onDrainCycle(durationMs, batchSize) {
90779
+ reportDraftQueueDrainCycle(durationMs, batchSize);
90780
+ },
90431
90781
  };
90432
90782
 
90433
90783
  // so eslint doesn't complain about nimbus
@@ -93770,6 +94120,9 @@ class SideEffectStore {
93770
94120
  this.initialize();
93771
94121
  }
93772
94122
  async addEffects(effects) {
94123
+ // Wall-clock across the whole method (including the durable write), matching
94124
+ // how the equivalent removeEffects/getEffectsByTag windows are measured.
94125
+ const startTime = Date.now();
93773
94126
  const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
93774
94127
  const durableEntries = {};
93775
94128
  effects.forEach((effect) => {
@@ -93784,8 +94137,11 @@ class SideEffectStore {
93784
94137
  this.regenerateKeyToEffectMap();
93785
94138
  }
93786
94139
  await this.durableStore.setEntries(durableEntries, SIDE_EFFECT_SEGMENT);
94140
+ this.reportOperation('add', incremental, startTime);
93787
94141
  }
93788
94142
  async removeEffects(effects) {
94143
+ // See addEffects — same wall-clock-across-the-method measurement.
94144
+ const startTime = Date.now();
93789
94145
  const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
93790
94146
  const effectKeys = effects.map((e) => e.uniqueId);
93791
94147
  effects.forEach((effect) => {
@@ -93799,6 +94155,7 @@ class SideEffectStore {
93799
94155
  this.regenerateKeyToEffectMap();
93800
94156
  }
93801
94157
  await this.durableStore.evictEntries(effectKeys, SIDE_EFFECT_SEGMENT);
94158
+ this.reportOperation('remove', incremental, startTime);
93802
94159
  }
93803
94160
  getEffects(key) {
93804
94161
  const effects = this.keyToEffectMap.get(key);
@@ -93808,6 +94165,10 @@ class SideEffectStore {
93808
94165
  return effects;
93809
94166
  }
93810
94167
  getEffectsByTag(tag) {
94168
+ // This scan is still O(N) over every effect regardless of the incremental-map
94169
+ // gate — timing it tells us whether that residual scan is the quadratic hotspot during churn.
94170
+ const startTime = Date.now();
94171
+ const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
93811
94172
  const filteredEffects = [];
93812
94173
  const { keyToEffectMap } = this;
93813
94174
  // Loop through every entry in the map
@@ -93817,7 +94178,17 @@ class SideEffectStore {
93817
94178
  // Add the matching effects to the filtered list
93818
94179
  filteredEffects.push(...matchingEffects);
93819
94180
  }
93820
- return filteredEffects.sort((a, b) => a.timestamp - b.timestamp);
94181
+ const result = filteredEffects.sort((a, b) => a.timestamp - b.timestamp);
94182
+ this.reportOperation('getByTag', incremental, startTime);
94183
+ return result;
94184
+ }
94185
+ reportOperation(op, incremental, startedAt) {
94186
+ try {
94187
+ reportDraftQueueSideEffectOp(op, incremental, Date.now() - startedAt, this.allEffects.size);
94188
+ }
94189
+ catch {
94190
+ // Telemetry must not change side-effect store behavior.
94191
+ }
93821
94192
  }
93822
94193
  async initialize() {
93823
94194
  const effects = await this.durableStore.getAllEntries(SIDE_EFFECT_SEGMENT);
@@ -97014,7 +97385,7 @@ function buildServiceDescriptor$b(luvio) {
97014
97385
  },
97015
97386
  };
97016
97387
  }
97017
- // version: 1.454.0-4223ab4365
97388
+ // version: 1.456.0-cef836b978
97018
97389
 
97019
97390
  /**
97020
97391
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -97040,7 +97411,7 @@ function buildServiceDescriptor$a(notifyRecordUpdateAvailable, getNormalizedLuvi
97040
97411
  },
97041
97412
  };
97042
97413
  }
97043
- // version: 1.454.0-4223ab4365
97414
+ // version: 1.456.0-cef836b978
97044
97415
 
97045
97416
  function findExecutableOperation$1(input) {
97046
97417
  const operations = input.query.definitions.filter(
@@ -99749,7 +100120,7 @@ register$1({
99749
100120
  id: '@salesforce/lds-network-adapter',
99750
100121
  instrument: instrument$2,
99751
100122
  });
99752
- // version: 1.454.0-4223ab4365
100123
+ // version: 1.456.0-cef836b978
99753
100124
 
99754
100125
  const { create: create$2, keys: keys$2 } = Object;
99755
100126
  const { stringify, parse } = JSON;
@@ -100213,10 +100584,11 @@ class BaseArrayFieldDef {
100213
100584
  }
100214
100585
  ]);
100215
100586
  }
100587
+ const existingArrayData = input.existingNormalizedData?.data;
100216
100588
  const arrayNormalizationErrors = [];
100217
100589
  const normalizedArray = [];
100218
100590
  input.data.forEach((item, index) => {
100219
- const existingItemData = input.existingNormalizedData?.[index];
100591
+ const existingItemData = existingArrayData?.[index];
100220
100592
  const normalizedItemResult = this.items.write(cache, {
100221
100593
  ...input,
100222
100594
  data: item,
@@ -107284,7 +107656,7 @@ function registerCallback(cb) {
107284
107656
  cb(graphql_v1_import, graphql_imperative$1, graphql_imperative_legacy_v1_import, graphql_state_manager, useOneStoreGraphQL);
107285
107657
  }
107286
107658
  }
107287
- // version: 1.454.0-761808c4e9
107659
+ // version: 1.456.0-6ed480b93c
107288
107660
 
107289
107661
  function createFragmentMap(documentNode) {
107290
107662
  const fragments = {};
@@ -124013,7 +124385,7 @@ function keyBuilderFromType(luvio, object) {
124013
124385
  return keyBuilder$z(luvio, keyParams);
124014
124386
  }
124015
124387
 
124016
- const { assign: assign$1, create: create$1, freeze: freeze$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
124388
+ const { assign: assign$1, create: create$1, freeze: freeze$1, getPrototypeOf: getPrototypeOf$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
124017
124389
  const { isArray: isArray$2 } = Array;
124018
124390
  const { concat: concat$1, filter: filter$1, includes: includes$1, push: push$1, reduce: reduce$1 } = Array.prototype;
124019
124391
 
@@ -136527,7 +136899,7 @@ register$1({
136527
136899
  configuration: { ...configurationForGraphQLAdapters$1 },
136528
136900
  instrument: instrument$1,
136529
136901
  });
136530
- // version: 1.454.0-761808c4e9
136902
+ // version: 1.456.0-6ed480b93c
136531
136903
 
136532
136904
  // On core the unstable adapters are re-exported with different names,
136533
136905
  // we want to match them here.
@@ -136679,7 +137051,7 @@ withDefaultLuvio((luvio) => {
136679
137051
  unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
136680
137052
  graphQLImperative = ldsAdapter;
136681
137053
  });
136682
- // version: 1.454.0-761808c4e9
137054
+ // version: 1.456.0-6ed480b93c
136683
137055
 
136684
137056
  var gqlApi = /*#__PURE__*/Object.freeze({
136685
137057
  __proto__: null,
@@ -137478,7 +137850,7 @@ const callbacks$1 = [];
137478
137850
  function register(r) {
137479
137851
  callbacks$1.forEach((callback) => callback(r));
137480
137852
  }
137481
- // version: 1.454.0-4223ab4365
137853
+ // version: 1.456.0-cef836b978
137482
137854
 
137483
137855
  /**
137484
137856
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -137764,7 +138136,7 @@ function buildAdapterValidationConfig(displayName, paramsMeta) {
137764
138136
  }
137765
138137
  const keyPrefix = 'UiApi';
137766
138138
 
137767
- const { assign, create, freeze, isFrozen, keys } = Object;
138139
+ const { assign, create, freeze, getPrototypeOf, isFrozen, keys } = Object;
137768
138140
  const { isArray } = Array;
137769
138141
  const { concat, filter, includes, push, reduce } = Array.prototype;
137770
138142
 
@@ -138767,4 +139139,4 @@ const { luvio } = getRuntime();
138767
139139
  setDefaultLuvio({ luvio });
138768
139140
 
138769
139141
  export { createPrimingSession, draftManager, draftQueue, evictCacheRecordsByIds, evictExpiredCacheEntries, executeAdapter, executeMutatingAdapter, getImperativeAdapterNames, importLuvioAdapterModule, importOneStoreAdapterModule, invokeAdapter, invokeAdapterWithDraftToMerge, invokeAdapterWithDraftToReplace, invokeAdapterWithMetadata, nimbusDraftQueue, registerReportObserver, setMetadataTTL, setUiApiRecordTTL, stopEviction, subscribeToAdapter };
138770
- // version: 1.454.0-4223ab4365
139142
+ // version: 1.456.0-cef836b978