import type { ISmartServeInstance, IConnectionInfo } from '../core/smartserve.interfaces.js'; import { BaseAdapter, type IAdapterCharacteristics, type TRequestHandler } from './adapter.base.js'; // Deno types (for type checking without requiring Deno runtime) declare const Deno: { serve(options: any, handler?: any): { shutdown(): Promise; finished: Promise }; upgradeWebSocket(request: Request): { socket: WebSocket; response: Response }; }; /** * Deno adapter - zero overhead, native Request/Response */ export class DenoAdapter extends BaseAdapter { private server: { shutdown(): Promise; finished: Promise } | null = null; get name(): 'deno' { return 'deno'; } get characteristics(): IAdapterCharacteristics { return { zeroCopyStreaming: true, http2Support: true, maxConnections: 'unlimited', nativeWebSocket: true, }; } isSupported(): boolean { return typeof (globalThis as any).Deno !== 'undefined'; } async start(handler: TRequestHandler): Promise { if (!this.isSupported()) { throw new Error('Deno runtime is not available'); } this.handler = handler; this.startTime = Date.now(); const serveOptions: any = { port: this.options.port, hostname: this.options.hostname ?? '0.0.0.0', }; // Add TLS if configured if (this.options.tls) { serveOptions.cert = this.options.tls.cert; serveOptions.key = this.options.tls.key; } this.server = Deno.serve(serveOptions, async (request: Request, info: any) => { this.stats.requestsTotal++; this.stats.requestsActive++; try { // Handle WebSocket upgrade if (this.options.websocket && request.headers.get('upgrade') === 'websocket') { const { socket, response } = Deno.upgradeWebSocket(request); this.attachWebSocketHooks(socket, request); return response; } // Create connection info const connectionInfo: IConnectionInfo = { remoteAddr: info?.remoteAddr?.hostname ?? 'unknown', remotePort: info?.remoteAddr?.port ?? 0, localAddr: this.options.hostname ?? '0.0.0.0', localPort: this.options.port, encrypted: !!this.options.tls, }; return await handler(request, connectionInfo); } catch (error) { if (this.options.onError) { return this.options.onError(error as Error, request); } return new Response('Internal Server Error', { status: 500 }); } finally { this.stats.requestsActive--; } }); return this.createInstance(); } async stop(): Promise { if (this.server) { await this.server.shutdown(); await this.server.finished; this.server = null; } } private attachWebSocketHooks(socket: WebSocket, request: Request): void { const hooks = this.options.websocket; if (!hooks) return; const peer = this.createWebSocketPeer(socket, request); socket.onopen = () => { hooks.onOpen?.(peer); }; socket.onmessage = (event) => { const message = { type: typeof event.data === 'string' ? 'text' as const : 'binary' as const, text: typeof event.data === 'string' ? event.data : undefined, data: event.data instanceof Uint8Array ? event.data : undefined, size: typeof event.data === 'string' ? event.data.length : (event.data as ArrayBuffer).byteLength, }; hooks.onMessage?.(peer, message); }; socket.onclose = (event) => { hooks.onClose?.(peer, event.code, event.reason); }; socket.onerror = (event) => { hooks.onError?.(peer, new Error('WebSocket error')); }; } private createWebSocketPeer(socket: WebSocket, request: Request): any { const url = this.parseUrl(request); return { id: crypto.randomUUID(), url: url.pathname, get readyState() { return socket.readyState; }, protocol: socket.protocol, extensions: socket.extensions, send: (data: string) => socket.send(data), sendBinary: (data: Uint8Array | ArrayBuffer) => socket.send(data), close: (code?: number, reason?: string) => socket.close(code, reason), ping: () => { /* Deno handles ping/pong automatically */ }, terminate: () => socket.close(), context: {} as any, // Will be populated with IRequestContext data: new Map(), }; } }