Initial commit (by create-cloudflare CLI)

This commit is contained in:
J-onasJones 2023-09-14 18:58:13 +02:00
commit 58a42872a0
1745 changed files with 741893 additions and 0 deletions

67
node_modules/wrangler/templates/middleware/common.ts generated vendored Normal file
View file

@ -0,0 +1,67 @@
export type Awaitable<T> = T | Promise<T>;
// TODO: allow dispatching more events?
export type Dispatcher = (
type: "scheduled",
init: { cron?: string }
) => Awaitable<void>;
export type IncomingRequest = Request<
unknown,
IncomingRequestCfProperties<unknown>
>;
export interface MiddlewareContext {
dispatch: Dispatcher;
next(request: IncomingRequest, env: any): Awaitable<Response>;
}
export type Middleware = (
request: IncomingRequest,
env: any,
ctx: ExecutionContext,
middlewareCtx: MiddlewareContext
) => Awaitable<Response>;
const __facade_middleware__: Middleware[] = [];
// The register functions allow for the insertion of one or many middleware,
// We register internal middleware first in the stack, but have no way of controlling
// the order that addMiddleware is run in service workers so need an internal function.
export function __facade_register__(...args: (Middleware | Middleware[])[]) {
__facade_middleware__.push(...args.flat());
}
export function __facade_registerInternal__(
...args: (Middleware | Middleware[])[]
) {
__facade_middleware__.unshift(...args.flat());
}
function __facade_invokeChain__(
request: IncomingRequest,
env: any,
ctx: ExecutionContext,
dispatch: Dispatcher,
middlewareChain: Middleware[]
): Awaitable<Response> {
const [head, ...tail] = middlewareChain;
const middlewareCtx: MiddlewareContext = {
dispatch,
next(newRequest, newEnv) {
return __facade_invokeChain__(newRequest, newEnv, ctx, dispatch, tail);
},
};
return head(request, env, ctx, middlewareCtx);
}
export function __facade_invoke__(
request: IncomingRequest,
env: any,
ctx: ExecutionContext,
dispatch: Dispatcher,
finalMiddleware: Middleware
): Awaitable<Response> {
return __facade_invokeChain__(request, env, ctx, dispatch, [
...__facade_middleware__,
finalMiddleware,
]);
}

View file

