@salesforce/lds-worker-api 1.453.0 → 1.455.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.
@@ -4148,7 +4148,7 @@ function createResourceParamsImpl(config, configMetadata) {
4148
4148
  }
4149
4149
  return resourceParams;
4150
4150
  }
4151
- // engine version: 0.161.0-fe06f180
4151
+ // engine version: 0.161.2-bd1bd38a
4152
4152
 
4153
4153
  /**
4154
4154
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -4276,7 +4276,7 @@ function withDefaultLuvio(callback) {
4276
4276
  }
4277
4277
  callbacks.push(callback);
4278
4278
  }
4279
- // version: 1.453.0-725e09cf25
4279
+ // version: 1.455.0-c53c97de2a
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.453.0-725e09cf25
5323
+ // version: 1.455.0-c53c97de2a
5324
5324
 
5325
5325
  function isSupportedEntity(_objectApiName) {
5326
5326
  return true;
@@ -5426,11 +5426,11 @@ var TypeCheckShapes;
5426
5426
  TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
5427
5427
  TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
5428
5428
  })(TypeCheckShapes || (TypeCheckShapes = {}));
5429
- // engine version: 0.161.0-fe06f180
5429
+ // engine version: 0.161.2-bd1bd38a
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.453.0-e6dc0c039a
32550
+ // version: 1.455.0-96e9b41a18
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,
@@ -80603,19 +80877,32 @@ class AbstractResourceRequestActionHandler {
80603
80877
  actionDataChanged = true;
80604
80878
  }
80605
80879
  else if (!this.isServerGeneratedError(response.body)) {
80606
- // Killswitch CLOSED (default) — only an edge/gateway-injected 400 (no
80880
+ // Killswitch CLOSED (default) — an edge/gateway-injected 400 (no
80607
80881
  // recognizable server error body) is retried with the SAME key, so the
80608
80882
  // server can dedupe a write that may already have committed at the origin.
80609
- // A real, server-generated 400 (UiApiError[] or an enhancedErrorType body,
80610
- // e.g. a field-validation failure) falls through to the error path below:
80611
- // retrying it unchanged would only be rejected again, so the draft is
80612
- // errored for the user to fix or discard — the same terminal outcome as
80613
- // before this fix, minus the duplicating key rotation. The key is only ever
80614
- // rotated by the recognized idempotency error codes above, by a backdating
80615
- // collision (new body), or when the user edits an errored draft
80616
- // (mergeActions/handleReplaceAction).
80883
+ // Rotating here is what duplicated the WOLI records (@W-23445154), so the
80884
+ // key is preserved.
80617
80885
  shouldRetry = true;
80618
80886
  }
80887
+ else {
80888
+ // Killswitch CLOSED — a REAL, server-generated 400 (UiApiError[] or an
80889
+ // enhancedErrorType body, e.g. a field-validation failure). The origin
80890
+ // understood the request and rejected it, so it definitively did NOT
80891
+ // commit — there is no already-written record to duplicate, which is what
80892
+ // makes rotation safe here (unlike the edge-injected case above).
80893
+ //
80894
+ // We still do NOT retry (shouldRetry stays false): the request as-is would
80895
+ // just be rejected again and wedge the queue. The draft errors for the user
80896
+ // to fix or discard. But we DO rotate the key: the server's idempotency
80897
+ // layer caches the 400 against the key, so if the same request is later
80898
+ // resubmitted unchanged after the server-side validation rule changes to
80899
+ // allow it, reusing the key would replay that cached 400 and the now-valid
80900
+ // write would never be applied. Rotating gives the retried request a fresh
80901
+ // key so the origin re-evaluates it. @W-23445154
80902
+ updatedAction.data.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
80903
+ reportIdempotencyKeyRotated(updatedAction.targetId, 'server-validation-400');
80904
+ actionDataChanged = true;
80905
+ }
80619
80906
  }
80620
80907
  if (response.status === HttpStatusCode$2.BadRequest &&
80621
80908
  this.isBackdatingError(response.body, action)) {
@@ -80660,6 +80947,11 @@ class AbstractResourceRequestActionHandler {
80660
80947
  const error = normalizeError$1(e);
80661
80948
  const attempt = this.getUploadRetryCount(action) + 1;
80662
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
+ }
80663
80955
  await this.retryOrCap(action, error, actionErrored);
80664
80956
  return ProcessActionResult.NETWORK_ERROR;
80665
80957
  }
@@ -80695,12 +80987,17 @@ class AbstractResourceRequestActionHandler {
80695
80987
  */
