@serve.zone/coremail 1.0.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 (75) hide show
  1. package/.smartconfig.json +50 -0
  2. package/changelog.md +10 -0
  3. package/cli.js +4 -0
  4. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  5. package/dist_ts/00_commitinfo_data.js +9 -0
  6. package/dist_ts/classes.auth.d.ts +45 -0
  7. package/dist_ts/classes.auth.js +204 -0
  8. package/dist_ts/classes.config.d.ts +2 -0
  9. package/dist_ts/classes.config.js +72 -0
  10. package/dist_ts/classes.coremail.d.ts +41 -0
  11. package/dist_ts/classes.coremail.js +155 -0
  12. package/dist_ts/classes.desiredstate.d.ts +40 -0
  13. package/dist_ts/classes.desiredstate.js +382 -0
  14. package/dist_ts/classes.gateway.d.ts +62 -0
  15. package/dist_ts/classes.gateway.js +669 -0
  16. package/dist_ts/classes.inbound.d.ts +49 -0
  17. package/dist_ts/classes.inbound.js +702 -0
  18. package/dist_ts/classes.maintenance.d.ts +16 -0
  19. package/dist_ts/classes.maintenance.js +339 -0
  20. package/dist_ts/classes.models.d.ts +161 -0
  21. package/dist_ts/classes.models.js +595 -0
  22. package/dist_ts/classes.server.d.ts +40 -0
  23. package/dist_ts/classes.server.js +309 -0
  24. package/dist_ts/classes.storage.d.ts +32 -0
  25. package/dist_ts/classes.storage.js +317 -0
  26. package/dist_ts/classes.submissions.d.ts +33 -0
  27. package/dist_ts/classes.submissions.js +385 -0
  28. package/dist_ts/classes.transfer.d.ts +41 -0
  29. package/dist_ts/classes.transfer.js +289 -0
  30. package/dist_ts/coremail.cursor.d.ts +20 -0
  31. package/dist_ts/coremail.cursor.js +191 -0
  32. package/dist_ts/coremail.log.d.ts +3 -0
  33. package/dist_ts/coremail.log.js +11 -0
  34. package/dist_ts/coremail.mime.d.ts +8 -0
  35. package/dist_ts/coremail.mime.js +63 -0
  36. package/dist_ts/coremail.persistence.d.ts +148 -0
  37. package/dist_ts/coremail.persistence.js +695 -0
  38. package/dist_ts/coremail.quota.d.ts +29 -0
  39. package/dist_ts/coremail.quota.js +149 -0
  40. package/dist_ts/coremail.selectors.d.ts +3 -0
  41. package/dist_ts/coremail.selectors.js +21 -0
  42. package/dist_ts/coremail.validation.d.ts +9 -0
  43. package/dist_ts/coremail.validation.js +325 -0
  44. package/dist_ts/index.d.ts +4 -0
  45. package/dist_ts/index.js +39 -0
  46. package/dist_ts/interfaces.d.ts +92 -0
  47. package/dist_ts/interfaces.js +2 -0
  48. package/dist_ts/plugins.d.ts +11 -0
  49. package/dist_ts/plugins.js +12 -0
  50. package/license.md +19 -0
  51. package/package.json +48 -0
  52. package/readme.md +199 -0
  53. package/ts/00_commitinfo_data.ts +8 -0
  54. package/ts/classes.auth.ts +321 -0
  55. package/ts/classes.config.ts +104 -0
  56. package/ts/classes.coremail.ts +249 -0
  57. package/ts/classes.desiredstate.ts +508 -0
  58. package/ts/classes.gateway.ts +811 -0
  59. package/ts/classes.inbound.ts +898 -0
  60. package/ts/classes.maintenance.ts +335 -0
  61. package/ts/classes.models.ts +530 -0
  62. package/ts/classes.server.ts +444 -0
  63. package/ts/classes.storage.ts +448 -0
  64. package/ts/classes.submissions.ts +554 -0
  65. package/ts/classes.transfer.ts +379 -0
  66. package/ts/coremail.cursor.ts +328 -0
  67. package/ts/coremail.log.ts +21 -0
  68. package/ts/coremail.mime.ts +94 -0
  69. package/ts/coremail.persistence.ts +1156 -0
  70. package/ts/coremail.quota.ts +214 -0
  71. package/ts/coremail.selectors.ts +35 -0
  72. package/ts/coremail.validation.ts +446 -0
  73. package/ts/index.ts +38 -0
  74. package/ts/interfaces.ts +109 -0
  75. package/ts/plugins.ts +11 -0