@ -0,0 +1,137 @@
// // This loads all middlewares exposed on the middleware object
// // and then starts the invocation chain.
// // The big idea is that we can add these to the middleware export dynamically
// // through wrangler, or we can potentially let users directly add them as a sort
// // of "plugin" system.
import {
Dispatcher,
Middleware,
__facade_invoke__,
__facade_register__,
} from "./common";
import worker from "__ENTRY_POINT__";
// We need to preserve all of the exports from the worker
export * from "__ENTRY_POINT__";
class __Facade_ScheduledController__ implements ScheduledController {
#noRetry: ScheduledController["noRetry"];
constructor(
readonly scheduledTime: number,
readonly cron: string,
noRetry: ScheduledController["noRetry"]
) {
this.#noRetry = noRetry;
}
noRetry() {
if (!(this instanceof __Facade_ScheduledController__)) {
throw new TypeError("Illegal invocation");
}
// Need to call native method immediately in case uncaught error thrown
this.#noRetry();
}
}
const __facade_modules_fetch__: ExportedHandlerFetchHandler = function (
request,
env,
ctx
) {
if (worker.fetch === undefined)
throw new Error("Handler does not export a fetch() function.");
return worker.fetch(request, env, ctx);
};
function getMaskedEnv(rawEnv: unknown) {
let env = rawEnv as Record<string, unknown>;
if (worker.envWrappers && worker.envWrappers.length > 0) {
for (const wrapFn of worker.envWrappers) {
env = wrapFn(env);
}
}
return env;
}
/**
* This type is here to cause a type error if a new export handler is added to
* `ExportHandler` without it being included in the `facade` below.
*/
type MissingExportHandlers = Omit<
Required<ExportedHandler>,
"tail" | "trace" | "scheduled" | "queue" | "test" | "email" | "fetch"
>;
let registeredMiddleware = false;
const facade: ExportedHandler<unknown> & MissingExportHandlers = {
...(worker.tail && {
tail: maskHandlerEnv(worker.tail),
}),
...(worker.trace && {
trace: maskHandlerEnv(worker.trace),
}),
...(worker.scheduled && {
scheduled: maskHandlerEnv(worker.scheduled),
}),
...(worker.queue && {
queue: maskHandlerEnv(worker.queue),
}),
...(worker.test && {
test: maskHandlerEnv(worker.test),
}),
...(worker.email && {
email: maskHandlerEnv(worker.email),
}),
fetch(request, rawEnv, ctx) {
const env = getMaskedEnv(rawEnv);
// Get the chain of middleware from the worker object
if (worker.middleware && worker.middleware.length > 0) {
// Make sure we only register middleware once:
// https://github.com/cloudflare/workers-sdk/issues/2386#issuecomment-1614715911
if (!registeredMiddleware) {
registeredMiddleware = true;
for (const middleware of worker.middleware) {
__facade_register__(middleware);
}
}
const __facade_modules_dispatch__: Dispatcher = function (type, init) {
if (type === "scheduled" && worker.scheduled !== undefined) {
const controller = new __Facade_ScheduledController__(
Date.now(),
init.cron ?? "",
() => {}
);
return worker.scheduled(controller, env, ctx);
}
};
return __facade_invoke__(
request,
env,
ctx,
__facade_modules_dispatch__,
__facade_modules_fetch__
);
} else {
// We didn't have any middleware so we can skip the invocation chain,
// and just call the fetch handler directly
// We "don't care" if this is undefined as we want to have the same behavior
// as if the worker completely bypassed middleware.
return __facade_modules_fetch__(request, env, ctx);
}
},
};
type HandlerFn<D, R> = (data: D, env: unknown, ctx: ExecutionContext) => R;
function maskHandlerEnv<D, R>(handler: HandlerFn<D, R>): HandlerFn<D, R> {
return (data, env, ctx) => handler(data, getMaskedEnv(env), ctx);
}
export default facade;

228
node_modules/wrangler/templates/middleware/loader-sw.ts generated vendored Normal file
View file

