@rapidmx/activesync-plugin 1.0.0-beta.2 → 1.0.0-beta.3

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.
Files changed (201) hide show
  1. package/README.md +4 -4
  2. package/dist/lib/BaseDeviceSyncStateRoute.js +32 -0
  3. package/dist/lib/BaseDeviceSyncStateRoute.js.map +1 -1
  4. package/dist/lib/BaseEasRoute.js +91 -15
  5. package/dist/lib/BaseEasRoute.js.map +1 -1
  6. package/dist/lib/EasAuditLog.js +56 -0
  7. package/dist/lib/EasAuditLog.js.map +1 -0
  8. package/dist/lib/EasCollectionLease.js +199 -0
  9. package/dist/lib/EasCollectionLease.js.map +1 -0
  10. package/dist/lib/EasCollectionStore.js +102 -0
  11. package/dist/lib/EasCollectionStore.js.map +1 -0
  12. package/dist/lib/EasCollectionSync.js +294 -0
  13. package/dist/lib/EasCollectionSync.js.map +1 -0
  14. package/dist/lib/EasSyncKeyUtils.js +125 -62
  15. package/dist/lib/EasSyncKeyUtils.js.map +1 -1
  16. package/dist/lib/MessageMoveRules.js +100 -0
  17. package/dist/lib/MessageMoveRules.js.map +1 -0
  18. package/dist/lib/MimeHeaderUtils.js +395 -0
  19. package/dist/lib/MimeHeaderUtils.js.map +1 -0
  20. package/dist/lib/RegexPatternUtils.js +30 -0
  21. package/dist/lib/RegexPatternUtils.js.map +1 -0
  22. package/dist/lib/RestapiCompat.js +41 -0
  23. package/dist/lib/RestapiCompat.js.map +1 -0
  24. package/dist/lib/adapters/CalendarSyncAdapter.js +142 -33
  25. package/dist/lib/adapters/CalendarSyncAdapter.js.map +1 -1
  26. package/dist/lib/adapters/EmailSyncAdapter.js +114 -27
  27. package/dist/lib/adapters/EmailSyncAdapter.js.map +1 -1
  28. package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js +2 -1
  29. package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js.map +1 -1
  30. package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js +2 -1
  31. package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js.map +1 -1
  32. package/dist/lib/codec/WbxmlDecoder.js +86 -34
  33. package/dist/lib/codec/WbxmlDecoder.js.map +1 -1
  34. package/dist/lib/codec/WbxmlEncoder.js +103 -22
  35. package/dist/lib/codec/WbxmlEncoder.js.map +1 -1
  36. package/dist/lib/commands/ComposeMailCommand.js +105 -31
  37. package/dist/lib/commands/ComposeMailCommand.js.map +1 -1
  38. package/dist/lib/commands/FolderSyncCommand.js +67 -27
  39. package/dist/lib/commands/FolderSyncCommand.js.map +1 -1
  40. package/dist/lib/commands/GetItemEstimateCommand.js +80 -59
  41. package/dist/lib/commands/GetItemEstimateCommand.js.map +1 -1
  42. package/dist/lib/commands/ItemOperationsCommand.js +219 -56
  43. package/dist/lib/commands/ItemOperationsCommand.js.map +1 -1
  44. package/dist/lib/commands/MeetingResponseCommand.js +212 -53
  45. package/dist/lib/commands/MeetingResponseCommand.js.map +1 -1
  46. package/dist/lib/commands/MoveItemsCommand.js +54 -21
  47. package/dist/lib/commands/MoveItemsCommand.js.map +1 -1
  48. package/dist/lib/commands/PingCommand.js +288 -56
  49. package/dist/lib/commands/PingCommand.js.map +1 -1
  50. package/dist/lib/commands/ProvisionCommand.js +34 -17
  51. package/dist/lib/commands/ProvisionCommand.js.map +1 -1
  52. package/dist/lib/commands/ResolveRecipientsCommand.js +43 -5
  53. package/dist/lib/commands/ResolveRecipientsCommand.js.map +1 -1
  54. package/dist/lib/commands/SearchCommand.js +92 -17
  55. package/dist/lib/commands/SearchCommand.js.map +1 -1
  56. package/dist/lib/commands/SettingsCommand.js +2 -1
  57. package/dist/lib/commands/SettingsCommand.js.map +1 -1
  58. package/dist/lib/commands/SmartForwardCommand.js +2 -1
  59. package/dist/lib/commands/SmartForwardCommand.js.map +1 -1
  60. package/dist/lib/commands/SmartReplyCommand.js +2 -1
  61. package/dist/lib/commands/SmartReplyCommand.js.map +1 -1
  62. package/dist/lib/commands/SyncCommand.js +481 -244
  63. package/dist/lib/commands/SyncCommand.js.map +1 -1
  64. package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js +6 -1
  65. package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js.map +1 -1
  66. package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js +3 -1
  67. package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js.map +1 -1
  68. package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js +2 -1
  69. package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js.map +1 -1
  70. package/dist/lib/commands/mongo/PingCommandMongo.js +23 -0
  71. package/dist/lib/commands/mongo/PingCommandMongo.js.map +1 -0
  72. package/dist/lib/commands/mongo/SearchCommandMongo.js +3 -1
  73. package/dist/lib/commands/mongo/SearchCommandMongo.js.map +1 -1
  74. package/dist/lib/commands/mongo/SendMailCommandMongo.js +2 -1
  75. package/dist/lib/commands/mongo/SendMailCommandMongo.js.map +1 -1
  76. package/dist/lib/commands/mongo/SmartForwardCommandMongo.js +2 -1
  77. package/dist/lib/commands/mongo/SmartForwardCommandMongo.js.map +1 -1
  78. package/dist/lib/commands/mongo/SmartReplyCommandMongo.js +2 -1
  79. package/dist/lib/commands/mongo/SmartReplyCommandMongo.js.map +1 -1
  80. package/dist/lib/commands/mongo/SyncCommandMongo.js +7 -1
  81. package/dist/lib/commands/mongo/SyncCommandMongo.js.map +1 -1
  82. package/dist/lib/commands/mongo/index.js +1 -0
  83. package/dist/lib/commands/mongo/index.js.map +1 -1
  84. package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js +6 -1
  85. package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js.map +1 -1
  86. package/dist/lib/commands/sql/ItemOperationsCommandSQL.js +3 -1
  87. package/dist/lib/commands/sql/ItemOperationsCommandSQL.js.map +1 -1
  88. package/dist/lib/commands/sql/MeetingResponseCommandSQL.js +2 -1
  89. package/dist/lib/commands/sql/MeetingResponseCommandSQL.js.map +1 -1
  90. package/dist/lib/commands/sql/PingCommandSQL.js +23 -0
  91. package/dist/lib/commands/sql/PingCommandSQL.js.map +1 -0
  92. package/dist/lib/commands/sql/SearchCommandSQL.js +3 -1
  93. package/dist/lib/commands/sql/SearchCommandSQL.js.map +1 -1
  94. package/dist/lib/commands/sql/SendMailCommandSQL.js +2 -1
  95. package/dist/lib/commands/sql/SendMailCommandSQL.js.map +1 -1
  96. package/dist/lib/commands/sql/SmartForwardCommandSQL.js +2 -1
  97. package/dist/lib/commands/sql/SmartForwardCommandSQL.js.map +1 -1
  98. package/dist/lib/commands/sql/SmartReplyCommandSQL.js +2 -1
  99. package/dist/lib/commands/sql/SmartReplyCommandSQL.js.map +1 -1
  100. package/dist/lib/commands/sql/SyncCommandSQL.js +7 -1
  101. package/dist/lib/commands/sql/SyncCommandSQL.js.map +1 -1
  102. package/dist/lib/commands/sql/index.js +1 -0
  103. package/dist/lib/commands/sql/index.js.map +1 -1
  104. package/dist/lib/index.js +5 -0
  105. package/dist/lib/index.js.map +1 -1
  106. package/dist/lib/jobs/EasDeviceStateCleanupJob.js +44 -2
  107. package/dist/lib/jobs/EasDeviceStateCleanupJob.js.map +1 -1
  108. package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js +4 -0
  109. package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js.map +1 -1
  110. package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js +9 -0
  111. package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js.map +1 -1
  112. package/dist/lib/models/EasCollectionChunk.js +2 -0
  113. package/dist/lib/models/EasCollectionChunk.js.map +1 -0
  114. package/dist/lib/models/EasCollectionState.js +2 -0
  115. package/dist/lib/models/EasCollectionState.js.map +1 -0
  116. package/dist/lib/models/mongo/DeviceSyncStateMongo.js +7 -0
  117. package/dist/lib/models/mongo/DeviceSyncStateMongo.js.map +1 -1
  118. package/dist/lib/models/mongo/EasCollectionChunkMongo.js +83 -0
  119. package/dist/lib/models/mongo/EasCollectionChunkMongo.js.map +1 -0
  120. package/dist/lib/models/mongo/EasCollectionStateMongo.js +162 -0
  121. package/dist/lib/models/mongo/EasCollectionStateMongo.js.map +1 -0
  122. package/dist/lib/models/sql/DeviceSyncStateSQL.js +7 -0
  123. package/dist/lib/models/sql/DeviceSyncStateSQL.js.map +1 -1
  124. package/dist/lib/models/sql/EasCollectionChunkSQL.js +83 -0
  125. package/dist/lib/models/sql/EasCollectionChunkSQL.js.map +1 -0
  126. package/dist/lib/models/sql/EasCollectionStateSQL.js +162 -0
  127. package/dist/lib/models/sql/EasCollectionStateSQL.js.map +1 -0
  128. package/dist/lib/mongo/EasRouteMongo.js +2 -2
  129. package/dist/lib/mongo/EasRouteMongo.js.map +1 -1
  130. package/dist/lib/mongo.js +2 -0
  131. package/dist/lib/mongo.js.map +1 -1
  132. package/dist/lib/sql/EasRouteSQL.js +2 -2
  133. package/dist/lib/sql/EasRouteSQL.js.map +1 -1
  134. package/dist/lib/sql.js +2 -0
  135. package/dist/lib/sql.js.map +1 -1
  136. package/dist/types/BaseDeviceSyncStateRoute.d.ts +10 -0
  137. package/dist/types/BaseEasRoute.d.ts +15 -4
  138. package/dist/types/EasAuditLog.d.ts +47 -0
  139. package/dist/types/EasCollectionLease.d.ts +60 -0
  140. package/dist/types/EasCollectionStore.d.ts +51 -0
  141. package/dist/types/EasCollectionSync.d.ts +96 -0
  142. package/dist/types/EasCommandHandler.d.ts +7 -4
  143. package/dist/types/EasSyncKeyUtils.d.ts +73 -42
  144. package/dist/types/MessageMoveRules.d.ts +45 -0
  145. package/dist/types/MimeHeaderUtils.d.ts +73 -0
  146. package/dist/types/RegexPatternUtils.d.ts +14 -0
  147. package/dist/types/RestapiCompat.d.ts +24 -0
  148. package/dist/types/adapters/CalendarSyncAdapter.d.ts +47 -18
  149. package/dist/types/adapters/EasCollectionSyncAdapter.d.ts +18 -2
  150. package/dist/types/adapters/EmailSyncAdapter.d.ts +24 -7
  151. package/dist/types/adapters/mongo/EmailSyncAdapterMongo.d.ts +1 -0
  152. package/dist/types/adapters/sql/EmailSyncAdapterSQL.d.ts +1 -0
  153. package/dist/types/codec/WbxmlDecoder.d.ts +39 -0
  154. package/dist/types/codec/WbxmlEncoder.d.ts +36 -1
  155. package/dist/types/commands/ComposeMailCommand.d.ts +33 -15
  156. package/dist/types/commands/FolderSyncCommand.d.ts +4 -1
  157. package/dist/types/commands/GetItemEstimateCommand.d.ts +20 -15
  158. package/dist/types/commands/ItemOperationsCommand.d.ts +29 -4
  159. package/dist/types/commands/MeetingResponseCommand.d.ts +52 -13
  160. package/dist/types/commands/MoveItemsCommand.d.ts +13 -3
  161. package/dist/types/commands/PingCommand.d.ts +72 -14
  162. package/dist/types/commands/ProvisionCommand.d.ts +16 -11
  163. package/dist/types/commands/ResolveRecipientsCommand.d.ts +4 -0
  164. package/dist/types/commands/SearchCommand.d.ts +13 -1
  165. package/dist/types/commands/SyncCommand.d.ts +102 -62
  166. package/dist/types/commands/mongo/GetItemEstimateCommandMongo.d.ts +3 -0
  167. package/dist/types/commands/mongo/ItemOperationsCommandMongo.d.ts +2 -0
  168. package/dist/types/commands/mongo/MeetingResponseCommandMongo.d.ts +1 -0
  169. package/dist/types/commands/mongo/PingCommandMongo.d.ts +8 -0
  170. package/dist/types/commands/mongo/SearchCommandMongo.d.ts +2 -0
  171. package/dist/types/commands/mongo/SendMailCommandMongo.d.ts +1 -0
  172. package/dist/types/commands/mongo/SmartForwardCommandMongo.d.ts +1 -0
  173. package/dist/types/commands/mongo/SmartReplyCommandMongo.d.ts +1 -0
  174. package/dist/types/commands/mongo/SyncCommandMongo.d.ts +4 -0
  175. package/dist/types/commands/mongo/index.d.ts +1 -0
  176. package/dist/types/commands/sql/GetItemEstimateCommandSQL.d.ts +3 -0
  177. package/dist/types/commands/sql/ItemOperationsCommandSQL.d.ts +2 -0
  178. package/dist/types/commands/sql/MeetingResponseCommandSQL.d.ts +1 -0
  179. package/dist/types/commands/sql/PingCommandSQL.d.ts +8 -0
  180. package/dist/types/commands/sql/SearchCommandSQL.d.ts +2 -0
  181. package/dist/types/commands/sql/SendMailCommandSQL.d.ts +1 -0
  182. package/dist/types/commands/sql/SmartForwardCommandSQL.d.ts +1 -0
  183. package/dist/types/commands/sql/SmartReplyCommandSQL.d.ts +1 -0
  184. package/dist/types/commands/sql/SyncCommandSQL.d.ts +4 -0
  185. package/dist/types/commands/sql/index.d.ts +1 -0
  186. package/dist/types/index.d.ts +5 -0
  187. package/dist/types/jobs/EasDeviceStateCleanupJob.d.ts +15 -0
  188. package/dist/types/jobs/mongo/EasDeviceStateCleanupJobMongo.d.ts +2 -0
  189. package/dist/types/jobs/sql/EasDeviceStateCleanupJobSQL.d.ts +4 -0
  190. package/dist/types/models/DeviceSyncState.d.ts +13 -2
  191. package/dist/types/models/EasCollectionChunk.d.ts +20 -0
  192. package/dist/types/models/EasCollectionState.d.ts +79 -0
  193. package/dist/types/models/mongo/DeviceSyncStateMongo.d.ts +1 -0
  194. package/dist/types/models/mongo/EasCollectionChunkMongo.d.ts +16 -0
  195. package/dist/types/models/mongo/EasCollectionStateMongo.d.ts +27 -0
  196. package/dist/types/models/sql/DeviceSyncStateSQL.d.ts +1 -0
  197. package/dist/types/models/sql/EasCollectionChunkSQL.d.ts +16 -0
  198. package/dist/types/models/sql/EasCollectionStateSQL.d.ts +27 -0
  199. package/dist/types/mongo.d.ts +2 -0
  200. package/dist/types/sql.d.ts +2 -0
  201. package/package.json +267 -238
