@dobuki/hello-worker 1.0.19 → 1.0.22

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.
@@ -1,7 +1,6 @@
1
1
  import { EnterRoom } from "./signal-room";
2
2
  import { SigType, SigPayload } from "./webrtc-peer-collector";
3
- export declare function enterWorld({ uid, appId, logLine, enterRoomFunction, peerlessUserExpiration, workerUrl, }: {
4
- uid?: string;
3
+ export declare function enterWorld({ appId, logLine, enterRoomFunction, peerlessUserExpiration, workerUrl, }: {
5
4
  appId: string;
6
5
  logLine?: (direction: string, obj?: any) => void;
7
6
  enterRoomFunction?: EnterRoom<SigType, SigPayload>;
@@ -22,8 +21,8 @@ export declare function enterWorld({ uid, appId, logLine, enterRoomFunction, pee
22
21
  getUsers: () => string[];
23
22
  addMessageListener: (listener: (data: any, from: string) => void) => () => void;
24
23
  removeMessageListener: (listener: (data: any, from: string) => void) => void;
25
- addUserListener: (listener: (user: string, action: "join" | "leave", users: string[]) => void) => () => void;
26
- removeUserListener: (listener: (user: string, action: "join" | "leave", users: string[]) => void) => void;
24
+ addUserListener: (listener: (userId: string, action: "join" | "leave", users: string[]) => void) => () => void;
25
+ removeUserListener: (listener: (userId: string, action: "join" | "leave", users: string[]) => void) => void;
27
26
  end(): void;
28
27
  };
29
28
  //# sourceMappingURL=enter-world.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"enter-world.d.ts","sourceRoot":"","sources":["../src/browser/enter-world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,UAAU,EAA0B,MAAM,yBAAyB,CAAC;AAEtF,wBAAgB,UAAU,CAAC,EACzB,GAAG,EAAE,KAAK,EAAE,OAAuB,EAAE,iBAA6B,EAAE,sBAAsB,EAAE,SAAS,GACtG,EAAE;IACD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,iBAAiB,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,SAAS,CAAC,EAAE,GAAG,CAAC;CACjB;;iBAkDqB,GAAG,WAAW,MAAM;;;;;;;;;;;mCAWF,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;sCAJ9B,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;;;;EA8B3E"}
1
+ {"version":3,"file":"enter-world.d.ts","sourceRoot":"","sources":["../src/browser/enter-world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAa,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,UAAU,EAA0B,MAAM,yBAAyB,CAAC;AAEtF,wBAAgB,UAAU,CAAC,EACzB,KAAK,EAAE,OAAuB,EAAE,iBAA6B,EAAE,sBAAsB,EAAE,SAAS,GACjG,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,iBAAiB,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,SAAS,CAAC,EAAE,GAAG,CAAC;CACjB;;iBA6DqB,GAAG,WAAW,MAAM;;;;;;;;;;;mCAWF,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;sCAJ9B,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI;gCAevC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAC,MAAM,GAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI;mCAJ7D,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAC,MAAM,GAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI;;EAgCvG"}
@@ -1,4 +1,4 @@
1
- function k({userId:h,appId:f,room:H,host:j,onOpen:W,onClose:S,onError:F,logLine:M,onPeerJoined:C,onPeerLeft:G,onMessage:K}){let Y=`wss://${j}/room/${f}/${H}?userId=${encodeURIComponent(h)}`,z=new WebSocket(Y),J=h,Z=new Map,Q=!1;function q(A,c,D){if(Q)return!1;let T={type:A,to:c,payload:D};return z.send(JSON.stringify(T)),M?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",T),!0}function $(A){let c=[],D=[],T=new Set;if(A.forEach(({userId:R,peerId:B})=>{if(R===J)return;if(!Z.has(B)){let O={userId:R,peerId:B,receive:(N,X)=>q(N,B,X)};Z.set(B,O),c.push(O)}T.add(B)}),Z.values().forEach(({peerId:R,userId:B})=>{if(!T.has(R))Z.delete(R),D.push({peerId:R,userId:B})}),c.length)C(c);if(D.length)G(D)}function b(A){let c;try{c=JSON.parse(A.data)}catch{M?.("⚠️ ERROR",{error:"invalid-json"});return}if(M?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",c),c.type==="peer-joined"){$(c.users);return}if(c.type==="peer-left"){$(c.users);return}if(c.peerId&&c.userId){let{userId:D,peerId:T}=c;K(c.type,c.payload,{userId:D,peerId:T,receive:(R,B)=>q(R,T,B)})}}if(z.addEventListener("message",b),W)z.addEventListener("open",W);if(S)z.addEventListener("close",S);if(F)z.addEventListener("error",F);return{exitRoom:()=>{if(Q=!0,z.close(),z.removeEventListener("message",b),W)z.removeEventListener("open",W);if(S)z.removeEventListener("close",S);if(F)z.removeEventListener("error",F)}}}function E({userId:h,appId:f,room:H,host:j,onOpen:W,onClose:S,onError:F,onPeerJoined:M,onPeerLeft:C,onMessage:G,logLine:K,workerUrl:Y}){if(!Y)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),k({userId:h,appId:f,room:H,host:j,onOpen:W,onClose:S,onError:F,onPeerJoined:M,onPeerLeft:C,onMessage:G});let z=new Worker(Y,{type:"module"}),J=!1;function Z({userId:q,peerId:$}){return{userId:q,peerId:$,receive:(b,A)=>{if(J)return!1;return z.postMessage({cmd:"send",toPeerId:$,type:b,payload:A}),!0}}}let Q=(q)=>{let $=q.data;if($.kind==="open")W?.();else if($.kind==="close")z.terminate();else if($.kind==="error")F?.();else if($.kind==="peer-joined")M($.users.map((b)=>Z({userId:b.userId,peerId:b.peerId})));else if($.kind==="peer-left")C($.users);else if($.kind==="message")G($.type,$.payload,Z({userId:$.fromUserId,peerId:$.fromPeerId}));else if($.kind==="log")K?.($.direction,$.obj)};return z.addEventListener("message",Q),z.postMessage({cmd:"enter",userId:h,appId:f,room:H,host:j}),{exitRoom:()=>{J=!0,z.removeEventListener("message",Q),z.postMessage({cmd:"exit"})}}}var v=E;function U({userId:h,appId:f,receivePeerConnection:H,peerlessUserExpiration:j,rtcConfig:W={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},enterRoomFunction:S=v,logLine:F=console.debug,onLeaveUser:M,workerUrl:C}){let G=new Map;function K(){return[...G.keys()]}let Y=new Set;function z(c){let D=G.get(c.userId);if(!D){let T={userId:c.userId,pc:new RTCPeerConnection(W),pendingRemoteIce:[],peers:new Map};T.peers.set(c.peerId,c),G.set(c.userId,T),T.pc.onicecandidate=(R)=>{if(!R.candidate)return;for(let B of T.peers.values())if(B.receive("ice",R.candidate.toJSON()))break},T.pc.onconnectionstatechange=()=>{F("\uD83D\uDCAC",{event:"pc-state",userId:T.userId,state:T.pc.connectionState})},D=T,Y.forEach((R)=>R(c.userId,"join",K())),G.set(D.userId,D)}else if(D)clearTimeout(D.expirationTimeout),D.expirationTimeout=0,D.peers.set(c.peerId,c);return D}function J(c){M?.(c);let D=G.get(c);if(!D)return;try{D.pc.close()}catch{}G.delete(c),Y.forEach((T)=>T(c,"leave",K())),F("\uD83D\uDC64 USER LEFT",c)}async function Z(c){if(!c.pc.remoteDescription)return;let D=c.pendingRemoteIce;c.pendingRemoteIce=[];for(let T of D)try{await c.pc.addIceCandidate(T)}catch(R){F("⚠️ ERROR",{error:"add-ice-failed",userId:c.userId,detail:String(R)})}}let Q=new Map;function q({room:c,host:D}){let T=`${D}/room/${c}`,R=Q.get(T);if(R)R.exitRoom(),Q.delete(T)}function $({room:c,host:D}){return new Promise((T,R)=>{async function B(N){let _=z(N).pc,V=await _.createOffer();await _.setLocalDescription(V),N.receive("offer",_.localDescription?.toJSON())}let{exitRoom:O}=S({userId:h,appId:f,room:c,host:D,logLine:F,workerUrl:C,onOpen:T,onError:R,onPeerJoined(N){N.forEach((X)=>{let V=z(X).pc;H({pc:V,userId:X.userId,initiator:!0}),B(X)})},onPeerLeft(N){N.forEach(({userId:X,peerId:_})=>{let V=G.get(X);if(!V)return;if(V.peers.delete(_),V.peers.size===0)V.expirationTimeout=setTimeout(()=>J(X),j??0)})},async onMessage(N,X,_){let V=z(_),x=V.pc;if(N==="offer"){H({pc:x,userId:_.userId,initiator:!1}),await x.setRemoteDescription(X);let y=await x.createAnswer();await x.setLocalDescription(y),_.receive("answer",x.localDescription?.toJSON()),await Z(V);return}if(N==="answer"){await x.setRemoteDescription(X),await Z(V),H({pc:x,userId:_.userId,initiator:!0});return}if(N==="ice"){let y=X;if(!x.remoteDescription){V.pendingRemoteIce.push(y);return}try{await x.addIceCandidate(y)}catch(P){F("⚠️ ERROR",{error:"add-ice-failed",userId:V.userId,detail:String(P)})}return}}});Q.set(`${D}/room/${c}`,{exitRoom:O,room:c,host:D})})}function b(c){Y.delete(c)}function A(c){return Y.add(c),()=>{b(c)}}return{enterRoom:$,exitRoom:q,leaveUser:J,getUsers:K,addUserListener:A,removeUserListener:b,getRooms(){return Array.from(Q.values())},end(){Q.forEach(({exitRoom:c})=>c()),Q.clear(),G.forEach(({userId:c})=>J(c)),Y.clear()}}}function t({uid:h,appId:f,logLine:H=console.debug,enterRoomFunction:j=E,peerlessUserExpiration:W,workerUrl:S}){let F=h??`user-${crypto.randomUUID()}`,M={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},C=new Set;function G(D,T){T.onopen=()=>H("\uD83D\uDCAC",{event:"dc-open",userId:D}),T.onmessage=({data:R})=>{C.forEach((B)=>B(R,D)),H("\uD83D\uDCAC",{event:"dc-message",userId:D,data:R})},T.onclose=()=>H("\uD83D\uDCAC",{event:"dc-close",userId:D}),T.onerror=()=>H("⚠️ ERROR",{error:"dc-error",userId:D})}let K=new Map,{enterRoom:Y,exitRoom:z,getUsers:J,leaveUser:Z,addUserListener:Q,removeUserListener:q,end:$}=U({userId:F,appId:f,rtcConfig:M,enterRoomFunction:j,logLine:H,workerUrl:S,peerlessUserExpiration:W,onLeaveUser(D){let T=K.get(D);try{T?.close()}catch{}K.delete(D)},receivePeerConnection({pc:D,userId:T,initiator:R}){if(R){let B=D.createDataChannel("data");G(T,B),K.set(T,B)}else D.ondatachannel=(B)=>{let O=B.channel;G(T,O),K.set(T,O)};H("\uD83D\uDCAC",{event:"pc-ready",userId:T,initiator:R})}});function b(D,T){K.forEach((R,B)=>{if(T&&B!==T)return;if(R.readyState==="open")R.send(D)})}function A(D){C.delete(D)}function c(D){return C.add(D),()=>{A(D)}}return{userId:F,send:b,enterRoom:Y,exitRoom:z,leaveUser:Z,getUsers:J,addMessageListener:c,removeMessageListener:A,addUserListener:Q,removeUserListener:q,end(){K.forEach((D)=>{try{D.close()}catch{}}),K.clear(),$()}}}export{t as enterWorld};
1
+ function x({userId:S,appId:Z,room:C,host:j,onOpen:W,onClose:K,onError:f,logLine:A,onPeerJoined:_,onPeerLeft:V,onMessage:X}){let Y=`wss://${j}/room/${Z}/${C}?userId=${encodeURIComponent(S)}`,H=new WebSocket(Y),$=S,q=new Map,h=!1;function D(Q,G,N){if(h)return!1;let c={type:Q,to:G,payload:N};return H.send(JSON.stringify(c)),A?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",c),!0}function T(Q){let G=[],N=[],c=new Set;if(Q.forEach(({userId:R,peerId:z})=>{if(R===$)return;if(!q.has(z)){let F={userId:R,peerId:z,receive:(b,J)=>D(b,z,J)};q.set(z,F),G.push(F)}c.add(z)}),q.values().forEach(({peerId:R,userId:z})=>{if(!c.has(R))q.delete(R),N.push({peerId:R,userId:z})}),G.length)_(G);if(N.length)V(N)}function B(Q){let G;try{G=JSON.parse(Q.data)}catch{A?.("⚠️ ERROR",{error:"invalid-json"});return}if(A?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",G),G.type==="peer-joined"||G.type==="peer-left"){T(G.users);return}if(G.peerId&&G.userId){let{userId:N,peerId:c}=G;X(G.type,G.payload,{userId:N,peerId:c,receive:(R,z)=>D(R,c,z)})}}if(H.addEventListener("message",B),W)H.addEventListener("open",W);if(K)H.addEventListener("close",K);if(f)H.addEventListener("error",f);return{exitRoom:()=>{if(h=!0,H.close(),H.removeEventListener("message",B),W)H.removeEventListener("open",W);if(K)H.removeEventListener("close",K);if(f)H.removeEventListener("error",f)}}}function M({userId:S,appId:Z,room:C,host:j,onOpen:W,onClose:K,onError:f,onPeerJoined:A,onPeerLeft:_,onMessage:V,logLine:X,workerUrl:Y}){if(!Y)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),x({userId:S,appId:Z,room:C,host:j,onOpen:W,onClose:K,onError:f,onPeerJoined:A,onPeerLeft:_,onMessage:V});let H=new Worker(Y,{type:"module"}),$=!1;function q({userId:D,peerId:T}){return{userId:D,peerId:T,receive:(B,Q)=>{if($)return!1;return H.postMessage({cmd:"send",toPeerId:T,type:B,payload:Q}),!0}}}let h=(D)=>{let T=D.data;if(T.kind==="open")W?.();else if(T.kind==="close")H.terminate();else if(T.kind==="error")f?.();else if(T.kind==="peer-joined")A(T.users.map((B)=>q({userId:B.userId,peerId:B.peerId})));else if(T.kind==="peer-left")_(T.users);else if(T.kind==="message")V(T.type,T.payload,q({userId:T.fromUserId,peerId:T.fromPeerId}));else if(T.kind==="log")X?.(T.direction,T.obj)};return H.addEventListener("message",h),H.postMessage({cmd:"enter",userId:S,appId:Z,room:C,host:j}),{exitRoom:()=>{$=!0,H.removeEventListener("message",h),H.postMessage({cmd:"exit"})}}}var E=M;function i({appId:S,receivePeerConnection:Z,peerlessUserExpiration:C,rtcConfig:j={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},enterRoomFunction:W=E,logLine:K=console.debug,onLeaveUser:f,workerUrl:A}){let _=`user-${crypto.randomUUID()}`,V=new Map;function X(D){let T=V.get(D.userId);if(!T){let B={userId:D.userId,pc:new RTCPeerConnection(j),pendingRemoteIce:[],peers:new Map};B.peers.set(D.peerId,D),V.set(D.userId,B),B.pc.onicecandidate=(Q)=>{if(!Q.candidate)return;for(let G of B.peers.values())if(G.receive("ice",Q.candidate.toJSON()))break},B.pc.onconnectionstatechange=()=>{K("\uD83D\uDCAC",{event:"pc-state",userId:B.userId,state:B.pc.connectionState})},T=B,V.set(T.userId,T)}else if(T)clearTimeout(T.expirationTimeout),T.expirationTimeout=0,T.peers.set(D.peerId,D);return T}function Y(D){f?.(D);let T=V.get(D);if(!T)return;try{T.pc.close()}catch{}V.delete(D)}async function H(D){if(!D.pc.remoteDescription)return;let T=D.pendingRemoteIce;D.pendingRemoteIce=[];for(let B of T)try{await D.pc.addIceCandidate(B)}catch(Q){K("⚠️ ERROR",{error:"add-ice-failed",userId:D.userId,detail:String(Q)})}}let $=new Map;function q({room:D,host:T}){let B=`${T}/room/${D}`,Q=$.get(B);if(Q)Q.exitRoom(),$.delete(B)}function h({room:D,host:T}){return new Promise((B,Q)=>{async function G(c){let z=X(c).pc,F=await z.createOffer();await z.setLocalDescription(F),c.receive("offer",z.localDescription?.toJSON())}let{exitRoom:N}=W({userId:_,appId:S,room:D,host:T,logLine:K,workerUrl:A,onOpen:B,onError:Q,onPeerJoined(c){c.forEach((R)=>{let F=X(R).pc;Z({pc:F,userId:R.userId,initiator:!0}),G(R)})},onPeerLeft(c){c.forEach(({userId:R,peerId:z})=>{let F=V.get(R);if(!F)return;if(F.peers.delete(z),!F.peers.size)F.expirationTimeout=setTimeout(()=>Y(R),C??0)})},async onMessage(c,R,z){let F=X(z),b=F.pc;if(c==="offer"){Z({pc:b,userId:z.userId,initiator:!1}),await b.setRemoteDescription(R);let J=await b.createAnswer();await b.setLocalDescription(J),z.receive("answer",b.localDescription?.toJSON()),await H(F);return}if(c==="answer"){await b.setRemoteDescription(R),await H(F);return}if(c==="ice"){let J=R;if(!b.remoteDescription){F.pendingRemoteIce.push(J);return}try{await b.addIceCandidate(J)}catch(O){K("⚠️ ERROR",{error:"add-ice-failed",userId:F.userId,detail:String(O)})}return}}});$.set(`${T}/room/${D}`,{exitRoom:N,room:D,host:T})})}return{userId:_,enterRoom:h,exitRoom:q,leaveUser:Y,getRooms(){return Array.from($.values())},end(){$.forEach(({exitRoom:D})=>D()),$.clear(),V.forEach(({userId:D})=>Y(D)),V.clear()}}}function l({appId:S,logLine:Z=console.debug,enterRoomFunction:C=M,peerlessUserExpiration:j,workerUrl:W}){let K=[],f={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},A=new Set;function _(){return K}function V(c,R){R.onopen=()=>{Z("\uD83D\uDCAC",{event:"dc-open",userId:c}),K.push(c),Y.forEach((z)=>z(c,"join",K))},R.onmessage=({data:z})=>{A.forEach((F)=>F(z,c)),Z("\uD83D\uDCAC",{event:"dc-message",userId:c,data:z})},R.onclose=()=>{Z("\uD83D\uDCAC",{event:"dc-close",userId:c}),K.splice(K.indexOf(c),1),Y.forEach((z)=>z(c,"leave",K))},R.onerror=()=>Z("⚠️ ERROR",{error:"dc-error",userId:c})}let X=new Map,Y=new Set,{userId:H,enterRoom:$,exitRoom:q,leaveUser:h,end:D}=i({appId:S,rtcConfig:f,enterRoomFunction:C,logLine:Z,workerUrl:W,peerlessUserExpiration:j,onLeaveUser(c){let R=X.get(c);try{R?.close()}catch{}X.delete(c)},receivePeerConnection({pc:c,userId:R,initiator:z}){if(z){let F=c.createDataChannel("data");V(R,F),X.set(R,F)}else c.ondatachannel=(F)=>{let b=F.channel;V(R,b),X.set(R,b),c.ondatachannel=null}}});function T(c,R){X.forEach((z,F)=>{if(R&&F!==R)return;if(z.readyState==="open")z.send(c)})}function B(c){A.delete(c)}function Q(c){return A.add(c),()=>{B(c)}}function G(c){Y.delete(c)}function N(c){return Y.add(c),()=>{G(c)}}return{userId:H,send:T,enterRoom:$,exitRoom:q,leaveUser:h,getUsers:_,addMessageListener:Q,removeMessageListener:B,addUserListener:N,removeUserListener:G,end(){X.forEach((c)=>{try{c.close()}catch{}}),X.clear(),D(),Y.clear(),K.length=0}}}export{l as enterWorld};
2
2
 
