liveblocks 1.0.1 → 1.0.3

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.
@@ -0,0 +1,296 @@
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
+ */
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{parse as i}from"@bomb.sh/args";function c(){return typeof Bun<"u"}var s=process.argv.slice(2),e=s.findIndex(o=>!o.startsWith("-")),r=i(e>=0?s.slice(0,e):s,{boolean:["help","version"],alias:{h:"help",v:"version"}}),n=e>=0?s[e]:void 0,t=e>=0?s.slice(e+1):[];async function a(o){switch(o){case"dev":return c()||(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)),(await import("./dev-server-MIZWEDIP.js")).default;case"upgrade":return(await import("./upgrade-7ASDJF6I.js")).default;default:return}}var d={dev:"Start the local Liveblocks dev server",upgrade:"Upgrade all Liveblocks packages"};function m(){console.log("liveblocks v1.0.1"),console.log(),console.log("Usage: liveblocks <command> [options]"),console.log(),console.log("SubCommands:");for(let[o,l]of Object.entries(d))console.log(` ${o.padEnd(12)} ${l}`);console.log(),console.log("Options:"),console.log(" -h, --help Show this help message"),console.log(" -v, --version Show version number")}async function u(){r.version&&(console.log("1.0.1"),process.exit(0)),(r.help||!n)&&(m(),process.exit(n?0:1));let o=await a(n);o?await o.run(t):(console.error(`Unknown command: ${n}`),console.error('Run "liveblocks --help" for usage.'),process.exit(1))}u();
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "liveblocks",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Liveblocks command line interface",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,8 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@bomb.sh/args": "^0.3.1",
42
- "@liveblocks/core": "^3.14.0-pre5",
43
- "@liveblocks/server": "1.0.1",
44
- "@liveblocks/zenrouter": "1.0.1"
42
+ "@liveblocks/server": "1.0.3",
43
+ "@liveblocks/zenrouter": "1.0.3"
45
44
  }
46
45
  }
