|
1 | 1 | import { Hono } from 'hono';
|
| 2 | +import { unstable_getPlatformObject } from 'waku/server'; |
2 | 3 | import { runner } from '../hono/runner.js';
|
| 4 | +import type { |
| 5 | + ExportedHandler, |
| 6 | + fetch, |
| 7 | + Response as CloudflareResponse, |
| 8 | +} from '@cloudflare/workers-types/experimental'; |
3 | 9 |
|
4 | 10 | const loadEntries = () => import(import.meta.env.WAKU_ENTRIES_FILE!);
|
5 | 11 | let serveWaku: ReturnType<typeof runner> | undefined;
|
6 | 12 |
|
7 | 13 | export interface CloudflareEnv {
|
8 | 14 | ASSETS: {
|
9 |
| - fetch: (input: RequestInit | URL, init?: RequestInit) => Promise<Response>; |
| 15 | + fetch: typeof fetch; |
10 | 16 | };
|
11 | 17 | }
|
12 | 18 |
|
13 | 19 | export const app = new Hono<{
|
14 | 20 | Bindings: CloudflareEnv & { [k: string]: unknown };
|
15 | 21 | }>();
|
16 |
| -app.use('*', (c, next) => serveWaku!(c, next)); |
| 22 | +app.use('*', (c, next) => { |
| 23 | + if (!serveWaku) { |
| 24 | + throw new Error('serveWaku is not initialized'); |
| 25 | + } |
| 26 | + const platform = unstable_getPlatformObject(); |
| 27 | + platform.honoContext = c; |
| 28 | + platform.env = c.env; |
| 29 | + platform.executionContext = c.executionCtx; |
| 30 | + return serveWaku(c, next); |
| 31 | +}); |
17 | 32 | app.notFound(async (c) => {
|
18 | 33 | const assetsFetcher = c.env.ASSETS;
|
19 | 34 | const url = new URL(c.req.raw.url);
|
20 | 35 | const errorHtmlUrl = `${url.origin}/404.html`;
|
21 |
| - const notFoundStaticAssetResponse = await assetsFetcher.fetch( |
| 36 | + const notFoundStaticAssetResponse = (await assetsFetcher.fetch( |
22 | 37 | new URL(errorHtmlUrl),
|
23 |
| - ); |
| 38 | + )) as unknown as Response; |
24 | 39 | if (notFoundStaticAssetResponse && notFoundStaticAssetResponse.status < 400) {
|
25 | 40 | return c.body(notFoundStaticAssetResponse.body, 404);
|
26 | 41 | }
|
27 | 42 | return c.text('404 Not Found', 404);
|
28 | 43 | });
|
29 | 44 |
|
30 |
| -export default { |
31 |
| - async fetch( |
32 |
| - request: Request, |
33 |
| - env: Record<string, string>, |
34 |
| - ctx: Parameters<typeof app.fetch>[2], |
35 |
| - ) { |
| 45 | +// Waku getEnv only supports strings |
| 46 | +// Cloudflare injects bindings to env and JSON |
| 47 | +// Use unstable_getPlatformObject() to access cloudflare env and execution context |
| 48 | +// https://developers.cloudflare.com/workers/configuration/environment-variables/#add-environment-variables-via-wrangler |
| 49 | +// https://developers.cloudflare.com/workers/runtime-apis/bindings/ |
| 50 | +const extractWakuEnv = (env: Record<string, unknown>): Record<string, string> => |
| 51 | + Object.fromEntries( |
| 52 | + Object.entries(env).filter(([, value]) => typeof value === 'string'), |
| 53 | + ) as Record<string, string>; |
| 54 | + |
| 55 | +const handler: ExportedHandler<CloudflareEnv & { [k: string]: never }> = { |
| 56 | + async fetch(request, env, ctx) { |
36 | 57 | if (!serveWaku) {
|
37 |
| - serveWaku = runner({ cmd: 'start', loadEntries, env }); |
| 58 | + serveWaku = runner({ |
| 59 | + cmd: 'start', |
| 60 | + loadEntries, |
| 61 | + env: extractWakuEnv(env), |
| 62 | + }); |
38 | 63 | }
|
39 |
| - return app.fetch(request, env, ctx); |
| 64 | + return app.fetch( |
| 65 | + request as unknown as Request, |
| 66 | + env, |
| 67 | + ctx, |
| 68 | + ) as unknown as CloudflareResponse; |
40 | 69 | },
|
| 70 | + // It might be useful to have a way to populate other handlers tail, trace, scheduled, email, queue |
| 71 | + // But it's not hard to create a separate worker with those handlers and access it via |
| 72 | + // service bindings. https://developers.cloudflare.com/pages/functions/bindings/#service-bindings |
41 | 73 | };
|
| 74 | + |
| 75 | +export default handler; |
0 commit comments