[{"data":1,"prerenderedAt":739},["ShallowReactive",2],{"navigation":3,"-adapters-sse":83,"-adapters-sse-surround":735},[4,46],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Guide","\u002Fguide","1.guide\u002F1.index",[9,11,16,21,26,31,36,41],{"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,"children":50,"icon":52},"Adapters","\u002Fadapters","2.adapters\u002F1.index",[51,53,58,63,68,73,78],{"title":47,"path":48,"stem":49,"icon":52},"emojione-monotone:electric-plug",{"title":54,"path":55,"stem":56,"icon":57},"Bun","\u002Fadapters\u002Fbun","2.adapters\u002Fbun","simple-icons:bun",{"title":59,"path":60,"stem":61,"icon":62},"Bunny","\u002Fadapters\u002Fbunny","2.adapters\u002Fbunny","mdi:rabbit",{"title":64,"path":65,"stem":66,"icon":67},"Cloudflare","\u002Fadapters\u002Fcloudflare","2.adapters\u002Fcloudflare","devicon-plain:cloudflareworkers",{"title":69,"path":70,"stem":71,"icon":72},"Deno","\u002Fadapters\u002Fdeno","2.adapters\u002Fdeno","teenyicons:deno-solid",{"title":74,"path":75,"stem":76,"icon":77},"Node.js","\u002Fadapters\u002Fnode","2.adapters\u002Fnode","akar-icons:node-fill",{"title":79,"path":80,"stem":81,"icon":82},"SSE","\u002Fadapters\u002Fsse","2.adapters\u002Fsse","clarity:two-way-arrows-line",{"id":84,"title":79,"body":85,"description":729,"extension":730,"meta":731,"navigation":732,"path":80,"seo":733,"stem":81,"__hash__":734},"content\u002F2.adapters\u002Fsse.md",{"type":86,"value":87,"toc":723,"icon":82},"minimark",[88,111,124,129,134,140,143,394,397,522,526,532,670,697,719],[89,90,91,92,102,103,110],"p",{},"If your deployment target does not supports handling WebSocket upgrades, crossws SSE adapter allows to add integration based on web platform standards (",[93,94,98],"a",{"href":95,"rel":96},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FFetch_API",[97],"nofollow",[99,100,101],"code",{},"fetch"," and ",[93,104,107],{"href":105,"rel":106},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FEventSource",[97],[99,108,109],{},"EventSource",")",[112,113,114],"important",{},[89,115,116,117,123],{},"\nThis is an experimental adapter and requires a custom ",[93,118,120],{"href":119},"#client-side",[99,121,122],{},"WebsocketSSE"," client to connect.",[125,126,128],"h2",{"id":127},"usage","Usage",[130,131,133],"h3",{"id":132},"server-side","Server side",[135,136,137],"note",{},[89,138,139],{},"\nHTTP\u002F2 + TLS is recommended in order to increase browser limitations about number of SSE connections (from 6 to 100) and also to allow bidirectional messaging with streaming.",[89,141,142],{},"Define adapter:",[144,145,150],"pre",{"className":146,"code":147,"language":148,"meta":149,"style":149},"language-ts shiki shiki-themes github-light github-dark github-dark","import sseAdapter from \"crossws\u002Fadapters\u002Fsse\";\n\nconst ws = sseAdapter({\n  bidir: true, \u002F\u002F Enable bidirectional messaging support\n  hooks: {\n    upgrade(request) {\n      \u002F\u002F In case of bidirectional mode, extra auth is recommended based on request\n      \u002F\u002F You can return a new Response() instead to abort\n      return {\n        headers: {},\n      };\n    },\n    open(peer) {\n      \u002F\u002F Use this hook to send messages to peer\n      peer.send(`Welcome ${peer}`);\n    },\n    message(peer, message) {\n      \u002F\u002F Accepting messages from peer (bidirectional mode)\n      console.log(`Message from ${peer}: ${message}`); \u002F\u002F Message from \u003Cid>: ping\n    },\n  },\n});\n","ts","",[99,151,152,175,182,202,218,224,240,246,252,261,267,273,279,292,298,320,325,342,348,377,382,388],{"__ignoreMap":149},[153,154,157,161,165,168,172],"span",{"class":155,"line":156},"line",1,[153,158,160],{"class":159},"so5gQ","import",[153,162,164],{"class":163},"slsVL"," sseAdapter ",[153,166,167],{"class":159},"from",[153,169,171],{"class":170},"sfrk1"," \"crossws\u002Fadapters\u002Fsse\"",[153,173,174],{"class":163},";\n",[153,176,178],{"class":155,"line":177},2,[153,179,181],{"emptyLinePlaceholder":180},true,"\n",[153,183,185,188,192,195,199],{"class":155,"line":184},3,[153,186,187],{"class":159},"const",[153,189,191],{"class":190},"suiK_"," ws",[153,193,194],{"class":159}," =",[153,196,198],{"class":197},"shcOC"," sseAdapter",[153,200,201],{"class":163},"({\n",[153,203,205,208,211,214],{"class":155,"line":204},4,[153,206,207],{"class":163},"  bidir: ",[153,209,210],{"class":190},"true",[153,212,213],{"class":163},", ",[153,215,217],{"class":216},"sCsY4","\u002F\u002F Enable bidirectional messaging support\n",[153,219,221],{"class":155,"line":220},5,[153,222,223],{"class":163},"  hooks: {\n",[153,225,227,230,233,237],{"class":155,"line":226},6,[153,228,229],{"class":197},"    upgrade",[153,231,232],{"class":163},"(",[153,234,236],{"class":235},"sQHwn","request",[153,238,239],{"class":163},") {\n",[153,241,243],{"class":155,"line":242},7,[153,244,245],{"class":216},"      \u002F\u002F In case of bidirectional mode, extra auth is recommended based on request\n",[153,247,249],{"class":155,"line":248},8,[153,250,251],{"class":216},"      \u002F\u002F You can return a new Response() instead to abort\n",[153,253,255,258],{"class":155,"line":254},9,[153,256,257],{"class":159},"      return",[153,259,260],{"class":163}," {\n",[153,262,264],{"class":155,"line":263},10,[153,265,266],{"class":163},"        headers: {},\n",[153,268,270],{"class":155,"line":269},11,[153,271,272],{"class":163},"      };\n",[153,274,276],{"class":155,"line":275},12,[153,277,278],{"class":163},"    },\n",[153,280,282,285,287,290],{"class":155,"line":281},13,[153,283,284],{"class":197},"    open",[153,286,232],{"class":163},[153,288,289],{"class":235},"peer",[153,291,239],{"class":163},[153,293,295],{"class":155,"line":294},14,[153,296,297],{"class":216},"      \u002F\u002F Use this hook to send messages to peer\n",[153,299,301,304,307,309,312,314,317],{"class":155,"line":300},15,[153,302,303],{"class":163},"      peer.",[153,305,306],{"class":197},"send",[153,308,232],{"class":163},[153,310,311],{"class":170},"`Welcome ${",[153,313,289],{"class":163},[153,315,316],{"class":170},"}`",[153,318,319],{"class":163},");\n",[153,321,323],{"class":155,"line":322},16,[153,324,278],{"class":163},[153,326,328,331,333,335,337,340],{"class":155,"line":327},17,[153,329,330],{"class":197},"    message",[153,332,232],{"class":163},[153,334,289],{"class":235},[153,336,213],{"class":163},[153,338,339],{"class":235},"message",[153,341,239],{"class":163},[153,343,345],{"class":155,"line":344},18,[153,346,347],{"class":216},"      \u002F\u002F Accepting messages from peer (bidirectional mode)\n",[153,349,351,354,357,359,362,364,367,369,371,374],{"class":155,"line":350},19,[153,352,353],{"class":163},"      console.",[153,355,356],{"class":197},"log",[153,358,232],{"class":163},[153,360,361],{"class":170},"`Message from ${",[153,363,289],{"class":163},[153,365,366],{"class":170},"}: ${",[153,368,339],{"class":163},[153,370,316],{"class":170},[153,372,373],{"class":163},"); ",[153,375,376],{"class":216},"\u002F\u002F Message from \u003Cid>: ping\n",[153,378,380],{"class":155,"line":379},20,[153,381,278],{"class":163},[153,383,385],{"class":155,"line":384},21,[153,386,387],{"class":163},"  },\n",[153,389,391],{"class":155,"line":390},22,[153,392,393],{"class":163},"});\n",[89,395,396],{},"Inside your web server handler:",[144,398,402],{"className":399,"code":400,"language":401,"meta":149,"style":149},"language-js shiki shiki-themes github-light github-dark github-dark","async fetch(request) {\n  \u002F\u002F Handle crossws upgrade\n  if (\n    request.headers.get(\"accept\") === \"text\u002Fevent-stream\" ||\n    request.headers.has(\"x-crossws-id\")\n  ) {\n    return ws.fetch(request);\n  }\n\n  \u002F\u002F Your normal application logic\n  return new Response(\"default page\")\n}\n","js",[99,403,404,414,419,427,452,467,472,485,490,494,499,517],{"__ignoreMap":149},[153,405,406,409,411],{"class":155,"line":156},[153,407,408],{"class":163},"async ",[153,410,101],{"class":197},[153,412,413],{"class":163},"(request) {\n",[153,415,416],{"class":155,"line":177},[153,417,418],{"class":216},"  \u002F\u002F Handle crossws upgrade\n",[153,420,421,424],{"class":155,"line":184},[153,422,423],{"class":159},"  if",[153,425,426],{"class":163}," (\n",[153,428,429,432,435,437,440,443,446,449],{"class":155,"line":204},[153,430,431],{"class":163},"    request.headers.",[153,433,434],{"class":197},"get",[153,436,232],{"class":163},[153,438,439],{"class":170},"\"accept\"",[153,441,442],{"class":163},") ",[153,444,445],{"class":159},"===",[153,447,448],{"class":170}," \"text\u002Fevent-stream\"",[153,450,451],{"class":159}," ||\n",[153,453,454,456,459,461,464],{"class":155,"line":220},[153,455,431],{"class":163},[153,457,458],{"class":197},"has",[153,460,232],{"class":163},[153,462,463],{"class":170},"\"x-crossws-id\"",[153,465,466],{"class":163},")\n",[153,468,469],{"class":155,"line":226},[153,470,471],{"class":163},"  ) {\n",[153,473,474,477,480,482],{"class":155,"line":242},[153,475,476],{"class":159},"    return",[153,478,479],{"class":163}," ws.",[153,481,101],{"class":197},[153,483,484],{"class":163},"(request);\n",[153,486,487],{"class":155,"line":248},[153,488,489],{"class":163},"  }\n",[153,491,492],{"class":155,"line":254},[153,493,181],{"emptyLinePlaceholder":180},[153,495,496],{"class":155,"line":263},[153,497,498],{"class":216},"  \u002F\u002F Your normal application logic\n",[153,500,501,504,507,510,512,515],{"class":155,"line":269},[153,502,503],{"class":159},"  return",[153,505,506],{"class":159}," new",[153,508,509],{"class":197}," Response",[153,511,232],{"class":163},[153,513,514],{"class":170},"\"default page\"",[153,516,466],{"class":163},[153,518,519],{"class":155,"line":275},[153,520,521],{"class":163},"}\n",[130,523,525],{"id":524},"client-side","Client side",[89,527,528,529,531],{},"In order to make communication with server, we need a special ",[99,530,122],{}," client.",[144,533,535],{"className":399,"code":534,"language":401,"meta":149,"style":149},"import { WebsocketSSE } from \"crossws\u002Fwebsocket\u002Fsse\";\n\nconst ws = new WebsocketSSE(\"https:\u002F\u002F\u003Cserver_address>\", { bdir: true });\n\nws.addEventListener(\"open\", () => {\n  ws.send(\"ping\");\n});\n\nws.addEventListener(\"message\", (event) => {\n  console.log(\"Received:\", event.data);\n});\n",[99,536,537,551,555,581,585,606,620,624,628,651,666],{"__ignoreMap":149},[153,538,539,541,544,546,549],{"class":155,"line":156},[153,540,160],{"class":159},[153,542,543],{"class":163}," { WebsocketSSE } ",[153,545,167],{"class":159},[153,547,548],{"class":170}," \"crossws\u002Fwebsocket\u002Fsse\"",[153,550,174],{"class":163},[153,552,553],{"class":155,"line":177},[153,554,181],{"emptyLinePlaceholder":180},[153,556,557,559,561,563,565,568,570,573,576,578],{"class":155,"line":184},[153,558,187],{"class":159},[153,560,191],{"class":190},[153,562,194],{"class":159},[153,564,506],{"class":159},[153,566,567],{"class":197}," WebsocketSSE",[153,569,232],{"class":163},[153,571,572],{"class":170},"\"https:\u002F\u002F\u003Cserver_address>\"",[153,574,575],{"class":163},", { bdir: ",[153,577,210],{"class":190},[153,579,580],{"class":163}," });\n",[153,582,583],{"class":155,"line":204},[153,584,181],{"emptyLinePlaceholder":180},[153,586,587,590,593,595,598,601,604],{"class":155,"line":220},[153,588,589],{"class":163},"ws.",[153,591,592],{"class":197},"addEventListener",[153,594,232],{"class":163},[153,596,597],{"class":170},"\"open\"",[153,599,600],{"class":163},", () ",[153,602,603],{"class":159},"=>",[153,605,260],{"class":163},[153,607,608,611,613,615,618],{"class":155,"line":226},[153,609,610],{"class":163},"  ws.",[153,612,306],{"class":197},[153,614,232],{"class":163},[153,616,617],{"class":170},"\"ping\"",[153,619,319],{"class":163},[153,621,622],{"class":155,"line":242},[153,623,393],{"class":163},[153,625,626],{"class":155,"line":248},[153,627,181],{"emptyLinePlaceholder":180},[153,629,630,632,634,636,639,642,645,647,649],{"class":155,"line":254},[153,631,589],{"class":163},[153,633,592],{"class":197},[153,635,232],{"class":163},[153,637,638],{"class":170},"\"message\"",[153,640,641],{"class":163},", (",[153,643,644],{"class":235},"event",[153,646,442],{"class":163},[153,648,603],{"class":159},[153,650,260],{"class":163},[153,652,653,656,658,660,663],{"class":155,"line":263},[153,654,655],{"class":163},"  console.",[153,657,356],{"class":197},[153,659,232],{"class":163},[153,661,662],{"class":170},"\"Received:\"",[153,664,665],{"class":163},", event.data);\n",[153,667,668],{"class":155,"line":269},[153,669,393],{"class":163},[135,671,672],{},[89,673,674,675,678,679,684,685,690,691,696],{},"\nBehind the scenes, ",[99,676,677],{},"WebSocketSSE",", uses ",[93,680,682],{"href":105,"rel":681},[97],[99,683,109],{}," to receive messages from server. In order to send messages to the server, it tries to make another connection stream using same peer id and if failed, fallback to ",[93,686,688],{"href":95,"rel":687},[97],[99,689,101],{}," for each message.\nIn theory, it is possible to have communication on a single HTTP\u002F2 connection, however, due to a ",[93,692,695],{"href":693,"rel":694},"https:\u002F\u002Fgithub.com\u002Fwhatwg\u002Ffetch\u002Fissues\u002F1254",[97],"current limitation in fetch standard"," we need 2 connections, one for receiving messages and one for sending.",[698,699,700],"read-more",{},[89,701,702,703,710,711,718],{},"See ",[93,704,707],{"href":705,"rel":706},"https:\u002F\u002Fgithub.com\u002Fh3js\u002Fcrossws\u002Fblob\u002Fmain\u002Ftest\u002Ffixture\u002Fsse.ts",[97],[99,708,709],{},"test\u002Ffixture\u002Fsse.ts"," for demo and ",[93,712,715],{"href":713,"rel":714},"https:\u002F\u002Fgithub.com\u002Fh3js\u002Fcrossws\u002Fblob\u002Fmain\u002Fsrc\u002Fadapters\u002Fsse.ts",[97],[99,716,717],{},"src\u002Fadapters\u002Fsse.ts"," for implementation.",[720,721,722],"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 .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}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":149,"searchDepth":177,"depth":177,"links":724},[725],{"id":127,"depth":177,"text":128,"children":726},[727,728],{"id":132,"depth":184,"text":133},{"id":524,"depth":184,"text":525},"Integrate crossws with server-sent events and fetch-api.","md",{"icon":82},{"icon":82},{"title":79,"description":729},"3BltEoDeRBmVPwESYTaxY2On-aWtKizubu-MGQPdWu4",[736,738],{"title":74,"path":75,"stem":76,"description":737,"icon":77,"children":-1},"Integrate crossws with Node.js (manually) or uWebSockets.js",null,1782852616981]