feat: init

This commit is contained in:
2026-02-13 22:02:30 +01:00
commit 8f9ff830fb
16711 changed files with 3307340 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
import "#nitro-internal-pollyfills";
import type * as CF from "@cloudflare/workers-types";
import type { ExportedHandler } from "@cloudflare/workers-types";
type MaybePromise<T> = T | Promise<T>;
export declare function createHandler<Env>(hooks: {
fetch: (...params: [
...Parameters<NonNullable<ExportedHandler<Env>["fetch"]>>,
url: URL,
cfContextExtras: any
]) => MaybePromise<Response | CF.Response | undefined>;
}): ExportedHandler<Env>;
export declare function fetchHandler(request: Request | CF.Request, env: unknown, context: CF.ExecutionContext | DurableObjectState, url: URL | undefined, nitroApp: any, ctxExt: any): Promise<Response>;
export {};

View File

@@ -0,0 +1,112 @@
import "#nitro-internal-pollyfills";
import { useNitroApp } from "nitropack/runtime";
import { requestHasBody, runCronTasks } from "nitropack/runtime/internal";
export function createHandler(hooks) {
const nitroApp = useNitroApp();
return {
async fetch(request, env, context) {
const ctxExt = {};
const url = new URL(request.url);
if (hooks.fetch) {
const res = await hooks.fetch(request, env, context, url, ctxExt);
if (res) {
return res;
}
}
return fetchHandler(request, env, context, url, nitroApp, ctxExt);
},
scheduled(controller, env, context) {
globalThis.__env__ = env;
context.waitUntil(
nitroApp.hooks.callHook("cloudflare:scheduled", {
controller,
env,
context
})
);
if (import.meta._tasks) {
context.waitUntil(
runCronTasks(controller.cron, {
context: {
cloudflare: {
env,
context
}
},
payload: {}
})
);
}
},
email(message, env, context) {
globalThis.__env__ = env;
context.waitUntil(
nitroApp.hooks.callHook("cloudflare:email", {
message,
event: message,
// backward compat
env,
context
})
);
},
queue(batch, env, context) {
globalThis.__env__ = env;
context.waitUntil(
nitroApp.hooks.callHook("cloudflare:queue", {
batch,
event: batch,
env,
context
})
);
},
tail(traces, env, context) {
globalThis.__env__ = env;
context.waitUntil(
nitroApp.hooks.callHook("cloudflare:tail", {
traces,
env,
context
})
);
},
trace(traces, env, context) {
globalThis.__env__ = env;
context.waitUntil(
nitroApp.hooks.callHook("cloudflare:trace", {
traces,
env,
context
})
);
}
};
}
export async function fetchHandler(request, env, context, url = new URL(request.url), nitroApp = useNitroApp(), ctxExt) {
let body;
if (requestHasBody(request)) {
body = Buffer.from(await request.arrayBuffer());
}
globalThis.__env__ = env;
return nitroApp.localFetch(url.pathname + url.search, {
context: {
waitUntil: (promise) => context.waitUntil(promise),
_platform: {
cf: request.cf,
cloudflare: {
request,
env,
context,
url,
...ctxExt
}
}
},
host: url.hostname,
protocol: url.protocol,
method: request.method,
headers: request.headers,
body
});
}

View File

