diff --git a/.changeset/poor-frogs-clean.md b/.changeset/poor-frogs-clean.md new file mode 100644 index 000000000000..353e304daed9 --- /dev/null +++ b/.changeset/poor-frogs-clean.md @@ -0,0 +1,6 @@ +--- +'@astrojs/cloudflare': patch +--- + +enable access to cloudflare runtime [KV, R2, Durable Objects] +- access native cloudflare runtime through `import { getRuntime } from "@astrojs/cloudflare/runtime"` now you can call `getRuntime(Astro.request)` and get access to the runtime environment diff --git a/packages/integrations/cloudflare/README.md b/packages/integrations/cloudflare/README.md index 755451185a71..66f4fdd209e4 100644 --- a/packages/integrations/cloudflare/README.md +++ b/packages/integrations/cloudflare/README.md @@ -68,6 +68,18 @@ $ pnpm install wrangler --save-dev It's then possible to update the preview script in your `package.json` to `"preview": "wrangler pages dev ./dist"`.This will allow you run your entire application locally with [Wrangler](https://github.com/cloudflare/wrangler2), which supports secrets, environment variables, KV namespaces, Durable Objects and [all other supported Cloudflare bindings](https://developers.cloudflare.com/pages/platform/functions/#adding-bindings). +## Access to the cloudflare runtime + +You have the posibility to access all the cloudflare bindings and environment variables from your astro pages and api routes through the adapter API + +``` +import { getRuntime } from "@astrojs/cloudflare/runtime"; + +getRuntime(Astro.request); +``` + +Depending your adapter mode (advanced = worker, directory = pages) the runtime object will look a little different due to the difference in the cloudflare API. + ## Streams Some integrations such as [React](https://github.com/withastro/astro/tree/main/packages/integrations/react) rely on web streams. Currently Cloudflare Pages Functions require enabling a flag to support Streams. diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index b33216c09063..df1348a18868 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@astrojs/cloudflare", - "description": "Deploy your site to cloudflare pages functions", + "description": "Deploy your site to cloudflare workers or cloudflare pages", "version": "3.1.0", "type": "module", "types": "./dist/index.d.ts", @@ -19,6 +19,7 @@ "homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/", "exports": { ".": "./dist/index.js", + "./runtime": "./dist/runtime.js", "./server.advanced.js": "./dist/server.advanced.js", "./server.directory.js": "./dist/server.directory.js", "./package.json": "./package.json" diff --git a/packages/integrations/cloudflare/src/runtime.ts b/packages/integrations/cloudflare/src/runtime.ts new file mode 100644 index 000000000000..ddf372cb4d40 --- /dev/null +++ b/packages/integrations/cloudflare/src/runtime.ts @@ -0,0 +1,28 @@ +export type WorkerRuntime = { + name: 'cloudflare'; + env: T; + waitUntil(promise: Promise): void; + passThroughOnException(): void; +}; + +export type PagesRuntime = { + name: 'cloudflare'; + env: T; + functionPath: string; + params: Record; + data: U; + waitUntil(promise: Promise): void; + next(request: Request): void; +}; + +export function getRuntime( + request: Request +): WorkerRuntime | PagesRuntime { + if (!!request) { + return Reflect.get(request, Symbol.for('runtime')); + } else { + throw new Error( + 'To retrieve the current cloudflare runtime you need to pass in the Astro request object' + ); + } +} diff --git a/packages/integrations/cloudflare/src/server.advanced.ts b/packages/integrations/cloudflare/src/server.advanced.ts index c285ccaba044..502700e0be97 100644 --- a/packages/integrations/cloudflare/src/server.advanced.ts +++ b/packages/integrations/cloudflare/src/server.advanced.ts @@ -5,12 +5,13 @@ import { App } from 'astro/app'; type Env = { ASSETS: { fetch: (req: Request) => Promise }; + name: string; }; export function createExports(manifest: SSRManifest) { const app = new App(manifest, false); - const fetch = async (request: Request, env: Env) => { + const fetch = async (request: Request, env: Env, context: any) => { const { origin, pathname } = new URL(request.url); // static assets @@ -26,6 +27,7 @@ export function createExports(manifest: SSRManifest) { Symbol.for('astro.clientAddress'), request.headers.get('cf-connecting-ip') ); + Reflect.set(request, Symbol.for('runtime'), { env, name: 'cloudflare', ...context }); let response = await app.render(request, routeData); if (app.setCookieHeaders) { diff --git a/packages/integrations/cloudflare/src/server.directory.ts b/packages/integrations/cloudflare/src/server.directory.ts index e51d0ea57c7a..d31e2189fde6 100644 --- a/packages/integrations/cloudflare/src/server.directory.ts +++ b/packages/integrations/cloudflare/src/server.directory.ts @@ -9,12 +9,12 @@ export function createExports(manifest: SSRManifest) { const onRequest = async ({ request, next, + ...runtimeEnv }: { request: Request; next: (request: Request) => void; - }) => { + } & Record) => { const { origin, pathname } = new URL(request.url); - // static assets if (manifest.assets.has(pathname)) { const assetRequest = new Request(`${origin}/static${pathname}`, request); @@ -28,6 +28,11 @@ export function createExports(manifest: SSRManifest) { Symbol.for('astro.clientAddress'), request.headers.get('cf-connecting-ip') ); + Reflect.set(request, Symbol.for('runtime'), { + ...runtimeEnv, + name: 'cloudflare', + next, + }); let response = await app.render(request, routeData); if (app.setCookieHeaders) {