| declare const _default: typeof globalThis.WebSocket; | ||
| export { _default as default }; |
| const _WebSocket = globalThis.WebSocket; | ||
| var BunWebSocket = class extends _WebSocket { | ||
| constructor(url, protocols, options) { | ||
| if (!options) { | ||
| super(url, protocols); | ||
| return; | ||
| } | ||
| const opts = { ...options }; | ||
| if (protocols !== void 0) opts.protocols = protocols; | ||
| super(url, opts); | ||
| } | ||
| }; | ||
| export { BunWebSocket as default }; |
| declare const _default: typeof globalThis.WebSocket; | ||
| export { _default as default }; |
| const _WebSocket = globalThis.WebSocket; | ||
| var DenoWebSocket = class extends _WebSocket { | ||
| constructor(url, protocols, options) { | ||
| const href = typeof url === "string" ? url : url.href; | ||
| const isUnix = href.startsWith("ws+unix:"); | ||
| if (!isUnix && !options) { | ||
| super(url, protocols); | ||
| return; | ||
| } | ||
| const opts = { ...options }; | ||
| if (protocols !== void 0) opts.protocols = protocols; | ||
| if (isUnix) { | ||
| const { socketPath, path } = _parseUnixTarget(href); | ||
| opts.client ??= Deno.createHttpClient({ proxy: { | ||
| transport: "unix", | ||
| path: socketPath | ||
| } }); | ||
| super(`ws://localhost${path}`, opts); | ||
| return; | ||
| } | ||
| super(url, opts); | ||
| } | ||
| }; | ||
| function _parseUnixTarget(href) { | ||
| const { pathname, search } = new URL(href); | ||
| const raw = pathname + search; | ||
| const colon = raw.indexOf(":"); | ||
| if (colon === -1) return { | ||
| socketPath: raw, | ||
| path: "/" | ||
| }; | ||
| return { | ||
| socketPath: raw.slice(0, colon), | ||
| path: raw.slice(colon + 1) || "/" | ||
| }; | ||
| } | ||
| export { DenoWebSocket as default }; |
+38
-0
@@ -7,2 +7,7 @@ import { Adapter, AdapterInstance, AdapterInternal, AdapterOptions, Hooks, Message, Peer, PeerContext, ResolveHooks, SyncAdapter, SyncDriver, SyncErrorContext, SyncMessage, WSError, WaitForDrainOptions, defineHooks, defineWebSocketAdapter } from "./_chunks/adapter.mjs"; | ||
| * | ||
| * A `ws+unix://<socketPath>:<pathname>` target is also supported out of the | ||
| * box for proxying to a Unix-socket upstream on Node, Bun, and Deno (no custom | ||
| * {@link WebSocket} constructor required) — crossws dials it through the | ||
| * matching per-runtime `crossws/websocket` client. See the guide for details. | ||
| * | ||
| * Can be a static string/URL or a function that resolves the target dynamically | ||
@@ -93,2 +98,35 @@ * based on the incoming {@link Peer}. The resolver may be **async** (return a | ||
| headers?: HeadersInit | ((peer: Peer) => HeadersInit | undefined | void); | ||
| /** | ||
| * Extra options merged into the upstream `WebSocket` constructor's third | ||
| * argument, as a static object or a per-peer resolver. | ||
| * | ||
| * This is the escape hatch for runtime- or client-specific dialing options | ||
| * that the WHATWG `WebSocket` signature doesn't cover — e.g. Deno's unstable | ||
| * `client` (to dial a Unix socket or use a custom `Deno.HttpClient`), or the | ||
| * `ws`/`undici` `createConnection`/`dispatcher`/`agent` options. | ||
| * | ||
| * Merged with {@link headers}: keys returned here are spread first, then the | ||
| * resolved `headers` option is applied on top (so a dedicated `headers` | ||
| * option wins over a `headers` key returned here). | ||
| * | ||
| * > [!NOTE] | ||
| * > Only honored by `WebSocket` constructors that accept a third options | ||
| * > argument. The WHATWG global browser constructor ignores it; Deno and Bun | ||
| * > extend the signature with their own options. | ||
| * | ||
| * @example Proxy to a Unix socket on Deno | ||
| * ```ts | ||
| * createWebSocketProxy({ | ||
| * // Deno's WebSocket rejects the `ws+unix:` scheme, so keep a plain | ||
| * // `ws://` target and redirect the transport via the `client` option. | ||
| * target: (peer) => `ws://localhost${new URL(peer.request.url).pathname}`, | ||
| * webSocketOptions: () => ({ | ||
| * client: Deno.createHttpClient({ | ||
| * proxy: { transport: "unix", path: "/run/worker.sock" }, | ||
| * }), | ||
| * }), | ||
| * }); | ||
| * ``` | ||
| */ | ||
| webSocketOptions?: Record<string, unknown> | ((peer: Peer) => Record<string, unknown> | undefined | void); | ||
| } | ||
@@ -95,0 +133,0 @@ /** |
+11
-7
| import { defineHooks, defineWebSocketAdapter } from "./_chunks/adapter.mjs"; | ||
| import runtimeWebSocket from "crossws/websocket"; | ||
| const DEFAULT_MAX_BUFFER_SIZE = 1024 * 1024; | ||
@@ -7,3 +8,3 @@ const DEFAULT_CONNECT_TIMEOUT = 1e4; | ||
| const options = typeof target === "string" || target instanceof URL || typeof target === "function" ? { target } : target; | ||
| const WebSocketCtor = options.WebSocket ?? globalThis.WebSocket; | ||
| const WebSocketCtor = options.WebSocket ?? runtimeWebSocket; | ||
| if (typeof WebSocketCtor !== "function") throw new TypeError("createWebSocketProxy requires a `WebSocket` constructor. Pass one via the `WebSocket` option, or use a runtime that provides a global `WebSocket` (Node.js >= 22, Bun, Deno, Cloudflare Workers, browsers)."); | ||
@@ -94,3 +95,3 @@ const upstreams = /* @__PURE__ */ new Map(); | ||
| const protocols = _resolveProtocols(peer, options.forwardProtocol); | ||
| const wsOptions = _resolveWsOptions(options.headers, peer); | ||
| const wsOptions = _resolveWsOptions(options, peer); | ||
| ws = wsOptions ? new WebSocketCtor(url, protocols, wsOptions) : new WebSocketCtor(url, protocols); | ||
@@ -151,7 +152,10 @@ ws.binaryType = "arraybuffer"; | ||
| } | ||
| function _resolveWsOptions(headers, peer) { | ||
| if (!headers) return; | ||
| const resolved = typeof headers === "function" ? headers(peer) : headers; | ||
| if (!resolved) return; | ||
| return { headers: resolved }; | ||
| function _resolveWsOptions(options, peer) { | ||
| const { headers, webSocketOptions } = options; | ||
| const extra = typeof webSocketOptions === "function" ? webSocketOptions(peer) : webSocketOptions; | ||
| const resolvedHeaders = typeof headers === "function" ? headers(peer) : headers; | ||
| if (!extra && !resolvedHeaders) return; | ||
| const merged = { ...extra }; | ||
| if (resolvedHeaders) merged.headers = resolvedHeaders; | ||
| return merged; | ||
| } | ||
@@ -158,0 +162,0 @@ function _resolveProtocols(peer, forwardProtocol) { |
@@ -1,2 +0,2 @@ | ||
| declare const Websocket: typeof globalThis.WebSocket; | ||
| export { Websocket as default }; | ||
| declare const NodeWebSocket: typeof globalThis.WebSocket; | ||
| export { NodeWebSocket as default }; |
| import { import_websocket } from "../_chunks/libs/ws.mjs"; | ||
| const Websocket = globalThis.WebSocket || import_websocket.default; | ||
| export { Websocket as default }; | ||
| const _global = globalThis.WebSocket; | ||
| const NodeWebSocket = _global ? new Proxy(_global, { construct(target, args) { | ||
| const url = args[0]; | ||
| const Ctor = (typeof url === "string" ? url : url?.href ?? "").startsWith("ws+unix:") || args[2] != null ? import_websocket.default : target; | ||
| return Reflect.construct(Ctor, args); | ||
| } }) : import_websocket.default; | ||
| export { NodeWebSocket as default }; |
+28
-27
| { | ||
| "name": "crossws", | ||
| "version": "0.4.7", | ||
| "version": "0.4.8", | ||
| "description": "Cross-platform WebSocket Servers for Node.js, Deno, Bun and Cloudflare Workers", | ||
| "homepage": "https://crossws.h3.dev", | ||
| "repository": "h3js/crossws", | ||
| "license": "MIT", | ||
| "repository": "h3js/crossws", | ||
| "files": [ | ||
| "dist", | ||
| "adapters", | ||
| "websocket", | ||
| "server", | ||
| "*.d.ts" | ||
| ], | ||
| "sideEffects": false, | ||
| "type": "module", | ||
| "sideEffects": false, | ||
| "main": "./dist/index.mjs", | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.mts", | ||
| "exports": { | ||
@@ -46,4 +36,4 @@ ".": "./dist/index.mjs", | ||
| "worker": "./dist/websocket/native.mjs", | ||
| "bun": "./dist/websocket/native.mjs", | ||
| "deno": "./dist/websocket/native.mjs", | ||
| "bun": "./dist/websocket/bun.mjs", | ||
| "deno": "./dist/websocket/deno.mjs", | ||
| "edge-light": "./dist/websocket/native.mjs", | ||
@@ -55,7 +45,18 @@ "workerd": "./dist/websocket/native.mjs", | ||
| }, | ||
| "main": "./dist/index.mjs", | ||
| "module": "./dist/index.mjs", | ||
| "types": "./dist/index.d.mts", | ||
| "files": [ | ||
| "dist", | ||
| "adapters", | ||
| "websocket", | ||
| "server", | ||
| "*.d.ts" | ||
| ], | ||
| "scripts": { | ||
| "prepare": "obuild --stub", | ||
| "build": "obuild", | ||
| "dev": "vitest", | ||
| "fmt": "oxlint . --fix && oxfmt src test", | ||
| "lint": "oxlint . && oxfmt --check src test", | ||
| "fmt": "oxlint . --fix && oxfmt src test", | ||
| "prepack": "pnpm run build", | ||
@@ -73,10 +74,13 @@ "play:bun": "bun --watch test/fixture/bun.ts", | ||
| }, | ||
| "resolutions": { | ||
| "crossws": "workspace:*" | ||
| }, | ||
| "devDependencies": { | ||
| "@cloudflare/workers-types": "^4.20260629.1", | ||
| "@cloudflare/workers-types": "^4.20260701.1", | ||
| "@types/bun": "^1.3.14", | ||
| "@types/deno": "^2.7.0", | ||
| "@types/node": "^26.0.1", | ||
| "@types/web": "^0.0.351", | ||
| "@types/node": "^26.1.0", | ||
| "@types/web": "^0.0.352", | ||
| "@types/ws": "^8.18.1", | ||
| "@typescript/native-preview": "7.0.0-dev.20260629.1", | ||
| "@typescript/native-preview": "^7.0.0-dev.20260701.1", | ||
| "@vitest/coverage-v8": "^4.1.9", | ||
@@ -94,5 +98,5 @@ "automd": "^0.4.3", | ||
| "obuild": "^0.4.37", | ||
| "oxfmt": "^0.56.0", | ||
| "oxlint": "^1.71.0", | ||
| "srvx": "^0.11.17", | ||
| "oxfmt": "^0.57.0", | ||
| "oxlint": "^1.72.0", | ||
| "srvx": "^0.11.18", | ||
| "typescript": "^6.0.3", | ||
@@ -103,3 +107,3 @@ "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.57.0", | ||
| "vitest": "^4.1.9", | ||
| "wrangler": "^4.105.0", | ||
| "wrangler": "^4.106.0", | ||
| "ws": "^8.21.0" | ||
@@ -115,6 +119,3 @@ }, | ||
| }, | ||
| "resolutions": { | ||
| "crossws": "workspace:*" | ||
| }, | ||
| "packageManager": "pnpm@11.7.0" | ||
| } |
234550
1.69%77
5.48%4562
1.31%