[{"data":1,"prerenderedAt":1030},["ShallowReactive",2],{"navigation:en":3,"\u002Fblog\u002Frealtime-websockets-durable-objects":311},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Nuxfire Docs","\u002Fdocs","docs\u002F0.index",[9,11,152],{"title":5,"path":6,"stem":7,"icon":10},"i-lucide-layout-grid",{"title":12,"path":13,"stem":14,"children":15,"icon":151},"SaaS Starter Kit","\u002Fdocs\u002Fsaas-starter-kit","docs\u002F1.saas-starter-kit\u002F0.index",[16,19,63,129],{"title":17,"path":13,"stem":14,"icon":18},"What is the SaaS Starter Kit?","i-lucide-info",{"title":20,"icon":21,"hide":22,"path":23,"stem":24,"children":25,"page":62},"Getting Started","i-lucide-play",true,"\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started","docs\u002F1.saas-starter-kit\u002F1.getting-started",[26,30,34,38,42,46,50,54,58],{"title":27,"path":28,"stem":29},"Quick Start","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fquick-start","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F0.quick-start",{"title":31,"path":32,"stem":33},"Installation","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Finstallation","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F1.installation",{"title":35,"path":36,"stem":37},"Cloudflare Access","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fcloudflare-access","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F2.cloudflare-access",{"title":39,"path":40,"stem":41},"Configuration","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fconfiguration","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F3.configuration",{"title":43,"path":44,"stem":45},"Secrets","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fsecrets","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F4.secrets",{"title":47,"path":48,"stem":49},"Environment Variables","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fenvironment-variables","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F5.environment-variables",{"title":51,"path":52,"stem":53},"Deploy","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fdeploy","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F6.deploy",{"title":55,"path":56,"stem":57},"Local Development","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Flocal-development","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F7.local-development",{"title":59,"path":60,"stem":61},"Project Structure","\u002Fdocs\u002Fsaas-starter-kit\u002Fgetting-started\u002Fproject-structure","docs\u002F1.saas-starter-kit\u002F1.getting-started\u002F8.project-structure",false,{"title":64,"icon":65,"hide":22,"path":66,"stem":67,"children":68,"page":62},"Features","i-lucide-box","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures","docs\u002F1.saas-starter-kit\u002F2.features",[69,73,77,81,85,89,93,97,101,105,109,113,117,121,125],{"title":70,"path":71,"stem":72},"Authentication","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fauth","docs\u002F1.saas-starter-kit\u002F2.features\u002F1.auth",{"title":74,"path":75,"stem":76},"Rate Limiting","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frate-limiting","docs\u002F1.saas-starter-kit\u002F2.features\u002F10.rate-limiting",{"title":78,"path":79,"stem":80},"WebSockets","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fwebsockets","docs\u002F1.saas-starter-kit\u002F2.features\u002F11.websockets",{"title":82,"path":83,"stem":84},"Blog","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fblog","docs\u002F1.saas-starter-kit\u002F2.features\u002F14.blog",{"title":86,"path":87,"stem":88},"Documentation","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdocumentation","docs\u002F1.saas-starter-kit\u002F2.features\u002F15.documentation",{"title":90,"path":91,"stem":92},"Analytics","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fanalytics","docs\u002F1.saas-starter-kit\u002F2.features\u002F16.analytics",{"title":94,"path":95,"stem":96},"Platform Admin Console","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fplatform-admin","docs\u002F1.saas-starter-kit\u002F2.features\u002F17.platform-admin",{"title":98,"path":99,"stem":100},"Database","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fdatabase","docs\u002F1.saas-starter-kit\u002F2.features\u002F2.database",{"title":102,"path":103,"stem":104},"Payments & Billing","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fpayments","docs\u002F1.saas-starter-kit\u002F2.features\u002F3.payments",{"title":106,"path":107,"stem":108},"Emails","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Femails","docs\u002F1.saas-starter-kit\u002F2.features\u002F4.emails",{"title":110,"path":111,"stem":112},"Notifications","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fnotifications","docs\u002F1.saas-starter-kit\u002F2.features\u002F5.notifications",{"title":114,"path":115,"stem":116},"Role-Based Access Control","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Frbac","docs\u002F1.saas-starter-kit\u002F2.features\u002F6.rbac",{"title":118,"path":119,"stem":120},"Async Jobs","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fasync-jobs","docs\u002F1.saas-starter-kit\u002F2.features\u002F7.async-jobs",{"title":122,"path":123,"stem":124},"Storage","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Fstorage","docs\u002F1.saas-starter-kit\u002F2.features\u002F8.storage",{"title":126,"path":127,"stem":128},"Internationalization","\u002Fdocs\u002Fsaas-starter-kit\u002Ffeatures\u002Finternationalization","docs\u002F1.saas-starter-kit\u002F2.features\u002F9.internationalization",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":62},"Concepts","i-lucide-graduation-cap","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts","docs\u002F1.saas-starter-kit\u002F3.concepts",[135,139,143,147],{"title":136,"path":137,"stem":138},"Technology Stack","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Ftech-stack","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F0.tech-stack",{"title":140,"path":141,"stem":142},"SST.dev","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fsst","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F1.sst",{"title":144,"path":145,"stem":146},"NuxtHub","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fnuxt-hub","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F2.nuxt-hub",{"title":148,"path":149,"stem":150},"Design System & Branding","\u002Fdocs\u002Fsaas-starter-kit\u002Fconcepts\u002Fdesign-system","docs\u002F1.saas-starter-kit\u002F3.concepts\u002F3.design-system","i-lucide-zap",{"title":153,"path":154,"stem":155,"children":156,"icon":159},"Fireskills","\u002Fdocs\u002Ffireskills","docs\u002F2.fireskills\u002F0.index",[157,160,219,249,275,293],{"title":158,"path":154,"stem":155,"icon":159},"What is Fireskills?","i-lucide-flame",{"title":20,"icon":21,"hide":22,"path":161,"stem":162,"children":163,"page":62},"\u002Fdocs\u002Ffireskills\u002Fgetting-started","docs\u002F2.fireskills\u002F1.getting-started",[164,167,171,175,179,183,187,191,195,199,203,207,211,215],{"title":27,"path":165,"stem":166},"\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fquick-start","docs\u002F2.fireskills\u002F1.getting-started\u002F00.quick-start",{"title":168,"path":169,"stem":170},"Workflow & Governance","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fworkflow","docs\u002F2.fireskills\u002F1.getting-started\u002F01.workflow",{"title":172,"path":173,"stem":174},"Project Context","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fproject-context","docs\u002F2.fireskills\u002F1.getting-started\u002F02.project-context",{"title":176,"path":177,"stem":178},"Step 0: Setup","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-setup","docs\u002F2.fireskills\u002F1.getting-started\u002F03.step-setup",{"title":180,"path":181,"stem":182},"Step 1: Inbox","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-inbox","docs\u002F2.fireskills\u002F1.getting-started\u002F04.step-inbox",{"title":184,"path":185,"stem":186},"Step 2: Backlog","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-backlog","docs\u002F2.fireskills\u002F1.getting-started\u002F05.step-backlog",{"title":188,"path":189,"stem":190},"Step 3: Specify","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-specify","docs\u002F2.fireskills\u002F1.getting-started\u002F06.step-specify",{"title":192,"path":193,"stem":194},"Step 4: Validate","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-validate","docs\u002F2.fireskills\u002F1.getting-started\u002F07.step-validate",{"title":196,"path":197,"stem":198},"Step 5: Tasks","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tasks","docs\u002F2.fireskills\u002F1.getting-started\u002F08.step-tasks",{"title":200,"path":201,"stem":202},"Step 6: TDD\u002FBDD","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-tdd-bdd","docs\u002F2.fireskills\u002F1.getting-started\u002F09.step-tdd-bdd",{"title":204,"path":205,"stem":206},"Step 7: Implement","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-implement","docs\u002F2.fireskills\u002F1.getting-started\u002F10.step-implement",{"title":208,"path":209,"stem":210},"Step 8: Documentator","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fstep-documentator","docs\u002F2.fireskills\u002F1.getting-started\u002F11.step-documentator",{"title":212,"path":213,"stem":214},"Late Changes","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Flate-changes","docs\u002F2.fireskills\u002F1.getting-started\u002F12.late-changes",{"title":216,"path":217,"stem":218},"Other Entry Points","\u002Fdocs\u002Ffireskills\u002Fgetting-started\u002Fother-entry-points","docs\u002F2.fireskills\u002F1.getting-started\u002F13.other-entry-points",{"title":220,"icon":221,"hide":22,"path":222,"stem":223,"children":224,"page":62},"Methodology","i-lucide-git-branch","\u002Fdocs\u002Ffireskills\u002Fmethodology","docs\u002F2.fireskills\u002F2.methodology",[225,229,233,237,241,245],{"title":226,"path":227,"stem":228},"The Three Acts","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-acts","docs\u002F2.fireskills\u002F2.methodology\u002F0.three-acts",{"title":230,"path":231,"stem":232},"The Three Gates","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fthree-gates","docs\u002F2.fireskills\u002F2.methodology\u002F1.three-gates",{"title":234,"path":235,"stem":236},"The Canonical Spec","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fcanonical-spec","docs\u002F2.fireskills\u002F2.methodology\u002F2.canonical-spec",{"title":238,"path":239,"stem":240},"Lifecycle States","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Flifecycle-states","docs\u002F2.fireskills\u002F2.methodology\u002F3.lifecycle-states",{"title":242,"path":243,"stem":244},"Effort Scale","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Feffort-scale","docs\u002F2.fireskills\u002F2.methodology\u002F4.effort-scale",{"title":246,"path":247,"stem":248},"Milestones & Governance","\u002Fdocs\u002Ffireskills\u002Fmethodology\u002Fgovernance-and-milestones","docs\u002F2.fireskills\u002F2.methodology\u002F5.governance-and-milestones",{"title":250,"icon":251,"hide":22,"path":252,"stem":253,"children":254,"page":62},"Skills","i-lucide-layers","\u002Fdocs\u002Ffireskills\u002Fskills","docs\u002F2.fireskills\u002F3.skills",[255,259,263,267,271],{"title":256,"path":257,"stem":258},"Catalog","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fcatalog","docs\u002F2.fireskills\u002F3.skills\u002F0.catalog",{"title":260,"path":261,"stem":262},"Act I: Define","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-1-define","docs\u002F2.fireskills\u002F3.skills\u002F1.act-1-define",{"title":264,"path":265,"stem":266},"Act II: Design & Prove","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-2-design-prove","docs\u002F2.fireskills\u002F3.skills\u002F2.act-2-design-prove",{"title":268,"path":269,"stem":270},"Act III: Deliver","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fact-3-deliver","docs\u002F2.fireskills\u002F3.skills\u002F3.act-3-deliver",{"title":272,"path":273,"stem":274},"Governance & Decisions","\u002Fdocs\u002Ffireskills\u002Fskills\u002Fgovernance-and-decisions","docs\u002F2.fireskills\u002F3.skills\u002F4.governance-and-decisions",{"title":276,"icon":277,"hide":22,"path":278,"stem":279,"children":280,"page":62},"Specialists","i-lucide-sparkles","\u002Fdocs\u002Ffireskills\u002Fspecialists","docs\u002F2.fireskills\u002F4.specialists",[281,285,289],{"title":282,"path":283,"stem":284},"Overview","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Foverview","docs\u002F2.fireskills\u002F4.specialists\u002F0.overview",{"title":286,"path":287,"stem":288},"Nuxfire Stack","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fnuxfire-stack","docs\u002F2.fireskills\u002F4.specialists\u002F1.nuxfire-stack",{"title":290,"path":291,"stem":292},"Engineering Specialists","\u002Fdocs\u002Ffireskills\u002Fspecialists\u002Fengineering-specialists","docs\u002F2.fireskills\u002F4.specialists\u002F2.engineering-specialists",{"title":294,"icon":295,"hide":22,"path":296,"stem":297,"children":298,"page":62},"CLI & Tooling","i-lucide-terminal","\u002Fdocs\u002Ffireskills\u002Fcli","docs\u002F2.fireskills\u002F5.cli",[299,303,307],{"title":300,"path":301,"stem":302},"CLI Overview","\u002Fdocs\u002Ffireskills\u002Fcli\u002Foverview","docs\u002F2.fireskills\u002F5.cli\u002F0.overview",{"title":304,"path":305,"stem":306},"Commands","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fcommands","docs\u002F2.fireskills\u002F5.cli\u002F1.commands",{"title":308,"path":309,"stem":310},"Safety Scripts","\u002Fdocs\u002Ffireskills\u002Fcli\u002Fgovernance-scripts","docs\u002F2.fireskills\u002F5.cli\u002F2.governance-scripts",{"id":312,"title":313,"author":314,"authorType":315,"body":316,"category":1009,"date":1010,"description":1011,"extension":1012,"image":1013,"lang":1014,"meta":1015,"navigation":22,"ogImage":1016,"path":1017,"readTime":1018,"seo":1019,"stem":1020,"tags":1021,"translations":1025,"updated":315,"__hash__":1029},"blog\u002Fblog\u002Frealtime-websockets-durable-objects.md","Real-Time WebSockets Without Redis: Using Cloudflare Durable Objects in Nuxt 4","Nuxfire Team",null,{"type":317,"value":318,"toc":1003},"minimark",[319,323,326,339,351,354,359,366,373,384,386,390,393,407,657,659,663,666,976,978,982,985,990,999],[320,321,322],"p",{},"Building real-time features (such as instant notifications, collaborative cursors or live dashboards) has always been one of the biggest nightmares in serverless architectures.",[320,324,325],{},"Traditionally, the recipe for supporting WebSockets required:",[327,328,329,333,336],"ol",{},[330,331,332],"li",{},"A cluster of always-on dedicated Node.js servers.",[330,334,335],{},"A Redis cluster with Pub\u002FSub to sync messages between instances.",[330,337,338],{},"A load balancer configured for persistent connections (Sticky Sessions).",[320,340,341,342,346,347,350],{},"The monthly cost of this minimal infrastructure rarely fell below hundreds of dollars. ",[343,344,345],"strong",{},"Nuxfire"," solves this challenge using ",[343,348,349],{},"Cloudflare Durable Objects",".",[352,353],"hr",{},[355,356,358],"h2",{"id":357},"what-are-cloudflare-durable-objects","What Are Cloudflare Durable Objects?",[320,360,361,362,365],{},"Durable Objects provide serverless compute with ",[343,363,364],{},"coordinated state",". Each object runs as a single instance on Cloudflare's global network, guaranteeing that all connections to the same \"channel\" or \"room\" reach the same memory process.",[320,367,368,369,372],{},"In addition, each Durable Object has its own ",[343,370,371],{},"embedded SQLite"," database, allowing message history to be persisted with sub-millisecond latency.",[374,375,380],"pre",{"className":376,"code":378,"language":379},[377],"language-text","[User A (Browser)] ──WebSockets───────> ┌────────────────────────────────┐\n                                        │ Cloudflare Durable Object      │\n[User B (Browser)] ──WebSockets───────> │ - Connection state in RAM      │\n                                        │ - Embedded SQLite database     │\n[Webhook \u002F Backend Worker] ──Fetch────> └────────────────────────────────┘\n","text",[381,382,378],"code",{"__ignoreMap":383},"",[352,385],{},[355,387,389],{"id":388},"robust-security-handshake-with-hmac-signed-tickets","Robust Security: Handshake with HMAC-Signed Tickets",[320,391,392],{},"WebSocket connections do not carry normal HTTP headers after the initial handshake. To guarantee maximum security against forged connections, Nuxfire uses cryptographically signed tickets:",[327,394,395,398,401,404],{},[330,396,397],{},"The client makes an authenticated HTTP request asking for a connection ticket.",[330,399,400],{},"The server generates an HMAC-signed token using the application's secret key, valid for 60 seconds.",[330,402,403],{},"The client opens the WebSocket connection passing the ticket in the query string.",[330,405,406],{},"The Durable Object validates the signature before accepting the handshake.",[374,408,412],{"className":409,"code":410,"language":411,"meta":383,"style":383},"language-typescript shiki shiki-themes material-theme-lighter github-light github-dark monokai","\u002F\u002F Generating the signed ticket in the authentication endpoint\nexport function generateWebSocketTicket(userId: string, workspaceId: string) {\n  const expiresAt = Date.now() + 60 * 1000;\n  const payload = `${userId}:${workspaceId}:${expiresAt}`;\n  const signature = createHmac(\"sha256\", env.WS_SECRET).update(payload).digest(\"hex\");\n  return `${payload}:${signature}`;\n}\n","typescript",[381,413,414,423,470,512,559,624,651],{"__ignoreMap":383},[415,416,419],"span",{"class":417,"line":418},"line",1,[415,420,422],{"class":421},"ss7Ak","\u002F\u002F Generating the signed ticket in the authentication endpoint\n",[415,424,426,430,434,438,442,446,450,454,457,460,462,464,467],{"class":417,"line":425},2,[415,427,429],{"class":428},"sRxSC","export",[415,431,433],{"class":432},"srJo8"," function",[415,435,437],{"class":436},"sD0ED"," generateWebSocketTicket",[415,439,441],{"class":440},"swvn1","(",[415,443,445],{"class":444},"sQgqH","userId",[415,447,449],{"class":448},"sGXK2",":",[415,451,453],{"class":452},"s_MOj"," string",[415,455,456],{"class":440},",",[415,458,459],{"class":444}," workspaceId",[415,461,449],{"class":448},[415,463,453],{"class":452},[415,465,466],{"class":440},")",[415,468,469],{"class":440}," {\n",[415,471,473,476,480,483,487,489,492,496,499,503,506,509],{"class":417,"line":472},3,[415,474,475],{"class":432},"  const",[415,477,479],{"class":478},"s91G_"," expiresAt",[415,481,482],{"class":448}," =",[415,484,486],{"class":485},"ss--_"," Date",[415,488,350],{"class":440},[415,490,491],{"class":436},"now",[415,493,495],{"class":494},"squCx","() ",[415,497,498],{"class":448},"+",[415,500,502],{"class":501},"sYThS"," 60",[415,504,505],{"class":448}," *",[415,507,508],{"class":501}," 1000",[415,510,511],{"class":440},";\n",[415,513,515,517,520,522,526,530,532,535,538,540,543,545,547,549,552,554,557],{"class":417,"line":514},4,[415,516,475],{"class":432},[415,518,519],{"class":478}," payload",[415,521,482],{"class":448},[415,523,525],{"class":524},"siCPE"," `",[415,527,529],{"class":528},"slF1C","${",[415,531,445],{"class":485},[415,533,534],{"class":528},"}",[415,536,449],{"class":537},"sLACW",[415,539,529],{"class":528},[415,541,542],{"class":485},"workspaceId",[415,544,534],{"class":528},[415,546,449],{"class":537},[415,548,529],{"class":528},[415,550,551],{"class":485},"expiresAt",[415,553,534],{"class":528},[415,555,556],{"class":524},"`",[415,558,511],{"class":440},[415,560,562,564,567,569,572,574,577,580,582,584,587,589,592,594,596,599,601,604,606,608,611,613,615,618,620,622],{"class":417,"line":561},5,[415,563,475],{"class":432},[415,565,566],{"class":478}," signature",[415,568,482],{"class":448},[415,570,571],{"class":436}," createHmac",[415,573,441],{"class":494},[415,575,576],{"class":524},"\"",[415,578,579],{"class":537},"sha256",[415,581,576],{"class":524},[415,583,456],{"class":440},[415,585,586],{"class":485}," env",[415,588,350],{"class":440},[415,590,591],{"class":478},"WS_SECRET",[415,593,466],{"class":494},[415,595,350],{"class":440},[415,597,598],{"class":436},"update",[415,600,441],{"class":494},[415,602,603],{"class":485},"payload",[415,605,466],{"class":494},[415,607,350],{"class":440},[415,609,610],{"class":436},"digest",[415,612,441],{"class":494},[415,614,576],{"class":524},[415,616,617],{"class":537},"hex",[415,619,576],{"class":524},[415,621,466],{"class":494},[415,623,511],{"class":440},[415,625,627,630,632,634,636,638,640,642,645,647,649],{"class":417,"line":626},6,[415,628,629],{"class":428},"  return",[415,631,525],{"class":524},[415,633,529],{"class":528},[415,635,603],{"class":485},[415,637,534],{"class":528},[415,639,449],{"class":537},[415,641,529],{"class":528},[415,643,644],{"class":485},"signature",[415,646,534],{"class":528},[415,648,556],{"class":524},[415,650,511],{"class":440},[415,652,654],{"class":417,"line":653},7,[415,655,656],{"class":440},"}\n",[352,658],{},[355,660,662],{"id":661},"consuming-it-in-the-frontend-with-nuxt-composables","Consuming It in the Frontend with Nuxt Composables",[320,664,665],{},"On the Nuxt 4 client side, connecting to the team channel is as simple as using a native composable:",[374,667,671],{"className":668,"code":669,"language":670,"meta":383,"style":383},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark monokai","\u003Cscript setup lang=\"ts\">\nconst { messages, status, send } = useTeamWebSockets();\n\nfunction handleNotify() {\n  send({ type: \"TEAM_PING\", content: \"New task created on the board!\" });\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003CUBadge :color=\"status === 'OPEN' ? 'success' : 'neutral'\">\n      {{ status === 'OPEN' ? 'Real Time Active' : 'Reconnecting...' }}\n    \u003C\u002FUBadge>\n    \u003Cdiv v-for=\"msg in messages\" :key=\"msg.id\">\n      {{ msg.content }}\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue",[381,672,673,702,736,741,753,796,800,809,814,824,835,893,899,909,942,948,957,967],{"__ignoreMap":383},[415,674,675,678,682,686,689,692,694,697,699],{"class":417,"line":418},[415,676,677],{"class":440},"\u003C",[415,679,681],{"class":680},"sHsBP","script",[415,683,685],{"class":684},"s_lYk"," setup",[415,687,688],{"class":684}," lang",[415,690,691],{"class":440},"=",[415,693,576],{"class":524},[415,695,696],{"class":537},"ts",[415,698,576],{"class":524},[415,700,701],{"class":440},">\n",[415,703,704,707,710,713,715,718,720,723,726,728,731,734],{"class":417,"line":425},[415,705,706],{"class":432},"const",[415,708,709],{"class":440}," {",[415,711,712],{"class":478}," messages",[415,714,456],{"class":440},[415,716,717],{"class":478}," status",[415,719,456],{"class":440},[415,721,722],{"class":478}," send",[415,724,725],{"class":440}," }",[415,727,482],{"class":448},[415,729,730],{"class":436}," useTeamWebSockets",[415,732,733],{"class":485},"()",[415,735,511],{"class":440},[415,737,738],{"class":417,"line":472},[415,739,740],{"emptyLinePlaceholder":22},"\n",[415,742,743,746,749,751],{"class":417,"line":514},[415,744,745],{"class":432},"function",[415,747,748],{"class":436}," handleNotify",[415,750,733],{"class":440},[415,752,469],{"class":440},[415,754,755,758,760,763,766,768,771,774,776,778,781,783,785,788,790,792,794],{"class":417,"line":561},[415,756,757],{"class":436},"  send",[415,759,441],{"class":494},[415,761,762],{"class":440},"{",[415,764,765],{"class":494}," type",[415,767,449],{"class":440},[415,769,770],{"class":524}," \"",[415,772,773],{"class":537},"TEAM_PING",[415,775,576],{"class":524},[415,777,456],{"class":440},[415,779,780],{"class":494}," content",[415,782,449],{"class":440},[415,784,770],{"class":524},[415,786,787],{"class":537},"New task created on the board!",[415,789,576],{"class":524},[415,791,725],{"class":440},[415,793,466],{"class":494},[415,795,511],{"class":440},[415,797,798],{"class":417,"line":626},[415,799,656],{"class":440},[415,801,802,805,807],{"class":417,"line":653},[415,803,804],{"class":440},"\u003C\u002F",[415,806,681],{"class":680},[415,808,701],{"class":440},[415,810,812],{"class":417,"line":811},8,[415,813,740],{"emptyLinePlaceholder":22},[415,815,817,819,822],{"class":417,"line":816},9,[415,818,677],{"class":440},[415,820,821],{"class":680},"template",[415,823,701],{"class":440},[415,825,827,830,833],{"class":417,"line":826},10,[415,828,829],{"class":440},"  \u003C",[415,831,832],{"class":680},"div",[415,834,701],{"class":440},[415,836,838,841,844,847,850,852,855,858,861,864,867,870,873,875,878,880,882,884,887,889,891],{"class":417,"line":837},11,[415,839,840],{"class":440},"    \u003C",[415,842,843],{"class":680},"UBadge",[415,845,846],{"class":440}," :",[415,848,849],{"class":684},"color",[415,851,691],{"class":440},[415,853,576],{"class":854},"s00De",[415,856,857],{"class":485},"status",[415,859,860],{"class":448}," ===",[415,862,863],{"class":524}," '",[415,865,866],{"class":537},"OPEN",[415,868,869],{"class":524},"'",[415,871,872],{"class":448}," ?",[415,874,863],{"class":524},[415,876,877],{"class":537},"success",[415,879,869],{"class":524},[415,881,846],{"class":448},[415,883,863],{"class":524},[415,885,886],{"class":537},"neutral",[415,888,869],{"class":524},[415,890,576],{"class":854},[415,892,701],{"class":440},[415,894,896],{"class":417,"line":895},12,[415,897,898],{"class":485},"      {{ status === 'OPEN' ? 'Real Time Active' : 'Reconnecting...' }}\n",[415,900,902,905,907],{"class":417,"line":901},13,[415,903,904],{"class":440},"    \u003C\u002F",[415,906,843],{"class":680},[415,908,701],{"class":440},[415,910,912,914,916,919,921,923,926,928,931,933,935,938,940],{"class":417,"line":911},14,[415,913,840],{"class":440},[415,915,832],{"class":680},[415,917,918],{"class":684}," v-for",[415,920,691],{"class":440},[415,922,576],{"class":524},[415,924,925],{"class":537},"msg in messages",[415,927,576],{"class":524},[415,929,930],{"class":684}," :key",[415,932,691],{"class":440},[415,934,576],{"class":524},[415,936,937],{"class":537},"msg.id",[415,939,576],{"class":524},[415,941,701],{"class":440},[415,943,945],{"class":417,"line":944},15,[415,946,947],{"class":485},"      {{ msg.content }}\n",[415,949,951,953,955],{"class":417,"line":950},16,[415,952,904],{"class":440},[415,954,832],{"class":680},[415,956,701],{"class":440},[415,958,960,963,965],{"class":417,"line":959},17,[415,961,962],{"class":440},"  \u003C\u002F",[415,964,832],{"class":680},[415,966,701],{"class":440},[415,968,970,972,974],{"class":417,"line":969},18,[415,971,804],{"class":440},[415,973,821],{"class":680},[415,975,701],{"class":440},[352,977],{},[355,979,981],{"id":980},"conclusion-enterprise-grade-real-time-within-your-reach","Conclusion: Enterprise-Grade Real Time Within Your Reach",[320,983,984],{},"With Durable Objects, you completely eliminate the costs of Redis and Socket.io servers, taking advantage of Cloudflare's global network to deliver an ultra-fast experience to your users.",[320,986,987,988,350],{},"This whole flow — from the backend workers to Nuxt's reactive composables — already comes 100% implemented and tested in ",[343,989,345],{},[320,991,992],{},[993,994,996],"a",{"href":995},"\u002F#pricing",[343,997,998],{},"Get your lifetime license and download the code right now →",[1000,1001,1002],"style",{},"html pre.shiki code .ss7Ak, html code.shiki .ss7Ak{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html pre.shiki code .sRxSC, html code.shiki .sRxSC{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html pre.shiki code .srJo8, html code.shiki .srJo8{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .sD0ED, html code.shiki .sD0ED{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .swvn1, html code.shiki .swvn1{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sQgqH, html code.shiki .sQgqH{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit;--shiki-sepia:#FD971F;--shiki-sepia-font-style:italic}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .s_MOj, html code.shiki .s_MOj{--shiki-light:#E2931D;--shiki-light-font-style:inherit;--shiki-default:#005CC5;--shiki-default-font-style:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .s91G_, html code.shiki .s91G_{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#F8F8F2}html pre.shiki code .ss--_, html code.shiki .ss--_{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .squCx, html code.shiki .squCx{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sYThS, html code.shiki .sYThS{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .slF1C, html code.shiki .slF1C{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#F92672}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}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);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sHsBP, html code.shiki .sHsBP{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D;--shiki-sepia:#F92672}html pre.shiki code .s_lYk, html code.shiki .s_lYk{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .s00De, html code.shiki .s00De{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#F8F8F2}",{"title":383,"searchDepth":425,"depth":425,"links":1004},[1005,1006,1007,1008],{"id":357,"depth":425,"text":358},{"id":388,"depth":425,"text":389},{"id":661,"depth":425,"text":662},{"id":980,"depth":425,"text":981},"Real-Time & WebSockets","2026-09-15","Discover how to build instant notifications and multi-user collaboration without dedicated Socket.io servers or expensive Redis instances, using Durable Objects.","md","\u002Fimages\u002Fblog\u002Fwebsockets-durable-objects-en.svg","en",{},"\u002Fimages\u002Fblog\u002Fwebsockets-durable-objects-en.png","\u002Fblog\u002Frealtime-websockets-durable-objects","6 min",{"title":313,"description":1011},"blog\u002Frealtime-websockets-durable-objects",[78,1022,1023,1024],"Durable Objects","Cloudflare","Real-Time",{"en":1026,"pt-br":1027,"es":1028},"realtime-websockets-durable-objects","websockets-durable-objects-tempo-real","websockets-durable-objects-tiempo-real","BcxUUs6dxhgsJDCN4XXh3MyQB6YpJiP_VDm09IHqv1E",1790707503359]