API reference
Reqon's programmatic API for advanced usage. The package is published as reqon-dsl, so import from 'reqon-dsl'.
npm install reqon-dsl
Core functions
parse
Parse a Reqon source string into an AST.
import { parse } from 'reqon-dsl';
const program = parse(`
mission Example {
source API { auth: bearer, base: "https://api.example.com" }
store data: file("data")
action Fetch { get "/data" }
run Fetch
}
`);
console.log(program.statements.length); // 1
Parameters:
source: string- Reqon source codefilePath?: string- Optional file path, used for error messages
Returns: ReqonProgram - the parsed AST, with a statements array
execute
Parse and execute a mission from source code.
import { execute } from 'reqon-dsl';
const result = await execute(`
mission Example {
source API { auth: none, base: "https://jsonplaceholder.typicode.com" }
store posts: memory("posts")
action Fetch {
get "/posts"
store response -> posts { key: .id }
}
run Fetch
}
`);
console.log(result.success); // true
console.log(result.duration); // 234
console.log(result.actionsRun); // ["Fetch"]
Parameters:
source: string- Reqon source codeconfig?: ExecutorConfig- optional configuration
Returns: Promise<ExecutionResult>
fromFile
Execute a mission from a single file.
import { fromFile } from 'reqon-dsl';
const result = await fromFile('./mission.vague', {
auth: {
API: { type: 'bearer', token: 'xxx' },
},
});
Parameters:
filePath: string- path to a.vagueor.reqonfileconfig?: ExecutorConfig- optional configuration
Returns: Promise<ExecutionResult>
fromPath
Execute a mission from a file or a folder (multi-file mission). Use this when you want folder missions to resolve their action files automatically.
import { fromPath } from 'reqon-dsl';
// Single file
const result1 = await fromPath('./mission.vague');
// Folder (multi-file mission)
const result2 = await fromPath('./missions/customer-sync/');
Parameters:
path: string- path to a file or folderconfig?: ExecutorConfig- optional configuration
Returns: Promise<ExecutionResult>
executeWithResume
Execute a mission and automatically resume it when a pause step's trigger fires. It stays live after a pause, routes an inbound webhook on the pause's path (or an expired timeout) into a resume, and re-executes with resumeFrom until the run finishes. Requires executionLog; webhook triggers also need webhookServer.
import { executeWithResume, FileExecutionLog } from 'reqon-dsl';
const result = await executeWithResume(source, {
executionLog: new FileExecutionLog('.reqon-data/execution-log'),
webhookServer,
});
Parameters:
source: string- Reqon source codeconfig: ExecutorConfig- must includeexecutionLogoptions?: ExecuteWithResumeOptions-pollInterval(timeout poll in ms, default one minute) andmaxResumes(safety cap on resume cycles, default 1000)
Returns: Promise<ExecutionResult>
See Pause for the full lifecycle.
reqon (tagged template)
Parse an inline mission with a tagged template literal. It returns a ReqonProgram, the same as parse; there is no program.execute() method, so pass the source to execute to run it.
import { reqon, MissionExecutor } from 'reqon-dsl';
const program = reqon`
mission Example {
source API { auth: bearer, base: "https://api.example.com" }
store data: file("data")
action Fetch { get "/data" }
run Fetch
}
`;
const result = await new MissionExecutor().execute(program);
Configuration
ExecutorConfig
These are the keys read by the executor. All are optional.
interface ExecutorConfig {
// Auth credentials by source name
auth?: Record<string, AuthConfig>;
// Custom store adapters by store name
stores?: Record<string, StoreAdapter>;
// Skip actual HTTP requests
dryRun?: boolean;
// Verbose logging
verbose?: boolean;
// Mission file directory (for resolving relative paths like OAS specs)
missionDir?: string;
// Use file stores when sql/nosql stores are declared (--dev mode)
developmentMode?: boolean;
// Base directory for file stores, sync, executions, traces (default: '.reqon-data')
dataDir?: string;
// Enable state persistence for resumable executions
persistState?: boolean;
// Resume from a previous execution ID
resumeFrom?: string;
// Progress callbacks for real-time UI updates
progress?: ProgressCallbacks;
// Webhook server for handling 'wait' steps
webhookServer?: WebhookServer;
// Control server for pause/resume and status queries
controlServer?: ControlServer;
// Append-only execution event log (durable-execution foundation)
executionLog?: ExecutionLogStore;
}
There are further advanced keys (metadata, executionStore, syncStore, traceStore, pauseStore, pauseManager, eventEmitter, logger, debugController, rateLimitCallbacks, circuitBreakerCallbacks, backfillMaxItemsPerRun, maxParallel, maxPaginationPages, maxPaginationItems, proxyAgentFactory, proxyFetchFactory); see ExecutorConfig in packages/reqon-dsl/src/interpreter/executor.ts for the full list. maxParallel (default 8) caps both parallel pipeline stages and for ... concurrency N.
AuthConfig
Credentials passed programmatically, keyed by source name. All four credentialed types attach auth to outgoing requests; a type configured without its credentials throws at source init.
interface AuthConfig {
type: 'bearer' | 'oauth2' | 'basic' | 'api_key' | 'none';
token?: string; // bearer
accessToken?: string; // oauth2
refreshToken?: string; // oauth2
tokenEndpoint?: string; // oauth2
clientId?: string; // oauth2
clientSecret?: string; // oauth2
username?: string; // basic
password?: string; // basic
apiKey?: string; // api_key
headerName?: string; // api_key (default 'X-API-Key')
apiKeyLocation?: 'header' | 'query'; // api_key (default 'header')
}
ProgressCallbacks
interface ProgressCallbacks {
onExecutionStart?: (event: ExecutionStartEvent) => void;
onExecutionComplete?: (event: ExecutionCompleteEvent) => void;
onStageStart?: (event: StageStartEvent) => void;
onStageComplete?: (event: StageCompleteEvent) => void;
}
interface ExecutionStartEvent {
executionId: string;
mission: string;
stageCount: number;
isResume: boolean;
metadata?: Record<string, unknown>;
}
interface StageStartEvent {
executionId: string;
mission: string;
stageIndex: number;
stageName: string;
totalStages: number;
}
StageCompleteEvent adds success, duration, and an optional error; ExecutionCompleteEvent reports success, duration, stagesCompleted, stagesFailed, and errors.
Results
ExecutionResult
interface ExecutionResult {
success: boolean;
duration: number; // milliseconds
actionsRun: string[];
errors: ExecutionError[];
stores: Map<string, StoreAdapter>;
executionId?: string; // for resuming
state?: ExecutionState; // when persistence is enabled
traceId?: string; // when tracing is enabled
pauseId?: string; // when execution paused
}
ExecutionError
interface ExecutionError {
action: string;
step: string;
message: string;
details?: unknown;
}
Store adapters
StoreAdapter interface
interface StoreAdapter {
get(key: string): Promise<Record<string, unknown> | null>;
set(key: string, value: Record<string, unknown>): Promise<void>;
bulkSet?(records: Array<{ key: string; value: Record<string, unknown> }>): Promise<void>;
bulkUpsert?(records: Array<{ key: string; value: Record<string, unknown> }>): Promise<void>;
update(key: string, value: Partial<Record<string, unknown>>): Promise<void>;
delete(key: string): Promise<void>;
list(filter?: StoreFilter): Promise<Record<string, unknown>[]>;
count(filter?: StoreFilter): Promise<number>;
clear(): Promise<void>;
}
interface StoreFilter {
where?: Record<string, unknown>; // equality match by field
limit?: number;
offset?: number;
}
where filters are equality-only.
Built-in stores and createStore
Reqon exports MemoryStore, FileStore, and a createStore factory. PostgRESTStore isn't re-exported from the package root; construct one through createStore with PostgREST options, or declare it in the mission.
import { createStore, MemoryStore, FileStore } from 'reqon-dsl';
const mem = new MemoryStore('cache');
const file = new FileStore('output', { baseDir: '.reqon-data' });
Using a custom store
There is no global store registry. To use your own adapter, implement StoreAdapter and pass it in ExecutorConfig.stores, keyed by the store name used in the mission.
import { execute, type StoreAdapter } from 'reqon-dsl';
class MyStore implements StoreAdapter {
/* ... */
}
await execute(source, {
stores: { customers: new MyStore() },
});
AST types
The full AST node set is exported from the package (export * from './ast'). The top-level shape is:
interface ReqonProgram {
statements: Statement[]; // mission definitions and other top-level statements
}
interface MissionDefinition {
type: 'MissionDefinition';
name: string;
schedule?: ScheduleDefinition;
checkpoint?: CheckpointConfig; // durable execution
trace?: TraceConfig; // time-travel debugging
sources: SourceDefinition[];
stores: StoreDefinition[];
schemas: SchemaDefinition[];
transforms: TransformDefinition[];
actions: ActionDefinition[];
pipeline: PipelineDefinition;
}
Error classes
import {
ReqonError,
ParseError,
LexerError,
RuntimeError,
ValidationError,
} from 'reqon-dsl';
try {
await execute(source);
} catch (error) {
if (error instanceof ParseError) {
console.error(error.format());
} else if (error instanceof ValidationError) {
console.error(`Validation failed: ${error.message}`);
}
}
ReqonError is the base class; all of the above extend it and provide a format() method that renders source context.
Observability
createStructuredLogger
Create a structured logger with console and/or JSON-lines output.
import { createStructuredLogger } from 'reqon-dsl';
const logger = createStructuredLogger({
prefix: 'MyApp',
level: 'info',
console: true,
jsonLines: true,
context: { service: 'data-sync' },
});
logger.info('Starting sync', { count: 100 });
const span = logger.span('fetchData');
// ... do work
span.end();
createEmitter
Create an event emitter for observability. It takes an execution ID and a mission name.
import { createEmitter } from 'reqon-dsl';
const emitter = createEmitter('exec-123', 'CustomerSync');
emitter.on('fetch.complete', (event) => {
console.log('fetch complete', event);
});
emitter.on('mission.complete', (event) => {
console.log('mission complete', event);
});
OTLPExporter
Export traces to an OpenTelemetry collector.
import { OTLPExporter, createOTelListener } from 'reqon-dsl';
const exporter = new OTLPExporter({
endpoint: 'http://localhost:4318/v1/traces',
serviceName: 'reqon-pipeline',
});
const listener = createOTelListener(exporter);
Event types
type EventType =
| 'mission.start' | 'mission.complete' | 'mission.failed' | 'mission.paused'
| 'stage.start' | 'stage.complete'
| 'step.start' | 'step.complete'
| 'fetch.start' | 'fetch.complete' | 'fetch.retry' | 'fetch.error' | 'fetch.heartbeat' | 'fetch.truncated'
| 'data.transform' | 'data.validate' | 'data.store'
| 'loop.start' | 'loop.iteration' | 'loop.item.failed' | 'loop.complete' | 'loop.heartbeat'
| 'match.attempt' | 'match.result'
| 'webhook.register' | 'webhook.event' | 'webhook.complete'
| 'checkpoint.save' | 'checkpoint.resume'
| 'sync.checkpoint'
| 'ratelimit.wait' | 'ratelimit.resume'
| 'circuit.open' | 'circuit.halfopen' | 'circuit.close';
MCP server
Reqon ships an MCP server, exposed as the reqon-mcp binary.
import { spawn } from 'node:child_process';
spawn('npx', ['reqon-mcp', '--verbose']);
MCP tools
| Tool | Description |
|---|---|
reqon.execute | Execute a mission from source |
reqon.execute_file | Execute a mission from a file |
reqon.parse | Parse and validate source |
reqon.query_store | Query store data |
reqon.list_stores | List stores |
reqon.register_store | Register a store |
Plugin system
Reqon registers itself as a Vague plugin on import. The exported helpers are reqonPlugin and registerReqonPlugin.
import { reqonPlugin, registerReqonPlugin } from 'reqon-dsl';
For expression syntax, pattern matching, and schema definitions, see the Vague documentation. For the authoritative export list, see the source code.