Scripting
RelayCore includes a Deno/V8 runtime for dynamic request and response modification using JavaScript or TypeScript.
Overview
Scripts can intercept and modify flows at various stages:
onRequest— Before the request is forwardedonResponse— After the response is receivedonWebSocket— For WebSocket messages
Basic Script
import { Flow, FlowAction } from "relay:script";
async function onRequest(flow: Flow): Promise<FlowAction> {
console.log(`Request: ${flow.method} ${flow.url}`);
// Add custom header
flow.request.headers["X-Script-Ran"] = "true";
// Log and continue
return FlowAction.Continue;
}
async function onResponse(flow: Flow): Promise<FlowAction> {
console.log(`Response: ${flow.status} for ${flow.url}`);
// Return mock response for specific URLs
if (flow.path === "/api/mocked") {
return FlowAction.Mock({
status: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify({ mocked: true }),
});
}
return FlowAction.Continue;
} Flow Object
interface Flow {
id: string;
timestamp: Date;
method: string;
url: string;
host: string;
path: string;
protocol: string;
status?: number;
request: {
headers: Record<string, string>;
body?: Uint8Array;
bodyText?: string;
bodyJson?: unknown;
};
response?: {
headers: Record<string, string>;
body?: Uint8Array;
bodyText?: string;
bodyJson?: unknown;
};
duration_ms: number;
size: number;
} FlowAction
enum FlowAction {
Continue = "continue", // Proceed normally
Drop = "drop", // Drop the flow
Mock = "mock", // Return mock response
Intercept = "intercept", // Pause for inspection
Redirect = "redirect", // Redirect to URL
} Advanced Example
import { Flow, FlowAction } from "relay:script";
// Mock API responses for testing
const mocks = new Map([
["/api/users", { users: [{ id: 1, name: "Alice" }] }],
["/api/products", { products: [{ id: 1, name: "Widget" }] }],
]);
async function onRequest(flow: Flow): Promise<FlowAction> {
// Inject auth token if missing
if (flow.path.startsWith("/api/") && !flow.request.headers["authorization"]) {
flow.request.headers["authorization"] = "Bearer test-token-123";
}
return FlowAction.Continue;
}
async function onResponse(flow: Flow): Promise<FlowAction> {
if (flow.response && flow.response.bodyJson) {
// Log all API responses
console.log(`API Response for ${flow.path}:`, flow.response.bodyJson);
// Inject metadata into responses
if (Array.isArray(flow.response.bodyJson)) {
flow.response.bodyJson._meta = {
mocked: true,
timestamp: new Date().toISOString(),
};
}
}
return FlowAction.Continue;
} Loading Scripts
# Load a script
relay-core-cli scripts load ./path/to/script.ts
# List loaded scripts
relay-core-cli scripts list
# Unload a script
relay-core-cli scripts unload my-script Script Configuration
# In config.toml
[scripting]
enabled = true
deno_dir = "~/.relay-core/deno"
auto_reload = true