@ -0,0 +1,228 @@
import {
Awaitable,
Dispatcher,
IncomingRequest,
Middleware,
__facade_invoke__,
__facade_register__,
__facade_registerInternal__,
} from "./common";
export { __facade_register__, __facade_registerInternal__ };
// Miniflare 2's `EventTarget` follows the spec and doesn't allow exceptions to
// be caught by `dispatchEvent`. Instead it has a custom `ThrowingEventTarget`
// class that rethrows errors from event listeners in `dispatchEvent`.
// We'd like errors to be propagated to the top-level `addEventListener`, so
// we'd like to use `ThrowingEventTarget`. Unfortunately, `ThrowingEventTarget`
// isn't exposed on the global scope, but `WorkerGlobalScope` (which extends
// `ThrowingEventTarget`) is. Therefore, we get at it in this nasty way.
let __FACADE_EVENT_TARGET__: EventTarget;
if ((globalThis as any).MINIFLARE) {
__FACADE_EVENT_TARGET__ = new (Object.getPrototypeOf(WorkerGlobalScope))();
} else {
__FACADE_EVENT_TARGET__ = new EventTarget();
}
function __facade_isSpecialEvent__(
type: string
): type is "fetch" | "scheduled" {
return type === "fetch" || type === "scheduled";
}
const __facade__originalAddEventListener__ = globalThis.addEventListener;
const __facade__originalRemoveEventListener__ = globalThis.removeEventListener;
const __facade__originalDispatchEvent__ = globalThis.dispatchEvent;
globalThis.addEventListener = function (type, listener, options) {
if (__facade_isSpecialEvent__(type)) {
__FACADE_EVENT_TARGET__.addEventListener(
type,
listener as EventListenerOrEventListenerObject,
options
);
} else {
__facade__originalAddEventListener__(type, listener, options);
}
};
globalThis.removeEventListener = function (type, listener, options) {
if (__facade_isSpecialEvent__(type)) {
__FACADE_EVENT_TARGET__.removeEventListener(
type,
listener as EventListenerOrEventListenerObject,
options
);
} else {
__facade__originalRemoveEventListener__(type, listener, options);
}
};
globalThis.dispatchEvent = function (event) {
if (__facade_isSpecialEvent__(event.type)) {
return __FACADE_EVENT_TARGET__.dispatchEvent(event);
} else {
return __facade__originalDispatchEvent__(event);
}
};
declare global {
var addMiddleware: typeof __facade_register__;
var addMiddlewareInternal: typeof __facade_registerInternal__;
}
globalThis.addMiddleware = __facade_register__;
globalThis.addMiddlewareInternal = __facade_registerInternal__;
const __facade_waitUntil__ = Symbol("__facade_waitUntil__");
const __facade_response__ = Symbol("__facade_response__");
const __facade_dispatched__ = Symbol("__facade_dispatched__");
class __Facade_ExtendableEvent__ extends Event {
[__facade_waitUntil__]: Awaitable<unknown>[] = [];
waitUntil(promise: Awaitable<any>) {
if (!(this instanceof __Facade_ExtendableEvent__)) {
throw new TypeError("Illegal invocation");
}
this[__facade_waitUntil__].push(promise);
}
}
interface FetchEventInit extends EventInit {
request: Request;
passThroughOnException: FetchEvent["passThroughOnException"];
}
class __Facade_FetchEvent__ extends __Facade_ExtendableEvent__ {
#request: Request;
#passThroughOnException: FetchEvent["passThroughOnException"];
[__facade_response__]?: Awaitable<Response>;
[__facade_dispatched__] = false;
constructor(type: "fetch", init: FetchEventInit) {
super(type);
this.#request = init.request;
this.#passThroughOnException = init.passThroughOnException;
}
get request() {
return this.#request;
}
respondWith(response: Awaitable<Response>) {
if (!(this instanceof __Facade_FetchEvent__)) {
throw new TypeError("Illegal invocation");
}
if (this[__facade_response__] !== undefined) {
throw new DOMException(
"FetchEvent.respondWith() has already been called; it can only be called once.",
"InvalidStateError"
);
}
if (this[__facade_dispatched__]) {
throw new DOMException(
"Too late to call FetchEvent.respondWith(). It must be called synchronously in the event handler.",
"InvalidStateError"
);
}
this.stopImmediatePropagation();
this[__facade_response__] = response;
}
passThroughOnException() {
if (!(this instanceof __Facade_FetchEvent__)) {
throw new TypeError("Illegal invocation");
}
// Need to call native method immediately in case uncaught error thrown
this.#passThroughOnException();
}
}
interface ScheduledEventInit extends EventInit {
scheduledTime: number;
cron: string;
noRetry: ScheduledEvent["noRetry"];
}
class __Facade_ScheduledEvent__ extends __Facade_ExtendableEvent__ {
#scheduledTime: number;
#cron: string;
#noRetry: ScheduledEvent["noRetry"];
constructor(type: "scheduled", init: ScheduledEventInit) {
super(type);
this.#scheduledTime = init.scheduledTime;
this.#cron = init.cron;
this.#noRetry = init.noRetry;
}
get scheduledTime() {
return this.#scheduledTime;
}
get cron() {
return this.#cron;
}
noRetry() {
if (!(this instanceof __Facade_ScheduledEvent__)) {
throw new TypeError("Illegal invocation");
}
// Need to call native method immediately in case uncaught error thrown
this.#noRetry();
}
}
__facade__originalAddEventListener__("fetch", (event) => {
const ctx: ExecutionContext = {
waitUntil: event.waitUntil.bind(event),
passThroughOnException: event.passThroughOnException.bind(event),
};
const __facade_sw_dispatch__: Dispatcher = function (type, init) {
if (type === "scheduled") {
const facadeEvent = new __Facade_ScheduledEvent__("scheduled", {
scheduledTime: Date.now(),
cron: init.cron ?? "",
noRetry() {},
});
__FACADE_EVENT_TARGET__.dispatchEvent(facadeEvent);
event.waitUntil(Promise.all(facadeEvent[__facade_waitUntil__]));
}
};
const __facade_sw_fetch__: Middleware = function (request, _env, ctx) {
const facadeEvent = new __Facade_FetchEvent__("fetch", {
request,
passThroughOnException: ctx.passThroughOnException,
});
__FACADE_EVENT_TARGET__.dispatchEvent(facadeEvent);
facadeEvent[__facade_dispatched__] = true;
event.waitUntil(Promise.all(facadeEvent[__facade_waitUntil__]));
const response = facadeEvent[__facade_response__];
if (response === undefined) {
throw new Error("No response!"); // TODO: proper error message
}
return response;
};
event.respondWith(
__facade_invoke__(
event.request as IncomingRequest,
globalThis,
ctx,
__facade_sw_dispatch__,
__facade_sw_fetch__
)
);
});
__facade__originalAddEventListener__("scheduled", (event) => {
const facadeEvent = new __Facade_ScheduledEvent__("scheduled", {
scheduledTime: event.scheduledTime,
cron: event.cron,
noRetry: event.noRetry.bind(event),
});
__FACADE_EVENT_TARGET__.dispatchEvent(facadeEvent);
event.waitUntil(Promise.all(facadeEvent[__facade_waitUntil__]));
});

