Skip to main content

Extending Reqon

Reqon's extension model is dependency injection, not a plugin registry. You implement an interface and pass the instance to the executor through ExecutorConfig. There's no global register* API and no hook system.

Custom store adapters​

The most common extension point. Implement the StoreAdapter interface and pass your instances in the stores config, keyed by store name:

import { execute, type StoreAdapter, type StoreFilter } from 'reqon-dsl';

class MyStoreAdapter implements StoreAdapter {
async get(key: string) { /* ... */ return null; }
async set(key: string, value: Record<string, unknown>) { /* ... */ }
async update(key: string, value: Partial<Record<string, unknown>>) { /* ... */ }
async delete(key: string) { /* ... */ }
async list(filter?: StoreFilter) { return []; }
async count(filter?: StoreFilter) { return 0; }
async clear() { /* ... */ }
}

await execute(source, {
stores: {
customers: new MyStoreAdapter(),
},
});

When a store name in the config matches a store declared in the mission, your adapter is used instead of the built-in one. Optional bulkSet and bulkUpsert methods are called when present for batched writes. See custom adapters for the full interface.

Custom durability stores​

The execution store, sync store, trace store, and pause store are all injectable the same way:

import { execute, MemoryExecutionStore, MemorySyncStore, MemoryTraceStore, MemoryPauseStore } from 'reqon-dsl';

await execute(source, {
executionStore: new MemoryExecutionStore(),
syncStore: new MemorySyncStore(),
traceStore: new MemoryTraceStore(),
pauseStore: new MemoryPauseStore(),
});

Each has a File* and a Memory* implementation out of the box, and a corresponding interface you can implement yourself.

Observability outputs and handlers​

Hook into execution by subscribing to the event emitter or by adding a custom log output. See observability for the full event catalog.

import { execute, ObservabilityEmitter, type LogOutput, type LogEntry } from 'reqon-dsl';

// Custom log output
class MyOutput implements LogOutput {
write(entry: LogEntry) {
// forward to your logging system
}
}

Vague plugin integration​

Reqon extends Vague (the underlying DSL layer) through its plugin system. The plugin teaches Vague's lexer about Reqon's keywords.

Registering the plugin​

Reqon registers its plugin automatically when you import the package. You can also register it explicitly:

import { registerReqonPlugin } from 'reqon-dsl';

registerReqonPlugin();

Inspecting the plugin​

import { reqonPlugin } from 'reqon-dsl';

console.log(reqonPlugin.name); // 'reqon'

Programmatic API​

For full control, parse and execute directly with MissionExecutor:

import { parse, MissionExecutor } from 'reqon-dsl';

const program = parse(source);

const executor = new MissionExecutor({
dryRun: false,
verbose: true,
progress: {
onStageComplete: (event) => console.log(`Stage done: ${event.stageName}`),
},
});

const result = await executor.execute(program);

The convenience functions execute, fromFile, and fromPath wrap this for the common cases.

Not currently supported​

These extension points don't exist. Avoid building against them:

  • Custom expression functions — there's no registerFunction. Expression functions come from Vague's evaluator.
  • Custom step handlers — there's no registerStepHandler; step types are fixed.
  • Custom auth providers — there's no registerAuthProvider. The built-in providers are bearer, OAuth2, basic, and API key (see authentication).
  • Custom pagination strategies — there's no registerPaginationStrategy; the strategies are offset, page, and cursor.
  • A plugin/hook system — there's no Reqon class, reqon.use(...), or reqon.hooks.*. Use store/observability injection instead.