@xtr-dev/rondevu-server 0.4.0 → 0.5.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/ADVANCED.md +502 -0
- package/README.md +136 -282
- package/dist/index.js +692 -731
- package/dist/index.js.map +4 -4
- package/migrations/0006_service_offer_refactor.sql +40 -0
- package/migrations/0007_simplify_schema.sql +54 -0
- package/migrations/0008_peer_id_to_username.sql +67 -0
- package/migrations/fresh_schema.sql +81 -0
- package/package.json +2 -1
- package/src/app.ts +38 -591
- package/src/config.ts +0 -13
- package/src/crypto.ts +98 -133
- package/src/rpc.ts +725 -0
- package/src/storage/d1.ts +169 -182
- package/src/storage/sqlite.ts +142 -168
- package/src/storage/types.ts +51 -95
- package/src/worker.ts +0 -6
- package/wrangler.toml +3 -3
- package/src/middleware/auth.ts +0 -51
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/app.ts", "../node_modules/@noble/ed25519/index.js", "../src/crypto.ts", "../src/
|
|
4
|
-
"sourcesContent": ["import { serve } from '@hono/node-server';\nimport { createApp } from './app.ts';\nimport { loadConfig } from './config.ts';\nimport { SQLiteStorage } from './storage/sqlite.ts';\nimport { Storage } from './storage/types.ts';\n\n/**\n * Main entry point for the standalone Node.js server\n */\nasync function main() {\n const config = loadConfig();\n\n console.log('Starting Rondevu server...');\n console.log('Configuration:', {\n port: config.port,\n storageType: config.storageType,\n storagePath: config.storagePath,\n offerDefaultTtl: `${config.offerDefaultTtl}ms`,\n offerMaxTtl: `${config.offerMaxTtl}ms`,\n offerMinTtl: `${config.offerMinTtl}ms`,\n cleanupInterval: `${config.cleanupInterval}ms`,\n maxOffersPerRequest: config.maxOffersPerRequest,\n corsOrigins: config.corsOrigins,\n version: config.version,\n });\n\n let storage: Storage;\n\n if (config.storageType === 'sqlite') {\n storage = new SQLiteStorage(config.storagePath);\n console.log('Using SQLite storage');\n } else {\n throw new Error('Unsupported storage type');\n }\n\n // Start periodic cleanup of expired offers\n const cleanupInterval = setInterval(async () => {\n try {\n const now = Date.now();\n const deleted = await storage.deleteExpiredOffers(now);\n if (deleted > 0) {\n console.log(`Cleanup: Deleted ${deleted} expired offer(s)`);\n }\n } catch (err) {\n console.error('Cleanup error:', err);\n }\n }, config.cleanupInterval);\n\n const app = createApp(storage, config);\n\n const server = serve({\n fetch: app.fetch,\n port: config.port,\n });\n\n console.log(`Server running on http://localhost:${config.port}`);\n console.log('Ready to accept connections');\n\n // Graceful shutdown handler\n const shutdown = async () => {\n console.log('\\nShutting down gracefully...');\n clearInterval(cleanupInterval);\n await storage.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n", "import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { Storage } from './storage/types.ts';\nimport { Config } from './config.ts';\nimport { createAuthMiddleware, getAuthenticatedPeerId } from './middleware/auth.ts';\nimport { generatePeerId, encryptPeerId, validateUsernameClaim, validateServicePublish, validateServiceFqn, parseServiceFqn, isVersionCompatible } from './crypto.ts';\nimport type { Context } from 'hono';\n\n/**\n * Creates the Hono application with username and service-based WebRTC signaling\n * RESTful API design - v0.11.0\n */\nexport function createApp(storage: Storage, config: Config) {\n const app = new Hono();\n\n // Create auth middleware\n const authMiddleware = createAuthMiddleware(config.authSecret);\n\n // Enable CORS\n app.use('/*', cors({\n origin: (origin) => {\n if (config.corsOrigins.length === 1 && config.corsOrigins[0] === '*') {\n return origin;\n }\n if (config.corsOrigins.includes(origin)) {\n return origin;\n }\n return config.corsOrigins[0];\n },\n allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Origin', 'Authorization'],\n exposeHeaders: ['Content-Type'],\n maxAge: 600,\n credentials: true,\n }));\n\n // ===== General Endpoints =====\n\n /**\n * GET /\n * Returns server information\n */\n app.get('/', (c) => {\n return c.json({\n version: config.version,\n name: 'Rondevu',\n description: 'DNS-like WebRTC signaling with username claiming and service discovery'\n });\n });\n\n /**\n * GET /health\n * Health check endpoint\n */\n app.get('/health', (c) => {\n return c.json({\n status: 'ok',\n timestamp: Date.now(),\n version: config.version\n });\n });\n\n /**\n * POST /register\n * Register a new peer\n */\n app.post('/register', async (c) => {\n try {\n const peerId = generatePeerId();\n const secret = await encryptPeerId(peerId, config.authSecret);\n\n return c.json({\n peerId,\n secret\n }, 200);\n } catch (err) {\n console.error('Error registering peer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== User Management (RESTful) =====\n\n /**\n * GET /users/:username\n * Check if username is available or get claim info\n */\n app.get('/users/:username', async (c) => {\n try {\n const username = c.req.param('username');\n\n const claimed = await storage.getUsername(username);\n\n if (!claimed) {\n return c.json({\n username,\n available: true\n }, 200);\n }\n\n return c.json({\n username: claimed.username,\n available: false,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt,\n publicKey: claimed.publicKey\n }, 200);\n } catch (err) {\n console.error('Error checking username:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /users/:username\n * Claim a username with cryptographic proof\n */\n app.post('/users/:username', async (c) => {\n try {\n const username = c.req.param('username');\n const body = await c.req.json();\n const { publicKey, signature, message } = body;\n\n if (!publicKey || !signature || !message) {\n return c.json({ error: 'Missing required parameters: publicKey, signature, message' }, 400);\n }\n\n // Validate claim\n const validation = await validateUsernameClaim(username, publicKey, signature, message);\n if (!validation.valid) {\n return c.json({ error: validation.error }, 400);\n }\n\n // Attempt to claim username\n try {\n const claimed = await storage.claimUsername({\n username,\n publicKey,\n signature,\n message\n });\n\n return c.json({\n username: claimed.username,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt\n }, 201);\n } catch (err: any) {\n if (err.message?.includes('already claimed')) {\n return c.json({ error: 'Username already claimed by different public key' }, 409);\n }\n throw err;\n }\n } catch (err) {\n console.error('Error claiming username:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /users/:username/services/:fqn\n * Get service by username and FQN with semver-compatible matching\n */\n app.get('/users/:username/services/:fqn', async (c) => {\n try {\n const username = c.req.param('username');\n const serviceFqn = decodeURIComponent(c.req.param('fqn'));\n\n // Parse the requested FQN\n const parsed = parseServiceFqn(serviceFqn);\n if (!parsed) {\n return c.json({ error: 'Invalid service FQN format' }, 400);\n }\n\n const { serviceName, version: requestedVersion } = parsed;\n\n // Find all services with matching service name\n const matchingServices = await storage.findServicesByName(username, serviceName);\n\n if (matchingServices.length === 0) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // Filter to compatible versions\n const compatibleServices = matchingServices.filter(service => {\n const serviceParsed = parseServiceFqn(service.serviceFqn);\n if (!serviceParsed) return false;\n return isVersionCompatible(requestedVersion, serviceParsed.version);\n });\n\n if (compatibleServices.length === 0) {\n return c.json({\n error: 'No compatible version found',\n message: `Requested ${serviceFqn}, but no compatible versions available`\n }, 404);\n }\n\n // Use the first compatible service (most recently created)\n const service = compatibleServices[0];\n\n // Get the UUID for this service\n const uuid = await storage.queryService(username, service.serviceFqn);\n\n if (!uuid) {\n return c.json({ error: 'Service index not found' }, 500);\n }\n\n // Get all offers for this service\n const serviceOffers = await storage.getOffersForService(service.id);\n\n if (serviceOffers.length === 0) {\n return c.json({ error: 'No offers found for this service' }, 404);\n }\n\n // Find an unanswered offer\n const availableOffer = serviceOffers.find(offer => !offer.answererPeerId);\n\n if (!availableOffer) {\n return c.json({\n error: 'No available offers',\n message: 'All offers from this service are currently in use. Please try again later.'\n }, 503);\n }\n\n return c.json({\n uuid: uuid,\n serviceId: service.id,\n username: service.username,\n serviceFqn: service.serviceFqn,\n offerId: availableOffer.id,\n sdp: availableOffer.sdp,\n isPublic: service.isPublic,\n metadata: service.metadata ? JSON.parse(service.metadata) : undefined,\n createdAt: service.createdAt,\n expiresAt: service.expiresAt\n }, 200);\n } catch (err) {\n console.error('Error getting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /users/:username/services\n * Publish a service with one or more offers (RESTful endpoint)\n */\n app.post('/users/:username/services', authMiddleware, async (c) => {\n let serviceFqn: string | undefined;\n let createdOffers: any[] = [];\n\n try {\n const username = c.req.param('username');\n const body = await c.req.json();\n serviceFqn = body.serviceFqn;\n const { offers, ttl, isPublic, metadata, signature, message } = body;\n\n if (!serviceFqn || !offers || !Array.isArray(offers) || offers.length === 0) {\n return c.json({ error: 'Missing required parameters: serviceFqn, offers (must be non-empty array)' }, 400);\n }\n\n // Validate service FQN\n const fqnValidation = validateServiceFqn(serviceFqn);\n if (!fqnValidation.valid) {\n return c.json({ error: fqnValidation.error }, 400);\n }\n\n // Verify username ownership (signature required)\n if (!signature || !message) {\n return c.json({ error: 'Missing signature or message for username verification' }, 400);\n }\n\n const usernameRecord = await storage.getUsername(username);\n if (!usernameRecord) {\n return c.json({ error: 'Username not claimed' }, 404);\n }\n\n // Verify signature matches username's public key\n const signatureValidation = await validateServicePublish(username, serviceFqn, usernameRecord.publicKey, signature, message);\n if (!signatureValidation.valid) {\n return c.json({ error: 'Invalid signature for username' }, 403);\n }\n\n // Delete existing service if one exists (upsert behavior)\n const existingUuid = await storage.queryService(username, serviceFqn);\n if (existingUuid) {\n const existingService = await storage.getServiceByUuid(existingUuid);\n if (existingService) {\n await storage.deleteService(existingService.id, username);\n }\n }\n\n // Validate all offers\n for (const offer of offers) {\n if (!offer.sdp || typeof offer.sdp !== 'string' || offer.sdp.length === 0) {\n return c.json({ error: 'Invalid SDP in offers array' }, 400);\n }\n\n if (offer.sdp.length > 64 * 1024) {\n return c.json({ error: 'SDP too large (max 64KB)' }, 400);\n }\n }\n\n // Calculate expiry\n const peerId = getAuthenticatedPeerId(c);\n const offerTtl = Math.min(\n Math.max(ttl || config.offerDefaultTtl, config.offerMinTtl),\n config.offerMaxTtl\n );\n const expiresAt = Date.now() + offerTtl;\n\n // Prepare offer requests\n const offerRequests = offers.map(offer => ({\n peerId,\n sdp: offer.sdp,\n expiresAt\n }));\n\n // Create service with offers\n const result = await storage.createService({\n username,\n serviceFqn,\n expiresAt,\n isPublic: isPublic || false,\n metadata: metadata ? JSON.stringify(metadata) : undefined,\n offers: offerRequests\n });\n\n createdOffers = result.offers;\n\n // Return full service details with all offers\n return c.json({\n uuid: result.indexUuid,\n serviceFqn: serviceFqn,\n username: username,\n serviceId: result.service.id,\n offers: result.offers.map(o => ({\n offerId: o.id,\n sdp: o.sdp,\n createdAt: o.createdAt,\n expiresAt: o.expiresAt\n })),\n isPublic: result.service.isPublic,\n metadata: metadata,\n createdAt: result.service.createdAt,\n expiresAt: result.service.expiresAt\n }, 201);\n } catch (err) {\n console.error('Error creating service:', err);\n console.error('Error details:', {\n message: (err as Error).message,\n stack: (err as Error).stack,\n username: c.req.param('username'),\n serviceFqn,\n offerIds: createdOffers.map(o => o.id)\n });\n return c.json({\n error: 'Internal server error',\n details: (err as Error).message\n }, 500);\n }\n });\n\n /**\n * DELETE /users/:username/services/:fqn\n * Delete a service by username and FQN (RESTful)\n */\n app.delete('/users/:username/services/:fqn', authMiddleware, async (c) => {\n try {\n const username = c.req.param('username');\n const serviceFqn = decodeURIComponent(c.req.param('fqn'));\n\n // Find service by username and FQN\n const uuid = await storage.queryService(username, serviceFqn);\n if (!uuid) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n const service = await storage.getServiceByUuid(uuid);\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n const deleted = await storage.deleteService(service.id, username);\n\n if (!deleted) {\n return c.json({ error: 'Service not found or not owned by this username' }, 404);\n }\n\n return c.json({ success: true }, 200);\n } catch (err) {\n console.error('Error deleting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Service Management (Legacy - for UUID-based access) =====\n\n /**\n * GET /services/:uuid\n * Get service details by index UUID (kept for privacy)\n */\n app.get('/services/:uuid', async (c) => {\n try {\n const uuid = c.req.param('uuid');\n\n const service = await storage.getServiceByUuid(uuid);\n\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // Get all offers for this service\n const serviceOffers = await storage.getOffersForService(service.id);\n\n if (serviceOffers.length === 0) {\n return c.json({ error: 'No offers found for this service' }, 404);\n }\n\n // Find an unanswered offer\n const availableOffer = serviceOffers.find(offer => !offer.answererPeerId);\n\n if (!availableOffer) {\n return c.json({\n error: 'No available offers',\n message: 'All offers from this service are currently in use. Please try again later.'\n }, 503);\n }\n\n return c.json({\n uuid: uuid,\n serviceId: service.id,\n username: service.username,\n serviceFqn: service.serviceFqn,\n offerId: availableOffer.id,\n sdp: availableOffer.sdp,\n isPublic: service.isPublic,\n metadata: service.metadata ? JSON.parse(service.metadata) : undefined,\n createdAt: service.createdAt,\n expiresAt: service.expiresAt\n }, 200);\n } catch (err) {\n console.error('Error getting service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n // ===== Service-Based WebRTC Signaling =====\n\n /**\n * POST /services/:uuid/answer\n * Answer a service offer\n */\n app.post('/services/:uuid/answer', authMiddleware, async (c) => {\n try {\n const uuid = c.req.param('uuid');\n const body = await c.req.json();\n const { sdp } = body;\n\n if (!sdp) {\n return c.json({ error: 'Missing required parameter: sdp' }, 400);\n }\n\n if (typeof sdp !== 'string' || sdp.length === 0) {\n return c.json({ error: 'Invalid SDP' }, 400);\n }\n\n if (sdp.length > 64 * 1024) {\n return c.json({ error: 'SDP too large (max 64KB)' }, 400);\n }\n\n // Get the service by UUID\n const service = await storage.getServiceByUuid(uuid);\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // Get available offer from service\n const serviceOffers = await storage.getOffersForService(service.id);\n const availableOffer = serviceOffers.find(offer => !offer.answererPeerId);\n\n if (!availableOffer) {\n return c.json({ error: 'No available offers' }, 503);\n }\n\n const answererPeerId = getAuthenticatedPeerId(c);\n\n const result = await storage.answerOffer(availableOffer.id, answererPeerId, sdp);\n\n if (!result.success) {\n return c.json({ error: result.error }, 400);\n }\n\n return c.json({\n success: true,\n offerId: availableOffer.id\n }, 200);\n } catch (err) {\n console.error('Error answering service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /services/:uuid/answer\n * Get answer for a service (offerer polls this)\n */\n app.get('/services/:uuid/answer', authMiddleware, async (c) => {\n try {\n const uuid = c.req.param('uuid');\n const peerId = getAuthenticatedPeerId(c);\n\n // Get the service by UUID\n const service = await storage.getServiceByUuid(uuid);\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // Get offers for this service owned by the requesting peer\n const serviceOffers = await storage.getOffersForService(service.id);\n const myOffer = serviceOffers.find(offer => offer.peerId === peerId && offer.answererPeerId);\n\n if (!myOffer || !myOffer.answerSdp) {\n return c.json({ error: 'Offer not yet answered' }, 404);\n }\n\n return c.json({\n offerId: myOffer.id,\n answererId: myOffer.answererPeerId,\n sdp: myOffer.answerSdp,\n answeredAt: myOffer.answeredAt\n }, 200);\n } catch (err) {\n console.error('Error getting service answer:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * POST /services/:uuid/ice-candidates\n * Add ICE candidates for a service\n */\n app.post('/services/:uuid/ice-candidates', authMiddleware, async (c) => {\n try {\n const uuid = c.req.param('uuid');\n const body = await c.req.json();\n const { candidates, offerId } = body;\n\n if (!Array.isArray(candidates) || candidates.length === 0) {\n return c.json({ error: 'Missing or invalid required parameter: candidates' }, 400);\n }\n\n const peerId = getAuthenticatedPeerId(c);\n\n // Get the service by UUID\n const service = await storage.getServiceByUuid(uuid);\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // If offerId is provided, use it; otherwise find the peer's offer\n let targetOfferId = offerId;\n if (!targetOfferId) {\n const serviceOffers = await storage.getOffersForService(service.id);\n const myOffer = serviceOffers.find(offer =>\n offer.peerId === peerId || offer.answererPeerId === peerId\n );\n if (!myOffer) {\n return c.json({ error: 'No offer found for this peer' }, 404);\n }\n targetOfferId = myOffer.id;\n }\n\n // Get offer to determine role\n const offer = await storage.getOfferById(targetOfferId);\n if (!offer) {\n return c.json({ error: 'Offer not found' }, 404);\n }\n\n // Determine role\n const role = offer.peerId === peerId ? 'offerer' : 'answerer';\n\n const count = await storage.addIceCandidates(targetOfferId, peerId, role, candidates);\n\n return c.json({ count, offerId: targetOfferId }, 200);\n } catch (err) {\n console.error('Error adding ICE candidates to service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n /**\n * GET /services/:uuid/ice-candidates\n * Get ICE candidates for a service\n */\n app.get('/services/:uuid/ice-candidates', authMiddleware, async (c) => {\n try {\n const uuid = c.req.param('uuid');\n const since = c.req.query('since');\n const offerId = c.req.query('offerId');\n const peerId = getAuthenticatedPeerId(c);\n\n // Get the service by UUID\n const service = await storage.getServiceByUuid(uuid);\n if (!service) {\n return c.json({ error: 'Service not found' }, 404);\n }\n\n // If offerId is provided, use it; otherwise find the peer's offer\n let targetOfferId = offerId;\n if (!targetOfferId) {\n const serviceOffers = await storage.getOffersForService(service.id);\n const myOffer = serviceOffers.find(offer =>\n offer.peerId === peerId || offer.answererPeerId === peerId\n );\n if (!myOffer) {\n return c.json({ error: 'No offer found for this peer' }, 404);\n }\n targetOfferId = myOffer.id;\n }\n\n // Get offer to determine role\n const offer = await storage.getOfferById(targetOfferId);\n if (!offer) {\n return c.json({ error: 'Offer not found' }, 404);\n }\n\n // Get candidates for opposite role\n const targetRole = offer.peerId === peerId ? 'answerer' : 'offerer';\n const sinceTimestamp = since ? parseInt(since, 10) : undefined;\n\n const candidates = await storage.getIceCandidates(targetOfferId, targetRole, sinceTimestamp);\n\n return c.json({\n candidates: candidates.map(c => ({\n candidate: c.candidate,\n createdAt: c.createdAt\n })),\n offerId: targetOfferId\n }, 200);\n } catch (err) {\n console.error('Error getting ICE candidates for service:', err);\n return c.json({ error: 'Internal server error' }, 500);\n }\n });\n\n return app;\n}\n", "/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */\n/**\n * 5KB JS implementation of ed25519 EdDSA signatures.\n * Compliant with RFC8032, FIPS 186-5 & ZIP215.\n * @module\n * @example\n * ```js\nimport * as ed from '@noble/ed25519';\n(async () => {\n const secretKey = ed.utils.randomSecretKey();\n const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);\n const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present\n const signature = await ed.signAsync(message, secretKey);\n const isValid = await ed.verifyAsync(signature, message, pubKey);\n})();\n```\n */\n/**\n * Curve params. ed25519 is twisted edwards curve. Equation is \u2212x\u00B2 + y\u00B2 = -a + dx\u00B2y\u00B2.\n * * P = `2n**255n - 19n` // field over which calculations are done\n * * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points\n * * h = 8 // cofactor\n * * a = `Fp.create(BigInt(-1))` // equation param\n * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param\n * * Gx, Gy are coordinates of Generator / base point\n */\nconst ed25519_CURVE = {\n p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,\n n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,\n h: 8n,\n a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,\n d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,\n Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,\n Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,\n};\nconst { p: P, n: N, Gx, Gy, a: _a, d: _d, h } = ed25519_CURVE;\nconst L = 32; // field / group byte length\nconst L2 = 64;\n// Helpers and Precomputes sections are reused between libraries\n// ## Helpers\n// ----------\nconst captureTrace = (...args) => {\n if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(...args);\n }\n};\nconst err = (message = '') => {\n const e = new Error(message);\n captureTrace(e, err);\n throw e;\n};\nconst isBig = (n) => typeof n === 'bigint'; // is big integer\nconst isStr = (s) => typeof s === 'string'; // is string\nconst isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n/** Asserts something is Uint8Array. */\nconst abytes = (value, length, title = '') => {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n err(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n};\n/** create Uint8Array */\nconst u8n = (len) => new Uint8Array(len);\nconst u8fr = (buf) => Uint8Array.from(buf);\nconst padh = (n, pad) => n.toString(16).padStart(pad, '0');\nconst bytesToHex = (b) => Array.from(abytes(b))\n .map((e) => padh(e, 2))\n .join('');\nconst C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters\nconst _ch = (ch) => {\n if (ch >= C._0 && ch <= C._9)\n return ch - C._0; // '2' => 50-48\n if (ch >= C.A && ch <= C.F)\n return ch - (C.A - 10); // 'B' => 66-(65-10)\n if (ch >= C.a && ch <= C.f)\n return ch - (C.a - 10); // 'b' => 98-(97-10)\n return;\n};\nconst hexToBytes = (hex) => {\n const e = 'hex invalid';\n if (!isStr(hex))\n return err(e);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2)\n return err(e);\n const array = u8n(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n // treat each char as ASCII\n const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16\n const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char\n if (n1 === undefined || n2 === undefined)\n return err(e);\n array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9\n }\n return array;\n};\nconst cr = () => globalThis?.crypto; // WebCrypto is available in all modern environments\nconst subtle = () => cr()?.subtle ?? err('crypto.subtle must be defined, consider polyfill');\n// prettier-ignore\nconst concatBytes = (...arrs) => {\n const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); // create u8a of summed length\n let pad = 0; // walk through each array,\n arrs.forEach(a => { r.set(a, pad); pad += a.length; }); // ensure they have proper type\n return r;\n};\n/** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */\nconst randomBytes = (len = L) => {\n const c = cr();\n return c.getRandomValues(u8n(len));\n};\nconst big = BigInt;\nconst assertRange = (n, min, max, msg = 'bad number: out of range') => (isBig(n) && min <= n && n < max ? n : err(msg));\n/** modular division */\nconst M = (a, b = P) => {\n const r = a % b;\n return r >= 0n ? r : b + r;\n};\nconst modN = (a) => M(a, N);\n/** Modular inversion using euclidean GCD (non-CT). No negative exponent for now. */\n// prettier-ignore\nconst invert = (num, md) => {\n if (num === 0n || md <= 0n)\n err('no inverse n=' + num + ' mod=' + md);\n let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;\n while (a !== 0n) {\n const q = b / a, r = b % a;\n const m = x - u * q, n = y - v * q;\n b = a, a = r, x = u, y = v, u = m, v = n;\n }\n return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point\n};\nconst callHash = (name) => {\n // @ts-ignore\n const fn = hashes[name];\n if (typeof fn !== 'function')\n err('hashes.' + name + ' not set');\n return fn;\n};\nconst hash = (msg) => callHash('sha512')(msg);\nconst apoint = (p) => (p instanceof Point ? p : err('Point expected'));\n// ## End of Helpers\n// -----------------\nconst B256 = 2n ** 256n;\n/** Point in XYZT extended coordinates. */\nclass Point {\n static BASE;\n static ZERO;\n X;\n Y;\n Z;\n T;\n constructor(X, Y, Z, T) {\n const max = B256;\n this.X = assertRange(X, 0n, max);\n this.Y = assertRange(Y, 0n, max);\n this.Z = assertRange(Z, 1n, max);\n this.T = assertRange(T, 0n, max);\n Object.freeze(this);\n }\n static CURVE() {\n return ed25519_CURVE;\n }\n static fromAffine(p) {\n return new Point(p.x, p.y, 1n, M(p.x * p.y));\n }\n /** RFC8032 5.1.3: Uint8Array to Point. */\n static fromBytes(hex, zip215 = false) {\n const d = _d;\n // Copy array to not mess it up.\n const normed = u8fr(abytes(hex, L));\n // adjust first LE byte = last BE byte\n const lastByte = hex[31];\n normed[31] = lastByte & ~0x80;\n const y = bytesToNumLE(normed);\n // zip215=true: 0 <= y < 2^256\n // zip215=false, RFC8032: 0 <= y < 2^255-19\n const max = zip215 ? B256 : P;\n assertRange(y, 0n, max);\n const y2 = M(y * y); // y\u00B2\n const u = M(y2 - 1n); // u=y\u00B2-1\n const v = M(d * y2 + 1n); // v=dy\u00B2+1\n let { isValid, value: x } = uvRatio(u, v); // (uv\u00B3)(uv\u2077)^(p-5)/8; square root\n if (!isValid)\n err('bad point: y not sqrt'); // not square root: bad point\n const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate\n const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit\n if (!zip215 && x === 0n && isLastByteOdd)\n err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1\n if (isLastByteOdd !== isXOdd)\n x = M(-x);\n return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy\n }\n static fromHex(hex, zip215) {\n return Point.fromBytes(hexToBytes(hex), zip215);\n }\n get x() {\n return this.toAffine().x;\n }\n get y() {\n return this.toAffine().y;\n }\n /** Checks if the point is valid and on-curve. */\n assertValidity() {\n const a = _a;\n const d = _d;\n const p = this;\n if (p.is0())\n return err('bad point: ZERO'); // TODO: optimize, with vars below?\n // Equation in affine coordinates: ax\u00B2 + y\u00B2 = 1 + dx\u00B2y\u00B2\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX\u00B2 + Y\u00B2)Z\u00B2 = Z\u2074 + dX\u00B2Y\u00B2\n const { X, Y, Z, T } = p;\n const X2 = M(X * X); // X\u00B2\n const Y2 = M(Y * Y); // Y\u00B2\n const Z2 = M(Z * Z); // Z\u00B2\n const Z4 = M(Z2 * Z2); // Z\u2074\n const aX2 = M(X2 * a); // aX\u00B2\n const left = M(Z2 * M(aX2 + Y2)); // (aX\u00B2 + Y\u00B2)Z\u00B2\n const right = M(Z4 + M(d * M(X2 * Y2))); // Z\u2074 + dX\u00B2Y\u00B2\n if (left !== right)\n return err('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = M(X * Y);\n const ZT = M(Z * T);\n if (XY !== ZT)\n return err('bad point: equation left != right (2)');\n return this;\n }\n /** Equality check: compare points P&Q. */\n equals(other) {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality\n const X1Z2 = M(X1 * Z2);\n const X2Z1 = M(X2 * Z1);\n const Y1Z2 = M(Y1 * Z2);\n const Y2Z1 = M(Y2 * Z1);\n return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;\n }\n is0() {\n return this.equals(I);\n }\n /** Flip point over y coordinate. */\n negate() {\n return new Point(M(-this.X), this.Y, this.Z, M(-this.T));\n }\n /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */\n double() {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const a = _a;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n const A = M(X1 * X1);\n const B = M(Y1 * Y1);\n const C = M(2n * M(Z1 * Z1));\n const D = M(a * A);\n const x1y1 = X1 + Y1;\n const E = M(M(x1y1 * x1y1) - A - B);\n const G = D + B;\n const F = G - C;\n const H = D - B;\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */\n add(other) {\n const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;\n const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve\n const a = _a;\n const d = _d;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3\n const A = M(X1 * X2);\n const B = M(Y1 * Y2);\n const C = M(T1 * d * T2);\n const D = M(Z1 * Z2);\n const E = M((X1 + Y1) * (X2 + Y2) - A - B);\n const F = M(D - C);\n const G = M(D + C);\n const H = M(B - a * A);\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n subtract(other) {\n return this.add(apoint(other).negate());\n }\n /**\n * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.\n * Uses {@link wNAF} for base point.\n * Uses fake point to mitigate side-channel leakage.\n * @param n scalar by which point is multiplied\n * @param safe safe mode guards against timing attacks; unsafe mode is faster\n */\n multiply(n, safe = true) {\n if (!safe && (n === 0n || this.is0()))\n return I;\n assertRange(n, 1n, N);\n if (n === 1n)\n return this;\n if (this.equals(G))\n return wNAF(n).p;\n // init result point & fake point\n let p = I;\n let f = G;\n for (let d = this; n > 0n; d = d.double(), n >>= 1n) {\n // if bit is present, add to point\n // if not present, add to fake, for timing safety\n if (n & 1n)\n p = p.add(d);\n else if (safe)\n f = f.add(d);\n }\n return p;\n }\n multiplyUnsafe(scalar) {\n return this.multiply(scalar, false);\n }\n /** Convert point to 2d xy affine point. (X, Y, Z) \u220B (x=X/Z, y=Y/Z) */\n toAffine() {\n const { X, Y, Z } = this;\n // fast-paths for ZERO point OR Z=1\n if (this.equals(I))\n return { x: 0n, y: 1n };\n const iz = invert(Z, P);\n // (Z * Z^-1) must be 1, otherwise bad math\n if (M(Z * iz) !== 1n)\n err('invalid inverse');\n // x = X*Z^-1; y = Y*Z^-1\n const x = M(X * iz);\n const y = M(Y * iz);\n return { x, y };\n }\n toBytes() {\n const { x, y } = this.assertValidity().toAffine();\n const b = numTo32bLE(y);\n // store sign in first LE byte\n b[31] |= x & 1n ? 0x80 : 0;\n return b;\n }\n toHex() {\n return bytesToHex(this.toBytes());\n }\n clearCofactor() {\n return this.multiply(big(h), false);\n }\n isSmallOrder() {\n return this.clearCofactor().is0();\n }\n isTorsionFree() {\n // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`\n let p = this.multiply(N / 2n, false).double();\n if (N % 2n)\n p = p.add(this);\n return p.is0();\n }\n}\n/** Generator / base point */\nconst G = new Point(Gx, Gy, 1n, M(Gx * Gy));\n/** Identity / zero point */\nconst I = new Point(0n, 1n, 1n, 0n);\n// Static aliases\nPoint.BASE = G;\nPoint.ZERO = I;\nconst numTo32bLE = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse();\nconst bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));\nconst pow2 = (x, power) => {\n // pow2(x, 4) == x^(2^4)\n let r = x;\n while (power-- > 0n) {\n r *= r;\n r %= P;\n }\n return r;\n};\n// prettier-ignore\nconst pow_2_252_3 = (x) => {\n const x2 = (x * x) % P; // x^2, bits 1\n const b2 = (x2 * x) % P; // x^3, bits 11\n const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111\n const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111\n const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)\n const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)\n const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)\n const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)\n const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)\n const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)\n const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)\n const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.\n return { pow_p_5_8, b2 };\n};\nconst RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // \u221A-1\n// for sqrt comp\n// prettier-ignore\nconst uvRatio = (u, v) => {\n const v3 = M(v * v * v); // v\u00B3\n const v7 = M(v3 * v3 * v); // v\u2077\n const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv\u2077)^(p-5)/8\n let x = M(u * v3 * pow); // (uv\u00B3)(uv\u2077)^(p-5)/8\n const vx2 = M(v * x * x); // vx\u00B2\n const root1 = x; // First root candidate\n const root2 = M(x * RM1); // Second root candidate; RM1 is \u221A-1\n const useRoot1 = vx2 === u; // If vx\u00B2 = u (mod p), x is a square root\n const useRoot2 = vx2 === M(-u); // If vx\u00B2 = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx\u00B2 = -u\u221A-1\n if (useRoot1)\n x = root1;\n if (useRoot2 || noRoot)\n x = root2; // We return root2 anyway, for const-time\n if ((M(x) & 1n) === 1n)\n x = M(-x); // edIsNegative\n return { isValid: useRoot1 || useRoot2, value: x };\n};\n// N == L, just weird naming\nconst modL_LE = (hash) => modN(bytesToNumLE(hash)); // modulo L; but little-endian\n/** hashes.sha512 should conform to the interface. */\n// TODO: rename\nconst sha512a = (...m) => hashes.sha512Async(concatBytes(...m)); // Async SHA512\nconst sha512s = (...m) => callHash('sha512')(concatBytes(...m));\n// RFC8032 5.1.5\nconst hash2extK = (hashed) => {\n // slice creates a copy, unlike subarray\n const head = hashed.slice(0, L);\n head[0] &= 248; // Clamp bits: 0b1111_1000\n head[31] &= 127; // 0b0111_1111\n head[31] |= 64; // 0b0100_0000\n const prefix = hashed.slice(L, L2); // secret key \"prefix\"\n const scalar = modL_LE(head); // modular division over curve order\n const point = G.multiply(scalar); // public key point\n const pointBytes = point.toBytes(); // point serialized to Uint8Array\n return { head, prefix, scalar, point, pointBytes };\n};\n// RFC8032 5.1.5; getPublicKey async, sync. Hash priv key and extract point.\nconst getExtendedPublicKeyAsync = (secretKey) => sha512a(abytes(secretKey, L)).then(hash2extK);\nconst getExtendedPublicKey = (secretKey) => hash2extK(sha512s(abytes(secretKey, L)));\n/** Creates 32-byte ed25519 public key from 32-byte secret key. Async. */\nconst getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);\n/** Creates 32-byte ed25519 public key from 32-byte secret key. To use, set `hashes.sha512` first. */\nconst getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;\nconst hashFinishA = (res) => sha512a(res.hashable).then(res.finish);\nconst hashFinishS = (res) => res.finish(sha512s(res.hashable));\n// Code, shared between sync & async sign\nconst _sign = (e, rBytes, msg) => {\n const { pointBytes: P, scalar: s } = e;\n const r = modL_LE(rBytes); // r was created outside, reduce it modulo L\n const R = G.multiply(r).toBytes(); // R = [r]B\n const hashable = concatBytes(R, P, msg); // dom2(F, C) || R || A || PH(M)\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l\n return abytes(concatBytes(R, numTo32bLE(S)), L2); // 64-byte sig: 32b R.x + 32b LE(S)\n };\n return { hashable, finish };\n};\n/**\n * Signs message using secret key. Async.\n * Follows RFC8032 5.1.6.\n */\nconst signAsync = async (message, secretKey) => {\n const m = abytes(message);\n const e = await getExtendedPublicKeyAsync(secretKey);\n const rBytes = await sha512a(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishA(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\n/**\n * Signs message using secret key. To use, set `hashes.sha512` first.\n * Follows RFC8032 5.1.6.\n */\nconst sign = (message, secretKey) => {\n const m = abytes(message);\n const e = getExtendedPublicKey(secretKey);\n const rBytes = sha512s(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishS(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\nconst defaultVerifyOpts = { zip215: true };\nconst _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {\n sig = abytes(sig, L2); // Signature hex str/Bytes, must be 64 bytes\n msg = abytes(msg); // Message hex str/Bytes\n pub = abytes(pub, L);\n const { zip215 } = opts; // switch between zip215 and rfc8032 verif\n let A;\n let R;\n let s;\n let SB;\n let hashable = Uint8Array.of();\n try {\n A = Point.fromBytes(pub, zip215); // public key A decoded\n R = Point.fromBytes(sig.slice(0, L), zip215); // 0 <= R < 2^256: ZIP215 R can be >= P\n s = bytesToNumLE(sig.slice(L, L2)); // Decode second half as an integer S\n SB = G.multiply(s, false); // in the range 0 <= s < L\n hashable = concatBytes(R.toBytes(), A.toBytes(), msg); // dom2(F, C) || R || A || PH(M)\n }\n catch (error) { }\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n if (SB == null)\n return false; // false if try-catch catched an error\n if (!zip215 && A.isSmallOrder())\n return false; // false for SBS: Strongly Binding Signature\n const k = modL_LE(hashed); // decode in little-endian, modulo L\n const RkA = R.add(A.multiply(k, false)); // [8]R + [8][k]A'\n return RkA.add(SB.negate()).clearCofactor().is0(); // [8][S]B = [8]R + [8][k]A'\n };\n return { hashable, finish };\n};\n/** Verifies signature on message and public key. Async. Follows RFC8032 5.1.7. */\nconst verifyAsync = async (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishA(_verify(signature, message, publicKey, opts));\n/** Verifies signature on message and public key. To use, set `hashes.sha512` first. Follows RFC8032 5.1.7. */\nconst verify = (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishS(_verify(signature, message, publicKey, opts));\n/** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */\nconst etc = {\n bytesToHex: bytesToHex,\n hexToBytes: hexToBytes,\n concatBytes: concatBytes,\n mod: M,\n invert: invert,\n randomBytes: randomBytes,\n};\nconst hashes = {\n sha512Async: async (message) => {\n const s = subtle();\n const m = concatBytes(message);\n return u8n(await s.digest('SHA-512', m.buffer));\n },\n sha512: undefined,\n};\n// FIPS 186 B.4.1 compliant key generation produces private keys\n// with modulo bias being neglible. takes >N+16 bytes, returns (hash mod n-1)+1\nconst randomSecretKey = (seed = randomBytes(L)) => seed;\nconst keygen = (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = getPublicKey(secretKey);\n return { secretKey, publicKey };\n};\nconst keygenAsync = async (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = await getPublicKeyAsync(secretKey);\n return { secretKey, publicKey };\n};\n/** ed25519-specific key utilities. */\nconst utils = {\n getExtendedPublicKeyAsync: getExtendedPublicKeyAsync,\n getExtendedPublicKey: getExtendedPublicKey,\n randomSecretKey: randomSecretKey,\n};\n// ## Precomputes\n// --------------\nconst W = 8; // W is window size\nconst scalarBits = 256;\nconst pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8, NOT 32 - see wNAF loop\nconst pwindowSize = 2 ** (W - 1); // 128 for W=8\nconst precompute = () => {\n const points = [];\n let p = G;\n let b = p;\n for (let w = 0; w < pwindows; w++) {\n b = p;\n points.push(b);\n for (let i = 1; i < pwindowSize; i++) {\n b = b.add(p);\n points.push(b);\n } // i=1, bc we skip 0\n p = b.double();\n }\n return points;\n};\nlet Gpows = undefined; // precomputes for base point G\n// const-time negate\nconst ctneg = (cnd, p) => {\n const n = p.negate();\n return cnd ? n : p;\n};\n/**\n * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by\n * caching multiples of G (base point). Cache is stored in 32MB of RAM.\n * Any time `G.multiply` is done, precomputes are used.\n * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.\n *\n * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,\n * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.\n *\n * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().\n */\nconst wNAF = (n) => {\n const comp = Gpows || (Gpows = precompute());\n let p = I;\n let f = G; // f must be G, or could become I in the end\n const pow_2_w = 2 ** W; // 256 for W=8\n const maxNum = pow_2_w; // 256 for W=8\n const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111\n const shiftBy = big(W); // 8 for W=8\n for (let w = 0; w < pwindows; w++) {\n let wbits = Number(n & mask); // extract W bits.\n n >>= shiftBy; // shift number by W bits.\n // We use negative indexes to reduce size of precomputed table by 2x.\n // Instead of needing precomputes 0..256, we only calculate them for 0..128.\n // If an index > 128 is found, we do (256-index) - where 256 is next window.\n // Naive: index +127 => 127, +224 => 224\n // Optimized: index +127 => 127, +224 => 256-32\n if (wbits > pwindowSize) {\n wbits -= maxNum;\n n += 1n;\n }\n const off = w * pwindowSize;\n const offF = off; // offsets, evaluate both\n const offP = off + Math.abs(wbits) - 1;\n const isEven = w % 2 !== 0; // conditions, evaluate both\n const isNeg = wbits < 0;\n if (wbits === 0) {\n // off == I: can't add it. Adding random offF instead.\n f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point\n }\n else {\n p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point\n }\n }\n if (n !== 0n)\n err('invalid wnaf');\n return { p, f }; // return both real and fake points for JIT\n};\n// !! Remove the export to easily use in REPL / browser console\nexport { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };\n", "/**\n * Crypto utilities for stateless peer authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n * Uses @noble/ed25519 for Ed25519 signature verification\n */\n\nimport * as ed25519 from '@noble/ed25519';\n\n// Set SHA-512 hash function for ed25519 (required in @noble/ed25519 v3+)\n// Uses Web Crypto API (compatible with both Node.js and Cloudflare Workers)\ned25519.hashes.sha512Async = async (message: Uint8Array) => {\n return new Uint8Array(await crypto.subtle.digest('SHA-512', message as BufferSource));\n};\n\nconst ALGORITHM = 'AES-GCM';\nconst IV_LENGTH = 12; // 96 bits for GCM\nconst KEY_LENGTH = 32; // 256 bits\n\n// Username validation\nconst USERNAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;\nconst USERNAME_MIN_LENGTH = 3;\nconst USERNAME_MAX_LENGTH = 32;\n\n// Timestamp validation (5 minutes tolerance)\nconst TIMESTAMP_TOLERANCE_MS = 5 * 60 * 1000;\n\n/**\n * Generates a random peer ID (16 bytes = 32 hex chars)\n */\nexport function generatePeerId(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Generates a random secret key for encryption (32 bytes = 64 hex chars)\n */\nexport function generateSecretKey(): string {\n const bytes = crypto.getRandomValues(new Uint8Array(KEY_LENGTH));\n return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Convert hex string to Uint8Array\n */\nfunction hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Convert Uint8Array to base64 string\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n const binString = Array.from(bytes, (byte) =>\n String.fromCodePoint(byte)\n ).join('');\n return btoa(binString);\n}\n\n/**\n * Convert base64 string to Uint8Array\n */\nfunction base64ToBytes(base64: string): Uint8Array {\n const binString = atob(base64);\n return Uint8Array.from(binString, (char) => char.codePointAt(0)!);\n}\n\n/**\n * Encrypts a peer ID using the server secret key\n * Returns base64-encoded encrypted data (IV + ciphertext)\n */\nexport async function encryptPeerId(peerId: string, secretKeyHex: string): Promise<string> {\n const keyBytes = hexToBytes(secretKeyHex);\n\n if (keyBytes.length !== KEY_LENGTH) {\n throw new Error(`Secret key must be ${KEY_LENGTH * 2} hex characters (${KEY_LENGTH} bytes)`);\n }\n\n // Import key\n const key = await crypto.subtle.importKey(\n 'raw',\n keyBytes,\n { name: ALGORITHM, length: 256 },\n false,\n ['encrypt']\n );\n\n // Generate random IV\n const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH));\n\n // Encrypt peer ID\n const encoder = new TextEncoder();\n const data = encoder.encode(peerId);\n\n const encrypted = await crypto.subtle.encrypt(\n { name: ALGORITHM, iv },\n key,\n data\n );\n\n // Combine IV + ciphertext and encode as base64\n const combined = new Uint8Array(iv.length + encrypted.byteLength);\n combined.set(iv, 0);\n combined.set(new Uint8Array(encrypted), iv.length);\n\n return bytesToBase64(combined);\n}\n\n/**\n * Decrypts an encrypted peer ID secret\n * Returns the plaintext peer ID or throws if decryption fails\n */\nexport async function decryptPeerId(encryptedSecret: string, secretKeyHex: string): Promise<string> {\n try {\n const keyBytes = hexToBytes(secretKeyHex);\n\n if (keyBytes.length !== KEY_LENGTH) {\n throw new Error(`Secret key must be ${KEY_LENGTH * 2} hex characters (${KEY_LENGTH} bytes)`);\n }\n\n // Decode base64\n const combined = base64ToBytes(encryptedSecret);\n\n // Extract IV and ciphertext\n const iv = combined.slice(0, IV_LENGTH);\n const ciphertext = combined.slice(IV_LENGTH);\n\n // Import key\n const key = await crypto.subtle.importKey(\n 'raw',\n keyBytes,\n { name: ALGORITHM, length: 256 },\n false,\n ['decrypt']\n );\n\n // Decrypt\n const decrypted = await crypto.subtle.decrypt(\n { name: ALGORITHM, iv },\n key,\n ciphertext\n );\n\n const decoder = new TextDecoder();\n return decoder.decode(decrypted);\n } catch (err) {\n throw new Error('Failed to decrypt peer ID: invalid secret or secret key');\n }\n}\n\n/**\n * Validates that a peer ID and secret match\n * Returns true if valid, false otherwise\n */\nexport async function validateCredentials(peerId: string, encryptedSecret: string, secretKey: string): Promise<boolean> {\n try {\n const decryptedPeerId = await decryptPeerId(encryptedSecret, secretKey);\n return decryptedPeerId === peerId;\n } catch {\n return false;\n }\n}\n\n// ===== Username and Ed25519 Signature Utilities =====\n\n/**\n * Validates username format\n * Rules: 3-32 chars, lowercase alphanumeric + dash, must start/end with alphanumeric\n */\nexport function validateUsername(username: string): { valid: boolean; error?: string } {\n if (typeof username !== 'string') {\n return { valid: false, error: 'Username must be a string' };\n }\n\n if (username.length < USERNAME_MIN_LENGTH) {\n return { valid: false, error: `Username must be at least ${USERNAME_MIN_LENGTH} characters` };\n }\n\n if (username.length > USERNAME_MAX_LENGTH) {\n return { valid: false, error: `Username must be at most ${USERNAME_MAX_LENGTH} characters` };\n }\n\n if (!USERNAME_REGEX.test(username)) {\n return { valid: false, error: 'Username must be lowercase alphanumeric with optional dashes, and start/end with alphanumeric' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates service FQN format (service-name@version)\n * Service name: reverse domain notation (com.example.service)\n * Version: semantic versioning (1.0.0, 2.1.3-beta, etc.)\n */\nexport function validateServiceFqn(fqn: string): { valid: boolean; error?: string } {\n if (typeof fqn !== 'string') {\n return { valid: false, error: 'Service FQN must be a string' };\n }\n\n // Split into service name and version\n const parts = fqn.split('@');\n if (parts.length !== 2) {\n return { valid: false, error: 'Service FQN must be in format: service-name@version' };\n }\n\n const [serviceName, version] = parts;\n\n // Validate service name (reverse domain notation)\n const serviceNameRegex = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;\n if (!serviceNameRegex.test(serviceName)) {\n return { valid: false, error: 'Service name must be reverse domain notation (e.g., com.example.service)' };\n }\n\n if (serviceName.length < 3 || serviceName.length > 128) {\n return { valid: false, error: 'Service name must be 3-128 characters' };\n }\n\n // Validate version (semantic versioning)\n const versionRegex = /^[0-9]+\\.[0-9]+\\.[0-9]+(-[a-z0-9.-]+)?$/;\n if (!versionRegex.test(version)) {\n return { valid: false, error: 'Version must be semantic versioning (e.g., 1.0.0, 2.1.3-beta)' };\n }\n\n return { valid: true };\n}\n\n/**\n * Parse semantic version string into components\n */\nexport function parseVersion(version: string): { major: number; minor: number; patch: number; prerelease?: string } | null {\n const match = version.match(/^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-[a-z0-9.-]+)?$/);\n if (!match) return null;\n\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n prerelease: match[4]?.substring(1), // Remove leading dash\n };\n}\n\n/**\n * Check if two versions are compatible (same major version)\n * Following semver rules: ^1.0.0 matches 1.x.x but not 2.x.x\n */\nexport function isVersionCompatible(requested: string, available: string): boolean {\n const req = parseVersion(requested);\n const avail = parseVersion(available);\n\n if (!req || !avail) return false;\n\n // Major version must match\n if (req.major !== avail.major) return false;\n\n // If major is 0, minor must also match (0.x.y is unstable)\n if (req.major === 0 && req.minor !== avail.minor) return false;\n\n // Available version must be >= requested version\n if (avail.minor < req.minor) return false;\n if (avail.minor === req.minor && avail.patch < req.patch) return false;\n\n // Prerelease versions are only compatible with exact matches\n if (req.prerelease && req.prerelease !== avail.prerelease) return false;\n\n return true;\n}\n\n/**\n * Parse service FQN into service name and version\n */\nexport function parseServiceFqn(fqn: string): { serviceName: string; version: string } | null {\n const parts = fqn.split('@');\n if (parts.length !== 2) return null;\n\n return {\n serviceName: parts[0],\n version: parts[1],\n };\n}\n\n/**\n * Validates timestamp is within acceptable range (prevents replay attacks)\n */\nexport function validateTimestamp(timestamp: number): { valid: boolean; error?: string } {\n if (typeof timestamp !== 'number' || !Number.isFinite(timestamp)) {\n return { valid: false, error: 'Timestamp must be a finite number' };\n }\n\n const now = Date.now();\n const diff = Math.abs(now - timestamp);\n\n if (diff > TIMESTAMP_TOLERANCE_MS) {\n return { valid: false, error: `Timestamp too old or too far in future (tolerance: ${TIMESTAMP_TOLERANCE_MS / 1000}s)` };\n }\n\n return { valid: true };\n}\n\n/**\n * Verifies Ed25519 signature\n * @param publicKey Base64-encoded Ed25519 public key (32 bytes)\n * @param signature Base64-encoded Ed25519 signature (64 bytes)\n * @param message Message that was signed (UTF-8 string)\n * @returns true if signature is valid, false otherwise\n */\nexport async function verifyEd25519Signature(\n publicKey: string,\n signature: string,\n message: string\n): Promise<boolean> {\n try {\n // Decode base64 to bytes\n const publicKeyBytes = base64ToBytes(publicKey);\n const signatureBytes = base64ToBytes(signature);\n\n // Encode message as UTF-8\n const encoder = new TextEncoder();\n const messageBytes = encoder.encode(message);\n\n // Verify signature using @noble/ed25519 (async version)\n const isValid = await ed25519.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);\n return isValid;\n } catch (err) {\n console.error('Ed25519 signature verification failed:', err);\n return false;\n }\n}\n\n/**\n * Validates a username claim request\n * Verifies format, timestamp, and signature\n */\nexport async function validateUsernameClaim(\n username: string,\n publicKey: string,\n signature: string,\n message: string\n): Promise<{ valid: boolean; error?: string }> {\n // Validate username format\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n\n // Parse message format: \"claim:{username}:{timestamp}\"\n const parts = message.split(':');\n if (parts.length !== 3 || parts[0] !== 'claim' || parts[1] !== username) {\n return { valid: false, error: 'Invalid message format (expected: claim:{username}:{timestamp})' };\n }\n\n const timestamp = parseInt(parts[2], 10);\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n // Validate timestamp\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n // Verify signature\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates a service publish signature\n * Message format: publish:{username}:{serviceFqn}:{timestamp}\n */\nexport async function validateServicePublish(\n username: string,\n serviceFqn: string,\n publicKey: string,\n signature: string,\n message: string\n): Promise<{ valid: boolean; error?: string }> {\n // Validate username format\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n\n // Parse message format: \"publish:{username}:{serviceFqn}:{timestamp}\"\n const parts = message.split(':');\n if (parts.length !== 4 || parts[0] !== 'publish' || parts[1] !== username || parts[2] !== serviceFqn) {\n return { valid: false, error: 'Invalid message format (expected: publish:{username}:{serviceFqn}:{timestamp})' };\n }\n\n const timestamp = parseInt(parts[3], 10);\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n // Validate timestamp\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n // Verify signature\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n return { valid: true };\n}\n", "import { Context, Next } from 'hono';\nimport { validateCredentials } from '../crypto.ts';\n\n/**\n * Authentication middleware for Rondevu\n * Validates Bearer token in format: {peerId}:{encryptedSecret}\n */\nexport function createAuthMiddleware(authSecret: string) {\n return async (c: Context, next: Next) => {\n const authHeader = c.req.header('Authorization');\n\n if (!authHeader) {\n return c.json({ error: 'Missing Authorization header' }, 401);\n }\n\n // Expect format: Bearer {peerId}:{secret}\n const parts = authHeader.split(' ');\n if (parts.length !== 2 || parts[0] !== 'Bearer') {\n return c.json({ error: 'Invalid Authorization header format. Expected: Bearer {peerId}:{secret}' }, 401);\n }\n\n const credentials = parts[1].split(':');\n if (credentials.length !== 2) {\n return c.json({ error: 'Invalid credentials format. Expected: {peerId}:{secret}' }, 401);\n }\n\n const [peerId, encryptedSecret] = credentials;\n\n // Validate credentials (async operation)\n const isValid = await validateCredentials(peerId, encryptedSecret, authSecret);\n if (!isValid) {\n return c.json({ error: 'Invalid credentials' }, 401);\n }\n\n // Attach peer ID to context for use in handlers\n c.set('peerId', peerId);\n\n await next();\n };\n}\n\n/**\n * Helper to get authenticated peer ID from context\n */\nexport function getAuthenticatedPeerId(c: Context): string {\n const peerId = c.get('peerId');\n if (!peerId) {\n throw new Error('No authenticated peer ID in context');\n }\n return peerId;\n}\n", "import { generateSecretKey } from './crypto.ts';\n\n/**\n * Application configuration\n * Reads from environment variables with sensible defaults\n */\nexport interface Config {\n port: number;\n storageType: 'sqlite' | 'memory';\n storagePath: string;\n corsOrigins: string[];\n version: string;\n authSecret: string;\n offerDefaultTtl: number;\n offerMaxTtl: number;\n offerMinTtl: number;\n cleanupInterval: number;\n maxOffersPerRequest: number;\n}\n\n/**\n * Loads configuration from environment variables\n */\nexport function loadConfig(): Config {\n // Generate or load auth secret\n let authSecret = process.env.AUTH_SECRET;\n if (!authSecret) {\n authSecret = generateSecretKey();\n console.warn('WARNING: No AUTH_SECRET provided. Generated temporary secret:', authSecret);\n console.warn('All peer credentials will be invalidated on server restart.');\n console.warn('Set AUTH_SECRET environment variable to persist credentials across restarts.');\n }\n\n return {\n port: parseInt(process.env.PORT || '3000', 10),\n storageType: (process.env.STORAGE_TYPE || 'sqlite') as 'sqlite' | 'memory',\n storagePath: process.env.STORAGE_PATH || ':memory:',\n corsOrigins: process.env.CORS_ORIGINS\n ? process.env.CORS_ORIGINS.split(',').map(o => o.trim())\n : ['*'],\n version: process.env.VERSION || 'unknown',\n authSecret,\n offerDefaultTtl: parseInt(process.env.OFFER_DEFAULT_TTL || '60000', 10),\n offerMaxTtl: parseInt(process.env.OFFER_MAX_TTL || '86400000', 10),\n offerMinTtl: parseInt(process.env.OFFER_MIN_TTL || '60000', 10),\n cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '60000', 10),\n maxOffersPerRequest: parseInt(process.env.MAX_OFFERS_PER_REQUEST || '100', 10)\n };\n}\n", "import Database from 'better-sqlite3';\nimport { randomUUID } from 'node:crypto';\nimport {\n Storage,\n Offer,\n IceCandidate,\n CreateOfferRequest,\n Username,\n ClaimUsernameRequest,\n Service,\n CreateServiceRequest,\n ServiceInfo,\n} from './types.ts';\nimport { generateOfferHash } from './hash-id.ts';\n\nconst YEAR_IN_MS = 365 * 24 * 60 * 60 * 1000; // 365 days\n\n/**\n * SQLite storage adapter for rondevu DNS-like system\n * Supports both file-based and in-memory databases\n */\nexport class SQLiteStorage implements Storage {\n private db: Database.Database;\n\n /**\n * Creates a new SQLite storage instance\n * @param path Path to SQLite database file, or ':memory:' for in-memory database\n */\n constructor(path: string = ':memory:') {\n this.db = new Database(path);\n this.initializeDatabase();\n }\n\n /**\n * Initializes database schema with username and service-based structure\n */\n private initializeDatabase(): void {\n this.db.exec(`\n -- WebRTC signaling offers\n CREATE TABLE IF NOT EXISTS offers (\n id TEXT PRIMARY KEY,\n peer_id TEXT NOT NULL,\n service_id TEXT,\n sdp TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_seen INTEGER NOT NULL,\n secret TEXT,\n answerer_peer_id TEXT,\n answer_sdp TEXT,\n answered_at INTEGER,\n FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_offers_peer ON offers(peer_id);\n CREATE INDEX IF NOT EXISTS idx_offers_service ON offers(service_id);\n CREATE INDEX IF NOT EXISTS idx_offers_expires ON offers(expires_at);\n CREATE INDEX IF NOT EXISTS idx_offers_last_seen ON offers(last_seen);\n CREATE INDEX IF NOT EXISTS idx_offers_answerer ON offers(answerer_peer_id);\n\n -- ICE candidates table\n CREATE TABLE IF NOT EXISTS ice_candidates (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offer_id TEXT NOT NULL,\n peer_id TEXT NOT NULL,\n role TEXT NOT NULL CHECK(role IN ('offerer', 'answerer')),\n candidate TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n FOREIGN KEY (offer_id) REFERENCES offers(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_ice_offer ON ice_candidates(offer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_peer ON ice_candidates(peer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_created ON ice_candidates(created_at);\n\n -- Usernames table\n CREATE TABLE IF NOT EXISTS usernames (\n username TEXT PRIMARY KEY,\n public_key TEXT NOT NULL UNIQUE,\n claimed_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_used INTEGER NOT NULL,\n metadata TEXT,\n CHECK(length(username) >= 3 AND length(username) <= 32)\n );\n\n CREATE INDEX IF NOT EXISTS idx_usernames_expires ON usernames(expires_at);\n CREATE INDEX IF NOT EXISTS idx_usernames_public_key ON usernames(public_key);\n\n -- Services table (one service can have multiple offers)\n CREATE TABLE IF NOT EXISTS services (\n id TEXT PRIMARY KEY,\n username TEXT NOT NULL,\n service_fqn TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n is_public INTEGER NOT NULL DEFAULT 0,\n metadata TEXT,\n FOREIGN KEY (username) REFERENCES usernames(username) ON DELETE CASCADE,\n UNIQUE(username, service_fqn)\n );\n\n CREATE INDEX IF NOT EXISTS idx_services_username ON services(username);\n CREATE INDEX IF NOT EXISTS idx_services_fqn ON services(service_fqn);\n CREATE INDEX IF NOT EXISTS idx_services_expires ON services(expires_at);\n\n -- Service index table (privacy layer)\n CREATE TABLE IF NOT EXISTS service_index (\n uuid TEXT PRIMARY KEY,\n service_id TEXT NOT NULL,\n username TEXT NOT NULL,\n service_fqn TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_service_index_username ON service_index(username);\n CREATE INDEX IF NOT EXISTS idx_service_index_expires ON service_index(expires_at);\n `);\n\n // Enable foreign keys\n this.db.pragma('foreign_keys = ON');\n }\n\n // ===== Offer Management =====\n\n async createOffers(offers: CreateOfferRequest[]): Promise<Offer[]> {\n const created: Offer[] = [];\n\n // Generate hash-based IDs for all offers first\n const offersWithIds = await Promise.all(\n offers.map(async (offer) => ({\n ...offer,\n id: offer.id || await generateOfferHash(offer.sdp),\n }))\n );\n\n // Use transaction for atomic creation\n const transaction = this.db.transaction((offersWithIds: (CreateOfferRequest & { id: string })[]) => {\n const offerStmt = this.db.prepare(`\n INSERT INTO offers (id, peer_id, service_id, sdp, created_at, expires_at, last_seen, secret)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const offer of offersWithIds) {\n const now = Date.now();\n\n // Insert offer\n offerStmt.run(\n offer.id,\n offer.peerId,\n offer.serviceId || null,\n offer.sdp,\n now,\n offer.expiresAt,\n now,\n offer.secret || null\n );\n\n created.push({\n id: offer.id,\n peerId: offer.peerId,\n serviceId: offer.serviceId || undefined,\n sdp: offer.sdp,\n createdAt: now,\n expiresAt: offer.expiresAt,\n lastSeen: now,\n secret: offer.secret,\n });\n }\n });\n\n transaction(offersWithIds);\n return created;\n }\n\n async getOffersByPeerId(peerId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE peer_id = ? AND expires_at > ?\n ORDER BY last_seen DESC\n `);\n\n const rows = stmt.all(peerId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n async getOfferById(offerId: string): Promise<Offer | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(offerId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToOffer(row);\n }\n\n async deleteOffer(offerId: string, ownerPeerId: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM offers\n WHERE id = ? AND peer_id = ?\n `);\n\n const result = stmt.run(offerId, ownerPeerId);\n return result.changes > 0;\n }\n\n async deleteExpiredOffers(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM offers WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async answerOffer(\n offerId: string,\n answererPeerId: string,\n answerSdp: string,\n secret?: string\n ): Promise<{ success: boolean; error?: string }> {\n // Check if offer exists and is not expired\n const offer = await this.getOfferById(offerId);\n\n if (!offer) {\n return {\n success: false,\n error: 'Offer not found or expired'\n };\n }\n\n // Verify secret if offer is protected\n if (offer.secret && offer.secret !== secret) {\n return {\n success: false,\n error: 'Invalid or missing secret'\n };\n }\n\n // Check if offer already has an answerer\n if (offer.answererPeerId) {\n return {\n success: false,\n error: 'Offer already answered'\n };\n }\n\n // Update offer with answer\n const stmt = this.db.prepare(`\n UPDATE offers\n SET answerer_peer_id = ?, answer_sdp = ?, answered_at = ?\n WHERE id = ? AND answerer_peer_id IS NULL\n `);\n\n const result = stmt.run(answererPeerId, answerSdp, Date.now(), offerId);\n\n if (result.changes === 0) {\n return {\n success: false,\n error: 'Offer already answered (race condition)'\n };\n }\n\n return { success: true };\n }\n\n async getAnsweredOffers(offererPeerId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE peer_id = ? AND answerer_peer_id IS NOT NULL AND expires_at > ?\n ORDER BY answered_at DESC\n `);\n\n const rows = stmt.all(offererPeerId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n // ===== ICE Candidate Management =====\n\n async addIceCandidates(\n offerId: string,\n peerId: string,\n role: 'offerer' | 'answerer',\n candidates: any[]\n ): Promise<number> {\n const stmt = this.db.prepare(`\n INSERT INTO ice_candidates (offer_id, peer_id, role, candidate, created_at)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n const baseTimestamp = Date.now();\n const transaction = this.db.transaction((candidates: any[]) => {\n for (let i = 0; i < candidates.length; i++) {\n stmt.run(\n offerId,\n peerId,\n role,\n JSON.stringify(candidates[i]),\n baseTimestamp + i\n );\n }\n });\n\n transaction(candidates);\n return candidates.length;\n }\n\n async getIceCandidates(\n offerId: string,\n targetRole: 'offerer' | 'answerer',\n since?: number\n ): Promise<IceCandidate[]> {\n let query = `\n SELECT * FROM ice_candidates\n WHERE offer_id = ? AND role = ?\n `;\n\n const params: any[] = [offerId, targetRole];\n\n if (since !== undefined) {\n query += ' AND created_at > ?';\n params.push(since);\n }\n\n query += ' ORDER BY created_at ASC';\n\n const stmt = this.db.prepare(query);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n offerId: row.offer_id,\n peerId: row.peer_id,\n role: row.role,\n candidate: JSON.parse(row.candidate),\n createdAt: row.created_at,\n }));\n }\n\n // ===== Username Management =====\n\n async claimUsername(request: ClaimUsernameRequest): Promise<Username> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n // Try to insert or update\n const stmt = this.db.prepare(`\n INSERT INTO usernames (username, public_key, claimed_at, expires_at, last_used, metadata)\n VALUES (?, ?, ?, ?, ?, NULL)\n ON CONFLICT(username) DO UPDATE SET\n expires_at = ?,\n last_used = ?\n WHERE public_key = ?\n `);\n\n const result = stmt.run(\n request.username,\n request.publicKey,\n now,\n expiresAt,\n now,\n expiresAt,\n now,\n request.publicKey\n );\n\n if (result.changes === 0) {\n throw new Error('Username already claimed by different public key');\n }\n\n return {\n username: request.username,\n publicKey: request.publicKey,\n claimedAt: now,\n expiresAt,\n lastUsed: now,\n };\n }\n\n async getUsername(username: string): Promise<Username | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM usernames\n WHERE username = ? AND expires_at > ?\n `);\n\n const row = stmt.get(username, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return {\n username: row.username,\n publicKey: row.public_key,\n claimedAt: row.claimed_at,\n expiresAt: row.expires_at,\n lastUsed: row.last_used,\n metadata: row.metadata || undefined,\n };\n }\n\n async touchUsername(username: string): Promise<boolean> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n const stmt = this.db.prepare(`\n UPDATE usernames\n SET last_used = ?, expires_at = ?\n WHERE username = ? AND expires_at > ?\n `);\n\n const result = stmt.run(now, expiresAt, username, now);\n return result.changes > 0;\n }\n\n async deleteExpiredUsernames(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM usernames WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n // ===== Service Management =====\n\n async createService(request: CreateServiceRequest): Promise<{\n service: Service;\n indexUuid: string;\n offers: Offer[];\n }> {\n const serviceId = randomUUID();\n const indexUuid = randomUUID();\n const now = Date.now();\n\n // Create offers with serviceId\n const offerRequests: CreateOfferRequest[] = request.offers.map(offer => ({\n ...offer,\n serviceId,\n }));\n\n const offers = await this.createOffers(offerRequests);\n\n const transaction = this.db.transaction(() => {\n // Insert service (no offer_id column anymore)\n const serviceStmt = this.db.prepare(`\n INSERT INTO services (id, username, service_fqn, created_at, expires_at, is_public, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n\n serviceStmt.run(\n serviceId,\n request.username,\n request.serviceFqn,\n now,\n request.expiresAt,\n request.isPublic ? 1 : 0,\n request.metadata || null\n );\n\n // Insert service index\n const indexStmt = this.db.prepare(`\n INSERT INTO service_index (uuid, service_id, username, service_fqn, created_at, expires_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n indexStmt.run(\n indexUuid,\n serviceId,\n request.username,\n request.serviceFqn,\n now,\n request.expiresAt\n );\n\n // Touch username to extend expiry\n this.touchUsername(request.username);\n });\n\n transaction();\n\n return {\n service: {\n id: serviceId,\n username: request.username,\n serviceFqn: request.serviceFqn,\n createdAt: now,\n expiresAt: request.expiresAt,\n isPublic: request.isPublic || false,\n metadata: request.metadata,\n },\n indexUuid,\n offers,\n };\n }\n\n async batchCreateServices(requests: CreateServiceRequest[]): Promise<Array<{\n service: Service;\n indexUuid: string;\n offers: Offer[];\n }>> {\n const results = [];\n\n for (const request of requests) {\n const result = await this.createService(request);\n results.push(result);\n }\n\n return results;\n }\n\n async getServiceById(serviceId: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM services\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(serviceId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async getServiceByUuid(uuid: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT s.* FROM services s\n INNER JOIN service_index si ON s.id = si.service_id\n WHERE si.uuid = ? AND s.expires_at > ?\n `);\n\n const row = stmt.get(uuid, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async listServicesForUsername(username: string): Promise<ServiceInfo[]> {\n const stmt = this.db.prepare(`\n SELECT si.uuid, s.is_public, s.service_fqn, s.metadata\n FROM service_index si\n INNER JOIN services s ON si.service_id = s.id\n WHERE si.username = ? AND si.expires_at > ?\n ORDER BY s.created_at DESC\n `);\n\n const rows = stmt.all(username, Date.now()) as any[];\n\n return rows.map(row => ({\n uuid: row.uuid,\n isPublic: row.is_public === 1,\n serviceFqn: row.is_public === 1 ? row.service_fqn : undefined,\n metadata: row.is_public === 1 ? row.metadata || undefined : undefined,\n }));\n }\n\n async queryService(username: string, serviceFqn: string): Promise<string | null> {\n const stmt = this.db.prepare(`\n SELECT si.uuid FROM service_index si\n INNER JOIN services s ON si.service_id = s.id\n WHERE si.username = ? AND si.service_fqn = ? AND si.expires_at > ?\n `);\n\n const row = stmt.get(username, serviceFqn, Date.now()) as any;\n\n return row ? row.uuid : null;\n }\n\n async findServicesByName(username: string, serviceName: string): Promise<Service[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM services\n WHERE username = ? AND service_fqn LIKE ? AND expires_at > ?\n ORDER BY created_at DESC\n `);\n\n const rows = stmt.all(username, `${serviceName}@%`, Date.now()) as any[];\n\n return rows.map(row => this.rowToService(row));\n }\n\n async deleteService(serviceId: string, username: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM services\n WHERE id = ? AND username = ?\n `);\n\n const result = stmt.run(serviceId, username);\n return result.changes > 0;\n }\n\n async deleteExpiredServices(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM services WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n\n // ===== Helper Methods =====\n\n /**\n * Helper method to convert database row to Offer object\n */\n private rowToOffer(row: any): Offer {\n return {\n id: row.id,\n peerId: row.peer_id,\n serviceId: row.service_id || undefined,\n sdp: row.sdp,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n lastSeen: row.last_seen,\n secret: row.secret || undefined,\n answererPeerId: row.answerer_peer_id || undefined,\n answerSdp: row.answer_sdp || undefined,\n answeredAt: row.answered_at || undefined,\n };\n }\n\n /**\n * Helper method to convert database row to Service object\n */\n private rowToService(row: any): Service {\n return {\n id: row.id,\n username: row.username,\n serviceFqn: row.service_fqn,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n isPublic: row.is_public === 1,\n metadata: row.metadata || undefined,\n };\n }\n\n /**\n * Get all offers for a service\n */\n async getOffersForService(serviceId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE service_id = ? AND expires_at > ?\n ORDER BY created_at ASC\n `);\n\n const rows = stmt.all(serviceId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n}\n", "/**\n * Generates a content-based offer ID using SHA-256 hash\n * Creates deterministic IDs based on offer SDP content\n * PeerID is not included as it's inferred from authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n *\n * @param sdp - The WebRTC SDP offer\n * @returns SHA-256 hash of the SDP content\n */\nexport async function generateOfferHash(sdp: string): Promise<string> {\n // Sanitize and normalize the offer content\n // Only include core offer content (not peerId - that's inferred from auth)\n const sanitizedOffer = {\n sdp\n };\n\n // Create non-prettified JSON string\n const jsonString = JSON.stringify(sanitizedOffer);\n\n // Convert string to Uint8Array for hashing\n const encoder = new TextEncoder();\n const data = encoder.encode(jsonString);\n\n // Generate SHA-256 hash\n const hashBuffer = await crypto.subtle.digest('SHA-256', data);\n\n // Convert hash to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\n\n return hashHex;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["C", "G", "
|
|
3
|
+
"sources": ["../src/index.ts", "../src/app.ts", "../node_modules/@noble/ed25519/index.js", "../src/crypto.ts", "../src/rpc.ts", "../src/config.ts", "../src/storage/sqlite.ts", "../src/storage/hash-id.ts"],
|
|
4
|
+
"sourcesContent": ["import { serve } from '@hono/node-server';\nimport { createApp } from './app.ts';\nimport { loadConfig } from './config.ts';\nimport { SQLiteStorage } from './storage/sqlite.ts';\nimport { Storage } from './storage/types.ts';\n\n/**\n * Main entry point for the standalone Node.js server\n */\nasync function main() {\n const config = loadConfig();\n\n console.log('Starting Rondevu server...');\n console.log('Configuration:', {\n port: config.port,\n storageType: config.storageType,\n storagePath: config.storagePath,\n offerDefaultTtl: `${config.offerDefaultTtl}ms`,\n offerMaxTtl: `${config.offerMaxTtl}ms`,\n offerMinTtl: `${config.offerMinTtl}ms`,\n cleanupInterval: `${config.cleanupInterval}ms`,\n maxOffersPerRequest: config.maxOffersPerRequest,\n corsOrigins: config.corsOrigins,\n version: config.version,\n });\n\n let storage: Storage;\n\n if (config.storageType === 'sqlite') {\n storage = new SQLiteStorage(config.storagePath);\n console.log('Using SQLite storage');\n } else {\n throw new Error('Unsupported storage type');\n }\n\n // Start periodic cleanup of expired offers\n const cleanupInterval = setInterval(async () => {\n try {\n const now = Date.now();\n const deleted = await storage.deleteExpiredOffers(now);\n if (deleted > 0) {\n console.log(`Cleanup: Deleted ${deleted} expired offer(s)`);\n }\n } catch (err) {\n console.error('Cleanup error:', err);\n }\n }, config.cleanupInterval);\n\n const app = createApp(storage, config);\n\n const server = serve({\n fetch: app.fetch,\n port: config.port,\n });\n\n console.log(`Server running on http://localhost:${config.port}`);\n console.log('Ready to accept connections');\n\n // Graceful shutdown handler\n const shutdown = async () => {\n console.log('\\nShutting down gracefully...');\n clearInterval(cleanupInterval);\n await storage.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n", "import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { Storage } from './storage/types.ts';\nimport { Config } from './config.ts';\nimport { handleRpc, RpcRequest } from './rpc.ts';\n\n// Constants\nconst MAX_BATCH_SIZE = 100;\n\n/**\n * Creates the Hono application with RPC interface\n */\nexport function createApp(storage: Storage, config: Config) {\n const app = new Hono();\n\n // Enable CORS\n app.use('/*', cors({\n origin: (origin) => {\n if (config.corsOrigins.length === 1 && config.corsOrigins[0] === '*') {\n return origin;\n }\n if (config.corsOrigins.includes(origin)) {\n return origin;\n }\n return config.corsOrigins[0];\n },\n allowMethods: ['GET', 'POST', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Origin'],\n exposeHeaders: ['Content-Type'],\n credentials: false,\n maxAge: 86400,\n }));\n\n // Root endpoint - server info\n app.get('/', (c) => {\n return c.json({\n version: config.version,\n name: 'Rondevu',\n description: 'WebRTC signaling with RPC interface and Ed25519 authentication',\n }, 200);\n });\n\n // Health check\n app.get('/health', (c) => {\n return c.json({\n status: 'ok',\n timestamp: Date.now(),\n version: config.version,\n }, 200);\n });\n\n /**\n * POST /rpc\n * RPC endpoint - accepts single or batch method calls\n */\n app.post('/rpc', async (c) => {\n try {\n const body = await c.req.json();\n\n // Support both single request and batch array\n const requests: RpcRequest[] = Array.isArray(body) ? body : [body];\n\n // Validate requests\n if (requests.length === 0) {\n return c.json({ error: 'Empty request array' }, 400);\n }\n\n if (requests.length > MAX_BATCH_SIZE) {\n return c.json({ error: `Too many requests in batch (max ${MAX_BATCH_SIZE})` }, 400);\n }\n\n // Handle RPC\n const responses = await handleRpc(requests, storage, config);\n\n // Return single response or array based on input\n return c.json(Array.isArray(body) ? responses : responses[0], 200);\n } catch (err) {\n console.error('RPC error:', err);\n return c.json({\n success: false,\n error: 'Invalid request format',\n }, 400);\n }\n });\n\n // 404 for all other routes\n app.all('*', (c) => {\n return c.json({\n error: 'Not found. Use POST /rpc for all API calls.',\n }, 404);\n });\n\n return app;\n}\n", "/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */\n/**\n * 5KB JS implementation of ed25519 EdDSA signatures.\n * Compliant with RFC8032, FIPS 186-5 & ZIP215.\n * @module\n * @example\n * ```js\nimport * as ed from '@noble/ed25519';\n(async () => {\n const secretKey = ed.utils.randomSecretKey();\n const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);\n const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present\n const signature = await ed.signAsync(message, secretKey);\n const isValid = await ed.verifyAsync(signature, message, pubKey);\n})();\n```\n */\n/**\n * Curve params. ed25519 is twisted edwards curve. Equation is \u2212x\u00B2 + y\u00B2 = -a + dx\u00B2y\u00B2.\n * * P = `2n**255n - 19n` // field over which calculations are done\n * * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points\n * * h = 8 // cofactor\n * * a = `Fp.create(BigInt(-1))` // equation param\n * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param\n * * Gx, Gy are coordinates of Generator / base point\n */\nconst ed25519_CURVE = {\n p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,\n n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,\n h: 8n,\n a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,\n d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,\n Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,\n Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,\n};\nconst { p: P, n: N, Gx, Gy, a: _a, d: _d, h } = ed25519_CURVE;\nconst L = 32; // field / group byte length\nconst L2 = 64;\n// Helpers and Precomputes sections are reused between libraries\n// ## Helpers\n// ----------\nconst captureTrace = (...args) => {\n if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {\n Error.captureStackTrace(...args);\n }\n};\nconst err = (message = '') => {\n const e = new Error(message);\n captureTrace(e, err);\n throw e;\n};\nconst isBig = (n) => typeof n === 'bigint'; // is big integer\nconst isStr = (s) => typeof s === 'string'; // is string\nconst isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');\n/** Asserts something is Uint8Array. */\nconst abytes = (value, length, title = '') => {\n const bytes = isBytes(value);\n const len = value?.length;\n const needsLen = length !== undefined;\n if (!bytes || (needsLen && len !== length)) {\n const prefix = title && `\"${title}\" `;\n const ofLen = needsLen ? ` of length ${length}` : '';\n const got = bytes ? `length=${len}` : `type=${typeof value}`;\n err(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);\n }\n return value;\n};\n/** create Uint8Array */\nconst u8n = (len) => new Uint8Array(len);\nconst u8fr = (buf) => Uint8Array.from(buf);\nconst padh = (n, pad) => n.toString(16).padStart(pad, '0');\nconst bytesToHex = (b) => Array.from(abytes(b))\n .map((e) => padh(e, 2))\n .join('');\nconst C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters\nconst _ch = (ch) => {\n if (ch >= C._0 && ch <= C._9)\n return ch - C._0; // '2' => 50-48\n if (ch >= C.A && ch <= C.F)\n return ch - (C.A - 10); // 'B' => 66-(65-10)\n if (ch >= C.a && ch <= C.f)\n return ch - (C.a - 10); // 'b' => 98-(97-10)\n return;\n};\nconst hexToBytes = (hex) => {\n const e = 'hex invalid';\n if (!isStr(hex))\n return err(e);\n const hl = hex.length;\n const al = hl / 2;\n if (hl % 2)\n return err(e);\n const array = u8n(al);\n for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n // treat each char as ASCII\n const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16\n const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char\n if (n1 === undefined || n2 === undefined)\n return err(e);\n array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9\n }\n return array;\n};\nconst cr = () => globalThis?.crypto; // WebCrypto is available in all modern environments\nconst subtle = () => cr()?.subtle ?? err('crypto.subtle must be defined, consider polyfill');\n// prettier-ignore\nconst concatBytes = (...arrs) => {\n const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); // create u8a of summed length\n let pad = 0; // walk through each array,\n arrs.forEach(a => { r.set(a, pad); pad += a.length; }); // ensure they have proper type\n return r;\n};\n/** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */\nconst randomBytes = (len = L) => {\n const c = cr();\n return c.getRandomValues(u8n(len));\n};\nconst big = BigInt;\nconst assertRange = (n, min, max, msg = 'bad number: out of range') => (isBig(n) && min <= n && n < max ? n : err(msg));\n/** modular division */\nconst M = (a, b = P) => {\n const r = a % b;\n return r >= 0n ? r : b + r;\n};\nconst modN = (a) => M(a, N);\n/** Modular inversion using euclidean GCD (non-CT). No negative exponent for now. */\n// prettier-ignore\nconst invert = (num, md) => {\n if (num === 0n || md <= 0n)\n err('no inverse n=' + num + ' mod=' + md);\n let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;\n while (a !== 0n) {\n const q = b / a, r = b % a;\n const m = x - u * q, n = y - v * q;\n b = a, a = r, x = u, y = v, u = m, v = n;\n }\n return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point\n};\nconst callHash = (name) => {\n // @ts-ignore\n const fn = hashes[name];\n if (typeof fn !== 'function')\n err('hashes.' + name + ' not set');\n return fn;\n};\nconst hash = (msg) => callHash('sha512')(msg);\nconst apoint = (p) => (p instanceof Point ? p : err('Point expected'));\n// ## End of Helpers\n// -----------------\nconst B256 = 2n ** 256n;\n/** Point in XYZT extended coordinates. */\nclass Point {\n static BASE;\n static ZERO;\n X;\n Y;\n Z;\n T;\n constructor(X, Y, Z, T) {\n const max = B256;\n this.X = assertRange(X, 0n, max);\n this.Y = assertRange(Y, 0n, max);\n this.Z = assertRange(Z, 1n, max);\n this.T = assertRange(T, 0n, max);\n Object.freeze(this);\n }\n static CURVE() {\n return ed25519_CURVE;\n }\n static fromAffine(p) {\n return new Point(p.x, p.y, 1n, M(p.x * p.y));\n }\n /** RFC8032 5.1.3: Uint8Array to Point. */\n static fromBytes(hex, zip215 = false) {\n const d = _d;\n // Copy array to not mess it up.\n const normed = u8fr(abytes(hex, L));\n // adjust first LE byte = last BE byte\n const lastByte = hex[31];\n normed[31] = lastByte & ~0x80;\n const y = bytesToNumLE(normed);\n // zip215=true: 0 <= y < 2^256\n // zip215=false, RFC8032: 0 <= y < 2^255-19\n const max = zip215 ? B256 : P;\n assertRange(y, 0n, max);\n const y2 = M(y * y); // y\u00B2\n const u = M(y2 - 1n); // u=y\u00B2-1\n const v = M(d * y2 + 1n); // v=dy\u00B2+1\n let { isValid, value: x } = uvRatio(u, v); // (uv\u00B3)(uv\u2077)^(p-5)/8; square root\n if (!isValid)\n err('bad point: y not sqrt'); // not square root: bad point\n const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate\n const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit\n if (!zip215 && x === 0n && isLastByteOdd)\n err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1\n if (isLastByteOdd !== isXOdd)\n x = M(-x);\n return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy\n }\n static fromHex(hex, zip215) {\n return Point.fromBytes(hexToBytes(hex), zip215);\n }\n get x() {\n return this.toAffine().x;\n }\n get y() {\n return this.toAffine().y;\n }\n /** Checks if the point is valid and on-curve. */\n assertValidity() {\n const a = _a;\n const d = _d;\n const p = this;\n if (p.is0())\n return err('bad point: ZERO'); // TODO: optimize, with vars below?\n // Equation in affine coordinates: ax\u00B2 + y\u00B2 = 1 + dx\u00B2y\u00B2\n // Equation in projective coordinates (X/Z, Y/Z, Z): (aX\u00B2 + Y\u00B2)Z\u00B2 = Z\u2074 + dX\u00B2Y\u00B2\n const { X, Y, Z, T } = p;\n const X2 = M(X * X); // X\u00B2\n const Y2 = M(Y * Y); // Y\u00B2\n const Z2 = M(Z * Z); // Z\u00B2\n const Z4 = M(Z2 * Z2); // Z\u2074\n const aX2 = M(X2 * a); // aX\u00B2\n const left = M(Z2 * M(aX2 + Y2)); // (aX\u00B2 + Y\u00B2)Z\u00B2\n const right = M(Z4 + M(d * M(X2 * Y2))); // Z\u2074 + dX\u00B2Y\u00B2\n if (left !== right)\n return err('bad point: equation left != right (1)');\n // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T\n const XY = M(X * Y);\n const ZT = M(Z * T);\n if (XY !== ZT)\n return err('bad point: equation left != right (2)');\n return this;\n }\n /** Equality check: compare points P&Q. */\n equals(other) {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality\n const X1Z2 = M(X1 * Z2);\n const X2Z1 = M(X2 * Z1);\n const Y1Z2 = M(Y1 * Z2);\n const Y2Z1 = M(Y2 * Z1);\n return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;\n }\n is0() {\n return this.equals(I);\n }\n /** Flip point over y coordinate. */\n negate() {\n return new Point(M(-this.X), this.Y, this.Z, M(-this.T));\n }\n /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */\n double() {\n const { X: X1, Y: Y1, Z: Z1 } = this;\n const a = _a;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd\n const A = M(X1 * X1);\n const B = M(Y1 * Y1);\n const C = M(2n * M(Z1 * Z1));\n const D = M(a * A);\n const x1y1 = X1 + Y1;\n const E = M(M(x1y1 * x1y1) - A - B);\n const G = D + B;\n const F = G - C;\n const H = D - B;\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */\n add(other) {\n const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;\n const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve\n const a = _a;\n const d = _d;\n // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3\n const A = M(X1 * X2);\n const B = M(Y1 * Y2);\n const C = M(T1 * d * T2);\n const D = M(Z1 * Z2);\n const E = M((X1 + Y1) * (X2 + Y2) - A - B);\n const F = M(D - C);\n const G = M(D + C);\n const H = M(B - a * A);\n const X3 = M(E * F);\n const Y3 = M(G * H);\n const T3 = M(E * H);\n const Z3 = M(F * G);\n return new Point(X3, Y3, Z3, T3);\n }\n subtract(other) {\n return this.add(apoint(other).negate());\n }\n /**\n * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.\n * Uses {@link wNAF} for base point.\n * Uses fake point to mitigate side-channel leakage.\n * @param n scalar by which point is multiplied\n * @param safe safe mode guards against timing attacks; unsafe mode is faster\n */\n multiply(n, safe = true) {\n if (!safe && (n === 0n || this.is0()))\n return I;\n assertRange(n, 1n, N);\n if (n === 1n)\n return this;\n if (this.equals(G))\n return wNAF(n).p;\n // init result point & fake point\n let p = I;\n let f = G;\n for (let d = this; n > 0n; d = d.double(), n >>= 1n) {\n // if bit is present, add to point\n // if not present, add to fake, for timing safety\n if (n & 1n)\n p = p.add(d);\n else if (safe)\n f = f.add(d);\n }\n return p;\n }\n multiplyUnsafe(scalar) {\n return this.multiply(scalar, false);\n }\n /** Convert point to 2d xy affine point. (X, Y, Z) \u220B (x=X/Z, y=Y/Z) */\n toAffine() {\n const { X, Y, Z } = this;\n // fast-paths for ZERO point OR Z=1\n if (this.equals(I))\n return { x: 0n, y: 1n };\n const iz = invert(Z, P);\n // (Z * Z^-1) must be 1, otherwise bad math\n if (M(Z * iz) !== 1n)\n err('invalid inverse');\n // x = X*Z^-1; y = Y*Z^-1\n const x = M(X * iz);\n const y = M(Y * iz);\n return { x, y };\n }\n toBytes() {\n const { x, y } = this.assertValidity().toAffine();\n const b = numTo32bLE(y);\n // store sign in first LE byte\n b[31] |= x & 1n ? 0x80 : 0;\n return b;\n }\n toHex() {\n return bytesToHex(this.toBytes());\n }\n clearCofactor() {\n return this.multiply(big(h), false);\n }\n isSmallOrder() {\n return this.clearCofactor().is0();\n }\n isTorsionFree() {\n // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`\n let p = this.multiply(N / 2n, false).double();\n if (N % 2n)\n p = p.add(this);\n return p.is0();\n }\n}\n/** Generator / base point */\nconst G = new Point(Gx, Gy, 1n, M(Gx * Gy));\n/** Identity / zero point */\nconst I = new Point(0n, 1n, 1n, 0n);\n// Static aliases\nPoint.BASE = G;\nPoint.ZERO = I;\nconst numTo32bLE = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse();\nconst bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));\nconst pow2 = (x, power) => {\n // pow2(x, 4) == x^(2^4)\n let r = x;\n while (power-- > 0n) {\n r *= r;\n r %= P;\n }\n return r;\n};\n// prettier-ignore\nconst pow_2_252_3 = (x) => {\n const x2 = (x * x) % P; // x^2, bits 1\n const b2 = (x2 * x) % P; // x^3, bits 11\n const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111\n const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111\n const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)\n const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)\n const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)\n const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)\n const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)\n const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)\n const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)\n const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.\n return { pow_p_5_8, b2 };\n};\nconst RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // \u221A-1\n// for sqrt comp\n// prettier-ignore\nconst uvRatio = (u, v) => {\n const v3 = M(v * v * v); // v\u00B3\n const v7 = M(v3 * v3 * v); // v\u2077\n const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv\u2077)^(p-5)/8\n let x = M(u * v3 * pow); // (uv\u00B3)(uv\u2077)^(p-5)/8\n const vx2 = M(v * x * x); // vx\u00B2\n const root1 = x; // First root candidate\n const root2 = M(x * RM1); // Second root candidate; RM1 is \u221A-1\n const useRoot1 = vx2 === u; // If vx\u00B2 = u (mod p), x is a square root\n const useRoot2 = vx2 === M(-u); // If vx\u00B2 = -u, set x <-- x * 2^((p-1)/4)\n const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx\u00B2 = -u\u221A-1\n if (useRoot1)\n x = root1;\n if (useRoot2 || noRoot)\n x = root2; // We return root2 anyway, for const-time\n if ((M(x) & 1n) === 1n)\n x = M(-x); // edIsNegative\n return { isValid: useRoot1 || useRoot2, value: x };\n};\n// N == L, just weird naming\nconst modL_LE = (hash) => modN(bytesToNumLE(hash)); // modulo L; but little-endian\n/** hashes.sha512 should conform to the interface. */\n// TODO: rename\nconst sha512a = (...m) => hashes.sha512Async(concatBytes(...m)); // Async SHA512\nconst sha512s = (...m) => callHash('sha512')(concatBytes(...m));\n// RFC8032 5.1.5\nconst hash2extK = (hashed) => {\n // slice creates a copy, unlike subarray\n const head = hashed.slice(0, L);\n head[0] &= 248; // Clamp bits: 0b1111_1000\n head[31] &= 127; // 0b0111_1111\n head[31] |= 64; // 0b0100_0000\n const prefix = hashed.slice(L, L2); // secret key \"prefix\"\n const scalar = modL_LE(head); // modular division over curve order\n const point = G.multiply(scalar); // public key point\n const pointBytes = point.toBytes(); // point serialized to Uint8Array\n return { head, prefix, scalar, point, pointBytes };\n};\n// RFC8032 5.1.5; getPublicKey async, sync. Hash priv key and extract point.\nconst getExtendedPublicKeyAsync = (secretKey) => sha512a(abytes(secretKey, L)).then(hash2extK);\nconst getExtendedPublicKey = (secretKey) => hash2extK(sha512s(abytes(secretKey, L)));\n/** Creates 32-byte ed25519 public key from 32-byte secret key. Async. */\nconst getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);\n/** Creates 32-byte ed25519 public key from 32-byte secret key. To use, set `hashes.sha512` first. */\nconst getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;\nconst hashFinishA = (res) => sha512a(res.hashable).then(res.finish);\nconst hashFinishS = (res) => res.finish(sha512s(res.hashable));\n// Code, shared between sync & async sign\nconst _sign = (e, rBytes, msg) => {\n const { pointBytes: P, scalar: s } = e;\n const r = modL_LE(rBytes); // r was created outside, reduce it modulo L\n const R = G.multiply(r).toBytes(); // R = [r]B\n const hashable = concatBytes(R, P, msg); // dom2(F, C) || R || A || PH(M)\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l\n return abytes(concatBytes(R, numTo32bLE(S)), L2); // 64-byte sig: 32b R.x + 32b LE(S)\n };\n return { hashable, finish };\n};\n/**\n * Signs message using secret key. Async.\n * Follows RFC8032 5.1.6.\n */\nconst signAsync = async (message, secretKey) => {\n const m = abytes(message);\n const e = await getExtendedPublicKeyAsync(secretKey);\n const rBytes = await sha512a(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishA(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\n/**\n * Signs message using secret key. To use, set `hashes.sha512` first.\n * Follows RFC8032 5.1.6.\n */\nconst sign = (message, secretKey) => {\n const m = abytes(message);\n const e = getExtendedPublicKey(secretKey);\n const rBytes = sha512s(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))\n return hashFinishS(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature\n};\nconst defaultVerifyOpts = { zip215: true };\nconst _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {\n sig = abytes(sig, L2); // Signature hex str/Bytes, must be 64 bytes\n msg = abytes(msg); // Message hex str/Bytes\n pub = abytes(pub, L);\n const { zip215 } = opts; // switch between zip215 and rfc8032 verif\n let A;\n let R;\n let s;\n let SB;\n let hashable = Uint8Array.of();\n try {\n A = Point.fromBytes(pub, zip215); // public key A decoded\n R = Point.fromBytes(sig.slice(0, L), zip215); // 0 <= R < 2^256: ZIP215 R can be >= P\n s = bytesToNumLE(sig.slice(L, L2)); // Decode second half as an integer S\n SB = G.multiply(s, false); // in the range 0 <= s < L\n hashable = concatBytes(R.toBytes(), A.toBytes(), msg); // dom2(F, C) || R || A || PH(M)\n }\n catch (error) { }\n const finish = (hashed) => {\n // k = SHA512(dom2(F, C) || R || A || PH(M))\n if (SB == null)\n return false; // false if try-catch catched an error\n if (!zip215 && A.isSmallOrder())\n return false; // false for SBS: Strongly Binding Signature\n const k = modL_LE(hashed); // decode in little-endian, modulo L\n const RkA = R.add(A.multiply(k, false)); // [8]R + [8][k]A'\n return RkA.add(SB.negate()).clearCofactor().is0(); // [8][S]B = [8]R + [8][k]A'\n };\n return { hashable, finish };\n};\n/** Verifies signature on message and public key. Async. Follows RFC8032 5.1.7. */\nconst verifyAsync = async (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishA(_verify(signature, message, publicKey, opts));\n/** Verifies signature on message and public key. To use, set `hashes.sha512` first. Follows RFC8032 5.1.7. */\nconst verify = (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishS(_verify(signature, message, publicKey, opts));\n/** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */\nconst etc = {\n bytesToHex: bytesToHex,\n hexToBytes: hexToBytes,\n concatBytes: concatBytes,\n mod: M,\n invert: invert,\n randomBytes: randomBytes,\n};\nconst hashes = {\n sha512Async: async (message) => {\n const s = subtle();\n const m = concatBytes(message);\n return u8n(await s.digest('SHA-512', m.buffer));\n },\n sha512: undefined,\n};\n// FIPS 186 B.4.1 compliant key generation produces private keys\n// with modulo bias being neglible. takes >N+16 bytes, returns (hash mod n-1)+1\nconst randomSecretKey = (seed = randomBytes(L)) => seed;\nconst keygen = (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = getPublicKey(secretKey);\n return { secretKey, publicKey };\n};\nconst keygenAsync = async (seed) => {\n const secretKey = randomSecretKey(seed);\n const publicKey = await getPublicKeyAsync(secretKey);\n return { secretKey, publicKey };\n};\n/** ed25519-specific key utilities. */\nconst utils = {\n getExtendedPublicKeyAsync: getExtendedPublicKeyAsync,\n getExtendedPublicKey: getExtendedPublicKey,\n randomSecretKey: randomSecretKey,\n};\n// ## Precomputes\n// --------------\nconst W = 8; // W is window size\nconst scalarBits = 256;\nconst pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8, NOT 32 - see wNAF loop\nconst pwindowSize = 2 ** (W - 1); // 128 for W=8\nconst precompute = () => {\n const points = [];\n let p = G;\n let b = p;\n for (let w = 0; w < pwindows; w++) {\n b = p;\n points.push(b);\n for (let i = 1; i < pwindowSize; i++) {\n b = b.add(p);\n points.push(b);\n } // i=1, bc we skip 0\n p = b.double();\n }\n return points;\n};\nlet Gpows = undefined; // precomputes for base point G\n// const-time negate\nconst ctneg = (cnd, p) => {\n const n = p.negate();\n return cnd ? n : p;\n};\n/**\n * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by\n * caching multiples of G (base point). Cache is stored in 32MB of RAM.\n * Any time `G.multiply` is done, precomputes are used.\n * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.\n *\n * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,\n * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.\n *\n * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().\n */\nconst wNAF = (n) => {\n const comp = Gpows || (Gpows = precompute());\n let p = I;\n let f = G; // f must be G, or could become I in the end\n const pow_2_w = 2 ** W; // 256 for W=8\n const maxNum = pow_2_w; // 256 for W=8\n const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111\n const shiftBy = big(W); // 8 for W=8\n for (let w = 0; w < pwindows; w++) {\n let wbits = Number(n & mask); // extract W bits.\n n >>= shiftBy; // shift number by W bits.\n // We use negative indexes to reduce size of precomputed table by 2x.\n // Instead of needing precomputes 0..256, we only calculate them for 0..128.\n // If an index > 128 is found, we do (256-index) - where 256 is next window.\n // Naive: index +127 => 127, +224 => 224\n // Optimized: index +127 => 127, +224 => 256-32\n if (wbits > pwindowSize) {\n wbits -= maxNum;\n n += 1n;\n }\n const off = w * pwindowSize;\n const offF = off; // offsets, evaluate both\n const offP = off + Math.abs(wbits) - 1;\n const isEven = w % 2 !== 0; // conditions, evaluate both\n const isNeg = wbits < 0;\n if (wbits === 0) {\n // off == I: can't add it. Adding random offF instead.\n f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point\n }\n else {\n p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point\n }\n }\n if (n !== 0n)\n err('invalid wnaf');\n return { p, f }; // return both real and fake points for JIT\n};\n// !! Remove the export to easily use in REPL / browser console\nexport { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };\n", "/**\n * Crypto utilities for Ed25519-based authentication\n * Uses @noble/ed25519 for Ed25519 signature verification\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n */\n\nimport * as ed25519 from '@noble/ed25519';\n\n// Set SHA-512 hash function for ed25519 (required in @noble/ed25519 v3+)\n// Uses Web Crypto API (compatible with both Node.js and Cloudflare Workers)\ned25519.hashes.sha512Async = async (message: Uint8Array) => {\n return new Uint8Array(await crypto.subtle.digest('SHA-512', message as BufferSource));\n};\n\n// Username validation\nconst USERNAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;\nconst USERNAME_MIN_LENGTH = 3;\nconst USERNAME_MAX_LENGTH = 32;\n\n// Timestamp validation (5 minutes tolerance)\nconst TIMESTAMP_TOLERANCE_MS = 5 * 60 * 1000;\n\n/**\n * Generates an anonymous username for users who don't want to claim one\n * Format: anon-{timestamp}-{random}\n * This reduces collision probability to near-zero\n */\nexport function generateAnonymousUsername(): string {\n const timestamp = Date.now().toString(36);\n const random = crypto.getRandomValues(new Uint8Array(3));\n const hex = Array.from(random).map(b => b.toString(16).padStart(2, '0')).join('');\n return `anon-${timestamp}-${hex}`;\n}\n\n/**\n * Convert Uint8Array to base64 string\n */\nfunction bytesToBase64(bytes: Uint8Array): string {\n const binString = Array.from(bytes, (byte) =>\n String.fromCodePoint(byte)\n ).join('');\n return btoa(binString);\n}\n\n/**\n * Convert base64 string to Uint8Array\n */\nfunction base64ToBytes(base64: string): Uint8Array {\n const binString = atob(base64);\n return Uint8Array.from(binString, (char) => char.codePointAt(0)!);\n}\n\n/**\n * Validates a generic auth message format\n * Expected format: action:username:params:timestamp\n * Validates that the message contains the expected username and has a valid timestamp\n */\nexport function validateAuthMessage(\n expectedUsername: string,\n message: string\n): { valid: boolean; error?: string } {\n const parts = message.split(':');\n\n if (parts.length < 3) {\n return { valid: false, error: 'Invalid message format: must have at least action:username:timestamp' };\n }\n\n // Extract username (second part) and timestamp (last part)\n const messageUsername = parts[1];\n const timestamp = parseInt(parts[parts.length - 1], 10);\n\n // Validate username matches\n if (messageUsername !== expectedUsername) {\n return { valid: false, error: 'Username in message does not match authenticated username' };\n }\n\n // Validate timestamp\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n return { valid: true };\n}\n\n// ===== Username and Ed25519 Signature Utilities =====\n\n/**\n * Validates username format\n * Rules: 3-32 chars, lowercase alphanumeric + dash, must start/end with alphanumeric\n */\nexport function validateUsername(username: string): { valid: boolean; error?: string } {\n if (typeof username !== 'string') {\n return { valid: false, error: 'Username must be a string' };\n }\n\n if (username.length < USERNAME_MIN_LENGTH) {\n return { valid: false, error: `Username must be at least ${USERNAME_MIN_LENGTH} characters` };\n }\n\n if (username.length > USERNAME_MAX_LENGTH) {\n return { valid: false, error: `Username must be at most ${USERNAME_MAX_LENGTH} characters` };\n }\n\n if (!USERNAME_REGEX.test(username)) {\n return { valid: false, error: 'Username must be lowercase alphanumeric with optional dashes, and start/end with alphanumeric' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates service FQN format (service:version@username or service:version)\n * Service name: lowercase alphanumeric with dots/dashes (e.g., chat, file-share, com.example.chat)\n * Version: semantic versioning (1.0.0, 2.1.3-beta, etc.)\n * Username: optional, lowercase alphanumeric with dashes\n */\nexport function validateServiceFqn(fqn: string): { valid: boolean; error?: string } {\n if (typeof fqn !== 'string') {\n return { valid: false, error: 'Service FQN must be a string' };\n }\n\n // Parse the FQN\n const parsed = parseServiceFqn(fqn);\n if (!parsed) {\n return { valid: false, error: 'Service FQN must be in format: service:version[@username]' };\n }\n\n const { serviceName, version, username } = parsed;\n\n // Validate service name (alphanumeric with dots/dashes)\n const serviceNameRegex = /^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/;\n if (!serviceNameRegex.test(serviceName)) {\n return { valid: false, error: 'Service name must be lowercase alphanumeric with optional dots/dashes' };\n }\n\n if (serviceName.length < 1 || serviceName.length > 128) {\n return { valid: false, error: 'Service name must be 1-128 characters' };\n }\n\n // Validate version (semantic versioning)\n const versionRegex = /^[0-9]+\\.[0-9]+\\.[0-9]+(-[a-z0-9.-]+)?$/;\n if (!versionRegex.test(version)) {\n return { valid: false, error: 'Version must be semantic versioning (e.g., 1.0.0, 2.1.3-beta)' };\n }\n\n // Validate username if present\n if (username) {\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n }\n\n return { valid: true };\n}\n\n/**\n * Parse semantic version string into components\n */\nexport function parseVersion(version: string): { major: number; minor: number; patch: number; prerelease?: string } | null {\n const match = version.match(/^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-[a-z0-9.-]+)?$/);\n if (!match) return null;\n\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n prerelease: match[4]?.substring(1), // Remove leading dash\n };\n}\n\n/**\n * Check if two versions are compatible (same major version)\n * Following semver rules: ^1.0.0 matches 1.x.x but not 2.x.x\n */\nexport function isVersionCompatible(requested: string, available: string): boolean {\n const req = parseVersion(requested);\n const avail = parseVersion(available);\n\n if (!req || !avail) return false;\n\n // Major version must match\n if (req.major !== avail.major) return false;\n\n // If major is 0, minor must also match (0.x.y is unstable)\n if (req.major === 0 && req.minor !== avail.minor) return false;\n\n // Available version must be >= requested version\n if (avail.minor < req.minor) return false;\n if (avail.minor === req.minor && avail.patch < req.patch) return false;\n\n // Prerelease versions are only compatible with exact matches\n if (req.prerelease && req.prerelease !== avail.prerelease) return false;\n\n return true;\n}\n\n/**\n * Parse service FQN into components\n * Formats supported:\n * - service:version@username (e.g., \"chat:1.0.0@alice\")\n * - service:version (e.g., \"chat:1.0.0\") for discovery\n */\nexport function parseServiceFqn(fqn: string): { serviceName: string; version: string; username: string | null } | null {\n if (!fqn || typeof fqn !== 'string') return null;\n\n // Check if username is present\n const atIndex = fqn.lastIndexOf('@');\n let serviceVersion: string;\n let username: string | null = null;\n\n if (atIndex > 0) {\n // Format: service:version@username\n serviceVersion = fqn.substring(0, atIndex);\n username = fqn.substring(atIndex + 1);\n } else {\n // Format: service:version (no username)\n serviceVersion = fqn;\n }\n\n // Split service:version\n const colonIndex = serviceVersion.indexOf(':');\n if (colonIndex <= 0) return null; // No colon or colon at start\n\n const serviceName = serviceVersion.substring(0, colonIndex);\n const version = serviceVersion.substring(colonIndex + 1);\n\n if (!serviceName || !version) return null;\n\n return {\n serviceName,\n version,\n username,\n };\n}\n\n/**\n * Validates timestamp is within acceptable range (prevents replay attacks)\n */\nexport function validateTimestamp(timestamp: number): { valid: boolean; error?: string } {\n if (typeof timestamp !== 'number' || !Number.isFinite(timestamp)) {\n return { valid: false, error: 'Timestamp must be a finite number' };\n }\n\n const now = Date.now();\n const diff = Math.abs(now - timestamp);\n\n if (diff > TIMESTAMP_TOLERANCE_MS) {\n return { valid: false, error: `Timestamp too old or too far in future (tolerance: ${TIMESTAMP_TOLERANCE_MS / 1000}s)` };\n }\n\n return { valid: true };\n}\n\n/**\n * Verifies Ed25519 signature\n * @param publicKey Base64-encoded Ed25519 public key (32 bytes)\n * @param signature Base64-encoded Ed25519 signature (64 bytes)\n * @param message Message that was signed (UTF-8 string)\n * @returns true if signature is valid, false otherwise\n */\nexport async function verifyEd25519Signature(\n publicKey: string,\n signature: string,\n message: string\n): Promise<boolean> {\n try {\n // Decode base64 to bytes\n const publicKeyBytes = base64ToBytes(publicKey);\n const signatureBytes = base64ToBytes(signature);\n\n // Encode message as UTF-8\n const encoder = new TextEncoder();\n const messageBytes = encoder.encode(message);\n\n // Verify signature using @noble/ed25519 (async version)\n const isValid = await ed25519.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);\n return isValid;\n } catch (err) {\n console.error('Ed25519 signature verification failed:', err);\n return false;\n }\n}\n\n/**\n * Validates a username claim request\n * Verifies format, timestamp, and signature\n */\nexport async function validateUsernameClaim(\n username: string,\n publicKey: string,\n signature: string,\n message: string\n): Promise<{ valid: boolean; error?: string }> {\n // Validate username format\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n\n // Parse message format: \"claim:{username}:{timestamp}\"\n const parts = message.split(':');\n if (parts.length !== 3 || parts[0] !== 'claim' || parts[1] !== username) {\n return { valid: false, error: 'Invalid message format (expected: claim:{username}:{timestamp})' };\n }\n\n const timestamp = parseInt(parts[2], 10);\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n // Validate timestamp\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n // Verify signature\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n return { valid: true };\n}\n\n/**\n * Validates a service publish signature\n * Message format: publish:{username}:{serviceFqn}:{timestamp}\n */\nexport async function validateServicePublish(\n username: string,\n serviceFqn: string,\n publicKey: string,\n signature: string,\n message: string\n): Promise<{ valid: boolean; error?: string }> {\n // Validate username format\n const usernameCheck = validateUsername(username);\n if (!usernameCheck.valid) {\n return usernameCheck;\n }\n\n // Parse message format: \"publish:{username}:{serviceFqn}:{timestamp}\"\n // Note: serviceFqn can contain colons (e.g., \"chat:2.0.0@user\"), so we need careful parsing\n const parts = message.split(':');\n if (parts.length < 4 || parts[0] !== 'publish' || parts[1] !== username) {\n return { valid: false, error: 'Invalid message format (expected: publish:{username}:{serviceFqn}:{timestamp})' };\n }\n\n // The timestamp is the last part\n const timestamp = parseInt(parts[parts.length - 1], 10);\n if (isNaN(timestamp)) {\n return { valid: false, error: 'Invalid timestamp in message' };\n }\n\n // The serviceFqn is everything between username and timestamp\n const extractedServiceFqn = parts.slice(2, parts.length - 1).join(':');\n if (extractedServiceFqn !== serviceFqn) {\n return { valid: false, error: `Service FQN mismatch (expected: ${serviceFqn}, got: ${extractedServiceFqn})` };\n }\n\n // Validate timestamp\n const timestampCheck = validateTimestamp(timestamp);\n if (!timestampCheck.valid) {\n return timestampCheck;\n }\n\n // Verify signature\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n return { valid: true };\n}\n", "import { Context } from 'hono';\nimport { Storage } from './storage/types.ts';\nimport { Config } from './config.ts';\nimport {\n validateUsernameClaim,\n validateServicePublish,\n validateServiceFqn,\n parseServiceFqn,\n isVersionCompatible,\n verifyEd25519Signature,\n validateAuthMessage,\n validateUsername,\n} from './crypto.ts';\n\n// Constants\nconst MAX_PAGE_SIZE = 100;\n\n/**\n * RPC request format\n */\nexport interface RpcRequest {\n method: string;\n message: string;\n signature: string;\n publicKey?: string; // Optional: for auto-claiming usernames\n params?: any;\n}\n\n/**\n * RPC response format\n */\nexport interface RpcResponse {\n success: boolean;\n result?: any;\n error?: string;\n}\n\n/**\n * RPC method handler\n */\ntype RpcHandler = (\n params: any,\n message: string,\n signature: string,\n publicKey: string | undefined,\n storage: Storage,\n config: Config\n) => Promise<any>;\n\n/**\n * Verify authentication for a method call\n * Automatically claims username if it doesn't exist\n */\nasync function verifyAuth(\n username: string,\n message: string,\n signature: string,\n publicKey: string | undefined,\n storage: Storage\n): Promise<{ valid: boolean; error?: string }> {\n // Get username record to fetch public key\n let usernameRecord = await storage.getUsername(username);\n\n // Auto-claim username if it doesn't exist\n if (!usernameRecord) {\n if (!publicKey) {\n return {\n valid: false,\n error: `Username \"${username}\" is not claimed and no public key provided for auto-claim.`,\n };\n }\n\n // Validate username format before claiming\n const usernameValidation = validateUsername(username);\n if (!usernameValidation.valid) {\n return usernameValidation;\n }\n\n // Verify signature against the current message (not a claim message)\n const signatureValid = await verifyEd25519Signature(publicKey, signature, message);\n if (!signatureValid) {\n return { valid: false, error: 'Invalid signature for auto-claim' };\n }\n\n // Auto-claim the username\n const expiresAt = Date.now() + 365 * 24 * 60 * 60 * 1000; // 365 days\n await storage.claimUsername({\n username,\n publicKey,\n expiresAt,\n });\n\n usernameRecord = await storage.getUsername(username);\n if (!usernameRecord) {\n return { valid: false, error: 'Failed to claim username' };\n }\n }\n\n // Verify Ed25519 signature\n const isValid = await verifyEd25519Signature(\n usernameRecord.publicKey,\n signature,\n message\n );\n if (!isValid) {\n return { valid: false, error: 'Invalid signature' };\n }\n\n // Validate message format and timestamp\n const validation = validateAuthMessage(username, message);\n if (!validation.valid) {\n return { valid: false, error: validation.error };\n }\n\n return { valid: true };\n}\n\n/**\n * Extract username from message\n */\nfunction extractUsername(message: string): string | null {\n // Message format: method:username:...\n const parts = message.split(':');\n if (parts.length < 2) return null;\n return parts[1];\n}\n\n/**\n * RPC Method Handlers\n */\n\nconst handlers: Record<string, RpcHandler> = {\n /**\n * Check if username is available\n */\n async getUser(params, message, signature, publicKey, storage, config) {\n const { username } = params;\n const claimed = await storage.getUsername(username);\n\n if (!claimed) {\n return {\n username,\n available: true,\n };\n }\n\n return {\n username: claimed.username,\n available: false,\n claimedAt: claimed.claimedAt,\n expiresAt: claimed.expiresAt,\n publicKey: claimed.publicKey,\n };\n },\n\n /**\n * Get service by FQN - Supports 3 modes:\n * 1. Direct lookup: FQN includes @username\n * 2. Paginated discovery: FQN without @username, with limit/offset\n * 3. Random discovery: FQN without @username, no limit\n */\n async getService(params, message, signature, publicKey, storage, config) {\n const { serviceFqn, limit, offset } = params;\n const username = extractUsername(message);\n\n // Verify authentication\n if (username) {\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n }\n\n // Parse and validate FQN\n const fqnValidation = validateServiceFqn(serviceFqn);\n if (!fqnValidation.valid) {\n throw new Error(fqnValidation.error || 'Invalid service FQN');\n }\n\n const parsed = parseServiceFqn(serviceFqn);\n if (!parsed) {\n throw new Error('Failed to parse service FQN');\n }\n\n // Helper: Filter services by version compatibility\n const filterCompatibleServices = (services) => {\n return services.filter((s) => {\n const serviceVersion = parseServiceFqn(s.serviceFqn);\n return (\n serviceVersion &&\n isVersionCompatible(parsed.version, serviceVersion.version)\n );\n });\n };\n\n // Helper: Find available offer for service\n const findAvailableOffer = async (service) => {\n const offers = await storage.getOffersForService(service.id);\n return offers.find((o) => !o.answererUsername);\n };\n\n // Helper: Build service response object\n const buildServiceResponse = (service, offer) => ({\n serviceId: service.id,\n username: service.username,\n serviceFqn: service.serviceFqn,\n offerId: offer.id,\n sdp: offer.sdp,\n createdAt: service.createdAt,\n expiresAt: service.expiresAt,\n });\n\n // Mode 1: Paginated discovery\n if (limit !== undefined) {\n const pageLimit = Math.min(Math.max(1, limit), MAX_PAGE_SIZE);\n const pageOffset = Math.max(0, offset || 0);\n\n const allServices = await storage.getServicesByName(parsed.service, parsed.version);\n const compatibleServices = filterCompatibleServices(allServices);\n\n // Get unique services per username with available offers\n const usernameSet = new Set<string>();\n const uniqueServices: any[] = [];\n\n for (const service of compatibleServices) {\n if (!usernameSet.has(service.username)) {\n usernameSet.add(service.username);\n const availableOffer = await findAvailableOffer(service);\n\n if (availableOffer) {\n uniqueServices.push(buildServiceResponse(service, availableOffer));\n }\n }\n }\n\n // Paginate results\n const paginatedServices = uniqueServices.slice(pageOffset, pageOffset + pageLimit);\n\n return {\n services: paginatedServices,\n count: paginatedServices.length,\n limit: pageLimit,\n offset: pageOffset,\n };\n }\n\n // Mode 2: Direct lookup with username\n if (parsed.username) {\n const service = await storage.getServiceByFqn(serviceFqn);\n if (!service) {\n throw new Error('Service not found');\n }\n\n const availableOffer = await findAvailableOffer(service);\n if (!availableOffer) {\n throw new Error('Service has no available offers');\n }\n\n return buildServiceResponse(service, availableOffer);\n }\n\n // Mode 3: Random discovery without username\n const allServices = await storage.getServicesByName(parsed.service, parsed.version);\n const compatibleServices = filterCompatibleServices(allServices);\n\n if (compatibleServices.length === 0) {\n throw new Error('No services found');\n }\n\n const randomService = compatibleServices[Math.floor(Math.random() * compatibleServices.length)];\n const availableOffer = await findAvailableOffer(randomService);\n\n if (!availableOffer) {\n throw new Error('Service has no available offers');\n }\n\n return buildServiceResponse(randomService, availableOffer);\n },\n\n /**\n * Publish a service\n */\n async publishService(params, message, signature, publicKey, storage, config) {\n const { serviceFqn, offers, ttl } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required for service publishing');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n // Validate service FQN\n const fqnValidation = validateServiceFqn(serviceFqn);\n if (!fqnValidation.valid) {\n throw new Error(fqnValidation.error || 'Invalid service FQN');\n }\n\n const parsed = parseServiceFqn(serviceFqn);\n if (!parsed || !parsed.username) {\n throw new Error('Service FQN must include username');\n }\n\n if (parsed.username !== username) {\n throw new Error('Service FQN username must match authenticated username');\n }\n\n // Validate offers\n if (!offers || !Array.isArray(offers) || offers.length === 0) {\n throw new Error('Must provide at least one offer');\n }\n\n if (offers.length > config.maxOffersPerRequest) {\n throw new Error(\n `Too many offers (max ${config.maxOffersPerRequest})`\n );\n }\n\n // Validate each offer has valid SDP\n offers.forEach((offer, index) => {\n if (!offer || typeof offer !== 'object') {\n throw new Error(`Invalid offer at index ${index}: must be an object`);\n }\n if (!offer.sdp || typeof offer.sdp !== 'string') {\n throw new Error(`Invalid offer at index ${index}: missing or invalid SDP`);\n }\n if (!offer.sdp.trim()) {\n throw new Error(`Invalid offer at index ${index}: SDP cannot be empty`);\n }\n });\n\n // Create service with offers\n const now = Date.now();\n const offerTtl =\n ttl !== undefined\n ? Math.min(\n Math.max(ttl, config.offerMinTtl),\n config.offerMaxTtl\n )\n : config.offerDefaultTtl;\n const expiresAt = now + offerTtl;\n\n // Prepare offer requests with TTL\n const offerRequests = offers.map(offer => ({\n username,\n serviceFqn,\n sdp: offer.sdp,\n expiresAt,\n }));\n\n const result = await storage.createService({\n serviceFqn,\n expiresAt,\n offers: offerRequests,\n });\n\n return {\n serviceId: result.service.id,\n username: result.service.username,\n serviceFqn: result.service.serviceFqn,\n offers: result.offers.map(offer => ({\n offerId: offer.id,\n sdp: offer.sdp,\n createdAt: offer.createdAt,\n expiresAt: offer.expiresAt,\n })),\n createdAt: result.service.createdAt,\n expiresAt: result.service.expiresAt,\n };\n },\n\n /**\n * Delete a service\n */\n async deleteService(params, message, signature, publicKey, storage, config) {\n const { serviceFqn } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n const parsed = parseServiceFqn(serviceFqn);\n if (!parsed || !parsed.username) {\n throw new Error('Service FQN must include username');\n }\n\n const service = await storage.getServiceByFqn(serviceFqn);\n if (!service) {\n throw new Error('Service not found');\n }\n\n const deleted = await storage.deleteService(service.id, username);\n if (!deleted) {\n throw new Error('Service not found or not owned by this username');\n }\n\n return { success: true };\n },\n\n /**\n * Answer an offer\n */\n async answerOffer(params, message, signature, publicKey, storage, config) {\n const { serviceFqn, offerId, sdp } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n if (!sdp || typeof sdp !== 'string' || sdp.length === 0) {\n throw new Error('Invalid SDP');\n }\n\n if (sdp.length > 64 * 1024) {\n throw new Error('SDP too large (max 64KB)');\n }\n\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n throw new Error('Offer not found');\n }\n\n if (offer.answererUsername) {\n throw new Error('Offer already answered');\n }\n\n await storage.answerOffer(offerId, username, sdp);\n\n return { success: true, offerId };\n },\n\n /**\n * Get answer for an offer\n */\n async getOfferAnswer(params, message, signature, publicKey, storage, config) {\n const { serviceFqn, offerId } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n throw new Error('Offer not found');\n }\n\n if (offer.username !== username) {\n throw new Error('Not authorized to access this offer');\n }\n\n if (!offer.answererUsername || !offer.answerSdp) {\n throw new Error('Offer not yet answered');\n }\n\n return {\n sdp: offer.answerSdp,\n offerId: offer.id,\n answererId: offer.answererUsername,\n answeredAt: offer.answeredAt,\n };\n },\n\n /**\n * Combined polling for answers and ICE candidates\n */\n async poll(params, message, signature, publicKey, storage, config) {\n const { since } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n const sinceTimestamp = since || 0;\n\n // Get all answered offers\n const answeredOffers = await storage.getAnsweredOffers(username);\n const filteredAnswers = answeredOffers.filter(\n (offer) => offer.answeredAt && offer.answeredAt > sinceTimestamp\n );\n\n // Get all user's offers\n const allOffers = await storage.getOffersByUsername(username);\n\n // For each offer, get ICE candidates from both sides\n const iceCandidatesByOffer: Record<string, any[]> = {};\n\n for (const offer of allOffers) {\n const offererCandidates = await storage.getIceCandidates(\n offer.id,\n 'offerer',\n sinceTimestamp\n );\n const answererCandidates = await storage.getIceCandidates(\n offer.id,\n 'answerer',\n sinceTimestamp\n );\n\n const allCandidates = [\n ...offererCandidates.map((c: any) => ({\n ...c,\n role: 'offerer' as const,\n })),\n ...answererCandidates.map((c: any) => ({\n ...c,\n role: 'answerer' as const,\n })),\n ];\n\n if (allCandidates.length > 0) {\n const isOfferer = offer.username === username;\n const filtered = allCandidates.filter((c) =>\n isOfferer ? c.role === 'answerer' : c.role === 'offerer'\n );\n\n if (filtered.length > 0) {\n iceCandidatesByOffer[offer.id] = filtered;\n }\n }\n }\n\n return {\n answers: filteredAnswers.map((offer) => ({\n offerId: offer.id,\n serviceId: offer.serviceId,\n answererId: offer.answererUsername,\n sdp: offer.answerSdp,\n answeredAt: offer.answeredAt,\n })),\n iceCandidates: iceCandidatesByOffer,\n };\n },\n\n /**\n * Add ICE candidates\n */\n async addIceCandidates(params, message, signature, publicKey, storage, config) {\n const { serviceFqn, offerId, candidates } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n if (!Array.isArray(candidates) || candidates.length === 0) {\n throw new Error('Missing or invalid required parameter: candidates');\n }\n\n // Validate each candidate is an object (don't enforce structure per CLAUDE.md)\n candidates.forEach((candidate, index) => {\n if (!candidate || typeof candidate !== 'object') {\n throw new Error(`Invalid candidate at index ${index}: must be an object`);\n }\n });\n\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n throw new Error('Offer not found');\n }\n\n const role = offer.username === username ? 'offerer' : 'answerer';\n const count = await storage.addIceCandidates(\n offerId,\n username,\n role,\n candidates\n );\n\n return { count, offerId };\n },\n\n /**\n * Get ICE candidates\n */\n async getIceCandidates(params, message, signature, publicKey, storage, config) {\n const { serviceFqn, offerId, since } = params;\n const username = extractUsername(message);\n\n if (!username) {\n throw new Error('Username required');\n }\n\n // Verify authentication\n const auth = await verifyAuth(username, message, signature, publicKey, storage);\n if (!auth.valid) {\n throw new Error(auth.error);\n }\n\n const sinceTimestamp = since || 0;\n\n const offer = await storage.getOfferById(offerId);\n if (!offer) {\n throw new Error('Offer not found');\n }\n\n const isOfferer = offer.username === username;\n const role = isOfferer ? 'answerer' : 'offerer';\n\n const candidates = await storage.getIceCandidates(\n offerId,\n role,\n sinceTimestamp\n );\n\n return {\n candidates: candidates.map((c: any) => ({\n candidate: c.candidate,\n createdAt: c.createdAt,\n })),\n offerId,\n };\n },\n};\n\n/**\n * Handle RPC batch request\n */\nexport async function handleRpc(\n requests: RpcRequest[],\n storage: Storage,\n config: Config\n): Promise<RpcResponse[]> {\n const responses: RpcResponse[] = [];\n\n for (const request of requests) {\n try {\n const { method, message, signature, publicKey, params } = request;\n\n // Validate request\n if (!method || typeof method !== 'string') {\n responses.push({\n success: false,\n error: 'Missing or invalid method',\n });\n continue;\n }\n\n if (!message || typeof message !== 'string') {\n responses.push({\n success: false,\n error: 'Missing or invalid message',\n });\n continue;\n }\n\n if (!signature || typeof signature !== 'string') {\n responses.push({\n success: false,\n error: 'Missing or invalid signature',\n });\n continue;\n }\n\n // Get handler\n const handler = handlers[method];\n if (!handler) {\n responses.push({\n success: false,\n error: `Unknown method: ${method}`,\n });\n continue;\n }\n\n // Execute handler\n const result = await handler(\n params || {},\n message,\n signature,\n publicKey,\n storage,\n config\n );\n\n responses.push({\n success: true,\n result,\n });\n } catch (err) {\n responses.push({\n success: false,\n error: (err as Error).message || 'Internal server error',\n });\n }\n }\n\n return responses;\n}\n", "/**\n * Application configuration\n * Reads from environment variables with sensible defaults\n */\nexport interface Config {\n port: number;\n storageType: 'sqlite' | 'memory';\n storagePath: string;\n corsOrigins: string[];\n version: string;\n offerDefaultTtl: number;\n offerMaxTtl: number;\n offerMinTtl: number;\n cleanupInterval: number;\n maxOffersPerRequest: number;\n}\n\n/**\n * Loads configuration from environment variables\n */\nexport function loadConfig(): Config {\n return {\n port: parseInt(process.env.PORT || '3000', 10),\n storageType: (process.env.STORAGE_TYPE || 'sqlite') as 'sqlite' | 'memory',\n storagePath: process.env.STORAGE_PATH || ':memory:',\n corsOrigins: process.env.CORS_ORIGINS\n ? process.env.CORS_ORIGINS.split(',').map(o => o.trim())\n : ['*'],\n version: process.env.VERSION || 'unknown',\n offerDefaultTtl: parseInt(process.env.OFFER_DEFAULT_TTL || '60000', 10),\n offerMaxTtl: parseInt(process.env.OFFER_MAX_TTL || '86400000', 10),\n offerMinTtl: parseInt(process.env.OFFER_MIN_TTL || '60000', 10),\n cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '60000', 10),\n maxOffersPerRequest: parseInt(process.env.MAX_OFFERS_PER_REQUEST || '100', 10)\n };\n}\n", "import Database from 'better-sqlite3';\nimport { randomUUID } from 'node:crypto';\nimport {\n Storage,\n Offer,\n IceCandidate,\n CreateOfferRequest,\n Username,\n ClaimUsernameRequest,\n Service,\n CreateServiceRequest,\n} from './types.ts';\nimport { generateOfferHash } from './hash-id.ts';\nimport { parseServiceFqn } from '../crypto.ts';\n\nconst YEAR_IN_MS = 365 * 24 * 60 * 60 * 1000; // 365 days\n\n/**\n * SQLite storage adapter for rondevu DNS-like system\n * Supports both file-based and in-memory databases\n */\nexport class SQLiteStorage implements Storage {\n private db: Database.Database;\n\n /**\n * Creates a new SQLite storage instance\n * @param path Path to SQLite database file, or ':memory:' for in-memory database\n */\n constructor(path: string = ':memory:') {\n this.db = new Database(path);\n this.initializeDatabase();\n }\n\n /**\n * Initializes database schema with username and service-based structure\n */\n private initializeDatabase(): void {\n this.db.exec(`\n -- WebRTC signaling offers\n CREATE TABLE IF NOT EXISTS offers (\n id TEXT PRIMARY KEY,\n username TEXT NOT NULL,\n service_id TEXT,\n sdp TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_seen INTEGER NOT NULL,\n answerer_username TEXT,\n answer_sdp TEXT,\n answered_at INTEGER,\n FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_offers_username ON offers(username);\n CREATE INDEX IF NOT EXISTS idx_offers_service ON offers(service_id);\n CREATE INDEX IF NOT EXISTS idx_offers_expires ON offers(expires_at);\n CREATE INDEX IF NOT EXISTS idx_offers_last_seen ON offers(last_seen);\n CREATE INDEX IF NOT EXISTS idx_offers_answerer ON offers(answerer_username);\n\n -- ICE candidates table\n CREATE TABLE IF NOT EXISTS ice_candidates (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offer_id TEXT NOT NULL,\n username TEXT NOT NULL,\n role TEXT NOT NULL CHECK(role IN ('offerer', 'answerer')),\n candidate TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n FOREIGN KEY (offer_id) REFERENCES offers(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_ice_offer ON ice_candidates(offer_id);\n CREATE INDEX IF NOT EXISTS idx_ice_username ON ice_candidates(username);\n CREATE INDEX IF NOT EXISTS idx_ice_created ON ice_candidates(created_at);\n\n -- Usernames table\n CREATE TABLE IF NOT EXISTS usernames (\n username TEXT PRIMARY KEY,\n public_key TEXT NOT NULL UNIQUE,\n claimed_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n last_used INTEGER NOT NULL,\n metadata TEXT,\n CHECK(length(username) >= 3 AND length(username) <= 32)\n );\n\n CREATE INDEX IF NOT EXISTS idx_usernames_expires ON usernames(expires_at);\n CREATE INDEX IF NOT EXISTS idx_usernames_public_key ON usernames(public_key);\n\n -- Services table (new schema with extracted fields for discovery)\n CREATE TABLE IF NOT EXISTS services (\n id TEXT PRIMARY KEY,\n service_fqn TEXT NOT NULL,\n service_name TEXT NOT NULL,\n version TEXT NOT NULL,\n username TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n FOREIGN KEY (username) REFERENCES usernames(username) ON DELETE CASCADE,\n UNIQUE(service_fqn)\n );\n\n CREATE INDEX IF NOT EXISTS idx_services_fqn ON services(service_fqn);\n CREATE INDEX IF NOT EXISTS idx_services_discovery ON services(service_name, version);\n CREATE INDEX IF NOT EXISTS idx_services_username ON services(username);\n CREATE INDEX IF NOT EXISTS idx_services_expires ON services(expires_at);\n `);\n\n // Enable foreign keys\n this.db.pragma('foreign_keys = ON');\n }\n\n // ===== Offer Management =====\n\n async createOffers(offers: CreateOfferRequest[]): Promise<Offer[]> {\n const created: Offer[] = [];\n\n // Generate hash-based IDs for all offers first\n const offersWithIds = await Promise.all(\n offers.map(async (offer) => ({\n ...offer,\n id: offer.id || await generateOfferHash(offer.sdp),\n }))\n );\n\n // Use transaction for atomic creation\n const transaction = this.db.transaction((offersWithIds: (CreateOfferRequest & { id: string })[]) => {\n const offerStmt = this.db.prepare(`\n INSERT INTO offers (id, username, service_id, sdp, created_at, expires_at, last_seen)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n\n for (const offer of offersWithIds) {\n const now = Date.now();\n\n // Insert offer\n offerStmt.run(\n offer.id,\n offer.username,\n offer.serviceId || null,\n offer.sdp,\n now,\n offer.expiresAt,\n now\n );\n\n created.push({\n id: offer.id,\n username: offer.username,\n serviceId: offer.serviceId || undefined,\n serviceFqn: offer.serviceFqn,\n sdp: offer.sdp,\n createdAt: now,\n expiresAt: offer.expiresAt,\n lastSeen: now,\n });\n }\n });\n\n transaction(offersWithIds);\n return created;\n }\n\n async getOffersByUsername(username: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE username = ? AND expires_at > ?\n ORDER BY last_seen DESC\n `);\n\n const rows = stmt.all(username, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n async getOfferById(offerId: string): Promise<Offer | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(offerId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToOffer(row);\n }\n\n async deleteOffer(offerId: string, ownerUsername: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM offers\n WHERE id = ? AND username = ?\n `);\n\n const result = stmt.run(offerId, ownerUsername);\n return result.changes > 0;\n }\n\n async deleteExpiredOffers(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM offers WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async answerOffer(\n offerId: string,\n answererUsername: string,\n answerSdp: string\n ): Promise<{ success: boolean; error?: string }> {\n // Check if offer exists and is not expired\n const offer = await this.getOfferById(offerId);\n\n if (!offer) {\n return {\n success: false,\n error: 'Offer not found or expired'\n };\n }\n\n // Check if offer already has an answerer\n if (offer.answererUsername) {\n return {\n success: false,\n error: 'Offer already answered'\n };\n }\n\n // Update offer with answer\n const stmt = this.db.prepare(`\n UPDATE offers\n SET answerer_username = ?, answer_sdp = ?, answered_at = ?\n WHERE id = ? AND answerer_username IS NULL\n `);\n\n const result = stmt.run(answererUsername, answerSdp, Date.now(), offerId);\n\n if (result.changes === 0) {\n return {\n success: false,\n error: 'Offer already answered (race condition)'\n };\n }\n\n return { success: true };\n }\n\n async getAnsweredOffers(offererUsername: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE username = ? AND answerer_username IS NOT NULL AND expires_at > ?\n ORDER BY answered_at DESC\n `);\n\n const rows = stmt.all(offererUsername, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n // ===== ICE Candidate Management =====\n\n async addIceCandidates(\n offerId: string,\n username: string,\n role: 'offerer' | 'answerer',\n candidates: any[]\n ): Promise<number> {\n const stmt = this.db.prepare(`\n INSERT INTO ice_candidates (offer_id, username, role, candidate, created_at)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n const baseTimestamp = Date.now();\n const transaction = this.db.transaction((candidates: any[]) => {\n for (let i = 0; i < candidates.length; i++) {\n stmt.run(\n offerId,\n username,\n role,\n JSON.stringify(candidates[i]),\n baseTimestamp + i\n );\n }\n });\n\n transaction(candidates);\n return candidates.length;\n }\n\n async getIceCandidates(\n offerId: string,\n targetRole: 'offerer' | 'answerer',\n since?: number\n ): Promise<IceCandidate[]> {\n let query = `\n SELECT * FROM ice_candidates\n WHERE offer_id = ? AND role = ?\n `;\n\n const params: any[] = [offerId, targetRole];\n\n if (since !== undefined) {\n query += ' AND created_at > ?';\n params.push(since);\n }\n\n query += ' ORDER BY created_at ASC';\n\n const stmt = this.db.prepare(query);\n const rows = stmt.all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n offerId: row.offer_id,\n username: row.username,\n role: row.role,\n candidate: JSON.parse(row.candidate),\n createdAt: row.created_at,\n }));\n }\n\n // ===== Username Management =====\n\n async claimUsername(request: ClaimUsernameRequest): Promise<Username> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n // Try to insert or update\n const stmt = this.db.prepare(`\n INSERT INTO usernames (username, public_key, claimed_at, expires_at, last_used, metadata)\n VALUES (?, ?, ?, ?, ?, NULL)\n ON CONFLICT(username) DO UPDATE SET\n expires_at = ?,\n last_used = ?\n WHERE public_key = ?\n `);\n\n const result = stmt.run(\n request.username,\n request.publicKey,\n now,\n expiresAt,\n now,\n expiresAt,\n now,\n request.publicKey\n );\n\n if (result.changes === 0) {\n throw new Error('Username already claimed by different public key');\n }\n\n return {\n username: request.username,\n publicKey: request.publicKey,\n claimedAt: now,\n expiresAt,\n lastUsed: now,\n };\n }\n\n async getUsername(username: string): Promise<Username | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM usernames\n WHERE username = ? AND expires_at > ?\n `);\n\n const row = stmt.get(username, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return {\n username: row.username,\n publicKey: row.public_key,\n claimedAt: row.claimed_at,\n expiresAt: row.expires_at,\n lastUsed: row.last_used,\n metadata: row.metadata || undefined,\n };\n }\n\n async touchUsername(username: string): Promise<boolean> {\n const now = Date.now();\n const expiresAt = now + YEAR_IN_MS;\n\n const stmt = this.db.prepare(`\n UPDATE usernames\n SET last_used = ?, expires_at = ?\n WHERE username = ? AND expires_at > ?\n `);\n\n const result = stmt.run(now, expiresAt, username, now);\n return result.changes > 0;\n }\n\n async deleteExpiredUsernames(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM usernames WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n // ===== Service Management =====\n\n async createService(request: CreateServiceRequest): Promise<{\n service: Service;\n offers: Offer[];\n }> {\n const serviceId = randomUUID();\n const now = Date.now();\n\n // Parse FQN to extract components\n const parsed = parseServiceFqn(request.serviceFqn);\n if (!parsed) {\n throw new Error(`Invalid service FQN: ${request.serviceFqn}`);\n }\n if (!parsed.username) {\n throw new Error(`Service FQN must include username: ${request.serviceFqn}`);\n }\n\n const { serviceName, version, username } = parsed;\n\n const transaction = this.db.transaction(() => {\n // Delete existing service with same (service_name, version, username) and its related offers (upsert behavior)\n const existingService = this.db.prepare(`\n SELECT id FROM services\n WHERE service_name = ? AND version = ? AND username = ?\n `).get(serviceName, version, username) as any;\n\n if (existingService) {\n // Delete related offers first (no FK cascade from offers to services)\n this.db.prepare(`\n DELETE FROM offers WHERE service_id = ?\n `).run(existingService.id);\n\n // Delete the service\n this.db.prepare(`\n DELETE FROM services WHERE id = ?\n `).run(existingService.id);\n }\n\n // Insert new service with extracted fields\n this.db.prepare(`\n INSERT INTO services (id, service_fqn, service_name, version, username, created_at, expires_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `).run(\n serviceId,\n request.serviceFqn,\n serviceName,\n version,\n username,\n now,\n request.expiresAt\n );\n\n // Touch username to extend expiry (inline logic)\n const expiresAt = now + YEAR_IN_MS;\n this.db.prepare(`\n UPDATE usernames\n SET last_used = ?, expires_at = ?\n WHERE username = ? AND expires_at > ?\n `).run(now, expiresAt, username, now);\n });\n\n transaction();\n\n // Create offers with serviceId (after transaction)\n const offerRequests = request.offers.map(offer => ({\n ...offer,\n serviceId,\n }));\n const offers = await this.createOffers(offerRequests);\n\n return {\n service: {\n id: serviceId,\n serviceFqn: request.serviceFqn,\n serviceName,\n version,\n username,\n createdAt: now,\n expiresAt: request.expiresAt,\n },\n offers,\n };\n }\n\n async getOffersForService(serviceId: string): Promise<Offer[]> {\n const stmt = this.db.prepare(`\n SELECT * FROM offers\n WHERE service_id = ? AND expires_at > ?\n ORDER BY created_at ASC\n `);\n\n const rows = stmt.all(serviceId, Date.now()) as any[];\n return rows.map(row => this.rowToOffer(row));\n }\n\n async getServiceById(serviceId: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM services\n WHERE id = ? AND expires_at > ?\n `);\n\n const row = stmt.get(serviceId, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async getServiceByFqn(serviceFqn: string): Promise<Service | null> {\n const stmt = this.db.prepare(`\n SELECT * FROM services\n WHERE service_fqn = ? AND expires_at > ?\n `);\n\n const row = stmt.get(serviceFqn, Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async discoverServices(\n serviceName: string,\n version: string,\n limit: number,\n offset: number\n ): Promise<Service[]> {\n // Query for unique services with available offers\n // We join with offers and filter for available ones (answerer_username IS NULL)\n const stmt = this.db.prepare(`\n SELECT DISTINCT s.* FROM services s\n INNER JOIN offers o ON o.service_id = s.id\n WHERE s.service_name = ?\n AND s.version = ?\n AND s.expires_at > ?\n AND o.answerer_username IS NULL\n AND o.expires_at > ?\n ORDER BY s.created_at DESC\n LIMIT ? OFFSET ?\n `);\n\n const rows = stmt.all(serviceName, version, Date.now(), Date.now(), limit, offset) as any[];\n return rows.map(row => this.rowToService(row));\n }\n\n async getRandomService(serviceName: string, version: string): Promise<Service | null> {\n // Get a random service with an available offer\n const stmt = this.db.prepare(`\n SELECT s.* FROM services s\n INNER JOIN offers o ON o.service_id = s.id\n WHERE s.service_name = ?\n AND s.version = ?\n AND s.expires_at > ?\n AND o.answerer_username IS NULL\n AND o.expires_at > ?\n ORDER BY RANDOM()\n LIMIT 1\n `);\n\n const row = stmt.get(serviceName, version, Date.now(), Date.now()) as any;\n\n if (!row) {\n return null;\n }\n\n return this.rowToService(row);\n }\n\n async deleteService(serviceId: string, username: string): Promise<boolean> {\n const stmt = this.db.prepare(`\n DELETE FROM services\n WHERE id = ? AND username = ?\n `);\n\n const result = stmt.run(serviceId, username);\n return result.changes > 0;\n }\n\n async deleteExpiredServices(now: number): Promise<number> {\n const stmt = this.db.prepare('DELETE FROM services WHERE expires_at < ?');\n const result = stmt.run(now);\n return result.changes;\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n\n // ===== Helper Methods =====\n\n /**\n * Helper method to convert database row to Offer object\n */\n private rowToOffer(row: any): Offer {\n return {\n id: row.id,\n username: row.username,\n serviceId: row.service_id || undefined,\n serviceFqn: row.service_fqn || undefined,\n sdp: row.sdp,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n lastSeen: row.last_seen,\n answererUsername: row.answerer_username || undefined,\n answerSdp: row.answer_sdp || undefined,\n answeredAt: row.answered_at || undefined,\n };\n }\n\n /**\n * Helper method to convert database row to Service object\n */\n private rowToService(row: any): Service {\n return {\n id: row.id,\n serviceFqn: row.service_fqn,\n serviceName: row.service_name,\n version: row.version,\n username: row.username,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n };\n }\n}\n", "/**\n * Generates a content-based offer ID using SHA-256 hash\n * Creates deterministic IDs based on offer SDP content\n * PeerID is not included as it's inferred from authentication\n * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers\n *\n * @param sdp - The WebRTC SDP offer\n * @returns SHA-256 hash of the SDP content\n */\nexport async function generateOfferHash(sdp: string): Promise<string> {\n // Sanitize and normalize the offer content\n // Only include core offer content (not peerId - that's inferred from auth)\n const sanitizedOffer = {\n sdp\n };\n\n // Create non-prettified JSON string\n const jsonString = JSON.stringify(sanitizedOffer);\n\n // Convert string to Uint8Array for hashing\n const encoder = new TextEncoder();\n const data = encoder.encode(jsonString);\n\n // Generate SHA-256 hash\n const hashBuffer = await crypto.subtle.digest('SHA-256', data);\n\n // Convert hash to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\n\n return hashHex;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["C", "G", "err", "allServices", "compatibleServices", "availableOffer", "err", "err", "Database", "offersWithIds", "candidates", "err"]
|
|
7
7
|
}
|