@lunora/mail 1.0.0-alpha.5 → 1.0.0-alpha.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE.md +6 -0
  2. package/dist/inbound/index.d.mts +209 -70
  3. package/dist/inbound/index.d.ts +209 -70
  4. package/dist/inbound/index.mjs +1 -2
  5. package/dist/index.d.mts +94 -94
  6. package/dist/index.d.ts +94 -94
  7. package/dist/index.mjs +1 -7
  8. package/dist/packem_shared/address-BQ5RUGdT.mjs +3 -0
  9. package/dist/packem_shared/capture-transport.d-_rIl9W6N.d.mts +117 -0
  10. package/dist/packem_shared/capture-transport.d-_rIl9W6N.d.ts +117 -0
  11. package/dist/packem_shared/consumeQueuedSend-8TXPj5o-.mjs +1 -0
  12. package/dist/packem_shared/createCaptureSink-CE24od5h.mjs +1 -0
  13. package/dist/packem_shared/createCaptureTransport-CKc6NpZR.mjs +1 -0
  14. package/dist/packem_shared/createCloudflareTransport-E-UdW8Dc.mjs +1 -0
  15. package/dist/packem_shared/createInboundEmailHandler-D2i0mEBB.mjs +1 -0
  16. package/dist/packem_shared/createMailer-LHgKs5yh.mjs +1 -0
  17. package/dist/packem_shared/createResendTransport-CG9s8iI9.mjs +1 -0
  18. package/dist/packem_shared/parseInboundEmail-Cxe54g-h.mjs +1 -0
  19. package/dist/packem_shared/provider-transport-DXmTG_xv.mjs +1 -0
  20. package/dist/packem_shared/renderEmail-BOUnr6i3.mjs +1 -0
  21. package/dist/packem_shared/shard-C0aRRoVy.mjs +1 -0
  22. package/dist/packem_shared/shard.d-DVADjmEJ.d.mts +29 -0
  23. package/dist/packem_shared/shard.d-DVADjmEJ.d.ts +29 -0
  24. package/dist/testing.d.mts +9 -9
  25. package/dist/testing.d.ts +9 -9
  26. package/dist/testing.mjs +1 -57
  27. package/package.json +5 -4
  28. package/dist/packem_shared/address-fkXxLKza.mjs +0 -62
  29. package/dist/packem_shared/capture-transport.d-ChnhdPO2.d.mts +0 -117
  30. package/dist/packem_shared/capture-transport.d-ChnhdPO2.d.ts +0 -117
  31. package/dist/packem_shared/consumeQueuedSend-BEKOdaxU.mjs +0 -75
  32. package/dist/packem_shared/createCaptureSink-DeihS4LH.mjs +0 -63
  33. package/dist/packem_shared/createCaptureTransport-Crz_8822.mjs +0 -11
  34. package/dist/packem_shared/createCloudflareTransport-yHOVEsZv.mjs +0 -26
  35. package/dist/packem_shared/createInboundEmailHandler-D0uCOrU-.mjs +0 -83
  36. package/dist/packem_shared/createMailer-oEKPAd4J.mjs +0 -77
  37. package/dist/packem_shared/createResendTransport-oNIorpzv.mjs +0 -16
  38. package/dist/packem_shared/parseInboundEmail-Bw9u_1oc.mjs +0 -72
  39. package/dist/packem_shared/provider-transport-C5CVbjRF.mjs +0 -47
  40. package/dist/packem_shared/renderEmail-hyS1bpVP.mjs +0 -8
  41. package/dist/packem_shared/shard-CJ-TvmfT.mjs +0 -13
  42. package/dist/packem_shared/shard.d-CL2Lmliv.d.mts +0 -39
  43. package/dist/packem_shared/shard.d-CL2Lmliv.d.ts +0 -39
@@ -1,5 +1,5 @@
1
- import { D as DurableObjectJurisdiction, S as ShardNamespaceLike } from "../packem_shared/shard.d-CL2Lmliv.js";
2
- export type { a as ShardStubLike } from "../packem_shared/shard.d-CL2Lmliv.js";
1
+ import { D as DurableObjectJurisdiction, S as ShardNamespaceLike } from "../packem_shared/shard.d-DVADjmEJ.js";
2
+ export type { a as ShardStubLike } from "../packem_shared/shard.d-DVADjmEJ.js";
3
3
  /** A raw RFC 822 message as accepted by the parser. */
4
4
  type RawInboundEmail = ArrayBuffer | ReadableStream<Uint8Array> | string | Uint8Array;
5
5
  /** One parsed attachment. `content` is preserved as the parser decoded it. */
@@ -16,16 +16,24 @@ interface InboundAttachment {
16
16
  mimeType: string;
17
17
  }
