From b58de8f9d9e53c3eeb4996d351818324a8041434 Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Sat, 1 Jun 2024 22:38:20 +0900 Subject: [PATCH 1/5] emailTask add like this? --- .../cloudflare/runtime/cloudflare-module.ts | 22 +++- src/runtime/emailtask.ts | 108 ++++++++++++++++++ src/runtime/index.ts | 1 + src/runtime/virtual/tasks.ts | 5 + 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/runtime/emailtask.ts diff --git a/src/presets/cloudflare/runtime/cloudflare-module.ts b/src/presets/cloudflare/runtime/cloudflare-module.ts index f739cab5f8..a41e332c36 100644 --- a/src/presets/cloudflare/runtime/cloudflare-module.ts +++ b/src/presets/cloudflare/runtime/cloudflare-module.ts @@ -1,7 +1,7 @@ import "#internal/nitro/virtual/polyfill"; import { requestHasBody } from "#internal/nitro/utils"; import { nitroApp } from "#internal/nitro/app"; -import { runCronTasks, useRuntimeConfig } from "#internal/nitro"; +import { runCronTasks, runEmailTask, useRuntimeConfig } from "#internal/nitro"; import { getPublicAssetMeta } from "#internal/nitro/virtual/public-assets"; import { withoutBase } from "ufo"; @@ -96,6 +96,26 @@ export default { ); } }, + email(event: any, env: CFModuleEnv, context: ExecutionContext) { + if (import.meta._tasks) { + (globalThis as any).__env__ = env; + + const domain = (event.to as string).split('@')[1] + + context.waitUntil( + runEmailTask(domain, { + context: { + ...event, + cloudflare: { + env, + context, + }, + }, + payload: {}, + }) + ) + } + } }; function assetsCacheControl(_request: Request) { diff --git a/src/runtime/emailtask.ts b/src/runtime/emailtask.ts new file mode 100644 index 0000000000..1db004d4c6 --- /dev/null +++ b/src/runtime/emailtask.ts @@ -0,0 +1,108 @@ +import { emailTasks, scheduledEmailTasks } from "#internal/nitro/virtual/tasks"; +import { createError } from "h3"; + +type MaybePromise = T | Promise; + +/** @experimental */ +export interface EmailContext { + readonly from?: string; + readonly to?: string; + readonly headers?: Headers; + readonly raw?: ReadableStream; + readonly rawSize?: number; + + setReject?(reason: string): void; + forward?(rcptTo: string, headers?: Headers): Promise; + reply?(message: EmailContext): Promise; +} + +/** @experimental */ +export interface EmailPayload { + [key: string]: unknown; +} + +/** @experimental */ +export interface EmailMeta { + domain?: string; + description?: string; +} + +/** @experimental */ +export interface EmailTaskEvent { + domain: string; + payload: EmailPayload; + context: EmailContext; +} + +/** @experimental */ +export interface EmailTaskResult { + result?: RT; +} + +/** @experimental */ +export interface EmailTask { + meta: EmailMeta; + run(event: EmailTaskEvent): MaybePromise<{ result?: RT }> +} + +/** @experimental */ +export function defineEmailTask(def: EmailTask): EmailTask { + if (typeof def.run !== "function") { + def.run = () => { + throw new TypeError("Task must implement a `run` method!"); + }; + } + return def; +} + +const __runningEmailTasks__: { [name: string]: MaybePromise> } = {}; + +/** @experimental */ +export async function runEmailTask( + domain: string, + { + payload = {}, + context = {}, + }: { payload?: EmailPayload; context?: EmailContext } = {} +): Promise> { + if (__runningEmailTasks__[domain]) { + return __runningEmailTasks__[domain] + } + + if (!(domain in emailTasks)) { + throw createError({ + message: `Task \`${domain}\` is not available!`, + statusCode: 404, + }); + } + + if (!emailTasks[domain].resolve) { + throw createError({ + message: `Task \`${domain}\` is not implemented!`, + statusCode: 501, + }); + } + + const handler = (await emailTasks[domain].resolve!()) as EmailTask; + const taskEvent: EmailTaskEvent = { domain, payload, context }; + __runningEmailTasks__[domain] = handler.run(taskEvent) + + try { + const res = await __runningEmailTasks__[domain]; + return res + } finally { + delete __runningEmailTasks__[domain] + } +} + +/** @experimental */ +export function getEmailTasks(domain: string): string[] { + return (scheduledEmailTasks || []).find((task) => task.domain.endsWith(domain))?.tasks || []; +} + +export function runEmailTasks( + domain: string, + ctx: { payload?: EmailPayload; context?: EmailContext } +): Promise { + return Promise.all(getEmailTasks(domain).map((name) => runEmailTask(name, ctx))) +} diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 9072ba8860..b719a328fd 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -3,6 +3,7 @@ export * from "./cache"; export { useNitroApp } from "./app"; export * from "./plugin"; export * from "./task"; +export * from "./emailtask" export * from "./renderer"; export { getRouteRules, getRouteRulesForPath } from "./route-rules"; export { defineRouteMeta } from "./meta"; diff --git a/src/runtime/virtual/tasks.ts b/src/runtime/virtual/tasks.ts index 52534a8b4a..458a331216 100644 --- a/src/runtime/virtual/tasks.ts +++ b/src/runtime/virtual/tasks.ts @@ -1,4 +1,5 @@ import type { Task, TaskMeta } from "../task"; +import { EmailMeta, EmailTask } from "#internal/nitro/emailtask"; export const tasks: Record< string, @@ -6,3 +7,7 @@ export const tasks: Record< > = {}; export const scheduledTasks: false | { cron: string; tasks: string[] }[] = []; + +export const emailTasks: Record Promise; meta: EmailMeta }> = {}; + +export const scheduledEmailTasks: false | { domain: string; tasks: string[] }[] = []; From 2a74e143ac9aa37b2437ed444184a3ed35df36ff Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Sun, 2 Jun 2024 11:49:53 +0900 Subject: [PATCH 2/5] emailTask's lint fix --- .../cloudflare/runtime/cloudflare-module.ts | 6 ++-- src/runtime/emailtask.ts | 29 ++++++++++++------- src/runtime/index.ts | 2 +- src/runtime/virtual/tasks.ts | 9 ++++-- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/presets/cloudflare/runtime/cloudflare-module.ts b/src/presets/cloudflare/runtime/cloudflare-module.ts index a41e332c36..ef5cb7aa5a 100644 --- a/src/presets/cloudflare/runtime/cloudflare-module.ts +++ b/src/presets/cloudflare/runtime/cloudflare-module.ts @@ -100,7 +100,7 @@ export default { if (import.meta._tasks) { (globalThis as any).__env__ = env; - const domain = (event.to as string).split('@')[1] + const domain = (event.to as string).split("@")[1]; context.waitUntil( runEmailTask(domain, { @@ -113,9 +113,9 @@ export default { }, payload: {}, }) - ) + ); } - } + }, }; function assetsCacheControl(_request: Request) { diff --git a/src/runtime/emailtask.ts b/src/runtime/emailtask.ts index 1db004d4c6..203db4e3e7 100644 --- a/src/runtime/emailtask.ts +++ b/src/runtime/emailtask.ts @@ -42,11 +42,13 @@ export interface EmailTaskResult { /** @experimental */ export interface EmailTask { meta: EmailMeta; - run(event: EmailTaskEvent): MaybePromise<{ result?: RT }> + run(event: EmailTaskEvent): MaybePromise<{ result?: RT }>; } /** @experimental */ -export function defineEmailTask(def: EmailTask): EmailTask { +export function defineEmailTask( + def: EmailTask +): EmailTask { if (typeof def.run !== "function") { def.run = () => { throw new TypeError("Task must implement a `run` method!"); @@ -55,7 +57,9 @@ export function defineEmailTask(def: EmailTask): EmailTask return def; } -const __runningEmailTasks__: { [name: string]: MaybePromise> } = {}; +const __runningEmailTasks__: { + [name: string]: MaybePromise>; +} = {}; /** @experimental */ export async function runEmailTask( @@ -66,7 +70,7 @@ export async function runEmailTask( }: { payload?: EmailPayload; context?: EmailContext } = {} ): Promise> { if (__runningEmailTasks__[domain]) { - return __runningEmailTasks__[domain] + return __runningEmailTasks__[domain]; } if (!(domain in emailTasks)) { @@ -77,7 +81,7 @@ export async function runEmailTask( } if (!emailTasks[domain].resolve) { - throw createError({ + throw createError({ message: `Task \`${domain}\` is not implemented!`, statusCode: 501, }); @@ -85,24 +89,29 @@ export async function runEmailTask( const handler = (await emailTasks[domain].resolve!()) as EmailTask; const taskEvent: EmailTaskEvent = { domain, payload, context }; - __runningEmailTasks__[domain] = handler.run(taskEvent) + __runningEmailTasks__[domain] = handler.run(taskEvent); try { const res = await __runningEmailTasks__[domain]; - return res + return res; } finally { - delete __runningEmailTasks__[domain] + delete __runningEmailTasks__[domain]; } } /** @experimental */ export function getEmailTasks(domain: string): string[] { - return (scheduledEmailTasks || []).find((task) => task.domain.endsWith(domain))?.tasks || []; + return ( + (scheduledEmailTasks || []).find((task) => task.domain.endsWith(domain)) + ?.tasks || [] + ); } export function runEmailTasks( domain: string, ctx: { payload?: EmailPayload; context?: EmailContext } ): Promise { - return Promise.all(getEmailTasks(domain).map((name) => runEmailTask(name, ctx))) + return Promise.all( + getEmailTasks(domain).map((name) => runEmailTask(name, ctx)) + ); } diff --git a/src/runtime/index.ts b/src/runtime/index.ts index b719a328fd..e925d07f85 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -3,7 +3,7 @@ export * from "./cache"; export { useNitroApp } from "./app"; export * from "./plugin"; export * from "./task"; -export * from "./emailtask" +export * from "./emailtask"; export * from "./renderer"; export { getRouteRules, getRouteRulesForPath } from "./route-rules"; export { defineRouteMeta } from "./meta"; diff --git a/src/runtime/virtual/tasks.ts b/src/runtime/virtual/tasks.ts index 458a331216..2ee0f5b06a 100644 --- a/src/runtime/virtual/tasks.ts +++ b/src/runtime/virtual/tasks.ts @@ -8,6 +8,11 @@ export const tasks: Record< export const scheduledTasks: false | { cron: string; tasks: string[] }[] = []; -export const emailTasks: Record Promise; meta: EmailMeta }> = {}; +export const emailTasks: Record< + string, + { resolve?: () => Promise; meta: EmailMeta } +> = {}; -export const scheduledEmailTasks: false | { domain: string; tasks: string[] }[] = []; +export const scheduledEmailTasks: + | false + | { domain: string; tasks: string[] }[] = []; From 4aba1484e687ec997112dc15766af5131111ddb3 Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:48:34 +0900 Subject: [PATCH 3/5] add "cloudflare:email" handler with RuntimeHooks --- .../cloudflare/runtime/cloudflare-module.ts | 15 +-- src/runtime/email.ts | 12 ++ src/runtime/emailtask.ts | 117 ------------------ src/runtime/types.ts | 7 ++ src/runtime/virtual/tasks.ts | 10 -- 5 files changed, 21 insertions(+), 140 deletions(-) create mode 100644 src/runtime/email.ts delete mode 100644 src/runtime/emailtask.ts diff --git a/src/presets/cloudflare/runtime/cloudflare-module.ts b/src/presets/cloudflare/runtime/cloudflare-module.ts index ef5cb7aa5a..97b05d78be 100644 --- a/src/presets/cloudflare/runtime/cloudflare-module.ts +++ b/src/presets/cloudflare/runtime/cloudflare-module.ts @@ -1,7 +1,7 @@ import "#internal/nitro/virtual/polyfill"; import { requestHasBody } from "#internal/nitro/utils"; import { nitroApp } from "#internal/nitro/app"; -import { runCronTasks, runEmailTask, useRuntimeConfig } from "#internal/nitro"; +import { runCronTasks, useRuntimeConfig } from "#internal/nitro"; import { getPublicAssetMeta } from "#internal/nitro/virtual/public-assets"; import { withoutBase } from "ufo"; @@ -100,19 +100,8 @@ export default { if (import.meta._tasks) { (globalThis as any).__env__ = env; - const domain = (event.to as string).split("@")[1]; - context.waitUntil( - runEmailTask(domain, { - context: { - ...event, - cloudflare: { - env, - context, - }, - }, - payload: {}, - }) + nitroApp.hooks.callHook("cloudflare:email", event, { env, context }) ); } }, diff --git a/src/runtime/email.ts b/src/runtime/email.ts new file mode 100644 index 0000000000..e1b741e810 --- /dev/null +++ b/src/runtime/email.ts @@ -0,0 +1,12 @@ +/** @experimental */ +export interface EmailContext { + readonly from?: string; + readonly to?: string; + readonly headers?: Headers; + readonly raw?: ReadableStream; + readonly rawSize?: number; + + setReject?(reason: string): void; + forward?(rcptTo: string, headers?: Headers): Promise; + reply?(message: EmailContext): Promise; +} diff --git a/src/runtime/emailtask.ts b/src/runtime/emailtask.ts deleted file mode 100644 index 203db4e3e7..0000000000 --- a/src/runtime/emailtask.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { emailTasks, scheduledEmailTasks } from "#internal/nitro/virtual/tasks"; -import { createError } from "h3"; - -type MaybePromise = T | Promise; - -/** @experimental */ -export interface EmailContext { - readonly from?: string; - readonly to?: string; - readonly headers?: Headers; - readonly raw?: ReadableStream; - readonly rawSize?: number; - - setReject?(reason: string): void; - forward?(rcptTo: string, headers?: Headers): Promise; - reply?(message: EmailContext): Promise; -} - -/** @experimental */ -export interface EmailPayload { - [key: string]: unknown; -} - -/** @experimental */ -export interface EmailMeta { - domain?: string; - description?: string; -} - -/** @experimental */ -export interface EmailTaskEvent { - domain: string; - payload: EmailPayload; - context: EmailContext; -} - -/** @experimental */ -export interface EmailTaskResult { - result?: RT; -} - -/** @experimental */ -export interface EmailTask { - meta: EmailMeta; - run(event: EmailTaskEvent): MaybePromise<{ result?: RT }>; -} - -/** @experimental */ -export function defineEmailTask( - def: EmailTask -): EmailTask { - if (typeof def.run !== "function") { - def.run = () => { - throw new TypeError("Task must implement a `run` method!"); - }; - } - return def; -} - -const __runningEmailTasks__: { - [name: string]: MaybePromise>; -} = {}; - -/** @experimental */ -export async function runEmailTask( - domain: string, - { - payload = {}, - context = {}, - }: { payload?: EmailPayload; context?: EmailContext } = {} -): Promise> { - if (__runningEmailTasks__[domain]) { - return __runningEmailTasks__[domain]; - } - - if (!(domain in emailTasks)) { - throw createError({ - message: `Task \`${domain}\` is not available!`, - statusCode: 404, - }); - } - - if (!emailTasks[domain].resolve) { - throw createError({ - message: `Task \`${domain}\` is not implemented!`, - statusCode: 501, - }); - } - - const handler = (await emailTasks[domain].resolve!()) as EmailTask; - const taskEvent: EmailTaskEvent = { domain, payload, context }; - __runningEmailTasks__[domain] = handler.run(taskEvent); - - try { - const res = await __runningEmailTasks__[domain]; - return res; - } finally { - delete __runningEmailTasks__[domain]; - } -} - -/** @experimental */ -export function getEmailTasks(domain: string): string[] { - return ( - (scheduledEmailTasks || []).find((task) => task.domain.endsWith(domain)) - ?.tasks || [] - ); -} - -export function runEmailTasks( - domain: string, - ctx: { payload?: EmailPayload; context?: EmailContext } -): Promise { - return Promise.all( - getEmailTasks(domain).map((name) => runEmailTask(name, ctx)) - ); -} diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 3d26913228..c054e21bbb 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -1,5 +1,7 @@ import type { H3Event, AppOptions } from "h3"; import type { RenderResponse } from "./renderer"; +import { EmailContext } from "#internal/nitro/email"; +import { ExecutionContext } from "@cloudflare/workers-types"; export type { NitroApp } from "./app"; export type { @@ -33,4 +35,9 @@ export interface NitroRuntimeHooks { response: Partial, context: { event: H3Event } ) => void; + + "cloudflare:email": ( + event: EmailContext, + context: { env: any; context: ExecutionContext } + ) => void; } diff --git a/src/runtime/virtual/tasks.ts b/src/runtime/virtual/tasks.ts index 2ee0f5b06a..52534a8b4a 100644 --- a/src/runtime/virtual/tasks.ts +++ b/src/runtime/virtual/tasks.ts @@ -1,5 +1,4 @@ import type { Task, TaskMeta } from "../task"; -import { EmailMeta, EmailTask } from "#internal/nitro/emailtask"; export const tasks: Record< string, @@ -7,12 +6,3 @@ export const tasks: Record< > = {}; export const scheduledTasks: false | { cron: string; tasks: string[] }[] = []; - -export const emailTasks: Record< - string, - { resolve?: () => Promise; meta: EmailMeta } -> = {}; - -export const scheduledEmailTasks: - | false - | { domain: string; tasks: string[] }[] = []; From f497d1f08a23e8da75058f07e98c350e7fac203f Mon Sep 17 00:00:00 2001 From: dalbodeule <11470513+dalbodeule@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:25:34 +0900 Subject: [PATCH 4/5] add "cloudflare:email", "cloudflare:queue" handler with merges. --- .../cloudflare/runtime/cloudflare-module.ts | 12 ++++++- src/runtime/cloudflare.ts | 31 +++++++++++++++++++ src/runtime/email.ts | 12 ------- src/types/runtime/nitro.ts | 11 +++++++ 4 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 src/runtime/cloudflare.ts delete mode 100644 src/runtime/email.ts diff --git a/src/presets/cloudflare/runtime/cloudflare-module.ts b/src/presets/cloudflare/runtime/cloudflare-module.ts index beb39fcc67..ad992ea903 100644 --- a/src/presets/cloudflare/runtime/cloudflare-module.ts +++ b/src/presets/cloudflare/runtime/cloudflare-module.ts @@ -16,6 +16,7 @@ import { // @ts-ignore Bundled by Wrangler // See https://github.com/cloudflare/kv-asset-handler#asset_manifest-required-for-es-modules import manifest from "__STATIC_CONTENT_MANIFEST"; +import { EmailContext, MessageBatch } from "#internal/nitro/cloudflare"; const nitroApp = useNitroApp(); @@ -99,7 +100,7 @@ export default { ); } }, - email(event: any, env: CFModuleEnv, context: ExecutionContext) { + email(event: EmailContext, env: CFModuleEnv, context: ExecutionContext) { if (import.meta._tasks) { (globalThis as any).__env__ = env; @@ -108,6 +109,15 @@ export default { ); } }, + queue(event: MessageBatch, env: CFModuleEnv, context: ExecutionContext) { + if (import.meta._tasks) { + (globalThis as any).__env__ = env; + + context.waitUntil( + nitroApp.hooks.callHook("cloudflare:queue", event, { env, context }) + ); + } + }, }; function assetsCacheControl(_request: Request) { diff --git a/src/runtime/cloudflare.ts b/src/runtime/cloudflare.ts new file mode 100644 index 0000000000..13729da069 --- /dev/null +++ b/src/runtime/cloudflare.ts @@ -0,0 +1,31 @@ +/** @experimental */ +export interface EmailContext { + readonly from?: string; + readonly to?: string; + readonly headers?: Headers; + readonly raw?: ReadableStream; + readonly rawSize?: number; + + setReject?(reason: string): void; + forward?(rcptTo: string, headers?: Headers): Promise; + reply?(message: EmailContext): Promise; +} + +export interface QueueRetryOptions { + delaySeconds?: number; +} + +export interface MessageBody { + readonly id: string; + readonly timestamp: Date; + readonly body: Body; + adk(): void; + retry(options?: QueueRetryOptions): void; +} + +export interface MessageBatch { + readonly queue: string; + readonly messages: MessageBody[]; + ackAll(): void; + retryAll(options?: QueueRetryOptions): void; +} diff --git a/src/runtime/email.ts b/src/runtime/email.ts deleted file mode 100644 index e1b741e810..0000000000 --- a/src/runtime/email.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** @experimental */ -export interface EmailContext { - readonly from?: string; - readonly to?: string; - readonly headers?: Headers; - readonly raw?: ReadableStream; - readonly rawSize?: number; - - setReject?(reason: string): void; - forward?(rcptTo: string, headers?: Headers): Promise; - reply?(message: EmailContext): Promise; -} diff --git a/src/types/runtime/nitro.ts b/src/types/runtime/nitro.ts index 50157efc09..a1732bd8da 100644 --- a/src/types/runtime/nitro.ts +++ b/src/types/runtime/nitro.ts @@ -4,6 +4,8 @@ import type { createCall, createFetch as createLocalFetch, } from "unenv/runtime/fetch/index"; +import { EmailContext, MessageBatch } from "#internal/nitro/cloudflare"; +import { ExecutionContext } from "@cloudflare/workers-types"; export interface NitroApp { h3App: H3App; @@ -55,4 +57,13 @@ export interface NitroRuntimeHooks { response: Partial, context: { event: H3Event } ) => void; + + "cloudflare:email": ( + event: EmailContext, + context: { env: any; context: ExecutionContext } + ) => void; + "cloudflare:queue": ( + event: MessageBatch, + context: { env: any; context: ExecutionContext } + ) => void; } From 6bb52572d5bbba2a05f04a670f75408cf1bfbd9f Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 12 Jun 2024 16:58:15 +0200 Subject: [PATCH 5/5] apply refactors --- .../cloudflare/runtime/cloudflare-module.ts | 35 ++++++++------ src/presets/cloudflare/types.ts | 48 +++++++++++++++++++ src/runtime/cloudflare.ts | 31 ------------ src/types/runtime/nitro.ts | 11 ----- 4 files changed, 68 insertions(+), 57 deletions(-) delete mode 100644 src/runtime/cloudflare.ts diff --git a/src/presets/cloudflare/runtime/cloudflare-module.ts b/src/presets/cloudflare/runtime/cloudflare-module.ts index ad992ea903..910f21fc93 100644 --- a/src/presets/cloudflare/runtime/cloudflare-module.ts +++ b/src/presets/cloudflare/runtime/cloudflare-module.ts @@ -13,10 +13,11 @@ import { mapRequestToAsset, } from "@cloudflare/kv-asset-handler"; +import type { CloudflareEmailContext, CloudflareMessageBatch } from "../types"; + // @ts-ignore Bundled by Wrangler // See https://github.com/cloudflare/kv-asset-handler#asset_manifest-required-for-es-modules import manifest from "__STATIC_CONTENT_MANIFEST"; -import { EmailContext, MessageBatch } from "#internal/nitro/cloudflare"; const nitroApp = useNitroApp(); @@ -100,23 +101,27 @@ export default { ); } }, - email(event: EmailContext, env: CFModuleEnv, context: ExecutionContext) { - if (import.meta._tasks) { - (globalThis as any).__env__ = env; - context.waitUntil( - nitroApp.hooks.callHook("cloudflare:email", event, { env, context }) - ); - } + email( + event: CloudflareEmailContext, + env: CFModuleEnv, + context: ExecutionContext + ) { + (globalThis as any).__env__ = env; + context.waitUntil( + nitroApp.hooks.callHook("cloudflare:email", { event, env, context }) + ); }, - queue(event: MessageBatch, env: CFModuleEnv, context: ExecutionContext) { - if (import.meta._tasks) { - (globalThis as any).__env__ = env; - context.waitUntil( - nitroApp.hooks.callHook("cloudflare:queue", event, { env, context }) - ); - } + queue( + event: CloudflareEmailContext, + env: CFModuleEnv, + context: ExecutionContext + ) { + (globalThis as any).__env__ = env; + context.waitUntil( + nitroApp.hooks.callHook("cloudflare:queue", { event, env, context }) + ); }, }; diff --git a/src/presets/cloudflare/types.ts b/src/presets/cloudflare/types.ts index 25a70665e2..b8176c30e0 100644 --- a/src/presets/cloudflare/types.ts +++ b/src/presets/cloudflare/types.ts @@ -1,4 +1,5 @@ import type { Config as WranglerConfig } from "./types.wrangler"; +import type { ExecutionContext } from "@cloudflare/workers-types"; /** * https://developers.cloudflare.com/pages/platform/functions/routing/#functions-invocation-routes @@ -50,3 +51,50 @@ export interface CloudflareOptions { defaultRoutes?: boolean; }; } + +/** @experimental */ +export interface CloudflareEmailContext { + readonly from?: string; + readonly to?: string; + readonly headers?: Headers; + readonly raw?: ReadableStream; + readonly rawSize?: number; + + setReject?(reason: string): void; + forward?(rcptTo: string, headers?: Headers): Promise; + reply?(message: CloudflareEmailContext): Promise; +} + +export interface CloudflareQueueRetryOptions { + delaySeconds?: number; +} + +export interface CloudflareMessageBody { + readonly id: string; + readonly timestamp: Date; + readonly body: Body; + adk(): void; + retry(options?: CloudflareQueueRetryOptions): void; +} + +export interface CloudflareMessageBatch { + readonly queue: string; + readonly messages: CloudflareMessageBody[]; + ackAll(): void; + retryAll(options?: CloudflareQueueRetryOptions): void; +} + +declare module "nitropack/types" { + export interface NitroRuntimeHooks { + "cloudflare:email": (_: { + event: CloudflareEmailContext; + env: any; + context: ExecutionContext; + }) => void; + "cloudflare:queue": (_: { + event: CloudflareEmailContext; + env: any; + context: ExecutionContext; + }) => void; + } +} diff --git a/src/runtime/cloudflare.ts b/src/runtime/cloudflare.ts deleted file mode 100644 index 13729da069..0000000000 --- a/src/runtime/cloudflare.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** @experimental */ -export interface EmailContext { - readonly from?: string; - readonly to?: string; - readonly headers?: Headers; - readonly raw?: ReadableStream; - readonly rawSize?: number; - - setReject?(reason: string): void; - forward?(rcptTo: string, headers?: Headers): Promise; - reply?(message: EmailContext): Promise; -} - -export interface QueueRetryOptions { - delaySeconds?: number; -} - -export interface MessageBody { - readonly id: string; - readonly timestamp: Date; - readonly body: Body; - adk(): void; - retry(options?: QueueRetryOptions): void; -} - -export interface MessageBatch { - readonly queue: string; - readonly messages: MessageBody[]; - ackAll(): void; - retryAll(options?: QueueRetryOptions): void; -} diff --git a/src/types/runtime/nitro.ts b/src/types/runtime/nitro.ts index a1732bd8da..50157efc09 100644 --- a/src/types/runtime/nitro.ts +++ b/src/types/runtime/nitro.ts @@ -4,8 +4,6 @@ import type { createCall, createFetch as createLocalFetch, } from "unenv/runtime/fetch/index"; -import { EmailContext, MessageBatch } from "#internal/nitro/cloudflare"; -import { ExecutionContext } from "@cloudflare/workers-types"; export interface NitroApp { h3App: H3App; @@ -57,13 +55,4 @@ export interface NitroRuntimeHooks { response: Partial, context: { event: H3Event } ) => void; - - "cloudflare:email": ( - event: EmailContext, - context: { env: any; context: ExecutionContext } - ) => void; - "cloudflare:queue": ( - event: MessageBatch, - context: { env: any; context: ExecutionContext } - ) => void; }