80696
80988
  async retryOrCap(action, lastFailure, actionErrored, retryDelayInMs, actionDataChanged) {
80697
80989
  if (!draftQueueMaxRetryAttemptsGate.isOpen({ fallback: false })) {
80698
- // 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);
80699
80995
  await actionErrored(action, true, retryDelayInMs, actionDataChanged);
80700
80996
  return;
80701
80997
  }
80702
80998
  const attempt = this.getUploadRetryCount(action) + 1;
80703
80999
  if (attempt >= MAX_RETRY_ATTEMPTS) {
81000
+ this.reportRetryAttempt(true);
80704
81001
  await actionErrored({
80705
81002
  ...action,
80706
81003
  error: buildMaxRetryError(lastFailure),
@@ -80708,6 +81005,7 @@ class AbstractResourceRequestActionHandler {
80708
81005
  }, false);
80709
81006
  return;
80710
81007
  }
81008
+ this.reportRetryAttempt(false);
80711
81009
  // Persist the incremented attempt count so it survives restarts. Forcing
80712
81010
  // actionDataChanged ensures the queue writes the updated metadata before the
80713
81011
  // action is rescheduled for retry.
@@ -80721,12 +81019,12 @@ class AbstractResourceRequestActionHandler {
80721
81019
  await actionErrored(retryingAction, true, retryDelayInMs, true);
80722
81020
  }
80723
81021
  async handleActionEnqueued(action) {
80724
- const impactedKeys = await this.recordService.setSideEffectsForActions([action]);
80725
- await this.recordService.reapplyRecordSideEffects(impactedKeys);
81022
+ const impactedKeys = await this.recordService.setSideEffectsForActions([action], 'enqueued');
81023
+ await this.recordService.reapplyRecordSideEffects(impactedKeys, 'enqueued');
80726
81024
  }
80727
81025
  async handleActionRemoved(action) {
80728
81026
  const impactedKeys = await this.recordService.removeSideEffectsForAction(action);
80729
- await this.recordService.reapplyRecordSideEffects(impactedKeys);
81027
+ await this.recordService.reapplyRecordSideEffects(impactedKeys, 'removed');
80730
81028
  }
80731
81029
  async handleActionReplaced(target, source) {
80732
81030
  // remove both the siden effects from the actions being merged before we
@@ -80734,10 +81032,10 @@ class AbstractResourceRequestActionHandler {
80734
81032
  const impactedKeysFromRemove = await this.recordService.removeSideEffectsForAction(source);
80735
81033
  const removedSideEffectFromSet = await this.recordService.removeSideEffectsForAction(target);
80736
81034
  // revert the values in the DEFAULT store back to what it was before the removed side effects
80737
- await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]));
81035
+ await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]), 'replaced-remove');
80738
81036
  // set the new side effect values for the merged action
80739
- const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target]);
80740
- 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');
80741
81039
  }
80742
81040
  async handleActionCompleted(action, queueOperations) {
80743
81041
  const { data: request, tag } = action;
@@ -80771,8 +81069,8 @@ class AbstractResourceRequestActionHandler {
80771
81069
  actionsNeedingReplay.push(qo.action);
80772
81070
  }
80773
81071
  });
80774
- const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay);
80775
- await this.recordService.reapplyRecordSideEffects(impactedKeys);
81072
+ const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay, 'completed-replay');
81073
+ await this.recordService.reapplyRecordSideEffects(impactedKeys, 'completed-replay');
80776
81074
  }
80777
81075
  getQueueOperationsForCompletingDrafts(queue, action) {
80778
81076
  const queueOperations = [];
@@ -81098,6 +81396,39 @@ class AbstractResourceRequestActionHandler {
81098
81396
  return new StoreKeyMap();
81099
81397
  });
81100
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';
81101
81432
  }
81102
81433
  function actionsForTag(tag, queue) {
81103
81434
  return queue.filter((action) => action.tag === tag);
@@ -81461,10 +81792,16 @@ class UiApiDraftRecordService {
81461
81792
  }
81462
81793
  // calculates the side effects for a given set of actions
81463
81794
  // and returns a set of impacted record keys
81464
- async setSideEffectsForActions(changedActions) {
81465
- const operations = await this.recalculateForChangedActions(changedActions);
81466
- await this.sideEffectStore.addEffects(operations);
81467
- 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
+ }
81468
81805
  }
81469
81806
  // removes the associated side effects for a given action and returns
81470
81807
  // a set of impacted record keys
@@ -81475,31 +81812,45 @@ class UiApiDraftRecordService {
81475
81812
  }
81476
81813
  // reads a set of records out of the durable store, re-applies current side
81477
81814
  // effects and persists the changed record
