# SmartServe Development Hints ## Architecture Overview SmartServe is a cross-platform HTTP server for Node.js, Deno, and Bun using: - **Web Standards API** (Request/Response) for cross-platform compatibility - **TC39 Stage 3 decorators** (TypeScript 5.0+) for route definition - **Adapter pattern** for runtime-specific implementations ## Key Files ### Core - `ts/core/smartserve.classes.smartserve.ts` - Main server class - `ts/core/smartserve.interfaces.ts` - All type definitions - `ts/core/smartserve.errors.ts` - HTTP error classes ### Adapters - `ts/adapters/adapter.factory.ts` - Runtime detection via @push.rocks/smartenv - `ts/adapters/adapter.node.ts` - Node.js with Request/Response conversion - `ts/adapters/adapter.deno.ts` - Deno (zero overhead, native) - `ts/adapters/adapter.bun.ts` - Bun (zero overhead, native) ### Decorators - `ts/decorators/decorators.route.ts` - @Route class decorator - `ts/decorators/decorators.methods.ts` - @Get, @Post, etc. - `ts/decorators/decorators.interceptors.ts` - @Guard, @Transform, @Intercept - `ts/decorators/decorators.registry.ts` - Controller registration and route matching ### Static Files - `ts/files/file.server.ts` - Static file serving with streaming, ETags, directory listing - `ts/utils/utils.mime.ts` - MIME type detection - `ts/utils/utils.etag.ts` - ETag generation ### Compression - `ts/compression/compression.runtime.ts` - Cross-runtime compression (Node.js zlib, Web CompressionStream) - `ts/compression/compression.middleware.ts` - Compression config and helpers - `ts/utils/utils.encoding.ts` - Accept-Encoding parsing - `ts/decorators/decorators.compress.ts` - @Compress and @NoCompress decorators ### Protocols - `ts/protocols/webdav/webdav.handler.ts` - WebDAV RFC 4918 handler - `ts/protocols/webdav/webdav.xml.ts` - XML generation (multistatus, lock responses) - `ts/protocols/webdav/webdav.types.ts` - WebDAV type definitions ## Decorator System Uses TC39 decorators (NOT experimental decorators). Metadata stored via Symbol property on classes. ### Interceptor Execution Order (Onion Model) ``` Request → Class Guards → Method Guards → Handler → Method Transforms → Class Transforms → Response ``` ### Guard vs Transform vs Intercept - `@Guard(fn)` = `@Intercept({ request: fn })` - returns boolean (true=allow, false=403) - `@Transform(fn)` = `@Intercept({ response: fn })` - modifies response - `@Intercept({ request?, response? })` - full control ## Dependencies Required: - `@push.rocks/smartenv` - Runtime detection - `@push.rocks/smartpath` - Path utilities - `@push.rocks/smartlog` - Logging - `@push.rocks/lik` - Collections Optional: - `ws` - WebSocket support for Node.js (Deno/Bun have native) ## WebDAV Usage ```typescript import { SmartServe } from '@push.rocks/smartserve'; const server = new SmartServe({ port: 8080, webdav: { root: '/path/to/files', auth: (ctx) => { // Optional auth - return true to allow, false to reject const auth = ctx.headers.get('Authorization'); return auth === 'Basic dXNlcjpwYXNz'; }, locking: true, // Enable file locking (RFC 4918) } }); await server.start(); // Mount at http://localhost:8080 as network drive ``` ### Supported WebDAV Methods - OPTIONS - Capability discovery - PROPFIND - Directory listing and file metadata - PROPPATCH - Property modification (returns 403) - MKCOL - Create directory - COPY - Copy files/directories - MOVE - Move/rename files/directories - LOCK/UNLOCK - Exclusive write locking - GET/HEAD/PUT/DELETE - Standard file operations ## TypedRouter WebSocket Integration SmartServe supports first-class TypedRouter integration for type-safe RPC over WebSockets. ### Usage ```typescript import { SmartServe } from '@push.rocks/smartserve'; import { TypedRouter, TypedHandler } from '@api.global/typedrequest'; const router = new TypedRouter(); router.addTypedHandler(new TypedHandler('echo', async (data) => { return { echoed: data.message }; })); const server = new SmartServe({ port: 3000, websocket: { typedRouter: router, onConnectionOpen: (peer) => { peer.tags.add('authenticated'); console.log(`Client connected: ${peer.id}`); }, onConnectionClose: (peer) => { console.log(`Client disconnected: ${peer.id}`); }, }, }); await server.start(); // Broadcast to all connections server.broadcastWebSocket({ type: 'notification', message: 'Hello!' }); // Broadcast to specific tag server.broadcastWebSocketByTag('authenticated', { type: 'secure-message' }); // Get all connections const connections = server.getWebSocketConnections(); ``` ### Key Features - **TypedRouter mode**: Set `typedRouter` for automatic JSON-RPC routing (mutually exclusive with `onMessage`) - **Connection registry**: Active only when `typedRouter` is set - **Peer tags**: Use `peer.tags.add/has/delete` for connection filtering - **Broadcast methods**: `broadcastWebSocket()` and `broadcastWebSocketByTag()` - **Lifecycle hooks**: `onConnectionOpen` and `onConnectionClose` (alongside existing `onOpen`/`onClose`) ### Architecture Notes - `typedRouter` and `onMessage` are mutually exclusive (throws `WebSocketConfigError` if both set) - Connection registry only active when `typedRouter` is configured - Bun adapter stores peer ID/tags in `ws.data` for persistence across events - Internal `_connectionCallbacks` passed to adapters for registry communication ## Compression SmartServe supports automatic response compression with Brotli and gzip. ### Configuration ```typescript const server = new SmartServe({ port: 3000, // Simple: enable with defaults (compression is ON by default) compression: true, // Detailed configuration compression: { enabled: true, algorithms: ['br', 'gzip'], // Brotli preferred, gzip fallback threshold: 1024, // Don't compress < 1KB level: 4, // Compression level compressibleTypes: [ // Custom MIME types 'text/', 'application/json', 'application/javascript', ], exclude: ['/api/stream/*'], // Skip certain paths }, // Pre-compressed static files static: { root: './public', precompressed: true, // Serve index.html.br, index.html.gz if available }, }); ``` ### Per-Route Control ```typescript @Controller('/api') class ApiController { @Get('/data') getData() { return { large: 'json' }; // Compressed by default } @Get('/stream') @NoCompress() // Skip compression for SSE/streaming getStream() { return new Response(eventStream, { headers: { 'Content-Type': 'text/event-stream' } }); } @Get('/heavy') @Compress({ level: 11 }) // Force max brotli compression getHeavy() { return massiveData; } } ``` ### Cross-Runtime Support | Runtime | Brotli | gzip | Implementation | |---------|--------|------|----------------| | Node.js | ✅ | ✅ | Native zlib module | | Deno | ⚠️ | ✅ | CompressionStream API | | Bun | ⚠️ | ✅ | CompressionStream API | Note: Brotli in Deno/Bun falls back to gzip if CompressionStream doesn't support it. ## TODO - [x] WebDAV protocol support (PROPFIND, MKCOL, COPY, MOVE, LOCK, UNLOCK) - [x] TypedRouter WebSocket integration - [x] Brotli/gzip compression with per-route control - [ ] HTTP/2 support investigation - [ ] Performance benchmarks