3
- //# debugId=785DC53F308F768364756E2164756E21
3
+ //# debugId=82AA55FF49A2708A64756E2164756E21
4
4
  //# sourceMappingURL=enter-world.js.map
@@ -2,12 +2,12 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/browser/impl/signal-room.ts", "../src/browser/signal-room.ts", "../src/browser/webrtc-peer-collector.ts", "../src/browser/enter-world.ts"],
4
4
  "sourcesContent": [
5
- "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
5
+ "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\" || msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
6
6
  "import type { IPeer } from \"./impl/signal-room.js\";\nimport { enterRoom as baseEnterRoom } from \"./impl/signal-room.js\";\nimport { RoomEvent } from \"./signal-room.worker.js\";\n\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n logLine,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n onPeerJoined: (users: IPeer<T, P>[]) => void;\n onPeerLeft: (users: {userId: string, peerId: string}[]) => void;\n onMessage: (type: T, payload: P, from: IPeer<T, P>) => void;\n logLine?: (direction: string, obj?: any) => void;\n\n // Pass the URL to your worker file (bundler will handle it)\n workerUrl?: URL;\n}): { exitRoom: () => void } {\n if (!workerUrl) {\n const CDN_WORKER_URL = `https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js`;\n\n console.warn(\"Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:\", CDN_WORKER_URL);\n return baseEnterRoom<T, P>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n });\n }\n const worker = new Worker(workerUrl, { type: \"module\" });\n let exited = false;\n\n function makeUser({ userId, peerId }: { userId: string; peerId: string }): IPeer<T, P> {\n return {\n userId,\n peerId,\n receive: (type: T, payload: P) => {\n if (exited) return false;\n worker.postMessage({ cmd: \"send\", toPeerId: peerId, type, payload });\n return true;\n },\n };\n }\n\n const onWorkerMessage = (e: MessageEvent<RoomEvent<T, P>>) => {\n const ev = e.data;\n\n if (ev.kind === \"open\") onOpen?.();\n else if (ev.kind === \"close\") worker.terminate();\n else if (ev.kind === \"error\") onError?.();\n else if (ev.kind === \"peer-joined\") onPeerJoined(ev.users.map(ev => makeUser({ userId: ev.userId, peerId: ev.peerId })));\n else if (ev.kind === \"peer-left\") onPeerLeft(ev.users);\n else if (ev.kind === \"message\") onMessage(ev.type, ev.payload, makeUser({ userId: ev.fromUserId, peerId: ev.fromPeerId }));\n else if (ev.kind === \"log\") logLine?.(ev.direction, ev.obj);\n };\n\n worker.addEventListener(\"message\", onWorkerMessage);\n\n worker.postMessage({ cmd: \"enter\", userId, appId, room, host });\n\n return {\n exitRoom: () => {\n exited = true;\n worker.removeEventListener(\"message\", onWorkerMessage);\n worker.postMessage({ cmd: \"exit\" });\n },\n };\n}\n\nexport type EnterRoom<T extends string, P> = typeof enterRoom<T, P>;\n",
7
- "import { IPeer } from \"./impl/signal-room\";\nimport { EnterRoom, enterRoom } from \"./signal-room\";\n\nexport type SigType = \"offer\" | \"answer\" | \"ice\";\nexport type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;\n\ntype UserState = {\n userId: string;\n pc: RTCPeerConnection;\n\n // ICE that arrived before we had remoteDescription\n pendingRemoteIce: RTCIceCandidateInit[];\n\n // the signaling \"user\" handle so we can send messages\n peers: Map<string, IPeer<SigType, SigPayload>>;\n\n expirationTimeout?: number;\n};\ntype UserListener = (user: string, action: \"join\"|\"leave\", users: string[]) => void;\n\nconst DEFAULT_ENTER_ROOM = enterRoom;\n\n\nexport function collectPeerConnections({\n userId,\n appId,\n receivePeerConnection,\n peerlessUserExpiration,\n rtcConfig = { iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }] },\n enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM,\n logLine = console.debug,\n onLeaveUser,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n rtcConfig?: RTCConfiguration;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n onLeaveUser?: (userId: string) => void;\n logLine?: (direction: string, obj?: any) => void;\n workerUrl?: URL;\n peerlessUserExpiration?: number;\n receivePeerConnection(connection: { pc: RTCPeerConnection, userId: string, initiator: boolean }): void;\n}) {\n const users: Map<string, UserState> = new Map();\n function getUsers() {\n return [...users.keys()];\n }\n\n const userListener: Set<UserListener> = new Set();\n function getPeer(peer: IPeer<SigType, SigPayload>): UserState {\n let state = users.get(peer.userId);\n if (!state) {\n const newState: UserState = {\n userId: peer.userId,\n pc: new RTCPeerConnection(rtcConfig),\n pendingRemoteIce: [],\n peers: new Map(),\n };\n newState.peers.set(peer.peerId, peer);\n users.set(peer.userId, newState);\n\n // Send local ICE candidates to this peer\n newState.pc.onicecandidate = (ev) => {\n if (!ev.candidate) return;\n for(let user of newState.peers.values()) {\n const success = user.receive(\"ice\", ev.candidate.toJSON());\n if (success) break;\n }\n };\n \n newState.pc.onconnectionstatechange = () => {\n logLine(\"💬\", { event: \"pc-state\", userId: newState.userId, state: newState.pc.connectionState });\n };\n state = newState;\n\n // New user\n userListener.forEach(listener => listener(peer.userId, \"join\", getUsers()));\n users.set(state.userId, state);\n } else if (state) {\n clearTimeout(state.expirationTimeout);\n state.expirationTimeout = 0;\n state.peers.set(peer.peerId, peer);\n }\n return state;\n }\n\n function leaveUser(userId: string) {\n onLeaveUser?.(userId);\n const p = users.get(userId);\n if (!p) return;\n try { p.pc.close(); } catch {}\n users.delete(userId);\n userListener.forEach(listener => listener(userId, \"leave\", getUsers()));\n logLine(\"👤 USER LEFT\", userId);\n }\n\n async function flushRemoteIce(state: UserState) {\n if (!state.pc.remoteDescription) return;\n\n const queued = state.pendingRemoteIce;\n state.pendingRemoteIce = [];\n\n for (const ice of queued) {\n try {\n await state.pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n }\n }\n\n const roomsEntered = new Map<string, { room: string; host: string; exitRoom: () => void }>();\n\n function exit({ room, host }: { room: string; host: string; }) {\n const key = `${host}/room/${room}`;\n const session = roomsEntered.get(key);\n if (session) {\n session.exitRoom();\n roomsEntered.delete(key);\n }\n }\n\n function enter({ room, host }: { room: string; host: string; }) {\n return new Promise<void>((resolve, reject) => {\n async function makeOffer(user: IPeer) {\n // Offer flow: createOffer -> setLocalDescription -> send localDescription\n const state = getPeer(user);\n const pc = state.pc;\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n user.receive(\"offer\", pc.localDescription?.toJSON()!);\n }\n\n const { exitRoom } = enterRoom({\n userId,\n appId,\n room,\n host,\n logLine,\n workerUrl,\n\n onOpen: resolve,\n onError: reject,\n\n // Existing peers initiate to the newcomer (Option 1)\n onPeerJoined(joiningUsers: IPeer<SigType, SigPayload>[]) {\n joiningUsers.forEach(user => {\n const state = getPeer(user);\n const pc = state.pc;\n receivePeerConnection({ pc, userId: user.userId, initiator: true });\n makeOffer(user);\n });\n },\n\n onPeerLeft(leavingUsers: { userId: string; peerId: string }[]) {\n leavingUsers.forEach(({ userId, peerId }) => {\n const state = users.get(userId);\n if (!state) return;\n state.peers.delete(peerId);\n if (state.peers.size === 0) {\n state.expirationTimeout = setTimeout(() => leaveUser(userId), peerlessUserExpiration ?? 0);\n }\n });\n },\n\n async onMessage(type: SigType, payload: any, from: IPeer) {\n const state = getPeer(from);\n const pc = state.pc;\n\n if (type === \"offer\") {\n receivePeerConnection({ pc, userId: from.userId, initiator: false });\n // Responder: set remote offer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n\n // Create and send answer\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n from.receive(\"answer\", pc.localDescription?.toJSON()!);\n\n // Now safe to apply any queued ICE from this peer\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"answer\") {\n // Initiator: set remote answer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n await flushRemoteIce(state);\n receivePeerConnection({ pc, userId: from.userId, initiator: true });\n return;\n }\n\n if (type === \"ice\") {\n const ice = payload as RTCIceCandidateInit;\n\n // If we don't have remoteDescription yet, queue it\n if (!pc.remoteDescription) {\n state.pendingRemoteIce.push(ice);\n return;\n }\n\n try {\n await pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n return;\n }\n },\n });\n roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });\n });\n }\n\n function removeUserListener(listener: UserListener) {\n userListener.delete(listener);\n }\n\n function addUserListener(listener: UserListener) {\n userListener.add(listener);\n return () => {\n removeUserListener(listener);\n };\n }\n\n return {\n enterRoom: enter,\n exitRoom: exit,\n leaveUser,\n getUsers,\n addUserListener,\n removeUserListener,\n getRooms() {\n return Array.from(roomsEntered.values());\n },\n end() {\n roomsEntered.forEach(({ exitRoom }) => exitRoom());\n roomsEntered.clear();\n users.forEach(({ userId }) => leaveUser(userId));\n userListener.clear();\n },\n };\n}\n\n\n\n",
8
- "import { EnterRoom, enterRoom } from \"./signal-room\";\nimport { SigType, SigPayload, collectPeerConnections } from \"./webrtc-peer-collector\";\n\nexport function enterWorld({\n uid, appId, logLine = console.debug, enterRoomFunction = enterRoom, peerlessUserExpiration, workerUrl,\n}: {\n uid?: string;\n appId: string;\n logLine?: (direction: string, obj?: any) => void;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n peerlessUserExpiration?: number;\n workerUrl?: URL;\n}) {\n const userId = uid ?? `user-${crypto.randomUUID()}`;\n const rtcConfig: RTCConfiguration = {\n iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }],\n };\n\n const messagesListeners = new Set<(data: any, from: string) => void>();\n\n function wireDataChannel(userId: string, dc: RTCDataChannel) {\n dc.onopen = () => logLine(\"💬\", { event: \"dc-open\", userId });\n dc.onmessage = ({ data }) => {\n messagesListeners.forEach(listener => listener(data as any, userId));\n logLine(\"💬\", { event: \"dc-message\", userId, data });\n };\n dc.onclose = () => logLine(\"💬\", { event: \"dc-close\", userId });\n dc.onerror = () => logLine(\"⚠️ ERROR\", { error: \"dc-error\", userId });\n }\n\n const dataChannels: Map<string, RTCDataChannel> = new Map();\n\n const { enterRoom, exitRoom, getUsers, leaveUser, addUserListener, removeUserListener, end: endPeerCollection } = collectPeerConnections({\n userId,\n appId,\n rtcConfig,\n enterRoomFunction,\n logLine,\n workerUrl,\n peerlessUserExpiration,\n onLeaveUser(userId: string) {\n const dc = dataChannels.get(userId);\n try { dc?.close(); } catch { }\n dataChannels.delete(userId);\n },\n receivePeerConnection({ pc, userId, initiator }) {\n if (initiator) {\n const dc = pc.createDataChannel(\"data\");\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n } else {\n pc.ondatachannel = (ev) => {\n const dc = ev.channel;\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n };\n }\n\n logLine(\"💬\", { event: \"pc-ready\", userId, initiator });\n },\n });\n\n function send(data: any, userId?: string) {\n dataChannels.forEach((dataChannel, pUserId) => {\n if (userId && pUserId !== userId) return;\n if (dataChannel.readyState === \"open\") dataChannel.send(data);\n });\n }\n\n function removeMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.delete(listener);\n }\n\n function addMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.add(listener);\n return () => {\n removeMessageListener(listener);\n };\n }\n\n return {\n userId,\n send,\n enterRoom,\n exitRoom,\n leaveUser,\n getUsers,\n addMessageListener,\n removeMessageListener,\n addUserListener,\n removeUserListener,\n end() {\n dataChannels.forEach((dataChannel) => {\n try { dataChannel.close(); } catch { }\n });\n dataChannels.clear();\n endPeerCollection();\n },\n };\n}\n"
7
+ "import { IPeer } from \"./impl/signal-room\";\nimport { EnterRoom, enterRoom } from \"./signal-room\";\n\nexport type SigType = \"offer\" | \"answer\" | \"ice\";\nexport type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;\n\ntype UserState = {\n userId: string;\n pc: RTCPeerConnection;\n\n // ICE that arrived before we had remoteDescription\n pendingRemoteIce: RTCIceCandidateInit[];\n\n // the signaling \"user\" handle so we can send messages\n peers: Map<string, IPeer<SigType, SigPayload>>;\n\n expirationTimeout?: number;\n};\ntype UserListener = (user: string, action: \"join\"|\"leave\") => void;\n\nconst DEFAULT_ENTER_ROOM = enterRoom;\n\n\nexport function collectPeerConnections({\n appId,\n receivePeerConnection,\n peerlessUserExpiration,\n rtcConfig = { iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }] },\n enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM,\n logLine = console.debug,\n onLeaveUser,\n workerUrl,\n}: {\n appId: string;\n rtcConfig?: RTCConfiguration;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n onLeaveUser?: (userId: string) => void;\n logLine?: (direction: string, obj?: any) => void;\n workerUrl?: URL;\n peerlessUserExpiration?: number;\n receivePeerConnection(connection: { pc: RTCPeerConnection, userId: string, initiator: boolean }): void;\n}) {\n const userId = `user-${crypto.randomUUID()}`;\n const users: Map<string, UserState> = new Map();\n\n function getPeer(peer: IPeer<SigType, SigPayload>): UserState {\n let state = users.get(peer.userId);\n if (!state) {\n const newState: UserState = {\n userId: peer.userId,\n pc: new RTCPeerConnection(rtcConfig),\n pendingRemoteIce: [],\n peers: new Map(),\n };\n newState.peers.set(peer.peerId, peer);\n users.set(peer.userId, newState);\n\n // Send local ICE candidates to this peer\n newState.pc.onicecandidate = (ev) => {\n if (!ev.candidate) return;\n for(let user of newState.peers.values()) {\n const success = user.receive(\"ice\", ev.candidate.toJSON());\n if (success) break;\n }\n };\n \n newState.pc.onconnectionstatechange = () => {\n logLine(\"💬\", { event: \"pc-state\", userId: newState.userId, state: newState.pc.connectionState });\n };\n state = newState;\n\n // New user\n users.set(state.userId, state);\n } else if (state) {\n clearTimeout(state.expirationTimeout);\n state.expirationTimeout = 0;\n state.peers.set(peer.peerId, peer);\n }\n return state;\n }\n\n function leaveUser(userId: string) {\n onLeaveUser?.(userId);\n const p = users.get(userId);\n if (!p) return;\n try { p.pc.close(); } catch {}\n users.delete(userId);\n }\n\n async function flushRemoteIce(state: UserState) {\n if (!state.pc.remoteDescription) return;\n\n const queued = state.pendingRemoteIce;\n state.pendingRemoteIce = [];\n\n for (const ice of queued) {\n try {\n await state.pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n }\n }\n\n const roomsEntered = new Map<string, { room: string; host: string; exitRoom: () => void }>();\n\n function exit({ room, host }: { room: string; host: string; }) {\n const key = `${host}/room/${room}`;\n const session = roomsEntered.get(key);\n if (session) {\n session.exitRoom();\n roomsEntered.delete(key);\n }\n }\n\n function enter({ room, host }: { room: string; host: string; }) {\n return new Promise<void>((resolve, reject) => {\n async function makeOffer(user: IPeer) {\n // Offer flow: createOffer -> setLocalDescription -> send localDescription\n const state = getPeer(user);\n const pc = state.pc;\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n user.receive(\"offer\", pc.localDescription?.toJSON()!);\n }\n\n const { exitRoom } = enterRoom({\n userId,\n appId,\n room,\n host,\n logLine,\n workerUrl,\n\n onOpen: resolve,\n onError: reject,\n\n // Existing peers initiate to the newcomer (Option 1)\n onPeerJoined(joiningUsers: IPeer<SigType, SigPayload>[]) {\n joiningUsers.forEach(user => {\n const state = getPeer(user);\n const pc = state.pc;\n receivePeerConnection({ pc, userId: user.userId, initiator: true });\n makeOffer(user);\n });\n },\n\n onPeerLeft(leavingUsers: { userId: string; peerId: string }[]) {\n leavingUsers.forEach(({ userId, peerId }) => {\n const state = users.get(userId);\n if (!state) return;\n state.peers.delete(peerId);\n if (!state.peers.size) {\n state.expirationTimeout = setTimeout(() => leaveUser(userId), peerlessUserExpiration ?? 0);\n }\n });\n },\n\n async onMessage(type: SigType, payload: any, from: IPeer) {\n const state = getPeer(from);\n const pc = state.pc;\n\n if (type === \"offer\") {\n receivePeerConnection({ pc, userId: from.userId, initiator: false });\n // Responder: set remote offer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n\n // Create and send answer\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n from.receive(\"answer\", pc.localDescription?.toJSON()!);\n\n // Now safe to apply any queued ICE from this peer\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"answer\") {\n // Initiator: set remote answer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"ice\") {\n const ice = payload as RTCIceCandidateInit;\n\n // If we don't have remoteDescription yet, queue it\n if (!pc.remoteDescription) {\n state.pendingRemoteIce.push(ice);\n return;\n }\n\n try {\n await pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n return;\n }\n },\n });\n roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });\n });\n }\n\n return {\n userId,\n enterRoom: enter,\n exitRoom: exit,\n leaveUser,\n getRooms() {\n return Array.from(roomsEntered.values());\n },\n end() {\n roomsEntered.forEach(({ exitRoom }) => exitRoom());\n roomsEntered.clear();\n users.forEach(({ userId }) => leaveUser(userId));\n users.clear();\n },\n };\n}\n\n\n\n",
8
+ "import { EnterRoom, enterRoom } from \"./signal-room\";\nimport { SigType, SigPayload, collectPeerConnections } from \"./webrtc-peer-collector\";\n\nexport function enterWorld({\n appId, logLine = console.debug, enterRoomFunction = enterRoom, peerlessUserExpiration, workerUrl,\n}: {\n appId: string;\n logLine?: (direction: string, obj?: any) => void;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n peerlessUserExpiration?: number;\n workerUrl?: URL;\n}) {\n const userIds: string[] = [];\n const rtcConfig: RTCConfiguration = {\n iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }],\n };\n\n const messagesListeners = new Set<(data: any, from: string) => void>();\n\n function getUsers() {\n return userIds;\n }\n\n function wireDataChannel(userId: string, dc: RTCDataChannel) {\n dc.onopen = () => {\n logLine(\"💬\", { event: \"dc-open\", userId });\n userIds.push(userId);\n userListeners.forEach(listener => listener(userId, \"join\", userIds));\n };\n dc.onmessage = ({ data }) => {\n messagesListeners.forEach(listener => listener(data as any, userId));\n logLine(\"💬\", { event: \"dc-message\", userId, data });\n };\n dc.onclose = () => {\n logLine(\"💬\", { event: \"dc-close\", userId });\n userIds.splice(userIds.indexOf(userId), 1);\n userListeners.forEach(listener => listener(userId, \"leave\", userIds));\n };\n dc.onerror = () => logLine(\"⚠️ ERROR\", { error: \"dc-error\", userId });\n }\n\n const dataChannels = new Map<string, RTCDataChannel>();\n const userListeners = new Set<(userId: string, action: \"join\"|\"leave\", users: string[]) => void>();\n\n const { userId, enterRoom, exitRoom, leaveUser, end: endPeerCollection } = collectPeerConnections({\n appId,\n rtcConfig,\n enterRoomFunction,\n logLine,\n workerUrl,\n peerlessUserExpiration,\n onLeaveUser(userId: string) {\n const dc = dataChannels.get(userId);\n try { dc?.close(); } catch { }\n dataChannels.delete(userId);\n },\n receivePeerConnection({ pc, userId, initiator }) {\n if (initiator) {\n const dc = pc.createDataChannel(\"data\");\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n } else {\n pc.ondatachannel = (ev) => {\n const dc = ev.channel;\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n pc.ondatachannel = null;\n };\n }\n },\n });\n\n function send(data: any, userId?: string) {\n dataChannels.forEach((dataChannel, pUserId) => {\n if (userId && pUserId !== userId) return;\n if (dataChannel.readyState === \"open\") dataChannel.send(data);\n });\n }\n\n function removeMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.delete(listener);\n }\n\n function addMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.add(listener);\n return () => {\n removeMessageListener(listener);\n };\n }\n\n function removeUserListener(listener: (userId: string, action:\"join\"|\"leave\", users: string[]) => void) {\n userListeners.delete(listener);\n }\n\n function addUserListener(listener: (userId: string, action:\"join\"|\"leave\", users: string[]) => void) {\n userListeners.add(listener);\n return () => {\n removeUserListener(listener);\n };\n }\n\n return {\n userId,\n send,\n enterRoom,\n exitRoom,\n leaveUser,\n getUsers,\n addMessageListener,\n removeMessageListener,\n addUserListener,\n removeUserListener,\n end() {\n dataChannels.forEach((dataChannel) => {\n try { dataChannel.close(); } catch { }\n });\n dataChannels.clear();\n endPeerCollection();\n userListeners.clear();\n userIds.length = 0;\n },\n };\n}\n"
9
9
  ],