81478
- async reapplyRecordSideEffects(recordKeys) {
81479
- const luvio = this.getLuvio();
81480
- const keys = Array.from(recordKeys);
81481
- const recordEntries = await this.durableRecordStore.getRecordsWithMetadata(keys);
81482
- keys.forEach((key) => {
81483
- let record;
81484
- const metadata = {
81485
- namespace: 'UiApi',
81486
- representationName: 'RecordRepresentation',
81487
- version: VERSION$1v$1,
81488
- ingestionTimestamp: Date.now(),
81489
- ttl: Number.MAX_SAFE_INTEGER,
81490
- };
81491
- const recordEntry = recordEntries.get(key);
81492
- if (recordEntry) {
81493
- record = recordEntry.record;
81494
- if (recordEntry.metadata) {
81495
- metadata.ingestionTimestamp = recordEntry.metadata.ingestionTimestamp;
81496
- 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
+ }
81497
81837
  }
81498
- }
81499
- luvio.storePublish(key, record);
81500
- luvio.publishStoreMetadata(key, metadata);
81501
- });
81502
- 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
+ }
81503
81854
  }
81504
81855
  async synthesizeId(apiName) {
81505
81856
  const objectInfo = await this.objectInfoService.getObjectInfo(apiName);
@@ -81735,7 +82086,7 @@ class UpdateRecordQuickActionExecutionRepresentationHandler extends AbstractQuic
81735
82086
  // since we don't ingest a record from the response, we need to manually trigger a re-apply here to ensure we
81736
82087
  // re-ingest the record without effects applied
81737
82088
  await this.recordService.removeSideEffectsForAction(action);
81738
- await this.recordService.reapplyRecordSideEffects(new Set([action.tag]));
82089
+ await this.recordService.reapplyRecordSideEffects(new Set([action.tag]), 'quick-action-completed');
81739
82090
  // notify luvio that record is now changed and needs to be refreshed
81740
82091
  await luvio.notifyStoreUpdateAvailable([action.tag]);
81741
82092
  }
@@ -90415,6 +90766,18 @@ const draftQueueInstrumentation = {
90415
90766
  onDurableOperation(op, segment, durationMs) {
90416
90767
  reportDraftQueueDurableOperation(op, segment, durationMs);
90417
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
+ },
90418
90781
  };
90419
90782
 
90420
90783
  // so eslint doesn't complain about nimbus
@@ -93757,6 +94120,9 @@ class SideEffectStore {
93757
94120
  this.initialize();
93758
94121
  }
93759
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();
93760
94126
  const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
93761
94127
  const durableEntries = {};
93762
94128
  effects.forEach((effect) => {
@@ -93771,8 +94137,11 @@ class SideEffectStore {
93771
94137
  this.regenerateKeyToEffectMap();
93772
94138
  }
93773
94139
  await this.durableStore.setEntries(durableEntries, SIDE_EFFECT_SEGMENT);
94140
+ this.reportOperation('add', incremental, startTime);
93774
94141
  }
93775
94142
  async removeEffects(effects) {
94143
+ // See addEffects — same wall-clock-across-the-method measurement.
94144
+ const startTime = Date.now();
93776
94145
  const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
93777
94146
  const effectKeys = effects.map((e) => e.uniqueId);
93778
94147
  effects.forEach((effect) => {
@@ -93786,6 +94155,7 @@ class SideEffectStore {
93786
94155
  this.regenerateKeyToEffectMap();
93787
94156
  }
93788
94157
  await this.durableStore.evictEntries(effectKeys, SIDE_EFFECT_SEGMENT);
94158
+ this.reportOperation('remove', incremental, startTime);
93789
94159
  }
93790
94160
  getEffects(key) {
93791
94161
  const effects = this.keyToEffectMap.get(key);
@@ -93795,6 +94165,10 @@ class SideEffectStore {
93795
94165
  return effects;
93796
94166
  }
93797
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 });
93798
94172
  const filteredEffects = [];
93799
94173
  const { keyToEffectMap } = this;
93800
94174
  // Loop through every entry in the map
@@ -93804,7 +94178,17 @@ class SideEffectStore {
93804
94178
  // Add the matching effects to the filtered list
93805
94179
  filteredEffects.push(...matchingEffects);
93806
94180
  }
93807
- 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
+ }
93808
94192
  }
93809
94193
  async initialize() {
93810
94194
  const effects = await this.durableStore.getAllEntries(SIDE_EFFECT_SEGMENT);
@@ -97001,7 +97385,7 @@ function buildServiceDescriptor$b(luvio) {
97001
97385
  },
97002
97386
  };
97003
97387
  }
97004
- // version: 1.453.0-725e09cf25
97388
+ // version: 1.455.0-c53c97de2a
97005
97389
 
