@salesforce/lds-drafts 1.313.0 → 1.314.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.
package/dist/ldsDrafts.js CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { HttpStatusCode, StoreKeyMap } from '@luvio/engine';
8
- import { uuidv4, AsyncWorkerPool } from '@salesforce/lds-utils-adapters';
8
+ import { AsyncWorkerPool, uuidv4 } from '@salesforce/lds-utils-adapters';
9
9
  import ldsIdempotencyWriteDisabled from '@salesforce/gate/lds.idempotencyWriteDisabled';
10
10
  import ldsBackdatingEnabled from '@salesforce/gate/lds.backdatingEnabled';
11
11
 
@@ -97,6 +97,63 @@ var QueueOperationType;
97
97
  QueueOperationType["Update"] = "update";
98
98
  })(QueueOperationType || (QueueOperationType = {}));
99
99
 
100
+ const { keys, create, assign, values } = Object;
101
+ const { stringify, parse } = JSON;
102
+ const { isArray } = Array;
103
+
104
+ const DraftIdMappingKeyPrefix240 = 'DraftIdMapping::';
105
+ const DRAFT_ID_MAPPINGS_SEGMENT = 'DRAFT_ID_MAPPINGS';
106
+ function isLegacyDraftIdMapping(key, data) {
107
+ return key.startsWith(DraftIdMappingKeyPrefix240);
108
+ }
109
+ // TODO [W-11677776]: in 242 we changed the format to store keys instead of ids
110
+ // this can be removed when we drop support for id storing
111
+ function getRecordKeyForId(id) {
112
+ return `UiApi::RecordRepresentation:${id}`;
113
+ }
114
+ /**
115
+ *
116
+ * @param mappingIds (optional) requested mapping ids, if undefined all will be retrieved
117
+ */
118
+ async function getDraftIdMappings(durableStore, mappingIds) {
119
+ const mappings = [];
120
+ let durableStoreOperation;
121
+ if (mappingIds === undefined) {
122
+ durableStoreOperation =
123
+ durableStore.getAllEntries(DRAFT_ID_MAPPINGS_SEGMENT);
124
+ }
125
+ else {
126
+ durableStoreOperation = durableStore.getEntries(mappingIds, DRAFT_ID_MAPPINGS_SEGMENT);
127
+ }
128
+ const entries = await durableStoreOperation;
129
+ if (entries === undefined) {
130
+ return mappings;
131
+ }
132
+ const keys$1 = keys(entries);
133
+ for (const key of keys$1) {
134
+ const entry = entries[key].data;
135
+ if (isLegacyDraftIdMapping(key)) {
136
+ mappings.push({
137
+ draftKey: getRecordKeyForId(entry.draftId),
138
+ canonicalKey: getRecordKeyForId(entry.canonicalId),
139
+ });
140
+ }
141
+ else {
142
+ mappings.push(entry);
143
+ }
144
+ }
145
+ return mappings;
146
+ }
147
+ async function clearDraftIdSegment(durableStore) {
148
+ const entries = await durableStore.getAllEntries(DRAFT_ID_MAPPINGS_SEGMENT);
149
+ if (entries) {
150
+ const keys$1 = keys(entries);
151
+ if (keys$1.length > 0) {
152
+ await durableStore.evictEntries(keys$1, DRAFT_ID_MAPPINGS_SEGMENT);
153
+ }
154
+ }
155
+ }
156
+
100
157
  class DraftSynthesisError extends Error {
101
158
  constructor(message, errorType) {
102
159
  super(message);
@@ -190,14 +247,6 @@ function createInternalErrorResponse() {
190
247
  return new DraftErrorFetchResponse(HttpStatusCode.ServerError, undefined);
191
248
  }
192
249
 
193
- const { keys, create, assign, values } = Object;
194
- const { stringify, parse } = JSON;
195
- const { isArray } = Array;
196
-
197
- function clone(obj) {
198
- return parse(stringify(obj));
199
- }
200
-
201
250
  /**
202
251
  * Generates a time-ordered, unique id to associate with a DraftAction. Ensures
203
252
  * no collisions with existing draft action IDs.
@@ -222,125 +271,6 @@ function generateUniqueDraftActionId(existingIds) {
222
271
  return newId.toString();
223
272
  }
224
273
 
225
- const HTTP_HEADER_RETRY_AFTER = 'Retry-After';
226
- const HTTP_HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
227
- const ERROR_CODE_IDEMPOTENCY_FEATURE_NOT_ENABLED = 'IDEMPOTENCY_FEATURE_NOT_ENABLED';
228
- const ERROR_CODE_IDEMPOTENCY_NOT_SUPPORTED = 'IDEMPOTENCY_NOT_SUPPORTED';
229
- const ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER = 'IDEMPOTENCY_KEY_USED_DIFFERENT_USER';
230
- const ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST = 'IDEMPOTENCY_CONCURRENT_REQUEST';
231
- const ERROR_CODE_IDEMPOTENCY_KEY_ALREADY_USED = 'IDEMPOTENCY_KEY_ALREADY_USED';
232
- const ERROR_CODE_IDEMPOTENCY_BACKEND_OPERATION_ERROR = 'IDEMPOTENCY_BACKEND_OPERATION_ERROR';
233
- /**
234
- * Get the retry after in milliseconds from the response headers, undefined if not specified.
235
- * The header could have two different format.
236
- * Retry-After: <http-date>, like Wed, 21 Oct 2015 07:28:00 GMT
237
- * Retry-After: <delay-seconds>, like 1.5s
238
- * @param headers http headers
239
- * @returns the time to delat in millisconds.
240
- */
241
- function getRetryAfterInMs(headers) {
242
- const retryAfterHeader = headers && headers[HTTP_HEADER_RETRY_AFTER];
243
- if (retryAfterHeader === undefined) {
244
- return undefined;
245
- }
246
- const delayInSecond = parseFloat(retryAfterHeader);
247
- if (retryAfterHeader === delayInSecond.toString()) {
248
- return Math.round(delayInSecond * 1000);
249
- }
250
- const delayUntilDateTime = Date.parse(retryAfterHeader);
251
- if (isNaN(delayUntilDateTime)) {
252
- return undefined;
253
- }
254
- return delayUntilDateTime - Date.now();
255
- }
256
-
257
- function buildLuvioOverrideForDraftAdapters(luvio, handler, extractTargetIdFromCacheKey) {
258
- // override this to create and enqueue a new draft action, and return synthetic response
259
- const dispatchResourceRequest = async function (resourceRequest, _context) {
260
- const resourceRequestCopy = clone(resourceRequest);
261
- resourceRequestCopy.headers = resourceRequestCopy.headers || {};
262
- if (handler.hasIdempotencySupport()) {
263
- resourceRequestCopy.headers[HTTP_HEADER_IDEMPOTENCY_KEY] = uuidv4();
264
- }
265
- const { data } = await handler.enqueue(resourceRequestCopy).catch((err) => {
266
- throw transformErrorToDraftSynthesisError(err);
267
- });
268
- if (data === undefined) {
269
- return Promise.reject(createDraftSynthesisErrorResponse());
270
- }
271
- return createOkResponse(data);
272
- };
273
- // override this to use an infinitely large ttl so the cache entry never expires
274
- const publishStoreMetadata = function (key, storeMetadataParams) {
275
- // if we aren't publishing a draft then use base luvio method
276
- const id = extractTargetIdFromCacheKey(key);
277
- if (id === undefined || !handler.isDraftId(id)) {
278
- return luvio.publishStoreMetadata(key, storeMetadataParams);
279
- }
280
- return luvio.publishStoreMetadata(key, {
281
- ...storeMetadataParams,
282
- ttl: Number.MAX_SAFE_INTEGER,
283
- });
284
- };
285
- return create(luvio, {
286
- dispatchResourceRequest: { value: dispatchResourceRequest },
287
- publishStoreMetadata: { value: publishStoreMetadata },
288
- });
289
- }
290
-
291
- const DraftIdMappingKeyPrefix240 = 'DraftIdMapping::';
292
- const DRAFT_ID_MAPPINGS_SEGMENT = 'DRAFT_ID_MAPPINGS';
293
- function isLegacyDraftIdMapping(key, data) {
294
- return key.startsWith(DraftIdMappingKeyPrefix240);
295
- }
296
- // TODO [W-11677776]: in 242 we changed the format to store keys instead of ids
297
- // this can be removed when we drop support for id storing
298
- function getRecordKeyForId(id) {
299
- return `UiApi::RecordRepresentation:${id}`;
300
- }
301
- /**
302
- *
303
- * @param mappingIds (optional) requested mapping ids, if undefined all will be retrieved
304
- */
305
- async function getDraftIdMappings(durableStore, mappingIds) {
306
- const mappings = [];
307
- let durableStoreOperation;
308
- if (mappingIds === undefined) {
309
- durableStoreOperation =
310
- durableStore.getAllEntries(DRAFT_ID_MAPPINGS_SEGMENT);
311
- }
312
- else {
313
- durableStoreOperation = durableStore.getEntries(mappingIds, DRAFT_ID_MAPPINGS_SEGMENT);
314
- }
315
- const entries = await durableStoreOperation;
316
- if (entries === undefined) {
317
- return mappings;
318
- }
319
- const keys$1 = keys(entries);
320
- for (const key of keys$1) {
321
- const entry = entries[key].data;
322
- if (isLegacyDraftIdMapping(key)) {
323
- mappings.push({
324
- draftKey: getRecordKeyForId(entry.draftId),
325
- canonicalKey: getRecordKeyForId(entry.canonicalId),
326
- });
327
- }
328
- else {
329
- mappings.push(entry);
330
- }
331
- }
332
- return mappings;
333
- }
334
- async function clearDraftIdSegment(durableStore) {
335
- const entries = await durableStore.getAllEntries(DRAFT_ID_MAPPINGS_SEGMENT);
336
- if (entries) {
337
- const keys$1 = keys(entries);
338
- if (keys$1.length > 0) {
339
- await durableStore.evictEntries(keys$1, DRAFT_ID_MAPPINGS_SEGMENT);
340
- }
341
- }
342
- }
343
-
344
274
  var CustomActionResultType;
345
275
  (function (CustomActionResultType) {
346
276
  CustomActionResultType["SUCCESS"] = "SUCCESS";
@@ -568,11 +498,7 @@ class DurableDraftQueue {
568
498
  if (this.state === DraftQueueState.Started) {
569
499
  this.processNextAction();
570
500
  }
571
- const actionData = (await handler.getDataForAction(pendingAction));
572
- return {
573
- action: pendingAction,
574
- data: actionData,
575
- };
501
+ return pendingAction;
576
502
  },
577
503
  });
578
504
  }
@@ -914,6 +840,10 @@ class DurableDraftQueue {
914
840
  }
915
841
  }
