@serve.zone/coremail 1.1.0 → 1.3.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 (57) hide show
  1. package/changelog.md +43 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.auth.d.ts +19 -0
  4. package/dist_ts/classes.auth.js +58 -1
  5. package/dist_ts/classes.coremail.d.ts +3 -0
  6. package/dist_ts/classes.coremail.js +11 -4
  7. package/dist_ts/classes.gateway.d.ts +11 -1
  8. package/dist_ts/classes.gateway.js +101 -63
  9. package/dist_ts/classes.inbound.d.ts +10 -1
  10. package/dist_ts/classes.inbound.js +45 -7
  11. package/dist_ts/classes.maintenance.js +16 -1
  12. package/dist_ts/classes.models.d.ts +24 -2
  13. package/dist_ts/classes.models.js +72 -2
  14. package/dist_ts/classes.server.d.ts +6 -2
  15. package/dist_ts/classes.server.js +18 -68
  16. package/dist_ts/classes.smtpsubmission.d.ts +85 -0
  17. package/dist_ts/classes.smtpsubmission.js +379 -0
  18. package/dist_ts/classes.storage.d.ts +9 -0
  19. package/dist_ts/classes.storage.js +44 -1
  20. package/dist_ts/classes.submissions.d.ts +27 -1
  21. package/dist_ts/classes.submissions.js +164 -14
  22. package/dist_ts/coremail.errors.d.ts +18 -0
  23. package/dist_ts/coremail.errors.js +84 -0
  24. package/dist_ts/coremail.log.d.ts +1 -1
  25. package/dist_ts/coremail.log.js +1 -1
  26. package/dist_ts/coremail.mime.d.ts +15 -0
  27. package/dist_ts/coremail.mime.js +76 -1
  28. package/dist_ts/coremail.persistence.d.ts +38 -1
  29. package/dist_ts/coremail.persistence.js +124 -40
  30. package/dist_ts/coremail.stats.d.ts +72 -0
  31. package/dist_ts/coremail.stats.js +242 -0
  32. package/dist_ts/coremail.validation.d.ts +15 -2
  33. package/dist_ts/coremail.validation.js +26 -78
  34. package/dist_ts/interfaces.d.ts +18 -0
  35. package/dist_ts/plugins.d.ts +1 -0
  36. package/dist_ts/plugins.js +2 -1
  37. package/package.json +12 -11
  38. package/readme.md +51 -2
  39. package/ts/00_commitinfo_data.ts +1 -1
  40. package/ts/classes.auth.ts +77 -0
  41. package/ts/classes.coremail.ts +20 -0
  42. package/ts/classes.gateway.ts +121 -66
  43. package/ts/classes.inbound.ts +71 -6
  44. package/ts/classes.maintenance.ts +14 -0
  45. package/ts/classes.models.ts +67 -1
  46. package/ts/classes.server.ts +23 -80
  47. package/ts/classes.smtpsubmission.ts +466 -0
  48. package/ts/classes.storage.ts +54 -0
  49. package/ts/classes.submissions.ts +247 -12
  50. package/ts/coremail.errors.ts +111 -0
  51. package/ts/coremail.log.ts +1 -0
  52. package/ts/coremail.mime.ts +89 -0
  53. package/ts/coremail.persistence.ts +196 -48
  54. package/ts/coremail.stats.ts +342 -0
  55. package/ts/coremail.validation.ts +31 -103
  56. package/ts/interfaces.ts +20 -0
  57. package/ts/plugins.ts +1 -0
