@salesforce/lds-drafts 1.100.3 → 1.100.4

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.
@@ -16,6 +16,7 @@ export declare class DurableDraftQueue implements DraftQueue {
16
16
  private replacingAction?;
17
17
  private uploadingActionId?;
18
18
  private timeoutHandler;
19
+ private workerPool;
19
20
  private handlers;
20
21
  private getHandler;
21
22
  constructor(draftStore: DraftStore);
@@ -11,6 +11,9 @@ export declare abstract class AbstractResourceRequestActionHandler<ResponseType,
11
11
  protected readonly draftQueue: DraftQueue;
12
12
  protected readonly networkAdapter: NetworkAdapter;
13
13
  protected readonly getLuvio: () => Luvio;
14
+ ephemeralRedirects: {
15
+ [key: string]: string;
16
+ };
14
17
  constructor(draftQueue: DraftQueue, networkAdapter: NetworkAdapter, getLuvio: () => Luvio);
15
18
  enqueue(data: ResourceRequest): Promise<PendingDraftAction<ResourceRequest>>;
16
19
  handleAction(action: DraftAction<ResourceRequest, ResponseType>, actionCompleted: (action: CompletedDraftAction<ResourceRequest, ResponseType>) => Promise<void>, actionErrored: (action: DraftAction<ResourceRequest, ResponseType>, retry: boolean) => Promise<void>): Promise<ProcessActionResult>;
package/dist/ldsDrafts.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { HttpStatusCode, StoreKeyMap } from '@luvio/engine';
8
+ import { AsyncWorkerPool } from '@salesforce/lds-utils-adapters';
8
9
 
9
10
  var DraftActionStatus;
10
11
  (function (DraftActionStatus) {
@@ -424,6 +425,7 @@ class DurableDraftQueue {
424
425
  this.timeoutHandler = undefined;
425
426
  this.handlers = {};
426
427
  this.draftStore = draftStore;
428
+ this.workerPool = new AsyncWorkerPool(1);
427
429
  }
428
430
  addHandler(handler) {
429
431
  const id = handler.handlerId;
@@ -523,20 +525,22 @@ class DurableDraftQueue {
523
525
  });
524
526
  }
525
527
  async enqueue(handlerId, data) {
526
- let queue = await this.getQueueActions();
527
- const handler = this.getHandler(handlerId);
528
- const pendingAction = (await handler.buildPendingAction(data, queue));
529
- await this.draftStore.writeAction(pendingAction);
530
- queue = await this.getQueueActions();
531
- await this.notifyChangedListeners({
532
- type: DraftQueueEventType.ActionAdded,
533
- action: pendingAction,
528
+ return this.workerPool.push(async () => {
529
+ let queue = await this.getQueueActions();
530
+ const handler = this.getHandler(handlerId);
531
+ const pendingAction = (await handler.buildPendingAction(data, queue));
532
+ await this.draftStore.writeAction(pendingAction);
533
+ queue = await this.getQueueActions();
534
+ await this.notifyChangedListeners({
535
+ type: DraftQueueEventType.ActionAdded,
536
+ action: pendingAction,
537
+ });
538
+ await handler.handleActionEnqueued(pendingAction, queue);
539
+ if (this.state === DraftQueueState.Started) {
540
+ this.processNextAction();
541
+ }
542
+ return pendingAction;
534
543
  });
535
- await handler.handleActionEnqueued(pendingAction, queue);
536
- if (this.state === DraftQueueState.Started) {
537
- this.processNextAction();
538
- }
539
- return pendingAction;
540
544
  }
541
545
  registerOnChangedListener(listener) {
542
546
  this.draftQueueChangedListeners.push(listener);
@@ -548,27 +552,29 @@ class DurableDraftQueue {
548
552
  };
549
553
  }
550
554
  async actionCompleted(action) {
551
- const handler = this.getHandler(action.handler);
552
- let queue = await this.getQueueActions();
553
- const queueOperations = handler.getQueueOperationsForCompletingDrafts(queue, action);
554
- const idAndKeyMappings = handler.getRedirectMappings(action);
555
- const keyMappings = idAndKeyMappings === undefined
556
- ? undefined
557
- : idAndKeyMappings.map((m) => {
558
- return { draftKey: m.draftKey, canonicalKey: m.canonicalKey };
555
+ return this.workerPool.push(async () => {
556
+ const handler = this.getHandler(action.handler);
557
+ let queue = await this.getQueueActions();
558
+ const queueOperations = handler.getQueueOperationsForCompletingDrafts(queue, action);
559
+ const idAndKeyMappings = handler.getRedirectMappings(action);
560
+ const keyMappings = idAndKeyMappings === undefined
561
+ ? undefined
562
+ : idAndKeyMappings.map((m) => {
563
+ return { draftKey: m.draftKey, canonicalKey: m.canonicalKey };
564
+ });
565
+ await this.draftStore.completeAction(queueOperations, keyMappings);
566
+ queue = await this.getQueueActions();
567
+ this.retryIntervalMilliseconds = 0;
568
+ this.uploadingActionId = undefined;
569
+ await handler.handleActionCompleted(action, queueOperations, queue, values(this.handlers));
570
+ await this.notifyChangedListeners({
571
+ type: DraftQueueEventType.ActionCompleted,
572
+ action,
559
573
  });
560
- await this.draftStore.completeAction(queueOperations, keyMappings);
561
- queue = await this.getQueueActions();
562
- this.retryIntervalMilliseconds = 0;
563
- this.uploadingActionId = undefined;
564
- await handler.handleActionCompleted(action, queueOperations, queue, values(this.handlers));
565
- await this.notifyChangedListeners({
566
- type: DraftQueueEventType.ActionCompleted,
567
- action,
574
+ if (this.state === DraftQueueState.Started) {
575
+ this.processNextAction();
576
+ }
568
577
  });
569
- if (this.state === DraftQueueState.Started) {
570
- this.processNextAction();
571
- }
572
578
  }
573
579
  async actionFailed(action, retry) {
574
580
  this.uploadingActionId = undefined;
@@ -1018,6 +1024,13 @@ class AbstractResourceRequestActionHandler {
1018
1024
  this.draftQueue = draftQueue;
1019
1025
  this.networkAdapter = networkAdapter;
1020
1026
  this.getLuvio = getLuvio;
1027
+ // NOTE[W-12567340]: This property stores in-memory mappings between draft
1028
+ // ids and canonical ids for the current session. Having a local copy of
1029
+ // these mappings is necessary to avoid a race condition between publishing
1030
+ // new mappings to the durable store and those mappings being loaded into
1031
+ // the luvio store redirect table, during which a new draft might be enqueued
1032
+ // which would not see a necessary mapping.
1033
+ this.ephemeralRedirects = {};
1021
1034
  }
1022
1035
  enqueue(data) {
1023
1036
  return this.draftQueue.enqueue(this.handlerId, data);
@@ -1085,7 +1098,8 @@ class AbstractResourceRequestActionHandler {
1085
1098
  }
1086
1099
  getQueueOperationsForCompletingDrafts(queue, action) {
1087
1100
  const queueOperations = [];
1088
- if (action.data.method === 'post') {
1101
+ const redirects = this.getRedirectMappings(action);
1102
+ if (redirects !== undefined) {
1089
1103
  const { length } = queue;
1090
1104
  for (let i = 0; i < length; i++) {
1091
1105
  const queueAction = queue[i];
@@ -1095,69 +1109,64 @@ class AbstractResourceRequestActionHandler {
1095
1109
  continue;
1096
1110
  }
1097
1111
  if (isResourceRequestAction(queueAction)) {
1098
- const redirects = this.getRedirectMappings(action);
1099
- if (redirects !== undefined) {
1100
- let queueOperationMutated = false;
1101
- let updatedActionTag = undefined;
1102
- let updatedActionTargetId = undefined;
1103
- const { tag: queueActionTag, data: queueActionRequest, id: queueActionId, } = queueAction;
1104
- let { basePath, body } = queueActionRequest;
1105
- let stringifiedBody = stringify(body);
1106
- // for each redirected ID/key we loop over the operation to see if it needs
1107
- // to be updated
1108
- for (const { draftId, draftKey, canonicalId, canonicalKey } of redirects) {
1109
- if (basePath.search(draftId) >= 0 ||
1110
- stringifiedBody.search(draftId) >= 0) {
1111
- basePath = basePath.replace(draftId, canonicalId);
1112
- stringifiedBody = stringifiedBody.replace(draftId, canonicalId);
1113
- queueOperationMutated = true;
1114
- }
1115
- // if the action is performed on a previous draft id, we need to replace the action
1116
- // with a new one at the updated canonical key
1117
- if (queueActionTag === draftKey) {
1118
- updatedActionTag = canonicalKey;
1119
- updatedActionTargetId = canonicalId;
1120
- }
1112
+ let queueOperationMutated = false;
1113
+ let updatedActionTag = undefined;
1114
+ let updatedActionTargetId = undefined;
1115
+ const { tag: queueActionTag, data: queueActionRequest, id: queueActionId, } = queueAction;
1116
+ let { basePath, body } = queueActionRequest;
1117
+ let stringifiedBody = stringify(body);
1118
+ // for each redirected ID/key we loop over the operation to see if it needs
1119
+ // to be updated
1120
+ for (const { draftId, draftKey, canonicalId, canonicalKey } of redirects) {
1121
+ if (basePath.search(draftId) >= 0 || stringifiedBody.search(draftId) >= 0) {
1122
+ basePath = basePath.replace(draftId, canonicalId);
1123
+ stringifiedBody = stringifiedBody.replace(draftId, canonicalId);
1124
+ queueOperationMutated = true;
1121
1125
  }
1122
- if (queueOperationMutated) {
1123
- if (updatedActionTag !== undefined &&
1124
- updatedActionTargetId !== undefined) {
1125
- const updatedAction = {
1126
- ...queueAction,
1127
- tag: updatedActionTag,
1128
- targetId: updatedActionTargetId,
1129
- data: {
1130
- ...queueActionRequest,
1131
- basePath: basePath,
1132
- body: parse(stringifiedBody),
1133
- },
1134
- };
1135
- // item needs to be replaced with a new item at the new record key
1136
- queueOperations.push({
1137
- type: QueueOperationType.Delete,
1138
- id: queueActionId,
1139
- });
1140
- queueOperations.push({
1141
- type: QueueOperationType.Add,
1142
- action: updatedAction,
1143
- });
1144
- }
1145
- else {
1146
- const updatedAction = {
1147
- ...queueAction,
1148
- data: {
1149
- ...queueActionRequest,
1150
- basePath: basePath,
1151
- body: parse(stringifiedBody),
1152
- },
1153
- };
1154
- // item needs to be updated
1155
- queueOperations.push({
1156
- type: QueueOperationType.Update,
1157
- id: queueActionId,
1158
- action: updatedAction,
1159
- });
1160
- }
1126
+ // if the action is performed on a previous draft id, we need to replace the action
1127
+ // with a new one at the updated canonical key
1128
+ if (queueActionTag === draftKey) {
1129
+ updatedActionTag = canonicalKey;
1130
+ updatedActionTargetId = canonicalId;
1131
+ }
1132
+ }
1133
+ if (queueOperationMutated) {
1134
+ if (updatedActionTag !== undefined && updatedActionTargetId !== undefined) {
1135
+ const updatedAction = {
1136
+ ...queueAction,
1137
+ tag: updatedActionTag,
1138
+ targetId: updatedActionTargetId,
1139
+ data: {
1140
+ ...queueActionRequest,
1141
+ basePath: basePath,
1142
+ body: parse(stringifiedBody),
1143
+ },
1144
+ };
1145
+ // item needs to be replaced with a new item at the new record key
1146
+ queueOperations.push({
1147
+ type: QueueOperationType.Delete,
1148
+ id: queueActionId,
1149
+ });
1150
+ queueOperations.push({
1151
+ type: QueueOperationType.Add,
1152
+ action: updatedAction,
1153
+ });
1154
+ }
1155
+ else {
1156
+ const updatedAction = {
1157
+ ...queueAction,
1158
+ data: {
1159
+ ...queueActionRequest,
1160
+ basePath: basePath,
1161
+ body: parse(stringifiedBody),
1162
+ },
1163
+ };
1164
+ // item needs to be updated
1165
+ queueOperations.push({
1166
+ type: QueueOperationType.Update,
1167
+ id: queueActionId,
1168
+ action: updatedAction,
1169
+ });
1161
1170
  }
1162
1171
  }
1163
1172
  }
@@ -1177,6 +1186,9 @@ class AbstractResourceRequestActionHandler {
1177
1186
  const body = action.response.body;
1178
1187
  const canonicalId = this.getIdFromResponseBody(body);
1179
1188
  const draftId = action.targetId;
1189
+ if (draftId !== undefined && canonicalId !== undefined && draftId !== canonicalId) {
1190
+ this.ephemeralRedirects[draftId] = canonicalId;
1191
+ }
1180
1192
  return [
1181
1193
  {
1182
1194
  draftId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/lds-drafts",
3
- "version": "1.100.3",
3
+ "version": "1.100.4",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "LDS Drafts",
6
6
  "main": "dist/ldsDrafts.js",
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@luvio/engine": "0.135.4",
28
- "@luvio/environments": "0.135.4"
28
+ "@luvio/environments": "0.135.4",
29
+ "@salesforce/lds-utils-adapters": "^1.100.4"
29
30
  }
30
31
  }