@push.rocks/smartmta 9.4.1 → 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.
Files changed (35) hide show
  1. package/changelog.md +14 -0
  2. package/dist_rust/mailer-bin_linux_amd64 +0 -0
  3. package/dist_rust/mailer-bin_linux_arm64 +0 -0
  4. package/dist_ts/00_commitinfo_data.js +1 -1
  5. package/dist_ts/index.d.ts +1 -0
  6. package/dist_ts/index.js +2 -1
  7. package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +63 -2
  8. package/dist_ts/mail/delivery/classes.delivery.queue.js +749 -193
  9. package/dist_ts/mail/delivery/classes.delivery.system.d.ts +6 -0
  10. package/dist_ts/mail/delivery/classes.delivery.system.js +146 -62
  11. package/dist_ts/mail/delivery/functions.raw-email.d.ts +9 -0
  12. package/dist_ts/mail/delivery/functions.raw-email.js +85 -0
  13. package/dist_ts/mail/delivery/symbols.delivery.queue.d.ts +6 -0
  14. package/dist_ts/mail/delivery/symbols.delivery.queue.js +7 -0
  15. package/dist_ts/mail/index.d.ts +1 -0
  16. package/dist_ts/mail/index.js +1 -1
  17. package/dist_ts/mail/routing/classes.unified.email.server.d.ts +40 -0
  18. package/dist_ts/mail/routing/classes.unified.email.server.js +222 -76
  19. package/dist_ts/mail/routing/symbols.unified.email.server.d.ts +2 -0
  20. package/dist_ts/mail/routing/symbols.unified.email.server.js +3 -0
  21. package/dist_ts/security/classes.rustsecuritybridge.d.ts +11 -0
  22. package/dist_ts/security/classes.rustsecuritybridge.js +1 -1
  23. package/package.json +2 -2
  24. package/readme.hints.md +8 -0
  25. package/readme.md +34 -3
  26. package/ts/00_commitinfo_data.ts +1 -1
  27. package/ts/index.ts +1 -0
  28. package/ts/mail/delivery/classes.delivery.queue.ts +923 -226
  29. package/ts/mail/delivery/classes.delivery.system.ts +192 -80
  30. package/ts/mail/delivery/functions.raw-email.ts +111 -0
  31. package/ts/mail/delivery/symbols.delivery.queue.ts +6 -0
  32. package/ts/mail/index.ts +1 -0
  33. package/ts/mail/routing/classes.unified.email.server.ts +329 -85
  34. package/ts/mail/routing/symbols.unified.email.server.ts +6 -0
  35. package/ts/security/classes.rustsecuritybridge.ts +6 -0
package/changelog.md CHANGED
@@ -1,5 +1,19 @@
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
+
3
17
  ## 2026-07-27 - 9.4.1
4
18
 
5
19
  ### Fixes
Binary file
Binary file
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartmta',
6
- version: '9.4.1',
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=
@@ -15,4 +15,5 @@ export declare const smartMtaCapabilities: Readonly<{
15
15
  readonly exactAcceptedEnvelopeDispatch: true;
16
16
  readonly terminalLocalDeliverActions: true;
17
17
  readonly smtpAuthAccountsAndScopes: true;
18
+ readonly durableRawOutboundQueue: true;
18
19
  }>;
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVqRCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ2hELDBCQUEwQixFQUFFLElBQUk7SUFDaEMscUJBQXFCLEVBQUUsSUFBSTtJQUMzQiwwQkFBMEIsRUFBRSxJQUFJO0lBQ2hDLHFCQUFxQixFQUFFLElBQUk7SUFDM0Isb0JBQW9CLEVBQUUsSUFBSTtJQUMxQixpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLG1CQUFtQixFQUFFLElBQUk7SUFDekIsbUJBQW1CLEVBQUUsSUFBSTtJQUN6Qiw0QkFBNEIsRUFBRSxJQUFJO0lBQ2xDLDZCQUE2QixFQUFFLElBQUk7SUFDbkMsMkJBQTJCLEVBQUUsSUFBSTtJQUNqQyx5QkFBeUIsRUFBRSxJQUFJO0NBQ3ZCLENBQUMsQ0FBQyJ9
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVqRCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ2hELDBCQUEwQixFQUFFLElBQUk7SUFDaEMscUJBQXFCLEVBQUUsSUFBSTtJQUMzQiwwQkFBMEIsRUFBRSxJQUFJO0lBQ2hDLHFCQUFxQixFQUFFLElBQUk7SUFDM0Isb0JBQW9CLEVBQUUsSUFBSTtJQUMxQixpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLG1CQUFtQixFQUFFLElBQUk7SUFDekIsbUJBQW1CLEVBQUUsSUFBSTtJQUN6Qiw0QkFBNEIsRUFBRSxJQUFJO0lBQ2xDLDZCQUE2QixFQUFFLElBQUk7SUFDbkMsMkJBQTJCLEVBQUUsSUFBSTtJQUNqQyx5QkFBeUIsRUFBRSxJQUFJO0lBQy9CLHVCQUF1QixFQUFFLElBQUk7Q0FDckIsQ0FBQyxDQUFDIn0=
@@ -1,9 +1,11 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import type { IBlobStorageManager } from '../interfaces.storage.js';
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,26 +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;
136
158
  private processingScanPromise?;
137
159
  private processingRescanRequested;
138
- private processingScanShutdownTimeoutMs;
139
160
  private totalProcessed;
140
161
  private ownsManagedPrefix;
141
162
  private lifecycleState;
142
163
  private readonly idempotentEnqueueFlights;
143
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?;
144
177
  /**
145
178
  * Create a new unified delivery queue
146
179
  * @param options Queue options
147
180
  */
148
181
  constructor(options: IQueueOptions);
149
182
  private assertMutable;
183
+ private assertAcceptingNewItems;
184
+ private trackEnqueueFlight;
150
185
  /** Whether queue entries are committed through caller-managed blob storage. */
151
186
  hasManagedStorage(): boolean;
152
187
  /** Whether managed storage can list a backend-bounded page of keys. */
153
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;
154
195
  private idempotentQueueId;
155
196
  private idempotencyTombstonePrefix;
156
197
  private idempotencyTombstoneKey;
@@ -172,6 +213,7 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
172
213
  * Start queue processing
173
214
  */
174
215
  private startProcessing;
216
+ private runPeriodicCleanup;
175
217
  /**
176
218
  * Stop queue processing
177
219
  */
@@ -193,6 +235,10 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
193
235
  * @param route Email route
194
236
  */
195
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;
196
242
  private enqueueNew;
197
243
  /**
198
244
  * Get an item from the queue
@@ -253,8 +299,21 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
253
299
  removeItem(id: string): Promise<boolean>;
254
300
  private storageKey;
255
301
  private persistItem;
302
+ private persistCurrentItem;
256
303
  private serializeItem;
304
+ private withItemMutex;
257
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>;
258
317
  private removeItemFromStorage;
259
318
  private deserializeItem;
260
319
  private loadFromStorage;
@@ -283,4 +342,6 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
283
342
  * Shutdown the queue
284
343
  */
285
344
  shutdown(): Promise<void>;
345
+ private shutdownOnce;
286
346
  }
347
+ export {};