devflare 1.0.0-next.1 → 1.0.0-next.10
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/LLM.md +775 -637
- package/R2.md +200 -0
- package/README.md +285 -514
- package/bin/devflare.js +8 -8
- package/dist/{account-rvrj687w.js → account-8psavtg6.js} +27 -4
- package/dist/bridge/miniflare.d.ts +6 -0
- package/dist/bridge/miniflare.d.ts.map +1 -1
- package/dist/bridge/proxy.d.ts +5 -6
- package/dist/bridge/proxy.d.ts.map +1 -1
- package/dist/bridge/server.d.ts.map +1 -1
- package/dist/browser.d.ts +50 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/{build-mnf6v8gd.js → build-k36xrzvy.js} +26 -7
- package/dist/bundler/do-bundler.d.ts +7 -0
- package/dist/bundler/do-bundler.d.ts.map +1 -1
- package/dist/cli/commands/account.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/types.d.ts.map +1 -1
- package/dist/cli/config-path.d.ts +5 -0
- package/dist/cli/config-path.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/package-metadata.d.ts +16 -0
- package/dist/cli/package-metadata.d.ts.map +1 -0
- package/dist/config/compiler.d.ts +7 -0
- package/dist/config/compiler.d.ts.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/schema.d.ts +2575 -1221
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/{deploy-nhceck39.js → deploy-dbvfq8vq.js} +33 -15
- package/dist/{dev-qnxet3j9.js → dev-rk8p6pse.js} +900 -234
- package/dist/dev-server/miniflare-log.d.ts +12 -0
- package/dist/dev-server/miniflare-log.d.ts.map +1 -0
- package/dist/dev-server/runtime-stdio.d.ts +8 -0
- package/dist/dev-server/runtime-stdio.d.ts.map +1 -0
- package/dist/dev-server/server.d.ts +2 -0
- package/dist/dev-server/server.d.ts.map +1 -1
- package/dist/dev-server/vite-utils.d.ts +37 -0
- package/dist/dev-server/vite-utils.d.ts.map +1 -0
- package/dist/{doctor-e8fy6fj5.js → doctor-06y8nxd4.js} +73 -50
- package/dist/{durable-object-t4kbb0yt.js → durable-object-yt8v1dyn.js} +1 -1
- package/dist/index-05fyzwne.js +195 -0
- package/dist/index-1p814k7s.js +227 -0
- package/dist/{index-hcex3rgh.js → index-1phx14av.js} +84 -7
- package/dist/{index-tk6ej9dj.js → index-2q3pmzrx.js} +12 -16
- package/dist/{index-pf5s73n9.js → index-59df49vn.js} +11 -281
- package/dist/index-5yxg30va.js +304 -0
- package/dist/index-62b3gt2g.js +12 -0
- package/dist/index-6h8xbs75.js +44 -0
- package/dist/{index-67qcae0f.js → index-6v3wjg1r.js} +16 -1
- package/dist/index-8gtqgb3q.js +529 -0
- package/dist/{index-gz1gndna.js → index-9wt9x09k.js} +42 -62
- package/dist/index-fef08w43.js +231 -0
- package/dist/{index-ep3445yc.js → index-jht2j546.js} +393 -170
- package/dist/index-k7r18na8.js +0 -0
- package/dist/{index-m2q41jwa.js → index-n932ytmq.js} +9 -1
- package/dist/index-pwgyy2q9.js +39 -0
- package/dist/{index-07q6yxyc.js → index-v8vvsn9x.js} +1 -0
- package/dist/index-vky23txa.js +70 -0
- package/dist/index-vs49yxn4.js +322 -0
- package/dist/{index-z14anrqp.js → index-wfbfz02q.js} +14 -15
- package/dist/index-ws68xvq2.js +311 -0
- package/dist/index-y1d8za14.js +196 -0
- package/dist/{init-f9mgmew3.js → init-na2atvz2.js} +42 -55
- package/dist/router/types.d.ts +24 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/runtime/context.d.ts +249 -8
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/exports.d.ts +50 -55
- package/dist/runtime/exports.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +8 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/middleware.d.ts +77 -60
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/router.d.ts +7 -0
- package/dist/runtime/router.d.ts.map +1 -0
- package/dist/runtime/validation.d.ts +1 -1
- package/dist/runtime/validation.d.ts.map +1 -1
- package/dist/src/browser.js +150 -0
- package/dist/src/cli/index.js +10 -0
- package/dist/{cloudflare → src/cloudflare}/index.js +3 -3
- package/dist/{decorators → src/decorators}/index.js +2 -2
- package/dist/src/index.js +132 -0
- package/dist/src/runtime/index.js +111 -0
- package/dist/{sveltekit → src/sveltekit}/index.js +14 -6
- package/dist/{test → src/test}/index.js +22 -13
- package/dist/{vite → src/vite}/index.js +128 -59
- package/dist/sveltekit/platform.d.ts.map +1 -1
- package/dist/test/bridge-context.d.ts +5 -2
- package/dist/test/bridge-context.d.ts.map +1 -1
- package/dist/test/cf.d.ts +25 -11
- package/dist/test/cf.d.ts.map +1 -1
- package/dist/test/email.d.ts +16 -7
- package/dist/test/email.d.ts.map +1 -1
- package/dist/test/queue.d.ts.map +1 -1
- package/dist/test/resolve-service-bindings.d.ts.map +1 -1
- package/dist/test/scheduled.d.ts.map +1 -1
- package/dist/test/simple-context.d.ts +1 -1
- package/dist/test/simple-context.d.ts.map +1 -1
- package/dist/test/tail.d.ts +2 -1
- package/dist/test/tail.d.ts.map +1 -1
- package/dist/test/worker.d.ts +6 -0
- package/dist/test/worker.d.ts.map +1 -1
- package/dist/transform/durable-object.d.ts.map +1 -1
- package/dist/transform/worker-entrypoint.d.ts.map +1 -1
- package/dist/{types-5nyrz1sz.js → types-x9q7t491.js} +30 -16
- package/dist/utils/entrypoint-discovery.d.ts +6 -3
- package/dist/utils/entrypoint-discovery.d.ts.map +1 -1
- package/dist/utils/send-email.d.ts +15 -0
- package/dist/utils/send-email.d.ts.map +1 -0
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/worker-entry/composed-worker.d.ts +13 -0
- package/dist/worker-entry/composed-worker.d.ts.map +1 -0
- package/dist/worker-entry/routes.d.ts +22 -0
- package/dist/worker-entry/routes.d.ts.map +1 -0
- package/dist/{worker-entrypoint-m9th0rg0.js → worker-entrypoint-c259fmfs.js} +1 -1
- package/package.json +21 -19
- package/dist/index.js +0 -298
- package/dist/runtime/index.js +0 -111
|
@@ -104,30 +104,26 @@ function generateWrapper(className, options = {}) {
|
|
|
104
104
|
const includeWebsockets = options.websockets ?? false;
|
|
105
105
|
let wrapper = `
|
|
106
106
|
// ============ Devflare DO Wrapper for ${className} ============
|
|
107
|
-
import {
|
|
107
|
+
import { createDurableObjectAlarmEvent, createDurableObjectFetchEvent, createDurableObjectWebSocketCloseEvent, createDurableObjectWebSocketErrorEvent, createDurableObjectWebSocketMessageEvent, runWithEventContext } from 'devflare/runtime'
|
|
108
108
|
|
|
109
109
|
const __Original${className} = ${className}
|
|
110
110
|
|
|
111
111
|
class ${className}Wrapper extends __Original${className} {
|
|
112
112
|
async fetch(request: Request): Promise<Response> {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
() => super.fetch(request),
|
|
118
|
-
'fetch'
|
|
113
|
+
const __devflareEvent = createDurableObjectFetchEvent(request, this.env, this.ctx)
|
|
114
|
+
return runWithEventContext(
|
|
115
|
+
__devflareEvent,
|
|
116
|
+
() => super.fetch(__devflareEvent)
|
|
119
117
|
)
|
|
120
118
|
}
|
|
121
119
|
`;
|
|
122
120
|
if (includeAlarms) {
|
|
123
121
|
wrapper += `
|
|
124
122
|
async alarm(): Promise<void> {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
() => super.alarm?.() ?? Promise.resolve(),
|
|
130
|
-
'scheduled'
|
|
123
|
+
const __devflareEvent = createDurableObjectAlarmEvent(this.env, this.ctx)
|
|
124
|
+
return runWithEventContext(
|
|
125
|
+
__devflareEvent,
|
|
126
|
+
() => super.alarm?.(__devflareEvent) ?? Promise.resolve()
|
|
131
127
|
)
|
|
132
128
|
}
|
|
133
129
|
`;
|
|
@@ -135,32 +131,26 @@ class ${className}Wrapper extends __Original${className} {
|
|
|
135
131
|
if (includeWebsockets) {
|
|
136
132
|
wrapper += `
|
|
137
133
|
async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
() => super.webSocketMessage?.(ws, message) ?? Promise.resolve(),
|
|
143
|
-
'fetch'
|
|
134
|
+
const __devflareEvent = createDurableObjectWebSocketMessageEvent(ws, message, this.env, this.ctx)
|
|
135
|
+
return runWithEventContext(
|
|
136
|
+
__devflareEvent,
|
|
137
|
+
() => super.webSocketMessage?.(__devflareEvent, message) ?? Promise.resolve()
|
|
144
138
|
)
|
|
145
139
|
}
|
|
146
140
|
|
|
147
141
|
async webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void> {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
() => super.webSocketClose?.(ws, code, reason, wasClean) ?? Promise.resolve(),
|
|
153
|
-
'fetch'
|
|
142
|
+
const __devflareEvent = createDurableObjectWebSocketCloseEvent(ws, code, reason, wasClean, this.env, this.ctx)
|
|
143
|
+
return runWithEventContext(
|
|
144
|
+
__devflareEvent,
|
|
145
|
+
() => super.webSocketClose?.(__devflareEvent, code, reason, wasClean) ?? Promise.resolve()
|
|
154
146
|
)
|
|
155
147
|
}
|
|
156
148
|
|
|
157
149
|
async webSocketError(ws: WebSocket, error: unknown): Promise<void> {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
() => super.webSocketError?.(ws, error) ?? Promise.resolve(),
|
|
163
|
-
'fetch'
|
|
150
|
+
const __devflareEvent = createDurableObjectWebSocketErrorEvent(ws, error, this.env, this.ctx)
|
|
151
|
+
return runWithEventContext(
|
|
152
|
+
__devflareEvent,
|
|
153
|
+
() => super.webSocketError?.(__devflareEvent, error) ?? Promise.resolve()
|
|
164
154
|
)
|
|
165
155
|
}
|
|
166
156
|
`;
|
|
@@ -212,7 +202,7 @@ async function transformDurableObject(code, id) {
|
|
|
212
202
|
}
|
|
213
203
|
}
|
|
214
204
|
const imports = `
|
|
215
|
-
import {
|
|
205
|
+
import { createDurableObjectAlarmEvent, createDurableObjectFetchEvent, createDurableObjectWebSocketCloseEvent, createDurableObjectWebSocketErrorEvent, createDurableObjectWebSocketMessageEvent, runWithEventContext } from 'devflare/runtime'
|
|
216
206
|
`;
|
|
217
207
|
s.prepend(imports);
|
|
218
208
|
for (const classInfo of doClasses) {
|
|
@@ -241,24 +231,20 @@ function generateWrapperCodeInternal(className, options) {
|
|
|
241
231
|
// ============ Devflare DO Wrapper for ${className} ============
|
|
242
232
|
class ${className}Wrapper extends __Original${className} {
|
|
243
233
|
async fetch(request: Request): Promise<Response> {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
() => super.fetch(request),
|
|
249
|
-
'fetch'
|
|
234
|
+
const __devflareEvent = createDurableObjectFetchEvent(request, this.env, this.ctx)
|
|
235
|
+
return runWithEventContext(
|
|
236
|
+
__devflareEvent,
|
|
237
|
+
() => super.fetch(__devflareEvent)
|
|
250
238
|
)
|
|
251
239
|
}
|
|
252
240
|
`;
|
|
253
241
|
if (options.alarms) {
|
|
254
242
|
wrapper += `
|
|
255
243
|
async alarm(): Promise<void> {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
() => super.alarm?.() ?? Promise.resolve(),
|
|
261
|
-
'scheduled'
|
|
244
|
+
const __devflareEvent = createDurableObjectAlarmEvent(this.env, this.ctx)
|
|
245
|
+
return runWithEventContext(
|
|
246
|
+
__devflareEvent,
|
|
247
|
+
() => super.alarm?.(__devflareEvent) ?? Promise.resolve()
|
|
262
248
|
)
|
|
263
249
|
}
|
|
264
250
|
`;
|
|
@@ -266,32 +252,26 @@ class ${className}Wrapper extends __Original${className} {
|
|
|
266
252
|
if (options.websockets) {
|
|
267
253
|
wrapper += `
|
|
268
254
|
async webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void> {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
() => super.webSocketMessage?.(ws, message) ?? Promise.resolve(),
|
|
274
|
-
'fetch'
|
|
255
|
+
const __devflareEvent = createDurableObjectWebSocketMessageEvent(ws, message, this.env, this.ctx)
|
|
256
|
+
return runWithEventContext(
|
|
257
|
+
__devflareEvent,
|
|
258
|
+
() => super.webSocketMessage?.(__devflareEvent, message) ?? Promise.resolve()
|
|
275
259
|
)
|
|
276
260
|
}
|
|
277
261
|
|
|
278
262
|
async webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void> {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
() => super.webSocketClose?.(ws, code, reason, wasClean) ?? Promise.resolve(),
|
|
284
|
-
'fetch'
|
|
263
|
+
const __devflareEvent = createDurableObjectWebSocketCloseEvent(ws, code, reason, wasClean, this.env, this.ctx)
|
|
264
|
+
return runWithEventContext(
|
|
265
|
+
__devflareEvent,
|
|
266
|
+
() => super.webSocketClose?.(__devflareEvent, code, reason, wasClean) ?? Promise.resolve()
|
|
285
267
|
)
|
|
286
268
|
}
|
|
287
269
|
|
|
288
270
|
async webSocketError(ws: WebSocket, error: unknown): Promise<void> {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
() => super.webSocketError?.(ws, error) ?? Promise.resolve(),
|
|
294
|
-
'fetch'
|
|
271
|
+
const __devflareEvent = createDurableObjectWebSocketErrorEvent(ws, error, this.env, this.ctx)
|
|
272
|
+
return runWithEventContext(
|
|
273
|
+
__devflareEvent,
|
|
274
|
+
() => super.webSocketError?.(__devflareEvent, error) ?? Promise.resolve()
|
|
295
275
|
)
|
|
296
276
|
}
|
|
297
277
|
`;
|
|
@@ -0,0 +1,231 @@
|
|
|
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
|
+
return isRecord(value) && typeof value.send === "function" && typeof value.sendBatch !== "function";
|
|
14
|
+
}
|
|
15
|
+
function isComposableSendEmailMessage(message) {
|
|
16
|
+
return isRecord(message) && typeof message.from === "string" && (typeof message.to === "string" || Array.isArray(message.to));
|
|
17
|
+
}
|
|
18
|
+
function formatEmailAddress(value) {
|
|
19
|
+
if (!value) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
return typeof value === "string" ? value : String(value);
|
|
23
|
+
}
|
|
24
|
+
function formatEmailList(value) {
|
|
25
|
+
if (!value) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
return Array.isArray(value) ? value.join(", ") : value;
|
|
29
|
+
}
|
|
30
|
+
function normalizeBodyText(value) {
|
|
31
|
+
return value.replace(/\r?\n/g, `\r
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
function buildMultipartAlternativeBody(message, boundary) {
|
|
35
|
+
const parts = [];
|
|
36
|
+
if (message.text) {
|
|
37
|
+
parts.push(`--${boundary}`, "Content-Type: text/plain; charset=UTF-8", "", normalizeBodyText(message.text));
|
|
38
|
+
}
|
|
39
|
+
if (message.html) {
|
|
40
|
+
parts.push(`--${boundary}`, "Content-Type: text/html; charset=UTF-8", "", normalizeBodyText(message.html));
|
|
41
|
+
}
|
|
42
|
+
parts.push(`--${boundary}--`);
|
|
43
|
+
return parts.join(`\r
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
function buildRawEmail(message) {
|
|
47
|
+
const lines = [];
|
|
48
|
+
const messageId = `<${Date.now()}-${Math.random().toString(36).slice(2)}@devflare.dev>`;
|
|
49
|
+
lines.push(`From: ${message.from}`);
|
|
50
|
+
lines.push(`To: ${formatEmailList(message.to)}`);
|
|
51
|
+
lines.push(`Date: ${new Date().toUTCString()}`);
|
|
52
|
+
lines.push(`Message-ID: ${messageId}`);
|
|
53
|
+
if (message.subject) {
|
|
54
|
+
lines.push(`Subject: ${message.subject}`);
|
|
55
|
+
}
|
|
56
|
+
const replyTo = formatEmailAddress(message.replyTo);
|
|
57
|
+
if (replyTo) {
|
|
58
|
+
lines.push(`Reply-To: ${replyTo}`);
|
|
59
|
+
}
|
|
60
|
+
const cc = formatEmailList(message.cc);
|
|
61
|
+
if (cc) {
|
|
62
|
+
lines.push(`Cc: ${cc}`);
|
|
63
|
+
}
|
|
64
|
+
const bcc = formatEmailList(message.bcc);
|
|
65
|
+
if (bcc) {
|
|
66
|
+
lines.push(`Bcc: ${bcc}`);
|
|
67
|
+
}
|
|
68
|
+
if (message.headers) {
|
|
69
|
+
for (const [key, value] of Object.entries(message.headers)) {
|
|
70
|
+
lines.push(`${key}: ${value}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
lines.push("MIME-Version: 1.0");
|
|
74
|
+
if (message.text && message.html) {
|
|
75
|
+
const boundary = `devflare-alt-${crypto.randomUUID()}`;
|
|
76
|
+
lines.push(`Content-Type: multipart/alternative; boundary="${boundary}"`);
|
|
77
|
+
lines.push("");
|
|
78
|
+
lines.push(buildMultipartAlternativeBody(message, boundary));
|
|
79
|
+
return lines.join(`\r
|
|
80
|
+
`);
|
|
81
|
+
}
|
|
82
|
+
lines.push(`Content-Type: ${message.html ? "text/html" : "text/plain"}; charset=UTF-8`);
|
|
83
|
+
lines.push("");
|
|
84
|
+
lines.push(normalizeBodyText(message.html ?? message.text ?? ""));
|
|
85
|
+
return lines.join(`\r
|
|
86
|
+
`);
|
|
87
|
+
}
|
|
88
|
+
function createEmailMessageRaw(raw) {
|
|
89
|
+
if (typeof raw === "string" || raw instanceof ReadableStream) {
|
|
90
|
+
return raw;
|
|
91
|
+
}
|
|
92
|
+
if (raw instanceof Uint8Array || raw instanceof ArrayBuffer) {
|
|
93
|
+
const body = new Response(raw).body;
|
|
94
|
+
if (!body) {
|
|
95
|
+
throw new Error("Could not create email body stream");
|
|
96
|
+
}
|
|
97
|
+
return body;
|
|
98
|
+
}
|
|
99
|
+
throw new Error("Unsupported EmailMessage raw payload");
|
|
100
|
+
}
|
|
101
|
+
function normalizeSendEmailMessage(message) {
|
|
102
|
+
if (!isComposableSendEmailMessage(message)) {
|
|
103
|
+
return message;
|
|
104
|
+
}
|
|
105
|
+
if (hasOwn(message, RAW_EMAIL)) {
|
|
106
|
+
return message;
|
|
107
|
+
}
|
|
108
|
+
if (hasOwn(message, "raw") && message.raw !== undefined) {
|
|
109
|
+
return {
|
|
110
|
+
from: message.from,
|
|
111
|
+
to: message.to,
|
|
112
|
+
[RAW_EMAIL]: createEmailMessageRaw(message.raw)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
from: message.from,
|
|
117
|
+
to: message.to,
|
|
118
|
+
[RAW_EMAIL]: createEmailMessageRaw(buildRawEmail(message))
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function wrapSendEmailBinding(binding) {
|
|
122
|
+
const cached = wrappedSendEmailBindings.get(binding);
|
|
123
|
+
if (cached) {
|
|
124
|
+
return cached;
|
|
125
|
+
}
|
|
126
|
+
const wrapped = new Proxy(binding, {
|
|
127
|
+
get(target, prop, receiver) {
|
|
128
|
+
if (prop === "send") {
|
|
129
|
+
return async (message) => target.send(normalizeSendEmailMessage(message));
|
|
130
|
+
}
|
|
131
|
+
const value = Reflect.get(target, prop, receiver);
|
|
132
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
wrappedSendEmailBindings.set(binding, wrapped);
|
|
136
|
+
return wrapped;
|
|
137
|
+
}
|
|
138
|
+
function createLocalSendEmailBinding(config = {}, options = {}) {
|
|
139
|
+
return {
|
|
140
|
+
async send(message) {
|
|
141
|
+
const normalized = normalizeSendEmailMessage(message);
|
|
142
|
+
if (isRecord(normalized)) {
|
|
143
|
+
const from = typeof normalized.from === "string" ? normalized.from : undefined;
|
|
144
|
+
const recipients = Array.isArray(normalized.to) ? normalized.to.filter((value) => typeof value === "string") : typeof normalized.to === "string" ? [normalized.to] : [];
|
|
145
|
+
if (from && config.allowedSenderAddresses && !config.allowedSenderAddresses.includes(from)) {
|
|
146
|
+
throw new Error(`email from ${from} not allowed`);
|
|
147
|
+
}
|
|
148
|
+
for (const recipient of recipients) {
|
|
149
|
+
if (config.destinationAddress !== undefined && recipient !== config.destinationAddress) {
|
|
150
|
+
throw new Error(`email to ${recipient} not allowed`);
|
|
151
|
+
}
|
|
152
|
+
if (config.allowedDestinationAddresses !== undefined && !config.allowedDestinationAddresses.includes(recipient)) {
|
|
153
|
+
throw new Error(`email to ${recipient} not allowed`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
await options.onSend?.(normalized);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function setLocalSendEmailBindings(bindings) {
|
|
163
|
+
localSendEmailBindings.clear();
|
|
164
|
+
for (const [name, config] of Object.entries(bindings)) {
|
|
165
|
+
localSendEmailBindings.set(name, createLocalSendEmailBinding(config));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function clearLocalSendEmailBindings() {
|
|
169
|
+
localSendEmailBindings.clear();
|
|
170
|
+
}
|
|
171
|
+
function needsEnvSendEmailWrapping(env) {
|
|
172
|
+
if (localSendEmailBindings.size > 0) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
for (const key of Reflect.ownKeys(env)) {
|
|
176
|
+
const value = Reflect.get(env, key);
|
|
177
|
+
if (isSendEmailBinding(value)) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
function wrapEnvSendEmailBindings(env) {
|
|
184
|
+
if (!isRecord(env)) {
|
|
185
|
+
return env;
|
|
186
|
+
}
|
|
187
|
+
if (!needsEnvSendEmailWrapping(env)) {
|
|
188
|
+
return env;
|
|
189
|
+
}
|
|
190
|
+
const cached = wrappedEnvBindings.get(env);
|
|
191
|
+
if (cached) {
|
|
192
|
+
return cached;
|
|
193
|
+
}
|
|
194
|
+
const wrapped = new Proxy(env, {
|
|
195
|
+
get(target, prop, receiver) {
|
|
196
|
+
const value = Reflect.get(target, prop, receiver);
|
|
197
|
+
if (value === undefined && typeof prop === "string") {
|
|
198
|
+
return localSendEmailBindings.get(prop);
|
|
199
|
+
}
|
|
200
|
+
return isSendEmailBinding(value) ? wrapSendEmailBinding(value) : value;
|
|
201
|
+
},
|
|
202
|
+
has(target, prop) {
|
|
203
|
+
return Reflect.has(target, prop) || typeof prop === "string" && localSendEmailBindings.has(prop);
|
|
204
|
+
},
|
|
205
|
+
ownKeys(target) {
|
|
206
|
+
return Array.from(new Set([
|
|
207
|
+
...Reflect.ownKeys(target),
|
|
208
|
+
...localSendEmailBindings.keys()
|
|
209
|
+
]));
|
|
210
|
+
},
|
|
211
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
212
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
213
|
+
if (descriptor) {
|
|
214
|
+
return descriptor;
|
|
215
|
+
}
|
|
216
|
+
if (typeof prop === "string" && localSendEmailBindings.has(prop)) {
|
|
217
|
+
return {
|
|
218
|
+
configurable: true,
|
|
219
|
+
enumerable: true,
|
|
220
|
+
writable: false,
|
|
221
|
+
value: localSendEmailBindings.get(prop)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
wrappedEnvBindings.set(env, wrapped);
|
|
228
|
+
return wrapped;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export { normalizeSendEmailMessage, createLocalSendEmailBinding, setLocalSendEmailBindings, clearLocalSendEmailBindings, wrapEnvSendEmailBindings };
|