@@ -0,0 +1,242 @@
1
+ import * as plugins from './plugins.js';
2
+ import { createSha256 } from './classes.storage.js';
3
+ import { coreMailStatKinds, } from './coremail.persistence.js';
4
+ const dayMs = 86_400_000;
5
+ /** How long a counted day is retained before the maintenance sweep drops it. */
6
+ export const coreMailStatRetentionMs = 90 * dayMs;
7
+ /**
8
+ * The counter row an event at `nowArg` belongs to.
9
+ *
10
+ * Counters are keyed by binding rather than binding revision: a revision bump
11
+ * is a configuration change, not a new tenant, and a day's totals must survive
12
+ * one.
13
+ */
14
+ export const createCoreMailStatDescriptor = (authorityArg, nowArg) => {
15
+ const dayUtc = Math.floor(nowArg / dayMs) * dayMs;
16
+ return {
17
+ tenantId: authorityArg.tenantId,
18
+ serviceId: authorityArg.serviceId,
19
+ bindingId: authorityArg.bindingId,
20
+ dayUtc,
21
+ statId: createSha256(JSON.stringify({
22
+ tenantId: authorityArg.tenantId,
23
+ serviceId: authorityArg.serviceId,
24
+ bindingId: authorityArg.bindingId,
25
+ dayUtc,
26
+ })),
27
+ };
28
+ };
29
+ const matchesDescriptor = (counterArg, descriptorArg) => counterArg.tenantId === descriptorArg.tenantId
30
+ && counterArg.serviceId === descriptorArg.serviceId
31
+ && counterArg.bindingId === descriptorArg.bindingId
32
+ && counterArg.dayUtc === descriptorArg.dayUtc;
33
+ /** Create the day's row if it does not exist yet. Safe to call concurrently. */
34
+ export const ensureCoreMailStatCounter = async (modelsArg, descriptorArg) => {
35
+ const existing = await modelsArg.StatCounter.exact.findStoredOne({
36
+ statId: descriptorArg.statId,
37
+ });
38
+ if (existing) {
39
+ if (!matchesDescriptor(existing, descriptorArg)) {
40
+ throw new Error('CoreMail stat counter identity conflicts with persisted state.');
41
+ }
42
+ return;
43
+ }
44
+ try {
45
+ const result = await modelsArg.StatCounter.exact.insert({
46
+ ...descriptorArg,
47
+ ...Object.fromEntries(coreMailStatKinds.map((kindArg) => [kindArg, 0])),
48
+ createdAt: descriptorArg.dayUtc,
49
+ updatedAt: descriptorArg.dayUtc,
50
+ });
51
+ if (result.status !== 'conflict') {
52
+ return;
53
+ }
54
+ }
55
+ catch (error) {
56
+ if (!(error instanceof plugins.smartdata.SmartdataExactPersistenceError)
57
+ || error.code !== 'unique_conflict') {
58
+ throw error;
59
+ }
60
+ }
61
+ const concurrent = await modelsArg.StatCounter.exact.findStoredOne({
62
+ statId: descriptorArg.statId,
63
+ });
64
+ if (!concurrent || !matchesDescriptor(concurrent, descriptorArg)) {
65
+ throw new Error('CoreMail stat counter identity conflicts with persisted state.');
66
+ }
67
+ };
68
+ /**
69
+ * Add one to a counter through the revision-fenced transition primitive, so
70
+ * the read and the write are one atomic compare-and-set. Call this inside the
71
+ * transaction that carries the counted state transition; then the event and
72
+ * its count commit together or not at all.
73
+ */
74
+ export const incrementCoreMailStatCounter = async (modelsArg, descriptorArg, kindArg, updatedAtArg, sessionArg) => {
75
+ const counter = await modelsArg.StatCounter.exact.findStoredOne({ statId: descriptorArg.statId }, sessionArg ? { session: sessionArg } : undefined);
76
+ if (!counter) {
77
+ throw new Error('CoreMail stat counter is unavailable.');
78
+ }
79
+ if (!matchesDescriptor(counter, descriptorArg)) {
80
+ throw new Error('CoreMail stat counter identity conflicts with persisted state.');
81
+ }
82
+ const update = await modelsArg.StatCounter.exact.transition({
83
+ current: counter,
84
+ change: (modelArg) => {
85
+ modelArg[kindArg] += 1;
86
+ modelArg.updatedAt = updatedAtArg;
87
+ },
88
+ }, sessionArg ? { session: sessionArg } : undefined);
89
+ if (update.status !== 'transitioned') {
90
+ throw new Error('CoreMail stat counter transition was contended.');
91
+ }
92
+ };
93
+ /**
94
+ * Ensure the day's row exists, then count one event on it.
95
+ *
96
+ * For a counted transition that runs inside a transaction, call
97
+ * `ensureCoreMailStatCounter` before opening it and
98
+ * `incrementCoreMailStatCounter` with the session inside it — the same order
99
+ * the quota counters use, so the row insert never contends with the
100
+ * transaction that increments it.
101
+ */
102
+ export const countCoreMailStat = async (modelsArg, authorityArg, kindArg, nowArg, sessionArg) => {
103
+ const descriptor = createCoreMailStatDescriptor(authorityArg, nowArg);
104
+ await ensureCoreMailStatCounter(modelsArg, descriptor);
105
+ await incrementCoreMailStatCounter(modelsArg, descriptor, kindArg, nowArg, sessionArg);
106
+ return descriptor;
107
+ };
108
+ /** Maximum rows one statistics page may return. */
109
+ export const coreMailStatPageMaximum = 200;
110
+ const dayPattern = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/;
111
+ /** `YYYY-MM-DD` to the UTC midnight milliseconds the counter rows are keyed by. */
112
+ export const parseCoreMailStatDay = (valueArg, labelArg) => {
113
+ if (typeof valueArg !== 'string' || !dayPattern.test(valueArg)) {
114
+ throw new Error(`CoreMail statistics ${labelArg} must be a YYYY-MM-DD day.`);
115
+ }
116
+ const parsed = Date.parse(`${valueArg}T00:00:00.000Z`);
117
+ if (!Number.isSafeInteger(parsed) || parsed % dayMs !== 0) {
118
+ throw new Error(`CoreMail statistics ${labelArg} must be a real UTC day.`);
119
+ }
120
+ return parsed;
121
+ };
122
+ export const formatCoreMailStatDay = (dayUtcArg) => new Date(dayUtcArg).toISOString().slice(0, 10);
123
+ /**
124
+ * Opaque composite cursor over `(dayUtc, statId)`.
125
+ *
126
+ * It carries no authority: the control session is what authorizes the read,
127
+ * and every filter is re-applied on the next page, so a replayed cursor can
128
+ * only ever resume the same ordered scan.
129
+ */
130
+ export const encodeCoreMailStatCursor = (positionArg) => Buffer.from(JSON.stringify({ v: 1, d: positionArg.dayUtc, s: positionArg.statId }), 'utf8').toString('base64url');
131
+ export const decodeCoreMailStatCursor = (valueArg) => {
132
+ if (typeof valueArg !== 'string'
133
+ || valueArg.length === 0
134
+ || valueArg.length
135
+ > plugins.serveZoneInterfaces.data.coreMailLimits.cursorBytes) {
136
+ throw new Error('CoreMail statistics cursor is invalid.');
137
+ }
138
+ let decoded;
139
+ try {
140
+ decoded = JSON.parse(Buffer.from(valueArg, 'base64url').toString('utf8'));
141
+ }
142
+ catch {
143
+ throw new Error('CoreMail statistics cursor is invalid.');
144
+ }
145
+ const record = decoded;
146
+ if (!record
147
+ || typeof record !== 'object'
148
+ || record.v !== 1
149
+ || !Number.isSafeInteger(record.d)
150
+ || Number(record.d) % dayMs !== 0
151
+ || typeof record.s !== 'string') {
152
+ throw new Error('CoreMail statistics cursor is invalid.');
153
+ }
154
+ try {
155
+ return {
156
+ dayUtc: Number(record.d),
157
+ statId: plugins.serveZoneInterfaces.data.normalizeCoreMailSha256(record.s),
158
+ };
159
+ }
160
+ catch {
161
+ throw new Error('CoreMail statistics cursor is invalid.');
162
+ }
163
+ };
164
+ /** Project one counter row onto the wire contract. */
165
+ export const toCoreMailServiceMailStatistics = (counterArg) => plugins.serveZoneInterfaces.data.normalizeCoreMailServiceMailStatistics({
166
+ tenantId: counterArg.tenantId,
167
+ serviceId: counterArg.serviceId,
168
+ bindingId: counterArg.bindingId,
169
+ dayUtc: formatCoreMailStatDay(counterArg.dayUtc),
170
+ outbound: {
171
+ submittedApi: counterArg.submittedApi,
172
+ submittedSmtp: counterArg.submittedSmtp,
173
+ delivered: counterArg.delivered,
174
+ deferred: counterArg.deferred,
175
+ failed: counterArg.failed,
176
+ deadLettered: counterArg.deadLettered,
177
+ },
178
+ inbound: {
179
+ received: counterArg.received,
180
+ acknowledgedProcessed: counterArg.acknowledgedProcessed,
181
+ acknowledgedDiscarded: counterArg.acknowledgedDiscarded,
182
+ },
183
+ updatedAt: counterArg.updatedAt,
184
+ });
185
+ /** One ordered, bounded page of per-service daily counters. */
186
+ export const listCoreMailServiceMailStatistics = async (modelsArg, requestArg) => {
187
+ const fromDayUtc = parseCoreMailStatDay(requestArg.fromDayUtc, 'fromDayUtc');
188
+ const toDayUtc = parseCoreMailStatDay(requestArg.toDayUtc, 'toDayUtc');
189
+ if (toDayUtc < fromDayUtc) {
190
+ throw new Error('CoreMail statistics range is inverted.');
191
+ }
192
+ if (!Number.isSafeInteger(requestArg.limit)
193
+ || requestArg.limit < 1
194
+ || requestArg.limit > coreMailStatPageMaximum) {
195
+ throw new Error(`CoreMail statistics limit must be between 1 and ${coreMailStatPageMaximum}.`);
196
+ }
197
+ let serviceIds;
198
+ if (requestArg.serviceIds !== undefined) {
199
+ if (!Array.isArray(requestArg.serviceIds)
200
+ || requestArg.serviceIds.length === 0
201
+ || requestArg.serviceIds.length > 1_000
202
+ || requestArg.serviceIds.some((entryArg) => typeof entryArg !== 'string')) {
203
+ throw new Error('CoreMail statistics serviceIds filter is invalid.');
204
+ }
205
+ serviceIds = [...new Set(requestArg.serviceIds)];
206
+ }
207
+ const cursor = requestArg.cursor === undefined
208
+ ? undefined
209
+ : decodeCoreMailStatCursor(requestArg.cursor);
210
+ const rows = await modelsArg.StatCounter.exact.findStored({
211
+ filter: {
212
+ $and: [
213
+ { dayUtc: { $gte: fromDayUtc, $lte: toDayUtc } },
214
+ ...(serviceIds ? [{ serviceId: { $in: serviceIds } }] : []),
215
+ ...(cursor
216
+ ? [{
217
+ $or: [
218
+ { dayUtc: { $gt: cursor.dayUtc } },
219
+ { dayUtc: cursor.dayUtc, statId: { $gt: cursor.statId } },
220
+ ],
221
+ }]
222
+ : []),
223
+ ],
224
+ },
225
+ sort: { dayUtc: 1, statId: 1 },
226
+ limit: requestArg.limit + 1,
227
+ });
228
+ const page = rows.slice(0, requestArg.limit);
229
+ const last = page.at(-1);
230
+ return {
231
+ statistics: page.map(toCoreMailServiceMailStatistics),
232
+ ...(rows.length > page.length && last
233
+ ? {
234
+ nextCursor: encodeCoreMailStatCursor({
235
+ dayUtc: last.dayUtc,
236
+ statId: last.statId,
237
+ }),
238
+ }
239
+ : {}),
240
+ };
241
+ };
242
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZW1haWwuc3RhdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jb3JlbWFpbC5zdGF0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxFQUNMLGlCQUFpQixHQUdsQixNQUFNLDJCQUEyQixDQUFDO0FBRW5DLE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQztBQUV6QixnRkFBZ0Y7QUFDaEYsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQztBQWFsRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBRyxDQUMxQyxZQUFvQyxFQUNwQyxNQUFjLEVBQ1csRUFBRTtJQUMzQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsR0FBRyxLQUFLLENBQUM7SUFDbEQsT0FBTztRQUNMLFFBQVEsRUFBRSxZQUFZLENBQUMsUUFBUTtRQUMvQixTQUFTLEVBQUUsWUFBWSxDQUFDLFNBQVM7UUFDakMsU0FBUyxFQUFFLFlBQVksQ0FBQyxTQUFTO1FBQ2pDLE1BQU07UUFDTixNQUFNLEVBQUUsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUM7WUFDbEMsUUFBUSxFQUFFLFlBQVksQ0FBQyxRQUFRO1lBQy9CLFNBQVMsRUFBRSxZQUFZLENBQUMsU0FBUztZQUNqQyxTQUFTLEVBQUUsWUFBWSxDQUFDLFNBQVM7WUFDakMsTUFBTTtTQUNQLENBQUMsQ0FBQztLQUNKLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLGlCQUFpQixHQUFHLENBQ3hCLFVBQXlFLEVBQ3pFLGFBQXNDLEVBQzdCLEVBQUUsQ0FDWCxVQUFVLENBQUMsUUFBUSxLQUFLLGFBQWEsQ0FBQyxRQUFRO09BQzND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
@@ -2,8 +2,21 @@ import * as plugins from './plugins.js';
2
2
  type TMessage = plugins.serveZoneInterfaces.data.ICoreMailOutboundMessageDescriptor;
