arcane-os 0.15.2 → 0.16.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 +22 -0
- package/README.md +9 -1
- package/docs/reference/cli.md +44 -30
- package/docs/reference/mail.md +166 -67
- package/docs/reviews/mail-server-purpose-review.md +350 -0
- package/package.json +1 -1
- package/runtime/arcane/modules/Mail.js +42 -71
- package/runtime/arcane/modules/MailOutbox.mjs +5 -5
- package/runtime/arcane/modules/MailTransport.mjs +12 -21
- package/src/cli/main.mjs +14 -46
- package/src/mail-server.mjs +333 -617
- package/src/mail.mjs +50 -110
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
[Roshi's Codex PRIME] The method and action review is complete, and the inspected gateway implements the removals and simplifications below. Subscription verification now has a public optional callback: an omitted callback leaves the initial setup operational with `callerAuthentication: 'none'`; a configured callback selects `'subscription'` and controls admission before any provider attempt. The real TWiNStripeServer endpoint adapter comes later and does not block this delivery. Version `0.16.0` is selected; commit, package, and publication outcomes must be reported by the delivery owner when they actually occur.
|
|
2
|
+
|
|
3
|
+
| Decision | Behavior | Why it matters | Source status at this review |
|
|
4
|
+
| --- | --- | --- | --- |
|
|
5
|
+
| Remove | Loopback-only admission, manual header reconstruction, address/origin normalization, local payload grammar, manual content-length scan, dead queue knobs | These restrict supported use, rewrite supplied values, or repeat work already owned elsewhere. | Removed from the inspected source; naming-only changes carry no runtime claim. |
|
|
6
|
+
| Remove and replace | Local app-key hashes and X-Mail-Key authentication | The selected application plus bearer subscription contract needs an actual verifier, not a local shared-key comparison. | Removed. Optional `verifySubscription` implements the local integration contract; the remote endpoint adapter remains future work. Initial setup without that callback performs no caller authentication. |
|
|
7
|
+
| Simplify | Exact CORS policy, one configuration resolution, one provider request construction/serialization, optional observation | Preserve the intended result while eliminating repeated parsing, copies, policy structures, and absent-observer work. | Present in inspected source. Explicit nonempty origin lists remain authoritative; otherwise the nominal-domain default applies. |
|
|
8
|
+
| Keep | Configured subscription authentication, explicit recipient policy/fallback, stable idempotency, real cancellation/deadlines, complete provider outcomes, concurrent requests and owned shutdown | These have concrete callers and determine whether mail is sent, retried, reported honestly, or stopped correctly. | Retained. Only a verifier result of `true` permits authenticated delivery; failures and cancellation prevent the provider attempt. |
|
|
9
|
+
|
|
10
|
+
This review covers every named method, callback owner, constant, and significant action in `src/mail-server.mjs` at baseline `f055e05`, plus the coupled CLI/browser paths needed to preserve behavior. The current-source observations were reconciled on 2026-09-07. No runtime speedup, successful live mail delivery, completed source release, or subscription acceptance is claimed.
|
|
11
|
+
|
|
12
|
+
The intended software outcome is one complete mail request reaching the configured provider through the owning gateway, followed by an honest complete result. The gateway must preserve caller content, useful recipient policy, configured subscription authentication, explicit allowed-origin CORS behavior, caller cancellation, provider acceptance and uncertainty, and owned shutdown. It must use the published `node-http-server` interface and work on the selected host/domain without a loopback-only assumption. The initial unauthenticated setup is an implementation assumption stated to the user; no live deployment is selected in this work.
|
|
13
|
+
|
|
14
|
+
The user's three gates apply to the behavior, not to how impressive a helper name sounds:
|
|
15
|
+
|
|
16
|
+
1. **Care:** Does this behavior serve the intended mail outcome or an explicitly selected requirement?
|
|
17
|
+
2. **Benefit:** What concrete result makes its runtime and maintenance cost worthwhile?
|
|
18
|
+
3. **Removal:** Can the behavior or a redundant implementation step be removed without losing the required result and reduce work?
|
|
19
|
+
|
|
20
|
+
In the tables, `Y/Y/N` means keep the behavior; `Y/Y/Y` means simplify it by removing the identified redundant step; `N/N/Y` means remove the behavior. `Pending` identifies a real unresolved external contract or compatibility question, not an automatic delivery hold. Cost descriptions identify allocations, scans, calls, listeners, or waits that source removal eliminates; they are not timing measurements. A rename alone has no claimed runtime benefit. The tables state the current source name when behavior remains; recommendations and pending changes are marked explicitly. Existing public entry-point names remain stable unless the user expressly changes their contract.
|
|
21
|
+
|
|
22
|
+
The review sources are [the gateway](../../src/mail-server.mjs), [mail command orchestration](../../src/mail.mjs), [CLI server ownership](../../src/cli/main.mjs), [the portable transport](../../runtime/arcane/modules/MailTransport.mjs), [the browser Mail owner](../../runtime/arcane/modules/Mail.js), [the outbox's result consumers](../../runtime/arcane/modules/MailOutbox.mjs), and [the public mail reference](../reference/mail.md). Outbox storage, scheduling, maintenance methods, and unrelated SDK modules are outside this cleanup scope. Relevant test source was read as evidence of expected interfaces; tests were not executed.
|
|
23
|
+
|
|
24
|
+
Resend's send API accepts recipient strings or arrays, additional provider fields, and templates whose content rules differ from ordinary text/HTML messages. Its response includes a provider identifier. These are reasons to retain provider-boundary mapping while removing narrower gateway schemas. [Resend Send Email](https://resend.com/docs/api-reference/emails/send-email)
|
|
25
|
+
|
|
26
|
+
Resend idempotency keys associate retries with one request; changing the payload under the same key produces a conflict. Keys expire after 24 hours. Preserve the caller's key and one-attempt behavior rather than inventing gateway retries. [Resend Idempotency Keys](https://resend.com/docs/dashboard/emails/idempotency-keys)
|
|
27
|
+
|
|
28
|
+
The latest user-selected boundaries govern this review:
|
|
29
|
+
|
|
30
|
+
- A configured nonempty `allowedOrigins` list requires exact membership and rejection of other origins. Multiple domains on the same machine can share one mail server. Removing `normalizeOrigin` and `normalizeOrigins` does not remove that policy. Without an explicit list, the selected implementation admits the current request authority as an HTTP or HTTPS origin by direct comparison. This is the nominal-domain default, not permission to bypass an explicit list. A request without Origin is outside CORS; configured subscription authentication still applies.
|
|
31
|
+
- Binding and request acceptance must not be limited to numeric loopback. Host/domain selection belongs to actual configuration and the HTTP server owner.
|
|
32
|
+
- Node already supplies `headers` and `headersDistinct`. Do not reconstruct headers by scanning `rawHeaders`, coercing them through several fallback forms, or building another header parser.
|
|
33
|
+
- The selected final integration verifies each request's application and bearer subscription key through TWiNStripeServer's `verify-subscription` endpoint. The current delivery exposes optional `verifySubscription({appName, subscriptionKey, signal})`; omitting it reports `callerAuthentication: 'none'` and permits the initial setup, while supplying it reports `'subscription'`. `X-Mail-App` carries an ordinary application string; `Authorization: Bearer ...` replaces `X-Mail-Key`. Any application may use this server: there is no closed application list, app-slug grammar, or equality requirement against one server-wide app identity. The remote endpoint adapter is later work; no endpoint URL, remote request/response schema, cache policy, or token transformation has been guessed.
|
|
34
|
+
- Explicit recipient allowlists and error-recipient fallback remain. A configured nonempty allowlist covers resolved `to`, `cc`, and `bcc` recipients; allowing additional provider fields must not bypass the selected recipient policy. With no allowlist, the policy performs no recipient scan. Per-address trimming, lowercasing, and local email grammar do not remain.
|
|
35
|
+
- Caller-selected deadlines, the cancellation adapter, complete provider outcomes, retry classification, stable idempotency, and independently constructed snapshots for emitted observations remain. Shared mutable provider snapshots have not been selected.
|
|
36
|
+
- Remove manual response content-length scanning, duplicate configuration/CORS construction, unobserved event payload creation, unused `allowZero`, and unused CLI queue options.
|
|
37
|
+
|
|
38
|
+
Source inspection during this report's handoff shows local app/email/sender/API-key format validators and loopback admission removed; origin values retained in one Set; complete provider JSON values or raw response text preserved; template-shaped provider requests no longer required to supply local text/HTML fields; and configuration passed once into `createConfiguredMailHandler`. Observer objects, pending Sets, callback closures, event payload reconstruction, and drain waits are absent when `onEvent` is omitted. An already-cancelled direct send stops before provider payload construction or serialization. Response writing no longer calculates content length. The fixed `/v1/mail` route accepts its query-bearing form, matching the portable endpoint parser. These are source observations, not executed behavior.
|
|
39
|
+
|
|
40
|
+
The old `appKeyDigest`, `normalizeCallerAuthentication`, and `authenticateLocalCaller` implementations and their crypto imports are removed. The gateway's `verifyMailSubscription` uses Node's parsed headers and awaits the supplied verifier through the existing cancellation adapter. Only `true` accepts; a missing bearer credential or another return value produces 401, a verifier exception produces retryable 503, and cancellation during verification produces 408 without a provider attempt. Missing or ambiguous `X-Mail-App` uses the existing required-header 400 response. The callback receives the complete application and credential separately from report content. Its local result contract is implemented; remote subscription acceptance has not been exercised or claimed.
|
|
41
|
+
|
|
42
|
+
Configuration and foundational methods follow. Each baseline name is recorded so that a later rename cannot hide a removed behavior.
|
|
43
|
+
|
|
44
|
+
| Baseline method or callback owner | Caller and actual purpose | Gates and decision | Concrete cost, preservation requirement, and retained name |
|
|
45
|
+
| --- | --- | --- | --- |
|
|
46
|
+
| `MailGatewayFault.constructor` | Gateway parsers, provider classification, and response writer share error fields. | Y/Y/N — Keep. | One error record carries code, details, retryability, delay, HTTP status, and uncertainty. Removing it would scatter the existing response contract. Keep the public-facing error fields; class name may remain. |
|
|
47
|
+
| `configurationError` | Configuration readers create `ARCANE_MAIL_CONFIG_INVALID`. | Y/Y/N — Keep. | A small common error boundary gives callers an actionable configuration failure. Current name remains `configurationError`. |
|
|
48
|
+
| `completeErrorDetails` | Provider, verifier, and request failures expose complete available error detail. | Y/Y/N — Keep. | Error properties such as message and stack are not ordinarily enumerable. Current source also preserves native `Error.cause` and `AggregateError.errors` details. Do not reduce failures to a generic string. Current name remains `completeErrorDetails`; it returns a detail object, not JSON text. |
|
|
49
|
+
| New `reportMailError(message, error)` | `reportObserverFailure` and `closeResponseAfterHandlerFailure` share complete stderr diagnostics. | Y/Y/N — Keep. | Two real failure owners need the same output behavior. Native `inspect` uses `depth: null`, `maxArrayLength: null`, and `maxStringLength: null` so its ordinary depth/array/string clipping does not shorten errors before `console.error` writes them. Formatting and output occur only on failure; no new logging framework or security policy is introduced. |
|
|
50
|
+
| `positiveInteger` | Resolves the retry delay; baseline exposes unused `allowZero`. | Y/Y/Y — Simplify. | The uncalled zero branch and its extra option/prose are removed. Current name: `readRetryDelayMs`, which resolves the actual retry-delay setting. |
|
|
51
|
+
| `optionalTimeoutMs` | Reads body/provider deadlines only when supplied. | Y/Y/N — Keep. | Omitting a deadline produces no timer. Node timer-range handling prevents caller-selected delays from changing meaning. Current name remains `optionalTimeoutMs`. |
|
|
52
|
+
| `normalizeRetryAfter` | Error and result constructors keep a usable retry delay. | Y/Y/N — Keep. | Retry scheduling consumes this value. It is control metadata, not a transformation of message content. Current name: `retryDelayOrZero`. |
|
|
53
|
+
| `portNumber` | Startup resolves default or configured port, including ephemeral port zero. | Y/Y/Y — Remove wrapper; retain configuration value. | The HTTP owner handles actual port binding. Preserve default 8025 and explicit port zero; no extra port validator or domain policy is required. |
|
|
54
|
+
| `validateSignal` | Direct send and server options accept caller cancellation. | Y/Y/Y — Remove wrapper; retain original signal. | Native signal operations already own their contract. Cancellation controllers/listeners and the abortable adapter remain. |
|
|
55
|
+
| `validateApiKey` | Provider configuration supplies the credential used by Resend Fetch. | Y/Y/Y — Remove local format validator. | CLI credential retrieval reports missing provider credentials; Fetch/provider own actual transport validity. Never echo the credential. |
|
|
56
|
+
| `validateAppId` | Validates application identity using the old lowercase-slug grammar. | Y/Y/Y — Remove the grammar and closed-list/equality admission. | Per-request identity matters and remains an ordinary string. Any application may use the shared server. Read the supplied identity for subscription verification without rewriting it; no standalone wrapper is needed solely to restrict spelling. |
|
|
57
|
+
| `appKeyDigest` | Hashes the old local shared app key for comparison. | N/N/Y — Removed with old authentication. | Eliminates digest creation/storage and old shared-key machinery. No replacement local digest is needed. |
|
|
58
|
+
| `normalizeCallerAuthentication` | Chooses old app-key versus unauthenticated modes and prepares digest state. | N/N/Y for the old mechanism — Removed. | Configuration directly reports `'subscription'` when a verifier exists or `'none'` for initial setup. No authentication factory or digest configuration remains. The real remote adapter is separate later work. |
|
|
59
|
+
| `normalizedEmail` | Changes configured addresses and applies a local grammar. | N/N/Y — Remove. | Eliminates per-address trimming, lowercasing, pattern scans, and unintended changes. Keep configured addresses exactly. |
|
|
60
|
+
| `validateFrom` | Parses and reconstructs the configured sender display name/address. | Y/Y/Y — Simplify. | Sender selection matters; reconstructing its text does not. Preserve the exact configured sender and let Resend decide supported syntax. The local wrapper is removed; configured `from` is passed unchanged. |
|
|
61
|
+
| `normalizeEmailList` | Walks configured allowlist/fallback addresses through `normalizedEmail`. | Y/Y/Y — Simplify. | Keep the explicitly configured list and fallback; remove per-address rewriting and redundant array copies. The wrapper is removed; configuration reads the actual lists directly. |
|
|
62
|
+
| `normalizeOrigin` | Parses, trims, normalizes, and rejects one configured origin. | N/N/Y as a standalone wrapper — Remove. | Preserve configured origins and do exact membership once. With no list, the selected nominal-domain default uses direct HTTP/HTTPS authority comparison; no URL-normalization helper is needed. |
|
|
63
|
+
| `normalizeOrigins` | Repeats origin parsing, tracks duplicates in one Set, then creates another Set. | Y/Y/Y — Remove this wrapper and redundant structures. | One configured membership Set is sufficient; duplicate entries do not need a separate rejection pass. A nonempty explicit list remains authoritative. |
|
|
64
|
+
| `validateLoopbackHost` | Rejects hosts other than two numeric loopback forms. | N/N/Y — Remove. | It prevents the selected hosted/domain use. Let configured host and upstream listener determine binding. |
|
|
65
|
+
| `normalizeConfiguration` | Resolves all server settings, dependencies, policy, and old auth state. | Y/Y/Y — Simplify and rename. | The baseline ran it twice. Current `resolveMailServerConfiguration` resolves once and passes its result into `createConfiguredMailHandler`. |
|
|
66
|
+
| `errorRecipientIsNotAllowed` | Eagerly checks configured fallback recipients against an explicit allowlist. | Y/Y/Y — Remove duplicate startup scan; keep policy at delivery. | `resolveReportRecipients` applies the same actual allowlist to selected fallback recipients before sending. No case rewriting. |
|
|
67
|
+
| `createRequestId` | Correlates diagnostics and public responses; fallback avoids losing an error response if the factory fails. | Y/Y/N — Keep current compatibility; broader grammar relaxation is deferred. | Current name remains `createRequestId`. Browser transport, native response parsing and outbox still require the current request-ID form. Preserve it until a complete coupled-consumer change is traced; no partial relaxation is implemented. |
|
|
68
|
+
| `isNumericLoopback` | Supports binding/request socket restrictions. | N/N/Y — Remove. | Its callers disappear with loopback-only admission. No replacement hostname heuristic is needed. |
|
|
69
|
+
|
|
70
|
+
HTTP headers, CORS, response writing, and observation follow.
|
|
71
|
+
|
|
72
|
+
| Baseline method or callback owner | Caller and actual purpose | Gates and decision | Concrete cost, preservation requirement, and retained name |
|
|
73
|
+
| --- | --- | --- | --- |
|
|
74
|
+
| `headerValues` | `singleHeader` and old authentication reconstruct headers from three representations. | N/N/Y — Remove. | Eliminate `rawHeaders` scans, string coercion, fallback arrays, and duplicate platform parsing. Read Node's `headers`/`headersDistinct` directly where needed. |
|
|
75
|
+
| `stringifyDistinctHeader` | Maps already-parsed distinct headers through `String`. | N/N/Y — Remove. | Node owns parsed header representation. This array copy adds no mail behavior. |
|
|
76
|
+
| `singleHeader` | Enforces a one-value rule for every header access. | Y/Y/Y — Simplify to actual required headers. | Current `requireRequestHeader` reads Node's `headersDistinct` directly for the nonempty idempotency key and the configured verifier's application identity. Bearer extraction also uses the platform's distinct-header array. No general raw-header reconstruction or metadata parser remains. |
|
|
77
|
+
| `validateLoopbackRequest` | Checks socket addresses, parses Host, reconstructs authority, and demands exact loopback spelling/port. | N/N/Y — Remove. | Eliminates socket-policy checks, URL parsing, and authority reconstruction that block domain-hosted operation. |
|
|
78
|
+
| `allowedOrigin` | Requires request Origin membership in configured allowed origins. | Y/Y/Y — Keep policy, inline its simple decision. | A nonempty explicit list performs one exact Set lookup and rejects other origins. Without a list, direct comparison against the request's HTTP/HTTPS authority implements the nominal-domain default. No Origin means no CORS decision; authentication still applies. |
|
|
79
|
+
| `authenticateLocalCaller` | Compares the old X-Mail-Key digest and handles its old bypass mode. | Y/Y/Y — Replaced. | Current `verifyMailSubscription` reads the application and bearer credential, invokes the configured verifier, and stops rejected, failed, or cancelled verification before provider delivery. No local-key comparison remains. Omitting the verifier is the explicitly described initial setup, not a claim of verified subscription. |
|
|
80
|
+
| New `verifyMailSubscription` and configured `verifySubscription` callback | `handleMailRequest` invokes this owner only when configured. | Y/Y/N — Keep the actual authentication integration. | `verifySubscription({appName, subscriptionKey, signal})` receives separate control fields. Only `true` permits delivery; false/nontrue is 401, exceptions are retryable 503, and cancellation is 408 with no provider attempt. The existing abortable-wait adapter handles a callback that ignores cancellation. No guessed remote request schema or new factory is introduced. |
|
|
81
|
+
| `corsHeaders` | Supplies browser permissions for allowed origin, method, request headers, and Retry-After visibility. | Y/Y/N — Keep, update header names. | Browser calls need this. Include `Authorization` in place of `X-Mail-Key`; preserve exact allowed origin. Current name: `createCorsResponseHeaders`. |
|
|
82
|
+
| `baseResponseHeaders` | Returns `corsHeaders(origin)` without another concern. | N/N/Y — Remove. | One extra call/name hides no useful separate ownership. Call the CORS owner directly. |
|
|
83
|
+
| `writeJson` | Serializes complete result once and ends the HTTP response. | Y/Y/Y — Simplify. | Keep complete JSON and response-state handling. Remove the manual content-length scan; the HTTP owner supplies transport framing. Current name: `sendJsonResponse`. |
|
|
84
|
+
| `writePreflight` | Sends OPTIONS response but constructs CORS headers twice. | Y/Y/Y — Simplify. | Build CORS headers once, update allowed request headers, and end the response. Remove explicit content-length bookkeeping. Current name: `sendCorsPreflightResponse`. |
|
|
85
|
+
| `writeFault` | Maps failure fields into the public gateway response. | Y/Y/Y — Simplify. | Preserve complete code/message/details and retry/uncertainty fields. Remove local provider-code regex substitution that hides the actual code. Current name: `sendMailFailureResponse`. |
|
|
86
|
+
| `normalizeFault` | Preserves gateway faults or converts unexpected failures to complete gateway error detail. | Y/Y/N — Keep. | Callers require an honest response on ordinary errors. Current name: `mailFaultFromError`. |
|
|
87
|
+
| `validatePreflight` | Reads the browser's requested method/headers and private-network request. | Y/Y/Y — Remove duplicate parser and gates. | Return the selected allowed methods/headers once; browser CORS implements that capability response. Origin policy remains at request owner. |
|
|
88
|
+
| `normalizeRequestedHeader` | Trims/lowercases CORS header-name tokens for duplicate preflight checks. | N/N/Y — Remove with redundant parser. | Browser receives the supported header list directly from the one response definition. |
|
|
89
|
+
| `headerIsNotAllowed` | Tests CORS header names against syntax and the supported list. | N/N/Y — Remove duplicated check. | The response's supported method/header definition and the browser own that capability decision; exact origin membership remains enforced by the server. |
|
|
90
|
+
| `createObserver` | Invokes optional callbacks while tracking their asynchronous completion. | Y/Y/Y — Simplify unused-path work, keep lifecycle ownership. | Current source instantiates no observer object, pending Set, callback closures, or drain wait when `onEvent` is absent, and creates no provider event payloads. Retain already-started observer tasks until drain when enabled. Current name: `createMailEventObserver`. |
|
|
91
|
+
| `observe` | Calls the observer and owns returned promises. | Y/Y/N — Keep. | Observation must not change the committed mail result. Preserve independently constructed snapshots for emitted provider observations. Current nested name remains `observe` at the event-observer owner. |
|
|
92
|
+
| `ignoreObserverFailure` | Consumes observer promise rejection. | Y/Y/Y — Preserve outcome independence and expose the actual failure. | Replaced by `reportObserverFailure`, which sends synchronous throws and asynchronous rejections through `reportMailError` for complete stderr diagnostics. Observer failure still cannot replace the mail classification. This is implemented source behavior, not a performed error-injection test. |
|
|
93
|
+
| `releaseObserverTask` | Deletes a settled observer task from the pending Set. | Y/Y/N — Keep. | Prevents indefinite retention after completion. Current nested name remains `releaseObserverTask`. |
|
|
94
|
+
| Observer `drain` | Joins already-started observer promises on send/close completion. | Y/Y/N — Keep. | Removing it would abandon work already invoked by this operation. It must not create an ordinary per-request wait before provider delivery. Current implementation name: `drainObserverTasks`, exposed as `drain` to internal callers. |
|
|
95
|
+
|
|
96
|
+
Complete request and provider-content handling follow.
|
|
97
|
+
|
|
98
|
+
| Baseline method or callback owner | Caller and actual purpose | Gates and decision | Concrete cost, preservation requirement, and retained name |
|
|
99
|
+
| --- | --- | --- | --- |
|
|
100
|
+
| `readRequestBody` / `collectRequestBody` | Collect the complete original Node request as UTF-8 text before parsing JSON. | Y/Y/N — Keep. | One collection/decoding boundary is necessary. No content cap, clipping, or duplicate parser. Current names: `readRequestBodyText` and `collectRequestBodyText`. |
|
|
101
|
+
| `expireRequestBody` | Acts only when the caller supplied a body deadline. | Y/Y/N — Keep. | One selected timer owns its real deadline and unread-request drain. Current callback name remains `expireRequestBody`. |
|
|
102
|
+
| Body-reader `cleanup` | Clears timer and owned stream/signal listeners. | Y/Y/N — Keep. | Prevents listener/timer retention after settlement. Current name: `releaseBodyReadResources`. |
|
|
103
|
+
| Body-reader `finish` | Settles a stream operation once amid end/error/abort races. | Y/Y/N — Keep. | Several platform events can occur for the same request; one result is required. Current name: `settleBodyRead`. |
|
|
104
|
+
| Body-reader `onData` | Adds the next chunk and accommodates non-Buffer chunks. | Y/Y/N — Keep current compatibility. | Current name: `collectBodyChunk`. Conversion remains because removing support for alternate supplied stream chunks has not been established as safe. Further interface narrowing is deferred; every chunk remains preserved. |
|
|
105
|
+
| Body-reader `onEnd` | Concatenates and decodes complete content. | Y/Y/N — Keep. | Required transport decoding; no added document transformation. Current name: `completeBodyRead`. |
|
|
106
|
+
| Body-reader `onError` | Captures request-stream failure. | Y/Y/N — Keep. | Preserve actual error detail. Current name: `rejectFailedBodyRead`. |
|
|
107
|
+
| Body-reader `onAborted` | Settles a client-aborted request. | Y/Y/N — Keep. | Necessary request lifecycle event. Current name: `rejectAbortedBodyRead`. |
|
|
108
|
+
| Body-reader `onSignalAbort` | Cancels collection and resumes unread request data. | Y/Y/N — Keep. | Settles cancellation without retaining listeners or blocking input drain. Current name: `cancelBodyReadFromSignal`. |
|
|
109
|
+
| `normalizedReportEmail` | Rewrites and grammar-checks report recipient strings. | N/N/Y — Remove. | Eliminates per-recipient trim/lowercase/pattern scans and preserves supplied values. |
|
|
110
|
+
| `normalizeReportRecipients` | Resolves actual recipients, explicit policy, and error fallback. | Y/Y/Y — Simplify and retain complete recipient policy. | Current `resolveReportRecipients` preserves fallback and exact string/array values. A configured nonempty allowlist checks resolved `to`, `cc`, and `bcc`; otherwise no policy scan runs. Removing address rewriting saves those scans/copies; covering `cc`/`bcc` adds one required membership lookup per such recipient. Restricting only `to` would bypass the selected policy. Public `recipientCount` remains based on resolved `to`. |
|
|
111
|
+
| `normalizeReport` | Applies local schema, strips app type, injects sender, creates provider body, serializes, and copies report. | Y/Y/Y — Simplify. | Keep one explicit provider-boundary mapping. Remove local type/text/HTML/subject restrictions, repeated spreads and unchanged field assignments. Preserve template/provider fields. Current name: `prepareProviderDelivery`. |
|
|
112
|
+
| `parseReport` | Parses inbound JSON and delegates provider mapping. | Y/Y/N — Keep. | JSON parsing is necessary for the actual provider adapter. Malformed input cannot be parsed; report it honestly. Current name: `parseMailRequest`. |
|
|
113
|
+
| `parseRetryAfter` | Parses provider Retry-After seconds or date into control delay. | Y/Y/N — Keep. | Consumers use the retry time. Current name: `parseRetryAfterMilliseconds`. |
|
|
114
|
+
| `responseHeader` | Catches/coerces access to standard Fetch Headers. | N/N/Y as a defensive wrapper — Remove/simplify. | Read the platform Headers API. Do not turn a thrown response error into a fictitious absent header. |
|
|
115
|
+
| `awaitAbortable` / `waitForAbortable` | Settles waits when injected provider operations ignore AbortSignal. | Y/Y/N — Keep under the selected caller-cancellation contract. | This is actual supported cancellation behavior, not a reason to serialize independent requests. Current outer name: `waitForResultOrAbort`; executor remains `waitForAbortable`. |
|
|
116
|
+
| Abortable-wait `cleanup` | Removes its one abort listener. | Y/Y/N — Keep. | Stops retention after promise settlement. Current nested name remains `cleanup`; its one concern is visible inside `waitForResultOrAbort`. |
|
|
117
|
+
| `settleResolved` / `settleRejected` | Handle whichever result/abort arrives first. | Y/Y/N — Keep. | Settlement and cleanup are necessary for the adapter. Current nested names remain `settleResolved` / `settleRejected`. |
|
|
118
|
+
| Abortable-wait `onAbort` | Rejects with the caller's abort reason. | Y/Y/N — Keep. | Preserve the actual reason; no synthetic delivery result. Current nested name remains `onAbort`. |
|
|
119
|
+
| `ignoreCancellationFailure` | Observes cancellation rejection for both body and reader cleanup. | Y/Y/N — Keep current shared cleanup callback. | Two real cancellation owners use it. The callback prevents a cleanup rejection from replacing the already-classified provider outcome; it does not log or report an error. |
|
|
120
|
+
| `cancelProviderBody` | Cancels a response body whose supplied interface cannot be read by the adapter. | Y/Y/N — Keep with current stream contract. | The current reader-based contract and cancellation adapter remain. Changing that contract to require native Response.text is deferred; this cleanup prevents retaining an unread body. Name remains `cancelProviderBody`. |
|
|
121
|
+
| `cancelProviderReader` | Cancels a partially consumed reader after failure/abort. | Y/Y/N — Keep while manual reading remains. | Releases actual stream resources. Name is clear. |
|
|
122
|
+
| `readProviderBody` | Reads all provider content with decoding and cancellation. | Y/Y/Y — Simplify local policing, retain full reading. | Native response text APIs may own decoding, but custom-reader compatibility and cancellation are retained. Never discard response text because it is not the preferred schema. Current name: `readProviderResponseText`. Redundant chunk-type policing is removed; native TextDecoder owns decoding, and interrupted reads preserve obtained text with `responseComplete: false`. |
|
|
123
|
+
| `parseProviderObject` | Converts JSON objects to values but drops every other body to null. | Y/Y/Y — Replace lossy restriction. | Preserve parsed JSON of any shape or complete original text. Current name: `parseProviderResponse`. |
|
|
124
|
+
| `providerCode` | Extracts provider name but rejects names outside a local pattern. | Y/Y/Y — Simplify. | Preserve actual string codes; use a fallback only when no code exists. Current name: `resolveProviderErrorCode`. |
|
|
125
|
+
| `providerRejection` | Maps provider failures to permanent/retryable outcomes and delay. | Y/Y/N — Keep classification; fix complete detail propagation. | Browser retry owners consume these distinctions. Do not collapse quota/conflict/transport failures. Current name: `classifyProviderRejection`. |
|
|
126
|
+
| `ambiguousResult` | Represents provider acceptance that could not be determined. | Y/Y/N — Keep. | Prevents both false success and false certainty that nothing was sent. Current name: `createUncertainProviderResult`. |
|
|
127
|
+
|
|
128
|
+
Provider attempt, direct-send result, and HTTP handler ownership follow.
|
|
129
|
+
|
|
130
|
+
| Baseline method or callback owner | Caller and actual purpose | Gates and decision | Concrete cost, preservation requirement, and retained name |
|
|
131
|
+
| --- | --- | --- | --- |
|
|
132
|
+
| `performResendAttempt` | Performs one fixed provider POST, reads its full result, and classifies it. | Y/Y/Y — Keep transport; remove redundant work. | Do not add gateway retries. Avoid event payload parsing when unobserved. Retain independent snapshots when emitted. Current name: `attemptResendDelivery`. |
|
|
133
|
+
| `completeAttempt` | Records the outcome returned by each branch for final observation. | Y/Y/N — Keep in the current multiple-return arrangement. | Removing it alone repeats state assignment at every exit. Current name: `recordAttemptOutcome`. |
|
|
134
|
+
| Attempt `forwardAbort` | Propagates request cancellation into provider Fetch. | Y/Y/N — Keep. | One request's cancellation stays local to that request. Current name: `abortProviderRequest`. |
|
|
135
|
+
| `expireResendAttempt` | Enforces the caller's selected provider deadline. | Y/Y/N — Keep. | Omitted deadline allocates no timer. Current name: `abortTimedOutProviderRequest`. |
|
|
136
|
+
| `normalizeDirectSendOptions` | Resolves direct-send defaults and dependencies. | Y/Y/Y — Simplify local grammar; preserve provider requirements. | Keep exact report key and credential/Fetch availability. Remove invented key grammar beyond the owning external protocol. Current name: `resolveDirectSendConfiguration`. |
|
|
137
|
+
| `directSendResult` | Produces CLI/toolchain accepted, rejected or uncertain result. | Y/Y/Y — Simplify repeated assignments. | Keep complete outcome, report, request snapshot, counts and provider detail. `providerStatus` and accepted `providerId` are already in the spread source. Current name: `createDirectSendResult`. |
|
|
138
|
+
| `sendResendMail` | One-shot direct entry point used by `src/mail.mjs`. | Y/Y/Y — Keep; stop an already-cancelled call before unnecessary work. | Current cancellation check precedes report mapping, serialization, request-ID creation, and observer construction. It retains `ARCANE_CANCELLED` and the caller's reason as cause. Cancellation after provider dispatch remains uncertain. Preserve public name. |
|
|
139
|
+
| `sendProviderResult` | Maps provider result to browser gateway HTTP/status response. | Y/Y/N — Keep. | Browser transport consumes 202 accepted and 207 uncertain plus the error mapping. Current name: `writeProviderDeliveryResponse`. |
|
|
140
|
+
| `createResendMailRequestHandler` | Exposes the raw request handler and its close owner. | Y/Y/Y — Keep entry point; avoid repeated configuration. | A private factory may consume already-resolved configuration. Preserve returned handle/close contract. |
|
|
141
|
+
| `forwardOwnerAbort` | Propagates external owner signal to handler cancellation. | Y/Y/N — Keep. | Required lifecycle propagation. Current name: `abortHandlerFromOwner`. |
|
|
142
|
+
| `handleOwnedRequest` | Routes, authenticates, reads, delivers, responds and emits request result. | Y/Y/Y — Simplify obsolete gates/state. | Keep real origin policy, subscription verification, routing, complete content and outcome. Do not serialize unrelated requests. Current name: `handleMailRequest`. |
|
|
143
|
+
| Request `abortFromOwner` | Cancels this request when handler closes. | Y/Y/N — Keep. | Actual dependency: handler owns request lifetime. Current name: `abortRequestFromHandler`. |
|
|
144
|
+
| `abortFromRequest` | Cancels when incoming request disconnects/errors. | Y/Y/N — Keep. | Prevents abandoned provider work where cancellation is possible. Current name: `abortDisconnectedRequest`. |
|
|
145
|
+
| `abortFromResponseClose` | Distinguishes premature response close from an already-ended response. | Y/Y/N — Keep. | A completed response must not retroactively erase acceptance. Current name: `abortRequestOnPrematureResponseClose`. |
|
|
146
|
+
| `absorbResponseError` | Only forwards to the request cancellation function. | Y/Y/Y — Remove redundant wrapper. | Attach the needed cancellation handler directly or preserve actual error cause at that owner. No separate method is required. |
|
|
147
|
+
| `releaseRequestListeners` | Releases listeners when the underlying request stream is finished. | Y/Y/N — Keep. | Handler completion can precede unread-request drain. Name is clear. |
|
|
148
|
+
| `releaseResponseListeners` | Releases response listeners after actual finish/destruction. | Y/Y/N — Keep. | Keeps error ownership until the real response ends. Name is clear. |
|
|
149
|
+
| Handler `handle` | Starts a concurrent operation and records it in active requests. | Y/Y/N — Keep. | Non-awaited dispatch preserves concurrent HTTP requests; tracking enables shutdown. Current private name: `dispatchMailRequest`; returned property remains `handle`. |
|
|
150
|
+
| `closeFailedRequest` | Destroys response after an unexpected escaped handler failure. | Y/Y/Y — Preserve cleanup and actual error cause. | Current `closeResponseAfterHandlerFailure(error)` calls `reportMailError` for complete stderr diagnostics and calls `response.destroy(error)` when the response remains open. It does not invent another diagnostics subsystem or replace a provider outcome. |
|
|
151
|
+
| `releaseActiveRequest` | Removes settled request promise from the active Set. | Y/Y/N — Keep. | Prevents retention and gives close the current work inventory. Name is clear. |
|
|
152
|
+
| `closeOwnedHandler` | Aborts requests, joins their settlement, then joins observer work. | Y/Y/N — Keep. | Required shutdown dependency; no global startup barrier. Current name: `closeMailRequestHandler`. |
|
|
153
|
+
| Handler `close` | Makes all callers join one close operation. | Y/Y/N — Keep. | Signals, explicit close, and server errors can race. Public property name is appropriate. |
|
|
154
|
+
|
|
155
|
+
The upstream listener and public lifecycle follow.
|
|
156
|
+
|
|
157
|
+
| Baseline method or callback owner | Caller and actual purpose | Gates and decision | Concrete cost, preservation requirement, and retained name |
|
|
158
|
+
| --- | --- | --- | --- |
|
|
159
|
+
| `deployMailServer` | Adapts published `deploy(callback)` into listener startup promise. | Y/Y/N — Keep. | Startup must return the actual bound address or an actual bind error. Current name: `listenForMailRequests`. |
|
|
160
|
+
| `waitForMailListener` | Owns the startup promise. | Y/Y/N — Keep. | Required callback-to-promise adapter at the upstream owner. Name is clear. |
|
|
161
|
+
| Listener `onError` | Rejects startup when binding fails. | Y/Y/N — Keep. | Do not claim listening before this boundary. Current callback name remains `onError`, local to the listener promise. |
|
|
162
|
+
| `onListening` | Removes startup error listener and resolves actual raw server. | Y/Y/N — Keep. | Retain upstream callback semantics. Current callback name remains `onListening`; its `(instance, server)` positions follow the upstream callback. |
|
|
163
|
+
| `startResendMailServer` | Constructs upstream server and mail handler, then exposes lifecycle. | Y/Y/Y — Keep entry point; remove duplicate configuration/loopback gate. | Use configured host/domain; keep selected upstream public interface and no implicit socket deadline. Preserve public name. |
|
|
164
|
+
| `handleMailRequest` assigned to `onRawRequest` | Hands original Node request/response to mail handler and returns true. | Y/Y/N — Keep. | `true` prevents upstream body/static processing of an already-owned mail request. Current name: `routeRawMailRequest`, distinct from the actual request handler. |
|
|
165
|
+
| `createMailLifecycle` | Creates public lifecycle promise used by CLI `waitForServer`. | Y/Y/N — Keep. | Actual consumer awaits this lifecycle and propagates failure. Name is clear. |
|
|
166
|
+
| `observeMailLifecycleFailure` | Prevents an early unhandled rejection while the exposed lifecycle remains rejected. | Y/Y/N for rejection observation. | This does not report the error; naming/comments must say that lifecycle retains it for the consumer. No new error-suppression layer. |
|
|
167
|
+
| `closeOwnedServer` | Closes upstream listener and handler concurrently, then settles lifecycle. | Y/Y/N — Keep. | Preserve concurrent close start through `Promise.all`; no serial wait is needed between these owners. Current name: `closeMailServer`. |
|
|
168
|
+
| Server `close` | Shares one close promise across repeated callers. | Y/Y/N — Keep. | Prevents repeated shared lifecycle mutations. Public name is appropriate. |
|
|
169
|
+
| `closeFromSignal` | Starts closure on owner abort. | Y/Y/N — Keep. | Failure remains on public lifecycle. Current name: `closeServerOnAbort`. |
|
|
170
|
+
| `ignoreSignalCloseFailure` | Observes close rejection after lifecycle takes responsibility. | Y/Y/N for narrow rejection observation. | It must not erase lifecycle failure. A local callback/comment is sufficient; no reusable helper needed. |
|
|
171
|
+
| `closeFromServerError` | Rejects lifecycle and starts cleanup for runtime server error. | Y/Y/N — Keep. | Real operational failure must remain observable. Current name: `closeServerAfterError`. |
|
|
172
|
+
| `observeOperationalCloseFailure` | Handles the second rejection path after lifecycle owns failure. | Y/Y/N for narrow rejection observation. | Keep ownership clear; do not claim this empty callback logs/reports anything. |
|
|
173
|
+
| `finishExternallyClosedServer` | Settles handler/lifecycle after the exposed raw server is closed externally. | Y/Y/N — Keep. | Raw `server` is a returned interface; external close is a real lifecycle path. Current name: `finishMailServerAfterExternalClose`. |
|
|
174
|
+
| `resolveExternalClose` | Resolves lifecycle after external close and handler completion. | Y/Y/N — Keep. | Required completion ordering. Name is clear. |
|
|
175
|
+
| `rejectExternalClose` | Rejects lifecycle and close promise if handler closure fails. | Y/Y/N — Keep. | Preserves the actual failure. Name is clear. |
|
|
176
|
+
| `observeExternalCloseFailure` | Avoids an unhandled duplicate close rejection while lifecycle exposes the error. | Y/Y/N for narrow rejection observation. | No standalone abstraction needed; maintain the actual exposed failure. |
|
|
177
|
+
|
|
178
|
+
Constants, imports, and non-callable runtime actions must pass the same gates.
|
|
179
|
+
|
|
180
|
+
| Baseline constant, field, or action | Gates and decision | Purpose, cost, and final ownership |
|
|
181
|
+
| --- | --- | --- |
|
|
182
|
+
| `Is` import and `is = new Is(false)` | Y/Y/N — Keep only checks that still serve real parsing/configuration. | Existing RIA-owned type utility; this review authorizes no new dependency. Removing one local use alone is not proof the dependency is removable from the SDK. |
|
|
183
|
+
| `createHash`, `timingSafeEqual` imports | N/N/Y — Removed. | Their only mail-server callers were the superseded digest mechanism. No replacement local hash scheme is introduced. |
|
|
184
|
+
| `randomUUID` import | Y/Y/N — Keep. | Supplies request correlation without using message content. |
|
|
185
|
+
| New native `inspect` import from `node:util` | Y/Y/N — Keep. | `reportMailError` formats errors for two actual failure owners with depth/array/string clipping disabled. It introduces no third-party dependency; formatting work occurs only on those failure paths. |
|
|
186
|
+
| `Server` import | Y/Y/N — Keep. | The selected published `node-http-server` owns HTTP serving; do not substitute a custom Node HTTP listener. |
|
|
187
|
+
| `RESEND_MAIL_SERVER_PROTOCOL` | Y/Y/N — Keep. | Public gateway protocol metadata and documentation refer to it. Reconcile actual protocol changes honestly; no cosmetic version change is prescribed here. |
|
|
188
|
+
| `RESEND_MAIL_PATH` | Y/Y/N — Keep. | Stable mail route used by clients and returned server URL. Current routing accepts `/v1/mail` and `/v1/mail?...`; a query does not change the selected route. |
|
|
189
|
+
| `RESEND_EMAIL_ENDPOINT` | Y/Y/N — Keep. | Provider credential is sent only to the intended Resend endpoint. It is distinct from the configured subscription-verifier callback and its future remote adapter. |
|
|
190
|
+
| `APP_ID_PATTERN` | N/N/Y — Remove. | Application is an ordinary string; no app enumeration, closed list, slug pattern, or single-app server assumption remains. |
|
|
191
|
+
| `EMAIL_PATTERN` | N/N/Y — Remove from gateway. | Provider owns email grammar; values remain unchanged. |
|
|
192
|
+
| `IDEMPOTENCY_KEY_PATTERN` | Y/Y/Y — Remove invented grammar, preserve exact supplied key. | Header transport and provider semantics own admissibility. No key rewriting, regeneration on retry, or gateway retry loop. |
|
|
193
|
+
| `PROVIDER_ID_PATTERN` | Y/Y/Y — Remove syntax restriction; retain actual identifier existence for provider acceptance. | Coordinate coupled browser checks so they do not reject valid provider metadata. |
|
|
194
|
+
| `PROVIDER_CODE_PATTERN` | N/N/Y — Remove. | Preserve actual provider code and details instead of replacing them with a generic code. |
|
|
195
|
+
| `REQUEST_ID_PATTERN` | Y/Y/N — Preserve current compatibility; relaxation deferred. | Browser transport, native response parser and outbox still consume this form. Its relaxation requires a separately traced coupled public-contract change; it is not partially implemented in this cleanup. |
|
|
196
|
+
| `JSON_CONTENT_TYPE_PATTERN` | Y/Y/Y — Simplify to the actual JSON transport boundary. | JSON parser decides readable JSON. Do not reject otherwise supported provider content because of narrowly spelled MIME parameters. |
|
|
197
|
+
| `HEADER_NAME_PATTERN` | N/N/Y — Remove duplicate header grammar. | Node and the CORS supported-header contract already own this information. |
|
|
198
|
+
| `MAIL_TYPES` | Y/Y/Y — Remove gateway type admission, preserve `type` as app metadata used for error fallback. | A gateway must not block provider-supported payloads solely on the app's reporting enum. Browser Mail's formatting enum is a separate owner and remains outside unrelated cleanup. |
|
|
199
|
+
| `PREFLIGHT_HEADERS` | Y/Y/Y — Remove duplicate Set; keep one response definition. | Authorization, Content-Type, Idempotency-Key, and X-Mail-App remain declared in CORS response headers. No second capability structure is needed. |
|
|
200
|
+
| Raw `request.url === RESEND_MAIL_PATH` routing restriction | Y/Y/Y — Simplify to fixed path with optional query. | Browser endpoint parsing permits query-bearing URLs. Current source accepts the exact mail path or the same path followed by `?`; it does not strip, rewrite, or inject anything into the report. |
|
|
201
|
+
| `PERMANENT_RATE_CODES` | Y/Y/N — Keep. | Current result consumers distinguish quota failures from retryable rate failures. It is delivery classification, not recipient admission. |
|
|
202
|
+
| `RETRYABLE_PROVIDER_STATUSES` | Y/Y/N — Keep. | Preserves retryable versus permanent outcome semantics consumed by browser/outbox. |
|
|
203
|
+
| `MAX_NODE_TIMER_DELAY_MS` | Y/Y/N — Keep. | Represents an actual platform timer range for explicitly selected deadlines. It is not a message-content gate. |
|
|
204
|
+
| `allowAnyRecipient`, `allowedRecipients`, `errorRecipients` | Y/Y/N — Keep selected policy/fallback. | Create the membership Set once. A nonempty allowlist checks exact resolved `to`, `cc`, and `bcc` values; the empty-list path skips the per-request recipient scan. Preserve error fallback and original address values. |
|
|
205
|
+
| `allowedOrigins` membership Set | Y/Y/N — Keep. | A nonempty list rejects nonmembers while supporting multiple exact domains. With no list, direct current-authority comparison supplies the selected default. |
|
|
206
|
+
| Numeric-loopback defaults, Host/socket admission, post-bind loopback check | N/N/Y — Remove loopback-only policy. | Host configuration and the actual bound address determine URL reporting. Keep IPv6 URL bracket formatting when reporting an IPv6 address. |
|
|
207
|
+
| Old `appKeyDigest`, `allowUnauthenticatedCaller`, `callerAuthentication` mode values | N/N/Y — Replaced. | Digest and old explicit bypass state are removed. `callerAuthentication` reports `'subscription'` when the optional verifier is configured, otherwise `'none'` for initial setup. Metadata never claims authentication occurred when no verifier exists. |
|
|
208
|
+
| `X-Mail-App` | Y/Y/N — Keep. | Per-request ordinary application string for subscription verification; no app-slug rewrite or server-wide equality test. |
|
|
209
|
+
| `singleHeader(request, 'x-mail-app') !== configuration.appId` admission | N/N/Y — Removed. | One shared server serves any application across allowed domains. A configured verifier receives each supplied application and its bearer credential; no one-app comparison remains. |
|
|
210
|
+
| `X-Mail-Key` | N/N/Y — Remove with coupled migration. | User selected bearer Authorization instead. Reconcile browser configuration, transport, CLI input, CORS and docs together. |
|
|
211
|
+
| `Authorization: Bearer ...` for subscription request | Y/Y/N — Keep at the configured authentication owner. | The local callback receives the token and application separately. The token is not put into ordinary request events or provider request snapshots. The remote endpoint adapter remains later work. |
|
|
212
|
+
| Optional `verifySubscription` configuration and callback result | Y/Y/N — Keep. | The callback is a public integration seam with actual per-request ownership, not an indirection factory. Type-check a supplied callable once; await its result only where provider admission depends on it. Omission allocates no verification operation and honestly reports no caller authentication. |
|
|
213
|
+
| Bearer header extraction and 401 challenge | Y/Y/N — Keep the selected authentication protocol. | Use `headersDistinct.authorization` and one Bearer extraction at verification. Missing/ambiguous credentials or nontrue verification receive 401 with `WWW-Authenticate: Bearer`; no custom raw-header reconstruction is restored. |
|
|
214
|
+
| Per-request application observation metadata | Y/Y/N — Keep. | Current handler reads the request's `X-Mail-App`, uses the verified application when configured, and passes it to provider/request observations. Optional `configuration.appId` remains a direct-send/server-summary default, not a shared-server admission rule. |
|
|
215
|
+
| Provider Authorization header | Y/Y/N — Keep. | Resend API credential remains separate from subscriber credential and never appears in event snapshots. |
|
|
216
|
+
| Idempotency-Key forwarding | Y/Y/N — Keep. | Reuses the caller's exact key for one attempt; preserves duplicate-send prevention semantics. |
|
|
217
|
+
| Fixed POST, JSON transport serialization | Y/Y/N — Keep. | Real provider boundary. Serialize complete mapped fields once for the send; do not alter document text/HTML. |
|
|
218
|
+
| Provider `User-Agent` | Y/Y/N — Keep provider-client identification. | One static transport header identifies this provider client without rewriting the message or acting as admission. It remains unchanged; no measurable benefit is claimed. |
|
|
219
|
+
| Fetch redirect policy | Y/Y/N — Keep credential routing at the exact provider owner. | A redirect must not silently move provider authority to a different destination. Do not generalize this into unrelated hardening. |
|
|
220
|
+
| Fetch `referrerPolicy` | N/N/Y — Removed from the Node provider call. | No page referrer is supplied there. The separate `redirect: 'error'` credential-routing boundary remains. Browser Fetch behavior is owned by the browser transport. |
|
|
221
|
+
| Complete report-to-provider mapping | Y/Y/N — Keep with simplification. | Excluding app metadata and adding the selected sender are explicit adapter responsibilities. Preserve all other provider fields and exact content. |
|
|
222
|
+
| Repeated provider-body JSON parsing for events | Y/Y/Y — Remove when no observer exists. | Avoid two full reconstructions in the unobserved attempt. Emitted observations retain independent snapshots; do not silently share mutable objects. |
|
|
223
|
+
| Duplicate `normalizeConfiguration` calls | Y/Y/Y — Remove second pass. | Avoid repeated policy construction and old auth setup at startup. Use resolved configuration at the private handler owner. |
|
|
224
|
+
| Manual response content-length calculation and preflight zero length | N/N/Y — Remove. | Upstream Node HTTP framing handles the complete response. Eliminate the manual scan and related metadata assignment. |
|
|
225
|
+
| Duplicate CORS spread in preflight | N/N/Y — Remove duplicate. | One CORS construction preserves all required browser behavior. |
|
|
226
|
+
| Provider HTTP status and response-id classification | Y/Y/Y for provider-ID simplification; Y/Y/N for retained HTTP-status compatibility. | Provider-ID syntax restriction is removed; a nonempty identifier and actual success response still establish acceptance. The current HTTP-status guard prevents an invalid injected response from being misclassified as a permanent rejection. Broader injected-interface narrowing is deferred. |
|
|
227
|
+
| Non-JSON/array/primitive provider-body rejection | N/N/Y — Remove content loss. | Preserve original response text or complete parsed value in result details. |
|
|
228
|
+
| `recipientCount` | Y/Y/N — Keep existing public meaning. | Gateway accepted response and direct-send result count resolved `to` recipients. Extending allowlist coverage to `cc`/`bcc` does not silently change that response contract. This is record count, not content accounting. |
|
|
229
|
+
| `providerAttempted`, outcome, request timing | Y/Y/N when observed/returned behavior needs them. | Distinguishes no attempt from uncertain attempt. Avoid timing/event construction on absent-observer paths where the value has no other consumer. |
|
|
230
|
+
| Request-scope `serialized` mutable slot | Y/Y/Y — Replace with local `const requestText`. | It is used at one parsing boundary; no request-lifetime mutable state is needed. |
|
|
231
|
+
| Request/response destroyed/ended checks | Y/Y/N — Keep. | Avoid writing after actual connection completion; this is lifecycle correctness. |
|
|
232
|
+
| Active-request Set and promise cleanup | Y/Y/N — Keep. | Gives shutdown ownership of concurrent requests; not a request-count admission gate. |
|
|
233
|
+
| Cancellation controllers and owned listeners | Y/Y/N — Keep. | Connect actual caller/request/server lifecycle; remove each at its settlement boundary. |
|
|
234
|
+
| Explicit timeout timers | Y/Y/N — Keep only when configured. | No default body/provider timeout or automatic retry timer is introduced. |
|
|
235
|
+
| Observer pending Set and drain | Y/Y/Y — Keep only when observation is configured. | Current source allocates the observer and pending Set only with `onEvent`, and skips empty-path drain calls. Enabled observation still owns already-started asynchronous work through completion. |
|
|
236
|
+
| Already-cancelled direct-send ordering | Y/Y/Y — Stop before report construction and serialization. | The existing cancellation result now precedes mapping, JSON serialization, diagnostic ID generation, and observer allocation. These removed operations have no consumer once the send is already cancelled. No timing claim is made. |
|
|
237
|
+
| Native error cause/aggregate detail extraction | Y/Y/N — Keep complete failure content. | `completeErrorDetails` explicitly includes native non-enumerable cause and aggregate errors in addition to message/name/stack and ordinary fields. |
|
|
238
|
+
| Observer and escaped-handler error reporting | Y/Y/N — Keep actual failure visibility at existing owners. | Both owners call `reportMailError`; native `inspect` disables its depth/array/string clipping before stderr output. Escaped handler failure also supplies its cause to `response.destroy(error)`. No new logging subsystem or change to provider classification is introduced. |
|
|
239
|
+
| Upstream `server: {timeout: 0}` | Y/Y/N — Keep. | Preserves absence of an implicit socket inactivity deadline; selected mail deadlines remain at mail owner. |
|
|
240
|
+
| `onRawRequest` returning true | Y/Y/N — Keep. | Prevents a second upstream body parser/static route from processing mail requests. |
|
|
241
|
+
| Server/handler concurrent close | Y/Y/N — Keep. | Both independent close operations start before their necessary completion join. |
|
|
242
|
+
| `closed` / `lifecycle` returned aliases | Y/Y/N — Keep existing interface. | Local nonuse of one alias does not establish that a returned public property is dead. |
|
|
243
|
+
| Raw `server`, `close`, address, URL, app/protocol/mode/target metadata | Y/Y/N — Keep accurate public result. | CLI reports address and awaits lifecycle; raw server close has an owned cleanup path. Do not expose credentials or report localhost for a configured domain listener. |
|
|
244
|
+
|
|
245
|
+
The following table records actual renamed gateway methods in the inspected source. The detailed rows above use these same names; unchanged local callbacks retain their existing context-specific names. No alternative name or new authentication factory is prescribed. A rename does not change the corresponding behavior's keep/remove decision.
|
|
246
|
+
|
|
247
|
+
| Baseline name | Observed retained name or removal |
|
|
248
|
+
| --- | --- |
|
|
249
|
+
| `positiveInteger` | `readRetryDelayMs`; unused `allowZero` branch removed. |
|
|
250
|
+
| `normalizeRetryAfter` | `retryDelayOrZero`. |
|
|
251
|
+
| `normalizeConfiguration` | `resolveMailServerConfiguration`. |
|
|
252
|
+
| `singleHeader` | `requireRequestHeader` uses Node `headersDistinct` directly for an actually required nonempty header; manual reconstruction is removed. |
|
|
253
|
+
| `appKeyDigest` / `normalizeCallerAuthentication` / `authenticateLocalCaller` | Removed; the actual configured subscription operation is `verifyMailSubscription`, using the public `verifySubscription` callback. |
|
|
254
|
+
| `corsHeaders` | `createCorsResponseHeaders`. |
|
|
255
|
+
| `writeJson` | `sendJsonResponse`. |
|
|
256
|
+
| `writePreflight` | `sendCorsPreflightResponse`. |
|
|
257
|
+
| `writeFault` | `sendMailFailureResponse`. |
|
|
258
|
+
| `normalizeFault` | `mailFaultFromError`. |
|
|
259
|
+
| `createObserver` | `createMailEventObserver`. |
|
|
260
|
+
| `ignoreObserverFailure` | `reportObserverFailure`; now reports the actual error to stderr without replacing delivery outcome. |
|
|
261
|
+
| New shared diagnostic callable | `reportMailError`; one complete native error formatter serves the observer and escaped-handler failure owners. |
|
|
262
|
+
| Observer `drain` | `drainObserverTasks`, still exposed as `drain` to its internal callers. |
|
|
263
|
+
| `readRequestBody` / `collectRequestBody` | `readRequestBodyText` / `collectRequestBodyText`. |
|
|
264
|
+
| Body-reader `cleanup` / `finish` | `releaseBodyReadResources` / `settleBodyRead`. |
|
|
265
|
+
| Body-reader `onData` / `onEnd` | `collectBodyChunk` / `completeBodyRead`. |
|
|
266
|
+
| Body-reader `onError` / `onAborted` / `onSignalAbort` | `rejectFailedBodyRead` / `rejectAbortedBodyRead` / `cancelBodyReadFromSignal`. |
|
|
267
|
+
| `normalizeReportRecipients` | `resolveReportRecipients`. |
|
|
268
|
+
| `normalizeReport` | `prepareProviderDelivery`. |
|
|
269
|
+
| `parseReport` | `parseMailRequest`. |
|
|
270
|
+
| `parseRetryAfter` | `parseRetryAfterMilliseconds`. |
|
|
271
|
+
| `awaitAbortable` | `waitForResultOrAbort`. |
|
|
272
|
+
| `readProviderBody` | `readProviderResponseText`. |
|
|
273
|
+
| `parseProviderObject` | `parseProviderResponse`. |
|
|
274
|
+
| `providerCode` | `resolveProviderErrorCode`. |
|
|
275
|
+
| `providerRejection` | `classifyProviderRejection`. |
|
|
276
|
+
| `ambiguousResult` | `createUncertainProviderResult`. |
|
|
277
|
+
| `performResendAttempt` / `completeAttempt` | `attemptResendDelivery` / `recordAttemptOutcome`. |
|
|
278
|
+
| Attempt `forwardAbort` / `expireResendAttempt` | `abortProviderRequest` / `abortTimedOutProviderRequest`. |
|
|
279
|
+
| `normalizeDirectSendOptions` | `resolveDirectSendConfiguration`. |
|
|
280
|
+
| `directSendResult` | `createDirectSendResult`. |
|
|
281
|
+
| `sendProviderResult` | `writeProviderDeliveryResponse`. |
|
|
282
|
+
| Handler construction after configuration | `createConfiguredMailHandler`; public `createResendMailRequestHandler` remains. |
|
|
283
|
+
| `absorbResponseError` | Removed; existing request cancellation listener is used directly. |
|
|
284
|
+
| `forwardOwnerAbort` / `handleOwnedRequest` | `abortHandlerFromOwner` / `handleMailRequest`. |
|
|
285
|
+
| Request `abortFromOwner` / `abortFromRequest` / `abortFromResponseClose` | `abortRequestFromHandler` / `abortDisconnectedRequest` / `abortRequestOnPrematureResponseClose`. |
|
|
286
|
+
| Handler `handle` / `closeFailedRequest` / `closeOwnedHandler` | `dispatchMailRequest` / `closeResponseAfterHandlerFailure` / `closeMailRequestHandler`; returned `handle` and `close` properties remain. |
|
|
287
|
+
| `deployMailServer` / raw-hook `handleMailRequest` | `listenForMailRequests` / `routeRawMailRequest`. |
|
|
288
|
+
| `closeOwnedServer` / `closeFromSignal` / `closeFromServerError` | `closeMailServer` / `closeServerOnAbort` / `closeServerAfterError`. |
|
|
289
|
+
| `finishExternallyClosedServer` | `finishMailServerAfterExternalClose`. |
|
|
290
|
+
|
|
291
|
+
Value names also record the representation explicitly.
|
|
292
|
+
|
|
293
|
+
| Baseline name | Clear retained name | Reason |
|
|
294
|
+
| --- | --- | --- |
|
|
295
|
+
| `delivery.providerBody` containing JSON text | `delivery.serializedProviderRequest` | Distinguishes transmitted text from an object. |
|
|
296
|
+
| A parsed provider request copy for an event/result | `providerRequest` | Identifies a complete observation snapshot, not the mutable source used to build the send. |
|
|
297
|
+
| `text` holding provider response | `providerResponseText` | States whose text it is and its representation. |
|
|
298
|
+
| `value` holding parsed provider response | `providerResponse` | Avoids confusing it with input report or configuration. |
|
|
299
|
+
| `result` across provider orchestration | Current `result` and recorded `outcome` | Their small owning scopes distinguish the return value from the outcome saved for final observation; no additional rename is prescribed. |
|
|
300
|
+
| `serialized` holding inbound request | `requestText` | The value is the received text before JSON parsing. |
|
|
301
|
+
| `server` versus upstream instance | Current `server` / `mailServer` | The raw Node listener and owning upstream instance remain distinct; no new name is prescribed. |
|
|
302
|
+
| `configuration` inside mail-only owner | Current `configuration` | The local owner makes its meaning clear; no new qualification is prescribed. |
|
|
303
|
+
| `completeAttempt` | `recordAttemptOutcome` | It records the classified result; it does not itself complete network I/O. |
|
|
304
|
+
| Baseline normalization names | Actual `resolveMailServerConfiguration`, `resolveReportRecipients`, `prepareProviderDelivery`, `parseMailRequest`, `parseProviderResponse`, and `retryDelayOrZero` | Each name describes the remaining operation; removed normalizers receive no substitute wrapper. |
|
|
305
|
+
| `ignoreObserverFailure` | `reportObserverFailure` | It now actually reports observer errors through stderr. Other unchanged lifecycle rejection observers remain local to the public promise that retains the error. |
|
|
306
|
+
|
|
307
|
+
The coupled CLI/browser actions below are necessary to avoid leaving contradictory behavior outside the gateway. They are not permission to redesign unrelated Mail/outbox functionality.
|
|
308
|
+
|
|
309
|
+
| Coupled path/action | Gates and decision | Required result and evidence boundary |
|
|
310
|
+
| --- | --- | --- |
|
|
311
|
+
| `src/mail.mjs` `serveMail` old hidden app-key input and local auth options | Y/Y/Y — Reconciled with the optional verifier contract. | Obsolete shared-app-key prompt/options are removed. Current `serveMailGateway` forwards `options.verifySubscription` to the server and keeps provider credential-manager operations and the provider API key separate. |
|
|
312
|
+
| `src/mail.mjs` `recipientList` and origin list preparation | Y/Y/Y — Remove redundant rewriting, preserve configured policy values. | Gateway and CLI must not disagree about preserved recipients/origins. An exact allowlist is still an intentional policy. |
|
|
313
|
+
| `src/mail.mjs` `withoutMailCredentials` | N/N/Y for recursive payload-key redaction — Remove. | It recursively traversed/copied complete results and deleted any content property named `apiKey` or `appKey`, including ordinary user payload fields. Keep actual transport credentials outside constructed public results at their owning boundary; do not rewrite the report based on property names. Source inspection shows this traversal removed. |
|
|
314
|
+
| `src/mail.mjs` `completeSendFailure` | Y/Y/Y — Remove helper after preserving the complete result directly. | Failure output still contains the provider result, or a narrow wrapper for a non-object injected result. No recursive copying/redaction pass remains. |
|
|
315
|
+
| CLI queue fields passed to a server that no longer consumes them | N/N/Y — Remove dead options/help/forwarding together. | `bodyQueueTimeoutMs`, `maxConcurrentBodyReads`, `maxConcurrentSends`, `maxQueuedBodyReads`, `maxQueuedSends`, and `sendQueueTimeoutMs` have no consumer in baseline mail-server configuration. Do not preserve misleading knobs or recreate queues for them. |
|
|
316
|
+
| CLI app-slug validation/help and server-wide app identity requirement | Y/Y/Y — Remove app restriction and shared-server assumption. | Application is an ordinary per-request string; any app may use the server. Do not locally lowercase, rewrite, enumerate, or compare it to one server app. |
|
|
317
|
+
| CLI mandatory `--from` | Y/Y/Y — Remove the redundant requirement; retain an explicit sender override. | The report or provider template may supply its sender. Requiring a shared CLI sender blocked those supported requests and per-report sender selection. Both mail commands now accept optional `--from`; Resend owns sender validity. The chosen credential profile and stable send key remain required. |
|
|
318
|
+
| `MailTransport.mjs` request-header construction | Y/Y/Y — Updated to optional bearer Authorization; retain X-Mail-App. | Current source accepts an omitted, null, or empty subscription key and omits Authorization when no key exists, allowing the initial server setup. A supplied nonempty string is sent unchanged as the bearer credential; a configured server owns rejection of missing/invalid authentication. Preserve complete report payload, exact report key, cancellation, and configured destination. Never use the subscriber key as Resend provider authority. |
|
|
319
|
+
| `MailTransport.mjs` provider ID/error code regexes | Y/Y/Y — Simplified in current source. | Provider ID requires an actual nonempty string, and provider error codes remain complete strings. The gateway and browser no longer disagree about provider metadata syntax. |
|
|
320
|
+
| Browser/native/outbox request-ID grammar | Y/Y/N — Preserve; broader relaxation deferred. | Request-ID consumers still require the existing form. No half-implemented grammar change is included in this cleanup. |
|
|
321
|
+
| `MailTransport.mjs` / `Mail.js` endpoint selection | Y/Y/Y where loopback-only assumptions conflict with actual configured hosting. | Use configured destination and the selected nominal-domain behavior. The browser credential destination must agree with the actual mail owner; explicit CORS lists remain authoritative. |
|
|
322
|
+
| `Mail.js` configuration carrying old `appKey` | Y/Y/Y — Browser source now uses `subscriptionKey`; gateway uses the optional verifier. | Preserve report formatting, saved mail records, prompts and unrelated public behavior. A browser header change and a local callback contract do not prove remote subscription acceptance. |
|
|
323
|
+
| `Mail.js` User resolution for subscription credentials | Y/Y/Y — Current source resolves the canonical owner at credential consumption. | `resolveMailUserEntity` uses an explicitly injected User when supplied, otherwise current `window.user` or the canonical User constructor. Mail retains only the explicit injection, avoiding a stale default User after disposal/replacement. This is source evidence, not a performed lifecycle test. |
|
|
324
|
+
| Direct-send CLI accepted-result check | Y/Y/N — Keep. | `src/mail.mjs` requires both `classification === 'accepted'` and `status === 'accepted'`; never turn uncertainty into exit-zero success. |
|
|
325
|
+
| Browser response HTTP/status mapping | Y/Y/N — Keep. | Transport maps accepted/uncertain/partial semantic statuses and exposes sent/partial/uncertain fields. Preserve supported response behavior while removing unnecessary syntax gates. |
|
|
326
|
+
| Outbox classification/retry consumption and provider metadata fidelity | Y/Y/Y — Keep behavior; narrow metadata-preservation change in current source. | Classification, timing, storage and retry lifecycle remain owned by outbox. Current result handling preserves provider IDs as strings rather than forcing the prior identifier pattern. This does not migrate stored history or redesign outbox policy. |
|
|
327
|
+
| CLI `serverSummary` and `waitForServer` | Y/Y/N — Keep accurate metadata and lifecycle use. | CLI awaits `lifecycle`, reports returned URL/address and `callerAuthentication`, and identifies this owner as the mail server. Human and machine output must distinguish initial `'none'` from configured `'subscription'`; no credential appears in that metadata. |
|
|
328
|
+
| Public mail docs and examples | Y/Y/Y — Reconcile the selected change. | Remove stale loopback-only, X-Mail-Key, local shared-secret, and discarded queue descriptions. Explain the optional local callback and initial unauthenticated setup plainly; describe the future remote adapter without inventing its contract or claiming it was tested. |
|
|
329
|
+
| CLI reference's mandatory report fields and restricted key wording | Y/Y/Y — Corrected in the inspected documentation. | `docs/reference/cli.md` now describes complete provider fields, template requests, provider-owned shape, and a nonempty report key forwarded unchanged in both the options table and detailed explanation. |
|
|
330
|
+
|
|
331
|
+
The coupled CLI source currently uses these descriptive private names: `usage` becomes `throwMailUsageError`; `validateOptions` becomes `validateMailCommandOptions`; `dependency` becomes `resolveMailCommandDependency`; `recipientList` becomes `mailRecipientOptions`; `credentialOptions` becomes `mailCredentialOptions`; `setCredential` becomes `setMailCredentialFromInput`; `credentialStatus` becomes `readMailCredentialStatus`; `deleteCredential` becomes `deleteMailCredentialProfile`; `sendMail` becomes `sendMailFromReport`; and `serveMail` becomes `serveMailGateway`. `originList`, `withoutMailCredentials`, and `completeSendFailure` no longer exist in that inspected source. These naming changes do not by themselves prove runtime compatibility or remote subscription acceptance.
|
|
332
|
+
|
|
333
|
+
The implementation must retain the actual provider JSON serialization boundary while avoiding transformations of message content. An app `type` used for fallback routing belongs outside the provider payload. Configured sender selection and configured fallback recipients are explicit mapping rules; arbitrary case rewriting, new schemas, content clipping, added model instructions, and guessed provider fields are not. Failure responses must preserve provider JSON or original text of any shape, and interrupted reads must say what remains incomplete rather than claiming an empty complete response.
|
|
334
|
+
|
|
335
|
+
The final status and intentionally deferred work are explicit:
|
|
336
|
+
|
|
337
|
+
| Item | Status and exact remaining action | Delivery implication |
|
|
338
|
+
| --- | --- | --- |
|
|
339
|
+
| Real TWiNStripeServer subscription endpoint adapter | Later integration, not a current delivery blocker. The public optional `verifySubscription({appName, subscriptionKey, signal})` callback and old local-key removal are implemented. Obtain the actual remote endpoint location, request fields, authoritative success/failure shape, and service-error semantics before writing that adapter. | Current setup may run without a verifier and reports `callerAuthentication: 'none'`. Configured verification reports `'subscription'` and controls provider admission. No remote verification or live deployment is claimed. |
|
|
340
|
+
| Per-request identity in server observations/results | Implemented. The handler uses request `X-Mail-App` metadata and the verified application returned by `verifyMailSubscription` for provider/request observations. `configuration.appId` remains only an optional metadata/default input; no equality gate remains. | Any ordinary application string can be passed to the configured verifier. This is a source observation, not proof that a remote service accepted a subscription. |
|
|
341
|
+
| Browser transport without a subscription key | Implemented in the inspected `MailTransport.mjs`. No bearer header is constructed for absent/null/empty keys; supplied nonempty string credentials retain their value. Canonical User lookup still occurs only at credential consumption when no key is configured. | The browser can call the initial no-verifier gateway; configured verification owns an honest 401 when required credentials are absent. No runtime or remote acceptance is claimed. |
|
|
342
|
+
| Request-ID grammar | Deferred and preserved. Trace the complete browser/native/outbox public consumers before any broader relaxation. | No partial request-ID grammar change is included; this retained compatibility does not block current delivery. |
|
|
343
|
+
| Native-only request/response interface narrowing | Deferred and preserved. The non-Buffer request-chunk conversion, reader-based provider body interface, cancellation adapter, and invalid injected-status classification remain. Removing them requires proving that supported injected callers do not need them. | No claim of safe removal or measured saving is made for these retained compatibility paths. |
|
|
344
|
+
| Escaped handler and event observer failure reporting | Implemented. Both call `reportMailError`, which uses native `inspect` with depth/array/string clipping disabled before stderr output. `closeResponseAfterHandlerFailure(error)` also passes the error to response destruction; observer errors do not change delivery classification. | Source evidence only; formatting work occurs only on failure. No local error-injection or runtime check was performed for this report. |
|
|
345
|
+
| Remaining local lifecycle rejection-observer names | Preserved. Their narrow purpose is preventing duplicate unhandled rejections while the public lifecycle/close promise retains failure. The inventory records their actual names; no additional abstraction or blanket naming rewrite is selected. | Do not report every possible naming improvement as implemented. |
|
|
346
|
+
| Final source delivery evidence | Version `0.16.0` selected; root owns final source/documentation reconciliation and the actual commit/package/publication outcome. | This report claims no completed source release, runtime test, live send, or remote subscription verification. The pending remote adapter does not hold the current increment. |
|
|
347
|
+
|
|
348
|
+
TWiNStripeServer owns the future `verify-subscription` endpoint adapter contract; the SDK owns the mail request's application/token consumption and the provider-attempt decision. Any application can use the shared service under its selected CORS policy. The current optional callback allows delivery now without pretending the remote adapter exists: omitted means initial setup with no caller authentication, configured means only an affirmative verifier result permits provider delivery. The later endpoint integration remains recorded and does not cancel or block this current increment.
|
|
349
|
+
|
|
350
|
+
No local test, lint, type check, validation build, browser QA, performance measurement, or live Resend send was performed for this report. No Git index, commit, branch, push, package, or publication operation was performed by the report author. Every baseline named method and callback owner, constant, and significant action remains represented above; removed names are retained in the inventory for traceability. Root owns source/documentation delivery and selected-output verification under its governing authorization. This report records source inspection, not release or runtime evidence.
|
package/package.json
CHANGED