10
- "mappings": "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",
11
- "debugId": "785DC53F308F768364756E2164756E21",
10
+ "mappings": "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",
11
+ "debugId": "82AA55FF49A2708A64756E2164756E21",
12
12
  "names": []
13
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"signal-room.d.ts","sourceRoot":"","sources":["../../src/browser/impl/signal-room.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,GAAG;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;CACzC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,EACjD,MAAM,EACN,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,OAAO,EACP,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,SAAS,GACZ,EAAE;IACC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAI,IAAI,CAAC;IAC1C,UAAU,CAAC,KAAK,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,EAAE,GAAI,IAAI,CAAC;IAC7D,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAI,IAAI,CAAC;CAC5D,GAAG;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,CAuF3B"}
1
+ {"version":3,"file":"signal-room.d.ts","sourceRoot":"","sources":["../../src/browser/impl/signal-room.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,GAAG;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;CACzC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,EACjD,MAAM,EACN,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,OAAO,EACP,OAAO,EACP,OAAO,EACP,YAAY,EACZ,UAAU,EACV,SAAS,GACZ,EAAE;IACC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAI,IAAI,CAAC;IAC1C,UAAU,CAAC,KAAK,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,EAAE,GAAI,IAAI,CAAC;IAC7D,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAI,IAAI,CAAC;CAC5D,GAAG;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,CAmF3B"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- function k({userId:M,appId:h,room:G,host:j,onOpen:N,onClose:S,onError:B,logLine:f,onPeerJoined:x,onPeerLeft:F,onMessage:H}){let W=`wss://${j}/room/${h}/${G}?userId=${encodeURIComponent(M)}`,$=new WebSocket(W),C=M,X=new Map,K=!1;function q(Z,c,D){if(K)return!1;let T={type:Z,to:c,payload:D};return $.send(JSON.stringify(T)),f?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",T),!0}function R(Z){let c=[],D=[],T=new Set;if(Z.forEach(({userId:b,peerId:z})=>{if(b===C)return;if(!X.has(z)){let O={userId:b,peerId:z,receive:(A,V)=>q(A,z,V)};X.set(z,O),c.push(O)}T.add(z)}),X.values().forEach(({peerId:b,userId:z})=>{if(!T.has(b))X.delete(b),D.push({peerId:b,userId:z})}),c.length)x(c);if(D.length)F(D)}function Y(Z){let c;try{c=JSON.parse(Z.data)}catch{f?.("⚠️ ERROR",{error:"invalid-json"});return}if(f?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",c),c.type==="peer-joined"){R(c.users);return}if(c.type==="peer-left"){R(c.users);return}if(c.peerId&&c.userId){let{userId:D,peerId:T}=c;H(c.type,c.payload,{userId:D,peerId:T,receive:(b,z)=>q(b,T,z)})}}if($.addEventListener("message",Y),N)$.addEventListener("open",N);if(S)$.addEventListener("close",S);if(B)$.addEventListener("error",B);return{exitRoom:()=>{if(K=!0,$.close(),$.removeEventListener("message",Y),N)$.removeEventListener("open",N);if(S)$.removeEventListener("close",S);if(B)$.removeEventListener("error",B)}}}function E({userId:M,appId:h,room:G,host:j,onOpen:N,onClose:S,onError:B,onPeerJoined:f,onPeerLeft:x,onMessage:F,logLine:H,workerUrl:W}){if(!W)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),k({userId:M,appId:h,room:G,host:j,onOpen:N,onClose:S,onError:B,onPeerJoined:f,onPeerLeft:x,onMessage:F});let $=new Worker(W,{type:"module"}),C=!1;function X({userId:q,peerId:R}){return{userId:q,peerId:R,receive:(Y,Z)=>{if(C)return!1;return $.postMessage({cmd:"send",toPeerId:R,type:Y,payload:Z}),!0}}}let K=(q)=>{let R=q.data;if(R.kind==="open")N?.();else if(R.kind==="close")$.terminate();else if(R.kind==="error")B?.();else if(R.kind==="peer-joined")f(R.users.map((Y)=>X({userId:Y.userId,peerId:Y.peerId})));else if(R.kind==="peer-left")x(R.users);else if(R.kind==="message")F(R.type,R.payload,X({userId:R.fromUserId,peerId:R.fromPeerId}));else if(R.kind==="log")H?.(R.direction,R.obj)};return $.addEventListener("message",K),$.postMessage({cmd:"enter",userId:M,appId:h,room:G,host:j}),{exitRoom:()=>{C=!0,$.removeEventListener("message",K),$.postMessage({cmd:"exit"})}}}var v=E;function U({userId:M,appId:h,receivePeerConnection:G,peerlessUserExpiration:j,rtcConfig:N={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},enterRoomFunction:S=v,logLine:B=console.debug,onLeaveUser:f,workerUrl:x}){let F=new Map;function H(){return[...F.keys()]}let W=new Set;function $(c){let D=F.get(c.userId);if(!D){let T={userId:c.userId,pc:new RTCPeerConnection(N),pendingRemoteIce:[],peers:new Map};T.peers.set(c.peerId,c),F.set(c.userId,T),T.pc.onicecandidate=(b)=>{if(!b.candidate)return;for(let z of T.peers.values())if(z.receive("ice",b.candidate.toJSON()))break},T.pc.onconnectionstatechange=()=>{B("\uD83D\uDCAC",{event:"pc-state",userId:T.userId,state:T.pc.connectionState})},D=T,W.forEach((b)=>b(c.userId,"join",H())),F.set(D.userId,D)}else if(D)clearTimeout(D.expirationTimeout),D.expirationTimeout=0,D.peers.set(c.peerId,c);return D}function C(c){f?.(c);let D=F.get(c);if(!D)return;try{D.pc.close()}catch{}F.delete(c),W.forEach((T)=>T(c,"leave",H())),B("\uD83D\uDC64 USER LEFT",c)}async function X(c){if(!c.pc.remoteDescription)return;let D=c.pendingRemoteIce;c.pendingRemoteIce=[];for(let T of D)try{await c.pc.addIceCandidate(T)}catch(b){B("⚠️ ERROR",{error:"add-ice-failed",userId:c.userId,detail:String(b)})}}let K=new Map;function q({room:c,host:D}){let T=`${D}/room/${c}`,b=K.get(T);if(b)b.exitRoom(),K.delete(T)}function R({room:c,host:D}){return new Promise((T,b)=>{async function z(A){let _=$(A).pc,Q=await _.createOffer();await _.setLocalDescription(Q),A.receive("offer",_.localDescription?.toJSON())}let{exitRoom:O}=S({userId:M,appId:h,room:c,host:D,logLine:B,workerUrl:x,onOpen:T,onError:b,onPeerJoined(A){A.forEach((V)=>{let Q=$(V).pc;G({pc:Q,userId:V.userId,initiator:!0}),z(V)})},onPeerLeft(A){A.forEach(({userId:V,peerId:_})=>{let Q=F.get(V);if(!Q)return;if(Q.peers.delete(_),Q.peers.size===0)Q.expirationTimeout=setTimeout(()=>C(V),j??0)})},async onMessage(A,V,_){let Q=$(_),J=Q.pc;if(A==="offer"){G({pc:J,userId:_.userId,initiator:!1}),await J.setRemoteDescription(V);let y=await J.createAnswer();await J.setLocalDescription(y),_.receive("answer",J.localDescription?.toJSON()),await X(Q);return}if(A==="answer"){await J.setRemoteDescription(V),await X(Q),G({pc:J,userId:_.userId,initiator:!0});return}if(A==="ice"){let y=V;if(!J.remoteDescription){Q.pendingRemoteIce.push(y);return}try{await J.addIceCandidate(y)}catch(P){B("⚠️ ERROR",{error:"add-ice-failed",userId:Q.userId,detail:String(P)})}return}}});K.set(`${D}/room/${c}`,{exitRoom:O,room:c,host:D})})}function Y(c){W.delete(c)}function Z(c){return W.add(c),()=>{Y(c)}}return{enterRoom:R,exitRoom:q,leaveUser:C,getUsers:H,addUserListener:Z,removeUserListener:Y,getRooms(){return Array.from(K.values())},end(){K.forEach(({exitRoom:c})=>c()),K.clear(),F.forEach(({userId:c})=>C(c)),W.clear()}}}function L({uid:M,appId:h,logLine:G=console.debug,enterRoomFunction:j=E,peerlessUserExpiration:N,workerUrl:S}){let B=M??`user-${crypto.randomUUID()}`,f={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},x=new Set;function F(D,T){T.onopen=()=>G("\uD83D\uDCAC",{event:"dc-open",userId:D}),T.onmessage=({data:b})=>{x.forEach((z)=>z(b,D)),G("\uD83D\uDCAC",{event:"dc-message",userId:D,data:b})},T.onclose=()=>G("\uD83D\uDCAC",{event:"dc-close",userId:D}),T.onerror=()=>G("⚠️ ERROR",{error:"dc-error",userId:D})}let H=new Map,{enterRoom:W,exitRoom:$,getUsers:C,leaveUser:X,addUserListener:K,removeUserListener:q,end:R}=U({userId:B,appId:h,rtcConfig:f,enterRoomFunction:j,logLine:G,workerUrl:S,peerlessUserExpiration:N,onLeaveUser(D){let T=H.get(D);try{T?.close()}catch{}H.delete(D)},receivePeerConnection({pc:D,userId:T,initiator:b}){if(b){let z=D.createDataChannel("data");F(T,z),H.set(T,z)}else D.ondatachannel=(z)=>{let O=z.channel;F(T,O),H.set(T,O)};G("\uD83D\uDCAC",{event:"pc-ready",userId:T,initiator:b})}});function Y(D,T){H.forEach((b,z)=>{if(T&&z!==T)return;if(b.readyState==="open")b.send(D)})}function Z(D){x.delete(D)}function c(D){return x.add(D),()=>{Z(D)}}return{userId:B,send:Y,enterRoom:W,exitRoom:$,leaveUser:X,getUsers:C,addMessageListener:c,removeMessageListener:Z,addUserListener:K,removeUserListener:q,end(){H.forEach((D)=>{try{D.close()}catch{}}),H.clear(),R()}}}export{L as enterWorld,k as enterRoom,U as collectPeerConnections};
1
+ function J({userId:S,appId:W,room:C,host:i,onOpen:A,onClose:G,onError:N,logLine:Z,onPeerJoined:_,onPeerLeft:K,onMessage:Q}){let V=`wss://${i}/room/${W}/${C}?userId=${encodeURIComponent(S)}`,F=new WebSocket(V),X=S,q=new Map,h=!1;function T(H,B,$){if(h)return!1;let c={type:H,to:B,payload:$};return F.send(JSON.stringify(c)),Z?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",c),!0}function f(H){let B=[],$=[],c=new Set;if(H.forEach(({userId:b,peerId:D})=>{if(b===X)return;if(!q.has(D)){let z={userId:b,peerId:D,receive:(Y,x)=>T(Y,D,x)};q.set(D,z),B.push(z)}c.add(D)}),q.values().forEach(({peerId:b,userId:D})=>{if(!c.has(b))q.delete(b),$.push({peerId:b,userId:D})}),B.length)_(B);if($.length)K($)}function R(H){let B;try{B=JSON.parse(H.data)}catch{Z?.("⚠️ ERROR",{error:"invalid-json"});return}if(Z?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",B),B.type==="peer-joined"||B.type==="peer-left"){f(B.users);return}if(B.peerId&&B.userId){let{userId:$,peerId:c}=B;Q(B.type,B.payload,{userId:$,peerId:c,receive:(b,D)=>T(b,c,D)})}}if(F.addEventListener("message",R),A)F.addEventListener("open",A);if(G)F.addEventListener("close",G);if(N)F.addEventListener("error",N);return{exitRoom:()=>{if(h=!0,F.close(),F.removeEventListener("message",R),A)F.removeEventListener("open",A);if(G)F.removeEventListener("close",G);if(N)F.removeEventListener("error",N)}}}function j({userId:S,appId:W,room:C,host:i,onOpen:A,onClose:G,onError:N,onPeerJoined:Z,onPeerLeft:_,onMessage:K,logLine:Q,workerUrl:V}){if(!V)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),J({userId:S,appId:W,room:C,host:i,onOpen:A,onClose:G,onError:N,onPeerJoined:Z,onPeerLeft:_,onMessage:K});let F=new Worker(V,{type:"module"}),X=!1;function q({userId:T,peerId:f}){return{userId:T,peerId:f,receive:(R,H)=>{if(X)return!1;return F.postMessage({cmd:"send",toPeerId:f,type:R,payload:H}),!0}}}let h=(T)=>{let f=T.data;if(f.kind==="open")A?.();else if(f.kind==="close")F.terminate();else if(f.kind==="error")N?.();else if(f.kind==="peer-joined")Z(f.users.map((R)=>q({userId:R.userId,peerId:R.peerId})));else if(f.kind==="peer-left")_(f.users);else if(f.kind==="message")K(f.type,f.payload,q({userId:f.fromUserId,peerId:f.fromPeerId}));else if(f.kind==="log")Q?.(f.direction,f.obj)};return F.addEventListener("message",h),F.postMessage({cmd:"enter",userId:S,appId:W,room:C,host:i}),{exitRoom:()=>{X=!0,F.removeEventListener("message",h),F.postMessage({cmd:"exit"})}}}var E=j;function M({appId:S,receivePeerConnection:W,peerlessUserExpiration:C,rtcConfig:i={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},enterRoomFunction:A=E,logLine:G=console.debug,onLeaveUser:N,workerUrl:Z}){let _=`user-${crypto.randomUUID()}`,K=new Map;function Q(T){let f=K.get(T.userId);if(!f){let R={userId:T.userId,pc:new RTCPeerConnection(i),pendingRemoteIce:[],peers:new Map};R.peers.set(T.peerId,T),K.set(T.userId,R),R.pc.onicecandidate=(H)=>{if(!H.candidate)return;for(let B of R.peers.values())if(B.receive("ice",H.candidate.toJSON()))break},R.pc.onconnectionstatechange=()=>{G("\uD83D\uDCAC",{event:"pc-state",userId:R.userId,state:R.pc.connectionState})},f=R,K.set(f.userId,f)}else if(f)clearTimeout(f.expirationTimeout),f.expirationTimeout=0,f.peers.set(T.peerId,T);return f}function V(T){N?.(T);let f=K.get(T);if(!f)return;try{f.pc.close()}catch{}K.delete(T)}async function F(T){if(!T.pc.remoteDescription)return;let f=T.pendingRemoteIce;T.pendingRemoteIce=[];for(let R of f)try{await T.pc.addIceCandidate(R)}catch(H){G("⚠️ ERROR",{error:"add-ice-failed",userId:T.userId,detail:String(H)})}}let X=new Map;function q({room:T,host:f}){let R=`${f}/room/${T}`,H=X.get(R);if(H)H.exitRoom(),X.delete(R)}function h({room:T,host:f}){return new Promise((R,H)=>{async function B(c){let D=Q(c).pc,z=await D.createOffer();await D.setLocalDescription(z),c.receive("offer",D.localDescription?.toJSON())}let{exitRoom:$}=A({userId:_,appId:S,room:T,host:f,logLine:G,workerUrl:Z,onOpen:R,onError:H,onPeerJoined(c){c.forEach((b)=>{let z=Q(b).pc;W({pc:z,userId:b.userId,initiator:!0}),B(b)})},onPeerLeft(c){c.forEach(({userId:b,peerId:D})=>{let z=K.get(b);if(!z)return;if(z.peers.delete(D),!z.peers.size)z.expirationTimeout=setTimeout(()=>V(b),C??0)})},async onMessage(c,b,D){let z=Q(D),Y=z.pc;if(c==="offer"){W({pc:Y,userId:D.userId,initiator:!1}),await Y.setRemoteDescription(b);let x=await Y.createAnswer();await Y.setLocalDescription(x),D.receive("answer",Y.localDescription?.toJSON()),await F(z);return}if(c==="answer"){await Y.setRemoteDescription(b),await F(z);return}if(c==="ice"){let x=b;if(!Y.remoteDescription){z.pendingRemoteIce.push(x);return}try{await Y.addIceCandidate(x)}catch(O){G("⚠️ ERROR",{error:"add-ice-failed",userId:z.userId,detail:String(O)})}return}}});X.set(`${f}/room/${T}`,{exitRoom:$,room:T,host:f})})}return{userId:_,enterRoom:h,exitRoom:q,leaveUser:V,getRooms(){return Array.from(X.values())},end(){X.forEach(({exitRoom:T})=>T()),X.clear(),K.forEach(({userId:T})=>V(T)),K.clear()}}}function v({appId:S,logLine:W=console.debug,enterRoomFunction:C=j,peerlessUserExpiration:i,workerUrl:A}){let G=[],N={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},Z=new Set;function _(){return G}function K(c,b){b.onopen=()=>{W("\uD83D\uDCAC",{event:"dc-open",userId:c}),G.push(c),V.forEach((D)=>D(c,"join",G))},b.onmessage=({data:D})=>{Z.forEach((z)=>z(D,c)),W("\uD83D\uDCAC",{event:"dc-message",userId:c,data:D})},b.onclose=()=>{W("\uD83D\uDCAC",{event:"dc-close",userId:c}),G.splice(G.indexOf(c),1),V.forEach((D)=>D(c,"leave",G))},b.onerror=()=>W("⚠️ ERROR",{error:"dc-error",userId:c})}let Q=new Map,V=new Set,{userId:F,enterRoom:X,exitRoom:q,leaveUser:h,end:T}=M({appId:S,rtcConfig:N,enterRoomFunction:C,logLine:W,workerUrl:A,peerlessUserExpiration:i,onLeaveUser(c){let b=Q.get(c);try{b?.close()}catch{}Q.delete(c)},receivePeerConnection({pc:c,userId:b,initiator:D}){if(D){let z=c.createDataChannel("data");K(b,z),Q.set(b,z)}else c.ondatachannel=(z)=>{let Y=z.channel;K(b,Y),Q.set(b,Y),c.ondatachannel=null}}});function f(c,b){Q.forEach((D,z)=>{if(b&&z!==b)return;if(D.readyState==="open")D.send(c)})}function R(c){Z.delete(c)}function H(c){return Z.add(c),()=>{R(c)}}function B(c){V.delete(c)}function $(c){return V.add(c),()=>{B(c)}}return{userId:F,send:f,enterRoom:X,exitRoom:q,leaveUser:h,getUsers:_,addMessageListener:H,removeMessageListener:R,addUserListener:$,removeUserListener:B,end(){Q.forEach((c)=>{try{c.close()}catch{}}),Q.clear(),T(),V.clear(),G.length=0}}}export{v as enterWorld,J as enterRoom,M as collectPeerConnections};
2
2
 
