@recordtimelabel/core 0.6.5 → 0.6.6

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/README.md CHANGED
@@ -17,10 +17,10 @@ During local development an app can consume a sibling checkout with:
17
17
  "@recordtimelabel/core": "file:../recordtimelabel-core"
18
18
  ```
19
19
 
20
- For release builds, consume a fixed npm package, git tag, or private registry version so builds do not depend on a sibling folder path. The release target is `0.6.5`; verify that its registry tarball and lockfile integrity are available before updating consumers:
20
+ For release builds, consume a fixed npm package, git tag, or private registry version so builds do not depend on a sibling folder path. The release target is `0.6.6`; verify that its registry tarball and lockfile integrity are available before updating consumers:
21
21
 
22
22
  ```json
23
- "@recordtimelabel/core": "0.6.5"
23
+ "@recordtimelabel/core": "0.6.6"
24
24
  ```
25
25
 
26
26
  If this checkout's `package.json` is ahead of the published version, publish the new package before updating consumers to that version.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recordtimelabel/core",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "type": "module",
5
5
  "description": "Shared RecordTimeLabel data model, merge logic, operations, and sync engine.",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -141,7 +141,7 @@ export {
141
141
  selectBestMatchingTwitchVod
142
142
  };
143
143
 
144
- export const RECORD_TIMELABEL_CORE_VERSION = '0.6.5';
144
+ export const RECORD_TIMELABEL_CORE_VERSION = '0.6.6';
145
145
  export const RTL_SYNC_PROTOCOL_VERSION = 2;
146
146
  export const RECORD_TIMELABEL_DURABLE_ENGINE_CAPABILITIES = Object.freeze([
147
147
  'fifo-retry-fence',
@@ -1145,6 +1145,10 @@ export const applyOperation = (state = {}, operation = {}) => {
1145
1145
  originalRecordIndex: Number.isInteger(payload.originalRecordIndex)
1146
1146
  ? payload.originalRecordIndex
1147
1147
  : Math.max(0, Number(existingEntry?.index || 0)),
1148
+ originalGroupId: String(payload.originalGroupId || '').trim(),
1149
+ originalGroupOrderIndex: Number.isInteger(payload.originalGroupOrderIndex)
1150
+ ? payload.originalGroupOrderIndex
1151
+ : -1,
1148
1152
  lifecycleGeneration,
1149
1153
  deletedAt,
1150
1154
  purgeAt: toFiniteTimestamp(payload.purgeAt) || deletedAt + RTL_TRASH_RETENTION_MS,
@@ -1206,6 +1210,16 @@ export const applyOperation = (state = {}, operation = {}) => {
1206
1210
  );
1207
1211
  targetRecords.splice(restoreIndex, 0, restoredRecord);
1208
1212
  nextState.records[targetFolderId] = targetRecords;
1213
+ const originalGroupId = String(trashEntry.originalGroupId || '').trim();
1214
+ const originalGroupOrderIndex = Number.isInteger(trashEntry.originalGroupOrderIndex)
1215
+ ? trashEntry.originalGroupOrderIndex
1216
+ : -1;
1217
+ if (originalGroupId && originalGroupOrderIndex >= 0 &&
1218
+ !nextState.groupOrder.includes(originalGroupId)) {
1219
+ const groupOrder = [...nextState.groupOrder];
1220
+ groupOrder.splice(Math.min(originalGroupOrderIndex, groupOrder.length), 0, originalGroupId);
1221
+ nextState.groupOrder = groupOrder;
1222
+ }
1209
1223
  delete nextState.trashEntries[trashEntryId];
1210
1224
  delete nextState.deletedRecordTombstones[recordId];
1211
1225
  break;
@@ -6232,6 +6246,19 @@ const rtlPayloadOrder = (operation, keys) => {
6232
6246
  }
6233
6247
  return [];
6234
6248
  };
6249
+ // Partial delete reads omit sibling records, so folder.recordOrder is the live slot.
6250
+ const rtlResolveOriginalRecordIndex = (payload, existingRecord, folders) => {
6251
+ if (Number.isInteger(payload?.originalRecordIndex) && payload.originalRecordIndex >= 0) {
6252
+ return payload.originalRecordIndex;
6253
+ }
6254
+ const recordId = normalizeId(existingRecord?.id);
6255
+ const folderId = safeFolderId(existingRecord?.folderId || payload?.folderId);
6256
+ const recordOrder = rtlMergeOrder(
6257
+ rtlOwn(folders, folderId) ? folders[folderId]?.recordOrder : []
6258
+ );
6259
+ const orderIndex = recordId ? recordOrder.indexOf(recordId) : -1;
6260
+ return orderIndex >= 0 ? orderIndex : 0;
6261
+ };
6235
6262
  const rtlHasInvalidPayloadValue = (value, depth = 0) => {
6236
6263
  if (depth > 20) return true;
6237
6264
  if (typeof value === 'number') return !Number.isFinite(value);
@@ -6863,7 +6890,21 @@ export const planFirestoreV2OperationChanges = ({
6863
6890
  break;
6864
6891
  }
6865
6892
  const sourceFolderId = safeFolderId(existingRecord.folderId);
6866
- applied = rtlApplyOperationToPartialDocuments({...nextDocuments, operation, now: operationNow});
6893
+ applied = rtlApplyOperationToPartialDocuments({
6894
+ ...nextDocuments,
6895
+ operation: {
6896
+ ...operation,
6897
+ payload: {
6898
+ ...payload,
6899
+ originalRecordIndex: rtlResolveOriginalRecordIndex(
6900
+ payload,
6901
+ existingRecord,
6902
+ nextDocuments.folders
6903
+ )
6904
+ }
6905
+ },
6906
+ now: operationNow
6907
+ });
6867
6908
  rtlSetRoot(nextDocuments.root, applied.documents.root);
6868
6909
  const trashDocument = rtlOwn(applied.documents.trash, operationTrashEntryId)
6869
6910
  ? applied.documents.trash[operationTrashEntryId]