916
842
 
843
+ function clone(obj) {
844
+ return parse(stringify(obj));
845
+ }
846
+
917
847
  const DRAFT_ACTION_KEY_JUNCTION = '__DraftAction__';
918
848
  function buildDraftDurableStoreKey(recordKey, draftActionId) {
919
849
  return `${recordKey}${DRAFT_ACTION_KEY_JUNCTION}${draftActionId}`;
@@ -1123,6 +1053,38 @@ class DurableDraftStore {
1123
1053
  }
1124
1054
  }
1125
1055
 
1056
+ const HTTP_HEADER_RETRY_AFTER = 'Retry-After';
1057
+ const HTTP_HEADER_IDEMPOTENCY_KEY = 'Idempotency-Key';
1058
+ const ERROR_CODE_IDEMPOTENCY_FEATURE_NOT_ENABLED = 'IDEMPOTENCY_FEATURE_NOT_ENABLED';
1059
+ const ERROR_CODE_IDEMPOTENCY_NOT_SUPPORTED = 'IDEMPOTENCY_NOT_SUPPORTED';
1060
+ const ERROR_CODE_IDEMPOTENCY_KEY_USED_DIFFERENT_USER = 'IDEMPOTENCY_KEY_USED_DIFFERENT_USER';
1061
+ const ERROR_CODE_IDEMPOTENCY_CONCURRENT_REQUEST = 'IDEMPOTENCY_CONCURRENT_REQUEST';
1062
+ const ERROR_CODE_IDEMPOTENCY_KEY_ALREADY_USED = 'IDEMPOTENCY_KEY_ALREADY_USED';
1063
+ const ERROR_CODE_IDEMPOTENCY_BACKEND_OPERATION_ERROR = 'IDEMPOTENCY_BACKEND_OPERATION_ERROR';
1064
+ /**
1065
+ * Get the retry after in milliseconds from the response headers, undefined if not specified.
1066
+ * The header could have two different format.
1067
+ * Retry-After: <http-date>, like Wed, 21 Oct 2015 07:28:00 GMT
1068
+ * Retry-After: <delay-seconds>, like 1.5s
1069
+ * @param headers http headers
1070
+ * @returns the time to delat in millisconds.
1071
+ */
1072
+ function getRetryAfterInMs(headers) {
1073
+ const retryAfterHeader = headers && headers[HTTP_HEADER_RETRY_AFTER];
1074
+ if (retryAfterHeader === undefined) {
1075
+ return undefined;
1076
+ }
1077
+ const delayInSecond = parseFloat(retryAfterHeader);
1078
+ if (retryAfterHeader === delayInSecond.toString()) {
1079
+ return Math.round(delayInSecond * 1000);
1080
+ }
1081
+ const delayUntilDateTime = Date.parse(retryAfterHeader);
1082
+ if (isNaN(delayUntilDateTime)) {
1083
+ return undefined;
1084
+ }
1085
+ return delayUntilDateTime - Date.now();
1086
+ }
1087
+
1126
1088
  const DEFAULT_FIELD_LAST_MODIFIED_DATE = 'LastModifiedDate';