@@ -0,0 +1,20 @@
import "#nitro-internal-pollyfills";
import type * as CF from "@cloudflare/workers-types";
import { DurableObject } from "cloudflare:workers";
declare const DURABLE_BINDING = "$DurableObject";
interface Env {
ASSETS?: {
fetch: typeof CF.fetch;
};
[DURABLE_BINDING]?: CF.DurableObjectNamespace;
}
declare const _default: CF.ExportedHandler<Env, unknown, unknown>;
export default _default;
export declare class $DurableObject extends DurableObject {
constructor(state: DurableObjectState, env: Record<string, any>);
fetch(request: Request): Promise<Response>;
publish(topic: string, data: unknown, opts: any): void;
alarm(): void | Promise<void>;
webSocketMessage(client: WebSocket, message: ArrayBuffer | string): Promise<void>;
webSocketClose(client: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void>;
}

View File

@@ -0,0 +1,82 @@
import "#nitro-internal-pollyfills";
import { DurableObject } from "cloudflare:workers";
import wsAdapter from "crossws/adapters/cloudflare-durable";
import { useNitroApp } from "nitropack/runtime";
import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets";
import { createHandler, fetchHandler } from "./_module-handler.mjs";
const DURABLE_BINDING = "$DurableObject";
const DURABLE_INSTANCE = "server";
const nitroApp = useNitroApp();
const getDurableStub = (env) => {
const binding = env[DURABLE_BINDING];
if (!binding) {
throw new Error(
`Durable Object binding "${DURABLE_BINDING}" not available.`
);
}
const id = binding.idFromName(DURABLE_INSTANCE);
return binding.get(id);
};
const ws = import.meta._websocket ? wsAdapter({
...nitroApp.h3App.websocket,
instanceName: DURABLE_INSTANCE,
bindingName: DURABLE_BINDING
}) : void 0;
export default createHandler({
fetch(request, env, context, url, ctxExt) {
if (env.ASSETS && isPublicAssetURL(url.pathname)) {
return env.ASSETS.fetch(request);
}
ctxExt.durableFetch = (req = request) => getDurableStub(env).fetch(req);
if (import.meta._websocket && request.headers.get("upgrade") === "websocket") {
return ws.handleUpgrade(request, env, context);
}
}
});
export class $DurableObject extends DurableObject {
constructor(state, env) {
super(state, env);
state.waitUntil(
nitroApp.hooks.callHook("cloudflare:durable:init", this, {
state,
env
})
);
if (import.meta._websocket) {
ws.handleDurableInit(this, state, env);
}
}
fetch(request) {
globalThis.__env__ = this.env;
if (import.meta._websocket && request.headers.get("upgrade") === "websocket") {
return ws.handleDurableUpgrade(this, request);
}
const url = new URL(request.url);
return fetchHandler(request, this.env, this.ctx, url, nitroApp, {
durable: this
});
}
publish(topic, data, opts) {
if (!ws) {
throw new Error("WebSocket not available");
}
return ws.publish(topic, data, opts);
}
alarm() {
this.ctx.waitUntil(
nitroApp.hooks.callHook("cloudflare:durable:alarm", this)
);
}
async webSocketMessage(client, message) {
globalThis.__env__ = this.env;
if (import.meta._websocket) {
return ws.handleDurableMessage(this, client, message);
}
}
async webSocketClose(client, code, reason, wasClean) {
globalThis.__env__ = this.env;
if (import.meta._websocket) {
return ws.handleDurableClose(this, client, code, reason, wasClean);
}
}
}

View File

@@ -0,0 +1,6 @@
import "#nitro-internal-pollyfills";
interface Env {
__STATIC_CONTENT?: any;
}
declare const _default: import("@cloudflare/workers-types").ExportedHandler<Env, unknown, unknown>;
export default _default;

View File

@@ -0,0 +1,52 @@
import "#nitro-internal-pollyfills";
import {
getAssetFromKV,
mapRequestToAsset
} from "@cloudflare/kv-asset-handler";
import wsAdapter from "crossws/adapters/cloudflare";
import { withoutBase } from "ufo";
import { useNitroApp, useRuntimeConfig } from "nitropack/runtime";
import { getPublicAssetMeta } from "#nitro-internal-virtual/public-assets";
import { createHandler } from "./_module-handler.mjs";
import manifest from "__STATIC_CONTENT_MANIFEST";
const nitroApp = useNitroApp();
const ws = import.meta._websocket ? wsAdapter(nitroApp.h3App.websocket) : void 0;
export default createHandler({
async fetch(request, env, context) {
if (import.meta._websocket && request.headers.get("upgrade") === "websocket") {
return ws.handleUpgrade(request, env, context);
}
try {
return await getAssetFromKV(
{
request,
waitUntil(promise) {
return context.waitUntil(promise);
}
},
{
cacheControl: assetsCacheControl,
mapRequestToAsset: baseURLModifier,
ASSET_NAMESPACE: env.__STATIC_CONTENT,
ASSET_MANIFEST: JSON.parse(manifest)
}
);
} catch {
}
}
});
function assetsCacheControl(_request) {
const url = new URL(_request.url);
const meta = getPublicAssetMeta(url.pathname);
if (meta.maxAge) {
return {
browserTTL: meta.maxAge,
edgeTTL: meta.maxAge
};
}
return {};
}
const baseURLModifier = (request) => {
const url = withoutBase(request.url, useRuntimeConfig().app.baseURL);
return mapRequestToAsset(new Request(url, request));
};

View File

@@ -0,0 +1,9 @@
import "#nitro-internal-pollyfills";
import type { fetch } from "@cloudflare/workers-types";
interface Env {
ASSETS?: {
fetch: typeof fetch;
};
}
declare const _default: import("@cloudflare/workers-types").ExportedHandler<Env, unknown, unknown>;
export default _default;

View File

@@ -0,0 +1,17 @@
import "#nitro-internal-pollyfills";
import wsAdapter from "crossws/adapters/cloudflare";
import { useNitroApp } from "nitropack/runtime";
import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets";
import { createHandler } from "./_module-handler.mjs";
const nitroApp = useNitroApp();
const ws = import.meta._websocket ? wsAdapter(nitroApp.h3App.websocket) : void 0;
export default createHandler({
fetch(request, env, context, url) {
if (env.ASSETS && isPublicAssetURL(url.pathname)) {
return env.ASSETS.fetch(request);
}
if (import.meta._websocket && request.headers.get("upgrade") === "websocket") {
return ws.handleUpgrade(request, env, context);
}
}
});

View File

@@ -0,0 +1,20 @@
import "#nitro-internal-pollyfills";
import type { Request as CFRequest, EventContext, ExecutionContext } from "@cloudflare/workers-types";
/**
* Reference: https://developers.cloudflare.com/workers/runtime-apis/fetch-event/#parameters
*/
interface CFPagesEnv {
ASSETS: {
fetch: (request: CFRequest) => Promise<Response>;
};
CF_PAGES: "1";
CF_PAGES_BRANCH: string;
CF_PAGES_COMMIT_SHA: string;
CF_PAGES_URL: string;
[key: string]: any;
}
declare const _default: {
fetch(request: CFRequest, env: CFPagesEnv, context: EventContext<CFPagesEnv, string, any>): Promise<any>;
scheduled(event: any, env: CFPagesEnv, context: ExecutionContext): void;
};
export default _default;

View File

@@ -0,0 +1,61 @@
import "#nitro-internal-pollyfills";
import { useNitroApp } from "nitropack/runtime";
import { requestHasBody, runCronTasks } from "nitropack/runtime/internal";
import { isPublicAssetURL } from "#nitro-internal-virtual/public-assets";
import wsAdapter from "crossws/adapters/cloudflare";
const nitroApp = useNitroApp();
const ws = import.meta._websocket ? wsAdapter(nitroApp.h3App.websocket) : void 0;
export default {
async fetch(request, env, context) {
if (import.meta._websocket && request.headers.get("upgrade") === "websocket") {
return ws.handleUpgrade(
request,
env,
context
);
}
const url = new URL(request.url);
if (env.ASSETS && isPublicAssetURL(url.pathname)) {
return env.ASSETS.fetch(request);
}
let body;
if (requestHasBody(request)) {
body = Buffer.from(await request.arrayBuffer());
}
globalThis.__env__ = env;
return nitroApp.localFetch(url.pathname + url.search, {
context: {
waitUntil: (promise) => context.waitUntil(promise),
_platform: {
cf: request.cf,
cloudflare: {
request,
env,
context
}
}
},
host: url.hostname,
protocol: url.protocol,
method: request.method,
headers: request.headers,
body
});
},
scheduled(event, env, context) {
if (import.meta._tasks) {
globalThis.__env__ = env;
context.waitUntil(
runCronTasks(event.cron, {
context: {
cloudflare: {
env,
context
}
},
payload: {}
})
);
}
}
};

View File

@@ -0,0 +1 @@
import "#nitro-internal-pollyfills";

View File

@@ -0,0 +1,65 @@
import "#nitro-internal-pollyfills";
import { useNitroApp, useRuntimeConfig } from "nitropack/runtime";
import { requestHasBody } from "nitropack/runtime/internal";
import { getPublicAssetMeta } from "#nitro-internal-virtual/public-assets";
import {
getAssetFromKV,
mapRequestToAsset
} from "@cloudflare/kv-asset-handler";
import wsAdapter from "crossws/adapters/cloudflare";
import { withoutBase } from "ufo";
addEventListener("fetch", (event) => {
event.respondWith(handleEvent(event));
});
const nitroApp = useNitroApp();
const ws = import.meta._websocket ? wsAdapter(nitroApp.h3App.websocket) : void 0;
async function handleEvent(event) {
if (import.meta._websocket && event.request.headers.get("upgrade") === "websocket") {
return ws.handleUpgrade(event.request, {}, event);
}
try {
return await getAssetFromKV(event, {
cacheControl: assetsCacheControl,
mapRequestToAsset: baseURLModifier
});
} catch {
}
const url = new URL(event.request.url);
let body;
if (requestHasBody(event.request)) {
body = Buffer.from(await event.request.arrayBuffer());
}
return nitroApp.localFetch(url.pathname + url.search, {
context: {
waitUntil: (promise) => event.waitUntil(promise),
_platform: {
// https://developers.cloudflare.com/workers/runtime-apis/request#incomingrequestcfproperties
cf: event.request.cf,
cloudflare: {
event
}
}
},
host: url.hostname,
protocol: url.protocol,
headers: event.request.headers,
method: event.request.method,
redirect: event.request.redirect,
body
});
}
function assetsCacheControl(_request) {
const url = new URL(_request.url);
const meta = getPublicAssetMeta(url.pathname);
if (meta.maxAge) {
return {
browserTTL: meta.maxAge,
edgeTTL: meta.maxAge
};
}
return {};
}
const baseURLModifier = (request) => {
const url = withoutBase(request.url, useRuntimeConfig().app.baseURL);
return mapRequestToAsset(new Request(url, request));
};

View File

@@ -0,0 +1,3 @@
import type { NitroAppPlugin } from "nitropack";
declare const _default: NitroAppPlugin;
export default _default;

View File

@@ -0,0 +1,84 @@
import { useRuntimeConfig, getRequestURL } from "#imports";
const proxy = await _getPlatformProxy().catch((error) => {
console.error("Failed to initialize wrangler bindings proxy", error);
return _createStubProxy();
});
globalThis.__env__ = proxy.env;
globalThis.__wait_until__ = proxy.ctx.waitUntil.bind(proxy.ctx);
export default (function(nitroApp) {
nitroApp.hooks.hook("request", async (event) => {
event.context.cf = proxy.cf;
event.context.waitUntil = proxy.ctx.waitUntil.bind(proxy.ctx);
const request = new Request(getRequestURL(event));
request.cf = proxy.cf;
event.context.cloudflare = {
...event.context.cloudflare,
request,
env: proxy.env,
context: proxy.ctx
};
event.node.req.__unenv__ = {
...event.node.req.__unenv__,
waitUntil: event.context.waitUntil
};
});
nitroApp.hooks._hooks.request.unshift(nitroApp.hooks._hooks.request.pop());
nitroApp.hooks.hook("close", () => {
return proxy?.dispose();
});
});
async function _getPlatformProxy() {
const _pkg = "wrangler";
const { getPlatformProxy } = await import(_pkg).catch(() => {
throw new Error(
"Package `wrangler` not found, please install it with: `npx nypm@latest add -D wrangler`"
);
});
const runtimeConfig = useRuntimeConfig();
const proxyOptions = {
configPath: runtimeConfig.wrangler.configPath,
persist: { path: runtimeConfig.wrangler.persistDir }
};
if (runtimeConfig.wrangler.environment) {
proxyOptions.environment = runtimeConfig.wrangler.environment;
}
const proxy2 = await getPlatformProxy(proxyOptions);
return proxy2;
}
function _createStubProxy() {
return {
env: {},
cf: {},
ctx: {
waitUntil() {
},
passThroughOnException() {
},
props: {}
},
caches: {
open() {
const result = Promise.resolve(new _CacheStub());
return result;
},
get default() {
return new _CacheStub();
}
},
dispose: () => Promise.resolve()
};
}
class _CacheStub {
delete() {
const result = Promise.resolve(false);
return result;
}
match() {
const result = Promise.resolve(void 0);
return result;
}
put() {
const result = Promise.resolve();
return result;
}
}

View File

@@ -0,0 +1,21 @@
export function waitUntil(promise: any): Promise<void>;
export function withEnv(newEnv: any, fn: any): void;
export class DurableObject extends NotImplemented {
}
export class RpcPromise extends NotImplemented {
}
export class RpcProperty extends NotImplemented {
}
export class RpcStub extends NotImplemented {
}
export class RpcTarget extends NotImplemented {
}
export class ServiceStub extends NotImplemented {
}
export class WorkerEntrypoint extends NotImplemented {
}
export class WorkflowEntrypoint extends NotImplemented {
}
declare class NotImplemented {
}
export {};

View File

@@ -0,0 +1,27 @@
// Shim for "cloudflare:workers" import in dev environment
// unenv shim respects __env__
export { env } from "unenv/node/internal/process/env";
export async function waitUntil(promise) {
await globalThis.__wait_until__?.(promise);
}
export function withEnv(newEnv, fn) {
throw new Error("cf.withEnv is not implemented in dev env currently.");
}
class NotImplemented {
constructor() {
throw new Error("Not implemented in dev env currently.");
}
}
export class DurableObject extends NotImplemented {}
export class RpcPromise extends NotImplemented {}
export class RpcProperty extends NotImplemented {}
export class RpcStub extends NotImplemented {}
export class RpcTarget extends NotImplemented {}
export class ServiceStub extends NotImplemented {}
export class WorkerEntrypoint extends NotImplemented {}
export class WorkflowEntrypoint extends NotImplemented {}