Skip to content

Core API

createSurf

Create a new Surf instance

createSurf(config)#

Creates a new Surf instance. The config object defines your service name, commands, auth, events, and behavior.

TypeScript
import { createSurf } from '@surfjs/core'
 
const surf = await createSurf({
name: 'My Service',
description: 'A Surf-enabled API',
version: '1.0.0',
commands: { /* ... */ },
events: { /* ... */ },
authVerifier: myVerifier,
rateLimit: { windowMs: 60_000, maxRequests: 100 },
strict: true,
})
 
// Returns a SurfInstance with:
surf.manifest() // Get the generated manifest
surf.manifestForToken(tok) // Get manifest for a specific auth token (shows hidden commands if valid)
surf.manifestHandler() // HTTP handler for /.well-known/surf.json
surf.httpHandler() // HTTP handler for /surf/execute
surf.middleware() // Combined HTTP middleware (manifest + execute + sessions + pipeline)
surf.wsHandler(server) // Attach WebSocket transport (requires 'ws' package)
surf.browserScript() // Generate a browser-injectable script
surf.browserBridge() // Generate a window bridge for browser execution
surf.emit(event, data) // Emit an event to connected clients
surf.use(middleware) // Add a middleware function
surf.live // Surf Live API (setState, patchState, getState, emit)
surf.events // Access the EventBus
surf.sessions // Access the SessionStore
surf.commands // Access the CommandRegistry

SurfConfig — Full options

| Option | Type | Description | |--------|------|-------------| | name | string | Service name (shown in manifest and badges) | | description | string? | Short description | | version | string? | Your API version string | | commands | CommandGroup | Command definitions (nested groups supported) | | events | Record<string, EventDefinition>? | Event definitions for Surf Live | | channels | Record<string, ChannelDefinition>? | Channel definitions for Surf Live | | about | string? | Longer context about your site for agents | | baseUrl | string? | Base URL for the API (included in manifest) | | auth | AuthConfig? | Auth type advertised in manifest (none, bearer, apiKey, oauth2) | | authVerifier | AuthVerifier? | Function to verify tokens — called for required/optional/hidden commands | | rateLimit | RateLimitConfig? | Global rate limiting | | sessionRateLimit | RateLimitConfig? | Rate limit for session creation (POST /surf/session/start). Defaults to 10 req/60s per IP when rateLimit is set | | cors | CorsConfig? | CORS configuration — origin string/array/function, credentials, custom headers. Omit or set origin: '*' for default wildcard | | strictParams | boolean? | Reject requests that include params not defined in the command schema | | strict | boolean? | Enable validateReturns, strictParams, and other strict checks | | validateReturns | boolean? | Validate command return values against returns schema | | debug | boolean? | Include internal error details in responses (dev only) | | middleware | SurfMiddleware[]? | Global middleware applied to all commands | | live | LiveConfig? | Surf Live config (WebSocket broadcast settings) |


Advanced Utilities#

InMemorySessionStore

The default session store — an in-memory map of sessionId → Session. For production or multi-replica deployments, implement the SessionStore interface:

TypeScript
import { InMemorySessionStore } from '@surfjs/core'
import type { SessionStore, Session } from '@surfjs/core'
 
// The SessionStore interface:
interface SessionStore {
create(): Promise<Session>
get(id: string): Promise<Session | undefined>
update(id: string, state: Record<string, unknown>): Promise<void>
destroy(id: string): Promise<void>
}
 
// InMemorySessionStore is the built-in default — works for single-process dev.
// For production, implement SessionStore backed by Redis, a database, etc.

generateManifest

Generate a manifest JSON object from a config without creating a full SurfInstance. Useful for testing, CI validation, or manifest pre-generation:

TypeScript
import { generateManifest } from '@surfjs/core'
 
const manifest = await generateManifest({
name: 'My Store',
version: '1.0.0',
baseUrl: 'https://shop.example.com',
commands: { search: { description: 'Search', run: async () => ({}) } },
})
 
// Write to disk, validate schema, publish to CDN, etc.
fs.writeFileSync('surf.json', JSON.stringify(manifest, null, 2))

generateManifest is async (it computes a SHA-256 checksum via Web Crypto). It accepts the same config shape as createSurf plus optional ManifestOptions (authenticated, updatedAt).

RateLimiter

The built-in sliding window rate limiter. Instantiate it directly for custom rate limiting logic:

TypeScript
import { RateLimiter } from '@surfjs/core'
 
const limiter = new RateLimiter()
 
// In a custom middleware or handler:
limiter.check(
{ windowMs: 60_000, maxRequests: 10, keyBy: 'ip' },
RateLimiter.buildKey('search', config, { ip: ctx.ip }),
)
// Throws SurfError { code: 'RATE_LIMITED' } if limit exceeded

Surf uses RateLimiter internally when you set rateLimit on a command or config. Use it directly to share a limiter across multiple services or to apply rate limiting outside of a Surf handler.

EventBus

The event broadcast system backing surf.emit(). Access via surf.events:

TypeScript
// Emit from anywhere in your app
surf.events.emit('cart.updated', { cartId: '123', items: [...] })
 
// Subscribe to events (useful for server-side consumers)
surf.events.on('cart.updated', (data) => {
metrics.increment('cart.updates')
})

The EventBus supports scoped events via channels — see Surf Live for the full broadcast API.