@push.rocks/smartmta 9.4.0 → 9.5.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.
- package/changelog.md +23 -0
- package/dist_rust/mailer-bin_linux_amd64 +0 -0
- package/dist_rust/mailer-bin_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +71 -1
- package/dist_ts/mail/delivery/classes.delivery.queue.js +794 -179
- package/dist_ts/mail/delivery/classes.delivery.system.d.ts +11 -0
- package/dist_ts/mail/delivery/classes.delivery.system.js +206 -80
- package/dist_ts/mail/delivery/functions.raw-email.d.ts +9 -0
- package/dist_ts/mail/delivery/functions.raw-email.js +85 -0
- package/dist_ts/mail/delivery/symbols.delivery.queue.d.ts +6 -0
- package/dist_ts/mail/delivery/symbols.delivery.queue.js +7 -0
- package/dist_ts/mail/index.d.ts +1 -0
- package/dist_ts/mail/index.js +1 -1
- package/dist_ts/mail/routing/classes.unified.email.server.d.ts +40 -0
- package/dist_ts/mail/routing/classes.unified.email.server.js +222 -76
- package/dist_ts/mail/routing/symbols.unified.email.server.d.ts +2 -0
- package/dist_ts/mail/routing/symbols.unified.email.server.js +3 -0
- package/dist_ts/security/classes.rustsecuritybridge.d.ts +11 -0
- package/dist_ts/security/classes.rustsecuritybridge.js +1 -1
- package/package.json +2 -2
- package/readme.hints.md +8 -0
- package/readme.md +36 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +1 -0
- package/ts/mail/delivery/classes.delivery.queue.ts +969 -209
- package/ts/mail/delivery/classes.delivery.system.ts +254 -101
- package/ts/mail/delivery/functions.raw-email.ts +111 -0
- package/ts/mail/delivery/symbols.delivery.queue.ts +6 -0
- package/ts/mail/index.ts +1 -0
- package/ts/mail/routing/classes.unified.email.server.ts +329 -85
- package/ts/mail/routing/symbols.unified.email.server.ts +6 -0
- package/ts/security/classes.rustsecuritybridge.ts +6 -0
package/changelog.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-07-31 - 9.5.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- add a durable raw outbound MTA queue (raw-outbound)
|
|
8
|
+
- Add managed-only `UnifiedEmailServer.enqueueRawEmail()` with canonical CRLF-terminated exact RFC822 bytes, a separate canonical ordered SMTP envelope, stable idempotency, a 32 MiB default message limit, and a weighted global raw-operation memory budget.
|
|
9
|
+
- Store raw items as atomic schema V3 queue blobs while retaining only sanitized metadata in memory; preserve structured schema V2 writes and V1/V2 hydration unchanged.
|
|
10
|
+
- Serialize raw status mutations and removal per item, verify payload length/digest/envelope on every lazy reread, refuse processing-item removal, and fail closed on missing or corrupt payloads.
|
|
11
|
+
- Isolate all public queue/status snapshots, keep queue-only operations behind internal symbols, and route internal readiness by item ID so observers cannot mutate delivery inputs.
|
|
12
|
+
- Reuse MX, self-MX, recipient checkpoint, retry, bounce, RemoteIngress proxy/source-evidence, timeout, TLS, pooling, capture, and cleanup behavior for raw delivery.
|
|
13
|
+
- Extend Rust raw SMTP delivery with mandatory caller-supplied DKIM material, canonical-byte enforcement, and actual-sent-byte capture without UTF-8 conversion; keep unsigned queue bytes immutable across attempts and capture memory reserved through verification.
|
|
14
|
+
- Snapshot raw caller buffers synchronously, reserve queue capacity before persistence, share the weighted memory budget with direct raw sends, cap fixed raw-operation overhead, use bounded startup hydration, close outbound admission before shutdown, drain admitted enqueue/queue-scan/delivery/authentication work before storage and Rust teardown, and recover interrupted V3 records without dropping their payload.
|
|
15
|
+
- Add `smartMtaCapabilities.durableRawOutboundQueue` and document the schema V3 downgrade gate and deployment-wide single-writer prerequisite.
|
|
16
|
+
|
|
17
|
+
## 2026-07-27 - 9.4.1
|
|
18
|
+
|
|
19
|
+
### Fixes
|
|
20
|
+
|
|
21
|
+
- dispatch newly queued delivery items immediately (delivery)
|
|
22
|
+
- Wake the normal queue eligibility scan after durable enqueue, resume, delivery completion, and rate-limit reset while preserving pause and retry timing.
|
|
23
|
+
- Serialize queue scan wakeups and bound shutdown when an active itemsReady observer does not settle.
|
|
24
|
+
- Use a fixed one-minute rate-limit window to avoid false throttling on freshly started delivery processing.
|
|
25
|
+
|
|
3
26
|
## 2026-07-27 - 9.4.0
|
|
4
27
|
|
|
5
28
|
### Features
|
|
Binary file
|
|
Binary file
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartmta',
|
|
6
|
-
version: '9.
|
|
6
|
+
version: '9.5.0',
|
|
7
7
|
description: 'A high-performance, enterprise-grade Mail Transfer Agent (MTA) built from scratch in TypeScript with Rust acceleration.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHlIQUF5SDtDQUN2SSxDQUFBIn0=
|
package/dist_ts/index.d.ts
CHANGED
package/dist_ts/index.js
CHANGED
|
@@ -15,5 +15,6 @@ export const smartMtaCapabilities = Object.freeze({
|
|
|
15
15
|
exactAcceptedEnvelopeDispatch: true,
|
|
16
16
|
terminalLocalDeliverActions: true,
|
|
17
17
|
smtpAuthAccountsAndScopes: true,
|
|
18
|
+
durableRawOutboundQueue: true,
|
|
18
19
|
});
|
|
19
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVqRCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ2hELDBCQUEwQixFQUFFLElBQUk7SUFDaEMscUJBQXFCLEVBQUUsSUFBSTtJQUMzQiwwQkFBMEIsRUFBRSxJQUFJO0lBQ2hDLHFCQUFxQixFQUFFLElBQUk7SUFDM0Isb0JBQW9CLEVBQUUsSUFBSTtJQUMxQixpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLG1CQUFtQixFQUFFLElBQUk7SUFDekIsbUJBQW1CLEVBQUUsSUFBSTtJQUN6Qiw0QkFBNEIsRUFBRSxJQUFJO0lBQ2xDLDZCQUE2QixFQUFFLElBQUk7SUFDbkMsMkJBQTJCLEVBQUUsSUFBSTtJQUNqQyx5QkFBeUIsRUFBRSxJQUFJO0lBQy9CLHVCQUF1QixFQUFFLElBQUk7Q0FDckIsQ0FBQyxDQUFDIn0=
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import type
|
|
2
|
+
import { type IBlobStorageManager } from '../interfaces.storage.js';
|
|
3
3
|
import { type EmailProcessingMode } from './interfaces.js';
|
|
4
4
|
import type { ISmtpTransactionAttempt } from './interfaces.js';
|
|
5
5
|
import type { IEmailRoute } from '../routing/interfaces.js';
|
|
6
6
|
import { Email } from '../core/classes.email.js';
|
|
7
|
+
import { type IRawSmtpEnvelope } from './functions.raw-email.js';
|
|
8
|
+
import { kQueueCloseAdmission, kQueueCreateItemSnapshot, kQueueEnqueueRaw, kQueueReserveRawAccess, kQueueSetReadyItemsHandler, kQueueWithRawMessage } from './symbols.delivery.queue.js';
|
|
7
9
|
/**
|
|
8
10
|
* Queue item status
|
|
9
11
|
*/
|
|
@@ -47,6 +49,14 @@ export interface IQueueItem {
|
|
|
47
49
|
idempotencyFingerprint?: string;
|
|
48
50
|
processingMode: EmailProcessingMode;
|
|
49
51
|
processingResult: Email;
|
|
52
|
+
/** Present only for durable exact-byte outbound queue items. */
|
|
53
|
+
messageFormat?: 'raw-rfc822';
|
|
54
|
+
/** SHA-256 of the immutable unsigned RFC822 bytes. */
|
|
55
|
+
rawMessageSha256?: string;
|
|
56
|
+
/** Exact immutable unsigned RFC822 byte length. */
|
|
57
|
+
rawMessageLength?: number;
|
|
58
|
+
/** Canonical SMTP envelope, independent from message headers. */
|
|
59
|
+
smtpEnvelope?: IRawSmtpEnvelope;
|
|
50
60
|
/** Materialized attachment count for queue/detail consumers. */
|
|
51
61
|
attachmentCount?: number;
|
|
52
62
|
route?: IEmailRoute;
|
|
@@ -64,6 +74,8 @@ export interface IQueueItem {
|
|
|
64
74
|
smtpTransactions?: ISmtpTransactionAttempt[];
|
|
65
75
|
}
|
|
66
76
|
export declare const ACCEPTED_ENVELOPE_IDEMPOTENCY_RETENTION_MS: number;
|
|
77
|
+
export declare const DEFAULT_MAX_RAW_MESSAGE_BYTES: number;
|
|
78
|
+
export declare const DEFAULT_RAW_IN_FLIGHT_BYTE_BUDGET: number;
|
|
67
79
|
export interface IQueueFailureOptions {
|
|
68
80
|
/** Unknown failures default to retryable so temporary internal faults do not lose mail. */
|
|
69
81
|
retryable?: boolean;
|
|
@@ -91,6 +103,10 @@ export interface IQueueOptions {
|
|
|
91
103
|
checkInterval?: number;
|
|
92
104
|
maxQueueSize?: number;
|
|
93
105
|
maxPerDestination?: number;
|
|
106
|
+
/** Maximum exact RFC822 bytes accepted by enqueueRawEmail. Defaults to 32 MiB. */
|
|
107
|
+
maxRawMessageBytes?: number;
|
|
108
|
+
/** Conservative memory budget for active raw operations. Defaults to 192 MiB. */
|
|
109
|
+
rawInFlightByteBudget?: number;
|
|
94
110
|
maxRetries?: number;
|
|
95
111
|
baseRetryDelay?: number;
|
|
96
112
|
maxRetryDelay?: number;
|
|
@@ -103,6 +119,11 @@ export interface IQueueEnqueueOptions {
|
|
|
103
119
|
/** Fail closed unless the queue is backed by managed blob storage. */
|
|
104
120
|
requireDurable?: boolean;
|
|
105
121
|
}
|
|
122
|
+
interface IRawQueueEnqueueOptions {
|
|
123
|
+
rawMessage: Buffer;
|
|
124
|
+
envelope: IRawSmtpEnvelope;
|
|
125
|
+
idempotencyKey: string;
|
|
126
|
+
}
|
|
106
127
|
export interface IQueueStats {
|
|
107
128
|
queueSize: number;
|
|
108
129
|
status: {
|
|
@@ -131,23 +152,46 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
|
|
|
131
152
|
private queue;
|
|
132
153
|
private checkTimer?;
|
|
133
154
|
private cleanupTimer?;
|
|
155
|
+
private cleanupFlight?;
|
|
134
156
|
private stats;
|
|
135
157
|
private processing;
|
|
158
|
+
private processingScanPromise?;
|
|
159
|
+
private processingRescanRequested;
|
|
136
160
|
private totalProcessed;
|
|
137
161
|
private ownsManagedPrefix;
|
|
138
162
|
private lifecycleState;
|
|
139
163
|
private readonly idempotentEnqueueFlights;
|
|
140
164
|
private idempotencyTombstoneCleanupCursor?;
|
|
165
|
+
private readonly itemMutationFlights;
|
|
166
|
+
private rawBytesInFlight;
|
|
167
|
+
private rawByteWaiters;
|
|
168
|
+
private rawReservationCount;
|
|
169
|
+
private rawReservationDrainWaiters;
|
|
170
|
+
private readyItemsHandler?;
|
|
171
|
+
private acceptingNewItems;
|
|
172
|
+
private acceptingMutations;
|
|
173
|
+
private acceptingRawReservations;
|
|
174
|
+
private readonly enqueueFlights;
|
|
175
|
+
private pendingNewItemCount;
|
|
176
|
+
private shutdownFlight?;
|
|
141
177
|
/**
|
|
142
178
|
* Create a new unified delivery queue
|
|
143
179
|
* @param options Queue options
|
|
144
180
|
*/
|
|
145
181
|
constructor(options: IQueueOptions);
|
|
146
182
|
private assertMutable;
|
|
183
|
+
private assertAcceptingNewItems;
|
|
184
|
+
private trackEnqueueFlight;
|
|
147
185
|
/** Whether queue entries are committed through caller-managed blob storage. */
|
|
148
186
|
hasManagedStorage(): boolean;
|
|
149
187
|
/** Whether managed storage can list a backend-bounded page of keys. */
|
|
150
188
|
hasPaginatedManagedStorage(): boolean;
|
|
189
|
+
[kQueueCloseAdmission](): void;
|
|
190
|
+
[kQueueSetReadyItemsHandler](handlerArg?: (itemIds: string[]) => Promise<void>): void;
|
|
191
|
+
private cloneEmail;
|
|
192
|
+
[kQueueCreateItemSnapshot](itemArg: IQueueItem): IQueueItem;
|
|
193
|
+
private emitItemEventSafely;
|
|
194
|
+
private emitReadyItemsSafely;
|
|
151
195
|
private idempotentQueueId;
|
|
152
196
|
private idempotencyTombstonePrefix;
|
|
153
197
|
private idempotencyTombstoneKey;
|
|
@@ -169,6 +213,7 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
|
|
|
169
213
|
* Start queue processing
|
|
170
214
|
*/
|
|
171
215
|
private startProcessing;
|
|
216
|
+
private runPeriodicCleanup;
|
|
172
217
|
/**
|
|
173
218
|
* Stop queue processing
|
|
174
219
|
*/
|
|
@@ -177,6 +222,12 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
|
|
|
177
222
|
* Check for items that need to be processed
|
|
178
223
|
*/
|
|
179
224
|
private processQueue;
|
|
225
|
+
/**
|
|
226
|
+
* Wake the normal eligibility scan without bypassing pause or retry timing.
|
|
227
|
+
* The interval remains the recovery path for retries and any missed wakeup.
|
|
228
|
+
*/
|
|
229
|
+
wake(): void;
|
|
230
|
+
private runProcessingScans;
|
|
180
231
|
/**
|
|
181
232
|
* Add an item to the queue
|
|
182
233
|
* @param processingResult Processing result to queue
|
|
@@ -184,6 +235,10 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
|
|
|
184
235
|
* @param route Email route
|
|
185
236
|
*/
|
|
186
237
|
enqueue(processingResult: Email, mode: EmailProcessingMode, route?: IEmailRoute, enqueueOptions?: IQueueEnqueueOptions): Promise<string>;
|
|
238
|
+
private enqueueAccepted;
|
|
239
|
+
[kQueueEnqueueRaw](optionsArg: IRawQueueEnqueueOptions): Promise<string>;
|
|
240
|
+
private enqueueRawAccepted;
|
|
241
|
+
private enqueueIdempotent;
|
|
187
242
|
private enqueueNew;
|
|
188
243
|
/**
|
|
189
244
|
* Get an item from the queue
|
|
@@ -244,8 +299,21 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
|
|
|
244
299
|
removeItem(id: string): Promise<boolean>;
|
|
245
300
|
private storageKey;
|
|
246
301
|
private persistItem;
|
|
302
|
+
private persistCurrentItem;
|
|
247
303
|
private serializeItem;
|
|
304
|
+
private withItemMutex;
|
|
248
305
|
private applyPersistedMutation;
|
|
306
|
+
private createRawIntegrityError;
|
|
307
|
+
private readVerifiedRawMessage;
|
|
308
|
+
private claimRawReservation;
|
|
309
|
+
private createRawByteRelease;
|
|
310
|
+
private reserveRawBytes;
|
|
311
|
+
private reserveRawBytesImmediately;
|
|
312
|
+
[kQueueReserveRawAccess](rawMessageLengthArg: number): () => void;
|
|
313
|
+
private releaseRawBytes;
|
|
314
|
+
private withRawByteReservation;
|
|
315
|
+
private waitForRawReservationsToDrain;
|
|
316
|
+
[kQueueWithRawMessage]<T>(itemIdArg: string, callbackArg: (rawMessage: Buffer) => Promise<T>): Promise<T>;
|
|
249
317
|
private removeItemFromStorage;
|
|
250
318
|
private deserializeItem;
|
|
251
319
|
private loadFromStorage;
|
|
@@ -274,4 +342,6 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
|
|
|
274
342
|
* Shutdown the queue
|
|
275
343
|
*/
|
|
276
344
|
shutdown(): Promise<void>;
|
|
345
|
+
private shutdownOnce;
|
|
277
346
|
}
|
|
347
|
+
export {};
|