@@ -1,294 +0,0 @@
1
- import{parse as Jt}from"@bomb.sh/args";import{WebsocketCloseCodes as Ft}from"@liveblocks/core";import{DefaultMap as Kt,Room as Bt}from"@liveblocks/server";import Wt from"bun";import{mkdirSync as qt}from"fs";import{ZenRelay as Yt}from"@liveblocks/zenrouter";import{nanoid as xe,Permission as Ue}from"@liveblocks/core";import{ProtocolVersion as ie}from"@liveblocks/server";import{nanoid as Pe}from"@liveblocks/core";function re(e){return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function oe(e){let t=e.replace(/-/g,"+").replace(/_/g,"/"),n=t+"=".repeat((4-t.length%4)%4);return atob(n)}function se(e){let t=Math.floor(Date.now()/1e3),n={...e,iat:t,exp:t+60*60,jti:Pe(12)},r=re(JSON.stringify({alg:"none",typ:"JWT"})),o=re(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(oe(n)).alg!=="none")return null}catch{return null}let i;try{i=JSON.parse(oe(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 Je(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 ae(e){let t=new URL(e.url),n=t.pathname==="/v7"?ie.V7:t.pathname==="/v8"?ie.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=Je(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:[Ue.Write]}];return null}return t.searchParams.get("pubkey")==="pk_localdev"?[r,{version:n,anonymousId:xe(),scopes:["room:write"]}]:null}import{asPos as Fe,CrdtType as w,nn as Ke}from"@liveblocks/core";import{makeInMemorySnapshot as Be,NestedMap as We,plainLsonToNodeStream as qe,quote as $}from"@liveblocks/server";import{Database as Ye}from"bun:sqlite";function J(e){try{return e!==void 0?JSON.parse(e):void 0}catch{return}}function ue(e){if(e>512)throw new Error("More than 512 params not supported");return new Array(e).fill("?").join(",")}function Ge(e){return Array.isArray(e)?e:Array.from(e)}function Ve(e){return e.query("SELECT node_id, crdt_json FROM nodes").values().map(([t,n])=>[t,J(n)])}function j(e,t){let n=e.prepare(`INSERT INTO nodes (node_id, crdt_json)
2
- VALUES (?, ?)
3
- 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 de(e,t){let n=Ge(t),r=n.length;e.query(`DELETE FROM nodes WHERE node_id IN (${ue(r)})`).run(...n)}function ce(e){let t=new We;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 Xe(e,t){let n=new Map(Ve(e));n.has("root")||n.set("root",{type:w.OBJECT,data:{}});let r=new Set,o=["root"],i=new Map,s=ce(n);for(;o.length>0;){let c=o.pop(),p=Ke(n.get(c));if(p.type===w.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 ${$(g)} from ${$(c)} (conflicted with child node)`));if(p.type!==w.REGISTER)o.push(...s.valuesAt(c));else if(n.get(p.parentId)?.type===w.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===w.REGISTER?t.warn(`[integrity] Found unreachable node ${$(c)} (child of live register)`):t.warn(`[integrity] Found conflicting sibling ${$(c)} (conflicted with ${$(s.get(p.parentId,p.parentKey))} at ${$(p.parentKey)})`):t.warn(`[integrity] Found orphan ${$(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)}j(e,c)}a.size>0&&de(e,a)}let m=a.size===0?s:ce(i);return{nodes:i,revNodes:m}}function le(e,t){return e?.type===w.OBJECT&&Object.prototype.hasOwnProperty.call(e.data,t)&&e.data[t]!==void 0}var C=class{db;constructor(t){let n=new Ye(t,{create:!0});n.run("PRAGMA journal_mode = WAL"),n.run("PRAGMA case_sensitive_like = ON"),n.run(`CREATE TABLE IF NOT EXISTS system (
4
- setting TEXT NOT NULL,
5
- jval TEXT NOT NULL,
6
- PRIMARY KEY (setting)
7
- )`),n.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
- )`),n.run(`CREATE TABLE IF NOT EXISTS metadata (
12
- key TEXT NOT NULL,
13
- jval TEXT NOT NULL,
14
- PRIMARY KEY (key)
15
- )`),n.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
- )`),this.db=n}load_nodes_api(t){let n=this.db,{nodes:r,revNodes:o}=Xe(n,t),i=l=>r.get(l),s=(l,u)=>o.get(l,u),a=(l,u)=>o.has(l,u);function m(l,u){let d;for(let y of o.keysAt(l)){let k=Fe(y);k>u&&(d===void 0||k<d)&&(d=k)}return d}function c(l,u,d=!1){let y=i(u.parentId);if(y===void 0)throw new Error(`No such parent ${$(u.parentId)}`);if(u.type===w.REGISTER&&y.type===w.OBJECT)throw new Error("Cannot add register under object");let k=s(u.parentId,u.parentKey);if(k!==l){let N=le(y,u.parentKey);if(k!==void 0||N)if(d)f(u.parentId,u.parentKey);else throw new Error(`Key ${$(u.parentKey)} already exists`);o.set(u.parentId,u.parentKey,l)}r.set(l,u),j(n,[[l,u]])}function p(l,u){let d=i(l);if(d?.parentId===void 0)return;if(a(d.parentId,u))throw new Error(`Pos ${$(u)} already taken`);o.delete(d.parentId,d.parentKey);let y={...d,parentKey:u};r.set(l,y),o.set(d.parentId,u,l),j(n,[[l,y]])}function g(l,u,d=!1){let y=i(l);if(y?.type!==w.OBJECT)return;for(let N of Object.keys(u)){let _=s(l,N);if(_!==void 0)if(d)v(_);else throw new Error(`Child node already exists under ${N}`)}let k={...y,data:{...y.data,...u}};r.set(l,k),j(n,[[l,k]])}function v(l){let u=i(l);if(u?.parentId===void 0)return;o.delete(u.parentId,u.parentKey);let d=[],y=[l];for(;y.length>0;){let k=y.pop();y.push(...o.valuesAt(k)),r.delete(k),o.deleteAll(k),d.push(k)}de(n,d)}function f(l,u){let d=i(l);if(le(d,u)){let{[u]:k,...N}=d.data,_={...d,data:N};r.set(l,_),j(n,[[l,_]])}let y=s(l,u);y!==void 0&&v(y)}return{get_node:i,iter_nodes:()=>r.entries(),has_node:l=>r.has(l),get_child_at:s,has_child_at:a,get_next_sibling:m,set_child:c,move_sibling:p,delete_node:v,delete_child_key:f,set_object_data:g,get_snapshot(l){return Be(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 qe(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,J(n)])}get_meta(t){let r=this.db.query("SELECT jval FROM metadata WHERE key = ?").get(t)?.jval;if(r!==void 0)return J(r)??null}put_meta(t,n){let r=JSON.stringify(n);this.db.run(`INSERT INTO metadata (key, jval)
21
- VALUES (?, ?)
22
- ON CONFLICT (key) DO UPDATE SET jval = ?
23
- `,[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)
24
- VALUES ('last_actor_id', '0')
25
- ON CONFLICT (setting) DO UPDATE SET jval = json(CAST(jval AS INTEGER) + 1)
26
- 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
27
- VALUES (?, ?, ?)
28
- 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 (${ue(r)})`).run(t,...n)}DANGEROUSLY_wipe_all_y_updates(){this.db.query("DELETE FROM ydocs").run()}close(){this.db.close()}};import{Permission as Mt}from"@liveblocks/core";function F(e){return typeof e=="number"}function me(e){return typeof e=="string"}function He(e){return typeof e=="bigint"}function ye(e){return!!e&&Object.prototype.toString.call(e)==="[object Date]"&&!isNaN(e)}function Ze(e){return typeof e=="object"&&e!==null&&"then"in e&&typeof e.then=="function"}function ge(e){return e!==null&&typeof e=="object"&&Object.prototype.toString.call(e)==="[object Object]"}var Qe=Symbol.for("decoders.kAnnotationRegistry"),be=globalThis[Qe]??=new WeakSet;function L(e){return be.add(e),e}function he(e,t){return L({type:"object",fields:e,text:t})}function et(e,t){return L({type:"array",items:e,text:t})}function R(e,t){return L({type:"opaque",value:e,text:t})}function tt(e,t){return L({type:"scalar",value:e,text:t})}function ke(e,t){return t!==void 0?L({...e,text:t}):e}function ve(e,t){let n=new Map([...e.fields,...t]);return he(n,e.text)}function $e(e){return be.has(e)}function nt(e,t,n){n.add(e);let r=[];for(let o of e)r.push(q(o,void 0,n));return et(r,t)}function we(e,t,n){n.add(e);let r=new Map;for(let o of Object.keys(e)){let i=e[o];r.set(o,q(i,void 0,n))}return he(r,t)}function q(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"?tt(e,t):$e(e)?ke(e,t):Array.isArray(e)?n.has(e)?R("<circular ref>",t):nt(e,t,n):ge(e)?n.has(e)?R("<circular ref>",t):we(e,t,n):typeof e=="function"?R("<function>",t):Ze(e)?R("<Promise>",t):e?.constructor?.name?R(`<${e.constructor.name}>`,t):R("???",t)}function E(e,t){return q(e,t,new WeakSet)}function Se(e,t){return we(e,t,new WeakSet)}var T=" ";function K(e){return e.includes(`
29
- `)}function Y(e,t=T){return K(e)?e.split(`
30
- `).map(n=>`${t}${n}`).join(`
31
- `):`${t}${e}`}var rt=/'/g;function I(e){return typeof e=="string"?"'"+e.replace(rt,"\\'")+"'":e===void 0?"undefined":JSON.stringify(e)}function D(e,t=[]){let n=[];if(e.type==="array"){let i=e.items,s=0;for(let a of i)for(let m of D(a,[...t,s++]))n.push(m)}else if(e.type==="object"){let i=e.fields;for(let[s,a]of i)for(let m of D(a,[...t,s]))n.push(m)}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 ${I(t[0])}: `:o=`Value at keypath ${I(t.map(String).join("."))}: `,[...n,`${o}${r}`]}function ot(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 st(e,t){let{items:n}=e;if(n.length===0)return"[]";let r=[];for(let o of n){let[i,s]=G(o,`${t}${T}`);r.push(`${t}${T}${i},`),s!==void 0&&r.push(Y(s,`${t}${T}`))}return["[",...r,`${t}]`].join(`
32
- `)}function it(e,t){let{fields:n}=e;if(n.size===0)return"{}";let r=[];for(let[o,i]of n){let s=Ee(o),a=`${t}${T}${" ".repeat(s.length+2)}`,[m,c]=G(i,`${t}${T}`);r.push(`${t}${T}${s}: ${m},`),c!==void 0&&r.push(Y(c,a))}return["{",...r,`${t}}`].join(`
33
- `)}function Ee(e){return typeof e=="string"?ot(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`:ye(e)?`new Date(${I(e.toISOString())})`:e instanceof Date?"(Invalid Date)":"(unserializable)"}function G(e,t=""){let n;e.type==="array"?n=st(e,t):e.type==="object"?n=it(e,t):e.type==="scalar"?n=Ee(e.value):n=e.value;let r=e.text;if(r!==void 0){let o="^".repeat(K(n)?1:n.length);return[n,[o,r].join(K(r)?`
34
- `:" ")]}else return[n,void 0]}function at(e){let[t,n]=G(e);return n!==void 0?`${t}
35
- ${n}`:t}function ct(e){return D(e,[]).join(`
36
- `)}function*B(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*B(r,t),t.pop();break}case"object":{for(let[n,r]of e.fields)t.push(n),yield*B(r,t),t.pop();break}case"scalar":case"opaque":break}}function lt(e){return Array.from(B(e,[]))}function Te(e){return{ok:!0,value:e,error:void 0}}function Ie(e){return{ok:!1,value:void 0,error:e}}function ut(e){return t=>{try{let n=e(t);return Te(n)}catch(n){return Ie(E(t,n instanceof Error?n.message:String(n)))}}}function dt(e,t){let n=t(e);if(typeof n=="string"){let r=new Error(`
37
- ${n}`);return r.name="Decoding error",r}else return n}function h(e){function t(f){return e(f,Te,l=>Ie($e(l)?l:E(f,l)))}function n(f,b=at){let l=t(f);if(l.ok)return l.value;throw dt(l.error,b)}function r(f){return t(f).value}function o(f){return a(ut(f))}function i(f,b){return c(l=>f(l)?null:b)}function s(){return v}function a(f){return h((b,l,u)=>{let d=t(b);if(!d.ok)return d;let y=fe(f)?f:f(d.value,l,u);return fe(y)?y.decode(d.value):y})}function m(f){return a(f)}function c(f){return a((b,l,u)=>{let d=f(b);return d===null?l(b):u(typeof d=="string"?E(b,d):d)})}function p(f){return h((b,l,u)=>{let d=t(b);return d.ok?d:u(E(d.error,f))})}let v=pt({verify:n,value:r,decode:t,transform:o,refine:i,refineType:s,reject:c,describe:p,then:a,pipe:m,"~standard":{version:1,vendor:"decoders",validate:f=>{let b=t(f);return b.ok?{value:b.value}:{issues:lt(b.error)}}}});return v}var ft=Symbol.for("decoders.kDecoderRegistry"),Oe=globalThis[ft]??=new WeakSet;function pt(e){return Oe.add(e),e}function fe(e){return Oe.has(e)}var mt=h((e,t,n)=>Array.isArray(e)?t(e):n("Must be an array"));function V(e){let t=e.decode;return mt.then((n,r,o)=>{let i=[];for(let s=0;s<n.length;++s){let a=n[s],m=t(a);if(m.ok)i.push(m.value);else{i.length=0;let c=m.error,p=n.slice();return p.splice(s,1,E(c,c.text?`${c.text} (at index ${s})`:`index ${s}`)),o(E(p))}}return r(i)})}function yt(e){return h((t,n,r)=>t instanceof e?n(t):r(`Must be ${e.name} instance`))}function Ne(e){return h(t=>e().decode(t))}function gt(e,t){let n=new Set;for(let r of e)t.has(r)||n.add(r);return n}var X=h((e,t,n)=>ge(e)?t(e):n("Must be an object"));function H(e){let t=new Set(Object.keys(e));return X.then((n,r,o)=>{let i=new Set(Object.keys(n)),s=gt(t,i),a={},m=null;for(let c of Object.keys(e)){let p=e[c],g=n[c],v=p.decode(g);if(v.ok){let f=v.value;f!==void 0&&(a[c]=f),s.delete(c)}else{let f=v.error;g===void 0?s.add(c):(m??=new Map,m.set(c,f))}}if(m||s.size>0){let c=Se(n);if(m&&(c=ve(c,m)),s.size>0){let p=Array.from(s).map(I).join(", "),g=s.size>1?"keys":"key";c=ke(c,`Missing ${g}: ${p}`)}return o(c)}return r(a)})}function Re(e){return X.pipe(t=>{let n=new Set(Object.keys(t));return H(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 W=`Either:
38
- `;function bt(e){return`-${Y(e).substring(1)}`}function ht(e){return e.startsWith(W)?e.substring(W.length):bt(e)}function P(...e){if(e.length===0)throw new Error("Pass at least one decoder to either()");return h((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=W+o.map(s=>ht(D(s).join(`
39
- `))).join(`
40
- `);return r(i)})}function pe(e){return h((t,n,r)=>{let o=e.indexOf(t);return o!==-1?n(e[o]):r(`Must be one of ${e.map(i=>I(i)).join(", ")}`)})}function _e(e){let t=Object.values(e);if(t.some(F)){let n=t.filter(F),r=new Set(n.map(i=>e[i])),o=t.filter(me).filter(i=>!r.has(i));return pe([...n,...o])}else return pe(t)}function kt(e){return typeof e=="function"?e():e}var vt=je(null),$t=je(void 0),cn=h((e,t,n)=>e==null?t(e):n("Must be undefined or null"));function A(e,t){let n=P($t,e);return arguments.length>=2?n.transform(r=>r??kt(t)):n}function je(e){return h((t,n,r)=>t===e?n(e):r(`Must be ${typeof e=="symbol"?String(e):I(e)}`))}var ln=h((e,t,n)=>t(e));var wt=h((e,t,n)=>typeof e=="boolean"?t(e):n("Must be boolean")),un=h((e,t,n)=>t(!!e));function Z(e,t){let n=t!==void 0?e:void 0,r=t??e;return X.then((o,i,s)=>{let a={},m=new Map;for(let c of Object.keys(o)){let p=o[c],g=n?.decode(c);if(g?.ok===!1)return s(E(o,`Invalid key ${I(c)}: ${ct(g.error)}`));let v=g?.value??c,f=r.decode(p);f.ok?m.size===0&&(a[v]=f.value):(m.set(c,f.error),a={})}return m.size>0?s(ve(Se(o),m)):i(a)})}var St=/^([A-Za-z]{2,12}(?:[+][A-Za-z]{2,12})?):\/\/(?:([^@:]*:?(?:[^@]+)?)@)?(?:([A-Za-z0-9.-]+)(?::([0-9]{2,5}))?)(\/(?:[-+~%/.,\w]*)?(?:\?[-+=&;%@.,/\w]*)?(?:#[.,!/\w]*)?)?$/,O=h((e,t,n)=>me(e)?t(e):n("Must be string")),dn=S(/\S/,"Must be non-empty string");function S(e,t){return O.refine(n=>e.test(n),t)}var fn=S(/^(([^<>()[\]\\.,;:\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"),Et=P(S(St,"Must be URL").transform(e=>new URL(e)),yt(URL)),pn=Et.refine(e=>e.protocol==="https:","Must be an HTTPS URL"),mn=S(/^[a-z_][a-z0-9_]*$/i,"Must be valid identifier");var Le=S(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,"Must be uuid"),yn=Le.refine(e=>e[14]==="1","Must be uuidv1"),gn=Le.refine(e=>e[14]==="4","Must be uuidv4"),Tt=S(/^[0-9]+$/,"Must only contain digits"),bn=S(/^[0-9a-f]+$/i,"Must only contain hexadecimal digits"),hn=Tt.transform(Number),It=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:[.]\d+)?(?:Z|[+-]\d{2}:?\d{2})$/,Ot=h((e,t,n)=>ye(e)?t(e):n("Must be a Date")),Nt=S(It,"Must be ISO8601 format").refine(e=>!Number.isNaN(new Date(e).getTime()),"Must be valid date/time value"),Rt=Nt.transform(e=>new Date(e)),kn=P(Ot,Rt).describe("Must be a Date or date string"),_t=h((e,t,n)=>F(e)?t(e):n("Must be number")),Q=_t.refine(e=>Number.isFinite(e),"Number must be finite"),jt=Q.refine(e=>Number.isInteger(e),"Number must be an integer"),vn=Q.refine(e=>e>=0&&!Object.is(e,-0),"Number must be positive"),$n=jt.refine(e=>e>=0&&!Object.is(e,-0),"Number must be positive"),wn=h((e,t,n)=>He(e)?t(e):n("Must be bigint")),Lt=Ne(()=>Z(Ae)),At=Ne(()=>V(Ae)),Ae=P(vt,O,Q,wt,Lt,At).describe("Must be valid JSON value");import{json as ee,ZenRouter as zt}from"@liveblocks/zenrouter";var Me=Re({name:A(O),avatar:A(O)}).refineType();var Ct=_e(Mt),x=new zt({authorize:({req:e})=>{let t=e.headers.get("Authorization");if(t==="Bearer sk_localdev")return!0;if(!t)throw ee({error:"Unauthorized",message:"Missing secret key"},401);if(t.startsWith("Bearer "))throw ee({error:"Forbidden",message:"Invalid secret key. The Liveblocks dev server can only be used with 'sk_localdev' as a secret key"},403);return!1}});x.route("POST /v2/authorize-user",H({userId:O,userInfo:A(Me),permissions:Z(V(Ct))}),({body:e})=>({token:se({k:"acc",pid:"localdev",uid:e.userId,perms:e.permissions,ui:e.userInfo})}));x.route("POST /v2/identify-user",()=>{throw ee({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 Dt}from"@liveblocks/zenrouter";var te=new Dt({authorize:({req:e})=>{let t=e.headers.get("Authorization");if(!t?.startsWith("Bearer "))return!1;let n=t.slice(7);return z(n)!==null}});te.route("GET /v2/rooms/<roomId>/storage",()=>({root:"Implement me"}));import{abort as Ce,html as xt,ZenRouter as Ut}from"@liveblocks/zenrouter";var ze=`<!DOCTYPE html>
41
- <html lang="en">
42
- <head>
43
- <meta charset="UTF-8">
44
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
45
- <title>Liveblocks Dev Server</title>
46
- <style>
47
- * { box-sizing: border-box; }
48
- body {
49
- font-family: system-ui, -apple-system, sans-serif;
50
- background: #0f0f0f;
51
- color: #e5e5e5;
52
- min-height: 100vh;
53
- margin: 0;
54
- padding: 3rem 2rem;
55
- }
56
- main { max-width: 1000px; margin: 0 auto; }
57
- h1 { color: #fff; font-size: 1.5rem; margin: 0 0 2rem; }
58
- h2 { color: #ccc; font-size: 1rem; font-weight: 500; margin: 0 0 1rem; }
59
- .pickers { display: flex; gap: 1rem; margin-bottom: 2rem; }
60
- fieldset {
61
- border: 1px solid #333;
62
- border-radius: 6px;
63
- padding: 1rem 1.25rem;
64
- margin: 0;
65
- flex: 1;
66
- }
67
- legend { color: #888; font-size: 0.75rem; text-transform: uppercase; padding: 0 0.5rem; }
68
- label { display: block; cursor: pointer; padding: 0.25rem 0; }
69
- label.nested { margin-left: 1.5rem; color: #999; }
70
- label.disabled { color: #555; cursor: default; }
71
- input[type="radio"] { margin-right: 0.5rem; accent-color: #7c6aef; }
72
- .columns { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: start; }
73
- .column h3 { color: #888; font-size: 0.75rem; font-weight: 500; margin: 0 0 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; }
74
- .column pre { margin: 0; min-height: 200px; }
75
- .note { color: #555; font-style: italic; margin: 0; padding: 1rem 0; }
76
- pre {
77
- background: #1a1a1a;
78
- border: 1px solid #333;
79
- border-radius: 8px;
80
- padding: 1.25rem;
81
- overflow-x: auto;
82
- font-size: 0.8rem;
83
- line-height: 1.6;
84
- }
85
- code { font-family: "SF Mono", Consolas, monospace; }
86
- .kw { color: #c586c0; }
87
- .str { color: #ce9178; }
88
- .fn { color: #dcdcaa; }
89
- .prop { color: #9cdcfe; }
90
- .cmt { color: #6a9955; }
91
- .hl {
92
- display: inline-block;
93
- width: calc(100% + 2.5rem);
94
- margin: 0 -1.25rem;
95
- padding: 0 1.25rem;
96
- background: rgba(124, 106, 239, 0.15);
97
- animation: pulse 2s ease-in-out infinite;
98
- }
99
- @keyframes pulse {
100
- 0%, 100% { background: rgba(124, 106, 239, 0.1); }
101
- 50% { background: rgba(124, 106, 239, 0.22); }
102
- }
103
- </style>
104
- </head>
105
- <body>
106
- <main>
107
- <h1>Liveblocks Dev Server</h1>
108
-
109
- <h2>How do you want to use Liveblocks?</h2>
110
- <div class="pickers">
111
- <fieldset>
112
- <legend>Library</legend>
113
- <label><input type="radio" name="library" value="client" checked onchange="update()"> @liveblocks/client</label>
114
- <label><input type="radio" name="library" value="react" onchange="update()"> @liveblocks/react</label>
115
- </fieldset>
116
-
117
- <fieldset>
118
- <legend>Authentication</legend>
119
- <label><input type="radio" name="auth" value="public" checked onchange="update()"> Public key</label>
120
- <label><input type="radio" name="auth" value="secret" onchange="update()"> Secret key <span style="color:#666">(production)</span></label>
121
- <label class="nested disabled" id="label-id"><input type="radio" name="token" value="id" disabled onchange="update()"> ID tokens</label>
122
- <label class="nested disabled" id="label-access"><input type="radio" name="token" value="access" checked disabled onchange="update()"> Access tokens</label>
123
- </fieldset>
124
- </div>
125
-
126
- <div class="columns">
127
- <div class="column">
128
- <h3>Your frontend</h3>
129
- <pre><code id="frontend-snippet"></code></pre>
130
- </div>
131
- <div class="column" id="backend-column">
132
- <h3>Your backend</h3>
133
- <p class="note" id="backend-note">No backend changes required for public key auth.</p>
134
- <pre id="backend-pre"><code id="backend-snippet"></code></pre>
135
- </div>
136
- </div>
137
- </main>
138
-
139
- <script>
140
- function h(cls, text) {
141
- return \`<span class="\${cls}">\${text}</span>\`;
142
- }
143
-
144
- const kw = t => h('kw', t);
145
- const str = t => h('str', \`"\${t}"\`);
146
- const fn = t => h('fn', t);
147
- const prop = t => h('prop', t);
148
- const cmt = t => h('cmt', t);
149
- const hl = t => h('hl', t); // highlighted line
150
-
151
- function update() {
152
- const auth = document.querySelector('input[name="auth"]:checked').value;
153
- const token = document.querySelector('input[name="token"]:checked').value;
154
- const library = document.querySelector('input[name="library"]:checked').value;
155
-
156
- // Enable/disable token options
157
- const isSecret = auth === 'secret';
158
- document.querySelectorAll('input[name="token"]').forEach(el => el.disabled = !isSecret);
159
- document.getElementById('label-id').classList.toggle('disabled', !isSecret);
160
- document.getElementById('label-access').classList.toggle('disabled', !isSecret);
161
-
162
- // Show note or code block for backend
163
- const noteEl = document.getElementById('backend-note');
164
- const preEl = document.getElementById('backend-pre');
165
- if (!isSecret) {
166
- noteEl.style.display = 'block';
167
- noteEl.textContent = 'No backend changes required for public key auth.';
168
- preEl.style.display = 'none';
169
- } else if (token === 'id') {
170
- noteEl.style.display = 'block';
171
- noteEl.textContent = 'ID tokens are not supported with the local dev server. \u{1F622}';
172
- preEl.style.display = 'block';
173
- preEl.style.opacity = '0.5';
174
- preEl.style.filter = 'grayscale(100%)';
175
- } else {
176
- noteEl.style.display = 'none';
177
- preEl.style.display = 'block';
178
- preEl.style.opacity = '1';
179
- preEl.style.filter = 'none';
180
- }
181
-
182
- let frontend = '';
183
- let backend = '';
184
-
185
- if (library === 'client') {
186
- if (auth === 'public') {
187
- frontend = \`\${kw('import')} { \${fn('createClient')} } \${kw('from')} \${str('@liveblocks/client')};
188
-
189
- \${kw('const')} \${prop('client')} = \${fn('createClient')}({
190
- \${hl(\` \${prop('baseUrl')}: \${str('http://localhost:1153')},\`)}
191
- \${hl(\` \${prop('publicApiKey')}: \${str('pk_localdev')},\`)}
192
- });\`;
193
- } else {
194
- frontend = \`\${kw('import')} { \${fn('createClient')} } \${kw('from')} \${str('@liveblocks/client')};
195
-
196
- \${kw('const')} \${prop('client')} = \${fn('createClient')}({
197
- \${hl(\` \${prop('baseUrl')}: \${str('http://localhost:1153')},\`)}
198
- \${hl(\` \${prop('authEndpoint')}: \${str('/api/liveblocks-auth')},\`)}
199
- });\`;
200
- }
201
- } else {
202
- // React
203
- if (auth === 'public') {
204
- frontend = \`\${kw('import')} { \${fn('LiveblocksProvider')}, \${fn('RoomProvider')} } \${kw('from')} \${str('@liveblocks/react')};
205
-
206
- \${kw('function')} \${fn('App')}() {
207
- \${kw('return')} (
208
- &lt;\${fn('LiveblocksProvider')}
209
- \${hl(\` \${prop('baseUrl')}=\${str('http://localhost:1153')}\`)}
210
- \${hl(\` \${prop('publicApiKey')}=\${str('pk_localdev')}\`)}
211
- &gt;
212
- &lt;\${fn('RoomProvider')} \${prop('id')}=\${str('my-room')}&gt;
213
- {\${cmt('/* your app */')}}
214
- &lt;/\${fn('RoomProvider')}&gt;
215
- &lt;/\${fn('LiveblocksProvider')}&gt;
216
- );
217
- }\`;
218
- } else {
219
- frontend = \`\${kw('import')} { \${fn('LiveblocksProvider')}, \${fn('RoomProvider')} } \${kw('from')} \${str('@liveblocks/react')};
220
-
221
- \${kw('function')} \${fn('App')}() {
222
- \${kw('return')} (
223
- &lt;\${fn('LiveblocksProvider')}
224
- \${hl(\` \${prop('baseUrl')}=\${str('http://localhost:1153')}\`)}
225
- \${hl(\` \${prop('authEndpoint')}=\${str('/api/liveblocks-auth')}\`)}
226
- &gt;
227
- &lt;\${fn('RoomProvider')} \${prop('id')}=\${str('my-room')}&gt;
228
- {\${cmt('/* your app */')}}
229
- &lt;/\${fn('RoomProvider')}&gt;
230
- &lt;/\${fn('LiveblocksProvider')}&gt;
231
- );
232
- }\`;
233
- }
234
- }
235
-
236
- // Backend code (only for secret key auth)
237
- if (auth === 'secret') {
238
- if (token === 'access') {
239
- backend = \`\${cmt('// In api/liveblocks-auth/route.ts')}
240
- \${kw('import')} { \${fn('Liveblocks')} } \${kw('from')} \${str('@liveblocks/node')};
241
-
242
- \${kw('const')} \${prop('liveblocks')} = \${kw('new')} \${fn('Liveblocks')}({
243
- \${hl(\` \${prop('secret')}: \${str('sk_localdev')},\`)}
244
- \${hl(\` \${prop('baseUrl')}: \${str('http://localhost:1153')},\`)}
245
- });
246
-
247
- \${kw('export async function')} \${fn('POST')}() {
248
- \${kw('const')} \${prop('user')} = \${cmt('// ... get user from your own session')};
249
-
250
- \${kw('const')} \${prop('session')} = \${prop('liveblocks')}.\${fn('prepareSession')}(
251
- \${prop('user')}.\${prop('id')},
252
- { \${prop('userInfo')}: { \${prop('name')}: \${prop('user')}.\${prop('name')} } }
253
- );
254
- \${prop('session')}.\${fn('allow')}(\${str('*')}, \${prop('session')}.\${prop('FULL_ACCESS')});
255
-
256
- \${kw('const')} { \${prop('status')}, \${prop('body')} } = \${kw('await')} \${prop('session')}.\${fn('authorize')}();
257
- \${kw('return new')} \${fn('Response')}(\${prop('body')}, { \${prop('status')} });
258
- }\`;
259
- } else {
260
- backend = \`\${cmt('// In api/liveblocks-auth/route.ts')}
261
- \${kw('import')} { \${fn('Liveblocks')} } \${kw('from')} \${str('@liveblocks/node')};
262
-
263
- \${kw('const')} \${prop('liveblocks')} = \${kw('new')} \${fn('Liveblocks')}({
264
- \${prop('secret')}: \${str('sk_localdev')},
265
- \${prop('baseUrl')}: \${str('http://localhost:1153')},
266
- });
267
-
268
- \${kw('export async function')} \${fn('POST')}() {
269
- \${kw('const')} \${prop('user')} = \${cmt('// ... get user from your own session')};
270
-
271
- \${kw('const')} { \${prop('status')}, \${prop('body')} } = \${kw('await')} \${prop('liveblocks')}.\${fn('identifyUser')}({
272
- \${prop('userId')}: \${prop('user')}.\${prop('id')},
273
- \${prop('groupIds')}: [],
274
- });
275
-
276
- \${kw('return new')} \${fn('Response')}(\${prop('body')}, { \${prop('status')} });
277
- }\`;
278
- }
279
- }
280
-
281
- document.getElementById('frontend-snippet').innerHTML = frontend;
282
- document.getElementById('backend-snippet').innerHTML = backend;
283
- }
284
-
285
- update();
286
- </script>
287
- </body>
288
- </html>
289
- `;var M=new Ut({authorize:()=>!0});M.route("GET /v7",()=>Ce(426));M.route("GET /v8",()=>Ce(426));M.route("GET /",()=>xt(ze));var De=".liveblocks/v1/rooms";function Gt(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 Vt=new Kt(e=>{qt(De,{recursive:!0});let t=new C(`${De}/${encodeURIComponent(e)}.db`);return new Bt(e,{storage:t})}),U=new Yt;U.relay("/v2/authorize-user/*",x);U.relay("/v2/*",te);U.relay("/*",M);var ne=1153,Xt={description:"Start the local Liveblocks dev server",run(e){let t=Jt(e,{string:["port"],boolean:["help"],default:{port:ne},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: ${ne})`),console.log(" -h, --help Show this help message");return}let n=Number(t.port)||ne,r=Wt.serve({hostname:"localhost",port:n,async fetch(o,i){if(o.headers.get("Upgrade")==="websocket"){let s=ae(o);if(!s)return Gt(i,o,Ft.NOT_ALLOWED,"You have no access to this room");let[a,m]=s,c=Vt.getOrCreate(a);await c.load();let p=await c.createTicket(m),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 U.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:m}=o.data;a&&m&&a.endBrowserSession(m,i,s)}}});console.log(`Liveblocks dev server running at http://${r.hostname}:${r.port}`)}},Xn=Xt;export{Xn as default};
290
- /*! Bundled license information:
291
-
292
- decoders/dist/index.js:
293
- (* istanbul ignore else -- @preserve *)
294
- */