@rapidmx/activesync 1.0.0-beta.0

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 (195) hide show
  1. package/LICENSE +382 -0
  2. package/README.md +57 -0
  3. package/dist/lib/BaseDeviceSyncStateRoute.js +90 -0
  4. package/dist/lib/BaseDeviceSyncStateRoute.js.map +1 -0
  5. package/dist/lib/BaseEasRoute.js +213 -0
  6. package/dist/lib/BaseEasRoute.js.map +1 -0
  7. package/dist/lib/CompactDateTime.js +43 -0
  8. package/dist/lib/CompactDateTime.js.map +1 -0
  9. package/dist/lib/EasCommandHandler.js +2 -0
  10. package/dist/lib/EasCommandHandler.js.map +1 -0
  11. package/dist/lib/EasSyncKeyUtils.js +119 -0
  12. package/dist/lib/EasSyncKeyUtils.js.map +1 -0
  13. package/dist/lib/adapters/CalendarSyncAdapter.js +255 -0
  14. package/dist/lib/adapters/CalendarSyncAdapter.js.map +1 -0
  15. package/dist/lib/adapters/ContactsSyncAdapter.js +164 -0
  16. package/dist/lib/adapters/ContactsSyncAdapter.js.map +1 -0
  17. package/dist/lib/adapters/EasCollectionSyncAdapter.js +2 -0
  18. package/dist/lib/adapters/EasCollectionSyncAdapter.js.map +1 -0
  19. package/dist/lib/adapters/EmailSyncAdapter.js +230 -0
  20. package/dist/lib/adapters/EmailSyncAdapter.js.map +1 -0
  21. package/dist/lib/adapters/TasksSyncAdapter.js +100 -0
  22. package/dist/lib/adapters/TasksSyncAdapter.js.map +1 -0
  23. package/dist/lib/codec/WbxmlCodePages.js +706 -0
  24. package/dist/lib/codec/WbxmlCodePages.js.map +1 -0
  25. package/dist/lib/codec/WbxmlDecoder.js +154 -0
  26. package/dist/lib/codec/WbxmlDecoder.js.map +1 -0
  27. package/dist/lib/codec/WbxmlElement.js +31 -0
  28. package/dist/lib/codec/WbxmlElement.js.map +1 -0
  29. package/dist/lib/codec/WbxmlEncoder.js +88 -0
  30. package/dist/lib/codec/WbxmlEncoder.js.map +1 -0
  31. package/dist/lib/commands/ComposeMailCommand.js +187 -0
  32. package/dist/lib/commands/ComposeMailCommand.js.map +1 -0
  33. package/dist/lib/commands/FolderSyncCommand.js +150 -0
  34. package/dist/lib/commands/FolderSyncCommand.js.map +1 -0
  35. package/dist/lib/commands/GetItemEstimateCommand.js +149 -0
  36. package/dist/lib/commands/GetItemEstimateCommand.js.map +1 -0
  37. package/dist/lib/commands/ItemOperationsCommand.js +337 -0
  38. package/dist/lib/commands/ItemOperationsCommand.js.map +1 -0
  39. package/dist/lib/commands/MeetingResponseCommand.js +120 -0
  40. package/dist/lib/commands/MeetingResponseCommand.js.map +1 -0
  41. package/dist/lib/commands/MoveItemsCommand.js +103 -0
  42. package/dist/lib/commands/MoveItemsCommand.js.map +1 -0
  43. package/dist/lib/commands/PingCommand.js +145 -0
  44. package/dist/lib/commands/PingCommand.js.map +1 -0
  45. package/dist/lib/commands/ProvisionCommand.js +164 -0
  46. package/dist/lib/commands/ProvisionCommand.js.map +1 -0
  47. package/dist/lib/commands/ResolveRecipientsCommand.js +124 -0
  48. package/dist/lib/commands/ResolveRecipientsCommand.js.map +1 -0
  49. package/dist/lib/commands/SearchCommand.js +137 -0
  50. package/dist/lib/commands/SearchCommand.js.map +1 -0
  51. package/dist/lib/commands/SendMailCommand.js +18 -0
  52. package/dist/lib/commands/SendMailCommand.js.map +1 -0
  53. package/dist/lib/commands/SettingsCommand.js +138 -0
  54. package/dist/lib/commands/SettingsCommand.js.map +1 -0
  55. package/dist/lib/commands/SmartForwardCommand.js +22 -0
  56. package/dist/lib/commands/SmartForwardCommand.js.map +1 -0
  57. package/dist/lib/commands/SmartReplyCommand.js +22 -0
  58. package/dist/lib/commands/SmartReplyCommand.js.map +1 -0
  59. package/dist/lib/commands/SyncCommand.js +406 -0
  60. package/dist/lib/commands/SyncCommand.js.map +1 -0
  61. package/dist/lib/commands/mongo/FolderSyncCommandMongo.js +16 -0
  62. package/dist/lib/commands/mongo/FolderSyncCommandMongo.js.map +1 -0
  63. package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js +21 -0
  64. package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js.map +1 -0
  65. package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js +18 -0
  66. package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js.map +1 -0
  67. package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js +17 -0
  68. package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js.map +1 -0
  69. package/dist/lib/commands/mongo/MoveItemsCommandMongo.js +17 -0
  70. package/dist/lib/commands/mongo/MoveItemsCommandMongo.js.map +1 -0
  71. package/dist/lib/commands/mongo/ResolveRecipientsCommandMongo.js +20 -0
  72. package/dist/lib/commands/mongo/ResolveRecipientsCommandMongo.js.map +1 -0
  73. package/dist/lib/commands/mongo/SearchCommandMongo.js +20 -0
  74. package/dist/lib/commands/mongo/SearchCommandMongo.js.map +1 -0
  75. package/dist/lib/commands/mongo/SendMailCommandMongo.js +17 -0
  76. package/dist/lib/commands/mongo/SendMailCommandMongo.js.map +1 -0
  77. package/dist/lib/commands/mongo/SettingsCommandMongo.js +16 -0
  78. package/dist/lib/commands/mongo/SettingsCommandMongo.js.map +1 -0
  79. package/dist/lib/commands/mongo/SmartForwardCommandMongo.js +17 -0
  80. package/dist/lib/commands/mongo/SmartForwardCommandMongo.js.map +1 -0
  81. package/dist/lib/commands/mongo/SmartReplyCommandMongo.js +17 -0
  82. package/dist/lib/commands/mongo/SmartReplyCommandMongo.js.map +1 -0
  83. package/dist/lib/commands/mongo/SyncCommandMongo.js +26 -0
  84. package/dist/lib/commands/mongo/SyncCommandMongo.js.map +1 -0
  85. package/dist/lib/commands/mongo/index.js +14 -0
  86. package/dist/lib/commands/mongo/index.js.map +1 -0
  87. package/dist/lib/commands/sql/FolderSyncCommandSQL.js +16 -0
  88. package/dist/lib/commands/sql/FolderSyncCommandSQL.js.map +1 -0
  89. package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js +21 -0
  90. package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js.map +1 -0
  91. package/dist/lib/commands/sql/ItemOperationsCommandSQL.js +18 -0
  92. package/dist/lib/commands/sql/ItemOperationsCommandSQL.js.map +1 -0
  93. package/dist/lib/commands/sql/MeetingResponseCommandSQL.js +17 -0
  94. package/dist/lib/commands/sql/MeetingResponseCommandSQL.js.map +1 -0
  95. package/dist/lib/commands/sql/MoveItemsCommandSQL.js +17 -0
  96. package/dist/lib/commands/sql/MoveItemsCommandSQL.js.map +1 -0
  97. package/dist/lib/commands/sql/ResolveRecipientsCommandSQL.js +20 -0
  98. package/dist/lib/commands/sql/ResolveRecipientsCommandSQL.js.map +1 -0
  99. package/dist/lib/commands/sql/SearchCommandSQL.js +20 -0
  100. package/dist/lib/commands/sql/SearchCommandSQL.js.map +1 -0
  101. package/dist/lib/commands/sql/SendMailCommandSQL.js +17 -0
  102. package/dist/lib/commands/sql/SendMailCommandSQL.js.map +1 -0
  103. package/dist/lib/commands/sql/SettingsCommandSQL.js +16 -0
  104. package/dist/lib/commands/sql/SettingsCommandSQL.js.map +1 -0
  105. package/dist/lib/commands/sql/SmartForwardCommandSQL.js +17 -0
  106. package/dist/lib/commands/sql/SmartForwardCommandSQL.js.map +1 -0
  107. package/dist/lib/commands/sql/SmartReplyCommandSQL.js +17 -0
  108. package/dist/lib/commands/sql/SmartReplyCommandSQL.js.map +1 -0
  109. package/dist/lib/commands/sql/SyncCommandSQL.js +26 -0
  110. package/dist/lib/commands/sql/SyncCommandSQL.js.map +1 -0
  111. package/dist/lib/commands/sql/index.js +14 -0
  112. package/dist/lib/commands/sql/index.js.map +1 -0
  113. package/dist/lib/index.js +56 -0
  114. package/dist/lib/index.js.map +1 -0
  115. package/dist/lib/mongo/DeviceSyncStateRouteMongo.js +16 -0
  116. package/dist/lib/mongo/DeviceSyncStateRouteMongo.js.map +1 -0
  117. package/dist/lib/mongo/EasRouteMongo.js +51 -0
  118. package/dist/lib/mongo/EasRouteMongo.js.map +1 -0
  119. package/dist/lib/mongo/index.js +8 -0
  120. package/dist/lib/mongo/index.js.map +1 -0
  121. package/dist/lib/mongo.js +6 -0
  122. package/dist/lib/mongo.js.map +1 -0
  123. package/dist/lib/sql/DeviceSyncStateRouteSQL.js +16 -0
  124. package/dist/lib/sql/DeviceSyncStateRouteSQL.js.map +1 -0
  125. package/dist/lib/sql/EasRouteSQL.js +50 -0
  126. package/dist/lib/sql/EasRouteSQL.js.map +1 -0
  127. package/dist/lib/sql/index.js +8 -0
  128. package/dist/lib/sql/index.js.map +1 -0
  129. package/dist/lib/sql.js +6 -0
  130. package/dist/lib/sql.js.map +1 -0
  131. package/dist/types/BaseDeviceSyncStateRoute.d.ts +34 -0
  132. package/dist/types/BaseEasRoute.d.ts +64 -0
  133. package/dist/types/CompactDateTime.d.ts +22 -0
  134. package/dist/types/EasCommandHandler.d.ts +59 -0
  135. package/dist/types/EasSyncKeyUtils.d.ts +89 -0
  136. package/dist/types/adapters/CalendarSyncAdapter.d.ts +52 -0
  137. package/dist/types/adapters/ContactsSyncAdapter.d.ts +33 -0
  138. package/dist/types/adapters/EasCollectionSyncAdapter.d.ts +52 -0
  139. package/dist/types/adapters/EmailSyncAdapter.d.ts +53 -0
  140. package/dist/types/adapters/TasksSyncAdapter.d.ts +32 -0
  141. package/dist/types/codec/WbxmlCodePages.d.ts +45 -0
  142. package/dist/types/codec/WbxmlDecoder.d.ts +33 -0
  143. package/dist/types/codec/WbxmlElement.d.ts +43 -0
  144. package/dist/types/codec/WbxmlEncoder.d.ts +20 -0
  145. package/dist/types/commands/ComposeMailCommand.d.ts +50 -0
  146. package/dist/types/commands/FolderSyncCommand.d.ts +25 -0
  147. package/dist/types/commands/GetItemEstimateCommand.d.ts +43 -0
  148. package/dist/types/commands/ItemOperationsCommand.d.ts +72 -0
  149. package/dist/types/commands/MeetingResponseCommand.d.ts +32 -0
  150. package/dist/types/commands/MoveItemsCommand.d.ts +29 -0
  151. package/dist/types/commands/PingCommand.d.ts +33 -0
  152. package/dist/types/commands/ProvisionCommand.d.ts +54 -0
  153. package/dist/types/commands/ResolveRecipientsCommand.d.ts +34 -0
  154. package/dist/types/commands/SearchCommand.d.ts +39 -0
  155. package/dist/types/commands/SendMailCommand.d.ts +10 -0
  156. package/dist/types/commands/SettingsCommand.d.ts +37 -0
  157. package/dist/types/commands/SmartForwardCommand.d.ts +17 -0
  158. package/dist/types/commands/SmartReplyCommand.d.ts +17 -0
  159. package/dist/types/commands/SyncCommand.d.ts +100 -0
  160. package/dist/types/commands/mongo/FolderSyncCommandMongo.d.ts +8 -0
  161. package/dist/types/commands/mongo/GetItemEstimateCommandMongo.d.ts +7 -0
  162. package/dist/types/commands/mongo/ItemOperationsCommandMongo.d.ts +9 -0
  163. package/dist/types/commands/mongo/MeetingResponseCommandMongo.d.ts +8 -0
  164. package/dist/types/commands/mongo/MoveItemsCommandMongo.d.ts +8 -0
  165. package/dist/types/commands/mongo/ResolveRecipientsCommandMongo.d.ts +8 -0
  166. package/dist/types/commands/mongo/SearchCommandMongo.d.ts +8 -0
  167. package/dist/types/commands/mongo/SendMailCommandMongo.d.ts +8 -0
  168. package/dist/types/commands/mongo/SettingsCommandMongo.d.ts +7 -0
  169. package/dist/types/commands/mongo/SmartForwardCommandMongo.d.ts +8 -0
  170. package/dist/types/commands/mongo/SmartReplyCommandMongo.d.ts +8 -0
  171. package/dist/types/commands/mongo/SyncCommandMongo.d.ts +8 -0
  172. package/dist/types/commands/mongo/index.d.ts +9 -0
  173. package/dist/types/commands/sql/FolderSyncCommandSQL.d.ts +8 -0
  174. package/dist/types/commands/sql/GetItemEstimateCommandSQL.d.ts +7 -0
  175. package/dist/types/commands/sql/ItemOperationsCommandSQL.d.ts +9 -0
  176. package/dist/types/commands/sql/MeetingResponseCommandSQL.d.ts +8 -0
  177. package/dist/types/commands/sql/MoveItemsCommandSQL.d.ts +8 -0
  178. package/dist/types/commands/sql/ResolveRecipientsCommandSQL.d.ts +8 -0
  179. package/dist/types/commands/sql/SearchCommandSQL.d.ts +8 -0
  180. package/dist/types/commands/sql/SendMailCommandSQL.d.ts +8 -0
  181. package/dist/types/commands/sql/SettingsCommandSQL.d.ts +7 -0
  182. package/dist/types/commands/sql/SmartForwardCommandSQL.d.ts +8 -0
  183. package/dist/types/commands/sql/SmartReplyCommandSQL.d.ts +8 -0
  184. package/dist/types/commands/sql/SyncCommandSQL.d.ts +8 -0
  185. package/dist/types/commands/sql/index.d.ts +9 -0
  186. package/dist/types/index.d.ts +51 -0
  187. package/dist/types/mongo/DeviceSyncStateRouteMongo.d.ts +8 -0
  188. package/dist/types/mongo/EasRouteMongo.d.ts +14 -0
  189. package/dist/types/mongo/index.d.ts +3 -0
  190. package/dist/types/mongo.d.ts +1 -0
  191. package/dist/types/sql/DeviceSyncStateRouteSQL.d.ts +8 -0
  192. package/dist/types/sql/EasRouteSQL.d.ts +13 -0
  193. package/dist/types/sql/index.d.ts +3 -0
  194. package/dist/types/sql.d.ts +1 -0
  195. package/package.json +94 -0
