cloudflare / workers-sdk

⛅️ Home to Wrangler, the CLI for Cloudflare Workers®
https://developers.cloudflare.com/workers/
Apache License 2.0
2.43k stars 602 forks source link

🐛 BUG: WebSocket typing doesn't work in apps that also pull in DOM types #5665

Open zwily opened 2 months ago

zwily commented 2 months ago

Which Cloudflare product(s) does this pertain to?

Workers Runtime

What version(s) of the tool(s) are you using?

3.51.0 [Wrangler]

What version of Node are you using?

No response

What operating system and version are you using?

Mac Sonoma

Describe the Bug

Observed behavior

I am in a Remix app on Cloudflare Pages, and adding a websocket endpoint. Things work fine, except for typescript typing. When I create a socket pair (in a loader, which runs in the worker), I get 2 WebSocket objects that are typed according to DOM WebSockets, not the Cloudflare flavor:

  const webSocketPair = new WebSocketPair();
  const [client, server] = Object.values(webSocketPair);

  // can't figure out how to get this typed as a cloudflare-style websocket?
  // @ts-ignore
  server.accept();

I believe this is happening because since this is a Remix app, the tsconfig.json specifies "DOM" in the lib list, and that WebSocket definition is overriding the one specified by workers-types.

Expected behavior

I'm not sure what the right thing to do here is. Maybe since Cloudflare WebSockets aren't 100% compatible with a DOM WebSocket, they should use a different name, like CloudflareWebSocket?

Steps to reproduce

export async function loader({ request, context }: LoaderFunctionArgs) {
  const upgradeHeader = request.headers.get("Upgrade");
  if (!upgradeHeader || upgradeHeader.toLowerCase() !== "websocket") {
    return new Response("Expected WebSocket request", { status: 400 });
  }

  const webSocketPair = new WebSocketPair();
  const [client, server] = Object.values(webSocketPair);

  // can't figure out how to get this typed as a cloudflare-style websocket?
  server.accept();
  server.addEventListener("message", (event) => {
    console.log("**", event.data);
  });

  return new Response(null, {
    status: 101,
    webSocket: client,
  });
}

See that the server.accept() line has an error saying accept isn't found on WebSocket, because it thinks server is a DOM WebSocket, not the WebSocket defined in @cloudflare/workers-types.

Relevant issue, before workers-types had WebSocket typing at all: https://github.com/cloudflare/workers-types/issues/84

Please provide a link to a minimal reproduction

No response

Please provide any relevant error logs

No response

threepointone commented 3 weeks ago

This is a hard one to fix in "isomorphic apps". I don't think there's a clean solution here, we can't rename our WebSocket to something else. You'd face this problem even with other runtimes as well. We'll have to think this one through...