3
3
  export declare const normalizeCoreMailMailboxAddress: (valueArg: unknown) => string;
4
4
  export declare const normalizeCoreMailEnvelope: (valueArg: unknown) => plugins.serveZoneInterfaces.data.ICoreMailEnvelope;
5
- export declare const normalizeCoreMailConnectionInfo: (valueArg: unknown) => plugins.serveZoneInterfaces.data.IMailConnectionInfo;
6
- export declare const normalizeCoreMailGatewayMessage: (valueArg: unknown) => plugins.serveZoneInterfaces.data.ICoreMailGatewayMessageDescriptor;
5
+ /**
6
+ * The single sender-authorization rule every outbound path applies: the
7
+ * envelope sender must be an exact member of the binding's allowed senders.
8
+ */
9
+ export declare const assertCoreMailSenderAllowed: (senderAddressArg: string, bindingArg: plugins.serveZoneInterfaces.data.ICoreMailBindingDesiredState) => void;
7
10
  export declare const normalizeCoreMailOutboundMessage: (valueArg: unknown, bindingArg: plugins.serveZoneInterfaces.data.ICoreMailBindingDesiredState) => TMessage;
11
+ /**
12
+ * Build the outbound message descriptor of an exact-byte SMTP submission.
13
+ *
14
+ * An SMTP submission has no CoreMail-composed body: the bytes are opaque and
15
+ * are owned by the immutable MIME tuple, so the descriptor carries only the
16
+ * SMTP envelope. `parts` is therefore empty, which is why such a descriptor is
17
+ * deliberately not routed through
18
+ * `normalizeCoreMailOutboundMessageDescriptor` (it requires at least one part).
19
+ */
20
+ export declare const createCoreMailRawOutboundMessage: (envelopeArg: plugins.serveZoneInterfaces.data.ICoreMailEnvelope) => TMessage;
8
21
  export declare const createCoreMailSubmissionDigest: (idempotencyKeyArg: string, messageArg: TMessage) => plugins.serveZoneInterfaces.data.TCoreMailSha256;
