@salesforce/lds-runtime-aura 1.401.0 → 1.403.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.
@@ -26,21 +26,22 @@ import { GetApexWireAdapterFactory, registerPrefetcher as registerPrefetcher$1 }
26
26
  import { instrument, getRecordAvatarsAdapterFactory, getRecordAdapterFactory, coerceFieldIdArray, getRecordsAdapterFactory, getRecordActionsAdapterFactory, getObjectInfosAdapterFactory, coerceObjectIdArray, getObjectInfoAdapterFactory, coerceObjectId, getRelatedListsActionsAdapterFactory, getRelatedListInfoBatchAdapterFactory, getRelatedListInfoAdapterFactory, getRelatedListRecordsBatchAdapterFactory, getRelatedListRecordsAdapterFactory, getListInfoByNameAdapterFactory, getListInfosByObjectNameAdapterFactory, getListRecordsByNameAdapterFactory, getListObjectInfoAdapterFactory, getRelatedListsInfoAdapterFactory, getRelatedListActionsAdapterFactory, getRecordId18Array, buildRecordRepKeyFromId, configuration, InMemoryRecordRepresentationQueryEvaluator, UiApiNamespace, RecordRepresentationRepresentationType, registerPrefetcher, RecordRepresentationVersion } from 'force/ldsAdaptersUiapi';
27
27
  import { getInstrumentation } from 'o11y/client';
28
28
  import { findExecutableOperation, buildGraphQLInputExtension, addTypenameToDocument } from 'force/luvioGraphqlNormalization';
29
- import { print } from 'force/luvioOnestoreGraphqlParser';
29
+ import { print, wrapConfigAndVerify, resolveAst, validateGraphQLOperations } from 'force/luvioOnestoreGraphqlParser';
30
30
  import { setServices } from 'force/luvioServiceProvisioner1';
31
+ import { assertIsValid, MissingRequiredPropertyError, JsonSchemaViolationError } from 'force/luvioJsonschemaValidate5';
31
32
  import { dispatchGlobalEvent, unstable_loadComponentDefs, executeGlobalControllerRawResponse } from 'aura';
32
33
  import auraNetworkAdapter, { dispatchAuraAction, defaultActionConfig, instrument as instrument$1, forceRecordTransactionsDisabled as forceRecordTransactionsDisabled$1, ldsNetworkAdapterInstrument, CrudEventState, CrudEventType, UIAPI_RECORDS_PATH, UIAPI_RELATED_LIST_RECORDS_BATCH_PATH, UIAPI_RELATED_LIST_RECORDS_PATH } from 'force/ldsNetwork';
33
- import { pageScopedCache } from 'instrumentation/utility';
34
- import { instrument as instrument$2, generateRequestId, setupLexNetworkAdapter, internalRequestTracker } from 'force/ldsNetworkFetch';
35
34
  import { ThirdPartyTracker } from 'instrumentation:thirdPartyTracker';
35
+ import { markStart, markEnd, counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, timer } from 'instrumentation/service';
36
+ import { instrument as instrument$2, setupLexNetworkAdapter, internalRequestTracker, generateRequestId as generateRequestId$1 } from 'force/ldsNetworkFetch';
36
37
  import { REFRESH_ADAPTER_EVENT, ADAPTER_UNFULFILLED_ERROR, instrument as instrument$3 } from 'force/ldsBindings';
37
- import { counter, registerCacheStats, perfStart, perfEnd, registerPeriodicLogger, interaction, timer } from 'instrumentation/service';
38
- import { LRUCache, instrumentAdapter, instrumentLuvio, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, logError, setLdsNetworkAdapterInstrumentation, incrementStateCreatedCount, executeAsyncActivity, METRIC_KEYS, onIdleDetected } from 'force/ldsInstrumentation';
38
+ import { LRUCache, instrumentAdapter, instrumentLuvio, setupInstrumentation as setupInstrumentation$1, logObjectInfoChanged as logObjectInfoChanged$1, updatePercentileHistogramMetric, incrementCounterMetric, incrementGetRecordNotifyChangeAllowCount, incrementGetRecordNotifyChangeDropCount, incrementNotifyRecordUpdateAvailableAllowCount, incrementNotifyRecordUpdateAvailableDropCount, setLdsAdaptersUiapiInstrumentation, logError as logError$2, setLdsNetworkAdapterInstrumentation, incrementStateCreatedCount, executeAsyncActivity, METRIC_KEYS, onIdleDetected } from 'force/ldsInstrumentation';
39
39
  import { instrument as instrument$4 } from 'force/adsBridge';
40
40
  import { instrument as instrument$5 } from '@lwc/state';
41
41
  import { withRegistration, register, setDefaultLuvio } from 'force/ldsEngine';
42
- import useHotspotLimit from '@salesforce/gate/lds.pdl.useHotspotLimit';
42
+ import { pageScopedCache } from 'instrumentation/utility';
43
43
  import { createStorage, clearStorages } from 'force/ldsStorage';
44
+ import useHotspotLimit from '@salesforce/gate/lds.pdl.useHotspotLimit';
44
45
  import useHttpUiapiOneApp from '@salesforce/gate/lds.useHttpUiapiOneApp';
45
46
  import useHttpUiapiOneRuntime from '@salesforce/gate/lds.useHttpUiapiOneRuntime';
46
47
 
@@ -52,14 +53,15 @@ import useHttpUiapiOneRuntime from '@salesforce/gate/lds.useHttpUiapiOneRuntime'
52
53
  const { create: create$1, freeze, keys: keys$2, entries: entries$1 } = Object;
53
54
  const { isArray: isArray$3 } = Array;
54
55
  const { stringify: stringify$3, parse: parse$2 } = JSON;
