// LiveKit helpers shared by routes.js (browser meeting/call join) and calls.js (native VoIP call payload). // Mint an access token (HS256 JWT signed with the API secret) — hand-rolled, same approach as push.js's // JWTs, so there's no SDK dependency. Grants join+publish+subscribe on exactly one room, as one identity. // The secret stays server-side. const crypto = require('crypto'); const { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, LIVEKIT_ENABLED } = require('./config'); const _b64u = (buf) => Buffer.from(buf).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); function livekitToken(identity, name, room, metadata) { const nowSec = Math.floor(Date.now() / 1000); const header = _b64u(JSON.stringify({ alg: 'HS256', typ: 'JWT' })); const payload = _b64u(JSON.stringify({ iss: LIVEKIT_API_KEY, sub: identity, name: name || identity, nbf: nowSec, exp: nowSec + 6 * 3600, // 6h — long enough for any meeting/call metadata: metadata || '', video: { room, roomJoin: true, canPublish: true, canSubscribe: true, canPublishData: true }, })); const sig = _b64u(crypto.createHmac('sha256', LIVEKIT_API_SECRET).update(header + '.' + payload).digest()); return header + '.' + payload + '.' + sig; } module.exports = { livekitToken, LIVEKIT_URL, LIVEKIT_ENABLED };