@serve.zone/dcrouter 17.6.1 → 17.7.1

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.
@@ -875,9 +875,11 @@ export class AcceptedEmailSpool {
875
875
  cachedEmail.status = 'deferred';
876
876
  cachedEmail.lastError = item.lastError || 'SmartMTA delivery deferred';
877
877
  const smartMtaNextAttempt = item.nextAttempt || new Date(Date.now() + ACCEPTED_EMAIL_RETRY_DELAY_MS);
878
+ cachedEmail.smartMtaNextAttempt = smartMtaNextAttempt;
878
879
  cachedEmail.nextAttempt = new Date(smartMtaNextAttempt.getTime() + ACCEPTED_EMAIL_QUEUE_LEASE_MS);
879
880
  } else {
880
881
  cachedEmail.status = 'queued';
882
+ cachedEmail.smartMtaNextAttempt = undefined;
881
883
  cachedEmail.nextAttempt = new Date(Date.now() + ACCEPTED_EMAIL_QUEUE_LEASE_MS);
882
884
  }
883
885
  await cachedEmail.save();
@@ -954,6 +956,7 @@ export class AcceptedEmailSpool {
954
956
  }
955
957
  this.updateSmartMtaRouteData(cachedEmail, queueItem, status);
956
958
  const smartMtaNextAttempt = queueItem.nextAttempt || new Date(Date.now() + ACCEPTED_EMAIL_RETRY_DELAY_MS);
959
+ cachedEmail.smartMtaNextAttempt = status === 'deferred' ? smartMtaNextAttempt : undefined;
957
960
  cachedEmail.nextAttempt = new Date(smartMtaNextAttempt.getTime() + ACCEPTED_EMAIL_QUEUE_LEASE_MS);
958
961
  await cachedEmail.save();
959
962
  await this.notifyEmailQueuePersisted(cachedEmail, 'email-live-queue-postponed');
package/ts/logger.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { SmartlogDestinationBuffer } from '@push.rocks/smartlog/destination-buffer';
4
+ import { DestinationLocal } from '@push.rocks/smartlog/destination-local';
4
5
 
5
6
  // Map NODE_ENV to valid TEnvironment
6
7
  const nodeEnv = process.env.NODE_ENV || 'production';
@@ -26,6 +27,11 @@ export const baseLogger = new plugins.smartlog.Smartlog({
26
27
  // Wire the buffer destination so all logs are captured
27
28
  baseLogger.addLogDestination(logBuffer);
28
29
 
30
+ // Also write to the process console: without this, dcrouter-level logs (e.g.
31
+ // RemoteIngress egress failures) exist only in the in-memory ops buffer and are
32
+ // invisible to process-manager log capture.
33
+ baseLogger.addLogDestination(new DestinationLocal());
34
+
29
35
  // Extended logger compatible with the original enhanced logger API
30
36
  class StandardLogger {
31
37
  private defaultContext: Record<string, any> = {};
@@ -180,9 +180,18 @@ export class EmailOpsHandler {
180
180
  const { headers, body } = this.parseRawEmail(rawContent);
181
181
  const session = this.parseCachedEmailSession(doc);
182
182
 
183
+ // Display SmartMTA's true retry schedule — doc.nextAttempt is the spool's
184
+ // recovery lease (retry time + 30min grace), not the user-facing countdown.
185
+ const nextAttemptMs = doc.smartMtaNextAttempt ? new Date(doc.smartMtaNextAttempt).getTime() : NaN;
183
186
  return {
184
187
  ...base,
185
188
  smtpTransactions: structuredClone(doc.smtpTransactions || []),
189
+ ...(base.status === 'deferred' && Number.isFinite(nextAttemptMs) && nextAttemptMs > 0
190
+ ? {
191
+ nextAttemptAt: nextAttemptMs,
192
+ nextAttemptNumber: (doc.attempts || 0) + 1,
193
+ }
194
+ : {}),
186
195
  toList: doc.to || [],
187
196
  cc: doc.cc || [],
188
197
  smtpLog: this.flattenSmtpTransactions(doc.smtpTransactions || []),
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '17.6.1',
6
+ version: '17.7.1',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }