Ctrl K
ComunidadGuías…

workers/app.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Copyright (c) 2026 Doforu
// Copyright (c) 2026 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE-APACHE file or at:
//     https://opensource.org/licenses/Apache-2.0
// Modifications Copyright (c) 2026 Doforu, distributed under the AGPL-3.0-only (see LICENSE).

import { Hono } from "hono";
import {
	createContext,
	createRequestHandler,
	RouterContextProvider,
} from "react-router";
import { app as apiApp, receiveEmail } from "./index";
import type { Env } from "./types";

/**
 * Context key for the Cloudflare bindings, exposed to React Router loaders
 * and middleware via `context.get(cloudflareContext)`.
 *
 * With `future.v8_middleware` enabled, the request context is a
 * `RouterContextProvider` (not a plain object), and `createRequestHandler`
 * rejects any other shape — so the bindings now travel as a typed context
 * entry instead of a plain `AppLoadContext` object.
 */
export const cloudflareContext = createContext<{
	env: Env;
	ctx: ExecutionContext;
}>();

declare module "react-router" {
	export interface AppLoadContext {
		cloudflare: {
			env: Env;
			ctx: ExecutionContext;
		};
	}
}

const requestHandler = createRequestHandler(
	() => import("virtual:react-router/server-build"),
	import.meta.env.MODE,
);

// Main app that wraps the API and adds React Router fallback
const app = new Hono<{ Bindings: Env }>();

// Mount the API routes
app.route("/", apiApp);

// React Router catch-all: serves the SPA for all non-API routes
app.all("*", (c) => {
	// With middleware enabled the load context must be a `RouterContextProvider`.
	// Route middleware (e.g. i18n) extends this same object for the request.
	const context = new RouterContextProvider();
	context.set(cloudflareContext, {
		env: c.env,
		ctx: c.executionCtx as ExecutionContext,
	});
	return requestHandler(c.req.raw, context);
});

// Export the Hono app as the default export with an email handler
export default {
	fetch: app.fetch,
	async email(
		event: { raw: ReadableStream; rawSize: number },
		env: Env,
		ctx: ExecutionContext,
	) {
		try {
			await receiveEmail(event, env, ctx);
		} catch (e) {
			console.error("Failed to process incoming email:", (e as Error).message, (e as Error).stack);
			// Re-throw so Cloudflare's email routing can retry delivery or bounce the message.
			// Swallowing the error would silently drop the email.
			throw e;
		}
	},
};