@salesforce/lds-runtime-mobile 1.287.0-dev15 → 1.287.0-dev16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/main.js +93 -38
  2. package/package.json +16 -16
  3. package/sfdc/main.js +93 -38
package/dist/main.js CHANGED
@@ -20,7 +20,7 @@ import { setupInstrumentation, instrumentAdapter as instrumentAdapter$1, instrum
20
20
  import { HttpStatusCode, setBypassDeepFreeze, StoreKeySet, serializeStructuredKey, StringKeyInMemoryStore, Reader, deepFreeze, emitAdapterEvent, createCustomAdapterEventEmitter, StoreKeyMap, isFileReference, Environment, Luvio, InMemoryStore } from '@luvio/engine';
21
21
  import excludeStaleRecordsGate from '@salesforce/gate/lds.graphqlEvalExcludeStaleRecords';
22
22
  import { parseAndVisit, Kind, buildSchema, isObjectType, defaultFieldResolver, visit, execute, parse as parse$7, extendSchema, isScalarType } from '@luvio/graphql-parser';
23
- import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion, getRecordsAdapterFactory } from '@salesforce/lds-adapters-uiapi';
23
+ import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, getRecordsAdapterFactory, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion } from '@salesforce/lds-adapters-uiapi';
24
24
  import ldsIdempotencyWriteDisabled from '@salesforce/gate/lds.idempotencyWriteDisabled';
25
25
  import ldsBackdatingEnabled from '@salesforce/gate/lds.backdatingEnabled';
26
26
  import FIRST_DAY_OF_WEEK from '@salesforce/i18n/firstDayOfWeek';
@@ -1566,6 +1566,32 @@ function makeDurable(environment, { durableStore, instrumentation, useRevivingSt
1566
1566
  }, revivingStore).finally(() => {
1567
1567
  });
1568
1568
  };
1569
+ const expirePossibleStaleRecords = async function (keys$1, config, refresh) {
1570
+ validateNotDisposed();
1571
+ const metadataKeys = keys$1.map(serializeStructuredKey);
1572
+ const now = Date.now();
1573
+ const entries = await durableStore.getMetadata(metadataKeys, DefaultDurableSegment);
1574
+ if (entries === undefined || keys$7(entries).length === 0) {
1575
+ return environment.expirePossibleStaleRecords(keys$1);
1576
+ }
1577
+ let metaDataChanged = false;
1578
+ const metadataEntries = metadataKeys.reduce((accu, key) => {
1579
+ const metadataEntry = entries[key];
1580
+ if (metadataEntry.metadata !== undefined) {
1581
+ const metadata = { ...metadataEntry.metadata, expirationTimestamp: now };
1582
+ accu[key] = { metadata };
1583
+ metaDataChanged = true;
1584
+ }
1585
+ return accu;
1586
+ }, {});
1587
+ if (metaDataChanged) {
1588
+ await durableStore.setMetadata(metadataEntries, DefaultDurableSegment);
1589
+ }
1590
+ if (config !== undefined && refresh !== undefined) {
1591
+ return environment.refreshPossibleStaleRecords(config, refresh);
1592
+ }
1593
+ return Promise.resolve();
1594
+ };
1569
1595
  // set the default cache policy of the base environment
1570
1596
  environment.setDefaultCachePolicy({
1571
1597
  type: 'stale-while-revalidate',
@@ -1598,6 +1624,7 @@ function makeDurable(environment, { durableStore, instrumentation, useRevivingSt
1598
1624
  handleErrorResponse: { value: handleErrorResponse },
1599
1625
  getNotifyChangeStoreEntries: { value: getNotifyChangeStoreEntries },
1600
1626
  notifyStoreUpdateAvailable: { value: notifyStoreUpdateAvailable },
1627
+ expirePossibleStaleRecords: { value: expirePossibleStaleRecords },
1601
1628
  });
1602
1629
  }
1603
1630
 
@@ -7230,6 +7257,7 @@ function createContext(store, objectInfos, eventEmitter, settings, snapshot, dra
7230
7257
  Record,
7231
7258
  snapshot,
7232
7259
  seenRecordIds: new Set(),
7260
+ possibleStaleRecordMap: new Map(),
7233
7261
  draftFunctions,
7234
7262
  };
7235
7263
  }
