[{"data":1,"prerenderedAt":1971},["ShallowReactive",2],{"docs:/docs/high-level-sdks/collab":3},{"id":4,"title":5,"body":6,"description":1964,"extension":1965,"meta":1966,"navigation":260,"path":1967,"seo":1968,"stem":1969,"__hash__":1970},"docs/docs/high-level-sdks/collab.md","Collab SDK",{"type":7,"value":8,"toc":1950},"minimark",[9,14,18,23,39,44,69,73,106,153,157,189,212,216,1338,1342,1345,1350,1546,1619,1623,1723,1726,1826,1830,1946],[10,11,13],"h1",{"id":12},"nolagcollab","@nolag/collab",[15,16,17],"p",{},"Real-time collaboration with operations, cursor tracking, and idle awareness.",[19,20,22],"h2",{"id":21},"overview","Overview",[15,24,25,26,30,31,34,35,38],{},"Add real-time collaboration to any editor or canvas. Operations (insert, delete, replace, format, or custom domain types) are broadcast to all document participants and stored for 24-hour replay. Cursor positions are synchronised via a throttled ephemeral channel so other participants see where each user is working without generating durable storage traffic. Users are automatically marked ",[27,28,29],"code",{},"idle"," by the SDK after a configurable period of no cursor activity, and marked ",[27,32,33],{},"editing"," again on the next cursor update. Each joined document is an independent collaboration session; join multiple documents for multi-tab or split-pane editors. Your app owns one core NoLag client and injects it into ",[27,36,37],{},"NoLagCollab","; the wrapper attaches its behaviour to that connection.",[40,41,43],"h3",{"id":42},"key-features","Key Features",[45,46,47,51,54,57,60,63,66],"ul",{},[48,49,50],"li",{},"Five built-in operation types: insert, delete, replace, format, and custom",[48,52,53],{},"24-hour operation history with replay on reconnect",[48,55,56],{},"Throttled ephemeral cursor sync with configurable interval",[48,58,59],{},"Automatic idle detection after configurable inactivity timeout",[48,61,62],{},"User online/offline presence via lobby",[48,64,65],{},"Per-document user join/leave events",[48,67,68],{},"Multiple documents per connection",[19,70,72],{"id":71},"how-it-works","How It Works",[15,74,75,77,78,81,82,85,86,89,90,93,94,97,98,101,102,105],{},[27,76,37],{}," attaches to an injected ",[27,79,80],{},"@nolag/js-sdk"," client and maintains a lobby for user presence. Calling ",[27,83,84],{},"joinDocument(name)"," returns a ",[27,87,88],{},"CollabDocument"," that subscribes to two topics: ",[27,91,92],{},"operations"," for durable operation history and ",[27,95,96],{},"_cursors"," for ephemeral cursor position updates. The SDK throttles outbound cursor messages to ",[27,99,100],{},"cursorThrottle"," (default 50 ms) and starts an idle timer that resets on every cursor update. When the timer fires the SDK emits ",[27,103,104],{},"awarenessChanged"," locally and broadcasts the idle status to other participants. The app owns the socket lifecycle; the wrapper never opens or closes it.",[107,108,109,125],"table",{},[110,111,112],"thead",{},[113,114,115,119,122],"tr",{},[116,117,118],"th",{},"Topic",[116,120,121],{},"Purpose",[116,123,124],{},"Replay",[126,127,128,141],"tbody",{},[113,129,130,135,138],{},[131,132,133],"td",{},[27,134,92],{},[131,136,137],{},"Document operations: insert, delete, replace, format, custom",[131,139,140],{},"24 hours",[113,142,143,147,150],{},[131,144,145],{},[27,146,96],{},[131,148,149],{},"Real-time cursor positions and awareness status (not persisted)",[131,151,152],{},"Ephemeral",[19,154,156],{"id":155},"installation","Installation",[158,159,160],"code-tabs",{},[161,162,168],"pre",{"className":163,"code":164,"filename":165,"language":166,"meta":167,"style":167},"language-bash shiki shiki-themes github-light github-dark","npm install @nolag/collab @nolag/js-sdk\n","Terminal","bash","",[27,169,170],{"__ignoreMap":167},[171,172,175,179,183,186],"span",{"class":173,"line":174},"line",1,[171,176,178],{"class":177},"sScJk","npm",[171,180,182],{"class":181},"sZZnC"," install",[171,184,185],{"class":181}," @nolag/collab",[171,187,188],{"class":181}," @nolag/js-sdk\n",[190,191,193],"note",{"title":192},"Shared connection",[15,194,195,196,199,200,203,204,207,208,211],{},"One core NoLag client can back several wrapper SDKs at once, for example collaboration, chat, and notify on a single socket, as long as each wrapper uses a distinct ",[27,197,198],{},"appName",". Each wrapper attaches its handlers on construction and releases them with ",[27,201,202],{},"detach()",", and never touches the socket itself. Your app owns ",[27,205,206],{},"connect()"," and ",[27,209,210],{},"disconnect()",".",[19,213,215],{"id":214},"quick-start","Quick Start",[158,217,218],{},[161,219,224],{"className":220,"code":221,"filename":222,"language":223,"meta":167,"style":167},"language-typescript shiki shiki-themes github-light github-dark","import { NoLag } from '@nolag/js-sdk'\nimport { NoLagCollab } from '@nolag/collab'\n\n// The app owns one core client. In a browser, pass a token provider so the\n// SDK can mint fresh short-lived client tokens from your backend.\nconst client = NoLag(async () => (await (await fetch('/api/nolag-token')).json()).token)\n\n// Inject the client into the collab wrapper\nconst collab = new NoLagCollab({\n  client,\n  username: 'Alice',\n  idleTimeout: 30_000,       // Mark user idle after 30 s without cursor activity\n  cursorThrottle: 50,        // Throttle cursor updates (default 50 ms)\n})\n\nawait client.connect()   // the app owns the connection\nawait collab.ready()     // wrapper setup complete\n\n// Join a document (each document is a separate collaboration session)\nconst doc = await collab.joinDocument('doc-proposal-q3')\n\n// ── Operations ────────────────────────────────────────────────────────────────\n\n// Send an insert operation\ndoc.sendOperation('insert', {\n  position: 42,\n  content: 'Hello, world!',\n})\n\n// Send a delete operation\ndoc.sendOperation('delete', {\n  position: 42,\n  length: 13,\n})\n\n// Send a format operation\ndoc.sendOperation('format', {\n  position: 10,\n  length: 5,\n  attributes: { bold: true },\n})\n\n// Send a custom operation (any domain-specific action)\ndoc.sendOperation('custom', {\n  type: 'highlight',\n  color: '#ffcc00',\n  range: { start: 0, end: 20 },\n})\n\n// Retrieve stored operations (replayed from last 24 hours on reconnect)\nconst ops = await doc.getOperations()\nconsole.log(`${ops.length} operations in history`)\n\n// React to operations from other users\ndoc.on('operation', ({ userId, type, opts, timestamp }) => {\n  console.log(`User ${userId} sent ${type} op`, opts)\n})\n\n// ── Cursors ───────────────────────────────────────────────────────────────────\n\n// Broadcast cursor position (throttled to cursorThrottle)\ndoc.updateCursor({ position: 42, line: 3, column: 8 })\n\n// Read all cursors from local cache\nconst cursors = doc.getCursors()\nconsole.log('Active cursors:', cursors.length)\n\n// React to cursor moves from other users\ndoc.on('cursorMoved', ({ userId, position, line, column }) => {\n  renderCursor(userId, { line, column })\n})\n\n// ── Awareness ─────────────────────────────────────────────────────────────────\n\n// Update own status\ndoc.setStatus('editing')  // 'editing' | 'idle' | 'away'\n\n// React to status changes (idle is set automatically by the SDK)\ndoc.on('awarenessChanged', ({ userId, status }) => {\n  console.log(`User ${userId} is now ${status}`)\n})\n\n// ── Presence ──────────────────────────────────────────────────────────────────\n\ncollab.on('userOnline', ({ userId }) => console.log('Joined lobby:', userId))\ncollab.on('userOffline', ({ userId }) => console.log('Left lobby:', userId))\n\ndoc.on('userJoined', ({ userId }) => console.log('Joined document:', userId))\ndoc.on('userLeft', ({ userId }) => console.log('Left document:', userId))\n\n// ── Teardown ──────────────────────────────────────────────────────────────────\n\n// The wrapper releases its handlers; the app closes the socket.\ncollab.detach()\nclient.disconnect()\n","TypeScript","typescript",[27,225,226,242,255,262,269,275,330,335,341,360,366,378,393,408,414,419,436,453,458,464,490,495,501,506,512,529,540,551,556,561,567,581,590,601,606,611,617,631,641,651,663,668,673,679,693,704,715,732,737,742,748,769,796,801,807,851,877,882,887,893,898,904,932,937,943,960,979,984,990,1026,1035,1040,1045,1051,1056,1062,1081,1086,1092,1119,1142,1147,1152,1158,1163,1197,1228,1233,1264,1295,1300,1306,1311,1317,1327],{"__ignoreMap":167},[171,227,228,232,236,239],{"class":173,"line":174},[171,229,231],{"class":230},"szBVR","import",[171,233,235],{"class":234},"sVt8B"," { NoLag } ",[171,237,238],{"class":230},"from",[171,240,241],{"class":181}," '@nolag/js-sdk'\n",[171,243,245,247,250,252],{"class":173,"line":244},2,[171,246,231],{"class":230},[171,248,249],{"class":234}," { NoLagCollab } ",[171,251,238],{"class":230},[171,253,254],{"class":181}," '@nolag/collab'\n",[171,256,258],{"class":173,"line":257},3,[171,259,261],{"emptyLinePlaceholder":260},true,"\n",[171,263,265],{"class":173,"line":264},4,[171,266,268],{"class":267},"sJ8bj","// The app owns one core client. In a browser, pass a token provider so the\n",[171,270,272],{"class":173,"line":271},5,[171,273,274],{"class":267},"// SDK can mint fresh short-lived client tokens from your backend.\n",[171,276,278,281,285,288,291,294,297,300,303,306,309,311,313,316,318,321,324,327],{"class":173,"line":277},6,[171,279,280],{"class":230},"const",[171,282,284],{"class":283},"sj4cs"," client",[171,286,287],{"class":230}," =",[171,289,290],{"class":177}," NoLag",[171,292,293],{"class":234},"(",[171,295,296],{"class":230},"async",[171,298,299],{"class":234}," () ",[171,301,302],{"class":230},"=>",[171,304,305],{"class":234}," (",[171,307,308],{"class":230},"await",[171,310,305],{"class":234},[171,312,308],{"class":230},[171,314,315],{"class":177}," fetch",[171,317,293],{"class":234},[171,319,320],{"class":181},"'/api/nolag-token'",[171,322,323],{"class":234},")).",[171,325,326],{"class":177},"json",[171,328,329],{"class":234},"()).token)\n",[171,331,333],{"class":173,"line":332},7,[171,334,261],{"emptyLinePlaceholder":260},[171,336,338],{"class":173,"line":337},8,[171,339,340],{"class":267},"// Inject the client into the collab wrapper\n",[171,342,344,346,349,351,354,357],{"class":173,"line":343},9,[171,345,280],{"class":230},[171,347,348],{"class":283}," collab",[171,350,287],{"class":230},[171,352,353],{"class":230}," new",[171,355,356],{"class":177}," NoLagCollab",[171,358,359],{"class":234},"({\n",[171,361,363],{"class":173,"line":362},10,[171,364,365],{"class":234},"  client,\n",[171,367,369,372,375],{"class":173,"line":368},11,[171,370,371],{"class":234},"  username: ",[171,373,374],{"class":181},"'Alice'",[171,376,377],{"class":234},",\n",[171,379,381,384,387,390],{"class":173,"line":380},12,[171,382,383],{"class":234},"  idleTimeout: ",[171,385,386],{"class":283},"30_000",[171,388,389],{"class":234},",       ",[171,391,392],{"class":267},"// Mark user idle after 30 s without cursor activity\n",[171,394,396,399,402,405],{"class":173,"line":395},13,[171,397,398],{"class":234},"  cursorThrottle: ",[171,400,401],{"class":283},"50",[171,403,404],{"class":234},",        ",[171,406,407],{"class":267},"// Throttle cursor updates (default 50 ms)\n",[171,409,411],{"class":173,"line":410},14,[171,412,413],{"class":234},"})\n",[171,415,417],{"class":173,"line":416},15,[171,418,261],{"emptyLinePlaceholder":260},[171,420,422,424,427,430,433],{"class":173,"line":421},16,[171,423,308],{"class":230},[171,425,426],{"class":234}," client.",[171,428,429],{"class":177},"connect",[171,431,432],{"class":234},"()   ",[171,434,435],{"class":267},"// the app owns the connection\n",[171,437,439,441,444,447,450],{"class":173,"line":438},17,[171,440,308],{"class":230},[171,442,443],{"class":234}," collab.",[171,445,446],{"class":177},"ready",[171,448,449],{"class":234},"()     ",[171,451,452],{"class":267},"// wrapper setup complete\n",[171,454,456],{"class":173,"line":455},18,[171,457,261],{"emptyLinePlaceholder":260},[171,459,461],{"class":173,"line":460},19,[171,462,463],{"class":267},"// Join a document (each document is a separate collaboration session)\n",[171,465,467,469,472,474,477,479,482,484,487],{"class":173,"line":466},20,[171,468,280],{"class":230},[171,470,471],{"class":283}," doc",[171,473,287],{"class":230},[171,475,476],{"class":230}," await",[171,478,443],{"class":234},[171,480,481],{"class":177},"joinDocument",[171,483,293],{"class":234},[171,485,486],{"class":181},"'doc-proposal-q3'",[171,488,489],{"class":234},")\n",[171,491,493],{"class":173,"line":492},21,[171,494,261],{"emptyLinePlaceholder":260},[171,496,498],{"class":173,"line":497},22,[171,499,500],{"class":267},"// ── Operations ────────────────────────────────────────────────────────────────\n",[171,502,504],{"class":173,"line":503},23,[171,505,261],{"emptyLinePlaceholder":260},[171,507,509],{"class":173,"line":508},24,[171,510,511],{"class":267},"// Send an insert operation\n",[171,513,515,518,521,523,526],{"class":173,"line":514},25,[171,516,517],{"class":234},"doc.",[171,519,520],{"class":177},"sendOperation",[171,522,293],{"class":234},[171,524,525],{"class":181},"'insert'",[171,527,528],{"class":234},", {\n",[171,530,532,535,538],{"class":173,"line":531},26,[171,533,534],{"class":234},"  position: ",[171,536,537],{"class":283},"42",[171,539,377],{"class":234},[171,541,543,546,549],{"class":173,"line":542},27,[171,544,545],{"class":234},"  content: ",[171,547,548],{"class":181},"'Hello, world!'",[171,550,377],{"class":234},[171,552,554],{"class":173,"line":553},28,[171,555,413],{"class":234},[171,557,559],{"class":173,"line":558},29,[171,560,261],{"emptyLinePlaceholder":260},[171,562,564],{"class":173,"line":563},30,[171,565,566],{"class":267},"// Send a delete operation\n",[171,568,570,572,574,576,579],{"class":173,"line":569},31,[171,571,517],{"class":234},[171,573,520],{"class":177},[171,575,293],{"class":234},[171,577,578],{"class":181},"'delete'",[171,580,528],{"class":234},[171,582,584,586,588],{"class":173,"line":583},32,[171,585,534],{"class":234},[171,587,537],{"class":283},[171,589,377],{"class":234},[171,591,593,596,599],{"class":173,"line":592},33,[171,594,595],{"class":234},"  length: ",[171,597,598],{"class":283},"13",[171,600,377],{"class":234},[171,602,604],{"class":173,"line":603},34,[171,605,413],{"class":234},[171,607,609],{"class":173,"line":608},35,[171,610,261],{"emptyLinePlaceholder":260},[171,612,614],{"class":173,"line":613},36,[171,615,616],{"class":267},"// Send a format operation\n",[171,618,620,622,624,626,629],{"class":173,"line":619},37,[171,621,517],{"class":234},[171,623,520],{"class":177},[171,625,293],{"class":234},[171,627,628],{"class":181},"'format'",[171,630,528],{"class":234},[171,632,634,636,639],{"class":173,"line":633},38,[171,635,534],{"class":234},[171,637,638],{"class":283},"10",[171,640,377],{"class":234},[171,642,644,646,649],{"class":173,"line":643},39,[171,645,595],{"class":234},[171,647,648],{"class":283},"5",[171,650,377],{"class":234},[171,652,654,657,660],{"class":173,"line":653},40,[171,655,656],{"class":234},"  attributes: { bold: ",[171,658,659],{"class":283},"true",[171,661,662],{"class":234}," },\n",[171,664,666],{"class":173,"line":665},41,[171,667,413],{"class":234},[171,669,671],{"class":173,"line":670},42,[171,672,261],{"emptyLinePlaceholder":260},[171,674,676],{"class":173,"line":675},43,[171,677,678],{"class":267},"// Send a custom operation (any domain-specific action)\n",[171,680,682,684,686,688,691],{"class":173,"line":681},44,[171,683,517],{"class":234},[171,685,520],{"class":177},[171,687,293],{"class":234},[171,689,690],{"class":181},"'custom'",[171,692,528],{"class":234},[171,694,696,699,702],{"class":173,"line":695},45,[171,697,698],{"class":234},"  type: ",[171,700,701],{"class":181},"'highlight'",[171,703,377],{"class":234},[171,705,707,710,713],{"class":173,"line":706},46,[171,708,709],{"class":234},"  color: ",[171,711,712],{"class":181},"'#ffcc00'",[171,714,377],{"class":234},[171,716,718,721,724,727,730],{"class":173,"line":717},47,[171,719,720],{"class":234},"  range: { start: ",[171,722,723],{"class":283},"0",[171,725,726],{"class":234},", end: ",[171,728,729],{"class":283},"20",[171,731,662],{"class":234},[171,733,735],{"class":173,"line":734},48,[171,736,413],{"class":234},[171,738,740],{"class":173,"line":739},49,[171,741,261],{"emptyLinePlaceholder":260},[171,743,745],{"class":173,"line":744},50,[171,746,747],{"class":267},"// Retrieve stored operations (replayed from last 24 hours on reconnect)\n",[171,749,751,753,756,758,760,763,766],{"class":173,"line":750},51,[171,752,280],{"class":230},[171,754,755],{"class":283}," ops",[171,757,287],{"class":230},[171,759,476],{"class":230},[171,761,762],{"class":234}," doc.",[171,764,765],{"class":177},"getOperations",[171,767,768],{"class":234},"()\n",[171,770,772,775,778,780,783,786,788,791,794],{"class":173,"line":771},52,[171,773,774],{"class":234},"console.",[171,776,777],{"class":177},"log",[171,779,293],{"class":234},[171,781,782],{"class":181},"`${",[171,784,785],{"class":234},"ops",[171,787,211],{"class":181},[171,789,790],{"class":283},"length",[171,792,793],{"class":181},"} operations in history`",[171,795,489],{"class":234},[171,797,799],{"class":173,"line":798},53,[171,800,261],{"emptyLinePlaceholder":260},[171,802,804],{"class":173,"line":803},54,[171,805,806],{"class":267},"// React to operations from other users\n",[171,808,810,812,815,817,820,823,827,830,833,835,838,840,843,846,848],{"class":173,"line":809},55,[171,811,517],{"class":234},[171,813,814],{"class":177},"on",[171,816,293],{"class":234},[171,818,819],{"class":181},"'operation'",[171,821,822],{"class":234},", ({ ",[171,824,826],{"class":825},"s4XuR","userId",[171,828,829],{"class":234},", ",[171,831,832],{"class":825},"type",[171,834,829],{"class":234},[171,836,837],{"class":825},"opts",[171,839,829],{"class":234},[171,841,842],{"class":825},"timestamp",[171,844,845],{"class":234}," }) ",[171,847,302],{"class":230},[171,849,850],{"class":234}," {\n",[171,852,854,857,859,861,864,866,869,871,874],{"class":173,"line":853},56,[171,855,856],{"class":234},"  console.",[171,858,777],{"class":177},[171,860,293],{"class":234},[171,862,863],{"class":181},"`User ${",[171,865,826],{"class":234},[171,867,868],{"class":181},"} sent ${",[171,870,832],{"class":234},[171,872,873],{"class":181},"} op`",[171,875,876],{"class":234},", opts)\n",[171,878,880],{"class":173,"line":879},57,[171,881,413],{"class":234},[171,883,885],{"class":173,"line":884},58,[171,886,261],{"emptyLinePlaceholder":260},[171,888,890],{"class":173,"line":889},59,[171,891,892],{"class":267},"// ── Cursors ───────────────────────────────────────────────────────────────────\n",[171,894,896],{"class":173,"line":895},60,[171,897,261],{"emptyLinePlaceholder":260},[171,899,901],{"class":173,"line":900},61,[171,902,903],{"class":267},"// Broadcast cursor position (throttled to cursorThrottle)\n",[171,905,907,909,912,915,917,920,923,926,929],{"class":173,"line":906},62,[171,908,517],{"class":234},[171,910,911],{"class":177},"updateCursor",[171,913,914],{"class":234},"({ position: ",[171,916,537],{"class":283},[171,918,919],{"class":234},", line: ",[171,921,922],{"class":283},"3",[171,924,925],{"class":234},", column: ",[171,927,928],{"class":283},"8",[171,930,931],{"class":234}," })\n",[171,933,935],{"class":173,"line":934},63,[171,936,261],{"emptyLinePlaceholder":260},[171,938,940],{"class":173,"line":939},64,[171,941,942],{"class":267},"// Read all cursors from local cache\n",[171,944,946,948,951,953,955,958],{"class":173,"line":945},65,[171,947,280],{"class":230},[171,949,950],{"class":283}," cursors",[171,952,287],{"class":230},[171,954,762],{"class":234},[171,956,957],{"class":177},"getCursors",[171,959,768],{"class":234},[171,961,963,965,967,969,972,975,977],{"class":173,"line":962},66,[171,964,774],{"class":234},[171,966,777],{"class":177},[171,968,293],{"class":234},[171,970,971],{"class":181},"'Active cursors:'",[171,973,974],{"class":234},", cursors.",[171,976,790],{"class":283},[171,978,489],{"class":234},[171,980,982],{"class":173,"line":981},67,[171,983,261],{"emptyLinePlaceholder":260},[171,985,987],{"class":173,"line":986},68,[171,988,989],{"class":267},"// React to cursor moves from other users\n",[171,991,993,995,997,999,1002,1004,1006,1008,1011,1013,1015,1017,1020,1022,1024],{"class":173,"line":992},69,[171,994,517],{"class":234},[171,996,814],{"class":177},[171,998,293],{"class":234},[171,1000,1001],{"class":181},"'cursorMoved'",[171,1003,822],{"class":234},[171,1005,826],{"class":825},[171,1007,829],{"class":234},[171,1009,1010],{"class":825},"position",[171,1012,829],{"class":234},[171,1014,173],{"class":825},[171,1016,829],{"class":234},[171,1018,1019],{"class":825},"column",[171,1021,845],{"class":234},[171,1023,302],{"class":230},[171,1025,850],{"class":234},[171,1027,1029,1032],{"class":173,"line":1028},70,[171,1030,1031],{"class":177},"  renderCursor",[171,1033,1034],{"class":234},"(userId, { line, column })\n",[171,1036,1038],{"class":173,"line":1037},71,[171,1039,413],{"class":234},[171,1041,1043],{"class":173,"line":1042},72,[171,1044,261],{"emptyLinePlaceholder":260},[171,1046,1048],{"class":173,"line":1047},73,[171,1049,1050],{"class":267},"// ── Awareness ─────────────────────────────────────────────────────────────────\n",[171,1052,1054],{"class":173,"line":1053},74,[171,1055,261],{"emptyLinePlaceholder":260},[171,1057,1059],{"class":173,"line":1058},75,[171,1060,1061],{"class":267},"// Update own status\n",[171,1063,1065,1067,1070,1072,1075,1078],{"class":173,"line":1064},76,[171,1066,517],{"class":234},[171,1068,1069],{"class":177},"setStatus",[171,1071,293],{"class":234},[171,1073,1074],{"class":181},"'editing'",[171,1076,1077],{"class":234},")  ",[171,1079,1080],{"class":267},"// 'editing' | 'idle' | 'away'\n",[171,1082,1084],{"class":173,"line":1083},77,[171,1085,261],{"emptyLinePlaceholder":260},[171,1087,1089],{"class":173,"line":1088},78,[171,1090,1091],{"class":267},"// React to status changes (idle is set automatically by the SDK)\n",[171,1093,1095,1097,1099,1101,1104,1106,1108,1110,1113,1115,1117],{"class":173,"line":1094},79,[171,1096,517],{"class":234},[171,1098,814],{"class":177},[171,1100,293],{"class":234},[171,1102,1103],{"class":181},"'awarenessChanged'",[171,1105,822],{"class":234},[171,1107,826],{"class":825},[171,1109,829],{"class":234},[171,1111,1112],{"class":825},"status",[171,1114,845],{"class":234},[171,1116,302],{"class":230},[171,1118,850],{"class":234},[171,1120,1122,1124,1126,1128,1130,1132,1135,1137,1140],{"class":173,"line":1121},80,[171,1123,856],{"class":234},[171,1125,777],{"class":177},[171,1127,293],{"class":234},[171,1129,863],{"class":181},[171,1131,826],{"class":234},[171,1133,1134],{"class":181},"} is now ${",[171,1136,1112],{"class":234},[171,1138,1139],{"class":181},"}`",[171,1141,489],{"class":234},[171,1143,1145],{"class":173,"line":1144},81,[171,1146,413],{"class":234},[171,1148,1150],{"class":173,"line":1149},82,[171,1151,261],{"emptyLinePlaceholder":260},[171,1153,1155],{"class":173,"line":1154},83,[171,1156,1157],{"class":267},"// ── Presence ──────────────────────────────────────────────────────────────────\n",[171,1159,1161],{"class":173,"line":1160},84,[171,1162,261],{"emptyLinePlaceholder":260},[171,1164,1166,1169,1171,1173,1176,1178,1180,1182,1184,1187,1189,1191,1194],{"class":173,"line":1165},85,[171,1167,1168],{"class":234},"collab.",[171,1170,814],{"class":177},[171,1172,293],{"class":234},[171,1174,1175],{"class":181},"'userOnline'",[171,1177,822],{"class":234},[171,1179,826],{"class":825},[171,1181,845],{"class":234},[171,1183,302],{"class":230},[171,1185,1186],{"class":234}," console.",[171,1188,777],{"class":177},[171,1190,293],{"class":234},[171,1192,1193],{"class":181},"'Joined lobby:'",[171,1195,1196],{"class":234},", userId))\n",[171,1198,1200,1202,1204,1206,1209,1211,1213,1215,1217,1219,1221,1223,1226],{"class":173,"line":1199},86,[171,1201,1168],{"class":234},[171,1203,814],{"class":177},[171,1205,293],{"class":234},[171,1207,1208],{"class":181},"'userOffline'",[171,1210,822],{"class":234},[171,1212,826],{"class":825},[171,1214,845],{"class":234},[171,1216,302],{"class":230},[171,1218,1186],{"class":234},[171,1220,777],{"class":177},[171,1222,293],{"class":234},[171,1224,1225],{"class":181},"'Left lobby:'",[171,1227,1196],{"class":234},[171,1229,1231],{"class":173,"line":1230},87,[171,1232,261],{"emptyLinePlaceholder":260},[171,1234,1236,1238,1240,1242,1245,1247,1249,1251,1253,1255,1257,1259,1262],{"class":173,"line":1235},88,[171,1237,517],{"class":234},[171,1239,814],{"class":177},[171,1241,293],{"class":234},[171,1243,1244],{"class":181},"'userJoined'",[171,1246,822],{"class":234},[171,1248,826],{"class":825},[171,1250,845],{"class":234},[171,1252,302],{"class":230},[171,1254,1186],{"class":234},[171,1256,777],{"class":177},[171,1258,293],{"class":234},[171,1260,1261],{"class":181},"'Joined document:'",[171,1263,1196],{"class":234},[171,1265,1267,1269,1271,1273,1276,1278,1280,1282,1284,1286,1288,1290,1293],{"class":173,"line":1266},89,[171,1268,517],{"class":234},[171,1270,814],{"class":177},[171,1272,293],{"class":234},[171,1274,1275],{"class":181},"'userLeft'",[171,1277,822],{"class":234},[171,1279,826],{"class":825},[171,1281,845],{"class":234},[171,1283,302],{"class":230},[171,1285,1186],{"class":234},[171,1287,777],{"class":177},[171,1289,293],{"class":234},[171,1291,1292],{"class":181},"'Left document:'",[171,1294,1196],{"class":234},[171,1296,1298],{"class":173,"line":1297},90,[171,1299,261],{"emptyLinePlaceholder":260},[171,1301,1303],{"class":173,"line":1302},91,[171,1304,1305],{"class":267},"// ── Teardown ──────────────────────────────────────────────────────────────────\n",[171,1307,1309],{"class":173,"line":1308},92,[171,1310,261],{"emptyLinePlaceholder":260},[171,1312,1314],{"class":173,"line":1313},93,[171,1315,1316],{"class":267},"// The wrapper releases its handlers; the app closes the socket.\n",[171,1318,1320,1322,1325],{"class":173,"line":1319},94,[171,1321,1168],{"class":234},[171,1323,1324],{"class":177},"detach",[171,1326,768],{"class":234},[171,1328,1330,1333,1336],{"class":173,"line":1329},95,[171,1331,1332],{"class":234},"client.",[171,1334,1335],{"class":177},"disconnect",[171,1337,768],{"class":234},[19,1339,1341],{"id":1340},"api-reference","API Reference",[40,1343,37],{"id":1344},"nolagcollab-1",[1346,1347,1349],"h4",{"id":1348},"constructor-options","Constructor Options",[107,1351,1352,1365],{},[110,1353,1354],{},[113,1355,1356,1359,1362],{},[116,1357,1358],{},"Option",[116,1360,1361],{},"Type",[116,1363,1364],{},"Description",[126,1366,1367,1386,1403,1417,1431,1446,1463,1478,1496,1513,1528],{},[113,1368,1369,1374,1379],{},[131,1370,1371],{},[27,1372,1373],{},"client",[131,1375,1376],{},[27,1377,1378],{},"NoLagSocket",[131,1380,1381,1385],{},[1382,1383,1384],"strong",{},"Required."," The injected core NoLag client the app owns and connects.",[113,1387,1388,1393,1398],{},[131,1389,1390],{},[27,1391,1392],{},"username",[131,1394,1395],{},[27,1396,1397],{},"string",[131,1399,1400,1402],{},[1382,1401,1384],{}," Display name for the local user.",[113,1404,1405,1410,1414],{},[131,1406,1407],{},[27,1408,1409],{},"avatar",[131,1411,1412],{},[27,1413,1397],{},[131,1415,1416],{},"Optional avatar URL.",[113,1418,1419,1424,1428],{},[131,1420,1421],{},[27,1422,1423],{},"color",[131,1425,1426],{},[27,1427,1397],{},[131,1429,1430],{},"Optional cursor/highlight colour.",[113,1432,1433,1438,1443],{},[131,1434,1435],{},[27,1436,1437],{},"metadata",[131,1439,1440],{},[27,1441,1442],{},"Record\u003Cstring, unknown>",[131,1444,1445],{},"Optional custom data attached to user presence.",[113,1447,1448,1452,1456],{},[131,1449,1450],{},[27,1451,198],{},[131,1453,1454],{},[27,1455,1397],{},[131,1457,1458,1459,1462],{},"NoLag app for topic prefixes (default ",[27,1460,1461],{},"'collab'",").",[113,1464,1465,1470,1475],{},[131,1466,1467],{},[27,1468,1469],{},"documents",[131,1471,1472],{},[27,1473,1474],{},"string[]",[131,1476,1477],{},"Documents to auto-join once the wrapper is ready.",[113,1479,1480,1485,1490],{},[131,1481,1482],{},[27,1483,1484],{},"maxOperationCache",[131,1486,1487],{},[27,1488,1489],{},"number",[131,1491,1492,1493,1462],{},"Max operations cached per document (default ",[27,1494,1495],{},"1000",[113,1497,1498,1503,1507],{},[131,1499,1500],{},[27,1501,1502],{},"idleTimeout",[131,1504,1505],{},[27,1506,1489],{},[131,1508,1509,1510,1462],{},"Ms of inactivity before a user is marked idle (default ",[27,1511,1512],{},"60000",[113,1514,1515,1519,1523],{},[131,1516,1517],{},[27,1518,100],{},[131,1520,1521],{},[27,1522,1489],{},[131,1524,1525,1526,1462],{},"Minimum ms between cursor broadcasts (default ",[27,1527,401],{},[113,1529,1530,1535,1540],{},[131,1531,1532],{},[27,1533,1534],{},"debug",[131,1536,1537],{},[27,1538,1539],{},"boolean",[131,1541,1542,1543,1462],{},"Enable wrapper debug logging (default ",[27,1544,1545],{},"false",[107,1547,1548,1560],{},[110,1549,1550],{},[113,1551,1552,1555,1558],{},[116,1553,1554],{},"Method",[116,1556,1557],{},"Returns",[116,1559,1364],{},[126,1561,1562,1577,1591,1605],{},[113,1563,1564,1569,1574],{},[131,1565,1566],{},[27,1567,1568],{},"ready()",[131,1570,1571],{},[27,1572,1573],{},"Promise\u003Cvoid>",[131,1575,1576],{},"Resolves once wrapper setup completed.",[113,1578,1579,1583,1588],{},[131,1580,1581],{},[27,1582,202],{},[131,1584,1585],{},[27,1586,1587],{},"void",[131,1589,1590],{},"Release this wrapper's handlers and topics; terminal, never closes the socket.",[113,1592,1593,1597,1602],{},[131,1594,1595],{},[27,1596,84],{},[131,1598,1599],{},[27,1600,1601],{},"Promise\u003CCollabDocument>",[131,1603,1604],{},"Subscribe to a collaboration document. Returns the document instance.",[113,1606,1607,1612,1616],{},[131,1608,1609],{},[27,1610,1611],{},"leaveDocument(name)",[131,1613,1614],{},[27,1615,1573],{},[131,1617,1618],{},"Unsubscribe from a document and release its resources.",[40,1620,1622],{"id":1621},"nolagcollab-events","NoLagCollab Events",[107,1624,1625,1637],{},[110,1626,1627],{},[113,1628,1629,1632,1635],{},[116,1630,1631],{},"Event",[116,1633,1634],{},"Payload",[116,1636,1364],{},[126,1638,1639,1652,1667,1679,1694,1709],{},[113,1640,1641,1646,1649],{},[131,1642,1643],{},[27,1644,1645],{},"connected",[131,1647,1648],{},"none",[131,1650,1651],{},"WebSocket connection established.",[113,1653,1654,1659,1664],{},[131,1655,1656],{},[27,1657,1658],{},"disconnected",[131,1660,1661],{},[27,1662,1663],{},"reason: string",[131,1665,1666],{},"Connection closed.",[113,1668,1669,1674,1676],{},[131,1670,1671],{},[27,1672,1673],{},"reconnected",[131,1675,1648],{},[131,1677,1678],{},"Connection restored; operation history replay begins automatically.",[113,1680,1681,1686,1691],{},[131,1682,1683],{},[27,1684,1685],{},"error",[131,1687,1688],{},[27,1689,1690],{},"error: Error",[131,1692,1693],{},"A transport or protocol error occurred.",[113,1695,1696,1701,1706],{},[131,1697,1698],{},[27,1699,1700],{},"userOnline",[131,1702,1703],{},[27,1704,1705],{},"{ userId: string }",[131,1707,1708],{},"A user joined the lobby.",[113,1710,1711,1716,1720],{},[131,1712,1713],{},[27,1714,1715],{},"userOffline",[131,1717,1718],{},[27,1719,1705],{},[131,1721,1722],{},"A user left the lobby.",[40,1724,88],{"id":1725},"collabdocument",[107,1727,1728,1738],{},[110,1729,1730],{},[113,1731,1732,1734,1736],{},[116,1733,1554],{},[116,1735,1557],{},[116,1737,1364],{},[126,1739,1740,1764,1779,1793,1808],{},[113,1741,1742,1747,1751],{},[131,1743,1744],{},[27,1745,1746],{},"sendOperation(type, opts?)",[131,1748,1749],{},[27,1750,1587],{},[131,1752,1753,1754,1756,1757,1760,1761,1763],{},"Broadcast an operation. ",[27,1755,832],{}," is ",[27,1758,1759],{},"'insert' | 'delete' | 'replace' | 'format' | 'custom'",". ",[27,1762,837],{}," is type-specific.",[113,1765,1766,1771,1776],{},[131,1767,1768],{},[27,1769,1770],{},"getOperations()",[131,1772,1773],{},[27,1774,1775],{},"Promise\u003COperation[]>",[131,1777,1778],{},"Fetch the stored operation history for this document (up to 24 hours).",[113,1780,1781,1786,1790],{},[131,1782,1783],{},[27,1784,1785],{},"updateCursor(opts)",[131,1787,1788],{},[27,1789,1587],{},[131,1791,1792],{},"Broadcast current cursor position. Automatically throttled. Resets the idle timer.",[113,1794,1795,1800,1805],{},[131,1796,1797],{},[27,1798,1799],{},"getCursors()",[131,1801,1802],{},[27,1803,1804],{},"Cursor[]",[131,1806,1807],{},"Return cursor positions for all active users from the local cache.",[113,1809,1810,1815,1819],{},[131,1811,1812],{},[27,1813,1814],{},"setStatus(status)",[131,1816,1817],{},[27,1818,1587],{},[131,1820,1821,1822,1825],{},"Manually set awareness status: ",[27,1823,1824],{},"'editing' | 'idle' | 'away'",". Broadcast to all participants.",[40,1827,1829],{"id":1828},"collabdocument-events","CollabDocument Events",[107,1831,1832,1842],{},[110,1833,1834],{},[113,1835,1836,1838,1840],{},[116,1837,1631],{},[116,1839,1634],{},[116,1841,1364],{},[126,1843,1844,1859,1874,1888,1902,1916,1931],{},[113,1845,1846,1851,1856],{},[131,1847,1848],{},[27,1849,1850],{},"operation",[131,1852,1853],{},[27,1854,1855],{},"{ userId, type, opts?, timestamp }",[131,1857,1858],{},"An operation was broadcast by another user.",[113,1860,1861,1866,1871],{},[131,1862,1863],{},[27,1864,1865],{},"cursorMoved",[131,1867,1868],{},[27,1869,1870],{},"{ userId, position, line?, column?, timestamp }",[131,1872,1873],{},"A user's cursor position changed. Delivered via the ephemeral channel.",[113,1875,1876,1881,1885],{},[131,1877,1878],{},[27,1879,1880],{},"userJoined",[131,1882,1883],{},[27,1884,1705],{},[131,1886,1887],{},"A user joined this document.",[113,1889,1890,1895,1899],{},[131,1891,1892],{},[27,1893,1894],{},"userLeft",[131,1896,1897],{},[27,1898,1705],{},[131,1900,1901],{},"A user left this document.",[113,1903,1904,1908,1913],{},[131,1905,1906],{},[27,1907,104],{},[131,1909,1910],{},[27,1911,1912],{},"{ userId, status: 'editing' | 'idle' | 'away' }",[131,1914,1915],{},"A user's awareness status changed. Fired locally when the idle timer elapses.",[113,1917,1918,1923,1928],{},[131,1919,1920],{},[27,1921,1922],{},"replayStart",[131,1924,1925],{},[27,1926,1927],{},"{ count: number }",[131,1929,1930],{},"Operation history replay has begun.",[113,1932,1933,1938,1943],{},[131,1934,1935],{},[27,1936,1937],{},"replayEnd",[131,1939,1940],{},[27,1941,1942],{},"{ replayed: number }",[131,1944,1945],{},"Operation history replay has completed.",[1947,1948,1949],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":167,"searchDepth":244,"depth":244,"links":1951},[1952,1955,1956,1957,1958],{"id":21,"depth":244,"text":22,"children":1953},[1954],{"id":42,"depth":257,"text":43},{"id":71,"depth":244,"text":72},{"id":155,"depth":244,"text":156},{"id":214,"depth":244,"text":215},{"id":1340,"depth":244,"text":1341,"children":1959},[1960,1961,1962,1963],{"id":1344,"depth":257,"text":37},{"id":1621,"depth":257,"text":1622},{"id":1725,"depth":257,"text":88},{"id":1828,"depth":257,"text":1829},"Real-time collaboration with operations, cursor tracking, and idle awareness for editors and canvases.","md",{},"/docs/high-level-sdks/collab",{"title":5,"description":1964},"docs/high-level-sdks/collab","edpuB7MrOifkCAKBUS8YMysJz7G7CgMbLaFkb0-K0MI",1788160343669]