devflare 1.0.0-next.20 → 1.0.0-next.21

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 (58) hide show
  1. package/LLM.md +9 -4
  2. package/README.md +10 -2
  3. package/dist/browser.js +3 -3
  4. package/dist/build-b1z6wqet.js +54 -0
  5. package/dist/build-x7maz3eb.js +54 -0
  6. package/dist/cli/commands/config.d.ts.map +1 -1
  7. package/dist/cli/commands/dev.d.ts +1 -0
  8. package/dist/cli/commands/dev.d.ts.map +1 -1
  9. package/dist/cli/commands/doctor.d.ts.map +1 -1
  10. package/dist/cli/help-pages/pages/core.d.ts.map +1 -1
  11. package/dist/cli/index.js +1 -1
  12. package/dist/config-qj5jw8km.js +93 -0
  13. package/dist/deploy-jf3yczsz.js +1055 -0
  14. package/dist/deploy-xqm869nf.js +1055 -0
  15. package/dist/dev-bgpxrwms.js +2551 -0
  16. package/dist/dev-kzs65xcr.js +2551 -0
  17. package/dist/dev-server/dev-server-state.d.ts +2 -0
  18. package/dist/dev-server/dev-server-state.d.ts.map +1 -1
  19. package/dist/dev-server/miniflare-dev-config.d.ts +4 -0
  20. package/dist/dev-server/miniflare-dev-config.d.ts.map +1 -1
  21. package/dist/dev-server/server.d.ts.map +1 -1
  22. package/dist/dev-zgx7fhe9.js +2553 -0
  23. package/dist/doctor-0a2brpyz.js +259 -0
  24. package/dist/index-05pbj4hy.js +1193 -0
  25. package/dist/index-3edvz3hs.js +124 -0
  26. package/dist/index-50em8s6c.js +898 -0
  27. package/dist/index-666tdx14.js +895 -0
  28. package/dist/index-8p7rxkbs.js +1426 -0
  29. package/dist/index-aqrwyy57.js +288 -0
  30. package/dist/index-bj5avaba.js +109 -0
  31. package/dist/index-dgww0ewn.js +574 -0
  32. package/dist/index-f1yshy4s.js +412 -0
  33. package/dist/index-hpwa6vsw.js +239 -0
  34. package/dist/index-kxc4gtyt.js +574 -0
  35. package/dist/index-nxkesg55.js +68 -0
  36. package/dist/index-p7q23nce.js +1031 -0
  37. package/dist/index-pt49cgjv.js +1426 -0
  38. package/dist/index-rp0aye39.js +1426 -0
  39. package/dist/index-tknbyxzn.js +2202 -0
  40. package/dist/index.js +4 -4
  41. package/dist/runtime/index.js +4 -4
  42. package/dist/sveltekit/index.js +2 -2
  43. package/dist/test/index.js +62 -440
  44. package/dist/test/resolve-service-bindings.d.ts +63 -3
  45. package/dist/test/resolve-service-bindings.d.ts.map +1 -1
  46. package/dist/types-vhvt4hvm.js +693 -0
  47. package/dist/utils/send-email.d.ts.map +1 -1
  48. package/dist/utils/send-email.js +1 -1
  49. package/dist/vite/index.js +4 -3
  50. package/dist/vite/plugin-context.d.ts +3 -1
  51. package/dist/vite/plugin-context.d.ts.map +1 -1
  52. package/dist/vite/plugin-programmatic.d.ts.map +1 -1
  53. package/dist/vite/plugin-service-bindings.d.ts +13 -0
  54. package/dist/vite/plugin-service-bindings.d.ts.map +1 -0
  55. package/dist/vite/plugin.d.ts +4 -2
  56. package/dist/vite/plugin.d.ts.map +1 -1
  57. package/dist/worker-entrypoint-3rmzd4c1.js +15 -0
  58. package/package.json +1 -1
