@dobuki/hello-worker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2025 Vincent Le Quang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # hello-worker
2
+
3
+ Creates a cloudflare worker for simple signaling between peer for WebRTC.
4
+
5
+ Test at: <https://hello.dobuki.net/>
@@ -0,0 +1,3 @@
1
+ export { joinWebRTCRoom } from "./webrtc-room.js";
2
+ export { enterRoom } from "./signal-room.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,5 @@
1
+ /// <reference lib="dom" />
2
+ /// <reference lib="dom.iterable" />
3
+ export { joinWebRTCRoom } from "./webrtc-room.js";
4
+ export { enterRoom } from "./signal-room.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,oCAAoC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function clearLog(): void;
2
+ export declare function testWelcome(): () => void;
3
+ export declare function testWebRTC(): () => void;
4
+ //# sourceMappingURL=sample.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../../src/browser/sample.ts"],"names":[],"mappings":"AAyBA,wBAAgB,QAAQ,SAEvB;AAED,wBAAgB,WAAW,eAkC1B;AAED,wBAAgB,UAAU,eAkGzB"}
@@ -0,0 +1,147 @@
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
+ const userId = crypto.randomUUID();
9
+ function ts() {
10
+ // HH:MM:SS.mmm (local time)
11
+ const d = new Date();
12
+ const p2 = (n) => String(n).padStart(2, "0");
13
+ const p3 = (n) => String(n).padStart(3, "0");
14
+ return `${p2(d.getHours())}:${p2(d.getMinutes())}:${p2(d.getSeconds())}.${p3(d.getMilliseconds())}`;
15
+ }
16
+ function logLine(direction, obj) {
17
+ logEl.textContent += ts() + " " + direction + " " + (obj ? JSON.stringify(obj) : "") + "\n";
18
+ logEl.scrollTop = logEl.scrollHeight;
19
+ }
20
+ export function clearLog() {
21
+ logEl.textContent = "";
22
+ }
23
+ export function testWelcome() {
24
+ const { exitRoom } = enterRoom({
25
+ userId,
26
+ room: "test",
27
+ host: location.host,
28
+ onOpen: () => {
29
+ statusEl.textContent = "connected";
30
+ logLine("🔗 CONNECTED");
31
+ },
32
+ onClose: () => {
33
+ statusEl.textContent = "closed";
34
+ logLine("⛓️‍💥 DISCONNECTED");
35
+ statusEl.textContent = "closed";
36
+ },
37
+ onError: () => {
38
+ statusEl.textContent = "error";
39
+ logLine("⚠️ ERROR");
40
+ },
41
+ onPeerJoined: (user) => {
42
+ user.receive("welcome", { note: welcomeEl.value });
43
+ },
44
+ onPeerLeft: (info) => {
45
+ logLine("👤 LEFT", info);
46
+ },
47
+ onMessage: (type, payload, user) => {
48
+ if (type === "welcome") {
49
+ user.receive("thanks", { note: "Thank you! 🙏" });
50
+ }
51
+ },
52
+ logLine,
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
+ userId,
100
+ logLine,
101
+ enterRoom,
102
+ onMessage: (data, from) => {
103
+ try {
104
+ const { x, y } = JSON.parse(String(data));
105
+ if (typeof x === "number" && typeof y === "number") {
106
+ setEmojiPos01(x, y);
107
+ }
108
+ }
109
+ catch {
110
+ // ignore non-json
111
+ }
112
+ }
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.js","sourceRoot":"","sources":["../../src/browser/sample.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ export interface IUser<T extends string = string, P = any> {
2
+ info: {
3
+ peerId: string;
4
+ userId: string;
5
+ };
6
+ receive(type: T, payload: P): boolean;
7
+ }
8
+ export type EnterRoom<T extends string = string, P = any> = (options: {
9
+ userId: string;
10
+ room: string;
11
+ host: string;
12
+ onOpen?: () => void;
13
+ onClose?: () => void;
14
+ onError?: () => void;
15
+ logLine?: (direction: string, obj?: any) => void;
16
+ onPeerJoined?: (user: IUser<T, P>) => void;
17
+ onPeerLeft?: (info: IUser["info"]) => void;
18
+ onMessage?: (type: T, payload: P, from: IUser<T, P>) => void;
19
+ }) => {
20
+ exitRoom: () => void;
21
+ };
22
+ /**
23
+ * enterRoom connects to the signaling room via WebSocket.
24
+ *
25
+ * Usage:
26
+ * const { exitRoom } = enterRoom({
27
+ * room: "test",
28
+ * host: location.host,
29
+ * onOpen: () => { ... },
30
+ * onClose: () => { ... },
31
+ * onError: () => { ... },
32
+ * onPeerJoined: (user) => { ... },
33
+ * onMessage: (type, payload, fromUser) => { ... },
34
+ * });
35
+ */
36
+ export declare function enterRoom<T extends string, P = any>({ userId, room, host, onOpen, onClose, onError, logLine, onPeerJoined, onPeerLeft, onMessage, }: {
37
+ userId: string;
38
+ room: string;
39
+ host: string;
40
+ onOpen?: () => void;
41
+ onClose?: () => void;
42
+ onError?: () => void;
43
+ logLine?: (direction: string, obj?: any) => void;
44
+ onPeerJoined?: (user: IUser) => void;
45
+ onPeerLeft?: (info: IUser["info"]) => void;
46
+ onMessage?: (type: T, payload: P, from: IUser) => void;
47
+ }): {
48
+ exitRoom: () => void;
49
+ };
50
+ //# sourceMappingURL=signal-room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal-room.d.ts","sourceRoot":"","sources":["../../src/browser/signal-room.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,GAAG;IACrD,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;CACzC;AAED,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,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,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;IAC3C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;CAChE,KAAK;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC;AAE/B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,EACjD,MAAM,EACN,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,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,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IAC3C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;CAC1D;;EAqEA"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * enterRoom connects to the signaling room via WebSocket.
3
+ *
4
+ * Usage:
5
+ * const { exitRoom } = enterRoom({
6
+ * room: "test",
7
+ * host: location.host,
8
+ * onOpen: () => { ... },
9
+ * onClose: () => { ... },
10
+ * onError: () => { ... },
11
+ * onPeerJoined: (user) => { ... },
12
+ * onMessage: (type, payload, fromUser) => { ... },
13
+ * });
14
+ */
15
+ export function enterRoom({ userId, room, host, onOpen, onClose, onError, logLine, onPeerJoined, onPeerLeft, onMessage, }) {
16
+ const wsUrl = "wss://" + host + "/room/" + room + "?userId=" + encodeURIComponent(userId);
17
+ const ws = new WebSocket(wsUrl);
18
+ let exited = false;
19
+ function send(type, toPeerId, payload) {
20
+ if (exited)
21
+ return false;
22
+ const obj = { type, to: toPeerId, payload };
23
+ ws.send(JSON.stringify(obj));
24
+ logLine?.("👤 ➡️ 🖥️", obj);
25
+ return true;
26
+ }
27
+ function onmessage(e) {
28
+ let msg;
29
+ try {
30
+ msg = JSON.parse(e.data);
31
+ }
32
+ catch {
33
+ logLine?.("⚠️ ERROR", { error: "invalid-json" });
34
+ return;
35
+ }
36
+ logLine?.("🖥️ ➡️ 👤", msg);
37
+ // Existing client greets newcomers
38
+ if (msg.type === "peer-joined" && msg.peerId && msg.userId) {
39
+ const { userId, peerId } = msg;
40
+ onPeerJoined?.({
41
+ info: { peerId, userId },
42
+ receive: (type, payload) => {
43
+ return send(type, peerId, payload);
44
+ },
45
+ });
46
+ return;
47
+ }
48
+ if (msg.type === "peer-left" && msg.peerId && msg.userId) {
49
+ const { userId, peerId } = msg;
50
+ onPeerLeft?.({ peerId, userId });
51
+ return;
52
+ }
53
+ if (msg.peerId && msg.userId) {
54
+ const { userId, peerId } = msg;
55
+ onMessage?.(msg.type, msg.payload, {
56
+ info: { peerId, userId },
57
+ receive: (type, payload) => {
58
+ return send(type, peerId, payload);
59
+ },
60
+ });
61
+ }
62
+ }
63
+ ;
64
+ ws.addEventListener("message", onmessage);
65
+ if (onOpen)
66
+ ws.addEventListener("open", onOpen);
67
+ if (onClose)
68
+ ws.addEventListener("close", onClose);
69
+ if (onError)
70
+ ws.addEventListener("error", onError);
71
+ return {
72
+ exitRoom: () => {
73
+ exited = true;
74
+ ws.close();
75
+ ws.removeEventListener("message", onmessage);
76
+ if (onOpen)
77
+ ws.removeEventListener("open", onOpen);
78
+ if (onClose)
79
+ ws.removeEventListener("close", onClose);
80
+ if (onError)
81
+ ws.removeEventListener("error", onError);
82
+ },
83
+ };
84
+ }
85
+ //# sourceMappingURL=signal-room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal-room.js","sourceRoot":"","sources":["../../src/browser/signal-room.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { EnterRoom } from "./signal-room";
2
+ type SigType = "offer" | "answer" | "ice";
3
+ type SigPayload = RTCSessionDescriptionInit | RTCIceCandidateInit;
4
+ export declare function joinWebRTCRoom({ userId, onMessage, logLine, enterRoom, }: {
5
+ userId: string;
6
+ onMessage?: (data: any, from: {
7
+ userId: string;
8
+ peerId: string;
9
+ }) => void;
10
+ logLine: (direction: string, obj?: any) => void;
11
+ enterRoom: EnterRoom<SigType, SigPayload>;
12
+ }): {
13
+ sendToUser: (userId: string, data: string) => void;
14
+ sendToAll: (data: string) => void;
15
+ end: () => void;
16
+ enter: ({ room, host }: {
17
+ room: string;
18
+ host: string;
19
+ }) => void;
20
+ exit: ({ room, host }: {
21
+ room: string;
22
+ host: string;
23
+ }) => void;
24
+ };
25
+ export {};
26
+ //# sourceMappingURL=webrtc-room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webrtc-room.d.ts","sourceRoot":"","sources":["../../src/browser/webrtc-room.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAS,MAAM,eAAe,CAAC;AAEjD,KAAK,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAC1C,KAAK,UAAU,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;AAelE,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,SAAS,EACT,OAAO,EACP,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC1E,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChD,SAAS,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;CAC3C;yBAqL6B,MAAM,QAAQ,MAAM;sBAMvB,MAAM;;4BAxGA;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;2BAyFhC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;KAAE;EAsC9D"}
@@ -0,0 +1,211 @@
1
+ export function joinWebRTCRoom({ userId, onMessage, logLine, enterRoom, }) {
2
+ const rtcConfig = {
3
+ iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
4
+ };
5
+ const peers = new Map();
6
+ function wireDataChannel(state) {
7
+ const dc = state.dataChannel;
8
+ if (!dc)
9
+ return;
10
+ dc.onopen = () => logLine("💬", { event: "dc-open", userId: state.userId });
11
+ dc.onmessage = (e) => {
12
+ onMessage?.(e.data, { userId: state.userId, peerId: state.userId });
13
+ logLine("💬", { event: "dc-message", userId: state.userId, data: e.data });
14
+ };
15
+ dc.onclose = () => logLine("💬", { event: "dc-close", userId: state.userId });
16
+ dc.onerror = () => logLine("⚠️ ERROR", { error: "dc-error", userId: state.userId });
17
+ }
18
+ async function flushRemoteIce(state) {
19
+ if (!state.pc.remoteDescription)
20
+ return;
21
+ const queued = state.pendingRemoteIce;
22
+ state.pendingRemoteIce = [];
23
+ for (const ice of queued) {
24
+ try {
25
+ await state.pc.addIceCandidate(ice);
26
+ }
27
+ catch (e) {
28
+ logLine("⚠️ ERROR", { error: "add-ice-failed", userId: state.userId, detail: String(e) });
29
+ }
30
+ }
31
+ }
32
+ function getPeer(user) {
33
+ let state = peers.get(user.info.userId);
34
+ if (!state) {
35
+ const newState = {
36
+ userId: user.info.userId,
37
+ pc: new RTCPeerConnection(rtcConfig),
38
+ pendingRemoteIce: [],
39
+ users: new Set([user]),
40
+ dataChannel: null,
41
+ };
42
+ peers.set(user.info.userId, newState);
43
+ // Send local ICE candidates to this peer
44
+ newState.pc.onicecandidate = (ev) => {
45
+ if (!ev.candidate)
46
+ return;
47
+ for (let user of newState.users) {
48
+ const success = user.receive("ice", ev.candidate.toJSON());
49
+ if (success)
50
+ break;
51
+ newState.users.delete(user);
52
+ }
53
+ };
54
+ // Responder receives DataChannel here
55
+ newState.pc.ondatachannel = (ev) => {
56
+ newState.dataChannel = ev.channel;
57
+ wireDataChannel(newState);
58
+ };
59
+ newState.pc.onconnectionstatechange = () => {
60
+ logLine("💬", { event: "pc-state", userId: newState.userId, state: newState.pc.connectionState });
61
+ };
62
+ state = newState;
63
+ }
64
+ else {
65
+ state.users.add(user);
66
+ }
67
+ peers.set(state.userId, state);
68
+ return state;
69
+ }
70
+ function leaveUser(userId) {
71
+ const p = peers.get(userId);
72
+ if (!p)
73
+ return;
74
+ try {
75
+ p.dataChannel?.close();
76
+ }
77
+ catch { }
78
+ try {
79
+ p.pc.close();
80
+ }
81
+ catch { }
82
+ peers.delete(userId);
83
+ logLine("👤 USER LEFT", userId);
84
+ }
85
+ const roomsEntered = new Map();
86
+ function enter({ room, host }) {
87
+ const { exitRoom } = enterRoom({
88
+ userId,
89
+ room,
90
+ host,
91
+ logLine,
92
+ // Existing peers initiate to the newcomer (Option 1)
93
+ onPeerJoined: async (user) => {
94
+ const state = getPeer(user);
95
+ const pc = state.pc;
96
+ // Initiator creates the DataChannel
97
+ if (!state.dataChannel) {
98
+ state.dataChannel = pc.createDataChannel("data");
99
+ wireDataChannel(state);
100
+ }
101
+ // Offer flow: createOffer -> setLocalDescription -> send localDescription
102
+ const offer = await pc.createOffer();
103
+ await pc.setLocalDescription(offer);
104
+ user.receive("offer", pc.localDescription);
105
+ },
106
+ onPeerLeft: (info) => {
107
+ const state = peers.get(info.userId);
108
+ if (!state)
109
+ return;
110
+ for (const user of state.users) {
111
+ if (user.info.userId === info.userId) {
112
+ state.users.delete(user);
113
+ break;
114
+ }
115
+ }
116
+ logLine("👤 LEFT", info);
117
+ if (state.users.size === 0) {
118
+ try {
119
+ state.dataChannel?.close();
120
+ }
121
+ catch { }
122
+ try {
123
+ state.pc.close();
124
+ }
125
+ catch { }
126
+ leaveUser(info.userId);
127
+ }
128
+ },
129
+ onMessage: async (type, payload, from) => {
130
+ const state = getPeer(from);
131
+ const pc = state.pc;
132
+ if (type === "offer") {
133
+ // Responder: set remote offer
134
+ await pc.setRemoteDescription(payload);
135
+ // Create and send answer
136
+ const answer = await pc.createAnswer();
137
+ await pc.setLocalDescription(answer);
138
+ from.receive("answer", pc.localDescription);
139
+ // Now safe to apply any queued ICE from this peer
140
+ await flushRemoteIce(state);
141
+ return;
142
+ }
143
+ if (type === "answer") {
144
+ // Initiator: set remote answer
145
+ await pc.setRemoteDescription(payload);
146
+ await flushRemoteIce(state);
147
+ return;
148
+ }
149
+ if (type === "ice") {
150
+ const ice = payload;
151
+ // If we don't have remoteDescription yet, queue it
152
+ if (!pc.remoteDescription) {
153
+ state.pendingRemoteIce.push(ice);
154
+ return;
155
+ }
156
+ try {
157
+ await pc.addIceCandidate(ice);
158
+ }
159
+ catch (e) {
160
+ logLine("⚠️ ERROR", { error: "add-ice-failed", userId: state.userId, detail: String(e) });
161
+ }
162
+ return;
163
+ }
164
+ },
165
+ });
166
+ roomsEntered.set(`${host}/room/${room}`, { exitRoom, host, room });
167
+ }
168
+ function exit({ room, host }) {
169
+ const key = `${host}/room/${room}`;
170
+ const session = roomsEntered.get(key);
171
+ if (session) {
172
+ session.exitRoom();
173
+ roomsEntered.delete(key);
174
+ }
175
+ }
176
+ const sendToUser = (userId, data) => {
177
+ const p = peers.get(userId);
178
+ if (!p)
179
+ return;
180
+ if (p.dataChannel?.readyState === "open")
181
+ p.dataChannel.send(data);
182
+ };
183
+ function sendToAll(data) {
184
+ for (const p of peers.values()) {
185
+ if (p.dataChannel?.readyState === "open")
186
+ p.dataChannel.send(data);
187
+ }
188
+ }
189
+ return {
190
+ sendToUser,
191
+ sendToAll,
192
+ end: () => {
193
+ roomsEntered.values().forEach(({ exitRoom }) => exitRoom());
194
+ roomsEntered.clear();
195
+ for (const p of peers.values()) {
196
+ try {
197
+ p.dataChannel?.close();
198
+ }
199
+ catch { }
200
+ try {
201
+ p.pc.close();
202
+ }
203
+ catch { }
204
+ }
205
+ peers.clear();
206
+ },
207
+ enter,
208
+ exit,
209
+ };
210
+ }
211
+ //# sourceMappingURL=webrtc-room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webrtc-room.js","sourceRoot":"","sources":["../../src/browser/webrtc-room.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface Env {
2
+ ROOM: DurableObjectNamespace;
3
+ ASSETS: Fetcher;
4
+ }
5
+ export { Room } from "./room";
6
+ declare const _default: {
7
+ fetch(req: Request, env: Env): Promise<Response>;
8
+ };
9
+ export default _default;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG;IAClB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;;eAGX,OAAO,OAAO,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;;AADxD,wBAuBE"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ export { Room } from "./room";
2
+ export default {
3
+ async fetch(req, env) {
4
+ const url = new URL(req.url);
5
+ // If NOT /room/<id>, serve test HTML
6
+ const match = url.pathname.match(/^\/room\/([^/]+)$/);
7
+ if (!match) {
8
+ // everything else falls through to static assets
9
+ return env.ASSETS.fetch(req);
10
+ }
11
+ // WebSocket upgrade required
12
+ const upgrade = req.headers.get("Upgrade");
13
+ if (upgrade?.toLowerCase() !== "websocket") {
14
+ return new Response("Expected WebSocket", { status: 426 });
15
+ }
16
+ const roomId = decodeURIComponent(match[1]);
17
+ const id = env.ROOM.idFromName(roomId);
18
+ const stub = env.ROOM.get(id);
19
+ return stub.fetch(req);
20
+ },
21
+ };
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,eAAe;IACb,KAAK,CAAC,KAAK,CAAC,GAAY,EAAE,GAAQ;QAChC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE7B,qCAAqC;QACrC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,iDAAiD;YACjD,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAED,6BAA6B;QAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;YAC3C,OAAO,IAAI,QAAQ,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAE9B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;CACF,CAAC"}
package/dist/room.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export declare class Room implements DurableObject {
2
+ private state;
3
+ private env;
4
+ constructor(state: DurableObjectState, env: unknown);
5
+ fetch(req: Request): Promise<Response>;
6
+ webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): void;
7
+ webSocketClose(ws: WebSocket): void;
8
+ webSocketError(ws: WebSocket, err: unknown): void;
9
+ }
10
+ //# sourceMappingURL=room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../src/room.ts"],"names":[],"mappings":"AAmBA,qBAAa,IAAK,YAAW,aAAa;IAC5B,OAAO,CAAC,KAAK;IAAsB,OAAO,CAAC,GAAG;gBAAtC,KAAK,EAAE,kBAAkB,EAAU,GAAG,EAAE,OAAO;IAI7D,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6B5C,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IA0D7D,cAAc,CAAC,EAAE,EAAE,SAAS;IAiB5B,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO;CAI3C"}
package/dist/room.js ADDED
@@ -0,0 +1,111 @@
1
+ function getAttachment(ws) {
2
+ try {
3
+ const a = ws.deserializeAttachment();
4
+ return a;
5
+ }
6
+ catch {
7
+ return null;
8
+ }
9
+ }
10
+ export class Room {
11
+ state;
12
+ env;
13
+ constructor(state, env) {
14
+ this.state = state;
15
+ this.env = env;
16
+ void env;
17
+ }
18
+ async fetch(req) {
19
+ const userId = new URL(req.url).searchParams.get("userId");
20
+ if (!userId) {
21
+ return new Response("Missing userId", { status: 400 });
22
+ }
23
+ const pair = new WebSocketPair();
24
+ const client = pair[0];
25
+ const server = pair[1];
26
+ // IMPORTANT: accept first
27
+ this.state.acceptWebSocket(server);
28
+ // Persist peerId via attachment (survives hibernation)
29
+ const peerId = crypto.randomUUID();
30
+ server.serializeAttachment({ peerId, userId });
31
+ console.log(`Room ${this.state.id.toString()} got new peer: ${peerId} (userId=${userId})`);
32
+ // Notify existing peers about the newcomer
33
+ for (const ws of this.state.getWebSockets()) {
34
+ if (ws === server)
35
+ continue;
36
+ try {
37
+ ws.send(JSON.stringify({ type: "peer-joined", peerId, userId }));
38
+ }
39
+ catch { }
40
+ }
41
+ return new Response(null, { status: 101, webSocket: client });
42
+ }
43
+ webSocketMessage(ws, message) {
44
+ const attachment = getAttachment(ws);
45
+ console.log(`Room ${this.state.id.toString()} got message from ${attachment}:`, message);
46
+ if (!attachment) {
47
+ // This should not happen after the attachment fix,
48
+ // but keep a helpful error if it does.
49
+ try {
50
+ ws.send(JSON.stringify({ type: "error", error: "missing-peerid" }));
51
+ }
52
+ catch { }
53
+ return;
54
+ }
55
+ if (typeof message !== "string") {
56
+ ws.send(JSON.stringify({ type: "error", error: "binary-not-supported" }));
57
+ return;
58
+ }
59
+ let msg;
60
+ try {
61
+ msg = JSON.parse(message);
62
+ }
63
+ catch {
64
+ ws.send(JSON.stringify({ type: "error", error: "invalid-json" }));
65
+ return;
66
+ }
67
+ // Generic relay: require msg.to
68
+ if (typeof msg.to === "string") {
69
+ const toPeerId = msg.to;
70
+ const out = {
71
+ type: msg.type,
72
+ userId: attachment.userId,
73
+ peerId: attachment.peerId,
74
+ payload: msg.payload ?? null,
75
+ };
76
+ for (const other of this.state.getWebSockets()) {
77
+ if (getAttachment(other)?.peerId === toPeerId) {
78
+ try {
79
+ other.send(JSON.stringify(out));
80
+ }
81
+ catch { }
82
+ return;
83
+ }
84
+ }
85
+ ws.send(JSON.stringify({ type: "error", error: "peer-not-found", to: toPeerId }));
86
+ return;
87
+ }
88
+ ws.send(JSON.stringify({ type: "error", error: "missing-to" }));
89
+ }
90
+ webSocketClose(ws) {
91
+ const attachment = getAttachment(ws);
92
+ console.log(`Room ${this.state.id.toString()} peer disconnected:`, attachment);
93
+ if (!attachment)
94
+ return;
95
+ const { peerId, userId } = attachment;
96
+ // Notify other peers about the departure
97
+ for (const other of this.state.getWebSockets()) {
98
+ if (other === ws)
99
+ continue;
100
+ try {
101
+ other.send(JSON.stringify({ type: "peer-left", peerId, userId }));
102
+ }
103
+ catch { }
104
+ }
105
+ }
106
+ webSocketError(ws, err) {
107
+ const peerId = getAttachment(ws);
108
+ console.log(`Room ${this.state.id.toString()} ws error for peer ${peerId}:`, err);
109
+ }
110
+ }
111
+ //# sourceMappingURL=room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room.js","sourceRoot":"","sources":["../src/room.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@dobuki/hello-worker",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./webrtc-room": { "types": "./dist/webrtc-room.d.ts", "default": "./dist/webrtc-room.js" },
13
+ "./signal-room": { "types": "./dist/signal-room.d.ts", "default": "./dist/signal-room.js" }
14
+ },
15
+ "files": ["dist"],
16
+ "scripts": {
17
+ "dev": "wrangler dev src/index.ts --config wrangler.dev.toml",
18
+ "deploy": "wrangler deploy",
19
+ "build": "bun i && bun build src/browser/*.ts --target browser --outdir public --minify --sourcemap && tsc -p tsconfig.json",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "devDependencies": {
23
+ "@cloudflare/workers-types": "latest",
24
+ "typescript": "latest",
25
+ "wrangler": "latest"
26
+ },
27
+ "dependencies": {}
28
+ }