@@ -0,0 +1,102 @@
1
+ import { asEntity } from "./RestapiCompat.js";
2
+ /** Largest held set kept inline on the `EasCollectionState` row (`serverIds`) - past it the set moves to chunk rows. */
3
+ export const INLINE_HELD_LIMIT = 2000;
4
+ /** Most `ServerId`s one `EasCollectionChunk` row holds. */
5
+ export const HELD_CHUNK_SIZE = 2000;
6
+ /** Chunk rows read per query while loading a held set. */
7
+ const CHUNK_PAGE_SIZE = 100;
8
+ /**
9
+ * Loads the `ServerId`s a device holds for a collection: `state.serverIds` while the set is inline, otherwise every
10
+ * `EasCollectionChunk` row of the collection (read in pages, ordered by `chunkIndex`).
11
+ */
12
+ export async function loadHeldSet(state, store) {
13
+ if (!state?.chunked) {
14
+ return { ids: new Set(state?.serverIds ?? []), chunks: [] };
15
+ }
16
+ const chunks = [];
17
+ let after = -1;
18
+ for (;;) {
19
+ const page = await store.repo.find({
20
+ mailboxUid: state.mailboxUid,
21
+ deviceId: state.deviceId,
22
+ folderUid: state.folderUid,
23
+ chunkIndex: `gt(${after})`,
24
+ sort: JSON.stringify({ chunkIndex: "ASC" }),
25
+ limit: CHUNK_PAGE_SIZE,
26
+ }, { ignoreACL: true, limit: CHUNK_PAGE_SIZE });
27
+ chunks.push(...page);
28
+ if (page.length < CHUNK_PAGE_SIZE) {
29
+ break;
30
+ }
31
+ after = page[page.length - 1].chunkIndex;
32
+ }
33
+ const ids = new Set();
34
+ for (const chunk of chunks) {
35
+ for (const id of chunk.ids) {
36
+ ids.add(id);
37
+ }
38
+ }
39
+ return { ids, chunks };
40
+ }
41
+ /**
42
+ * Persists `ids` as the collection's new held set, given the `loaded` set the round started from, and returns the
43
+ * `serverIds`/`chunked` values the state row must be saved with.
44
+ *
45
+ * A set within `INLINE_HELD_LIMIT` that was never chunked stays inline (no chunk rows touched). Otherwise only the
46
+ * difference is written: each existing chunk drops the ids no longer held, new ids fill the free space of existing
47
+ * chunks before new chunks are appended, and only chunks whose content changed are updated (an emptied chunk is
48
+ * deleted) - a round that adds a window of items rewrites one or two chunks, never the whole set.
49
+ *
50
+ * Writes are not atomic with the state row: the caller must treat a failure here (or of the state row after this)
51
+ * as a lost round and make the device restart the collection.
52
+ */
53
+ export async function saveHeldSet(key, loaded, ids, wasChunked, store) {
54
+ if (!wasChunked && ids.size <= INLINE_HELD_LIMIT) {
55
+ return { serverIds: [...ids], chunked: false };
56
+ }
57
+ const placed = new Set();
58
+ const kept = loaded.chunks.map((chunk) => chunk.ids.filter((id) => {
59
+ if (!ids.has(id) || placed.has(id)) {
60
+ return false;
61
+ }
62
+ placed.add(id);
63
+ return true;
64
+ }));
65
+ const pending = [...ids].filter((id) => !placed.has(id));
66
+ let next = 0;
67
+ for (const chunkIds of kept) {
68
+ while (chunkIds.length < HELD_CHUNK_SIZE && next < pending.length) {
69
+ chunkIds.push(pending[next++]);
70
+ }
71
+ }
72
+ for (let i = 0; i < loaded.chunks.length; i++) {
73
+ const chunk = loaded.chunks[i];
74
+ const chunkIds = kept[i];
75
+ const unchanged = chunkIds.length === chunk.ids.length && chunkIds.every((id, j) => id === chunk.ids[j]);
76
+ if (unchanged) {
77
+ continue;
78
+ }
79
+ if (chunkIds.length === 0) {
80
+ await store.repo.delete(chunk.uid, { ignoreACL: true, purge: true, skipPush: true });
81
+ }
82
+ else {
83
+ await store.repo.update({ uid: chunk.uid, version: chunk.version, ids: chunkIds }, asEntity(store.repo, chunk), {
84
+ ignoreACL: true,
85
+ skipPush: true,
86
+ });
87
+ }
88
+ }
89
+ let chunkIndex = loaded.chunks.reduce((max, chunk) => Math.max(max, chunk.chunkIndex), -1);
90
+ while (next < pending.length) {
91
+ const chunkIds = pending.slice(next, next + HELD_CHUNK_SIZE);
92
+ next += chunkIds.length;
93
+ chunkIndex++;
94
+ await store.repo.create(new store.chunkClass({ mailboxUid: key.mailboxUid, deviceId: key.deviceId, folderUid: key.folderUid, chunkIndex, ids: chunkIds }), { ignoreACL: true, skipPush: true });
95
+ }
96
+ return { serverIds: [], chunked: true };
97
+ }
98
+ /** Removes every chunk row of a collection (a restart with `SyncKey 0`, or a forgotten device). */
99
+ export async function clearHeldSet(key, store) {
100
+ await store.repo.truncate({ mailboxUid: key.mailboxUid, deviceId: key.deviceId, folderUid: key.folderUid }, { ignoreACL: true });
101
+ }
102
+ //# sourceMappingURL=EasCollectionStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EasCollectionStore.js","sourceRoot":"","sources":["../../src/EasCollectionStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,294 @@
1
+ import { FolderType } from "@rapidmx/restapi";
2
+ import { compareCursor, cursorOf, isListableUid, parseSyncKey, scanAfter, scanOverlap } from "./EasSyncKeyUtils.js";
3
+ /** How far before a round's start the out-of-folder cursor is fast-forwarded while the device holds nothing -
4
+ * generous slack for clock differences between the servers stamping `dateModified`. */
5
+ const MOVE_CURSOR_SLACK_MS = 60000;
6
+ /** How far behind each cursor a round re-reads the stream for rows committed out of order by another replica. */
7
+ export const DEFAULT_OVERLAP_MS = 5000;
8
+ /** Most rows one overlap re-read returns, and most entries `recent` keeps. */
9
+ export const DEFAULT_OVERLAP_LIMIT = 1000;
10
+ function mapOf(record) {
11
+ return record ? new Map(Object.entries(record)) : undefined;
12
+ }
13
+ /** Loads the working state for the round a client's current `SyncKey` (`state.syncKey`) continues. `held` is the
14
+ * collection's held set (see `EasCollectionStore.loadHeldSet`); defaults to the inline `serverIds`. */
15
+ export function workingStateFromRow(state, held = new Set(state.serverIds)) {
16
+ return {
17
+ generation: parseSyncKey(state.syncKey)?.generation ?? 0,
18
+ cursor: { date: new Date(state.cursorDate), uid: state.cursorUid },
19
+ moveCursor: { date: new Date(state.moveCursorDate), uid: state.moveCursorUid },
20
+ serverIds: new Set(held),
21
+ echoes: new Map(Object.entries(state.echoes ?? {})),
22
+ recent: mapOf(state.recent),
23
+ reconcileCursor: state.reconcileCursor ?? "",
24
+ filterType: state.filterType ?? undefined,
25
+ };
26
+ }
27
+ /** Rebuilds the working state as it stood before the most recent round, for a client retrying `round.syncKey`. */
28
+ export function workingStateFromRound(state, round, held = new Set(state.serverIds)) {
29
+ const serverIds = new Set(held);
30
+ for (const uid of round.addedIds) {
31
+ serverIds.delete(uid);
32
+ }
33
+ for (const uid of round.removedIds) {
34
+ serverIds.add(uid);
35
+ }
36
+ return {
37
+ generation: parseSyncKey(round.syncKey)?.generation ?? 0,
38
+ cursor: { date: new Date(round.cursorDate), uid: round.cursorUid },
39
+ moveCursor: { date: new Date(round.moveCursorDate), uid: round.moveCursorUid },
40
+ serverIds,
41
+ echoes: new Map(Object.entries(round.echoes)),
42
+ recent: mapOf(round.recent),
43
+ reconcileCursor: round.reconcileCursor ?? "",
44
+ filterType: state.filterType ?? undefined,
45
+ };
46
+ }
47
+ /** Deep-copies a working state so a dry run (`GetItemEstimate`) can't disturb the original. */
48
+ export function cloneWorkingState(state) {
49
+ return {
50
+ ...state,
51
+ cursor: { ...state.cursor },
52
+ moveCursor: { ...state.moveCursor },
53
+ serverIds: new Set(state.serverIds),
54
+ echoes: new Map(state.echoes),
55
+ recent: state.recent ? new Map(state.recent) : undefined,
56
+ };
57
+ }
58
+ /** Records the round that turned `base` into `result` (see `EasCollectionRound`). */
59
+ export function roundRecord(syncKey, base, result, clientIds) {
60
+ return {
61
+ syncKey,
62
+ cursorDate: base.cursor.date.toISOString(),
63
+ cursorUid: base.cursor.uid,
64
+ moveCursorDate: base.moveCursor.date.toISOString(),
65
+ moveCursorUid: base.moveCursor.uid,
66
+ addedIds: [...result.serverIds].filter((uid) => !base.serverIds.has(uid)),
67
+ removedIds: [...base.serverIds].filter((uid) => !result.serverIds.has(uid)),
68
+ echoes: Object.fromEntries(base.echoes),
69
+ ...(base.recent ? { recent: Object.fromEntries(base.recent) } : {}),
70
+ reconcileCursor: base.reconcileCursor,
71
+ clientIds: [...clientIds].map(([clientId, serverId]) => ({ clientId, serverId })),
72
+ };
73
+ }
74
+ /**
75
+ * Computes one round of server-side changes for a `Sync` collection and advances `state` past them:
76
+ *
77
+ * - **Out-of-folder stream** (rows of the same mailbox in any other folder after `state.moveCursor`, live or
78
+ * deleted): an item the device holds has been moved out of this folder and is a `Delete`. Read before the folder
79
+ * rows are processed, so when an item moves between the two reads the out-of-folder row (the newer one) wins.
80
+ * Skipped while the device holds nothing; the cursor is then fast-forwarded to just before the round started
81
+ * instead, so the first real scan doesn't have to crawl the whole mailbox history.
82
+ * - **Folder stream** (rows of this folder after `state.cursor`): a live item the device holds is a `Change`, one
83
+ * it doesn't hold is an `Add` (subject to `include`), a soft-deleted item it holds is a `Delete`; a row whose
84
+ * `dateModified` still equals the device's own recorded write (`state.echoes`) is skipped.
85
+ * - **Overlap**: `dateModified` is stamped before a write commits, so with several replicas a row can become visible
86
+ * after a cursor has already passed its timestamp. Both streams therefore also re-read the last `overlapMs` behind
87
+ * their cursor. Out-of-folder rows are idempotent (an item is only deleted while held), so they're simply
88
+ * re-applied; folder rows are deduplicated against `state.recent` (uid -> the `dateModified` it was processed at),
89
+ * and only a row not recorded there at that timestamp - one that became visible late - is processed.
90
+ * - **Reconcile**: a hard-purged row leaves no trace in either stream. Once a round has caught up (nothing more
91
+ * available), up to `reconcileLimit` held ids after `state.reconcileCursor` are looked up in the folder, and each
92
+ * one that no longer exists there is a `Delete`; the cursor wraps around after the last held id.
93
+ *
94
+ * Both cursors only ever advance past rows actually processed - never to "now" - so nothing is skipped when the
95
+ * window fills up (`moreAvailable`).
96
+ */
97
+ export async function enumerateCollection(state, options) {
98
+ const startedAt = (options.now ?? new Date()).getTime();
99
+ const overlapMs = options.overlapMs ?? DEFAULT_OVERLAP_MS;
100
+ const overlapLimit = options.overlapLimit ?? DEFAULT_OVERLAP_LIMIT;
101
+ const folderCriteria = { folderUid: options.folderUid };
102
+ const moveCriteria = { mailboxUid: options.folderMailboxUid, folderUid: `ne(${options.folderUid})` };
103
+ const folderLate = await scanOverlap(options.repo, folderCriteria, state.cursor, overlapMs, overlapLimit);
104
+ const folderPage = await scanAfter(options.repo, folderCriteria, state.cursor, options.windowSize);
105
+ const holdsItems = state.serverIds.size > 0;
106
+ const moveLate = holdsItems ? await scanOverlap(options.repo, moveCriteria, state.moveCursor, overlapMs, overlapLimit) : [];
107
+ const movePage = holdsItems ? await scanAfter(options.repo, moveCriteria, state.moveCursor, options.moveScanLimit) : undefined;
108
+ const commands = [];
109
+ let budget = options.windowSize;
110
+ let moreAvailable = folderPage.more || !!movePage?.more;
111
+ // A row saved before overlap tracking existed has no record of what its window already reported: everything
112
+ // currently visible there is taken as reported, rather than re-sent.
113
+ const recent = state.recent ?? new Map(folderLate.map((row) => [row.uid, new Date(row.dateModified).toISOString()]));
114
+ const movedOut = new Set();
115
+ /** Processes one out-of-folder row; `false` when the window is full and the row was left for a later round. */
116
+ const processMoved = (row) => {
117
+ if (state.serverIds.has(row.uid)) {
118
+ if (budget === 0) {
119
+ moreAvailable = true;
120
+ return false;
121
+ }
122
+ commands.push({ kind: "Delete", uid: row.uid });
123
+ state.serverIds.delete(row.uid);
124
+ budget--;
125
+ }
126
+ movedOut.add(row.uid);
127
+ return true;
128
+ };
129
+ if (movePage) {
130
+ for (const row of moveLate) {
131
+ if (!processMoved(row)) {
132
+ break;
133
+ }
134
+ }
135
+ for (const row of movePage.rows) {
136
+ if (!processMoved(row)) {
137
+ break;
138
+ }
139
+ state.moveCursor = cursorOf(row);
140
+ }
141
+ }
142
+ else {
143
+ const floor = { date: new Date(startedAt - MOVE_CURSOR_SLACK_MS), uid: "" };
144
+ if (compareCursor(floor, state.moveCursor) > 0) {
145
+ state.moveCursor = floor;
146
+ }
147
+ }
148
+ /** Processes one folder-stream row; `false` when the window is full and the row was left for a later round. */
149
+ const processFolderRow = (row, iso) => {
150
+ const uid = row.uid;
151
+ const echo = state.echoes.get(uid);
152
+ let command;
153
+ if (movedOut.has(uid) || (echo !== undefined && echo === iso)) {
154
+ command = undefined;
155
+ }
156
+ else if (row.deleted === true) {
157
+ command = state.serverIds.has(uid) ? { kind: "Delete", uid } : undefined;
158
+ }
159
+ else if (state.serverIds.has(uid)) {
160
+ command = { kind: "Change", item: row };
161
+ }
162
+ else if (!options.include || options.include(row)) {
163
+ command = { kind: "Add", item: row };
164
+ }
165
+ if (command) {
166
+ if (budget === 0) {
167
+ moreAvailable = true;
168
+ return false;
169
+ }
170
+ commands.push(command);
171
+ if (command.kind === "Delete") {
172
+ state.serverIds.delete(uid);
173
+ }
174
+ else {
175
+ state.serverIds.add(uid);
176
+ }
177
+ budget--;
178
+ }
179
+ recent.set(uid, iso);
180
+ return true;
181
+ };
182
+ for (const row of folderLate) {
183
+ const iso = new Date(row.dateModified).toISOString();
184
+ if (recent.get(row.uid) !== iso && !processFolderRow(row, iso)) {
185
+ break;
186
+ }
187
+ }
188
+ for (const row of folderPage.rows) {
189
+ if (!processFolderRow(row, new Date(row.dateModified).toISOString())) {
190
+ break;
191
+ }
192
+ state.cursor = cursorOf(row);
193
+ }
194
+ for (const [uid, iso] of state.echoes) {
195
+ if (compareCursor({ date: new Date(iso), uid }, state.cursor) <= 0) {
196
+ state.echoes.delete(uid);
197
+ }
198
+ }
199
+ state.recent = pruneRecent(recent, state.cursor, overlapMs, overlapLimit);
200
+ if (!moreAvailable && budget > 0 && (options.reconcileLimit ?? 0) > 0 && state.serverIds.size > 0) {
201
+ moreAvailable = await reconcile(state, options, commands, budget);
202
+ }
203
+ return { commands, moreAvailable };
204
+ }
205
+ /** Keeps only the `recent` entries still inside the overlap window behind `cursor`, at most `limit` (the newest). */
206
+ function pruneRecent(recent, cursor, overlapMs, limit) {
207
+ const floor = cursor.date.getTime() - overlapMs;
208
+ const kept = [...recent].filter(([, iso]) => new Date(iso).getTime() >= floor);
209
+ kept.sort((a, b) => (a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0));
210
+ return new Map(kept.slice(0, limit));
211
+ }
212
+ /** One reconcile slice (see `enumerateCollection`). Returns whether commands were left for a later round. */
213
+ async function reconcile(state, options, commands, budget) {
214
+ const limit = options.reconcileLimit;
215
+ const slice = [...state.serverIds]
216
+ .filter((uid) => uid > state.reconcileCursor)
217
+ .sort()
218
+ .slice(0, limit);
219
+ if (slice.length === 0) {
220
+ state.reconcileCursor = "";
221
+ return false;
222
+ }
223
+ // Only plain uids go into the `in(...)` operand, which the query parser splits on commas and coerces per value (`me`
224
+ // is the caller, `null` is null); any other held id is checked on its own by exact uid.
225
+ const listable = slice.filter(isListableUid);
226
+ const found = listable.length === 0
227
+ ? []
228
+ : await options.repo.find({ folderUid: options.folderUid, uid: `in(${listable.join(",")})`, limit: listable.length }, {
229
+ ignoreACL: true,
230
+ limit: listable.length,
231
+ });
232
+ const present = new Set(found.filter((row) => row.folderUid === options.folderUid).map((row) => row.uid));
233
+ for (const uid of slice.filter((id) => !isListableUid(id))) {
234
+ const row = await options.repo.findOne(uid, { ignoreACL: true });
235
+ if (row && row.uid === uid && row.folderUid === options.folderUid) {
236
+ present.add(uid);
237
+ }
238
+ }
239
+ for (const uid of slice) {
240
+ if (!present.has(uid)) {
241
+ if (budget === 0) {
242
+ return true;
243
+ }
244
+ commands.push({ kind: "Delete", uid });
245
+ state.serverIds.delete(uid);
246
+ state.echoes.delete(uid);
247
+ budget--;
248
+ }
249
+ state.reconcileCursor = uid;
250
+ }
251
+ if (slice.length < limit) {
252
+ state.reconcileCursor = "";
253
+ }
254
+ return false;
255
+ }
256
+ /** The `Class` a folder of `type` holds - for a `Sync`/`GetItemEstimate` request that omits `Class` for a collection
257
+ * with no remembered class. */
258
+ export function classForFolderType(type) {
259
+ switch (type) {
260
+ case FolderType.CALENDAR:
261
+ return "Calendar";
262
+ case FolderType.CONTACTS:
263
+ return "Contacts";
264
+ case FolderType.TASKS:
265
+ return "Tasks";
266
+ default:
267
+ return "Email";
268
+ }
269
+ }
270
+ const DAY_MS = 24 * 60 * 60 * 1000;
271
+ /** [MS-ASCMD] `FilterType` age windows, in days (`1`..`7`). */
272
+ const FILTER_DAYS = { "1": 1, "2": 3, "3": 7, "4": 14, "5": 30, "6": 90, "7": 180 };
273
+ /**
274
+ * Builds the `include` predicate for a collection's `FilterType`, or `undefined` for no filtering: `Email` keeps
275
+ * messages received within the window; `Calendar` keeps recurring events and events ending within it; `Tasks`
276
+ * keeps incomplete tasks for `8`. Values a class doesn't define (and no `FilterType` at all) are treated as "no
277
+ * filter".
278
+ */
279
+ export function filterPredicate(collectionClass, filterType, now = new Date()) {
280
+ const days = filterType !== undefined ? FILTER_DAYS[filterType] : undefined;
281
+ if (collectionClass === "Email" && days !== undefined && days <= 30) {
282
+ const cutoff = now.getTime() - days * DAY_MS;
283
+ return (item) => new Date(item.receivedDate).getTime() >= cutoff;
284
+ }
285
+ if (collectionClass === "Calendar" && days !== undefined && days >= 14) {
286
+ const cutoff = now.getTime() - days * DAY_MS;
287
+ return (item) => !!item.recurrenceRule || new Date(item.endDate).getTime() >= cutoff;
288
+ }
289
+ if (collectionClass === "Tasks" && filterType === "8") {
290
+ return (item) => !item.completed;
291
+ }
292
+ return undefined;
293
+ }
294
+ //# sourceMappingURL=EasCollectionSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EasCollectionSync.js","sourceRoot":"","sources":["../../src/EasCollectionSync.ts"],"names":[],"mappings":"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"}