@recordtimelabel/core 0.1.4 → 0.1.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/package.json +1 -1
- package/src/index.js +121 -24
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -21,6 +21,13 @@ export const OPERATION_TYPES = Object.freeze({
|
|
|
21
21
|
EXPANDED_GROUPS_UPDATE: 'expandedGroups.update',
|
|
22
22
|
SETTINGS_UPDATE: 'settings.update'
|
|
23
23
|
});
|
|
24
|
+
|
|
25
|
+
const ORDER_OPERATION_TYPES = new Set([
|
|
26
|
+
OPERATION_TYPES.RECORD_REORDER,
|
|
27
|
+
OPERATION_TYPES.FOLDER_REORDER,
|
|
28
|
+
OPERATION_TYPES.GROUP_REORDER,
|
|
29
|
+
OPERATION_TYPES.EXPANDED_GROUPS_UPDATE
|
|
30
|
+
]);
|
|
24
31
|
|
|
25
32
|
export const RECORD_TIMELABEL_SYNC_MODES = Object.freeze({
|
|
26
33
|
FULL: 'full',
|
|
@@ -514,15 +521,53 @@ export const preserveRecordOrderFromLocal = (records = {}, localRecords = {}) =>
|
|
|
514
521
|
return result;
|
|
515
522
|
};
|
|
516
523
|
|
|
517
|
-
export const createOperation = (type, payload = {}, options = {}) => ({
|
|
518
|
-
id: options.id || `${type}:${options.clientId || 'client'}:${options.now || Date.now()}:${Math.random().toString(36).slice(2, 10)}`,
|
|
519
|
-
type,
|
|
520
|
-
payload,
|
|
521
|
-
clientId: options.clientId || null,
|
|
522
|
-
createdAt: options.now || Date.now()
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
|
|
524
|
+
export const createOperation = (type, payload = {}, options = {}) => ({
|
|
525
|
+
id: options.id || `${type}:${options.clientId || 'client'}:${options.now || Date.now()}:${Math.random().toString(36).slice(2, 10)}`,
|
|
526
|
+
type,
|
|
527
|
+
payload,
|
|
528
|
+
clientId: options.clientId || null,
|
|
529
|
+
createdAt: options.now || Date.now()
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
const getOperationClientInstanceId = (operation = {}, payload = {}) => (
|
|
533
|
+
operation.clientInstanceId ||
|
|
534
|
+
operation.instanceId ||
|
|
535
|
+
payload.clientInstanceId ||
|
|
536
|
+
payload.instanceId ||
|
|
537
|
+
null
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
const buildOperationSyncMeta = (previousSyncMeta = {}, operation = {}, payload = {}, operationTime) => {
|
|
541
|
+
const nextSyncMeta = {
|
|
542
|
+
...(previousSyncMeta || {}),
|
|
543
|
+
lastOperationId: operation.id || previousSyncMeta?.lastOperationId || null,
|
|
544
|
+
lastOperationType: operation.type || previousSyncMeta?.lastOperationType || null,
|
|
545
|
+
lastClientId: operation.clientId || previousSyncMeta?.lastClientId || null,
|
|
546
|
+
lastOperationAt: operationTime
|
|
547
|
+
};
|
|
548
|
+
const nextClientInstanceId = getOperationClientInstanceId(operation, payload);
|
|
549
|
+
|
|
550
|
+
if (nextClientInstanceId) {
|
|
551
|
+
nextSyncMeta.lastClientInstanceId = nextClientInstanceId;
|
|
552
|
+
} else if (operation.clientId) {
|
|
553
|
+
delete nextSyncMeta.lastClientInstanceId;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (ORDER_OPERATION_TYPES.has(operation.type)) {
|
|
557
|
+
nextSyncMeta.lastOrderOperationAtByType = {
|
|
558
|
+
...(previousSyncMeta?.lastOrderOperationAtByType || {}),
|
|
559
|
+
[operation.type]: operationTime
|
|
560
|
+
};
|
|
561
|
+
nextSyncMeta.lastOrderOperationIdByType = {
|
|
562
|
+
...(previousSyncMeta?.lastOrderOperationIdByType || {}),
|
|
563
|
+
[operation.type]: operation.id || null
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return nextSyncMeta;
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
export const applyOperation = (state = {}, operation = {}) => {
|
|
526
571
|
const normalized = normalizeState(state);
|
|
527
572
|
const type = operation.type;
|
|
528
573
|
const payload = operation.payload || {};
|
|
@@ -723,16 +768,15 @@ export const applyOperation = (state = {}, operation = {}) => {
|
|
|
723
768
|
|
|
724
769
|
default:
|
|
725
770
|
return normalized;
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
nextState.lastModified = Math.max(nextState.lastModified || 0, operationTime);
|
|
729
|
-
nextState.rtlSyncMeta =
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
};
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
nextState.lastModified = Math.max(nextState.lastModified || 0, operationTime);
|
|
774
|
+
nextState.rtlSyncMeta = buildOperationSyncMeta(
|
|
775
|
+
nextState.rtlSyncMeta,
|
|
776
|
+
operation,
|
|
777
|
+
payload,
|
|
778
|
+
operationTime
|
|
779
|
+
);
|
|
736
780
|
|
|
737
781
|
return normalizeState(nextState);
|
|
738
782
|
};
|
|
@@ -1334,6 +1378,12 @@ const getLastLocalOperationType = (data = {}) => String(
|
|
|
1334
1378
|
''
|
|
1335
1379
|
);
|
|
1336
1380
|
|
|
1381
|
+
const getLastRemoteOperationType = (data = {}) => String(
|
|
1382
|
+
data?.rtlSyncMeta?.lastOperationType ||
|
|
1383
|
+
data?.syncMeta?.lastRemoteOperationType ||
|
|
1384
|
+
''
|
|
1385
|
+
);
|
|
1386
|
+
|
|
1337
1387
|
const getLastLocalOperationAt = (data = {}) => toFiniteTimestamp(
|
|
1338
1388
|
data?.rtlSyncMeta?.lastOperationAt ||
|
|
1339
1389
|
data?.rtlSyncMeta?.lastLocalOperationAt ||
|
|
@@ -1347,23 +1397,70 @@ const getLastRemoteOperationAt = (data = {}) => toFiniteTimestamp(
|
|
|
1347
1397
|
data?.lastModified
|
|
1348
1398
|
);
|
|
1349
1399
|
|
|
1400
|
+
const getLastClientId = (data = {}) => String(
|
|
1401
|
+
data?.rtlSyncMeta?.lastClientId ||
|
|
1402
|
+
data?.syncMeta?.lastClientId ||
|
|
1403
|
+
data?.syncMeta?.lastMergedClientId ||
|
|
1404
|
+
''
|
|
1405
|
+
);
|
|
1406
|
+
|
|
1407
|
+
const getOrderOperationAtByType = (data = {}, operationType) => toFiniteTimestamp(
|
|
1408
|
+
data?.rtlSyncMeta?.lastOrderOperationAtByType?.[operationType] ||
|
|
1409
|
+
data?.syncMeta?.lastOrderOperationAtByType?.[operationType]
|
|
1410
|
+
);
|
|
1411
|
+
|
|
1412
|
+
const hasOperationMarker = (data = {}, operationType, operationTypeResolver = getLastRemoteOperationType) => {
|
|
1413
|
+
const lastOperationId = String(data?.rtlSyncMeta?.lastOperationId || '');
|
|
1414
|
+
const lastOperationType = operationTypeResolver(data);
|
|
1415
|
+
return lastOperationId.startsWith(`${operationType}:`) || lastOperationType === operationType;
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
const getMarkedOrderOperationAt = (data = {}, operationType, {
|
|
1419
|
+
operationTypeResolver = getLastRemoteOperationType,
|
|
1420
|
+
operationAtResolver = getLastRemoteOperationAt
|
|
1421
|
+
} = {}) => {
|
|
1422
|
+
const operationAtByType = getOrderOperationAtByType(data, operationType);
|
|
1423
|
+
if (operationAtByType) return operationAtByType;
|
|
1424
|
+
return hasOperationMarker(data, operationType, operationTypeResolver)
|
|
1425
|
+
? operationAtResolver(data)
|
|
1426
|
+
: 0;
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1350
1429
|
const hasRecentLocalOperation = (localData = {}, remoteData = {}, operationType) => {
|
|
1351
|
-
const
|
|
1352
|
-
|
|
1353
|
-
|
|
1430
|
+
const localOperationAt = getMarkedOrderOperationAt(localData, operationType, {
|
|
1431
|
+
operationTypeResolver: getLastLocalOperationType,
|
|
1432
|
+
operationAtResolver: getLastLocalOperationAt
|
|
1433
|
+
});
|
|
1434
|
+
if (!localOperationAt) {
|
|
1354
1435
|
return false;
|
|
1355
1436
|
}
|
|
1356
1437
|
|
|
1357
|
-
const
|
|
1358
|
-
|
|
1438
|
+
const remoteOrderOperationAt = getMarkedOrderOperationAt(remoteData, operationType, {
|
|
1439
|
+
operationTypeResolver: getLastRemoteOperationType,
|
|
1440
|
+
operationAtResolver: getLastRemoteOperationAt
|
|
1441
|
+
});
|
|
1442
|
+
const remoteOperationAt = remoteOrderOperationAt || getLastRemoteOperationAt(remoteData);
|
|
1359
1443
|
return !localOperationAt || !remoteOperationAt || localOperationAt >= remoteOperationAt;
|
|
1360
1444
|
};
|
|
1361
1445
|
|
|
1446
|
+
const hasRemoteOrderOperationFromDifferentClient = (localData = {}, remoteData = {}, operationType) => {
|
|
1447
|
+
if (!hasOperationMarker(remoteData, operationType, getLastRemoteOperationType)) {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
const remoteClientId = getLastClientId(remoteData);
|
|
1452
|
+
return Boolean(remoteClientId) && remoteClientId !== getLastClientId(localData);
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1362
1455
|
const shouldPreferRecentLocalOrder = (localData = {}, remoteData = {}, operationType) => {
|
|
1363
1456
|
if (hasRecentLocalOperation(localData, remoteData, operationType)) {
|
|
1364
1457
|
return true;
|
|
1365
1458
|
}
|
|
1366
1459
|
|
|
1460
|
+
if (hasRemoteOrderOperationFromDifferentClient(localData, remoteData, operationType)) {
|
|
1461
|
+
return false;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1367
1464
|
const localOperationAt = getLastLocalOperationAt(localData);
|
|
1368
1465
|
const remoteOperationAt = getLastRemoteOperationAt(remoteData);
|
|
1369
1466
|
return Boolean(localOperationAt) && (!remoteOperationAt || localOperationAt >= remoteOperationAt);
|