3
- //# debugId=ECF8FB936A1DF5A064756E2164756E21
3
+ //# debugId=B796A1CA2AC2575C64756E2164756E21
4
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -2,12 +2,12 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/browser/impl/signal-room.ts", "../src/browser/signal-room.ts", "../src/browser/webrtc-peer-collector.ts", "../src/browser/enter-world.ts"],
4
4
  "sourcesContent": [
5
- "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
5
+ "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\" || msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
6
6
  "import type { IPeer } from \"./impl/signal-room.js\";\nimport { enterRoom as baseEnterRoom } from \"./impl/signal-room.js\";\nimport { RoomEvent } from \"./signal-room.worker.js\";\n\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n logLine,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n onPeerJoined: (users: IPeer<T, P>[]) => void;\n onPeerLeft: (users: {userId: string, peerId: string}[]) => void;\n onMessage: (type: T, payload: P, from: IPeer<T, P>) => void;\n logLine?: (direction: string, obj?: any) => void;\n\n // Pass the URL to your worker file (bundler will handle it)\n workerUrl?: URL;\n}): { exitRoom: () => void } {\n if (!workerUrl) {\n const CDN_WORKER_URL = `https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js`;\n\n console.warn(\"Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:\", CDN_WORKER_URL);\n return baseEnterRoom<T, P>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n });\n }\n const worker = new Worker(workerUrl, { type: \"module\" });\n let exited = false;\n\n function makeUser({ userId, peerId }: { userId: string; peerId: string }): IPeer<T, P> {\n return {\n userId,\n peerId,\n receive: (type: T, payload: P) => {\n if (exited) return false;\n worker.postMessage({ cmd: \"send\", toPeerId: peerId, type, payload });\n return true;\n },\n };\n }\n\n const onWorkerMessage = (e: MessageEvent<RoomEvent<T, P>>) => {\n const ev = e.data;\n\n if (ev.kind === \"open\") onOpen?.();\n else if (ev.kind === \"close\") worker.terminate();\n else if (ev.kind === \"error\") onError?.();\n else if (ev.kind === \"peer-joined\") onPeerJoined(ev.users.map(ev => makeUser({ userId: ev.userId, peerId: ev.peerId })));\n else if (ev.kind === \"peer-left\") onPeerLeft(ev.users);\n else if (ev.kind === \"message\") onMessage(ev.type, ev.payload, makeUser({ userId: ev.fromUserId, peerId: ev.fromPeerId }));\n else if (ev.kind === \"log\") logLine?.(ev.direction, ev.obj);\n };\n\n worker.addEventListener(\"message\", onWorkerMessage);\n\n worker.postMessage({ cmd: \"enter\", userId, appId, room, host });\n\n return {\n exitRoom: () => {\n exited = true;\n worker.removeEventListener(\"message\", onWorkerMessage);\n worker.postMessage({ cmd: \"exit\" });\n },\n };\n}\n\nexport type EnterRoom<T extends string, P> = typeof enterRoom<T, P>;\n",
7
- "import { IPeer } from \"./impl/signal-room\";\nimport { EnterRoom, enterRoom } from \"./signal-room\";\n\nexport type SigType = \"offer\" | \"answer\" | \"ice\";\nexport type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;\n\ntype UserState = {\n userId: string;\n pc: RTCPeerConnection;\n\n // ICE that arrived before we had remoteDescription\n pendingRemoteIce: RTCIceCandidateInit[];\n\n // the signaling \"user\" handle so we can send messages\n peers: Map<string, IPeer<SigType, SigPayload>>;\n\n expirationTimeout?: number;\n};\ntype UserListener = (user: string, action: \"join\"|\"leave\", users: string[]) => void;\n\nconst DEFAULT_ENTER_ROOM = enterRoom;\n\n\nexport function collectPeerConnections({\n userId,\n appId,\n receivePeerConnection,\n peerlessUserExpiration,\n rtcConfig = { iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }] },\n enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM,\n logLine = console.debug,\n onLeaveUser,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n rtcConfig?: RTCConfiguration;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n onLeaveUser?: (userId: string) => void;\n logLine?: (direction: string, obj?: any) => void;\n workerUrl?: URL;\n peerlessUserExpiration?: number;\n receivePeerConnection(connection: { pc: RTCPeerConnection, userId: string, initiator: boolean }): void;\n}) {\n const users: Map<string, UserState> = new Map();\n function getUsers() {\n return [...users.keys()];\n }\n\n const userListener: Set<UserListener> = new Set();\n function getPeer(peer: IPeer<SigType, SigPayload>): UserState {\n let state = users.get(peer.userId);\n if (!state) {\n const newState: UserState = {\n userId: peer.userId,\n pc: new RTCPeerConnection(rtcConfig),\n pendingRemoteIce: [],\n peers: new Map(),\n };\n newState.peers.set(peer.peerId, peer);\n users.set(peer.userId, newState);\n\n // Send local ICE candidates to this peer\n newState.pc.onicecandidate = (ev) => {\n if (!ev.candidate) return;\n for(let user of newState.peers.values()) {\n const success = user.receive(\"ice\", ev.candidate.toJSON());\n if (success) break;\n }\n };\n \n newState.pc.onconnectionstatechange = () => {\n logLine(\"💬\", { event: \"pc-state\", userId: newState.userId, state: newState.pc.connectionState });\n };\n state = newState;\n\n // New user\n userListener.forEach(listener => listener(peer.userId, \"join\", getUsers()));\n users.set(state.userId, state);\n } else if (state) {\n clearTimeout(state.expirationTimeout);\n state.expirationTimeout = 0;\n state.peers.set(peer.peerId, peer);\n }\n return state;\n }\n\n function leaveUser(userId: string) {\n onLeaveUser?.(userId);\n const p = users.get(userId);\n if (!p) return;\n try { p.pc.close(); } catch {}\n users.delete(userId);\n userListener.forEach(listener => listener(userId, \"leave\", getUsers()));\n logLine(\"👤 USER LEFT\", userId);\n }\n\n async function flushRemoteIce(state: UserState) {\n if (!state.pc.remoteDescription) return;\n\n const queued = state.pendingRemoteIce;\n state.pendingRemoteIce = [];\n\n for (const ice of queued) {\n try {\n await state.pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n }\n }\n\n const roomsEntered = new Map<string, { room: string; host: string; exitRoom: () => void }>();\n\n function exit({ room, host }: { room: string; host: string; }) {\n const key = `${host}/room/${room}`;\n const session = roomsEntered.get(key);\n if (session) {\n session.exitRoom();\n roomsEntered.delete(key);\n }\n }\n\n function enter({ room, host }: { room: string; host: string; }) {\n return new Promise<void>((resolve, reject) => {\n async function makeOffer(user: IPeer) {\n // Offer flow: createOffer -> setLocalDescription -> send localDescription\n const state = getPeer(user);\n const pc = state.pc;\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n user.receive(\"offer\", pc.localDescription?.toJSON()!);\n }\n\n const { exitRoom } = enterRoom({\n userId,\n appId,\n room,\n host,\n logLine,\n workerUrl,\n\n onOpen: resolve,\n onError: reject,\n\n // Existing peers initiate to the newcomer (Option 1)\n onPeerJoined(joiningUsers: IPeer<SigType, SigPayload>[]) {\n joiningUsers.forEach(user => {\n const state = getPeer(user);\n const pc = state.pc;\n receivePeerConnection({ pc, userId: user.userId, initiator: true });\n makeOffer(user);\n });\n },\n\n onPeerLeft(leavingUsers: { userId: string; peerId: string }[]) {\n leavingUsers.forEach(({ userId, peerId }) => {\n const state = users.get(userId);\n if (!state) return;\n state.peers.delete(peerId);\n if (state.peers.size === 0) {\n state.expirationTimeout = setTimeout(() => leaveUser(userId), peerlessUserExpiration ?? 0);\n }\n });\n },\n\n async onMessage(type: SigType, payload: any, from: IPeer) {\n const state = getPeer(from);\n const pc = state.pc;\n\n if (type === \"offer\") {\n receivePeerConnection({ pc, userId: from.userId, initiator: false });\n // Responder: set remote offer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n\n // Create and send answer\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n from.receive(\"answer\", pc.localDescription?.toJSON()!);\n\n // Now safe to apply any queued ICE from this peer\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"answer\") {\n // Initiator: set remote answer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n await flushRemoteIce(state);\n receivePeerConnection({ pc, userId: from.userId, initiator: true });\n return;\n }\n\n if (type === \"ice\") {\n const ice = payload as RTCIceCandidateInit;\n\n // If we don't have remoteDescription yet, queue it\n if (!pc.remoteDescription) {\n state.pendingRemoteIce.push(ice);\n return;\n }\n\n try {\n await pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n return;\n }\n },\n });\n roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });\n });\n }\n\n function removeUserListener(listener: UserListener) {\n userListener.delete(listener);\n }\n\n function addUserListener(listener: UserListener) {\n userListener.add(listener);\n return () => {\n removeUserListener(listener);\n };\n }\n\n return {\n enterRoom: enter,\n exitRoom: exit,\n leaveUser,\n getUsers,\n addUserListener,\n removeUserListener,\n getRooms() {\n return Array.from(roomsEntered.values());\n },\n end() {\n roomsEntered.forEach(({ exitRoom }) => exitRoom());\n roomsEntered.clear();\n users.forEach(({ userId }) => leaveUser(userId));\n userListener.clear();\n },\n };\n}\n\n\n\n",
8
- "import { EnterRoom, enterRoom } from \"./signal-room\";\nimport { SigType, SigPayload, collectPeerConnections } from \"./webrtc-peer-collector\";\n\nexport function enterWorld({\n uid, appId, logLine = console.debug, enterRoomFunction = enterRoom, peerlessUserExpiration, workerUrl,\n}: {\n uid?: string;\n appId: string;\n logLine?: (direction: string, obj?: any) => void;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n peerlessUserExpiration?: number;\n workerUrl?: URL;\n}) {\n const userId = uid ?? `user-${crypto.randomUUID()}`;\n const rtcConfig: RTCConfiguration = {\n iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }],\n };\n\n const messagesListeners = new Set<(data: any, from: string) => void>();\n\n function wireDataChannel(userId: string, dc: RTCDataChannel) {\n dc.onopen = () => logLine(\"💬\", { event: \"dc-open\", userId });\n dc.onmessage = ({ data }) => {\n messagesListeners.forEach(listener => listener(data as any, userId));\n logLine(\"💬\", { event: \"dc-message\", userId, data });\n };\n dc.onclose = () => logLine(\"💬\", { event: \"dc-close\", userId });\n dc.onerror = () => logLine(\"⚠️ ERROR\", { error: \"dc-error\", userId });\n }\n\n const dataChannels: Map<string, RTCDataChannel> = new Map();\n\n const { enterRoom, exitRoom, getUsers, leaveUser, addUserListener, removeUserListener, end: endPeerCollection } = collectPeerConnections({\n userId,\n appId,\n rtcConfig,\n enterRoomFunction,\n logLine,\n workerUrl,\n peerlessUserExpiration,\n onLeaveUser(userId: string) {\n const dc = dataChannels.get(userId);\n try { dc?.close(); } catch { }\n dataChannels.delete(userId);\n },\n receivePeerConnection({ pc, userId, initiator }) {\n if (initiator) {\n const dc = pc.createDataChannel(\"data\");\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n } else {\n pc.ondatachannel = (ev) => {\n const dc = ev.channel;\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n };\n }\n\n logLine(\"💬\", { event: \"pc-ready\", userId, initiator });\n },\n });\n\n function send(data: any, userId?: string) {\n dataChannels.forEach((dataChannel, pUserId) => {\n if (userId && pUserId !== userId) return;\n if (dataChannel.readyState === \"open\") dataChannel.send(data);\n });\n }\n\n function removeMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.delete(listener);\n }\n\n function addMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.add(listener);\n return () => {\n removeMessageListener(listener);\n };\n }\n\n return {\n userId,\n send,\n enterRoom,\n exitRoom,\n leaveUser,\n getUsers,\n addMessageListener,\n removeMessageListener,\n addUserListener,\n removeUserListener,\n end() {\n dataChannels.forEach((dataChannel) => {\n try { dataChannel.close(); } catch { }\n });\n dataChannels.clear();\n endPeerCollection();\n },\n };\n}\n"
7
+ "import { IPeer } from \"./impl/signal-room\";\nimport { EnterRoom, enterRoom } from \"./signal-room\";\n\nexport type SigType = \"offer\" | \"answer\" | \"ice\";\nexport type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;\n\ntype UserState = {\n userId: string;\n pc: RTCPeerConnection;\n\n // ICE that arrived before we had remoteDescription\n pendingRemoteIce: RTCIceCandidateInit[];\n\n // the signaling \"user\" handle so we can send messages\n peers: Map<string, IPeer<SigType, SigPayload>>;\n\n expirationTimeout?: number;\n};\ntype UserListener = (user: string, action: \"join\"|\"leave\") => void;\n\nconst DEFAULT_ENTER_ROOM = enterRoom;\n\n\nexport function collectPeerConnections({\n appId,\n receivePeerConnection,\n peerlessUserExpiration,\n rtcConfig = { iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }] },\n enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM,\n logLine = console.debug,\n onLeaveUser,\n workerUrl,\n}: {\n appId: string;\n rtcConfig?: RTCConfiguration;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n onLeaveUser?: (userId: string) => void;\n logLine?: (direction: string, obj?: any) => void;\n workerUrl?: URL;\n peerlessUserExpiration?: number;\n receivePeerConnection(connection: { pc: RTCPeerConnection, userId: string, initiator: boolean }): void;\n}) {\n const userId = `user-${crypto.randomUUID()}`;\n const users: Map<string, UserState> = new Map();\n\n function getPeer(peer: IPeer<SigType, SigPayload>): UserState {\n let state = users.get(peer.userId);\n if (!state) {\n const newState: UserState = {\n userId: peer.userId,\n pc: new RTCPeerConnection(rtcConfig),\n pendingRemoteIce: [],\n peers: new Map(),\n };\n newState.peers.set(peer.peerId, peer);\n users.set(peer.userId, newState);\n\n // Send local ICE candidates to this peer\n newState.pc.onicecandidate = (ev) => {\n if (!ev.candidate) return;\n for(let user of newState.peers.values()) {\n const success = user.receive(\"ice\", ev.candidate.toJSON());\n if (success) break;\n }\n };\n \n newState.pc.onconnectionstatechange = () => {\n logLine(\"💬\", { event: \"pc-state\", userId: newState.userId, state: newState.pc.connectionState });\n };\n state = newState;\n\n // New user\n users.set(state.userId, state);\n } else if (state) {\n clearTimeout(state.expirationTimeout);\n state.expirationTimeout = 0;\n state.peers.set(peer.peerId, peer);\n }\n return state;\n }\n\n function leaveUser(userId: string) {\n onLeaveUser?.(userId);\n const p = users.get(userId);\n if (!p) return;\n try { p.pc.close(); } catch {}\n users.delete(userId);\n }\n\n async function flushRemoteIce(state: UserState) {\n if (!state.pc.remoteDescription) return;\n\n const queued = state.pendingRemoteIce;\n state.pendingRemoteIce = [];\n\n for (const ice of queued) {\n try {\n await state.pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n }\n }\n\n const roomsEntered = new Map<string, { room: string; host: string; exitRoom: () => void }>();\n\n function exit({ room, host }: { room: string; host: string; }) {\n const key = `${host}/room/${room}`;\n const session = roomsEntered.get(key);\n if (session) {\n session.exitRoom();\n roomsEntered.delete(key);\n }\n }\n\n function enter({ room, host }: { room: string; host: string; }) {\n return new Promise<void>((resolve, reject) => {\n async function makeOffer(user: IPeer) {\n // Offer flow: createOffer -> setLocalDescription -> send localDescription\n const state = getPeer(user);\n const pc = state.pc;\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n user.receive(\"offer\", pc.localDescription?.toJSON()!);\n }\n\n const { exitRoom } = enterRoom({\n userId,\n appId,\n room,\n host,\n logLine,\n workerUrl,\n\n onOpen: resolve,\n onError: reject,\n\n // Existing peers initiate to the newcomer (Option 1)\n onPeerJoined(joiningUsers: IPeer<SigType, SigPayload>[]) {\n joiningUsers.forEach(user => {\n const state = getPeer(user);\n const pc = state.pc;\n receivePeerConnection({ pc, userId: user.userId, initiator: true });\n makeOffer(user);\n });\n },\n\n onPeerLeft(leavingUsers: { userId: string; peerId: string }[]) {\n leavingUsers.forEach(({ userId, peerId }) => {\n const state = users.get(userId);\n if (!state) return;\n state.peers.delete(peerId);\n if (!state.peers.size) {\n state.expirationTimeout = setTimeout(() => leaveUser(userId), peerlessUserExpiration ?? 0);\n }\n });\n },\n\n async onMessage(type: SigType, payload: any, from: IPeer) {\n const state = getPeer(from);\n const pc = state.pc;\n\n if (type === \"offer\") {\n receivePeerConnection({ pc, userId: from.userId, initiator: false });\n // Responder: set remote offer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n\n // Create and send answer\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n from.receive(\"answer\", pc.localDescription?.toJSON()!);\n\n // Now safe to apply any queued ICE from this peer\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"answer\") {\n // Initiator: set remote answer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"ice\") {\n const ice = payload as RTCIceCandidateInit;\n\n // If we don't have remoteDescription yet, queue it\n if (!pc.remoteDescription) {\n state.pendingRemoteIce.push(ice);\n return;\n }\n\n try {\n await pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n return;\n }\n },\n });\n roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });\n });\n }\n\n return {\n userId,\n enterRoom: enter,\n exitRoom: exit,\n leaveUser,\n getRooms() {\n return Array.from(roomsEntered.values());\n },\n end() {\n roomsEntered.forEach(({ exitRoom }) => exitRoom());\n roomsEntered.clear();\n users.forEach(({ userId }) => leaveUser(userId));\n users.clear();\n },\n };\n}\n\n\n\n",
8
+ "import { EnterRoom, enterRoom } from \"./signal-room\";\nimport { SigType, SigPayload, collectPeerConnections } from \"./webrtc-peer-collector\";\n\nexport function enterWorld({\n appId, logLine = console.debug, enterRoomFunction = enterRoom, peerlessUserExpiration, workerUrl,\n}: {\n appId: string;\n logLine?: (direction: string, obj?: any) => void;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n peerlessUserExpiration?: number;\n workerUrl?: URL;\n}) {\n const userIds: string[] = [];\n const rtcConfig: RTCConfiguration = {\n iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }],\n };\n\n const messagesListeners = new Set<(data: any, from: string) => void>();\n\n function getUsers() {\n return userIds;\n }\n\n function wireDataChannel(userId: string, dc: RTCDataChannel) {\n dc.onopen = () => {\n logLine(\"💬\", { event: \"dc-open\", userId });\n userIds.push(userId);\n userListeners.forEach(listener => listener(userId, \"join\", userIds));\n };\n dc.onmessage = ({ data }) => {\n messagesListeners.forEach(listener => listener(data as any, userId));\n logLine(\"💬\", { event: \"dc-message\", userId, data });\n };\n dc.onclose = () => {\n logLine(\"💬\", { event: \"dc-close\", userId });\n userIds.splice(userIds.indexOf(userId), 1);\n userListeners.forEach(listener => listener(userId, \"leave\", userIds));\n };\n dc.onerror = () => logLine(\"⚠️ ERROR\", { error: \"dc-error\", userId });\n }\n\n const dataChannels = new Map<string, RTCDataChannel>();\n const userListeners = new Set<(userId: string, action: \"join\"|\"leave\", users: string[]) => void>();\n\n const { userId, enterRoom, exitRoom, leaveUser, end: endPeerCollection } = collectPeerConnections({\n appId,\n rtcConfig,\n enterRoomFunction,\n logLine,\n workerUrl,\n peerlessUserExpiration,\n onLeaveUser(userId: string) {\n const dc = dataChannels.get(userId);\n try { dc?.close(); } catch { }\n dataChannels.delete(userId);\n },\n receivePeerConnection({ pc, userId, initiator }) {\n if (initiator) {\n const dc = pc.createDataChannel(\"data\");\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n } else {\n pc.ondatachannel = (ev) => {\n const dc = ev.channel;\n wireDataChannel(userId, dc);\n dataChannels.set(userId, dc);\n pc.ondatachannel = null;\n };\n }\n },\n });\n\n function send(data: any, userId?: string) {\n dataChannels.forEach((dataChannel, pUserId) => {\n if (userId && pUserId !== userId) return;\n if (dataChannel.readyState === \"open\") dataChannel.send(data);\n });\n }\n\n function removeMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.delete(listener);\n }\n\n function addMessageListener(listener: (data: any, from: string) => void) {\n messagesListeners.add(listener);\n return () => {\n removeMessageListener(listener);\n };\n }\n\n function removeUserListener(listener: (userId: string, action:\"join\"|\"leave\", users: string[]) => void) {\n userListeners.delete(listener);\n }\n\n function addUserListener(listener: (userId: string, action:\"join\"|\"leave\", users: string[]) => void) {\n userListeners.add(listener);\n return () => {\n removeUserListener(listener);\n };\n }\n\n return {\n userId,\n send,\n enterRoom,\n exitRoom,\n leaveUser,\n getUsers,\n addMessageListener,\n removeMessageListener,\n addUserListener,\n removeUserListener,\n end() {\n dataChannels.forEach((dataChannel) => {\n try { dataChannel.close(); } catch { }\n });\n dataChannels.clear();\n endPeerCollection();\n userListeners.clear();\n userIds.length = 0;\n },\n };\n}\n"
9
9
  ],