View file

@ -0,0 +1,3 @@
declare module "config:middleware/d1-beta" {
export const D1_IMPORTS: string[];
}

View file

@ -0,0 +1,33 @@
import type { Middleware } from "./common";
interface JsonError {
message?: string;
name?: string;
stack?: string;
cause?: JsonError;
}
function reduceError(e: any): JsonError {
return {
name: e?.name,
message: e?.message ?? String(e),
stack: e?.stack,
cause: e?.cause === undefined ? undefined : reduceError(e.cause),
};
}
// See comment in `bundle.ts` for details on why this is needed
const jsonError: Middleware = async (request, env, _ctx, middlewareCtx) => {
try {
return await middlewareCtx.next(request, env);
} catch (e: any) {
const error = reduceError(e);
return Response.json(error, {
status: 500,
headers: { "MF-Experimental-Error-Stack": "true" },
});
}
};
export default jsonError;
export const wrap = undefined;

View file

@ -0,0 +1,4 @@
declare module "config:middleware/multiworker-dev" {
import type { WorkerRegistry } from "../../src/dev-registry";
export const workers: WorkerRegistry;
}

View file

@ -0,0 +1,59 @@
// @ts-nocheck
/// <reference path="middleware-multiworker-dev.d.ts"/>
import { workers } from "config:middleware/multiworker-dev";
import type { WorkerRegistry } from "../../src/dev-registry";
export function wrap(env: Record<string, unknown>) {
const facadeEnv = { ...env };
// For every Worker definition that's available,
// create a fetcher for it on the facade env.
// for const [name, binding] of env
// if Workers[name]
// const details = Workers[name];
for (const [name, details] of Object.entries(workers as WorkerRegistry)) {
if (details) {
facadeEnv[name] = {
async fetch(...reqArgs: Parameters<Fetcher["fetch"]>) {
const reqFromArgs = new Request(...reqArgs);
if (details.headers) {
for (const [key, value] of Object.entries(details.headers)) {
// In remote mode, you need to add a couple of headers
// to make sure it's talking to the 'dev' preview session
// (much like wrangler dev already does via proxy.ts)
reqFromArgs.headers.set(key, value);
}
return (env[name] as Fetcher).fetch(reqFromArgs);
}
const url = new URL(reqFromArgs.url);
if (details.protocol !== undefined) {
url.protocol = details.protocol;
}
if (details.host !== undefined) {
url.host = details.host;
}
if (details.port !== undefined) {
url.port = details.port.toString();
}
const request = new Request(url.toString(), reqFromArgs);
return fetch(request);
},
};
} else {
// This means there's no dev binding available.
// Let's use whatever's available, or put a shim with a message.
facadeEnv[name] = facadeEnv[name] || {
async fetch() {
return new Response(
`You should start up wrangler dev --local on the ${name} worker`,
{ status: 404 }
);
},
};
}
}
return facadeEnv;
}

