diff --git a/demos/mcp-clerk-oauth/.gitignore b/demos/mcp-clerk-oauth/.gitignore
new file mode 100644
index 00000000..3b0fe33c
--- /dev/null
+++ b/demos/mcp-clerk-oauth/.gitignore
@@ -0,0 +1,172 @@
+# Logs
+
+logs
+_.log
+npm-debug.log_
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+
+report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
+
+# Runtime data
+
+pids
+_.pid
+_.seed
+\*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+
+lib-cov
+
+# Coverage directory used by tools like istanbul
+
+coverage
+\*.lcov
+
+# nyc test coverage
+
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+
+bower_components
+
+# node-waf configuration
+
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+
+build/Release
+
+# Dependency directories
+
+node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+
+web_modules/
+
+# TypeScript cache
+
+\*.tsbuildinfo
+
+# Optional npm cache directory
+
+.npm
+
+# Optional eslint cache
+
+.eslintcache
+
+# Optional stylelint cache
+
+.stylelintcache
+
+# Microbundle cache
+
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+
+.node_repl_history
+
+# Output of 'npm pack'
+
+\*.tgz
+
+# Yarn Integrity file
+
+.yarn-integrity
+
+# dotenv environment variable files
+
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+
+.cache
+.parcel-cache
+
+# Next.js build output
+
+.next
+out
+
+# Nuxt.js build / generate output
+
+.nuxt
+dist
+
+# Gatsby files
+
+.cache/
+
+# Comment in the public line in if your project uses Gatsby and not Next.js
+
+# https://nextjs.org/blog/next-9-1#public-directory-support
+
+# public
+
+# vuepress build output
+
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+
+.temp
+.cache
+
+# Docusaurus cache and generated files
+
+.docusaurus
+
+# Serverless directories
+
+.serverless/
+
+# FuseBox cache
+
+.fusebox/
+
+# DynamoDB Local files
+
+.dynamodb/
+
+# TernJS port file
+
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+
+.vscode-test
+
+# yarn v2
+
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.\*
+
+# wrangler project
+
+.dev.vars
+.wrangler/
diff --git a/demos/mcp-clerk-oauth/README.md b/demos/mcp-clerk-oauth/README.md
new file mode 100644
index 00000000..4ebe9c68
--- /dev/null
+++ b/demos/mcp-clerk-oauth/README.md
@@ -0,0 +1,132 @@
+# Model Context Protocol (MCP) Server + Clerk OAuth
+
+
+
+This is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server that supports remote MCP connections, with [Clerk](http://clerk.com/) OAuth for your instance built-in.
+
+You can deploy it to your own Cloudflare account, and after you create your own Clerk OAuth client app for your instance, you'll have a fully functional remote MCP server that you can build off. Users will be able to connect to your MCP server by signing in with their account on your Clerk instance.
+
+You can use this as a reference example for how to integrate other OAuth providers with an MCP server deployed to Cloudflare, using the [`workers-oauth-provider` library](https://github.com/cloudflare/workers-oauth-provider).
+
+The MCP server (powered by [Cloudflare Workers](https://developers.cloudflare.com/workers/)):
+
+* Acts as OAuth _Server_ to your MCP clients
+* Acts as OAuth _Client_ to your _real_ OAuth server (in this case, your Clerk instance)
+
+## Getting Started
+
+### For Production
+Create a new [Clerk OAuth app](https://clerk.com/docs/advanced-usage/clerk-idp#create-a-clerk-o-auth-application) for your instance:
+- For the Redirect URI, specify `https://mcp-clerk-oauth..workers.dev/callback`
+- Note your Client ID and Client secret.
+
+#### Variables
+- `CLERK_OAUTH_SCOPES`: Scopes that define the level of access for user data for your MCP server, comma delimeted - these can be set in `wrangler.jsonc` - [Clerk OAuth Scopes](https://clerk.com/docs/advanced-usage/clerk-idp#scopes)
+
+#### Secrets
+- `CLERK_APP_CLIENT_ID` Client ID for Clerk OAuth application
+- `CLERK_APP_CLIENT_SECRET` Confidential secret for your Clerk OAuth application
+- `CLERK_APP_URL`: The base URL for your Clerk auth instance ie. `pretty-clouds-11.clerk.accounts.dev`
+
+
+- Set secrets via Wrangler
+```bash
+wrangler secret put CLERK_APP_CLIENT_ID
+wrangler secret put CLERK_APP_CLIENT_SECRET
+wrangler secret put CLERK_APP_URL
+```
+
+#### Set up a KV namespace
+- Create the KV namespace:
+`wrangler kv namespace create "OAUTH_KV"`
+- Update the Wrangler file with the KV ID
+
+#### Deploy & Test
+Deploy the MCP server to make it available on your workers.dev domain
+` wrangler deploy`
+
+Test the remote server using [Inspector](https://modelcontextprotocol.io/docs/tools/inspector):
+
+```
+npx @modelcontextprotocol/inspector@latest
+```
+Enter `https://mcp-clerk-oauth..workers.dev/sse` and hit connect. Once you go through the authentication flow, you'll see the Tools working:
+
+
+
+You now have a remote MCP server deployed!
+
+#### Access the remote MCP server from Claude Desktop
+
+Open Claude Desktop and navigate to Settings -> Developer -> Edit Config. This opens the configuration file that controls which MCP servers Claude can access.
+
+Replace the content with the following configuration. Once you restart Claude Desktop, a browser window will open showing your OAuth login page. Complete the authentication flow to grant Claude access to your MCP server. After you grant access, the tools will become available for you to use.
+
+```
+{
+ "mcpServers": {
+ "math": {
+ "command": "npx",
+ "args": [
+ "mcp-remote",
+ "https://mcp-clerk-oauth..workers.dev/sse"
+ ]
+ }
+ }
+}
+```
+
+Once the Tools (under 🔨) show up in the interface, you can ask Claude to use them. For example: "Could you use the math tool to add 23 and 19?". Claude should invoke the tool and show the result generated by the MCP server.
+
+### For Local Development
+If you'd like to iterate and test your MCP server, you can do so in local development. This will require you to create another OAuth App on Clerk:
+- For the Redirect URI, specify `http://localhost:8788/callback`
+- Note your Client ID and Client secret.
+- Create a `.dev.vars` file in your project root with:
+```
+CLERK_APP_CLIENT_ID="your_clerk_app_client_id"
+CLERK_APP_CLIENT_SECRET="your_clerk_app_client_secret"
+CLERK_OAUTH_SCOPES="your_scopes_for_your_mcp_comma_delimeted"
+CLERK_APP_URL="your_clerk_auth_application_url"
+```
+
+#### Develop & Test
+Run the server locally to make it available at `http://localhost:8788`
+`wrangler dev`
+
+To test the local server, enter `http://localhost:8788/sse` into Inspector and hit connect. Once you follow the prompts, you'll be able to "List Tools".
+
+#### Using Claude and other MCP Clients
+
+When using Claude to connect to your remote MCP server, you may see some error messages. This is because Claude Desktop doesn't yet support remote MCP servers, so it sometimes gets confused. To verify whether the MCP server is connected, hover over the 🔨 icon in the bottom right corner of Claude's interface. You should see your tools available there.
+
+#### Using Cursor and other MCP Clients
+
+To connect Cursor with your MCP server, choose `Type`: "Command" and in the `Command` field, combine the command and args fields into one (e.g. `npx mcp-remote https://..workers.dev/sse`).
+
+Note that while Cursor supports HTTP+SSE servers, it doesn't support authentication, so you still need to use `mcp-remote` (and to use a STDIO server, not an HTTP one).
+
+You can connect your MCP server to other MCP clients like Windsurf by opening the client's configuration file, adding the same JSON that was used for the Claude setup, and restarting the MCP client.
+
+## How does it work?
+
+#### OAuth Provider
+The OAuth Provider library serves as a complete OAuth 2.1 server implementation for Cloudflare Workers. It handles the complexities of the OAuth flow, including token issuance, validation, and management. In this project, it plays the dual role of:
+
+- Authenticating MCP clients that connect to your server
+- Managing the connection to your Clerk instance's OAuth services
+- Securely storing tokens and authentication state in KV storage
+
+#### McpAgent
+McpAgent extends the base MCP functionality with Cloudflare's Durable Objects, providing:
+- Persistent state management for your MCP server
+- Secure storage of authentication context between requests
+- Access to authenticated user information via `this.props`
+- Support for conditional tool availability based on user identity
+
+#### MCP Remote
+The MCP Remote library enables your server to expose tools that can be invoked by MCP clients like the Inspector. It:
+- Defines the protocol for communication between clients and your server
+- Provides a structured way to define tools
+- Handles serialization and deserialization of requests and responses
+- Maintains the Server-Sent Events (SSE) connection between clients and your server
diff --git a/demos/mcp-clerk-oauth/biome.json b/demos/mcp-clerk-oauth/biome.json
new file mode 100644
index 00000000..f9c94e1f
--- /dev/null
+++ b/demos/mcp-clerk-oauth/biome.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.6.2/schema.json",
+ "organizeImports": {
+ "enabled": true
+ },
+ "files": {
+ "ignore": ["node_modules/**/*", "dist/**/*"],
+ "include": ["src/**/*.ts"]
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true,
+ "suspicious": {
+ "noExplicitAny": "off",
+ "noDebugger": "off",
+ "noConsoleLog": "off",
+ "noConfusingVoidType": "off"
+ },
+ "style": {
+ "noNonNullAssertion": "off"
+ }
+ }
+ },
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "tab",
+ "indentWidth": 4,
+ "lineWidth": 100
+ }
+}
diff --git a/demos/mcp-clerk-oauth/package.json b/demos/mcp-clerk-oauth/package.json
new file mode 100644
index 00000000..9f0bb210
--- /dev/null
+++ b/demos/mcp-clerk-oauth/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "mcp-clerk-oauth",
+ "type": "module",
+ "scripts": {
+ "deploy": "wrangler deploy",
+ "dev": "wrangler dev",
+ "start": "wrangler dev",
+ "cf-typegen": "wrangler types",
+ "format": "biome format --write",
+ "lint": "biome lint --error-on-warnings",
+ "lint:fix": "biome lint --fix"
+ },
+ "devDependencies": {
+ "typescript": "^5.5.2",
+ "wrangler": "^4.2.0",
+ "@biomejs/biome": "^1.8.2"
+ },
+ "dependencies": {
+ "@cloudflare/workers-oauth-provider": "^0.0.2",
+ "@modelcontextprotocol/sdk": "^1.7.0",
+ "hono": "^4.7.4",
+ "agents": "^0.0.46",
+ "zod": "^3.24.2"
+ }
+}
diff --git a/demos/mcp-clerk-oauth/src/clerk-handler.ts b/demos/mcp-clerk-oauth/src/clerk-handler.ts
new file mode 100644
index 00000000..b6f5c920
--- /dev/null
+++ b/demos/mcp-clerk-oauth/src/clerk-handler.ts
@@ -0,0 +1,93 @@
+import type { AuthRequest, OAuthHelpers } from "@cloudflare/workers-oauth-provider";
+import { Hono } from "hono";
+import { fetchUpstreamAuthToken, getUpstreamAuthorizeUrl } from "./utils";
+import type { Props } from "./types";
+
+const app = new Hono<{ Bindings: Env & { OAUTH_PROVIDER: OAuthHelpers } }>();
+
+/**
+ * OAuth Authorization Endpoint
+ *
+ * This route initiates the Clerk OAuth flow when a user wants to log in.
+ * It creates a random state parameter to prevent CSRF attacks and stores the
+ * original OAuth request information in KV storage for later retrieval.
+ * Then it redirects the user to Clerk's authorization page for your app with the appropriate
+ * parameters so the user can authenticate.
+ */
+app.get("/authorize", async (c) => {
+ const oauthReqInfo = await c.env.OAUTH_PROVIDER.parseAuthRequest(c.req.raw);
+
+ if (!oauthReqInfo.clientId) {
+ return c.text("Invalid request", 400);
+ }
+
+ return Response.redirect(
+ getUpstreamAuthorizeUrl({
+ upstream_url: `${c.env.CLERK_APP_URL}/oauth/authorize`,
+ scopes: c.env.CLERK_OAUTH_SCOPES,
+ client_id: c.env.CLERK_APP_CLIENT_ID,
+ redirect_uri: new URL("/callback", c.req.url).href,
+ state: btoa(JSON.stringify(oauthReqInfo)),
+ }),
+ );
+});
+
+/**
+ * OAuth Callback Endpoint
+ *
+ * This route handles the callback from Clerk after user authentication.
+ * It exchanges the temporary code for an access token, then stores some
+ * user metadata & the auth token as part of the 'props' on the token passed
+ * down to the client. It ends by redirecting the client back to _its_ callback URL
+ */
+app.get("/callback", async (c) => {
+ // Get the oauthReqInfo out of KV
+ const oauthReqInfo = JSON.parse(atob(c.req.query("state") as string)) as AuthRequest;
+
+ if (!oauthReqInfo.clientId) {
+ return c.text("Invalid state", 400);
+ }
+
+ // Exchange the code for an access token
+ const [accessToken, errResponse] = await fetchUpstreamAuthToken({
+ upstream_url: `${c.env.CLERK_APP_URL}/oauth/token`,
+ client_id: c.env.CLERK_APP_CLIENT_ID,
+ client_secret: c.env.CLERK_APP_CLIENT_SECRET,
+ code: c.req.query("code"),
+ redirect_uri: new URL("/callback", c.req.url).href,
+ });
+
+ if (errResponse) return errResponse;
+
+ const props: Props = {
+ accessToken,
+ };
+
+ const userResponse = await fetch(`${c.env.CLERK_APP_URL}/oauth/userinfo`, {
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ },
+ });
+
+ if (!userResponse.ok) {
+ return new Response("Failed to fetch user info", { status: 500 });
+ }
+
+ const user = (await userResponse.json()) as {
+ user_id: string;
+ };
+
+ // Return back to the MCP client a new token
+ const { redirectTo } = await c.env.OAUTH_PROVIDER.completeAuthorization({
+ request: oauthReqInfo,
+ userId: user.user_id,
+ metadata: {},
+ scope: oauthReqInfo.scope,
+ // This will be available on this.props inside MyMCP
+ props,
+ });
+
+ return Response.redirect(redirectTo);
+});
+
+export const ClerkHandler = app;
diff --git a/demos/mcp-clerk-oauth/src/index.ts b/demos/mcp-clerk-oauth/src/index.ts
new file mode 100644
index 00000000..a3bbaabb
--- /dev/null
+++ b/demos/mcp-clerk-oauth/src/index.ts
@@ -0,0 +1,53 @@
+import OAuthProvider from "@cloudflare/workers-oauth-provider";
+import { McpAgent } from "agents/mcp";
+import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import { ClerkHandler } from "./clerk-handler";
+import type { Props } from "./types";
+
+export class MyMCP extends McpAgent {
+ server = new McpServer({
+ name: "Clerk OAuth Proxy Demo",
+ version: "1.0.0",
+ });
+
+ async init() {
+ // Hello, world!
+ this.server.tool(
+ "add",
+ "Add two numbers the way only MCP can",
+ { a: z.number(), b: z.number() },
+ async ({ a, b }) => ({
+ content: [{ type: "text", text: String(a + b) }],
+ }),
+ );
+
+ // Gets the currently signed in user's info on your Clerk app.
+ this.server.tool("get_user", "Get the users info", {}, async () => {
+ const accessToken = this.props.accessToken;
+
+ const user = await fetch(`${this.env.CLERK_APP_URL}/oauth/userinfo`, {
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ },
+ }).then((r) => r.json());
+
+ return {
+ content: [{ type: "text", text: JSON.stringify(user) }],
+ };
+ });
+ }
+}
+
+export default new OAuthProvider({
+ apiRoute: "/sse",
+ // @ts-ignore
+ // ref: https://github.com/cloudflare/workers-oauth-provider/issues/17
+ apiHandler: MyMCP.mount("/sse"),
+ // @ts-ignore
+ // ref: https://github.com/cloudflare/workers-oauth-provider/issues/17
+ defaultHandler: ClerkHandler,
+ authorizeEndpoint: "/authorize",
+ tokenEndpoint: "/token",
+ clientRegistrationEndpoint: "/register",
+});
diff --git a/demos/mcp-clerk-oauth/src/types.ts b/demos/mcp-clerk-oauth/src/types.ts
new file mode 100644
index 00000000..9ad087ad
--- /dev/null
+++ b/demos/mcp-clerk-oauth/src/types.ts
@@ -0,0 +1,5 @@
+// Context from the auth process, encrypted & stored in the auth token
+// and provided to the McpAgent as this.props
+export type Props = {
+ accessToken: string;
+};
diff --git a/demos/mcp-clerk-oauth/src/utils.ts b/demos/mcp-clerk-oauth/src/utils.ts
new file mode 100644
index 00000000..b1fbf162
--- /dev/null
+++ b/demos/mcp-clerk-oauth/src/utils.ts
@@ -0,0 +1,93 @@
+/**
+ * Constructs an authorization URL for an upstream service.
+ *
+ * @param {Object} options
+ * @param {string} options.upstream_url - The base URL of the upstream service.
+ * @param {string} options.client_id - The client ID of the application.
+ * @param {string} options.redirect_uri - The redirect URI of the application.
+ * @param {string} [options.state] - The state parameter.
+ *
+ * @returns {string} The authorization URL.
+ */
+export function getUpstreamAuthorizeUrl({
+ upstream_url,
+ client_id,
+ scopes,
+ redirect_uri,
+ state,
+}: {
+ upstream_url: string;
+ client_id: string;
+ scopes: string;
+ redirect_uri: string;
+ state?: string;
+}) {
+ const upstream = new URL(upstream_url);
+ upstream.searchParams.set("client_id", client_id);
+ upstream.searchParams.set("redirect_uri", redirect_uri);
+ upstream.searchParams.set("scopes", scopes);
+ if (state) upstream.searchParams.set("state", state);
+ upstream.searchParams.set("response_type", "code");
+ return upstream.href;
+}
+
+/**
+ * Fetches an authorization token from an upstream service.
+ *
+ * @param {Object} options
+ * @param {string} options.client_id - The client ID of the application.
+ * @param {string} options.client_secret - The client secret of the application.
+ * @param {string} options.code - The authorization code.
+ * @param {string} options.redirect_uri - The redirect URI of the application.
+ * @param {string} options.upstream_url - The token endpoint URL of the upstream service.
+ *
+ * @returns {Promise<[string, null] | [null, Response]>} A promise that resolves to an array containing the access token or an error response.
+ */
+export async function fetchUpstreamAuthToken({
+ client_id,
+ client_secret,
+ code,
+ redirect_uri,
+ upstream_url,
+ grant_type = "authorization_code",
+}: {
+ code: string | undefined;
+ upstream_url: string;
+ client_secret: string;
+ redirect_uri: string;
+ client_id: string;
+ grant_type?: string;
+}): Promise<[string, null] | [null, Response]> {
+ if (!code) {
+ return [null, new Response("Missing code", { status: 400 })];
+ }
+
+ const resp = await fetch(upstream_url, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/x-www-form-urlencoded",
+ },
+ body: new URLSearchParams({
+ client_id,
+ client_secret,
+ code,
+ redirect_uri,
+ grant_type,
+ }).toString(),
+ });
+ if (!resp.ok) {
+ return [null, new Response("Failed to fetch access token", { status: 500 })];
+ }
+
+ const body = (await resp.json()) as {
+ access_token: string;
+ };
+
+ const accessToken = body?.access_token;
+
+ if (!accessToken) {
+ return [null, new Response("Missing access token", { status: 400 })];
+ }
+
+ return [accessToken, null];
+}
diff --git a/demos/mcp-clerk-oauth/tsconfig.json b/demos/mcp-clerk-oauth/tsconfig.json
new file mode 100644
index 00000000..ed0b1938
--- /dev/null
+++ b/demos/mcp-clerk-oauth/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "es2021",
+ "lib": ["es2021"],
+ "jsx": "react-jsx",
+ "module": "es2022",
+ "moduleResolution": "Bundler",
+ "resolveJsonModule": true,
+ "allowJs": true,
+ "checkJs": false,
+ "noEmit": true,
+ "isolatedModules": true,
+ "allowSyntheticDefaultImports": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "skipLibCheck": true
+ },
+ "include": ["worker-configuration.d.ts", "src/**/*.ts"]
+}
diff --git a/demos/mcp-clerk-oauth/worker-configuration.d.ts b/demos/mcp-clerk-oauth/worker-configuration.d.ts
new file mode 100644
index 00000000..150ce5e3
--- /dev/null
+++ b/demos/mcp-clerk-oauth/worker-configuration.d.ts
@@ -0,0 +1,5713 @@
+// Generated by Wrangler by running `wrangler types` (hash: 5d2fddb6a21263dc79cd18fa953b5128)
+// Runtime types generated with workerd@1.20250317.0 2025-03-10 nodejs_als
+declare namespace Cloudflare {
+ interface Env {
+ OAUTH_KV: KVNamespace;
+ CLERK_OAUTH_SCOPES: "email,profile";
+ CLERK_APP_CLIENT_ID: string;
+ CLERK_APP_CLIENT_SECRET: string;
+ CLERK_APP_URL: string;
+ MCP_OBJECT: DurableObjectNamespace;
+ AI: Ai;
+ }
+}
+interface Env extends Cloudflare.Env {}
+
+// Begin runtime types
+/*! *****************************************************************************
+Copyright (c) Cloudflare. All rights reserved.
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at http://www.apache.org/licenses/LICENSE-2.0
+THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+MERCHANTABLITY OR NON-INFRINGEMENT.
+See the Apache Version 2.0 License for specific language governing permissions
+and limitations under the License.
+***************************************************************************** */
+/* eslint-disable */
+// noinspection JSUnusedGlobalSymbols
+declare var onmessage: never;
+/**
+ * An abnormal event (called an exception) which occurs as a result of calling a method or accessing a property of a web API.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException)
+ */
+declare class DOMException extends Error {
+ constructor(message?: string, name?: string);
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/message) */
+ readonly message: string;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/name) */
+ readonly name: string;
+ /**
+ * @deprecated
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMException/code)
+ */
+ readonly code: number;
+ static readonly INDEX_SIZE_ERR: number;
+ static readonly DOMSTRING_SIZE_ERR: number;
+ static readonly HIERARCHY_REQUEST_ERR: number;
+ static readonly WRONG_DOCUMENT_ERR: number;
+ static readonly INVALID_CHARACTER_ERR: number;
+ static readonly NO_DATA_ALLOWED_ERR: number;
+ static readonly NO_MODIFICATION_ALLOWED_ERR: number;
+ static readonly NOT_FOUND_ERR: number;
+ static readonly NOT_SUPPORTED_ERR: number;
+ static readonly INUSE_ATTRIBUTE_ERR: number;
+ static readonly INVALID_STATE_ERR: number;
+ static readonly SYNTAX_ERR: number;
+ static readonly INVALID_MODIFICATION_ERR: number;
+ static readonly NAMESPACE_ERR: number;
+ static readonly INVALID_ACCESS_ERR: number;
+ static readonly VALIDATION_ERR: number;
+ static readonly TYPE_MISMATCH_ERR: number;
+ static readonly SECURITY_ERR: number;
+ static readonly NETWORK_ERR: number;
+ static readonly ABORT_ERR: number;
+ static readonly URL_MISMATCH_ERR: number;
+ static readonly QUOTA_EXCEEDED_ERR: number;
+ static readonly TIMEOUT_ERR: number;
+ static readonly INVALID_NODE_TYPE_ERR: number;
+ static readonly DATA_CLONE_ERR: number;
+ get stack(): any;
+ set stack(value: any);
+}
+type WorkerGlobalScopeEventMap = {
+ fetch: FetchEvent;
+ scheduled: ScheduledEvent;
+ queue: QueueEvent;
+ unhandledrejection: PromiseRejectionEvent;
+ rejectionhandled: PromiseRejectionEvent;
+};
+declare abstract class WorkerGlobalScope extends EventTarget {
+ EventTarget: typeof EventTarget;
+}
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console) */
+interface Console {
+ "assert"(condition?: boolean, ...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/clear_static) */
+ clear(): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/count_static) */
+ count(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/countreset_static) */
+ countReset(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/debug_static) */
+ debug(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dir_static) */
+ dir(item?: any, options?: any): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/dirxml_static) */
+ dirxml(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static) */
+ error(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/group_static) */
+ group(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupcollapsed_static) */
+ groupCollapsed(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/groupend_static) */
+ groupEnd(): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/info_static) */
+ info(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static) */
+ log(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/table_static) */
+ table(tabularData?: any, properties?: string[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/time_static) */
+ time(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timeend_static) */
+ timeEnd(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/timelog_static) */
+ timeLog(label?: string, ...data: any[]): void;
+ timeStamp(label?: string): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/trace_static) */
+ trace(...data: any[]): void;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static) */
+ warn(...data: any[]): void;
+}
+declare const console: Console;
+type BufferSource = ArrayBufferView | ArrayBuffer;
+type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
+declare namespace WebAssembly {
+ class CompileError extends Error {
+ constructor(message?: string);
+ }
+ class RuntimeError extends Error {
+ constructor(message?: string);
+ }
+ type ValueType = "anyfunc" | "externref" | "f32" | "f64" | "i32" | "i64" | "v128";
+ interface GlobalDescriptor {
+ value: ValueType;
+ mutable?: boolean;
+ }
+ class Global {
+ constructor(descriptor: GlobalDescriptor, value?: any);
+ value: any;
+ valueOf(): any;
+ }
+ type ImportValue = ExportValue | number;
+ type ModuleImports = Record;
+ type Imports = Record;
+ type ExportValue = Function | Global | Memory | Table;
+ type Exports = Record;
+ class Instance {
+ constructor(module: Module, imports?: Imports);
+ readonly exports: Exports;
+ }
+ interface MemoryDescriptor {
+ initial: number;
+ maximum?: number;
+ shared?: boolean;
+ }
+ class Memory {
+ constructor(descriptor: MemoryDescriptor);
+ readonly buffer: ArrayBuffer;
+ grow(delta: number): number;
+ }
+ type ImportExportKind = "function" | "global" | "memory" | "table";
+ interface ModuleExportDescriptor {
+ kind: ImportExportKind;
+ name: string;
+ }
+ interface ModuleImportDescriptor {
+ kind: ImportExportKind;
+ module: string;
+ name: string;
+ }
+ abstract class Module {
+ static customSections(module: Module, sectionName: string): ArrayBuffer[];
+ static exports(module: Module): ModuleExportDescriptor[];
+ static imports(module: Module): ModuleImportDescriptor[];
+ }
+ type TableKind = "anyfunc" | "externref";
+ interface TableDescriptor {
+ element: TableKind;
+ initial: number;
+ maximum?: number;
+ }
+ class Table {
+ constructor(descriptor: TableDescriptor, value?: any);
+ readonly length: number;
+ get(index: number): any;
+ grow(delta: number, value?: any): number;
+ set(index: number, value?: any): void;
+ }
+ function instantiate(module: Module, imports?: Imports): Promise;
+ function validate(bytes: BufferSource): boolean;
+}
+/**
+ * This ServiceWorker API interface represents the global execution context of a service worker.
+ * Available only in secure contexts.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/ServiceWorkerGlobalScope)
+ */
+interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
+ DOMException: typeof DOMException;
+ WorkerGlobalScope: typeof WorkerGlobalScope;
+ btoa(data: string): string;
+ atob(data: string): string;
+ setTimeout(callback: (...args: any[]) => void, msDelay?: number): number;
+ setTimeout(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number;
+ clearTimeout(timeoutId: number | null): void;
+ setInterval(callback: (...args: any[]) => void, msDelay?: number): number;
+ setInterval(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number;
+ clearInterval(timeoutId: number | null): void;
+ queueMicrotask(task: Function): void;
+ structuredClone(value: T, options?: StructuredSerializeOptions): T;
+ reportError(error: any): void;
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise;
+ self: ServiceWorkerGlobalScope;
+ crypto: Crypto;
+ caches: CacheStorage;
+ scheduler: Scheduler;
+ performance: Performance;
+ Cloudflare: Cloudflare;
+ readonly origin: string;
+ Event: typeof Event;
+ ExtendableEvent: typeof ExtendableEvent;
+ CustomEvent: typeof CustomEvent;
+ PromiseRejectionEvent: typeof PromiseRejectionEvent;
+ FetchEvent: typeof FetchEvent;
+ TailEvent: typeof TailEvent;
+ TraceEvent: typeof TailEvent;
+ ScheduledEvent: typeof ScheduledEvent;
+ MessageEvent: typeof MessageEvent;
+ CloseEvent: typeof CloseEvent;
+ ReadableStreamDefaultReader: typeof ReadableStreamDefaultReader;
+ ReadableStreamBYOBReader: typeof ReadableStreamBYOBReader;
+ ReadableStream: typeof ReadableStream;
+ WritableStream: typeof WritableStream;
+ WritableStreamDefaultWriter: typeof WritableStreamDefaultWriter;
+ TransformStream: typeof TransformStream;
+ ByteLengthQueuingStrategy: typeof ByteLengthQueuingStrategy;
+ CountQueuingStrategy: typeof CountQueuingStrategy;
+ ErrorEvent: typeof ErrorEvent;
+ EventSource: typeof EventSource;
+ ReadableStreamBYOBRequest: typeof ReadableStreamBYOBRequest;
+ ReadableStreamDefaultController: typeof ReadableStreamDefaultController;
+ ReadableByteStreamController: typeof ReadableByteStreamController;
+ WritableStreamDefaultController: typeof WritableStreamDefaultController;
+ TransformStreamDefaultController: typeof TransformStreamDefaultController;
+ CompressionStream: typeof CompressionStream;
+ DecompressionStream: typeof DecompressionStream;
+ TextEncoderStream: typeof TextEncoderStream;
+ TextDecoderStream: typeof TextDecoderStream;
+ Headers: typeof Headers;
+ Body: typeof Body;
+ Request: typeof Request;
+ Response: typeof Response;
+ WebSocket: typeof WebSocket;
+ WebSocketPair: typeof WebSocketPair;
+ WebSocketRequestResponsePair: typeof WebSocketRequestResponsePair;
+ AbortController: typeof AbortController;
+ AbortSignal: typeof AbortSignal;
+ TextDecoder: typeof TextDecoder;
+ TextEncoder: typeof TextEncoder;
+ navigator: Navigator;
+ Navigator: typeof Navigator;
+ URL: typeof URL;
+ URLSearchParams: typeof URLSearchParams;
+ URLPattern: typeof URLPattern;
+ Blob: typeof Blob;
+ File: typeof File;
+ FormData: typeof FormData;
+ Crypto: typeof Crypto;
+ SubtleCrypto: typeof SubtleCrypto;
+ CryptoKey: typeof CryptoKey;
+ CacheStorage: typeof CacheStorage;
+ Cache: typeof Cache;
+ FixedLengthStream: typeof FixedLengthStream;
+ IdentityTransformStream: typeof IdentityTransformStream;
+ HTMLRewriter: typeof HTMLRewriter;
+ GPUAdapter: typeof GPUAdapter;
+ GPUOutOfMemoryError: typeof GPUOutOfMemoryError;
+ GPUValidationError: typeof GPUValidationError;
+ GPUInternalError: typeof GPUInternalError;
+ GPUDeviceLostInfo: typeof GPUDeviceLostInfo;
+ GPUBufferUsage: typeof GPUBufferUsage;
+ GPUShaderStage: typeof GPUShaderStage;
+ GPUMapMode: typeof GPUMapMode;
+ GPUTextureUsage: typeof GPUTextureUsage;
+ GPUColorWrite: typeof GPUColorWrite;
+}
+declare function addEventListener(type: Type, handler: EventListenerOrEventListenerObject, options?: EventTargetAddEventListenerOptions | boolean): void;
+declare function removeEventListener(type: Type, handler: EventListenerOrEventListenerObject, options?: EventTargetEventListenerOptions | boolean): void;
+/**
+ * Dispatches a synthetic event event to target and returns true if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
+ *
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/EventTarget/dispatchEvent)
+ */
+declare function dispatchEvent(event: WorkerGlobalScopeEventMap[keyof WorkerGlobalScopeEventMap]): boolean;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/btoa) */
+declare function btoa(data: string): string;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/atob) */
+declare function atob(data: string): string;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/setTimeout) */
+declare function setTimeout(callback: (...args: any[]) => void, msDelay?: number): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/setTimeout) */
+declare function setTimeout(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/clearTimeout) */
+declare function clearTimeout(timeoutId: number | null): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/setInterval) */
+declare function setInterval(callback: (...args: any[]) => void, msDelay?: number): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/setInterval) */
+declare function setInterval(callback: (...args: Args) => void, msDelay?: number, ...args: Args): number;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/clearInterval) */
+declare function clearInterval(timeoutId: number | null): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/queueMicrotask) */
+declare function queueMicrotask(task: Function): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/structuredClone) */
+declare function structuredClone(value: T, options?: StructuredSerializeOptions): T;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/reportError) */
+declare function reportError(error: any): void;
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/fetch) */
+declare function fetch(input: RequestInfo | URL, init?: RequestInit): Promise;
+declare const self: ServiceWorkerGlobalScope;
+/**
+* The Web Crypto API provides a set of low-level functions for common cryptographic tasks.
+* The Workers runtime implements the full surface of this API, but with some differences in
+* the [supported algorithms](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#supported-algorithms)
+* compared to those implemented in most browsers.
+*
+* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/)
+*/
+declare const crypto: Crypto;
+/**
+* The Cache API allows fine grained control of reading and writing from the Cloudflare global network cache.
+*
+* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/cache/)
+*/
+declare const caches: CacheStorage;
+declare const scheduler: Scheduler;
+/**
+* The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
+* as well as timing of subrequests and other operations.
+*
+* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/)
+*/
+declare const performance: Performance;
+declare const Cloudflare: Cloudflare;
+declare const origin: string;
+declare const navigator: Navigator;
+interface TestController {
+}
+interface ExecutionContext {
+ waitUntil(promise: Promise): void;
+ passThroughOnException(): void;
+ props: any;
+}
+type ExportedHandlerFetchHandler = (request: Request>, env: Env, ctx: ExecutionContext) => Response | Promise;
+type ExportedHandlerTailHandler = (events: TraceItem[], env: Env, ctx: ExecutionContext) => void | Promise;
+type ExportedHandlerTraceHandler = (traces: TraceItem[], env: Env, ctx: ExecutionContext) => void | Promise;
+type ExportedHandlerTailStreamHandler = (event: TailStream.TailEvent, env: Env, ctx: ExecutionContext) => TailStream.TailEventHandlerType | Promise;
+type ExportedHandlerScheduledHandler = (controller: ScheduledController, env: Env, ctx: ExecutionContext) => void | Promise;
+type ExportedHandlerQueueHandler = (batch: MessageBatch, env: Env, ctx: ExecutionContext) => void | Promise;
+type ExportedHandlerTestHandler = (controller: TestController, env: Env, ctx: ExecutionContext) => void | Promise;
+interface ExportedHandler {
+ fetch?: ExportedHandlerFetchHandler;
+ tail?: ExportedHandlerTailHandler;
+ trace?: ExportedHandlerTraceHandler;
+ tailStream?: ExportedHandlerTailStreamHandler;
+ scheduled?: ExportedHandlerScheduledHandler;
+ test?: ExportedHandlerTestHandler;
+ email?: EmailExportedHandler;
+ queue?: ExportedHandlerQueueHandler;
+}
+interface StructuredSerializeOptions {
+ transfer?: any[];
+}
+/* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent) */
+declare abstract class PromiseRejectionEvent extends Event {
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/promise) */
+ readonly promise: Promise;
+ /* [MDN Reference](https://developer.mozilla.org/docs/Web/API/PromiseRejectionEvent/reason) */
+ readonly reason: any;
+}
+declare abstract class Navigator {
+ sendBeacon(url: string, body?: (ReadableStream | string | (ArrayBuffer | ArrayBufferView) | Blob | FormData | URLSearchParams | URLSearchParams)): boolean;
+ readonly userAgent: string;
+ readonly gpu?: GPU;
+}
+/**
+* The Workers runtime supports a subset of the Performance API, used to measure timing and performance,
+* as well as timing of subrequests and other operations.
+*
+* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/)
+*/
+interface Performance {
+ /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancetimeorigin) */
+ readonly timeOrigin: number;
+ /* [Cloudflare Docs Reference](https://developers.cloudflare.com/workers/runtime-apis/performance/#performancenow) */
+ now(): number;
+}
+interface AlarmInvocationInfo {
+ readonly isRetry: boolean;
+ readonly retryCount: number;
+}
+interface Cloudflare {
+ readonly compatibilityFlags: Record;
+}
+interface DurableObject {
+ fetch(request: Request): Response | Promise;
+ alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise;
+ webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise;
+ webSocketClose?(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise;
+ webSocketError?(ws: WebSocket, error: unknown): void | Promise;
+}
+type DurableObjectStub = Fetcher & {
+ readonly id: DurableObjectId;
+ readonly name?: string;
+};
+interface DurableObjectId {
+ toString(): string;
+ equals(other: DurableObjectId): boolean;
+ readonly name?: string;
+}
+interface DurableObjectNamespace {
+ newUniqueId(options?: DurableObjectNamespaceNewUniqueIdOptions): DurableObjectId;
+ idFromName(name: string): DurableObjectId;
+ idFromString(id: string): DurableObjectId;
+ get(id: DurableObjectId, options?: DurableObjectNamespaceGetDurableObjectOptions): DurableObjectStub;
+ jurisdiction(jurisdiction: DurableObjectJurisdiction): DurableObjectNamespace;
+}
+type DurableObjectJurisdiction = "eu" | "fedramp";
+interface DurableObjectNamespaceNewUniqueIdOptions {
+ jurisdiction?: DurableObjectJurisdiction;
+}
+type DurableObjectLocationHint = "wnam" | "enam" | "sam" | "weur" | "eeur" | "apac" | "oc" | "afr" | "me";
+interface DurableObjectNamespaceGetDurableObjectOptions {
+ locationHint?: DurableObjectLocationHint;
+}
+interface DurableObjectState {
+ waitUntil(promise: Promise): void;
+ readonly id: DurableObjectId;
+ readonly storage: DurableObjectStorage;
+ container?: Container;
+ blockConcurrencyWhile(callback: () => Promise): Promise;
+ acceptWebSocket(ws: WebSocket, tags?: string[]): void;
+ getWebSockets(tag?: string): WebSocket[];
+ setWebSocketAutoResponse(maybeReqResp?: WebSocketRequestResponsePair): void;
+ getWebSocketAutoResponse(): WebSocketRequestResponsePair | null;
+ getWebSocketAutoResponseTimestamp(ws: WebSocket): Date | null;
+ setHibernatableWebSocketEventTimeout(timeoutMs?: number): void;
+ getHibernatableWebSocketEventTimeout(): number | null;
+ getTags(ws: WebSocket): string[];
+ abort(reason?: string): void;
+}
+interface DurableObjectTransaction {
+ get(key: string, options?: DurableObjectGetOptions): Promise;
+ get(keys: string[], options?: DurableObjectGetOptions): Promise