@@ -0,0 +1,150 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ ///////////////////////////////////////////////////////////////////////////////
11
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
12
+ // SPDX-License-Identifier: MPL-2.0
13
+ ///////////////////////////////////////////////////////////////////////////////
14
+ import { ApiError, ObjectDecorators } from "@rapidrest/core";
15
+ import { ApiErrorMessages, ApiErrors, RepoUtils } from "@rapidrest/service-core";
16
+ import { WbxmlCodePage } from "../codec/WbxmlCodePages.js";
17
+ import { childText, element, textElement } from "../codec/WbxmlElement.js";
18
+ import { computeChanges, formatSyncKey, persistDeviceSyncState, resolveSyncKey } from "../EasSyncKeyUtils.js";
19
+ import { FolderType } from "@rapidmx/restapi";
20
+ const { Config, Init } = ObjectDecorators;
21
+ /** Maps this library's `FolderType` to the closest MS-ASCMD folder type code. Several of this app's types
22
+ * collapse onto the spec's "default well-known folder" codes rather than distinguishing a default folder from
23
+ * a second, user-created folder of the same content type (e.g. a second calendar also reports as `8`) - a
24
+ * deliberate pragmatic-subset simplification, not an oversight; see `BaseFolderRoute`'s own precedent for
25
+ * this library's general stance on this kind of gap. */
26
+ const FOLDER_TYPE_CODES = {
27
+ [FolderType.INBOX]: "2",
28
+ [FolderType.DRAFTS]: "3",
29
+ [FolderType.DELETED_ITEMS]: "4",
30
+ [FolderType.SENT_ITEMS]: "5",
31
+ [FolderType.OUTBOX]: "6",
32
+ [FolderType.TASKS]: "7",
33
+ [FolderType.CALENDAR]: "8",
34
+ [FolderType.CONTACTS]: "9",
35
+ [FolderType.NOTES]: "10",
36
+ [FolderType.JUNK]: "12",
37
+ [FolderType.USER]: "12",
38
+ };
39
+ /** EAS represents "no parent" (a top-level folder) as the literal string `"0"`, not an absent element. */
40
+ const ROOT_PARENT_ID = "0";
41
+ /** The (somewhat arbitrary, since `FolderSync` covers the whole mailbox's folder hierarchy rather than one
42
+ * particular folder) key `DeviceSyncState.folderSyncKeys` is stored under for this cursor - distinct from any
43
+ * real `Folder.uid`, which is exactly why using the mailbox's own uid here would be ambiguous. */
44
+ const FOLDER_HIERARCHY_CURSOR_KEY = "$foldersync";
45
+ /** Caps how many folder changes are enumerated per round - real mailboxes rarely have more than a few dozen
46
+ * folders, so this is generous, not a real-world binding constraint; it exists so `computeChanges()`'s
47
+ * `MoreAvailable` mechanism is exercised the same way it will be for `SyncCommand`'s much larger item
48
+ * collections. */
49
+ const DEFAULT_WINDOW_SIZE = 512;
50
+ /**
51
+ * Handles EAS `FolderSync`: enumerates `Add`/`Update`/`Delete`s for the caller's mailbox's `Folder` hierarchy
52
+ * since the device's last `FolderSync`, using the shared watermark-based cursor mechanism in
53
+ * `EasSyncKeyUtils.ts` (scoped by `mailboxUid` over the `Folder` collection, rather than `folderUid` over a
54
+ * per-folder item collection the way `SyncCommand` will be).
55
+ *
56
+ * `folderClass` is supplied by the Mongo/SQL concrete subclasses, following the exact one-line-per-backend
57
+ * pattern used throughout this library's other routes/jobs.
58
+ *
59
+ * @author Jean-Philippe Steinmetz
60
+ */
61
+ export class FolderSyncCommand {
62
+ constructor() {
63
+ this.command = "FolderSync";
64
+ this.windowSize = DEFAULT_WINDOW_SIZE;
65
+ }
66
+ async init() {
67
+ this.folderRepo = await this._objectFactory.newInstance(RepoUtils, {
68
+ name: this.folderClass.name,
69
+ args: [this.folderClass],
70
+ });
71
+ }
72
+ async handle(ctx) {
73
+ if (!this.folderRepo) {
74
+ throw new ApiError(ApiErrors.INTERNAL_ERROR, 500, ApiErrorMessages.INTERNAL_ERROR);
75
+ }
76
+ const clientSyncKey = ctx.request ? childText(ctx.request, "SyncKey") : undefined;
77
+ const storedSyncKey = ctx.deviceSyncState.folderSyncKeys[FOLDER_HIERARCHY_CURSOR_KEY];
78
+ const resolution = resolveSyncKey(clientSyncKey, storedSyncKey);
79
+ if (resolution.kind === "invalid") {
80
+ return element(WbxmlCodePage.FolderHierarchy, "FolderSync", [
81
+ textElement(WbxmlCodePage.FolderHierarchy, "Status", "3"),
82
+ ]);
83
+ }
84
+ if (resolution.kind === "initial") {
85
+ // Per spec: the first response to SyncKey "0" never returns items itself, only establishes a
86
+ // cursor - but that cursor's watermark must be the epoch, not "now": the client's *next* request
87
+ // (with this key) is its true first full sync and must report every existing folder as an Add,
88
+ // including ones that existed and were last modified long before this handshake ever started.
89
+ // Watermarking at "now" here would silently skip all of those (an epoch-old folder never appears
90
+ // as "modified after now"), which is exactly backwards for a brand-new device's first sync.
91
+ const newKey = formatSyncKey({ generation: 1, watermark: new Date(0) });
92
+ await this.persistSyncKey(ctx, newKey);
93
+ return element(WbxmlCodePage.FolderHierarchy, "FolderSync", [
94
+ textElement(WbxmlCodePage.FolderHierarchy, "Status", "1"),
95
+ textElement(WbxmlCodePage.FolderHierarchy, "SyncKey", newKey),
96
+ ]);
97
+ }
98
+ const changes = await computeChanges(this.folderRepo, "mailboxUid", ctx.mailboxUid, resolution.key.watermark, this.windowSize);
99
+ const newKey = formatSyncKey({ generation: resolution.key.generation + 1, watermark: changes.newWatermark });
100
+ await this.persistSyncKey(ctx, newKey);
101
+ const totalChanges = changes.adds.length + changes.changes.length + changes.deletes.length;
102
+ if (totalChanges === 0) {
103
+ return element(WbxmlCodePage.FolderHierarchy, "FolderSync", [
104
+ textElement(WbxmlCodePage.FolderHierarchy, "Status", "1"),
105
+ textElement(WbxmlCodePage.FolderHierarchy, "SyncKey", newKey),
106
+ ]);
107
+ }
108
+ const changeElements = [
109
+ ...changes.adds.map((folder) => this.folderToChangeElement("Add", folder)),
110
+ ...changes.changes.map((folder) => this.folderToChangeElement("Update", folder)),
111
+ ...changes.deletes.map((folder) => element(WbxmlCodePage.FolderHierarchy, "Delete", [
112
+ textElement(WbxmlCodePage.FolderHierarchy, "ServerId", folder.uid),
113
+ ])),
114
+ ];
115
+ return element(WbxmlCodePage.FolderHierarchy, "FolderSync", [
116
+ textElement(WbxmlCodePage.FolderHierarchy, "Status", "1"),
117
+ textElement(WbxmlCodePage.FolderHierarchy, "SyncKey", newKey),
118
+ element(WbxmlCodePage.FolderHierarchy, "Changes", [
119
+ textElement(WbxmlCodePage.FolderHierarchy, "Count", String(totalChanges)),
120
+ ...changeElements,
121
+ ]),
122
+ ]);
123
+ }
124
+ folderToChangeElement(kind, folder) {
125
+ return element(WbxmlCodePage.FolderHierarchy, kind, [
126
+ textElement(WbxmlCodePage.FolderHierarchy, "ServerId", folder.uid),
127
+ textElement(WbxmlCodePage.FolderHierarchy, "ParentId", folder.parentFolderUid ?? ROOT_PARENT_ID),
128
+ textElement(WbxmlCodePage.FolderHierarchy, "DisplayName", folder.name),
129
+ /* v8 ignore next -- unreachable via real data: FOLDER_TYPE_CODES has an entry for every FolderType
130
+ enum value, so the `??` fallback only guards a future enum member added to one without the
131
+ other; `folder.type` can never carry a value outside the enum. */
132
+ textElement(WbxmlCodePage.FolderHierarchy, "Type", FOLDER_TYPE_CODES[folder.type] ?? FOLDER_TYPE_CODES[FolderType.USER]),
133
+ ]);
134
+ }
135
+ async persistSyncKey(ctx, newKey) {
136
+ const folderSyncKeys = { ...ctx.deviceSyncState.folderSyncKeys, [FOLDER_HIERARCHY_CURSOR_KEY]: newKey };
137
+ await persistDeviceSyncState(ctx.deviceSyncState, ctx.deviceSyncStateRepo, { folderSyncKeys });
138
+ }
139
+ }
140
+ __decorate([
141
+ Config("mail:eas:foldersync_window_size", DEFAULT_WINDOW_SIZE),
142
+ __metadata("design:type", Number)
143
+ ], FolderSyncCommand.prototype, "windowSize", void 0);
144
+ __decorate([
145
+ Init,
146
+ __metadata("design:type", Function),
147
+ __metadata("design:paramtypes", []),
148
+ __metadata("design:returntype", Promise)
149
+ ], FolderSyncCommand.prototype, "init", null);
150
+ //# sourceMappingURL=FolderSyncCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FolderSyncCommand.js","sourceRoot":"","sources":["../../../src/commands/FolderSyncCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ ///////////////////////////////////////////////////////////////////////////////
11
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
12
+ // SPDX-License-Identifier: MPL-2.0
13
+ ///////////////////////////////////////////////////////////////////////////////
14
+ import { ApiError, ObjectDecorators } from "@rapidrest/core";
15
+ import { ACLAction, ACLUtils, ApiErrorMessages, ApiErrors } from "@rapidrest/service-core";
16
+ import { RecoverableRepoUtils } from "@rapidmx/restapi";
17
+ import { WbxmlCodePage } from "../codec/WbxmlCodePages.js";
18
+ import { childText, element, findChild, findChildren, textElement } from "../codec/WbxmlElement.js";
19
+ import { computeChanges, resolveSyncKey } from "../EasSyncKeyUtils.js";
20
+ const { Config, Init, Inject } = ObjectDecorators;
21
+ /** Caps how many changes `computeChanges()` will actually enumerate (and therefore count) per collection for
22
+ * an already-synced folder - a real estimate, not a precise unbounded count, matching the command's own name;
23
+ * a folder with more pending changes than this reports exactly this many, not the true total. Deliberately
24
+ * separate from `SyncCommand`'s own `mail:eas:sync_window_size` - the two commands have no reason to share one
25
+ * config knob just because they happen to reuse the same underlying enumeration helper. */
26
+ const DEFAULT_MAX_COUNT = 512;
27
+ /**
28
+ * Handles EAS `GetItemEstimate`: reports, per requested `<Collection>`, an estimated count of the
29
+ * `Add`/`Change`/`Delete`s a subsequent `Sync` of that collection would return - read-only, it never issues or
30
+ * consumes a `SyncKey` itself.
31
+ *
32
+ * The modern (14.0+) request/response reuses `WbxmlCodePage.AirSync`'s own `Collections`/`Collection`/`Class`/
33
+ * `CollectionId`/`SyncKey` via `SWITCH_PAGE` rather than this page's own legacy (`Folders`/`Folder`/`FolderId`)
34
+ * shape - see `WbxmlCodePages.ts`'s own doc comment on `WbxmlCodePage.ItemEstimate` for why, and
35
+ * `ItemOperationsCommand.fetchMessage`'s identical cross-page-reuse precedent.
36
+ *
37
+ * A `SyncKey` of `"0"` (or one this device has never synced this folder with before) reports the folder's
38
+ * total live item count - what a first `Sync` would report as `Add`s. Otherwise reuses `EasSyncKeyUtils.
39
+ * computeChanges()` (the same enumeration `SyncCommand` itself uses), capped at `DEFAULT_MAX_COUNT` - see its
40
+ * own doc comment for why this is a real, documented approximation on a very active folder rather than a
41
+ * precise unbounded count.
42
+ *
43
+ * **ACL-checked like `Sync`**: `estimateCollection()` requires `ACLAction.READ` on the client-supplied
44
+ * `CollectionId` before counting anything - without it, a crafted `CollectionId` belonging to another
45
+ * mailbox's folder would return a real pending-change count for it. A denied folder is reported identically to
46
+ * an unrecognized collection (`Status 2`), never distinguishable from "you don't have this collection at all".
47
+ *
48
+ * @author Jean-Philippe Steinmetz
49
+ */
50
+ export class GetItemEstimateCommand {
51
+ constructor() {
52
+ this.command = "GetItemEstimate";
53
+ this.maxCount = DEFAULT_MAX_COUNT;
54
+ this.repos = new Map();
55
+ }
56
+ async init() {
57
+ for (const [collectionClass, binding] of Object.entries(this.collectionBindings)) {
58
+ this.repos.set(collectionClass, await this._objectFactory.newInstance(RecoverableRepoUtils, {
59
+ name: binding.entityClass.name,
60
+ args: [binding.entityClass],
61
+ }));
62
+ }
63
+ }
64
+ async handle(ctx) {
65
+ if (!this.aclUtils) {
66
+ throw new ApiError(ApiErrors.INTERNAL_ERROR, 500, ApiErrorMessages.INTERNAL_ERROR);
67
+ }
68
+ const collections = ctx.request ? findChild(ctx.request, "Collections") : undefined;
69
+ const collectionEls = collections ? findChildren(collections, "Collection") : [];
70
+ if (collectionEls.length === 0) {
71
+ return element(WbxmlCodePage.ItemEstimate, "GetItemEstimate", [
72
+ element(WbxmlCodePage.ItemEstimate, "Response", [
73
+ textElement(WbxmlCodePage.ItemEstimate, "Status", "2"),
74
+ ]),
75
+ ]);
76
+ }
77
+ const responses = [];
78
+ for (const collectionEl of collectionEls) {
79
+ responses.push(await this.estimateCollection(ctx, collectionEl));
80
+ }
81
+ return element(WbxmlCodePage.ItemEstimate, "GetItemEstimate", responses);
82
+ }
83
+ async estimateCollection(ctx, collectionEl) {
84
+ const collectionClass = childText(collectionEl, "Class");
85
+ const folderUid = childText(collectionEl, "CollectionId");
86
+ const clientSyncKey = childText(collectionEl, "SyncKey");
87
+ const repo = collectionClass ? this.repos.get(collectionClass) : undefined;
88
+ if (!collectionClass || !folderUid || !repo) {
89
+ // Status 2 ("Invalid collection") per [MS-ASCMD] - the request named a collection this device
90
+ // hasn't (or can't) sync.
91
+ return element(WbxmlCodePage.ItemEstimate, "Response", [
92
+ textElement(WbxmlCodePage.ItemEstimate, "Status", "2"),
93
+ ]);
94
+ }
95
+ // Never count against a folder the caller can't even read - see this class's own doc comment.
96
+ if (!(await this.aclUtils.hasPermission(ctx.user, folderUid, ACLAction.READ))) {
97
+ return element(WbxmlCodePage.ItemEstimate, "Response", [
98
+ textElement(WbxmlCodePage.ItemEstimate, "Status", "2"),
99
+ ]);
100
+ }
101
+ const storedSyncKey = ctx.deviceSyncState.folderSyncKeys[folderUid];
102
+ const resolution = resolveSyncKey(clientSyncKey, storedSyncKey);
103
+ if (resolution.kind === "invalid") {
104
+ return element(WbxmlCodePage.ItemEstimate, "Response", [
105
+ textElement(WbxmlCodePage.ItemEstimate, "Status", "2"),
106
+ this.collectionElement(collectionClass, folderUid, undefined),
107
+ ]);
108
+ }
109
+ // A brand-new (or never-synced-by-this-device) folder: every live item would be reported as an Add on
110
+ // the device's first real Sync round - a plain count() of non-deleted rows (excluded by default; see
111
+ // computeChanges()'s own doc comment on this query builder behavior), not computeChanges() itself,
112
+ // which would incorrectly also count this folder's entire soft-deleted history (irrelevant to a client
113
+ // that has never seen any of those rows in the first place).
114
+ let count;
115
+ if (resolution.kind === "initial") {
116
+ count = await repo.count({ folderUid }, { ignoreACL: true });
117
+ }
118
+ else {
119
+ const changes = await computeChanges(repo, "folderUid", folderUid, resolution.key.watermark, this.maxCount);
120
+ count = changes.adds.length + changes.changes.length + changes.deletes.length;
121
+ }
122
+ return element(WbxmlCodePage.ItemEstimate, "Response", [
123
+ textElement(WbxmlCodePage.ItemEstimate, "Status", "1"),
124
+ this.collectionElement(collectionClass, folderUid, count),
125
+ ]);
126
+ }
127
+ collectionElement(collectionClass, folderUid, estimate) {
128
+ return element(WbxmlCodePage.AirSync, "Collection", [
129
+ textElement(WbxmlCodePage.AirSync, "Class", collectionClass),
130
+ textElement(WbxmlCodePage.AirSync, "CollectionId", folderUid),
131
+ ...(estimate !== undefined ? [textElement(WbxmlCodePage.ItemEstimate, "Estimate", String(estimate))] : []),
132
+ ]);
133
+ }
134
+ }
135
+ __decorate([
136
+ Config("mail:eas:item_estimate_max_count", DEFAULT_MAX_COUNT),
137
+ __metadata("design:type", Number)
138
+ ], GetItemEstimateCommand.prototype, "maxCount", void 0);
139
+ __decorate([
140
+ Inject(ACLUtils),
141
+ __metadata("design:type", ACLUtils)
142
+ ], GetItemEstimateCommand.prototype, "aclUtils", void 0);
143
+ __decorate([
144
+ Init,
145
+ __metadata("design:type", Function),
146
+ __metadata("design:paramtypes", []),
147
+ __metadata("design:returntype", Promise)
148
+ ], GetItemEstimateCommand.prototype, "init", null);
149
+ //# sourceMappingURL=GetItemEstimateCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GetItemEstimateCommand.js","sourceRoot":"","sources":["../../../src/commands/GetItemEstimateCommand.ts"],"names":[],"mappings":"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"}