@push.rocks/smartmta 8.1.0 → 8.2.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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-07-21 - 8.2.0
4
+
5
+ ### Features
6
+
7
+ - support permanent SMTP envelope rejections from accept hooks (routing)
8
+ - Add AcceptEnvelopeRejectionError so onAcceptEnvelope consumers can reject envelopes with custom 5xx SMTP responses.
9
+ - Handle policy rejections separately from infrastructure failures to avoid returning generic temporary failures.
10
+
11
+ ## 2026-07-21 - 8.1.1
12
+
13
+ ### Features
14
+
15
+ - add exact accepted-envelope dispatch for durable consumers
16
+ - Snapshot resolved per-recipient actions as immutable JSON-safe plans and replay them without consulting live routes.
17
+ - Scope parsed messages and SMTP sessions per envelope recipient while preserving the accepted raw RFC822 bytes unchanged.
18
+ - Queue forward, process, and deliver actions with durable deterministic idempotency keys and return their queue IDs.
19
+ - Persist bounded replay checkpoints through caller-managed storage; no filesystem persistence is introduced.
20
+ - Add backend-bounded prefix pagination and use it for convergent checkpoint and queue-tombstone cleanup.
21
+ - add exact accepted-envelope dispatch (accepted-envelope-dispatch)
22
+ - Snapshot resolved per-recipient actions as immutable JSON-safe plans for replay without consulting live routes.
23
+ - Queue forward, process, and deliver actions with deterministic durable idempotency keys and return queue IDs.
24
+ - Add accepted-envelope replay checkpoints with bounded cleanup backed by caller-managed storage.
25
+ - Introduce backend-bounded prefix pagination and use it for checkpoint and queue tombstone cleanup.
26
+
3
27
  ## 2026-07-21 - 8.1.0
4
28
 
5
29
  ### Features
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartmta',
6
- version: '8.1.0',
6
+ version: '8.2.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=
@@ -12,4 +12,5 @@ export declare const smartMtaCapabilities: Readonly<{
12
12
  readonly outboundAttachments: true;
13
13
  readonly topologyAwareSelfMx: true;
14
14
  readonly durableDeliveryFailureOutbox: true;
15
+ readonly exactAcceptedEnvelopeDispatch: true;
15
16
  }>;
package/dist_ts/index.js CHANGED
@@ -12,5 +12,6 @@ export const smartMtaCapabilities = Object.freeze({
12
12
  outboundAttachments: true,
13
13
  topologyAwareSelfMx: true,
14
14
  durableDeliveryFailureOutbox: true,
15
+ exactAcceptedEnvelopeDispatch: true,
15
16
  });
16
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVqRCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ2hELDBCQUEwQixFQUFFLElBQUk7SUFDaEMscUJBQXFCLEVBQUUsSUFBSTtJQUMzQiwwQkFBMEIsRUFBRSxJQUFJO0lBQ2hDLHFCQUFxQixFQUFFLElBQUk7SUFDM0Isb0JBQW9CLEVBQUUsSUFBSTtJQUMxQixpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLG1CQUFtQixFQUFFLElBQUk7SUFDekIsbUJBQW1CLEVBQUUsSUFBSTtJQUN6Qiw0QkFBNEIsRUFBRSxJQUFJO0NBQzFCLENBQUMsQ0FBQyJ9
17
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVqRCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ2hELDBCQUEwQixFQUFFLElBQUk7SUFDaEMscUJBQXFCLEVBQUUsSUFBSTtJQUMzQiwwQkFBMEIsRUFBRSxJQUFJO0lBQ2hDLHFCQUFxQixFQUFFLElBQUk7SUFDM0Isb0JBQW9CLEVBQUUsSUFBSTtJQUMxQixpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLG1CQUFtQixFQUFFLElBQUk7SUFDekIsbUJBQW1CLEVBQUUsSUFBSTtJQUN6Qiw0QkFBNEIsRUFBRSxJQUFJO0lBQ2xDLDZCQUE2QixFQUFFLElBQUk7Q0FDM0IsQ0FBQyxDQUFDIn0=
@@ -41,6 +41,10 @@ export interface IBounceOperation {
41
41
  */
42
42
  export interface IQueueItem {
43
43
  id: string;
44
+ /** Stable caller-supplied key used to make enqueue replay-safe. */
45
+ idempotencyKey?: string;
46
+ /** Fingerprint of the exact work associated with the idempotency key. */
47
+ idempotencyFingerprint?: string;
44
48
  processingMode: EmailProcessingMode;
45
49
  processingResult: Email;
46
50
  /** Materialized attachment count for queue/detail consumers. */
@@ -59,6 +63,7 @@ export interface IQueueItem {
59
63
  bounceOperations?: IBounceOperation[];
60
64
  smtpTransactions?: ISmtpTransactionAttempt[];
61
65
  }
66
+ export declare const ACCEPTED_ENVELOPE_IDEMPOTENCY_RETENTION_MS: number;
62
67
  export interface IQueueFailureOptions {
63
68
  /** Unknown failures default to retryable so temporary internal faults do not lose mail. */
64
69
  retryable?: boolean;
@@ -90,6 +95,14 @@ export interface IQueueOptions {
90
95
  baseRetryDelay?: number;
91
96
  maxRetryDelay?: number;
92
97
  }
98
+ export interface IQueueEnqueueOptions {
99
+ /** Stable key that resolves to one deterministic queue item id. */
100
+ idempotencyKey?: string;
101
+ /** Required with idempotencyKey to reject reuse for different work. */
102
+ idempotencyFingerprint?: string;
103
+ /** Fail closed unless the queue is backed by managed blob storage. */
104
+ requireDurable?: boolean;
105
+ }
93
106
  export interface IQueueStats {
94
107
  queueSize: number;
95
108
  status: {
@@ -123,12 +136,25 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
123
136
  private totalProcessed;
124
137
  private ownsManagedPrefix;
125
138
  private lifecycleState;
139
+ private readonly idempotentEnqueueFlights;
140
+ private idempotencyTombstoneCleanupCursor?;
126
141
  /**
127
142
  * Create a new unified delivery queue
128
143
  * @param options Queue options
129
144
  */
130
145
  constructor(options: IQueueOptions);
131
146
  private assertMutable;
147
+ /** Whether queue entries are committed through caller-managed blob storage. */
148
+ hasManagedStorage(): boolean;
149
+ /** Whether managed storage can list a backend-bounded page of keys. */
150
+ hasPaginatedManagedStorage(): boolean;
151
+ private idempotentQueueId;
152
+ private idempotencyTombstonePrefix;
153
+ private idempotencyTombstoneKey;
154
+ private readIdempotencyTombstone;
155
+ private parseIdempotencyTombstone;
156
+ private persistIdempotencyTombstone;
157
+ private cleanupExpiredIdempotencyTombstones;
132
158
  private createInitialRecipientStates;
133
159
  private createBounceOperationId;
134
160
  /**
@@ -157,7 +183,8 @@ export declare class UnifiedDeliveryQueue extends EventEmitter {
157
183
  * @param mode Processing mode
158
184
  * @param route Email route
159
185
  */
160
- enqueue(processingResult: Email, mode: EmailProcessingMode, route?: IEmailRoute): Promise<string>;
186
+ enqueue(processingResult: Email, mode: EmailProcessingMode, route?: IEmailRoute, enqueueOptions?: IQueueEnqueueOptions): Promise<string>;
187
+ private enqueueNew;
161
188
  /**
162
189
  * Get an item from the queue
163
190
  * @param id Item ID