@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,83 @@
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 { BaseEntity, DocDecorators, ModelDecorators, PersistenceDecorators } from "@rapidrest/service-core";
15
+ import { MailboxScopedData } from "@rapidmx/restapi";
16
+ const { Description } = DocDecorators;
17
+ const { DataStore, Protect } = ModelDecorators;
18
+ const { Column, Entity, Index } = PersistenceDecorators;
19
+ /**
20
+ * Implementation of the `EasCollectionChunk` interface for storage in a SQL database. If MongoDB is desired,
21
+ * please use `models.mongo.EasCollectionChunkMongo` instead.
22
+ *
23
+ * @author Jean-Philippe Steinmetz
24
+ */
25
+ let EasCollectionChunkSQL = class EasCollectionChunkSQL extends BaseEntity {
26
+ constructor(other) {
27
+ super(other);
28
+ this.mailboxUid = "";
29
+ this.deviceId = "";
30
+ this.folderUid = "";
31
+ this.chunkIndex = 0;
32
+ this.ids = [];
33
+ if (other) {
34
+ this.mailboxUid = other.mailboxUid !== undefined ? other.mailboxUid : this.mailboxUid;
35
+ this.deviceId = other.deviceId !== undefined ? other.deviceId : this.deviceId;
36
+ this.folderUid = other.folderUid !== undefined ? other.folderUid : this.folderUid;
37
+ this.chunkIndex = other.chunkIndex !== undefined ? other.chunkIndex : this.chunkIndex;
38
+ this.ids = other.ids !== undefined ? other.ids : this.ids;
39
+ }
40
+ }
41
+ };
42
+ __decorate([
43
+ Column(),
44
+ Description("The unique identifier of the `Mailbox` the device is synced against."),
45
+ __metadata("design:type", String)
46
+ ], EasCollectionChunkSQL.prototype, "mailboxUid", void 0);
47
+ __decorate([
48
+ Column(),
49
+ Description("The unique identifier of the paired device."),
50
+ __metadata("design:type", String)
51
+ ], EasCollectionChunkSQL.prototype, "deviceId", void 0);
52
+ __decorate([
53
+ Column(),
54
+ Description("The unique identifier of the synced `Folder`."),
55
+ __metadata("design:type", String)
56
+ ], EasCollectionChunkSQL.prototype, "folderUid", void 0);
57
+ __decorate([
58
+ Column(),
59
+ Description("Position of the chunk within the collection."),
60
+ __metadata("design:type", Number)
61
+ ], EasCollectionChunkSQL.prototype, "chunkIndex", void 0);
62
+ __decorate([
63
+ Column({ type: "simple-json" }),
64
+ Description("The `ServerId`s this chunk holds."),
65
+ __metadata("design:type", Array)
66
+ ], EasCollectionChunkSQL.prototype, "ids", void 0);
67
+ EasCollectionChunkSQL = __decorate([
68
+ DataStore("sql"),
69
+ Entity(),
70
+ MailboxScopedData(),
71
+ Description("One slice of the items a device holds for an EAS `Sync` collection."),
72
+ Index("eascollectionchunk_mailbox_device_folder_index", ["mailboxUid", "deviceId", "folderUid", "chunkIndex"], { unique: true }),
73
+ Protect({
74
+ uid: "EasCollectionChunk",
75
+ records: [
76
+ { userOrRoleId: "anonymous", actions: [] },
77
+ { userOrRoleId: ".*", actions: [] },
78
+ ],
79
+ }, false),
80
+ __metadata("design:paramtypes", [Object])
81
+ ], EasCollectionChunkSQL);
82
+ export { EasCollectionChunkSQL };
83
+ //# sourceMappingURL=EasCollectionChunkSQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EasCollectionChunkSQL.js","sourceRoot":"","sources":["../../../../src/models/sql/EasCollectionChunkSQL.ts"],"names":[],"mappings":";;;;;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC5G,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,EAAE,WAAW,EAAE,GAAG,aAAa,CAAC;AACtC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC;AAC/C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,qBAAqB,CAAC;AAExD;;;;;GAKG;AAgBI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,UAAU;IAqBjD,YAAY,KAAsC;QAC9C,KAAK,CAAC,KAAK,CAAC,CAAC;QAnBV,eAAU,GAAW,EAAE,CAAC;QAIxB,aAAQ,GAAW,EAAE,CAAC;QAItB,cAAS,GAAW,EAAE,CAAC;QAIvB,eAAU,GAAW,CAAC,CAAC;QAIvB,QAAG,GAAa,EAAE,CAAC;QAKtB,IAAI,KAAK,EAAE,CAAC;YACR,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;YACtF,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;YAC9E,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;YAClF,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;YACtF,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC9D,CAAC;IACL,CAAC;CACJ,CAAA;AA7BU;IAFN,MAAM,EAAE;IACR,WAAW,CAAC,sEAAsE,CAAC;;yDACrD;AAIxB;IAFN,MAAM,EAAE;IACR,WAAW,CAAC,6CAA6C,CAAC;;uDAC9B;AAItB;IAFN,MAAM,EAAE;IACR,WAAW,CAAC,+CAA+C,CAAC;;wDAC/B;AAIvB;IAFN,MAAM,EAAE;IACR,WAAW,CAAC,8CAA8C,CAAC;;yDAC9B;AAIvB;IAFN,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IAC/B,WAAW,CAAC,mCAAmC,CAAC;;kDACvB;AAnBjB,qBAAqB;IAfjC,SAAS,CAAC,KAAK,CAAC;IAChB,MAAM,EAAE;IACR,iBAAiB,EAAE;IACnB,WAAW,CAAC,qEAAqE,CAAC;IAClF,KAAK,CAAC,gDAAgD,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChI,OAAO,CACJ;QACI,GAAG,EAAE,oBAAoB;QACzB,OAAO,EAAE;YACL,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE;YAC1C,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;SACtC;KACJ,EACD,KAAK,CACR;;GACY,qBAAqB,CAgCjC"}
@@ -0,0 +1,162 @@
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 { BaseEntity, DocDecorators, ModelDecorators, PersistenceDecorators } from "@rapidrest/service-core";
15
+ import { ObjectDecorators } from "@rapidrest/core";
16
+ import { MailboxScopedData } from "@rapidmx/restapi";
17
+ const { Description } = DocDecorators;
18
+ const { DataStore, Protect } = ModelDecorators;
19
+ const { Nullable } = ObjectDecorators;
20
+ const { Column, Entity, Index } = PersistenceDecorators;
21
+ /**
22
+ * Implementation of the `EasCollectionState` interface for storage in a SQL database. If MongoDB is desired,
23
+ * please use `models.mongo.EasCollectionStateMongo` instead.
24
+ *
25
+ * @author Jean-Philippe Steinmetz
26
+ */
27
+ let EasCollectionStateSQL = class EasCollectionStateSQL extends BaseEntity {
28
+ constructor(other) {
29
+ super(other);
30
+ this.mailboxUid = "";
31
+ this.deviceId = "";
32
+ this.folderUid = "";
33
+ this.collectionClass = "";
34
+ this.syncKey = "";
35
+ this.cursorDate = new Date(0);
36
+ this.cursorUid = "";
37
+ this.moveCursorDate = new Date(0);
38
+ this.moveCursorUid = "";
39
+ this.serverIds = [];
40
+ this.echoes = {};
41
+ if (other) {
42
+ this.mailboxUid = other.mailboxUid !== undefined ? other.mailboxUid : this.mailboxUid;
43
+ this.deviceId = other.deviceId !== undefined ? other.deviceId : this.deviceId;
44
+ this.folderUid = other.folderUid !== undefined ? other.folderUid : this.folderUid;
45
+ this.collectionClass = other.collectionClass !== undefined ? other.collectionClass : this.collectionClass;
46
+ this.syncKey = other.syncKey !== undefined ? other.syncKey : this.syncKey;
47
+ this.cursorDate = other.cursorDate !== undefined ? other.cursorDate : this.cursorDate;
48
+ this.cursorUid = other.cursorUid !== undefined ? other.cursorUid : this.cursorUid;
49
+ this.moveCursorDate = other.moveCursorDate !== undefined ? other.moveCursorDate : this.moveCursorDate;
50
+ this.moveCursorUid = other.moveCursorUid !== undefined ? other.moveCursorUid : this.moveCursorUid;
51
+ this.serverIds = other.serverIds !== undefined ? other.serverIds : this.serverIds;
52
+ this.echoes = other.echoes !== undefined ? other.echoes : this.echoes;
53
+ this.chunked = "chunked" in other ? other.chunked : this.chunked;
54
+ this.recent = "recent" in other ? other.recent : this.recent;
55
+ this.reconcileCursor = "reconcileCursor" in other ? other.reconcileCursor : this.reconcileCursor;
56
+ this.filterType = "filterType" in other ? other.filterType : this.filterType;
57
+ this.previous = "previous" in other ? other.previous : this.previous;
58
+ }
59
+ }
60
+ };
61
+ __decorate([
62
+ Column(),
63
+ Description("The unique identifier of the `Mailbox` the device is synced against."),
64
+ __metadata("design:type", String)
65
+ ], EasCollectionStateSQL.prototype, "mailboxUid", void 0);
66
+ __decorate([
67
+ Column(),
68
+ Description("The unique identifier of the paired device."),
69
+ __metadata("design:type", String)
70
+ ], EasCollectionStateSQL.prototype, "deviceId", void 0);
71
+ __decorate([
72
+ Column(),
73
+ Description("The unique identifier of the synced `Folder`."),
74
+ __metadata("design:type", String)
75
+ ], EasCollectionStateSQL.prototype, "folderUid", void 0);
76
+ __decorate([
77
+ Column(),
78
+ Description("The EAS `Class` of the collection."),
79
+ __metadata("design:type", String)
80
+ ], EasCollectionStateSQL.prototype, "collectionClass", void 0);
81
+ __decorate([
82
+ Column(),
83
+ Description("The `SyncKey` most recently issued for this collection."),
84
+ __metadata("design:type", String)
85
+ ], EasCollectionStateSQL.prototype, "syncKey", void 0);
86
+ __decorate([
87
+ Column(),
88
+ Description("The `dateModified` position in the folder's change stream."),
89
+ __metadata("design:type", Date)
90
+ ], EasCollectionStateSQL.prototype, "cursorDate", void 0);
91
+ __decorate([
92
+ Column(),
93
+ Description("The `uid` tie-breaker of the folder change stream position."),
94
+ __metadata("design:type", String)
95
+ ], EasCollectionStateSQL.prototype, "cursorUid", void 0);
96
+ __decorate([
97
+ Column(),
98
+ Description("The `dateModified` position in the stream of items outside the folder."),
99
+ __metadata("design:type", Date)
100
+ ], EasCollectionStateSQL.prototype, "moveCursorDate", void 0);
101
+ __decorate([
102
+ Column(),
103
+ Description("The `uid` tie-breaker of the outside-the-folder stream position."),
104
+ __metadata("design:type", String)
105
+ ], EasCollectionStateSQL.prototype, "moveCursorUid", void 0);
106
+ __decorate([
107
+ Column({ type: "simple-json" }),
108
+ Description("The `ServerId`s the device currently holds for this collection."),
109
+ __metadata("design:type", Array)
110
+ ], EasCollectionStateSQL.prototype, "serverIds", void 0);
111
+ __decorate([
112
+ Column({ type: "simple-json" }),
113
+ Description("Item uid to the `dateModified` left by the device's own write."),
114
+ __metadata("design:type", Object)
115
+ ], EasCollectionStateSQL.prototype, "echoes", void 0);
116
+ __decorate([
117
+ Column({ nullable: true }),
118
+ Description("`true` once the held set is stored in `EasCollectionChunk` rows."),
119
+ Nullable,
120
+ __metadata("design:type", Boolean)
121
+ ], EasCollectionStateSQL.prototype, "chunked", void 0);
122
+ __decorate([
123
+ Column({ type: "simple-json", nullable: true }),
124
+ Description("Item uid to `dateModified` of rows processed within the overlap window before the cursor."),
125
+ Nullable,
126
+ __metadata("design:type", Object)
127
+ ], EasCollectionStateSQL.prototype, "recent", void 0);
128
+ __decorate([
129
+ Column({ nullable: true }),
130
+ Description("The last held `ServerId` checked by the periodic reconcile."),
131
+ Nullable,
132
+ __metadata("design:type", String)
133
+ ], EasCollectionStateSQL.prototype, "reconcileCursor", void 0);
134
+ __decorate([
135
+ Column({ nullable: true }),
136
+ Description("The `FilterType` the collection was synced with."),
137
+ Nullable,
138
+ __metadata("design:type", String)
139
+ ], EasCollectionStateSQL.prototype, "filterType", void 0);
140
+ __decorate([
141
+ Column({ type: "simple-json", nullable: true }),
142
+ Description("The state before the most recent round, for a retried `SyncKey`."),
143
+ Nullable,
144
+ __metadata("design:type", Object)
145
+ ], EasCollectionStateSQL.prototype, "previous", void 0);
146
+ EasCollectionStateSQL = __decorate([
147
+ DataStore("sql"),
148
+ Entity(),
149
+ MailboxScopedData(),
150
+ Description("Per-device state of one EAS `Sync` collection."),
151
+ Index("eascollectionstate_mailbox_device_folder", ["mailboxUid", "deviceId", "folderUid"], { unique: true }),
152
+ Protect({
153
+ uid: "EasCollectionState",
154
+ records: [
155
+ { userOrRoleId: "anonymous", actions: [] },
156
+ { userOrRoleId: ".*", actions: [] },
157
+ ],
158
+ }, false),
159
+ __metadata("design:paramtypes", [Object])
160
+ ], EasCollectionStateSQL);
161
+ export { EasCollectionStateSQL };
162
+ //# sourceMappingURL=EasCollectionStateSQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EasCollectionStateSQL.js","sourceRoot":"","sources":["../../../../src/models/sql/EasCollectionStateSQL.ts"],"names":[],"mappings":"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"}
@@ -13,7 +13,7 @@ import { RouteDecorators } from "@rapidrest/service-core";
13
13
  import { DeviceSyncStateMongo } from "../models/mongo/DeviceSyncStateMongo.js";