18
18
  /**
19
- * Sender-authentication verdicts pulled from the `Authentication-Results` header
20
- * the receiving MX (e.g. Cloudflare Email Routing) stamped on the message.
21
- *
22
- * SECURITY: Cloudflare Email Routing authenticates only the *recipient* domain,
23
- * **not** the sender. The envelope `from` and message content are trivially
24
- * spoofable, so a downstream handler MUST NOT make trust/authorization decisions
25
- * on `email.from` alone — gate on these verdicts (or your own policy) instead.
26
- * Verdicts are best-effort: when the receiving MX did not stamp an
27
- * `Authentication-Results` header, every field is `null` ("unknown").
28
- */
19
+ * Sender-authentication verdicts pulled from the `Authentication-Results` header
20
+ * the receiving MX (e.g. Cloudflare Email Routing) stamped on the message.
21
+ *
22
+ * SECURITY: Cloudflare Email Routing authenticates only the *recipient* domain,
23
+ * **not** the sender. The envelope `from` and message content are trivially
24
+ * spoofable, so a downstream handler MUST NOT make trust/authorization decisions
25
+ * on `email.from` alone — gate on these verdicts (or your own policy) instead.
26
+ * Verdicts are best-effort: when the receiving MX did not stamp an
27
+ * `Authentication-Results` header, every field is `null` ("unknown").
28
+ *
29
+ * SECURITY: verdicts are read from the **first/topmost** `Authentication-Results`
30
+ * header in document order. The receiving MX prepends its own genuine header per
31
+ * RFC 8601, so the topmost occurrence is the trustworthy one; any lower
32
+ * occurrences (which an untrusted sender can inject into the raw message) are
33
+ * ignored. As defense-in-depth a consumer may additionally verify the topmost
34
+ * header's `authserv-id` matches its receiving MX (e.g. Cloudflare) — that needs
35
+ * config this runtime-agnostic parser does not carry, so it is left to the host.
36
+ */
29
37
  interface InboundAuthentication {
30
38
  /** DKIM verdict (`"pass"`/`"fail"`/…), or `null` when not reported. */
31
39
  dkim: string | null;
@@ -39,10 +47,13 @@ interface InboundEmail {
39
47
  /** Decoded attachments (empty array when none). */
40
48
  attachments: InboundAttachment[];
41
49
  /**
42
- * Sender-authentication verdicts (DKIM/SPF/DMARC) parsed from the receiving
43
- * MX's `Authentication-Results` header. SECURITY: see {@link InboundAuthentication}
44
- * — `from` is spoofable; gate trust on these verdicts, not on `from`.
45
- */
50
+ * Sender-authentication verdicts (DKIM/SPF/DMARC) parsed from the receiving
51
+ * MX's **first/topmost** `Authentication-Results` header. SECURITY: see
52
+ * {@link InboundAuthentication} — `from` is spoofable; gate trust on these
53
+ * verdicts, not on `from`. Reading the raw `headers["authentication-results"]`
54
+ * map instead exposes last-wins (a lower, potentially attacker-injected)
55
+ * value — trust `authentication`, not the raw map.
56
+ */
46
57
  authentication: InboundAuthentication;
47
58
  /** Sender mailbox (`from`), CR/LF-checked. Empty string when the message omitted it. SECURITY: spoofable — do not trust for authorization. */
48
59
  from: string;
@@ -64,17 +75,17 @@ interface InboundEmail {
64
75
  to: string[];
65
76
  }
66
77
  /**
67
- * Parse a raw RFC 822 message into a normalised {@link InboundEmail}. Accepts the
68
- * shapes a Cloudflare Email Worker can hand off — `ReadableStream`, `ArrayBuffer`,
69
- * `Uint8Array`, or a decoded string.
70
- */
78
+ * Parse a raw RFC 822 message into a normalised {@link InboundEmail}. Accepts the
79
+ * shapes a Cloudflare Email Worker can hand off — `ReadableStream`, `ArrayBuffer`,
80
+ * `Uint8Array`, or a decoded string.
81
+ */
71
82
  declare const parseInboundEmail: (raw: RawInboundEmail) => Promise<InboundEmail>;
72
83
  /**
73
- * Structural projection of Cloudflare's `ForwardableEmailMessage` (verified
74
- * against `@cloudflare/workers-types`' `ForwardableEmailMessage`). Only the
75
- * members the handler touches are modelled, so the host can pass the real
76
- * runtime object without `@lunora/mail` importing `cloudflare:email`.
77
- */
84
+ * Structural projection of Cloudflare's `ForwardableEmailMessage` (verified
85
+ * against `@cloudflare/workers-types`' `ForwardableEmailMessage`). Only the
86
+ * members the handler touches are modelled, so the host can pass the real
87
+ * runtime object without `@lunora/mail` importing `cloudflare:email`.
88
+ */
78
89
  interface ForwardableEmailMessageLike {
79
90
  /** Forward this message to a verified destination address. */
80
91
  forward: (rcptTo: string, headers?: Headers) => Promise<unknown>;
@@ -107,43 +118,43 @@ interface InboundDispatchContext<TEnv = Record<string, unknown>> {
107
118
  /** Routes a parsed message into a Lunora function (or anywhere). */
108
119
  type InboundDispatch<TEnv = Record<string, unknown>> = (email: InboundEmail, context: InboundDispatchContext<TEnv>) => Promise<void>;
109
120
  /**
110
- * Opt-in sender-verification gate. Runs after `parse` and before `dispatch` with
111
- * the parsed message. Return `false` (or throw) to reject the message before it
112
- * reaches the privileged dispatch — use it to enforce DKIM/SPF/DMARC via
113
- * `email.authentication`, an allow-list, etc. Returning `true`/`undefined`
114
- * proceeds.
115
- */
121
+ * Opt-in sender-verification gate. Runs after `parse` and before `dispatch` with
122
+ * the parsed message. Return `false` (or throw) to reject the message before it
123
+ * reaches the privileged dispatch — use it to enforce DKIM/SPF/DMARC via
124
+ * `email.authentication`, an allow-list, etc. Returning `true`/`undefined`
125
+ * proceeds.
126
+ */
116
127
  type InboundVerify<TEnv = Record<string, unknown>> = (email: InboundEmail, context: InboundDispatchContext<TEnv>) => Promise<boolean | void> | boolean | void;
117
128
  /** Options for {@link createInboundEmailHandler}. */
118
129
  interface InboundEmailHandlerOptions<TEnv = Record<string, unknown>> {
119
130
  /** Routes the parsed message onward (e.g. {@link dispatchToLunoraFunction}). */
120
131
  dispatch: InboundDispatch<TEnv>;
121
132
  /**
122
- * Called when `parse`/`verify`/`dispatch` throws. The default rejects the
123
- * message via `message.setReject` so Cloudflare bounces/retries rather than
124
- * silently dropping it. SECURITY: the reject reason is delivered to the
125
- * (attacker-controlled) sender as a bounce, so the default reason is a fixed,
126
- * generic string and the real error is logged server-side. Override to log,
127
- * forward, or swallow — but never pass internal error text to `setReject`.
128
- */
133
+ * Called when `parse`/`verify`/`dispatch` throws. The default rejects the
134
+ * message via `message.setReject` so Cloudflare bounces/retries rather than
135
+ * silently dropping it. SECURITY: the reject reason is delivered to the
136
+ * (attacker-controlled) sender as a bounce, so the default reason is a fixed,
137
+ * generic string and the real error is logged server-side. Override to log,
138
+ * forward, or swallow — but never pass internal error text to `setReject`.
139
+ */
129
140
  onError?: (error: unknown, context: InboundDispatchContext<TEnv>) => Promise<void> | void;
130
141
  /** Parses raw bytes into an {@link InboundEmail} (e.g. `parseInboundEmail`). */
131
142
  parse: (raw: RawInboundEmail) => Promise<InboundEmail>;
132
143
  /**
133
- * Opt-in sender-authentication gate run before `dispatch`. SECURITY: inbound
134
- * `from` is spoofable and dispatch is privileged — supply this (gating on
135
- * `email.authentication`) when an inbound function makes any trust decision.
136
- */
144
+ * Opt-in sender-authentication gate run before `dispatch`. SECURITY: inbound
145
+ * `from` is spoofable and dispatch is privileged — supply this (gating on
146
+ * `email.authentication`) when an inbound function makes any trust decision.
147
+ */
137
148
  verify?: InboundVerify<TEnv>;
138
149
  }
139
150
  /** The `email(message, env, ctx)` callback the factory returns. */
140
151
  type InboundEmailHandler<TEnv = Record<string, unknown>> = (message: ForwardableEmailMessageLike, env: TEnv, context: unknown) => Promise<void>;
141
152
  /**
142
- * Build the `email(message, env, ctx)` handler. It (a) reads `message.raw`,
143
- * (b) parses it via `parse`, (c) runs the optional `verify` gate, then
144
- * (d) calls `dispatch(parsed, { message, env, ctx })`. Any throw (or a falsy
145
- * `verify`) routes through `onError` (default: a generic `message.setReject`).
146
- */
153
+ * Build the `email(message, env, ctx)` handler. It (a) reads `message.raw`,
154
+ * (b) parses it via `parse`, (c) runs the optional `verify` gate, then
155
+ * (d) calls `dispatch(parsed, { message, env, ctx })`. Any throw (or a falsy
156
+ * `verify`) routes through `onError` (default: a generic `message.setReject`).
157
+ */
147
158
  declare const createInboundEmailHandler: <TEnv = Record<string, unknown>>(options: InboundEmailHandlerOptions<TEnv>) => InboundEmailHandler<TEnv>;
148
159
  /** The `RpcEnvelope` shape the runtime's `/_lunora/rpc` path consumes. */
149
160
  interface RpcEnvelope {
@@ -154,23 +165,23 @@ interface RpcEnvelope {
154
165
  /** Options for {@link dispatchToLunoraFunction}. */
155
166
  interface DispatchToLunoraFunctionOptions<TEnv = Record<string, unknown>> {
156
167
  /**
157
- * Admin bearer authorizing the shard RPC. Defaults to reading
158
- * `env.LUNORA_ADMIN_TOKEN` at dispatch time.
159
- */
168
+ * Admin bearer authorizing the shard RPC. Defaults to reading
169
+ * `env.LUNORA_ADMIN_TOKEN` at dispatch time.
170
+ */
160
171
  adminToken?: string;
161
172
  /** `functionPath` of the target mutation/action (e.g. `"inbound:onEmail"`). */
162
173
  functionPath: string;
163
174
  /**
164
- * Pin inbound dispatch to a Cloudflare data-residency jurisdiction. Pass the
165
- * same value as the worker's `jurisdiction` so inbound mail routes to the
166
- * jurisdiction-pinned shard. Omit for the un-pinned global namespace.
167
- */
175
+ * Pin inbound dispatch to a Cloudflare data-residency jurisdiction. Pass the
176
+ * same value as the worker's `jurisdiction` so inbound mail routes to the
177
+ * jurisdiction-pinned shard. Omit for the un-pinned global namespace.
178
+ */
168
179
  jurisdiction?: DurableObjectJurisdiction;
169
180
  /**
170
- * Map the parsed message into the function's args. Defaults to passing the
171
- * whole {@link InboundEmail} with binary attachment `content` base64-encoded
172
- * (see {@link toJsonSafeEmail}) so it survives the JSON-serialised RPC body.
173
- */
181
+ * Map the parsed message into the function's args. Defaults to passing the
182
+ * whole {@link InboundEmail} with binary attachment `content` base64-encoded
183
+ * (see {@link toJsonSafeEmail}) so it survives the JSON-serialised RPC body.
184
+ */
174
185
  resolveArgs?: (email: InboundEmail, context: InboundDispatchContext<TEnv>) => unknown;
175
186
  /** The `SHARD` Durable Object namespace. */
176
187
  shard: ShardNamespaceLike;
@@ -178,16 +189,144 @@ interface DispatchToLunoraFunctionOptions<TEnv = Record<string, unknown>> {
178
189
  shardKey?: string;
179
190
  }
180
191
  /**
181
- * Build a {@link InboundDispatch} that posts an {@link RpcEnvelope} to the root
182
- * shard stub — the same admin-RPC-over-shard path the dev capture sink uses
183
- * (`from-env.ts`) — routing the parsed message into a named Lunora
184
- * mutation/action. Throws on a non-2xx RPC or a missing admin token so the
185
- * handler's `onError` (default `setReject`) bounces the message.
186
- *
187
- * SECURITY: the RPC carries the admin bearer, so the target function runs with
188
- * RLS bypassed over fully attacker-controlled, spoofable input — see the module
189
- * docstring. Verify the sender (`verify` hook / `email.authentication`) before
190
- * making any trust decision in the target function.
191
- */
192
+ * Build a {@link InboundDispatch} that posts an {@link RpcEnvelope} to the root
193
+ * shard stub — the same admin-RPC-over-shard path the dev capture sink uses
194
+ * (`from-env.ts`) — routing the parsed message into a named Lunora
195
+ * mutation/action. Throws on a non-2xx RPC or a missing admin token so the
196
+ * handler's `onError` (default `setReject`) bounces the message.
197
+ *
198
+ * SECURITY: the RPC carries the admin bearer, so the target function runs with
199
+ * RLS bypassed over fully attacker-controlled, spoofable input — see the module
200
+ * docstring. Verify the sender (`verify` hook / `email.authentication`) before
201
+ * making any trust decision in the target function.
202
+ */
192
203
  declare const dispatchToLunoraFunction: <TEnv extends Record<string, unknown> = Record<string, unknown>>(options: DispatchToLunoraFunctionOptions<TEnv>) => InboundDispatch<TEnv>;
193
- export { type DispatchToLunoraFunctionOptions, type ForwardableEmailMessageLike, type InboundAttachment, type InboundAuthentication, type InboundDispatch, type InboundDispatchContext, type InboundEmail, type InboundEmailHandler, type InboundEmailHandlerOptions, type InboundVerify, type RawInboundEmail, type RpcEnvelope, type ShardNamespaceLike, createInboundEmailHandler, dispatchToLunoraFunction, parseInboundEmail };
204
+ export {
205
+ /**
206
+ * `@lunora/mail/inbound` — inbound Email Routing support.
207
+ *
208
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
209
+ * mutation/action:
210
+ *
211
+ * ```ts
212
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
213
+ *
214
+ * export const email = createInboundEmailHandler({
215
+ * parse: parseInboundEmail,
216
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
217
+ * });
218
+ * ```
219
+ */
220
+ type DispatchToLunoraFunctionOptions,
221
+ /**
222
+ * `@lunora/mail/inbound` — inbound Email Routing support.
223
+ *
224
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
225
+ * mutation/action:
226
+ *
227
+ * ```ts
228
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
229
+ *
230
+ * export const email = createInboundEmailHandler({
231
+ * parse: parseInboundEmail,
232
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
233
+ * });
234
+ * ```
235
+ */
236
+ type ForwardableEmailMessageLike, type InboundAttachment, type InboundAuthentication,
237
+ /**
238
+ * `@lunora/mail/inbound` — inbound Email Routing support.
239
+ *
240
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
241
+ * mutation/action:
242
+ *
243
+ * ```ts
244
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
245
+ *
246
+ * export const email = createInboundEmailHandler({
247
+ * parse: parseInboundEmail,
248
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
249
+ * });
250
+ * ```
251
+ */
252
+ type InboundDispatch,
253
+ /**
254
+ * `@lunora/mail/inbound` — inbound Email Routing support.
255
+ *
256
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
257
+ * mutation/action:
258
+ *
259
+ * ```ts
260
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
261
+ *
262
+ * export const email = createInboundEmailHandler({
263
+ * parse: parseInboundEmail,
264
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
265
+ * });
266
+ * ```
267
+ */
268
+ type InboundDispatchContext, type InboundEmail,
269
+ /**
270
+ * `@lunora/mail/inbound` — inbound Email Routing support.
271
+ *
272
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
273
+ * mutation/action:
274
+ *
275
+ * ```ts
276
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
277
+ *
278
+ * export const email = createInboundEmailHandler({
279
+ * parse: parseInboundEmail,
280
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
281
+ * });
282
+ * ```
283
+ */
284
+ type InboundEmailHandler,
285
+ /**
286
+ * `@lunora/mail/inbound` — inbound Email Routing support.
287
+ *
288
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
289
+ * mutation/action:
290
+ *
291
+ * ```ts
292
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
293
+ *
294
+ * export const email = createInboundEmailHandler({
295
+ * parse: parseInboundEmail,
296
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
297
+ * });
298
+ * ```
299
+ */
300
+ type InboundEmailHandlerOptions,
301
+ /**
302
+ * `@lunora/mail/inbound` — inbound Email Routing support.
303
+ *
304
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
305
+ * mutation/action:
306
+ *
307
+ * ```ts
308
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
309
+ *
310
+ * export const email = createInboundEmailHandler({
311
+ * parse: parseInboundEmail,
312
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
313
+ * });
314
+ * ```
315
+ */
316
+ type InboundVerify, type RawInboundEmail,
317
+ /**
318
+ * `@lunora/mail/inbound` — inbound Email Routing support.
319
+ *
320
+ * Wire a Cloudflare Email Worker entry to route received mail into a Lunora
321
+ * mutation/action:
322
+ *
323
+ * ```ts
324
+ * import { createInboundEmailHandler, parseInboundEmail, dispatchToLunoraFunction } from "@lunora/mail/inbound";
325
+ *
326
+ * export const email = createInboundEmailHandler({
327
+ * parse: parseInboundEmail,
328
+ * dispatch: dispatchToLunoraFunction({ shard: env.SHARD, functionPath: "inbound:onEmail" }),
329
+ * });
330
+ * ```
331
+ */
332
+ type RpcEnvelope, type ShardNamespaceLike, createInboundEmailHandler, dispatchToLunoraFunction, parseInboundEmail };
@@ -1,2 +1 @@
1
- export { createInboundEmailHandler, dispatchToLunoraFunction } from '../packem_shared/createInboundEmailHandler-D0uCOrU-.mjs';
2
- export { parseInboundEmail } from '../packem_shared/parseInboundEmail-Bw9u_1oc.mjs';
1
+ import{createInboundEmailHandler as r,dispatchToLunoraFunction as a}from"../packem_shared/createInboundEmailHandler-D2i0mEBB.mjs";import{parseInboundEmail as t}from"../packem_shared/parseInboundEmail-Cxe54g-h.mjs";export{r as createInboundEmailHandler,a as dispatchToLunoraFunction,t as parseInboundEmail};
package/dist/index.d.mts CHANGED
@@ -1,20 +1,20 @@
1
- import { M as MailTransport, L as LunoraMailOptions, a as Mailer, b as MailboxSink, S as SendOptions } from "./packem_shared/capture-transport.d-ChnhdPO2.mjs";
2
- export { type C as CapturedMail, type Q as QueueLike, type c as SendPayload, d as createCaptureTransport } from "./packem_shared/capture-transport.d-ChnhdPO2.mjs";
3
- import { D as DurableObjectJurisdiction } from "./packem_shared/shard.d-CL2Lmliv.mjs";
1
+ import { M as MailTransport, L as LunoraMailOptions, a as Mailer, b as MailboxSink, S as SendOptions } from "./packem_shared/capture-transport.d-_rIl9W6N.mjs";
2
+ export { type C as CapturedMail, type Q as QueueLike, type c as SendPayload, d as createCaptureTransport } from "./packem_shared/capture-transport.d-_rIl9W6N.mjs";
3
+ import { D as DurableObjectJurisdiction } from "./packem_shared/shard.d-DVADjmEJ.mjs";
4
4
  import { ReactElement } from 'react';
5
5
  /**
6
- * Sends a raw RFC 822 message through a Worker's Email send binding. The Workers
7
- * runtime owns the binding, so the caller supplies this thin callback — keeping
8
- * `@lunora/mail` free of a `cloudflare:email` import and unit-testable. Wire it
9
- * in your project as:
10
- *
11
- * ```ts
12
- * send: async (from, to, raw) => {
13
- * const { EmailMessage } = await import("cloudflare:email");
14
- * await env.SEND_EMAIL.send(new EmailMessage(from, to, raw));
15
- * }
16
- * ```
17
- */
6
+ * Sends a raw RFC 822 message through a Worker's Email send binding. The Workers
7
+ * runtime owns the binding, so the caller supplies this thin callback — keeping
8
+ * `@lunora/mail` free of a `cloudflare:email` import and unit-testable. Wire it
9
+ * in your project as:
10
+ *
11
+ * ```ts
12
+ * send: async (from, to, raw) => {
13
+ * const { EmailMessage } = await import("cloudflare:email");
14
+ * await env.SEND_EMAIL.send(new EmailMessage(from, to, raw));
15
+ * }
16
+ * ```
17
+ */
18
18
  type CloudflareSend = (from: string, to: string, raw: string) => Promise<void>;
19
19
  interface CloudflareTransportOptions {
20
20
  /** Default sender used when a `SendOptions.from` isn't supplied. */
@@ -23,34 +23,34 @@ interface CloudflareTransportOptions {
23
23
  send: CloudflareSend;
24
24
  }
25
25
  /**
26
- * Build the default Cloudflare Email Workers transport via `@visulima/email`.
27
- * Cloudflare's `send_email` binding is **single-recipient** and only delivers to
28
- * **verified Email Routing destination addresses**, and the underlying provider
29
- * rejects any `cc`/`bcc` or a non-single `to` outright. So this enforces a single
30
- * `to` recipient (throwing a clear error instead of silently dropping the rest)
31
- * and rejects `cc`/`bcc` rather than forwarding them into a generic "send failed".
32
- * Multi-recipient transactional mail must fan out one send per recipient at the
33
- * call site. In dev the capture transport intercepts before this runs, so the
34
- * verified-address constraint never bites the dev loop.
35
- */
26
+ * Build the default Cloudflare Email Workers transport via `@visulima/email`.
27
+ * Cloudflare's `send_email` binding is **single-recipient** and only delivers to
28
+ * **verified Email Routing destination addresses**, and the underlying provider
29
+ * rejects any `cc`/`bcc` or a non-single `to` outright. So this enforces a single
30
+ * `to` recipient (throwing a clear error instead of silently dropping the rest)
31
+ * and rejects `cc`/`bcc` rather than forwarding them into a generic "send failed".
32
+ * Multi-recipient transactional mail must fan out one send per recipient at the
33
+ * call site. In dev the capture transport intercepts before this runs, so the
34
+ * verified-address constraint never bites the dev loop.
35
+ */
36
36
  declare const createCloudflareTransport: (options: CloudflareTransportOptions) => MailTransport;
37
37
  /**
38
- * Create a mailer bound to a transport.
39
- *
40
- * SECURITY — recipient policy and HTML content are the caller's responsibility.
41
- * The mailer fully blocks header/CRLF/comma injection in addresses
42
- * (`assertSafeAddresses` / `assertSafeHeaderValue`), but it does NOT decide WHO
43
- * you may send to or WHAT HTML you render.
44
- *
45
- * Open relay: derive `to`/`cc`/`bcc` from server-trusted state, never from raw
46
- * request input, and prefer a fixed/allowlisted `from` — sending to an arbitrary
47
- * user-supplied address turns your deployment into a spam relay.
48
- *
49
- * Template XSS / content injection: treat template HTML like any other HTML sink
50
- * — never interpolate untrusted data into raw markup (or a
51
- * `dangerouslySetInnerHTML`-style template) without escaping. The mailer sends
52
- * whatever HTML you hand it verbatim.
53
- */
38
+ * Create a mailer bound to a transport.
39
+ *
40
+ * SECURITY — recipient policy and HTML content are the caller's responsibility.
41
+ * The mailer fully blocks header/CRLF/comma injection in addresses
42
+ * (`assertSafeAddresses` / `assertSafeHeaderValue`), but it does NOT decide WHO
43
+ * you may send to or WHAT HTML you render.
44
+ *
45
+ * Open relay: derive `to`/`cc`/`bcc` from server-trusted state, never from raw
46
+ * request input, and prefer a fixed/allowlisted `from` — sending to an arbitrary
47
+ * user-supplied address turns your deployment into a spam relay.
48
+ *
49
+ * Template XSS / content injection: treat template HTML like any other HTML sink
50
+ * — never interpolate untrusted data into raw markup (or a
51
+ * `dangerouslySetInnerHTML`-style template) without escaping. The mailer sends
52
+ * whatever HTML you hand it verbatim.
53
+ */
54
54
  declare const createMailer: (options: LunoraMailOptions) => Mailer;
55
55
  /** A Worker `env` projected as a plain record (vars, secrets, and bindings are `unknown`-valued). */
56
56
  type MailEnv = Record<string, unknown>;
@@ -59,39 +59,39 @@ interface FromEnvOptions {
59
59
  /** RFC 822 send callback bound to the Worker's `send_email` binding (Cloudflare default transport). */
60
60
  cloudflareSend?: CloudflareSend;
61
61
  /**
62
- * Pin the captured-mail inbox shard to a Cloudflare data-residency
63
- * jurisdiction. Pass the same value as the worker's `jurisdiction` so the
64
- * dev inbox co-resides with app data. Omit for the un-pinned global namespace.
65
- */
62
+ * Pin the captured-mail inbox shard to a Cloudflare data-residency
63
+ * jurisdiction. Pass the same value as the worker's `jurisdiction` so the
64
+ * dev inbox co-resides with app data. Omit for the un-pinned global namespace.
65
+ */
66
66
  jurisdiction?: DurableObjectJurisdiction;
67
67
  /** Shard the captured-mail inbox lives on; override if your worker sets a custom `defaultShardKey`. */
68
68
  rootShard?: string;
69
69
  }
70
70
  /**
71
- * Whether outbound mail should be captured (into the studio inbox) rather than
72
- * delivered. Explicit `LUNORA_MAIL_CAPTURE` (`"1"`/`"true"` vs `"0"`/`"false"`)
73
- * always wins; unset, capture is on only in a development environment. It does
74
- * NOT fall back to "no SEND_EMAIL binding ⇒ capture" — a production deploy that
75
- * forgot the binding must fail loudly on send, not silently swallow mail.
76
- */
71
+ * Whether outbound mail should be captured (into the studio inbox) rather than
72
+ * delivered. Explicit `LUNORA_MAIL_CAPTURE` (`"1"`/`"true"` vs `"0"`/`"false"`)
73
+ * always wins; unset, capture is on only in a development environment. It does
74
+ * NOT fall back to "no SEND_EMAIL binding ⇒ capture" — a production deploy that
75
+ * forgot the binding must fail loudly on send, not silently swallow mail.
76
+ */
77
77
  declare const shouldCaptureMail: (env: MailEnv) => boolean;
78
78
  /**
79
- * Build the {@link MailboxSink} that records a captured message into the studio's
80
- * root-shard inbox via the reserved `recordMail` admin RPC — the same
81
- * worker→root-shard path the runtime uses for auth events. Best-effort: without
82
- * the `SHARD` binding or `LUNORA_ADMIN_TOKEN` it returns a sentinel id so a send
83
- * never fails for lack of somewhere to record.
84
- */
79
+ * Build the {@link MailboxSink} that records a captured message into the studio's
80
+ * root-shard inbox via the reserved `recordMail` admin RPC — the same
81
+ * worker→root-shard path the runtime uses for auth events. Best-effort: without
82
+ * the `SHARD` binding or `LUNORA_ADMIN_TOKEN` it returns a sentinel id so a send
83
+ * never fails for lack of somewhere to record.
84
+ */
85
85
  declare const createCaptureSink: (env: MailEnv, rootShard?: string, jurisdiction?: DurableObjectJurisdiction) => MailboxSink;
86
86
  /**
87
- * Build a {@link Mailer} from a Worker `env`. In a dev environment every send is
88
- * captured into the studio's Mail inbox; otherwise it delivers via the supplied
89
- * `cloudflareSend` (the `SEND_EMAIL` binding) or, failing that, `RESEND_API_KEY`.
90
- * Throws when neither a capture context nor a real transport is available, so a
91
- * misconfigured production deploy fails loudly instead of silently dropping mail.
92
- *
93
- * `MAIL_FROM` is required (the default sender).
94
- */
87
+ * Build a {@link Mailer} from a Worker `env`. In a dev environment every send is
88
+ * captured into the studio's Mail inbox; otherwise it delivers via the supplied
89
+ * `cloudflareSend` (the `SEND_EMAIL` binding) or, failing that, `RESEND_API_KEY`.
90
+ * Throws when neither a capture context nor a real transport is available, so a
91
+ * misconfigured production deploy fails loudly instead of silently dropping mail.
92
+ *
93
+ * `MAIL_FROM` is required (the default sender).
94
+ */
95
95
  declare const createMailerFromEnv: (env: MailEnv, options?: FromEnvOptions) => Mailer;
96
96
  /** Serializable representation of a `SendOptions` payload — drops the `react` field. */
97
97
  interface QueuedSend {
@@ -106,45 +106,45 @@ interface QueuedSend {
106
106
  to: string | string[];
107
107
  }
108
108
  /**
109
- * Narrow a `SendOptions` to its serializable `QueuedSend` shape by dropping the
110
- * non-cloneable `react` field. React elements are not structured-cloneable, so
111
- * the queue body must carry only the pre-rendered html/text and scalar fields.
112
- */
109
+ * Narrow a `SendOptions` to its serializable `QueuedSend` shape by dropping the
110
+ * non-cloneable `react` field. React elements are not structured-cloneable, so
111
+ * the queue body must carry only the pre-rendered html/text and scalar fields.
112
+ */
113
113
  declare const toQueuedPayload: (options: SendOptions) => QueuedSend;
114
114
  /**
115
- * Helper used by Queue consumers: rehydrate a `QueuedSend` payload and forward
116
- * to a configured `Mailer.send()`. Use this inside your Worker's `queue()`
117
- * handler.
118
- *
119
- * ```ts
120
- * export default {
121
- * queue: async (batch, env) => {
122
- * const mailer = createMailer({ apiKey: env.RESEND_API_KEY, from: "..." });
123
- * for (const message of batch.messages) {
124
- * await consumeQueuedSend(mailer, message.body);
125
- * }
126
- * },
127
- * };
128
- * ```
129
- */
115
+ * Helper used by Queue consumers: rehydrate a `QueuedSend` payload and forward
116
+ * to a configured `Mailer.send()`. Use this inside your Worker's `queue()`
117
+ * handler.
118
+ *
119
+ * ```ts
120
+ * export default {
121
+ * queue: async (batch, env) => {
122
+ * const mailer = createMailer({ apiKey: env.RESEND_API_KEY, from: "..." });
123
+ * for (const message of batch.messages) {
124
+ * await consumeQueuedSend(mailer, message.body);
125
+ * }
126
+ * },
127
+ * };
128
+ * ```
129
+ */
130
130
  declare const consumeQueuedSend: (mailer: Mailer, payload: unknown) => Promise<{
131
131
  id: string;
132
132
  }>;
133
133
  /**
134
- * Render a React element to an HTML/text pair suitable for inlining into a
135
- * provider payload. Wraps `@react-email/render` so we can swap to
136
- * `@visulima/email`'s react-email template engine without touching callers.
137
- */
134
+ * Render a React element to an HTML/text pair suitable for inlining into a
135
+ * provider payload. Wraps `@react-email/render` so we can swap to
136
+ * `@visulima/email`'s react-email template engine without touching callers.
137
+ */
138
138
  declare const renderEmail: (element: ReactElement) => Promise<{
139
139
  html: string;
140
140
  text: string;
141
141
  }>;
142
142
  /**
143
- * Build a Resend-backed transport via `@visulima/email`. Wraps the provider's
144
- * `sendEmail()` into the minimal `{ send(payload) -> { id } }` shape the rest of
145
- * `@lunora/mail` consumes. Kept reachable as a named export so a project that
146
- * prefers Resend over the Cloudflare default can pass
147
- * `transport: createResendTransport(apiKey, from)` to `createMailer`.
148
- */
143
+ * Build a Resend-backed transport via `@visulima/email`. Wraps the provider's
144
+ * `sendEmail()` into the minimal `{ send(payload) -> { id } }` shape the rest of
145
+ * `@lunora/mail` consumes. Kept reachable as a named export so a project that
146
+ * prefers Resend over the Cloudflare default can pass
147
+ * `transport: createResendTransport(apiKey, from)` to `createMailer`.
148
+ */
149
149
  declare const createResendTransport: (apiKey: string, defaultFrom: string) => MailTransport;
150
150
  export { type CloudflareSend, type CloudflareTransportOptions, type FromEnvOptions, type LunoraMailOptions, type MailEnv, type MailTransport, type MailboxSink, type Mailer, type QueuedSend, type SendOptions, consumeQueuedSend, createCaptureSink, createCloudflareTransport, createMailer, createMailerFromEnv, createResendTransport, renderEmail, shouldCaptureMail, toQueuedPayload };