97006
97390
  /**
97007
97391
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -97027,7 +97411,7 @@ function buildServiceDescriptor$a(notifyRecordUpdateAvailable, getNormalizedLuvi
97027
97411
  },
97028
97412
  };
97029
97413
  }
97030
- // version: 1.453.0-725e09cf25
97414
+ // version: 1.455.0-c53c97de2a
97031
97415
 
97032
97416
  function findExecutableOperation$1(input) {
97033
97417
  const operations = input.query.definitions.filter(
@@ -99736,7 +100120,7 @@ register$1({
99736
100120
  id: '@salesforce/lds-network-adapter',
99737
100121
  instrument: instrument$2,
99738
100122
  });
99739
- // version: 1.453.0-725e09cf25
100123
+ // version: 1.455.0-c53c97de2a
99740
100124
 
99741
100125
  const { create: create$2, keys: keys$2 } = Object;
99742
100126
  const { stringify, parse } = JSON;
@@ -107271,7 +107655,7 @@ function registerCallback(cb) {
107271
107655
  cb(graphql_v1_import, graphql_imperative$1, graphql_imperative_legacy_v1_import, graphql_state_manager, useOneStoreGraphQL);
107272
107656
  }
107273
107657
  }
107274
- // version: 1.453.0-e6dc0c039a
107658
+ // version: 1.455.0-96e9b41a18
107275
107659
 
107276
107660
  function createFragmentMap(documentNode) {
107277
107661
  const fragments = {};
@@ -124000,7 +124384,7 @@ function keyBuilderFromType(luvio, object) {
124000
124384
  return keyBuilder$z(luvio, keyParams);
124001
124385
  }
124002
124386
 
124003
- const { assign: assign$1, create: create$1, freeze: freeze$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
124387
+ const { assign: assign$1, create: create$1, freeze: freeze$1, getPrototypeOf: getPrototypeOf$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
124004
124388
  const { isArray: isArray$2 } = Array;
124005
124389
  const { concat: concat$1, filter: filter$1, includes: includes$1, push: push$1, reduce: reduce$1 } = Array.prototype;
124006
124390
 
@@ -136514,7 +136898,7 @@ register$1({
136514
136898
  configuration: { ...configurationForGraphQLAdapters$1 },
136515
136899
  instrument: instrument$1,
136516
136900
  });
136517
- // version: 1.453.0-e6dc0c039a
136901
+ // version: 1.455.0-96e9b41a18
136518
136902
 
136519
136903
  // On core the unstable adapters are re-exported with different names,
136520
136904
  // we want to match them here.
@@ -136666,7 +137050,7 @@ withDefaultLuvio((luvio) => {
136666
137050
  unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
136667
137051
  graphQLImperative = ldsAdapter;
136668
137052
  });
136669
- // version: 1.453.0-e6dc0c039a
137053
+ // version: 1.455.0-96e9b41a18
136670
137054
 
136671
137055
  var gqlApi = /*#__PURE__*/Object.freeze({
136672
137056
  __proto__: null,
@@ -137465,7 +137849,7 @@ const callbacks$1 = [];
137465
137849
  function register(r) {
137466
137850
  callbacks$1.forEach((callback) => callback(r));
137467
137851
  }
137468
- // version: 1.453.0-725e09cf25
137852
+ // version: 1.455.0-c53c97de2a
137469
137853
 
137470
137854
  /**
137471
137855
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -137751,7 +138135,7 @@ function buildAdapterValidationConfig(displayName, paramsMeta) {
137751
138135
  }
137752
138136
  const keyPrefix = 'UiApi';
137753
138137
 
137754
- const { assign, create, freeze, isFrozen, keys } = Object;
138138
+ const { assign, create, freeze, getPrototypeOf, isFrozen, keys } = Object;
137755
138139
  const { isArray } = Array;
137756
138140
  const { concat, filter, includes, push, reduce } = Array.prototype;
137757
138141
 
@@ -138754,4 +139138,4 @@ const { luvio } = getRuntime();
138754
139138
  setDefaultLuvio({ luvio });
138755
139139
 
138756
139140
  export { createPrimingSession, draftManager, draftQueue, evictCacheRecordsByIds, evictExpiredCacheEntries, executeAdapter, executeMutatingAdapter, getImperativeAdapterNames, importLuvioAdapterModule, importOneStoreAdapterModule, invokeAdapter, invokeAdapterWithDraftToMerge, invokeAdapterWithDraftToReplace, invokeAdapterWithMetadata, nimbusDraftQueue, registerReportObserver, setMetadataTTL, setUiApiRecordTTL, stopEviction, subscribeToAdapter };
138757
- // version: 1.453.0-725e09cf25
139141
+ // version: 1.455.0-c53c97de2a