// OxiLink signalling relay - the entire server. // It relays small opaque strings between at most two peers for at most five // minutes, then dies. No media, no logs, no accounts, no persistence. // Copyright 2026 COOLJAPAN OU (Team Kitasan). Apache-2.0. const TTL_MS = 5 * 60 * 1000; const MAX_MSG = 16384; const CODE_RE = /^\/ws\/([ABCDEFGHJKMNPQRSTVWXYZ23456789]{8})$/; export class Room { constructor(ctx) { this.ctx = ctx; } async fetch(request) { if (request.headers.get("Upgrade") !== "websocket") { return new Response("websocket only", { status: 426 }); } if (this.ctx.getWebSockets().length >= 2) { return new Response("room full", { status: 409 }); } const pair = new WebSocketPair(); this.ctx.acceptWebSocket(pair[1]); // hibernation API: idle rooms cost ~nothing if ((await this.ctx.storage.getAlarm()) === null) { await this.ctx.storage.setAlarm(Date.now() + TTL_MS); // absolute TTL from first join } for (const peer of this.ctx.getWebSockets()) { if (peer !== pair[1]) peer.send('{"type":"peer-joined"}'); } return new Response(null, { status: 101, webSocket: pair[0] }); } webSocketMessage(ws, message) { if (typeof message !== "string" || message.length > MAX_MSG) { return ws.close(1009, "bad message"); } for (const peer of this.ctx.getWebSockets()) { if (peer !== ws) peer.send(message); } } webSocketClose(ws) { for (const peer of this.ctx.getWebSockets()) { if (peer !== ws) peer.send('{"type":"peer-left"}'); } } async alarm() { for (const ws of this.ctx.getWebSockets()) { ws.close(1000, "room expired"); } await this.ctx.storage.deleteAll(); } } export default { async fetch(request, env) { const match = new URL(request.url).pathname.match(CODE_RE); if (!match) return new Response("not found", { status: 404 }); return env.ROOM.get(env.ROOM.idFromName(match[1])).fetch(request); } };