liveblocks 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  Liveblocks command line interface.
4
4
 
5
+ ## Run with Docker
6
+
7
+ ```bash
8
+ docker run -P ghcr.io/liveblocks/cli
9
+ ```
10
+
11
+ See [DOCKER.md](./DOCKER.md) for configuration, volume mounts, and image signature verification.
12
+
5
13
  ## License
6
14
 
7
15
  Licensed under the GNU Affero General Public License v3.0 or later, Copyright ©
@@ -0,0 +1,303 @@
1
+ import{parse as Lt}from"@bomb.sh/args";import{WebsocketCloseCodes as Nt}from"@liveblocks/core";import{ZenRelay as kt}from"@liveblocks/zenrouter";import Pt from"bun";function k(t){return`\x1B[33m${t}\x1B[0m`}function V(t){return`\x1B[34m${t}\x1B[0m`}function Y(t){return`\x1B[35m${t}\x1B[0m`}function L(t){return`\x1B[32m${t}\x1B[0m`}function q(t){return`\x1B[31m${t}\x1B[0m`}function O(t){return`\x1B[2m${t}\x1B[0m`}import{nanoid as Pe,Permission as De}from"@liveblocks/core";import{ProtocolVersion as te}from"@liveblocks/server";import{nanoid as ke}from"@liveblocks/core";function Z(t){return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Q(t){let e=t.replace(/-/g,"+").replace(/_/g,"/"),o=e+"=".repeat((4-e.length%4)%4);return atob(o)}function ee(t){let e=Math.floor(Date.now()/1e3),o={...t,iat:e,exp:e+60*60,jti:ke(12)},s=Z(JSON.stringify({alg:"none",typ:"JWT"})),n=Z(JSON.stringify(o));return`${s}.${n}.`}function $(t){let e=t.split(".");if(e.length!==3)return null;let[o,s,n]=e;try{if(JSON.parse(Q(o)).alg!=="none")return null}catch{return null}let a;try{a=JSON.parse(Q(s))}catch{return null}if(n!==""||a.pid!=="localdev")return null;let u=a.exp;return typeof u=="number"&&u<Math.floor(Date.now()/1e3)?null:a}function Ae(t,e){if(e[t])return e[t];for(let[o,s]of Object.entries(e))if(o.endsWith("*")){let n=o.slice(0,-1);if(t.startsWith(n))return s}return[]}function oe(t){let e=new URL(t.url),o=e.pathname==="/v7"?te.V7:e.pathname==="/v8"?te.V8:null;if(o===null)return{ok:!1};let s=e.searchParams.get("roomId");if(!s)return{ok:!1};let n=e.searchParams.get("tok");if(n!==null){let u=$(n);if(!u)return{ok:!1};if(u.k==="acc"){let c=Ae(s,u.perms);return c.length===0?{ok:!1}:{ok:!0,roomId:s,ticketData:{version:o,id:u.uid,info:u.ui,scopes:c}}}else if(u.k==="id")return{ok:!0,roomId:s,ticketData:{version:o,id:u.uid,info:u.ui,scopes:[De.Write]}};return{ok:!1}}let a=e.searchParams.get("pubkey");return a!==null?a!=="pk_localdev"?{ok:!1,xwarn:"You can only use 'pk_localdev' as the public key"}:{ok:!0,roomId:s,ticketData:{version:o,anonymousId:Pe(),scopes:["room:write"]}}:{ok:!1}}import{DefaultMap as Fe,Room as He}from"@liveblocks/server";import{mkdirSync as de,readdirSync as We}from"fs";import{resolve as ae}from"path";import{asPos as Me,CrdtType as x,nn as je}from"@liveblocks/core";import{makeInMemorySnapshot as Ue,NestedMap as Je,plainLsonToNodeStream as Ge,quote as b}from"@liveblocks/server";import{Database as Ye}from"bun:sqlite";function N(t){try{return t!==void 0?JSON.parse(t):void 0}catch{return}}function ne(t){if(t>512)throw new Error("More than 512 params not supported");return new Array(t).fill("?").join(",")}function $e(t){return Array.isArray(t)?t:Array.from(t)}function Be(t){return t.query("SELECT node_id, crdt_json FROM nodes").values().map(([e,o])=>[e,N(o)])}function M(t,e){let o=t.prepare(`INSERT INTO nodes (node_id, crdt_json)
2
+ VALUES (?, ?)
3
+ ON CONFLICT (node_id) DO UPDATE SET crdt_json = ?`);t.transaction(n=>{for(let[a,u]of n){let c=JSON.stringify(u);o.run(a,c,c)}})(e)}function ie(t,e){let o=$e(e),s=o.length;t.query(`DELETE FROM nodes WHERE node_id IN (${ne(s)})`).run(...o)}function re(t){let e=new Je;for(let[o,s]of t){if(s.parentId===void 0)continue;let n=e.get(s.parentId,s.parentKey);(n===void 0||o>n)&&e.set(s.parentId,s.parentKey,o)}return e}function ze(t,e){let o=new Map(Be(t));o.has("root")||o.set("root",{type:x.OBJECT,data:{}});let s=new Set,n=["root"],a=new Map,u=re(o);for(;n.length>0;){let p=n.pop(),f=je(o.get(p));if(f.type===x.OBJECT)for(let I of u.keysAt(p))Object.prototype.hasOwnProperty.call(f.data,I)&&(delete f.data[I],s.add(p),e.warn(`[integrity] Found data key ${b(I)} from ${b(p)} (conflicted with child node)`));if(f.type!==x.REGISTER)n.push(...u.valuesAt(p));else if(o.get(f.parentId)?.type===x.OBJECT)continue;a.set(p,f)}let c=new Set;for(let[p,f]of o)a.has(p)||(f.parentId!==void 0&&a.has(f.parentId)?a.get(f.parentId)?.type===x.REGISTER?e.warn(`[integrity] Found unreachable node ${b(p)} (child of live register)`):e.warn(`[integrity] Found conflicting sibling ${b(p)} (conflicted with ${b(u.get(f.parentId,f.parentKey))} at ${b(f.parentKey)})`):e.warn(`[integrity] Found orphan ${b(p)}`),c.add(p),s.delete(p));if(s.size>0||c.size>0){if(s.size>0){let p=new Map;for(let f of s){let I=a.get(f);I!==void 0&&p.set(f,I)}M(t,p)}c.size>0&&ie(t,c)}let h=c.size===0?u:re(a);return{nodes:a,revNodes:h}}function se(t,e){return t?.type===x.OBJECT&&Object.prototype.hasOwnProperty.call(t.data,e)&&t.data[e]!==void 0}var B=class{db;constructor(e){let o=new Ye(e,{create:!0});o.run("PRAGMA journal_mode = WAL"),o.run("PRAGMA case_sensitive_like = ON"),o.run(`CREATE TABLE IF NOT EXISTS system (
4
+ setting TEXT NOT NULL,
5
+ jval TEXT NOT NULL,
6
+ PRIMARY KEY (setting)
7
+ )`),o.run(`CREATE TABLE IF NOT EXISTS nodes (
8
+ node_id TEXT NOT NULL,
9
+ crdt_json TEXT NOT NULL,
10
+ PRIMARY KEY (node_id)
11
+ )`),o.run(`CREATE TABLE IF NOT EXISTS metadata (
12
+ key TEXT NOT NULL,
13
+ jval TEXT NOT NULL,
14
+ PRIMARY KEY (key)
15
+ )`),o.run(`CREATE TABLE IF NOT EXISTS ydocs (
16
+ doc_id TEXT NOT NULL,
17
+ key TEXT NOT NULL,
18
+ data BLOB NOT NULL,
19
+ PRIMARY KEY (doc_id, key)
20
+ )`),o.run(`CREATE TABLE IF NOT EXISTS leased_sessions (
21
+ session_id TEXT NOT NULL PRIMARY KEY,
22
+ jpresence TEXT NOT NULL,
23
+ updated_at INTEGER NOT NULL,
24
+ juserinfo TEXT NOT NULL,
25
+ ttl INTEGER NOT NULL,
26
+ actor_id INTEGER NOT NULL
27
+ )`),o.run("CREATE INDEX IF NOT EXISTS idx_leased_sessions_expiry ON leased_sessions(updated_at, ttl)"),this.db=o}load_nodes_api(e){let o=this.db,{nodes:s,revNodes:n}=ze(o,e),a=m=>s.get(m),u=(m,l)=>n.get(m,l),c=(m,l)=>n.has(m,l);function h(m,l){let g;for(let v of n.keysAt(m)){let y=Me(v);y>l&&(g===void 0||y<g)&&(g=y)}return g}function p(m,l,g=!1){let v=a(l.parentId);if(v===void 0)throw new Error(`No such parent ${b(l.parentId)}`);if(l.type===x.REGISTER&&v.type===x.OBJECT)throw new Error("Cannot add register under object");let y=u(l.parentId,l.parentKey);if(y!==m){let S=se(v,l.parentKey);if(y!==void 0||S)if(g)G(l.parentId,l.parentKey);else throw new Error(`Key ${b(l.parentKey)} already exists`);n.set(l.parentId,l.parentKey,m)}s.set(m,l),M(o,[[m,l]])}function f(m,l){let g=a(m);if(g?.parentId===void 0)return;if(c(g.parentId,l))throw new Error(`Pos ${b(l)} already taken`);n.delete(g.parentId,g.parentKey);let v={...g,parentKey:l};s.set(m,v),n.set(g.parentId,l,m),M(o,[[m,v]])}function I(m,l,g=!1){let v=a(m);if(v?.type!==x.OBJECT)return;for(let S of Object.keys(l)){let _=u(m,S);if(_!==void 0)if(g)E(_);else throw new Error(`Child node already exists under ${S}`)}let y={...v,data:{...v.data,...l}};s.set(m,y),M(o,[[m,y]])}function E(m){let l=a(m);if(l?.parentId===void 0)return;n.delete(l.parentId,l.parentKey);let g=[],v=[m];for(;v.length>0;){let y=v.pop();v.push(...n.valuesAt(y)),s.delete(y),n.deleteAll(y),g.push(y)}ie(o,g)}function G(m,l){let g=a(m);if(se(g,l)){let{[l]:y,...S}=g.data,_={...g,data:S};s.set(m,_),M(o,[[m,_]])}let v=u(m,l);v!==void 0&&E(v)}return{get_node:a,iter_nodes:()=>s.entries(),has_node:m=>s.has(m),get_child_at:u,has_child_at:c,get_next_sibling:h,set_child:p,move_sibling:f,delete_node:E,delete_child_key:G,set_object_data:I,get_snapshot(m){return Ue(s)}}}DANGEROUSLY_reset_nodes(e){let o=this.db.prepare("DELETE FROM nodes"),s=this.db.prepare("INSERT INTO nodes (node_id, crdt_json) VALUES (?, ?)");this.db.transaction(()=>{o.run();for(let[a,u]of Ge(e))s.run(a,JSON.stringify(u))})()}raw_iter_nodes(){return this.db.query("SELECT node_id, crdt_json FROM nodes").values().map(([e,o])=>[e,N(o)])}get_meta(e){let s=this.db.query("SELECT jval FROM metadata WHERE key = ?").get(e)?.jval;if(s!==void 0)return N(s)??null}put_meta(e,o){let s=JSON.stringify(o);this.db.run(`INSERT INTO metadata (key, jval)
28
+ VALUES (?, ?)
29
+ ON CONFLICT (key) DO UPDATE SET jval = ?
30
+ `,[e,s,s])}delete_meta(e){this.db.query("DELETE FROM metadata WHERE key = ?").run(e)}next_actor(){let e=this.db.query(`INSERT INTO system (setting, jval)
31
+ VALUES ('last_actor_id', '0')
32
+ ON CONFLICT (setting) DO UPDATE SET jval = json(CAST(jval AS INTEGER) + 1)
33
+ RETURNING jval`).get();return JSON.parse(e.jval)}iter_y_updates(e){return this.db.query("SELECT key, data FROM ydocs WHERE doc_id = ?").values(e)}write_y_updates(e,o,s){this.db.query(`INSERT INTO ydocs
34
+ VALUES (?, ?, ?)
35
+ ON CONFLICT (doc_id, key) DO UPDATE SET data = ?`).run(e,o,s,s)}delete_y_updates(e,o){let s=o.length;this.db.query(`DELETE FROM ydocs WHERE doc_id = ? AND key IN (${ne(s)})`).run(e,...o)}DANGEROUSLY_wipe_all_y_updates(){this.db.query("DELETE FROM ydocs").run()}list_leased_sessions(){let e=this.db.query("SELECT session_id, jpresence, updated_at, juserinfo, ttl, actor_id FROM leased_sessions").all();return Array.from(e,o=>[o.session_id,{sessionId:o.session_id,presence:N(o.jpresence)??null,updatedAt:o.updated_at,info:N(o.juserinfo)??{name:""},ttl:o.ttl,actorId:o.actor_id}])}get_leased_session(e){let o=this.db.query("SELECT session_id, jpresence, updated_at, juserinfo, ttl, actor_id FROM leased_sessions WHERE session_id = ?").get(e);if(o!=null)return{sessionId:o.session_id,presence:N(o.jpresence)??null,updatedAt:o.updated_at,info:N(o.juserinfo)??{name:""},ttl:o.ttl,actorId:o.actor_id}}put_leased_session(e){this.db.query(`INSERT INTO leased_sessions (session_id, jpresence, updated_at, juserinfo, ttl, actor_id)
36
+ VALUES (?, ?, ?, ?, ?, ?)
37
+ ON CONFLICT (session_id) DO UPDATE SET
38
+ jpresence = excluded.jpresence,
39
+ updated_at = excluded.updated_at,
40
+ juserinfo = excluded.juserinfo,
41
+ ttl = excluded.ttl,
42
+ actor_id = excluded.actor_id`).run(e.sessionId,JSON.stringify(e.presence),e.updatedAt,JSON.stringify(e.info),e.ttl,e.actorId)}delete_leased_session(e){this.db.query("DELETE FROM leased_sessions WHERE session_id = ?").run(e)}close(){this.db.close()}};var j=".liveblocks/v1/rooms",ce=new Fe(t=>{de(j,{recursive:!0});let e=new B(ue(t));return new He(t,{storage:e})});function ue(t){let e=ae(j,`${encodeURIComponent(t)}.db`);if(!e.startsWith(ae(j)+"/"))throw new Error("Invalid room ID");return e}function w(t){return ce.getOrCreate(t)}async function C(t){let e=ue(t);return await Bun.file(e).exists()}function le(){try{return de(j,{recursive:!0}),We(j).filter(o=>o.endsWith(".db")).map(o=>decodeURIComponent(o.replace(/\.db$/,"")))}catch{return[]}}async function me(t){if(await C(t))throw new Error(`Room with id "${t}" already exists`);let e=ce.getOrCreate(t);await e.load();let o={liveblocksType:"LiveObject",data:{}};await e.driver.DANGEROUSLY_reset_nodes(o),e.unload()}function Ke(t){return t.trim().split(`
43
+ `).filter(Boolean).map(e=>{let o=e.match(/^(.+?):(\d+):(.*)$/);return o?{file:o[1],line:parseInt(o[2],10),text:o[3]}:null}).filter(e=>e!==null)}async function fe(...t){try{let e=["git","grep","-nF",...t.flatMap(n=>["-e",n]),"--","."],o=Bun.spawn(e,{stdout:"pipe",stderr:"pipe"}),s=await new Response(o.stdout).text();return await o.exited,Ke(s)}catch{return[]}}function Xe(t){let e=t.trim();return e.startsWith("#")||e.startsWith("//")||e.startsWith("*")||e.startsWith("/*")}var Ve=[{pattern:"<LiveblocksProvider",expected:"baseUrl=",fixSnippet:t=>`${Y("baseUrl")}=${L(`"${t}"`)}`},{pattern:"createClient(",expected:"baseUrl:",fixSnippet:t=>`${Y("baseUrl")}: ${L(`"${t}"`)}`},{pattern:"new Liveblocks(",expected:"baseUrl:",fixSnippet:t=>`${Y("baseUrl")}: ${L(`"${t}"`)}`}];async function ge(t){let e=`http://localhost:${t}`,o=[];for(let s of Ve){let n=(await fe(s.pattern)).filter(c=>!Xe(c.text));if(n.length===0)continue;let a=await fe(s.expected),u=new Set(a.map(c=>c.file));for(let c of n)u.has(c.file)||o.push({match:c,check:s})}if(o.length>0){console.log(),console.warn(k("\u26A0 Your project may not be configured for the local dev server.")),console.log(),console.log(` Missing baseUrl in the following location(s):
44
+ `);for(let{match:s,check:n}of o)console.log(` ${V(`${s.file}:${s.line}`)}`),console.log(` To fix, add ${n.fixSnippet(e)}`),console.log();console.log(O(" \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E")),console.log(O(" \u2502 Press p to copy an AI fix prompt to your clipboard \u2502")),console.log(O(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F")),console.log()}return o}var qe={"<LiveblocksProvider":t=>`baseUrl="${t}"`,"createClient(":t=>`baseUrl: "${t}"`,"new Liveblocks(":t=>`baseUrl: "${t}"`},Ze={"<LiveblocksProvider":{prop:"publicApiKey",value:"pk_localdev"},"createClient(":{prop:"publicApiKey",value:"pk_localdev"},"new Liveblocks(":{prop:"secret",value:"sk_localdev"}};function he(t,e){let o=[`In the following file(s), the Liveblocks setup is missing a \`baseUrl\` property pointing to the local dev server at ${e}. Please add the missing configuration:`,""];for(let{match:n,check:a}of t){let u=qe[a.pattern]?.(e)??`baseUrl: "${e}"`;o.push(`- In \`${n.file}\` at line ${n.line}, add \`${u}\` to the \`${a.pattern}\` call`)}o.push("","Also make sure the API keys are set to the local dev server keys:");let s=new Set;for(let{check:n}of t){let a=Ze[n.pattern];a&&!s.has(a.value)&&(s.add(a.value),o.push(`- Set \`${a.prop}\` to \`"${a.value}"\` (either directly or via an environment variable)`))}return o.join(`
45
+ `)}import{execSync as Qe}from"node:child_process";function ve(t){let e=process.platform==="darwin"?"pbcopy":process.platform==="win32"?"clip.exe":"xclip -selection clipboard";Qe(e,{input:t})}import et from"bun";function Ie(t,e){let{promise:o,resolve:s}=Promise.withResolvers();return et.connect({hostname:e,port:t,socket:{data(){},open(n){n.end(),s(!0)},error(){s(!1)},connectError(){s(!1)}}}),o}var H=new Set;function W(t,e=t){e&&!H.has(e)&&(H.add(e),console.log(k(` \u26A0 ${t??e}`)))}function Te(){H.clear()}import{Permission as st}from"@liveblocks/core";import{ZenRouter as nt}from"@liveblocks/zenrouter";import{array as it,enum_ as at,object as dt,optional as ct,record as ut,string as lt}from"decoders";import{json as ot}from"@liveblocks/zenrouter";import{nanoid as tt}from"@liveblocks/core";import{json as ye}from"@liveblocks/zenrouter";function U(t,e,o,s){let n={};return n["X-LB-Warn"]=o,s&&(n["X-LB-Warn-Key"]=s),ye(t,e,n)}function R(t,e,o="This is a dummy response."){return U(t,e,o,tt())}function r(t="This endpoint isn't implemented in the Liveblocks dev server"){return ye({error:"Not implemented",message:t},501,{"X-LB-Warn":t})}function z(t){let e=t.headers.get("Authorization");if(e==="Bearer sk_localdev")return!0;if(!e)throw ot({error:"Unauthorized",message:"Missing secret key"},401);if(e.startsWith("Bearer "))throw U({error:"Forbidden",message:"Invalid secret key. You can only use 'sk_localdev' as a secret key"},403,"You can only use 'sk_localdev' as the secret key");return!1}import{inexact as rt,optional as be,string as Ee}from"decoders";var Se=rt({name:be(Ee),avatar:be(Ee)}).refineType();var mt=at(st),J=new nt({authorize:({req:t})=>z(t)});J.route("POST /v2/authorize-user",dt({userId:lt,userInfo:ct(Se),permissions:ut(it(mt))}),({body:t})=>({token:ee({k:"acc",pid:"localdev",uid:t.userId,perms:t.permissions,ui:t.userInfo})}));J.route("POST /v2/identify-user",()=>r("ID tokens are not supported in the Liveblocks dev server. To develop locally, use access tokens instead (via POST /v2/authorize-user)"));import{ZenRouter as pt}from"@liveblocks/zenrouter";var d=new pt({cors:{allowCredentials:!0,maxAge:600},authorize:({req:t})=>{let e=t.headers.get("Authorization");if(!e?.startsWith("Bearer "))return!1;let o=e.slice(7);return $(o)!==null}});d.route("GET /v2/c/threads",()=>R({threads:[],inboxNotifications:[],subscriptions:[],meta:{nextCursor:null,requestedAt:new Date().toISOString(),permissionHints:{}}}));d.route("GET /v2/c/threads/delta",()=>R({threads:[],inboxNotifications:[],subscriptions:[],meta:{requestedAt:new Date().toISOString(),permissionHints:{}}}));d.route("GET /v2/c/inbox-notifications",()=>R({inboxNotifications:[],threads:[],subscriptions:[],groups:[],meta:{nextCursor:null,requestedAt:new Date().toISOString()}}));d.route("GET /v2/c/inbox-notifications/count",()=>R({count:0}));d.route("GET /v2/c/rooms/<roomId>/threads",()=>R({data:[],inboxNotifications:[],subscriptions:[],meta:{nextCursor:null,requestedAt:new Date().toISOString(),permissionHints:{}}}));d.route("GET /v2/c/rooms/<roomId>/threads/delta",()=>R({data:[],inboxNotifications:[],subscriptions:[],deletedThreads:[],deletedInboxNotifications:[],deletedSubscriptions:[],meta:{requestedAt:new Date().toISOString(),permissionHints:{}}}));d.route("POST /v2/c/rooms/<roomId>/text-metadata",()=>R({status:"ok"}));d.route("PUT /v2/c/rooms/<roomId>/attachments/<attachmentId>/upload/<name>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/attachments/<attachmentId>/multipart/<name>",()=>r()),d.route("PUT /v2/c/rooms/<roomId>/attachments/<attachmentId>/multipart/<uploadId>/<partNumber>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/attachments/<attachmentId>/multipart/<uploadId>/complete",()=>r()),d.route("DELETE /v2/c/rooms/<roomId>/attachments/<attachmentId>/multipart/<uploadId>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/attachments/presigned-urls",()=>r()),d.route("POST /v2/c/rooms/<roomId>/send-message",()=>r()),d.route("GET /v2/c/rooms/<roomId>/storage",()=>r()),d.route("POST /v2/c/rooms/<roomId>/version",()=>r()),d.route("GET /v2/c/rooms/<roomId>/y-version/<version>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/ai/contextual-prompt",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/search",()=>r()),d.route("DELETE /v2/c/rooms/<roomId>/threads/<threadId>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/metadata",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/mark-as-resolved",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/mark-as-unresolved",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/subscribe",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/unsubscribe",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/comments",()=>r()),d.route("GET /v2/c/rooms/<roomId>/threads/<threadId>/comments/<commentId>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/comments/<commentId>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/comments/<commentId>/metadata",()=>r()),d.route("DELETE /v2/c/rooms/<roomId>/threads/<threadId>/comments/<commentId>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/threads/<threadId>/comments/<commentId>/reactions",()=>r()),d.route("DELETE /v2/c/rooms/<roomId>/threads/<threadId>/comments/<commentId>/reactions/<emoji>",()=>r()),d.route("GET /v2/c/rooms/<roomId>/threads/comments/search",()=>r()),d.route("GET /v2/c/rooms/<roomId>/threads/<threadId>/participants",()=>r()),d.route("GET /v2/c/rooms/<roomId>/notification-settings",()=>r()),d.route("GET /v2/c/rooms/<roomId>/subscription-settings",()=>r()),d.route("POST /v2/c/rooms/<roomId>/notification-settings",()=>r()),d.route("POST /v2/c/rooms/<roomId>/subscription-settings",()=>r()),d.route("GET /v2/c/inbox-notifications/delta",()=>r()),d.route("DELETE /v2/c/inbox-notifications",()=>r()),d.route("POST /v2/c/inbox-notifications/read",()=>r()),d.route("DELETE /v2/c/inbox-notifications/<inboxNotificationId>",()=>r()),d.route("POST /v2/c/rooms/<roomId>/inbox-notifications/read",()=>r()),d.route("POST /v2/c/rooms/<roomId>/text-mentions",()=>r()),d.route("DELETE /v2/c/rooms/<roomId>/text-mentions/<mentionId>",()=>r()),d.route("GET /v2/c/notification-settings",()=>r()),d.route("POST /v2/c/notification-settings",()=>r()),d.route("GET /v2/c/rooms/<roomId>/thread-with-notification/<threadId>",()=>r()),d.route("GET /v2/c/urls/metadata",()=>r()),d.route("GET /v2/c/rooms/<roomId>/versions",()=>r()),d.route("GET /v2/c/rooms/<roomId>/versions/delta",()=>r()),d.route("POST /v2/c/groups/find",()=>r());import{abort as Ce,html as gt,json as ht,ZenRouter as vt}from"@liveblocks/zenrouter";var xe=`<!doctype html>
46
+ <html lang="en">
47
+ <head>
48
+ <meta charset="UTF-8" />
49
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
50
+ <title>Liveblocks dev server</title>
51
+ <style>
52
+ * {
53
+ box-sizing: border-box;
54
+ margin: 0;
55
+ padding: 0;
56
+ }
57
+
58
+ :root {
59
+ --bg: #f9f9f9;
60
+ --fg: #202020;
61
+ --fg-secondary: #646464;
62
+ --code-bg: #fcfcfc;
63
+ --shadow: 0px 0px 0px 1px rgba(0, 0, 0, 0.06),
64
+ 0px 1px 2px -1px rgba(0, 0, 0, 0.06),
65
+ 0px 2px 4px 0px rgba(0, 0, 0, 0.04);
66
+ --shadow-hover: 0px 0px 0px 1px rgba(0, 0, 0, 0.08),
67
+ 0px 1px 2px -1px rgba(0, 0, 0, 0.08),
68
+ 0px 2px 4px 0px rgba(0, 0, 0, 0.06);
69
+ --pill-bg: #171717;
70
+ --pill-fg: #e5e7eb;
71
+ --green: #05df72;
72
+ --green-glow: rgba(5, 223, 114, 0.4);
73
+ }
74
+
75
+ @media (prefers-color-scheme: dark) {
76
+ :root {
77
+ --bg: #111;
78
+ --fg: #e5e5e5;
79
+ --fg-secondary: #a0a0a0;
80
+ --code-bg: #1a1a1a;
81
+ --shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.08),
82
+ 0px 1px 2px -1px rgba(0, 0, 0, 0.4),
83
+ 0px 2px 4px 0px rgba(0, 0, 0, 0.3);
84
+ --shadow-hover: 0px 0px 0px 1px rgba(255, 255, 255, 0.12),
85
+ 0px 1px 2px -1px rgba(0, 0, 0, 0.5),
86
+ 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
87
+ --pill-bg: #f5f5f5;
88
+ --pill-fg: #202020;
89
+ }
90
+ }
91
+
92
+ body {
93
+ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
94
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
95
+ background: var(--bg);
96
+ color: var(--fg);
97
+ min-height: 100vh;
98
+ -webkit-font-smoothing: antialiased;
99
+ -moz-osx-font-smoothing: grayscale;
100
+ }
101
+
102
+ main {
103
+ position: relative;
104
+ min-height: 100vh;
105
+ overflow: hidden;
106
+ padding: 2rem 1.5rem;
107
+ }
108
+
109
+ .logo {
110
+ position: absolute;
111
+ left: 50%;
112
+ top: 2rem;
113
+ transform: translateX(-50%);
114
+ animation: fade-in 0.6s ease-out both;
115
+ }
116
+
117
+ .logo svg {
118
+ height: 1.5rem;
119
+ width: auto;
120
+ color: var(--fg);
121
+ }
122
+
123
+ .center {
124
+ position: absolute;
125
+ inset: 0;
126
+ z-index: 10;
127
+ display: flex;
128
+ flex-direction: column;
129
+ align-items: center;
130
+ justify-content: center;
131
+ text-align: center;
132
+ }
133
+
134
+ h1 {
135
+ margin-bottom: 0.25rem;
136
+ font-weight: 500;
137
+ font-size: 1rem;
138
+ animation: fade-in 0.6s ease-out 0.1s both;
139
+ }
140
+
141
+ .description {
142
+ margin-bottom: 1rem;
143
+ max-width: 20rem;
144
+ font-size: 0.875rem;
145
+ line-height: 1.625;
146
+ color: var(--fg-secondary);
147
+ animation: fade-in 0.6s ease-out 0.2s both;
148
+ }
149
+
150
+ .description code {
151
+ white-space: nowrap;
152
+ border-radius: 0.25rem;
153
+ background: var(--code-bg);
154
+ padding: 0.125rem 0.375rem;
155
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
156
+ monospace;
157
+ box-shadow: var(--shadow);
158
+ font-size: 0.75rem;
159
+ color: var(--fg);
160
+ }
161
+
162
+ .docs-link {
163
+ display: inline-flex;
164
+ align-items: center;
165
+ justify-content: center;
166
+ border-radius: 0.375rem;
167
+ font-size: 0.875rem;
168
+ font-weight: 500;
169
+ background: var(--code-bg);
170
+ box-shadow: var(--shadow);
171
+ height: 2.25rem;
172
+ padding: 0.5rem 1rem;
173
+ color: var(--fg);
174
+ text-decoration: none;
175
+ transition: box-shadow 0.15s;
176
+ animation: fade-in 0.6s ease-out 0.3s both;
177
+ }
178
+
179
+ .docs-link:hover {
180
+ box-shadow: var(--shadow-hover);
181
+ }
182
+
183
+ .status {
184
+ position: absolute;
185
+ bottom: 2rem;
186
+ left: 50%;
187
+ transform: translateX(-50%);
188
+ animation: fade-in 0.6s ease-out 0.4s both;
189
+ display: inline-flex;
190
+ align-items: center;
191
+ gap: 0.5rem;
192
+ border-radius: 9999px;
193
+ background: var(--pill-bg);
194
+ color: var(--pill-fg);
195
+ box-shadow: var(--shadow);
196
+ padding: 0.5rem 0.75rem 0.5rem 0.625rem;
197
+ }
198
+
199
+ .status-dot {
200
+ position: relative;
201
+ width: 0.75rem;
202
+ height: 0.75rem;
203
+ }
204
+
205
+ .status-dot .glow {
206
+ position: absolute;
207
+ inset: 0;
208
+ background: var(--green-glow);
209
+ border-radius: 9999px;
210
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
211
+ }
212
+
213
+ .status-dot .dot {
214
+ position: absolute;
215
+ width: 0.25rem;
216
+ height: 0.25rem;
217
+ left: 50%;
218
+ top: 50%;
219
+ transform: translate(-50%, -50%);
220
+ background: var(--green);
221
+ border-radius: 9999px;
222
+ }
223
+
224
+ .status-text {
225
+ font-size: 0.75rem;
226
+ font-weight: 500;
227
+ }
228
+
229
+ @keyframes fade-in {
230
+ from {
231
+ opacity: 0;
232
+ }
233
+ to {
234
+ opacity: 1;
235
+ }
236
+ }
237
+
238
+ @keyframes pulse {
239
+ 50% {
240
+ opacity: 0.5;
241
+ }
242
+ }
243
+ </style>
244
+ </head>
245
+ <body>
246
+ <main>
247
+ <div class="logo">
248
+ <svg
249
+ width="384"
250
+ height="72"
251
+ viewBox="0 0 128 24"
252
+ fill="none"
253
+ xmlns="http://www.w3.org/2000/svg"
254
+ >
255
+ <path
256
+ fill-rule="evenodd"
257
+ clip-rule="evenodd"
258
+ d="M28.8316 3.21884H26L26.0007 19.9974H28.8316V3.21884ZM34.0855 8.01549H31.2547V19.9974H34.0855V8.01549ZM34.0855 3.08984H31.2547V6.14356H34.0855V3.08984ZM38.2401 8.01549H35.1978L39.4807 19.9974H42.6398L46.9226 8.01549H43.9269L42.1367 13.6908C42.0901 13.8384 41.9224 14.416 41.6336 15.4222L41.0602 17.3529C40.7213 16.1277 40.3665 14.9069 39.996 13.6908L38.2401 8.01549ZM58.5185 11.7601C58.2841 10.9567 57.9408 10.2737 57.4879 9.71184C56.9805 9.08118 56.3376 8.59313 55.5579 8.24984C54.7853 7.89868 53.9274 7.72381 52.9836 7.72381C51.1897 7.72381 49.7542 8.28496 48.6778 9.40798C48.1408 9.9882 47.7303 10.6737 47.4723 11.4211C47.2072 12.1929 47.0746 13.0472 47.0746 13.9832C47.0746 15.9877 47.6092 17.5364 48.6785 18.6286C49.7621 19.7359 51.2055 20.2898 53.0072 20.2898C54.5517 20.2898 55.803 19.943 56.7633 19.2485C57.723 18.5541 58.3586 17.5249 58.6704 16.1597L55.909 15.949C55.7765 16.69 55.4719 17.244 54.996 17.6102C54.5201 17.9693 53.8493 18.1492 52.9836 18.1492C51.0027 18.1492 49.9886 17.0333 49.942 14.8023H58.8575L58.8696 14.4046C58.8696 13.445 58.7521 12.5635 58.5185 11.7601ZM50.5734 10.918C51.0729 10.2157 51.8763 9.86449 52.9836 9.86449C53.5218 9.86449 53.9747 9.93831 54.341 10.0867C54.7079 10.235 55.024 10.4729 55.2891 10.8005C55.4953 11.0547 55.6539 11.3441 55.7571 11.6547C55.8734 11.9788 55.9443 12.3174 55.9678 12.6609H49.9649C50.0352 11.9665 50.238 11.3853 50.5734 10.918ZM69.8685 8.48419C69.0651 7.96103 68.137 7.70016 67.0842 7.70016H67.0827C66.3188 7.70016 65.6207 7.85568 64.9886 8.16814C64.3667 8.4713 63.8342 8.9309 63.4435 9.50186V3.21884H60.6126V19.9974H63.4442V18.3477C63.8031 18.9405 64.3115 19.4286 64.9184 19.7631C65.5505 20.1143 66.2485 20.2898 67.0125 20.2898C68.0739 20.2898 69.0135 20.0361 69.8341 19.5295C70.6525 19.0228 71.2882 18.2968 71.7404 17.3529C72.2005 16.4012 72.4313 15.2861 72.4313 14.0068C72.4313 12.7584 72.2041 11.659 71.7526 10.7073C71.3076 9.74768 70.6797 9.00664 69.8685 8.48419ZM68.663 17.1774C68.2108 17.8639 67.4389 18.2065 66.346 18.2065C65.3627 18.2065 64.6224 17.8517 64.1236 17.1422C63.6241 16.4327 63.3747 15.395 63.3747 14.0298C63.3747 12.7111 63.5968 11.682 64.0412 10.9409C64.4941 10.192 65.2545 9.81791 66.3231 9.81791C67.4153 9.81791 68.1914 10.1612 68.6516 10.847C69.1124 11.5257 69.3417 12.5792 69.3417 14.0068C69.3417 15.4337 69.116 16.4908 68.663 17.1774ZM77.0302 3.21884H74.1986V19.9974H77.0302V3.21884ZM81.6169 19.5409C82.5379 20.0404 83.6294 20.2898 84.8936 20.2898C86.1105 20.2898 87.1791 20.0283 88.0993 19.5065C89.0131 18.9985 89.7576 18.2335 90.2407 17.3064C90.7474 16.3546 91.0011 15.2545 91.0011 14.0068C91.0011 12.8057 90.7517 11.7285 90.2522 10.7775C89.7734 9.83933 89.0341 9.05921 88.1229 8.53078C87.202 7.99256 86.1256 7.72309 84.8936 7.72309C83.653 7.72309 82.5687 7.99256 81.6406 8.53078C80.7318 9.05692 79.9926 9.83235 79.5106 10.7653C79.0197 11.7092 78.7739 12.7899 78.7739 14.0068C78.7739 15.3018 79.0154 16.4206 79.4992 17.3644C79.9697 18.2867 80.7079 19.0453 81.6169 19.5409ZM87.245 17.1895C86.7691 17.8603 85.9851 18.1957 84.8936 18.1957C84.1525 18.1957 83.5556 18.0474 83.1033 17.7507C82.6504 17.4468 82.3229 16.9903 82.12 16.3819C81.9172 15.7655 81.8162 14.9736 81.8162 14.0061C81.8162 12.5556 82.0541 11.4949 82.53 10.8241C83.0137 10.1533 83.8014 9.81791 84.8936 9.81791C85.9779 9.81791 86.7577 10.1533 87.2335 10.8241C87.7173 11.4949 87.9588 12.5556 87.9588 14.0068C87.9588 15.4574 87.7209 16.518 87.245 17.1895ZM94.8626 19.5409C95.7756 20.0404 96.8635 20.2898 98.1277 20.2898C99.1103 20.2898 99.9882 20.1186 100.76 19.7753C101.533 19.432 102.16 18.9525 102.644 18.3362C103.129 17.708 103.447 16.967 103.568 16.1826L100.842 15.9024C100.655 16.6506 100.343 17.2089 99.9058 17.5751C99.4693 17.942 98.8759 18.1255 98.1277 18.1255C97.363 18.1255 96.7625 17.9693 96.3253 17.6568C95.8888 17.3372 95.5842 16.8814 95.413 16.288C95.241 15.6874 95.1557 14.927 95.1557 14.0068C95.1557 13.1017 95.241 12.3528 95.413 11.7601C95.5842 11.1595 95.8845 10.6994 96.3138 10.3791C96.751 10.0515 97.3552 9.88814 98.1277 9.88814C98.9541 9.88814 99.5668 10.1182 99.9646 10.5783C100.37 11.0305 100.659 11.6504 100.83 12.4388L103.51 11.9586C103.253 10.6793 102.671 9.65379 101.766 8.88194C100.869 8.10938 99.6564 7.72381 98.1277 7.72381C96.8793 7.72381 95.7992 7.98898 94.8862 8.51931C93.9847 9.03823 93.2562 9.81153 92.7921 10.7424C92.3083 11.6863 92.0661 12.7742 92.0661 14.0068C92.0661 15.309 92.304 16.4327 92.7799 17.3766C93.2637 18.3204 93.9581 19.0421 94.8626 19.5409ZM107.91 15.5512L109.232 14.287L112.742 19.9974H116.007L111.151 12.4732L115.855 8.01549H112.18L107.91 12.3922V3.21884H105.078V19.9974H107.91V15.5512ZM118.488 19.8569C119.284 20.1457 120.169 20.2897 121.144 20.2897C122.634 20.2897 123.862 19.993 124.83 19.4011C125.805 18.8077 126.293 17.8402 126.293 16.4986C126.293 15.6249 126.066 14.9384 125.614 14.4396C125.162 13.9322 124.623 13.5695 123.999 13.351C123.383 13.1252 122.544 12.8952 121.484 12.6608C120.867 12.5282 120.38 12.4035 120.021 12.2867C119.662 12.1692 119.373 12.0172 119.155 11.8302C118.945 11.6424 118.839 11.4009 118.839 11.1049C118.839 10.6678 119.034 10.3367 119.424 10.1102C119.814 9.88373 120.298 9.77049 120.875 9.77049C121.639 9.77049 122.236 9.95396 122.666 10.3209C123.102 10.6878 123.336 11.2375 123.367 11.9707L125.988 11.5378C125.863 10.1962 125.337 9.22511 124.408 8.62383C123.488 8.02398 122.31 7.72298 120.875 7.72298C120.032 7.72298 119.253 7.85126 118.535 8.10926C117.825 8.35866 117.252 8.75283 116.815 9.29176C116.378 9.82926 116.16 10.5079 116.16 11.3271C116.16 12.0839 116.347 12.6959 116.721 13.1639C117.102 13.6369 117.592 14.0102 118.149 14.2518C118.726 14.5019 119.451 14.7399 120.325 14.9656L121.051 15.1412C121.535 15.256 122.015 15.3887 122.49 15.5389C122.817 15.6407 123.086 15.7812 123.297 15.9603C123.508 16.1395 123.613 16.3739 123.613 16.6627C123.613 17.1694 123.402 17.5599 122.981 17.8323C122.568 18.106 121.963 18.2422 121.168 18.2422C120.356 18.2422 119.709 18.0394 119.225 17.6338C118.742 17.2281 118.496 16.6433 118.488 15.8786L115.821 16.1825C115.851 17.1034 116.105 17.8717 116.581 18.488C117.065 19.1044 117.7 19.5602 118.488 19.8569Z"
259
+ fill="currentColor"
260
+ ></path>
261
+ <path
262
+ fill-rule="evenodd"
263
+ clip-rule="evenodd"
264
+ d="M13.5 9H0L4 13V18.5L13.5 9Z"
265
+ fill="currentColor"
266
+ ></path>
267
+ <path
268
+ fill-rule="evenodd"
269
+ clip-rule="evenodd"
270
+ d="M6.5 20H20L16 16V10.5L6.5 20Z"
271
+ fill="currentColor"
272
+ ></path>
273
+ </svg>
274
+ </div>
275
+
276
+ <div class="center">
277
+ <h1>You're all set</h1>
278
+ <p class="description">
279
+ This is the Liveblocks dev server. Point your app to
280
+ <code>http://localhost:1153</code> and start building. This page is
281
+ not meant to be used directly.
282
+ </p>
283
+ <a
284
+ href="https://liveblocks.io/docs/tools/devserver?from=__VERSION__"
285
+ target="_blank"
286
+ rel="noopener noreferrer"
287
+ class="docs-link"
288
+ >Read the docs</a
289
+ >
290
+ </div>
291
+
292
+ <div class="status">
293
+ <span class="status-dot">
294
+ <span class="glow" aria-hidden="true"></span>
295
+ <span class="dot" aria-hidden="true"></span>
296
+ </span>
297
+ <span class="status-text">Dev server is running</span>
298
+ </div>
299
+ </main>
300
+ </body>
301
+ </html>
302
+ `;var P=new vt({authorize:()=>!0});P.route("GET /v7",()=>Ce(426));P.route("GET /v8",()=>Ce(426));P.route("GET /health",()=>ht({status:"ok"}));P.route("GET /",()=>gt(xe.replace("__VERSION__","1.0.5")));import{jsonObjectYolo as bt,ROOT_YDOC_ID as K,snapshotToLossyJson_eager as Et,snapshotToPlainLson_eager as Re}from"@liveblocks/server";import{json as St,ZenRouter as xt}from"@liveblocks/zenrouter";import{constant as Ct,enum_ as Ot,object as _e,string as wt}from"decoders";import{Base64 as Rt}from"js-base64";import*as F from"yjs";import*as T from"yjs";function It(t){return t.content instanceof T.ContentFormat||t.content instanceof T.ContentEmbed?"text":"arr"in t.content?"array":"str"in t.content?"text":"type"in t.content?"xml":"unknown"}function Tt(t){let e=[],o=t;for(;o!==null;){if(!o.deleted)if(o.content instanceof T.ContentType)e.push(o.content.type.toJSON());else if(o.content instanceof T.ContentString)e.push(o.content.str);else if(o.content instanceof T.ContentFormat){let{key:s,value:n}=o.content;e.push({key:s,value:n})}else o.content instanceof T.ContentEmbed&&e.push(o.content.embed);o=o.right}return e}function Oe(t,e,o,s=!1){if(!e._first&&e._map instanceof Map&&e._map.size>0)return t.getMap(o).toJSON();if(e._first!==null){let n=It(e._first);if(n==="text")return s?Tt(e._first):t.getText(o).toJSON();if(n==="array")return t.getArray(o).toJSON();if(n==="xml")return t.getXmlFragment(o).toJSON()}return e.toJSON()}var yt={ytext:T.Text,yxmlfragment:T.XmlFragment,yxmltext:T.XmlText,ymap:T.Map,yarray:T.Array};function we(t,e="",o=!1,s=""){let n={};if(e.length){if(t.share.has(e)){if(s.length){let a=yt[s];if(a)return t.get(e,a).toJSON()}return{[e]:Oe(t,t.share.get(e),e,o)}}return{[e]:""}}for(let[a,u]of t.share)n[a]=Oe(t,u,a,o);return n}var Le=(o=>(o.PlainLson="plain-lson",o.LossyJson="json",o))(Le||{}),_t=Ot(Le),i=new xt({authorize:({req:t})=>z(t)});function D(t){return St({error:"ROOM_NOT_FOUND",message:`Room with id "${t}" not found.`},404)}i.route("GET /v2/rooms/<roomId>",async({p:t})=>{if(!await C(t.roomId))throw D(t.roomId);return{type:"room",id:t.roomId,createdAt:new Date().toISOString(),metadata:{},defaultAccesses:["room:write"],groupsAccesses:{},usersAccesses:{}}});i.route("GET /v2/rooms",()=>{let e=le().map(o=>({type:"room",id:o,createdAt:new Date().toISOString(),metadata:{},defaultAccesses:["room:write"],groupsAccesses:{},usersAccesses:{}}));return U({data:e,nextPage:null,nextCursor:null},200,"The Liveblocks dev server doesn't implement room permissions or pagination yet, so all rooms are returned in a single page with nextPage set to null.","GET /v2/rooms")});i.route("POST /v2/rooms",_e({id:wt}),async({body:t})=>{if(await C(t.id))return new Response(JSON.stringify({error:"ROOM_ALREADY_EXISTS",message:`Room with id "${t.id}" already exists.`}),{status:409,headers:{"Content-Type":"application/json"}});try{await me(t.id)}catch(o){if(o instanceof Error&&o.message.includes("already exists"))return new Response(JSON.stringify({error:"ROOM_ALREADY_EXISTS",message:`Room with id "${t.id}" already exists.`}),{status:409,headers:{"Content-Type":"application/json"}});throw o}return{type:"room",id:t.id,createdAt:new Date().toISOString(),metadata:{},defaultAccesses:["room:write"],groupsAccesses:{},usersAccesses:{}}});i.route("POST /v2/rooms/<roomId>",()=>r());i.route("GET /v2/rooms/<roomId>/storage",async({url:t,p:e})=>{if(!await C(e.roomId))throw D(e.roomId);let s=_t.value(t.searchParams.get("format"))??"plain-lson",n=w(e.roomId);await n.load();let a=n.storage.loadedDriver.get_snapshot(!1),u=s==="json"?Et(a):Re(a);return new Response(JSON.stringify(u),{status:200,headers:{"Content-Type":"application/json"}})});i.route("POST /v2/rooms/<roomId>/storage",_e({liveblocksType:Ct("LiveObject"),data:bt}).refineType(),async({p:t,body:e})=>{if(!await C(t.roomId))throw D(t.roomId);let s=w(t.roomId);await s.load();let n=s.storage.loadedDriver.get_snapshot(!1),a=Re(n);return Object.keys(a.data).length>0?new Response(JSON.stringify({error:"CANNOT_UPDATE_EXISTING_STORAGE",message:"The room already has storage data. It's only possible to initialize the storage for an empty room.",suggestion:"Create another room or clear this room storage first."}),{status:409,headers:{"Content-Type":"application/json"}}):(await s.driver.DANGEROUSLY_reset_nodes(e),s.unload(),new Response(JSON.stringify(e),{status:200,headers:{"Content-Type":"application/json"}}))});i.route("GET /v2/rooms/<roomId>/ydoc",async({url:t,p:e})=>{if(!await C(e.roomId))throw D(e.roomId);let s=w(e.roomId);await s.load();let n=t.searchParams.get("key")??"",a=t.searchParams.get("type")??"",u=t.searchParams.get("guid")??K,c=t.searchParams.get("formatting")!==null,h=await s.yjsStorage.getYDoc(u),p=we(h,n,c,a);return new Response(JSON.stringify(p),{status:200,headers:{"Content-Type":"application/json"}})});i.route("PUT /v2/rooms/<roomId>/ydoc",async({req:t,url:e,p:o})=>{if(t.headers.get("content-type")!=="application/octet-stream")return new Response(JSON.stringify({error:"BAD_REQUEST",message:'Expected "Content-Type" header to be "application/octet-stream", and the HTTP body to be a valid binary Yjs update.'}),{status:400,headers:{"Content-Type":"application/json"}});if(!await C(o.roomId))throw D(o.roomId);let n=w(o.roomId);await n.load();let a=await t.arrayBuffer(),u=Rt.fromUint8Array(new Uint8Array(a)),c=e.searchParams.get("guid"),p=e.searchParams.get("encoder")==="v2",f=c&&c!==K?c:void 0;try{return await n.mutex.runExclusive(()=>n.yjsStorage.addYDocUpdate({},u,f,p)),new Response(JSON.stringify({success:!0}),{status:200,headers:{"Content-Type":"application/json"}})}catch(I){return new Response(JSON.stringify({error:"UNPROCESSABLE_ENTITY",message:I instanceof Error?I.message:"Could not apply update",suggestion:"Please ensure the update is correct, and you selected the correct encoder to use (v1 or v2)."}),{status:422,headers:{"Content-Type":"application/json"}})}});i.route("GET /v2/rooms/<roomId>/ydoc-binary",async({url:t,p:e})=>{if(!await C(e.roomId))throw D(e.roomId);let s=w(e.roomId);await s.load();let n=t.searchParams.get("guid")??K,a=t.searchParams.get("encoder"),u=await s.yjsStorage.getYDoc(n),c=a==="v2"?F.encodeStateAsUpdateV2(u):F.encodeStateAsUpdate(u);return new Response(c,{status:200,headers:{"Content-Type":"application/octet-stream"}})});i.route("DELETE /v2/rooms/<roomId>/storage",()=>r()),i.route("GET /v2/rooms/<roomId>/threads",()=>r()),i.route("POST /v2/rooms/<roomId>/upsert",()=>r()),i.route("DELETE /v2/rooms/<roomId>",()=>r()),i.route("POST /v2/rooms/<roomId>/update-room-id",()=>r()),i.route("POST /v2/rooms/<roomId>/update-tenant-id",()=>r()),i.route("POST /v2/rooms/<roomId>/update-organization-id",()=>r()),i.route("GET /v2/rooms/<roomId>/prewarm",()=>r()),i.route("POST /v2/rooms/<roomId>/request-storage-mutation",()=>r()),i.route("GET /v2/rooms/<roomId>/rippling/text-editor",()=>r()),i.route("POST /v2/rooms/<roomId>/rippling/text-editor",()=>r()),i.route("GET /v2/rooms/<roomId>/active_users",()=>r()),i.route("POST /v2/rooms/<roomId>/send-message",()=>r()),i.route("POST /v2/rooms/<roomId>/broadcast_event",()=>r()),i.route("GET /v2/rooms/<roomId>/versions",()=>r()),i.route("GET /v2/rooms/<roomId>/version/<version>",()=>r()),i.route("POST /v2/rooms/<roomId>/version",()=>r()),i.route("POST /v2/rooms/<roomId>/threads",()=>r()),i.route("GET /v2/rooms/<roomId>/threads/<threadId>",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/mark-as-resolved",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/mark-as-unresolved",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/subscribe",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/unsubscribe",()=>r()),i.route("GET /v2/rooms/<roomId>/threads/<threadId>/subscriptions",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/metadata",()=>r()),i.route("DELETE /v2/rooms/<roomId>/threads/<threadId>",()=>r()),i.route("GET /v2/rooms/<roomId>/threads/<threadId>/participants",()=>r()),i.route("GET /v2/rooms/<roomId>/threads/<threadId>/inbox-notifications",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/comments",()=>r()),i.route("GET /v2/rooms/<roomId>/threads/<threadId>/comments/<commentId>",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/comments/<commentId>",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/comments/<commentId>/metadata",()=>r()),i.route("DELETE /v2/rooms/<roomId>/threads/<threadId>/comments/<commentId>",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/comments/<commentId>/add-reaction",()=>r()),i.route("POST /v2/rooms/<roomId>/threads/<threadId>/comments/<commentId>/remove-reaction",()=>r()),i.route("GET /v2/rooms/<roomId>/users/<userId>/notification-settings",()=>r()),i.route("GET /v2/rooms/<roomId>/users/<userId>/subscription-settings",()=>r()),i.route("POST /v2/rooms/<roomId>/users/<userId>/notification-settings",()=>r()),i.route("POST /v2/rooms/<roomId>/users/<userId>/subscription-settings",()=>r()),i.route("DELETE /v2/rooms/<roomId>/users/<userId>/notification-settings",()=>r()),i.route("DELETE /v2/rooms/<roomId>/users/<userId>/subscription-settings",()=>r()),i.route("GET /v2/users/<userId>/inbox-notifications/<inboxNotificationId>",()=>r()),i.route("DELETE /v2/users/<userId>/inbox-notifications/<inboxNotificationId>",()=>r()),i.route("GET /v2/users/<userId>/inbox-notifications",()=>r()),i.route("DELETE /v2/users/<userId>/inbox-notifications",()=>r()),i.route("GET /v2/users/<userId>/notification-settings",()=>r()),i.route("POST /v2/users/<userId>/notification-settings",()=>r()),i.route("DELETE /v2/users/<userId>/notification-settings",()=>r()),i.route("GET /v2/users/<userId>/room-subscription-settings",()=>r()),i.route("GET /v2/users/<userId>/threads",()=>r()),i.route("POST /v2/inbox-notifications/trigger",()=>r()),i.route("POST /v2/inbox-notifications/<inboxNotificationId>/read",()=>r()),i.route("GET /v2/threads",()=>r()),i.route("POST /v2/groups",()=>r()),i.route("GET /v2/groups/<groupId>",()=>r()),i.route("POST /v2/groups/<groupId>/add-members",()=>r()),i.route("POST /v2/groups/<groupId>/remove-members",()=>r()),i.route("DELETE /v2/groups/<groupId>",()=>r()),i.route("GET /v2/groups",()=>r()),i.route("GET /v2/users/<userId>/groups",()=>r());function Dt(t,e,o,s){if(!t.upgrade(e,{data:{refuseConnection:{code:o,message:s}}}))return new Response("Could not upgrade to WebSocket",{status:426})}var A=new kt;A.relay("/v2/authorize-user/*",J);A.relay("/v2/identify-user/*",J);A.relay("/v2/c/*",d);A.relay("/v2/*",i);A.relay("/*",P);var Ne=1153;function At(t){if(t===void 0)return;let e=Number(t);return Number.isInteger(e)&&e>0&&e<=65535?e:void 0}var Mt={description:"Start the local Liveblocks dev server",async run(t){let e=Lt(t,{string:["port","host"],boolean:["help"],alias:{h:"help",p:"port"}});if(e.help){console.log("Usage: liveblocks dev [options]"),console.log(),console.log("Start the local Liveblocks dev server"),console.log(),console.log("Options:"),console.log(` -p, --port Port to listen on (default: ${Ne})`),console.log(" --host Host to bind to (default: localhost)"),console.log(" -h, --help Show this help message");return}let o=At(e.port)??Ne,s=e.host||"localhost";await Ie(o,s)&&(console.error(`Port ${o} is already in use.
303
+ Is another dev server already running?`),process.exit(1));let n=Pt.serve({hostname:s,port:o,async fetch(c,h){if(c.headers.get("Upgrade")==="websocket"){let l=oe(c);if(!l.ok)return W(l.xwarn),Dt(h,c,Nt.NOT_ALLOWED,"You have no access to this room");let{roomId:g,ticketData:v}=l,y=w(g);await y.load();let S=await y.createTicket(v),_=S.sessionKey;if(h.upgrade(c,{data:{room:y,ticket:S,sessionKey:_}})){console.log(`${L("101")} WS ${new URL(c.url).pathname}`);return}return new Response("Could not upgrade to WebSocket",{status:426})}let p=new URL(c.url),f=`${c.method} ${p.pathname}`,I=await A.fetch(c),E=I.status,G=E>=500?q(String(E)):E>=400?k(String(E)):L(String(E));console.log(`${G} ${f}`);let X=I.headers.get("X-LB-Warn")??void 0,m=I.headers.get("X-LB-Warn-Key")??void 0;return W(X,m),I},error(c){return console.error(c),new Response("An unknown error occurred",{status:500})},websocket:{async open(c){let{refuseConnection:h,room:p,ticket:f}=c.data;if(h){c.close(h.code,h.message);return}p&&f&&await p.startBrowserSession(f,c)},async message(c,h){let{room:p,sessionKey:f}=c.data;p&&f&&await p.handleData(f,h)},close(c,h,p){let{room:f,sessionKey:I}=c.data;f&&I&&f.endBrowserSession(I,h,p)}}});console.log(`Liveblocks dev server running at http://${n.hostname}:${n.port}`);let a=await ge(o),u=`http://localhost:${o}`;console.log(O("Press q to quit, c to clear")),process.stdin.isTTY&&(process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",c=>{let h=c.toString();if(h==="q"||h==="")n.stop().then(()=>process.exit(0));else if(h==="c")console.clear(),Te();else if(h==="p")if(a.length>0){let p=he(a,u);ve(p),console.log(O("Copied AI fix prompt to clipboard"))}else console.log(O("No setup issues detected"))}))}},tr=Mt;export{tr as default};
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{execFileSync as c,spawnSync as l}from"node:child_process";import{parse as t}from"@bomb.sh/args";function a(){try{return c("bun",["--version"],{stdio:"ignore"}),!0}catch{return!1}}function d(){if(a()){let e=l("bun",process.argv.slice(1),{stdio:"inherit"});process.exit(e.status??1)}else console.error("The Liveblocks local dev server requires Bun."),console.error("See https://liveblocks.io/docs/get-started/dev-server for more information."),process.exit(1)}var s=process.argv.slice(2),o=s.findIndex(e=>!e.startsWith("-")),r=t(o>=0?s.slice(0,o):s,{boolean:["help","version"],alias:{h:"help",v:"version"}}),n=o>=0?s[o]:void 0,u=o>=0?s.slice(o+1):[];async function m(e){switch(e){case"dev":return typeof Bun>"u"&&d(),(await import("./dev-server-UWZNJSR7.js")).default;case"upgrade":return(await import("./upgrade-7ASDJF6I.js")).default;default:return}}var v={dev:"Start the local Liveblocks dev server",upgrade:"Upgrade all Liveblocks packages"};function p(){console.log("liveblocks v1.0.3"),console.log(),console.log("Usage: liveblocks <command> [options]"),console.log(),console.log("SubCommands:");for(let[e,i]of Object.entries(v))console.log(` ${e.padEnd(12)} ${i}`);console.log(),console.log("Options:"),console.log(" -h, --help Show this help message"),console.log(" -v, --version Show version number")}async function g(){r.version&&(console.log("1.0.3"),process.exit(0)),(r.help||!n)&&(p(),process.exit(n?0:1));let e=await m(n);e?await e.run(u):(console.error(`Unknown command: ${n}`),console.error('Run "liveblocks --help" for usage.'),process.exit(1))}g();
2
+ import{execFileSync as c,spawnSync as t}from"node:child_process";import{parse as l}from"@bomb.sh/args";function a(){try{return c("bun",["--version"],{stdio:"ignore"}),!0}catch{return!1}}function d(){if(a()){let e=t("bun",process.argv.slice(1),{stdio:"inherit"});process.exit(e.status??1)}else console.error("The Liveblocks local dev server requires Bun."),console.error("See https://liveblocks.io/docs/get-started/dev-server for more information."),process.exit(1)}var s=process.argv.slice(2),o=s.findIndex(e=>!e.startsWith("-")),r=l(o>=0?s.slice(0,o):s,{boolean:["help","version"],alias:{h:"help",v:"version"}}),n=o>=0?s[o]:void 0,u=o>=0?s.slice(o+1):[];async function m(e){switch(e){case"dev":return typeof Bun>"u"&&d(),(await import("./dev-server-TYPUD5KO.js")).default;case"upgrade":return(await import("./upgrade-EKOUUSAC.js")).default;default:return}}var v={dev:"Start the local Liveblocks dev server",upgrade:"Upgrade all Liveblocks packages"};function p(){console.log("liveblocks v1.0.5"),console.log(),console.log("Usage: liveblocks <command> [options]"),console.log(),console.log("Commands:");for(let[e,i]of Object.entries(v))console.log(` ${e.padEnd(12)} ${i}`);console.log(),console.log("Options:"),console.log(" -h, --help Show this help message"),console.log(" -v, --version Show version number")}async function f(){r.version&&(console.log("1.0.5"),process.exit(0)),(r.help||!n)&&(p(),process.exit(n?0:1));let e=await m(n);e?await e.run(u):(console.error(`Unknown command: ${n}`),console.error('Run "liveblocks --help" for usage.'),process.exit(1))}f();
@@ -1 +1 @@
1
- import{parse as b}from"@bomb.sh/args";import{execFileSync as k}from"child_process";import{existsSync as c,readFileSync as f}from"fs";import{resolve as n}from"path";function p(e){return Object.keys(e??{}).filter(s=>s.startsWith("@liveblocks/"))}function v(){let e=process.cwd();return c(n(e,"yarn.lock"))?"yarn":c(n(e,"pnpm-lock.yaml"))?"pnpm":c(n(e,"bun.lockb"))||c(n(e,"bun.lock"))?"bun":"npm"}var h={description:"Upgrade all Liveblocks packages",run(e){let s=b(e,{boolean:["help"],alias:{h:"help"}});if(s.help){console.log("Usage: liveblocks upgrade [version]"),console.log(),console.log("Upgrade all @liveblocks/* packages in your project to the same version."),console.log(),console.log("Arguments:"),console.log(' version Target version or tag (default: "latest")'),console.log(),console.log("Options:"),console.log(" -h, --help Show this help message");return}let g=String(s._[0]??"latest"),u=n(process.cwd(),"package.json"),l;try{l=JSON.parse(f(u,"utf-8"))}catch{console.error("No package.json found in the current directory."),process.exit(1)}let r=Array.from(new Set([...p(l.dependencies),...p(l.devDependencies),...p(l.peerDependencies)]));r.length===0&&(console.error("No @liveblocks/* packages found in package.json."),process.exit(1));let d=r.map(o=>o==="@liveblocks/react-comments"?"@liveblocks/react-ui":o),m=r.filter(o=>o==="@liveblocks/react-comments"),t=v(),i,a;switch(t){case"yarn":case"bun":case"pnpm":i="add",a="remove";break;case"npm":default:i="install",a="uninstall";break}console.log(),console.log(`Upgrading all @liveblocks/* packages to ${g}...`),console.log(),m.length>0&&k(t,[a,...m],{stdio:"inherit"}),d.length>0&&k(t,[i,...d.map(o=>`${o}@${g}`)],{stdio:"inherit"}),r.includes("@liveblocks/core")&&(console.log(),console.warn("Warning: @liveblocks/core contains private APIs only. It is recommended to only rely on @liveblocks/client."),console.log())}},D=h;export{D as default};
1
+ import{parse as b}from"@bomb.sh/args";import{execFileSync as k}from"child_process";import{existsSync as c,readFileSync as f}from"fs";import{resolve as n}from"path";function p(e){return Object.keys(e??{}).filter(s=>s.startsWith("@liveblocks/"))}function v(){let e=process.cwd();return c(n(e,"yarn.lock"))?"yarn":c(n(e,"pnpm-lock.yaml"))?"pnpm":c(n(e,"bun.lockb"))||c(n(e,"bun.lock"))?"bun":"npm"}var h={description:"Upgrade all Liveblocks packages",run(e){let s=b(e,{boolean:["help"],alias:{h:"help"}});if(s.help){console.log("Usage: liveblocks upgrade [version]"),console.log(),console.log("Upgrade all @liveblocks/* packages in your project to the same version."),console.log(),console.log("Arguments:"),console.log(' version Target version or tag (default: "latest")'),console.log(),console.log("Options:"),console.log(" -h, --help Show this help message");return}let g=String(s._[0]??"latest"),u=n(process.cwd(),"package.json"),l;try{l=JSON.parse(f(u,"utf-8"))}catch{console.error("No package.json found in the current directory."),process.exit(1)}let r=Array.from(new Set([...p(l.dependencies),...p(l.devDependencies),...p(l.peerDependencies)]));r.length===0&&(console.error("No @liveblocks/* packages found in package.json."),process.exit(1));let d=r.map(o=>o==="@liveblocks/react-comments"?"@liveblocks/react-ui":o),m=r.filter(o=>o==="@liveblocks/react-comments"),t=v(),i,a;switch(t){case"yarn":case"bun":case"pnpm":i="add",a="remove";break;case"npm":default:i="install",a="uninstall";break}console.log(),console.log(`Upgrading all @liveblocks/* packages to ${g}...`),console.log(),m.length>0&&k(t,[a,...m],{stdio:"inherit"}),d.length>0&&k(t,[i,...d.map(o=>`${o}@${g}`)],{stdio:"inherit"}),r.includes("@liveblocks/core")&&(console.log(),console.warn("Warning: @liveblocks/core contains private APIs only. It is recommended to only rely on @liveblocks/client."),console.log())}},P=h;export{P as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "liveblocks",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Liveblocks command line interface",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,7 +17,7 @@
17
17
  "add-license-headers": "eslint --fix 'src/**/*.{ts,tsx}' 'test/**/*.{ts,tsx}'",
18
18
  "lint": "eslint 'src/**/*.{ts,tsx}' 'test/**/*.{ts,tsx}'",
19
19
  "lint:package": "publint --strict && attw --pack",
20
- "format": "eslint --fix 'src/**/*.{ts,tsx}' 'test/**/*.{ts,tsx}'",
20
+ "format": "eslint --fix src/ test/ ; prettier --write src/ test/",
21
21
  "test": "bun test",
22
22
  "test:typescript": "tsc --noEmit"
23
23
  },
@@ -39,7 +39,11 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@bomb.sh/args": "^0.3.1",
42
- "@liveblocks/server": "1.0.3",
43
- "@liveblocks/zenrouter": "1.0.3"
42
+ "@liveblocks/core": "3.14.0-rc1",
43
+ "@liveblocks/server": "1.0.5",
44
+ "@liveblocks/zenrouter": "1.0.5",
45
+ "decoders": "^2.8.0-1",
46
+ "js-base64": "^3.7.5",
47
+ "yjs": "^13.6.10"
44
48
  }
45
49
  }
@@ -1,296 +0,0 @@
1
- import{parse as Dn}from"@bomb.sh/args";var ut=Object.defineProperty,lt=(e,t)=>{for(var n in t)ut(e,n,{get:t[n],enumerable:!0})},ve="@liveblocks/core",K="3.14.0-rc1",ft="esm",B=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:{},ht="https://liveblocks.io/docs/errors/cross-linked",pt="https://liveblocks.io/docs/errors/dupes",me=" ";function ge(e){if(process.env.NODE_ENV==="production")console.error(e);else throw new Error(e)}function mt(e,t,n){let r=Symbol.for(e),o=n?`${t||"dev"} (${n})`:t||"dev";if(!B[r])B[r]=o;else if(B[r]!==o){let i=[`Multiple copies of Liveblocks are being loaded in your project. This will cause issues! See ${pt+me}`,"","Conflicts:",`- ${e} ${B[r]} (already loaded)`,`- ${e} ${o} (trying to load this now)`].join(`
2
- `);ge(i)}t&&K&&t!==K&&ge([`Cross-linked versions of Liveblocks found, which will cause issues! See ${ht+me}`,"","Conflicts:",`- ${ve} is at ${K}`,`- ${e} is at ${t}`,"","Always upgrade all Liveblocks packages to the same version number."].join(`
3
- `))}function be(){let e=new Set;function t(s){return e.add(s),()=>e.delete(s)}function n(s){let a=t(l=>(a(),s(l)));return a}async function r(s){let a;return new Promise(l=>{a=t(c=>{(s===void 0||s(c))&&l(c)})}).finally(()=>a?.())}function o(s){let a=!1;for(let l of e)l(s),a=!0;return a}function i(){return e.size}return{notify:o,subscribe:t,subscribeOnce:n,count:i,waitUntil:r,dispose(){e.clear()},observable:{subscribe:t,subscribeOnce:n,waitUntil:r}}}var Kn=process.env.NODE_ENV==="production"?e=>e:Object.freeze;function we(e){throw new Error(e)}var T=Symbol("kSinks"),G=Symbol("kTrigger"),ye=null,$=null;function gt(e){ye||we("Expected to be in an active batch"),ye.add(e)}var yt=class{equals;#e;[T];constructor(e){this.equals=e??Object.is,this.#e=be(),this[T]=new Set,this.get=this.get.bind(this),this.subscribe=this.subscribe.bind(this),this.subscribeOnce=this.subscribeOnce.bind(this)}dispose(){this.#e.dispose(),this.#e="(disposed)",this.equals="(disposed)"}get hasWatchers(){if(this.#e.count()>0)return!0;for(let e of this[T])if(e.hasWatchers)return!0;return!1}[G](){this.#e.notify();for(let e of this[T])gt(e)}subscribe(e){return this.#e.count()===0&&this.get(),this.#e.subscribe(e)}subscribeOnce(e){let t=this.subscribe(()=>(t(),e()));return t}waitUntil(){throw new Error("waitUntil not supported on Signals")}markSinksDirty(){for(let e of this[T])e.markDirty()}addSink(e){this[T].add(e)}removeSink(e){this[T].delete(e)}asReadonly(){return this}};var vt=Symbol(),Vn=class Y extends yt{#e;#n;#t;#r;#o;static from(...t){let n=t.pop();if(typeof n!="function"&&we("Invalid .from() call, last argument expected to be a function"),typeof t[t.length-1]=="function"){let r=n,o=t.pop();return new Y(t,o,r)}else{let r=n;return new Y(t,r)}}constructor(t,n,r){super(r),this.#n=!0,this.#e=vt,this.#r=t,this.#t=new Set,this.#o=n}dispose(){for(let t of this.#t)t.removeSink(this);this.#e="(disposed)",this.#t="(disposed)",this.#r="(disposed)",this.#o="(disposed)"}get isDirty(){return this.#n}#s(){let t=$,n;$=new Set;try{n=this.#o(...this.#r.map(r=>r.get()))}finally{let r=this.#t;this.#t=new Set;for(let o of $)this.#t.add(o),r.delete(o);for(let o of r)o.removeSink(this);for(let o of this.#t)o.addSink(this);$=t}return this.#n=!1,this.equals(this.#e,n)?!1:(this.#e=n,!0)}markDirty(){this.#n||(this.#n=!0,this.markSinksDirty())}get(){return this.#n&&this.#s(),$?.add(this),this.#e}[G](){if(!this.hasWatchers)return;this.#s()&&super[G]()}};function bt(e,t){if(process.env.NODE_ENV!=="production"&&!e){let n=new Error(t);throw n.name="Assertion failure",n}}function Ee(e,t="Expected value to be non-nullable"){return bt(e!=null,t),e}var wt={};lt(wt,{error:()=>Te,errorWithTitle:()=>_t,warn:()=>Ie,warnWithTitle:()=>St});var Se="background:#0e0d12;border-radius:9999px;color:#fff;padding:3px 7px;font-family:sans-serif;font-weight:600;",Et="font-weight:600";function _e(e){return typeof window>"u"||process.env.NODE_ENV==="test"?console[e]:(t,...n)=>console[e]("%cLiveblocks",Se,t,...n)}var Ie=_e("warn"),Te=_e("error");function Ce(e){return typeof window>"u"||process.env.NODE_ENV==="test"?console[e]:(t,n,...r)=>console[e](`%cLiveblocks%c ${t}`,Se,Et,n,...r)}var St=Ce("warn"),_t=Ce("error");var V=(e=21)=>crypto.getRandomValues(new Uint8Array(e)).reduce((t,n)=>t+=(n&=63)<36?n.toString(36):n<62?(n-26).toString(36).toUpperCase():n<63?"_":"-","");var zn=Object.freeze({UPDATE_PRESENCE:100,USER_JOINED:101,USER_LEFT:102,BROADCASTED_EVENT:103,ROOM_STATE:104,STORAGE_STATE_V7:200,STORAGE_CHUNK:210,STORAGE_STREAM_END:211,UPDATE_STORAGE:201,UPDATE_YDOC:300,THREAD_CREATED:400,THREAD_DELETED:407,THREAD_METADATA_UPDATED:401,THREAD_UPDATED:408,COMMENT_CREATED:402,COMMENT_EDITED:403,COMMENT_DELETED:404,COMMENT_REACTION_ADDED:405,COMMENT_REACTION_REMOVED:406,COMMENT_METADATA_UPDATED:409,REJECT_STORAGE_OP:299}),Z=(e=>(e[e.CLOSE_NORMAL=1e3]="CLOSE_NORMAL",e[e.CLOSE_ABNORMAL=1006]="CLOSE_ABNORMAL",e[e.UNEXPECTED_CONDITION=1011]="UNEXPECTED_CONDITION",e[e.TRY_AGAIN_LATER=1013]="TRY_AGAIN_LATER",e[e.INVALID_MESSAGE_FORMAT=4e3]="INVALID_MESSAGE_FORMAT",e[e.NOT_ALLOWED=4001]="NOT_ALLOWED",e[e.MAX_NUMBER_OF_MESSAGES_PER_SECONDS=4002]="MAX_NUMBER_OF_MESSAGES_PER_SECONDS",e[e.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS=4003]="MAX_NUMBER_OF_CONCURRENT_CONNECTIONS",e[e.MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP=4004]="MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP",e[e.MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM=4005]="MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM",e[e.ROOM_ID_UPDATED=4006]="ROOM_ID_UPDATED",e[e.KICKED=4100]="KICKED",e[e.TOKEN_EXPIRED=4109]="TOKEN_EXPIRED",e[e.CLOSE_WITHOUT_RETRY=4999]="CLOSE_WITHOUT_RETRY",e))(Z||{});var It=[250,500,1e3,2e3,4e3,8e3,1e4],Fn=It[0]-1;function Tt(e,t){let n=e===2?Te:e===1?Ie:()=>{};return()=>{n(t)}}var Hn=Tt(1,"Connection to WebSocket closed permanently. Won't retry.");var qn=Symbol(),Wn=Object.freeze({}),Jn=Array.from(new Set("null")),Gn=Array.from(new Set("true")),Yn=Array.from(new Set("false")),Zn=Array.from(new Set("nulltruefalse"));var Xn=Symbol("*");var P=(e=>(e.Read="room:read",e.Write="room:write",e.PresenceWrite="room:presence:write",e.CommentsWrite="comments:write",e.CommentsRead="comments:read",e))(P||{});var Ae=be();process.env.NODE_ENV!=="production"&&typeof window<"u"&&window.addEventListener("message",e=>{e.source===window&&e.data?.source==="liveblocks-devtools-panel"&&Ae.notify(e.data)});var Qn=Ae.observable;var er=Date.now();var tr=Symbol("notification-settings-plain");var _=32,N=126,Ct=N-_+1,At=X(0),kt=X(1),nr=At+X(-1);function X(e){let t=_+(e<0?Ct+e:e);if(t<_||t>N)throw new Error(`Invalid n value: ${e}`);return String.fromCharCode(t)}var Ot=_+1;function Rt(e){if(e==="")return!1;let t=e.length-1,n=e.charCodeAt(t);if(n<Ot||n>N)return!1;for(let r=0;r<t;r++){let o=e.charCodeAt(r);if(o<_||o>N)return!1}return!0}function Nt(e){let t=[];for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t.push(r<_?_:r>N?N:r)}for(;t.length>0&&t[t.length-1]===_;)t.length--;return t.length>0?String.fromCharCode(...t):kt}function ke(e){return Rt(e)?e:Nt(e)}var rr=Object.freeze({INIT:0,SET_PARENT_KEY:1,CREATE_LIST:2,UPDATE_OBJECT:3,CREATE_OBJECT:4,DELETE_CRDT:5,DELETE_OBJECT_KEY:6,CREATE_MAP:7,CREATE_REGISTER:8});var or=Object.freeze({type:"NoParent"});var E=Object.freeze({OBJECT:0,LIST:1,MAP:2,REGISTER:3});var sr=128*1024;var ir=Object.freeze({UPDATE_PRESENCE:100,BROADCAST_EVENT:103,FETCH_STORAGE:200,UPDATE_STORAGE:201,FETCH_YDOC:300,UPDATE_YDOC:301});var Dt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},ar=new RegExp(Object.keys(Dt).map(e=>`\\${e}`).join("|"),"g");var Lt={_:"\\_","*":"\\*","#":"\\#","`":"\\`","~":"\\~","!":"\\!","|":"\\|","(":"\\(",")":"\\)","{":"\\{","}":"\\}","[":"\\[","]":"\\]"},cr=new RegExp(Object.keys(Lt).map(e=>`\\${e}`).join("|"),"g");mt(ve,K,ft);import{DefaultMap as Ln,Room as $n}from"@liveblocks/server";import Pn from"bun";import{mkdirSync as Mn}from"fs";import{ZenRelay as xn}from"@liveblocks/zenrouter";import{ProtocolVersion as De}from"@liveblocks/server";function Oe(e){return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Re(e){let t=e.replace(/-/g,"+").replace(/_/g,"/"),n=t+"=".repeat((4-t.length%4)%4);return atob(n)}function Ne(e){let t=Math.floor(Date.now()/1e3),n={...e,iat:t,exp:t+60*60,jti:V(12)},r=Oe(JSON.stringify({alg:"none",typ:"JWT"})),o=Oe(JSON.stringify(n));return`${r}.${o}.`}function z(e){let t=e.split(".");if(t.length!==3)return null;let[n,r,o]=t;try{if(JSON.parse(Re(n)).alg!=="none")return null}catch{return null}let i;try{i=JSON.parse(Re(r))}catch{return null}if(o!==""||i.pid!=="localdev")return null;let s=i.exp;return typeof s=="number"&&s<Math.floor(Date.now()/1e3)?null:i}function $t(e,t){if(t[e])return t[e];for(let[n,r]of Object.entries(t))if(n.endsWith("*")){let o=n.slice(0,-1);if(e.startsWith(o))return r}return[]}function Le(e){let t=new URL(e.url),n=t.pathname==="/v7"?De.V7:t.pathname==="/v8"?De.V8:null;if(n===null)return null;let r=t.searchParams.get("roomId");if(!r)return null;let o=t.searchParams.get("tok");if(o!==null){let s=z(o);if(!s)return null;if(s.k==="acc"){let a=$t(r,s.perms);return a.length===0?null:[r,{version:n,id:s.uid,info:s.ui,scopes:a}]}else if(s.k==="id")return[r,{version:n,id:s.uid,info:s.ui,scopes:[P.Write]}];return null}return t.searchParams.get("pubkey")==="pk_localdev"?[r,{version:n,anonymousId:V(),scopes:["room:write"]}]:null}import{makeInMemorySnapshot as Pt,NestedMap as Mt,plainLsonToNodeStream as xt,quote as S}from"@liveblocks/server";import{Database as Ut}from"bun:sqlite";function Q(e){try{return e!==void 0?JSON.parse(e):void 0}catch{return}}function Me(e){if(e>512)throw new Error("More than 512 params not supported");return new Array(e).fill("?").join(",")}function jt(e){return Array.isArray(e)?e:Array.from(e)}function Bt(e){return e.query("SELECT node_id, crdt_json FROM nodes").values().map(([t,n])=>[t,Q(n)])}function M(e,t){let n=e.prepare(`INSERT INTO nodes (node_id, crdt_json)
4
- VALUES (?, ?)
5
- ON CONFLICT (node_id) DO UPDATE SET crdt_json = ?`);e.transaction(o=>{for(let[i,s]of o){let a=JSON.stringify(s);n.run(i,a,a)}})(t)}function xe(e,t){let n=jt(t),r=n.length;e.query(`DELETE FROM nodes WHERE node_id IN (${Me(r)})`).run(...n)}function $e(e){let t=new Mt;for(let[n,r]of e){if(r.parentId===void 0)continue;let o=t.get(r.parentId,r.parentKey);(o===void 0||n>o)&&t.set(r.parentId,r.parentKey,n)}return t}function Kt(e,t){let n=new Map(Bt(e));n.has("root")||n.set("root",{type:E.OBJECT,data:{}});let r=new Set,o=["root"],i=new Map,s=$e(n);for(;o.length>0;){let c=o.pop(),p=Ee(n.get(c));if(p.type===E.OBJECT)for(let g of s.keysAt(c))Object.prototype.hasOwnProperty.call(p.data,g)&&(delete p.data[g],r.add(c),t.warn(`[integrity] Found data key ${S(g)} from ${S(c)} (conflicted with child node)`));if(p.type!==E.REGISTER)o.push(...s.valuesAt(c));else if(n.get(p.parentId)?.type===E.OBJECT)continue;i.set(c,p)}let a=new Set;for(let[c,p]of n)i.has(c)||(p.parentId!==void 0&&i.has(p.parentId)?i.get(p.parentId)?.type===E.REGISTER?t.warn(`[integrity] Found unreachable node ${S(c)} (child of live register)`):t.warn(`[integrity] Found conflicting sibling ${S(c)} (conflicted with ${S(s.get(p.parentId,p.parentKey))} at ${S(p.parentKey)})`):t.warn(`[integrity] Found orphan ${S(c)}`),a.add(c),r.delete(c));if(r.size>0||a.size>0){if(r.size>0){let c=new Map;for(let p of r){let g=i.get(p);g!==void 0&&c.set(p,g)}M(e,c)}a.size>0&&xe(e,a)}let l=a.size===0?s:$e(i);return{nodes:i,revNodes:l}}function Pe(e,t){return e?.type===E.OBJECT&&Object.prototype.hasOwnProperty.call(e.data,t)&&e.data[t]!==void 0}var F=class{db;constructor(t){let n=new Ut(t,{create:!0});n.run("PRAGMA journal_mode = WAL"),n.run("PRAGMA case_sensitive_like = ON"),n.run(`CREATE TABLE IF NOT EXISTS system (
6
- setting TEXT NOT NULL,
7
- jval TEXT NOT NULL,
8
- PRIMARY KEY (setting)
9
- )`),n.run(`CREATE TABLE IF NOT EXISTS nodes (
10
- node_id TEXT NOT NULL,
11
- crdt_json TEXT NOT NULL,
12
- PRIMARY KEY (node_id)
13
- )`),n.run(`CREATE TABLE IF NOT EXISTS metadata (
14
- key TEXT NOT NULL,
15
- jval TEXT NOT NULL,
16
- PRIMARY KEY (key)
17
- )`),n.run(`CREATE TABLE IF NOT EXISTS ydocs (
18
- doc_id TEXT NOT NULL,
19
- key TEXT NOT NULL,
20
- data BLOB NOT NULL,
21
- PRIMARY KEY (doc_id, key)
22
- )`),this.db=n}load_nodes_api(t){let n=this.db,{nodes:r,revNodes:o}=Kt(n,t),i=d=>r.get(d),s=(d,u)=>o.get(d,u),a=(d,u)=>o.has(d,u);function l(d,u){let f;for(let m of o.keysAt(d)){let b=ke(m);b>u&&(f===void 0||b<f)&&(f=b)}return f}function c(d,u,f=!1){let m=i(u.parentId);if(m===void 0)throw new Error(`No such parent ${S(u.parentId)}`);if(u.type===E.REGISTER&&m.type===E.OBJECT)throw new Error("Cannot add register under object");let b=s(u.parentId,u.parentKey);if(b!==d){let R=Pe(m,u.parentKey);if(b!==void 0||R)if(f)h(u.parentId,u.parentKey);else throw new Error(`Key ${S(u.parentKey)} already exists`);o.set(u.parentId,u.parentKey,d)}r.set(d,u),M(n,[[d,u]])}function p(d,u){let f=i(d);if(f?.parentId===void 0)return;if(a(f.parentId,u))throw new Error(`Pos ${S(u)} already taken`);o.delete(f.parentId,f.parentKey);let m={...f,parentKey:u};r.set(d,m),o.set(f.parentId,u,d),M(n,[[d,m]])}function g(d,u,f=!1){let m=i(d);if(m?.type!==E.OBJECT)return;for(let R of Object.keys(u)){let L=s(d,R);if(L!==void 0)if(f)w(L);else throw new Error(`Child node already exists under ${R}`)}let b={...m,data:{...m.data,...u}};r.set(d,b),M(n,[[d,b]])}function w(d){let u=i(d);if(u?.parentId===void 0)return;o.delete(u.parentId,u.parentKey);let f=[],m=[d];for(;m.length>0;){let b=m.pop();m.push(...o.valuesAt(b)),r.delete(b),o.deleteAll(b),f.push(b)}xe(n,f)}function h(d,u){let f=i(d);if(Pe(f,u)){let{[u]:b,...R}=f.data,L={...f,data:R};r.set(d,L),M(n,[[d,L]])}let m=s(d,u);m!==void 0&&w(m)}return{get_node:i,iter_nodes:()=>r.entries(),has_node:d=>r.has(d),get_child_at:s,has_child_at:a,get_next_sibling:l,set_child:c,move_sibling:p,delete_node:w,delete_child_key:h,set_object_data:g,get_snapshot(d){return Pt(r)}}}DANGEROUSLY_reset_nodes(t){let n=this.db.prepare("DELETE FROM nodes"),r=this.db.prepare("INSERT INTO nodes (node_id, crdt_json) VALUES (?, ?)");this.db.transaction(()=>{n.run();for(let[i,s]of xt(t))r.run(i,JSON.stringify(s))})()}raw_iter_nodes(){return this.db.query("SELECT node_id, crdt_json FROM nodes").values().map(([t,n])=>[t,Q(n)])}get_meta(t){let r=this.db.query("SELECT jval FROM metadata WHERE key = ?").get(t)?.jval;if(r!==void 0)return Q(r)??null}put_meta(t,n){let r=JSON.stringify(n);this.db.run(`INSERT INTO metadata (key, jval)
23
- VALUES (?, ?)
24
- ON CONFLICT (key) DO UPDATE SET jval = ?
25
- `,[t,r,r])}delete_meta(t){this.db.query("DELETE FROM metadata WHERE key = ?").run(t)}next_actor(){let t=this.db.query(`INSERT INTO system (setting, jval)
26
- VALUES ('last_actor_id', '0')
27
- ON CONFLICT (setting) DO UPDATE SET jval = json(CAST(jval AS INTEGER) + 1)
28
- RETURNING jval`).get();return JSON.parse(t.jval)}iter_y_updates(t){return this.db.query("SELECT key, data FROM ydocs WHERE doc_id = ?").values(t)}write_y_updates(t,n,r){this.db.query(`INSERT INTO ydocs
29
- VALUES (?, ?, ?)
30
- ON CONFLICT (doc_id, key) DO UPDATE SET data = ?`).run(t,n,r,r)}delete_y_updates(t,n){let r=n.length;this.db.query(`DELETE FROM ydocs WHERE doc_id = ? AND key IN (${Me(r)})`).run(t,...n)}DANGEROUSLY_wipe_all_y_updates(){this.db.query("DELETE FROM ydocs").run()}close(){this.db.close()}};function ee(e){return typeof e=="number"}function Be(e){return typeof e=="string"}function Vt(e){return typeof e=="bigint"}function Ke(e){return!!e&&Object.prototype.toString.call(e)==="[object Date]"&&!isNaN(e)}function zt(e){return typeof e=="object"&&e!==null&&"then"in e&&typeof e.then=="function"}function Ve(e){return e!==null&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"}var Ft=Symbol.for("decoders.kAnnotationRegistry"),ze=globalThis[Ft]??=new WeakSet;function x(e){return ze.add(e),e}function Fe(e,t){return x({type:"object",fields:e,text:t})}function Ht(e,t){return x({type:"array",items:e,text:t})}function D(e,t){return x({type:"opaque",value:e,text:t})}function qt(e,t){return x({type:"scalar",value:e,text:t})}function He(e,t){return t!==void 0?x({...e,text:t}):e}function qe(e,t){let n=new Map([...e.fields,...t]);return Fe(n,e.text)}function We(e){return ze.has(e)}function Wt(e,t,n){n.add(e);let r=[];for(let o of e)r.push(oe(o,void 0,n));return Ht(r,t)}function Je(e,t,n){n.add(e);let r=new Map;for(let o of Object.keys(e)){let i=e[o];r.set(o,oe(i,void 0,n))}return Fe(r,t)}function oe(e,t,n){return e==null||typeof e=="string"||typeof e=="number"||typeof e=="boolean"||typeof e=="symbol"||typeof e=="bigint"||typeof e.getMonth=="function"?qt(e,t):We(e)?He(e,t):Array.isArray(e)?n.has(e)?D("<circular ref>",t):Wt(e,t,n):Ve(e)?n.has(e)?D("<circular ref>",t):Je(e,t,n):typeof e=="function"?D("<function>",t):zt(e)?D("<Promise>",t):e?.constructor?.name?D(`<${e.constructor.name}>`,t):D("???",t)}function C(e,t){return oe(e,t,new WeakSet)}function Ge(e,t){return Je(e,t,new WeakSet)}var A=" ";function te(e){return e.includes(`
31
- `)}function se(e,t=A){return te(e)?e.split(`
32
- `).map(n=>`${t}${n}`).join(`
33
- `):`${t}${e}`}var Jt=/'/g;function k(e){return typeof e=="string"?"'"+e.replace(Jt,"\\'")+"'":e===void 0?"undefined":JSON.stringify(e)}function H(e,t=[]){let n=[];if(e.type==="array"){let i=e.items,s=0;for(let a of i)for(let l of H(a,[...t,s++]))n.push(l)}else if(e.type==="object"){let i=e.fields;for(let[s,a]of i)for(let l of H(a,[...t,s]))n.push(l)}let r=e.text;if(!r)return n;let o;return t.length===0?o="":t.length===1?o=typeof t[0]=="number"?`Value at index ${t[0]}: `:`Value at key ${k(t[0])}: `:o=`Value at keypath ${k(t.map(String).join("."))}: `,[...n,`${o}${r}`]}function Gt(e,t=80){let n=JSON.stringify(e);if(n.length<=t)return n;let r=`${e.substring(0,t-15)}...`;return n=`${JSON.stringify(r)} [truncated]`,n}function Yt(e,t){let{items:n}=e;if(n.length===0)return"[]";let r=[];for(let o of n){let[i,s]=ie(o,`${t}${A}`);r.push(`${t}${A}${i},`),s!==void 0&&r.push(se(s,`${t}${A}`))}return["[",...r,`${t}]`].join(`
34
- `)}function Zt(e,t){let{fields:n}=e;if(n.size===0)return"{}";let r=[];for(let[o,i]of n){let s=Ye(o),a=`${t}${A}${" ".repeat(s.length+2)}`,[l,c]=ie(i,`${t}${A}`);r.push(`${t}${A}${s}: ${l},`),c!==void 0&&r.push(se(c,a))}return["{",...r,`${t}}`].join(`
35
- `)}function Ye(e){return typeof e=="string"?Gt(e):typeof e=="number"||typeof e=="boolean"||typeof e=="symbol"?e.toString():e===null?"null":e===void 0?"undefined":typeof e=="bigint"?`${e.toString()}n`:Ke(e)?`new Date(${k(e.toISOString())})`:e instanceof Date?"(Invalid Date)":"(unserializable)"}function ie(e,t=""){let n;e.type==="array"?n=Yt(e,t):e.type==="object"?n=Zt(e,t):e.type==="scalar"?n=Ye(e.value):n=e.value;let r=e.text;if(r!==void 0){let o="^".repeat(te(n)?1:n.length);return[n,[o,r].join(te(r)?`
36
- `:" ")]}else return[n,void 0]}function Xt(e){let[t,n]=ie(e);return n!==void 0?`${t}
37
- ${n}`:t}function Qt(e){return H(e,[]).join(`
38
- `)}function*ne(e,t){switch(e.text&&(t.length>0?yield{message:e.text,path:[...t]}:yield{message:e.text}),e.type){case"array":{let n=0;for(let r of e.items)t.push(n++),yield*ne(r,t),t.pop();break}case"object":{for(let[n,r]of e.fields)t.push(n),yield*ne(r,t),t.pop();break}case"scalar":case"opaque":break}}function en(e){return Array.from(ne(e,[]))}function Ze(e){return{ok:!0,value:e,error:void 0}}function Xe(e){return{ok:!1,value:void 0,error:e}}function tn(e){return t=>{try{let n=e(t);return Ze(n)}catch(n){return Xe(C(t,n instanceof Error?n.message:String(n)))}}}function nn(e,t){let n=t(e);if(typeof n=="string"){let r=new Error(`
39
- ${n}`);return r.name="Decoding error",r}else return n}function v(e){function t(h){return e(h,Ze,d=>Xe(We(d)?d:C(h,d)))}function n(h,y=Xt){let d=t(h);if(d.ok)return d.value;throw nn(d.error,y)}function r(h){return t(h).value}function o(h){return a(tn(h))}function i(h,y){return c(d=>h(d)?null:y)}function s(){return w}function a(h){return v((y,d,u)=>{let f=t(y);if(!f.ok)return f;let m=Ue(h)?h:h(f.value,d,u);return Ue(m)?m.decode(f.value):m})}function l(h){return a(h)}function c(h){return a((y,d,u)=>{let f=h(y);return f===null?d(y):u(typeof f=="string"?C(y,f):f)})}function p(h){return v((y,d,u)=>{let f=t(y);return f.ok?f:u(C(f.error,h))})}let w=on({verify:n,value:r,decode:t,transform:o,refine:i,refineType:s,reject:c,describe:p,then:a,pipe:l,"~standard":{version:1,vendor:"decoders",validate:h=>{let y=t(h);return y.ok?{value:y.value}:{issues:en(y.error)}}}});return w}var rn=Symbol.for("decoders.kDecoderRegistry"),Qe=globalThis[rn]??=new WeakSet;function on(e){return Qe.add(e),e}function Ue(e){return Qe.has(e)}var sn=v((e,t,n)=>Array.isArray(e)?t(e):n("Must be an array"));function ae(e){let t=e.decode;return sn.then((n,r,o)=>{let i=[];for(let s=0;s<n.length;++s){let a=n[s],l=t(a);if(l.ok)i.push(l.value);else{i.length=0;let c=l.error,p=n.slice();return p.splice(s,1,C(c,c.text?`${c.text} (at index ${s})`:`index ${s}`)),o(C(p))}}return r(i)})}function an(e){return v((t,n,r)=>t instanceof e?n(t):r(`Must be ${e.name} instance`))}function et(e){return v(t=>e().decode(t))}function cn(e,t){let n=new Set;for(let r of e)t.has(r)||n.add(r);return n}var ce=v((e,t,n)=>Ve(e)?t(e):n("Must be an object"));function de(e){let t=new Set(Object.keys(e));return ce.then((n,r,o)=>{let i=new Set(Object.keys(n)),s=cn(t,i),a={},l=null;for(let c of Object.keys(e)){let p=e[c],g=n[c],w=p.decode(g);if(w.ok){let h=w.value;h!==void 0&&(a[c]=h),s.delete(c)}else{let h=w.error;g===void 0?s.add(c):(l??=new Map,l.set(c,h))}}if(l||s.size>0){let c=Ge(n);if(l&&(c=qe(c,l)),s.size>0){let p=Array.from(s).map(k).join(", "),g=s.size>1?"keys":"key";c=He(c,`Missing ${g}: ${p}`)}return o(c)}return r(a)})}function tt(e){return ce.pipe(t=>{let n=new Set(Object.keys(t));return de(e).transform(r=>{let o=new Set(Object.keys(e));for(let s of o)n.add(s);let i={};for(let s of n)if(o.has(s)){let a=r[s];a!==void 0&&(i[s]=a)}else i[s]=t[s];return i})})}var re=`Either:
40
- `;function dn(e){return`-${se(e).substring(1)}`}function un(e){return e.startsWith(re)?e.substring(re.length):dn(e)}function q(...e){if(e.length===0)throw new Error("Pass at least one decoder to either()");return v((t,n,r)=>{let o=[];for(let s of e){let a=s.decode(t);if(a.ok)return a;o.push(a.error)}let i=re+o.map(s=>un(H(s).join(`
41
- `))).join(`
42
- `);return r(i)})}function je(e){return v((t,n,r)=>{let o=e.indexOf(t);return o!==-1?n(e[o]):r(`Must be one of ${e.map(i=>k(i)).join(", ")}`)})}function nt(e){let t=Object.values(e);if(t.some(ee)){let n=t.filter(ee),r=new Set(n.map(i=>e[i])),o=t.filter(Be).filter(i=>!r.has(i));return je([...n,...o])}else return je(t)}function ln(e){return typeof e=="function"?e():e}var fn=rt(null),hn=rt(void 0),Er=v((e,t,n)=>e==null?t(e):n("Must be undefined or null"));function U(e,t){let n=q(hn,e);return arguments.length>=2?n.transform(r=>r??ln(t)):n}function rt(e){return v((t,n,r)=>t===e?n(e):r(`Must be ${typeof e=="symbol"?String(e):k(e)}`))}var Sr=v((e,t,n)=>t(e));var pn=v((e,t,n)=>typeof e=="boolean"?t(e):n("Must be boolean")),_r=v((e,t,n)=>t(!!e));function ue(e,t){let n=t!==void 0?e:void 0,r=t??e;return ce.then((o,i,s)=>{let a={},l=new Map;for(let c of Object.keys(o)){let p=o[c],g=n?.decode(c);if(g?.ok===!1)return s(C(o,`Invalid key ${k(c)}: ${Qt(g.error)}`));let w=g?.value??c,h=r.decode(p);h.ok?l.size===0&&(a[w]=h.value):(l.set(c,h.error),a={})}return l.size>0?s(qe(Ge(o),l)):i(a)})}var mn=/^([A-Za-z]{2,12}(?:[+][A-Za-z]{2,12})?):\/\/(?:([^@:]*:?(?:[^@]+)?)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,/\w]*)?(?:#[.,!/\w]*)?)?$/,O=v((e,t,n)=>Be(e)?t(e):n("Must be string")),Ir=I(/\S/,"Must be non-empty string");function I(e,t){return O.refine(n=>e.test(n),t)}var Tr=I(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,"Must be email"),gn=q(I(mn,"Must be URL").transform(e=>new URL(e)),an(URL)),Cr=gn.refine(e=>e.protocol==="https:","Must be an HTTPS URL"),Ar=I(/^[a-z_][a-z0-9_]*$/i,"Must be valid identifier");var ot=I(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,"Must be uuid"),kr=ot.refine(e=>e[14]==="1","Must be uuidv1"),Or=ot.refine(e=>e[14]==="4","Must be uuidv4"),yn=I(/^[0-9]+$/,"Must only contain digits"),Rr=I(/^[0-9a-f]+$/i,"Must only contain hexadecimal digits"),Nr=yn.transform(Number),vn=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/,bn=v((e,t,n)=>Ke(e)?t(e):n("Must be a Date")),wn=I(vn,"Must be ISO8601 format").refine(e=>!Number.isNaN(new Date(e).getTime()),"Must be valid date/time value"),En=wn.transform(e=>new Date(e)),Dr=q(bn,En).describe("Must be a Date or date string"),Sn=v((e,t,n)=>ee(e)?t(e):n("Must be number")),le=Sn.refine(e=>Number.isFinite(e),"Number must be finite"),_n=le.refine(e=>Number.isInteger(e),"Number must be an integer"),Lr=le.refine(e=>e>=0&&!Object.is(e,-0),"Number must be positive"),$r=_n.refine(e=>e>=0&&!Object.is(e,-0),"Number must be positive"),Pr=v((e,t,n)=>Vt(e)?t(e):n("Must be bigint")),In=et(()=>ue(st)),Tn=et(()=>ae(st)),st=q(fn,O,le,pn,In,Tn).describe("Must be valid JSON value");import{json as fe,ZenRouter as Cn}from"@liveblocks/zenrouter";var it=tt({name:U(O),avatar:U(O)}).refineType();var An=nt(P),W=new Cn({authorize:({req:e})=>{let t=e.headers.get("Authorization");if(t==="Bearer sk_localdev")return!0;if(!t)throw fe({error:"Unauthorized",message:"Missing secret key"},401);if(t.startsWith("Bearer "))throw fe({error:"Forbidden",message:"Invalid secret key. The Liveblocks dev server can only be used with 'sk_localdev' as a secret key"},403);return!1}});W.route("POST /v2/authorize-user",de({userId:O,userInfo:U(it),permissions:ue(ae(An))}),({body:e})=>({token:Ne({k:"acc",pid:"localdev",uid:e.userId,perms:e.permissions,ui:e.userInfo})}));W.route("POST /v2/identify-user",()=>{throw fe({error:"Not supported",message:"ID tokens are not supported with the local dev server. To develop locally, use access tokens instead (via POST /v2/authorize-user)."},404)});import{ZenRouter as kn}from"@liveblocks/zenrouter";var he=new kn({authorize:({req:e})=>{let t=e.headers.get("Authorization");if(!t?.startsWith("Bearer "))return!1;let n=t.slice(7);return z(n)!==null}});he.route("GET /v2/rooms/<roomId>/storage",()=>({root:"Implement me"}));import{abort as ct,html as Rn,ZenRouter as Nn}from"@liveblocks/zenrouter";var at=`<!DOCTYPE html>
43
- <html lang="en">
44
- <head>
45
- <meta charset="UTF-8">
46
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
47
- <title>Liveblocks Dev Server</title>
48
- <style>
49
- * { box-sizing: border-box; }
50
- body {
51
- font-family: system-ui, -apple-system, sans-serif;
52
- background: #0f0f0f;
53
- color: #e5e5e5;
54
- min-height: 100vh;
55
- margin: 0;
56
- padding: 3rem 2rem;
57
- }
58
- main { max-width: 1000px; margin: 0 auto; }
59
- h1 { color: #fff; font-size: 1.5rem; margin: 0 0 2rem; }
60
- h2 { color: #ccc; font-size: 1rem; font-weight: 500; margin: 0 0 1rem; }
61
- .pickers { display: flex; gap: 1rem; margin-bottom: 2rem; }
62
- fieldset {
63
- border: 1px solid #333;
64
- border-radius: 6px;
65
- padding: 1rem 1.25rem;
66
- margin: 0;
67
- flex: 1;
68
- }
69
- legend { color: #888; font-size: 0.75rem; text-transform: uppercase; padding: 0 0.5rem; }
70
- label { display: block; cursor: pointer; padding: 0.25rem 0; }
71
- label.nested { margin-left: 1.5rem; color: #999; }
72
- label.disabled { color: #555; cursor: default; }
73
- input[type="radio"] { margin-right: 0.5rem; accent-color: #7c6aef; }
74
- .columns { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: start; }
75
- .column h3 { color: #888; font-size: 0.75rem; font-weight: 500; margin: 0 0 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
76
- .column pre { margin: 0; min-height: 200px; }
77
- .note { color: #555; font-style: italic; margin: 0; padding: 1rem 0; }
78
- pre {
79
- background: #1a1a1a;
80
- border: 1px solid #333;
81
- border-radius: 8px;
82
- padding: 1.25rem;
83
- overflow-x: auto;
84
- font-size: 0.8rem;
85
- line-height: 1.6;
86
- }
87
- code { font-family: "SF Mono", Consolas, monospace; }
88
- .kw { color: #c586c0; }
89
- .str { color: #ce9178; }
90
- .fn { color: #dcdcaa; }
91
- .prop { color: #9cdcfe; }
92
- .cmt { color: #6a9955; }
93
- .hl {
94
- display: inline-block;
95
- width: calc(100% + 2.5rem);
96
- margin: 0 -1.25rem;
97
- padding: 0 1.25rem;
98
- background: rgba(124, 106, 239, 0.15);
99
- animation: pulse 2s ease-in-out infinite;
100
- }
101
- @keyframes pulse {
102
- 0%, 100% { background: rgba(124, 106, 239, 0.1); }
103
- 50% { background: rgba(124, 106, 239, 0.22); }
104
- }
105
- </style>
106
- </head>
107
- <body>
108
- <main>
109
- <h1>Liveblocks Dev Server</h1>
110
-
111
- <h2>How do you want to use Liveblocks?</h2>
112
- <div class="pickers">
113
- <fieldset>
114
- <legend>Library</legend>
115
- <label><input type="radio" name="library" value="client" checked onchange="update()"> @liveblocks/client</label>
116
- <label><input type="radio" name="library" value="react" onchange="update()"> @liveblocks/react</label>
117
- </fieldset>
118
-
119
- <fieldset>
120
- <legend>Authentication</legend>
121
- <label><input type="radio" name="auth" value="public" checked onchange="update()"> Public key</label>
122
- <label><input type="radio" name="auth" value="secret" onchange="update()"> Secret key <span style="color:#666">(production)</span></label>
123
- <label class="nested disabled" id="label-id"><input type="radio" name="token" value="id" disabled onchange="update()"> ID tokens</label>
124
- <label class="nested disabled" id="label-access"><input type="radio" name="token" value="access" checked disabled onchange="update()"> Access tokens</label>
125
- </fieldset>
126
- </div>
127
-
128
- <div class="columns">
129
- <div class="column">
130
- <h3>Your frontend</h3>
131
- <pre><code id="frontend-snippet"></code></pre>
132
- </div>
133
- <div class="column" id="backend-column">
134
- <h3>Your backend</h3>
135
- <p class="note" id="backend-note">No backend changes required for public key auth.</p>
136
- <pre id="backend-pre"><code id="backend-snippet"></code></pre>
137
- </div>
138
- </div>
139
- </main>
140
-
141
- <script>
142
- function h(cls, text) {
143
- return \`<span class="\${cls}">\${text}</span>\`;
144
- }
145
-
146
- const kw = t => h('kw', t);
147
- const str = t => h('str', \`"\${t}"\`);
148
- const fn = t => h('fn', t);
149
- const prop = t => h('prop', t);
150
- const cmt = t => h('cmt', t);
151
- const hl = t => h('hl', t); // highlighted line
152
-
153
- function update() {
154
- const auth = document.querySelector('input[name="auth"]:checked').value;
155
- const token = document.querySelector('input[name="token"]:checked').value;
156
- const library = document.querySelector('input[name="library"]:checked').value;
157
-
158
- // Enable/disable token options
159
- const isSecret = auth === 'secret';
160
- document.querySelectorAll('input[name="token"]').forEach(el => el.disabled = !isSecret);
161
- document.getElementById('label-id').classList.toggle('disabled', !isSecret);
162
- document.getElementById('label-access').classList.toggle('disabled', !isSecret);
163
-
164
- // Show note or code block for backend
165
- const noteEl = document.getElementById('backend-note');
166
- const preEl = document.getElementById('backend-pre');
167
- if (!isSecret) {
168
- noteEl.style.display = 'block';
169
- noteEl.textContent = 'No backend changes required for public key auth.';
170
- preEl.style.display = 'none';
171
- } else if (token === 'id') {
172
- noteEl.style.display = 'block';
173
- noteEl.textContent = 'ID tokens are not supported with the local dev server. \u{1F622}';
174
- preEl.style.display = 'block';
175
- preEl.style.opacity = '0.5';
176
- preEl.style.filter = 'grayscale(100%)';
177
- } else {
178
- noteEl.style.display = 'none';
179
- preEl.style.display = 'block';
180
- preEl.style.opacity = '1';
181
- preEl.style.filter = 'none';
182
- }
183
-
184
- let frontend = '';
185
- let backend = '';
186
-
187
- if (library === 'client') {
188
- if (auth === 'public') {
189
- frontend = \`\${kw('import')} { \${fn('createClient')} } \${kw('from')} \${str('@liveblocks/client')};
190
-
191
- \${kw('const')} \${prop('client')} = \${fn('createClient')}({
192
- \${hl(\` \${prop('baseUrl')}: \${str('http://localhost:1153')},\`)}
193
- \${hl(\` \${prop('publicApiKey')}: \${str('pk_localdev')},\`)}
194
- });\`;
195
- } else {
196
- frontend = \`\${kw('import')} { \${fn('createClient')} } \${kw('from')} \${str('@liveblocks/client')};
197
-
198
- \${kw('const')} \${prop('client')} = \${fn('createClient')}({
199
- \${hl(\` \${prop('baseUrl')}: \${str('http://localhost:1153')},\`)}
200
- \${hl(\` \${prop('authEndpoint')}: \${str('/api/liveblocks-auth')},\`)}
201
- });\`;
202
- }
203
- } else {
204
- // React
205
- if (auth === 'public') {
206
- frontend = \`\${kw('import')} { \${fn('LiveblocksProvider')}, \${fn('RoomProvider')} } \${kw('from')} \${str('@liveblocks/react')};
207
-
208
- \${kw('function')} \${fn('App')}() {
209
- \${kw('return')} (
210
- &lt;\${fn('LiveblocksProvider')}
211
- \${hl(\` \${prop('baseUrl')}=\${str('http://localhost:1153')}\`)}
212
- \${hl(\` \${prop('publicApiKey')}=\${str('pk_localdev')}\`)}
213
- &gt;
214
- &lt;\${fn('RoomProvider')} \${prop('id')}=\${str('my-room')}&gt;
215
- {\${cmt('/* your app */')}}
216
- &lt;/\${fn('RoomProvider')}&gt;
217
- &lt;/\${fn('LiveblocksProvider')}&gt;
218
- );
219
- }\`;
220
- } else {
221
- frontend = \`\${kw('import')} { \${fn('LiveblocksProvider')}, \${fn('RoomProvider')} } \${kw('from')} \${str('@liveblocks/react')};
222
-
223
- \${kw('function')} \${fn('App')}() {
224
- \${kw('return')} (
225
- &lt;\${fn('LiveblocksProvider')}
226
- \${hl(\` \${prop('baseUrl')}=\${str('http://localhost:1153')}\`)}
227
- \${hl(\` \${prop('authEndpoint')}=\${str('/api/liveblocks-auth')}\`)}
228
- &gt;
229
- &lt;\${fn('RoomProvider')} \${prop('id')}=\${str('my-room')}&gt;
230
- {\${cmt('/* your app */')}}
231
- &lt;/\${fn('RoomProvider')}&gt;
232
- &lt;/\${fn('LiveblocksProvider')}&gt;
233
- );
234
- }\`;
235
- }
236
- }
237
-
238
- // Backend code (only for secret key auth)
239
- if (auth === 'secret') {
240
- if (token === 'access') {
241
- backend = \`\${cmt('// In api/liveblocks-auth/route.ts')}
242
- \${kw('import')} { \${fn('Liveblocks')} } \${kw('from')} \${str('@liveblocks/node')};
243
-
244
- \${kw('const')} \${prop('liveblocks')} = \${kw('new')} \${fn('Liveblocks')}({
245
- \${hl(\` \${prop('secret')}: \${str('sk_localdev')},\`)}
246
- \${hl(\` \${prop('baseUrl')}: \${str('http://localhost:1153')},\`)}
247
- });
248
-
249
- \${kw('export async function')} \${fn('POST')}() {
250
- \${kw('const')} \${prop('user')} = \${cmt('// ... get user from your own session')};
251
-
252
- \${kw('const')} \${prop('session')} = \${prop('liveblocks')}.\${fn('prepareSession')}(
253
- \${prop('user')}.\${prop('id')},
254
- { \${prop('userInfo')}: { \${prop('name')}: \${prop('user')}.\${prop('name')} } }
255
- );
256
- \${prop('session')}.\${fn('allow')}(\${str('*')}, \${prop('session')}.\${prop('FULL_ACCESS')});
257
-
258
- \${kw('const')} { \${prop('status')}, \${prop('body')} } = \${kw('await')} \${prop('session')}.\${fn('authorize')}();
259
- \${kw('return new')} \${fn('Response')}(\${prop('body')}, { \${prop('status')} });
260
- }\`;
261
- } else {
262
- backend = \`\${cmt('// In api/liveblocks-auth/route.ts')}
263
- \${kw('import')} { \${fn('Liveblocks')} } \${kw('from')} \${str('@liveblocks/node')};
264
-
265
- \${kw('const')} \${prop('liveblocks')} = \${kw('new')} \${fn('Liveblocks')}({
266
- \${prop('secret')}: \${str('sk_localdev')},
267
- \${prop('baseUrl')}: \${str('http://localhost:1153')},
268
- });
269
-
270
- \${kw('export async function')} \${fn('POST')}() {
271
- \${kw('const')} \${prop('user')} = \${cmt('// ... get user from your own session')};
272
-
273
- \${kw('const')} { \${prop('status')}, \${prop('body')} } = \${kw('await')} \${prop('liveblocks')}.\${fn('identifyUser')}({
274
- \${prop('userId')}: \${prop('user')}.\${prop('id')},
275
- \${prop('groupIds')}: [],
276
- });
277
-
278
- \${kw('return new')} \${fn('Response')}(\${prop('body')}, { \${prop('status')} });
279
- }\`;
280
- }
281
- }
282
-
283
- document.getElementById('frontend-snippet').innerHTML = frontend;
284
- document.getElementById('backend-snippet').innerHTML = backend;
285
- }
286
-
287
- update();
288
- </script>
289
- </body>
290
- </html>
291
- `;var j=new Nn({authorize:()=>!0});j.route("GET /v7",()=>ct(426));j.route("GET /v8",()=>ct(426));j.route("GET /",()=>Rn(at));var dt=".liveblocks/v1/rooms";function Un(e,t,n,r){if(!e.upgrade(t,{data:{refuseConnection:{code:n,message:r}}}))return new Response("Could not upgrade to WebSocket",{status:426})}var jn=new Ln(e=>{Mn(dt,{recursive:!0});let t=new F(`${dt}/${encodeURIComponent(e)}.db`);return new $n(e,{storage:t})}),J=new xn;J.relay("/v2/authorize-user/*",W);J.relay("/v2/*",he);J.relay("/*",j);var pe=1153,Bn={description:"Start the local Liveblocks dev server",run(e){let t=Dn(e,{string:["port"],boolean:["help"],default:{port:pe},alias:{h:"help",p:"port"}});if(t.help){console.log("Usage: liveblocks dev [options]"),console.log(),console.log("Start the local Liveblocks dev server"),console.log(),console.log("Options:"),console.log(` -p, --port Port to listen on (default: ${pe})`),console.log(" -h, --help Show this help message");return}let n=Number(t.port)||pe,r=Pn.serve({hostname:"localhost",port:n,async fetch(o,i){if(o.headers.get("Upgrade")==="websocket"){let s=Le(o);if(!s)return Un(i,o,Z.NOT_ALLOWED,"You have no access to this room");let[a,l]=s,c=jn.getOrCreate(a);await c.load();let p=await c.createTicket(l),g=p.sessionKey;return i.upgrade(o,{data:{room:c,ticket:p,sessionKey:g}})?void 0:new Response("Could not upgrade to WebSocket",{status:426})}return J.fetch(o)},error(o){return console.error(o),new Response("An unknown error occurred",{status:500})},websocket:{open(o){let{refuseConnection:i,room:s,ticket:a}=o.data;if(i){o.close(i.code,i.message);return}s&&a&&s.startBrowserSession(a,o)},async message(o,i){let{room:s,sessionKey:a}=o.data;s&&a&&await s.handleData(a,i)},close(o,i,s){let{room:a,sessionKey:l}=o.data;a&&l&&a.endBrowserSession(l,i,s)}}});console.log(`Liveblocks dev server running at http://${r.hostname}:${r.port}`)}},uo=Bn;export{uo as default};
292
- /*! Bundled license information:
293
-
294
- decoders/dist/index.js:
295
- (* istanbul ignore else -- @preserve *)
296
- */