10
- "mappings": "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",
11
- "debugId": "ECF8FB936A1DF5A064756E2164756E21",
10
+ "mappings": "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",
11
+ "debugId": "B796A1CA2AC2575C64756E2164756E21",
12
12
  "names": []
13
13
  }
@@ -1,4 +1,4 @@
1
- function h({userId:Z,appId:$,room:c,host:R,onOpen:G,onClose:X,onError:H,logLine:Y,onPeerJoined:S,onPeerLeft:W,onMessage:J}){let b=`wss://${R}/room/${$}/${c}?userId=${encodeURIComponent(Z)}`,z=new WebSocket(b),x=Z,K=new Map,_=!1;function N(T,A,V){if(_)return!1;let D={type:T,to:A,payload:V};return z.send(JSON.stringify(D)),Y?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",D),!0}function q(T){let A=[],V=[],D=new Set;if(T.forEach(({userId:F,peerId:B})=>{if(F===x)return;if(!K.has(B)){let j={userId:F,peerId:B,receive:(M,C)=>N(M,B,C)};K.set(B,j),A.push(j)}D.add(B)}),K.values().forEach(({peerId:F,userId:B})=>{if(!D.has(F))K.delete(F),V.push({peerId:F,userId:B})}),A.length)S(A);if(V.length)W(V)}function Q(T){let A;try{A=JSON.parse(T.data)}catch{Y?.("⚠️ ERROR",{error:"invalid-json"});return}if(Y?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",A),A.type==="peer-joined"){q(A.users);return}if(A.type==="peer-left"){q(A.users);return}if(A.peerId&&A.userId){let{userId:V,peerId:D}=A;J(A.type,A.payload,{userId:V,peerId:D,receive:(F,B)=>N(F,D,B)})}}if(z.addEventListener("message",Q),G)z.addEventListener("open",G);if(X)z.addEventListener("close",X);if(H)z.addEventListener("error",H);return{exitRoom:()=>{if(_=!0,z.close(),z.removeEventListener("message",Q),G)z.removeEventListener("open",G);if(X)z.removeEventListener("close",X);if(H)z.removeEventListener("error",H)}}}function O({userId:Z,appId:$,room:c,host:R,onOpen:G,onClose:X,onError:H,onPeerJoined:Y,onPeerLeft:S,onMessage:W,logLine:J,workerUrl:b}){if(!b)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),h({userId:Z,appId:$,room:c,host:R,onOpen:G,onClose:X,onError:H,onPeerJoined:Y,onPeerLeft:S,onMessage:W});let z=new Worker(b,{type:"module"}),x=!1;function K({userId:N,peerId:q}){return{userId:N,peerId:q,receive:(Q,T)=>{if(x)return!1;return z.postMessage({cmd:"send",toPeerId:q,type:Q,payload:T}),!0}}}let _=(N)=>{let q=N.data;if(q.kind==="open")G?.();else if(q.kind==="close")z.terminate();else if(q.kind==="error")H?.();else if(q.kind==="peer-joined")Y(q.users.map((Q)=>K({userId:Q.userId,peerId:Q.peerId})));else if(q.kind==="peer-left")S(q.users);else if(q.kind==="message")W(q.type,q.payload,K({userId:q.fromUserId,peerId:q.fromPeerId}));else if(q.kind==="log")J?.(q.direction,q.obj)};return z.addEventListener("message",_),z.postMessage({cmd:"enter",userId:Z,appId:$,room:c,host:R}),{exitRoom:()=>{x=!0,z.removeEventListener("message",_),z.postMessage({cmd:"exit"})}}}export{O as enterRoom};
1
+ function h({userId:Z,appId:$,room:c,host:R,onOpen:G,onClose:X,onError:H,logLine:Y,onPeerJoined:S,onPeerLeft:W,onMessage:J}){let b=`wss://${R}/room/${$}/${c}?userId=${encodeURIComponent(Z)}`,z=new WebSocket(b),x=Z,K=new Map,_=!1;function N(T,A,V){if(_)return!1;let D={type:T,to:A,payload:V};return z.send(JSON.stringify(D)),Y?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",D),!0}function q(T){let A=[],V=[],D=new Set;if(T.forEach(({userId:F,peerId:B})=>{if(F===x)return;if(!K.has(B)){let j={userId:F,peerId:B,receive:(M,C)=>N(M,B,C)};K.set(B,j),A.push(j)}D.add(B)}),K.values().forEach(({peerId:F,userId:B})=>{if(!D.has(F))K.delete(F),V.push({peerId:F,userId:B})}),A.length)S(A);if(V.length)W(V)}function Q(T){let A;try{A=JSON.parse(T.data)}catch{Y?.("⚠️ ERROR",{error:"invalid-json"});return}if(Y?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",A),A.type==="peer-joined"||A.type==="peer-left"){q(A.users);return}if(A.peerId&&A.userId){let{userId:V,peerId:D}=A;J(A.type,A.payload,{userId:V,peerId:D,receive:(F,B)=>N(F,D,B)})}}if(z.addEventListener("message",Q),G)z.addEventListener("open",G);if(X)z.addEventListener("close",X);if(H)z.addEventListener("error",H);return{exitRoom:()=>{if(_=!0,z.close(),z.removeEventListener("message",Q),G)z.removeEventListener("open",G);if(X)z.removeEventListener("close",X);if(H)z.removeEventListener("error",H)}}}function O({userId:Z,appId:$,room:c,host:R,onOpen:G,onClose:X,onError:H,onPeerJoined:Y,onPeerLeft:S,onMessage:W,logLine:J,workerUrl:b}){if(!b)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),h({userId:Z,appId:$,room:c,host:R,onOpen:G,onClose:X,onError:H,onPeerJoined:Y,onPeerLeft:S,onMessage:W});let z=new Worker(b,{type:"module"}),x=!1;function K({userId:N,peerId:q}){return{userId:N,peerId:q,receive:(Q,T)=>{if(x)return!1;return z.postMessage({cmd:"send",toPeerId:q,type:Q,payload:T}),!0}}}let _=(N)=>{let q=N.data;if(q.kind==="open")G?.();else if(q.kind==="close")z.terminate();else if(q.kind==="error")H?.();else if(q.kind==="peer-joined")Y(q.users.map((Q)=>K({userId:Q.userId,peerId:Q.peerId})));else if(q.kind==="peer-left")S(q.users);else if(q.kind==="message")W(q.type,q.payload,K({userId:q.fromUserId,peerId:q.fromPeerId}));else if(q.kind==="log")J?.(q.direction,q.obj)};return z.addEventListener("message",_),z.postMessage({cmd:"enter",userId:Z,appId:$,room:c,host:R}),{exitRoom:()=>{x=!0,z.removeEventListener("message",_),z.postMessage({cmd:"exit"})}}}export{O as enterRoom};
2
2
 
3
- //# debugId=6467E57AEE09475564756E2164756E21
3
+ //# debugId=BFB04698485FDADB64756E2164756E21
4
4
  //# sourceMappingURL=signal-room.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/browser/impl/signal-room.ts", "../src/browser/signal-room.ts"],
4
4
  "sourcesContent": [
5
- "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
5
+ "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\" || msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
6
6
  "import type { IPeer } from \"./impl/signal-room.js\";\nimport { enterRoom as baseEnterRoom } from \"./impl/signal-room.js\";\nimport { RoomEvent } from \"./signal-room.worker.js\";\n\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n logLine,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n onPeerJoined: (users: IPeer<T, P>[]) => void;\n onPeerLeft: (users: {userId: string, peerId: string}[]) => void;\n onMessage: (type: T, payload: P, from: IPeer<T, P>) => void;\n logLine?: (direction: string, obj?: any) => void;\n\n // Pass the URL to your worker file (bundler will handle it)\n workerUrl?: URL;\n}): { exitRoom: () => void } {\n if (!workerUrl) {\n const CDN_WORKER_URL = `https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js`;\n\n console.warn(\"Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:\", CDN_WORKER_URL);\n return baseEnterRoom<T, P>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n });\n }\n const worker = new Worker(workerUrl, { type: \"module\" });\n let exited = false;\n\n function makeUser({ userId, peerId }: { userId: string; peerId: string }): IPeer<T, P> {\n return {\n userId,\n peerId,\n receive: (type: T, payload: P) => {\n if (exited) return false;\n worker.postMessage({ cmd: \"send\", toPeerId: peerId, type, payload });\n return true;\n },\n };\n }\n\n const onWorkerMessage = (e: MessageEvent<RoomEvent<T, P>>) => {\n const ev = e.data;\n\n if (ev.kind === \"open\") onOpen?.();\n else if (ev.kind === \"close\") worker.terminate();\n else if (ev.kind === \"error\") onError?.();\n else if (ev.kind === \"peer-joined\") onPeerJoined(ev.users.map(ev => makeUser({ userId: ev.userId, peerId: ev.peerId })));\n else if (ev.kind === \"peer-left\") onPeerLeft(ev.users);\n else if (ev.kind === \"message\") onMessage(ev.type, ev.payload, makeUser({ userId: ev.fromUserId, peerId: ev.fromPeerId }));\n else if (ev.kind === \"log\") logLine?.(ev.direction, ev.obj);\n };\n\n worker.addEventListener(\"message\", onWorkerMessage);\n\n worker.postMessage({ cmd: \"enter\", userId, appId, room, host });\n\n return {\n exitRoom: () => {\n exited = true;\n worker.removeEventListener(\"message\", onWorkerMessage);\n worker.postMessage({ cmd: \"exit\" });\n },\n };\n}\n\nexport type EnterRoom<T extends string, P> = typeof enterRoom<T, P>;\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "6467E57AEE09475564756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "BFB04698485FDADB64756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1,4 +1,4 @@
1
- function R({userId:T,appId:z,room:V,host:B,onOpen:q,onClose:A,onError:Z,logLine:W,onPeerJoined:b,onPeerLeft:v,onMessage:x}){let C=`wss://${B}/room/${z}/${V}?userId=${encodeURIComponent(T)}`,D=new WebSocket(C),L=T,_=new Map,h=!1;function F(X,k,N){if(h)return!1;let H={type:X,to:k,payload:N};return D.send(JSON.stringify(H)),W?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",H),!0}function J(X){let k=[],N=[],H=new Set;if(X.forEach(({userId:K,peerId:G})=>{if(K===L)return;if(!_.has(G)){let U={userId:K,peerId:G,receive:(O,S)=>F(O,G,S)};_.set(G,U),k.push(U)}H.add(G)}),_.values().forEach(({peerId:K,userId:G})=>{if(!H.has(K))_.delete(K),N.push({peerId:K,userId:G})}),k.length)b(k);if(N.length)v(N)}function M(X){let k;try{k=JSON.parse(X.data)}catch{W?.("⚠️ ERROR",{error:"invalid-json"});return}if(W?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",k),k.type==="peer-joined"){J(k.users);return}if(k.type==="peer-left"){J(k.users);return}if(k.peerId&&k.userId){let{userId:N,peerId:H}=k;x(k.type,k.payload,{userId:N,peerId:H,receive:(K,G)=>F(K,H,G)})}}if(D.addEventListener("message",M),q)D.addEventListener("open",q);if(A)D.addEventListener("close",A);if(Z)D.addEventListener("error",Z);return{exitRoom:()=>{if(h=!0,D.close(),D.removeEventListener("message",M),q)D.removeEventListener("open",q);if(A)D.removeEventListener("close",A);if(Z)D.removeEventListener("error",Z)}}}var $=null,Y=new Map;function Q(T){self.postMessage(T)}self.addEventListener("message",(T)=>{let z=T.data;if(console.debug("[signal-room.worker] received command",z),z.cmd==="enter"){$?.(),$=null,Y.clear(),$=R({userId:z.userId,appId:z.appId,room:z.room,host:z.host,onOpen:()=>Q({kind:"open"}),onClose:()=>Q({kind:"close"}),onError:()=>Q({kind:"error"}),logLine:(B,q)=>{console.debug(`[signal-room.worker] ${B}`,q),Q({kind:"log",direction:B,obj:q})},onPeerJoined:(B)=>{B.forEach(({peerId:q,receive:A})=>Y.set(q,A)),Q({kind:"peer-joined",users:B.map(({userId:q,peerId:A})=>({userId:q,peerId:A}))})},onPeerLeft:(B)=>{B.forEach(({peerId:q})=>Y.delete(q)),Q({kind:"peer-left",users:B})},onMessage:(B,q,A)=>{Y.set(A.peerId,A.receive),Q({kind:"message",type:B,payload:q,fromUserId:A.userId,fromPeerId:A.peerId})}}).exitRoom;return}if(z.cmd==="send"){let V=Y.get(z.toPeerId);if(V)V(z.type,z.payload);return}if(z.cmd==="exit"){$?.(),self.close();return}});
1
+ function U({userId:T,appId:z,room:V,host:B,onOpen:q,onClose:A,onError:Z,logLine:W,onPeerJoined:R,onPeerLeft:b,onMessage:v}){let x=`wss://${B}/room/${z}/${V}?userId=${encodeURIComponent(T)}`,D=new WebSocket(x),C=T,_=new Map,h=!1;function F(X,k,N){if(h)return!1;let H={type:X,to:k,payload:N};return D.send(JSON.stringify(H)),W?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",H),!0}function L(X){let k=[],N=[],H=new Set;if(X.forEach(({userId:K,peerId:G})=>{if(K===C)return;if(!_.has(G)){let M={userId:K,peerId:G,receive:(O,S)=>F(O,G,S)};_.set(G,M),k.push(M)}H.add(G)}),_.values().forEach(({peerId:K,userId:G})=>{if(!H.has(K))_.delete(K),N.push({peerId:K,userId:G})}),k.length)R(k);if(N.length)b(N)}function J(X){let k;try{k=JSON.parse(X.data)}catch{W?.("⚠️ ERROR",{error:"invalid-json"});return}if(W?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",k),k.type==="peer-joined"||k.type==="peer-left"){L(k.users);return}if(k.peerId&&k.userId){let{userId:N,peerId:H}=k;v(k.type,k.payload,{userId:N,peerId:H,receive:(K,G)=>F(K,H,G)})}}if(D.addEventListener("message",J),q)D.addEventListener("open",q);if(A)D.addEventListener("close",A);if(Z)D.addEventListener("error",Z);return{exitRoom:()=>{if(h=!0,D.close(),D.removeEventListener("message",J),q)D.removeEventListener("open",q);if(A)D.removeEventListener("close",A);if(Z)D.removeEventListener("error",Z)}}}var $=null,Y=new Map;function Q(T){self.postMessage(T)}self.addEventListener("message",(T)=>{let z=T.data;if(console.debug("[signal-room.worker] received command",z),z.cmd==="enter"){$?.(),$=null,Y.clear(),$=U({userId:z.userId,appId:z.appId,room:z.room,host:z.host,onOpen:()=>Q({kind:"open"}),onClose:()=>Q({kind:"close"}),onError:()=>Q({kind:"error"}),logLine:(B,q)=>{console.debug(`[signal-room.worker] ${B}`,q),Q({kind:"log",direction:B,obj:q})},onPeerJoined:(B)=>{B.forEach(({peerId:q,receive:A})=>Y.set(q,A)),Q({kind:"peer-joined",users:B.map(({userId:q,peerId:A})=>({userId:q,peerId:A}))})},onPeerLeft:(B)=>{B.forEach(({peerId:q})=>Y.delete(q)),Q({kind:"peer-left",users:B})},onMessage:(B,q,A)=>{Y.set(A.peerId,A.receive),Q({kind:"message",type:B,payload:q,fromUserId:A.userId,fromPeerId:A.peerId})}}).exitRoom;return}if(z.cmd==="send"){let V=Y.get(z.toPeerId);if(V)V(z.type,z.payload);return}if(z.cmd==="exit"){$?.(),self.close();return}});
2
2
 