@@ -0,0 +1,16 @@
1
+ import type { ICoreMailModels } from './classes.models.js';
2
+ import type { CoreMailStorage } from './classes.storage.js';
3
+ export declare class CoreMailMaintenanceService {
4
+ private readonly models;
5
+ private readonly storage;
6
+ private readonly now;
7
+ private sweepTimer;
8
+ private sweepTask;
9
+ private sweepController;
10
+ constructor(models: ICoreMailModels, storage: CoreMailStorage, now?: () => number);
11
+ start(): void;
12
+ stop(): Promise<void>;
13
+ sweep(signalArg?: AbortSignal): Promise<void>;
14
+ private purgeSubmission;
15
+ private runSweep;
16
+ }
@@ -0,0 +1,339 @@
1
+ import * as plugins from './plugins.js';
2
+ import { logCoreMailFailure } from './coremail.log.js';
3
+ const sweepIntervalMs = 60_000;
4
+ const batchSize = 100;
5
+ const transferRetirementGraceMs = plugins.serveZoneInterfaces.data.coreMailLimits.transferGrantTtlMs
6
+ + plugins.serveZoneInterfaces.data.coreMailLimits.transferOverallTimeoutMs
7
+ + 2 * 60_000;
8
+ export class CoreMailMaintenanceService {
9
+ models;
10
+ storage;
11
+ now;
12
+ sweepTimer = null;
13
+ sweepTask = null;
14
+ sweepController = null;
15
+ constructor(models, storage, now = Date.now) {
16
+ this.models = models;
17
+ this.storage = storage;
18
+ this.now = now;
19
+ }
20
+ start() {
21
+ if (this.sweepTimer)
22
+ return;
23
+ this.sweepTimer = setInterval(() => {
24
+ void this.runSweep();
25
+ }, sweepIntervalMs);
26
+ this.sweepTimer.unref?.();
27
+ }
28
+ async stop() {
29
+ if (this.sweepTimer) {
30
+ clearInterval(this.sweepTimer);
31
+ this.sweepTimer = null;
32
+ }
33
+ this.sweepController?.abort();
34
+ await this.sweepTask?.catch(() => undefined);
35
+ }
36
+ async sweep(signalArg) {
37
+ const now = this.now();
38
+ const terminalOutboundCutoff = now
39
+ - plugins.serveZoneInterfaces.data.coreMailRetentionPolicy.terminalOutboundMs;
40
+ const acknowledgedInboundCutoff = now
41
+ - plugins.serveZoneInterfaces.data.coreMailRetentionPolicy.acknowledgedInboundMs;
42
+ const idempotencyReceiptCutoff = now
43
+ - plugins.serveZoneInterfaces.data.coreMailRetentionPolicy.idempotencyReceiptMs;
44
+ const expiredCapabilityCutoff = now
45
+ - plugins.serveZoneInterfaces.data.coreMailRetentionPolicy.expiredCapabilityMs;
46
+ const transferRetirementCutoff = now - transferRetirementGraceMs;
47
+ while (!signalArg?.aborted) {
48
+ const terminalSubmissions = await this.models.Submission.exact.findStored({
49
+ filter: {
50
+ state: { $in: ['delivered', 'failed', 'deadLettered'] },
51
+ terminalAt: { $lte: terminalOutboundCutoff },
52
+ $or: [
53
+ { retiringAt: { $exists: false } },
54
+ { retiringAt: { $lte: transferRetirementCutoff } },
55
+ ],
56
+ },
57
+ sort: { terminalAt: 1, submissionId: 1 },
58
+ limit: batchSize,
59
+ });
60
+ for (const submission of terminalSubmissions) {
61
+ signalArg?.throwIfAborted();
62
+ await this.purgeSubmission(submission, signalArg);
63
+ }
64
+ if (terminalSubmissions.length < batchSize)
65
+ break;
66
+ }
67
+ while (!signalArg?.aborted) {
68
+ const abandonedSubmissions = await this.models.Submission.exact.findStored({
69
+ filter: {
70
+ state: { $in: ['preparing', 'uploading', 'ready'] },
71
+ updatedAt: { $lte: idempotencyReceiptCutoff },
72
+ $or: [
73
+ { leaseExpiresAt: { $exists: false } },
74
+ { leaseExpiresAt: { $lte: now } },
75
+ ],
76
+ },
77
+ sort: { createdAt: 1, submissionId: 1 },
78
+ limit: batchSize,
79
+ });
80
+ for (const submission of abandonedSubmissions) {
81
+ signalArg?.throwIfAborted();
82
+ const retirement = await this.models.Submission.exact.transition({
83
+ current: submission,
84
+ change: (modelArg) => {
85
+ modelArg.state = 'failed';
86
+ modelArg.error = { code: 'STATE_CONFLICT', retryable: false };
87
+ modelArg.terminalAt = submission.updatedAt;
88
+ modelArg.retiringAt = now;
89
+ modelArg.updatedAt = now;
90
+ modelArg.revision += 1;
91
+ delete modelArg.nextAttemptAt;
92
+ delete modelArg.workerRetryAt;
93
+ delete modelArg.deliveredAt;
94
+ delete modelArg.leaseOwnerTaskId;
95
+ delete modelArg.leaseToken;
96
+ delete modelArg.leaseExpiresAt;
97
+ },
98
+ });
99
+ if (retirement.status !== 'transitioned')
100
+ continue;
101
+ }
102
+ if (abandonedSubmissions.length < batchSize)
103
+ break;
104
+ }
105
+ while (!signalArg?.aborted) {
106
+ const deliveries = await this.models.InboundDelivery.exact.findStored({
107
+ filter: {
108
+ state: 'acknowledged',
109
+ updatedAt: { $lte: acknowledgedInboundCutoff },
110
+ },
111
+ sort: { updatedAt: 1, deliveryId: 1 },
112
+ limit: batchSize,
113
+ });
114
+ for (const delivery of deliveries) {
115
+ signalArg?.throwIfAborted();
116
+ const retainedReferences = await this.models.InboundDelivery.exact.count({
117
+ rawMimeObjectKey: delivery.rawMimeObjectKey,
118
+ deliveryId: { $ne: delivery.deliveryId },
119
+ $or: [
120
+ { state: { $ne: 'acknowledged' } },
121
+ { updatedAt: { $gt: acknowledgedInboundCutoff } },
122
+ ],
123
+ });
124
+ if (retainedReferences === 0) {
125
+ await this.storage.purgeExact(delivery.rawMimeObjectKey, signalArg);
126
+ }
127
+ await this.models.InboundDelivery.exact.delete({ current: delivery });
128
+ }
129
+ if (deliveries.length < batchSize)
130
+ break;
131
+ }
132
+ let handoffCursor;
133
+ while (!signalArg?.aborted) {
134
+ const incompleteHandoffs = await this.models.InboundHandoff.exact.findStored({
135
+ filter: {
136
+ $and: [
137
+ {
138
+ $or: [
139
+ {
140
+ state: { $in: ['prepared', 'uploaded', 'failed'] },
141
+ updatedAt: { $lte: idempotencyReceiptCutoff },
142
+ },
143
+ {
144
+ state: 'retiring',
145
+ retiringAt: { $lte: transferRetirementCutoff },
146
+ },
147
+ ],
148
+ },
149
+ ...(handoffCursor
150
+ ? [{
151
+ $or: [
152
+ { createdAt: { $gt: handoffCursor.createdAt } },
153
+ {
154
+ createdAt: handoffCursor.createdAt,
155
+ handoffId: { $gt: handoffCursor.handoffId },
156
+ },
157
+ ],
158
+ }]
159
+ : []),
160
+ ],
161
+ },
162
+ sort: { createdAt: 1, handoffId: 1 },
163
+ limit: batchSize,
164
+ });
165
+ for (const handoff of incompleteHandoffs) {
166
+ signalArg?.throwIfAborted();
167
+ let retiringHandoff = handoff;
168
+ if (handoff.state !== 'retiring') {
169
+ const retirement = await this.models.InboundHandoff.exact.transition({
170
+ current: handoff,
171
+ change: (modelArg) => {
172
+ modelArg.state = 'retiring';
173
+ modelArg.retiringAt = now;
174
+ modelArg.updatedAt = now;
175
+ modelArg.revision += 1;
176
+ },
177
+ });
178
+ if (retirement.status !== 'transitioned')
179
+ continue;
180
+ continue;
181
+ }
182
+ const deliveryReferences = await this.models.InboundDelivery.exact.count({
183
+ rawMimeObjectKey: retiringHandoff.objectKey,
184
+ });
185
+ if (deliveryReferences === 0) {
186
+ await this.storage.purgeExact(retiringHandoff.objectKey, signalArg);
187
+ await this.models.InboundHandoff.exact.delete({ current: retiringHandoff });
188
+ }
189
+ }
190
+ const lastHandoff = incompleteHandoffs.at(-1);
191
+ if (!lastHandoff || incompleteHandoffs.length < batchSize)
192
+ break;
193
+ handoffCursor = {
194
+ createdAt: lastHandoff.createdAt,
195
+ handoffId: lastHandoff.handoffId,
196
+ };
197
+ }
198
+ while (!signalArg?.aborted) {
199
+ const completedHandoffs = await this.models.InboundHandoff.exact.findStored({
200
+ filter: {
201
+ state: 'completed',
202
+ completedAt: { $lte: idempotencyReceiptCutoff },
203
+ },
204
+ sort: { completedAt: 1, handoffId: 1 },
205
+ limit: batchSize,
206
+ });
207
+ for (const handoff of completedHandoffs) {
208
+ signalArg?.throwIfAborted();
209
+ await this.models.InboundHandoff.exact.delete({ current: handoff });
210
+ }
211
+ if (completedHandoffs.length < batchSize)
212
+ break;
213
+ }
214
+ while (!signalArg?.aborted) {
215
+ const activeState = await this.models.State.exact.findStoredOne({
216
+ stateId: 'active',
217
+ });
218
+ const snapshots = await this.models.DesiredSnapshot.exact.findStored({
219
+ filter: {
220
+ $or: [
221
+ {
222
+ state: { $in: ['staged', 'superseded', 'failed'] },
223
+ updatedAt: { $lte: idempotencyReceiptCutoff },
224
+ },
225
+ {
226
+ state: 'retiring',
227
+ retiringAt: { $lte: transferRetirementCutoff },
228
+ },
229
+ ],
230
+ ...(activeState ? { snapshotId: { $ne: activeState.snapshotId } } : {}),
231
+ },
232
+ sort: { createdAt: 1, snapshotId: 1 },
233
+ limit: batchSize,
234
+ });
235
+ for (const snapshot of snapshots) {
236
+ signalArg?.throwIfAborted();
237
+ let retiringSnapshot = snapshot;
238
+ if (snapshot.state !== 'retiring') {
239
+ const retirement = await this.models.DesiredSnapshot.exact.transition({
240
+ current: snapshot,
241
+ change: (modelArg) => {
242
+ modelArg.state = 'retiring';
243
+ modelArg.retiringAt = now;
244
+ modelArg.updatedAt = now;
245
+ },
246
+ });
247
+ if (retirement.status !== 'transitioned')
248
+ continue;
249
+ continue;
250
+ }
251
+ await this.storage.purgeExact(retiringSnapshot.objectKey, signalArg);
252
+ await this.models.DesiredSnapshot.exact.delete({ current: retiringSnapshot });
253
+ }
254
+ if (snapshots.length < batchSize)
255
+ break;
256
+ }
257
+ while (!signalArg?.aborted) {
258
+ const grants = await this.models.TransferGrant.exact.findStored({
259
+ filter: { expiresAt: { $lte: expiredCapabilityCutoff } },
260
+ sort: { expiresAt: 1, grantId: 1 },
261
+ limit: batchSize,
262
+ });
263
+ for (const grant of grants) {
264
+ signalArg?.throwIfAborted();
265
+ await this.models.TransferGrant.exact.delete({ current: grant });
266
+ }
267
+ if (grants.length < batchSize)
268
+ break;
269
+ }
270
+ while (!signalArg?.aborted) {
271
+ const handles = await this.models.RecipientHandle.exact.findStored({
272
+ filter: { expiresAt: { $lte: expiredCapabilityCutoff } },
273
+ sort: { expiresAt: 1, routingHandle: 1 },
274
+ limit: batchSize,
275
+ });
276
+ for (const handle of handles) {
277
+ signalArg?.throwIfAborted();
278
+ await this.models.RecipientHandle.exact.delete({ current: handle });
279
+ }
280
+ if (handles.length < batchSize)
281
+ break;
282
+ }
283
+ while (!signalArg?.aborted) {
284
+ const counters = await this.models.QuotaCounter.exact.findStored({
285
+ filter: {
286
+ updatedAt: { $lte: idempotencyReceiptCutoff },
287
+ $or: [{
288
+ kind: { $in: ['outbound-minute', 'outbound-day'] },
289
+ }, {
290
+ kind: 'pending-inbound',
291
+ count: 0,
292
+ }],
293
+ },
294
+ sort: { updatedAt: 1, counterId: 1 },
295
+ limit: batchSize,
296
+ });
297
+ for (const counter of counters) {
298
+ signalArg?.throwIfAborted();
299
+ await this.models.QuotaCounter.exact.delete({ current: counter });
300
+ }
301
+ if (counters.length < batchSize)
302
+ break;
303
+ }
304
+ }
305
+ async purgeSubmission(submissionArg, signalArg) {
306
+ const objectKeys = new Set(submissionArg.parts.map((partArg) => partArg.objectKey));
307
+ if (submissionArg.mimeObjectKey)
308
+ objectKeys.add(submissionArg.mimeObjectKey);
309
+ for (const objectKey of objectKeys) {
310
+ signalArg?.throwIfAborted();
311
+ await this.storage.purgeExact(objectKey, signalArg);
312
+ }
313
+ await this.models.Submission.exact.delete({ current: submissionArg });
314
+ }
315
+ async runSweep() {
316
+ if (this.sweepTask)
317
+ return await this.sweepTask;
318
+ const controller = new AbortController();
319
+ this.sweepController = controller;
320
+ const task = this.sweep(controller.signal).catch(async () => {
321
+ if (!controller.signal.aborted) {
322
+ await logCoreMailFailure('retention', 'SWEEP_FAILED').catch(() => undefined);
323
+ }
324
+ });
325
+ this.sweepTask = task;
326
+ try {
327
+ await task;
328
+ }
329
+ finally {
330
+ if (this.sweepTask === task) {
331
+ this.sweepTask = null;
332
+ }
333
+ if (this.sweepController === controller) {
334
+ this.sweepController = null;
335
+ }
336
+ }
337
+ }
338
+ }
339
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tYWludGVuYW5jZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMubWFpbnRlbmFuY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFHeEMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFdkQsTUFBTSxlQUFlLEdBQUcsTUFBTSxDQUFDO0FBQy9CLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQztBQUN0QixNQUFNLHlCQUF5QixHQUM3QixPQUFPLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxrQkFBa0I7TUFDaEUsT0FBTyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsd0JBQXdCO01BQ3hFLENBQUMsR0FBRyxNQUFNLENBQUM7QUFFZixNQUFNLE9BQU8sMEJBQTBCO0lBTWxCO0lBQ0E7SUFDQTtJQVBYLFVBQVUsR0FBMEMsSUFBSSxDQUFDO0lBQ3pELFNBQVMsR0FBeUIsSUFBSSxDQUFDO0lBQ3ZDLGVBQWUsR0FBMkIsSUFBSSxDQUFDO0lBRXZELFlBQ21CLE1BQXVCLEVBQ3ZCLE9BQXdCLEVBQ3hCLE1BQW9CLElBQUksQ0FBQyxHQUFHO1FBRjVCLFdBQU0sR0FBTixNQUFNLENBQWlCO1FBQ3ZCLFlBQU8sR0FBUCxPQUFPLENBQWlCO1FBQ3hCLFFBQUcsR0FBSCxHQUFHLENBQXlCO0lBQzVDLENBQUM7SUFFRyxLQUFLO1FBQ1YsSUFBSSxJQUFJLENBQUMsVUFBVTtZQUFFLE9BQU87UUFDNUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQ2pDLEtBQUssSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3ZCLENBQUMsRUFBRSxlQUFlLENBQUMsQ0FBQztRQUNwQixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUM7SUFDNUIs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
@@ -0,0 +1,161 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { ISubmissionPartRecord, TTransferGrantPurpose } from './interfaces.js';
3
+ import { type ICoreMailDesiredSnapshotRecord, type ICoreMailInboundDeliveryRecord, type ICoreMailInboundHandoffRecord, type ICoreMailQuotaCounterRecord, type ICoreMailRecipientHandleRecord, type ICoreMailStateRecord, type ICoreMailSubmissionRecord, type ICoreMailTransferGrantRecord } from './coremail.persistence.js';
4
+ type TCoreMailSha256 = plugins.serveZoneInterfaces.data.TCoreMailSha256;
5
+ export declare class CoreMailStateDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailStateDoc, ICoreMailStateRecord> implements ICoreMailStateRecord {
6
+ static exact: plugins.smartdata.TExact<CoreMailStateDoc>;
7
+ stateId: string;
8
+ appliedConfigEpoch: number;
9
+ appliedDesiredStateDigest: TCoreMailSha256;
10
+ snapshotId: string;
11
+ updatedAt: number;
12
+ }
13
+ export declare class CoreMailDesiredSnapshotDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailDesiredSnapshotDoc, ICoreMailDesiredSnapshotRecord> implements ICoreMailDesiredSnapshotRecord {
14
+ static exact: plugins.smartdata.TExact<CoreMailDesiredSnapshotDoc>;
15
+ snapshotId: string;
16
+ reconciliationId: string;
17
+ expectedAppliedConfigEpoch: number;
18
+ configEpoch: number;
19
+ desiredStateDigest: TCoreMailSha256;
20
+ lengthBytes: number;
21
+ objectKey: string;
22
+ state: 'staged' | 'active' | 'superseded' | 'failed' | 'retiring';
23
+ createdAt: number;
24
+ updatedAt: number;
25
+ activatedAt?: number;
26
+ retiringAt?: number;
27
+ errorCode?: plugins.serveZoneInterfaces.data.TCoreMailErrorCode;
28
+ }
29
+ export declare class CoreMailQuotaCounterDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailQuotaCounterDoc, ICoreMailQuotaCounterRecord> implements ICoreMailQuotaCounterRecord {
30
+ static exact: plugins.smartdata.TExact<CoreMailQuotaCounterDoc>;
31
+ counterId: TCoreMailSha256;
32
+ tenantId: string;
33
+ serviceId: string;
34
+ bindingId: string;
35
+ bindingRevision: number;
36
+ kind: ICoreMailQuotaCounterRecord['kind'];
37
+ windowStartedAt?: number;
38
+ count: number;
39
+ createdAt: number;
40
+ updatedAt: number;
41
+ }
42
+ export declare class CoreMailTransferGrantDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailTransferGrantDoc, ICoreMailTransferGrantRecord> implements ICoreMailTransferGrantRecord {
43
+ static exact: plugins.smartdata.TExact<CoreMailTransferGrantDoc>;
44
+ grantId: string;
45
+ authorityKind: 'control' | 'gateway' | 'workload';
46
+ tenantId: string;
47
+ serviceId: string;
48
+ bindingId: string;
49
+ purpose: TTransferGrantPurpose;
50
+ method: 'PUT' | 'GET';
51
+ path: string;
52
+ bearerSha256: TCoreMailSha256;
53
+ expectedSha256: TCoreMailSha256;
54
+ lengthBytes: number;
55
+ contentType: string;
56
+ objectKey: string;
57
+ state: 'issued' | 'transferring' | 'consumed' | 'failed' | 'expired';
58
+ expiresAt: number;
59
+ createdAt: number;
60
+ consumedAt?: number;
61
+ }
62
+ export declare class CoreMailSubmissionDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailSubmissionDoc, ICoreMailSubmissionRecord> implements ICoreMailSubmissionRecord {
63
+ static exact: plugins.smartdata.TExact<CoreMailSubmissionDoc>;
64
+ submissionId: string;
65
+ tenantId: string;
66
+ serviceId: string;
67
+ bindingId: string;
68
+ bindingRevision: number;
69
+ revision: number;
70
+ idempotencyKey: string;
71
+ submissionDigest: TCoreMailSha256;
72
+ state: plugins.serveZoneInterfaces.data.TCoreMailSubmissionState;
73
+ message: plugins.serveZoneInterfaces.data.ICoreMailOutboundMessageDescriptor;
74
+ parts: ISubmissionPartRecord[];
75
+ mimeObjectKey?: string;
76
+ mimeSha256?: TCoreMailSha256;
77
+ mimeLengthBytes?: number;
78
+ mimePublishedAt?: number;
79
+ transportMessageId?: string;
80
+ transportGrantId?: string;
81
+ gatewayStatusUpdatedAt?: number;
82
+ attempts: number;
83
+ nextAttemptAt?: number;
84
+ workerRetryAt?: number;
85
+ retiringAt?: number;
86
+ leaseOwnerTaskId?: string;
87
+ leaseToken?: string;
88
+ leaseExpiresAt?: number;
89
+ acceptedAt?: number;
90
+ deliveredAt?: number;
91
+ terminalAt?: number;
92
+ error?: plugins.serveZoneInterfaces.data.ICoreMailErrorData;
93
+ createdAt: number;
94
+ updatedAt: number;
95
+ }
96
+ export declare class CoreMailInboundDeliveryDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailInboundDeliveryDoc, ICoreMailInboundDeliveryRecord> implements ICoreMailInboundDeliveryRecord {
97
+ static exact: plugins.smartdata.TExact<CoreMailInboundDeliveryDoc>;
98
+ deliveryId: string;
99
+ tenantId: string;
100
+ serviceId: string;
101
+ bindingId: string;
102
+ bindingRevision: number;
103
+ revision: number;
104
+ transportDeliveryId: string;
105
+ state: plugins.serveZoneInterfaces.data.TCoreMailInboundDeliveryState;
106
+ envelope: plugins.serveZoneInterfaces.data.ICoreMailEnvelope;
107
+ rawMimeSha256: TCoreMailSha256;
108
+ rawMimeLengthBytes: number;
109
+ rawMimeObjectKey: string;
110
+ messageId?: string;
111
+ subject?: string;
112
+ receivedAt: number;
113
+ updatedAt: number;
114
+ fetchGrantId?: string;
115
+ acknowledgedOutcome?: plugins.serveZoneInterfaces.data.TCoreMailInboundAckOutcome;
116
+ }
117
+ export declare class CoreMailRecipientHandleDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailRecipientHandleDoc, ICoreMailRecipientHandleRecord> implements ICoreMailRecipientHandleRecord {
118
+ static exact: plugins.smartdata.TExact<CoreMailRecipientHandleDoc>;
119
+ routingHandle: string;
120
+ tenantId: string;
121
+ serviceId: string;
122
+ bindingId: string;
123
+ bindingRevision: number;
124
+ maxPendingInbound: number;
125
+ recipient: string;
126
+ envelopeDigest: TCoreMailSha256;
127
+ state: 'issued' | 'consumed' | 'expired';
128
+ handoffId?: string;
129
+ expiresAt: number;
130
+ createdAt: number;
131
+ }
132
+ export declare class CoreMailInboundHandoffDoc extends plugins.smartdata.SmartDataDbDoc<CoreMailInboundHandoffDoc, ICoreMailInboundHandoffRecord> implements ICoreMailInboundHandoffRecord {
133
+ static exact: plugins.smartdata.TExact<CoreMailInboundHandoffDoc>;
134
+ handoffId: string;
135
+ revision: number;
136
+ transportDeliveryId: string;
137
+ routingHandles: string[];
138
+ message: plugins.serveZoneInterfaces.data.ICoreMailGatewayMessageDescriptor;
139
+ source: plugins.serveZoneInterfaces.data.IMailConnectionInfo;
140
+ state: 'prepared' | 'uploaded' | 'completed' | 'failed' | 'retiring';
141
+ objectKey: string;
142
+ grantId?: string;
143
+ deliveryIds: string[];
144
+ createdAt: number;
145
+ updatedAt: number;
146
+ completedAt?: number;
147
+ retiringAt?: number;
148
+ }
149
+ export interface ICoreMailModels {
150
+ State: typeof CoreMailStateDoc;
151
+ DesiredSnapshot: typeof CoreMailDesiredSnapshotDoc;
152
+ QuotaCounter: typeof CoreMailQuotaCounterDoc;
153
+ TransferGrant: typeof CoreMailTransferGrantDoc;
154
+ Submission: typeof CoreMailSubmissionDoc;
155
+ InboundDelivery: typeof CoreMailInboundDeliveryDoc;
156
+ RecipientHandle: typeof CoreMailRecipientHandleDoc;
157
+ InboundHandoff: typeof CoreMailInboundHandoffDoc;
158
+ }
159
+ export declare const createCoreMailModels: (dbArg: plugins.smartdata.SmartdataDb) => ICoreMailModels;
160
+ export declare const prepareCoreMailModelsForTransactions: (modelsArg: ICoreMailModels) => Promise<void>;
161
+ export {};