9
22
  export {};
@@ -63,90 +63,38 @@ export const normalizeCoreMailEnvelope = (valueArg) => {
63
63
  }
64
64
  return { mailFrom, rcptTo };
65
65
  };
66
- export const normalizeCoreMailConnectionInfo = (valueArg) => {
67
- const value = requirePlainRecord(valueArg, 'connectionInfo');
68
- requireExactKeys(value, ['protocol'], [
69
- 'remoteAddress',
70
- 'proxyAddress',
71
- 'heloName',
72
- 'tls',
73
- 'authUsername',
74
- 'authenticatedCredentialId',
75
- ], 'connectionInfo');
76
- if (value.protocol !== 'smtp'
77
- && value.protocol !== 'submission'
78
- && value.protocol !== 'api') {
79
- throw new Error('CoreMail gateway connection protocol is invalid.');
80
- }
81
- for (const key of [
82
- 'remoteAddress',
83
- 'proxyAddress',
84
- 'heloName',
85
- 'authUsername',
86
- 'authenticatedCredentialId',
87
- ]) {
88
- if (value[key] !== undefined
89
- && (typeof value[key] !== 'string'
90
- || value[key].length === 0
91
- || Buffer.byteLength(value[key], 'utf8') > 512
92
- || value[key].trim() !== value[key])) {
93
- throw new Error(`CoreMail gateway connection ${key} is invalid.`);
94
- }
95
- }
96
- if (value.tls !== undefined && typeof value.tls !== 'boolean') {
97
- throw new Error('CoreMail gateway connection TLS state is invalid.');
98
- }
99
- return {
100
- protocol: value.protocol,
101
- ...(value.remoteAddress === undefined
102
- ? {}
103
- : { remoteAddress: value.remoteAddress }),
104
- ...(value.proxyAddress === undefined
105
- ? {}
106
- : { proxyAddress: value.proxyAddress }),
107
- ...(value.heloName === undefined
108
- ? {}
109
- : { heloName: value.heloName }),
110
- ...(value.tls === undefined ? {} : { tls: value.tls }),
111
- ...(value.authUsername === undefined
112
- ? {}
113
- : { authUsername: value.authUsername }),
114
- ...(value.authenticatedCredentialId === undefined
115
- ? {}
116
- : {
117
- authenticatedCredentialId: value.authenticatedCredentialId,
118
- }),
119
- };
120
- };
121
- export const normalizeCoreMailGatewayMessage = (valueArg) => {
122
- const value = requirePlainRecord(valueArg, 'gatewayMessage');
123
- requireExactKeys(value, ['envelope', 'rawMime'], [], 'gatewayMessage');
124
- const rawMime = requirePlainRecord(value.rawMime, 'gatewayMessage.rawMime');
125
- requireExactKeys(rawMime, ['sha256', 'lengthBytes', 'contentType'], [], 'gatewayMessage.rawMime');
126
- if (rawMime.contentType !== 'message/rfc822'
127
- || !Number.isSafeInteger(rawMime.lengthBytes)
128
- || Number(rawMime.lengthBytes) < 1
129
- || Number(rawMime.lengthBytes)
130
- > plugins.serveZoneInterfaces.data.coreMailLimits.serializedMimeBytes) {
131
- throw new Error('CoreMail gateway MIME descriptor is invalid.');
66
+ /**
67
+ * The single sender-authorization rule every outbound path applies: the
68
+ * envelope sender must be an exact member of the binding's allowed senders.
69
+ */
70
+ export const assertCoreMailSenderAllowed = (senderAddressArg, bindingArg) => {
71
+ if (!bindingArg.allowedSenders.includes(senderAddressArg)) {
72
+ throw new Error('CoreMail sender is not authorized by the binding.');
132
73
  }
133
- return {
134
- envelope: normalizeCoreMailEnvelope(value.envelope),
135
- rawMime: {
136
- sha256: plugins.serveZoneInterfaces.data.normalizeCoreMailSha256(rawMime.sha256),
137
- lengthBytes: Number(rawMime.lengthBytes),
138
- contentType: 'message/rfc822',
139
- },
140
- };
141
74
  };
142
75
  export const normalizeCoreMailOutboundMessage = (valueArg, bindingArg) => {
143
76
  const message = plugins.serveZoneInterfaces.data
144
77
  .normalizeCoreMailOutboundMessageDescriptor(valueArg);
145
- if (!bindingArg.allowedSenders.includes(message.sender.address)) {
146
- throw new Error('CoreMail sender is not authorized by the binding.');
147
- }
78
+ assertCoreMailSenderAllowed(message.sender.address, bindingArg);
148
79
  return message;
149
80
  };
81
+ /**
82
+ * Build the outbound message descriptor of an exact-byte SMTP submission.
83
+ *
84
+ * An SMTP submission has no CoreMail-composed body: the bytes are opaque and
85
+ * are owned by the immutable MIME tuple, so the descriptor carries only the
86
+ * SMTP envelope. `parts` is therefore empty, which is why such a descriptor is
87
+ * deliberately not routed through
88
+ * `normalizeCoreMailOutboundMessageDescriptor` (it requires at least one part).
89
+ */
90
+ export const createCoreMailRawOutboundMessage = (envelopeArg) => ({
91
+ sender: { address: envelopeArg.mailFrom },
92
+ recipients: {
93
+ to: envelopeArg.rcptTo.map((recipientArg) => ({ address: recipientArg })),
94
+ },
95
+ subject: '',
96
+ parts: [],
97
+ });
150
98
  export const createCoreMailSubmissionDigest = (idempotencyKeyArg, messageArg) => {
151
99
  if (!idRegex.test(idempotencyKeyArg)) {
152
100
  throw new Error('CoreMail idempotency key is invalid.');
@@ -157,4 +105,4 @@ export const createCoreMailSubmissionDigest = (idempotencyKeyArg, messageArg) =>
157
105
  message: messageArg,
158
106
  }));
159
107
  };
