@serve.zone/dcrouter 34.7.0 → 34.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.
package/readme.md CHANGED
@@ -161,7 +161,7 @@ Bootstrap behavior:
161
161
  | `baseDir` | Root directory for dcrouter runtime data. Defaults to `~/.serve.zone/dcrouter`. |
162
162
  | `coreTrafficConfig` | Main CoreTraffic route configuration for HTTP/HTTPS/TCP/SNI traffic. `smartProxyConfig` remains accepted as a legacy alias. |
163
163
  | `emailConfig` | UnifiedEmailServer configuration: hostname, ports, domains, and mail routes. |
164
- | `emailOutboundMode` | Outbound SMTP mode. Defaults to `remoteIngress`; explicit `direct` mode lets unmanaged/static senders dial from the hub. |
164
+ | `emailOutboundMode` | Outbound SMTP mode; explicit `direct` mode lets unmanaged/static senders dial from the hub. With the database enabled it seeds the stored email settings on first start only; after that the stored settings are authoritative, they default to `remoteIngress`, and the mode changes through the email settings API or Ops UI. Without the database it is read directly on every delivery and has no default: while it is unset, outbound mail defers. |
165
165
  | `emailPortConfig` | External-to-internal email port mapping and received-email storage path. |
166
166
  | `tls` | Legacy/static TLS and ACME contact settings used to seed certificate config. |
167
167
  | `dnsNsDomains` | Nameserver hostnames used for generated NS records and DoH routes. A zone becomes authoritative by having its public NS records observed naming one of these. |
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '34.7.0',
6
+ version: '34.7.1',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -116,7 +116,13 @@ export interface IDcRouterOptions {
116
116
  /** SmartBucket configuration for durable SmartMTA queue and attachment blobs. */
117
117
  emailBlobStorage?: ISmartMtaBlobStorageConfig;
118
118
 
119
- /** Outbound SMTP connection mode. Defaults to direct unless DB settings override it. */
119
+ /**
120
+ * Outbound SMTP connection mode. With the database enabled it seeds the
121
+ * stored email settings on first start only; after that the stored settings
122
+ * are authoritative, and they default to `remoteIngress`. Without the
123
+ * database it is read directly on every delivery and has no default: while
124
+ * it is unset, outbound mail defers.
125
+ */
120
126
  emailOutboundMode?: TEmailOutboundMode;
121
127
 
122
128
  /**
@@ -149,6 +149,20 @@ const contractError = (
149
149
  ) satisfies plugins.servezoneInterfaces.data.ICoreMailErrorData,
150
150
  );
151
151
 
152
+ /**
153
+ * Whether a replayed envelope is the one the stored handoff was prepared with.
154
+ * Compares values, never encodings: the stored envelope is whatever the
155
+ * document store returns, and its key order is not part of the data. The
156
+ * recipient order is, as it is in the submission digest.
157
+ */
158
+ const isSameCoreMailEnvelope = (
159
+ storedArg: plugins.servezoneInterfaces.data.ICoreMailEnvelope,
160
+ replayedArg: plugins.servezoneInterfaces.data.ICoreMailEnvelope,
161
+ ): boolean =>
162
+ storedArg.mailFrom === replayedArg.mailFrom
163
+ && storedArg.rcptTo.length === replayedArg.rcptTo.length
164
+ && storedArg.rcptTo.every((recipientArg, indexArg) => recipientArg === replayedArg.rcptTo[indexArg]);
165
+
152
166
  /**
153
167
  * Answers a wire-9 request with the handler's own contract refusal: TypedRequest 9
154
168
  * answers an error of another class, TypedRequest 8's `TypedResponseError`
@@ -580,7 +594,7 @@ export class CoreMailGatewayManager {
580
594
  || existing.submissionDigest !== submissionDigest
581
595
  || existing.rawMimeSha256 !== message.rawMime.sha256
582
596
  || existing.rawMimeLengthBytes !== message.rawMime.lengthBytes
583
- || JSON.stringify(existing.envelope) !== JSON.stringify(message.envelope)
597
+ || !isSameCoreMailEnvelope(existing.envelope, message.envelope)
584
598
  ) {
585
599
  throw contractError('IDEMPOTENCY_CONFLICT');
586
600
  }
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '34.7.0',
6
+ version: '34.7.1',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }