@dobuki/hello-worker 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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};
2
+
3
+ //# debugId=7979C2C0F3726FCA64756E2164756E21
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 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
+ "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",
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"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "7979C2C0F3726FCA64756E2164756E21",
12
+ "names": []
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dobuki/hello-worker",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -19,8 +19,9 @@
19
19
  "build:worker": "bun build src/browser/signal-room.worker.ts --target browser --format esm --outdir dist --minify --sourcemap",
20
20
  "build:sample": "bun build src/browser/sample/index.ts src/browser/signal-room.worker.ts --target browser --format esm --outdir public --minify --sourcemap",
21
21
  "build:types": "tsc -p tsconfig.json",
22
- "build": "bun i && npm run build:worker && npm run build:sample && npm run build:types",
23
- "prepublishOnly": "npm run build",
22
+ "build:main": "bun build src/browser --target browser --format esm --outdir dist --minify --sourcemap",
23
+ "build": "bun i && bun run build:worker && bun run build:main && bun run build:sample && bun run build:types",
24
+ "prepublishOnly": "bun run build",
24
25
  "npm-patch": "npm version patch && npm publish"
25
26
  },
26
27
  "devDependencies": {
@@ -1,101 +0,0 @@
1
- import { enterRoom } from "./signal-room";
2
- import { collectPeerConnections } from "./webrtc-peer-collector";
3
- export function enterWorld({ uid, logLine = console.debug, enterRoomFunction = enterRoom, autoLeaveUsers = false, workerUrl, }) {
4
- const userId = uid ?? `user-${crypto.randomUUID()}`;
5
- const rtcConfig = {
6
- iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
7
- };
8
- const messagesListeners = new Set();
9
- const usersListener = new Set();
10
- function wireDataChannel(userId, dc) {
11
- dc.onopen = () => logLine("💬", { event: "dc-open", userId });
12
- dc.onmessage = ({ data }) => {
13
- messagesListeners.forEach(listener => listener(data, userId));
14
- logLine("💬", { event: "dc-message", userId, data });
15
- };
16
- dc.onclose = () => logLine("💬", { event: "dc-close", userId });
17
- dc.onerror = () => logLine("⚠️ ERROR", { error: "dc-error", userId });
18
- }
19
- const dataChannels = new Map();
20
- const { enterRoom, exitRoom, leaveUser, getUsers, getRooms } = collectPeerConnections({
21
- userId,
22
- rtcConfig,
23
- enterRoomFunction,
24
- logLine,
25
- workerUrl,
26
- leaveUserWithoutPeer: autoLeaveUsers,
27
- onLeaveUser(userId) {
28
- const dc = dataChannels.get(userId);
29
- try {
30
- dc?.close();
31
- }
32
- catch { }
33
- dataChannels.delete(userId);
34
- },
35
- receivePeerConnection({ pc, userId, initiator }) {
36
- if (initiator) {
37
- const dc = pc.createDataChannel("data");
38
- wireDataChannel(userId, dc);
39
- dataChannels.set(userId, dc);
40
- }
41
- else {
42
- pc.ondatachannel = (ev) => {
43
- const dc = ev.channel;
44
- wireDataChannel(userId, dc);
45
- dataChannels.set(userId, dc);
46
- };
47
- }
48
- logLine("💬", { event: "pc-ready", userId, initiator });
49
- },
50
- });
51
- function send(data, userId) {
52
- dataChannels.forEach((dataChannel, pUserId) => {
53
- if (userId && pUserId !== userId)
54
- return;
55
- if (dataChannel.readyState === "open")
56
- dataChannel.send(data);
57
- });
58
- }
59
- function removeMessageListener(listener) {
60
- messagesListeners.delete(listener);
61
- }
62
- function addMessageListener(listener) {
63
- messagesListeners.add(listener);
64
- return () => {
65
- removeMessageListener(listener);
66
- };
67
- }
68
- function removeUserListener(listener) {
69
- usersListener.delete(listener);
70
- }
71
- function addUserListener(listener) {
72
- usersListener.add(listener);
73
- return () => {
74
- removeUserListener(listener);
75
- };
76
- }
77
- return {
78
- userId,
79
- send,
80
- enterRoom,
81
- exitRoom,
82
- leaveUser,
83
- getUsers,
84
- addMessageListener,
85
- removeMessageListener,
86
- addUserListener,
87
- removeUserListener,
88
- end() {
89
- getUsers().forEach(user => leaveUser(user));
90
- getRooms().forEach(({ room, host }) => exitRoom({ room, host }));
91
- dataChannels.forEach((dataChannel) => {
92
- try {
93
- dataChannel.close();
94
- }
95
- catch { }
96
- });
97
- dataChannels.clear();
98
- },
99
- };
100
- }
101
- //# sourceMappingURL=enter-world.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enter-world.js","sourceRoot":"","sources":["../src/browser/enter-world.ts"],"names":[],"mappings":"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"}
@@ -1,76 +0,0 @@
1
- /**
2
- * enterRoom connects to the signaling room via WebSocket.
3
- */
4
- export function enterRoom({ userId, room, host, onOpen, onClose, onError, logLine, onPeerJoined, onPeerLeft, onMessage, }) {
5
- const wsUrl = "wss://" + host + "/room/" + room + "?userId=" + encodeURIComponent(userId);
6
- const ws = new WebSocket(wsUrl);
7
- let exited = false;
8
- function send(type, toPeerId, payload) {
9
- if (exited)
10
- return false;
11
- const obj = { type, to: toPeerId, payload };
12
- ws.send(JSON.stringify(obj));
13
- logLine?.("👤 ➡️ 🖥️", obj);
14
- return true;
15
- }
16
- function onmessage(e) {
17
- let msg;
18
- try {
19
- msg = JSON.parse(e.data);
20
- }
21
- catch {
22
- logLine?.("⚠️ ERROR", { error: "invalid-json" });
23
- return;
24
- }
25
- logLine?.("🖥️ ➡️ 👤", msg);
26
- // Existing client greets newcomers
27
- if (msg.type === "peer-joined" && msg.peerId && msg.userId) {
28
- const { userId, peerId } = msg;
29
- onPeerJoined({
30
- userId,
31
- peerId,
32
- receive: (type, payload) => {
33
- return send(type, peerId, payload);
34
- },
35
- });
36
- return;
37
- }
38
- if (msg.type === "peer-left" && msg.peerId && msg.userId) {
39
- const { userId, peerId } = msg;
40
- onPeerLeft(userId, peerId);
41
- return;
42
- }
43
- if (msg.peerId && msg.userId) {
44
- const { userId, peerId } = msg;
45
- onMessage(msg.type, msg.payload, {
46
- userId,
47
- peerId,
48
- receive: (type, payload) => {
49
- return send(type, peerId, payload);
50
- },
51
- });
52
- }
53
- }
54
- ;
55
- ws.addEventListener("message", onmessage);
56
- if (onOpen)
57
- ws.addEventListener("open", onOpen);
58
- if (onClose)
59
- ws.addEventListener("close", onClose);
60
- if (onError)
61
- ws.addEventListener("error", onError);
62
- return {
63
- exitRoom: () => {
64
- exited = true;
65
- ws.close();
66
- ws.removeEventListener("message", onmessage);
67
- if (onOpen)
68
- ws.removeEventListener("open", onOpen);
69
- if (onClose)
70
- ws.removeEventListener("close", onClose);
71
- if (onError)
72
- ws.removeEventListener("error", onError);
73
- },
74
- };
75
- }
76
- //# sourceMappingURL=signal-room.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"signal-room.js","sourceRoot":"","sources":["../../src/browser/impl/signal-room.ts"],"names":[],"mappings":"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"}
package/dist/index.js DELETED
@@ -1,6 +0,0 @@
1
- /// <reference lib="dom" />
2
- /// <reference lib="dom.iterable" />
3
- export { collectPeerConnections } from "./webrtc-peer-collector";
4
- export { enterRoom } from "./impl/signal-room";
5
- export { enterWorld } from "./enter-world";
6
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/browser/index.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,oCAAoC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -1,145 +0,0 @@
1
- /// <reference lib="dom" />
2
- /// <reference lib="dom.iterable" />
3
- import { enterRoom } from "../signal-room.js";
4
- import { enterWorld } from "../enter-world.js";
5
- const statusEl = document.getElementById("status");
6
- const logEl = document.getElementById("log");
7
- const welcomeEl = document.getElementById("welcome");
8
- function ts() {
9
- // HH:MM:SS.mmm (local time)
10
- const d = new Date();
11
- const p2 = (n) => String(n).padStart(2, "0");
12
- const p3 = (n) => String(n).padStart(3, "0");
13
- return `${p2(d.getHours())}:${p2(d.getMinutes())}:${p2(d.getSeconds())}.${p3(d.getMilliseconds())}`;
14
- }
15
- function logLine(direction, obj) {
16
- logEl.textContent += ts() + " " + direction + " " + (obj ? JSON.stringify(obj) : "") + "\n";
17
- logEl.scrollTop = logEl.scrollHeight;
18
- }
19
- export function clearLog() {
20
- logEl.textContent = "";
21
- }
22
- export function testWelcome() {
23
- const { exitRoom } = enterRoom({
24
- userId: crypto.randomUUID(),
25
- room: "test",
26
- host: location.host,
27
- onOpen: () => {
28
- statusEl.textContent = "🟢 connected";
29
- logLine("🔗 CONNECTED");
30
- },
31
- onClose: () => {
32
- statusEl.textContent = "🔴 closed";
33
- logLine("⛓️‍💥 DISCONNECTED");
34
- },
35
- onError: () => {
36
- statusEl.textContent = "🔴 error";
37
- logLine("⚠️ ERROR");
38
- },
39
- onPeerJoined: (user) => {
40
- user.receive("welcome", { note: welcomeEl.value });
41
- },
42
- onPeerLeft: (info) => {
43
- logLine("👤 LEFT", info);
44
- },
45
- onMessage: (type, payload, user) => {
46
- if (type === "welcome") {
47
- user.receive("thanks", { note: "Thank you! 🙏" });
48
- }
49
- },
50
- logLine,
51
- workerUrl: new URL("../signal-room.worker.js", import.meta.url),
52
- });
53
- return () => {
54
- exitRoom();
55
- };
56
- }
57
- export function testWebRTC() {
58
- // --- create a stage + emoji (if not already in HTML) ---
59
- let stageEl = document.getElementById("stage");
60
- if (!stageEl) {
61
- stageEl = document.createElement("div");
62
- stageEl.id = "stage";
63
- stageEl.style.position = "relative";
64
- stageEl.style.width = "100%";
65
- stageEl.style.height = "280px";
66
- stageEl.style.border = "1px solid #333";
67
- stageEl.style.borderRadius = "8px";
68
- stageEl.style.margin = "12px 0";
69
- stageEl.style.userSelect = "none";
70
- stageEl.style.touchAction = "none";
71
- document.body.insertBefore(stageEl, welcomeEl);
72
- }
73
- welcomeEl.classList.add("hidden");
74
- let emojiEl = document.getElementById("emoji");
75
- if (!emojiEl) {
76
- emojiEl = document.createElement("div");
77
- emojiEl.id = "emoji";
78
- emojiEl.textContent = "🦊";
79
- emojiEl.style.position = "absolute";
80
- emojiEl.style.left = "0px";
81
- emojiEl.style.top = "0px";
82
- emojiEl.style.transform = "translate(-50%, -50%)";
83
- emojiEl.style.fontSize = "36px";
84
- emojiEl.style.pointerEvents = "none";
85
- stageEl.appendChild(emojiEl);
86
- }
87
- function setEmojiPos01(x01, y01) {
88
- const r = stageEl.getBoundingClientRect();
89
- const x = Math.max(0, Math.min(1, x01)) * r.width;
90
- const y = Math.max(0, Math.min(1, y01)) * r.height;
91
- emojiEl.style.left = `${x}px`;
92
- emojiEl.style.top = `${y}px`;
93
- }
94
- // --- start WebRTC mesh using YOUR joinWebRTCRoom ---
95
- statusEl.textContent = "🟡 connecting";
96
- logLine("💬", { event: "start-webrtc-test" });
97
- const session = enterWorld({
98
- logLine,
99
- workerUrl: new URL("../signal-room.worker.js", import.meta.url),
100
- });
101
- session.enterRoom({
102
- room: "test",
103
- host: location.host,
104
- });
105
- session.addMessageListener(data => {
106
- try {
107
- const { x, y } = JSON.parse(String(data));
108
- if (typeof x === "number" && typeof y === "number") {
109
- setEmojiPos01(x, y);
110
- }
111
- }
112
- catch {
113
- // ignore non-json
114
- }
115
- });
116
- // --- send mouse position over all open data channels ---
117
- let lastSent = 0;
118
- function broadcastMove(x01, y01) {
119
- const now = performance.now();
120
- if (now - lastSent < 16)
121
- return; // ~60Hz throttle
122
- lastSent = now;
123
- const msg = JSON.stringify({ x: x01, y: y01 });
124
- session.send(msg);
125
- }
126
- function onPointerMove(ev) {
127
- const r = stageEl.getBoundingClientRect();
128
- const x01 = (ev.clientX - r.left) / r.width;
129
- const y01 = (ev.clientY - r.top) / r.height;
130
- // move locally too (feels instant)
131
- setEmojiPos01(x01, y01);
132
- // broadcast to peers via datachannel
133
- broadcastMove(x01, y01);
134
- }
135
- stageEl.addEventListener("pointermove", onPointerMove);
136
- // return cleanup function (same pattern as testWelcome)
137
- return () => {
138
- stageEl.removeEventListener("pointermove", onPointerMove);
139
- stageEl.remove();
140
- welcomeEl.classList.remove("hidden");
141
- session.end();
142
- logLine("💬", { event: "stop-webrtc-test" });
143
- };
144
- }
145
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/sample/index.ts"],"names":[],"mappings":"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"}
package/dist/sample.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export declare function clearLog(): void;
2
- export declare function testWelcome(): () => void;
3
- export declare function testWebRTC(): () => void;
4
- //# sourceMappingURL=sample.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../src/browser/sample.ts"],"names":[],"mappings":"AAuBA,wBAAgB,QAAQ,SAEvB;AAED,wBAAgB,WAAW,eAmC1B;AAED,wBAAgB,UAAU,eAkGzB"}
package/dist/sample.js DELETED
@@ -1,147 +0,0 @@
1
- /// <reference lib="dom" />
2
- /// <reference lib="dom.iterable" />
3
- import { enterRoom } from "./signal-room.js";
4
- import { joinWebRTCRoom } from "./webrtc-room.js";
5
- const statusEl = document.getElementById("status");
6
- const logEl = document.getElementById("log");
7
- const welcomeEl = document.getElementById("welcome");
8
- function ts() {
9
- // HH:MM:SS.mmm (local time)
10
- const d = new Date();
11
- const p2 = (n) => String(n).padStart(2, "0");
12
- const p3 = (n) => String(n).padStart(3, "0");
13
- return `${p2(d.getHours())}:${p2(d.getMinutes())}:${p2(d.getSeconds())}.${p3(d.getMilliseconds())}`;
14
- }
15
- function logLine(direction, obj) {
16
- logEl.textContent += ts() + " " + direction + " " + (obj ? JSON.stringify(obj) : "") + "\n";
17
- logEl.scrollTop = logEl.scrollHeight;
18
- }
19
- export function clearLog() {
20
- logEl.textContent = "";
21
- }
22
- export function testWelcome() {
23
- const { exitRoom } = enterRoom({
24
- userId: crypto.randomUUID(),
25
- room: "test",
26
- host: location.host,
27
- onOpen: () => {
28
- statusEl.textContent = "connected";
29
- logLine("🔗 CONNECTED");
30
- },
31
- onClose: () => {
32
- statusEl.textContent = "closed";
33
- logLine("⛓️‍💥 DISCONNECTED");
34
- statusEl.textContent = "closed";
35
- },
36
- onError: () => {
37
- statusEl.textContent = "error";
38
- logLine("⚠️ ERROR");
39
- },
40
- onPeerJoined: (user) => {
41
- user.receive("welcome", { note: welcomeEl.value });
42
- },
43
- onPeerLeft: (info) => {
44
- logLine("👤 LEFT", info);
45
- },
46
- onMessage: (type, payload, user) => {
47
- if (type === "welcome") {
48
- user.receive("thanks", { note: "Thank you! 🙏" });
49
- }
50
- },
51
- logLine,
52
- workerUrl: new URL("./signal-room.worker.js", import.meta.url),
53
- });
54
- return () => {
55
- exitRoom();
56
- };
57
- }
58
- export function testWebRTC() {
59
- // --- create a stage + emoji (if not already in HTML) ---
60
- let stageEl = document.getElementById("stage");
61
- if (!stageEl) {
62
- stageEl = document.createElement("div");
63
- stageEl.id = "stage";
64
- stageEl.style.position = "relative";
65
- stageEl.style.width = "100%";
66
- stageEl.style.height = "280px";
67
- stageEl.style.border = "1px solid #333";
68
- stageEl.style.borderRadius = "8px";
69
- stageEl.style.margin = "12px 0";
70
- stageEl.style.userSelect = "none";
71
- stageEl.style.touchAction = "none";
72
- document.body.insertBefore(stageEl, welcomeEl);
73
- }
74
- welcomeEl.classList.add("hidden");
75
- let emojiEl = document.getElementById("emoji");
76
- if (!emojiEl) {
77
- emojiEl = document.createElement("div");
78
- emojiEl.id = "emoji";
79
- emojiEl.textContent = "🦊";
80
- emojiEl.style.position = "absolute";
81
- emojiEl.style.left = "0px";
82
- emojiEl.style.top = "0px";
83
- emojiEl.style.transform = "translate(-50%, -50%)";
84
- emojiEl.style.fontSize = "36px";
85
- emojiEl.style.pointerEvents = "none";
86
- stageEl.appendChild(emojiEl);
87
- }
88
- function setEmojiPos01(x01, y01) {
89
- const r = stageEl.getBoundingClientRect();
90
- const x = Math.max(0, Math.min(1, x01)) * r.width;
91
- const y = Math.max(0, Math.min(1, y01)) * r.height;
92
- emojiEl.style.left = `${x}px`;
93
- emojiEl.style.top = `${y}px`;
94
- }
95
- // --- start WebRTC mesh using YOUR joinWebRTCRoom ---
96
- statusEl.textContent = "connecting";
97
- logLine("💬", { event: "start-webrtc-test" });
98
- const session = joinWebRTCRoom({
99
- logLine,
100
- enterRoom,
101
- onMessage: (data) => {
102
- try {
103
- const { x, y } = JSON.parse(String(data));
104
- if (typeof x === "number" && typeof y === "number") {
105
- setEmojiPos01(x, y);
106
- }
107
- }
108
- catch {
109
- // ignore non-json
110
- }
111
- },
112
- workerUrl: new URL("./signal-room.worker.js", import.meta.url),
113
- });
114
- session.enter({
115
- room: "test",
116
- host: location.host,
117
- });
118
- // --- send mouse position over all open data channels ---
119
- let lastSent = 0;
120
- function broadcastMove(x01, y01) {
121
- const now = performance.now();
122
- if (now - lastSent < 16)
123
- return; // ~60Hz throttle
124
- lastSent = now;
125
- const msg = JSON.stringify({ x: x01, y: y01 });
126
- session.sendToAll(msg);
127
- }
128
- function onPointerMove(ev) {
129
- const r = stageEl.getBoundingClientRect();
130
- const x01 = (ev.clientX - r.left) / r.width;
131
- const y01 = (ev.clientY - r.top) / r.height;
132
- // move locally too (feels instant)
133
- setEmojiPos01(x01, y01);
134
- // broadcast to peers via datachannel
135
- broadcastMove(x01, y01);
136
- }
137
- stageEl.addEventListener("pointermove", onPointerMove);
138
- // return cleanup function (same pattern as testWelcome)
139
- return () => {
140
- stageEl.removeEventListener("pointermove", onPointerMove);
141
- stageEl.remove();
142
- welcomeEl.classList.remove("hidden");
143
- session.end();
144
- logLine("💬", { event: "stop-webrtc-test" });
145
- };
146
- }
147
- //# sourceMappingURL=sample.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sample.js","sourceRoot":"","sources":["../src/browser/sample.ts"],"names":[],"mappings":"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"}
@@ -1,59 +0,0 @@
1
- import { enterRoom as baseEnterRoom } from "./impl/signal-room.js";
2
- export function enterRoom({ userId, room, host, onOpen, onClose, onError, onPeerJoined, onPeerLeft, onMessage, logLine, workerUrl, }) {
3
- if (!workerUrl) {
4
- const CDN_WORKER_URL = `https://cdn.jsdelivr.net/npm/@dobuki/hello-worker/dist/signal-room.worker.min.js`;
5
- console.warn("Warning: enterRoom called without workerUrl; this may cause issues in some environments. You should pass workerUrl explicitly. Use:", CDN_WORKER_URL);
6
- return baseEnterRoom({
7
- userId,
8
- room,
9
- host,
10
- onOpen,
11
- onClose,
12
- onError,
13
- onPeerJoined,
14
- onPeerLeft,
15
- onMessage,
16
- });
17
- }
18
- const worker = new Worker(workerUrl, { type: "module" });
19
- let exited = false;
20
- function makeUser({ userId, peerId }) {
21
- return {
22
- userId,
23
- peerId,
24
- receive: (type, payload) => {
25
- if (exited)
26
- return false;
27
- worker.postMessage({ cmd: "send", toPeerId: peerId, type, payload });
28
- return true;
29
- },
30
- };
31
- }
32
- const onWorkerMessage = (e) => {
33
- const ev = e.data;
34
- if (ev.kind === "open")
35
- onOpen?.();
36
- else if (ev.kind === "close")
37
- worker.terminate();
38
- else if (ev.kind === "error")
39
- onError?.();
40
- else if (ev.kind === "peer-joined")
41
- onPeerJoined(makeUser({ userId: ev.userId, peerId: ev.peerId }));
42
- else if (ev.kind === "peer-left")
43
- onPeerLeft(ev.userId, ev.peerId);
44
- else if (ev.kind === "message")
45
- onMessage(ev.type, ev.payload, makeUser({ userId: ev.fromUserId, peerId: ev.fromPeerId }));
46
- else if (ev.kind === "log")
47
- logLine?.(ev.direction, ev.obj);
48
- };
49
- worker.addEventListener("message", onWorkerMessage);
50
- worker.postMessage({ cmd: "enter", userId, room, host });
51
- return {
52
- exitRoom: () => {
53
- exited = true;
54
- worker.removeEventListener("message", onWorkerMessage);
55
- worker.postMessage({ cmd: "exit" });
56
- },
57
- };
58
- }
59
- //# sourceMappingURL=signal-room.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"signal-room.js","sourceRoot":"","sources":["../src/browser/signal-room.ts"],"names":[],"mappings":"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"}
@@ -1,155 +0,0 @@
1
- import { enterRoom } from "./signal-room";
2
- const DEFAULT_ENTER_ROOM = enterRoom;
3
- export function collectPeerConnections({ userId, receivePeerConnection, leaveUserWithoutPeer = false, rtcConfig = { iceServers: [{ urls: "stun:stun.l.google.com:19302" }] }, enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM, logLine = console.debug, onLeaveUser, workerUrl, }) {
4
- const users = new Map();
5
- function getPeer(peer) {
6
- let state = users.get(peer.userId);
7
- if (!state) {
8
- const newState = {
9
- userId: peer.userId,
10
- pc: new RTCPeerConnection(rtcConfig),
11
- pendingRemoteIce: [],
12
- peers: new Set([peer]),
13
- };
14
- users.set(peer.userId, newState);
15
- // Send local ICE candidates to this peer
16
- newState.pc.onicecandidate = (ev) => {
17
- if (!ev.candidate)
18
- return;
19
- for (let user of newState.peers) {
20
- const success = user.receive("ice", ev.candidate.toJSON());
21
- if (success)
22
- break;
23
- }
24
- };
25
- newState.pc.onconnectionstatechange = () => {
26
- logLine("💬", { event: "pc-state", userId: newState.userId, state: newState.pc.connectionState });
27
- };
28
- state = newState;
29
- }
30
- else {
31
- state.peers.add(peer);
32
- }
33
- users.set(state.userId, state);
34
- return state;
35
- }
36
- function leaveUser(userId) {
37
- onLeaveUser?.(userId);
38
- const p = users.get(userId);
39
- if (!p)
40
- return;
41
- try {
42
- p.pc.close();
43
- }
44
- catch { }
45
- users.delete(userId);
46
- logLine("👤 USER LEFT", userId);
47
- }
48
- async function flushRemoteIce(state) {
49
- if (!state.pc.remoteDescription)
50
- return;
51
- const queued = state.pendingRemoteIce;
52
- state.pendingRemoteIce = [];
53
- for (const ice of queued) {
54
- try {
55
- await state.pc.addIceCandidate(ice);
56
- }
57
- catch (e) {
58
- logLine("⚠️ ERROR", { error: "add-ice-failed", userId: state.userId, detail: String(e) });
59
- }
60
- }
61
- }
62
- const roomsEntered = new Map();
63
- function exit({ room, host }) {
64
- const key = `${host}/room/${room}`;
65
- const session = roomsEntered.get(key);
66
- if (session) {
67
- session.exitRoom();
68
- roomsEntered.delete(key);
69
- }
70
- }
71
- function enter({ room, host }) {
72
- const { exitRoom } = enterRoom({
73
- userId,
74
- room,
75
- host,
76
- logLine,
77
- workerUrl,
78
- // Existing peers initiate to the newcomer (Option 1)
79
- async onPeerJoined(user) {
80
- const state = getPeer(user);
81
- const pc = state.pc;
82
- receivePeerConnection({ pc, userId: user.userId, initiator: true });
83
- // Offer flow: createOffer -> setLocalDescription -> send localDescription
84
- const offer = await pc.createOffer();
85
- await pc.setLocalDescription(offer);
86
- user.receive("offer", pc.localDescription?.toJSON());
87
- },
88
- onPeerLeft(userId, peerId) {
89
- const state = users.get(userId);
90
- if (!state)
91
- return;
92
- for (const user of state.peers) {
93
- if (user.peerId === peerId) {
94
- state.peers.delete(user);
95
- break;
96
- }
97
- }
98
- if (state.peers.size === 0 && leaveUserWithoutPeer) {
99
- leaveUser(userId);
100
- }
101
- },
102
- async onMessage(type, payload, from) {
103
- const state = getPeer(from);
104
- const pc = state.pc;
105
- if (type === "offer") {
106
- receivePeerConnection({ pc, userId: from.userId, initiator: false });
107
- // Responder: set remote offer
108
- await pc.setRemoteDescription(payload);
109
- // Create and send answer
110
- const answer = await pc.createAnswer();
111
- await pc.setLocalDescription(answer);
112
- from.receive("answer", pc.localDescription?.toJSON());
113
- // Now safe to apply any queued ICE from this peer
114
- await flushRemoteIce(state);
115
- return;
116
- }
117
- if (type === "answer") {
118
- // Initiator: set remote answer
119
- await pc.setRemoteDescription(payload);
120
- await flushRemoteIce(state);
121
- receivePeerConnection({ pc, userId: from.userId, initiator: true });
122
- return;
123
- }
124
- if (type === "ice") {
125
- const ice = payload;
126
- // If we don't have remoteDescription yet, queue it
127
- if (!pc.remoteDescription) {
128
- state.pendingRemoteIce.push(ice);
129
- return;
130
- }
131
- try {
132
- await pc.addIceCandidate(ice);
133
- }
134
- catch (e) {
135
- logLine("⚠️ ERROR", { error: "add-ice-failed", userId: state.userId, detail: String(e) });
136
- }
137
- return;
138
- }
139
- },
140
- });
141
- roomsEntered.set(`${host}/room/${room}`, { exitRoom, room, host });
142
- }
143
- return {
144
- enterRoom: enter,
145
- exitRoom: exit,
146
- leaveUser,
147
- getUsers() {
148
- return Array.from(users.keys());
149
- },
150
- getRooms() {
151
- return Array.from(roomsEntered.values());
152
- },
153
- };
154
- }
155
- //# sourceMappingURL=webrtc-peer-collector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webrtc-peer-collector.js","sourceRoot":"","sources":["../src/browser/webrtc-peer-collector.ts"],"names":[],"mappings":"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"}
@@ -1,52 +0,0 @@
1
- import { EnterRoom } from "./signal-room";
2
- type SigType = "offer" | "answer" | "ice";
3
- type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;
4
- export declare function collectPeerConnections({ userId, receivePeerConnection, leaveUserWithoutPeer, rtcConfig, enterRoomFunction: enterRoom, logLine, onLeaveUser, workerUrl, }: {
5
- userId: string;
6
- rtcConfig?: RTCConfiguration;
7
- enterRoomFunction?: EnterRoom<SigType, SigPayload>;
8
- onLeaveUser?: (userId: string) => void;
9
- logLine?: (direction: string, obj?: any) => void;
10
- workerUrl?: URL;
11
- leaveUserWithoutPeer?: boolean;
12
- receivePeerConnection(connection: {
13
- pc: RTCPeerConnection;
14
- userId: string;
15
- initiator: boolean;
16
- }): void;
17
- }): {
18
- enterRoom: ({ room, host }: {
19
- room: string;
20
- host: string;
21
- }) => void;
22
- exitRoom: ({ room, host }: {
23
- room: string;
24
- host: string;
25
- }) => void;
26
- leaveUser: (userId: string) => void;
27
- getUsers(): string[];
28
- };
29
- export declare function joinWebRTCRoom({ uid, onMessage, logLine, enterRoomFunction, autoLeaveUsers, workerUrl, }: {
30
- uid?: string;
31
- onMessage?: (data: any, from: string) => void;
32
- logLine?: (direction: string, obj?: any) => void;
33
- enterRoomFunction?: EnterRoom<SigType, SigPayload>;
34
- autoLeaveUsers?: boolean;
35
- workerUrl?: URL;
36
- }): {
37
- userId: string;
38
- send: (data: any, userId?: string) => void;
39
- enterRoom: ({ room, host }: {
40
- room: string;
41
- host: string;
42
- }) => void;
43
- exitRoom: ({ room, host }: {
44
- room: string;
45
- host: string;
46
- }) => void;
47
- leaveUser: (userId: string) => void;
48
- getUsers: () => string[];
49
- end(): void;
50
- };
51
- export {};
52
- //# sourceMappingURL=webrtc-room.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webrtc-room.d.ts","sourceRoot":"","sources":["../src/browser/webrtc-room.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAa,MAAM,eAAe,CAAC;AAErD,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAC1C,KAAK,UAAU,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;AAgBlE,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,qBAAqB,EACrB,oBAA4B,EAC5B,SAAsE,EACtE,iBAAiB,EAAE,SAA8B,EACjD,OAAuB,EACvB,WAAW,EACX,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,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,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,UAAU,EAAE;QAAE,EAAE,EAAE,iBAAiB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACxG;gCAoEgC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;+BAThC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;wBA1BlC,MAAM;;EAsHlC;AAGD,wBAAgB,cAAc,CAAC,EAC7B,GAAG,EACH,SAAS,EACT,OAAuB,EACvB,iBAAsC,EACtC,cAAsB,EACtB,SAAS,GACV,EAAE;IACD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,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,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,GAAG,CAAC;CACjB;;iBA+CqB,GAAG,WAAW,MAAM;gCAnJT;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;+BAThC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;wBA1BlC,MAAM;;;EA2MlC"}
@@ -1,216 +0,0 @@
1
- import { enterRoom } from "./signal-room";
2
- const DEFAULT_ENTER_ROOM = enterRoom;
3
- export function collectPeerConnections({ userId, receivePeerConnection, leaveUserWithoutPeer = false, rtcConfig = { iceServers: [{ urls: "stun:stun.l.google.com:19302" }] }, enterRoomFunction: enterRoom = DEFAULT_ENTER_ROOM, logLine = console.debug, onLeaveUser, workerUrl, }) {
4
- const users = new Map();
5
- function getPeer(peer) {
6
- let state = users.get(peer.userId);
7
- if (!state) {
8
- const newState = {
9
- userId: peer.userId,
10
- pc: new RTCPeerConnection(rtcConfig),
11
- pendingRemoteIce: [],
12
- peers: new Set([peer]),
13
- };
14
- users.set(peer.userId, newState);
15
- // Send local ICE candidates to this peer
16
- newState.pc.onicecandidate = (ev) => {
17
- if (!ev.candidate)
18
- return;
19
- for (let user of newState.peers) {
20
- const success = user.receive("ice", ev.candidate.toJSON());
21
- if (success)
22
- break;
23
- }
24
- };
25
- newState.pc.onconnectionstatechange = () => {
26
- logLine("💬", { event: "pc-state", userId: newState.userId, state: newState.pc.connectionState });
27
- };
28
- state = newState;
29
- }
30
- else {
31
- state.peers.add(peer);
32
- }
33
- users.set(state.userId, state);
34
- return state;
35
- }
36
- function leaveUser(userId) {
37
- onLeaveUser?.(userId);
38
- const p = users.get(userId);
39
- if (!p)
40
- return;
41
- try {
42
- p.pc.close();
43
- }
44
- catch { }
45
- users.delete(userId);
46
- logLine("👤 USER LEFT", userId);
47
- }
48
- async function flushRemoteIce(state) {
49
- if (!state.pc.remoteDescription)
50
- return;
51
- const queued = state.pendingRemoteIce;
52
- state.pendingRemoteIce = [];
53
- for (const ice of queued) {
54
- try {
55
- await state.pc.addIceCandidate(ice);
56
- }
57
- catch (e) {
58
- logLine("⚠️ ERROR", { error: "add-ice-failed", userId: state.userId, detail: String(e) });
59
- }
60
- }
61
- }
62
- const roomsEntered = new Map();
63
- function exit({ room, host }) {
64
- const key = `${host}/room/${room}`;
65
- const session = roomsEntered.get(key);
66
- if (session) {
67
- session.exitRoom();
68
- roomsEntered.delete(key);
69
- }
70
- }
71
- function enter({ room, host }) {
72
- const { exitRoom } = enterRoom({
73
- userId,
74
- room,
75
- host,
76
- logLine,
77
- workerUrl,
78
- // Existing peers initiate to the newcomer (Option 1)
79
- async onPeerJoined(user) {
80
- const state = getPeer(user);
81
- const pc = state.pc;
82
- // Offer flow: createOffer -> setLocalDescription -> send localDescription
83
- const offer = await pc.createOffer();
84
- await pc.setLocalDescription(offer);
85
- user.receive("offer", pc.localDescription?.toJSON());
86
- },
87
- onPeerLeft(userId, peerId) {
88
- const state = users.get(userId);
89
- if (!state)
90
- return;
91
- for (const user of state.peers) {
92
- if (user.peerId === peerId) {
93
- state.peers.delete(user);
94
- break;
95
- }
96
- }
97
- if (state.peers.size === 0 && leaveUserWithoutPeer) {
98
- leaveUser(userId);
99
- }
100
- },
101
- async onMessage(type, payload, from) {
102
- const state = getPeer(from);
103
- const pc = state.pc;
104
- if (type === "offer") {
105
- // Responder: set remote offer
106
- await pc.setRemoteDescription(payload);
107
- // Create and send answer
108
- const answer = await pc.createAnswer();
109
- await pc.setLocalDescription(answer);
110
- from.receive("answer", pc.localDescription?.toJSON());
111
- // Now safe to apply any queued ICE from this peer
112
- await flushRemoteIce(state);
113
- receivePeerConnection({ pc, userId: from.userId, initiator: false });
114
- return;
115
- }
116
- if (type === "answer") {
117
- // Initiator: set remote answer
118
- await pc.setRemoteDescription(payload);
119
- await flushRemoteIce(state);
120
- receivePeerConnection({ pc, userId: from.userId, initiator: true });
121
- return;
122
- }
123
- if (type === "ice") {
124
- const ice = payload;
125
- // If we don't have remoteDescription yet, queue it
126
- if (!pc.remoteDescription) {
127
- state.pendingRemoteIce.push(ice);
128
- return;
129
- }
130
- try {
131
- await pc.addIceCandidate(ice);
132
- }
133
- catch (e) {
134
- logLine("⚠️ ERROR", { error: "add-ice-failed", userId: state.userId, detail: String(e) });
135
- }
136
- return;
137
- }
138
- },
139
- });
140
- roomsEntered.set(`${host}/room/${room}`, { exitRoom });
141
- }
142
- return { enterRoom: enter, exitRoom: exit, leaveUser, getUsers() { return Array.from(users.keys()); } };
143
- }
144
- export function joinWebRTCRoom({ uid, onMessage, logLine = console.debug, enterRoomFunction = DEFAULT_ENTER_ROOM, autoLeaveUsers = false, workerUrl, }) {
145
- const userId = uid ?? `user-${crypto.randomUUID()}`;
146
- const rtcConfig = {
147
- iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
148
- };
149
- function wireDataChannel(userId, dc) {
150
- dc.onopen = () => logLine("💬", { event: "dc-open", userId });
151
- dc.onmessage = ({ data }) => {
152
- onMessage?.(data, userId);
153
- logLine("💬", { event: "dc-message", userId, data: data });
154
- };
155
- dc.onclose = () => logLine("💬", { event: "dc-close", userId });
156
- dc.onerror = () => logLine("⚠️ ERROR", { error: "dc-error", userId });
157
- }
158
- const dataChannels = new Map();
159
- const { enterRoom, exitRoom, leaveUser, getUsers } = collectPeerConnections({
160
- userId,
161
- rtcConfig,
162
- enterRoomFunction,
163
- logLine,
164
- workerUrl,
165
- leaveUserWithoutPeer: autoLeaveUsers,
166
- onLeaveUser: (userId) => {
167
- const dc = dataChannels.get(userId);
168
- try {
169
- dc?.close();
170
- }
171
- catch { }
172
- dataChannels.delete(userId);
173
- },
174
- receivePeerConnection({ pc, userId, initiator }) {
175
- if (initiator) {
176
- const dc = pc.createDataChannel("data");
177
- wireDataChannel(userId, dc);
178
- dataChannels.set(userId, dc);
179
- }
180
- else {
181
- pc.ondatachannel = (ev) => {
182
- const dc = ev.channel;
183
- wireDataChannel(userId, dc);
184
- dataChannels.set(userId, dc);
185
- };
186
- }
187
- logLine("💬", { event: "pc-ready", userId, initiator });
188
- },
189
- });
190
- function send(data, userId) {
191
- dataChannels.forEach((dataChannel, pUserId) => {
192
- if (userId && pUserId !== userId)
193
- return;
194
- if (dataChannel.readyState === "open")
195
- dataChannel.send(data);
196
- });
197
- }
198
- return {
199
- userId,
200
- send,
201
- enterRoom,
202
- exitRoom,
203
- leaveUser,
204
- getUsers,
205
- end() {
206
- dataChannels.forEach((dataChannel) => {
207
- try {
208
- dataChannel.close();
209
- }
210
- catch { }
211
- });
212
- dataChannels.clear();
213
- },
214
- };
215
- }
216
- //# sourceMappingURL=webrtc-room.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webrtc-room.js","sourceRoot":"","sources":["../src/browser/webrtc-room.ts"],"names":[],"mappings":"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"}