@salesforce/lds-drafts 1.124.3 → 1.124.5
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
|
@@ -367,10 +367,6 @@ function customActionHandler(executor, id, draftQueue) {
|
|
|
367
367
|
});
|
|
368
368
|
return queueOperations;
|
|
369
369
|
};
|
|
370
|
-
const replaceAction = (actionId, _withActionId, _uploadingActionId, _actions) => {
|
|
371
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
372
|
-
throw new Error(`${actionId} does not support action replacing. You can only delete ${actionId}`);
|
|
373
|
-
};
|
|
374
370
|
const getRedirectMappings = (_action) => {
|
|
375
371
|
return undefined;
|
|
376
372
|
};
|
|
@@ -382,7 +378,9 @@ function customActionHandler(executor, id, draftQueue) {
|
|
|
382
378
|
handleAction: handle,
|
|
383
379
|
buildPendingAction,
|
|
384
380
|
getQueueOperationsForCompletingDrafts: getQueueOperationsForCompletingDrafts,
|
|
385
|
-
handleReplaceAction:
|
|
381
|
+
handleReplaceAction: () => {
|
|
382
|
+
throw Error('replaceAction not supported for custom actions');
|
|
383
|
+
},
|
|
386
384
|
getRedirectMappings,
|
|
387
385
|
handleActionRemoved: () => Promise.resolve(),
|
|
388
386
|
handleActionCompleted: () => Promise.resolve(),
|
|
@@ -449,13 +447,13 @@ class DurableDraftQueue {
|
|
|
449
447
|
this.userState = DraftQueueState.Started;
|
|
450
448
|
if (this.state === DraftQueueState.Started) {
|
|
451
449
|
// Do nothing if the queue state is already started
|
|
452
|
-
return
|
|
450
|
+
return;
|
|
453
451
|
}
|
|
454
452
|
if (this.replacingAction !== undefined) {
|
|
455
453
|
// If we're replacing an action do nothing
|
|
456
454
|
// replace will restart the queue for us as long as the user
|
|
457
455
|
// has last set the queue to be started
|
|
458
|
-
return
|
|
456
|
+
return;
|
|
459
457
|
}
|
|
460
458
|
this.retryIntervalMilliseconds = 0;
|
|
461
459
|
this.state = DraftQueueState.Started;
|
|
@@ -695,92 +693,11 @@ class DurableDraftQueue {
|
|
|
695
693
|
await this.startQueue();
|
|
696
694
|
}
|
|
697
695
|
}
|
|
698
|
-
replaceAction(
|
|
699
|
-
|
|
700
|
-
if (actionId === withActionId) {
|
|
701
|
-
return Promise.reject('Swapped and swapping action ids cannot be the same');
|
|
702
|
-
}
|
|
703
|
-
// cannot have a replace action already in progress
|
|
704
|
-
if (this.replacingAction !== undefined) {
|
|
705
|
-
return Promise.reject('Cannot replace actions while a replace action is in progress');
|
|
706
|
-
}
|
|
707
|
-
this.stopQueueManually();
|
|
708
|
-
const replacing = this.getQueueActions().then(async (actions) => {
|
|
709
|
-
const first = actions.filter((action) => action.id === actionId)[0];
|
|
710
|
-
if (first === undefined) {
|
|
711
|
-
this.replacingAction = undefined;
|
|
712
|
-
await this.startQueueSafe();
|
|
713
|
-
return Promise.reject('No action to replace');
|
|
714
|
-
}
|
|
715
|
-
// put in a try/finally block so we don't leave this.replacingAction
|
|
716
|
-
// indefinitely set
|
|
717
|
-
let actionToReplace;
|
|
718
|
-
try {
|
|
719
|
-
const replaceResult = this.getHandler(first.handler).handleReplaceAction(actionId, withActionId, this.uploadingActionId, actions);
|
|
720
|
-
actionToReplace = replaceResult.actionToReplace;
|
|
721
|
-
// TODO [W-8873834]: Will add batching support to durable store
|
|
722
|
-
// we should use that here to remove and set both actions in one operation
|
|
723
|
-
await this.removeDraftAction(replaceResult.replacingAction.id);
|
|
724
|
-
await this.draftStore.writeAction(actionToReplace);
|
|
725
|
-
await this.notifyChangedListeners({
|
|
726
|
-
type: DraftQueueEventType.ActionUpdated,
|
|
727
|
-
action: actionToReplace,
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
finally {
|
|
731
|
-
this.replacingAction = undefined;
|
|
732
|
-
}
|
|
733
|
-
await this.startQueueSafe();
|
|
734
|
-
return actionToReplace;
|
|
735
|
-
});
|
|
736
|
-
this.replacingAction = replacing;
|
|
737
|
-
return replacing;
|
|
696
|
+
replaceAction(targetActionId, sourceActionId) {
|
|
697
|
+
return this.replaceOrMergeActions(targetActionId, sourceActionId, false);
|
|
738
698
|
}
|
|
739
699
|
mergeActions(targetActionId, sourceActionId) {
|
|
740
|
-
|
|
741
|
-
if (targetActionId === sourceActionId) {
|
|
742
|
-
return Promise.reject(new Error('targetActionId and sourceActionId cannot be the same.'));
|
|
743
|
-
}
|
|
744
|
-
// cannot have a replace action already in progress
|
|
745
|
-
if (this.replacingAction !== undefined) {
|
|
746
|
-
return Promise.reject(new Error('Cannot merge actions while a replace/merge action operation is in progress.'));
|
|
747
|
-
}
|
|
748
|
-
this.stopQueueManually();
|
|
749
|
-
const promise = this.getQueueActions().then(async (actions) => {
|
|
750
|
-
const target = actions.find((action) => action.id === targetActionId);
|
|
751
|
-
if (target === undefined) {
|
|
752
|
-
this.replacingAction = undefined;
|
|
753
|
-
await this.startQueueSafe();
|
|
754
|
-
throw Error('targetActionId not found in the draft queue.');
|
|
755
|
-
}
|
|
756
|
-
const source = actions.find((action) => action.id === sourceActionId);
|
|
757
|
-
if (source === undefined) {
|
|
758
|
-
this.replacingAction = undefined;
|
|
759
|
-
await this.startQueueSafe();
|
|
760
|
-
throw Error('sourceActionId not found in the draft queue.');
|
|
761
|
-
}
|
|
762
|
-
// put in a try/finally block so we don't leave this.replacingAction
|
|
763
|
-
// indefinitely set
|
|
764
|
-
let merged;
|
|
765
|
-
try {
|
|
766
|
-
merged = this.getHandler(target.handler).mergeActions(target, source);
|
|
767
|
-
// update the target
|
|
768
|
-
await this.draftStore.writeAction(merged);
|
|
769
|
-
await this.notifyChangedListeners({
|
|
770
|
-
type: DraftQueueEventType.ActionUpdated,
|
|
771
|
-
action: merged,
|
|
772
|
-
});
|
|
773
|
-
// remove the source from queue
|
|
774
|
-
await this.removeDraftAction(sourceActionId);
|
|
775
|
-
}
|
|
776
|
-
finally {
|
|
777
|
-
this.replacingAction = undefined;
|
|
778
|
-
}
|
|
779
|
-
await this.startQueueSafe();
|
|
780
|
-
return merged;
|
|
781
|
-
});
|
|
782
|
-
this.replacingAction = promise;
|
|
783
|
-
return promise;
|
|
700
|
+
return this.replaceOrMergeActions(targetActionId, sourceActionId, true);
|
|
784
701
|
}
|
|
785
702
|
async setMetadata(actionId, metadata) {
|
|
786
703
|
const keys$1 = keys(metadata);
|
|
@@ -815,6 +732,81 @@ class DurableDraftQueue {
|
|
|
815
732
|
}
|
|
816
733
|
}, this.retryIntervalMilliseconds);
|
|
817
734
|
}
|
|
735
|
+
async getActionsForReplaceOrMerge(targetActionId, sourceActionId) {
|
|
736
|
+
const actions = await this.getQueueActions();
|
|
737
|
+
const target = actions.find((action) => action.id === targetActionId);
|
|
738
|
+
if (target === undefined) {
|
|
739
|
+
this.replacingAction = undefined;
|
|
740
|
+
await this.startQueueSafe();
|
|
741
|
+
throw Error(`targetActionId ${targetActionId} not found in the draft queue.`);
|
|
742
|
+
}
|
|
743
|
+
const source = actions.find((action) => action.id === sourceActionId);
|
|
744
|
+
if (source === undefined) {
|
|
745
|
+
this.replacingAction = undefined;
|
|
746
|
+
await this.startQueueSafe();
|
|
747
|
+
throw Error(`sourceActionId ${sourceActionId} not found in the draft queue.`);
|
|
748
|
+
}
|
|
749
|
+
return { target, source };
|
|
750
|
+
}
|
|
751
|
+
assertReplaceOrMergePrerequisites(target, source) {
|
|
752
|
+
// ensure actions are in a state to be replaced/merged
|
|
753
|
+
const { targetId: targetCacheKey, tag: targetTag, status: targetStatus, version: targetVersion, } = target;
|
|
754
|
+
const { targetId: sourceCacheKey, tag: sourceTag, status: sourceStatus, version: sourceVersion, } = source;
|
|
755
|
+
if (targetCacheKey !== sourceCacheKey) {
|
|
756
|
+
throw Error('Cannot replace/merge actions for different targetIds.');
|
|
757
|
+
}
|
|
758
|
+
if (targetTag !== sourceTag) {
|
|
759
|
+
throw Error('Cannot replace/merge actions for different tags.');
|
|
760
|
+
}
|
|
761
|
+
if (targetStatus === DraftActionStatus.Completed ||
|
|
762
|
+
targetStatus === DraftActionStatus.Uploading) {
|
|
763
|
+
throw Error(`Cannot replace/merge actions when targetAction is in ${targetStatus} status.`);
|
|
764
|
+
}
|
|
765
|
+
if (sourceStatus !== DraftActionStatus.Pending) {
|
|
766
|
+
throw Error(`Cannot replace/merge actions when sourceAction is in ${sourceStatus} status.`);
|
|
767
|
+
}
|
|
768
|
+
if (targetVersion !== sourceVersion) {
|
|
769
|
+
throw Error('Cannot replace/merge actions with different versions.');
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
async replaceOrMergeActions(targetActionId, sourceActionId, merge) {
|
|
773
|
+
// ids must be unique
|
|
774
|
+
if (targetActionId === sourceActionId) {
|
|
775
|
+
throw Error('targetActionId and sourceActionId cannot be the same.');
|
|
776
|
+
}
|
|
777
|
+
// cannot have a replace action already in progress
|
|
778
|
+
if (this.replacingAction !== undefined) {
|
|
779
|
+
throw Error('Cannot replace/merge actions while a replace/merge action operation is in progress.');
|
|
780
|
+
}
|
|
781
|
+
this.stopQueueManually();
|
|
782
|
+
const promise = this.getActionsForReplaceOrMerge(targetActionId, sourceActionId).then(async ({ target, source }) => {
|
|
783
|
+
// put in a try/finally block so we don't leave this.replacingAction
|
|
784
|
+
// indefinitely set
|
|
785
|
+
let updatedTarget;
|
|
786
|
+
try {
|
|
787
|
+
this.assertReplaceOrMergePrerequisites(target, source);
|
|
788
|
+
const handler = this.getHandler(target.handler);
|
|
789
|
+
updatedTarget = merge
|
|
790
|
+
? handler.mergeActions(target, source)
|
|
791
|
+
: handler.handleReplaceAction(target, source);
|
|
792
|
+
// update the target
|
|
793
|
+
await this.draftStore.writeAction(updatedTarget);
|
|
794
|
+
await this.notifyChangedListeners({
|
|
795
|
+
type: DraftQueueEventType.ActionUpdated,
|
|
796
|
+
action: updatedTarget,
|
|
797
|
+
});
|
|
798
|
+
// remove the source from queue
|
|
799
|
+
await this.removeDraftAction(sourceActionId);
|
|
800
|
+
}
|
|
801
|
+
finally {
|
|
802
|
+
this.replacingAction = undefined;
|
|
803
|
+
await this.startQueueSafe();
|
|
804
|
+
}
|
|
805
|
+
return updatedTarget;
|
|
806
|
+
});
|
|
807
|
+
this.replacingAction = promise;
|
|
808
|
+
return promise;
|
|
809
|
+
}
|
|
818
810
|
}
|
|
819
811
|
|
|
820
812
|
const DRAFT_ACTION_KEY_JUNCTION = '__DraftAction__';
|
|
@@ -1248,55 +1240,52 @@ class AbstractResourceRequestActionHandler {
|
|
|
1248
1240
|
}
|
|
1249
1241
|
await this.ingestResponses(recordsToIngest, action);
|
|
1250
1242
|
}
|
|
1251
|
-
handleReplaceAction(
|
|
1252
|
-
// get the action to replace
|
|
1253
|
-
const actionToReplace = actions.filter((action) => action.id === actionId)[0];
|
|
1254
|
-
// get the replacing action
|
|
1255
|
-
const replacingAction = actions.filter((action) => action.id === withActionId)[0];
|
|
1256
|
-
// reject if either action is undefined
|
|
1257
|
-
if (actionToReplace === undefined || replacingAction === undefined) {
|
|
1258
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1259
|
-
throw new Error('One or both actions does not exist');
|
|
1260
|
-
}
|
|
1261
|
-
// reject if either action is uploading
|
|
1262
|
-
if (actionToReplace.id === uploadingActionId || replacingAction.id === uploadingActionId) {
|
|
1263
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1264
|
-
throw new Error('Cannot replace an draft action that is uploading');
|
|
1265
|
-
}
|
|
1266
|
-
// reject if these two draft actions aren't acting on the same target
|
|
1267
|
-
if (actionToReplace.tag !== replacingAction.tag) {
|
|
1268
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1269
|
-
throw new Error('Cannot swap actions targeting different targets');
|
|
1270
|
-
}
|
|
1271
|
-
// reject if the replacing action is not pending
|
|
1272
|
-
if (replacingAction.status !== DraftActionStatus.Pending) {
|
|
1273
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1274
|
-
throw new Error('Cannot replace with a non-pending action');
|
|
1275
|
-
}
|
|
1243
|
+
handleReplaceAction(targetAction, sourceAction) {
|
|
1276
1244
|
//reject if the action to replace is a POST action
|
|
1277
|
-
const pendingAction =
|
|
1245
|
+
const pendingAction = targetAction;
|
|
1278
1246
|
if (pendingAction.data.method === 'post') {
|
|
1279
|
-
|
|
1280
|
-
throw new Error('Cannot replace a POST action');
|
|
1247
|
+
throw Error('Cannot replace a POST action');
|
|
1281
1248
|
}
|
|
1282
|
-
if (this.isActionOfType(
|
|
1283
|
-
this.isActionOfType(
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
};
|
|
1288
|
-
actionToReplace.status = DraftActionStatus.Pending;
|
|
1289
|
-
actionToReplace.data = replacingAction.data;
|
|
1290
|
-
return {
|
|
1291
|
-
original: actionToReplaceCopy,
|
|
1292
|
-
actionToReplace: actionToReplace,
|
|
1293
|
-
replacingAction: replacingAction,
|
|
1294
|
-
};
|
|
1249
|
+
if (this.isActionOfType(targetAction) &&
|
|
1250
|
+
this.isActionOfType(sourceAction)) {
|
|
1251
|
+
targetAction.status = DraftActionStatus.Pending;
|
|
1252
|
+
targetAction.data = sourceAction.data;
|
|
1253
|
+
return targetAction;
|
|
1295
1254
|
}
|
|
1296
1255
|
else {
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1256
|
+
throw Error('Incompatible Action types to replace one another');
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
mergeActions(targetAction, sourceAction) {
|
|
1260
|
+
const { id: targetId, data: targetData, metadata: targetMetadata, timestamp: targetTimestamp, } = targetAction;
|
|
1261
|
+
const { method: targetMethod, body: targetBody } = targetData;
|
|
1262
|
+
const { data: sourceData, metadata: sourceMetadata } = sourceAction;
|
|
1263
|
+
const { method: sourceMethod, body: sourceBody } = sourceData;
|
|
1264
|
+
if (targetMethod.toLowerCase() === 'delete' || sourceMethod.toLowerCase() === 'delete') {
|
|
1265
|
+
throw Error('Cannot merge DELETE actions.');
|
|
1266
|
+
}
|
|
1267
|
+
if (targetMethod.toLowerCase() === 'patch' && sourceMethod.toLowerCase() === 'post') {
|
|
1268
|
+
// overlaying a POST over a PATCH is not supported
|
|
1269
|
+
throw Error('Cannot merge a POST action over top of a PATCH action.');
|
|
1270
|
+
}
|
|
1271
|
+
// overlay top-level properties, maintain target's timestamp and id
|
|
1272
|
+
const merged = {
|
|
1273
|
+
...targetAction,
|
|
1274
|
+
...sourceAction,
|
|
1275
|
+
timestamp: targetTimestamp,
|
|
1276
|
+
id: targetId,
|
|
1277
|
+
};
|
|
1278
|
+
// overlay data
|
|
1279
|
+
// NOTE: we stick to the target's ResourceRequest properties (except body
|
|
1280
|
+
// which is merged) because we don't want to overwrite a POST with a PATCH
|
|
1281
|
+
// (all other cases should be fine or wouldn't have passed pre-requisites)
|
|
1282
|
+
merged.data = {
|
|
1283
|
+
...targetData,
|
|
1284
|
+
body: this.mergeRequestBody(targetBody, sourceBody),
|
|
1285
|
+
};
|
|
1286
|
+
// overlay metadata
|
|
1287
|
+
merged.metadata = { ...targetMetadata, ...sourceMetadata };
|
|
1288
|
+
return merged;
|
|
1300
1289
|
}
|
|
1301
1290
|
shouldDeleteActionByTagOnRemoval(action) {
|
|
1302
1291
|
return action.data.method === 'post';
|
|
@@ -201,10 +201,13 @@ export interface DraftQueue {
|
|
|
201
201
|
* of `actionId`. Action ids cannot be equal. Both actions must be acting
|
|
202
202
|
* on the same target object, and neither can currently be in progress.
|
|
203
203
|
*
|
|
204
|
-
* @param
|
|
205
|
-
*
|
|
204
|
+
* @param targetActionId The draft action id of the target action. This action
|
|
205
|
+
* will be replaced by the source action while maintaining its position in
|
|
206
|
+
* the queue.
|
|
207
|
+
* @param sourceActionId The draft action id of the source action. This
|
|
208
|
+
* action will replace the target action and will be removed from the queue.
|
|
206
209
|
*/
|
|
207
|
-
replaceAction(
|
|
210
|
+
replaceAction<Data, Response>(targetActionId: string, sourceActionId: string): Promise<DraftAction<Data, Response>>;
|
|
208
211
|
/**
|
|
209
212
|
* Merges two actions into a single target action. The target action maintains
|
|
210
213
|
* its position in the queue, while the source action is removed from the queue.
|
|
@@ -45,8 +45,11 @@ export declare class DurableDraftQueue implements DraftQueue {
|
|
|
45
45
|
*/
|
|
46
46
|
private startQueueSafe;
|
|
47
47
|
removeDraftAction(actionId: string): Promise<void>;
|
|
48
|
-
replaceAction(
|
|
48
|
+
replaceAction<Data, Response>(targetActionId: string, sourceActionId: string): Promise<DraftAction<Data, Response>>;
|
|
49
49
|
mergeActions<Data, Response>(targetActionId: string, sourceActionId: string): Promise<DraftAction<Data, Response>>;
|
|
50
50
|
setMetadata(actionId: string, metadata: DraftActionMetadata): Promise<DraftAction<unknown, unknown>>;
|
|
51
51
|
private scheduleRetry;
|
|
52
|
+
private getActionsForReplaceOrMerge;
|
|
53
|
+
private assertReplaceOrMergePrerequisites;
|
|
54
|
+
private replaceOrMergeActions;
|
|
52
55
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NetworkAdapter, ResourceRequest, Luvio, DurableStoreKeyMetadataMap } from '@luvio/engine';
|
|
2
2
|
import type { DraftAction, CompletedDraftAction, QueueOperation, PendingDraftAction, DraftActionMetadata, DraftQueue, EnqueueResult } from '../DraftQueue';
|
|
3
3
|
import { ProcessActionResult } from '../DraftQueue';
|
|
4
|
-
import type { ActionHandler, DraftIdAndKeyMapping
|
|
4
|
+
import type { ActionHandler, DraftIdAndKeyMapping } from './ActionHandler';
|
|
5
5
|
export type ResponseIngestionEntry<T = unknown> = {
|
|
6
6
|
response: T;
|
|
7
7
|
synchronousIngest: AbstractResourceRequestActionHandler<T, unknown>['synchronousIngest'];
|
|
@@ -23,7 +23,8 @@ export declare abstract class AbstractResourceRequestActionHandler<ResponseType,
|
|
|
23
23
|
getQueueOperationsForCompletingDrafts(queue: DraftAction<unknown, unknown>[], action: CompletedDraftAction<ResourceRequest, ResponseType>): QueueOperation[];
|
|
24
24
|
getRedirectMappings(action: CompletedDraftAction<ResourceRequest, ResponseType>): DraftIdAndKeyMapping[] | undefined;
|
|
25
25
|
handleActionCompleted(action: CompletedDraftAction<ResourceRequest, ResponseType>, queueOperations: QueueOperation[], _queue: DraftAction<unknown, unknown>[], allHandlers: ActionHandler<unknown, unknown, unknown>[]): Promise<void>;
|
|
26
|
-
handleReplaceAction
|
|
26
|
+
handleReplaceAction(targetAction: DraftAction<ResourceRequest, ResponseType>, sourceAction: DraftAction<ResourceRequest, ResponseType>): DraftAction<ResourceRequest, ResponseType>;
|
|
27
|
+
mergeActions(targetAction: DraftAction<ResourceRequest, ResponseType>, sourceAction: DraftAction<ResourceRequest, ResponseType>): DraftAction<ResourceRequest, ResponseType>;
|
|
27
28
|
shouldDeleteActionByTagOnRemoval(action: DraftAction<ResourceRequest, ResponseType>): boolean;
|
|
28
29
|
updateMetadata(_existingMetadata: DraftActionMetadata, incomingMetadata: DraftActionMetadata): DraftActionMetadata;
|
|
29
30
|
private isActionOfType;
|
|
@@ -48,6 +49,9 @@ export declare abstract class AbstractResourceRequestActionHandler<ResponseType,
|
|
|
48
49
|
* @param targetId the targetId to check
|
|
49
50
|
*/
|
|
50
51
|
abstract isDraftId(targetId: string): boolean;
|
|
51
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Overlay the sourceBody over top of the targetBody
|
|
54
|
+
*/
|
|
55
|
+
abstract mergeRequestBody<T = unknown>(targetBody: T, sourceBody: T): T;
|
|
52
56
|
}
|
|
53
57
|
export declare function isResourceRequestAction(action: DraftAction<unknown, unknown>): action is DraftAction<ResourceRequest, unknown>;
|
|
@@ -87,13 +87,19 @@ export interface ActionHandler<Data, DraftMetadata, Type> {
|
|
|
87
87
|
*/
|
|
88
88
|
handleActionCompleted(action: CompletedDraftAction<Data, Type>, queueOperations: QueueOperation[], queue: DraftAction<unknown, unknown>[], allHandlers: ActionHandler<unknown, unknown, unknown>[]): Promise<void>;
|
|
89
89
|
/**
|
|
90
|
-
* Replace
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
90
|
+
* Replace the targetAction's data with the sourceAction's data and return
|
|
91
|
+
* the targetAction. Also sets the targetAction's status to Pending.
|
|
92
|
+
*
|
|
93
|
+
* NOTE: this method mutates the targetAction.
|
|
94
|
+
*
|
|
95
|
+
* Implementations can assume the caller has already ensured the given draft
|
|
96
|
+
* actions have the same targetId, same tag, same version, and are not currently
|
|
97
|
+
* being uploaded.
|
|
98
|
+
*
|
|
99
|
+
* Replacing draft actions with different targetIds or different tags will result
|
|
100
|
+
* in an error.
|
|
95
101
|
*/
|
|
96
|
-
handleReplaceAction
|
|
102
|
+
handleReplaceAction(targetAction: DraftAction<Data, Type>, sourceAction: DraftAction<Data, Type>): DraftAction<Data, Type>;
|
|
97
103
|
/**
|
|
98
104
|
* Invoked by the durable store and the draft environment to get the data that is associated with this draft action
|
|
99
105
|
* The data should include all drafts applied to it (if any)
|
|
@@ -140,8 +146,9 @@ export interface ActionHandler<Data, DraftMetadata, Type> {
|
|
|
140
146
|
* both actions will be combined, if there are conflicts the source's data will
|
|
141
147
|
* be used).
|
|
142
148
|
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
149
|
+
* Implementations can assume the caller has already ensured the given draft
|
|
150
|
+
* actions have the same targetId, same tag, same version, and are not currently
|
|
151
|
+
* being uploaded.
|
|
145
152
|
*
|
|
146
153
|
* NOTE: the resulting merged action will use the target's timestamp and id.
|
|
147
154
|
*/
|