[{"data":1,"prerenderedAt":805},["ShallowReactive",2],{"navigation":3,"-guide-client":88,"-guide-client-surround":801},[4,51],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Guide","\u002Fguide","1.guide\u002F1.index",[9,11,16,21,26,31,36,41,46],{"title":5,"path":6,"stem":7,"icon":10},"ph:book-open-duotone",{"title":12,"path":13,"stem":14,"icon":15},"Hooks","\u002Fguide\u002Fhooks","1.guide\u002F2.hooks","material-symbols-light:data-object",{"title":17,"path":18,"stem":19,"icon":20},"Peer","\u002Fguide\u002Fpeer","1.guide\u002F3.peer","mynaui:api",{"title":22,"path":23,"stem":24,"icon":25},"Message","\u002Fguide\u002Fmessage","1.guide\u002F4.message","solar:letter-line-duotone",{"title":27,"path":28,"stem":29,"icon":30},"Pub \u002F Sub","\u002Fguide\u002Fpubsub","1.guide\u002F5.pubsub","simple-icons:googlepubsub",{"title":32,"path":33,"stem":34,"icon":35},"Sync Backplane","\u002Fguide\u002Fsync","1.guide\u002F6.sync","tabler:refresh",{"title":37,"path":38,"stem":39,"icon":40},"Resolver API","\u002Fguide\u002Fresolver","1.guide\u002F7.resolver","tabler:route",{"title":42,"path":43,"stem":44,"icon":45},"WebSocket Proxy","\u002Fguide\u002Fproxy","1.guide\u002F8.proxy","tabler:arrows-exchange",{"title":47,"path":48,"stem":49,"icon":50},"WebSocket Client","\u002Fguide\u002Fclient","1.guide\u002F9.client","tabler:plug-connected",{"title":52,"path":53,"stem":54,"children":55,"icon":57},"Adapters","\u002Fadapters","2.adapters\u002F1.index",[56,58,63,68,73,78,83],{"title":52,"path":53,"stem":54,"icon":57},"emojione-monotone:electric-plug",{"title":59,"path":60,"stem":61,"icon":62},"Bun","\u002Fadapters\u002Fbun","2.adapters\u002Fbun","simple-icons:bun",{"title":64,"path":65,"stem":66,"icon":67},"Bunny","\u002Fadapters\u002Fbunny","2.adapters\u002Fbunny","mdi:rabbit",{"title":69,"path":70,"stem":71,"icon":72},"Cloudflare","\u002Fadapters\u002Fcloudflare","2.adapters\u002Fcloudflare","devicon-plain:cloudflareworkers",{"title":74,"path":75,"stem":76,"icon":77},"Deno","\u002Fadapters\u002Fdeno","2.adapters\u002Fdeno","teenyicons:deno-solid",{"title":79,"path":80,"stem":81,"icon":82},"Node.js","\u002Fadapters\u002Fnode","2.adapters\u002Fnode","akar-icons:node-fill",{"title":84,"path":85,"stem":86,"icon":87},"SSE","\u002Fadapters\u002Fsse","2.adapters\u002Fsse","clarity:two-way-arrows-line",{"id":89,"title":47,"body":90,"description":795,"extension":796,"meta":797,"navigation":798,"path":48,"seo":799,"stem":49,"__hash__":800},"content\u002F1.guide\u002F9.client.md",{"type":91,"value":92,"toc":788,"icon":50},"minimark",[93,134,142,164,169,175,304,337,341,366,420,426,488,504,508,524,639,651,655,665,705,719,738,742,775,784],[94,95,96,97,101,102,106,107,110,111,114,115,118,119,122,123,126,127,129,130,133],"p",{},"Every runtime exposes a slightly different ",[98,99,100],"code",{},"WebSocket"," constructor for ",[103,104,105],"strong",{},"dialing"," a server: Bun and Deno take their dialing options as the constructor's second argument, the WHATWG\u002F",[98,108,109],{},"ws"," clients take a third, and only some accept the ",[98,112,113],{},"ws+unix:"," scheme or custom upgrade headers. crossws smooths this over with the ",[98,116,117],{},"crossws\u002Fwebsocket"," subpath — a thin per-runtime client that dials ",[98,120,121],{},"ws:",", ",[98,124,125],{},"wss:",", and ",[98,128,113],{}," upstreams through one uniform ",[98,131,132],{},"(url, protocols, options)"," signature.",[94,135,136,137,141],{},"This is the same client ",[138,139,140],"a",{"href":43},"the proxy"," uses under the hood. Reach for it directly when you need to dial an upstream WebSocket yourself — for example from a custom hook — and want custom headers or Unix-socket support to work the same way on every runtime.",[143,144,145],"note",{},[94,146,147,149,150,153,154,157,158,163],{},[98,148,117],{}," is a ",[103,151,152],{},"client"," (it dials out). To accept incoming connections, use an ",[138,155,156],{"href":53},"adapter"," or ",[138,159,160],{"href":6},[98,161,162],{},"crossws\u002Fserver",".",[165,166,168],"h2",{"id":167},"usage","Usage",[94,170,171,172,174],{},"Import the default export and construct it like a standard ",[98,173,100],{},":",[176,177,182],"pre",{"className":178,"code":179,"language":180,"meta":181,"style":181},"language-ts shiki shiki-themes github-light github-dark github-dark","import WebSocket from \"crossws\u002Fwebsocket\";\n\nconst ws = new WebSocket(\"wss:\u002F\u002Fecho.websocket.org\");\nws.onopen = () => ws.send(\"hello\");\nws.onmessage = (event) => console.log(event.data);\n","ts","",[98,183,184,207,214,243,273],{"__ignoreMap":181},[185,186,189,193,197,200,204],"span",{"class":187,"line":188},"line",1,[185,190,192],{"class":191},"so5gQ","import",[185,194,196],{"class":195},"slsVL"," WebSocket ",[185,198,199],{"class":191},"from",[185,201,203],{"class":202},"sfrk1"," \"crossws\u002Fwebsocket\"",[185,205,206],{"class":195},";\n",[185,208,210],{"class":187,"line":209},2,[185,211,213],{"emptyLinePlaceholder":212},true,"\n",[185,215,217,220,224,227,230,234,237,240],{"class":187,"line":216},3,[185,218,219],{"class":191},"const",[185,221,223],{"class":222},"suiK_"," ws",[185,225,226],{"class":191}," =",[185,228,229],{"class":191}," new",[185,231,233],{"class":232},"shcOC"," WebSocket",[185,235,236],{"class":195},"(",[185,238,239],{"class":202},"\"wss:\u002F\u002Fecho.websocket.org\"",[185,241,242],{"class":195},");\n",[185,244,246,249,252,254,257,260,263,266,268,271],{"class":187,"line":245},4,[185,247,248],{"class":195},"ws.",[185,250,251],{"class":232},"onopen",[185,253,226],{"class":191},[185,255,256],{"class":195}," () ",[185,258,259],{"class":191},"=>",[185,261,262],{"class":195}," ws.",[185,264,265],{"class":232},"send",[185,267,236],{"class":195},[185,269,270],{"class":202},"\"hello\"",[185,272,242],{"class":195},[185,274,276,278,281,283,286,290,293,295,298,301],{"class":187,"line":275},5,[185,277,248],{"class":195},[185,279,280],{"class":232},"onmessage",[185,282,226],{"class":191},[185,284,285],{"class":195}," (",[185,287,289],{"class":288},"sQHwn","event",[185,291,292],{"class":195},") ",[185,294,259],{"class":191},[185,296,297],{"class":195}," console.",[185,299,300],{"class":232},"log",[185,302,303],{"class":195},"(event.data);\n",[94,305,306,307,314,315,122,318,122,321,122,324,327,328,122,330,332,333,336],{},"The returned instance is a standard ",[138,308,312],{"href":309,"rel":310},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWebSocket",[311],"nofollow",[98,313,100],{}," — the same events (",[98,316,317],{},"open",[98,319,320],{},"message",[98,322,323],{},"close",[98,325,326],{},"error","), methods (",[98,329,265],{},[98,331,323],{},"), and static members (",[98,334,335],{},"WebSocket.OPEN",", …) you already know.",[165,338,340],{"id":339},"signature","Signature",[176,342,344],{"className":178,"code":343,"language":180,"meta":181,"style":181},"new WebSocket(url, protocols?, options?);\n",[98,345,346],{"__ignoreMap":181},[185,347,348,351,353,356,359,362,364],{"class":187,"line":188},[185,349,350],{"class":191},"new",[185,352,233],{"class":232},[185,354,355],{"class":195},"(url, protocols",[185,357,358],{"class":191},"?",[185,360,361],{"class":195},", options",[185,363,358],{"class":191},[185,365,242],{"class":195},[367,368,369,394,405],"ul",{},[370,371,372,377,378,381,382,122,384,386,387,393],"li",{},[103,373,374],{},[98,375,376],{},"url"," — ",[98,379,380],{},"string | URL",". The upstream to dial: ",[98,383,121],{},[98,385,125],{},", or a ",[138,388,390],{"href":389},"#unix-domain-sockets",[98,391,392],{},"ws+unix:\u002F\u002F\u003CsocketPath>:\u003Cpathname>"," target.",[370,395,396,377,401,404],{},[103,397,398],{},[98,399,400],{},"protocols",[98,402,403],{},"string | string[]"," (optional). Subprotocol(s) offered during the handshake, exactly as the WHATWG constructor.",[370,406,407,377,412,415,416,419],{},[103,408,409],{},[98,410,411],{},"options",[98,413,414],{},"Record\u003Cstring, unknown>"," (optional). Extra dialing options — most commonly custom upgrade ",[98,417,418],{},"headers",". crossws relays this into whichever argument position the current runtime expects.",[94,421,422,423,425],{},"The third ",[98,424,411],{}," argument is the value the WHATWG browser constructor can't express. crossws makes it behave the same everywhere:",[176,427,429],{"className":178,"code":428,"language":180,"meta":181,"style":181},"import WebSocket from \"crossws\u002Fwebsocket\";\n\nconst ws = new WebSocket(\"wss:\u002F\u002Fbackend.example.com\", undefined, {\n  headers: { authorization: \"Bearer …\" },\n});\n",[98,430,431,443,447,472,483],{"__ignoreMap":181},[185,432,433,435,437,439,441],{"class":187,"line":188},[185,434,192],{"class":191},[185,436,196],{"class":195},[185,438,199],{"class":191},[185,440,203],{"class":202},[185,442,206],{"class":195},[185,444,445],{"class":187,"line":209},[185,446,213],{"emptyLinePlaceholder":212},[185,448,449,451,453,455,457,459,461,464,466,469],{"class":187,"line":216},[185,450,219],{"class":191},[185,452,223],{"class":222},[185,454,226],{"class":191},[185,456,229],{"class":191},[185,458,233],{"class":232},[185,460,236],{"class":195},[185,462,463],{"class":202},"\"wss:\u002F\u002Fbackend.example.com\"",[185,465,122],{"class":195},[185,467,468],{"class":222},"undefined",[185,470,471],{"class":195},", {\n",[185,473,474,477,480],{"class":187,"line":245},[185,475,476],{"class":195},"  headers: { authorization: ",[185,478,479],{"class":202},"\"Bearer …\"",[185,481,482],{"class":195}," },\n",[185,484,485],{"class":187,"line":275},[185,486,487],{"class":195},"});\n",[489,490,491],"tip",{},[94,492,493,494,497,498,500,501,503],{},"\nWhen you call it with just ",[98,495,496],{},"(url, protocols)"," and no ",[98,499,411],{},", crossws keeps the runtime's native positional path — so option-less calls are identical to using the global ",[98,502,100],{}," directly.",[165,505,507],{"id":506},"per-runtime-behavior","Per-runtime behavior",[94,509,510,511,516,517,519,520,523],{},"crossws resolves a runtime-specific implementation through ",[138,512,515],{"href":513,"rel":514},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fpackages.html#conditional-exports",[311],"export conditions",", so a bundle built for one runtime tree-shakes away the others (e.g. ",[98,518,109],{}," and ",[98,521,522],{},"node:*"," never enter a Deno or browser bundle):",[525,526,527,540],"table",{},[528,529,530],"thead",{},[531,532,533,537],"tr",{},[534,535,536],"th",{},"Runtime",[534,538,539],{},"Implementation",[541,542,543,567,596,623],"tbody",{},[531,544,545,550],{},[546,547,548],"td",{},[103,549,59],{},[546,551,552,553,555,556,558,559,558,561,563,564,566],{},"Global ",[98,554,100],{}," — dials ",[98,557,121],{},"\u002F",[98,560,125],{},[98,562,113],{}," natively. crossws relays ",[98,565,411],{}," into Bun's second-argument form.",[531,568,569,573],{},[546,570,571],{},[103,572,79],{},[546,574,552,575,577,578,558,580,582,583,589,590,592,593,595],{},[98,576,100],{}," (undici) for the common ",[98,579,121],{},[98,581,125],{}," path; routes through ",[138,584,587],{"href":585,"rel":586},"https:\u002F\u002Fgithub.com\u002Fwebsockets\u002Fws",[311],[98,588,109],{}," (bundled, no extra dependency) whenever ",[98,591,411],{}," are passed or the target is ",[98,594,113],{}," — and everywhere on Node \u003C 22, which has no global.",[531,597,598,602],{},[546,599,600],{},[103,601,74],{},[546,603,552,604,606,607,609,610,612,613,620,621,163],{},[98,605,100],{},"; relays ",[98,608,411],{}," into Deno's second-argument form, and rewrites ",[98,611,113],{}," targets through ",[138,614,617],{"href":615,"rel":616},"https:\u002F\u002Fdocs.deno.com\u002Fapi\u002Fdeno\u002F~\u002FDeno.createHttpClient",[311],[98,618,619],{},"Deno.createHttpClient","'s unix ",[98,622,152],{},[531,624,625,630],{},[546,626,627],{},[103,628,629],{},"Browser \u002F Workers \u002F edge",[546,631,632,633,635,636,638],{},"The WHATWG global ",[98,634,100],{}," verbatim. It has no third-argument options, so custom ",[98,637,418],{}," are silently ignored.",[640,641,642],"important",{},[94,643,644,645,647,648,650],{},"\nCustom ",[98,646,418],{}," (and other ",[98,649,411],{},") are honored on Bun, Deno, and Node — not in browsers, Cloudflare Workers, or other edge runtimes, whose WHATWG constructor drops them. Don't rely on upstream identity via headers there.",[165,652,654],{"id":653},"unix-domain-sockets","Unix domain sockets",[94,656,657,658,660,661,664],{},"Dial an upstream listening on a Unix domain socket by passing a ",[98,659,392],{}," URL. This works ",[103,662,663],{},"out of the box"," on Node.js, Bun, and Deno:",[176,666,668],{"className":178,"code":667,"language":180,"meta":181,"style":181},"import WebSocket from \"crossws\u002Fwebsocket\";\n\nconst ws = new WebSocket(\"ws+unix:\u002F\u002F\u002Fvar\u002Frun\u002Fbackend.sock:\u002Fchat\");\n",[98,669,670,682,686],{"__ignoreMap":181},[185,671,672,674,676,678,680],{"class":187,"line":188},[185,673,192],{"class":191},[185,675,196],{"class":195},[185,677,199],{"class":191},[185,679,203],{"class":202},[185,681,206],{"class":195},[185,683,684],{"class":187,"line":209},[185,685,213],{"emptyLinePlaceholder":212},[185,687,688,690,692,694,696,698,700,703],{"class":187,"line":216},[185,689,219],{"class":191},[185,691,223],{"class":222},[185,693,226],{"class":191},[185,695,229],{"class":191},[185,697,233],{"class":232},[185,699,236],{"class":195},[185,701,702],{"class":202},"\"ws+unix:\u002F\u002F\u002Fvar\u002Frun\u002Fbackend.sock:\u002Fchat\"",[185,704,242],{"class":195},[94,706,707,708,710,711,714,715,718],{},"The path before the ",[98,709,174],{}," is the socket file (",[98,712,713],{},"\u002Fvar\u002Frun\u002Fbackend.sock","); the path after it is the request path forwarded to the upstream (",[98,716,717],{},"\u002Fchat",").",[143,720,721],{},[94,722,723,724,726,727,729,730,733,734,737],{},"\nOn ",[103,725,74],{},", the unix transport uses ",[98,728,619],{},", an ",[103,731,732],{},"unstable"," API — run Deno with the ",[98,735,736],{},"--unstable-net"," flag to enable it.",[165,739,741],{"id":740},"relationship-to-the-proxy","Relationship to the proxy",[94,743,744,749,750,122,755,126,761,767,768,774],{},[138,745,746],{"href":43},[98,747,748],{},"createWebSocketProxy()"," dials every upstream through this client, which is why its ",[138,751,753],{"href":752},"\u002Fguide\u002Fproxy#forwarding-headers",[98,754,418],{},[138,756,758],{"href":757},"\u002Fguide\u002Fproxy#per-peer-constructor-options",[98,759,760],{},"webSocketOptions",[138,762,764,766],{"href":763},"\u002Fguide\u002Fproxy#unix-domain-sockets",[98,765,113],{}," targets"," work uniformly across runtimes without a custom constructor. Passing an explicit ",[138,769,771,773],{"href":770},"\u002Fguide\u002Fproxy#custom-websocket-constructor",[98,772,100],{}," option"," to the proxy opts out of this per-runtime handling and dials with your constructor verbatim.",[776,777,778],"read-more",{"title":42,"to":43},[94,779,780,781,783],{},"See the ",[138,782,42],{"href":43}," guide for forwarding incoming connections to an upstream.",[785,786,787],"style",{},"html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":181,"searchDepth":209,"depth":209,"links":789},[790,791,792,793,794],{"id":167,"depth":209,"text":168},{"id":339,"depth":209,"text":340},{"id":506,"depth":209,"text":507},{"id":653,"depth":209,"text":654},{"id":740,"depth":209,"text":741},"A per-runtime WebSocket client for dialing upstream servers with one consistent signature.","md",{"icon":50},{"icon":50},{"title":47,"description":795},"3u1FTSKKMovRQJMcJutqvn5a46B-BC_tdK2F7IUVGDo",[802,804],{"title":42,"path":43,"stem":44,"description":803,"icon":45,"children":-1},"Forward incoming WebSocket connections to an upstream ws:\u002F\u002F or wss:\u002F\u002F target.",{"title":52,"path":53,"stem":54,"description":181,"icon":57,"children":-1},1783076551116]