@@ -0,0 +1,412 @@
1
+ import {
2
+ createContextProxy,
3
+ createFetchEvent,
4
+ getContextOrNull,
5
+ runWithEventContext
6
+ } from "./index-tknbyxzn.js";
7
+
8
+ // src/runtime/exports.ts
9
+ function createReadonlyProxy(getter, name) {
10
+ return createContextProxy(getter, name, { mutable: false });
11
+ }
12
+ var env = createReadonlyProxy(() => getContextOrNull()?.env, "env");
13
+ var ctx = createReadonlyProxy(() => getContextOrNull()?.ctx, "ctx");
14
+ var event = createReadonlyProxy(() => getContextOrNull()?.event, "event");
15
+ var locals = createContextProxy(() => getContextOrNull()?.locals, "locals");
16
+ // src/runtime/middleware.ts
17
+ var FETCH_SEQUENCE_SYMBOL = Symbol.for("devflare.fetch-sequence");
18
+ var FETCH_RESOLVE_STYLE_SYMBOL = Symbol.for("devflare.fetch-resolve-style");
19
+ var FETCH_WORKER_STYLE_SYMBOL = Symbol.for("devflare.fetch-worker-style");
20
+ var QUEUE_WORKER_STYLE_SYMBOL = Symbol.for("devflare.queue-worker-style");
21
+ var SCHEDULED_WORKER_STYLE_SYMBOL = Symbol.for("devflare.scheduled-worker-style");
22
+ function createNotFoundResponse() {
23
+ return new Response("Not Found", { status: 404 });
24
+ }
25
+ function isFunction(value) {
26
+ return typeof value === "function";
27
+ }
28
+ function markResolveStyle(handler) {
29
+ Object.defineProperty(handler, FETCH_RESOLVE_STYLE_SYMBOL, {
30
+ value: true,
31
+ enumerable: false,
32
+ configurable: true,
33
+ writable: false
34
+ });
35
+ return handler;
36
+ }
37
+ function markWorkerStyle(handler) {
38
+ Object.defineProperty(handler, FETCH_WORKER_STYLE_SYMBOL, {
39
+ value: true,
40
+ enumerable: false,
41
+ configurable: true,
42
+ writable: false
43
+ });
44
+ return handler;
45
+ }
46
+ function defineFetchHandler(handler, options) {
47
+ if (options?.style === "resolve") {
48
+ return markResolveStyle(handler);
49
+ }
50
+ if (options?.style === "worker") {
51
+ return markWorkerStyle(handler);
52
+ }
53
+ return handler;
54
+ }
55
+ function hasResolveStyleMarker(handler) {
56
+ const record = handler;
57
+ return Boolean(record[FETCH_RESOLVE_STYLE_SYMBOL] || record[FETCH_SEQUENCE_SYMBOL]);
58
+ }
59
+ function hasWorkerStyleMarker(handler) {
60
+ const record = handler;
61
+ return Boolean(record[FETCH_WORKER_STYLE_SYMBOL]);
62
+ }
63
+ function isResolveStyleFunction(handler) {
64
+ return hasResolveStyleMarker(handler);
65
+ }
66
+ function assertExplicit2ArgStyle(handler) {
67
+ if (handler.length !== 2) {
68
+ return;
69
+ }
70
+ if (hasResolveStyleMarker(handler) || hasWorkerStyleMarker(handler)) {
71
+ return;
72
+ }
73
+ throw new Error("[devflare] Ambiguous 2-argument fetch handler. The calling convention must be declared explicitly via " + "`defineFetchHandler(fn, { style: 'resolve' })` (for `(event, resolve) => Response`) or " + "`defineFetchHandler(fn, { style: 'worker' })` (for `(request, env) => Response`). " + "Single-arg `(event) => Response` and 3-arg worker-style `(request, env, ctx) => Response` " + "handlers do not require wrapping.");
74
+ }
75
+ function defineQueueHandler(handler) {
76
+ Object.defineProperty(handler, QUEUE_WORKER_STYLE_SYMBOL, {
77
+ value: true,
78
+ enumerable: false,
79
+ configurable: true,
80
+ writable: false
81
+ });
82
+ return handler;
83
+ }
84
+ function defineScheduledHandler(handler) {
85
+ Object.defineProperty(handler, SCHEDULED_WORKER_STYLE_SYMBOL, {
86
+ value: true,
87
+ enumerable: false,
88
+ configurable: true,
89
+ writable: false
90
+ });
91
+ return handler;
92
+ }
93
+ function hasQueueWorkerStyleMarker(handler) {
94
+ const record = handler;
95
+ return Boolean(record[QUEUE_WORKER_STYLE_SYMBOL]);
96
+ }
97
+ function hasScheduledWorkerStyleMarker(handler) {
98
+ const record = handler;
99
+ return Boolean(record[SCHEDULED_WORKER_STYLE_SYMBOL]);
100
+ }
101
+ function assertExplicitQueueHandlerStyle(handler) {
102
+ if (handler.length !== 2) {
103
+ return;
104
+ }
105
+ if (hasQueueWorkerStyleMarker(handler)) {
106
+ return;
107
+ }
108
+ throw new Error("[devflare] Ambiguous 2-argument queue handler. The calling convention must be declared explicitly via " + "`defineQueueHandler(fn)` for `(batch, env) => void` worker-style handlers. " + "Single-arg `(event) => void` and 3-arg `(batch, env, ctx) => void` handlers do not require wrapping.");
109
+ }
110
+ function assertExplicitScheduledHandlerStyle(handler) {
111
+ if (handler.length !== 2) {
112
+ return;
113
+ }
114
+ if (hasScheduledWorkerStyleMarker(handler)) {
115
+ return;
116
+ }
117
+ throw new Error("[devflare] Ambiguous 2-argument scheduled handler. The calling convention must be declared explicitly via " + "`defineScheduledHandler(fn)` for `(controller, env) => void` worker-style handlers. " + "Single-arg `(event) => void` and 3-arg `(controller, env, ctx) => void` handlers do not require wrapping.");
118
+ }
119
+ function isWorkerStyleFetchFunction(handler) {
120
+ if (isResolveStyleFunction(handler)) {
121
+ return false;
122
+ }
123
+ if (handler.length >= 3) {
124
+ return true;
125
+ }
126
+ return hasWorkerStyleMarker(handler);
127
+ }
128
+ function invokeWorkerStyleFetchFunction(handler, event2) {
129
+ return handler(event2.request, event2.env, event2.ctx);
130
+ }
131
+ function bindMethod(target, key) {
132
+ if (!target || typeof target !== "object") {
133
+ return null;
134
+ }
135
+ const value = target[key];
136
+ if (!isFunction(value)) {
137
+ return null;
138
+ }
139
+ const boundHandler = value.bind(target);
140
+ if (isResolveStyleFunction(value)) {
141
+ markResolveStyle(boundHandler);
142
+ }
143
+ if (hasWorkerStyleMarker(value)) {
144
+ markWorkerStyle(boundHandler);
145
+ }
146
+ return boundHandler;
147
+ }
148
+ function createFetchSequence(middlewares) {
149
+ return async (event2, resolve = async () => createNotFoundResponse()) => {
150
+ const executeMiddleware = async (index, activeEvent) => {
151
+ if (index >= middlewares.length) {
152
+ return resolve(activeEvent);
153
+ }
154
+ const middleware = middlewares[index];
155
+ return middleware(activeEvent, async (nextEvent = activeEvent) => {
156
+ return executeMiddleware(index + 1, nextEvent);
157
+ });
158
+ };
159
+ return executeMiddleware(0, event2);
160
+ };
161
+ }
162
+ function sequence(...middlewares) {
163
+ const composed = createFetchSequence(middlewares);
164
+ Object.defineProperty(composed, FETCH_SEQUENCE_SYMBOL, {
165
+ value: true,
166
+ enumerable: false,
167
+ configurable: false,
168
+ writable: false
169
+ });
170
+ return markResolveStyle(composed);
171
+ }
172
+ function getDefaultHandleHandler(module) {
173
+ return bindMethod(module.default, "handle");
174
+ }
175
+ function getDefaultFetchHandler(module) {
176
+ const defaultExport = module.default;
177
+ if (isFunction(defaultExport)) {
178
+ return defaultExport;
179
+ }
180
+ return bindMethod(defaultExport, "fetch");
181
+ }
182
+ function getPrimaryFetchEntryCandidates(module) {
183
+ const candidates = [];
184
+ const namedHandle = isFunction(module.handle) ? module.handle : null;
185
+ if (namedHandle) {
186
+ candidates.push({
187
+ name: "handle",
188
+ handler: namedHandle
189
+ });
190
+ }
191
+ const namedFetch = isFunction(module.fetch) ? module.fetch : null;
192
+ if (namedFetch) {
193
+ candidates.push({
194
+ name: "fetch",
195
+ handler: namedFetch
196
+ });
197
+ }
198
+ const defaultHandle = getDefaultHandleHandler(module);
199
+ if (defaultHandle) {
200
+ candidates.push({
201
+ name: "default.handle",
202
+ handler: defaultHandle
203
+ });
204
+ }
205
+ const defaultFetch = getDefaultFetchHandler(module);
206
+ if (defaultFetch) {
207
+ candidates.push({
208
+ name: isFunction(module.default) ? "default" : "default.fetch",
209
+ handler: defaultFetch
210
+ });
211
+ }
212
+ return candidates;
213
+ }
214
+ function assertSinglePrimaryFetchEntry(candidates) {
215
+ if (candidates.length <= 1) {
216
+ return;
217
+ }
218
+ const foundEntries = candidates.map(({ name }) => `"${name}"`).join(", ");
219
+ throw new Error(`Ambiguous fetch entry module. Export exactly one primary fetch entry per module. ` + `Use either "fetch" or "handle" (or one default equivalent), not both. ` + `Found: ${foundEntries}`);
220
+ }
221
+ function resolveMethodHandler(module, method) {
222
+ const normalizedMethod = method.toUpperCase();
223
+ const directHandler = isFunction(module[normalizedMethod]) ? module[normalizedMethod] : bindMethod(module.default, normalizedMethod);
224
+ if (directHandler) {
225
+ return {
226
+ handler: directHandler,
227
+ stripBody: false
228
+ };
229
+ }
230
+ if (normalizedMethod === "HEAD") {
231
+ const getHandler = isFunction(module.GET) ? module.GET : bindMethod(module.default, "GET");
232
+ if (getHandler) {
233
+ return {
234
+ handler: getHandler,
235
+ stripBody: true
236
+ };
237
+ }
238
+ }
239
+ const allHandler = isFunction(module.ALL) ? module.ALL : bindMethod(module.default, "ALL");
240
+ if (allHandler) {
241
+ return {
242
+ handler: allHandler,
243
+ stripBody: false
244
+ };
245
+ }
246
+ return null;
247
+ }
248
+ async function invokeResolvedFetchHandler(handler, event2) {
249
+ if (isResolveStyleFunction(handler)) {
250
+ return handler(event2, async () => createNotFoundResponse());
251
+ }
252
+ if (isWorkerStyleFetchFunction(handler)) {
253
+ return invokeWorkerStyleFetchFunction(handler, event2);
254
+ }
255
+ assertExplicit2ArgStyle(handler);
256
+ return handler(event2);
257
+ }
258
+ function resolveFetchHandler(module) {
259
+ const candidates = getPrimaryFetchEntryCandidates(module);
260
+ assertSinglePrimaryFetchEntry(candidates);
261
+ return candidates[0]?.handler ?? null;
262
+ }
263
+ async function invokeFetchHandler(handler, event2, resolve = async () => createNotFoundResponse()) {
264
+ if (!isFunction(handler)) {
265
+ return resolve(event2);
266
+ }
267
+ if (isResolveStyleFunction(handler)) {
268
+ const response2 = await handler(event2, resolve);
269
+ return response2 ?? createNotFoundResponse();
270
+ }
271
+ if (isWorkerStyleFetchFunction(handler)) {
272
+ const response2 = await invokeWorkerStyleFetchFunction(handler, event2);
273
+ return response2 ?? createNotFoundResponse();
274
+ }
275
+ assertExplicit2ArgStyle(handler);
276
+ const response = await handler(event2);
277
+ return response ?? createNotFoundResponse();
278
+ }
279
+ function createResolveFetch(module, _currentEntry, initialEvent, options = {}) {
280
+ return async (nextEvent = initialEvent) => {
281
+ return runWithEventContext(nextEvent, async () => {
282
+ const methodResolution = resolveMethodHandler(module, nextEvent.request.method);
283
+ if (methodResolution) {
284
+ const response = await invokeResolvedFetchHandler(methodResolution.handler, nextEvent);
285
+ const finalResponse = response ?? createNotFoundResponse();
286
+ if (methodResolution.stripBody) {
287
+ return new Response(null, finalResponse);
288
+ }
289
+ return finalResponse;
290
+ }
291
+ if (options.fallbackResolve) {
292
+ return options.fallbackResolve(nextEvent);
293
+ }
294
+ return createNotFoundResponse();
295
+ });
296
+ };
297
+ }
298
+ async function invokeFetchModule(module, event2, fallbackResolve) {
299
+ const handler = resolveFetchHandler(module);
300
+ if (!handler) {
301
+ return createResolveFetch(module, null, event2, { fallbackResolve })(event2);
302
+ }
303
+ return invokeFetchHandler(handler, event2, createResolveFetch(module, handler, event2, { fallbackResolve }));
304
+ }
305
+ // src/runtime/router/index.ts
306
+ function normalizePathname(pathname) {
307
+ if (!pathname || pathname === "/") {
308
+ return "/";
309
+ }
310
+ const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
311
+ const trimmed = normalized.replace(/\/+$|\/+$/g, "");
312
+ return trimmed === "" ? "/" : trimmed;
313
+ }
314
+ function decodePathSegment(segment) {
315
+ try {
316
+ return decodeURIComponent(segment);
317
+ } catch {
318
+ return segment;
319
+ }
320
+ }
321
+ function getPathSegments(pathname) {
322
+ const normalizedPathname = normalizePathname(pathname);
323
+ if (normalizedPathname === "/") {
324
+ return [];
325
+ }
326
+ return normalizedPathname.slice(1).split("/").filter(Boolean).map(decodePathSegment);
327
+ }
328
+ function getMatchPathname(input) {
329
+ if (input instanceof Request) {
330
+ return new URL(input.url).pathname;
331
+ }
332
+ if (input instanceof URL) {
333
+ return input.pathname;
334
+ }
335
+ if (input.includes("://")) {
336
+ return new URL(input).pathname;
337
+ }
338
+ return input;
339
+ }
340
+ function matchRouteSegments(routeSegments, pathnameSegments) {
341
+ if (routeSegments.length === 0) {
342
+ return pathnameSegments.length === 0 ? {} : null;
343
+ }
344
+ const params = {};
345
+ let routeIndex = 0;
346
+ let pathIndex = 0;
347
+ while (routeIndex < routeSegments.length) {
348
+ const routeSegment = routeSegments[routeIndex];
349
+ if (routeSegment.type === "optional-rest") {
350
+ params[routeSegment.name] = pathnameSegments.slice(pathIndex).join("/");
351
+ pathIndex = pathnameSegments.length;
352
+ routeIndex += 1;
353
+ continue;
354
+ }
355
+ if (routeSegment.type === "rest") {
356
+ if (pathIndex >= pathnameSegments.length) {
357
+ return null;
358
+ }
359
+ params[routeSegment.name] = pathnameSegments.slice(pathIndex).join("/");
360
+ pathIndex = pathnameSegments.length;
361
+ routeIndex += 1;
362
+ continue;
363
+ }
364
+ const pathnameSegment = pathnameSegments[pathIndex];
365
+ if (pathnameSegment === undefined) {
366
+ return null;
367
+ }
368
+ if (routeSegment.type === "static") {
369
+ if (pathnameSegment !== routeSegment.value) {
370
+ return null;
371
+ }
372
+ } else {
373
+ params[routeSegment.name] = pathnameSegment;
374
+ }
375
+ pathIndex += 1;
376
+ routeIndex += 1;
377
+ }
378
+ if (pathIndex !== pathnameSegments.length) {
379
+ return null;
380
+ }
381
+ return params;
382
+ }
383
+ function matchFetchRoute(routes, input) {
384
+ const pathnameSegments = getPathSegments(getMatchPathname(input));
385
+ for (const route of routes) {
386
+ const params = matchRouteSegments(route.segments, pathnameSegments);
387
+ if (params) {
388
+ return {
389
+ route,
390
+ params
391
+ };
392
+ }
393
+ }
394
+ return null;
395
+ }
396
+ async function invokeRouteModules(routes, event2) {
397
+ const match = matchFetchRoute(routes, event2.request);
398
+ if (!match) {
399
+ return new Response("Not Found", { status: 404 });
400
+ }
401
+ const routeEvent = createFetchEvent(event2.request, event2.env, event2.ctx, {
402
+ params: match.params,
403
+ locals: event2.locals
404
+ });
405
+ return runWithEventContext(routeEvent, () => invokeFetchModule(match.route.module, routeEvent));
406
+ }
407
+ function createRouteResolve(routes, initialEvent) {
408
+ return async (nextEvent = initialEvent) => {
409
+ return invokeRouteModules(routes, nextEvent);
410
+ };
411
+ }
412
+ export { env, ctx, event, locals, markResolveStyle, markWorkerStyle, defineFetchHandler, defineQueueHandler, defineScheduledHandler, assertExplicitQueueHandlerStyle, assertExplicitScheduledHandlerStyle, sequence, resolveFetchHandler, invokeFetchHandler, createResolveFetch, invokeFetchModule, matchFetchRoute, invokeRouteModules, createRouteResolve };
@@ -0,0 +1,239 @@
1
+ // src/utils/send-email.ts
2
+ var RAW_EMAIL = "EmailMessage::raw";
3
+ var wrappedSendEmailBindings = new WeakMap;
4
+ var wrappedEnvBindings = new WeakMap;
5
+ var localSendEmailBindings = new Map;
6
+ function hasOwn(value, key) {
7
+ return Object.prototype.hasOwnProperty.call(value, key);
8
+ }
9
+ function isRecord(value) {
10
+ return typeof value === "object" && value !== null;
11
+ }
12
+ function isSendEmailBinding(value) {
13
+ if (!isRecord(value)) {
14
+ return false;
15
+ }
16
+ try {
17
+ return typeof value.send === "function" && typeof value.sendBatch !== "function";
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ function isComposableSendEmailMessage(message) {
23
+ return isRecord(message) && typeof message.from === "string" && (typeof message.to === "string" || Array.isArray(message.to));
24
+ }
25
+ function formatEmailAddress(value) {
26
+ if (!value) {
27
+ return;
28
+ }
29
+ return typeof value === "string" ? value : String(value);
30
+ }
31
+ function formatEmailList(value) {
32
+ if (!value) {
33
+ return;
34
+ }
35
+ return Array.isArray(value) ? value.join(", ") : value;
36
+ }
37
+ function normalizeBodyText(value) {
38
+ return value.replace(/\r?\n/g, `\r
39
+ `);
40
+ }
41
+ function buildMultipartAlternativeBody(message, boundary) {
42
+ const parts = [];
43
+ if (message.text) {
44
+ parts.push(`--${boundary}`, "Content-Type: text/plain; charset=UTF-8", "", normalizeBodyText(message.text));
45
+ }
46
+ if (message.html) {
47
+ parts.push(`--${boundary}`, "Content-Type: text/html; charset=UTF-8", "", normalizeBodyText(message.html));
48
+ }
49
+ parts.push(`--${boundary}--`);
50
+ return parts.join(`\r
51
+ `);
52
+ }
53
+ function buildRawEmail(message) {
54
+ const lines = [];
55
+ const messageId = `<${Date.now()}-${Math.random().toString(36).slice(2)}@devflare.dev>`;
56
+ lines.push(`From: ${message.from}`);
57
+ lines.push(`To: ${formatEmailList(message.to)}`);
58
+ lines.push(`Date: ${new Date().toUTCString()}`);
59
+ lines.push(`Message-ID: ${messageId}`);
60
+ if (message.subject) {
61
+ lines.push(`Subject: ${message.subject}`);
62
+ }
63
+ const replyTo = formatEmailAddress(message.replyTo);
64
+ if (replyTo) {
65
+ lines.push(`Reply-To: ${replyTo}`);
66
+ }
67
+ const cc = formatEmailList(message.cc);
68
+ if (cc) {
69
+ lines.push(`Cc: ${cc}`);
70
+ }
71
+ const bcc = formatEmailList(message.bcc);
72
+ if (bcc) {
73
+ lines.push(`Bcc: ${bcc}`);
74
+ }
75
+ if (message.headers) {
76
+ for (const [key, value] of Object.entries(message.headers)) {
77
+ lines.push(`${key}: ${value}`);
78
+ }
79
+ }
80
+ lines.push("MIME-Version: 1.0");
81
+ if (message.text && message.html) {
82
+ const boundary = `devflare-alt-${crypto.randomUUID()}`;
83
+ lines.push(`Content-Type: multipart/alternative; boundary="${boundary}"`);
84
+ lines.push("");
85
+ lines.push(buildMultipartAlternativeBody(message, boundary));
86
+ return lines.join(`\r
87
+ `);
88
+ }
89
+ lines.push(`Content-Type: ${message.html ? "text/html" : "text/plain"}; charset=UTF-8`);
90
+ lines.push("");
91
+ lines.push(normalizeBodyText(message.html ?? message.text ?? ""));
92
+ return lines.join(`\r
93
+ `);
94
+ }
95
+ function createEmailMessageRaw(raw) {
96
+ if (typeof raw === "string" || raw instanceof ReadableStream) {
97
+ return raw;
98
+ }
99
+ if (raw instanceof Uint8Array) {
100
+ const copy = new Uint8Array(raw.byteLength);
101
+ copy.set(raw);
102
+ return new Blob([copy]).stream();
103
+ }
104
+ if (raw instanceof ArrayBuffer) {
105
+ return new Blob([new Uint8Array(raw.slice(0))]).stream();
106
+ }
107
+ throw new Error("Unsupported EmailMessage raw payload");
108
+ }
109
+ function normalizeSendEmailMessage(message) {
110
+ if (!isComposableSendEmailMessage(message)) {
111
+ return message;
112
+ }
113
+ if (hasOwn(message, RAW_EMAIL)) {
114
+ return message;
115
+ }
116
+ if (hasOwn(message, "raw") && message.raw !== undefined) {
117
+ return {
118
+ from: message.from,
119
+ to: message.to,
120
+ [RAW_EMAIL]: createEmailMessageRaw(message.raw)
121
+ };
122
+ }
123
+ return {
124
+ from: message.from,
125
+ to: message.to,
126
+ [RAW_EMAIL]: createEmailMessageRaw(buildRawEmail(message))
127
+ };
128
+ }
129
+ function wrapSendEmailBinding(binding) {
130
+ const cached = wrappedSendEmailBindings.get(binding);
131
+ if (cached) {
132
+ return cached;
133
+ }
134
+ const wrapped = new Proxy(binding, {
135
+ get(target, prop, receiver) {
136
+ if (prop === "send") {
137
+ return async (message) => target.send(normalizeSendEmailMessage(message));
138
+ }
139
+ const value = Reflect.get(target, prop, receiver);
140
+ return typeof value === "function" ? value.bind(target) : value;
141
+ }
142
+ });
143
+ wrappedSendEmailBindings.set(binding, wrapped);
144
+ return wrapped;
145
+ }
146
+ function createLocalSendEmailBinding(config = {}, options = {}) {
147
+ return {
148
+ async send(message) {
149
+ const normalized = normalizeSendEmailMessage(message);
150
+ if (isRecord(normalized)) {
151
+ const from = typeof normalized.from === "string" ? normalized.from : undefined;
152
+ const recipients = Array.isArray(normalized.to) ? normalized.to.filter((value) => typeof value === "string") : typeof normalized.to === "string" ? [normalized.to] : [];
153
+ if (from && config.allowedSenderAddresses && !config.allowedSenderAddresses.includes(from)) {
154
+ throw new Error(`email from ${from} not allowed`);
155
+ }
156
+ for (const recipient of recipients) {
157
+ if (config.destinationAddress !== undefined && recipient !== config.destinationAddress) {
158
+ throw new Error(`email to ${recipient} not allowed`);
159
+ }
160
+ if (config.allowedDestinationAddresses !== undefined && !config.allowedDestinationAddresses.includes(recipient)) {
161
+ throw new Error(`email to ${recipient} not allowed`);
162
+ }
163
+ }
164
+ }
165
+ await options.onSend?.(normalized);
166
+ return;
167
+ }
168
+ };
169
+ }
170
+ function setLocalSendEmailBindings(bindings) {
171
+ localSendEmailBindings.clear();
172
+ for (const [name, config] of Object.entries(bindings)) {
173
+ localSendEmailBindings.set(name, createLocalSendEmailBinding(config));
174
+ }
175
+ }
176
+ function clearLocalSendEmailBindings() {
177
+ localSendEmailBindings.clear();
178
+ }
179
+ function needsEnvSendEmailWrapping(env) {
180
+ if (localSendEmailBindings.size > 0) {
181
+ return true;
182
+ }
183
+ for (const key of Reflect.ownKeys(env)) {
184
+ const value = Reflect.get(env, key);
185
+ if (isSendEmailBinding(value)) {
186
+ return true;
187
+ }
188
+ }
189
+ return false;
190
+ }
191
+ function wrapEnvSendEmailBindings(env) {
192
+ if (!isRecord(env)) {
193
+ return env;
194
+ }
195
+ if (!needsEnvSendEmailWrapping(env)) {
196
+ return env;
197
+ }
198
+ const cached = wrappedEnvBindings.get(env);
199
+ if (cached) {
200
+ return cached;
201
+ }
202
+ const wrapped = new Proxy(env, {
203
+ get(target, prop, receiver) {
204
+ if (typeof prop === "string" && localSendEmailBindings.has(prop)) {
205
+ return localSendEmailBindings.get(prop);
206
+ }
207
+ const value = Reflect.get(target, prop, receiver);
208
+ return isSendEmailBinding(value) ? wrapSendEmailBinding(value) : value;
209
+ },
210
+ has(target, prop) {
211
+ return Reflect.has(target, prop) || typeof prop === "string" && localSendEmailBindings.has(prop);
212
+ },
213
+ ownKeys(target) {
214
+ return Array.from(new Set([
215
+ ...Reflect.ownKeys(target),
216
+ ...localSendEmailBindings.keys()
217
+ ]));
218
+ },
219
+ getOwnPropertyDescriptor(target, prop) {
220
+ if (typeof prop === "string" && localSendEmailBindings.has(prop)) {
221
+ return {
222
+ configurable: true,
223
+ enumerable: true,
224
+ writable: false,
225
+ value: localSendEmailBindings.get(prop)
226
+ };
227
+ }
228
+ const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
229
+ if (descriptor) {
230
+ return descriptor;
231
+ }
232
+ return;
233
+ }
234
+ });
235
+ wrappedEnvBindings.set(env, wrapped);
236
+ return wrapped;
237
+ }
238
+
239
+ export { createEmailMessageRaw, normalizeSendEmailMessage, wrapSendEmailBinding, createLocalSendEmailBinding, setLocalSendEmailBindings, clearLocalSendEmailBindings, wrapEnvSendEmailBindings };