55
- const LogLevelMap$1 = {
56
+ const WeakSetConstructor = WeakSet;
57
+ const LogLevelMap = {
56
58
  TRACE: 4,
57
59
  DEBUG: 3,
58
60
  INFO: 2,
59
61
  WARN: 1,
60
62
  ERROR: 0
61
63
  };
62
- let ConsoleLogger$1 = class ConsoleLogger {
64
+ class ConsoleLogger {
63
65
  constructor(level = "WARN", printer = console.log, formatter = (level2, message) => `${level2}: ${message}`) {
64
66
  this.level = level;
65
67
  this.printer = printer;
@@ -82,12 +84,15 @@ let ConsoleLogger$1 = class ConsoleLogger {
82
84
  this.log("ERROR", message);
83
85
  }
84
86
  log(level, message) {
85
- if (LogLevelMap$1[level] > LogLevelMap$1[this.level]) {
87
+ if (LogLevelMap[level] > LogLevelMap[this.level]) {
86
88
  return;
87
89
  }
88
90
  this.printer(this.formatter(level, message));
89
91
  }
90
- };
92
+ }
93
+ function loggerService(level, printer, formatter) {
94
+ return new ConsoleLogger(level, printer, formatter);
95
+ }
91
96
  let Ok$2 = class Ok {
92
97
  constructor(value) {
93
98
  this.value = value;
@@ -131,41 +136,41 @@ function buildSubscribableResult$1(result, subscribe, refresh) {
131
136
  return err$1({ failure: result.error, subscribe, refresh });
132
137
  }
133
138
  }
134
- function resolvedPromiseLike$3(result) {
135
- if (isPromiseLike$3(result)) {
139
+ function resolvedPromiseLike$2(result) {
140
+ if (isPromiseLike$2(result)) {
136
141
  return result.then((nextResult) => nextResult);
137
142
  }
138
143
  return {
139
144
  then: (onFulfilled, _onRejected) => {
140
145
  try {
141
- return resolvedPromiseLike$3(onFulfilled(result));
146
+ return resolvedPromiseLike$2(onFulfilled(result));
142
147
  } catch (e) {
143
148
  if (onFulfilled === void 0) {
144
- return resolvedPromiseLike$3(result);
149
+ return resolvedPromiseLike$2(result);
145
150
  }
146
- return rejectedPromiseLike$3(e);
151
+ return rejectedPromiseLike$2(e);
147
152
  }
148
153
  }
149
154
  };
150
155
  }
151
- function rejectedPromiseLike$3(reason) {
152
- if (isPromiseLike$3(reason)) {
156
+ function rejectedPromiseLike$2(reason) {
157
+ if (isPromiseLike$2(reason)) {
153
158
  return reason.then((nextResult) => nextResult);
154
159
  }
155
160
  return {
156
161
  then: (_onFulfilled, onRejected) => {
157
162
  if (typeof onRejected === "function") {
158
163
  try {
159
- return resolvedPromiseLike$3(onRejected(reason));
164
+ return resolvedPromiseLike$2(onRejected(reason));
160
165
  } catch (e) {
161
- return rejectedPromiseLike$3(e);
166
+ return rejectedPromiseLike$2(e);
162
167
  }
163
168
  }
164
- return rejectedPromiseLike$3(reason);
169
+ return rejectedPromiseLike$2(reason);
165
170
  }
166
171
  };
167
172
  }
168
- function isPromiseLike$3(x) {
173
+ function isPromiseLike$2(x) {
169
174
  return typeof (x == null ? void 0 : x.then) === "function";
170
175
  }
171
176
  function stableJSONStringify$2(node) {
@@ -271,6 +276,24 @@ class FetchResponse extends Error {
271
276
  this.statusText = getStatusText(status);
272
277
  }
273
278
  }
279
+ const deeplyFrozen = new WeakSetConstructor();
280
+ function deepFreeze(value) {
281
+ if (typeof value !== "object" || value === null || deeplyFrozen.has(value)) {
282
+ return;
283
+ }
284
+ deeplyFrozen.add(value);
285
+ if (isArray$3(value)) {
286
+ for (let i = 0, len = value.length; i < len; i += 1) {
287
+ deepFreeze(value[i]);
288
+ }
289
+ } else {
290
+ const keys$1 = keys$2(value);
291
+ for (let i = 0, len = keys$1.length; i < len; i += 1) {
292
+ deepFreeze(value[keys$1[i]]);
293
+ }
294
+ }
295
+ freeze(value);
296
+ }
274
297
  class InternalError extends Error {
275
298
  constructor(data) {
276
299
  super();
@@ -285,6 +308,15 @@ class UserVisibleError extends Error {
285
308
  this.type = "user-visible";
286
309
  }
287
310
  }
311
+ function isUserVisibleError$1(error) {
312
+ return error instanceof Error && "type" in error && error.type === "user-visible";
313
+ }
314
+ function logError$1(error) {
315
+ if (isUserVisibleError$1(error)) {
316
+ return;
317
+ }
318
+ console.error("OneStore Command threw an error that we did not expect", error);
319
+ }
288
320
 
289
321
  /*!
290
322
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -341,7 +373,7 @@ let NetworkCommand$1 = class NetworkCommand extends BaseCommand {
341
373
  async afterRequestHooks(_options) {
342
374
  }
343
375
  };
344
- function buildServiceDescriptor$k() {
376
+ function buildServiceDescriptor$r() {
345
377
  return {
346
378
  type: "networkCommandBaseClass",
347
379
  version: "1.0",
@@ -440,10 +472,10 @@ class AuraNetworkCommand extends NetworkCommand$1 {
440
472
  } else if (this.shouldUseFetch()) {
441
473
  return this.convertFetchResponseToData(this.services.fetch(...this.fetchParams));
442
474
  }
443
- return resolvedPromiseLike$3(err$1(toError("Aura/Fetch network services not found")));
475
+ return resolvedPromiseLike$2(err$1(toError("Aura/Fetch network services not found")));
444
476
  }
445
477
  }
446
- function buildServiceDescriptor$j() {
478
+ function buildServiceDescriptor$q() {
447
479
  return {
448
480
  type: "auraNetworkCommandBaseClass",
449
481
  version: "1.0",
@@ -493,41 +525,41 @@ function buildSubscribableResult(result, subscribe, refresh) {
493
525
  return err({ failure: result.error, subscribe, refresh });
494
526
  }
495
527
  }
496
- function resolvedPromiseLike$2(result) {
497
- if (isPromiseLike$2(result)) {
528
+ function resolvedPromiseLike$1(result) {
529
+ if (isPromiseLike$1(result)) {
498
530
  return result.then((nextResult) => nextResult);
499
531
  }
500
532
  return {
501
533
  then: (onFulfilled, _onRejected) => {
502
534
  try {
503
- return resolvedPromiseLike$2(onFulfilled(result));
535
+ return resolvedPromiseLike$1(onFulfilled(result));
504
536
  } catch (e) {
505
537
  if (onFulfilled === void 0) {
506
- return resolvedPromiseLike$2(result);
538
+ return resolvedPromiseLike$1(result);
507
539
  }
508
- return rejectedPromiseLike$2(e);
540
+ return rejectedPromiseLike$1(e);
509
541
  }
510
542
  }
511
543
  };
512
544
  }
513
- function rejectedPromiseLike$2(reason) {
514
- if (isPromiseLike$2(reason)) {
545
+ function rejectedPromiseLike$1(reason) {
546
+ if (isPromiseLike$1(reason)) {
515
547
  return reason.then((nextResult) => nextResult);
516
548
  }
517
549
  return {
518
550
  then: (_onFulfilled, onRejected) => {
519
551
  if (typeof onRejected === "function") {
520
552
  try {
521
- return resolvedPromiseLike$2(onRejected(reason));
553
+ return resolvedPromiseLike$1(onRejected(reason));
522
554
  } catch (e) {
523
- return rejectedPromiseLike$2(e);
555
+ return rejectedPromiseLike$1(e);
524
556
  }
525
557
  }
526
- return rejectedPromiseLike$2(reason);
558
+ return rejectedPromiseLike$1(reason);
527
559
  }
528
560
  };
529
561
  }
530
- function isPromiseLike$2(x) {
562
+ function isPromiseLike$1(x) {
531
563
  return typeof (x == null ? void 0 : x.then) === "function";
532
564
  }
533
565
  function deepEquals$1(x, y) {
@@ -762,7 +794,7 @@ class CacheControlCommand extends BaseCommand {
762
794
  });
763
795
  }
764
796
  }
765
- return resolvedPromiseLike$2(void 0);
797
+ return resolvedPromiseLike$1(void 0);
766
798
  }
767
799
  get operationType() {
768
800
  return "query";
@@ -1038,7 +1070,7 @@ let AuraCacheControlCommand$1 = class AuraCacheControlCommand extends CacheContr
1038
1070
  } else if (this.shouldUseFetch()) {
1039
1071
  return this.convertFetchResponseToData(this.services.fetch(...this.fetchParams));
1040
1072
  }
1041
- return resolvedPromiseLike$3(err$1(toError("Aura/Fetch network services not found")));
1073
+ return resolvedPromiseLike$2(err$1(toError("Aura/Fetch network services not found")));
1042
1074
  }
1043
1075
  coerceAuraErrors(auraErrors) {
1044
1076
  return toError(auraErrors[0]);
@@ -1112,9 +1144,9 @@ class AuraResourceCacheControlCommand extends AuraCacheControlCommand$1 {
1112
1144
  var _a;
1113
1145
  const data = (_a = cache.get(this.buildKey())) == null ? void 0 : _a.value;
1114
1146
  if (data === void 0) {
1115
- return resolvedPromiseLike$3(err$1(new Error("Failed to find data in cache")));
1147
+ return resolvedPromiseLike$2(err$1(new Error("Failed to find data in cache")));
1116
1148
  }
1117
- return resolvedPromiseLike$3(ok$2(data));
1149
+ return resolvedPromiseLike$2(ok$2(data));
1118
1150
  }
1119
1151
  writeToCache(cache, networkResult) {
1120
1152
  if (networkResult.isOk()) {
@@ -1125,13 +1157,13 @@ class AuraResourceCacheControlCommand extends AuraCacheControlCommand$1 {
1125
1157
  }
1126
1158
  });
1127
1159
  }
1128
- return resolvedPromiseLike$3(void 0);
1160
+ return resolvedPromiseLike$2(void 0);
1129
1161
  }
1130
1162
  buildKey() {
1131
1163
  return `{"endpoint":${this.endpoint},"params":${stableJSONStringify$2(this.auraParams)}}`;
1132
1164
  }
1133
1165
  }
1134
- function buildServiceDescriptor$i() {
1166
+ function buildServiceDescriptor$p() {
1135
1167
  return {
1136
1168
  type: "auraResourceCacheControlCommand",
1137
1169
  version: "1.0",
@@ -1181,7 +1213,7 @@ class AuraCacheControlCommand extends CacheControlCommand {
1181
1213
  } else if (this.shouldUseFetch()) {
1182
1214
  return this.convertFetchResponseToData(this.services.fetch(...this.fetchParams));
1183
1215
  }
1184
- return resolvedPromiseLike$3(err$1(toError("Aura/Fetch network services not found")));
1216
+ return resolvedPromiseLike$2(err$1(toError("Aura/Fetch network services not found")));
1185
1217
  }
1186
1218
  coerceAuraErrors(auraErrors) {
1187
1219
  return toError(auraErrors[0]);
@@ -1254,11 +1286,11 @@ class AuraNormalizedCacheControlCommand extends AuraCacheControlCommand {
1254
1286
  readFromCache(cache) {
1255
1287
  const data = this.buildResultType().query(cache, this.buildQuery());
1256
1288
  if (data.isErr()) {
1257
- return resolvedPromiseLike$3(
1289
+ return resolvedPromiseLike$2(
1258
1290
  err$1(new Error(`Failed to build data from type: ${stringify$3(data.error)}`))
1259
1291
  );
1260
1292
  }
1261
- return resolvedPromiseLike$3(ok$2(data.value));
1293
+ return resolvedPromiseLike$2(ok$2(data.value));
1262
1294
  }
1263
1295
  writeToCache(cache, networkResult) {
1264
1296
  if (networkResult.isOk()) {
@@ -1267,10 +1299,10 @@ class AuraNormalizedCacheControlCommand extends AuraCacheControlCommand {
1267
1299
  this.buildWriteInput(networkResult.value)
1268
1300
  );
1269
1301
  }
1270
- return resolvedPromiseLike$3(void 0);
1302
+ return resolvedPromiseLike$2(void 0);
1271
1303
  }
1272
1304
  }
1273
- function buildServiceDescriptor$h() {
1305
+ function buildServiceDescriptor$o() {
1274
1306
  return {
1275
1307
  type: "auraNormalizedCacheControlCommand",
1276
1308
  version: "1.0",
@@ -1343,11 +1375,11 @@ class HttpNormalizedCacheControlCommand extends HttpCacheControlCommand {
1343
1375
  readFromCache(cache) {
1344
1376
  const data = this.buildResultType().query(cache, this.buildQuery());
1345
1377
  if (data.isErr()) {
1346
- return resolvedPromiseLike$3(
1378
+ return resolvedPromiseLike$2(
1347
1379
  err$1(new Error(`Failed to build data from type: ${stringify$3(data.error)}`))
1348
1380
  );
1349
1381
  }
1350
- return resolvedPromiseLike$3(ok$2(data.value));
1382
+ return resolvedPromiseLike$2(ok$2(data.value));
1351
1383
  }
1352
1384
  writeToCache(cache, networkResult) {
1353
1385
  if (networkResult.isOk()) {
@@ -1356,10 +1388,10 @@ class HttpNormalizedCacheControlCommand extends HttpCacheControlCommand {
1356
1388
  this.buildWriteInput(networkResult.value)
1357
1389
  );
1358
1390
  }
1359
- return resolvedPromiseLike$3(void 0);
1391
+ return resolvedPromiseLike$2(void 0);
1360
1392
  }
1361
1393
  }
1362
- function buildServiceDescriptor$g() {
1394
+ function buildServiceDescriptor$n() {
1363
1395
  return {
1364
1396
  type: "httpNormalizedCacheControlCommand",
1365
1397
  version: "1.0",
@@ -1537,7 +1569,7 @@ _FetchNetworkCommand.availableDecorators = {
1537
1569
  abortable: createAbortableDecorator
1538
1570
  };
1539
1571
  let FetchNetworkCommand = _FetchNetworkCommand;
1540
- function buildServiceDescriptor$f() {
1572
+ function buildServiceDescriptor$m() {
1541
1573
  return {
1542
1574
  type: "fetchNetworkCommandBaseClass",
1543
1575
  version: "1.0",
@@ -1573,7 +1605,7 @@ class StreamingCommand extends BaseCommand {
1573
1605
  );
1574
1606
  }
1575
1607
  }
1576
- function buildServiceDescriptor$e() {
1608
+ function buildServiceDescriptor$l() {
1577
1609
  return {
1578
1610
  type: "streamingCommandBaseClass",
1579
1611
  version: "1.0",
@@ -1656,7 +1688,7 @@ class SSEParsingStream extends TransformStream {
1656
1688
  });
1657
1689
  }
1658
1690
  }
1659
- function buildServiceDescriptor$d() {
1691
+ function buildServiceDescriptor$k() {
1660
1692
  return {
1661
1693
  type: "SSECommandBaseClass",
1662
1694
  version: "1.0",
@@ -1707,7 +1739,7 @@ function buildInstrumentCommand(services) {
1707
1739
  };
1708
1740
  };
1709
1741
  }
1710
- function buildServiceDescriptor$c(instrumentation) {
1742
+ function buildServiceDescriptor$j(instrumentation) {
1711
1743
  return {
1712
1744
  type: "instrumentCommand",
1713
1745
  version: "1.0",
@@ -1977,7 +2009,7 @@ class O11yInstrumentation {
1977
2009
  this.metrics = new O11yOTelMetricsAPI(this.services);
1978
2010
  }
1979
2011
  }
1980
- function buildServiceDescriptor$b(logger) {
2012
+ function buildServiceDescriptor$i(logger) {
1981
2013
  return {
1982
2014
  type: "instrumentation",
1983
2015
  version: "1.0",
@@ -2230,7 +2262,7 @@ let DefaultCache$1 = class DefaultCache {
2230
2262
  return new FixedTimeWritableCache$1(this, generatedTime);
2231
2263
  }
2232
2264
  };
2233
- function buildServiceDescriptor$a() {
2265
+ function buildServiceDescriptor$h() {
2234
2266
  return {
2235
2267
  type: "cache",
2236
2268
  version: "1.0",
@@ -2453,7 +2485,7 @@ class CacheController {
2453
2485
  yield* this.services.cacheInclusionPolicy.findAndModify(query, cacheUpdate);
2454
2486
  }
2455
2487
  }
2456
- function buildServiceDescriptor$9(cache, cacheInclusionPolicy, instrumentation) {
2488
+ function buildServiceDescriptor$g(cache, cacheInclusionPolicy, instrumentation) {
2457
2489
  return {
2458
2490
  type: "cacheController",
2459
2491
  version: "1.0",
@@ -2466,48 +2498,6 @@ function buildServiceDescriptor$9(cache, cacheInclusionPolicy, instrumentation)
2466
2498
  * All rights reserved.
2467
2499
  * For full license text, see the LICENSE.txt file
2468
2500
  */
2469
- /*!
2470
- * Copyright (c) 2022, Salesforce, Inc.,
2471
- * All rights reserved.
2472
- * For full license text, see the LICENSE.txt file
2473
- */
2474
- function resolvedPromiseLike$1(result) {
2475
- if (isPromiseLike$1(result)) {
2476
- return result.then((nextResult) => nextResult);
2477
- }
2478
- return {
2479
- then: (onFulfilled, _onRejected) => {
2480
- try {
2481
- return resolvedPromiseLike$1(onFulfilled(result));
2482
- } catch (e) {
2483
- if (onFulfilled === void 0) {
2484
- return resolvedPromiseLike$1(result);
2485
- }
2486
- return rejectedPromiseLike$1(e);
2487
- }
2488
- }
2489
- };
2490
- }
2491
- function rejectedPromiseLike$1(reason) {
2492
- if (isPromiseLike$1(reason)) {
2493
- return reason.then((nextResult) => nextResult);
2494
- }
2495
- return {
2496
- then: (_onFulfilled, onRejected) => {
2497
- if (typeof onRejected === "function") {
2498
- try {
2499
- return resolvedPromiseLike$1(onRejected(reason));
2500
- } catch (e) {
2501
- return rejectedPromiseLike$1(e);
2502
- }
2503
- }
2504
- return rejectedPromiseLike$1(reason);
2505
- }
2506
- };
2507
- }
2508
- function isPromiseLike$1(x) {
2509
- return typeof (x == null ? void 0 : x.then) === "function";
2510
- }
2511
2501
  const EventTypeWildcard = Symbol("EventTypeWildcard");
2512
2502
  class DefaultPubSubService {
2513
2503
  constructor() {
@@ -2535,14 +2525,14 @@ class DefaultPubSubService {
2535
2525
  return;
2536
2526
  }
2537
2527
  const returnVal = subscription.callback.call(subscription, event);
2538
- if (isPromiseLike$1(returnVal)) {
2528
+ if (isPromiseLike$2(returnVal)) {
2539
2529
  promises.push(returnVal);
2540
2530
  }
2541
2531
  });
2542
2532
  if (promises.length > 0) {
2543
2533
  return Promise.all(promises).then(() => void 0);
2544
2534
  }
2545
- return resolvedPromiseLike$1(void 0);
2535
+ return resolvedPromiseLike$2(void 0);
2546
2536
  }
2547
2537
  getSubscriptions(event) {
2548
2538
  const eventTypeSubscriptions = this.subscriptions.get(event.type);
@@ -2563,7 +2553,7 @@ class DefaultPubSubService {
2563
2553
  return matchingSubscriptions;
2564
2554
  }
2565
2555
  }
2566
- function buildServiceDescriptor$8() {
2556
+ function buildServiceDescriptor$f() {
2567
2557
  return {
2568
2558
  type: "pubSub",
2569
2559
  version: "1.0",
@@ -2626,7 +2616,7 @@ class NDJSONParsingStream extends TransformStream {
2626
2616
  });
2627
2617
  }
2628
2618
  }
2629
- function buildServiceDescriptor$7() {
2619
+ function buildServiceDescriptor$e() {
2630
2620
  return {
2631
2621
  type: "NDJSONCommandBaseClass",
2632
2622
  version: "1.0",
@@ -2667,7 +2657,7 @@ function buildServiceDescriptor$7() {
2667
2657
  * };
2668
2658
  * ```
2669
2659
  */
2670
- function buildServiceDescriptor$6(luvio) {
2660
+ function buildServiceDescriptor$d(luvio) {
2671
2661
  return {
2672
2662
  type: 'luvio',
2673
2663
  version: '1.0',
@@ -2676,7 +2666,7 @@ function buildServiceDescriptor$6(luvio) {
2676
2666
  },
2677
2667
  };
2678
2668
  }
2679
- // version: 1.401.0-c620f9ffed
2669
+ // version: 1.403.0-5476a05446
2680
2670
 
2681
2671
  /*!
2682
2672
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -2798,7 +2788,7 @@ class AuraGraphQLNormalizedCacheControlCommand extends AuraNormalizedCacheContro
2798
2788
  return buildSubscribableResult$1(result, this.buildSubscribe(), () => this.refresh());
2799
2789
  });
2800
2790
  }
2801
- return resolvedPromiseLike$3(
2791
+ return resolvedPromiseLike$2(
2802
2792
  buildSubscribableResult$1(
2803
2793
  err$1(toError("Aura/Fetch network services not found")),
2804
2794
  this.buildSubscribe(),
@@ -2840,7 +2830,7 @@ class AuraGraphQLNormalizedCacheControlCommand extends AuraNormalizedCacheContro
2840
2830
  });
2841
2831
  }
2842
2832
  }
2843
- function buildServiceDescriptor$5() {
2833
+ function buildServiceDescriptor$c() {
2844
2834
  return {
2845
2835
  type: "auraGraphQLNormalizedCacheControlCommand",
2846
2836
  version: "1.0",
@@ -2958,7 +2948,7 @@ class HttpGraphQLNormalizedCacheControlCommand extends HttpNormalizedCacheContro
2958
2948
  });
2959
2949
  }
2960
2950
  }
2961
- function buildServiceDescriptor$4() {
2951
+ function buildServiceDescriptor$b() {
2962
2952
  return {
2963
2953
  type: "httpGraphQLNormalizedCacheControlCommand",
2964
2954
  version: "1.0",
@@ -2982,7 +2972,7 @@ class FeatureFlagsService {
2982
2972
  return this.flags.get(flagName) || defaultValue;
2983
2973
  }
2984
2974
  }
2985
- function buildServiceDescriptor$3() {
2975
+ function buildServiceDescriptor$a() {
2986
2976
  return {
2987
2977
  version: "1.0",
2988
2978
  service: new FeatureFlagsService(),
@@ -3004,7 +2994,7 @@ function buildServiceDescriptor$3() {
3004
2994
  * *******************************************************************************************
3005
2995
  */
3006
2996
  /* proxy-compat-disable */
3007
- function buildServiceDescriptor$2(notifyRecordUpdateAvailable, getNormalizedLuvioRecord) {
2997
+ function buildServiceDescriptor$9(notifyRecordUpdateAvailable, getNormalizedLuvioRecord) {
3008
2998
  return {
3009
2999
  type: 'luvioUiapiRecords',
3010
3000
  version: '1.0',
@@ -3014,7 +3004,7 @@ function buildServiceDescriptor$2(notifyRecordUpdateAvailable, getNormalizedLuvi
3014
3004
  },
3015
3005
  };
3016
3006
  }
3017
- // version: 1.401.0-c620f9ffed
3007
+ // version: 1.403.0-5476a05446
3018
3008
 
3019
3009
  /*!
3020
3010
  * Copyright (c) 2022, Salesforce, Inc.,
@@ -3037,9 +3027,12 @@ class RetryService {
3037
3027
  totalElapsedMs: Date.now() - startTime,
3038
3028
  lastResult: result
3039
3029
  };
3040
- while (policy.shouldRetry(result, context)) {
3041
- const delay = policy.calculateDelay(result, context);
3030
+ while (await policy.shouldRetry(result, context)) {
3031
+ const delay = await policy.calculateDelay(result, context);
3042
3032
  await this.delay(delay);
3033
+ if (policy.prepareRetry) {
3034
+ await policy.prepareRetry(result, context);
3035
+ }
3043
3036
  attempt++;
3044
3037
  result = await operation();
3045
3038
  context = {
@@ -3058,7 +3051,109 @@ class RetryService {
3058
3051
  }
3059
3052
  class RetryPolicy {
3060
3053
  }
3061
- function buildServiceDescriptor$1(defaultRetryPolicy) {
3054
+ class ComposedRetryPolicy extends RetryPolicy {
3055
+ constructor(policies) {
3056
+ super();
3057
+ this.policies = policies;
3058
+ }
3059
+ /**
3060
+ * Returns true if any of the composed policies want to retry.
3061
+ *
3062
+ * Uses OR logic: if ANY policy returns true, this returns true.
3063
+ * Policies are checked in order and evaluation short-circuits on the first match.
3064
+ */
3065
+ async shouldRetry(result, context) {
3066
+ for (const policy of this.policies) {
3067
+ if (await policy.shouldRetry(result, context)) {
3068
+ return true;
3069
+ }
3070
+ }
3071
+ return false;
3072
+ }
3073
+ /**
3074
+ * Returns the delay from the first policy that wants to retry.
3075
+ *
3076
+ * If multiple policies want to retry, only the FIRST policy's delay is used.
3077
+ * Policy order in the constructor array determines priority.
3078
+ * If no policy wants to retry, returns 0.
3079
+ *
3080
+ * @example
3081
+ * ```typescript
3082
+ * // If both PolicyA (1000ms) and PolicyB (5000ms) want to retry:
3083
+ * const composed = new ComposedRetryPolicy([policyA, policyB]);
3084
+ * composed.calculateDelay(result, context); // Returns 1000ms (PolicyA wins)
3085
+ * ```
3086
+ */
3087
+ async calculateDelay(result, context) {
3088
+ for (const policy of this.policies) {
3089
+ if (await policy.shouldRetry(result, context)) {
3090
+ return policy.calculateDelay(result, context);
3091
+ }
3092
+ }
3093
+ return 0;
3094
+ }
3095
+ /**
3096
+ * Calls prepareRetry on policies that both:
3097
+ * 1. Implement the prepareRetry hook, AND
3098
+ * 2. Returned true from shouldRetry for this result
3099
+ *
3100
+ * This allows only the matching policies to perform preparation work (e.g., token refresh).
3101
+ * All matching prepareRetry calls run in parallel for efficiency.
3102
+ *
3103
+ * **Important**: prepareRetry only runs on policies that matched shouldRetry. This ensures
3104
+ * you don't perform unnecessary work or side effects for unrelated retry conditions.
3105
+ *
3106
+ * **Note**: If multiple policies match and have prepareRetry, ensure they don't have
3107
+ * conflicting side effects since they run in parallel.
3108
+ *
3109
+ * @example
3110
+ * ```typescript
3111
+ * // Status 401 occurs
3112
+ * const composed = new ComposedRetryPolicy([
3113
+ * authPolicy, // shouldRetry(401) → true, has prepareRetry
3114
+ * throttlePolicy, // shouldRetry(401) → false, has prepareRetry
3115
+ * ]);
3116
+ *
3117
+ * await composed.prepareRetry(result, context);
3118
+ * // → Only authPolicy.prepareRetry() runs (because it matched)
3119
+ * // → throttlePolicy.prepareRetry() does NOT run (didn't match)
3120
+ * ```
3121
+ */
3122
+ async prepareRetry(result, context) {
3123
+ const matchingPolicies = [];
3124
+ for (const policy of this.policies) {
3125
+ if (policy.prepareRetry !== void 0 && await policy.shouldRetry(result, context)) {
3126
+ matchingPolicies.push(policy);
3127
+ }
3128
+ }
3129
+ if (matchingPolicies.length > 0) {
3130
+ await Promise.all(
3131
+ matchingPolicies.map((policy) => policy.prepareRetry(result, context))
3132
+ );
3133
+ }
3134
+ }
3135
+ /**
3136
+ * Returns all composed policies.
3137
+ * Useful for accessing or configuring individual policies after composition.
3138
+ */
3139
+ getPolicies() {
3140
+ return this.policies;
3141
+ }
3142
+ /**
3143
+ * Helper to get a specific policy by type.
3144
+ * Useful for calling policy-specific methods after composition.
3145
+ *
3146
+ * @example
3147
+ * ```typescript
3148
+ * const csrfPolicy = composedPolicy.getPolicyByType(CsrfTokenRetryPolicy);
3149
+ * csrfPolicy?.setRequestContext(mutableRequest);
3150
+ * ```
3151
+ */
3152
+ getPolicyByType(policyType) {
3153
+ return this.policies.find((policy) => policy instanceof policyType);
3154
+ }
3155
+ }
3156
+ function buildServiceDescriptor$8(defaultRetryPolicy) {
3062
3157
  return {
3063
3158
  version: "1.0",
3064
3159
  service: new RetryService(defaultRetryPolicy),
@@ -3071,898 +3166,1509 @@ function buildServiceDescriptor$1(defaultRetryPolicy) {
3071
3166
  * All rights reserved.
3072
3167
  * For full license text, see the LICENSE.txt file
3073
3168
  */
3074
- function e$1(e2) {
3075
- this.message = e2;
3169
+ function isUserVisibleError(error) {
3170
+ return error instanceof Error && "type" in error && error.type === "user-visible";
3076
3171
  }
3077
- e$1.prototype = new Error(), e$1.prototype.name = "InvalidCharacterError";
3078
- var r = "undefined" != typeof window && window.atob && window.atob.bind(window) || function(r2) {
3079
- var t2 = String(r2).replace(/=+$/, "");
3080
- if (t2.length % 4 == 1) throw new e$1("'atob' failed: The string to be decoded is not correctly encoded.");
3081
- for (var n2, o2, a = 0, i = 0, c = ""; o2 = t2.charAt(i++); ~o2 && (n2 = a % 4 ? 64 * n2 + o2 : o2, a++ % 4) ? c += String.fromCharCode(255 & n2 >> (-2 * a & 6)) : 0) o2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o2);
3082
- return c;
3083
- };
3084
- function t(e2) {
3085
- var t2 = e2.replace(/-/g, "+").replace(/_/g, "/");
3086
- switch (t2.length % 4) {
3087
- case 0:
3088
- break;
3089
- case 2:
3090
- t2 += "==";
3091
- break;
3092
- case 3:
3093
- t2 += "=";
3094
- break;
3095
- default:
3096
- throw "Illegal base64url string!";
3097
- }
3098
- try {
3099
- return (function(e3) {
3100
- return decodeURIComponent(r(e3).replace(/(.)/g, (function(e4, r2) {
3101
- var t3 = r2.charCodeAt(0).toString(16).toUpperCase();
3102
- return t3.length < 2 && (t3 = "0" + t3), "%" + t3;
3103
- })));
3104
- })(t2);
3105
- } catch (e3) {
3106
- return r(t2);
3107
- }
3172
+ function throwUserlandError(error) {
3173
+ logError(error);
3174
+ throw buildUserlandError(error);
3108
3175
  }
3109
- function n$1(e2) {
3110
- this.message = e2;
3176
+ function emitError(callback, error) {
3177
+ logError(error);
3178
+ callback({ data: void 0, error: buildUserlandError(error) });
3111
3179
  }
3112
- function o(e2, r2) {
3113
- if ("string" != typeof e2) throw new n$1("Invalid token specified");
3114
- var o2 = true === (r2 = r2 || {}).header ? 0 : 1;
3115
- try {
3116
- return JSON.parse(t(e2.split(".")[o2]));
3117
- } catch (e3) {
3118
- throw new n$1("Invalid token specified: " + e3.message);
3180
+ function buildUserlandError(error) {
3181
+ if (isUserVisibleError(error)) {
3182
+ return error.data;
3119
3183
  }
3184
+ return new Error("Internal error in Lightning Data Service adapter occurred.");
3120
3185
  }
3121
- n$1.prototype = new Error(), n$1.prototype.name = "InvalidTokenError";
3186
+ function logError(error) {
3187
+ if (isUserVisibleError(error)) {
3188
+ return;
3189
+ }
3190
+ console.error("OneStore Command threw an error that we did not expect", error);
3191
+ }
3192
+
3122
3193
  /*!
3123
3194
  * Copyright (c) 2022, Salesforce, Inc.,
3124
3195
  * All rights reserved.
3125
3196
  * For full license text, see the LICENSE.txt file
3126
3197
  */
3127
- const LogLevelMap = {
3128
- TRACE: 4,
3129
- DEBUG: 3,
3130
- INFO: 2,
3131
- WARN: 1,
3132
- ERROR: 0
3133
- };
3134
- class ConsoleLogger {
3135
- constructor(level = "WARN", printer = console.log, formatter = (level2, message) => `${level2}: ${message}`) {
3136
- this.level = level;
3137
- this.printer = printer;
3138
- this.formatter = formatter;
3139
- this.messages = [];
3140
- }
3141
- trace(message) {
3142
- this.log("TRACE", message);
3143
- }
3144
- debug(message) {
3145
- this.log("DEBUG", message);
3146
- }
3147
- info(message) {
3148
- this.log("INFO", message);
3149
- }
3150
- warn(message) {
3151
- this.log("WARN", message);
3198
+ function buildBaseImperativeInvoker(getCommand, transformResult) {
3199
+ return async (...params) => {
3200
+ const command = getCommand({ params, assertIsValid });
3201
+ try {
3202
+ return command.execute().then((result) => transformResult(result));
3203
+ } catch (error) {
3204
+ throwUserlandError(error);
3205
+ }
3206
+ };
3207
+ }
3208
+ const supportedCachePolicyTypes = ["no-cache", "only-if-cached"];
3209
+ function requestContextIsSupportedCachePolicy(requestContext) {
3210
+ return typeof requestContext === "object" && requestContext !== null && "cachePolicy" in requestContext && typeof requestContext.cachePolicy === "object" && requestContext.cachePolicy !== null && "type" in requestContext.cachePolicy && typeof requestContext.cachePolicy.type === "string" && supportedCachePolicyTypes.includes(
3211
+ requestContext.cachePolicy.type
3212
+ );
3213
+ }
3214
+ function getOverridesForLegacyRequestContext(requestContext) {
3215
+ if (requestContextIsSupportedCachePolicy(requestContext)) {
3216
+ return { cacheControlConfig: { type: requestContext.cachePolicy.type } };
3152
3217
  }
3153
- error(message) {
3154
- this.log("ERROR", message);
3218
+ return {};
3219
+ }
3220
+ function handleEmit(res, callback) {
3221
+ const consumerEmittedData = {
3222
+ data: void 0,
3223
+ errors: void 0
3224
+ };
3225
+ if (res.isOk()) {
3226
+ consumerEmittedData.data = res.value.data;
3227
+ } else {
3228
+ const { data, errors } = toGraphQLResponseFromFailure$1(res.error);
3229
+ consumerEmittedData.data = data;
3230
+ consumerEmittedData.errors = errors;
3155
3231
  }
3156
- log(level, message) {
3157
- if (LogLevelMap[level] > LogLevelMap[this.level]) {
3158
- return;
3159
- }
3160
- this.printer(this.formatter(level, message));
3232
+ callback(consumerEmittedData);
3233
+ }
3234
+ function toGraphQLResponseFromFailure$1(failure) {
3235
+ if (isUserVisibleError$1(failure)) {
3236
+ return {
3237
+ data: failure.data.data,
3238
+ errors: failure.data.errors
3239
+ };
3161
3240
  }
3241
+ logError$1(failure);
3242
+ return {
3243
+ data: void 0,
3244
+ errors: [{ message: "Internal error in GraphQL adapter occurred", locations: [] }]
3245
+ };
3162
3246
  }
3163
- function loggerService(level, printer, formatter) {
3164
- return new ConsoleLogger(level, printer, formatter);
3247
+ class DefaultImperativeBindingsService {
3248
+ bind(getCommand) {
3249
+ return buildBaseImperativeInvoker(getCommand, (result) => {
3250
+ if (result.isOk()) {
3251
+ deepFreeze(result.value);
3252
+ return isSubscribableResult(result) ? result.value.data : result.value;
3253
+ }
3254
+ throw toError(isSubscribableResult(result) ? result.error.failure : result.error);
3255
+ });
3256
+ }
3165
3257
  }
3166
- class JwtToken {
3167
- /**
3168
- * Create a new JwtToken.
3169
- *
3170
- * @param _token - The JWT string.
3171
- * @param _decodedInfo - The decoded information from the JWT.
3172
- * @param _extraInfo - Any additional information associated with the JWT.
3173
- */
3174
- constructor(_token, _decodedInfo, _extraInfo) {
3175
- this._token = _token;
3176
- this._decodedInfo = _decodedInfo;
3177
- this._extraInfo = _extraInfo;
3178
- }
3179
- /**
3180
- * Get the JWT string.
3181
- *
3182
- * @returns The JWT string.
3183
- */
3184
- get token() {
3185
- return this._token;
3186
- }
3187
- /**
3188
- * Get the additional information associated with the JWT.
3189
- *
3190
- * @returns The additional information.
3191
- */
3192
- get extraInfo() {
3193
- return this._extraInfo;
3194
- }
3195
- /**
3196
- * Get the decoded information from the JWT.
3197
- *
3198
- * @returns The decoded information.
3199
- */
3200
- get decodedInfo() {
3201
- return this._decodedInfo;
3202
- }
3203
- /**
3204
- * Get the remaining time in seconds until the JWT expires.
3205
- *
3206
- * @returns The remaining time in seconds.
3207
- */
3208
- get tokenRemainingSeconds() {
3209
- return this.decodedInfo.exp - Date.now() / 1e3;
3210
- }
3211
- /**
3212
- * Check if the JWT is expired.
3213
- *
3214
- * @returns True if the JWT is expired, false otherwise.
3215
- */
3216
- get isExpired() {
3217
- return this.tokenRemainingSeconds <= 0;
3218
- }
3258
+ function buildServiceDescriptor$6() {
3259
+ return {
3260
+ type: "defaultImperativeBindings",
3261
+ version: "1.0",
3262
+ service: new DefaultImperativeBindingsService()
3263
+ };
3219
3264
  }
3220
- let defaultLogger = {
3221
- trace: () => {
3222
- },
3223
- debug: () => {
3224
- },
3225
- info: () => {
3226
- },
3227
- warn: () => {
3228
- },
3229
- error: () => {
3265
+ class QueryImperativeBindingsService {
3266
+ bind(getCommand) {
3267
+ return buildBaseImperativeInvoker(getCommand, (result) => {
3268
+ if (result.isOk()) {
3269
+ deepFreeze(result.value);
3270
+ return isSubscribableResult(result) ? { data: result.value.data } : { data: result.value };
3271
+ }
3272
+ throw toError(isSubscribableResult(result) ? result.error.failure : result.error);
3273
+ });
3230
3274
  }
3231
- };
3232
- if (process.env.NODE_ENV !== "production") {
3233
- defaultLogger = loggerService();
3234
3275
  }
3235
- function computeDecodedInfo(token, defaultTokenTTLInSeconds, logger) {
3236
- const decodedInfo = o(token);
3237
- if (decodedInfo.exp === void 0) {
3238
- logger.warn(`"exp" claim is not present in the provided token.`);
3239
- decodedInfo.exp = Date.now() / 1e3 + defaultTokenTTLInSeconds;
3240
- }
3241
- return decodedInfo;
3276
+ function buildServiceDescriptor$5() {
3277
+ return {
3278
+ type: "queryImperativeBindings",
3279
+ version: "1.0",
3280
+ service: new QueryImperativeBindingsService()
3281
+ };
3242
3282
  }
3243
- class JwtRepository {
3244
- /**
3245
- * @param limitInSeconds - Time in seconds before the token's expiry to notify observers.
3246
- * @param defaultTokenTTLInSeconds - Default token expiry time in seconds if "exp" claim is not present in token.
3247
- * @param logger - Logger for logging warnings and errors.
3248
- */
3249
- constructor(limitInSeconds = 5, defaultTokenTTLInSeconds = 120, logger = defaultLogger) {
3250
- this.limitInSeconds = limitInSeconds;
3251
- this.defaultTokenTTLInSeconds = defaultTokenTTLInSeconds;
3252
- this.logger = logger;
3253
- this.observers = [];
3254
- }
3255
- /**
3256
- * Get the current token.
3257
- */
3258
- get token() {
3259
- return this._token;
3260
- }
3261
- /**
3262
- * Set the current token.
3263
- *
3264
- * @param token - JWT token as a string.
3265
- * @param extraInfo - Optional extra information.
3266
- */
3267
- setToken(token, extraInfo) {
3268
- const decodedInfo = computeDecodedInfo(
3269
- token,
3270
- this.defaultTokenTTLInSeconds,
3271
- this.logger
3283
+ class SubscribableImperativeBindingsService {
3284
+ bind(getCommand, exposeRefresh = false) {
3285
+ return buildBaseImperativeInvoker(
3286
+ getCommand,
3287
+ (result) => this.transformResult(result, exposeRefresh)
3272
3288
  );
3273
- this._token = new JwtToken(token, decodedInfo, extraInfo);
3274
- this.observeTokenExpiration();
3275
- return this._token;
3276
3289
  }
3277
- /**
3278
- * Remove the current token.
3279
- */
3280
- removeToken() {
3281
- this._token = void 0;
3282
- this.clearTimeoutHandler();
3290
+ transformResult(result, exposeRefresh = false) {
3291
+ if (!isSubscribableResult(result)) {
3292
+ console.error(
3293
+ "Non-subscribable result encountered - please use correct operation type"
3294
+ );
3295
+ throw new Error("Internal error in Lightning Data Service adapter occurred");
3296
+ }
3297
+ if (result.isOk()) {
3298
+ deepFreeze(result.value.data);
3299
+ const api = {
3300
+ data: result.value.data,
3301
+ subscribe: (cb) => {
3302
+ result.value.subscribe((result2) => {
3303
+ if (result2.isErr()) {
3304
+ return cb({ data: void 0, error: toError(result2.error) });
3305
+ }
3306
+ return cb({ data: result2.value, error: void 0 });
3307
+ });
3308
+ }
3309
+ };
3310
+ if (exposeRefresh) {
3311
+ return {
3312
+ ...api,
3313
+ refresh: () => {
3314
+ return result.value.refresh().then((res) => {
3315
+ if (res.isOk()) {
3316
+ return void 0;
3317
+ }
3318
+ throw res.error;
3319
+ });
3320
+ }
3321
+ };
3322
+ } else {
3323
+ return api;
3324
+ }
3325
+ } else {
3326
+ throw toError(result.error.failure);
3327
+ }
3283
3328
  }
3284
- /**
3285
- * Subscribe to the token nearing its expiration.
3286
- *
3287
- * @param cb - Callback function to execute when token is nearing expiration.
3288
- */
3289
- subscribeToTokenNearExpiration(cb) {
3290
- this.observers.push(cb);
3291
- this.observeTokenExpiration();
3292
- return () => {
3293
- this.observers = this.observers.filter((observer) => observer !== cb);
3329
+ }
3330
+ function buildServiceDescriptor$4() {
3331
+ return {
3332
+ type: "subscribableImperativeBindings",
3333
+ version: "1.0",
3334
+ service: new SubscribableImperativeBindingsService()
3335
+ };
3336
+ }
3337
+ class LegacyImperativeBindingsService {
3338
+ bind(getCommand) {
3339
+ const invoke = async (config, requestContext, callback) => {
3340
+ const command = getCommand({ config, assertIsValid });
3341
+ try {
3342
+ const overrides = getOverridesForLegacyRequestContext(requestContext);
3343
+ const result = await command.execute(overrides);
3344
+ if (result.isOk()) {
3345
+ deepFreeze(result.value);
3346
+ callback({ data: result.value.data, error: void 0 });
3347
+ } else {
3348
+ callback({ data: void 0, error: toError(result.error.failure) });
3349
+ }
3350
+ } catch (error) {
3351
+ emitError(callback, error);
3352
+ }
3353
+ };
3354
+ const subscribe = (config, requestContext, callback) => {
3355
+ const command = getCommand({ config, assertIsValid });
3356
+ let unsubscribe = () => {
3357
+ };
3358
+ try {
3359
+ const overrides = getOverridesForLegacyRequestContext(requestContext);
3360
+ command.execute(overrides).then(
3361
+ (result) => {
3362
+ if (!result.isOk()) {
3363
+ callback({ data: void 0, error: toError(result.error.failure) });
3364
+ return;
3365
+ }
3366
+ unsubscribe = result.value.subscribe((res) => {
3367
+ if (res.isOk()) {
3368
+ callback({ data: res.value, error: void 0 });
3369
+ } else {
3370
+ callback({ data: void 0, error: toError(res.error) });
3371
+ }
3372
+ });
3373
+ callback({ data: result.value.data, error: void 0 });
3374
+ },
3375
+ (e) => {
3376
+ emitError(callback, e);
3377
+ }
3378
+ );
3379
+ } catch (e) {
3380
+ emitError(callback, e);
3381
+ }
3382
+ return () => {
3383
+ unsubscribe();
3384
+ };
3294
3385
  };
3386
+ return { invoke, subscribe };
3295
3387
  }
3296
- /**
3297
- * Clear the timeout handler.
3298
- */
3299
- clearTimeoutHandler() {
3300
- if (this.timeoutHandler !== void 0) {
3301
- clearTimeout(this.timeoutHandler);
3302
- }
3388
+ }
3389
+ function buildServiceDescriptor$3() {
3390
+ return {
3391
+ type: "legacyImperativeBindings",
3392
+ version: "1.0",
3393
+ service: new LegacyImperativeBindingsService()
3394
+ };
3395
+ }
3396
+ class GraphQLImperativeBindingsService {
3397
+ bind(getCommand, exposeRefresh = false) {
3398
+ return async (...params) => {
3399
+ try {
3400
+ if (params.length) {
3401
+ params[0] = wrapConfigAndVerify(params[0]);
3402
+ }
3403
+ return await buildBaseImperativeInvoker(getCommand, (result) => this.transformResult(result, exposeRefresh))(...params);
3404
+ } catch (error) {
3405
+ logError$1(error);
3406
+ return {
3407
+ data: void 0,
3408
+ errors: [
3409
+ { message: "Internal error in GraphQL adapter occurred", locations: [] }
3410
+ ]
3411
+ };
3412
+ }
3413
+ };
3303
3414
  }
3304
- /**
3305
- * Observe and handle token expiration.
3306
- */
3307
- observeTokenExpiration() {
3308
- this.clearTimeoutHandler();
3309
- if (this.observers.length === 0 || this.token === void 0) {
3310
- return;
3415
+ transformResult(result, exposeRefresh = false) {
3416
+ const consumerEmittedData = {
3417
+ data: void 0,
3418
+ errors: void 0
3419
+ };
3420
+ if (result.isOk()) {
3421
+ deepFreeze(result.value);
3422
+ consumerEmittedData.data = result.value.data.data;
3423
+ consumerEmittedData.subscribe = (cb) => {
3424
+ result.value.subscribe((res) => {
3425
+ const consumerEmittedData2 = {
3426
+ data: void 0,
3427
+ errors: void 0
3428
+ };
3429
+ if (res.isOk()) {
3430
+ consumerEmittedData2.data = res.value.data;
3431
+ } else {
3432
+ if (isUserVisibleError$1(res.error)) {
3433
+ consumerEmittedData2.data = res.error.data.data;
3434
+ consumerEmittedData2.errors = res.error.data.errors;
3435
+ } else {
3436
+ logError$1(res.error);
3437
+ consumerEmittedData2.errors = [
3438
+ {
3439
+ message: "Internal error in GraphQL adapter occurred",
3440
+ locations: []
3441
+ }
3442
+ ];
3443
+ }
3444
+ }
3445
+ cb(consumerEmittedData2);
3446
+ });
3447
+ };
3448
+ if (exposeRefresh) {
3449
+ consumerEmittedData.refresh = () => {
3450
+ return new Promise((resolve, reject) => {
3451
+ try {
3452
+ result.value.refresh().then((res) => {
3453
+ if (res.isOk()) {
3454
+ resolve();
3455
+ } else {
3456
+ reject(
3457
+ new Error(
3458
+ "Internal error in GraphQL adapter occurred: Failed to refresh GraphQL data"
3459
+ )
3460
+ );
3461
+ }
3462
+ });
3463
+ } catch (error) {
3464
+ logError$1(error);
3465
+ reject(
3466
+ new Error(
3467
+ "Internal error in GraphQL adapter occurred: Failed to refresh GraphQL data"
3468
+ )
3469
+ );
3470
+ }
3471
+ });
3472
+ };
3473
+ }
3474
+ } else {
3475
+ const resp = toGraphQLResponseFromFailure$1(result.error.failure);
3476
+ consumerEmittedData.data = resp.data;
3477
+ consumerEmittedData.errors = resp.errors;
3311
3478
  }
3312
- this.timeoutHandler = setTimeout(
3313
- () => this.notifyTokenIsExpiring(),
3314
- this.computeTimeoutTimeInMs()
3315
- );
3316
- }
3317
- /**
3318
- * Compute the timeout time in milliseconds.
3319
- */
3320
- computeTimeoutTimeInMs() {
3321
- const remainingSeconds = this.token.tokenRemainingSeconds;
3322
- let timeoutTimeInSeconds = remainingSeconds - this.limitInSeconds;
3323
- return timeoutTimeInSeconds < 0 ? 0 : timeoutTimeInSeconds * 1e3;
3479
+ return consumerEmittedData;
3324
3480
  }
3325
- /**
3326
- * Notify all observers that the token is expiring.
3327
- */
3328
- notifyTokenIsExpiring() {
3329
- this.observers.forEach((cb) => {
3481
+ }
3482
+ function buildServiceDescriptor$2$1() {
3483
+ return {
3484
+ type: "graphQLImperativeBindings",
3485
+ version: "1.0",
3486
+ service: new GraphQLImperativeBindingsService()
3487
+ };
3488
+ }
3489
+ class GraphQLLegacyImperativeBindingsService {
3490
+ bind(getCommand) {
3491
+ const invoke = async (config, requestContext, callback) => {
3492
+ config = wrapConfigAndVerify(config);
3493
+ const command = getCommand({ config, assertIsValid });
3330
3494
  try {
3331
- cb.call(void 0, this.token);
3332
- } catch (e2) {
3333
- this.logger.error(e2.message);
3495
+ const overrides = getOverridesForLegacyRequestContext(requestContext);
3496
+ const result = await command.execute(overrides);
3497
+ const consumerEmittedData = {
3498
+ data: void 0,
3499
+ errors: void 0
3500
+ };
3501
+ if (result.isOk()) {
3502
+ deepFreeze(result.value);
3503
+ consumerEmittedData.data = result.value.data.data;
3504
+ } else {
3505
+ const { data, errors } = toGraphQLResponseFromFailure$1(result.error.failure);
3506
+ consumerEmittedData.data = data;
3507
+ consumerEmittedData.errors = errors;
3508
+ }
3509
+ callback(consumerEmittedData);
3510
+ } catch (error) {
3511
+ logError$1(error);
3512
+ callback({
3513
+ data: void 0,
3514
+ errors: [
3515
+ { message: "Internal error in GraphQL adapter occurred", locations: [] }
3516
+ ]
3517
+ });
3334
3518
  }
3335
- });
3519
+ };
3520
+ const subscribe = (config, requestContext, callback) => {
3521
+ config = wrapConfigAndVerify(config);
3522
+ const command = getCommand({ config, assertIsValid });
3523
+ let unsubscribe = () => {
3524
+ };
3525
+ const overrides = getOverridesForLegacyRequestContext(requestContext);
3526
+ command.execute(overrides).then((result) => {
3527
+ const consumerEmittedData = {
3528
+ data: void 0,
3529
+ errors: void 0
3530
+ };
3531
+ if (result.isOk()) {
3532
+ deepFreeze(result.value);
3533
+ consumerEmittedData.data = result.value.data.data;
3534
+ unsubscribe = result.value.subscribe(
3535
+ (res) => {
3536
+ handleEmit(res, callback);
3537
+ }
3538
+ );
3539
+ } else {
3540
+ const { data, errors } = toGraphQLResponseFromFailure$1(result.error.failure);
3541
+ consumerEmittedData.data = data;
3542
+ consumerEmittedData.errors = errors;
3543
+ unsubscribe = result.error.subscribe(
3544
+ (res) => {
3545
+ handleEmit(res, callback);
3546
+ }
3547
+ );
3548
+ }
3549
+ callback(consumerEmittedData);
3550
+ });
3551
+ return () => {
3552
+ unsubscribe();
3553
+ };
3554
+ };
3555
+ return { invoke, subscribe };
3336
3556
  }
3337
3557
  }
3338
- class JwtManager {
3339
- /**
3340
- * Constructor for JwtManager class.
3341
- *
3342
- * @param {JwtRepository<T, ExtraInfo>} jwtRepository JwtRepository instance used for token management.
3343
- * @param {JwtResolver<ExtraInfo>} resolver JwtResolver instance used for token retrieval.
3344
- * @param {JwtManagerOptions} options JwtManagerOptions bag to customize behavior.
3345
- */
3346
- constructor(jwtRepository, resolver, options) {
3347
- this.jwtRepository = jwtRepository;
3348
- this.resolver = resolver;
3349
- if (options == null ? void 0 : options.keepTokenUpdated) {
3350
- jwtRepository.subscribeToTokenNearExpiration(() => this.refreshToken());
3351
- }
3352
- }
3353
- /**
3354
- * Method to get a JWT token.
3355
- * If there's a token request in progress, it will return the Promise of this request.
3356
- * If the current token is undefined or expired, it will initiate a token refresh.
3357
- * Otherwise, it will return the current token.
3358
- *
3359
- * @returns {JwtToken<T, ExtraInfo> | Promise<JwtToken<T, ExtraInfo>>} The current token or the Promise of a token request.
3360
- */
3361
- getJwt() {
3362
- if (this.inflightPromise) {
3363
- return this.inflightPromise;
3364
- }
3365
- const token = this.jwtRepository.token;
3366
- if (token === void 0 || token.isExpired) {
3367
- return this.refreshToken();
3368
- }
3369
- return token;
3370
- }
3371
- /**
3372
- * Method to refresh a JWT token.
3373
- * If a refresh request is already in progress, it will return the Promise of this request.
3374
- * Otherwise, it will start a new refresh request and return its Promise.
3375
- *
3376
- * @returns {Promise<JwtToken<T, ExtraInfo>>} Promise of the refreshed token.
3377
- */
3378
- refreshToken() {
3379
- if (this.inflightPromise === void 0) {
3380
- this.inflightPromise = new Promise((resolve, reject) => {
3381
- this.resolver.getJwt().then(({ jwt, extraInfo }) => {
3382
- this.inflightPromise = void 0;
3383
- const token = this.jwtRepository.setToken(jwt, extraInfo);
3384
- resolve(token);
3385
- }).catch((reason) => {
3386
- this.inflightPromise = void 0;
3387
- reject(reason);
3388
- });
3389
- });
3390
- }
3391
- return this.inflightPromise;
3392
- }
3393
- /**
3394
- * Method to check if a token refresh is in progress.
3395
- *
3396
- * @returns {boolean} true if a token refresh is in progress, false otherwise.
3397
- */
3398
- get isRefreshingToken() {
3399
- return this.inflightPromise !== void 0;
3558
+ function buildServiceDescriptor$1$1() {
3559
+ return {
3560
+ type: "graphQLLegacyImperativeBindings",
3561
+ version: "1.0",
3562
+ service: new GraphQLLegacyImperativeBindingsService()
3563
+ };
3564
+ }
3565
+ class GraphQLMutationBindingsService {
3566
+ bind(getCommand) {
3567
+ return async (...params) => {
3568
+ try {
3569
+ if (params.length) {
3570
+ params[0] = wrapConfigAndVerify(params[0], {
3571
+ acceptedOperations: ["mutation"]
3572
+ });
3573
+ }
3574
+ const command = getCommand({ params, assertIsValid });
3575
+ const result = await command.execute({ cacheControlConfig: { type: "no-cache" } });
3576
+ if (result.isOk()) {
3577
+ deepFreeze(result.value);
3578
+ return result.value.data;
3579
+ } else {
3580
+ return toGraphQLResponseFromFailure$1(result.error.failure);
3581
+ }
3582
+ } catch (error) {
3583
+ logError$1(error);
3584
+ return {
3585
+ data: void 0,
3586
+ errors: [
3587
+ { message: "Internal error in GraphQL adapter occurred", locations: [] }
3588
+ ]
3589
+ };
3590
+ }
3591
+ };
3400
3592
  }
3401
3593
  }
3594
+ function buildServiceDescriptor$7() {
3595
+ return {
3596
+ type: "graphQLMutationBindings",
3597
+ version: "1.0",
3598
+ service: new GraphQLMutationBindingsService()
3599
+ };
3600
+ }
3402
3601
 
3403
3602
  /*!
3404
3603
  * Copyright (c) 2022, Salesforce, Inc.,
3405
3604
  * All rights reserved.
3406
3605
  * For full license text, see the LICENSE.txt file
3407
3606
  */
3408
- function setHeader(headerName, headerValue, [resource, options = {}], {
3409
- throwOnExisting = false,
3410
- errorMessage = `Unexpected ${headerName} header encountered`
3411
- } = {}) {
3412
- let hasHeaderBeenSet = false;
3413
- if (resource instanceof Request && !(options == null ? void 0 : options.headers)) {
3414
- if (throwOnExisting && resource.headers.has(headerName)) {
3415
- throw new Error(errorMessage);
3607
+ class Sanitizer {
3608
+ constructor(obj) {
3609
+ this.obj = obj;
3610
+ this.copy = {};
3611
+ this.currentPath = {
3612
+ key: "",
3613
+ value: obj,
3614
+ parent: null,
3615
+ data: this.copy
3616
+ };
3617
+ }
3618
+ sanitize() {
3619
+ const sanitizer = this;
3620
+ JSON.stringify(this.obj, function(key, value) {
3621
+ if (key === "") {
3622
+ return value;
3623
+ }
3624
+ const parent = this;
3625
+ if (parent !== sanitizer.currentPath.value) {
3626
+ sanitizer.exit(parent);
3627
+ }
3628
+ if (typeof value === "object" && value !== null) {
3629
+ sanitizer.enter(key, value);
3630
+ return value;
3631
+ }
3632
+ sanitizer.currentPath.data[key] = value;
3633
+ return value;
3634
+ });
3635
+ return this.copy;
3636
+ }
3637
+ enter(key, value) {
3638
+ const { currentPath: parentPath } = this;
3639
+ const data = parentPath.data[key] = Array.isArray(value) ? [] : {};
3640
+ this.currentPath = {
3641
+ key,
3642
+ value,
3643
+ parent: parentPath,
3644
+ data
3645
+ };
3646
+ }
3647
+ exit(parent) {
3648
+ while (this.currentPath.value !== parent) {
3649
+ this.currentPath = this.currentPath.parent || this.currentPath;
3416
3650
  }
3417
- resource.headers.set(headerName, headerValue);
3418
- hasHeaderBeenSet = true;
3419
3651
  }
3420
- if ((options == null ? void 0 : options.headers) instanceof Headers) {
3421
- if (throwOnExisting && options.headers.has(headerName)) {
3422
- throw new Error(errorMessage);
3652
+ }
3653
+ function sanitize(obj) {
3654
+ return new Sanitizer(obj).sanitize();
3655
+ }
3656
+ function isIncompleteConfigError(err) {
3657
+ return err instanceof MissingRequiredPropertyError || err instanceof JsonSchemaViolationError && err.validationErrors.find(
3658
+ (validationError) => validationError instanceof MissingRequiredPropertyError
3659
+ ) !== void 0;
3660
+ }
3661
+ class CommandWireAdapterConstructor {
3662
+ constructor(callback, sourceContext, options) {
3663
+ this.callback = callback;
3664
+ this.connected = false;
3665
+ this.exposeRefresh = false;
3666
+ if (!(options == null ? void 0 : options.skipEmptyEmit)) {
3667
+ this.emit();
3423
3668
  }
3424
- options.headers.set(headerName, headerValue);
3425
- } else {
3426
- if (throwOnExisting && (options == null ? void 0 : options.headers) && Reflect.has(options.headers, headerName)) {
3427
- throw new Error(errorMessage);
3669
+ }
3670
+ connect() {
3671
+ this.connected = true;
3672
+ this.invokeAdapter();
3673
+ }
3674
+ disconnect() {
3675
+ this.unsubscribe();
3676
+ this.connected = false;
3677
+ }
3678
+ update(config, _context) {
3679
+ this.unsubscribe();
3680
+ this.config = sanitize(config);
3681
+ this.invokeAdapter();
3682
+ }
3683
+ emit(result) {
3684
+ try {
3685
+ if (result === void 0) {
3686
+ this.callback({ data: void 0, error: void 0 });
3687
+ } else {
3688
+ const consumerEmittedRefresh = () => {
3689
+ if (!this.refresh) {
3690
+ return Promise.resolve();
3691
+ }
3692
+ return new Promise((resolve, reject) => {
3693
+ if (!this.refresh) {
3694
+ resolve();
3695
+ return;
3696
+ }
3697
+ this.refresh().then((res) => {
3698
+ if (res.isOk()) {
3699
+ resolve();
3700
+ } else {
3701
+ reject(
3702
+ new Error(
3703
+ "Internal error in Lightning Data Service adapter occurred: Failed to refresh data"
3704
+ )
3705
+ );
3706
+ }
3707
+ });
3708
+ });
3709
+ };
3710
+ let consumerEmittedData = {
3711
+ data: void 0,
3712
+ error: void 0
3713
+ };
3714
+ if (this.exposeRefresh && this.refresh) {
3715
+ consumerEmittedData.refresh = consumerEmittedRefresh;
3716
+ }
3717
+ if (result.isErr()) {
3718
+ if (isSubscribableResult(result)) {
3719
+ consumerEmittedData.error = result.error.failure;
3720
+ } else {
3721
+ consumerEmittedData.error = result.error;
3722
+ }
3723
+ } else {
3724
+ if (isSubscribableResult(result)) {
3725
+ deepFreeze(result.value.data);
3726
+ consumerEmittedData.data = result.value.data;
3727
+ } else {
3728
+ deepFreeze(result.value);
3729
+ consumerEmittedData.data = result.value;
3730
+ }
3731
+ }
3732
+ this.callback(consumerEmittedData);
3733
+ }
3734
+ } catch (e) {
3735
+ this.handleExecutionThrow(e);
3428
3736
  }
3429
- if (!hasHeaderBeenSet) {
3430
- options.headers = {
3431
- ...options == null ? void 0 : options.headers,
3432
- [headerName]: headerValue
3433
- };
3737
+ }
3738
+ invokeAdapter() {
3739
+ if (!this.connected || this.config === void 0) {
3740
+ return;
3741
+ }
3742
+ if (this.configSchema) {
3743
+ try {
3744
+ assertIsValid(this.config, this.configSchema);
3745
+ } catch (err) {
3746
+ if (isIncompleteConfigError(err)) {
3747
+ return;
3748
+ }
3749
+ throw err;
3750
+ }
3751
+ }
3752
+ const initialConfig = this.config;
3753
+ const command = this.getCommand();
3754
+ try {
3755
+ command.execute().then((result) => {
3756
+ if (!this.connected || this.config !== initialConfig) {
3757
+ return;
3758
+ }
3759
+ this.refresh = void 0;
3760
+ if (result.isOk()) {
3761
+ if (isSubscribableResult(result)) {
3762
+ const value = result.value;
3763
+ this.unsubscriber = value.subscribe((updatedResult) => {
3764
+ if (!this.connected || this.config !== initialConfig) {
3765
+ this.unsubscribe();
3766
+ return;
3767
+ }
3768
+ this.emit(updatedResult);
3769
+ });
3770
+ this.refresh = value.refresh;
3771
+ this.emit(ok$2(value.data));
3772
+ } else {
3773
+ this.emit(result);
3774
+ }
3775
+ } else {
3776
+ if (isSubscribableResult(result)) {
3777
+ const value = result.error;
3778
+ this.unsubscriber = value.subscribe((updatedResult) => {
3779
+ if (!this.connected || this.config !== initialConfig) {
3780
+ this.unsubscribe();
3781
+ return;
3782
+ }
3783
+ this.emit(updatedResult);
3784
+ });
3785
+ this.refresh = value.refresh;
3786
+ this.emit(result);
3787
+ } else {
3788
+ this.unsubscriber = () => {
3789
+ };
3790
+ this.emit(result);
3791
+ }
3792
+ }
3793
+ });
3794
+ } catch (e) {
3795
+ this.handleExecutionThrow(e);
3796
+ }
3797
+ }
3798
+ handleExecutionThrow(error) {
3799
+ emitError(this.callback, error);
3800
+ }
3801
+ unsubscribe() {
3802
+ if (this.unsubscriber) {
3803
+ this.unsubscriber();
3804
+ delete this.unsubscriber;
3434
3805
  }
3435
3806
  }
3436
- return [resource, options];
3437
3807
  }
3438
- const UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE = "Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor";
3439
- function setHeaderAuthorization({ token }, fetchParams) {
3440
- const authorizationValue = `Bearer ${token}`;
3441
- return setHeader("Authorization", authorizationValue, fetchParams, {
3442
- throwOnExisting: true,
3443
- errorMessage: UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE
3444
- });
3808
+ function toGraphQLResponseFromFailure(failure) {
3809
+ if (isUserVisibleError$1(failure)) {
3810
+ return {
3811
+ data: failure.data.data,
3812
+ errors: failure.data.errors
3813
+ };
3814
+ }
3815
+ logError$1(failure);
3816
+ return {
3817
+ data: void 0,
3818
+ errors: [{ message: "Internal error in GraphQL adapter occurred", locations: [] }]
3819
+ };
3445
3820
  }
3446
- function buildJwtRequestHeaderInterceptor(jwtManager, jwtRequestModifier = (_e, fetchArgs) => fetchArgs) {
3447
- return (args) => {
3448
- return resolvedPromiseLike$3(jwtManager.getJwt()).then((token) => {
3449
- const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);
3450
- return token.extraInfo ? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization) : fetchArgsWithRequestHeaderAuthorization;
3821
+ class LWCWireBindingsService {
3822
+ bind(getCommand, configSchema, exposeRefresh = false) {
3823
+ return class extends CommandWireAdapterConstructor {
3824
+ constructor() {
3825
+ super(...arguments);
3826
+ this.configSchema = configSchema;
3827
+ this.exposeRefresh = exposeRefresh;
3828
+ }
3829
+ getCommand() {
3830
+ return getCommand(this.config);
3831
+ }
3832
+ };
3833
+ }
3834
+ }
3835
+ function buildServiceDescriptor$1() {
3836
+ return {
3837
+ type: "lwcWireBindings",
3838
+ version: "1.0",
3839
+ service: new LWCWireBindingsService()
3840
+ };
3841
+ }
3842
+ class GraphQLCommandWireAdapterConstructor extends CommandWireAdapterConstructor {
3843
+ emit(result) {
3844
+ try {
3845
+ if (result === void 0) {
3846
+ this.callback({ data: void 0, errors: void 0 });
3847
+ } else {
3848
+ const consumerEmittedRefresh = () => {
3849
+ if (!this.refresh) {
3850
+ return Promise.resolve();
3851
+ }
3852
+ return new Promise((resolve, reject) => {
3853
+ if (!this.refresh) {
3854
+ resolve();
3855
+ return;
3856
+ }
3857
+ this.refresh().then((res) => {
3858
+ if (res.isOk()) {
3859
+ resolve();
3860
+ } else {
3861
+ reject(
3862
+ new Error(
3863
+ "Internal error in GraphQL adapter occurred: Failed to refresh GraphQL data"
3864
+ )
3865
+ );
3866
+ }
3867
+ });
3868
+ });
3869
+ };
3870
+ let consumerEmittedData = {
3871
+ data: void 0,
3872
+ errors: void 0
3873
+ };
3874
+ if (this.exposeRefresh && this.refresh) {
3875
+ consumerEmittedData.refresh = consumerEmittedRefresh;
3876
+ }
3877
+ if (result.isErr()) {
3878
+ const failure = isSubscribableResult(result) ? result.error.failure : result.error;
3879
+ const resp = toGraphQLResponseFromFailure(failure);
3880
+ consumerEmittedData.data = resp.data;
3881
+ consumerEmittedData.errors = resp.errors;
3882
+ } else {
3883
+ consumerEmittedData.data = result.value.data;
3884
+ }
3885
+ deepFreeze(consumerEmittedData);
3886
+ this.callback(consumerEmittedData);
3887
+ }
3888
+ } catch (e) {
3889
+ logError$1(e);
3890
+ this.handleExecutionThrow(e);
3891
+ }
3892
+ }
3893
+ handleExecutionThrow(e) {
3894
+ logError$1(e);
3895
+ this.callback({
3896
+ data: void 0,
3897
+ errors: [{ message: "Internal error in GraphQL adapter occurred", locations: [] }]
3451
3898
  });
3899
+ }
3900
+ update(config, _context) {
3901
+ this.unsubscribe();
3902
+ const resolvedQuery = resolveAst(config.query);
3903
+ if (resolvedQuery) {
3904
+ validateGraphQLOperations(
3905
+ { query: resolvedQuery, operationName: config == null ? void 0 : config.operationName },
3906
+ { acceptedOperations: ["query"] }
3907
+ );
3908
+ }
3909
+ this.config = {
3910
+ ...sanitize(config),
3911
+ query: resolvedQuery
3912
+ };
3913
+ this.invokeAdapter();
3914
+ }
3915
+ }
3916
+ class LWCGraphQLWireBindingsService {
3917
+ bind(getCommand, configSchema, exposeRefresh = false) {
3918
+ return class extends GraphQLCommandWireAdapterConstructor {
3919
+ constructor() {
3920
+ super(...arguments);
3921
+ this.configSchema = configSchema;
3922
+ this.exposeRefresh = exposeRefresh;
3923
+ }
3924
+ getCommand() {
3925
+ return getCommand(this.config);
3926
+ }
3927
+ };
3928
+ }
3929
+ }
3930
+ function buildServiceDescriptor$2() {
3931
+ return {
3932
+ type: "lwcGraphQLWireBindings",
3933
+ version: "1.0",
3934
+ service: new LWCGraphQLWireBindingsService()
3452
3935
  };
3453
3936
  }
3454
3937
 
3455
- var SnapshotState;
3456
- (function (SnapshotState) {
3457
- SnapshotState["Fulfilled"] = "Fulfilled";
3458
- SnapshotState["Unfulfilled"] = "Unfulfilled";
3459
- SnapshotState["Error"] = "Error";
3460
- SnapshotState["Pending"] = "Pending";
3461
- SnapshotState["Stale"] = "Stale";
3462
- })(SnapshotState || (SnapshotState = {}));
3463
- const { isArray: isArray$1 } = Array;
3464
-
3465
- Promise.resolve();
3938
+ function createLockerCompatibleWireConstructor(DelegateCtor) {
3939
+ function Constructor(callback, sourceContext, options) {
3940
+ const delegate = new DelegateCtor(callback, sourceContext, options);
3941
+ this.connect = () => delegate.connect();
3942
+ this.disconnect = () => delegate.disconnect();
3943
+ this.update = (config, context) => delegate.update(config, context);
3944
+ }
3945
+ return Constructor;
3946
+ }
3947
+ function buildLWCWireBindingsServiceDescriptor() {
3948
+ const base = buildServiceDescriptor$1();
3949
+ const originalBind = base.service.bind.bind(base.service);
3950
+ const bind = (...args) => {
3951
+ const ctor = originalBind(...args);
3952
+ return createLockerCompatibleWireConstructor(ctor);
3953
+ };
3954
+ return {
3955
+ ...base,
3956
+ service: {
3957
+ ...base.service,
3958
+ bind,
3959
+ },
3960
+ };
3961
+ }
3962
+ function buildLWCGraphQLWireBindingsServiceDescriptor() {
3963
+ const base = buildServiceDescriptor$2();
3964
+ const originalBind = base.service.bind.bind(base.service);
3965
+ const bind = (...args) => {
3966
+ const ctor = originalBind(...args);
3967
+ return createLockerCompatibleWireConstructor(ctor);
3968
+ };
3969
+ return {
3970
+ ...base,
3971
+ service: {
3972
+ ...base.service,
3973
+ bind,
3974
+ },
3975
+ };
3976
+ }
3466
3977
 
3467
- var StoreErrorStatus;
3468
- (function (StoreErrorStatus) {
3469
- StoreErrorStatus[StoreErrorStatus["RESOURCE_NOT_FOUND"] = 404] = "RESOURCE_NOT_FOUND";
3470
- })(StoreErrorStatus || (StoreErrorStatus = {}));
3471
- var StoreRecordType;
3472
- (function (StoreRecordType) {
3473
- StoreRecordType["Error"] = "error";
3474
- })(StoreRecordType || (StoreRecordType = {}));
3475
- var StoreLinkStateValues$1;
3476
- (function (StoreLinkStateValues) {
3477
- StoreLinkStateValues[StoreLinkStateValues["NotPresent"] = 0] = "NotPresent";
3478
- StoreLinkStateValues[StoreLinkStateValues["RefNotPresent"] = 1] = "RefNotPresent";
3479
- StoreLinkStateValues[StoreLinkStateValues["RefPresent"] = 2] = "RefPresent";
3480
- StoreLinkStateValues[StoreLinkStateValues["Null"] = 3] = "Null";
3481
- StoreLinkStateValues[StoreLinkStateValues["Missing"] = 4] = "Missing";
3482
- StoreLinkStateValues[StoreLinkStateValues["Pending"] = 5] = "Pending";
3483
- })(StoreLinkStateValues$1 || (StoreLinkStateValues$1 = {}));
3484
- var StoreResolveResultState;
3485
- (function (StoreResolveResultState) {
3486
- StoreResolveResultState[StoreResolveResultState["Found"] = 0] = "Found";
3487
- StoreResolveResultState[StoreResolveResultState["Error"] = 1] = "Error";
3488
- StoreResolveResultState[StoreResolveResultState["Null"] = 2] = "Null";
3489
- StoreResolveResultState[StoreResolveResultState["NotPresent"] = 3] = "NotPresent";
3490
- StoreResolveResultState[StoreResolveResultState["Stale"] = 4] = "Stale";
3491
- })(StoreResolveResultState || (StoreResolveResultState = {}));
3492
- var HttpStatusCode;
3493
- (function (HttpStatusCode) {
3494
- HttpStatusCode[HttpStatusCode["Ok"] = 200] = "Ok";
3495
- HttpStatusCode[HttpStatusCode["Created"] = 201] = "Created";
3496
- HttpStatusCode[HttpStatusCode["NoContent"] = 204] = "NoContent";
3497
- HttpStatusCode[HttpStatusCode["NotModified"] = 304] = "NotModified";
3498
- HttpStatusCode[HttpStatusCode["BadRequest"] = 400] = "BadRequest";
3499
- HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
3500
- HttpStatusCode[HttpStatusCode["Forbidden"] = 403] = "Forbidden";
3501
- HttpStatusCode[HttpStatusCode["NotFound"] = 404] = "NotFound";
3502
- HttpStatusCode[HttpStatusCode["ServerError"] = 500] = "ServerError";
3503
- HttpStatusCode[HttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout";
3504
- })(HttpStatusCode || (HttpStatusCode = {}));
3505
- /**
3506
- * A type guard function for determining if an unknown object is a {@link FormData}
3507
- */
3508
- function isFormData(obj) {
3509
- return (typeof obj === 'object' &&
3510
- obj !== null &&
3511
- 'namedEntries' in obj &&
3512
- isArray$1(obj.namedEntries));
3513
- }
3514
- /**
3515
- * A type guard function for determining if an unknown object is a {@link FileReference}
3978
+ /*!
3979
+ * Copyright (c) 2022, Salesforce, Inc.,
3980
+ * All rights reserved.
3981
+ * For full license text, see the LICENSE.txt file
3516
3982
  */
3517
- function isFileReference(entryValue) {
3518
- return (typeof entryValue === 'object' &&
3519
- entryValue !== null &&
3520
- 'isFileReference' in entryValue &&
3521
- entryValue.isFileReference === true);
3983
+ function e$1(e2) {
3984
+ this.message = e2;
3522
3985
  }
3523
- var GraphNodeType;
3524
- (function (GraphNodeType) {
3525
- GraphNodeType["Link"] = "Link";
3526
- GraphNodeType["Node"] = "Node";
3527
- GraphNodeType["Error"] = "Error";
3528
- GraphNodeType["Locked"] = "Locked";
3529
- })(GraphNodeType || (GraphNodeType = {}));
3530
-
3531
- var StoreLinkStateValues;
3532
- (function (StoreLinkStateValues) {
3533
- StoreLinkStateValues[StoreLinkStateValues["NotPresent"] = 0] = "NotPresent";
3534
- StoreLinkStateValues[StoreLinkStateValues["RefNotPresent"] = 1] = "RefNotPresent";
3535
- StoreLinkStateValues[StoreLinkStateValues["RefPresent"] = 2] = "RefPresent";
3536
- StoreLinkStateValues[StoreLinkStateValues["Null"] = 3] = "Null";
3537
- StoreLinkStateValues[StoreLinkStateValues["Missing"] = 4] = "Missing";
3538
- StoreLinkStateValues[StoreLinkStateValues["Pending"] = 5] = "Pending";
3539
- })(StoreLinkStateValues || (StoreLinkStateValues = {}));
3540
- var FragmentReadResultState;
3541
- (function (FragmentReadResultState) {
3542
- FragmentReadResultState[FragmentReadResultState["Missing"] = 0] = "Missing";
3543
- FragmentReadResultState[FragmentReadResultState["Success"] = 1] = "Success";
3544
- FragmentReadResultState[FragmentReadResultState["Error"] = 2] = "Error";
3545
- })(FragmentReadResultState || (FragmentReadResultState = {}));
3546
- ({
3547
- state: FragmentReadResultState.Missing,
3548
- });
3549
-
3550
- var ResourceParamType;
3551
- (function (ResourceParamType) {
3552
- ResourceParamType[ResourceParamType["UrlParameter"] = 0] = "UrlParameter";
3553
- ResourceParamType[ResourceParamType["QueryParameter"] = 1] = "QueryParameter";
3554
- ResourceParamType[ResourceParamType["Body"] = 2] = "Body";
3555
- ResourceParamType[ResourceParamType["Header"] = 3] = "Header";
3556
- })(ResourceParamType || (ResourceParamType = {}));
3557
- var TypeCheckShapes;
3558
- (function (TypeCheckShapes) {
3559
- TypeCheckShapes[TypeCheckShapes["String"] = 0] = "String";
3560
- TypeCheckShapes[TypeCheckShapes["Boolean"] = 1] = "Boolean";
3561
- TypeCheckShapes[TypeCheckShapes["Number"] = 2] = "Number";
3562
- TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
3563
- TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
3564
- })(TypeCheckShapes || (TypeCheckShapes = {}));
3565
- // engine version: 0.158.7-bafe2646
3566
-
3567
- const { keys: keys$1 } = Object;
3568
-
3569
- // we're going to intentionally bundle this small bit of luvio engine code into
3570
- // this module to keep it runtime dependency-free
3571
- const fetchNetworkAdapter = async (resourceRequest, _resourceRequestContext) => {
3572
- const { baseUri, basePath, body: requestBody, queryParams, method, headers } = resourceRequest;
3573
- const qs = generateQueryString(queryParams);
3574
- const path = `${baseUri}${basePath}${qs}`;
3575
- let body;
3576
- // some endpoints use FormData for POST request body, check here
3577
- // if we have a POST body that is FormData
3578
- if (method === 'post' && isFormData(requestBody)) {
3579
- // we will populate a DOM FormData and pass that to fetch
3580
- const newForm = new FormData();
3581
- for (const { name, value } of requestBody.namedEntries) {
3582
- // if this is a string or real DOM File then we can
3583
- // just add it to FormData
3584
- if (typeof value === 'string' || value instanceof File) {
3585
- newForm.append(name, value);
3586
- }
3587
- // this network adapter doesn't currently support FileReference's
3588
- else if (isFileReference(value)) {
3589
- throw Error(`Luvio fetchNetworkAdapter does not support FileReference's`);
3590
- }
3591
- // else we have a Luvio File that isn't a real DOM file,
3592
- // so we need to turn it into a DOM file
3593
- else {
3594
- const buffer = await value.arrayBuffer();
3595
- newForm.append(name, new File([new Uint8Array(buffer)], value.name, {
3596
- type: value.type,
3597
- }));
3598
- }
3599
- }
3600
- body = newForm;
3601
- }
3602
- else if (requestBody === null) {
3603
- body = null;
3604
- }
3605
- else {
3606
- body = JSON.stringify(requestBody);
3607
- headers['Content-Type'] = 'application/json';
3608
- }
3609
- const response = await fetch(path, {
3610
- method: method.toUpperCase(),
3611
- headers: generateHeaders(headers),
3612
- body,
3613
- });
3614
- const { status, ok, statusText } = response;
3615
- // coerce headers
3616
- const responseHeaders = {};
3617
- response.headers.forEach((value, key) => {
3618
- responseHeaders[key] = value;
3619
- });
3620
- // parse body
3621
- let responseBody = null;
3622
- if (status !== 204) {
3623
- const contentType = responseHeaders['content-type'];
3624
- responseBody =
3625
- contentType && contentType.startsWith('application/json')
3626
- ? await response.json()
3627
- : await response.text();
3628
- }
3629
- return {
3630
- body: responseBody,
3631
- status,
3632
- statusText,
3633
- ok,
3634
- headers: responseHeaders,
3635
- };
3986
+ e$1.prototype = new Error(), e$1.prototype.name = "InvalidCharacterError";
3987
+ var r = "undefined" != typeof window && window.atob && window.atob.bind(window) || function(r2) {
3988
+ var t2 = String(r2).replace(/=+$/, "");
3989
+ if (t2.length % 4 == 1) throw new e$1("'atob' failed: The string to be decoded is not correctly encoded.");
3990
+ for (var n2, o2, a = 0, i = 0, c = ""; o2 = t2.charAt(i++); ~o2 && (n2 = a % 4 ? 64 * n2 + o2 : o2, a++ % 4) ? c += String.fromCharCode(255 & n2 >> (-2 * a & 6)) : 0) o2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o2);
3991
+ return c;
3636
3992
  };
3637
- function generateQueryString(params) {
3638
- const queryStrings = [];
3639
- for (const key of keys$1(params)) {
3640
- queryStrings.push(`${key}=${params[key]}`);
3641
- }
3642
- if (queryStrings.length > 0) {
3643
- return `?${queryStrings.join('&')}`;
3644
- }
3645
- return '';
3993
+ function t(e2) {
3994
+ var t2 = e2.replace(/-/g, "+").replace(/_/g, "/");
3995
+ switch (t2.length % 4) {
3996
+ case 0:
3997
+ break;
3998
+ case 2:
3999
+ t2 += "==";
4000
+ break;
4001
+ case 3:
4002
+ t2 += "=";
4003
+ break;
4004
+ default:
4005
+ throw "Illegal base64url string!";
4006
+ }
4007
+ try {
4008
+ return (function(e3) {
4009
+ return decodeURIComponent(r(e3).replace(/(.)/g, (function(e4, r2) {
4010
+ var t3 = r2.charCodeAt(0).toString(16).toUpperCase();
4011
+ return t3.length < 2 && (t3 = "0" + t3), "%" + t3;
4012
+ })));
4013
+ })(t2);
4014
+ } catch (e3) {
4015
+ return r(t2);
4016
+ }
3646
4017
  }
3647
- function generateHeaders(headers) {
3648
- const fetchHeaders = new Headers();
3649
- for (const key of keys$1(headers)) {
3650
- fetchHeaders.set(key, headers[key]);
3651
- }
3652
- return fetchHeaders;
4018
+ function n$1(e2) {
4019
+ this.message = e2;
3653
4020
  }
3654
-
3655
- const SALESFORCE_API_BASE_URI_FLAG = 'api.salesforce.com';
3656
- const SFAPController = 'SalesforceApiPlatformController';
3657
- const SFAPJwtMethod = 'getSFAPLightningJwtService';
3658
- /**
3659
- * We expect jwt info and baseUri to be present in the response.
3660
- *
3661
- * @param body
3662
- */
3663
- function validateResponse(body) {
3664
- if (!body || !body.jwt || !body.baseUri) {
3665
- // wrapped the invocation in env conditional
3666
- // eslint-disable-next-line @salesforce/lds/no-error-in-production
3667
- throw new Error(`Expected jwt info and baseUri to be present but instead got: ${JSON.stringify(body)}`);
3668
- }
4021
+ function o(e2, r2) {
4022
+ if ("string" != typeof e2) throw new n$1("Invalid token specified");
4023
+ var o2 = true === (r2 = r2 || {}).header ? 0 : 1;
4024
+ try {
4025
+ return JSON.parse(t(e2.split(".")[o2]));
4026
+ } catch (e3) {
4027
+ throw new n$1("Invalid token specified: " + e3.message);
4028
+ }
3669
4029
  }
3670
- /**
3671
- * Resolves Jwt token for SFAP by calling Aura action
3672
- * {@link JwtResolver} for platform SFAP
3673
- */
3674
- const platformSfapJwtResolver = {
3675
- getJwt() {
3676
- return new Promise((resolve, reject) => {
3677
- dispatchAuraAction(`${SFAPController}.${SFAPJwtMethod}`, {}, defaultActionConfig)
3678
- .then((response) => {
3679
- const body = response.body;
3680
- if (process.env.NODE_ENV !== 'production') {
3681
- validateResponse(body);
3682
- }
3683
- resolve({
3684
- jwt: body.jwt,
3685
- extraInfo: {
3686
- baseUri: body.baseUri,
3687
- },
3688
- });
3689
- })
3690
- .catch((error) => {
3691
- if (error instanceof Error) {
3692
- reject(error.message);
3693
- return;
3694
- }
3695
- // AuraFetchResponse errors
3696
- const { status } = error;
3697
- if (status !== HttpStatusCode$2.ServerError) {
3698
- // ConnectInJavaError
3699
- reject(error.body.message);
3700
- return;
3701
- }
3702
- reject(error.body.error);
3703
- });
3704
- });
3705
- },
4030
+ n$1.prototype = new Error(), n$1.prototype.name = "InvalidTokenError";
4031
+ class JwtToken {
4032
+ /**
4033
+ * Create a new JwtToken.
4034
+ *
4035
+ * @param _token - The JWT string.
4036
+ * @param _decodedInfo - The decoded information from the JWT.
4037
+ * @param _extraInfo - Any additional information associated with the JWT.
4038
+ */
4039
+ constructor(_token, _decodedInfo, _extraInfo) {
4040
+ this._token = _token;
4041
+ this._decodedInfo = _decodedInfo;
4042
+ this._extraInfo = _extraInfo;
4043
+ }
4044
+ /**
4045
+ * Get the JWT string.
4046
+ *
4047
+ * @returns The JWT string.
4048
+ */
4049
+ get token() {
4050
+ return this._token;
4051
+ }
4052
+ /**
4053
+ * Get the additional information associated with the JWT.
4054
+ *
4055
+ * @returns The additional information.
4056
+ */
4057
+ get extraInfo() {
4058
+ return this._extraInfo;
4059
+ }
4060
+ /**
4061
+ * Get the decoded information from the JWT.
4062
+ *
4063
+ * @returns The decoded information.
4064
+ */
4065
+ get decodedInfo() {
4066
+ return this._decodedInfo;
4067
+ }
4068
+ /**
4069
+ * Get the remaining time in seconds until the JWT expires.
4070
+ *
4071
+ * @returns The remaining time in seconds.
4072
+ */
4073
+ get tokenRemainingSeconds() {
4074
+ return this.decodedInfo.exp - Date.now() / 1e3;
4075
+ }
4076
+ /**
4077
+ * Check if the JWT is expired.
4078
+ *
4079
+ * @returns True if the JWT is expired, false otherwise.
4080
+ */
4081
+ get isExpired() {
4082
+ return this.tokenRemainingSeconds <= 0;
4083
+ }
4084
+ }
4085
+ let defaultLogger = {
4086
+ trace: () => {
4087
+ },
4088
+ debug: () => {
4089
+ },
4090
+ info: () => {
4091
+ },
4092
+ warn: () => {
4093
+ },
4094
+ error: () => {
4095
+ }
3706
4096
  };
3707
- const jwtManager = new JwtManager(new JwtRepository(), platformSfapJwtResolver);
3708
- const authenticateRequest = (resourceRequest, jwt) => {
3709
- const { token } = jwt;
3710
- const { headers } = resourceRequest;
3711
- // Only supporting Bearer <auth-scheme>
3712
- const authenticatedHeaders = {
3713
- ...headers,
3714
- Authorization: `Bearer ${token}`,
3715
- };
3716
- return {
3717
- ...resourceRequest,
3718
- headers: authenticatedHeaders,
4097
+ if (process.env.NODE_ENV !== "production") {
4098
+ defaultLogger = loggerService();
4099
+ }
4100
+ function computeDecodedInfo(token, defaultTokenTTLInSeconds, logger) {
4101
+ const decodedInfo = o(token);
4102
+ if (decodedInfo.exp === void 0) {
4103
+ logger.warn(`"exp" claim is not present in the provided token.`);
4104
+ decodedInfo.exp = Date.now() / 1e3 + defaultTokenTTLInSeconds;
4105
+ }
4106
+ return decodedInfo;
4107
+ }
4108
+ class JwtRepository {
4109
+ /**
4110
+ * @param limitInSeconds - Time in seconds before the token's expiry to notify observers.
4111
+ * @param defaultTokenTTLInSeconds - Default token expiry time in seconds if "exp" claim is not present in token.
4112
+ * @param logger - Logger for logging warnings and errors.
4113
+ */
4114
+ constructor(limitInSeconds = 5, defaultTokenTTLInSeconds = 120, logger = defaultLogger) {
4115
+ this.limitInSeconds = limitInSeconds;
4116
+ this.defaultTokenTTLInSeconds = defaultTokenTTLInSeconds;
4117
+ this.logger = logger;
4118
+ this.observers = [];
4119
+ }
4120
+ /**
4121
+ * Get the current token.
4122
+ */
4123
+ get token() {
4124
+ return this._token;
4125
+ }
4126
+ /**
4127
+ * Set the current token.
4128
+ *
4129
+ * @param token - JWT token as a string.
4130
+ * @param extraInfo - Optional extra information.
4131
+ */
4132
+ setToken(token, extraInfo) {
4133
+ const decodedInfo = computeDecodedInfo(
4134
+ token,
4135
+ this.defaultTokenTTLInSeconds,
4136
+ this.logger
4137
+ );
4138
+ this._token = new JwtToken(token, decodedInfo, extraInfo);
4139
+ this.observeTokenExpiration();
4140
+ return this._token;
4141
+ }
4142
+ /**
4143
+ * Remove the current token.
4144
+ */
4145
+ removeToken() {
4146
+ this._token = void 0;
4147
+ this.clearTimeoutHandler();
4148
+ }
4149
+ /**
4150
+ * Subscribe to the token nearing its expiration.
4151
+ *
4152
+ * @param cb - Callback function to execute when token is nearing expiration.
4153
+ */
4154
+ subscribeToTokenNearExpiration(cb) {
4155
+ this.observers.push(cb);
4156
+ this.observeTokenExpiration();
4157
+ return () => {
4158
+ this.observers = this.observers.filter((observer) => observer !== cb);
3719
4159
  };
3720
- };
3721
- /**
3722
- * This hook is used to modify the resource request before it is sent to the server.
3723
- * SFAP uses extraInfo assocaiated JwtToken to update the baseUri for the resource request.
3724
- *
3725
- * @param resourceRequest
3726
- * @param jwtToken
3727
- * @returns resourceRequest with updated baseUri
4160
+ }
4161
+ /**
4162
+ * Clear the timeout handler.
4163
+ */
4164
+ clearTimeoutHandler() {
4165
+ if (this.timeoutHandler !== void 0) {
4166
+ clearTimeout(this.timeoutHandler);
4167
+ }
4168
+ }
4169
+ /**
4170
+ * Observe and handle token expiration.
4171
+ */
4172
+ observeTokenExpiration() {
4173
+ this.clearTimeoutHandler();
4174
+ if (this.observers.length === 0 || this.token === void 0) {
4175
+ return;
4176
+ }
4177
+ this.timeoutHandler = setTimeout(
4178
+ () => this.notifyTokenIsExpiring(),
4179
+ this.computeTimeoutTimeInMs()
4180
+ );
4181
+ }
4182
+ /**
4183
+ * Compute the timeout time in milliseconds.
4184
+ */
4185
+ computeTimeoutTimeInMs() {
4186
+ const remainingSeconds = this.token.tokenRemainingSeconds;
4187
+ let timeoutTimeInSeconds = remainingSeconds - this.limitInSeconds;
4188
+ return timeoutTimeInSeconds < 0 ? 0 : timeoutTimeInSeconds * 1e3;
4189
+ }
4190
+ /**
4191
+ * Notify all observers that the token is expiring.
4192
+ */
4193
+ notifyTokenIsExpiring() {
4194
+ this.observers.forEach((cb) => {
4195
+ try {
4196
+ cb.call(void 0, this.token);
4197
+ } catch (e2) {
4198
+ this.logger.error(e2.message);
4199
+ }
4200
+ });
4201
+ }
4202
+ }
4203
+ class JwtManager {
4204
+ /**
4205
+ * Constructor for JwtManager class.
4206
+ *
4207
+ * @param {JwtRepository<T, ExtraInfo>} jwtRepository JwtRepository instance used for token management.
4208
+ * @param {JwtResolver<ExtraInfo>} resolver JwtResolver instance used for token retrieval.
4209
+ * @param {JwtManagerOptions} options JwtManagerOptions bag to customize behavior.
4210
+ */
4211
+ constructor(jwtRepository, resolver, options) {
4212
+ this.jwtRepository = jwtRepository;
4213
+ this.resolver = resolver;
4214
+ if (options == null ? void 0 : options.keepTokenUpdated) {
4215
+ jwtRepository.subscribeToTokenNearExpiration(() => this.refreshToken());
4216
+ }
4217
+ }
4218
+ /**
4219
+ * Method to get a JWT token.
4220
+ * If there's a token request in progress, it will return the Promise of this request.
4221
+ * If the current token is undefined or expired, it will initiate a token refresh.
4222
+ * Otherwise, it will return the current token.
4223
+ *
4224
+ * @returns {JwtToken<T, ExtraInfo> | Promise<JwtToken<T, ExtraInfo>>} The current token or the Promise of a token request.
4225
+ */
4226
+ getJwt() {
4227
+ if (this.inflightPromise) {
4228
+ return this.inflightPromise;
4229
+ }
4230
+ const token = this.jwtRepository.token;
4231
+ if (token === void 0 || token.isExpired) {
4232
+ return this.refreshToken();
4233
+ }
4234
+ return token;
4235
+ }
4236
+ /**
4237
+ * Method to refresh a JWT token.
4238
+ * If a refresh request is already in progress, it will return the Promise of this request.
4239
+ * Otherwise, it will start a new refresh request and return its Promise.
4240
+ *
4241
+ * @returns {Promise<JwtToken<T, ExtraInfo>>} Promise of the refreshed token.
4242
+ */
4243
+ refreshToken() {
4244
+ if (this.inflightPromise === void 0) {
4245
+ this.inflightPromise = new Promise((resolve, reject) => {
4246
+ this.resolver.getJwt().then(({ jwt, extraInfo }) => {
4247
+ this.inflightPromise = void 0;
4248
+ const token = this.jwtRepository.setToken(jwt, extraInfo);
4249
+ resolve(token);
4250
+ }).catch((reason) => {
4251
+ this.inflightPromise = void 0;
4252
+ reject(reason);
4253
+ });
4254
+ });
4255
+ }
4256
+ return this.inflightPromise;
4257
+ }
4258
+ /**
4259
+ * Method to check if a token refresh is in progress.
4260
+ *
4261
+ * @returns {boolean} true if a token refresh is in progress, false otherwise.
4262
+ */
4263
+ get isRefreshingToken() {
4264
+ return this.inflightPromise !== void 0;
4265
+ }
4266
+ }
4267
+
4268
+ /*!
4269
+ * Copyright (c) 2022, Salesforce, Inc.,
4270
+ * All rights reserved.
4271
+ * For full license text, see the LICENSE.txt file
3728
4272
  */
3729
- const modifySfapResourceRequest = function (resourceRequest, jwtToken) {
3730
- const { baseUri } = jwtToken.extraInfo;
3731
- return {
3732
- ...resourceRequest,
3733
- baseUri,
3734
- };
3735
- };
3736
- const sfapNetworkAdapter = async (resourceRequest, resourceRequestContext) => {
3737
- let jwtToken;
3738
- try {
3739
- jwtToken = await jwtManager.getJwt();
4273
+ function setHeader(headerName, headerValue, [resource, options = {}], {
4274
+ throwOnExisting = false,
4275
+ errorMessage = `Unexpected ${headerName} header encountered`
4276
+ } = {}) {
4277
+ let hasHeaderBeenSet = false;
4278
+ if (resource instanceof Request && !(options == null ? void 0 : options.headers)) {
4279
+ if (throwOnExisting && resource.headers.has(headerName)) {
4280
+ throw new Error(errorMessage);
3740
4281
  }
3741
- catch (error) {
3742
- if (process.env.NODE_ENV !== 'production') {
3743
- throw new Error(`There was an error while fetching Jwt token: ${JSON.stringify(error)}`);
3744
- }
3745
- return Promise.reject(new LdsNetworkAdapterErrorResponse('Unable to fetch the jwt required to make this request', error));
4282
+ resource.headers.set(headerName, headerValue);
4283
+ hasHeaderBeenSet = true;
4284
+ }
4285
+ if ((options == null ? void 0 : options.headers) instanceof Headers) {
4286
+ if (throwOnExisting && options.headers.has(headerName)) {
4287
+ throw new Error(errorMessage);
3746
4288
  }
3747
- let authenticatedRequest = authenticateRequest(resourceRequest, jwtToken);
3748
- authenticatedRequest = modifySfapResourceRequest(authenticatedRequest, jwtToken);
3749
- return fetchNetworkAdapter(authenticatedRequest);
3750
- };
3751
- class LdsNetworkAdapterErrorResponse extends Error {
3752
- constructor(message, _error) {
3753
- super(message);
3754
- this._error = _error;
3755
- this.errorType = 'networkAdapterError';
3756
- this.name = this.constructor.name;
4289
+ options.headers.set(headerName, headerValue);
4290
+ } else {
4291
+ if (throwOnExisting && (options == null ? void 0 : options.headers) && Reflect.has(options.headers, headerName)) {
4292
+ throw new Error(errorMessage);
4293
+ }
4294
+ if (!hasHeaderBeenSet) {
4295
+ options.headers = {
4296
+ ...options == null ? void 0 : options.headers,
4297
+ [headerName]: headerValue
4298
+ };
3757
4299
  }
4300
+ }
4301
+ return [resource, options];
4302
+ }
4303
+ const UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE = "Unexpected Authorization header encountered. To specify a custom Authorization header, use a Fetch service that is not configured with JwtRequestHeaderInterceptor";
4304
+ function setHeaderAuthorization({ token }, fetchParams) {
4305
+ const authorizationValue = `Bearer ${token}`;
4306
+ return setHeader("Authorization", authorizationValue, fetchParams, {
4307
+ throwOnExisting: true,
4308
+ errorMessage: UNEXPECTED_AUTHORIZATION_HEADER_MESSAGE
4309
+ });
4310
+ }
4311
+ function buildJwtRequestHeaderInterceptor(jwtManager, jwtRequestModifier = (_e, fetchArgs) => fetchArgs) {
4312
+ return (args) => {
4313
+ return resolvedPromiseLike$2(jwtManager.getJwt()).then((token) => {
4314
+ const fetchArgsWithRequestHeaderAuthorization = setHeaderAuthorization(token, args);
4315
+ return token.extraInfo ? jwtRequestModifier(token.extraInfo, fetchArgsWithRequestHeaderAuthorization) : fetchArgsWithRequestHeaderAuthorization;
4316
+ });
4317
+ };
3758
4318
  }
3759
- const composedNetworkAdapter$1 = {
3760
- shouldHandleRequest(resourceRequest) {
3761
- return resourceRequest.baseUri === SALESFORCE_API_BASE_URI_FLAG;
3762
- },
3763
- adapter: sfapNetworkAdapter,
3764
- };
3765
4319
 
3766
- function e(e){this.message=e;}e.prototype=new Error,e.prototype.name="InvalidCharacterError";"undefined"!=typeof window&&window.atob&&window.atob.bind(window)||function(r){var t=String(r).replace(/=+$/,"");if(t.length%4==1)throw new e("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,o,a=0,i=0,c="";o=t.charAt(i++);~o&&(n=a%4?64*n+o:o,a++%4)?c+=String.fromCharCode(255&n>>(-2*a&6)):0)o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o);return c};function n(e){this.message=e;}n.prototype=new Error,n.prototype.name="InvalidTokenError";
4320
+ var SnapshotState;
4321
+ (function (SnapshotState) {
4322
+ SnapshotState["Fulfilled"] = "Fulfilled";
4323
+ SnapshotState["Unfulfilled"] = "Unfulfilled";
4324
+ SnapshotState["Error"] = "Error";
4325
+ SnapshotState["Pending"] = "Pending";
4326
+ SnapshotState["Stale"] = "Stale";
4327
+ })(SnapshotState || (SnapshotState = {}));
4328
+ const { isArray: isArray$1 } = Array;
3767
4329
 
3768
- function buildLexRuntimeAuthExpirationRedirectResponseInterceptor(logger) {
3769
- return async (response) => {
3770
- if (response.status === 401) {
3771
- try {
3772
- const coercedResponse = (await coerceResponseToFetchResponse(response.clone()));
3773
- if (coercedResponse.body.errorCode === 'INVALID_SESSION_ID') {
3774
- logger.warn(`Received ${response.status} status code from LEX runtime service`);
3775
- // Fire the event asynchronously, similar to the legacy setTimeout pattern
3776
- window.setTimeout(() => {
3777
- dispatchGlobalEvent('aura:invalidSession');
3778
- }, 0);
3779
- }
4330
+ Promise.resolve();
4331
+
4332
+ var StoreErrorStatus;
4333
+ (function (StoreErrorStatus) {
4334
+ StoreErrorStatus[StoreErrorStatus["RESOURCE_NOT_FOUND"] = 404] = "RESOURCE_NOT_FOUND";
4335
+ })(StoreErrorStatus || (StoreErrorStatus = {}));
4336
+ var StoreRecordType;
4337
+ (function (StoreRecordType) {
4338
+ StoreRecordType["Error"] = "error";
4339
+ })(StoreRecordType || (StoreRecordType = {}));
4340
+ var StoreLinkStateValues$1;
4341
+ (function (StoreLinkStateValues) {
4342
+ StoreLinkStateValues[StoreLinkStateValues["NotPresent"] = 0] = "NotPresent";
4343
+ StoreLinkStateValues[StoreLinkStateValues["RefNotPresent"] = 1] = "RefNotPresent";
4344
+ StoreLinkStateValues[StoreLinkStateValues["RefPresent"] = 2] = "RefPresent";
4345
+ StoreLinkStateValues[StoreLinkStateValues["Null"] = 3] = "Null";
4346
+ StoreLinkStateValues[StoreLinkStateValues["Missing"] = 4] = "Missing";
4347
+ StoreLinkStateValues[StoreLinkStateValues["Pending"] = 5] = "Pending";
4348
+ })(StoreLinkStateValues$1 || (StoreLinkStateValues$1 = {}));
4349
+ var StoreResolveResultState;
4350
+ (function (StoreResolveResultState) {
4351
+ StoreResolveResultState[StoreResolveResultState["Found"] = 0] = "Found";
4352
+ StoreResolveResultState[StoreResolveResultState["Error"] = 1] = "Error";
4353
+ StoreResolveResultState[StoreResolveResultState["Null"] = 2] = "Null";
4354
+ StoreResolveResultState[StoreResolveResultState["NotPresent"] = 3] = "NotPresent";
4355
+ StoreResolveResultState[StoreResolveResultState["Stale"] = 4] = "Stale";
4356
+ })(StoreResolveResultState || (StoreResolveResultState = {}));
4357
+ var HttpStatusCode;
4358
+ (function (HttpStatusCode) {
4359
+ HttpStatusCode[HttpStatusCode["Ok"] = 200] = "Ok";
4360
+ HttpStatusCode[HttpStatusCode["Created"] = 201] = "Created";
4361
+ HttpStatusCode[HttpStatusCode["NoContent"] = 204] = "NoContent";
4362
+ HttpStatusCode[HttpStatusCode["NotModified"] = 304] = "NotModified";
4363
+ HttpStatusCode[HttpStatusCode["BadRequest"] = 400] = "BadRequest";
4364
+ HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
4365
+ HttpStatusCode[HttpStatusCode["Forbidden"] = 403] = "Forbidden";
4366
+ HttpStatusCode[HttpStatusCode["NotFound"] = 404] = "NotFound";
4367
+ HttpStatusCode[HttpStatusCode["ServerError"] = 500] = "ServerError";
4368
+ HttpStatusCode[HttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout";
4369
+ })(HttpStatusCode || (HttpStatusCode = {}));
4370
+ /**
4371
+ * A type guard function for determining if an unknown object is a {@link FormData}
4372
+ */
4373
+ function isFormData(obj) {
4374
+ return (typeof obj === 'object' &&
4375
+ obj !== null &&
4376
+ 'namedEntries' in obj &&
4377
+ isArray$1(obj.namedEntries));
4378
+ }
4379
+ /**
4380
+ * A type guard function for determining if an unknown object is a {@link FileReference}
4381
+ */
4382
+ function isFileReference(entryValue) {
4383
+ return (typeof entryValue === 'object' &&
4384
+ entryValue !== null &&
4385
+ 'isFileReference' in entryValue &&
4386
+ entryValue.isFileReference === true);
4387
+ }
4388
+ var GraphNodeType;
4389
+ (function (GraphNodeType) {
4390
+ GraphNodeType["Link"] = "Link";
4391
+ GraphNodeType["Node"] = "Node";
4392
+ GraphNodeType["Error"] = "Error";
4393
+ GraphNodeType["Locked"] = "Locked";
4394
+ })(GraphNodeType || (GraphNodeType = {}));
4395
+
4396
+ var StoreLinkStateValues;
4397
+ (function (StoreLinkStateValues) {
4398
+ StoreLinkStateValues[StoreLinkStateValues["NotPresent"] = 0] = "NotPresent";
4399
+ StoreLinkStateValues[StoreLinkStateValues["RefNotPresent"] = 1] = "RefNotPresent";
4400
+ StoreLinkStateValues[StoreLinkStateValues["RefPresent"] = 2] = "RefPresent";
4401
+ StoreLinkStateValues[StoreLinkStateValues["Null"] = 3] = "Null";
4402
+ StoreLinkStateValues[StoreLinkStateValues["Missing"] = 4] = "Missing";
4403
+ StoreLinkStateValues[StoreLinkStateValues["Pending"] = 5] = "Pending";
4404
+ })(StoreLinkStateValues || (StoreLinkStateValues = {}));
4405
+ var FragmentReadResultState;
4406
+ (function (FragmentReadResultState) {
4407
+ FragmentReadResultState[FragmentReadResultState["Missing"] = 0] = "Missing";
4408
+ FragmentReadResultState[FragmentReadResultState["Success"] = 1] = "Success";
4409
+ FragmentReadResultState[FragmentReadResultState["Error"] = 2] = "Error";
4410
+ })(FragmentReadResultState || (FragmentReadResultState = {}));
4411
+ ({
4412
+ state: FragmentReadResultState.Missing,
4413
+ });
4414
+
4415
+ var ResourceParamType;
4416
+ (function (ResourceParamType) {
4417
+ ResourceParamType[ResourceParamType["UrlParameter"] = 0] = "UrlParameter";
4418
+ ResourceParamType[ResourceParamType["QueryParameter"] = 1] = "QueryParameter";
4419
+ ResourceParamType[ResourceParamType["Body"] = 2] = "Body";
4420
+ ResourceParamType[ResourceParamType["Header"] = 3] = "Header";
4421
+ })(ResourceParamType || (ResourceParamType = {}));
4422
+ var TypeCheckShapes;
4423
+ (function (TypeCheckShapes) {
4424
+ TypeCheckShapes[TypeCheckShapes["String"] = 0] = "String";
4425
+ TypeCheckShapes[TypeCheckShapes["Boolean"] = 1] = "Boolean";
4426
+ TypeCheckShapes[TypeCheckShapes["Number"] = 2] = "Number";
4427
+ TypeCheckShapes[TypeCheckShapes["Integer"] = 3] = "Integer";
4428
+ TypeCheckShapes[TypeCheckShapes["Unsupported"] = 4] = "Unsupported";
4429
+ })(TypeCheckShapes || (TypeCheckShapes = {}));
4430
+ // engine version: 0.158.7-bafe2646
4431
+
4432
+ const { keys: keys$1 } = Object;
4433
+
4434
+ // we're going to intentionally bundle this small bit of luvio engine code into
4435
+ // this module to keep it runtime dependency-free
4436
+ const fetchNetworkAdapter = async (resourceRequest, _resourceRequestContext) => {
4437
+ const { baseUri, basePath, body: requestBody, queryParams, method, headers } = resourceRequest;
4438
+ const qs = generateQueryString(queryParams);
4439
+ const path = `${baseUri}${basePath}${qs}`;
4440
+ let body;
4441
+ // some endpoints use FormData for POST request body, check here
4442
+ // if we have a POST body that is FormData
4443
+ if (method === 'post' && isFormData(requestBody)) {
4444
+ // we will populate a DOM FormData and pass that to fetch
4445
+ const newForm = new FormData();
4446
+ for (const { name, value } of requestBody.namedEntries) {
4447
+ // if this is a string or real DOM File then we can
4448
+ // just add it to FormData
4449
+ if (typeof value === 'string' || value instanceof File) {
4450
+ newForm.append(name, value);
3780
4451
  }
3781
- catch (error) {
3782
- logger.warn(`Error parsing response from LEX runtime service: ${error}`);
4452
+ // this network adapter doesn't currently support FileReference's
4453
+ else if (isFileReference(value)) {
4454
+ throw Error(`Luvio fetchNetworkAdapter does not support FileReference's`);
3783
4455
  }
3784
- }
3785
- return response;
3786
- };
3787
- }
3788
- function buildLexRuntimeLuvioAuthExpirationRedirectResponseInterceptor() {
3789
- return async (response) => {
3790
- if (response.status === 401) {
3791
- if (response.body.errorCode === 'INVALID_SESSION_ID') {
3792
- window.setTimeout(() => {
3793
- dispatchGlobalEvent('aura:invalidSession');
3794
- }, 0);
4456
+ // else we have a Luvio File that isn't a real DOM file,
4457
+ // so we need to turn it into a DOM file
4458
+ else {
4459
+ const buffer = await value.arrayBuffer();
4460
+ newForm.append(name, new File([new Uint8Array(buffer)], value.name, {
4461
+ type: value.type,
4462
+ }));
3795
4463
  }
3796
4464
  }
3797
- return response;
4465
+ body = newForm;
4466
+ }
4467
+ else if (requestBody === null) {
4468
+ body = null;
4469
+ }
4470
+ else {
4471
+ body = JSON.stringify(requestBody);
4472
+ headers['Content-Type'] = 'application/json';
4473
+ }
4474
+ const response = await fetch(path, {
4475
+ method: method.toUpperCase(),
4476
+ headers: generateHeaders(headers),
4477
+ body,
4478
+ });
4479
+ const { status, ok, statusText } = response;
4480
+ // coerce headers
4481
+ const responseHeaders = {};
4482
+ response.headers.forEach((value, key) => {
4483
+ responseHeaders[key] = value;
4484
+ });
4485
+ // parse body
4486
+ let responseBody = null;
4487
+ if (status !== 204) {
4488
+ const contentType = responseHeaders['content-type'];
4489
+ responseBody =
4490
+ contentType && contentType.startsWith('application/json')
4491
+ ? await response.json()
4492
+ : await response.text();
4493
+ }
4494
+ return {
4495
+ body: responseBody,
4496
+ status,
4497
+ statusText,
4498
+ ok,
4499
+ headers: responseHeaders,
3798
4500
  };
3799
- }
3800
-
3801
- /**
3802
- * Extracts the ErrorId from a server error response message.
3803
- * Looks for pattern: "ErrorId if you contact support: 1033627214-37969 (-1272663771)"
3804
- * Returns the numeric value in parentheses.
3805
- *
3806
- * @param responseBody The response body text to parse.
3807
- * @returns The extracted error ID, or null if not found.
3808
- */
3809
- function extractErrorIdFromResponse(responseBody) {
3810
- try {
3811
- const parsed = JSON.parse(responseBody);
3812
- if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].message) {
3813
- const message = parsed[0].message;
3814
- // Look for pattern: "ErrorId if you contact support: XXXXXX-XXXXX (YYYYY)"
3815
- const match = message.match(/ErrorId[^:]*:\s*[\d-]+\s*\((-?\d+)\)/);
3816
- if (match && match[1]) {
3817
- return parseInt(match[1], 10);
3818
- }
3819
- }
4501
+ };
4502
+ function generateQueryString(params) {
4503
+ const queryStrings = [];
4504
+ for (const key of keys$1(params)) {
4505
+ queryStrings.push(`${key}=${params[key]}`);
3820
4506
  }
3821
- catch (e) {
3822
- // If parsing fails, return null to use fallback
4507
+ if (queryStrings.length > 0) {
4508
+ return `?${queryStrings.join('&')}`;
3823
4509
  }
3824
- return null;
4510
+ return '';
3825
4511
  }
3826
- /**
3827
- * Generates a unique error ID for tracking specific error occurrences.
3828
- * Used as fallback when server doesn't provide an ErrorId.
3829
- *
3830
- * @param idInput The input value to hash.
3831
- * @returns A unique error ID in Salesforce-compatible numeric format.
3832
- */
3833
- function generateErrorId(idInput) {
3834
- let hash = 0;
3835
- if (!idInput || idInput.length === 0) {
3836
- return hash;
3837
- }
3838
- let i, chr;
3839
- for (i = 0; i < idInput.length; i++) {
3840
- chr = idInput.charCodeAt(i);
3841
- hash = (hash << 5) - hash + chr;
3842
- hash |= 0; // Convert to 32bit integer
4512
+ function generateHeaders(headers) {
4513
+ const fetchHeaders = new Headers();
4514
+ for (const key of keys$1(headers)) {
4515
+ fetchHeaders.set(key, headers[key]);
3843
4516
  }
3844
- return hash;
4517
+ return fetchHeaders;
3845
4518
  }
4519
+
4520
+ const SALESFORCE_API_BASE_URI_FLAG = 'api.salesforce.com';
4521
+ const X_REQUEST_ID_HEADER = 'x-request-id';
4522
+ const SFAPController = 'SalesforceApiPlatformController';
4523
+ const SFAPJwtMethod = 'getSFAPLightningJwtService';
3846
4524
  /**
3847
- * Gets error ID from response body or generates a fallback.
3848
- * Tries to extract server-provided ErrorId first, falls back to generated hash.
4525
+ * We expect jwt info and baseUri to be present in the response.
3849
4526
  *
3850
- * @param responseBody The response body to parse.
3851
- * @param status The HTTP status code (for fallback).
3852
- * @param statusText The HTTP status text (for fallback, optional).
3853
- * @returns A numeric error ID.
4527
+ * @param body
3854
4528
  */
3855
- function getOrGenerateErrorId(responseBody, status, statusText) {
3856
- const extractedId = extractErrorIdFromResponse(responseBody);
3857
- if (extractedId !== null) {
3858
- return extractedId;
4529
+ function validateResponse(body) {
4530
+ if (!body || !body.jwt || !body.baseUri) {
4531
+ // wrapped the invocation in env conditional
4532
+ // eslint-disable-next-line @salesforce/lds/no-error-in-production
4533
+ throw new Error(`Expected jwt info and baseUri to be present but instead got: ${JSON.stringify(body)}`);
3859
4534
  }
3860
- // Fallback to generated error ID using status and timestamp
3861
- // statusText is optional and may not always be present
3862
- const context = [status, statusText || '', Date.now()].join('|');
3863
- return generateErrorId(context);
3864
- }
3865
- function buildLexRuntime5xxStatusResponseInterceptor(logger) {
3866
- return async (response) => {
3867
- if (response.status >= 500 && response.status < 600) {
3868
- const internalLogMessage = `LEX runtime 5xx: ${response.status} ${response.statusText || ''}`.trim();
3869
- logger.warn(internalLogMessage);
3870
- const userMessage = 'A server error occurred. Please try again later.';
3871
- // Try to extract ErrorId from response body, fallback to generated ID
3872
- let errorId;
3873
- try {
3874
- const responseText = await response.clone().text();
3875
- errorId = getOrGenerateErrorId(responseText, response.status, response.statusText);
3876
- }
3877
- catch (e) {
3878
- // If reading response fails, use fallback
3879
- const context = [response.status, response.statusText, Date.now()].join('|');
3880
- errorId = generateErrorId(context);
3881
- }
3882
- // Create an error object similar to Aura's current shape for system errors
3883
- const error = {
3884
- message: userMessage,
3885
- severity: 'ALERT',
3886
- name: 'LEXRuntimeError',
3887
- stack: null,
3888
- handled: false,
3889
- reported: false,
3890
- id: errorId,
3891
- };
3892
- const evtArgs = {
3893
- message: error.message,
3894
- error: null,
3895
- auraError: error,
3896
- };
3897
- // Fire the event asynchronously, similar to the legacy setTimeout pattern
3898
- window.setTimeout(() => {
3899
- dispatchGlobalEvent('markup://aura:systemError', evtArgs);
3900
- }, 0);
3901
- // Throw a simple error to terminate the request completely
3902
- // The consumer has NOT opted in to handle 5xx errors, so we don't return any response
3903
- // The systemError event above will handle showing the gack dialog
3904
- throw new Error(error.message);
3905
- }
3906
- return response;
3907
- };
3908
- }
3909
- function buildLexRuntimeLuvio5xxStatusResponseInterceptor() {
3910
- return async (response) => {
3911
- if (response.status >= 500 && response.status < 600) {
3912
- const userMessage = 'A server error occurred. Please try again later.';
3913
- // Try to extract ErrorId from response body, fallback to generated ID
3914
- let errorId;
3915
- try {
3916
- const responseBody = response.body ? JSON.stringify(response.body) : '';
3917
- errorId = getOrGenerateErrorId(responseBody, response.status, response.statusText);
3918
- }
3919
- catch (e) {
3920
- // If reading response fails, use fallback
3921
- const context = [response.status, response.statusText, Date.now()].join('|');
3922
- errorId = generateErrorId(context);
3923
- }
3924
- // Create an error object similar to Aura's current shape for system errors
3925
- const error = {
3926
- message: userMessage,
3927
- severity: 'ALERT',
3928
- name: 'LEXRuntimeError',
3929
- stack: null,
3930
- handled: false,
3931
- reported: false,
3932
- id: errorId,
3933
- };
3934
- const evtArgs = {
3935
- message: error.message,
3936
- error: null,
3937
- auraError: error,
3938
- };
3939
- // Fire the event asynchronously, similar to the legacy setTimeout pattern
3940
- window.setTimeout(() => {
3941
- dispatchGlobalEvent('markup://aura:systemError', evtArgs);
3942
- }, 0);
3943
- // Throw a simple error to terminate the request completely
3944
- // The consumer has NOT opted in to handle 5xx errors, so we don't return any response
3945
- // The systemError event above will handle showing the gack dialog
3946
- throw new Error(error.message);
3947
- }
3948
- return response;
3949
- };
3950
4535
  }
3951
-
3952
- function buildPageScopedCacheRequestInterceptor() {
3953
- return async (fetchArgs) => {
3954
- const pageScopedCacheHeaders = {};
3955
- // Allow the instrumentation util to set up the header value on our "dummy" header object
3956
- pageScopedCache.addHeader(pageScopedCacheHeaders);
3957
- let returnedFetchArgs = fetchArgs;
3958
- // If it set a value, add it to our fetchParams
3959
- Object.entries(pageScopedCacheHeaders).forEach(([key, value]) => {
3960
- returnedFetchArgs = setHeader(key, value, returnedFetchArgs);
4536
+ /**
4537
+ * Resolves Jwt token for SFAP by calling Aura action
4538
+ * {@link JwtResolver} for platform SFAP
4539
+ */
4540
+ const platformSfapJwtResolver = {
4541
+ getJwt() {
4542
+ return new Promise((resolve, reject) => {
4543
+ dispatchAuraAction(`${SFAPController}.${SFAPJwtMethod}`, {}, defaultActionConfig)
4544
+ .then((response) => {
4545
+ const body = response.body;
4546
+ if (process.env.NODE_ENV !== 'production') {
4547
+ validateResponse(body);
4548
+ }
4549
+ resolve({
4550
+ jwt: body.jwt,
4551
+ extraInfo: {
4552
+ baseUri: body.baseUri,
4553
+ },
4554
+ });
4555
+ })
4556
+ .catch((error) => {
4557
+ if (error instanceof Error) {
4558
+ reject(error.message);
4559
+ return;
4560
+ }
4561
+ // AuraFetchResponse errors
4562
+ const { status } = error;
4563
+ if (status !== HttpStatusCode$2.ServerError) {
4564
+ // ConnectInJavaError
4565
+ reject(error.body.message);
4566
+ return;
4567
+ }
4568
+ reject(error.body.error);
4569
+ });
3961
4570
  });
3962
- return resolvedPromiseLike$3(returnedFetchArgs);
4571
+ },
4572
+ };
4573
+ const jwtManager = new JwtManager(new JwtRepository(), platformSfapJwtResolver);
4574
+ const authenticateRequest = (resourceRequest, jwt) => {
4575
+ const { token } = jwt;
4576
+ const { headers } = resourceRequest;
4577
+ // Only supporting Bearer <auth-scheme>
4578
+ const authenticatedHeaders = {
4579
+ ...headers,
4580
+ Authorization: `Bearer ${token}`,
4581
+ };
4582
+ return {
4583
+ ...resourceRequest,
4584
+ headers: authenticatedHeaders,
4585
+ };
4586
+ };
4587
+ /**
4588
+ * This hook is used to modify the resource request before it is sent to the server.
4589
+ * SFAP uses extraInfo assocaiated JwtToken to update the baseUri for the resource request.
4590
+ *
4591
+ * @param resourceRequest
4592
+ * @param jwtToken
4593
+ * @returns resourceRequest with updated baseUri
4594
+ */
4595
+ const modifySfapResourceRequest = function (resourceRequest, jwtToken) {
4596
+ const { baseUri } = jwtToken.extraInfo;
4597
+ return {
4598
+ ...resourceRequest,
4599
+ baseUri,
3963
4600
  };
4601
+ };
4602
+ // used for instrumentation and tracking
4603
+ let sfapRequestCount = 0;
4604
+ const sfapNetworkAdapter = async (resourceRequest, resourceRequestContext) => {
4605
+ let jwtToken;
4606
+ try {
4607
+ jwtToken = await jwtManager.getJwt();
4608
+ }
4609
+ catch (error) {
4610
+ if (process.env.NODE_ENV !== 'production') {
4611
+ throw new Error(`There was an error while fetching Jwt token: ${JSON.stringify(error)}`);
4612
+ }
4613
+ return Promise.reject(new LdsNetworkAdapterErrorResponse('Unable to fetch the jwt required to make this request', error));
4614
+ }
4615
+ let authenticatedRequest = authenticateRequest(resourceRequest, jwtToken);
4616
+ authenticatedRequest = modifySfapResourceRequest(authenticatedRequest, jwtToken);
4617
+ // --- instrumentation block --- start
4618
+ const uniqueRequestTaskIdentifier = 'sfap-' + sfapRequestCount++;
4619
+ const uniqueRequestGuid = generateRequestId();
4620
+ // request id header allows logging the request id and searching for the request logs
4621
+ authenticatedRequest.headers[X_REQUEST_ID_HEADER] = uniqueRequestGuid;
4622
+ let fetchComplete = false;
4623
+ ThirdPartyTracker.registerHandler(uniqueRequestTaskIdentifier, 'sfap-request', () => fetchComplete);
4624
+ markStart('transport', 'request', {
4625
+ auraXHRId: uniqueRequestTaskIdentifier,
4626
+ requestLength: -1,
4627
+ background: false,
4628
+ actionDefs: ['sfap'],
4629
+ requestId: uniqueRequestGuid,
4630
+ });
4631
+ // --- instrumentation block --- end
4632
+ const fetchNetworkAdapterPromise = fetchNetworkAdapter(authenticatedRequest);
4633
+ // --- instrumentation block --- start
4634
+ fetchNetworkAdapterPromise.finally(function requestCompleteTracker() {
4635
+ ThirdPartyTracker.markLoaded(uniqueRequestTaskIdentifier);
4636
+ fetchComplete = true;
4637
+ markEnd('transport', 'request', {
4638
+ auraXHRId: uniqueRequestTaskIdentifier,
4639
+ });
4640
+ });
4641
+ // --- instrumentation block --- end
4642
+ return fetchNetworkAdapterPromise;
4643
+ };
4644
+ class LdsNetworkAdapterErrorResponse extends Error {
4645
+ constructor(message, _error) {
4646
+ super(message);
4647
+ this._error = _error;
4648
+ this.errorType = 'networkAdapterError';
4649
+ this.name = this.constructor.name;
4650
+ }
4651
+ }
4652
+ const composedNetworkAdapter$1 = {
4653
+ shouldHandleRequest(resourceRequest) {
4654
+ return resourceRequest.baseUri === SALESFORCE_API_BASE_URI_FLAG;
4655
+ },
4656
+ adapter: sfapNetworkAdapter,
4657
+ };
4658
+ function generateRequestId() {
4659
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
4660
+ // as nov. 2025 caniuse says this has 93.5% support (all modern browsers)
4661
+ return crypto.randomUUID();
4662
+ }
4663
+ else {
4664
+ // fallback to Math.random() if crypto.randomUUID is not available (unlikely)
4665
+ return (Math.random().toString(36).substring(2, 15) +
4666
+ Math.random().toString(36).substring(2, 15));
4667
+ }
3964
4668
  }
3965
4669
 
4670
+ function e(e){this.message=e;}e.prototype=new Error,e.prototype.name="InvalidCharacterError";"undefined"!=typeof window&&window.atob&&window.atob.bind(window)||function(r){var t=String(r).replace(/=+$/,"");if(t.length%4==1)throw new e("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,o,a=0,i=0,c="";o=t.charAt(i++);~o&&(n=a%4?64*n+o:o,a++%4)?c+=String.fromCharCode(255&n>>(-2*a&6)):0)o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o);return c};function n(e){this.message=e;}n.prototype=new Error,n.prototype.name="InvalidTokenError";
4671
+
3966
4672
  /**
3967
4673
  * Copyright (c) 2022, Salesforce, Inc.,
3968
4674
  * All rights reserved.
@@ -4001,7 +4707,7 @@ function getEnvironmentSetting(name) {
4001
4707
  }
4002
4708
  return undefined;
4003
4709
  }
4004
- // version: 1.401.0-c620f9ffed
4710
+ // version: 1.403.0-5476a05446
4005
4711
 
4006
4712
  /**
4007
4713
  * Observability / Critical Availability Program (230+)
@@ -4343,506 +5049,858 @@ class Instrumentation {
4343
5049
  this.refreshAdapterEvents[adapterName] += 1;
4344
5050
  this.lastRefreshApiCall = null;
4345
5051
  }
4346
- /**
4347
- * Increments call stat for incoming refresh api call, and sets the name
4348
- * to be used in {@link aggregateRefreshCalls}
4349
- * @param from The name of the refresh function called.
4350
- */
4351
- handleRefreshApiCall(apiName) {
4352
- this.refreshApiCallEventStats[apiName] += 1;
4353
- // set function call to be used with aggregateRefreshCalls
4354
- this.lastRefreshApiCall = apiName;
5052
+ /**
5053
+ * Increments call stat for incoming refresh api call, and sets the name
5054
+ * to be used in {@link aggregateRefreshCalls}
5055
+ * @param from The name of the refresh function called.
5056
+ */
5057
+ handleRefreshApiCall(apiName) {
5058
+ this.refreshApiCallEventStats[apiName] += 1;
5059
+ // set function call to be used with aggregateRefreshCalls
5060
+ this.lastRefreshApiCall = apiName;
5061
+ }
5062
+ /**
5063
+ * W-7302241
5064
+ * Logs refresh call summary stats as a LightningInteraction.
5065
+ */
5066
+ logRefreshStats() {
5067
+ if (keys(this.refreshAdapterEvents).length > 0) {
5068
+ interaction(REFRESH_PAYLOAD_TARGET, REFRESH_PAYLOAD_SCOPE, this.refreshAdapterEvents, REFRESH_EVENTSOURCE, REFRESH_EVENTTYPE, this.refreshApiCallEventStats);
5069
+ this.resetRefreshStats();
5070
+ }
5071
+ }
5072
+ /**
5073
+ * Resets the stat trackers for refresh call events.
5074
+ */
5075
+ resetRefreshStats() {
5076
+ this.refreshAdapterEvents = {};
5077
+ this.refreshApiCallEventStats = {
5078
+ [REFRESH_APEX_KEY]: 0,
5079
+ [REFRESH_UIAPI_KEY]: 0,
5080
+ [SUPPORTED_KEY]: 0,
5081
+ [UNSUPPORTED_KEY]: 0,
5082
+ };
5083
+ this.lastRefreshApiCall = null;
5084
+ }
5085
+ /**
5086
+ * W-7801618
5087
+ * Counter for occurrences where the incoming record to be merged has a different apiName.
5088
+ * Dynamically generated metric, stored in an {@link RecordApiNameChangeCounters} object.
5089
+ *
5090
+ * @param context The transaction context.
5091
+ *
5092
+ * Note: Short-lived metric candidate, remove at the end of 230
5093
+ */
5094
+ incrementRecordApiNameChangeCount(_incomingApiName, existingApiName) {
5095
+ let apiNameChangeCounter = this.recordApiNameChangeCounters[existingApiName];
5096
+ if (apiNameChangeCounter === undefined) {
5097
+ apiNameChangeCounter = counter(createMetricsKey(NAMESPACE, RECORD_API_NAME_CHANGE_COUNT_METRIC_NAME, existingApiName));
5098
+ this.recordApiNameChangeCounters[existingApiName] = apiNameChangeCounter;
5099
+ }
5100
+ apiNameChangeCounter.increment(1);
5101
+ }
5102
+ /**
5103
+ * W-8620679
5104
+ * Increment the counter for an UnfulfilledSnapshotError coming from luvio
5105
+ *
5106
+ * @param context The transaction context.
5107
+ */
5108
+ incrementAdapterRequestErrorCount(context) {
5109
+ // We are consolidating all apex adapter instrumentation calls under a single key
5110
+ const adapterName = normalizeAdapterName(context.adapterName);
5111
+ let adapterRequestErrorCounter = this.adapterUnfulfilledErrorCounters[adapterName];
5112
+ if (adapterRequestErrorCounter === undefined) {
5113
+ adapterRequestErrorCounter = counter(createMetricsKey(OBSERVABILITY_NAMESPACE, ADAPTER_ERROR_COUNT_METRIC_NAME, adapterName));
5114
+ this.adapterUnfulfilledErrorCounters[adapterName] = adapterRequestErrorCounter;
5115
+ }
5116
+ adapterRequestErrorCounter.increment(1);
5117
+ totalAdapterErrorMetric.increment(1);
5118
+ }
5119
+ }
5120
+ function createMetricsKey(owner, name, unit) {
5121
+ let metricName = name;
5122
+ if (unit) {
5123
+ metricName = metricName + '.' + unit;
5124
+ }
5125
+ return {
5126
+ get() {
5127
+ return { owner: owner, name: metricName };
5128
+ },
5129
+ };
5130
+ }
5131
+ /**
5132
+ * Returns whether adapter is an Apex one or not.
5133
+ * @param adapterName The name of the adapter.
5134
+ */
5135
+ function isApexAdapter(adapterName) {
5136
+ return adapterName.indexOf(APEX_ADAPTER_NAME) > -1;
5137
+ }
5138
+ /**
5139
+ * Normalizes getApex adapter names to `Apex.getApex`. Non-Apex adapters will be prefixed with
5140
+ * API family, if supplied. Example: `UiApi.getRecord`.
5141
+ *
5142
+ * Note: If you are adding additional logging that can come from getApex adapter contexts that provide
5143
+ * the full getApex adapter name (i.e. getApex_[namespace]_[class]_[function]_[continuation]),
5144
+ * ensure to call this method to normalize all logging to 'getApex'. This
5145
+ * is because Argus has a 50k key cardinality limit. More context: W-8379680.
5146
+ *
5147
+ * @param adapterName The name of the adapter.
5148
+ * @param apiFamily The API family of the adapter.
5149
+ */
5150
+ function normalizeAdapterName(adapterName, apiFamily) {
5151
+ if (isApexAdapter(adapterName)) {
5152
+ return NORMALIZED_APEX_ADAPTER_NAME;
5153
+ }
5154
+ return apiFamily ? `${apiFamily}.${adapterName}` : adapterName;
5155
+ }
5156
+ const timerMetricTracker = create(null);
5157
+ /**
5158
+ * Calls instrumentation/service telemetry timer
5159
+ * @param name Name of the metric
5160
+ * @param duration number to update backing percentile histogram, negative numbers ignored
5161
+ */
5162
+ function updateTimerMetric(name, duration) {
5163
+ let metric = timerMetricTracker[name];
5164
+ if (metric === undefined) {
5165
+ metric = timer(createMetricsKey(NAMESPACE, name));
5166
+ timerMetricTracker[name] = metric;
5167
+ }
5168
+ timerMetricAddDuration(metric, duration);
5169
+ }
5170
+ function timerMetricAddDuration(timer, duration) {
5171
+ // Guard against negative values since it causes error to be thrown by MetricsService
5172
+ if (duration >= 0) {
5173
+ timer.addDuration(duration);
5174
+ }
5175
+ }
5176
+ /**
5177
+ * W-10315098
5178
+ * Increments the counter associated with the request response. Counts are bucketed by status.
5179
+ */
5180
+ const requestResponseMetricTracker = create(null);
5181
+ function incrementRequestResponseCount(cb) {
5182
+ const status = cb().status;
5183
+ let metric = requestResponseMetricTracker[status];
5184
+ if (metric === undefined) {
5185
+ metric = counter(createMetricsKey(OBSERVABILITY_NAMESPACE, NETWORK_ADAPTER_RESPONSE_METRIC_NAME, `${status.valueOf()}`));
5186
+ requestResponseMetricTracker[status] = metric;
5187
+ }
5188
+ metric.increment();
5189
+ }
5190
+ function logObjectInfoChanged() {
5191
+ logObjectInfoChanged$1();
5192
+ }
5193
+ /**
5194
+ * Create a new instrumentation cache stats and return it.
5195
+ *
5196
+ * @param name The cache logger name.
5197
+ */
5198
+ function registerLdsCacheStats(name) {
5199
+ return registerCacheStats(`${NAMESPACE}:${name}`);
5200
+ }
5201
+ /**
5202
+ * Add or overwrite hooks that require aura implementations
5203
+ */
5204
+ function setAuraInstrumentationHooks() {
5205
+ instrument({
5206
+ recordConflictsResolved: (serverRequestCount) => {
5207
+ // Ignore 0 values which can originate from ADS bridge
5208
+ if (serverRequestCount > 0) {
5209
+ updatePercentileHistogramMetric('record-conflicts-resolved', serverRequestCount);
5210
+ }
5211
+ },
5212
+ nullDisplayValueConflict: ({ fieldType, areValuesEqual }) => {
5213
+ const metricName = `merge-null-dv-count.${fieldType}`;
5214
+ if (fieldType === 'scalar') {
5215
+ incrementCounterMetric(`${metricName}.${areValuesEqual}`);
5216
+ }
5217
+ else {
5218
+ incrementCounterMetric(metricName);
5219
+ }
5220
+ },
5221
+ getRecordNotifyChangeAllowed: incrementGetRecordNotifyChangeAllowCount,
5222
+ getRecordNotifyChangeDropped: incrementGetRecordNotifyChangeDropCount,
5223
+ notifyRecordUpdateAvailableAllowed: incrementNotifyRecordUpdateAvailableAllowCount,
5224
+ notifyRecordUpdateAvailableDropped: incrementNotifyRecordUpdateAvailableDropCount,
5225
+ recordApiNameChanged: instrumentation.incrementRecordApiNameChangeCount.bind(instrumentation),
5226
+ weakEtagZero: instrumentation.aggregateWeakETagEvents.bind(instrumentation),
5227
+ getRecordNotifyChangeNetworkResult: instrumentation.notifyChangeNetwork.bind(instrumentation),
5228
+ });
5229
+ withRegistration('@salesforce/lds-adapters-uiapi', (reg) => setLdsAdaptersUiapiInstrumentation(reg));
5230
+ instrument$1({
5231
+ logCrud: logCRUDLightningInteraction,
5232
+ networkResponse: incrementRequestResponseCount,
5233
+ });
5234
+ instrument$2({
5235
+ error: logError$2,
5236
+ });
5237
+ instrument$3({
5238
+ refreshCalled: instrumentation.handleRefreshApiCall.bind(instrumentation),
5239
+ instrumentAdapter: instrumentation.instrumentAdapter.bind(instrumentation),
5240
+ });
5241
+ instrument$4({
5242
+ timerMetricAddDuration: updateTimerMetric,
5243
+ });
5244
+ // Our getRecord through aggregate-ui CRUD logging has moved
5245
+ // to lds-network-adapter. We still need to respect the
5246
+ // orgs environment setting
5247
+ if (forceRecordTransactionsDisabled$1 === false) {
5248
+ ldsNetworkAdapterInstrument({
5249
+ getRecordAggregateResolve: (cb) => {
5250
+ const { recordId, apiName } = cb();
5251
+ logCRUDLightningInteraction('read', {
5252
+ recordId,
5253
+ recordType: apiName,
5254
+ state: 'SUCCESS',
5255
+ });
5256
+ },
5257
+ getRecordAggregateReject: (cb) => {
5258
+ const recordId = cb();
5259
+ logCRUDLightningInteraction('read', {
5260
+ recordId,
5261
+ state: 'ERROR',
5262
+ });
5263
+ },
5264
+ });
5265
+ }
5266
+ withRegistration('@salesforce/lds-network-adapter', (reg) => setLdsNetworkAdapterInstrumentation(reg));
5267
+ }
5268
+ let stateManagerInstrumentationHooksInitialized = false;
5269
+ function setStateManagerInstrumentationHooks() {
5270
+ if (stateManagerInstrumentationHooksInitialized) {
5271
+ return;
4355
5272
  }
4356
- /**
4357
- * W-7302241
4358
- * Logs refresh call summary stats as a LightningInteraction.
4359
- */
4360
- logRefreshStats() {
4361
- if (keys(this.refreshAdapterEvents).length > 0) {
4362
- interaction(REFRESH_PAYLOAD_TARGET, REFRESH_PAYLOAD_SCOPE, this.refreshAdapterEvents, REFRESH_EVENTSOURCE, REFRESH_EVENTTYPE, this.refreshApiCallEventStats);
4363
- this.resetRefreshStats();
4364
- }
5273
+ instrument$5({
5274
+ stateCreated: incrementStateCreatedCount,
5275
+ });
5276
+ stateManagerInstrumentationHooksInitialized = true;
5277
+ }
5278
+ /**
5279
+ * Initialize the instrumentation and instrument the LDS instance and the InMemoryStore.
5280
+ *
5281
+ * @param luvio The Luvio instance to instrument.
5282
+ * @param store The InMemoryStore to instrument.
5283
+ */
5284
+ function setupInstrumentation(luvio, store) {
5285
+ setupInstrumentation$1(luvio, store);
5286
+ setAuraInstrumentationHooks();
5287
+ setStateManagerInstrumentationHooks();
5288
+ }
5289
+ /**
5290
+ * Note: locator.scope is set to 'force_record' in order for the instrumentation gate to work, which will
5291
+ * disable all crud operations if it is on.
5292
+ * @param eventSource - Source of the logging event.
5293
+ * @param attributes - Free form object of attributes to log.
5294
+ */
5295
+ function logCRUDLightningInteraction(eventSource, attributes) {
5296
+ interaction(eventSource, 'force_record', null, eventSource, 'crud', attributes);
5297
+ }
5298
+ const instrumentation = new Instrumentation();
5299
+
5300
+ const forceRecordTransactionsDisabled = getEnvironmentSetting(EnvironmentSettings.ForceRecordTransactionsDisabled);
5301
+ //TODO: Some duplication here that can be most likely moved to a util class
5302
+ const NO_RECORD_ID_204 = '204_NO_RECORD_ID';
5303
+ const NO_RECORD_TYPE_204 = '204_NO_RECORD_TYPE';
5304
+ let crudInstrumentationCallbacks = {};
5305
+ let crudRLInstrumentationCallbacks = {};
5306
+ if (forceRecordTransactionsDisabled === false) {
5307
+ // Record callbacks
5308
+ crudInstrumentationCallbacks = {
5309
+ createRecordRejectFunction: (config) => {
5310
+ logCRUDLightningInteraction(CrudEventType.CREATE, {
5311
+ // recordId: config.params.recordInput.apiName, // seems wrong?
5312
+ recordId: config.params.recordId || NO_RECORD_ID_204,
5313
+ state: CrudEventState.ERROR,
5314
+ });
5315
+ },
5316
+ createRecordResolveFunction: (config) => {
5317
+ const recordId = config.body ? config.body.id : NO_RECORD_ID_204;
5318
+ const recordType = config.body ? config.body.apiName : NO_RECORD_TYPE_204;
5319
+ logCRUDLightningInteraction(CrudEventType.CREATE, {
5320
+ recordId,
5321
+ recordType,
5322
+ state: CrudEventState.SUCCESS,
5323
+ });
5324
+ },
5325
+ deleteRecordRejectFunction: (config) => {
5326
+ logCRUDLightningInteraction(CrudEventType.DELETE, {
5327
+ recordId: config.params.recordId,
5328
+ state: CrudEventState.ERROR,
5329
+ });
5330
+ },
5331
+ deleteRecordResolveFunction: (config) => {
5332
+ logCRUDLightningInteraction(CrudEventType.DELETE, {
5333
+ recordId: config.params.recordId,
5334
+ state: CrudEventState.SUCCESS,
5335
+ });
5336
+ },
5337
+ // These should be handled by the network adapater?
5338
+ // getRecordAggregateRejectFunction: (config: InstrumentationRejectConfig) => {
5339
+ // logCRUDLightningInteraction(CrudEventType.READ, {
5340
+ // recordId: config.params.recordId,
5341
+ // state: CrudEventState.ERROR,
5342
+ // });
5343
+ // },
5344
+ // getRecordAggregateResolveFunction: (config: InstrumentationResolveConfig) => {
5345
+ // logCRUDLightningInteraction(CrudEventType.READ, {
5346
+ // recordId: config.params.recordId,
5347
+ // recordType: config.body.apiName,
5348
+ // state: CrudEventState.SUCCESS,
5349
+ // });
5350
+ // },
5351
+ getRecordRejectFunction: (config) => {
5352
+ logCRUDLightningInteraction(CrudEventType.READ, {
5353
+ recordId: config.params.recordId,
5354
+ state: CrudEventState.ERROR,
5355
+ });
5356
+ },
5357
+ getRecordResolveFunction: (config) => {
5358
+ logCRUDLightningInteraction(CrudEventType.READ, {
5359
+ recordId: config.params.recordId,
5360
+ recordType: config.body.apiName,
5361
+ state: CrudEventState.SUCCESS,
5362
+ });
5363
+ },
5364
+ updateRecordRejectFunction: (config) => {
5365
+ logCRUDLightningInteraction(CrudEventType.UPDATE, {
5366
+ recordId: config.params.recordId,
5367
+ state: CrudEventState.ERROR,
5368
+ });
5369
+ },
5370
+ updateRecordResolveFunction: (config) => {
5371
+ const recordType = config.body ? config.body.apiName : NO_RECORD_TYPE_204;
5372
+ logCRUDLightningInteraction(CrudEventType.UPDATE, {
5373
+ recordId: config.params.recordId,
5374
+ recordType,
5375
+ state: CrudEventState.SUCCESS,
5376
+ });
5377
+ },
5378
+ };
5379
+ // Related list callbacks
5380
+ crudRLInstrumentationCallbacks = {
5381
+ getRelatedListRecordsRejectFunction: (config) => {
5382
+ logCRUDLightningInteraction(CrudEventType.READS, {
5383
+ parentRecordId: config.params.parentRecordId,
5384
+ relatedListId: config.params.relatedListId,
5385
+ state: CrudEventState.ERROR,
5386
+ });
5387
+ },
5388
+ getRelatedListRecordsResolveFunction: (config) => {
5389
+ logGetRelatedListRecordsInteraction(config.body);
5390
+ },
5391
+ getRelatedListRecordsBatchRejectFunction: (config) => {
5392
+ logCRUDLightningInteraction(CrudEventType.READS, {
5393
+ parentRecordId: config.params.parentRecordId,
5394
+ relatedListIds: config.params.relatedListParameters.map((entry) => entry.relatedListId),
5395
+ state: CrudEventState.ERROR,
5396
+ });
5397
+ },
5398
+ getRelatedListRecordsBatchResolveFunction: (config) => {
5399
+ config.body.results.forEach((res) => {
5400
+ // Log for each RL that was returned from batch endpoint
5401
+ if (res.statusCode === 200) {
5402
+ logGetRelatedListRecordsInteraction(res.result);
5403
+ }
5404
+ });
5405
+ },
5406
+ };
5407
+ }
5408
+ // Helper function copied from ui-api
5409
+ function logGetRelatedListRecordsInteraction(body) {
5410
+ const records = body.records;
5411
+ // Don't log anything if the related list has no records.
5412
+ if (records.length === 0) {
5413
+ return;
4365
5414
  }
5415
+ const recordIds = records.map((record) => {
5416
+ return record.id;
5417
+ });
4366
5418
  /**
4367
- * Resets the stat trackers for refresh call events.
5419
+ * In almost every case - the relatedList records will all be of the same apiName, but there is an edge case for
5420
+ Activities entity that could return Events & Tasks- so handle that case by returning a joined string.
5421
+ ADS Implementation only looks at the first record returned to determine the apiName.
5422
+ See force/recordLibrary/recordMetricsPlugin.js _getRecordType method.
4368
5423
  */
4369
- resetRefreshStats() {
4370
- this.refreshAdapterEvents = {};
4371
- this.refreshApiCallEventStats = {
4372
- [REFRESH_APEX_KEY]: 0,
4373
- [REFRESH_UIAPI_KEY]: 0,
4374
- [SUPPORTED_KEY]: 0,
4375
- [UNSUPPORTED_KEY]: 0,
4376
- };
4377
- this.lastRefreshApiCall = null;
5424
+ logCRUDLightningInteraction(CrudEventType.READS, {
5425
+ parentRecordId: body.listReference.inContextOfRecordId,
5426
+ relatedListId: body.listReference.relatedListId,
5427
+ recordIds,
5428
+ recordType: body.records[0].apiName,
5429
+ state: CrudEventState.SUCCESS,
5430
+ });
5431
+ }
5432
+ const crudInstrumentationConfig = {
5433
+ records: {
5434
+ post: {
5435
+ rejectFn: crudInstrumentationCallbacks.createRecordRejectFunction,
5436
+ resolveFn: crudInstrumentationCallbacks.createRecordResolveFunction,
5437
+ },
5438
+ get: {
5439
+ rejectFn: crudInstrumentationCallbacks.getRecordRejectFunction,
5440
+ resolveFn: crudInstrumentationCallbacks.getRecordResolveFunction,
5441
+ },
5442
+ patch: {
5443
+ rejectFn: crudInstrumentationCallbacks.updateRecordRejectFunction,
5444
+ resolveFn: crudInstrumentationCallbacks.updateRecordResolveFunction,
5445
+ },
5446
+ delete: {
5447
+ rejectFn: crudInstrumentationCallbacks.deleteRecordRejectFunction,
5448
+ resolveFn: crudInstrumentationCallbacks.deleteRecordResolveFunction,
5449
+ },
5450
+ },
5451
+ relatedListRecords: {
5452
+ post: {
5453
+ rejectFn: crudRLInstrumentationCallbacks.getRelatedListRecordsRejectFunction,
5454
+ resolveFn: crudRLInstrumentationCallbacks.getRelatedListRecordsResolveFunction,
5455
+ },
5456
+ },
5457
+ relatedListRecordsBatch: {
5458
+ post: {
5459
+ rejectFn: crudRLInstrumentationCallbacks.getRelatedListRecordsBatchRejectFunction,
5460
+ resolveFn: crudRLInstrumentationCallbacks.getRelatedListRecordsBatchResolveFunction,
5461
+ },
5462
+ },
5463
+ };
5464
+ function checkAndLogCrudInteraction(request, isResolve, error, response) {
5465
+ let configPath;
5466
+ const baseUrl = `${request.baseUri}${request.basePath}`;
5467
+ if (baseUrl.startsWith(UIAPI_RECORDS_PATH)) {
5468
+ configPath = crudInstrumentationConfig['records']; // maybe use a constant for this
4378
5469
  }
4379
- /**
4380
- * W-7801618
4381
- * Counter for occurrences where the incoming record to be merged has a different apiName.
4382
- * Dynamically generated metric, stored in an {@link RecordApiNameChangeCounters} object.
4383
- *
4384
- * @param context The transaction context.
4385
- *
4386
- * Note: Short-lived metric candidate, remove at the end of 230
4387
- */
4388
- incrementRecordApiNameChangeCount(_incomingApiName, existingApiName) {
4389
- let apiNameChangeCounter = this.recordApiNameChangeCounters[existingApiName];
4390
- if (apiNameChangeCounter === undefined) {
4391
- apiNameChangeCounter = counter(createMetricsKey(NAMESPACE, RECORD_API_NAME_CHANGE_COUNT_METRIC_NAME, existingApiName));
4392
- this.recordApiNameChangeCounters[existingApiName] = apiNameChangeCounter;
4393
- }
4394
- apiNameChangeCounter.increment(1);
5470
+ else if (baseUrl.startsWith(UIAPI_RELATED_LIST_RECORDS_BATCH_PATH)) {
5471
+ configPath = crudInstrumentationConfig['relatedListRecordsBatch'];
4395
5472
  }
4396
- /**
4397
- * W-8620679
4398
- * Increment the counter for an UnfulfilledSnapshotError coming from luvio
4399
- *
4400
- * @param context The transaction context.
4401
- */
4402
- incrementAdapterRequestErrorCount(context) {
4403
- // We are consolidating all apex adapter instrumentation calls under a single key
4404
- const adapterName = normalizeAdapterName(context.adapterName);
4405
- let adapterRequestErrorCounter = this.adapterUnfulfilledErrorCounters[adapterName];
4406
- if (adapterRequestErrorCounter === undefined) {
4407
- adapterRequestErrorCounter = counter(createMetricsKey(OBSERVABILITY_NAMESPACE, ADAPTER_ERROR_COUNT_METRIC_NAME, adapterName));
4408
- this.adapterUnfulfilledErrorCounters[adapterName] = adapterRequestErrorCounter;
5473
+ else if (baseUrl.startsWith(UIAPI_RELATED_LIST_RECORDS_PATH)) {
5474
+ configPath = crudInstrumentationConfig['relatedListRecords'];
5475
+ }
5476
+ if (configPath) {
5477
+ const crudCallbacks = configPath[request.method];
5478
+ if (crudCallbacks) {
5479
+ if (isResolve && crudCallbacks.resolveFn) {
5480
+ crudCallbacks.resolveFn(setResolveConfig(request, response));
5481
+ }
5482
+ else if (crudCallbacks.rejectFn) {
5483
+ crudCallbacks.rejectFn(setRejectConfig(request, error));
5484
+ }
4409
5485
  }
4410
- adapterRequestErrorCounter.increment(1);
4411
- totalAdapterErrorMetric.increment(1);
4412
5486
  }
4413
5487
  }
4414
- function createMetricsKey(owner, name, unit) {
4415
- let metricName = name;
4416
- if (unit) {
4417
- metricName = metricName + '.' + unit;
4418
- }
5488
+ function setResolveConfig(request, response) {
5489
+ const responseBody = response ? response.body : {};
5490
+ const urlParams = request.urlParams || {};
4419
5491
  return {
4420
- get() {
4421
- return { owner: owner, name: metricName };
5492
+ body: responseBody,
5493
+ params: {
5494
+ recordId: urlParams.recordId,
4422
5495
  },
4423
5496
  };
4424
5497
  }
4425
- /**
4426
- * Returns whether adapter is an Apex one or not.
4427
- * @param adapterName The name of the adapter.
4428
- */
4429
- function isApexAdapter(adapterName) {
4430
- return adapterName.indexOf(APEX_ADAPTER_NAME) > -1;
5498
+ function setRejectConfig(request, error) {
5499
+ const requestBody = request.body || {};
5500
+ const urlParams = request.urlParams || {};
5501
+ return {
5502
+ err: error,
5503
+ params: {
5504
+ recordId: urlParams.recordId,
5505
+ // pass these in even if they're undefined
5506
+ parentRecordId: urlParams.parentRecordId,
5507
+ relatedListId: urlParams.relatedListId,
5508
+ relatedListParameters: requestBody.relatedListParameters,
5509
+ },
5510
+ };
4431
5511
  }
5512
+
4432
5513
  /**
4433
- * Normalizes getApex adapter names to `Apex.getApex`. Non-Apex adapters will be prefixed with
4434
- * API family, if supplied. Example: `UiApi.getRecord`.
5514
+ * Builds a Luvio Request interceptor that adds page-scoped cache headers
5515
+ * to ResourceRequest objects used by the Luvio network adapter.
4435
5516
  *
4436
- * Note: If you are adding additional logging that can come from getApex adapter contexts that provide
4437
- * the full getApex adapter name (i.e. getApex_[namespace]_[class]_[function]_[continuation]),
4438
- * ensure to call this method to normalize all logging to 'getApex'. This
4439
- * is because Argus has a 50k key cardinality limit. More context: W-8379680.
5517
+ * This interceptor works with the Luvio ResourceRequest format, which has
5518
+ * a simpler structure than FetchParameters - headers are always a plain object.
4440
5519
  *
4441
- * @param adapterName The name of the adapter.
4442
- * @param apiFamily The API family of the adapter.
4443
- */
4444
- function normalizeAdapterName(adapterName, apiFamily) {
4445
- if (isApexAdapter(adapterName)) {
4446
- return NORMALIZED_APEX_ADAPTER_NAME;
4447
- }
4448
- return apiFamily ? `${apiFamily}.${adapterName}` : adapterName;
4449
- }
4450
- const timerMetricTracker = create(null);
4451
- /**
4452
- * Calls instrumentation/service telemetry timer
4453
- * @param name Name of the metric
4454
- * @param duration number to update backing percentile histogram, negative numbers ignored
5520
+ * @returns A RequestInterceptor function for Luvio network requests
4455
5521
  */
4456
- function updateTimerMetric(name, duration) {
4457
- let metric = timerMetricTracker[name];
4458
- if (metric === undefined) {
4459
- metric = timer(createMetricsKey(NAMESPACE, name));
4460
- timerMetricTracker[name] = metric;
4461
- }
4462
- timerMetricAddDuration(metric, duration);
4463
- }
4464
- function timerMetricAddDuration(timer, duration) {
4465
- // Guard against negative values since it causes error to be thrown by MetricsService
4466
- if (duration >= 0) {
4467
- timer.addDuration(duration);
4468
- }
5522
+ function buildLuvioPageScopedCacheRequestInterceptor() {
5523
+ return (resourceRequest) => {
5524
+ // Ensure headers object exists
5525
+ if (!resourceRequest.headers) {
5526
+ resourceRequest.headers = {};
5527
+ }
5528
+ // Pass the headers to pageScopedCache which will mutate them
5529
+ pageScopedCache.addHeader(resourceRequest.headers);
5530
+ return resolvedPromiseLike$2(resourceRequest);
5531
+ };
4469
5532
  }
4470
- /**
4471
- * W-10315098
4472
- * Increments the counter associated with the request response. Counts are bucketed by status.
4473
- */
4474
- const requestResponseMetricTracker = create(null);
4475
- function incrementRequestResponseCount(cb) {
4476
- const status = cb().status;
4477
- let metric = requestResponseMetricTracker[status];
4478
- if (metric === undefined) {
4479
- metric = counter(createMetricsKey(OBSERVABILITY_NAMESPACE, NETWORK_ADAPTER_RESPONSE_METRIC_NAME, `${status.valueOf()}`));
4480
- requestResponseMetricTracker[status] = metric;
4481
- }
4482
- metric.increment();
5533
+
5534
+ function buildLexRuntimeAuthExpirationRedirectResponseInterceptor(logger) {
5535
+ return async (response) => {
5536
+ if (response.status === 401) {
5537
+ try {
5538
+ const coercedResponse = (await coerceResponseToFetchResponse(response.clone()));
5539
+ if (coercedResponse.body.errorCode === 'INVALID_SESSION_ID') {
5540
+ logger.warn(`Received ${response.status} status code from LEX runtime service`);
5541
+ // Fire the event asynchronously, similar to the legacy setTimeout pattern
5542
+ window.setTimeout(() => {
5543
+ dispatchGlobalEvent('aura:invalidSession');
5544
+ }, 0);
5545
+ }
5546
+ }
5547
+ catch (error) {
5548
+ logger.warn(`Error parsing response from LEX runtime service: ${error}`);
5549
+ }
5550
+ }
5551
+ return response;
5552
+ };
4483
5553
  }
4484
- function logObjectInfoChanged() {
4485
- logObjectInfoChanged$1();
5554
+ function buildLexRuntimeLuvioAuthExpirationRedirectResponseInterceptor() {
5555
+ return async (response) => {
5556
+ if (response.status === 401) {
5557
+ if (response.body.errorCode === 'INVALID_SESSION_ID') {
5558
+ window.setTimeout(() => {
5559
+ dispatchGlobalEvent('aura:invalidSession');
5560
+ }, 0);
5561
+ }
5562
+ }
5563
+ return response;
5564
+ };
4486
5565
  }
5566
+
4487
5567
  /**
4488
- * Create a new instrumentation cache stats and return it.
5568
+ * Extracts the ErrorId from a server error response message.
5569
+ * Looks for pattern: "ErrorId if you contact support: 1033627214-37969 (-1272663771)"
5570
+ * Returns the numeric value in parentheses.
4489
5571
  *
4490
- * @param name The cache logger name.
4491
- */
4492
- function registerLdsCacheStats(name) {
4493
- return registerCacheStats(`${NAMESPACE}:${name}`);
4494
- }
4495
- /**
4496
- * Add or overwrite hooks that require aura implementations
5572
+ * @param responseBody The response body text to parse.
5573
+ * @returns The extracted error ID, or null if not found.
4497
5574
  */
4498
- function setAuraInstrumentationHooks() {
4499
- instrument({
4500
- recordConflictsResolved: (serverRequestCount) => {
4501
- // Ignore 0 values which can originate from ADS bridge
4502
- if (serverRequestCount > 0) {
4503
- updatePercentileHistogramMetric('record-conflicts-resolved', serverRequestCount);
4504
- }
4505
- },
4506
- nullDisplayValueConflict: ({ fieldType, areValuesEqual }) => {
4507
- const metricName = `merge-null-dv-count.${fieldType}`;
4508
- if (fieldType === 'scalar') {
4509
- incrementCounterMetric(`${metricName}.${areValuesEqual}`);
4510
- }
4511
- else {
4512
- incrementCounterMetric(metricName);
4513
- }
4514
- },
4515
- getRecordNotifyChangeAllowed: incrementGetRecordNotifyChangeAllowCount,
4516
- getRecordNotifyChangeDropped: incrementGetRecordNotifyChangeDropCount,
4517
- notifyRecordUpdateAvailableAllowed: incrementNotifyRecordUpdateAvailableAllowCount,
4518
- notifyRecordUpdateAvailableDropped: incrementNotifyRecordUpdateAvailableDropCount,
4519
- recordApiNameChanged: instrumentation.incrementRecordApiNameChangeCount.bind(instrumentation),
4520
- weakEtagZero: instrumentation.aggregateWeakETagEvents.bind(instrumentation),
4521
- getRecordNotifyChangeNetworkResult: instrumentation.notifyChangeNetwork.bind(instrumentation),
4522
- });
4523
- withRegistration('@salesforce/lds-adapters-uiapi', (reg) => setLdsAdaptersUiapiInstrumentation(reg));
4524
- instrument$1({
4525
- logCrud: logCRUDLightningInteraction,
4526
- networkResponse: incrementRequestResponseCount,
4527
- });
4528
- instrument$2({
4529
- error: logError,
4530
- });
4531
- instrument$3({
4532
- refreshCalled: instrumentation.handleRefreshApiCall.bind(instrumentation),
4533
- instrumentAdapter: instrumentation.instrumentAdapter.bind(instrumentation),
4534
- });
4535
- instrument$4({
4536
- timerMetricAddDuration: updateTimerMetric,
4537
- });
4538
- // Our getRecord through aggregate-ui CRUD logging has moved
4539
- // to lds-network-adapter. We still need to respect the
4540
- // orgs environment setting
4541
- if (forceRecordTransactionsDisabled$1 === false) {
4542
- ldsNetworkAdapterInstrument({
4543
- getRecordAggregateResolve: (cb) => {
4544
- const { recordId, apiName } = cb();
4545
- logCRUDLightningInteraction('read', {
4546
- recordId,
4547
- recordType: apiName,
4548
- state: 'SUCCESS',
4549
- });
4550
- },
4551
- getRecordAggregateReject: (cb) => {
4552
- const recordId = cb();
4553
- logCRUDLightningInteraction('read', {
4554
- recordId,
4555
- state: 'ERROR',
4556
- });
4557
- },
4558
- });
5575
+ function extractErrorIdFromResponse(responseBody) {
5576
+ try {
5577
+ const parsed = JSON.parse(responseBody);
5578
+ if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].message) {
5579
+ const message = parsed[0].message;
5580
+ // Look for pattern: "ErrorId if you contact support: XXXXXX-XXXXX (YYYYY)"
5581
+ const match = message.match(/ErrorId[^:]*:\s*[\d-]+\s*\((-?\d+)\)/);
5582
+ if (match && match[1]) {
5583
+ return parseInt(match[1], 10);
5584
+ }
5585
+ }
4559
5586
  }
4560
- withRegistration('@salesforce/lds-network-adapter', (reg) => setLdsNetworkAdapterInstrumentation(reg));
4561
- }
4562
- let stateManagerInstrumentationHooksInitialized = false;
4563
- function setStateManagerInstrumentationHooks() {
4564
- if (stateManagerInstrumentationHooksInitialized) {
4565
- return;
5587
+ catch (e) {
5588
+ // If parsing fails, return null to use fallback
4566
5589
  }
4567
- instrument$5({
4568
- stateCreated: incrementStateCreatedCount,
4569
- });
4570
- stateManagerInstrumentationHooksInitialized = true;
5590
+ return null;
4571
5591
  }
4572
5592
  /**
4573
- * Initialize the instrumentation and instrument the LDS instance and the InMemoryStore.
5593
+ * Generates a unique error ID for tracking specific error occurrences.
5594
+ * Used as fallback when server doesn't provide an ErrorId.
4574
5595
  *
4575
- * @param luvio The Luvio instance to instrument.
4576
- * @param store The InMemoryStore to instrument.
5596
+ * @param idInput The input value to hash.
5597
+ * @returns A unique error ID in Salesforce-compatible numeric format.
4577
5598
  */
4578
- function setupInstrumentation(luvio, store) {
4579
- setupInstrumentation$1(luvio, store);
4580
- setAuraInstrumentationHooks();
4581
- setStateManagerInstrumentationHooks();
5599
+ function generateErrorId(idInput) {
5600
+ let hash = 0;
5601
+ if (!idInput || idInput.length === 0) {
5602
+ return hash;
5603
+ }
5604
+ let i, chr;
5605
+ for (i = 0; i < idInput.length; i++) {
5606
+ chr = idInput.charCodeAt(i);
5607
+ hash = (hash << 5) - hash + chr;
5608
+ hash |= 0; // Convert to 32bit integer
5609
+ }
5610
+ return hash;
4582
5611
  }
4583
5612
  /**
4584
- * Note: locator.scope is set to 'force_record' in order for the instrumentation gate to work, which will
4585
- * disable all crud operations if it is on.
4586
- * @param eventSource - Source of the logging event.
4587
- * @param attributes - Free form object of attributes to log.
5613
+ * Gets error ID from response body or generates a fallback.
5614
+ * Tries to extract server-provided ErrorId first, falls back to generated hash.
5615
+ *
5616
+ * @param responseBody The response body to parse.
5617
+ * @param status The HTTP status code (for fallback).
5618
+ * @param statusText The HTTP status text (for fallback, optional).
5619
+ * @returns A numeric error ID.
4588
5620
  */
4589
- function logCRUDLightningInteraction(eventSource, attributes) {
4590
- interaction(eventSource, 'force_record', null, eventSource, 'crud', attributes);
5621
+ function getOrGenerateErrorId(responseBody, status, statusText) {
5622
+ const extractedId = extractErrorIdFromResponse(responseBody);
5623
+ if (extractedId !== null) {
5624
+ return extractedId;
5625
+ }
5626
+ // Fallback to generated error ID using status and timestamp
5627
+ // statusText is optional and may not always be present
5628
+ const context = [status, statusText || '', Date.now()].join('|');
5629
+ return generateErrorId(context);
4591
5630
  }
4592
- const instrumentation = new Instrumentation();
4593
-
4594
- const forceRecordTransactionsDisabled = getEnvironmentSetting(EnvironmentSettings.ForceRecordTransactionsDisabled);
4595
- //TODO: Some duplication here that can be most likely moved to a util class
4596
- const NO_RECORD_ID_204 = '204_NO_RECORD_ID';
4597
- const NO_RECORD_TYPE_204 = '204_NO_RECORD_TYPE';
4598
- let crudInstrumentationCallbacks = {};
4599
- let crudRLInstrumentationCallbacks = {};
4600
- if (forceRecordTransactionsDisabled === false) {
4601
- // Record callbacks
4602
- crudInstrumentationCallbacks = {
4603
- createRecordRejectFunction: (config) => {
4604
- logCRUDLightningInteraction(CrudEventType.CREATE, {
4605
- // recordId: config.params.recordInput.apiName, // seems wrong?
4606
- recordId: config.params.recordId || NO_RECORD_ID_204,
4607
- state: CrudEventState.ERROR,
4608
- });
4609
- },
4610
- createRecordResolveFunction: (config) => {
4611
- const recordId = config.body ? config.body.id : NO_RECORD_ID_204;
4612
- const recordType = config.body ? config.body.apiName : NO_RECORD_TYPE_204;
4613
- logCRUDLightningInteraction(CrudEventType.CREATE, {
4614
- recordId,
4615
- recordType,
4616
- state: CrudEventState.SUCCESS,
4617
- });
4618
- },
4619
- deleteRecordRejectFunction: (config) => {
4620
- logCRUDLightningInteraction(CrudEventType.DELETE, {
4621
- recordId: config.params.recordId,
4622
- state: CrudEventState.ERROR,
4623
- });
4624
- },
4625
- deleteRecordResolveFunction: (config) => {
4626
- logCRUDLightningInteraction(CrudEventType.DELETE, {
4627
- recordId: config.params.recordId,
4628
- state: CrudEventState.SUCCESS,
4629
- });
4630
- },
4631
- // These should be handled by the network adapater?
4632
- // getRecordAggregateRejectFunction: (config: InstrumentationRejectConfig) => {
4633
- // logCRUDLightningInteraction(CrudEventType.READ, {
4634
- // recordId: config.params.recordId,
4635
- // state: CrudEventState.ERROR,
4636
- // });
4637
- // },
4638
- // getRecordAggregateResolveFunction: (config: InstrumentationResolveConfig) => {
4639
- // logCRUDLightningInteraction(CrudEventType.READ, {
4640
- // recordId: config.params.recordId,
4641
- // recordType: config.body.apiName,
4642
- // state: CrudEventState.SUCCESS,
4643
- // });
4644
- // },
4645
- getRecordRejectFunction: (config) => {
4646
- logCRUDLightningInteraction(CrudEventType.READ, {
4647
- recordId: config.params.recordId,
4648
- state: CrudEventState.ERROR,
4649
- });
4650
- },
4651
- getRecordResolveFunction: (config) => {
4652
- logCRUDLightningInteraction(CrudEventType.READ, {
4653
- recordId: config.params.recordId,
4654
- recordType: config.body.apiName,
4655
- state: CrudEventState.SUCCESS,
4656
- });
4657
- },
4658
- updateRecordRejectFunction: (config) => {
4659
- logCRUDLightningInteraction(CrudEventType.UPDATE, {
4660
- recordId: config.params.recordId,
4661
- state: CrudEventState.ERROR,
4662
- });
4663
- },
4664
- updateRecordResolveFunction: (config) => {
4665
- const recordType = config.body ? config.body.apiName : NO_RECORD_TYPE_204;
4666
- logCRUDLightningInteraction(CrudEventType.UPDATE, {
4667
- recordId: config.params.recordId,
4668
- recordType,
4669
- state: CrudEventState.SUCCESS,
4670
- });
4671
- },
4672
- };
4673
- // Related list callbacks
4674
- crudRLInstrumentationCallbacks = {
4675
- getRelatedListRecordsRejectFunction: (config) => {
4676
- logCRUDLightningInteraction(CrudEventType.READS, {
4677
- parentRecordId: config.params.parentRecordId,
4678
- relatedListId: config.params.relatedListId,
4679
- state: CrudEventState.ERROR,
4680
- });
4681
- },
4682
- getRelatedListRecordsResolveFunction: (config) => {
4683
- logGetRelatedListRecordsInteraction(config.body);
4684
- },
4685
- getRelatedListRecordsBatchRejectFunction: (config) => {
4686
- logCRUDLightningInteraction(CrudEventType.READS, {
4687
- parentRecordId: config.params.parentRecordId,
4688
- relatedListIds: config.params.relatedListParameters.map((entry) => entry.relatedListId),
4689
- state: CrudEventState.ERROR,
4690
- });
4691
- },
4692
- getRelatedListRecordsBatchResolveFunction: (config) => {
4693
- config.body.results.forEach((res) => {
4694
- // Log for each RL that was returned from batch endpoint
4695
- if (res.statusCode === 200) {
4696
- logGetRelatedListRecordsInteraction(res.result);
4697
- }
4698
- });
4699
- },
5631
+ function buildLexRuntime5xxStatusResponseInterceptor(logger) {
5632
+ return async (response) => {
5633
+ if (response.status >= 500 && response.status < 600) {
5634
+ const internalLogMessage = `LEX runtime 5xx: ${response.status} ${response.statusText || ''}`.trim();
5635
+ logger.warn(internalLogMessage);
5636
+ const userMessage = 'A server error occurred. Please try again later.';
5637
+ // Try to extract ErrorId from response body, fallback to generated ID
5638
+ let errorId;
5639
+ try {
5640
+ const responseText = await response.clone().text();
5641
+ errorId = getOrGenerateErrorId(responseText, response.status, response.statusText);
5642
+ }
5643
+ catch (e) {
5644
+ // If reading response fails, use fallback
5645
+ const context = [response.status, response.statusText, Date.now()].join('|');
5646
+ errorId = generateErrorId(context);
5647
+ }
5648
+ // Create an error object similar to Aura's current shape for system errors
5649
+ const error = {
5650
+ message: userMessage,
5651
+ severity: 'ALERT',
5652
+ name: 'LEXRuntimeError',
5653
+ stack: null,
5654
+ handled: false,
5655
+ reported: false,
5656
+ id: errorId,
5657
+ };
5658
+ const evtArgs = {
5659
+ message: error.message,
5660
+ error: null,
5661
+ auraError: error,
5662
+ };
5663
+ // Fire the event asynchronously, similar to the legacy setTimeout pattern
5664
+ window.setTimeout(() => {
5665
+ dispatchGlobalEvent('markup://aura:systemError', evtArgs);
5666
+ }, 0);
5667
+ // Throw a simple error to terminate the request completely
5668
+ // The consumer has NOT opted in to handle 5xx errors, so we don't return any response
5669
+ // The systemError event above will handle showing the gack dialog
5670
+ throw new Error(error.message);
5671
+ }
5672
+ return response;
4700
5673
  };
4701
5674
  }
4702
- // Helper function copied from ui-api
4703
- function logGetRelatedListRecordsInteraction(body) {
4704
- const records = body.records;
4705
- // Don't log anything if the related list has no records.
4706
- if (records.length === 0) {
4707
- return;
5675
+ function buildLexRuntimeLuvio5xxStatusResponseInterceptor() {
5676
+ return async (response) => {
5677
+ if (response.status >= 500 && response.status < 600) {
5678
+ const userMessage = 'A server error occurred. Please try again later.';
5679
+ // Try to extract ErrorId from response body, fallback to generated ID
5680
+ let errorId;
5681
+ try {
5682
+ const responseBody = response.body ? JSON.stringify(response.body) : '';
5683
+ errorId = getOrGenerateErrorId(responseBody, response.status, response.statusText);
5684
+ }
5685
+ catch (e) {
5686
+ // If reading response fails, use fallback
5687
+ const context = [response.status, response.statusText, Date.now()].join('|');
5688
+ errorId = generateErrorId(context);
5689
+ }
5690
+ // Create an error object similar to Aura's current shape for system errors
5691
+ const error = {
5692
+ message: userMessage,
5693
+ severity: 'ALERT',
5694
+ name: 'LEXRuntimeError',
5695
+ stack: null,
5696
+ handled: false,
5697
+ reported: false,
5698
+ id: errorId,
5699
+ };
5700
+ const evtArgs = {
5701
+ message: error.message,
5702
+ error: null,
5703
+ auraError: error,
5704
+ };
5705
+ // Fire the event asynchronously, similar to the legacy setTimeout pattern
5706
+ window.setTimeout(() => {
5707
+ dispatchGlobalEvent('markup://aura:systemError', evtArgs);
5708
+ }, 0);
5709
+ // Throw a simple error to terminate the request completely
5710
+ // The consumer has NOT opted in to handle 5xx errors, so we don't return any response
5711
+ // The systemError event above will handle showing the gack dialog
5712
+ throw new Error(error.message);
5713
+ }
5714
+ return response;
5715
+ };
5716
+ }
5717
+
5718
+ const CSRF_TOKEN_KEY = 'salesforce_csrf_token';
5719
+ const CSRF_STORAGE_NAME = 'ldsCSRFToken';
5720
+ const CSRF_STORAGE_CONFIG = {
5721
+ name: CSRF_STORAGE_NAME,
5722
+ persistent: true,
5723
+ secure: true,
5724
+ maxSize: 1024,
5725
+ expiration: 24 * 60 * 60,
5726
+ clearOnInit: false,
5727
+ debugLogging: false,
5728
+ };
5729
+ /**
5730
+ * Manages CSRF token fetching and caching for secure requests.
5731
+ * Implements a singleton pattern to ensure consistent token management across the application.
5732
+ */
5733
+ class CsrfTokenManager {
5734
+ constructor() {
5735
+ // Initialize AuraStorage
5736
+ this.storage = createStorage(CSRF_STORAGE_CONFIG);
5737
+ // Try to load token from AuraStorage on initialization
5738
+ this.tokenPromise = this.loadOrFetchToken();
5739
+ }
5740
+ static getInstance() {
5741
+ if (!CsrfTokenManager.instance) {
5742
+ CsrfTokenManager.instance = new CsrfTokenManager();
5743
+ }
5744
+ return CsrfTokenManager.instance;
4708
5745
  }
4709
- const recordIds = records.map((record) => {
4710
- return record.id;
4711
- });
4712
5746
  /**
4713
- * In almost every case - the relatedList records will all be of the same apiName, but there is an edge case for
4714
- Activities entity that could return Events & Tasks- so handle that case by returning a joined string.
4715
- ADS Implementation only looks at the first record returned to determine the apiName.
4716
- See force/recordLibrary/recordMetricsPlugin.js _getRecordType method.
5747
+ * Obtain a CSRF token, either from AuraStorage or by fetching a fresh one.
5748
+ *
5749
+ * @private
4717
5750
  */
4718
- logCRUDLightningInteraction(CrudEventType.READS, {
4719
- parentRecordId: body.listReference.inContextOfRecordId,
4720
- relatedListId: body.listReference.relatedListId,
4721
- recordIds,
4722
- recordType: body.records[0].apiName,
4723
- state: CrudEventState.SUCCESS,
4724
- });
4725
- }
4726
- const crudInstrumentationConfig = {
4727
- records: {
4728
- post: {
4729
- rejectFn: crudInstrumentationCallbacks.createRecordRejectFunction,
4730
- resolveFn: crudInstrumentationCallbacks.createRecordResolveFunction,
4731
- },
4732
- get: {
4733
- rejectFn: crudInstrumentationCallbacks.getRecordRejectFunction,
4734
- resolveFn: crudInstrumentationCallbacks.getRecordResolveFunction,
4735
- },
4736
- patch: {
4737
- rejectFn: crudInstrumentationCallbacks.updateRecordRejectFunction,
4738
- resolveFn: crudInstrumentationCallbacks.updateRecordResolveFunction,
4739
- },
4740
- delete: {
4741
- rejectFn: crudInstrumentationCallbacks.deleteRecordRejectFunction,
4742
- resolveFn: crudInstrumentationCallbacks.deleteRecordResolveFunction,
4743
- },
4744
- },
4745
- relatedListRecords: {
4746
- post: {
4747
- rejectFn: crudRLInstrumentationCallbacks.getRelatedListRecordsRejectFunction,
4748
- resolveFn: crudRLInstrumentationCallbacks.getRelatedListRecordsResolveFunction,
4749
- },
4750
- },
4751
- relatedListRecordsBatch: {
4752
- post: {
4753
- rejectFn: crudRLInstrumentationCallbacks.getRelatedListRecordsBatchRejectFunction,
4754
- resolveFn: crudRLInstrumentationCallbacks.getRelatedListRecordsBatchResolveFunction,
4755
- },
4756
- },
4757
- };
4758
- function checkAndLogCrudInteraction(request, isResolve, error, response) {
4759
- let configPath;
4760
- const baseUrl = `${request.baseUri}${request.basePath}`;
4761
- if (baseUrl.startsWith(UIAPI_RECORDS_PATH)) {
4762
- configPath = crudInstrumentationConfig['records']; // maybe use a constant for this
5751
+ async loadOrFetchToken() {
5752
+ // First try to get token from AuraStorage
5753
+ if (this.storage) {
5754
+ try {
5755
+ const cachedToken = await this.storage.get(CSRF_TOKEN_KEY);
5756
+ if (typeof cachedToken === 'string' && cachedToken) {
5757
+ return cachedToken;
5758
+ }
5759
+ }
5760
+ catch {
5761
+ // If storage read fails, continue to fetch
5762
+ }
5763
+ }
5764
+ // No cached token, fetch from server
5765
+ return this.fetchFreshToken();
4763
5766
  }
4764
- else if (baseUrl.startsWith(UIAPI_RELATED_LIST_RECORDS_BATCH_PATH)) {
4765
- configPath = crudInstrumentationConfig['relatedListRecordsBatch'];
5767
+ /**
5768
+ * Call API endpoint to acquire a CSRF token and cache it.
5769
+ *
5770
+ * @private
5771
+ */
5772
+ async fetchFreshToken() {
5773
+ try {
5774
+ const response = await fetch('/session/csrf', {
5775
+ method: 'GET',
5776
+ credentials: 'same-origin',
5777
+ });
5778
+ if (!response.ok) {
5779
+ return undefined;
5780
+ }
5781
+ const data = await response.json();
5782
+ const token = data.csrfToken;
5783
+ if (token && this.storage) {
5784
+ // Cache the token in AuraStorage
5785
+ try {
5786
+ await this.storage.set(CSRF_TOKEN_KEY, token);
5787
+ }
5788
+ catch {
5789
+ // Non-fatal: token is still available even if caching fails
5790
+ }
5791
+ }
5792
+ return token;
5793
+ }
5794
+ catch {
5795
+ return undefined;
5796
+ }
4766
5797
  }
4767
- else if (baseUrl.startsWith(UIAPI_RELATED_LIST_RECORDS_PATH)) {
4768
- configPath = crudInstrumentationConfig['relatedListRecords'];
5798
+ /**
5799
+ * Returns the current token value as a Promise.
5800
+ */
5801
+ async getToken() {
5802
+ return this.tokenPromise;
4769
5803
  }
4770
- if (configPath) {
4771
- const crudCallbacks = configPath[request.method];
4772
- if (crudCallbacks) {
4773
- if (isResolve && crudCallbacks.resolveFn) {
4774
- crudCallbacks.resolveFn(setResolveConfig(request, response));
5804
+ /**
5805
+ * Obtains and returns a new token value as a promise.
5806
+ * This will clear the cached token and fetch a fresh one.
5807
+ */
5808
+ async refreshToken() {
5809
+ // Clear cached token
5810
+ if (this.storage) {
5811
+ try {
5812
+ await this.storage.remove(CSRF_TOKEN_KEY);
4775
5813
  }
4776
- else if (crudCallbacks.rejectFn) {
4777
- crudCallbacks.rejectFn(setRejectConfig(request, error));
5814
+ catch {
5815
+ // Non-fatal: continue with refresh even if clear fails
4778
5816
  }
4779
5817
  }
5818
+ // Fetch (and cache) fresh token
5819
+ this.tokenPromise = this.fetchFreshToken();
5820
+ return this.tokenPromise;
5821
+ }
5822
+ /**
5823
+ * Reset the singleton instance (useful for testing).
5824
+ * @internal
5825
+ */
5826
+ static resetInstance() {
5827
+ CsrfTokenManager.instance = null;
4780
5828
  }
4781
5829
  }
4782
- function setResolveConfig(request, response) {
4783
- const responseBody = response ? response.body : {};
4784
- const urlParams = request.urlParams || {};
4785
- return {
4786
- body: responseBody,
4787
- params: {
4788
- recordId: urlParams.recordId,
4789
- },
4790
- };
4791
- }
4792
- function setRejectConfig(request, error) {
4793
- const requestBody = request.body || {};
4794
- const urlParams = request.urlParams || {};
4795
- return {
4796
- err: error,
4797
- params: {
4798
- recordId: urlParams.recordId,
4799
- // pass these in even if they're undefined
4800
- parentRecordId: urlParams.parentRecordId,
4801
- relatedListId: urlParams.relatedListId,
4802
- relatedListParameters: requestBody.relatedListParameters,
4803
- },
4804
- };
4805
- }
5830
+ CsrfTokenManager.instance = null;
4806
5831
 
5832
+ const CSRF_TOKEN_HEADER = 'X-CSRF-Token';
4807
5833
  /**
4808
- * Builds a Luvio Request interceptor that adds page-scoped cache headers
4809
- * to ResourceRequest objects used by the Luvio network adapter.
4810
- *
4811
- * This interceptor works with the Luvio ResourceRequest format, which has
4812
- * a simpler structure than FetchParameters - headers are always a plain object.
5834
+ * Determines if the HTTP method requires CSRF protection.
5835
+ * Only mutating operations (POST, PUT, PATCH, DELETE) require CSRF tokens.
4813
5836
  *
4814
- * @returns A RequestInterceptor function for Luvio network requests
5837
+ * @param method - The HTTP method to check
5838
+ * @returns true if the method requires CSRF protection
4815
5839
  */
4816
- function buildLuvioPageScopedCacheRequestInterceptor() {
4817
- return (resourceRequest) => {
4818
- // Ensure headers object exists
4819
- if (!resourceRequest.headers) {
4820
- resourceRequest.headers = {};
4821
- }
4822
- // Pass the headers to pageScopedCache which will mutate them
4823
- pageScopedCache.addHeader(resourceRequest.headers);
4824
- return resolvedPromiseLike$3(resourceRequest);
4825
- };
5840
+ function isCsrfMethod(method) {
5841
+ if (!method) {
5842
+ return false;
5843
+ }
5844
+ const normalizedMethod = method.toLowerCase();
5845
+ return (normalizedMethod === 'post' ||
5846
+ normalizedMethod === 'put' ||
5847
+ normalizedMethod === 'patch' ||
5848
+ normalizedMethod === 'delete');
4826
5849
  }
4827
-
4828
- const REQUEST_ID_KEY = 'X-SFDC-Request-Id';
4829
- function buildRequestIdInterceptor() {
5850
+ /**
5851
+ * Builds a request interceptor that adds CSRF token headers to mutating requests.
5852
+ * The CSRF token is fetched once and cached for subsequent requests.
5853
+ * Only POST, PUT, PATCH, and DELETE requests will have the CSRF token added.
5854
+ *
5855
+ * @returns A RequestInterceptor function for FetchParameters
5856
+ */
5857
+ function buildCsrfTokenInterceptor() {
5858
+ const csrfTokenManager = CsrfTokenManager.getInstance();
4830
5859
  return async (fetchArgs) => {
4831
- fetchArgs = setHeader(REQUEST_ID_KEY, generateRequestId(), fetchArgs);
4832
- return resolvedPromiseLike$3(fetchArgs);
5860
+ const [urlOrRequest, options] = fetchArgs;
5861
+ // Determine the method from either Request object or options
5862
+ let method;
5863
+ if (typeof urlOrRequest !== 'string' && 'method' in urlOrRequest) {
5864
+ method = urlOrRequest.method;
5865
+ }
5866
+ else if (options && 'method' in options) {
5867
+ method = options.method;
5868
+ }
5869
+ // Only add CSRF token for mutating operations
5870
+ if (isCsrfMethod(method)) {
5871
+ const token = await csrfTokenManager.getToken();
5872
+ if (token) {
5873
+ fetchArgs = setHeader(CSRF_TOKEN_HEADER, token, fetchArgs);
5874
+ }
5875
+ }
5876
+ return resolvedPromiseLike$2(fetchArgs);
4833
5877
  };
4834
5878
  }
4835
- function buildLuvioRequestIdInterceptor() {
4836
- return (resourceRequest) => {
5879
+ /**
5880
+ * Builds a Luvio request interceptor that adds CSRF token headers to mutating requests.
5881
+ * The CSRF token is fetched once and cached for subsequent requests.
5882
+ * Only POST, PUT, PATCH, and DELETE requests will have the CSRF token added.
5883
+ *
5884
+ * @returns A request interceptor function for Luvio ResourceRequest objects
5885
+ */
5886
+ function buildLuvioCsrfTokenInterceptor() {
5887
+ const csrfTokenManager = CsrfTokenManager.getInstance();
5888
+ return async (resourceRequest) => {
4837
5889
  // Ensure headers object exists
4838
5890
  if (!resourceRequest.headers) {
4839
5891
  resourceRequest.headers = {};
4840
5892
  }
4841
- // Don't overwrite request id header if it already exists
4842
- if (!resourceRequest.headers[REQUEST_ID_KEY]) {
4843
- resourceRequest.headers[REQUEST_ID_KEY] = generateRequestId();
5893
+ // Only add CSRF token for mutating operations
5894
+ if (isCsrfMethod(resourceRequest.method)) {
5895
+ // Don't overwrite existing CSRF token header if it already exists
5896
+ if (!resourceRequest.headers[CSRF_TOKEN_HEADER]) {
5897
+ const token = await csrfTokenManager.getToken();
5898
+ if (token) {
5899
+ resourceRequest.headers[CSRF_TOKEN_HEADER] = token;
5900
+ }
5901
+ }
4844
5902
  }
4845
- return resolvedPromiseLike$3(resourceRequest);
5903
+ return resolvedPromiseLike$2(resourceRequest);
4846
5904
  };
4847
5905
  }
4848
5906
 
@@ -4907,7 +5965,7 @@ const composedFetchNetworkAdapter = {
4907
5965
  return API_PATH_MATCHERS.some((matcher) => matcher.test(path));
4908
5966
  },
4909
5967
  adapter: setupLexNetworkAdapter(requestTracker, requestLogger, {
4910
- request: [buildLuvioPageScopedCacheRequestInterceptor(), buildLuvioRequestIdInterceptor()],
5968
+ request: [buildLuvioPageScopedCacheRequestInterceptor(), buildLuvioCsrfTokenInterceptor()],
4911
5969
  response: [
4912
5970
  buildLexRuntimeLuvio5xxStatusResponseInterceptor(),
4913
5971
  buildLexRuntimeLuvioAuthExpirationRedirectResponseInterceptor(),
@@ -4915,13 +5973,195 @@ const composedFetchNetworkAdapter = {
4915
5973
  }),
4916
5974
  };
4917
5975
 
5976
+ function buildThirdPartyTrackerFinishInterceptor() {
5977
+ return async (context) => {
5978
+ if (context && context.instrumentationId) {
5979
+ instrumentationTracker.markFinished(context.instrumentationId);
5980
+ }
5981
+ };
5982
+ }
5983
+
5984
+ function buildThirdPartyTrackerRegisterInterceptor() {
5985
+ return async (fetchArgs, context) => {
5986
+ if (context && context.instrumentationId) {
5987
+ instrumentationTracker.registerHandler(context.instrumentationId, 'onestore-inflight-network-request', () => {
5988
+ // return false until we signal we are finished
5989
+ return false;
5990
+ });
5991
+ }
5992
+ return resolvedPromiseLike$2(fetchArgs);
5993
+ };
5994
+ }
5995
+
5996
+ function createInstrumentationIdContext() {
5997
+ return () => ({
5998
+ instrumentationId: generateRequestId$1(),
5999
+ });
6000
+ }
6001
+ function createStartMark(requestId) {
6002
+ const startMark = markStart('transport', 'request');
6003
+ startMark.context = {
6004
+ auraXHRId: requestId,
6005
+ background: false,
6006
+ actionDefs: ['lds-fetch'],
6007
+ requestId,
6008
+ requestLength: -1, // not known
6009
+ };
6010
+ }
6011
+
6012
+ function buildPageScopedCacheRequestInterceptor() {
6013
+ return async (fetchArgs) => {
6014
+ const pageScopedCacheHeaders = {};
6015
+ // Allow the instrumentation util to set up the header value on our "dummy" header object
6016
+ pageScopedCache.addHeader(pageScopedCacheHeaders);
6017
+ let returnedFetchArgs = fetchArgs;
6018
+ // If it set a value, add it to our fetchParams
6019
+ Object.entries(pageScopedCacheHeaders).forEach(([key, value]) => {
6020
+ returnedFetchArgs = setHeader(key, value, returnedFetchArgs);
6021
+ });
6022
+ return resolvedPromiseLike$2(returnedFetchArgs);
6023
+ };
6024
+ }
6025
+
6026
+ const SFDC_REQUEST_ID_KEY = 'X-SFDC-Request-Id';
6027
+ function buildTransportMarksSendInterceptor() {
6028
+ return async (fetchArgs, context) => {
6029
+ // First set the requestId header. If there's not context, it means we won't be able to track the mark and something is hosed, and so not worth even trying
6030
+ if (context && context.instrumentationId) {
6031
+ const requestId = context.instrumentationId;
6032
+ fetchArgs = setHeader(SFDC_REQUEST_ID_KEY, requestId, fetchArgs);
6033
+ createStartMark(requestId);
6034
+ }
6035
+ return resolvedPromiseLike$2(fetchArgs);
6036
+ };
6037
+ }
6038
+
6039
+ function buildTransportMarksReceiveInterceptor() {
6040
+ return async (context) => {
6041
+ if (context && context.instrumentationId) {
6042
+ markEnd('transport', 'request', { auraXHRId: context.instrumentationId });
6043
+ }
6044
+ };
6045
+ }
6046
+
6047
+ const DEFAULT_CONFIG$1 = {
6048
+ maxRetries: 1, // Only retry once after token refresh
6049
+ };
6050
+ /**
6051
+ * Retry policy that handles CSRF token expiration errors.
6052
+ *
6053
+ * When a request fails with a CSRF token error this policy will:
6054
+ * 1. Detect the error condition in shouldRetry
6055
+ * 2. Refresh the CSRF token in prepareRetry hook
6056
+ * 3. Update the request headers with the new token via mutable context
6057
+ * 4. Retry the request once (maxRetries = 1)
6058
+ *
6059
+ */
6060
+ class CsrfTokenRetryPolicy extends RetryPolicy {
6061
+ constructor(config = DEFAULT_CONFIG$1) {
6062
+ super();
6063
+ this.config = config;
6064
+ this.csrfTokenManager = CsrfTokenManager.getInstance();
6065
+ }
6066
+ /**
6067
+ * Allows the fetch service to pass mutable request context.
6068
+ * This is a side-channel that enables request modification between retries.
6069
+ *
6070
+ * @param context - Mutable container holding fetch arguments
6071
+ */
6072
+ setRequestContext(context) {
6073
+ this.requestContext = context;
6074
+ }
6075
+ /**
6076
+ * Determines if a failed request should be retried due to CSRF token issues.
6077
+ */
6078
+ async shouldRetry(result, context) {
6079
+ // Only retry once
6080
+ if (context.attempt >= this.config.maxRetries) {
6081
+ return false;
6082
+ }
6083
+ // Only retry on 400 status
6084
+ if (result.status !== 400) {
6085
+ return false;
6086
+ }
6087
+ // Check if this is a CSRF error by examining the response body
6088
+ // This avoids retrying all 400s (validation errors, bad requests, etc.)
6089
+ return await isCsrfError(result);
6090
+ }
6091
+ /**
6092
+ * CSRF token refresh should happen immediately with no delay.
6093
+ */
6094
+ async calculateDelay(_result, _context) {
6095
+ return 0; // No delay - retry immediately after token refresh
6096
+ }
6097
+ /**
6098
+ * Called by retry service before each retry attempt.
6099
+ *
6100
+ * This hook is supported by the Conduit retry service (with prepareRetry support).
6101
+ * It performs token refresh and request update:
6102
+ * 1. Refreshes the CSRF token from the server
6103
+ * 2. Updates the mutable request context with the new token
6104
+ *
6105
+ * Note: We already validated this is a CSRF error in shouldRetry,
6106
+ * so we can proceed directly to token refresh.
6107
+ *
6108
+ * The fetch service must call setRequestContext() to provide the mutable args container.
6109
+ * When the retry service re-executes the operation, it will use the updated args.
6110
+ *
6111
+ * @param _result - The failed response that triggered the retry (unused, already validated)
6112
+ * @param _context - Current retry context (unused but part of interface)
6113
+ */
6114
+ async prepareRetry(_result, _context) {
6115
+ // Refresh the CSRF token (we already know this is a CSRF error from shouldRetry)
6116
+ const newToken = await this.csrfTokenManager.refreshToken();
6117
+ if (!newToken || !this.requestContext) {
6118
+ // If we can't get a new token or don't have request context,
6119
+ // the retry will fail again but that's expected
6120
+ return;
6121
+ }
6122
+ // Update the fetch arguments with the new token using the setHeader utility
6123
+ this.requestContext.args = setHeader('X-CSRF-Token', newToken, this.requestContext.args);
6124
+ }
6125
+ }
6126
+ /**
6127
+ * Helper to check if a response indicates a CSRF token error.
6128
+ *
6129
+ * @param response - The response to check
6130
+ * @returns true if the response indicates a CSRF token error (INVALID_ACCESS_TOKEN)
6131
+ */
6132
+ async function isCsrfError(response) {
6133
+ try {
6134
+ // Clone to avoid consuming the original response
6135
+ const cloned = response.clone();
6136
+ const body = await cloned.json();
6137
+ // Check the error array format: data[0].errorCode
6138
+ const errorCode = body?.data?.[0]?.errorCode;
6139
+ return errorCode === 'INVALID_ACCESS_TOKEN';
6140
+ }
6141
+ catch {
6142
+ // If we can't parse the body (network error, non-JSON response, etc.),
6143
+ // assume it's not a CSRF error
6144
+ return false;
6145
+ }
6146
+ }
6147
+
4918
6148
  function buildLexRuntimeDefaultFetchServiceDescriptor(logger, retryService) {
4919
6149
  const fetchService = buildLexConnectFetchServiceDescriptor({
4920
- request: [buildPageScopedCacheRequestInterceptor(), buildRequestIdInterceptor()],
6150
+ createContext: createInstrumentationIdContext(),
6151
+ request: [
6152
+ buildThirdPartyTrackerRegisterInterceptor(),
6153
+ buildPageScopedCacheRequestInterceptor(),
6154
+ buildTransportMarksSendInterceptor(),
6155
+ buildCsrfTokenInterceptor(),
6156
+ ],
4921
6157
  response: [
4922
6158
  buildLexRuntime5xxStatusResponseInterceptor(logger),
4923
6159
  buildLexRuntimeAuthExpirationRedirectResponseInterceptor(logger),
4924
6160
  ],
6161
+ finally: [
6162
+ buildTransportMarksReceiveInterceptor(),
6163
+ buildThirdPartyTrackerFinishInterceptor(),
6164
+ ],
4925
6165
  }, retryService);
4926
6166
  return {
4927
6167
  ...fetchService,
@@ -4929,38 +6169,69 @@ function buildLexRuntimeDefaultFetchServiceDescriptor(logger, retryService) {
4929
6169
  }
4930
6170
  function buildLexRuntimeAllow5xxFetchServiceDescriptor(logger, retryService) {
4931
6171
  const fetchService = buildLexConnectFetchServiceDescriptor({
4932
- request: [buildPageScopedCacheRequestInterceptor(), buildRequestIdInterceptor()],
6172
+ createContext: createInstrumentationIdContext(),
6173
+ request: [
6174
+ buildThirdPartyTrackerRegisterInterceptor(),
6175
+ buildPageScopedCacheRequestInterceptor(),
6176
+ buildTransportMarksSendInterceptor(),
6177
+ buildCsrfTokenInterceptor(),
6178
+ ],
4933
6179
  response: [buildLexRuntimeAuthExpirationRedirectResponseInterceptor(logger)],
6180
+ finally: [
6181
+ buildTransportMarksReceiveInterceptor(),
6182
+ buildThirdPartyTrackerFinishInterceptor(),
6183
+ ],
4934
6184
  }, retryService);
4935
6185
  return {
4936
6186
  ...fetchService,
4937
6187
  tags: { interceptors: 'allow_500s' },
4938
6188
  };
4939
6189
  }
4940
- function buildLexConnectFetchServiceDescriptor(interceptors = { request: [], response: [] }, retryService) {
6190
+ // Temporarily cloned from conduit fetch until the retry service is updated there
6191
+ function buildLexConnectFetchServiceDescriptor(interceptors = { request: [], response: [], finally: [] }, retryService) {
4941
6192
  return {
4942
6193
  type: 'fetch',
4943
6194
  version: '1.0',
4944
6195
  service: function (...args) {
4945
- const { request: requestInterceptors = [], response: responseInterceptors = [] } = interceptors;
4946
- const pending = requestInterceptors.reduce((previousPromise, interceptor) => previousPromise.then(interceptor), resolvedPromiseLike$3(args));
4947
- const trackerId = generateRequestId();
4948
- instrumentationTracker.registerHandler(trackerId, 'onestore-inflight-network-request', () => {
4949
- // return false until we signal we are finished
4950
- return false;
4951
- });
6196
+ // Create context per request if factory is provided
6197
+ const context = interceptors.createContext?.();
6198
+ const { request: requestInterceptors = [], response: responseInterceptors = [], finally: finallyInterceptors = [], } = interceptors;
6199
+ const pending = requestInterceptors.reduce((previousPromise, interceptor) => previousPromise.then((args) => interceptor(args, context)), resolvedPromiseLike$2(args));
4952
6200
  return Promise.resolve(pending)
4953
- .then((args) => {
6201
+ .then((interceptedArgs) => {
4954
6202
  if (retryService) {
4955
- return retryService.applyRetry(() => fetch(...args));
6203
+ // Create mutable context for CSRF retry policy
6204
+ const mutableRequest = { args: interceptedArgs };
6205
+ // Pass context to CSRF policy if it's being used
6206
+ const policy = retryService.defaultRetryPolicy;
6207
+ // Handle both direct CSRF policy and composed policy
6208
+ if (policy instanceof CsrfTokenRetryPolicy) {
6209
+ policy.setRequestContext(mutableRequest);
6210
+ }
6211
+ else if (policy instanceof ComposedRetryPolicy) {
6212
+ // Extract CSRF policy from composed policy
6213
+ const csrfPolicy = policy.getPolicyByType(CsrfTokenRetryPolicy);
6214
+ if (csrfPolicy) {
6215
+ csrfPolicy.setRequestContext(mutableRequest);
6216
+ }
6217
+ }
6218
+ // Retry service will call prepareRetry hook which updates mutableRequest.args
6219
+ return retryService.applyRetry(async () => {
6220
+ return await fetch(...mutableRequest.args);
6221
+ });
4956
6222
  }
4957
- return fetch(...args);
6223
+ return fetch(...interceptedArgs);
4958
6224
  })
4959
6225
  .then((response) => {
4960
- return responseInterceptors.reduce((previousPromise, interceptor) => previousPromise.then(interceptor), resolvedPromiseLike$3(response));
6226
+ // Success path - run response interceptors
6227
+ return responseInterceptors.reduce((previousPromise, interceptor) => previousPromise.then((response) => interceptor(response, context)), resolvedPromiseLike$2(response));
4961
6228
  })
4962
6229
  .finally(() => {
4963
- instrumentationTracker.markFinished(trackerId);
6230
+ // Always run finally interceptors for cleanup
6231
+ if (finallyInterceptors.length > 0) {
6232
+ // Run all finally interceptors sequentially
6233
+ return finallyInterceptors.reduce((previousPromise, interceptor) => previousPromise.then(() => interceptor(context)), Promise.resolve());
6234
+ }
4964
6235
  });
4965
6236
  },
4966
6237
  };
@@ -4971,7 +6242,9 @@ const sfapJwtRepository = new JwtRepository();
4971
6242
  const sfapJwtManager = new JwtManager(sfapJwtRepository, platformSfapJwtResolver);
4972
6243
  function buildJwtAuthorizedSfapFetchServiceDescriptor(logger) {
4973
6244
  const jwtAuthorizedFetchService = buildLexConnectFetchServiceDescriptor({
4974
- request: [buildJwtRequestInterceptor(logger)],
6245
+ createContext: createInstrumentationIdContext(),
6246
+ request: [buildThirdPartyTrackerRegisterInterceptor(), buildJwtRequestInterceptor(logger)],
6247
+ finally: [buildThirdPartyTrackerFinishInterceptor()],
4975
6248
  });
4976
6249
  return {
4977
6250
  ...jwtAuthorizedFetchService,
@@ -4990,7 +6263,9 @@ function buildCopilotFetchServiceDescriptor(logger) {
4990
6263
  // Interceptor here with the logic in buildJwtAuthorizedSfapFetchServiceDescriptor()
4991
6264
  // above.
4992
6265
  ...buildLexConnectFetchServiceDescriptor({
6266
+ createContext: createInstrumentationIdContext(),
4993
6267
  request: [
6268
+ buildThirdPartyTrackerRegisterInterceptor(),
4994
6269
  // Note that this function is VERY closely tied to the fetchParams generated
4995
6270
  // by copilotStartSessionCommand. Any changes to those parameters will require
4996
6271
  // corresponding updates to the logic below.
@@ -5003,9 +6278,9 @@ function buildCopilotFetchServiceDescriptor(logger) {
5003
6278
  requestInit.method !== 'POST' ||
5004
6279
  !requestInit.body ||
5005
6280
  typeof requestInit.body !== 'string') {
5006
- return resolvedPromiseLike$3(args);
6281
+ return resolvedPromiseLike$2(args);
5007
6282
  }
5008
- return resolvedPromiseLike$3(sfapJwtManager.getJwt()).then((token) => {
6283
+ return resolvedPromiseLike$2(sfapJwtManager.getJwt()).then((token) => {
5009
6284
  // replace the body's instanceConfig.endpoint with the JWT's iss value
5010
6285
  const body = JSON.parse(requestInit.body);
5011
6286
  if (!body || !token.decodedInfo || !token.decodedInfo.iss) {
@@ -5030,12 +6305,17 @@ function buildCopilotFetchServiceDescriptor(logger) {
5030
6305
  },
5031
6306
  buildJwtRequestInterceptor(logger),
5032
6307
  ],
6308
+ finally: [buildThirdPartyTrackerFinishInterceptor()],
5033
6309
  }),
5034
6310
  tags: { specialHacksFor: 'copilot' },
5035
6311
  };
5036
6312
  }
5037
6313
  function buildUnauthorizedFetchServiceDescriptor() {
5038
- const fetchService = buildLexConnectFetchServiceDescriptor();
6314
+ const fetchService = buildLexConnectFetchServiceDescriptor({
6315
+ createContext: createInstrumentationIdContext(),
6316
+ request: [buildThirdPartyTrackerRegisterInterceptor()],
6317
+ finally: [buildThirdPartyTrackerFinishInterceptor()],
6318
+ });
5039
6319
  return {
5040
6320
  ...fetchService,
5041
6321
  tags: { authenticationScopes: '' },
@@ -7785,12 +9065,12 @@ class FetchThrottlingRetryPolicy extends RetryPolicy {
7785
9065
  super();
7786
9066
  this.config = config;
7787
9067
  }
7788
- shouldRetry(result, context) {
9068
+ async shouldRetry(result, context) {
7789
9069
  return ((result.status === 429 || result.status === 503) &&
7790
9070
  context.attempt < this.config.maxRetries &&
7791
9071
  context.totalElapsedMs <= this.config.maxTimeToRetry);
7792
9072
  }
7793
- calculateDelay(result, context) {
9073
+ async calculateDelay(result, context) {
7794
9074
  let delay;
7795
9075
  // If retry-after header is present and valid, use it
7796
9076
  const retryAfterHeader = this.parseRetryAfterHeader(result);
@@ -8407,18 +9687,18 @@ function initializeLDS() {
8407
9687
  }
8408
9688
  // Initializes OneStore in LEX
8409
9689
  function initializeOneStore(luvio) {
8410
- const loggerService = new ConsoleLogger$1('ERROR');
8411
- const cacheServiceDescriptor = buildServiceDescriptor$a();
8412
- const instrumentationServiceDescriptor = buildServiceDescriptor$b(loggerService);
9690
+ const loggerService = new ConsoleLogger('ERROR');
9691
+ const cacheServiceDescriptor = buildServiceDescriptor$h();
9692
+ const instrumentationServiceDescriptor = buildServiceDescriptor$i(loggerService);
8413
9693
  const inMemoryCacheInclusionPolicyServiceDescriptor = buildInMemoryCacheInclusionPolicyService(cacheServiceDescriptor.service);
8414
9694
  const durableCacheInclusionPolicyServiceDescriptor = buildAuraDurableCacheInclusionPolicyService();
8415
9695
  const durableCacheControlService = {
8416
- ...buildServiceDescriptor$9(cacheServiceDescriptor.service, durableCacheInclusionPolicyServiceDescriptor.service, instrumentationServiceDescriptor.service),
9696
+ ...buildServiceDescriptor$g(cacheServiceDescriptor.service, durableCacheInclusionPolicyServiceDescriptor.service, instrumentationServiceDescriptor.service),
8417
9697
  tags: { storage: 'durable' },
8418
9698
  };
8419
- const featureFlagsServiceDescriptor = buildServiceDescriptor$3();
9699
+ const featureFlagsServiceDescriptor = buildServiceDescriptor$a();
8420
9700
  const featureFlagsService = featureFlagsServiceDescriptor.service;
8421
- const luvioUiapiRecordsServiceDescriptor = buildServiceDescriptor$2((configs) => {
9701
+ const luvioUiapiRecordsServiceDescriptor = buildServiceDescriptor$9((configs) => {
8422
9702
  return notifyUpdateAvailableFactory(luvio)(configs);
8423
9703
  }, (recordId, reader) => {
8424
9704
  const recordKey = buildRecordRepKeyFromId(recordId);
@@ -8437,8 +9717,11 @@ function initializeOneStore(luvio) {
8437
9717
  reader.unMarkMissing();
8438
9718
  return linkedData.data;
8439
9719
  });
8440
- const retryPolicy = new FetchThrottlingRetryPolicy();
8441
- const retryServiceDescriptor = buildServiceDescriptor$1(retryPolicy);
9720
+ // Compose both throttling and CSRF retry policies
9721
+ const throttlingPolicy = new FetchThrottlingRetryPolicy();
9722
+ const csrfPolicy = new CsrfTokenRetryPolicy();
9723
+ const retryPolicy = new ComposedRetryPolicy([throttlingPolicy, csrfPolicy]);
9724
+ const retryServiceDescriptor = buildServiceDescriptor$8(retryPolicy);
8442
9725
  const retryService = retryServiceDescriptor.service;
8443
9726
  // set flags based on gates
8444
9727
  featureFlagsService.set('useOneStoreGraphQL', useOneStoreGraphql.isOpen({ fallback: false }));
@@ -8449,27 +9732,36 @@ function initializeOneStore(luvio) {
8449
9732
  buildJwtAuthorizedSfapFetchServiceDescriptor(loggerService),
8450
9733
  buildCopilotFetchServiceDescriptor(loggerService),
8451
9734
  buildAuraNetworkService(),
8452
- buildServiceDescriptor$c(instrumentationServiceDescriptor.service),
9735
+ buildServiceDescriptor$j(instrumentationServiceDescriptor.service),
8453
9736
  // Ordering of services matters - L1 only CacheControlService must come before durable
8454
- buildServiceDescriptor$9(cacheServiceDescriptor.service, inMemoryCacheInclusionPolicyServiceDescriptor.service, instrumentationServiceDescriptor.service),
9737
+ buildServiceDescriptor$g(cacheServiceDescriptor.service, inMemoryCacheInclusionPolicyServiceDescriptor.service, instrumentationServiceDescriptor.service),
8455
9738
  durableCacheControlService,
8456
- buildServiceDescriptor$j(),
8457
- buildServiceDescriptor$7(),
8458
- buildServiceDescriptor$f(),
8459
- buildServiceDescriptor$k(),
9739
+ buildServiceDescriptor$q(),
8460
9740
  buildServiceDescriptor$e(),
8461
- buildServiceDescriptor$d(),
8462
- buildServiceDescriptor$i(),
8463
- buildServiceDescriptor$h(),
8464
- buildServiceDescriptor$g(),
8465
- buildServiceDescriptor$8(),
9741
+ buildServiceDescriptor$m(),
9742
+ buildServiceDescriptor$r(),
9743
+ buildServiceDescriptor$l(),
9744
+ buildServiceDescriptor$k(),
9745
+ buildServiceDescriptor$p(),
9746
+ buildServiceDescriptor$o(),
9747
+ buildServiceDescriptor$n(),
9748
+ buildServiceDescriptor$f(),
8466
9749
  buildLexRuntimeAllow5xxFetchServiceDescriptor(loggerService, retryService),
8467
- buildServiceDescriptor$6(luvio),
9750
+ buildServiceDescriptor$d(luvio),
8468
9751
  luvioUiapiRecordsServiceDescriptor,
8469
- buildServiceDescriptor$5(),
8470
- buildServiceDescriptor$4(),
9752
+ buildServiceDescriptor$c(),
9753
+ buildServiceDescriptor$b(),
8471
9754
  featureFlagsServiceDescriptor,
8472
9755
  retryServiceDescriptor,
9756
+ buildServiceDescriptor$6(),
9757
+ buildServiceDescriptor$5(),
9758
+ buildServiceDescriptor$4(),
9759
+ buildServiceDescriptor$3(),
9760
+ buildServiceDescriptor$2$1(),
9761
+ buildServiceDescriptor$1$1(),
9762
+ buildServiceDescriptor$7(),
9763
+ buildLWCWireBindingsServiceDescriptor(),
9764
+ buildLWCGraphQLWireBindingsServiceDescriptor(),
8473
9765
  ];
8474
9766
  setServices(services);
8475
9767
  }
@@ -8489,4 +9781,4 @@ function ldsEngineCreator() {
8489
9781
  }
8490
9782
 
8491
9783
  export { LexRequestStrategy, PdlRequestPriority, buildPredictorForContext, ldsEngineCreator as default, initializeLDS, initializeOneStore, notifyUpdateAvailableFactory, registerRequestStrategy, saveRequestAsPrediction, unregisterRequestStrategy, whenPredictionsReady };
8492
- // version: 1.401.0-b1adb82748
9784
+ // version: 1.403.0-bc09fbc54b