View file

@ -0,0 +1,40 @@
import type { Middleware } from "./common";
// A middleware has to be a function of type Middleware
const prettyError: Middleware = async (request, env, _ctx, middlewareCtx) => {
try {
const response = await middlewareCtx.next(request, env);
return response;
} catch (e: any) {
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error 🚨</title>
<style>
pre {
margin: 16px auto;
max-width: 600px;
background-color: #eeeeee;
border-radius: 4px;
padding: 16px;
}
</style>
</head>
<body>
<pre>${e.stack}</pre>
</body>
</html>
`;
return new Response(html, {
status: 500,
headers: { "Content-Type": "text/html;charset=utf-8" },
});
}
};
export default prettyError;

View file

@ -0,0 +1,15 @@
import type { Middleware } from "./common";
// A middleware has to be a function of type Middleware
const scheduled: Middleware = async (request, env, _ctx, middlewareCtx) => {
const url = new URL(request.url);
if (url.pathname === "/__scheduled") {
const cron = url.searchParams.get("cron") ?? "";
await middlewareCtx.dispatch("scheduled", { cron });
return new Response("Ran scheduled event");
}
return middlewareCtx.next(request, env);
};
export default scheduled;

View file

@ -0,0 +1,6 @@
declare module "config:middleware/serve-static-assets" {
import type { CacheControl } from "@cloudflare/kv-asset-handler";
export const spaMode: boolean;
export const cacheControl: Partial<CacheControl>;
}

View file

@ -0,0 +1,56 @@
/// <reference path="middleware-serve-static-assets.d.ts"/>
import {
getAssetFromKV,
NotFoundError,
MethodNotAllowedError,
serveSinglePageApp,
} from "@cloudflare/kv-asset-handler";
import type { Options } from "@cloudflare/kv-asset-handler";
import { spaMode, cacheControl } from "config:middleware/serve-static-assets";
import type * as kvAssetHandler from "@cloudflare/kv-asset-handler";
import manifest from "__STATIC_CONTENT_MANIFEST";
const ASSET_MANIFEST = JSON.parse(manifest);
import type { Middleware } from "./common";
const staticAssets: Middleware = async (request, env, _ctx, middlewareCtx) => {
let options: Partial<Options> = {
ASSET_MANIFEST,
ASSET_NAMESPACE: env.__STATIC_CONTENT,
cacheControl: cacheControl,
mapRequestToAsset: spaMode ? serveSinglePageApp : undefined,
};
try {
const page = await (getAssetFromKV as typeof kvAssetHandler.getAssetFromKV)(
{
request,
waitUntil(promise) {
return _ctx.waitUntil(promise);
},
},
options
);
// allow headers to be altered
const response = new Response(page.body, page);
response.headers.set("X-XSS-Protection", "1; mode=block");
response.headers.set("X-Content-Type-Options", "nosniff");
response.headers.set("X-Frame-Options", "DENY");
response.headers.set("Referrer-Policy", "unsafe-url");
response.headers.set("Feature-Policy", "none");
return response;
} catch (e) {
if (e instanceof NotFoundError || e instanceof MethodNotAllowedError) {
// if a known error is thrown then serve from actual worker
return await middlewareCtx.next(request, env);
}
// otherwise it's a real error, so throw it
throw e;
}
};
export default staticAssets;