From 04178bff9047e8cf6aeaf96f8136afaf5ce84c44 Mon Sep 17 00:00:00 2001 From: YairEtzion Date: Tue, 31 Mar 2026 15:14:17 +0300 Subject: [PATCH] relay: migrate from Fastify to Bun.serve() native Replace Fastify v5 + @fastify/websocket + ws with Bun's native HTTP and WebSocket server. Drops 62 transitive dependencies from the relay package. - Rewrite server.ts to use Bun.serve() with native WebSocket handlers - Update session.ts types for Bun's ServerWebSocket - Switch tests from vitest to bun:test (relay must run under Bun runtime) - Update Dockerfile.relay: Node.js build stage + oven/bun:1.3-slim runtime - Remove fastify, @fastify/websocket, @fastify/rate-limit, ws, @types/ws - Add @types/bun for type definitions Tested: local Docker, Cloud Run deployment, health + WebSocket verified. --- Dockerfile.relay | 10 +- packages/relay/package.json | 17 +- .../__tests__/handshake.integration.test.ts | 19 +- packages/relay/src/index.ts | 1 + packages/relay/src/server.ts | 268 +++++----- packages/relay/src/session.ts | 9 +- packages/relay/src/start.ts | 8 +- pnpm-lock.yaml | 457 +----------------- 8 files changed, 190 insertions(+), 599 deletions(-) diff --git a/Dockerfile.relay b/Dockerfile.relay index 9a5a364..090d804 100644 --- a/Dockerfile.relay +++ b/Dockerfile.relay @@ -21,22 +21,20 @@ COPY packages/relay/tsconfig.json packages/relay/ # Build RUN pnpm build --filter=@authmesh/relay -# --- Production stage --- -FROM node:24-slim +# --- Production stage (Bun runtime) --- +FROM oven/bun:1.3-slim WORKDIR /app -COPY --from=build /app/package.json /app/pnpm-workspace.yaml /app/pnpm-lock.yaml ./ +# Only copy the built dist files — relay has zero external runtime deps COPY --from=build /app/packages/core/package.json packages/core/ COPY --from=build /app/packages/core/dist packages/core/dist COPY --from=build /app/packages/relay/package.json packages/relay/ COPY --from=build /app/packages/relay/dist packages/relay/dist -RUN corepack enable pnpm && pnpm install --frozen-lockfile --prod - EXPOSE 3001 ENV PORT=3001 ENV HOST=0.0.0.0 -CMD ["node", "packages/relay/dist/start.js"] +CMD ["bun", "packages/relay/dist/start.js"] diff --git a/packages/relay/package.json b/packages/relay/package.json index 82fde99..9485575 100644 --- a/packages/relay/package.json +++ b/packages/relay/package.json @@ -16,7 +16,7 @@ "relay", "websocket", "handshake", - "fastify", + "bun", "pairing" ], "publishConfig": { @@ -31,26 +31,21 @@ "files": ["dist"], "scripts": { "build": "tsc -b", - "test": "vitest run", - "test:watch": "vitest", + "test": "bun test src/__tests__/", + "test:watch": "bun test --watch src/__tests__/", "lint": "eslint src/", "lint:fix": "eslint src/ --fix", "clean": "rm -rf dist *.tsbuildinfo", - "start": "node dist/start.js" + "start": "bun dist/start.js" }, "dependencies": { - "@authmesh/core": "workspace:*", - "fastify": "^5.0.0", - "@fastify/websocket": "^11.0.0", - "ws": "^8.0.0", - "@fastify/rate-limit": "^10.0.0" + "@authmesh/core": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.0.0", "@noble/curves": "2.0.1", "@noble/hashes": "2.0.1", - "@types/node": "^22.0.0", - "@types/ws": "^8.0.0", + "@types/bun": "^1.3.0", "eslint": "^9.0.0", "typescript": "^5.7.0", "typescript-eslint": "^8.0.0", diff --git a/packages/relay/src/__tests__/handshake.integration.test.ts b/packages/relay/src/__tests__/handshake.integration.test.ts index 0793866..2cf5dfd 100644 --- a/packages/relay/src/__tests__/handshake.integration.test.ts +++ b/packages/relay/src/__tests__/handshake.integration.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { describe, it, expect, beforeAll, afterAll } from 'bun:test'; import { p256 } from '@noble/curves/nist.js'; import { signMessage } from '@authmesh/core'; import { createRelayServer } from '../server.js'; @@ -8,18 +8,17 @@ import { computeSAS, } from '../../../cli/src/handshake.js'; -let relay: Awaited>; +let relay: ReturnType; let relayUrl: string; -beforeAll(async () => { - relay = await createRelayServer({ host: '127.0.0.1', port: 0 }); - await relay.app.listen({ host: '127.0.0.1', port: 0 }); - const port = (relay.app.server.address() as { port: number }).port; - relayUrl = `ws://127.0.0.1:${port}/ws`; +beforeAll(() => { + relay = createRelayServer({ host: '127.0.0.1', port: 0 }); + const addr = relay.start(); + relayUrl = `ws://127.0.0.1:${addr.port}/ws`; }); -afterAll(async () => { - await relay.stop(); +afterAll(() => { + relay.stop(); }); function makeIdentity() { @@ -82,7 +81,7 @@ describe('full handshake integration', () => { it('controller gets error for nonexistent OTC', async () => { const controller = makeIdentity(); - await expect( + expect( runControllerHandshake( relayUrl, '999999', diff --git a/packages/relay/src/index.ts b/packages/relay/src/index.ts index 2095fb1..00d7c0f 100644 --- a/packages/relay/src/index.ts +++ b/packages/relay/src/index.ts @@ -1,3 +1,4 @@ export { createRelayServer } from './server.js'; +export type { WebSocketData } from './server.js'; export { SessionStore } from './session.js'; export { RateLimiter } from './rate-limit.js'; diff --git a/packages/relay/src/server.ts b/packages/relay/src/server.ts index 28f3905..637882f 100644 --- a/packages/relay/src/server.ts +++ b/packages/relay/src/server.ts @@ -1,6 +1,4 @@ -import Fastify from 'fastify'; -import websocket from '@fastify/websocket'; -import type { WebSocket } from 'ws'; +import type { ServerWebSocket } from 'bun'; import { SessionStore } from './session.js'; import { RateLimiter, OTCAttemptTracker } from './rate-limit.js'; @@ -9,179 +7,128 @@ interface RelayMessage { otc?: string; payload?: string; jti?: string; + token?: string; + targetPubKey?: string; [key: string]: unknown; } +export interface WebSocketData { + otc?: string; + btJti?: string; + ip: string; +} + const MAX_PAYLOAD = 65_536; // 64 KB — generous for handshake messages const MAX_CONNECTIONS = 10_000; const BOOTSTRAP_WATCHER_TTL_MS = 300_000; // 5 minutes -export async function createRelayServer(opts?: { host?: string; port?: number }) { - const app = Fastify({ logger: false }); +export function createRelayServer(opts?: { host?: string; port?: number }) { const sessions = new SessionStore(); const rateLimiter = new RateLimiter(5, 60_000); const otcAttempts = new OTCAttemptTracker(10); // Bootstrap watchers: jti → { socket, createdAt } - const bootstrapWatchers = new Map(); + const bootstrapWatchers = new Map; createdAt: number }>(); + // Track all connected sockets for bootstrap response routing + const connectedSockets = new Set>(); let connectionCount = 0; - await app.register(websocket, { - options: { maxPayload: MAX_PAYLOAD }, - }); - - app.get('/health', async () => ({ status: 'ok', sessions: sessions.size })); - // Purge stale bootstrap watchers every 30 seconds const bootstrapCleanupTimer = setInterval(() => { const now = Date.now(); for (const [jti, entry] of bootstrapWatchers) { - if (now - entry.createdAt > BOOTSTRAP_WATCHER_TTL_MS || entry.socket.readyState !== 1) { + if (now - entry.createdAt > BOOTSTRAP_WATCHER_TTL_MS || entry.socket.readyState !== WebSocket.OPEN) { bootstrapWatchers.delete(jti); } } }, 30_000); bootstrapCleanupTimer.unref(); - app.register(async function (fastify) { - fastify.get('/ws', { websocket: true }, (socket: WebSocket, req) => { - // Connection limit - connectionCount++; - if (connectionCount > MAX_CONNECTIONS) { - socket.close(1013, 'too_many_connections'); - connectionCount--; - return; - } - - const ip = req.ip; - - socket.on('message', (raw: Buffer) => { - let msg: RelayMessage; - try { - msg = JSON.parse(raw.toString()); - } catch { - socket.send(JSON.stringify({ type: 'error', code: 'invalid_message' })); - return; - } - - switch (msg.type) { - case 'listen': - handleListen(socket, msg, ip); - break; - case 'connect': - handleConnect(socket, msg, ip); - break; - case 'data': - handleData(socket, msg); - break; - case 'done': - handleDone(socket); - break; - case 'bootstrap_watch': - handleBootstrapWatch(socket, msg); - break; - case 'bootstrap_init': - handleBootstrapInit(socket, msg); - break; - case 'bootstrap_ack': - case 'bootstrap_reject': - handleBootstrapResponse(socket, msg); - break; - default: - socket.send(JSON.stringify({ type: 'error', code: 'unknown_type' })); - } - }); - - socket.on('close', () => { - connectionCount--; - cleanupSocket(socket); - }); - }); - }); + const host = opts?.host ?? '0.0.0.0'; + const port = opts?.port ?? 3001; - function handleListen(socket: WebSocket, msg: RelayMessage, ip: string) { + function handleListen(ws: ServerWebSocket, msg: RelayMessage) { const otc = msg.otc; if (!otc || !/^\d{6}$/.test(otc)) { - socket.send(JSON.stringify({ type: 'error', code: 'invalid_otc' })); + ws.send(JSON.stringify({ type: 'error', code: 'invalid_otc' })); return; } - if (!rateLimiter.check(ip)) { - socket.send(JSON.stringify({ type: 'error', code: 'rate_limited' })); + if (!rateLimiter.check(ws.data.ip)) { + ws.send(JSON.stringify({ type: 'error', code: 'rate_limited' })); return; } try { - sessions.create(otc, socket); - socket.send(JSON.stringify({ type: 'ack', message: 'session_open' })); - // Store OTC on socket for cleanup - (socket as WebSocket & { _otc?: string })._otc = otc; + sessions.create(otc, ws); + ws.send(JSON.stringify({ type: 'ack', message: 'session_open' })); + ws.data.otc = otc; } catch { - socket.send(JSON.stringify({ type: 'error', code: 'otc_in_use' })); + ws.send(JSON.stringify({ type: 'error', code: 'otc_in_use' })); } } - function handleConnect(socket: WebSocket, msg: RelayMessage, ip: string) { + function handleConnect(ws: ServerWebSocket, msg: RelayMessage) { const otc = msg.otc; if (!otc || !/^\d{6}$/.test(otc)) { - socket.send(JSON.stringify({ type: 'error', code: 'invalid_otc' })); + ws.send(JSON.stringify({ type: 'error', code: 'invalid_otc' })); return; } - if (!rateLimiter.check(ip)) { - socket.send(JSON.stringify({ type: 'error', code: 'rate_limited' })); + if (!rateLimiter.check(ws.data.ip)) { + ws.send(JSON.stringify({ type: 'error', code: 'rate_limited' })); return; } const session = sessions.get(otc); if (!session) { - rateLimiter.recordFailure(ip); + rateLimiter.recordFailure(ws.data.ip); // Per-OTC attempt tracking: invalidate OTC after too many failures if (!otcAttempts.recordAndCheck(otc)) { // OTC exhausted by brute-force — silently drop (already removed or expired) } - socket.send(JSON.stringify({ type: 'error', code: 'otc_not_found' })); + ws.send(JSON.stringify({ type: 'error', code: 'otc_not_found' })); return; } if (session.controller) { - socket.send(JSON.stringify({ type: 'error', code: 'peer_already_connected' })); + ws.send(JSON.stringify({ type: 'error', code: 'peer_already_connected' })); return; } - session.controller = socket; - (socket as WebSocket & { _otc?: string })._otc = otc; + session.controller = ws; + ws.data.otc = otc; // Successful connect — clean up OTC attempt tracking otcAttempts.remove(otc); // Notify both sides session.target.send(JSON.stringify({ type: 'peer_found' })); - socket.send(JSON.stringify({ type: 'peer_found' })); + ws.send(JSON.stringify({ type: 'peer_found' })); } - function handleData(socket: WebSocket, msg: RelayMessage) { - const otc = (socket as WebSocket & { _otc?: string })._otc; + function handleData(ws: ServerWebSocket, msg: RelayMessage) { + const otc = ws.data.otc; if (!otc) return; const session = sessions.get(otc); if (!session) return; // Forward to the other peer (opaque blob forwarding) - const peer = socket === session.target ? session.controller : session.target; - if (peer && peer.readyState === 1) { + const peer = ws === session.target ? session.controller : session.target; + if (peer && peer.readyState === WebSocket.OPEN) { peer.send(JSON.stringify({ type: 'data', payload: msg.payload })); } } - function handleDone(socket: WebSocket) { - const otc = (socket as WebSocket & { _otc?: string })._otc; + function handleDone(ws: ServerWebSocket) { + const otc = ws.data.otc; if (!otc) return; const session = sessions.get(otc); if (!session) return; // Notify peer and clean up - const peer = socket === session.target ? session.controller : session.target; - if (peer && peer.readyState === 1) { + const peer = ws === session.target ? session.controller : session.target; + if (peer && peer.readyState === WebSocket.OPEN) { peer.send(JSON.stringify({ type: 'done' })); } @@ -189,22 +136,22 @@ export async function createRelayServer(opts?: { host?: string; port?: number }) } // Bootstrap: controller registers to watch for a specific jti - function handleBootstrapWatch(socket: WebSocket, msg: RelayMessage) { - if (!msg.jti) { socket.send(JSON.stringify({ type: 'error', code: 'missing_jti' })); return; } - bootstrapWatchers.set(msg.jti, { socket, createdAt: Date.now() }); - socket.send(JSON.stringify({ type: 'bootstrap_watching', jti: msg.jti })); + function handleBootstrapWatch(ws: ServerWebSocket, msg: RelayMessage) { + if (!msg.jti) { ws.send(JSON.stringify({ type: 'error', code: 'missing_jti' })); return; } + bootstrapWatchers.set(msg.jti, { socket: ws, createdAt: Date.now() }); + ws.send(JSON.stringify({ type: 'bootstrap_watching', jti: msg.jti })); } // Bootstrap: target initiates pairing with a token - function handleBootstrapInit(socket: WebSocket, msg: RelayMessage) { - if (!msg.jti) { socket.send(JSON.stringify({ type: 'error', code: 'missing_jti' })); return; } + function handleBootstrapInit(ws: ServerWebSocket, msg: RelayMessage) { + if (!msg.jti) { ws.send(JSON.stringify({ type: 'error', code: 'missing_jti' })); return; } const entry = bootstrapWatchers.get(msg.jti); - if (!entry || entry.socket.readyState !== 1) { - socket.send(JSON.stringify({ type: 'bootstrap_reject', error: 'no_watcher' })); + if (!entry || entry.socket.readyState !== WebSocket.OPEN) { + ws.send(JSON.stringify({ type: 'bootstrap_reject', error: 'no_watcher' })); return; } // Store target socket for response routing - (socket as WebSocket & { _btJti?: string })._btJti = msg.jti; + ws.data.btJti = msg.jti; // Whitelist forwarded fields — do not forward arbitrary attacker-controlled data entry.socket.send(JSON.stringify({ type: msg.type, @@ -215,28 +162,27 @@ export async function createRelayServer(opts?: { host?: string; port?: number }) } // Bootstrap: controller responds (ack or reject) — forward to target - function handleBootstrapResponse(socket: WebSocket, msg: RelayMessage) { - const jti = msg.jti ?? (socket as WebSocket & { _btWatchJti?: string })._btWatchJti; + function handleBootstrapResponse(ws: ServerWebSocket, msg: RelayMessage) { + const jti = msg.jti; if (!jti) return; // Find target socket by jti - // Simple approach: iterate connected sockets (relay is small) - app.websocketServer?.clients.forEach((client: WebSocket) => { - if ((client as WebSocket & { _btJti?: string })._btJti === jti && client.readyState === 1) { + for (const client of connectedSockets) { + if (client.data.btJti === jti && client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(msg)); } - }); + } // Clean up watcher bootstrapWatchers.delete(jti); } - function cleanupSocket(socket: WebSocket) { + function cleanupSocket(ws: ServerWebSocket) { // Clean up pairing sessions - const otc = (socket as WebSocket & { _otc?: string })._otc; + const otc = ws.data.otc; if (otc) { const session = sessions.get(otc); if (session) { - const peer = socket === session.target ? session.controller : session.target; - if (peer && peer.readyState === 1) { + const peer = ws === session.target ? session.controller : session.target; + if (peer && peer.readyState === WebSocket.OPEN) { peer.send(JSON.stringify({ type: 'error', code: 'peer_disconnected' })); } sessions.remove(otc); @@ -244,33 +190,107 @@ export async function createRelayServer(opts?: { host?: string; port?: number }) } // Clean up bootstrap watchers - const btJti = (socket as WebSocket & { _btJti?: string })._btJti; + const btJti = ws.data.btJti; if (btJti) bootstrapWatchers.delete(btJti); // Also check if this socket was a watcher for (const [jti, entry] of bootstrapWatchers) { - if (entry.socket === socket) { + if (entry.socket === ws) { bootstrapWatchers.delete(jti); break; } } } - const host = opts?.host ?? '0.0.0.0'; - const port = opts?.port ?? 3001; + let server: ReturnType>; return { - app, sessions, - async start() { - await app.listen({ host, port }); - return { host, port }; + get server() { return server; }, + start() { + server = Bun.serve({ + hostname: host, + port, + fetch(req, srv) { + const url = new URL(req.url); + + if (url.pathname === '/health') { + return Response.json({ status: 'ok', sessions: sessions.size }); + } + + if (url.pathname === '/ws') { + const ip = srv.requestIP(req)?.address ?? 'unknown'; + const upgraded = srv.upgrade(req, { + data: { ip }, + }); + if (upgraded) return undefined; + return new Response('WebSocket upgrade failed', { status: 400 }); + } + + return new Response('Not found', { status: 404 }); + }, + websocket: { + maxPayloadLength: MAX_PAYLOAD, + open(ws) { + connectionCount++; + connectedSockets.add(ws); + if (connectionCount > MAX_CONNECTIONS) { + ws.close(1013, 'too_many_connections'); + connectionCount--; + connectedSockets.delete(ws); + } + }, + message(ws, raw) { + let msg: RelayMessage; + try { + msg = JSON.parse(typeof raw === 'string' ? raw : Buffer.from(raw).toString()); + } catch { + ws.send(JSON.stringify({ type: 'error', code: 'invalid_message' })); + return; + } + + switch (msg.type) { + case 'listen': + handleListen(ws, msg); + break; + case 'connect': + handleConnect(ws, msg); + break; + case 'data': + handleData(ws, msg); + break; + case 'done': + handleDone(ws); + break; + case 'bootstrap_watch': + handleBootstrapWatch(ws, msg); + break; + case 'bootstrap_init': + handleBootstrapInit(ws, msg); + break; + case 'bootstrap_ack': + case 'bootstrap_reject': + handleBootstrapResponse(ws, msg); + break; + default: + ws.send(JSON.stringify({ type: 'error', code: 'unknown_type' })); + } + }, + close(ws) { + connectionCount--; + connectedSockets.delete(ws); + cleanupSocket(ws); + }, + }, + }); + + return { host, port: server.port }; }, - async stop() { + stop() { clearInterval(bootstrapCleanupTimer); sessions.destroy(); rateLimiter.destroy(); otcAttempts.destroy(); - await app.close(); + server?.stop(); }, }; } diff --git a/packages/relay/src/session.ts b/packages/relay/src/session.ts index d4701e7..3db9e79 100644 --- a/packages/relay/src/session.ts +++ b/packages/relay/src/session.ts @@ -1,9 +1,10 @@ -import type { WebSocket } from 'ws'; +import type { ServerWebSocket } from 'bun'; +import type { WebSocketData } from './server.js'; export interface PairingSession { otc: string; - target: WebSocket; - controller: WebSocket | null; + target: ServerWebSocket; + controller: ServerWebSocket | null; createdAt: number; expiresAt: number; } @@ -21,7 +22,7 @@ export class SessionStore { this.cleanupTimer = setInterval(() => this.purge(), 10_000); } - create(otc: string, target: WebSocket, ttlSeconds = 120): PairingSession { + create(otc: string, target: ServerWebSocket, ttlSeconds = 120): PairingSession { if (this.sessions.has(otc)) { throw new Error('OTC already in use'); } diff --git a/packages/relay/src/start.ts b/packages/relay/src/start.ts index a1144e1..52df5e9 100644 --- a/packages/relay/src/start.ts +++ b/packages/relay/src/start.ts @@ -3,8 +3,8 @@ import { createRelayServer } from './server.js'; const port = parseInt(process.env.PORT ?? '3001', 10); const host = process.env.HOST ?? '0.0.0.0'; -const relay = await createRelayServer({ host, port }); -await relay.start(); +const relay = createRelayServer({ host, port }); +const addr = relay.start(); -console.log(`amesh relay listening on ws://${host}:${port}/ws`); -console.log('Health check: http://' + host + ':' + port + '/health'); +console.log(`amesh relay listening on ws://${addr.host}:${addr.port}/ws`); +console.log('Health check: http://' + addr.host + ':' + addr.port + '/health'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e585978..1f489ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -208,18 +208,6 @@ importers: '@authmesh/core': specifier: workspace:* version: link:../core - '@fastify/rate-limit': - specifier: ^10.0.0 - version: 10.3.0 - '@fastify/websocket': - specifier: ^11.0.0 - version: 11.2.0 - fastify: - specifier: ^5.0.0 - version: 5.8.4 - ws: - specifier: ^8.0.0 - version: 8.20.0 devDependencies: '@eslint/js': specifier: ^9.0.0 @@ -230,12 +218,9 @@ importers: '@noble/hashes': specifier: 2.0.1 version: 2.0.1 - '@types/node': - specifier: ^22.0.0 - version: 22.19.15 - '@types/ws': - specifier: ^8.0.0 - version: 8.18.1 + '@types/bun': + specifier: ^1.3.0 + version: 1.3.11 eslint: specifier: ^9.0.0 version: 9.39.4(jiti@2.6.1) @@ -521,30 +506,6 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@fastify/ajv-compiler@4.0.5': - resolution: {integrity: sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==} - - '@fastify/error@4.2.0': - resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} - - '@fastify/fast-json-stringify-compiler@5.0.3': - resolution: {integrity: sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==} - - '@fastify/forwarded@3.0.1': - resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} - - '@fastify/merge-json-schemas@0.2.1': - resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} - - '@fastify/proxy-addr@5.1.0': - resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} - - '@fastify/rate-limit@10.3.0': - resolution: {integrity: sha512-eIGkG9XKQs0nyynatApA3EVrojHOuq4l6fhB4eeCk4PIOeadvOJz9/4w3vGI44Go17uaXOWEcPkaD8kuKm7g6Q==} - - '@fastify/websocket@11.2.0': - resolution: {integrity: sha512-3HrDPbAG1CzUCqnslgJxppvzaAZffieOVbLp1DAy1huCSynUWPifSvfdEDUR8HlJLp3sp1A36uOM2tJogADS8w==} - '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -585,10 +546,6 @@ packages: peerDependencies: svelte: ^5 - '@lukeed/ms@2.0.2': - resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} - engines: {node: '>=8'} - '@napi-rs/wasm-runtime@1.1.2': resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} peerDependencies: @@ -614,9 +571,6 @@ packages: '@oxc-project/types@0.122.0': resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - '@pinojs/redact@0.4.0': - resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -1027,6 +981,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/bun@1.3.11': + resolution: {integrity: sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1148,9 +1105,6 @@ packages: '@vitest/utils@4.1.2': resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} - abstract-logging@2.0.1: - resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1161,20 +1115,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -1208,13 +1151,6 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} - - avvio@9.2.0: - resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1236,6 +1172,9 @@ packages: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} engines: {node: 18 || 20 || >=22} + bun-types@1.3.11: + resolution: {integrity: sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg==} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1289,10 +1228,6 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - cookie@1.1.1: - resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} - engines: {node: '>=18'} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1317,10 +1252,6 @@ packages: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -1328,9 +1259,6 @@ packages: devalue@5.6.4: resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} - duplexify@4.1.3: - resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - ejs@3.1.10: resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} engines: {node: '>=0.10.0'} @@ -1339,9 +1267,6 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.20.1: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} @@ -1417,36 +1342,15 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - fast-decode-uri-component@1.0.1: - resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - fast-json-stringify@6.3.0: - resolution: {integrity: sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==} - fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-querystring@1.1.2: - resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - - fastify-plugin@5.1.0: - resolution: {integrity: sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==} - - fastify@5.8.4: - resolution: {integrity: sha512-sa42J1xylbBAYUWALSBoyXKPDUvM3OoNOibIefA+Oha57FryXKKCZarA1iDntOCWp3O35voZLuDg2mdODXtPzQ==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1463,10 +1367,6 @@ packages: filelist@1.0.6: resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} - find-my-way@9.5.0: - resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==} - engines: {node: '>=20'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1528,17 +1428,10 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ioredis@5.6.1: resolution: {integrity: sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==} engines: {node: '>=12.22.0'} - ipaddr.js@2.3.0: - resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} - engines: {node: '>= 10'} - is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -1597,15 +1490,9 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-schema-ref-resolver@3.0.0: - resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -1620,9 +1507,6 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - light-my-request@6.6.0: - resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} - lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -1760,13 +1644,6 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1801,16 +1678,6 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pino-abstract-transport@3.0.0: - resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} - - pino-std-serializers@7.1.0: - resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} - - pino@10.3.1: - resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} - hasBin: true - postcss@8.5.8: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} @@ -1884,31 +1751,14 @@ packages: engines: {node: '>=14'} hasBin: true - process-warning@4.0.1: - resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} - - process-warning@5.0.0: - resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} - redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} @@ -1917,10 +1767,6 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1928,17 +1774,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - ret@0.5.0: - resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} - engines: {node: '>=10'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rolldown@1.0.0-rc.12: resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1953,28 +1788,11 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-regex2@5.1.0: - resolution: {integrity: sha512-pNHAuBW7TrcleFHsxBr5QMi/Iyp0ENjUKz7GCcX1UO7cMh+NmVK6HxQckNL1tJp1XAJVjG6B8OKIPqodqj9rtw==} - hasBin: true - - safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} - - secure-json-parse@4.1.0: - resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} - semver@7.7.4: resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - set-cookie-parser@3.1.0: resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} @@ -1993,17 +1811,10 @@ packages: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} - sonic-boom@4.2.1: - resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -2013,16 +1824,10 @@ packages: std-env@4.0.0: resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2058,10 +1863,6 @@ packages: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} - thread-stream@4.0.0: - resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} - engines: {node: '>=20'} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -2077,10 +1878,6 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - toad-cache@3.7.0: - resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} - engines: {node: '>=12'} - totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -2129,9 +1926,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - vite@7.3.1: resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2283,9 +2077,6 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.20.0: resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} @@ -2462,44 +2253,6 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@fastify/ajv-compiler@4.0.5': - dependencies: - ajv: 8.18.0 - ajv-formats: 3.0.1(ajv@8.18.0) - fast-uri: 3.1.0 - - '@fastify/error@4.2.0': {} - - '@fastify/fast-json-stringify-compiler@5.0.3': - dependencies: - fast-json-stringify: 6.3.0 - - '@fastify/forwarded@3.0.1': {} - - '@fastify/merge-json-schemas@0.2.1': - dependencies: - dequal: 2.0.3 - - '@fastify/proxy-addr@5.1.0': - dependencies: - '@fastify/forwarded': 3.0.1 - ipaddr.js: 2.3.0 - - '@fastify/rate-limit@10.3.0': - dependencies: - '@lukeed/ms': 2.0.2 - fastify-plugin: 5.1.0 - toad-cache: 3.7.0 - - '@fastify/websocket@11.2.0': - dependencies: - duplexify: 4.1.3 - fastify-plugin: 5.1.0 - ws: 8.20.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -2536,8 +2289,6 @@ snapshots: dependencies: svelte: 5.55.1 - '@lukeed/ms@2.0.2': {} - '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: '@emnapi/core': 1.9.1 @@ -2576,8 +2327,6 @@ snapshots: '@oxc-project/types@0.122.0': {} - '@pinojs/redact@0.4.0': {} - '@polka/url@1.0.0-next.29': {} '@rolldown/binding-android-arm64@1.0.0-rc.12': @@ -2845,6 +2594,10 @@ snapshots: tslib: 2.8.1 optional: true + '@types/bun@1.3.11': + dependencies: + bun-types: 1.3.11 + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -3014,18 +2767,12 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - abstract-logging@2.0.1: {} - acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 acorn@8.16.0: {} - ajv-formats@3.0.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -3033,13 +2780,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -3066,13 +2806,6 @@ snapshots: async@3.2.6: {} - atomic-sleep@1.0.0: {} - - avvio@9.2.0: - dependencies: - '@fastify/error': 4.2.0 - fastq: 1.20.1 - axobject-query@4.1.0: {} balanced-match@1.0.2: {} @@ -3092,6 +2825,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + bun-types@1.3.11: + dependencies: + '@types/node': 22.19.15 + callsites@3.1.0: {} chai@6.2.2: {} @@ -3129,8 +2866,6 @@ snapshots: cookie@0.6.0: {} - cookie@1.1.1: {} - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -3149,29 +2884,16 @@ snapshots: denque@2.1.0: {} - dequal@2.0.3: {} - detect-libc@2.1.2: {} devalue@5.6.4: {} - duplexify@4.1.3: - dependencies: - end-of-stream: 1.4.5 - inherits: 2.0.4 - readable-stream: 3.6.2 - stream-shift: 1.0.3 - ejs@3.1.10: dependencies: jake: 10.9.4 emoji-regex@8.0.0: {} - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 - enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 @@ -3293,53 +3015,12 @@ snapshots: expect-type@1.3.0: {} - fast-decode-uri-component@1.0.1: {} - fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} - fast-json-stringify@6.3.0: - dependencies: - '@fastify/merge-json-schemas': 0.2.1 - ajv: 8.18.0 - ajv-formats: 3.0.1(ajv@8.18.0) - fast-uri: 3.1.0 - json-schema-ref-resolver: 3.0.0 - rfdc: 1.4.1 - fast-levenshtein@2.0.6: {} - fast-querystring@1.1.2: - dependencies: - fast-decode-uri-component: 1.0.1 - - fast-uri@3.1.0: {} - - fastify-plugin@5.1.0: {} - - fastify@5.8.4: - dependencies: - '@fastify/ajv-compiler': 4.0.5 - '@fastify/error': 4.2.0 - '@fastify/fast-json-stringify-compiler': 5.0.3 - '@fastify/proxy-addr': 5.1.0 - abstract-logging: 2.0.1 - avvio: 9.2.0 - fast-json-stringify: 6.3.0 - find-my-way: 9.5.0 - light-my-request: 6.6.0 - pino: 10.3.1 - process-warning: 5.0.0 - rfdc: 1.4.1 - secure-json-parse: 4.1.0 - semver: 7.7.4 - toad-cache: 3.7.0 - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -3352,12 +3033,6 @@ snapshots: dependencies: minimatch: 5.1.9 - find-my-way@9.5.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-querystring: 1.1.2 - safe-regex2: 5.1.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -3404,8 +3079,6 @@ snapshots: indent-string@4.0.0: {} - inherits@2.0.4: {} - ioredis@5.6.1: dependencies: '@ioredis/commands': 1.5.1 @@ -3420,8 +3093,6 @@ snapshots: transitivePeerDependencies: - supports-color - ipaddr.js@2.3.0: {} - is-docker@2.2.1: {} is-extglob@2.1.1: {} @@ -3471,14 +3142,8 @@ snapshots: json-buffer@3.0.1: {} - json-schema-ref-resolver@3.0.0: - dependencies: - dequal: 2.0.3 - json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} keyv@4.5.4: @@ -3492,12 +3157,6 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - light-my-request@6.6.0: - dependencies: - cookie: 1.1.1 - process-warning: 4.0.1 - set-cookie-parser: 2.7.2 - lightningcss-android-arm64@1.32.0: optional: true @@ -3599,12 +3258,6 @@ snapshots: obug@2.1.1: {} - on-exit-leak-free@2.1.2: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3636,26 +3289,6 @@ snapshots: picomatch@4.0.4: {} - pino-abstract-transport@3.0.0: - dependencies: - split2: 4.2.0 - - pino-std-serializers@7.1.0: {} - - pino@10.3.1: - dependencies: - '@pinojs/redact': 0.4.0 - atomic-sleep: 1.0.0 - on-exit-leak-free: 2.1.2 - pino-abstract-transport: 3.0.0 - pino-std-serializers: 7.1.0 - process-warning: 5.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.2.0 - safe-stable-stringify: 2.5.0 - sonic-boom: 4.2.1 - thread-stream: 4.0.0 - postcss@8.5.8: dependencies: nanoid: 3.3.11 @@ -3674,42 +3307,20 @@ snapshots: prettier@3.8.1: {} - process-warning@4.0.1: {} - - process-warning@5.0.0: {} - punycode@2.3.1: {} - quick-format-unescaped@4.0.4: {} - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - readdirp@4.1.2: {} - real-require@0.2.0: {} - redis-errors@1.2.0: {} redis-parser@3.0.0: dependencies: redis-errors: 1.2.0 - require-from-string@2.0.2: {} - resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} - ret@0.5.0: {} - - reusify@1.1.0: {} - - rfdc@1.4.1: {} - rolldown@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1): dependencies: '@oxc-project/types': 0.122.0 @@ -3769,20 +3380,8 @@ snapshots: dependencies: mri: 1.2.0 - safe-buffer@5.2.1: {} - - safe-regex2@5.1.0: - dependencies: - ret: 0.5.0 - - safe-stable-stringify@2.5.0: {} - - secure-json-parse@4.1.0: {} - semver@7.7.4: {} - set-cookie-parser@2.7.2: {} - set-cookie-parser@3.1.0: {} shebang-command@2.0.0: @@ -3799,32 +3398,20 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 - sonic-boom@4.2.1: - dependencies: - atomic-sleep: 1.0.0 - source-map-js@1.2.1: {} - split2@4.2.0: {} - stackback@0.0.2: {} standard-as-callback@2.1.0: {} std-env@4.0.0: {} - stream-shift@1.0.3: {} - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -3874,10 +3461,6 @@ snapshots: tapable@2.3.2: {} - thread-stream@4.0.0: - dependencies: - real-require: 0.2.0 - tinybench@2.9.0: {} tinyexec@1.0.4: {} @@ -3889,8 +3472,6 @@ snapshots: tinyrainbow@3.1.0: {} - toad-cache@3.7.0: {} - totalist@3.0.1: {} ts-api-utils@2.5.0(typescript@5.9.3): @@ -3941,8 +3522,6 @@ snapshots: dependencies: punycode: 2.3.1 - util-deprecate@1.0.2: {} - vite@7.3.1(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0): dependencies: esbuild: 0.27.4 @@ -4029,8 +3608,6 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrappy@1.0.2: {} - ws@8.20.0: {} yocto-queue@0.1.0: {}