feat(typedserver): Add configurable security headers and default SPA behavior
Introduce structured security headers support (CSP, HSTS, X-Frame-Options, COOP/COEP/CORP, Permissions-Policy, Referrer-Policy, X-XSS-Protection, etc.) and apply them to responses and OPTIONS preflight. Expose configuration via the server API and document usage. Also update UtilityWebsiteServer defaults (SPA fallback enabled by default) and related docs.
This commit is contained in:
119
readme.md
119
readme.md
@@ -9,12 +9,13 @@ 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
|
||||
- ⚡ **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
|
||||
- 🎯 **SPA Support** - Single-page application fallback routing (default in UtilityWebsiteServer)
|
||||
- 📱 **PWA Ready** - Web App Manifest generation for progressive web apps
|
||||
|
||||
## 📦 Installation
|
||||
@@ -189,6 +190,73 @@ const swClient = await getServiceworkerClient({
|
||||
// - Background sync
|
||||
```
|
||||
|
||||
## 🛡️ Security Headers
|
||||
|
||||
Configure comprehensive security headers including CSP, HSTS, and more:
|
||||
|
||||
```typescript
|
||||
import { TypedServer } from '@api.global/typedserver';
|
||||
|
||||
const server = new TypedServer({
|
||||
serveDir: './dist',
|
||||
cors: true,
|
||||
|
||||
securityHeaders: {
|
||||
// Content Security Policy
|
||||
csp: {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'", "'unsafe-inline'", 'https://cdn.example.com'],
|
||||
styleSrc: ["'self'", "'unsafe-inline'"],
|
||||
imgSrc: ["'self'", 'data:', 'https:'],
|
||||
connectSrc: ["'self'", 'wss:', 'https://api.example.com'],
|
||||
fontSrc: ["'self'", 'https://fonts.gstatic.com'],
|
||||
frameAncestors: ["'none'"],
|
||||
upgradeInsecureRequests: true,
|
||||
},
|
||||
|
||||
// HSTS (HTTP Strict Transport Security)
|
||||
hstsMaxAge: 31536000, // 1 year
|
||||
hstsIncludeSubDomains: true,
|
||||
hstsPreload: true,
|
||||
|
||||
// Other security headers
|
||||
xFrameOptions: 'DENY',
|
||||
xContentTypeOptions: true,
|
||||
xXssProtection: true,
|
||||
referrerPolicy: 'strict-origin-when-cross-origin',
|
||||
|
||||
// Cross-Origin policies
|
||||
crossOriginOpenerPolicy: 'same-origin',
|
||||
crossOriginEmbedderPolicy: 'require-corp',
|
||||
crossOriginResourcePolicy: 'same-origin',
|
||||
|
||||
// Permissions Policy
|
||||
permissionsPolicy: {
|
||||
camera: [],
|
||||
microphone: [],
|
||||
geolocation: ['self'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await server.start();
|
||||
```
|
||||
|
||||
### Security Headers Reference
|
||||
|
||||
| Header | Option | Description |
|
||||
|--------|--------|-------------|
|
||||
| `Content-Security-Policy` | `csp` | Controls resources the browser can load |
|
||||
| `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) |
|
||||
| `Referrer-Policy` | `referrerPolicy` | Controls referrer information |
|
||||
| `Permissions-Policy` | `permissionsPolicy` | Controls browser features |
|
||||
| `Cross-Origin-Opener-Policy` | `crossOriginOpenerPolicy` | Isolates browsing context |
|
||||
| `Cross-Origin-Embedder-Policy` | `crossOriginEmbedderPolicy` | Controls cross-origin embedding |
|
||||
| `Cross-Origin-Resource-Policy` | `crossOriginResourcePolicy` | Controls cross-origin resource sharing |
|
||||
|
||||
## 📋 Configuration Reference
|
||||
|
||||
### IServerOptions
|
||||
@@ -213,6 +281,7 @@ const swClient = await getServiceworkerClient({
|
||||
| `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.) |
|
||||
|
||||
## 🏗️ Package Exports
|
||||
|
||||
@@ -228,21 +297,57 @@ const swClient = await getServiceworkerClient({
|
||||
|
||||
## 🔄 Utility Servers
|
||||
|
||||
Pre-configured server templates for common use cases:
|
||||
Pre-configured server templates with best practices built-in:
|
||||
|
||||
### UtilityWebsiteServer
|
||||
|
||||
Optimized for modern web applications with SPA support enabled by default:
|
||||
|
||||
```typescript
|
||||
import { utilityservers } from '@api.global/typedserver';
|
||||
|
||||
// WebsiteServer - optimized for static websites
|
||||
const websiteServer = new utilityservers.WebsiteServer({
|
||||
const websiteServer = new utilityservers.UtilityWebsiteServer({
|
||||
serveDir: './dist',
|
||||
domain: 'example.com',
|
||||
|
||||
// SPA fallback enabled by default (serves index.html for client routes)
|
||||
spaFallback: true, // default: true
|
||||
|
||||
// Optional security headers
|
||||
securityHeaders: {
|
||||
csp: {
|
||||
defaultSrc: ["'self'"],
|
||||
scriptSrc: ["'self'", "'unsafe-inline'"],
|
||||
styleSrc: ["'self'", "'unsafe-inline'"],
|
||||
},
|
||||
xFrameOptions: 'SAMEORIGIN',
|
||||
xContentTypeOptions: true,
|
||||
},
|
||||
|
||||
// Other options
|
||||
cors: true, // default: true
|
||||
forceSsl: false, // default: false
|
||||
appSemVer: '1.0.0',
|
||||
});
|
||||
|
||||
// ServiceServer - optimized for API services
|
||||
const serviceServer = new utilityservers.ServiceServer({
|
||||
cors: true,
|
||||
await websiteServer.start(); // Default port 3000
|
||||
```
|
||||
|
||||
### UtilityServiceServer
|
||||
|
||||
Optimized for API services:
|
||||
|
||||
```typescript
|
||||
import { utilityservers } from '@api.global/typedserver';
|
||||
|
||||
const serviceServer = new utilityservers.UtilityServiceServer({
|
||||
serviceName: 'My API',
|
||||
serviceVersion: '1.0.0',
|
||||
serviceDomain: 'api.example.com',
|
||||
port: 8080,
|
||||
});
|
||||
|
||||
await serviceServer.start();
|
||||
```
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
Reference in New Issue
Block a user