DeployCode Deployment
Deploy as APIs
Expose MDX Functions as REST or RPC APIs
Deploy MDX Functions as APIs
Documentation Status: This documentation describes the planned API design for the .do platform. Code examples represent the intended interface and may not reflect the current implementation state. See roadmap for implementation status.
Transform your MDX functions into production-ready APIs with automatic documentation, authentication, rate limiting, and monitoring.
Overview
When you deploy MDX functions as APIs, you get:
- Automatic REST endpoints - Functions become HTTP endpoints
- RPC support - Type-safe RPC with automatic client generation
- Auto-generated docs - OpenAPI/Swagger documentation
- Built-in auth - JWT, OAuth, API keys
- Rate limiting - Protect your APIs from abuse
- Monitoring - Real-time metrics and logging
flowchart TB
A[MDX Functions] --> B[API Deployment]
B --> C[REST Endpoints]
B --> D[RPC Endpoints]
C --> E[Route Mapping]
D --> F[Type Generation]
E --> G[Authentication]
F --> G
G --> H[Rate Limiting]
H --> I[Request Handling]
I --> J[Response]
J --> K[OpenAPI Docs]
J --> L[Monitoring]
J --> M[Logging]
Creating APIs from MDX
Basic REST API
---
title: User Management API
description: CRUD operations for users
---
export async function getUser(id: string) {
return await $.db.users.findById(id)
}
export async function createUser(data: { email: string; name: string }) {
// Validate
if (!data.email || !data.name) {
throw new Error('Email and name are required')
}
// Create user
const user = await $.db.users.create({
...data,
createdAt: new Date(),
status: 'active'
})
// Send welcome email
await $.email.send.message({
to: user.email,
subject: 'Welcome!',
template: 'welcome',
data: { name: user.name }
})
return user
}
export async function updateUser(id: string, data: Partial<User>) {
return await $.db.users.update(id, data)
}
export async function deleteUser(id: string) {
return await $.db.users.delete(id)
}
export async function listUsers(params: { page?: number; limit?: number }) {
return await $.db.users.find({
limit: params.limit || 20,
offset: ((params.page || 1) - 1) * (params.limit || 20)
})
}Deploy as REST API
// Automatic REST endpoint generation
import { createUser, getUser, updateUser, deleteUser, listUsers } from './users.mdx'
export default {
apis: {
'/api/users': {
GET: listUsers,
POST: createUser,
},
'/api/users/:id': {
GET: getUser,
PUT: updateUser,
DELETE: deleteUser,
},
},
}The platform automatically generates:
GET /api/users # List users
POST /api/users # Create user
GET /api/users/:id # Get user by ID
PUT /api/users/:id # Update user
DELETE /api/users/:id # Delete userRPC API
Type-Safe RPC
---
title: Product Service
description: Product catalog operations
---
export interface Product {
id: string
name: string
price: number
category: string
inStock: boolean
}
export interface SearchParams {
query?: string
category?: string
minPrice?: number
maxPrice?: number
inStockOnly?: boolean
}
export async function searchProducts(params: SearchParams): Promise<Product[]> {
let query = $.db.products.find()
if (params.query) {
query = query.where('name', 'like', `%${params.query}%`)
}
if (params.category) {
query = query.where('category', '=', params.category)
}
if (params.minPrice) {
query = query.where('price', '>=', params.minPrice)
}
if (params.maxPrice) {
query = query.where('price', '<=', params.maxPrice)
}
if (params.inStockOnly) {
query = query.where('inStock', '=', true)
}
return await query.execute()
}
export async function getProductById(id: string): Promise<Product | null> {
return await $.db.products.findById(id)
}RPC Client Generation
The platform automatically generates type-safe clients:
// Auto-generated client
import { client } from 'sdk.do'
const api = client('https://api.example.do')
// Type-safe RPC calls
const products = await api.searchProducts({
category: 'electronics',
minPrice: 100,
inStockOnly: true,
})
const product = await api.getProductById('prod_123')Authentication
API Key Authentication
export default {
apis: {
'/api/protected': {
GET: myFunction,
auth: {
type: 'api_key',
header: 'X-API-Key',
},
},
},
}JWT Authentication
export default {
apis: {
'/api/user/profile': {
GET: getUserProfile,
auth: {
type: 'jwt',
secret: process.env.JWT_SECRET,
required: true,
},
},
},
}OAuth
export default {
apis: {
'/api/oauth/callback': {
GET: handleOAuthCallback,
auth: {
type: 'oauth',
provider: 'github',
scopes: ['user:email', 'read:org'],
},
},
},
}Rate Limiting
Protect your APIs from abuse:
export default {
apis: {
'/api/expensive-operation': {
POST: expensiveFunction,
rateLimit: {
requests: 10,
window: '1m',
by: 'ip', // or 'user', 'api_key'
},
},
'/api/frequent-calls': {
GET: frequentFunction,
rateLimit: {
requests: 1000,
window: '1h',
by: 'api_key',
},
},
},
}Automatic Documentation
OpenAPI Generation
The platform automatically generates OpenAPI 3.0 specs:
// Access at /api/docs
export default {
apis: {
'/api/users': {
POST: createUser,
},
},
docs: {
enabled: true,
title: 'User Management API',
version: '1.0.0',
description: 'API for managing users',
servers: [
{ url: 'https://api.example.do', description: 'Production' },
{ url: 'https://staging.example.do', description: 'Staging' },
],
},
}JSDoc Annotations
Add documentation directly in your MDX:
/\*\*
- Create a new user account
-
- @param data - User data
- @param data.email - User's email address
- @param data.name - User's full name
- @returns Created user object
- @throws {ValidationError} If email or name is invalid
-
- @example
- ```typescript
```
- const user = await createUser({
- email: '[email protected]',
- name: 'John Doe'
- })
- ```
*/
export async function createUser(data: { email: string; name: string }) {
// Implementation
}
```Validation
Input Validation
import { z } from 'zod'
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
age: z.number().min(18).optional()
})
export async function createUser(data: unknown) {
// Automatic validation
const validated = CreateUserSchema.parse(data)
return await $.db.users.create(validated)
}Output Validation
const UserOutputSchema = z.object({
id: z.string(),
email: z.string().email(),
name: z.string(),
createdAt: z.date()
})
export async function getUser(id: string) {
const user = await $.db.users.findById(id)
// Ensure output matches schema
return UserOutputSchema.parse(user)
}Error Handling
Structured Errors
export class ValidationError extends Error {
constructor(message: string, public field: string) {
super(message)
this.name = 'ValidationError'
}
}
export class NotFoundError extends Error {
constructor(resource: string, id: string) {
super(`${resource} not found: ${id}`)
this.name = 'NotFoundError'
}
}
export async function getUser(id: string) {
const user = await $.db.users.findById(id)
if (!user) {
throw new NotFoundError('User', id)
}
return user
}The platform automatically maps errors to HTTP status codes:
// Automatic error mapping
ValidationError -> 400 Bad Request
NotFoundError -> 404 Not Found
UnauthorizedError -> 401 Unauthorized
ForbiddenError -> 403 Forbidden
Error -> 500 Internal Server ErrorVersioning
graph LR
A[Client Request] --> B{API Version}
B -->|v1| C[v1 Endpoints]
B -->|v2| D[v2 Endpoints]
C --> E[Legacy Implementation]
D --> F[Current Implementation]
E --> G[Response]
F --> G
API Versions
export default {
apis: {
v1: {
'/api/users': {
GET: v1_listUsers,
POST: v1_createUser,
},
},
v2: {
'/api/users': {
GET: v2_listUsers,
POST: v2_createUser,
},
},
},
}Accessible at:
/v1/api/users/v2/api/users
Caching
Response Caching
export default {
apis: {
'/api/products': {
GET: listProducts,
cache: {
ttl: 3600, // 1 hour
key: (req) => `products:${req.query.category}`,
invalidateOn: ['product.created', 'product.updated'],
},
},
},
}Webhooks
Expose Webhooks
---
title: Stripe Webhook Handler
description: Handle Stripe webhook events
---
export async function handleStripeWebhook(event: StripeEvent) {
// Verify signature
const signature = event.headers['stripe-signature']
const verified = await $.stripe.verify(event.body, signature)
if (!verified) {
throw new Error('Invalid signature')
}
// Handle different event types
switch (event.type) {
case 'payment_intent.succeeded':
await handlePaymentSuccess(event.data)
break
case 'payment_intent.failed':
await handlePaymentFailure(event.data)
break
case 'customer.subscription.updated':
await handleSubscriptionUpdate(event.data)
break
}
return { received: true }
}export default {
apis: {
'/webhooks/stripe': {
POST: handleStripeWebhook,
rateLimit: {
requests: 1000,
window: '1m',
},
},
},
}Monitoring
API Metrics
// Access real-time metrics
const metrics = await $.api.metrics.get('/api/users', {
period: 'last_24h',
})
console.log({
requests: metrics.total,
successRate: metrics.successRate,
averageLatency: metrics.avgLatency,
p95Latency: metrics.p95,
errors: metrics.errors,
})Deployment Configuration
// do.config.ts
export default {
apis: [
{
name: 'user-api',
source: './api/users.mdx',
deployment: {
domain: 'api.example.do',
basePath: '/v1',
cors: {
origin: ['https://example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
},
rateLimit: {
global: {
requests: 10000,
window: '1h',
},
},
timeout: 30000,
},
environment: {
DATABASE_URL: process.env.DATABASE_URL,
JWT_SECRET: process.env.JWT_SECRET,
API_KEY: process.env.API_KEY,
},
},
],
}Best Practices
Security
- Always validate inputs
- Use authentication for sensitive endpoints
- Implement rate limiting
- Sanitize error messages (don't leak sensitive data)
- Use HTTPS in production
Performance
- Implement caching where appropriate
- Use pagination for large datasets
- Optimize database queries
- Set appropriate timeouts
- Monitor and optimize slow endpoints
Documentation
- Add JSDoc comments to all functions
- Provide usage examples
- Document error responses
- Keep OpenAPI spec up to date
Production Deployment
Deployment Strategies
// Production API deployment configuration
export default {
apis: [
{
name: 'production-api',
source: './api/index.mdx',
deployment: {
strategy: 'rolling', // 'rolling' | 'blue-green' | 'canary'
// Rolling deployment
rolling: {
enabled: true,
maxSurge: '25%', // Max number of instances above desired count
maxUnavailable: '25%', // Max number of instances unavailable during update
healthCheckGracePeriod: 30000,
},
// Blue-green deployment
blueGreen: {
enabled: false,
healthCheckUrl: '/health',
testTrafficPercent: 10,
switchoverAfter: '5m',
},
// Canary deployment
canary: {
enabled: false,
steps: [
{ weight: 5, duration: '2m' },
{ weight: 25, duration: '5m' },
{ weight: 50, duration: '10m' },
{ weight: 100 },
],
successMetrics: {
errorRate: { max: 0.01 },
latency: { p99: 1000 },
},
},
},
},
],
}Health & Readiness Endpoints
---
title: API Health Checks
description: Health and readiness endpoints
---
export async function healthCheck() {
const checks = {
database: await checkDatabase(),
cache: await checkCache(),
externalAPIs: await checkExternalAPIs(),
}
const isHealthy = Object.values(checks).every(check => check.status === 'healthy')
return {
status: isHealthy ? 'healthy' : 'unhealthy',
timestamp: new Date().toISOString(),
version: process.env.APP_VERSION,
checks,
}
}
export async function readinessCheck() {
// Readiness means ready to accept traffic
const ready = {
database: await isDatabaseReady(),
migrations: await areMigrationsComplete(),
cache: await isCacheWarmed(),
}
return {
ready: Object.values(ready).every(Boolean),
checks: ready,
}
}
export async function livenessCheck() {
// Liveness means process is running and not deadlocked
return {
alive: true,
uptime: process.uptime(),
memory: process.memoryUsage(),
}
}
async function checkDatabase() {
try {
const start = Date.now()
await $.db.raw('SELECT 1')
return {
status: 'healthy',
latency: Date.now() - start,
}
} catch (error) {
return {
status: 'unhealthy',
error: error.message,
}
}
}
async function checkCache() {
try {
const start = Date.now()
await $.cache.ping()
return {
status: 'healthy',
latency: Date.now() - start,
}
} catch (error) {
return {
status: 'degraded',
error: error.message,
}
}
}API Gateway Configuration
export default {
apis: [
{
name: 'production-api',
gateway: {
// Load balancing
loadBalancer: {
algorithm: 'round-robin', // 'round-robin' | 'least-connections' | 'ip-hash'
healthCheck: {
enabled: true,
interval: 30000,
timeout: 5000,
unhealthyThreshold: 3,
healthyThreshold: 2,
},
stickySession: {
enabled: true,
cookieName: 'SESSION_ID',
ttl: 86400,
},
},
// Circuit breaker
circuitBreaker: {
enabled: true,
errorThreshold: 50, // % errors to open circuit
timeout: 30000, // Time to wait before retry
resetTimeout: 60000, // Time before attempting to close circuit
},
// Request/Response transformation
transform: {
request: {
headers: {
add: { 'X-API-Version': '1.0' },
remove: ['X-Internal-Header'],
},
},
response: {
headers: {
add: {
'X-Response-Time': '${latency}ms',
'X-Request-ID': '${requestId}',
},
},
},
},
// Caching
cache: {
enabled: true,
ttl: 300, // 5 minutes
varyBy: ['Accept', 'Authorization'],
cacheableStatusCodes: [200, 203, 204, 206, 300, 301],
bypassHeader: 'X-Cache-Bypass',
},
},
},
],
}Rate Limiting & Quotas
export default {
apis: [
{
name: 'production-api',
rateLimit: {
// Global rate limit
global: {
requests: 10000,
window: '1h',
strategy: 'sliding-window',
},
// Per-user rate limit
perUser: {
requests: 1000,
window: '1h',
keyExtractor: (req) => req.user?.id,
},
// Per-IP rate limit
perIP: {
requests: 100,
window: '15m',
keyExtractor: (req) => req.ip,
},
// Endpoint-specific limits
endpoints: {
'POST /api/expensive': {
requests: 10,
window: '1m',
},
'GET /api/search': {
requests: 100,
window: '1m',
},
},
// Quota management
quotas: {
free: {
requests: 1000,
period: 'month',
resetOn: 1, // day of month
},
pro: {
requests: 50000,
period: 'month',
},
enterprise: {
requests: -1, // unlimited
},
},
// Response headers
headers: {
limit: 'X-RateLimit-Limit',
remaining: 'X-RateLimit-Remaining',
reset: 'X-RateLimit-Reset',
},
// Exceeded behavior
onExceeded: {
statusCode: 429,
message: 'Rate limit exceeded',
retryAfter: true,
},
},
},
],
}API Monitoring & Observability
export default {
apis: [
{
name: 'production-api',
monitoring: {
// Metrics collection
metrics: {
enabled: true,
interval: 30000,
metrics: [
// Request metrics
'http_requests_total',
'http_request_duration_seconds',
'http_response_size_bytes',
'http_request_size_bytes',
// Application metrics
'api_errors_total',
'api_success_rate',
'api_endpoint_calls',
// Resource metrics
'nodejs_memory_usage',
'nodejs_cpu_usage',
'nodejs_event_loop_lag',
],
labels: ['method', 'endpoint', 'status_code', 'user_tier'],
},
// Distributed tracing
tracing: {
enabled: true,
provider: 'opentelemetry',
endpoint: 'https://traces.example.do',
sampleRate: 1.0,
propagation: ['w3c', 'b3'],
includeDB: true,
includeExternal: true,
},
// Logging
logging: {
level: 'info',
format: 'json',
includeRequestBody: false,
includeResponseBody: false,
redactFields: ['password', 'apiKey', 'token'],
destinations: [
{ type: 'stdout' },
{ type: 'cloudwatch', logGroup: '/api/production' },
{ type: 'datadog', service: 'production-api' },
],
},
// Alerting
alerts: [
{
name: 'high-error-rate',
query: 'rate(api_errors_total[5m]) > 0.05',
severity: 'critical',
notify: ['[email protected]', 'pagerduty'],
runbook: 'https://docs.example.do/runbooks/api-errors',
},
{
name: 'high-latency-p99',
query: 'http_request_duration_seconds{quantile="0.99"} > 2',
severity: 'warning',
notify: ['[email protected]'],
},
{
name: 'traffic-spike',
query: 'rate(http_requests_total[5m]) > 1000',
severity: 'info',
notify: ['[email protected]'],
},
],
},
},
],
}CI/CD Pipeline for APIs
# .github/workflows/deploy-api.yml
name: Deploy API to Production
on:
push:
branches: [main]
paths:
- 'api/**'
- 'package.json'
env:
NODE_VERSION: '20'
PNPM_VERSION: '8'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run unit tests
run: pnpm test api/
- name: Run integration tests
run: pnpm test:integration
env:
DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
- name: Type check
run: pnpm typecheck
- name: Lint
run: pnpm lint api/
- name: Security audit
run: pnpm audit --prod
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- name: Build API
run: pnpm build:api
- name: Create deployment artifact
run: |
tar -czf api-${{ github.sha }}.tar.gz \
dist/ \
package.json \
pnpm-lock.yaml
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: api-build
path: api-${{ github.sha }}.tar.gz
retention-days: 7
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging-api.example.do
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: api-build
- name: Extract artifact
run: tar -xzf api-${{ github.sha }}.tar.gz
- name: Deploy to staging
run: |
pnpm do deploy:api \
--env staging \
--version ${{ github.sha }}
env:
DO_TOKEN: ${{ secrets.DO_STAGING_TOKEN }}
- name: Wait for deployment
run: pnpm do wait-for-deployment --timeout 300
- name: Health check
run: |
curl --fail --retry 10 --retry-delay 5 \
https://staging-api.example.do/health
- name: Run smoke tests
run: pnpm test:smoke --env staging
- name: Performance baseline
run: pnpm test:performance --env staging
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://api.example.do
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: api-build
- name: Extract artifact
run: tar -xzf api-${{ github.sha }}.tar.gz
- name: Deploy with canary strategy
run: |
# Start canary deployment
pnpm do deploy:api \
--env production \
--strategy canary \
--version ${{ github.sha }} \
--auto-rollback
env:
DO_TOKEN: ${{ secrets.DO_PRODUCTION_TOKEN }}
- name: Monitor canary (5% traffic)
run: |
pnpm do monitor-deployment \
--canary-weight 5 \
--duration 120 \
--error-threshold 0.01
- name: Promote to 25% traffic
run: pnpm do promote-canary --weight 25
- name: Monitor canary (25% traffic)
run: |
pnpm do monitor-deployment \
--canary-weight 25 \
--duration 300
- name: Promote to 100% traffic
run: pnpm do promote-canary --weight 100
- name: Verify production deployment
run: |
curl --fail https://api.example.do/health
pnpm do verify-deployment --env production
- name: Create deployment tag
run: |
git tag -a "api-v${{ github.sha }}" -m "Production deployment"
git push origin "api-v${{ github.sha }}"
- name: Notify deployment
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "✅ API deployment successful",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*API Deployment Successful*\n\nVersion: `${{ github.sha }}`\nEnvironment: Production\nDeployed by: ${{ github.actor }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
rollback:
if: failure()
needs: [deploy-production]
runs-on: ubuntu-latest
steps:
- name: Automatic rollback
run: |
pnpm do rollback --api production-api --immediate
env:
DO_TOKEN: ${{ secrets.DO_PRODUCTION_TOKEN }}
- name: Notify rollback
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "⚠️ API deployment failed - automatic rollback initiated"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}API Versioning & Deprecation
export default {
apis: [
{
name: 'production-api',
versioning: {
strategy: 'url', // 'url' | 'header' | 'query'
// URL versioning: /v1/users, /v2/users
url: {
prefix: '/v{version}',
current: 2,
supported: [1, 2],
},
// Version lifecycle
versions: {
v1: {
status: 'deprecated',
deprecatedAt: '2024-01-01',
sunsetAt: '2024-06-01',
migrationGuide: 'https://docs.example.do/migration/v1-to-v2',
},
v2: {
status: 'active',
releasedAt: '2024-01-01',
},
},
// Deprecation warnings
deprecation: {
includeHeader: true,
headerName: 'X-API-Deprecation',
logWarnings: true,
notifyUsers: true,
},
},
},
],
}API Documentation & OpenAPI
export default {
apis: [
{
name: 'production-api',
documentation: {
// OpenAPI generation
openapi: {
enabled: true,
version: '3.1.0',
output: '/docs/openapi.json',
info: {
title: 'Production API',
version: '2.0.0',
description: 'Production API for Example Company',
contact: {
name: 'API Support',
email: '[email protected]',
url: 'https://support.example.com',
},
license: {
name: 'Proprietary',
},
},
servers: [
{
url: 'https://api.example.do',
description: 'Production',
},
{
url: 'https://staging-api.example.do',
description: 'Staging',
},
],
security: [
{ bearerAuth: [] },
{ apiKey: [] },
],
},
// Interactive documentation
swagger: {
enabled: true,
path: '/docs',
oauth: {
clientId: process.env.SWAGGER_CLIENT_ID,
scopes: ['read', 'write'],
},
},
// API changelog
changelog: {
enabled: true,
path: '/changelog',
source: './CHANGELOG.md',
},
},
},
],
}Performance Optimization
export default {
apis: [
{
name: 'production-api',
performance: {
// Response compression
compression: {
enabled: true,
algorithm: 'brotli', // 'gzip' | 'brotli' | 'deflate'
level: 6,
threshold: 1024, // bytes
mimeTypes: ['application/json', 'text/plain', 'text/html'],
},
// Connection management
keepAlive: {
enabled: true,
timeout: 65000,
maxRequests: 100,
},
// HTTP/2 support
http2: {
enabled: true,
pushResources: ['/api/schema'],
},
// Query optimization
database: {
connectionPool: {
min: 10,
max: 50,
acquireTimeoutMillis: 30000,
idleTimeoutMillis: 600000,
},
queryTimeout: 30000,
statementCache: {
enabled: true,
size: 1000,
},
},
// Caching strategies
cache: {
// In-memory cache
memory: {
enabled: true,
maxSize: '100MB',
ttl: 300,
},
// Distributed cache
redis: {
enabled: true,
host: process.env.REDIS_HOST,
port: 6379,
db: 0,
keyPrefix: 'api:',
ttl: 3600,
},
// CDN cache
cdn: {
enabled: true,
provider: 'cloudflare',
ttl: {
static: 31536000, // 1 year
dynamic: 300, // 5 minutes
},
purgeOnDeploy: true,
},
},
// Request batching
batching: {
enabled: true,
maxBatchSize: 100,
maxWaitTime: 50, // ms
endpoints: ['/api/graphql'],
},
},
},
],
}Security Best Practices
export default {
apis: [
{
name: 'production-api',
security: {
// CORS configuration
cors: {
origin: [
'https://app.example.do',
'https://www.example.do',
],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
credentials: true,
maxAge: 86400,
exposedHeaders: ['X-Request-ID'],
},
// Content Security Policy
csp: {
enabled: true,
directives: {
'default-src': ["'self'"],
'script-src': ["'self'", "'unsafe-inline'"],
'style-src': ["'self'", "'unsafe-inline'"],
'img-src': ["'self'", 'data:', 'https:'],
},
},
// Input validation
validation: {
enabled: true,
strict: true,
stripUnknown: true,
abortEarly: false,
},
// SQL injection prevention
database: {
useParameterizedQueries: true,
escapeValues: true,
noRawQueries: true,
},
// XSS prevention
xss: {
enabled: true,
sanitizeInput: true,
escapeOutput: true,
},
// CSRF protection
csrf: {
enabled: true,
tokenLength: 32,
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN',
},
// Security headers
headers: {
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'strict-origin-when-cross-origin',
},
},
},
],
}Related Documentation
-
- RPC - RPC protocol details
-
- Functions - Function types and composition
- Agents - Deploy as agents
- Apps - Deploy as applications
- Configuration - Deployment configuration
- Build Process - Build pipeline