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