160
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZW1haWwudmFsaWRhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NvcmVtYWlsLnZhbGlkYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBSXBELE1BQU0scUJBQXFCLEdBQUcsaUNBQWlDLENBQUM7QUFDaEUsTUFBTSx1QkFBdUIsR0FBRyx3Q0FBd0MsQ0FBQztBQUN6RSxNQUFNLE9BQU8sR0FBRyxxQ0FBcUMsQ0FBQztBQUV0RCxNQUFNLGtCQUFrQixHQUFHLENBQ3pCLFFBQWlCLEVBQ2pCLFFBQWdCLEVBQ1MsRUFBRTtJQUMzQixJQUNFLENBQUMsUUFBUTtXQUNOLE9BQU8sUUFBUSxLQUFLLFFBQVE7V0FDNUIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7V0FDdkIsQ0FDRCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTO2VBQ2pELE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEtBQUssSUFBSSxDQUM1QyxFQUNELENBQUM7UUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsUUFBUSwwQkFBMEIsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFDRCxPQUFPLFFBQW1DLENBQUM7QUFDN0MsQ0FBQyxDQUFDO0FBRUYsTUFBTSxnQkFBZ0IsR0FBRyxDQUN2QixTQUFrQyxFQUNsQyxXQUFxQixFQUNyQixXQUFxQixFQUNyQixRQUFnQixFQUNWLEVBQUU7SUFDUixNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsV0FBVyxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQztJQUMxRCxJQUNFLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFD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
108
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZW1haWwudmFsaWRhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NvcmVtYWlsLnZhbGlkYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBSXBELE1BQU0scUJBQXFCLEdBQUcsaUNBQWlDLENBQUM7QUFDaEUsTUFBTSx1QkFBdUIsR0FBRyx3Q0FBd0MsQ0FBQztBQUN6RSxNQUFNLE9BQU8sR0FBRyxxQ0FBcUMsQ0FBQztBQUV0RCxNQUFNLGtCQUFrQixHQUFHLENBQ3pCLFFBQWlCLEVBQ2pCLFFBQWdCLEVBQ1MsRUFBRTtJQUMzQixJQUNFLENBQUMsUUFBUTtXQUNOLE9BQU8sUUFBUSxLQUFLLFFBQVE7V0FDNUIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7V0FDdkIsQ0FDRCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTO2VBQ2pELE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEtBQUssSUFBSSxDQUM1QyxFQUNELENBQUM7UUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsUUFBUSwwQkFBMEIsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFDRCxPQUFPLFFBQW1DLENBQUM7QUFDN0MsQ0FBQyxDQUFDO0FBRUYsTUFBTSxnQkFBZ0IsR0FBRyxDQUN2QixTQUFrQyxFQUNsQyxXQUFxQixFQUNyQixXQUFxQixFQUNyQixRQUFnQixFQUNWLEVBQUU7SUFDUixNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsV0FBVyxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQztJQUMxRCxJQUNFLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFD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
@@ -56,6 +56,22 @@ export interface ITransferAuthority {
56
56
  serviceId: string;
57
57
  bindingId: string;
58
58
  }