14
14
  import { BaseEasRoute } from "../BaseEasRoute.js";
15
15
  import { ProvisionCommand } from "../commands/ProvisionCommand.js";
16
- import { PingCommand } from "../commands/PingCommand.js";
16
+ import { PingCommandMongo } from "../commands/mongo/PingCommandMongo.js";
17
17
  import { FolderSyncCommandMongo } from "../commands/mongo/FolderSyncCommandMongo.js";
18
18
  import { SyncCommandMongo } from "../commands/mongo/SyncCommandMongo.js";
19
19
  import { SendMailCommandMongo } from "../commands/mongo/SendMailCommandMongo.js";
@@ -49,7 +49,7 @@ let EasRouteMongo = class EasRouteMongo extends BaseEasRoute {
49
49
  SearchCommandMongo,
50
50
  MeetingResponseCommandMongo,
51
51
  SettingsCommandMongo,
52
- PingCommand,
52
+ PingCommandMongo,
53
53
  GetItemEstimateCommandMongo,
54
54
  MoveItemsCommandMongo,
55
55
  ResolveRecipientsCommandMongo,
@@ -1 +1 @@
1
- {"version":3,"file":"EasRouteMongo.js","sourceRoot":"","sources":["../../../src/mongo/EasRouteMongo.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;GAKG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,YAAgD;IAA5E;;QACO,yBAAoB,GAAQ,oBAAoB,CAAC;QACjD,iBAAY,GAAQ,YAAY,CAAC;QACjC,0BAAqB,GAAU;YACrC,gBAAgB;YAChB,sBAAsB;YACtB,gBAAgB;YAChB,oBAAoB;YACpB,wBAAwB;YACxB,sBAAsB;YACtB,0BAA0B;YAC1B,kBAAkB;YAClB,2BAA2B;YAC3B,oBAAoB;YACpB,WAAW;YACX,2BAA2B;YAC3B,qBAAqB;YACrB,6BAA6B;SAChC,CAAC;IACN,CAAC;CAAA,CAAA;AAnBY,aAAa;IADzB,KAAK,CAAC,8BAA8B,CAAC;GACzB,aAAa,CAmBzB"}
1
+ {"version":3,"file":"EasRouteMongo.js","sourceRoot":"","sources":["../../../src/mongo/EasRouteMongo.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6CAA6C,CAAC;AACrF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AAC/F,OAAO,EAAE,qBAAqB,EAAE,MAAM,4CAA4C,CAAC;AACnF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;GAKG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,YAAgD;IAA5E;;QACO,yBAAoB,GAAQ,oBAAoB,CAAC;QACjD,iBAAY,GAAQ,YAAY,CAAC;QACjC,0BAAqB,GAAU;YACrC,gBAAgB;YAChB,sBAAsB;YACtB,gBAAgB;YAChB,oBAAoB;YACpB,wBAAwB;YACxB,sBAAsB;YACtB,0BAA0B;YAC1B,kBAAkB;YAClB,2BAA2B;YAC3B,oBAAoB;YACpB,gBAAgB;YAChB,2BAA2B;YAC3B,qBAAqB;YACrB,6BAA6B;SAChC,CAAC;IACN,CAAC;CAAA,CAAA;AAnBY,aAAa;IADzB,KAAK,CAAC,8BAA8B,CAAC;GACzB,aAAa,CAmBzB"}
package/dist/lib/mongo.js CHANGED
@@ -11,5 +11,7 @@
11
11
  export { EasRouteMongo } from "./mongo/EasRouteMongo.js";
12
12
  export { DeviceSyncStateRouteMongo } from "./mongo/DeviceSyncStateRouteMongo.js";
13
13
  export { DeviceSyncStateMongo } from "./models/mongo/DeviceSyncStateMongo.js";
14
+ export { EasCollectionStateMongo } from "./models/mongo/EasCollectionStateMongo.js";
15
+ export { EasCollectionChunkMongo } from "./models/mongo/EasCollectionChunkMongo.js";
14
16
  export { EasDeviceStateCleanupJobMongo } from "./jobs/mongo/EasDeviceStateCleanupJobMongo.js";
15
17
  //# sourceMappingURL=mongo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mongo.js","sourceRoot":"","sources":["../../src/mongo.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,6BAA6B,EAAE,MAAM,+CAA+C,CAAC"}
1
+ {"version":3,"file":"mongo.js","sourceRoot":"","sources":["../../src/mongo.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E;;;;;GAKG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACpF,OAAO,EAAE,6BAA6B,EAAE,MAAM,+CAA+C,CAAC"}
@@ -13,7 +13,7 @@ import { RouteDecorators } from "@rapidrest/service-core";
13
13
  import { DeviceSyncStateSQL } from "../models/sql/DeviceSyncStateSQL.js";
14
14
  import { BaseEasRoute } from "../BaseEasRoute.js";
15
15
  import { ProvisionCommand } from "../commands/ProvisionCommand.js";
16
- import { PingCommand } from "../commands/PingCommand.js";
16
+ import { PingCommandSQL } from "../commands/sql/PingCommandSQL.js";
17
17
  import { FolderSyncCommandSQL } from "../commands/sql/FolderSyncCommandSQL.js";
18
18
  import { SyncCommandSQL } from "../commands/sql/SyncCommandSQL.js";
19
19
  import { SendMailCommandSQL } from "../commands/sql/SendMailCommandSQL.js";
@@ -49,7 +49,7 @@ let EasRouteSQL = class EasRouteSQL extends BaseEasRoute {
49
49
  SearchCommandSQL,
50
50
  MeetingResponseCommandSQL,
51
51
  SettingsCommandSQL,
52
- PingCommand,
52
+ PingCommandSQL,
53
53
  GetItemEstimateCommandSQL,
54
54
  MoveItemsCommandSQL,
55
55
  ResolveRecipientsCommandSQL,
@@ -1 +1 @@
1
- {"version":3,"file":"EasRouteSQL.js","sourceRoot":"","sources":["../../../src/sql/EasRouteSQL.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAC7F,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;GAKG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,YAA4C;IAAtE;;QACO,yBAAoB,GAAQ,kBAAkB,CAAC;QAC/C,iBAAY,GAAQ,UAAU,CAAC;QAC/B,0BAAqB,GAAU;YACrC,gBAAgB;YAChB,oBAAoB;YACpB,cAAc;YACd,kBAAkB;YAClB,sBAAsB;YACtB,oBAAoB;YACpB,wBAAwB;YACxB,gBAAgB;YAChB,yBAAyB;YACzB,kBAAkB;YAClB,WAAW;YACX,yBAAyB;YACzB,mBAAmB;YACnB,2BAA2B;SAC9B,CAAC;IACN,CAAC;CAAA,CAAA;AAnBY,WAAW;IADvB,KAAK,CAAC,8BAA8B,CAAC;GACzB,WAAW,CAmBvB"}
1
+ {"version":3,"file":"EasRouteSQL.js","sourceRoot":"","sources":["../../../src/sql/EasRouteSQL.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,yBAAyB,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,gDAAgD,CAAC;AAC7F,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;GAKG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,YAA4C;IAAtE;;QACO,yBAAoB,GAAQ,kBAAkB,CAAC;QAC/C,iBAAY,GAAQ,UAAU,CAAC;QAC/B,0BAAqB,GAAU;YACrC,gBAAgB;YAChB,oBAAoB;YACpB,cAAc;YACd,kBAAkB;YAClB,sBAAsB;YACtB,oBAAoB;YACpB,wBAAwB;YACxB,gBAAgB;YAChB,yBAAyB;YACzB,kBAAkB;YAClB,cAAc;YACd,yBAAyB;YACzB,mBAAmB;YACnB,2BAA2B;SAC9B,CAAC;IACN,CAAC;CAAA,CAAA;AAnBY,WAAW;IADvB,KAAK,CAAC,8BAA8B,CAAC;GACzB,WAAW,CAmBvB"}
package/dist/lib/sql.js CHANGED
@@ -11,5 +11,7 @@
11
11
  export { EasRouteSQL } from "./sql/EasRouteSQL.js";
12
12
  export { DeviceSyncStateRouteSQL } from "./sql/DeviceSyncStateRouteSQL.js";
13
13
  export { DeviceSyncStateSQL } from "./models/sql/DeviceSyncStateSQL.js";
14
+ export { EasCollectionStateSQL } from "./models/sql/EasCollectionStateSQL.js";
15
+ export { EasCollectionChunkSQL } from "./models/sql/EasCollectionChunkSQL.js";
14
16
  export { EasDeviceStateCleanupJobSQL } from "./jobs/sql/EasDeviceStateCleanupJobSQL.js";
15
17
  //# sourceMappingURL=sql.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC"}
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC"}
@@ -12,6 +12,11 @@ import type { DeviceSyncState } from "./models/DeviceSyncState.js";
12
12
  * existing 449 gate, at which point `ProvisionCommand.issuePolicy` sees the flag and sends the device a
13
13
  * `RemoteWipe` directive instead of a normal policy document - no separate push/notification channel is needed.
14
14
  *
15
+ * **Scope**: a `DeviceSyncState` row is one (mailbox, client-supplied `DeviceId`) pairing, so the wipe and the block
16
+ * that follows its acknowledgement apply to that `DeviceId` only. A compliant client wipes itself; a client that
17
+ * ignores the directive can pair again under a different `DeviceId` with the same credentials. Cutting such a client
18
+ * off requires revoking the account's credentials - not something this route does.
19
+ *
15
20
  * `deviceSyncStateClass` is supplied by the Mongo/SQL concrete subclasses, the same one-line-per-backend
16
21
  * pattern used throughout this library.
17
22
  *
@@ -31,4 +36,9 @@ export declare abstract class BaseDeviceSyncStateRoute<D extends DeviceSyncState
31
36
  * the two.
32
37
  */
33
38
  remoteWipe(uid: string, req: HttpRequest, user?: JWTUser): Promise<D>;
39
+ /**
40
+ * Lets a device that acknowledged a remote wipe (`blocked`, see `ProvisionCommand`) connect again: it must still
41
+ * complete a fresh Provision handshake. Admin-only, like `remoteWipe`.
42
+ */
43
+ unblock(uid: string, user?: JWTUser): Promise<D>;
34
44
  }
@@ -2,6 +2,8 @@ import { type JWTUser } from "@rapidrest/core";
2
2
  import { HttpRequest, HttpResponse } from "@rapidrest/service-core";
3
3
  import { Mailbox } from "@rapidmx/restapi";
4
4
  import { DeviceSyncState } from "./models/DeviceSyncState.js";
5
+ /** Whether `deviceId` is an acceptable `DeviceId` (`DEVICE_ID_PATTERN`, and not one of `RESERVED_DEVICE_IDS`). */
6
+ export declare function isValidDeviceId(deviceId: string | undefined): deviceId is string;
5
7
  /**
6
8
  * Abstract base for the single fixed EAS endpoint (`POST /Microsoft-Server-ActiveSync` by MS-ASHTTP
7
9
  * convention, though the concrete path is left to the consuming application to mount via `@Route(...)` — see
@@ -15,10 +17,13 @@ import { DeviceSyncState } from "./models/DeviceSyncState.js";
15
17
  * deliberately does not implement itself — see the architecture plan's "Auth" section for the full reasoning
16
18
  * behind this choice over a per-request Basic Auth strategy.
17
19
  *
18
- * **Dispatch flow**: resolve the caller's own `Mailbox` (never a client-supplied one — `resolveCallerMailboxUid`,
19
- * the same helper `BaseSearchRoute` already uses), find-or-create that (mailbox, device) pair's
20
- * `DeviceSyncState`, enforce the provisioning gate, decode the WBXML request body (if any), dispatch to the
21
- * matching registered `EasCommandHandler`, bump `lastSyncAt`, and encode the handler's response back to WBXML.
20
+ * **Dispatch flow**: reject a body over `mail:eas:max_request_bytes` (413), resolve the caller's own `Mailbox` (never
21
+ * a client-supplied one `resolveCallerMailboxUid`), find-or-create that (mailbox, device) pair's `DeviceSyncState`,
22
+ * refuse a `blocked` device (one that acknowledged a remote wipe) with 403 for anything but `Provision` (which
23
+ * answers Status 129 itself), decode the WBXML request body (if any; malformed or over the decoder's element limits
24
+ * -> 400), enforce the provisioning gate (provisioned *and* presenting the stored policy key, else 449 - only
25
+ * `Provision` and a `Settings` request limited to `UserInformation`/`DeviceInformation` are exempt), dispatch to the matching registered
26
+ * `EasCommandHandler`, record `lastSyncAt` (best-effort), and encode the handler's response back to WBXML.
22
27
  *
23
28
  * **Command handlers** are supplied via `commandHandlerClasses` (empty by default — this class alone is just
24
29
  * the transport skeleton; concrete command support, e.g. `ProvisionCommand`/`FolderSyncCommand`, is added
@@ -49,6 +54,8 @@ export declare abstract class BaseEasRoute<D extends DeviceSyncState, M extends
49
54
  private deviceSyncStateRepo?;
50
55
  private mailboxRepo?;
51
56
  private readonly handlers;
57
+ /** Largest request body `dispatch()` accepts (HTTP 413 beyond it). */
58
+ private maxRequestBytes;
52
59
  private logger;
53
60
  init(): Promise<void>;
54
61
  /**
@@ -61,5 +68,9 @@ export declare abstract class BaseEasRoute<D extends DeviceSyncState, M extends
61
68
  */
62
69
  options(res: HttpResponse): Promise<void>;
63
70
  dispatch(req: HttpRequest, res: HttpResponse, user?: JWTUser): Promise<void>;
71
+ /** Decodes the WBXML request body, if any (malformed or over the decoder's element limits -> 400). */
72
+ private decodeRequest;
73
+ /** `Provision`, and a `Settings` request whose every element is one `SETTINGS_WITHOUT_PROVISIONING` allows. */
74
+ private exemptFromProvisioning;
64
75
  private findOrCreateDeviceSyncState;
65
76
  }
@@ -0,0 +1,47 @@
1
+ import type { ObjectFactory } from "@rapidrest/core";
2
+ import type { RepoUtils } from "@rapidrest/service-core";
3
+ import { AuditAction } from "@rapidmx/restapi";
4
+ import type { EasCommandContext } from "./EasCommandHandler.js";
5
+ /** What an `EasAuditLog` needs from the command using it. */
6
+ export interface EasAuditDependencies {
7
+ objectFactory: ObjectFactory;
8
+ /** The concrete `AuditLogEntry` class (`AuditLogEntryMongo`/`AuditLogEntrySQL`). */
9
+ auditLogClass: any;
10
+ mailboxRepo: RepoUtils<any>;
11
+ /** The whole configuration (`@Config()`), as restapi's routes pass it to `recordAuditLog()`. */
12
+ config?: any;
13
+ logger?: any;
14
+ }
15
+ /** One audited ActiveSync action against a mailbox. */
16
+ export interface EasAuditEntry {
17
+ action: AuditAction;
18
+ /** The mailbox whose content was read or deleted - only a mailbox the caller doesn't own is audited. */
19
+ mailboxUid: string;
20
+ targetType: string;
21
+ targetUid: string;
22
+ details?: Record<string, any>;
23
+ }
24
+ /**
25
+ * Audit entries for ActiveSync access to mail in a mailbox the caller doesn't own - an administrator reaching in
26
+ * through a trusted role, or a delegate working in a shared folder. It uses restapi's `recordAuditLog()` and
27
+ * `isNonOwnerAccess()`, as `BaseMessageRoute` does: REST records `MESSAGE_CONTENT_ACCESSED` for a non-owner content
28
+ * read and `MESSAGE_DELETE` for a delete.
29
+ *
30
+ * Built once per request. The caller's own mailbox (`ctx.mailboxUid`, resolved by `ownerUserUid`) is never audited
31
+ * and needs no lookup. Any other mailbox is loaded once. A mailbox that can't be loaded counts as non-owner, the
32
+ * defensive reading restapi's `content()` uses. Recording never throws: an audit failure is logged and the command
33
+ * goes on, like restapi's own best-effort persistence.
34
+ *
35
+ * Every entry's `details` carries `protocol: "ActiveSync"`, the command and the `DeviceId`.
36
+ */
37
+ export declare class EasAuditLog {
38
+ private readonly deps;
39
+ private readonly ctx;
40
+ private readonly command;
41
+ private readonly nonOwner;
42
+ constructor(deps: EasAuditDependencies, ctx: EasCommandContext, command: string);
43
+ /** Whether reading `mailboxUid`'s content is a non-owner access for this request's caller. */
44
+ isNonOwner(mailboxUid: string): Promise<boolean>;
45
+ /** Records `entry` when its mailbox isn't the caller's own. */
46
+ record(entry: EasAuditEntry): Promise<void>;
47
+ }
@@ -0,0 +1,60 @@
1
+ /** Releases an acquired lease. Never throws. */
2
+ export type LeaseRelease = () => Promise<void>;
3
+ export interface LeaseOptions {
4
+ /** Redis to hold the lease in across server copies (`datastores:cache`); in-process only without it. */
5
+ redisUrl?: string;
6
+ /** How long a Redis lease lives if its holder never releases it (a crashed server copy). While held, it's renewed
7
+ * every third of this. */
8
+ ttlMs: number;
9
+ /** How long to wait for a held lease before giving up. */
10
+ waitMs: number;
11
+ /** Delay between Redis acquisition attempts. */
12
+ pollMs?: number;
13
+ /** Longest a single Redis connect, `SET` or release may take before the lease fails open. The connect and the first
14
+ * `SET` always get all of it, however long the in-process wait took; a later `SET` while polling for another
15
+ * copy's key is also capped by `waitMs`'s deadline. */
16
+ redisTimeoutMs?: number;
17
+ }
18
+ /**
19
+ * A short exclusive lease on one key - `SyncCommand` holds one per (mailbox, device, folder) for the duration of a
20
+ * collection's round, so two concurrent `Sync`s of the same collection (a client retrying while its first request is
21
+ * still running, or two server copies) can't both read the same state, apply their commands and overwrite each
22
+ * other's result.
23
+ *
24
+ * Always taken in-process first (a per-key promise chain), then - when a Redis URL is configured - as a `SET NX PX`
25
+ * key shared by every server copy, released with a token check and renewed (token-checked `PEXPIRE`) every
26
+ * `ttlMs / 3` while held, so a round that outlasts `ttlMs` doesn't lose it to another copy.
27
+ *
28
+ * **Redis being unreachable fails open** to the in-process lease alone rather than refusing - or hanging - every
29
+ * `Sync`: the client is created with `disableOfflineQueue` (a command fails at once while disconnected instead of
30
+ * waiting in a queue) and a bounded `reconnectStrategy` (so `connect()` rejects instead of retrying forever), and
31
+ * every connect/`SET` is additionally raced against `redisTimeoutMs`. The connect and the first `SET` get the whole
32
+ * `redisTimeoutMs` even when the in-process wait already used up `waitMs` - otherwise a healthy Redis would get no time
33
+ * at all and the lease would fail open for nothing; only the polling `SET`s after Redis has answered are cut short by
34
+ * the deadline, which then means another copy still holds the key (`undefined`). A `SET` that times out but lands later
35
+ * is released again straight away. A client whose reconnects gave up is replaced on the next lease.
36
+ *
37
+ * **Release never hangs**: the token-checked release is raced against `redisTimeoutMs` too (the key expires on its
38
+ * own), and the in-process lease is freed whatever happens to it.
39
+ *
40
+ * @author Jean-Philippe Steinmetz
41
+ */
42
+ export declare class EasCollectionLease {
43
+ /** The in-process holder of each key: resolves once that holder releases. */
44
+ private static readonly local;
45
+ /** Shared command clients, keyed by Redis URL. */
46
+ private static readonly clients;
47
+ /** Forgets all process-wide state. Intended for tests. */
48
+ static resetSharedState(): void;
49
+ private static getClient;
50
+ private static forgetClient;
51
+ /** Waits for `key`'s in-process holder (if any) to release, up to `deadline`, then takes it over with `held` - the
52
+ * check and the take-over happen in the same tick, so two waiters can never both find the key free. `false` on
53
+ * timeout. */
54
+ private static takeLocal;
55
+ /**
56
+ * Acquires the lease on `key`, waiting up to `options.waitMs` for a current holder. Resolves with the release
57
+ * function, or `undefined` when the lease couldn't be acquired in time.
58
+ */
59
+ static acquire(key: string, options: LeaseOptions): Promise<LeaseRelease | undefined>;
60
+ }
@@ -0,0 +1,51 @@
1
+ import type { RepoUtils } from "@rapidrest/service-core";
2
+ import type { EasCollectionChunk } from "./models/EasCollectionChunk.js";
3
+ import type { EasCollectionState } from "./models/EasCollectionState.js";
4
+ /** Largest held set kept inline on the `EasCollectionState` row (`serverIds`) - past it the set moves to chunk rows. */
5
+ export declare const INLINE_HELD_LIMIT = 2000;
6
+ /** Most `ServerId`s one `EasCollectionChunk` row holds. */
7
+ export declare const HELD_CHUNK_SIZE = 2000;
8
+ /** Identifies one collection's rows. */
9
+ export interface CollectionKey {
10
+ mailboxUid: string;
11
+ deviceId: string;
12
+ folderUid: string;
13
+ }
14
+ type StoredChunk = EasCollectionChunk & {
15
+ uid: string;
16
+ version: number;
17
+ };
18
+ /** A collection's held set as loaded for one round, with the chunk rows it came from (empty while inline). */
19
+ export interface HeldSet {
20
+ ids: Set<string>;
21
+ chunks: StoredChunk[];
22
+ }
23
+ /** Everything the held-set functions need to reach the chunk rows. */
24
+ export interface ChunkStore {
25
+ repo: RepoUtils<any>;
26
+ chunkClass: any;
27
+ }
28
+ /**
29
+ * Loads the `ServerId`s a device holds for a collection: `state.serverIds` while the set is inline, otherwise every
30
+ * `EasCollectionChunk` row of the collection (read in pages, ordered by `chunkIndex`).
31
+ */
32
+ export declare function loadHeldSet(state: EasCollectionState | undefined, store: ChunkStore): Promise<HeldSet>;
33
+ /**
34
+ * Persists `ids` as the collection's new held set, given the `loaded` set the round started from, and returns the
35
+ * `serverIds`/`chunked` values the state row must be saved with.
36
+ *
37
+ * A set within `INLINE_HELD_LIMIT` that was never chunked stays inline (no chunk rows touched). Otherwise only the
38
+ * difference is written: each existing chunk drops the ids no longer held, new ids fill the free space of existing
39
+ * chunks before new chunks are appended, and only chunks whose content changed are updated (an emptied chunk is
40
+ * deleted) - a round that adds a window of items rewrites one or two chunks, never the whole set.
41
+ *
42
+ * Writes are not atomic with the state row: the caller must treat a failure here (or of the state row after this)
43
+ * as a lost round and make the device restart the collection.
44
+ */
45
+ export declare function saveHeldSet(key: CollectionKey, loaded: HeldSet, ids: Set<string>, wasChunked: boolean, store: ChunkStore): Promise<{
46
+ serverIds: string[];
47
+ chunked: boolean;
48
+ }>;
49
+ /** Removes every chunk row of a collection (a restart with `SyncKey 0`, or a forgotten device). */
50
+ export declare function clearHeldSet(key: CollectionKey, store: ChunkStore): Promise<void>;
51
+ export {};