3
- //# debugId=5465A5D210652A5664756E2164756E21
3
+ //# debugId=B4D6FE1CAC5FA63564756E2164756E21
4
4
  //# sourceMappingURL=signal-room.worker.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/browser/impl/signal-room.ts", "../src/browser/signal-room.worker.ts"],
4
4
  "sourcesContent": [
5
- "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
5
+ "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\" || msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
6
6
  "/// <reference lib=\"webworker\" />\n\nimport { enterRoom, type IPeer } from \"./impl/signal-room.js\";\n\nexport type RoomEvent<T extends string = string, P = any> =\n | { kind: \"open\" }\n | { kind: \"close\" }\n | { kind: \"error\" }\n | { kind: \"peer-joined\"; users: {userId: string, peerId: string}[] }\n | { kind: \"peer-left\"; users: {userId: string, peerId: string}[] }\n | { kind: \"message\"; type: T; payload: P; fromUserId: string; fromPeerId: string }\n | { kind: \"log\"; direction: string; obj?: any };\n\ntype WorkerCommand<T extends string = string, P = any> =\n | { cmd: \"enter\"; userId: string; appId: string; room: string; host: string }\n | { cmd: \"exit\" }\n | { cmd: \"send\"; toPeerId: string; type: T; payload: P };\n\nlet exitRoom: (() => void) | null = null;\n\n// Map from userId -> a function to send to that peer (comes from IUser.receive)\nconst peerSend = new Map<string, (type: any, payload: any) => boolean>();\n\nfunction emit<T extends string, P>(ev: RoomEvent<T, P>) {\n (self as DedicatedWorkerGlobalScope).postMessage(ev);\n}\n\nself.addEventListener(\"message\", (e: MessageEvent<WorkerCommand>) => {\n const msg = e.data;\n console.debug(\"[signal-room.worker] received command\", msg);\n\n if (msg.cmd === \"enter\") {\n // If re-entering, clean up first\n exitRoom?.();\n exitRoom = null;\n peerSend.clear();\n\n const result = enterRoom({\n userId: msg.userId,\n appId: msg.appId,\n room: msg.room,\n host: msg.host,\n onOpen: () => emit({ kind: \"open\" }),\n onClose: () => emit({ kind: \"close\" }),\n onError: () => emit({ kind: \"error\" }),\n logLine: (direction: string, obj?: any) => {\n console.debug(`[signal-room.worker] ${direction}`, obj);\n emit({ kind: \"log\", direction, obj });\n },\n onPeerJoined: (users: IPeer[]) => {\n // Save the ability to send to this peer\n users.forEach(({ peerId, receive }) => peerSend.set(peerId, receive));\n emit({ kind: \"peer-joined\", users: users.map(({ userId, peerId }) => ({ userId, peerId })) });\n },\n onPeerLeft: (users: {userId: string, peerId: string}[]) => {\n users.forEach(({ peerId }) => peerSend.delete(peerId));\n emit({ kind: \"peer-left\", users });\n },\n onMessage: (type: any, payload: any, from: IPeer) => {\n // We can also learn peerSend via onMessage in case join events vary\n peerSend.set(from.peerId, from.receive);\n emit({ kind: \"message\", type, payload, fromUserId: from.userId, fromPeerId: from.peerId });\n },\n });\n\n exitRoom = result.exitRoom;\n return;\n }\n\n if (msg.cmd === \"send\") {\n const sendFn = peerSend.get(msg.toPeerId);\n if (sendFn) sendFn(msg.type, msg.payload);\n return;\n }\n\n if (msg.cmd === \"exit\") {\n exitRoom?.();\n self.close();\n return;\n }\n});\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "5465A5D210652A5664756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "B4D6FE1CAC5FA63564756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1,9 +1,7 @@
1
1
  import { EnterRoom } from "./signal-room";
2
2
  export type SigType = "offer" | "answer" | "ice";
3
3
  export type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;
4
- type UserListener = (user: string, action: "join" | "leave", users: string[]) => void;
5
- export declare function collectPeerConnections({ userId, appId, receivePeerConnection, peerlessUserExpiration, rtcConfig, enterRoomFunction: enterRoom, logLine, onLeaveUser, workerUrl, }: {
6
- userId: string;
4
+ export declare function collectPeerConnections({ appId, receivePeerConnection, peerlessUserExpiration, rtcConfig, enterRoomFunction: enterRoom, logLine, onLeaveUser, workerUrl, }: {
7
5
  appId: string;
8
6
  rtcConfig?: RTCConfiguration;
9
7
  enterRoomFunction?: EnterRoom<SigType, SigPayload>;
@@ -17,6 +15,7 @@ export declare function collectPeerConnections({ userId, appId, receivePeerConne
17
15
  initiator: boolean;
18
16
  }): void;
19
17
  }): {
18
+ userId: string;
20
19
  enterRoom: ({ room, host }: {
21
20
  room: string;
22
21
  host: string;
@@ -26,9 +25,6 @@ export declare function collectPeerConnections({ userId, appId, receivePeerConne
26
25
  host: string;
27
26
  }) => void;
28
27
  leaveUser: (userId: string) => void;
29
- getUsers: () => string[];
30
- addUserListener: (listener: UserListener) => () => void;
31
- removeUserListener: (listener: UserListener) => void;
32
28
  getRooms(): {
33
29
  room: string;
34
30
  host: string;
@@ -36,5 +32,4 @@ export declare function collectPeerConnections({ userId, appId, receivePeerConne
36
32
  }[];
37
33
  end(): void;
38
34
  };
39
- export {};
40
35
  //# sourceMappingURL=webrtc-peer-collector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webrtc-peer-collector.d.ts","sourceRoot":"","sources":["../src/browser/webrtc-peer-collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAa,MAAM,eAAe,CAAC;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AACjD,MAAM,MAAM,UAAU,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;AAczE,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AAKpF,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,KAAK,EACL,qBAAqB,EACrB,sBAAsB,EACtB,SAAsE,EACtE,iBAAiB,EAAE,SAA8B,EACjD,OAAuB,EACvB,WAAW,EACX,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,iBAAiB,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,qBAAqB,CAAC,UAAU,EAAE;QAAE,EAAE,EAAE,iBAAiB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACxG;gCAgFgC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;+BAThC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;wBA3BlC,MAAM;;gCAqIE,YAAY;mCAJT,YAAY;;cAxGL,MAAM;cAAQ,MAAM;kBAAY,MAAM,IAAI;;;EAoIxF"}
1
+ {"version":3,"file":"webrtc-peer-collector.d.ts","sourceRoot":"","sources":["../src/browser/webrtc-peer-collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAa,MAAM,eAAe,CAAC;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AACjD,MAAM,MAAM,UAAU,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;AAmBzE,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,qBAAqB,EACrB,sBAAsB,EACtB,SAAsE,EACtE,iBAAiB,EAAE,SAA8B,EACjD,OAAuB,EACvB,WAAW,EACX,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,iBAAiB,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,qBAAqB,CAAC,UAAU,EAAE;QAAE,EAAE,EAAE,iBAAiB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACxG;;gCA0EgC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;+BAThC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;wBAzBlC,MAAM;;cAuBY,MAAM;cAAQ,MAAM;kBAAY,MAAM,IAAI;;;EAsHxF"}
@@ -1,4 +1,4 @@
1
- function P({userId:R,appId:C,room:M,host:h,onOpen:W,onClose:S,onError:X,logLine:j,onPeerJoined:k,onPeerLeft:Y,onMessage:O}){let q=`wss://${h}/room/${C}/${M}?userId=${encodeURIComponent(R)}`,K=new WebSocket(q),x=R,D=new Map,A=!1;function _(b,z,B){if(A)return!1;let G={type:b,to:z,payload:B};return K.send(JSON.stringify(G)),j?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",G),!0}function H(b){let z=[],B=[],G=new Set;if(b.forEach(({userId:Q,peerId:Z})=>{if(Q===x)return;if(!D.has(Z)){let E={userId:Q,peerId:Z,receive:(F,$)=>_(F,Z,$)};D.set(Z,E),z.push(E)}G.add(Z)}),D.values().forEach(({peerId:Q,userId:Z})=>{if(!G.has(Q))D.delete(Q),B.push({peerId:Q,userId:Z})}),z.length)k(z);if(B.length)Y(B)}function T(b){let z;try{z=JSON.parse(b.data)}catch{j?.("⚠️ ERROR",{error:"invalid-json"});return}if(j?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",z),z.type==="peer-joined"){H(z.users);return}if(z.type==="peer-left"){H(z.users);return}if(z.peerId&&z.userId){let{userId:B,peerId:G}=z;O(z.type,z.payload,{userId:B,peerId:G,receive:(Q,Z)=>_(Q,G,Z)})}}if(K.addEventListener("message",T),W)K.addEventListener("open",W);if(S)K.addEventListener("close",S);if(X)K.addEventListener("error",X);return{exitRoom:()=>{if(A=!0,K.close(),K.removeEventListener("message",T),W)K.removeEventListener("open",W);if(S)K.removeEventListener("close",S);if(X)K.removeEventListener("error",X)}}}function U({userId:R,appId:C,room:M,host:h,onOpen:W,onClose:S,onError:X,onPeerJoined:j,onPeerLeft:k,onMessage:Y,logLine:O,workerUrl:q}){if(!q)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),P({userId:R,appId:C,room:M,host:h,onOpen:W,onClose:S,onError:X,onPeerJoined:j,onPeerLeft:k,onMessage:Y});let K=new Worker(q,{type:"module"}),x=!1;function D({userId:_,peerId:H}){return{userId:_,peerId:H,receive:(T,b)=>{if(x)return!1;return K.postMessage({cmd:"send",toPeerId:H,type:T,payload:b}),!0}}}let A=(_)=>{let H=_.data;if(H.kind==="open")W?.();else if(H.kind==="close")K.terminate();else if(H.kind==="error")X?.();else if(H.kind==="peer-joined")j(H.users.map((T)=>D({userId:T.userId,peerId:T.peerId})));else if(H.kind==="peer-left")k(H.users);else if(H.kind==="message")Y(H.type,H.payload,D({userId:H.fromUserId,peerId:H.fromPeerId}));else if(H.kind==="log")O?.(H.direction,H.obj)};return K.addEventListener("message",A),K.postMessage({cmd:"enter",userId:R,appId:C,room:M,host:h}),{exitRoom:()=>{x=!0,K.removeEventListener("message",A),K.postMessage({cmd:"exit"})}}}var L=U;function u({userId:R,appId:C,receivePeerConnection:M,peerlessUserExpiration:h,rtcConfig:W={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},enterRoomFunction:S=L,logLine:X=console.debug,onLeaveUser:j,workerUrl:k}){let Y=new Map;function O(){return[...Y.keys()]}let q=new Set;function K(z){let B=Y.get(z.userId);if(!B){let G={userId:z.userId,pc:new RTCPeerConnection(W),pendingRemoteIce:[],peers:new Map};G.peers.set(z.peerId,z),Y.set(z.userId,G),G.pc.onicecandidate=(Q)=>{if(!Q.candidate)return;for(let Z of G.peers.values())if(Z.receive("ice",Q.candidate.toJSON()))break},G.pc.onconnectionstatechange=()=>{X("\uD83D\uDCAC",{event:"pc-state",userId:G.userId,state:G.pc.connectionState})},B=G,q.forEach((Q)=>Q(z.userId,"join",O())),Y.set(B.userId,B)}else if(B)clearTimeout(B.expirationTimeout),B.expirationTimeout=0,B.peers.set(z.peerId,z);return B}function x(z){j?.(z);let B=Y.get(z);if(!B)return;try{B.pc.close()}catch{}Y.delete(z),q.forEach((G)=>G(z,"leave",O())),X("\uD83D\uDC64 USER LEFT",z)}async function D(z){if(!z.pc.remoteDescription)return;let B=z.pendingRemoteIce;z.pendingRemoteIce=[];for(let G of B)try{await z.pc.addIceCandidate(G)}catch(Q){X("⚠️ ERROR",{error:"add-ice-failed",userId:z.userId,detail:String(Q)})}}let A=new Map;function _({room:z,host:B}){let G=`${B}/room/${z}`,Q=A.get(G);if(Q)Q.exitRoom(),A.delete(G)}function H({room:z,host:B}){return new Promise((G,Q)=>{async function Z(F){let N=K(F).pc,V=await N.createOffer();await N.setLocalDescription(V),F.receive("offer",N.localDescription?.toJSON())}let{exitRoom:E}=S({userId:R,appId:C,room:z,host:B,logLine:X,workerUrl:k,onOpen:G,onError:Q,onPeerJoined(F){F.forEach(($)=>{let V=K($).pc;M({pc:V,userId:$.userId,initiator:!0}),Z($)})},onPeerLeft(F){F.forEach(({userId:$,peerId:N})=>{let V=Y.get($);if(!V)return;if(V.peers.delete(N),V.peers.size===0)V.expirationTimeout=setTimeout(()=>x($),h??0)})},async onMessage(F,$,N){let V=K(N),J=V.pc;if(F==="offer"){M({pc:J,userId:N.userId,initiator:!1}),await J.setRemoteDescription($);let f=await J.createAnswer();await J.setLocalDescription(f),N.receive("answer",J.localDescription?.toJSON()),await D(V);return}if(F==="answer"){await J.setRemoteDescription($),await D(V),M({pc:J,userId:N.userId,initiator:!0});return}if(F==="ice"){let f=$;if(!J.remoteDescription){V.pendingRemoteIce.push(f);return}try{await J.addIceCandidate(f)}catch(y){X("⚠️ ERROR",{error:"add-ice-failed",userId:V.userId,detail:String(y)})}return}}});A.set(`${B}/room/${z}`,{exitRoom:E,room:z,host:B})})}function T(z){q.delete(z)}function b(z){return q.add(z),()=>{T(z)}}return{enterRoom:H,exitRoom:_,leaveUser:x,getUsers:O,addUserListener:b,removeUserListener:T,getRooms(){return Array.from(A.values())},end(){A.forEach(({exitRoom:z})=>z()),A.clear(),Y.forEach(({userId:z})=>x(z)),q.clear()}}}export{u as collectPeerConnections};
1
+ function h({userId:J,appId:M,room:R,host:O,onOpen:D,onClose:A,onError:T,logLine:_,onPeerJoined:S,onPeerLeft:$,onMessage:j}){let b=`wss://${O}/room/${M}/${R}?userId=${encodeURIComponent(J)}`,H=new WebSocket(b),F=J,W=new Map,x=!1;function B(Y,K,N){if(x)return!1;let X={type:Y,to:K,payload:N};return H.send(JSON.stringify(X)),_?.("\uD83D\uDC64 ➡️ \uD83D\uDDA5️",X),!0}function z(Y){let K=[],N=[],X=new Set;if(Y.forEach(({userId:Q,peerId:V})=>{if(Q===F)return;if(!W.has(V)){let Z={userId:Q,peerId:V,receive:(q,C)=>B(q,V,C)};W.set(V,Z),K.push(Z)}X.add(V)}),W.values().forEach(({peerId:Q,userId:V})=>{if(!X.has(Q))W.delete(Q),N.push({peerId:Q,userId:V})}),K.length)S(K);if(N.length)$(N)}function G(Y){let K;try{K=JSON.parse(Y.data)}catch{_?.("⚠️ ERROR",{error:"invalid-json"});return}if(_?.("\uD83D\uDDA5️ ➡️ \uD83D\uDC64",K),K.type==="peer-joined"||K.type==="peer-left"){z(K.users);return}if(K.peerId&&K.userId){let{userId:N,peerId:X}=K;j(K.type,K.payload,{userId:N,peerId:X,receive:(Q,V)=>B(Q,X,V)})}}if(H.addEventListener("message",G),D)H.addEventListener("open",D);if(A)H.addEventListener("close",A);if(T)H.addEventListener("error",T);return{exitRoom:()=>{if(x=!0,H.close(),H.removeEventListener("message",G),D)H.removeEventListener("open",D);if(A)H.removeEventListener("close",A);if(T)H.removeEventListener("error",T)}}}function k({userId:J,appId:M,room:R,host:O,onOpen:D,onClose:A,onError:T,onPeerJoined:_,onPeerLeft:S,onMessage:$,logLine:j,workerUrl:b}){if(!b)return console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:","https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js"),h({userId:J,appId:M,room:R,host:O,onOpen:D,onClose:A,onError:T,onPeerJoined:_,onPeerLeft:S,onMessage:$});let H=new Worker(b,{type:"module"}),F=!1;function W({userId:B,peerId:z}){return{userId:B,peerId:z,receive:(G,Y)=>{if(F)return!1;return H.postMessage({cmd:"send",toPeerId:z,type:G,payload:Y}),!0}}}let x=(B)=>{let z=B.data;if(z.kind==="open")D?.();else if(z.kind==="close")H.terminate();else if(z.kind==="error")T?.();else if(z.kind==="peer-joined")_(z.users.map((G)=>W({userId:G.userId,peerId:G.peerId})));else if(z.kind==="peer-left")S(z.users);else if(z.kind==="message")$(z.type,z.payload,W({userId:z.fromUserId,peerId:z.fromPeerId}));else if(z.kind==="log")j?.(z.direction,z.obj)};return H.addEventListener("message",x),H.postMessage({cmd:"enter",userId:J,appId:M,room:R,host:O}),{exitRoom:()=>{F=!0,H.removeEventListener("message",x),H.postMessage({cmd:"exit"})}}}var U=k;function v({appId:J,receivePeerConnection:M,peerlessUserExpiration:R,rtcConfig:O={iceServers:[{urls:"stun:stun.l.google.com:19302"}]},enterRoomFunction:D=U,logLine:A=console.debug,onLeaveUser:T,workerUrl:_}){let S=`user-${crypto.randomUUID()}`,$=new Map;function j(B){let z=$.get(B.userId);if(!z){let G={userId:B.userId,pc:new RTCPeerConnection(O),pendingRemoteIce:[],peers:new Map};G.peers.set(B.peerId,B),$.set(B.userId,G),G.pc.onicecandidate=(Y)=>{if(!Y.candidate)return;for(let K of G.peers.values())if(K.receive("ice",Y.candidate.toJSON()))break},G.pc.onconnectionstatechange=()=>{A("\uD83D\uDCAC",{event:"pc-state",userId:G.userId,state:G.pc.connectionState})},z=G,$.set(z.userId,z)}else if(z)clearTimeout(z.expirationTimeout),z.expirationTimeout=0,z.peers.set(B.peerId,B);return z}function b(B){T?.(B);let z=$.get(B);if(!z)return;try{z.pc.close()}catch{}$.delete(B)}async function H(B){if(!B.pc.remoteDescription)return;let z=B.pendingRemoteIce;B.pendingRemoteIce=[];for(let G of z)try{await B.pc.addIceCandidate(G)}catch(Y){A("⚠️ ERROR",{error:"add-ice-failed",userId:B.userId,detail:String(Y)})}}let F=new Map;function W({room:B,host:z}){let G=`${z}/room/${B}`,Y=F.get(G);if(Y)Y.exitRoom(),F.delete(G)}function x({room:B,host:z}){return new Promise((G,Y)=>{async function K(X){let V=j(X).pc,Z=await V.createOffer();await V.setLocalDescription(Z),X.receive("offer",V.localDescription?.toJSON())}let{exitRoom:N}=D({userId:S,appId:J,room:B,host:z,logLine:A,workerUrl:_,onOpen:G,onError:Y,onPeerJoined(X){X.forEach((Q)=>{let Z=j(Q).pc;M({pc:Z,userId:Q.userId,initiator:!0}),K(Q)})},onPeerLeft(X){X.forEach(({userId:Q,peerId:V})=>{let Z=$.get(Q);if(!Z)return;if(Z.peers.delete(V),!Z.peers.size)Z.expirationTimeout=setTimeout(()=>b(Q),R??0)})},async onMessage(X,Q,V){let Z=j(V),q=Z.pc;if(X==="offer"){M({pc:q,userId:V.userId,initiator:!1}),await q.setRemoteDescription(Q);let C=await q.createAnswer();await q.setLocalDescription(C),V.receive("answer",q.localDescription?.toJSON()),await H(Z);return}if(X==="answer"){await q.setRemoteDescription(Q),await H(Z);return}if(X==="ice"){let C=Q;if(!q.remoteDescription){Z.pendingRemoteIce.push(C);return}try{await q.addIceCandidate(C)}catch(E){A("⚠️ ERROR",{error:"add-ice-failed",userId:Z.userId,detail:String(E)})}return}}});F.set(`${z}/room/${B}`,{exitRoom:N,room:B,host:z})})}return{userId:S,enterRoom:x,exitRoom:W,leaveUser:b,getRooms(){return Array.from(F.values())},end(){F.forEach(({exitRoom:B})=>B()),F.clear(),$.forEach(({userId:B})=>b(B)),$.clear()}}}export{v as collectPeerConnections};
2
2
 
3
- //# debugId=B41F283EA3BA21EC64756E2164756E21
3
+ //# debugId=C180D94D2452675564756E2164756E21
4
4
  //# sourceMappingURL=webrtc-peer-collector.js.map
@@ -2,11 +2,11 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/browser/impl/signal-room.ts", "../src/browser/signal-room.ts", "../src/browser/webrtc-peer-collector.ts"],
4
4
  "sourcesContent": [
5
- "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
5
+ "export interface IPeer<T extends string = string, P = any> {\n userId: string;\n peerId: string;\n receive(type: T, payload: P): boolean;\n}\n\n/**\n * enterRoom connects to the signaling room via WebSocket.\n */\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n logLine,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n logLine?: (direction: string, obj?: any) => void;\n onPeerJoined(users: IPeer<T, P>[]) : void;\n onPeerLeft(users: {userId: string, peerId: string}[]) : void;\n onMessage(type: T, payload: P, from: IPeer<T, P>) : void;\n}): { exitRoom: () => void } {\n const wsUrl = `wss://${host}/room/${appId}/${room}?userId=${encodeURIComponent(userId)}`;\n const ws = new WebSocket(wsUrl);\n const selfUserId = userId;\n\n const peers = new Map<string, IPeer<T, P>>();\n let exited = false;\n function send(type: T, toPeerId: string, payload: P) {\n if (exited) return false;\n const obj = { type, to: toPeerId, payload };\n ws.send(JSON.stringify(obj));\n logLine?.(\"👤 ➡️ 🖥️\", obj);\n return true;\n }\n\n function updatePeers(updatedUsers: { peerId: string; userId: string }[]) {\n const joined: IPeer<T,P>[] = [];\n const left: Omit<IPeer<T,P>, \"receive\">[] = [];\n const updatedPeerSet = new Set<string>();\n updatedUsers.forEach(({ userId, peerId }) => {\n if (userId === selfUserId) return;\n if (!peers.has(peerId)) {\n const newPeer = { userId, peerId, receive: (type: T, payload: P) => send(type, peerId, payload)};\n peers.set(peerId, newPeer);\n joined.push(newPeer);\n }\n updatedPeerSet.add(peerId);\n });\n peers.values().forEach(({ peerId, userId }) => {\n if (!updatedPeerSet.has(peerId)) {\n peers.delete(peerId);\n left.push({ peerId, userId });\n }\n });\n if (joined.length) onPeerJoined(joined);\n if (left.length) onPeerLeft(left);\n }\n\n function onmessage(e: MessageEvent) {\n let msg: {\n type: T;\n peerId: string;\n userId: string;\n users: { peerId: string, userId: string }[],\n payload: P;\n };\n try { msg = JSON.parse(e.data); }\n catch {\n logLine?.(\"⚠️ ERROR\", { error: \"invalid-json\" });\n return;\n }\n\n logLine?.(\"🖥️ ➡️ 👤\", msg);\n\n // Existing client greets newcomers\n if (msg.type === \"peer-joined\" || msg.type === \"peer-left\") {\n updatePeers(msg.users);\n return;\n }\n if (msg.peerId && msg.userId) {\n const { userId, peerId } = msg;\n onMessage(msg.type, msg.payload, {\n userId,\n peerId,\n receive: (type: T, payload: P) => send(type, peerId, payload),\n });\n }\n };\n\n ws.addEventListener(\"message\", onmessage);\n if (onOpen) ws.addEventListener(\"open\", onOpen);\n if (onClose) ws.addEventListener(\"close\", onClose);\n if (onError) ws.addEventListener(\"error\", onError);\n return {\n exitRoom: () => {\n exited = true;\n ws.close();\n ws.removeEventListener(\"message\", onmessage);\n if (onOpen) ws.removeEventListener(\"open\", onOpen);\n if (onClose) ws.removeEventListener(\"close\", onClose);\n if (onError) ws.removeEventListener(\"error\", onError);\n },\n };\n}\n",
6
6
  "import type { IPeer } from \"./impl/signal-room.js\";\nimport { enterRoom as baseEnterRoom } from \"./impl/signal-room.js\";\nimport { RoomEvent } from \"./signal-room.worker.js\";\n\nexport function enterRoom<T extends string, P = any>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n logLine,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n room: string;\n host: string;\n onOpen?: () => void;\n onClose?: () => void;\n onError?: () => void;\n onPeerJoined: (users: IPeer<T, P>[]) => void;\n onPeerLeft: (users: {userId: string, peerId: string}[]) => void;\n onMessage: (type: T, payload: P, from: IPeer<T, P>) => void;\n logLine?: (direction: string, obj?: any) => void;\n\n // Pass the URL to your worker file (bundler will handle it)\n workerUrl?: URL;\n}): { exitRoom: () => void } {\n if (!workerUrl) {\n const CDN_WORKER_URL = `https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js`;\n\n console.warn(\"Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:\", CDN_WORKER_URL);\n return baseEnterRoom<T, P>({\n userId,\n appId,\n room,\n host,\n onOpen,\n onClose,\n onError,\n onPeerJoined,\n onPeerLeft,\n onMessage,\n });\n }\n const worker = new Worker(workerUrl, { type: \"module\" });\n let exited = false;\n\n function makeUser({ userId, peerId }: { userId: string; peerId: string }): IPeer<T, P> {\n return {\n userId,\n peerId,\n receive: (type: T, payload: P) => {\n if (exited) return false;\n worker.postMessage({ cmd: \"send\", toPeerId: peerId, type, payload });\n return true;\n },\n };\n }\n\n const onWorkerMessage = (e: MessageEvent<RoomEvent<T, P>>) => {\n const ev = e.data;\n\n if (ev.kind === \"open\") onOpen?.();\n else if (ev.kind === \"close\") worker.terminate();\n else if (ev.kind === \"error\") onError?.();\n else if (ev.kind === \"peer-joined\") onPeerJoined(ev.users.map(ev => makeUser({ userId: ev.userId, peerId: ev.peerId })));\n else if (ev.kind === \"peer-left\") onPeerLeft(ev.users);\n else if (ev.kind === \"message\") onMessage(ev.type, ev.payload, makeUser({ userId: ev.fromUserId, peerId: ev.fromPeerId }));\n else if (ev.kind === \"log\") logLine?.(ev.direction, ev.obj);\n };\n\n worker.addEventListener(\"message\", onWorkerMessage);\n\n worker.postMessage({ cmd: \"enter\", userId, appId, room, host });\n\n return {\n exitRoom: () => {\n exited = true;\n worker.removeEventListener(\"message\", onWorkerMessage);\n worker.postMessage({ cmd: \"exit\" });\n },\n };\n}\n\nexport type EnterRoom<T extends string, P> = typeof enterRoom<T, P>;\n",
7
- "import { IPeer } from \"./impl/signal-room\";\nimport { EnterRoom, enterRoom } from \"./signal-room\";\n\nexport type SigType = \"offer\" | \"answer\" | \"ice\";\nexport type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;\n\ntype UserState = {\n userId: string;\n pc: RTCPeerConnection;\n\n // ICE that arrived before we had remoteDescription\n pendingRemoteIce: RTCIceCandidateInit[];\n\n // the signaling \"user\" handle so we can send messages\n peers: Map<string, IPeer<SigType, SigPayload>>;\n\n expirationTimeout?: number;\n};\ntype UserListener = (user: string, action: \"join\"|\"leave\", users: string[]) => void;\n\nconst DEFAULT_ENTER_ROOM = enterRoom;\n\n\nexport function collectPeerConnections({\n userId,\n appId,\n receivePeerConnection,\n peerlessUserExpiration,\n rtcConfig = { iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }] },\n enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM,\n logLine = console.debug,\n onLeaveUser,\n workerUrl,\n}: {\n userId: string;\n appId: string;\n rtcConfig?: RTCConfiguration;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n onLeaveUser?: (userId: string) => void;\n logLine?: (direction: string, obj?: any) => void;\n workerUrl?: URL;\n peerlessUserExpiration?: number;\n receivePeerConnection(connection: { pc: RTCPeerConnection, userId: string, initiator: boolean }): void;\n}) {\n const users: Map<string, UserState> = new Map();\n function getUsers() {\n return [...users.keys()];\n }\n\n const userListener: Set<UserListener> = new Set();\n function getPeer(peer: IPeer<SigType, SigPayload>): UserState {\n let state = users.get(peer.userId);\n if (!state) {\n const newState: UserState = {\n userId: peer.userId,\n pc: new RTCPeerConnection(rtcConfig),\n pendingRemoteIce: [],\n peers: new Map(),\n };\n newState.peers.set(peer.peerId, peer);\n users.set(peer.userId, newState);\n\n // Send local ICE candidates to this peer\n newState.pc.onicecandidate = (ev) => {\n if (!ev.candidate) return;\n for(let user of newState.peers.values()) {\n const success = user.receive(\"ice\", ev.candidate.toJSON());\n if (success) break;\n }\n };\n \n newState.pc.onconnectionstatechange = () => {\n logLine(\"💬\", { event: \"pc-state\", userId: newState.userId, state: newState.pc.connectionState });\n };\n state = newState;\n\n // New user\n userListener.forEach(listener => listener(peer.userId, \"join\", getUsers()));\n users.set(state.userId, state);\n } else if (state) {\n clearTimeout(state.expirationTimeout);\n state.expirationTimeout = 0;\n state.peers.set(peer.peerId, peer);\n }\n return state;\n }\n\n function leaveUser(userId: string) {\n onLeaveUser?.(userId);\n const p = users.get(userId);\n if (!p) return;\n try { p.pc.close(); } catch {}\n users.delete(userId);\n userListener.forEach(listener => listener(userId, \"leave\", getUsers()));\n logLine(\"👤 USER LEFT\", userId);\n }\n\n async function flushRemoteIce(state: UserState) {\n if (!state.pc.remoteDescription) return;\n\n const queued = state.pendingRemoteIce;\n state.pendingRemoteIce = [];\n\n for (const ice of queued) {\n try {\n await state.pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n }\n }\n\n const roomsEntered = new Map<string, { room: string; host: string; exitRoom: () => void }>();\n\n function exit({ room, host }: { room: string; host: string; }) {\n const key = `${host}/room/${room}`;\n const session = roomsEntered.get(key);\n if (session) {\n session.exitRoom();\n roomsEntered.delete(key);\n }\n }\n\n function enter({ room, host }: { room: string; host: string; }) {\n return new Promise<void>((resolve, reject) => {\n async function makeOffer(user: IPeer) {\n // Offer flow: createOffer -> setLocalDescription -> send localDescription\n const state = getPeer(user);\n const pc = state.pc;\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n user.receive(\"offer\", pc.localDescription?.toJSON()!);\n }\n\n const { exitRoom } = enterRoom({\n userId,\n appId,\n room,\n host,\n logLine,\n workerUrl,\n\n onOpen: resolve,\n onError: reject,\n\n // Existing peers initiate to the newcomer (Option 1)\n onPeerJoined(joiningUsers: IPeer<SigType, SigPayload>[]) {\n joiningUsers.forEach(user => {\n const state = getPeer(user);\n const pc = state.pc;\n receivePeerConnection({ pc, userId: user.userId, initiator: true });\n makeOffer(user);\n });\n },\n\n onPeerLeft(leavingUsers: { userId: string; peerId: string }[]) {\n leavingUsers.forEach(({ userId, peerId }) => {\n const state = users.get(userId);\n if (!state) return;\n state.peers.delete(peerId);\n if (state.peers.size === 0) {\n state.expirationTimeout = setTimeout(() => leaveUser(userId), peerlessUserExpiration ?? 0);\n }\n });\n },\n\n async onMessage(type: SigType, payload: any, from: IPeer) {\n const state = getPeer(from);\n const pc = state.pc;\n\n if (type === \"offer\") {\n receivePeerConnection({ pc, userId: from.userId, initiator: false });\n // Responder: set remote offer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n\n // Create and send answer\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n from.receive(\"answer\", pc.localDescription?.toJSON()!);\n\n // Now safe to apply any queued ICE from this peer\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"answer\") {\n // Initiator: set remote answer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n await flushRemoteIce(state);\n receivePeerConnection({ pc, userId: from.userId, initiator: true });\n return;\n }\n\n if (type === \"ice\") {\n const ice = payload as RTCIceCandidateInit;\n\n // If we don't have remoteDescription yet, queue it\n if (!pc.remoteDescription) {\n state.pendingRemoteIce.push(ice);\n return;\n }\n\n try {\n await pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n return;\n }\n },\n });\n roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });\n });\n }\n\n function removeUserListener(listener: UserListener) {\n userListener.delete(listener);\n }\n\n function addUserListener(listener: UserListener) {\n userListener.add(listener);\n return () => {\n removeUserListener(listener);\n };\n }\n\n return {\n enterRoom: enter,\n exitRoom: exit,\n leaveUser,\n getUsers,\n addUserListener,\n removeUserListener,\n getRooms() {\n return Array.from(roomsEntered.values());\n },\n end() {\n roomsEntered.forEach(({ exitRoom }) => exitRoom());\n roomsEntered.clear();\n users.forEach(({ userId }) => leaveUser(userId));\n userListener.clear();\n },\n };\n}\n\n\n\n"
7
+ "import { IPeer } from \"./impl/signal-room\";\nimport { EnterRoom, enterRoom } from \"./signal-room\";\n\nexport type SigType = \"offer\" | \"answer\" | \"ice\";\nexport type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;\n\ntype UserState = {\n userId: string;\n pc: RTCPeerConnection;\n\n // ICE that arrived before we had remoteDescription\n pendingRemoteIce: RTCIceCandidateInit[];\n\n // the signaling \"user\" handle so we can send messages\n peers: Map<string, IPeer<SigType, SigPayload>>;\n\n expirationTimeout?: number;\n};\ntype UserListener = (user: string, action: \"join\"|\"leave\") => void;\n\nconst DEFAULT_ENTER_ROOM = enterRoom;\n\n\nexport function collectPeerConnections({\n appId,\n receivePeerConnection,\n peerlessUserExpiration,\n rtcConfig = { iceServers: [{ urls: \"stun:stun.l.google.com:19302\" }] },\n enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM,\n logLine = console.debug,\n onLeaveUser,\n workerUrl,\n}: {\n appId: string;\n rtcConfig?: RTCConfiguration;\n enterRoomFunction?: EnterRoom<SigType, SigPayload>;\n onLeaveUser?: (userId: string) => void;\n logLine?: (direction: string, obj?: any) => void;\n workerUrl?: URL;\n peerlessUserExpiration?: number;\n receivePeerConnection(connection: { pc: RTCPeerConnection, userId: string, initiator: boolean }): void;\n}) {\n const userId = `user-${crypto.randomUUID()}`;\n const users: Map<string, UserState> = new Map();\n\n function getPeer(peer: IPeer<SigType, SigPayload>): UserState {\n let state = users.get(peer.userId);\n if (!state) {\n const newState: UserState = {\n userId: peer.userId,\n pc: new RTCPeerConnection(rtcConfig),\n pendingRemoteIce: [],\n peers: new Map(),\n };\n newState.peers.set(peer.peerId, peer);\n users.set(peer.userId, newState);\n\n // Send local ICE candidates to this peer\n newState.pc.onicecandidate = (ev) => {\n if (!ev.candidate) return;\n for(let user of newState.peers.values()) {\n const success = user.receive(\"ice\", ev.candidate.toJSON());\n if (success) break;\n }\n };\n \n newState.pc.onconnectionstatechange = () => {\n logLine(\"💬\", { event: \"pc-state\", userId: newState.userId, state: newState.pc.connectionState });\n };\n state = newState;\n\n // New user\n users.set(state.userId, state);\n } else if (state) {\n clearTimeout(state.expirationTimeout);\n state.expirationTimeout = 0;\n state.peers.set(peer.peerId, peer);\n }\n return state;\n }\n\n function leaveUser(userId: string) {\n onLeaveUser?.(userId);\n const p = users.get(userId);\n if (!p) return;\n try { p.pc.close(); } catch {}\n users.delete(userId);\n }\n\n async function flushRemoteIce(state: UserState) {\n if (!state.pc.remoteDescription) return;\n\n const queued = state.pendingRemoteIce;\n state.pendingRemoteIce = [];\n\n for (const ice of queued) {\n try {\n await state.pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n }\n }\n\n const roomsEntered = new Map<string, { room: string; host: string; exitRoom: () => void }>();\n\n function exit({ room, host }: { room: string; host: string; }) {\n const key = `${host}/room/${room}`;\n const session = roomsEntered.get(key);\n if (session) {\n session.exitRoom();\n roomsEntered.delete(key);\n }\n }\n\n function enter({ room, host }: { room: string; host: string; }) {\n return new Promise<void>((resolve, reject) => {\n async function makeOffer(user: IPeer) {\n // Offer flow: createOffer -> setLocalDescription -> send localDescription\n const state = getPeer(user);\n const pc = state.pc;\n const offer = await pc.createOffer();\n await pc.setLocalDescription(offer);\n user.receive(\"offer\", pc.localDescription?.toJSON()!);\n }\n\n const { exitRoom } = enterRoom({\n userId,\n appId,\n room,\n host,\n logLine,\n workerUrl,\n\n onOpen: resolve,\n onError: reject,\n\n // Existing peers initiate to the newcomer (Option 1)\n onPeerJoined(joiningUsers: IPeer<SigType, SigPayload>[]) {\n joiningUsers.forEach(user => {\n const state = getPeer(user);\n const pc = state.pc;\n receivePeerConnection({ pc, userId: user.userId, initiator: true });\n makeOffer(user);\n });\n },\n\n onPeerLeft(leavingUsers: { userId: string; peerId: string }[]) {\n leavingUsers.forEach(({ userId, peerId }) => {\n const state = users.get(userId);\n if (!state) return;\n state.peers.delete(peerId);\n if (!state.peers.size) {\n state.expirationTimeout = setTimeout(() => leaveUser(userId), peerlessUserExpiration ?? 0);\n }\n });\n },\n\n async onMessage(type: SigType, payload: any, from: IPeer) {\n const state = getPeer(from);\n const pc = state.pc;\n\n if (type === \"offer\") {\n receivePeerConnection({ pc, userId: from.userId, initiator: false });\n // Responder: set remote offer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n\n // Create and send answer\n const answer = await pc.createAnswer();\n await pc.setLocalDescription(answer);\n\n from.receive(\"answer\", pc.localDescription?.toJSON()!);\n\n // Now safe to apply any queued ICE from this peer\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"answer\") {\n // Initiator: set remote answer\n await pc.setRemoteDescription(payload as RTCSessionDescriptionInit);\n await flushRemoteIce(state);\n return;\n }\n\n if (type === \"ice\") {\n const ice = payload as RTCIceCandidateInit;\n\n // If we don't have remoteDescription yet, queue it\n if (!pc.remoteDescription) {\n state.pendingRemoteIce.push(ice);\n return;\n }\n\n try {\n await pc.addIceCandidate(ice);\n } catch (e) {\n logLine(\"⚠️ ERROR\", { error: \"add-ice-failed\", userId: state.userId, detail: String(e) });\n }\n return;\n }\n },\n });\n roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });\n });\n }\n\n return {\n userId,\n enterRoom: enter,\n exitRoom: exit,\n leaveUser,\n getRooms() {\n return Array.from(roomsEntered.values());\n },\n end() {\n roomsEntered.forEach(({ exitRoom }) => exitRoom());\n roomsEntered.clear();\n users.forEach(({ userId }) => leaveUser(userId));\n users.clear();\n },\n };\n}\n\n\n\n"
8
8
  ],
9
- "mappings": "AASO,SAAS,CAAoC,EAChD,SACA,QACA,OACA,OACA,SACA,UACA,UACA,UACA,eACA,aACA,aAayB,CACzB,IAAM,EAAQ,SAAS,UAAa,KAAS,YAAe,mBAAmB,CAAM,IAC/E,EAAK,IAAI,UAAU,CAAK,EACxB,EAAa,EAEb,EAAQ,IAAI,IACd,EAAS,GACb,SAAS,CAAI,CAAC,EAAS,EAAkB,EAAY,CACjD,GAAI,EAAQ,MAAO,GACnB,IAAM,EAAM,CAAE,OAAM,GAAI,EAAU,SAAQ,EAG1C,OAFA,EAAG,KAAK,KAAK,UAAU,CAAG,CAAC,EAC3B,IAAU,gCAAY,CAAG,EAClB,GAGX,SAAS,CAAW,CAAC,EAAoD,CACrE,IAAM,EAAuB,CAAC,EACxB,EAAsC,CAAC,EACvC,EAAiB,IAAI,IAgB3B,GAfA,EAAa,QAAQ,EAAG,SAAQ,YAAa,CACzC,GAAI,IAAW,EAAY,OAC3B,GAAI,CAAC,EAAM,IAAI,CAAM,EAAG,CACpB,IAAM,EAAU,CAAE,SAAQ,SAAQ,QAAS,CAAC,EAAS,IAAe,EAAK,EAAM,EAAQ,CAAO,CAAC,EAC/F,EAAM,IAAI,EAAQ,CAAO,EACzB,EAAO,KAAK,CAAO,EAEvB,EAAe,IAAI,CAAM,EAC5B,EACD,EAAM,OAAO,EAAE,QAAQ,EAAG,SAAQ,YAAa,CAC3C,GAAI,CAAC,EAAe,IAAI,CAAM,EAC1B,EAAM,OAAO,CAAM,EACnB,EAAK,KAAK,CAAE,SAAQ,QAAO,CAAC,EAEnC,EACG,EAAO,OAAQ,EAAa,CAAM,EACtC,GAAI,EAAK,OAAQ,EAAW,CAAI,EAGpC,SAAS,CAAS,CAAC,EAAiB,CAChC,IAAI,EAOJ,GAAI,CAAE,EAAM,KAAK,MAAM,EAAE,IAAI,EAC7B,KAAM,CACF,IAAU,WAAW,CAAE,MAAO,cAAe,CAAC,EAC9C,OAMJ,GAHA,IAAU,gCAAY,CAAG,EAGrB,EAAI,OAAS,cAAe,CAC5B,EAAY,EAAI,KAAK,EACrB,OAEJ,GAAI,EAAI,OAAS,YAAa,CAC1B,EAAY,EAAI,KAAK,EACrB,OAEJ,GAAI,EAAI,QAAU,EAAI,OAAQ,CAC1B,IAAQ,SAAQ,UAAW,EAC3B,EAAU,EAAI,KAAM,EAAI,QAAS,CAC7B,SACA,SACA,QAAS,CAAC,EAAS,IAAe,EAAK,EAAM,EAAQ,CAAO,CAChE,CAAC,GAKT,GADA,EAAG,iBAAiB,UAAW,CAAS,EACpC,EAAQ,EAAG,iBAAiB,OAAQ,CAAM,EAC9C,GAAI,EAAS,EAAG,iBAAiB,QAAS,CAAO,EACjD,GAAI,EAAS,EAAG,iBAAiB,QAAS,CAAO,EACjD,MAAO,CACH,SAAU,IAAM,CAIZ,GAHA,EAAS,GACT,EAAG,MAAM,EACT,EAAG,oBAAoB,UAAW,CAAS,EACvC,EAAQ,EAAG,oBAAoB,OAAQ,CAAM,EACjD,GAAI,EAAS,EAAG,oBAAoB,QAAS,CAAO,EACpD,GAAI,EAAS,EAAG,oBAAoB,QAAS,CAAO,EAE5D,ECnHG,SAAS,CAAoC,EAClD,SACA,QACA,OACA,OACA,SACA,UACA,UACA,eACA,aACA,YACA,UACA,aAgB2B,CACzB,GAAI,CAAC,EAID,OADA,QAAQ,KAAK,sIAFU,kFAE2I,EAC3J,EAAoB,CACvB,SACA,QACA,OACA,OACA,SACA,UACA,UACA,eACA,aACA,WACJ,CAAC,EAEP,IAAM,EAAS,IAAI,OAAO,EAAW,CAAE,KAAM,QAAS,CAAC,EACnD,EAAS,GAEb,SAAS,CAAQ,EAAG,SAAQ,UAA2D,CACrF,MAAO,CACL,SACA,SACA,QAAS,CAAC,EAAS,IAAe,CAChC,GAAI,EAAQ,MAAO,GAEnB,OADA,EAAO,YAAY,CAAE,IAAK,OAAQ,SAAU,EAAQ,OAAM,SAAQ,CAAC,EAC5D,GAEX,EAGF,IAAM,EAAkB,CAAC,IAAqC,CAC5D,IAAM,EAAK,EAAE,KAEb,GAAI,EAAG,OAAS,OAAQ,IAAS,EAC5B,QAAI,EAAG,OAAS,QAAS,EAAO,UAAU,EAC1C,QAAI,EAAG,OAAS,QAAS,IAAU,EACnC,QAAI,EAAG,OAAS,cAAe,EAAa,EAAG,MAAM,IAAI,KAAM,EAAS,CAAE,OAAQ,EAAG,OAAQ,OAAQ,EAAG,MAAO,CAAC,CAAC,CAAC,EAClH,QAAI,EAAG,OAAS,YAAa,EAAW,EAAG,KAAK,EAChD,QAAI,EAAG,OAAS,UAAW,EAAU,EAAG,KAAM,EAAG,QAAS,EAAS,CAAE,OAAQ,EAAG,WAAY,OAAQ,EAAG,UAAW,CAAC,CAAC,EACpH,QAAI,EAAG,OAAS,MAAO,IAAU,EAAG,UAAW,EAAG,GAAG,GAO5D,OAJA,EAAO,iBAAiB,UAAW,CAAe,EAElD,EAAO,YAAY,CAAE,IAAK,QAAS,SAAQ,QAAO,OAAM,MAAK,CAAC,EAEvD,CACL,SAAU,IAAM,CACd,EAAS,GACT,EAAO,oBAAoB,UAAW,CAAe,EACrD,EAAO,YAAY,CAAE,IAAK,MAAO,CAAC,EAEtC,ECnEF,IAAM,EAAqB,EAGpB,SAAS,CAAsB,EACpC,SACA,QACA,wBACA,yBACA,YAAY,CAAE,WAAY,CAAC,CAAE,KAAM,8BAA+B,CAAC,CAAE,EACrE,kBAAmB,EAAY,EAC/B,UAAU,QAAQ,MAClB,cACA,aAWC,CACD,IAAM,EAAgC,IAAI,IAC1C,SAAS,CAAQ,EAAG,CAClB,MAAO,CAAC,GAAG,EAAM,KAAK,CAAC,EAGzB,IAAM,EAAkC,IAAI,IAC5C,SAAS,CAAO,CAAC,EAA6C,CAC5D,IAAI,EAAQ,EAAM,IAAI,EAAK,MAAM,EACjC,GAAI,CAAC,EAAO,CACR,IAAM,EAAsB,CAC1B,OAAQ,EAAK,OACb,GAAI,IAAI,kBAAkB,CAAS,EACnC,iBAAkB,CAAC,EACnB,MAAO,IAAI,GACb,EACA,EAAS,MAAM,IAAI,EAAK,OAAQ,CAAI,EACpC,EAAM,IAAI,EAAK,OAAQ,CAAQ,EAG/B,EAAS,GAAG,eAAiB,CAAC,IAAO,CACnC,GAAI,CAAC,EAAG,UAAW,OACnB,QAAQ,KAAQ,EAAS,MAAM,OAAO,EAElC,GADgB,EAAK,QAAQ,MAAO,EAAG,UAAU,OAAO,CAAC,EAC5C,OAInB,EAAS,GAAG,wBAA0B,IAAM,CAC1C,EAAQ,eAAK,CAAE,MAAO,WAAY,OAAQ,EAAS,OAAQ,MAAO,EAAS,GAAG,eAAgB,CAAC,GAEjG,EAAQ,EAGR,EAAa,QAAQ,KAAY,EAAS,EAAK,OAAQ,OAAQ,EAAS,CAAC,CAAC,EAC1E,EAAM,IAAI,EAAM,OAAQ,CAAK,EAC1B,QAAI,EACT,aAAa,EAAM,iBAAiB,EACpC,EAAM,kBAAoB,EAC1B,EAAM,MAAM,IAAI,EAAK,OAAQ,CAAI,EAEnC,OAAO,EAGT,SAAS,CAAS,CAAC,EAAgB,CACjC,IAAc,CAAM,EACpB,IAAM,EAAI,EAAM,IAAI,CAAM,EAC1B,GAAI,CAAC,EAAG,OACR,GAAI,CAAE,EAAE,GAAG,MAAM,EAAK,KAAM,EAC5B,EAAM,OAAO,CAAM,EACnB,EAAa,QAAQ,KAAY,EAAS,EAAQ,QAAS,EAAS,CAAC,CAAC,EACtE,EAAQ,yBAAe,CAAM,EAG/B,eAAe,CAAc,CAAC,EAAkB,CAC9C,GAAI,CAAC,EAAM,GAAG,kBAAmB,OAEjC,IAAM,EAAS,EAAM,iBACrB,EAAM,iBAAmB,CAAC,EAE1B,QAAW,KAAO,EAChB,GAAI,CACF,MAAM,EAAM,GAAG,gBAAgB,CAAG,EAClC,MAAO,EAAG,CACV,EAAQ,WAAW,CAAE,MAAO,iBAAkB,OAAQ,EAAM,OAAQ,OAAQ,OAAO,CAAC,CAAE,CAAC,GAK7F,IAAM,EAAe,IAAI,IAEzB,SAAS,CAAI,EAAG,OAAM,QAAyC,CAC7D,IAAM,EAAM,GAAG,UAAa,IACtB,EAAU,EAAa,IAAI,CAAG,EACpC,GAAI,EACF,EAAQ,SAAS,EACjB,EAAa,OAAO,CAAG,EAI3B,SAAS,CAAK,EAAG,OAAM,QAAyC,CAC9D,OAAO,IAAI,QAAc,CAAC,EAAS,IAAW,CAC5C,eAAe,CAAS,CAAC,EAAa,CAGlC,IAAM,EADQ,EAAQ,CAAI,EACT,GACX,EAAQ,MAAM,EAAG,YAAY,EACnC,MAAM,EAAG,oBAAoB,CAAK,EAClC,EAAK,QAAQ,QAAS,EAAG,kBAAkB,OAAO,CAAE,EAGxD,IAAQ,YAAa,EAAU,CAC7B,SACA,QACA,OACA,OACA,UACA,YAEA,OAAQ,EACR,QAAS,EAGT,YAAY,CAAC,EAA4C,CACvD,EAAa,QAAQ,KAAQ,CAE3B,IAAM,EADQ,EAAQ,CAAI,EACT,GACjB,EAAsB,CAAE,KAAI,OAAQ,EAAK,OAAQ,UAAW,EAAK,CAAC,EAClE,EAAU,CAAI,EACf,GAGH,UAAU,CAAC,EAAoD,CAC7D,EAAa,QAAQ,EAAG,SAAQ,YAAa,CAC3C,IAAM,EAAQ,EAAM,IAAI,CAAM,EAC9B,GAAI,CAAC,EAAO,OAEZ,GADA,EAAM,MAAM,OAAO,CAAM,EACrB,EAAM,MAAM,OAAS,EACvB,EAAM,kBAAoB,WAAW,IAAM,EAAU,CAAM,EAAG,GAA0B,CAAC,EAE5F,QAGG,UAAS,CAAC,EAAe,EAAc,EAAa,CACxD,IAAM,EAAQ,EAAQ,CAAI,EACpB,EAAK,EAAM,GAEjB,GAAI,IAAS,QAAS,CACpB,EAAsB,CAAE,KAAI,OAAQ,EAAK,OAAQ,UAAW,EAAM,CAAC,EAEnE,MAAM,EAAG,qBAAqB,CAAoC,EAGlE,IAAM,EAAS,MAAM,EAAG,aAAa,EACrC,MAAM,EAAG,oBAAoB,CAAM,EAEnC,EAAK,QAAQ,SAAU,EAAG,kBAAkB,OAAO,CAAE,EAGrD,MAAM,EAAe,CAAK,EAC1B,OAGF,GAAI,IAAS,SAAU,CAErB,MAAM,EAAG,qBAAqB,CAAoC,EAClE,MAAM,EAAe,CAAK,EAC1B,EAAsB,CAAE,KAAI,OAAQ,EAAK,OAAQ,UAAW,EAAK,CAAC,EAClE,OAGF,GAAI,IAAS,MAAO,CAClB,IAAM,EAAM,EAGZ,GAAI,CAAC,EAAG,kBAAmB,CACzB,EAAM,iBAAiB,KAAK,CAAG,EAC/B,OAGF,GAAI,CACF,MAAM,EAAG,gBAAgB,CAAG,EAC5B,MAAO,EAAG,CACV,EAAQ,WAAW,CAAE,MAAO,iBAAkB,OAAQ,EAAM,OAAQ,OAAQ,OAAO,CAAC,CAAE,CAAC,EAEzF,QAGN,CAAC,EACD,EAAa,IAAI,GAAG,UAAa,IAAQ,CAAE,WAAU,OAAM,MAAK,CAAC,EAClE,EAGH,SAAS,CAAkB,CAAC,EAAwB,CAClD,EAAa,OAAO,CAAQ,EAG9B,SAAS,CAAe,CAAC,EAAwB,CAE/C,OADA,EAAa,IAAI,CAAQ,EAClB,IAAM,CACX,EAAmB,CAAQ,GAI/B,MAAO,CACL,UAAW,EACX,SAAU,EACV,YACA,WACA,kBACA,qBACA,QAAQ,EAAG,CACT,OAAO,MAAM,KAAK,EAAa,OAAO,CAAC,GAEzC,GAAG,EAAG,CACJ,EAAa,QAAQ,EAAG,cAAe,EAAS,CAAC,EACjD,EAAa,MAAM,EACnB,EAAM,QAAQ,EAAG,YAAa,EAAU,CAAM,CAAC,EAC/C,EAAa,MAAM,EAEvB",
10
- "debugId": "B41F283EA3BA21EC64756E2164756E21",
9
+ "mappings": "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",
10
+ "debugId": "C180D94D2452675564756E2164756E21",
11
11
  "names": []
12
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dobuki/hello-worker",
3
- "version": "1.0.19",
3
+ "version": "1.0.22",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",