59
+ /**
60
+ * How an outbound submission entered CoreMail. Records persisted before this
61
+ * discriminator existed carry no value and are read as 'api'.
62
+ */
63
+ export type TCoreMailSubmissionSource = 'api' | 'smtp';
64
+ /**
65
+ * Exact-byte SMTP submission handed to CoreMail by an authenticated MSA
66
+ * session. CoreMail never parses or rewrites `rawMime`.
67
+ */
68
+ export interface ICoreMailRawSubmissionInput {
69
+ envelope: {
70
+ from: string;
71
+ to: string[];
72
+ };
73
+ rawMime: Uint8Array;
74
+ }
59
75
  export interface ISubmissionPartRecord {
60
76
  partId: string;
61
77
  kind: plugins.serveZoneInterfaces.data.TCoreMailPartKind;
@@ -76,6 +92,8 @@ export interface ICoreMailReadiness {
76
92
  exactPurge: boolean;
77
93
  controlBootstrap: boolean;
78
94
  gateway: boolean;
95
+ /** False whenever the desired state asks for an SMTP listener that is not accepting submissions. */
96
+ smtpSubmission: boolean;
79
97
  }
80
98
  export interface ICoreMailAuthLimiterSnapshot {
81
99
  inFlight: number;
@@ -6,6 +6,7 @@ export * as projectinfo from '@push.rocks/projectinfo';
6
6
  export * as smartbucket from '@push.rocks/smartbucket';
7
7
  export * as smartdata from '@push.rocks/smartdata';
8
8
  export * as smartlog from '@push.rocks/smartlog';
9
+ export * as smartmta from '@push.rocks/smartmta';
9
10
  export * as serveZoneInterfaces from '@serve.zone/interfaces';
10
11
  export * as argon2 from 'argon2';
11
12
  export * as nodeCrypto from 'node:crypto';
@@ -6,7 +6,8 @@ export * as projectinfo from '@push.rocks/projectinfo';
6
6
  export * as smartbucket from '@push.rocks/smartbucket';
7
7
  export * as smartdata from '@push.rocks/smartdata';
8
8
  export * as smartlog from '@push.rocks/smartlog';
9
+ export * as smartmta from '@push.rocks/smartmta';
9
10
  export * as serveZoneInterfaces from '@serve.zone/interfaces';
10
11
  export * as argon2 from 'argon2';
11
12
  export * as nodeCrypto from 'node:crypto';
12
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLFlBQVksTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEtBQUssc0JBQXNCLE1BQU0scUNBQXFDLENBQUM7QUFDOUUsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssV0FBVyxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssU0FBUyxNQUFNLHVCQUF1QixDQUFDO0FBQ25ELE9BQU8sS0FBSyxRQUFRLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxLQUFLLG1CQUFtQixNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQ2pDLE9BQU8sS0FBSyxVQUFVLE1BQU0sYUFBYSxDQUFDIn0=
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLFlBQVksTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEtBQUssc0JBQXNCLE1BQU0scUNBQXFDLENBQUM7QUFDOUUsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssV0FBVyxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssU0FBUyxNQUFNLHVCQUF1QixDQUFDO0FBQ25ELE9BQU8sS0FBSyxRQUFRLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxLQUFLLFFBQVEsTUFBTSxzQkFBc0IsQ0FBQztBQUNqRCxPQUFPLEtBQUssbUJBQW1CLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxLQUFLLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDakMsT0FBTyxLQUFLLFVBQVUsTUFBTSxhQUFhLENBQUMifQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/coremail",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Authenticated mail persistence and delivery orchestration for serve.zone workloads.",
5
5
  "main": "dist_ts/index.js",
6
6
  "typings": "dist_ts/index.d.ts",
@@ -8,24 +8,25 @@
8
8
  "author": "Task Venture Capital GmbH",
9
9
  "license": "MIT",
10
10
  "devDependencies": {
11
- "@git.zone/tsbuild": "^4.4.2",
12
- "@git.zone/tsdocker": "^3.4.1",
11
+ "@git.zone/tsbuild": "^4.4.3",
12
+ "@git.zone/tsdocker": "^3.5.8",
13
13
  "@git.zone/tsrun": "^2.0.6",
14
- "@git.zone/tstest": "^3.6.7",
14
+ "@git.zone/tstest": "6.1.0",
15
15
  "@git.zone/tswatch": "^3.3.5",
16
- "@push.rocks/smartmongo": "^7.0.0",
17
- "@types/node": "^26.1.1"
16
+ "@push.rocks/smartmongo": "9.0.0",
17
+ "@types/node": "26.5.0"
18
18
  },
19
19
  "dependencies": {
20
- "@api.global/typedrequest": "^3.7.0",
21
- "@api.global/typedrequest-interfaces": "^4.0.0",
22
- "@api.global/typedserver": "^8.10.0",
23
- "@api.global/typedsocket": "^5.1.1",
20
+ "@api.global/typedrequest": "^8.0.4",
21
+ "@api.global/typedrequest-interfaces": "^7.1.0",
22
+ "@api.global/typedserver": "^11.4.1",
23
+ "@api.global/typedsocket": "^8.2.1",
24
24
  "@push.rocks/projectinfo": "^5.1.0",
25
25
  "@push.rocks/smartbucket": "^4.11.0",
26
26
  "@push.rocks/smartdata": "^10.4.0",
27
27
  "@push.rocks/smartlog": "^3.2.2",
28
- "@serve.zone/interfaces": "^23.0.4",
28
+ "@push.rocks/smartmta": "^9.6.1",
29
+ "@serve.zone/interfaces": "30.13.0",
29
30
  "argon2": "^0.45.1"
30
31
  },
31
32
  "files": [
package/readme.md CHANGED
@@ -11,6 +11,12 @@ needs to provision and reconcile bindings without proxying message traffic.
11
11
  pnpm add @serve.zone/coremail
12
12
  ```
13
13
 
14
+ CoreMail installs on Linux only. Its SMTP submission listener is built on
15
+ `@push.rocks/smartmta`, which declares `os: linux` and ships the prebuilt Rust
16
+ `mailer-bin` for `linux-x64` and `linux-arm64` — CoreMail's own runtime target.
17
+ Installing on macOS or Windows fails at the dependency, by design; develop
18
+ against a Linux container or host.
19
+
14
20
  The package exports the service lifecycle and its strict configuration reader:
15
21
 
16
22
  ```typescript
@@ -75,11 +81,19 @@ CoreMail enforces these boundaries:
75
81
  One strict hostname surface is exposed:
76
82
 
77
83
  - `GET /live` reports process liveness.
78
- - `GET /ready` reports database, exact object-storage, desired-state, and
79
- authenticated gateway readiness.
84
+ - `GET /ready` reports database, exact object-storage, desired-state,
85
+ authenticated gateway, and SMTP submission listener readiness.
80
86
  - `GET|PUT /transfers/:grantId` consumes one-time transfer capabilities.
81
87
  - `GET /socket` upgrades to the authenticated TypedSocket RPC transport.
82
88
 
89
+ When the desired state enables it, an SMTP submission listener (MSA) runs on
90
+ its own port. It offers `STARTTLS` and accepts `AUTH` only on an encrypted
91
+ session — the username is a `bindingId` and the password any accepted
92
+ credential secret of that binding. Accepted messages go straight to the durable
93
+ outbound pipeline as exact bytes; the embedded SMTP stack stores, queues and
94
+ forwards nothing. A listener whose certificate or private key material does not
95
+ resolve stays down and is reported unavailable.
96
+
83
97
  HTTP TypedRequest and built-in routes are disabled. WebSocket messages are
84
98
  limited to 64 KiB, unauthenticated connections have five seconds to complete
85
99
  their first authentication request, and HTTP connection/header/request
@@ -98,6 +112,13 @@ ready. Malformed startup configuration terminates
98
112
  startup. Missing desired-state secret references keep the affected gateway or
99
113
  cursor operation unavailable.
100
114
 
115
+ The SMTP submission listener is configured entirely through desired state
116
+ (`smtp`): `enabled`, `port`, `hostname`, and `tls.certificatePemSecretKey` /
117
+ `tls.privateKeyPemSecretKey`, which name runtime secret keys holding PEM text —
118
+ never the PEM values themselves. An omitted or disabled `smtp` section keeps the
119
+ API-only surface; an enabled one whose secret keys do not resolve leaves the
120
+ listener down. Changing any of these values restarts the listener in place.
121
+
101
122
  ```text
102
123
  /opt/serve.zone/runtime-assets/workloadinit/v1/workloadinit run \
103
124
  --map /run/serve.zone/workloadinit-map-v1.json -- node cli.js
@@ -140,6 +161,15 @@ header, publishes that MIME exactly once, and queues a lease-fenced worker.
140
161
  The downstream transport identity is the CoreMail submission ID and remains
141
162
  stable across ambiguous responses and retries.
142
163
 
164
+ Every outbound submission records how it entered CoreMail. API submissions are
165
+ composed from declared parts as described above. An SMTP submission is accepted
166
+ as exact RFC822 bytes: it has no part descriptors, its bytes become its
167
+ immutable MIME unchanged, and it enters the same lease-fenced worker in the same
168
+ state a finalized API submission does. It is subject to the same binding
169
+ authority, sender authorization, recipient validation, serialized-MIME byte
170
+ budget, and minute and day quota. Records written before this discriminator
171
+ existed are read as API submissions.
172
+
143
173
  Inbound SMTP recipient resolution returns short-lived opaque handles. The
144
174
  gateway uploads one immutable MIME object, after which CoreMail resumes a
145
175
  SmartData saga that consumes handles and creates one delivery per binding.
@@ -154,6 +184,25 @@ one-time grant, and may acknowledge only after the exact fetch completes.
154
184
  Cursor signatures rotate through current and bounded retiring desired-state
155
185
  keys without exposing runtime secret material.
156
186
 
187
+ Every gateway-facing handler answers with the same privacy-safe typed error
188
+ envelope the workload handlers use, so the transport can tell a retryable
189
+ `QUOTA_EXCEEDED` or `STATE_CONFLICT` from a permanent refusal without ever
190
+ receiving a cause string.
191
+
192
+ Inbound deliveries carry the `Message-ID` and `Subject` read from a bounded
193
+ prefix of the stored message. The gateway message descriptor cannot carry
194
+ either, and a header scan that fails never costs a delivery — the fields simply
195
+ stay absent.
196
+
197
+ Per-binding counters are kept for each UTC day: `submittedApi` and
198
+ `submittedSmtp` when a submission is published to the worker, `delivered`,
199
+ `deferred`, `failed` and `deadLettered` on outbound transitions, and `received`,
200
+ `acknowledgedProcessed` and `acknowledgedDiscarded` on inbound ones. Each
201
+ increment commits in the same transaction as the durable transition it counts,
202
+ so a replayed transition — a repeated finalization, a re-applied gateway status,
203
+ a replayed handoff completion or acknowledgement — counts nothing. Counter rows
204
+ are retained for 90 days.
205
+
157
206
  Desired-state activation uses immutable snapshots and a strictly increasing
158
207
  `configEpoch` compare-and-set pointer. Replayed or stale configurations cannot
159
208
  replace newer authority.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/coremail',
6
- version: '1.1.0',
6
+ version: '1.3.0',
7
7
  description: 'Authenticated mail persistence and delivery orchestration for serve.zone workloads.'
8
8
  }