fix(readme): Update README to reflect new features and updated examples (SPA/PWA/Edge/ServiceWorker) and clarify API usage
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-12-05 - 7.8.18 - fix(readme)
|
||||
Update README to reflect new features and updated examples (SPA/PWA/Edge/ServiceWorker) and clarify API usage
|
||||
|
||||
- Rewrite project introduction and features list to highlight Service Worker, Edge Workers, SPA support, and PWA readiness
|
||||
- Replace and expand example sections: Basic Server, Full Configuration, TypedRequest handlers, WebSocket usage, Edge Worker entrypoint, and Service Worker client usage
|
||||
- Update configuration reference: remove legacy compression flags, add spaFallback, defaultAnswer, feedMetadata, and blockWaybackMachine options
|
||||
- Document package exports and add examples for utility servers (WebsiteServer, ServiceServer)
|
||||
- Clarify TypedRequest/TypedSocket usage by showing server.typedrouter and service worker client initializer (getServiceworkerClient)
|
||||
|
||||
## 2025-12-04 - 7.8.11 - fix(web_inject)
|
||||
Improve logging in web injection (TypedRequest) and update dees-comms dependency
|
||||
|
||||
|
||||
195
readme.md
195
readme.md
@@ -1,6 +1,6 @@
|
||||
# @api.global/typedserver
|
||||
|
||||
A powerful TypeScript-first web server framework featuring static file serving, live reload, compression, and seamless type-safe API integration. Part of the `@api.global` ecosystem, it provides a modern foundation for building full-stack TypeScript applications with first-class support for typed HTTP requests and WebSocket communication.
|
||||
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.
|
||||
|
||||
## Issue Reporting and Security
|
||||
|
||||
@@ -8,15 +8,14 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🔒 **Type-Safe API Ecosystem** - Full TypeScript support with `@api.global/typedrequest` and `@api.global/typedsocket`
|
||||
- 🔒 **Type-Safe API** - Full TypeScript support with `@api.global/typedrequest` and `@api.global/typedsocket`
|
||||
- ⚡ **Live Reload** - Automatic browser refresh on file changes during development
|
||||
- 🗜️ **Compression** - Built-in support for gzip, deflate, and brotli compression
|
||||
- 🌐 **CORS Management** - Flexible cross-origin resource sharing configuration
|
||||
- 🔧 **Service Worker Integration** - Advanced caching and offline capabilities
|
||||
- ☁️ **Edge Worker Support** - Cloudflare Workers compatible edge computing
|
||||
- 📡 **WebSocket Support** - Real-time bidirectional communication via TypedSocket
|
||||
- 🗺️ **Sitemap & Feeds** - Automatic sitemap and RSS feed generation
|
||||
- 🤖 **Robots.txt** - Built-in robots.txt handling
|
||||
- 🛠️ **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
|
||||
- 📱 **PWA Ready** - Web App Manifest generation for progressive web apps
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
@@ -30,7 +29,7 @@ npm install @api.global/typedserver
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Basic Static File Server
|
||||
### Basic Server
|
||||
|
||||
```typescript
|
||||
import { TypedServer } from '@api.global/typedserver';
|
||||
@@ -43,10 +42,10 @@ const server = new TypedServer({
|
||||
});
|
||||
|
||||
await server.start();
|
||||
console.log('Server running on port 3000');
|
||||
console.log('Server running!');
|
||||
```
|
||||
|
||||
### Server with All Options
|
||||
### Full Configuration
|
||||
|
||||
```typescript
|
||||
import { TypedServer } from '@api.global/typedserver';
|
||||
@@ -55,15 +54,23 @@ const server = new TypedServer({
|
||||
port: 8080,
|
||||
serveDir: './dist',
|
||||
cors: true,
|
||||
|
||||
// Development
|
||||
watch: true,
|
||||
injectReload: true,
|
||||
enableCompression: true,
|
||||
preferredCompressionMethod: 'brotli',
|
||||
forceSsl: false,
|
||||
|
||||
// Production
|
||||
forceSsl: true,
|
||||
spaFallback: true, // Serve index.html for client-side routes
|
||||
|
||||
// SEO
|
||||
sitemap: true,
|
||||
feed: true,
|
||||
robots: true,
|
||||
domain: 'example.com',
|
||||
blockWaybackMachine: false,
|
||||
|
||||
// PWA
|
||||
appVersion: 'v1.0.0',
|
||||
manifest: {
|
||||
name: 'My App',
|
||||
@@ -83,11 +90,11 @@ await server.start();
|
||||
### Adding TypedRequest Handlers
|
||||
|
||||
```typescript
|
||||
import { TypedServer, servertools } from '@api.global/typedserver';
|
||||
import { TypedServer } from '@api.global/typedserver';
|
||||
import * as typedrequest from '@api.global/typedrequest';
|
||||
|
||||
// Define your typed request interface
|
||||
interface IGetUser {
|
||||
interface IGetUser extends typedrequest.implementsTR<IGetUser> {
|
||||
method: 'getUser';
|
||||
request: { userId: string };
|
||||
response: { name: string; email: string };
|
||||
@@ -95,94 +102,46 @@ interface IGetUser {
|
||||
|
||||
const server = new TypedServer({ serveDir: './public', cors: true });
|
||||
|
||||
// Create a typed router
|
||||
const typedRouter = new typedrequest.TypedRouter();
|
||||
|
||||
// Add a typed handler
|
||||
typedRouter.addTypedHandler<IGetUser>(
|
||||
// Add a typed handler directly to the server's router
|
||||
server.typedrouter.addTypedHandler<IGetUser>(
|
||||
new typedrequest.TypedHandler('getUser', async (data) => {
|
||||
// Your logic here
|
||||
return { name: 'John Doe', email: 'john@example.com' };
|
||||
})
|
||||
);
|
||||
|
||||
// Attach the router to the server
|
||||
server.server.addRoute('/api', new servertools.HandlerTypedRouter(typedRouter));
|
||||
|
||||
await server.start();
|
||||
```
|
||||
|
||||
### WebSocket Communication with TypedSocket
|
||||
### Real-Time WebSocket Communication
|
||||
|
||||
TypedServer automatically sets up TypedSocket for real-time communication:
|
||||
|
||||
```typescript
|
||||
import { TypedServer } from '@api.global/typedserver';
|
||||
import * as typedrequest from '@api.global/typedrequest';
|
||||
import * as typedsocket from '@api.global/typedsocket';
|
||||
|
||||
const server = new TypedServer({ serveDir: './public', cors: true });
|
||||
const typedRouter = new typedrequest.TypedRouter();
|
||||
|
||||
await server.start();
|
||||
|
||||
// Create WebSocket server attached to the HTTP server
|
||||
const socketServer = await typedsocket.TypedSocket.createServer(
|
||||
typedRouter,
|
||||
server.server
|
||||
);
|
||||
|
||||
// Handle real-time events
|
||||
interface IChatMessage {
|
||||
interface IChatMessage extends typedrequest.implementsTR<IChatMessage> {
|
||||
method: 'sendMessage';
|
||||
request: { text: string; room: string };
|
||||
response: { messageId: string; timestamp: number };
|
||||
}
|
||||
|
||||
typedRouter.addTypedHandler<IChatMessage>(
|
||||
const server = new TypedServer({ serveDir: './public', cors: true });
|
||||
|
||||
// Handle real-time messages
|
||||
server.typedrouter.addTypedHandler<IChatMessage>(
|
||||
new typedrequest.TypedHandler('sendMessage', async (data) => {
|
||||
return { messageId: crypto.randomUUID(), timestamp: Date.now() };
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
## 🛠️ Server Tools
|
||||
await server.start();
|
||||
|
||||
### Custom Route Handlers
|
||||
|
||||
```typescript
|
||||
import { servertools } from '@api.global/typedserver';
|
||||
|
||||
const server = new servertools.Server({
|
||||
cors: true,
|
||||
domain: 'example.com',
|
||||
});
|
||||
|
||||
// Add a custom route with handler
|
||||
server.addRoute('/api/hello', new servertools.Handler('GET', async (req, res) => {
|
||||
res.json({ message: 'Hello, World!' });
|
||||
}));
|
||||
|
||||
// Serve static files from a directory
|
||||
server.addRoute('/{*splat}', new servertools.HandlerStatic('./public', {
|
||||
serveIndexHtmlDefault: true,
|
||||
enableCompression: true,
|
||||
}));
|
||||
|
||||
await server.start(3000);
|
||||
```
|
||||
|
||||
### Proxy Handler
|
||||
|
||||
```typescript
|
||||
import { servertools } from '@api.global/typedserver';
|
||||
|
||||
const server = new servertools.Server({ cors: true });
|
||||
|
||||
// Proxy requests to another server
|
||||
server.addRoute('/proxy/{*splat}', new servertools.HandlerProxy({
|
||||
target: 'https://api.example.com',
|
||||
}));
|
||||
|
||||
await server.start(3000);
|
||||
// Push messages to connected clients
|
||||
const connections = await server.typedsocket.findAllTargetConnectionsByTag('typedserver_frontend');
|
||||
for (const conn of connections) {
|
||||
// Push to specific clients
|
||||
}
|
||||
```
|
||||
|
||||
## ☁️ Edge Worker (Cloudflare Workers)
|
||||
@@ -190,36 +149,44 @@ await server.start(3000);
|
||||
```typescript
|
||||
import { EdgeWorker, DomainRouter } from '@api.global/typedserver/edgeworker';
|
||||
|
||||
const router = new DomainRouter();
|
||||
const worker = new EdgeWorker();
|
||||
|
||||
router.addDomainInstruction({
|
||||
// Configure domain routing
|
||||
worker.domainRouter.addDomainInstruction({
|
||||
domainPattern: '*.example.com',
|
||||
originUrl: 'https://origin.example.com',
|
||||
type: 'cache',
|
||||
cacheConfig: { maxAge: 3600 },
|
||||
});
|
||||
|
||||
const worker = new EdgeWorker(router);
|
||||
worker.domainRouter.addDomainInstruction({
|
||||
domainPattern: 'api.example.com',
|
||||
originUrl: 'https://api-origin.example.com',
|
||||
type: 'origin', // Pass through to origin
|
||||
});
|
||||
|
||||
// In your Cloudflare Worker entry point
|
||||
// Cloudflare Worker entry point
|
||||
export default {
|
||||
fetch: (request: Request, env: any, ctx: any) => worker.handleRequest(request, env, ctx),
|
||||
fetch: worker.fetchFunction.bind(worker),
|
||||
};
|
||||
```
|
||||
|
||||
## 🔧 Service Worker Client
|
||||
|
||||
Manage service workers in your frontend application:
|
||||
|
||||
```typescript
|
||||
import { ServiceWorkerClient } from '@api.global/typedserver/web_serviceworker_client';
|
||||
import { getServiceworkerClient } from '@api.global/typedserver/web_serviceworker_client';
|
||||
|
||||
const swClient = new ServiceWorkerClient();
|
||||
|
||||
// Register and manage service worker
|
||||
await swClient.register('/serviceworker.bundle.js');
|
||||
|
||||
// Listen for updates
|
||||
swClient.onUpdate(() => {
|
||||
console.log('New version available!');
|
||||
// Initialize and register service worker
|
||||
const swClient = await getServiceworkerClient({
|
||||
pollInterval: 30000, // Poll for updates every 30s
|
||||
});
|
||||
|
||||
// The service worker handles:
|
||||
// - Cache invalidation from server
|
||||
// - Offline support
|
||||
// - Background sync
|
||||
```
|
||||
|
||||
## 📋 Configuration Reference
|
||||
@@ -233,9 +200,8 @@ swClient.onUpdate(() => {
|
||||
| `cors` | `boolean` | `true` | Enable CORS headers |
|
||||
| `watch` | `boolean` | `false` | Watch files for changes |
|
||||
| `injectReload` | `boolean` | `false` | Inject live reload script into HTML |
|
||||
| `enableCompression` | `boolean` | `false` | Enable response compression |
|
||||
| `preferredCompressionMethod` | `'gzip' \| 'deflate' \| 'brotli'` | - | Preferred compression algorithm |
|
||||
| `forceSsl` | `boolean` | `false` | Redirect HTTP to HTTPS |
|
||||
| `spaFallback` | `boolean` | `false` | Serve index.html for non-file routes |
|
||||
| `sitemap` | `boolean` | `false` | Generate sitemap at `/sitemap` |
|
||||
| `feed` | `boolean` | `false` | Generate RSS feed at `/feed` |
|
||||
| `robots` | `boolean` | `false` | Serve robots.txt |
|
||||
@@ -244,16 +210,39 @@ swClient.onUpdate(() => {
|
||||
| `manifest` | `object` | - | Web App Manifest configuration |
|
||||
| `publicKey` | `string` | - | SSL certificate |
|
||||
| `privateKey` | `string` | - | SSL private key |
|
||||
| `defaultAnswer` | `function` | - | Custom default response handler |
|
||||
| `feedMetadata` | `object` | - | RSS feed metadata options |
|
||||
| `blockWaybackMachine` | `boolean` | `false` | Block Wayback Machine archiving |
|
||||
|
||||
## 🏗️ Architecture
|
||||
## 🏗️ Package Exports
|
||||
|
||||
```
|
||||
@api.global/typedserver
|
||||
├── /backend - Main server exports (TypedServer, servertools)
|
||||
├── /edgeworker - Cloudflare Workers edge computing
|
||||
├── /web_inject - Live reload script injection
|
||||
├── /web_serviceworker - Service Worker implementation
|
||||
└── /web_serviceworker_client - Service Worker client utilities
|
||||
├── . - Main server (TypedServer)
|
||||
├── /backend - Alias for main server
|
||||
├── /edgeworker - Cloudflare Workers edge computing
|
||||
├── /web_inject - Live reload script injection
|
||||
├── /web_serviceworker - Service Worker implementation
|
||||
└── /web_serviceworker_client - Service Worker client utilities
|
||||
```
|
||||
|
||||
## 🔄 Utility Servers
|
||||
|
||||
Pre-configured server templates for common use cases:
|
||||
|
||||
```typescript
|
||||
import { utilityservers } from '@api.global/typedserver';
|
||||
|
||||
// WebsiteServer - optimized for static websites
|
||||
const websiteServer = new utilityservers.WebsiteServer({
|
||||
serveDir: './dist',
|
||||
domain: 'example.com',
|
||||
});
|
||||
|
||||
// ServiceServer - optimized for API services
|
||||
const serviceServer = new utilityservers.ServiceServer({
|
||||
cors: true,
|
||||
});
|
||||
```
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@api.global/typedserver',
|
||||
version: '7.8.11',
|
||||
version: '7.8.18',
|
||||
description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user