diff --git a/changelog.md b/changelog.md index 16cf0eb..f432e67 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,18 @@ # Changelog +## 2025-12-05 - 7.10.2 - fix(docs) +Update README with routing examples and utility server config; bump @cloudflare/workers-types and @push.rocks/smartserve versions + +- Bumped dependency @cloudflare/workers-types to ^4.20251205.0 +- Bumped dependency @push.rocks/smartserve to ^1.3.0 +- Expanded README: added decorator-based routing examples (Route/Get/Post) using smartserve +- Added programmatic routing examples (addRoute) and SPA/wildcard route samples +- Enhanced UtilityWebsiteServer and UtilityServiceServer docs: default port, ads.txt, feedMetadata, addCustomRoutes example and other config options +- Clarified security headers descriptions and configuration reference +- Updated Quick Start console message to show running port ("Server running on port 3000!") +- Documented EdgeWorker/domain routing caching example and noted service worker version update behavior +- Adjusted TypedSocket example tag to use 'allClients' in README + ## 2025-12-05 - 7.10.1 - fix(typedserver) Use smartserve ControllerRegistry for custom routes and remove custom route parsing diff --git a/package.json b/package.json index f588b24..19f21ee 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@api.global/typedrequest": "^3.2.5", "@api.global/typedrequest-interfaces": "^3.0.19", "@api.global/typedsocket": "^4.1.0", - "@cloudflare/workers-types": "^4.20251202.0", + "@cloudflare/workers-types": "^4.20251205.0", "@design.estate/dees-catalog": "^2.0.3", "@design.estate/dees-comms": "^1.0.30", "@push.rocks/lik": "^6.2.2", @@ -83,7 +83,7 @@ "@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartrequest": "^5.0.1", "@push.rocks/smartrx": "^3.0.10", - "@push.rocks/smartserve": "^1.1.2", + "@push.rocks/smartserve": "^1.3.0", "@push.rocks/smartsitemap": "^2.0.4", "@push.rocks/smartstream": "^3.2.5", "@push.rocks/smarttime": "^4.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b5e35f..e9b01e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,10 +16,10 @@ importers: version: 3.0.19 '@api.global/typedsocket': specifier: ^4.1.0 - version: 4.1.0(@push.rocks/smartserve@1.1.2) + version: 4.1.0(@push.rocks/smartserve@1.3.0) '@cloudflare/workers-types': - specifier: ^4.20251202.0 - version: 4.20251202.0 + specifier: ^4.20251205.0 + version: 4.20251205.0 '@design.estate/dees-catalog': specifier: ^2.0.3 version: 2.0.3(@tiptap/pm@2.27.1) @@ -84,8 +84,8 @@ importers: specifier: ^3.0.10 version: 3.0.10 '@push.rocks/smartserve': - specifier: ^1.1.2 - version: 1.1.2 + specifier: ^1.3.0 + version: 1.3.0 '@push.rocks/smartsitemap': specifier: ^2.0.4 version: 2.0.4 @@ -125,7 +125,7 @@ importers: version: 2.0.0 '@git.zone/tstest': specifier: ^3.1.3 - version: 3.1.3(@aws-sdk/credential-providers@3.787.0)(@push.rocks/smartserve@1.1.2)(socks@2.8.7)(typescript@5.9.3) + version: 3.1.3(@aws-sdk/credential-providers@3.787.0)(@push.rocks/smartserve@1.3.0)(socks@2.8.7)(typescript@5.9.3) '@types/node': specifier: ^24.10.1 version: 24.10.1 @@ -543,8 +543,8 @@ packages: '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} - '@cloudflare/workers-types@4.20251202.0': - resolution: {integrity: sha512-Q7m1Ivu2fbKalOPm00KLpu6GfRaq4TlrPknqugvZgp/gDH96OYKINO4x7jvCIBvCz/aK9vVoOj8tlbSQBervVA==} + '@cloudflare/workers-types@4.20251205.0': + resolution: {integrity: sha512-7pup7fYkuQW5XD8RUS/vkxF9SXlrGyCXuZ4ro3uVQvca/GTeSa+8bZ8T4wbq1Aea5lmLIGSlKbhl2msME7bRBA==} '@configvault.io/interfaces@1.0.17': resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==} @@ -1297,8 +1297,8 @@ packages: '@push.rocks/smarts3@3.0.3': resolution: {integrity: sha512-Y9nXMwurthJ9Z7yi0RwjhPFUC58aY8Mhia8kFo6Xj1tBM4LE8Oxg/ydejF7otHqQGr3QyqV5C4YrDEG17rUuzg==} - '@push.rocks/smartserve@1.1.2': - resolution: {integrity: sha512-NkJNgdDt/rfsd9AMheCxtFd5X+ubzffvxOxjb0Aw1A5JR3xmiWeRifqEV1oN7mMTGL9jyQVvIME6Yrdxr244dA==} + '@push.rocks/smartserve@1.3.0': + resolution: {integrity: sha512-4ZR9uKVWXVAPzU5wtCQ1mA9jNmOlUl3oGr50EceLT6803UwbNcst7Ek/BhzSaZ0qb2pz0jO5T/V+icgvZ1/5ww==} '@push.rocks/smartshell@3.3.0': resolution: {integrity: sha512-m0w618H6YBs+vXGz1CgS4nPi5CUAnqRtckcS9/koGwfcIx1IpjqmiP47BoCTbdgcv0IPUxQVBG1IXTHPuZ8Z5g==} @@ -4298,12 +4298,12 @@ snapshots: '@push.rocks/webrequest': 3.0.37 '@push.rocks/webstream': 1.0.10 - '@api.global/typedserver@3.0.80(@push.rocks/smartserve@1.1.2)': + '@api.global/typedserver@3.0.80(@push.rocks/smartserve@1.3.0)': dependencies: '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 - '@api.global/typedsocket': 3.1.1(@push.rocks/smartserve@1.1.2) - '@cloudflare/workers-types': 4.20251202.0 + '@api.global/typedsocket': 3.1.1(@push.rocks/smartserve@1.3.0) + '@cloudflare/workers-types': 4.20251205.0 '@design.estate/dees-comms': 1.0.30 '@push.rocks/lik': 6.2.2 '@push.rocks/smartchok': 1.1.1 @@ -4346,7 +4346,7 @@ snapshots: - utf-8-validate - vue - '@api.global/typedsocket@3.1.1(@push.rocks/smartserve@1.1.2)': + '@api.global/typedsocket@3.1.1(@push.rocks/smartserve@1.3.0)': dependencies: '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 @@ -4357,7 +4357,7 @@ snapshots: '@push.rocks/smartstring': 4.1.0 '@push.rocks/smarturl': 3.1.0 optionalDependencies: - '@push.rocks/smartserve': 1.1.2 + '@push.rocks/smartserve': 1.3.0 transitivePeerDependencies: - '@nuxt/kit' - bufferutil @@ -4366,7 +4366,7 @@ snapshots: - utf-8-validate - vue - '@api.global/typedsocket@4.1.0(@push.rocks/smartserve@1.1.2)': + '@api.global/typedsocket@4.1.0(@push.rocks/smartserve@1.3.0)': dependencies: '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 @@ -4375,7 +4375,7 @@ snapshots: '@push.rocks/smartjson': 5.2.0 '@push.rocks/smartpromise': 4.2.3 '@push.rocks/smartrx': 3.0.10 - '@push.rocks/smartserve': 1.1.2 + '@push.rocks/smartserve': 1.3.0 '@push.rocks/smartstring': 4.1.0 '@push.rocks/smarturl': 3.1.0 @@ -5639,7 +5639,7 @@ snapshots: '@borewit/text-codec@0.1.1': {} - '@cloudflare/workers-types@4.20251202.0': {} + '@cloudflare/workers-types@4.20251205.0': {} '@configvault.io/interfaces@1.0.17': dependencies: @@ -6026,9 +6026,9 @@ snapshots: '@push.rocks/smartshell': 3.3.0 tsx: 4.20.6 - '@git.zone/tstest@3.1.3(@aws-sdk/credential-providers@3.787.0)(@push.rocks/smartserve@1.1.2)(socks@2.8.7)(typescript@5.9.3)': + '@git.zone/tstest@3.1.3(@aws-sdk/credential-providers@3.787.0)(@push.rocks/smartserve@1.3.0)(socks@2.8.7)(typescript@5.9.3)': dependencies: - '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.1.2) + '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.3.0) '@git.zone/tsbundle': 2.6.3 '@git.zone/tsrun': 2.0.0 '@push.rocks/consolecolor': 2.0.3 @@ -6874,7 +6874,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@push.rocks/smartserve@1.1.2': + '@push.rocks/smartserve@1.3.0': dependencies: '@api.global/typedrequest': 3.2.5 '@push.rocks/lik': 6.2.2 @@ -6907,7 +6907,7 @@ snapshots: '@push.rocks/smartsocket@2.1.0': dependencies: '@api.global/typedrequest-interfaces': 3.0.19 - '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.1.2) + '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.3.0) '@push.rocks/isohash': 2.0.1 '@push.rocks/isounique': 1.0.5 '@push.rocks/lik': 6.2.2 diff --git a/readme.md b/readme.md index 1a1487b..b62d3ef 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # @api.global/typedserver -A TypeScript-first web server framework for building modern full-stack applications. Features static file serving, live reload, type-safe API integration, service worker support, and edge computing capabilities. Part of the `@api.global` ecosystem. +A powerful TypeScript-first web server framework for building modern full-stack applications. Features static file serving, live reload, type-safe API integration, decorator-based routing, service worker support, and edge computing capabilities. Part of the `@api.global` ecosystem. ## Issue Reporting and Security @@ -9,13 +9,14 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community ## ✨ Features - πŸ”’ **Type-Safe API** - Full TypeScript support with `@api.global/typedrequest` and `@api.global/typedsocket` -- πŸ›‘οΈ **Security Headers** - Built-in CSP, HSTS, X-Frame-Options, and more +- 🎯 **Decorator Routing** - Clean, expressive routing with `@Route`, `@Get`, `@Post` decorators via smartserve +- πŸ›‘οΈ **Security Headers** - Built-in CSP, HSTS, X-Frame-Options, and comprehensive security configuration - ⚑ **Live Reload** - Automatic browser refresh on file changes during development - πŸ› οΈ **Service Worker** - Advanced caching, offline support, and background sync - ☁️ **Edge Workers** - Cloudflare Workers compatible edge computing with domain routing - πŸ“‘ **WebSocket** - Real-time bidirectional communication via TypedSocket - πŸ—ΊοΈ **SEO Tools** - Built-in sitemap, RSS feed, and robots.txt generation -- 🎯 **SPA Support** - Single-page application fallback routing (default in UtilityWebsiteServer) +- 🎯 **SPA Support** - Single-page application fallback routing - πŸ“± **PWA Ready** - Web App Manifest generation for progressive web apps ## πŸ“¦ Installation @@ -43,7 +44,7 @@ const server = new TypedServer({ }); await server.start(); -console.log('Server running!'); +console.log('Server running on port 3000!'); ``` ### Full Configuration @@ -86,6 +87,85 @@ const server = new TypedServer({ await server.start(); ``` +## πŸ›£οΈ Routing + +TypedServer uses a unified routing system powered by `@push.rocks/smartserve`. You can add routes using decorators or the programmatic API. + +### Decorator-Based Routing + +Create clean, expressive controllers using decorators: + +```typescript +import * as smartserve from '@push.rocks/smartserve'; + +@smartserve.Route('/api/users') +class UserController { + @smartserve.Get('/') + async listUsers(ctx: smartserve.IRequestContext): Promise { + const users = await getUsersFromDb(); + return new Response(JSON.stringify(users), { + headers: { 'Content-Type': 'application/json' }, + }); + } + + @smartserve.Get('/:id') + async getUser(ctx: smartserve.IRequestContext): Promise { + const userId = ctx.params.id; + const user = await getUserById(userId); + return new Response(JSON.stringify(user), { + headers: { 'Content-Type': 'application/json' }, + }); + } + + @smartserve.Post('/') + async createUser(ctx: smartserve.IRequestContext): Promise { + const userData = ctx.body; + const newUser = await createUserInDb(userData); + return new Response(JSON.stringify(newUser), { + status: 201, + headers: { 'Content-Type': 'application/json' }, + }); + } +} + +// Register the controller +smartserve.ControllerRegistry.registerInstance(new UserController()); +``` + +### Programmatic Routes with `addRoute()` + +Add routes dynamically using the `addRoute()` API: + +```typescript +import { TypedServer } from '@api.global/typedserver'; + +const server = new TypedServer({ serveDir: './public', cors: true }); + +// Simple route +server.addRoute('/api/health', 'GET', async (request) => { + return new Response(JSON.stringify({ status: 'ok' }), { + headers: { 'Content-Type': 'application/json' }, + }); +}); + +// Route with parameters (Express-style :param syntax) +server.addRoute('/api/items/:id', 'GET', async (request) => { + const itemId = (request as any).params.id; + return new Response(JSON.stringify({ id: itemId }), { + headers: { 'Content-Type': 'application/json' }, + }); +}); + +// Wildcard routes +server.addRoute('/files/*path', 'GET', async (request) => { + const filePath = (request as any).params.path; + // Handle file serving logic + return new Response(`Requested: ${filePath}`); +}); + +await server.start(); +``` + ## πŸ”Œ Type-Safe API Integration ### Adding TypedRequest Handlers @@ -139,20 +219,22 @@ server.typedrouter.addTypedHandler( await server.start(); // Push messages to connected clients -const connections = await server.typedsocket.findAllTargetConnectionsByTag('typedserver_frontend'); +const connections = await server.typedsocket.findAllTargetConnectionsByTag('allClients'); for (const conn of connections) { - // Push to specific clients + // Push to specific clients via TypedSocket } ``` ## ☁️ Edge Worker (Cloudflare Workers) +Deploy your application to the edge with Cloudflare Workers: + ```typescript import { EdgeWorker, DomainRouter } from '@api.global/typedserver/edgeworker'; const worker = new EdgeWorker(); -// Configure domain routing +// Configure domain routing with caching worker.domainRouter.addDomainInstruction({ domainPattern: '*.example.com', originUrl: 'https://origin.example.com', @@ -160,10 +242,11 @@ worker.domainRouter.addDomainInstruction({ cacheConfig: { maxAge: 3600 }, }); +// Pass-through to origin for API routes worker.domainRouter.addDomainInstruction({ domainPattern: 'api.example.com', originUrl: 'https://api-origin.example.com', - type: 'origin', // Pass through to origin + type: 'origin', }); // Cloudflare Worker entry point @@ -188,6 +271,7 @@ const swClient = await getServiceworkerClient({ // - Cache invalidation from server // - Offline support // - Background sync +// - Version updates ``` ## πŸ›‘οΈ Security Headers @@ -250,7 +334,7 @@ await server.start(); | `Strict-Transport-Security` | `hstsMaxAge`, `hstsIncludeSubDomains`, `hstsPreload` | Forces HTTPS connections | | `X-Frame-Options` | `xFrameOptions` | Prevents clickjacking attacks | | `X-Content-Type-Options` | `xContentTypeOptions` | Prevents MIME-sniffing | -| `X-XSS-Protection` | `xXssProtection` | Legacy XSS filter (still useful) | +| `X-XSS-Protection` | `xXssProtection` | Legacy XSS filter | | `Referrer-Policy` | `referrerPolicy` | Controls referrer information | | `Permissions-Policy` | `permissionsPolicy` | Controls browser features | | `Cross-Origin-Opener-Policy` | `crossOriginOpenerPolicy` | Isolates browsing context | @@ -281,7 +365,7 @@ await server.start(); | `defaultAnswer` | `function` | - | Custom default response handler | | `feedMetadata` | `object` | - | RSS feed metadata options | | `blockWaybackMachine` | `boolean` | `false` | Block Wayback Machine archiving | -| `securityHeaders` | `ISecurityHeaders` | - | Security headers configuration (CSP, HSTS, etc.) | +| `securityHeaders` | `ISecurityHeaders` | - | Security headers configuration | ## πŸ—οΈ Package Exports @@ -297,7 +381,7 @@ await server.start(); ## πŸ”„ Utility Servers -Pre-configured server templates with best practices built-in: +Pre-configured server templates with best practices built-in. ### UtilityWebsiteServer @@ -310,10 +394,10 @@ const websiteServer = new utilityservers.UtilityWebsiteServer({ serveDir: './dist', domain: 'example.com', - // SPA fallback enabled by default (serves index.html for client routes) + // SPA fallback enabled by default spaFallback: true, // default: true - // Optional security headers + // Security headers securityHeaders: { csp: { defaultSrc: ["'self'"], @@ -328,14 +412,34 @@ const websiteServer = new utilityservers.UtilityWebsiteServer({ cors: true, // default: true forceSsl: false, // default: false appSemVer: '1.0.0', + port: 3000, // default: 3000 + + // Optional ads.txt entries (only served if configured) + adsTxt: [ + 'google.com, pub-1234567890, DIRECT, f08c47fec0942fa0', + ], + + // RSS feed metadata + feedMetadata: { + title: 'My Blog', + description: 'A cool blog', + link: 'https://example.com', + }, + + // Add custom routes + addCustomRoutes: async (typedserver) => { + typedserver.addRoute('/api/custom', 'GET', async () => { + return new Response('Custom route!'); + }); + }, }); -await websiteServer.start(); // Default port 3000 +await websiteServer.start(); ``` ### UtilityServiceServer -Optimized for API services: +Optimized for API services with auto-generated info page: ```typescript import { utilityservers } from '@api.global/typedserver'; @@ -345,11 +449,42 @@ const serviceServer = new utilityservers.UtilityServiceServer({ serviceVersion: '1.0.0', serviceDomain: 'api.example.com', port: 8080, + + // Add custom routes + addCustomRoutes: async (typedserver) => { + typedserver.addRoute('/api/status', 'GET', async () => { + return new Response(JSON.stringify({ status: 'healthy' }), { + headers: { 'Content-Type': 'application/json' }, + }); + }); + }, }); await serviceServer.start(); ``` +## 🧩 Architecture Overview + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ TypedServer β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ SmartServe β”‚ β”‚ TypedRouter β”‚ β”‚ TypedSocket β”‚ β”‚ +β”‚ β”‚ (Routing) β”‚ β”‚ (RPC) β”‚ β”‚ (WebSocket) β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β–Ό β–Ό β–Ό β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ Request Handler Pipeline β”‚ β”‚ +β”‚ β”‚ 1. Controller Registry (Decorated Routes) β”‚ β”‚ +β”‚ β”‚ 2. TypedRequest/TypedSocket handlers β”‚ β”‚ +β”‚ β”‚ 3. Static File Serving β”‚ β”‚ +β”‚ β”‚ 4. SPA Fallback β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + ## License and Legal Information This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file. diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 70bfa26..9812f17 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@api.global/typedserver', - version: '7.10.1', + version: '7.10.2', description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.' }