7.2 KiB
7.2 KiB
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 classts/core/smartserve.interfaces.ts- All type definitionsts/core/smartserve.errors.ts- HTTP error classes
Adapters
ts/adapters/adapter.factory.ts- Runtime detection via @push.rocks/smartenvts/adapters/adapter.node.ts- Node.js with Request/Response conversionts/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 decoratorts/decorators/decorators.methods.ts- @Get, @Post, etc.ts/decorators/decorators.interceptors.ts- @Guard, @Transform, @Interceptts/decorators/decorators.registry.ts- Controller registration and route matching
Static Files
ts/files/file.server.ts- Static file serving with streaming, ETags, directory listingts/utils/utils.mime.ts- MIME type detectionts/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 helpersts/utils/utils.encoding.ts- Accept-Encoding parsingts/decorators/decorators.compress.ts- @Compress and @NoCompress decorators
Protocols
ts/protocols/webdav/webdav.handler.ts- WebDAV RFC 4918 handlerts/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
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
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
typedRouterfor automatic JSON-RPC routing (mutually exclusive withonMessage) - Connection registry: Active only when
typedRouteris set - Peer tags: Use
peer.tags.add/has/deletefor connection filtering - Broadcast methods:
broadcastWebSocket()andbroadcastWebSocketByTag() - Lifecycle hooks:
onConnectionOpenandonConnectionClose(alongside existingonOpen/onClose)
Architecture Notes
typedRouterandonMessageare mutually exclusive (throwsWebSocketConfigErrorif both set)- Connection registry only active when
typedRouteris configured - Bun adapter stores peer ID/tags in
ws.datafor persistence across events - Internal
_connectionCallbackspassed to adapters for registry communication
Compression
SmartServe supports automatic response compression with Brotli and gzip.
Configuration
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
@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
- WebDAV protocol support (PROPFIND, MKCOL, COPY, MOVE, LOCK, UNLOCK)
- TypedRouter WebSocket integration
- Brotli/gzip compression with per-route control
- HTTP/2 support investigation
- Performance benchmarks