1127
1089
  const DEFAULT_FIELD_CREATED_DATE = 'CreatedDate';
1128
1090
  class AbstractResourceRequestActionHandler {
@@ -1721,7 +1683,7 @@ class DraftManager {
1721
1683
  tag,
1722
1684
  })
1723
1685
  .then((result) => {
1724
- return this.buildDraftQueueItem(result.action);
1686
+ return this.buildDraftQueueItem(result);
1725
1687
  });
1726
1688
  }
1727
1689
  /**
@@ -2043,4 +2005,4 @@ function makeEnvironmentDraftAware(luvio, env, durableStore, handlers, draftQueu
2043
2005
  });
2044
2006
  }
2045
2007
 
2046
- export { AbstractResourceRequestActionHandler, CustomActionResultType, DEFAULT_FIELD_CREATED_DATE, DEFAULT_FIELD_LAST_MODIFIED_DATE, DRAFT_ERROR_CODE, DRAFT_ID_MAPPINGS_SEGMENT, DRAFT_SEGMENT, DraftActionOperationType, DraftActionStatus, DraftErrorFetchResponse, DraftFetchResponse, DraftManager, DraftQueueEventType, DraftQueueState, DraftSynthesisError, DurableDraftQueue, DurableDraftStore, ProcessActionResult, buildLuvioOverrideForDraftAdapters, createBadRequestResponse, createDeletedResponse, createDraftSynthesisErrorResponse, createInternalErrorResponse, createNotFoundResponse, createOkResponse, generateUniqueDraftActionId, isDraftSynthesisError, makeEnvironmentDraftAware, transformErrorToDraftSynthesisError };
2008
+ export { AbstractResourceRequestActionHandler, CustomActionResultType, DEFAULT_FIELD_CREATED_DATE, DEFAULT_FIELD_LAST_MODIFIED_DATE, DRAFT_ERROR_CODE, DRAFT_ID_MAPPINGS_SEGMENT, DRAFT_SEGMENT, DraftActionOperationType, DraftActionStatus, DraftErrorFetchResponse, DraftFetchResponse, DraftManager, DraftQueueEventType, DraftQueueState, DraftSynthesisError, DurableDraftQueue, DurableDraftStore, ProcessActionResult, createBadRequestResponse, createDeletedResponse, createDraftSynthesisErrorResponse, createInternalErrorResponse, createNotFoundResponse, createOkResponse, generateUniqueDraftActionId, isDraftSynthesisError, makeEnvironmentDraftAware, transformErrorToDraftSynthesisError };
@@ -152,10 +152,6 @@ export interface UpdateQueueOperation {
152
152
  action: DraftAction<unknown, unknown>;
153
153
  }
154
154
  export type QueueOperation = UpdateQueueOperation | AddQueueOperation | DeleteQueueOperation;
155
- export interface EnqueueResult<Data, Response> {
156
- action: PendingDraftAction<Data>;
157
- data: Response;
158
- }
159
155
  export interface DraftQueue {
160
156
  /**
161
157
  * Enqueues a draft action into the DraftQueue
@@ -164,7 +160,7 @@ export interface DraftQueue {
164
160
  * @returns A promise including the pending action created for the request and the data associated with the action
165
161
  * @throws {Error} An error when a proper action handler is not found or conditions are not met to enqueue the action
166
162
  */