@@ -7841,7 +7869,6 @@ function isTodayStartOfWeek() {
7841
7869
 
7842
7870
  const JSON_EXTRACT_PATH_INGESTION_TIMESTAMP = '$.ingestionTimestamp';
7843
7871
  const JSON_EXTRACT_PATH_INGESTION_APINAME = '$.apiName';
7844
- const JSON_EXTRACT_PATH_DRAFTS = '$.drafts';
7845
7872
 
7846
7873
  const MultiPickListValueSeparator = ';';
7847
7874
  function filterToPredicates(where, recordType, alias, objectInfoMap, joins, draftFunctions) {
@@ -8371,18 +8398,11 @@ function buildQuery(config) {
8371
8398
  const joins = buildJoins(config);
8372
8399
  const predicates = buildPredicates(config);
8373
8400
  const orderBy = buildOrderBy(config);
8374
- const staleRecordsSql = excludeStaleRecordsGate.isOpen({ fallback: false })
8375
- ? `AND (
8376
- json_extract("${config.alias}".metadata, '${JSON_EXTRACT_PATH_INGESTION_TIMESTAMP}') >= ?
8377
- OR json_extract("${config.alias}".data, '${JSON_EXTRACT_PATH_DRAFTS}') IS NOT NULL
8378
- )`
8379
- : '';
8380
8401
  const sql = `
8381
- SELECT "${config.alias}".data
8402
+ SELECT "${config.alias}".data, "${config.alias}".metadata
8382
8403
  FROM lds_data "${config.alias}" ${joins.sql}
8383
8404
  WHERE "${config.alias}".key like 'UiApi::RecordRepresentation:%'
8384
8405
  AND json_extract("${config.alias}".data, '${JSON_EXTRACT_PATH_INGESTION_APINAME}') = '${config.alias}'
8385
- ${staleRecordsSql}
8386
8406
  ${predicates.sql}
8387
8407
  ${orderBy.sql}
8388
8408
  LIMIT ?
@@ -8393,7 +8413,6 @@ function buildQuery(config) {
8393
8413
  const bindings = [
8394
8414
  // bindings from predicates on joins
8395
8415
  ...joins.bindings,
8396
- ...(excludeStaleRecordsGate.isOpen({ fallback: false }) ? [config.ingestionTimestamp] : []),
8397
8416
  // where clause and parent scope bindings
8398
8417
  ...predicates.bindings,
8399
8418
  // limit binding
@@ -8419,33 +8438,19 @@ function buildJoins(config) {
8419
8438
  if (allJoins.length === 0)
8420
8439
  return { sql, bindings };
8421
8440
  sql = allJoins.reduce((joinAccumulator, join) => {
8422
- let timestampAdded = false;
8423
8441
  const joinConditions = join.conditions.reduce((conditionAccumulator, condition) => {
8424
8442
  let joined_sql;
8425
- const joinMetadataTimestamp = excludeStaleRecordsGate.isOpen({ fallback: false })
8426
- ? ` AND (json_extract("${join.alias}".metadata, '${JSON_EXTRACT_PATH_INGESTION_TIMESTAMP}') >= ? OR json_extract("${join.alias}".data, '${JSON_EXTRACT_PATH_DRAFTS}') IS NOT NULL)`
8427
- : '';
8428
8443
  // predicate on a value, use the newly joined table
8429
8444
  if ('type' in condition) {
8430
8445
  const { sql, binding } = predicateToSQL(condition, join.alias);
8431
- joined_sql = ` AND ${sql}${timestampAdded ? '' : joinMetadataTimestamp}`;
8446
+ joined_sql = ` AND ${sql}`;
8432
8447
  bindings.push(...binding);
8433
- if (excludeStaleRecordsGate.isOpen({ fallback: false }) &&
8434
- timestampAdded === false) {
8435
- bindings.push(config.ingestionTimestamp);
8436
- timestampAdded = true;
8437
- }
8438
8448
  }
8439
8449
  else {
8440
8450
  // predicate on a path
8441
8451
  const left = ` AND json_extract("${join.to}".data, '${condition.leftPath}')`;
8442
8452
  const right = `json_extract("${join.alias}".data, '${condition.rightPath}')`;
8443
- joined_sql = `${left} = ${right}${timestampAdded ? '' : joinMetadataTimestamp}`;
8444
- if (excludeStaleRecordsGate.isOpen({ fallback: false }) &&
8445
- timestampAdded === false) {
8446
- bindings.push(config.ingestionTimestamp);
8447
- timestampAdded = true;
8448
- }
8453
+ joined_sql = `${left} = ${right}`;
8449
8454
  }
8450
8455
  conditionAccumulator += joined_sql;
8451
8456
  return conditionAccumulator;
@@ -9390,8 +9395,7 @@ function addResolversToSchema(schema, polyFields) {
9390
9395
  for (const field of fields) {
9391
9396
  if (field.name === 'node') {
9392
9397
  field.resolve = function nodeResolver(obj, _args, { seenRecordIds }) {
9393
- const { record, ingestionTimestamp } = obj;
9394
- const recordRepresentation = parse$4(record);
9398
+ const { recordRepresentation, ingestionTimestamp } = obj;
9395
9399
  seenRecordIds.add(recordRepresentation.id);
9396
9400
  return { recordRepresentation, ingestionTimestamp };
9397
9401
  };
@@ -9605,16 +9609,30 @@ async function connectionEdgeResolver(obj, _args, context) {
9605
9609
  predicates,
9606
9610
  orderBy: orderByToPredicate(parentArgs.orderBy, alias, alias, context.objectInfos),
9607
9611
  limit: parentArgs.first,
9608
- ingestionTimestamp,
9609
9612
  };
9610
9613
  const { sql, bindings } = buildQuery(queryConfig);
9611
9614
  const results = await query(sql, bindings);
9612
9615
  //map each sql result with the ingestion timestamp to pass it down a level
9613
- return results.rows
9614
- .map((row) => row[0])
9615
- .map((record) => {
9616
+ return results.rows.map((row) => {
9617
+ const recordMetadataResult = {
9618
+ recordRepresentation: parse$4(row[0]),
9619
+ metadata: parse$4(row[1]),
9620
+ };
9621
+ const { recordRepresentation, metadata } = recordMetadataResult;
9622
+ context.seenRecordIds.add(recordRepresentation.id);
9623
+ if (metadata.ingestionTimestamp < ingestionTimestamp &&
9624
+ recordRepresentation.drafts === undefined) {
9625
+ if (context.possibleStaleRecordMap.has(recordRepresentation.apiName) === false) {
9626
+ context.possibleStaleRecordMap.set(recordRepresentation.apiName, []);
9627
+ }
9628
+ const ids = context.possibleStaleRecordMap.get(recordRepresentation.apiName);
9629
+ if (ids !== undefined) {
9630
+ ids.push(recordRepresentation.id);
9631
+ context.possibleStaleRecordMap.set(recordRepresentation.apiName, ids);
9632
+ }
9633
+ }
9616
9634
  return {
9617
- record,
9635
+ recordRepresentation,
9618
9636
  ingestionTimestamp,
9619
9637
  };
9620
9638
  });
@@ -10179,7 +10197,11 @@ async function evaluate(config, observers, settings, objectInfos, store, snapsho
10179
10197
  seenRecordIds.push(queryString);
10180
10198
  });
10181
10199
  }
10182
- return { result, seenRecordIds };
10200
+ return {
10201
+ result,
10202
+ seenRecordIds,
10203
+ possibleStaleRecordMap: contextValue.possibleStaleRecordMap,
10204
+ };
10183
10205
  }
10184
10206
  finally {
10185
10207
  eventEmitter({ type: 'graphql-eval-end' });
@@ -13922,8 +13944,13 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13922
13944
  : [];
13923
13945
  let gqlResult;
13924
13946
  let seenRecordIds;
13947
+ let possibleStaleRecordMap;
13925
13948
  try {
13926
- ({ result: gqlResult, seenRecordIds } = await evaluate({
13949
+ ({
13950
+ result: gqlResult,
13951
+ seenRecordIds,
13952
+ possibleStaleRecordMap,
13953
+ } = await evaluate({
13927
13954
  ...config,
13928
13955
  //need to create another copy of the ast for future writes
13929
13956
  query: parse$3(stringify$3(injectedAST)),
@@ -13953,13 +13980,18 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13953
13980
  const seenRecords = createSeenRecords(seenRecordIds, nonEvaluatedSnapshot);
13954
13981
  const recordId = generateUniqueRecordId();
13955
13982
  const rebuildWithLocalEval = async (originalSnapshot) => {
13956
- let { result: rebuildResult, seenRecordIds } = await evaluate({
13983
+ let { result: rebuildResult, seenRecordIds, possibleStaleRecordMap, } = await evaluate({
13957
13984
  ...config,
13958
13985
  query: injectedAST,
13959
13986
  }, observers, { userId }, objectInfoNeeded, store, originalSnapshot, graphqlSchemaCache, draftFunctions);
13960
13987
  if (!rebuildResult.errors) {
13961
13988
  rebuildResult = removeSyntheticFields(rebuildResult, config.query);
13962
13989
  }
13990
+ let snapshotState = 'Fulfilled';
13991
+ if (possibleStaleRecordMap.size > 0) {
13992
+ initiateStaleRecordRefresh(luvio, possibleStaleRecordMap);
13993
+ snapshotState = 'Stale';
13994
+ }
13963
13995
  if (objectsDeepEqual(rebuildResult, originalSnapshot.data)) {
13964
13996
  return originalSnapshot;
13965
13997
  }
@@ -13968,6 +14000,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13968
14000
  ...originalSnapshot,
13969
14001
  data: rebuildResult,
13970
14002
  recordId,
14003
+ state: snapshotState,
13971
14004
  seenRecords: createSeenRecords(seenRecordIds, nonEvaluatedSnapshot),
13972
14005
  rebuildWithLocalEval,
13973
14006
  };
@@ -14005,6 +14038,10 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
14005
14038
  },
14006
14039
  };
14007
14040
  }
14041
+ if (possibleStaleRecordMap.size > 0) {
14042
+ initiateStaleRecordRefresh(luvio, possibleStaleRecordMap);
14043
+ resultSnapshot.state = 'Stale';
14044
+ }
14008
14045
  return resultSnapshot;
14009
14046
  };
14010
14047
  }
@@ -14065,6 +14102,24 @@ function environmentAwareGraphQLBatchAdapterFactory(objectInfoService, luvio, is
14065
14102
  };
14066
14103
  };
14067
14104
  }
14105
+ function initiateStaleRecordRefresh(luvio, keyMap) {
14106
+ const staleRecordKeys = from$1(keyMap.values())
14107
+ .flat()
14108
+ .map((id) => `UiApi::RecordRepresentation:${id}`);
14109
+ luvio.storeExpirePossibleStaleRecords(staleRecordKeys, makeGetRecordsConfig(keyMap), getRecordsAdapterFactory(luvio));
14110
+ }
14111
+ function makeGetRecordsConfig(keyMap) {
14112
+ const records = [];
14113
+ keyMap.forEach((recordIds, apiName) => {
14114
+ records.push({
14115
+ recordIds,
14116
+ fields: [`${apiName}.Id`],
14117
+ });
14118
+ });
14119
+ return {
14120
+ records,
14121
+ };
14122
+ }
14068
14123
 
14069
14124
  const CONTENT_DOCUMENT_DRAFT_ID_KEY = 'CONTENT_DOCUMENT_DRAFT_ID';
14070
14125
  const CONTENT_VERSION_DRAFT_ID_KEY = 'CONTENT_VERSION_DRAFT_ID';
@@ -18374,4 +18429,4 @@ register({
18374
18429
  });
18375
18430
 
18376
18431
  export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, registerReportObserver, reportGraphqlQueryParseError };
18377
- // version: 1.287.0-dev15-a292df40d2
18432
+ // version: 1.287.0-dev16-db839640ab
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-runtime-mobile",
3
- "version": "1.287.0-dev15",
3
+ "version": "1.287.0-dev16",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS runtime for mobile/hybrid environments.",
6
6
  "main": "dist/main.js",
@@ -32,25 +32,25 @@
32
32
  "release:corejar": "yarn build && ../core-build/scripts/core.js --name=lds-runtime-mobile"
33
33
  },
34
34
  "dependencies": {
35
- "@salesforce/lds-adapters-uiapi": "^1.287.0-dev15",
36
- "@salesforce/lds-bindings": "^1.287.0-dev15",
37
- "@salesforce/lds-instrumentation": "^1.287.0-dev15",
38
- "@salesforce/lds-priming": "^1.287.0-dev15",
35
+ "@salesforce/lds-adapters-uiapi": "^1.287.0-dev16",
36
+ "@salesforce/lds-bindings": "^1.287.0-dev16",
37
+ "@salesforce/lds-instrumentation": "^1.287.0-dev16",
38
+ "@salesforce/lds-priming": "^1.287.0-dev16",
39
39
  "@salesforce/user": "0.0.21",
40
40
  "o11y": "250.7.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@salesforce/lds-adapters-graphql": "^1.287.0-dev15",
44
- "@salesforce/lds-drafts": "^1.287.0-dev15",
45
- "@salesforce/lds-drafts-adapters-uiapi": "^1.287.0-dev15",
46
- "@salesforce/lds-graphql-eval": "^1.287.0-dev15",
47
- "@salesforce/lds-network-adapter": "^1.287.0-dev15",
48
- "@salesforce/lds-network-nimbus": "^1.287.0-dev15",
49
- "@salesforce/lds-store-binary": "^1.287.0-dev15",
50
- "@salesforce/lds-store-nimbus": "^1.287.0-dev15",
51
- "@salesforce/lds-store-sql": "^1.287.0-dev15",
52
- "@salesforce/lds-utils-adapters": "^1.287.0-dev15",
53
- "@salesforce/nimbus-plugin-lds": "^1.287.0-dev15",
43
+ "@salesforce/lds-adapters-graphql": "^1.287.0-dev16",
44
+ "@salesforce/lds-drafts": "^1.287.0-dev16",
45
+ "@salesforce/lds-drafts-adapters-uiapi": "^1.287.0-dev16",
46
+ "@salesforce/lds-graphql-eval": "^1.287.0-dev16",
47
+ "@salesforce/lds-network-adapter": "^1.287.0-dev16",
48
+ "@salesforce/lds-network-nimbus": "^1.287.0-dev16",
49
+ "@salesforce/lds-store-binary": "^1.287.0-dev16",
50
+ "@salesforce/lds-store-nimbus": "^1.287.0-dev16",
51
+ "@salesforce/lds-store-sql": "^1.287.0-dev16",
52
+ "@salesforce/lds-utils-adapters": "^1.287.0-dev16",
53
+ "@salesforce/nimbus-plugin-lds": "^1.287.0-dev16",
54
54
  "babel-plugin-dynamic-import-node": "^2.3.3",
55
55
  "wait-for-expect": "^3.0.2"
56
56
  },
package/sfdc/main.js CHANGED
@@ -20,7 +20,7 @@ import { setupInstrumentation, instrumentAdapter as instrumentAdapter$1, instrum
20
20
  import { HttpStatusCode, setBypassDeepFreeze, StoreKeySet, serializeStructuredKey, StringKeyInMemoryStore, Reader, deepFreeze, emitAdapterEvent, createCustomAdapterEventEmitter, StoreKeyMap, isFileReference, Environment, Luvio, InMemoryStore } from 'force/luvioEngine';
21
21
  import excludeStaleRecordsGate from '@salesforce/gate/lds.graphqlEvalExcludeStaleRecords';
22
22
  import { parseAndVisit, Kind, buildSchema, isObjectType, defaultFieldResolver, visit, execute, parse as parse$7, extendSchema, isScalarType } from 'force/ldsGraphqlParser';
23
- import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion, getRecordsAdapterFactory } from 'force/ldsAdaptersUiapi';
23
+ import { RECORD_ID_PREFIX, RECORD_FIELDS_KEY_JUNCTION, isStoreKeyRecordViewEntity, getRecordId18, RECORD_REPRESENTATION_NAME, extractRecordIdFromStoreKey, keyBuilderQuickActionExecutionRepresentation, ingestQuickActionExecutionRepresentation, keyBuilderContentDocumentCompositeRepresentation, getResponseCacheKeysContentDocumentCompositeRepresentation, keyBuilderFromTypeContentDocumentCompositeRepresentation, ingestContentDocumentCompositeRepresentation, keyBuilderRecord, RECORD_VIEW_ENTITY_ID_PREFIX, getTypeCacheKeysRecord, keyBuilderFromTypeRecordRepresentation, ingestRecord, getRecordsAdapterFactory, RecordRepresentationRepresentationType, ObjectInfoRepresentationType, getRecordAdapterFactory, getObjectInfoAdapterFactory, getObjectInfosAdapterFactory, getObjectInfoDirectoryAdapterFactory, UiApiNamespace, RecordRepresentationType, RecordRepresentationTTL, RecordRepresentationVersion } from 'force/ldsAdaptersUiapi';
24
24
  import ldsIdempotencyWriteDisabled from '@salesforce/gate/lds.idempotencyWriteDisabled';
25
25
  import ldsBackdatingEnabled from '@salesforce/gate/lds.backdatingEnabled';
26
26
  import FIRST_DAY_OF_WEEK from '@salesforce/i18n/firstDayOfWeek';
@@ -1566,6 +1566,32 @@ function makeDurable(environment, { durableStore, instrumentation, useRevivingSt
1566
1566
  }, revivingStore).finally(() => {
1567
1567
  });
1568
1568
  };
1569
+ const expirePossibleStaleRecords = async function (keys$1, config, refresh) {
1570
+ validateNotDisposed();
1571
+ const metadataKeys = keys$1.map(serializeStructuredKey);
1572
+ const now = Date.now();
1573
+ const entries = await durableStore.getMetadata(metadataKeys, DefaultDurableSegment);
1574
+ if (entries === undefined || keys$7(entries).length === 0) {
1575
+ return environment.expirePossibleStaleRecords(keys$1);
1576
+ }
1577
+ let metaDataChanged = false;
1578
+ const metadataEntries = metadataKeys.reduce((accu, key) => {
1579
+ const metadataEntry = entries[key];
1580
+ if (metadataEntry.metadata !== undefined) {
1581
+ const metadata = { ...metadataEntry.metadata, expirationTimestamp: now };
1582
+ accu[key] = { metadata };
1583
+ metaDataChanged = true;
1584
+ }
1585
+ return accu;
1586
+ }, {});
1587
+ if (metaDataChanged) {
1588
+ await durableStore.setMetadata(metadataEntries, DefaultDurableSegment);
1589
+ }
1590
+ if (config !== undefined && refresh !== undefined) {
1591
+ return environment.refreshPossibleStaleRecords(config, refresh);
1592
+ }
1593
+ return Promise.resolve();
1594
+ };
1569
1595
  // set the default cache policy of the base environment
1570
1596
  environment.setDefaultCachePolicy({
1571
1597
  type: 'stale-while-revalidate',
@@ -1598,6 +1624,7 @@ function makeDurable(environment, { durableStore, instrumentation, useRevivingSt
1598
1624
  handleErrorResponse: { value: handleErrorResponse },
1599
1625
  getNotifyChangeStoreEntries: { value: getNotifyChangeStoreEntries },
1600
1626
  notifyStoreUpdateAvailable: { value: notifyStoreUpdateAvailable },
1627
+ expirePossibleStaleRecords: { value: expirePossibleStaleRecords },
1601
1628
  });
1602
1629
  }
1603
1630
 
@@ -7230,6 +7257,7 @@ function createContext(store, objectInfos, eventEmitter, settings, snapshot, dra
7230
7257
  Record,
7231
7258
  snapshot,
7232
7259
  seenRecordIds: new Set(),
7260
+ possibleStaleRecordMap: new Map(),
7233
7261
  draftFunctions,
7234
7262
  };
7235
7263
  }
@@ -7841,7 +7869,6 @@ function isTodayStartOfWeek() {
7841
7869
 
7842
7870
  const JSON_EXTRACT_PATH_INGESTION_TIMESTAMP = '$.ingestionTimestamp';
7843
7871
  const JSON_EXTRACT_PATH_INGESTION_APINAME = '$.apiName';
7844
- const JSON_EXTRACT_PATH_DRAFTS = '$.drafts';
7845
7872
 
7846
7873
  const MultiPickListValueSeparator = ';';
7847
7874
  function filterToPredicates(where, recordType, alias, objectInfoMap, joins, draftFunctions) {
@@ -8371,18 +8398,11 @@ function buildQuery(config) {
8371
8398
  const joins = buildJoins(config);
8372
8399
  const predicates = buildPredicates(config);
8373
8400
  const orderBy = buildOrderBy(config);
8374
- const staleRecordsSql = excludeStaleRecordsGate.isOpen({ fallback: false })
8375
- ? `AND (
8376
- json_extract("${config.alias}".metadata, '${JSON_EXTRACT_PATH_INGESTION_TIMESTAMP}') >= ?
8377
- OR json_extract("${config.alias}".data, '${JSON_EXTRACT_PATH_DRAFTS}') IS NOT NULL
8378
- )`
8379
- : '';
8380
8401
  const sql = `
8381
- SELECT "${config.alias}".data
8402
+ SELECT "${config.alias}".data, "${config.alias}".metadata
8382
8403
  FROM lds_data "${config.alias}" ${joins.sql}
8383
8404
  WHERE "${config.alias}".key like 'UiApi::RecordRepresentation:%'
8384
8405
  AND json_extract("${config.alias}".data, '${JSON_EXTRACT_PATH_INGESTION_APINAME}') = '${config.alias}'
8385
- ${staleRecordsSql}
8386
8406
  ${predicates.sql}
8387
8407
  ${orderBy.sql}
8388
8408
  LIMIT ?
@@ -8393,7 +8413,6 @@ function buildQuery(config) {
8393
8413
  const bindings = [
8394
8414
  // bindings from predicates on joins
8395
8415
  ...joins.bindings,
8396
- ...(excludeStaleRecordsGate.isOpen({ fallback: false }) ? [config.ingestionTimestamp] : []),
8397
8416
  // where clause and parent scope bindings
8398
8417
  ...predicates.bindings,
8399
8418
  // limit binding
@@ -8419,33 +8438,19 @@ function buildJoins(config) {
8419
8438
  if (allJoins.length === 0)
8420
8439
  return { sql, bindings };
8421
8440
  sql = allJoins.reduce((joinAccumulator, join) => {
8422
- let timestampAdded = false;
8423
8441
  const joinConditions = join.conditions.reduce((conditionAccumulator, condition) => {
8424
8442
  let joined_sql;
8425
- const joinMetadataTimestamp = excludeStaleRecordsGate.isOpen({ fallback: false })
8426
- ? ` AND (json_extract("${join.alias}".metadata, '${JSON_EXTRACT_PATH_INGESTION_TIMESTAMP}') >= ? OR json_extract("${join.alias}".data, '${JSON_EXTRACT_PATH_DRAFTS}') IS NOT NULL)`
8427
- : '';
8428
8443
  // predicate on a value, use the newly joined table
8429
8444
  if ('type' in condition) {
8430
8445
  const { sql, binding } = predicateToSQL(condition, join.alias);
8431
- joined_sql = ` AND ${sql}${timestampAdded ? '' : joinMetadataTimestamp}`;
8446
+ joined_sql = ` AND ${sql}`;
8432
8447
  bindings.push(...binding);
8433
- if (excludeStaleRecordsGate.isOpen({ fallback: false }) &&
8434
- timestampAdded === false) {
8435
- bindings.push(config.ingestionTimestamp);
8436
- timestampAdded = true;
8437
- }
8438
8448
  }
8439
8449
  else {
8440
8450
  // predicate on a path
8441
8451
  const left = ` AND json_extract("${join.to}".data, '${condition.leftPath}')`;
8442
8452
  const right = `json_extract("${join.alias}".data, '${condition.rightPath}')`;
8443
- joined_sql = `${left} = ${right}${timestampAdded ? '' : joinMetadataTimestamp}`;
8444
- if (excludeStaleRecordsGate.isOpen({ fallback: false }) &&
8445
- timestampAdded === false) {
8446
- bindings.push(config.ingestionTimestamp);
8447
- timestampAdded = true;
8448
- }
8453
+ joined_sql = `${left} = ${right}`;
8449
8454
  }
8450
8455
  conditionAccumulator += joined_sql;
8451
8456
  return conditionAccumulator;
@@ -9390,8 +9395,7 @@ function addResolversToSchema(schema, polyFields) {
9390
9395
  for (const field of fields) {
9391
9396
  if (field.name === 'node') {
9392
9397
  field.resolve = function nodeResolver(obj, _args, { seenRecordIds }) {
9393
- const { record, ingestionTimestamp } = obj;
9394
- const recordRepresentation = parse$4(record);
9398
+ const { recordRepresentation, ingestionTimestamp } = obj;
9395
9399
  seenRecordIds.add(recordRepresentation.id);
9396
9400
  return { recordRepresentation, ingestionTimestamp };
9397
9401
  };
@@ -9605,16 +9609,30 @@ async function connectionEdgeResolver(obj, _args, context) {
9605
9609
  predicates,
9606
9610
  orderBy: orderByToPredicate(parentArgs.orderBy, alias, alias, context.objectInfos),
9607
9611
  limit: parentArgs.first,
9608
- ingestionTimestamp,
9609
9612
  };
9610
9613
  const { sql, bindings } = buildQuery(queryConfig);
9611
9614
  const results = await query(sql, bindings);
9612
9615
  //map each sql result with the ingestion timestamp to pass it down a level
9613
- return results.rows
9614
- .map((row) => row[0])
9615
- .map((record) => {
9616
+ return results.rows.map((row) => {
9617
+ const recordMetadataResult = {
9618
+ recordRepresentation: parse$4(row[0]),
9619
+ metadata: parse$4(row[1]),
9620
+ };
9621
+ const { recordRepresentation, metadata } = recordMetadataResult;
9622
+ context.seenRecordIds.add(recordRepresentation.id);
9623
+ if (metadata.ingestionTimestamp < ingestionTimestamp &&
9624
+ recordRepresentation.drafts === undefined) {
9625
+ if (context.possibleStaleRecordMap.has(recordRepresentation.apiName) === false) {
9626
+ context.possibleStaleRecordMap.set(recordRepresentation.apiName, []);
9627
+ }
9628
+ const ids = context.possibleStaleRecordMap.get(recordRepresentation.apiName);
9629
+ if (ids !== undefined) {
9630
+ ids.push(recordRepresentation.id);
9631
+ context.possibleStaleRecordMap.set(recordRepresentation.apiName, ids);
9632
+ }
9633
+ }
9616
9634
  return {
9617
- record,
9635
+ recordRepresentation,
9618
9636
  ingestionTimestamp,
9619
9637
  };
9620
9638
  });
@@ -10179,7 +10197,11 @@ async function evaluate(config, observers, settings, objectInfos, store, snapsho
10179
10197
  seenRecordIds.push(queryString);
10180
10198
  });
10181
10199
  }
10182
- return { result, seenRecordIds };
10200
+ return {
10201
+ result,
10202
+ seenRecordIds,
10203
+ possibleStaleRecordMap: contextValue.possibleStaleRecordMap,
10204
+ };
10183
10205
  }
10184
10206
  finally {
10185
10207
  eventEmitter({ type: 'graphql-eval-end' });
@@ -13922,8 +13944,13 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13922
13944
  : [];
13923
13945
  let gqlResult;
13924
13946
  let seenRecordIds;
13947
+ let possibleStaleRecordMap;
13925
13948
  try {
13926
- ({ result: gqlResult, seenRecordIds } = await evaluate({
13949
+ ({
13950
+ result: gqlResult,
13951
+ seenRecordIds,
13952
+ possibleStaleRecordMap,
13953
+ } = await evaluate({
13927
13954
  ...config,
13928
13955
  //need to create another copy of the ast for future writes
13929
13956
  query: parse$3(stringify$3(injectedAST)),
@@ -13953,13 +13980,18 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13953
13980
  const seenRecords = createSeenRecords(seenRecordIds, nonEvaluatedSnapshot);
13954
13981
  const recordId = generateUniqueRecordId();
13955
13982
  const rebuildWithLocalEval = async (originalSnapshot) => {
13956
- let { result: rebuildResult, seenRecordIds } = await evaluate({
13983
+ let { result: rebuildResult, seenRecordIds, possibleStaleRecordMap, } = await evaluate({
13957
13984
  ...config,
13958
13985
  query: injectedAST,
13959
13986
  }, observers, { userId }, objectInfoNeeded, store, originalSnapshot, graphqlSchemaCache, draftFunctions);
13960
13987
  if (!rebuildResult.errors) {
13961
13988
  rebuildResult = removeSyntheticFields(rebuildResult, config.query);
13962
13989
  }
13990
+ let snapshotState = 'Fulfilled';
13991
+ if (possibleStaleRecordMap.size > 0) {
13992
+ initiateStaleRecordRefresh(luvio, possibleStaleRecordMap);
13993
+ snapshotState = 'Stale';
13994
+ }
13963
13995
  if (objectsDeepEqual(rebuildResult, originalSnapshot.data)) {
13964
13996
  return originalSnapshot;
13965
13997
  }
@@ -13968,6 +14000,7 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
13968
14000
  ...originalSnapshot,
13969
14001
  data: rebuildResult,
13970
14002
  recordId,
14003
+ state: snapshotState,
13971
14004
  seenRecords: createSeenRecords(seenRecordIds, nonEvaluatedSnapshot),
13972
14005
  rebuildWithLocalEval,
13973
14006
  };
@@ -14005,6 +14038,10 @@ function draftAwareGraphQLAdapterFactory(userId, objectInfoService, store, luvio
14005
14038
  },
14006
14039
  };
14007
14040
  }
14041
+ if (possibleStaleRecordMap.size > 0) {
14042
+ initiateStaleRecordRefresh(luvio, possibleStaleRecordMap);
14043
+ resultSnapshot.state = 'Stale';
14044
+ }
14008
14045
  return resultSnapshot;
14009
14046
  };
14010
14047
  }
@@ -14065,6 +14102,24 @@ function environmentAwareGraphQLBatchAdapterFactory(objectInfoService, luvio, is
14065
14102
  };
14066
14103
  };
14067
14104
  }
14105
+ function initiateStaleRecordRefresh(luvio, keyMap) {
14106
+ const staleRecordKeys = from$1(keyMap.values())
14107
+ .flat()
14108
+ .map((id) => `UiApi::RecordRepresentation:${id}`);
14109
+ luvio.storeExpirePossibleStaleRecords(staleRecordKeys, makeGetRecordsConfig(keyMap), getRecordsAdapterFactory(luvio));
14110
+ }
14111
+ function makeGetRecordsConfig(keyMap) {
14112
+ const records = [];
14113
+ keyMap.forEach((recordIds, apiName) => {
14114
+ records.push({
14115
+ recordIds,
14116
+ fields: [`${apiName}.Id`],
14117
+ });
14118
+ });
14119
+ return {
14120
+ records,
14121
+ };
14122
+ }
14068
14123
 
14069
14124
  const CONTENT_DOCUMENT_DRAFT_ID_KEY = 'CONTENT_DOCUMENT_DRAFT_ID';
14070
14125
  const CONTENT_VERSION_DRAFT_ID_KEY = 'CONTENT_VERSION_DRAFT_ID';
@@ -18374,4 +18429,4 @@ register({
18374
18429
  });
18375
18430
 
18376
18431
  export { O11Y_NAMESPACE_LDS_MOBILE, getRuntime, registerReportObserver, reportGraphqlQueryParseError };
18377
- // version: 1.287.0-dev15-a292df40d2
18432
+ // version: 1.287.0-dev16-db839640ab