Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: use getPlatformProxy and provide more context fields #6

Merged
merged 2 commits into from Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
@@ -1,6 +1,6 @@
# Cloudflare Bindings for Nitro and Nuxt
# Cloudflare Platform for Nitro and Nuxt

This proof of concept module enables access to the Cloudflare runtime bindings in the development server of [Nitro](https://nitro.unjs.io) and [Nuxt](https://nuxt.com) using the [new `getBindingsProxy` API](https://github.com/cloudflare/workers-sdk/pull/4523) exposed by [wrangler](https://developers.cloudflare.com/workers/wrangler/) and [miniflare](https://miniflare.dev/)
This proof of concept module enables access to the Cloudflare runtime platform in the development server of [Nitro](https://nitro.unjs.io) and [Nuxt](https://nuxt.com) using the [new `getPlatformProxy` API](https://github.com/cloudflare/workers-sdk/pull/5002) exposed by [wrangler](https://developers.cloudflare.com/workers/wrangler/) and [miniflare](https://miniflare.dev/)

> [!NOTE]
> Nitro plans to introduce a new method to allow native dev presets, meaning you can natively run [miniflare](https://miniflare.dev/) as your development server without this module or a proxy in the future!
Expand Down
4 changes: 2 additions & 2 deletions examples/nitro/routes/counter.ts
Expand Up @@ -2,7 +2,7 @@ export default eventHandler(async (event) => {
const { KV } = event.context.cloudflare.env;

let ctr = (await KV.get("counter")) || 0;
await KV.put("counter", ++ctr);
await KV.put("counter", ++ctr % 100);

return { counter: ctr };
return `counter: ${(await KV.get("counter")) || 0}`;
});
20 changes: 17 additions & 3 deletions examples/nitro/routes/index.ts
@@ -1,4 +1,18 @@
export default eventHandler(async () => {
const { counter } = (await $fetch("/counter")) as { counter: number };
return `<div>Counter: ${counter}</div>`;
export default eventHandler(async (event) => {
const cloudflare = await event.context.cloudflare;

const logs: string[] = [];
const log = (str: string) => logs.push(str);

log(`Keys of cloudflare: ${Object.keys(cloudflare).join(", ")}`);

log(`Keys of cloudflare.env: ${Object.keys(cloudflare.env).join(", ")}`);

log(`Colo: ${cloudflare.request.cf.colo}`);

log(
`typeof cloudflare.context.waitUntil: ${typeof cloudflare.context.waitUntil}`,
);

return `<div><ul><br>${logs.map((str) => `<li>${str}</li>`).join("\n<br>\n")}</ul></div>`;
});
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -52,7 +52,7 @@
"prettier": "^3.2.4",
"typescript": "^5.2.2",
"unbuild": "^2.0.0",
"wrangler": "^3.24.0"
"wrangler": "^3.28.2"
},
"packageManager": "[email protected]"
}
87 changes: 72 additions & 15 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 55 additions & 9 deletions src/runtime/plugin.dev.ts
@@ -1,23 +1,52 @@
import type { NitroAppPlugin } from "nitropack";
// @ts-ignore
import { useRuntimeConfig } from "#imports";
import { useRuntimeConfig, getRequestURL } from "#imports";

export default <NitroAppPlugin>function (nitroApp) {
let _proxy: ReturnType<typeof getBindingsProxy>;
let _proxy: ReturnType<typeof getPlatformProxy>;

nitroApp.hooks.hook("request", async (event) => {
// Lazy initialize proxy when first request comes in
if (!_proxy) {
_proxy = getBindingsProxy().catch((error) => {
_proxy = getPlatformProxy().catch((error) => {
console.error("Failed to initialize wrangler bindings proxy", error);
return { bindings: {}, dispose: () => Promise.resolve() };
return {
env: {},
cf: {},
ctx: {
waitUntil() {},
passThroughOnException() {},
},
caches: {
open(): Promise<Cache> {
const result = Promise.resolve(new Cache());
return result;
},
get default(): Cache {
return new Cache();
},
},
dispose: () => Promise.resolve(),
} as unknown as ReturnType<typeof getPlatformProxy>;
});
}

// Inject proxy bindings to the request context
const proxy = await _proxy;

// Inject the various cf values from the proxy in event and event.context

event.waitUntil = proxy.ctx.waitUntil;
(event.context as any).cf = proxy.cf;
(event.context as any).waitUntil = proxy.ctx.waitUntil;

const request = new Request(getRequestURL(event));
(request as any).cf = proxy.cf;

event.context.cloudflare = {
...event.context.cloudflare,
env: (await _proxy).bindings,
request,
env: proxy.env,
context: proxy.ctx,
};
});

Expand All @@ -27,20 +56,37 @@ export default <NitroAppPlugin>function (nitroApp) {
});
};

async function getBindingsProxy() {
async function getPlatformProxy() {
const _pkg = "wrangler"; // Bypass bundling!
const { getBindingsProxy } = (await import(
const { getPlatformProxy } = (await import(
_pkg
)) as typeof import("wrangler");

const runtimeConfig: {
wrangler: { configPath: string; persistDir: string };
} = useRuntimeConfig();

const proxy = await getBindingsProxy({
const proxy = await getPlatformProxy({
configPath: runtimeConfig.wrangler.configPath,
persist: { path: runtimeConfig.wrangler.persistDir },
});

return proxy;
}

class Cache {
delete(): Promise<boolean> {
const result = Promise.resolve(false);
return result;
}

match() {
const result = Promise.resolve(undefined);
return result;
}

put(): Promise<void> {
const result = Promise.resolve();
return result;
}
}