167
- enqueue<Data, Response>(handlerId: string, data: Data): Promise<EnqueueResult<Data, Response>>;
163
+ enqueue<Data>(handlerId: string, data: Data): Promise<PendingDraftAction<Data>>;
168
164
  /**
169
165
  * add a new handler to the draft queue to process the data in the actions
170
166
  * @param id identifier to the handler
@@ -1,4 +1,4 @@
1
- import type { DraftQueue, DraftAction, CompletedDraftAction, PendingDraftAction, DraftQueueChangeListener, DraftActionMetadata, EnqueueResult } from './DraftQueue';
1
+ import type { DraftQueue, DraftAction, CompletedDraftAction, PendingDraftAction, DraftQueueChangeListener, DraftActionMetadata } from './DraftQueue';
2
2
  import { ProcessActionResult, DraftQueueState } from './DraftQueue';
3
3
  import type { CustomActionExecutor } from './actionHandlers/CustomActionHandler';
4
4
  import type { ActionHandler } from './actionHandlers/ActionHandler';
@@ -31,7 +31,7 @@ export declare class DurableDraftQueue implements DraftQueue {
31
31
  */
32
32
  private stopQueueManually;
33
33
  getQueueActions<Data = unknown, Response = unknown>(): Promise<DraftAction<Data, Response>[]>;
34
- enqueue<Data, Response>(handlerId: string, data: unknown): Promise<EnqueueResult<Data, Response>>;
34
+ enqueue<Data>(handlerId: string, data: unknown): Promise<PendingDraftAction<Data>>;
35
35
  registerOnChangedListener(listener: DraftQueueChangeListener): () => Promise<void>;
36
36
  actionCompleted(action: CompletedDraftAction<unknown, unknown>): Promise<void>;
37
37
  actionFailed(action: DraftAction<unknown, unknown>, retry: boolean, retryDelayInMs?: number, actionDataChanged?: boolean): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import type { NetworkAdapter, ResourceRequest, Luvio, DurableStoreKeyMetadataMap } from '@luvio/engine';
2
- import type { DraftAction, CompletedDraftAction, QueueOperation, PendingDraftAction, DraftActionMetadata, DraftQueue, EnqueueResult } from '../DraftQueue';
2
+ import type { DraftAction, CompletedDraftAction, QueueOperation, PendingDraftAction, DraftActionMetadata, DraftQueue } from '../DraftQueue';
3
3
  import { ProcessActionResult } from '../DraftQueue';
4
4
  import type { ActionHandler, DraftIdAndKeyMapping } from './ActionHandler';
5
5
  export type ResponseIngestionEntry<T = unknown> = {
@@ -20,7 +20,7 @@ export declare abstract class AbstractResourceRequestActionHandler<ResponseType,
20
20
  isLdsIdempotencyWriteDisabled: boolean;
21
21
  isBackdatingEnabled: boolean;
22
22
  constructor(draftQueue: DraftQueue, networkAdapter: NetworkAdapter, getLuvio: () => Luvio);
23
- enqueue(data: ResourceRequest): Promise<EnqueueResult<ResourceRequest, ResponseType>>;
23
+ enqueue(data: ResourceRequest): Promise<PendingDraftAction<ResourceRequest>>;
24
24
  handleAction(action: DraftAction<ResourceRequest, ResponseType>, actionCompleted: (action: CompletedDraftAction<ResourceRequest, ResponseType>) => Promise<void>, actionErrored: (action: DraftAction<ResourceRequest, ResponseType>, retry: boolean, retryDelayInMs?: number, actionDataChanged?: boolean) => Promise<void>): Promise<ProcessActionResult>;
25
25
  handleIdempotencyServerError(responseBody: any, action: DraftAction<ResourceRequest, ResponseType>, updateIdempotencyKey: boolean, ...targetErrorCodes: string[]): boolean;
26
26
  isUiApiErrors(body: any): boolean;
@@ -1,4 +1,4 @@
1
- import type { CompletedDraftAction, DraftAction, DraftActionMetadata, EnqueueResult, PendingDraftAction, ProcessActionResult, QueueOperation } from '../DraftQueue';
1
+ import type { CompletedDraftAction, DraftAction, DraftActionMetadata, PendingDraftAction, ProcessActionResult, QueueOperation } from '../DraftQueue';
2
2
  import type { DraftKeyMapping } from '../DraftIdMapping';
3
3
  export interface ReplacingActions<Response, Data> {
4
4
  original: DraftAction<Response, Data>;
@@ -36,7 +36,7 @@ export interface ActionHandler<Data, DraftMetadata, Type> {
36
36
  * Enqueues an action to the draft queue
37
37
  * @param data the data that will get added to the draft action
38
38
  */
39
- enqueue(data: Data): Promise<EnqueueResult<Data, Type>>;
39
+ enqueue(data: Data): Promise<PendingDraftAction<Data>>;
40
40
  /**
41
41
  * Used to build a PendingDraftAction that is specific to the type of Data and Response.
42
42
  * @param data
@@ -1,5 +1,4 @@
1
1
  export { DraftQueue, DraftQueueState, DraftAction, ErrorDraftAction, PendingDraftAction, CompletedDraftAction, DraftActionStatus, ProcessActionResult, DraftQueueChangeListener, DraftActionMetadata, DraftQueueEventType, QueueOperation, } from './DraftQueue';
2
- export { AdapterBuildNetworkSnapshot, buildLuvioOverrideForDraftAdapters, } from './DraftAwareAdapter';
3
2
  export { DRAFT_ID_MAPPINGS_SEGMENT, DraftKeyMapping } from './DraftIdMapping';
4
3
  export { DurableDraftQueue, DRAFT_SEGMENT } from './DurableDraftQueue';
5
4
  export { generateUniqueDraftActionId } from './utils/id';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-drafts",
3
- "version": "1.313.0",
3
+ "version": "1.314.0",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS Drafts",
6
6
  "main": "dist/ldsDrafts.js",
@@ -26,7 +26,7 @@
26
26
  "dependencies": {
27
27
  "@luvio/engine": "0.156.4",
28
28
  "@luvio/environments": "0.156.4",
29
- "@salesforce/lds-utils-adapters": "^1.313.0"
29
+ "@salesforce/lds-utils-adapters": "^1.314.0"
30
30
  },
31
31
  "volta": {
32
32
  "extends": "../../package.json"
@@ -1,4 +0,0 @@
1
- import type { DispatchResourceRequestContext, Luvio, Snapshot } from '@luvio/engine';
2
- import type { AbstractResourceRequestActionHandler } from './actionHandlers/AbstractResourceRequestActionHandler';
3
- export type AdapterBuildNetworkSnapshot<Config, Response> = (luvio: Luvio, config: Config, dispatchResourceRequestContext?: DispatchResourceRequestContext) => Promise<Snapshot<Response>>;
4
- export declare function buildLuvioOverrideForDraftAdapters<ResponseType = unknown, DraftMetadata = unknown>(luvio: Luvio, handler: AbstractResourceRequestActionHandler<ResponseType, DraftMetadata>, extractTargetIdFromCacheKey: (cacheKey: string) => string | undefined): Luvio;