@mockingbirdjs/core
v0.1.0
Published
Framework-agnostic fixture store, request matching, sanitization, and middleware powering Mockingbird.
Readme
@mockingbirdjs/core
Framework-agnostic engine powering Mockingbird — fixture store, request matching, sanitization pipeline, and Node.js middleware.
Used internally by @mockingbirdjs/vite and @mockingbirdjs/next. Install this directly if you want to build a Mockingbird adapter for another framework (Express, Fastify, Nuxt, Remix, etc.).
Install
npm i @mockingbirdjs/coreQuick start
import { resolveCoreConfig, createRuntime } from "@mockingbirdjs/core";
import type { IncomingMessage, ServerResponse } from "node:http";
const config = resolveCoreConfig({
dir: "./mockingbird", // fixture directory
mode: "hybrid", // 'live' | 'mock' | 'hybrid'
});
const runtime = createRuntime(config);
await runtime.init();
// Drop runtime.middleware into any Node.js HTTP server
app.use(runtime.middleware);resolveCoreConfig(options)
Merges your options with defaults and returns a fully-resolved CoreConfig.
resolveCoreConfig({
// Fixture directory (absolute or relative to cwd). Default: 'mockingbird'
dir: "./mockingbird",
// Starting mode. Default: 'hybrid'
mode: "hybrid",
// Request matching
match: {
body: true, // match on request body hash
headers: [], // additional headers to match on
inferPathParams: true, // auto-detect [id]-style path segments
query: { ignore: [] }, // 'all' | 'none' | { only?, ignore? }
},
// Recording
record: {
maxBodyBytes: 5_000_000,
maxVariantsPerEndpoint: 10,
onDuplicate: "update", // 'update' | 'keep' | 'variants'
latency: true,
wildcardFallback: true, // write a wildcard fallback for parameterised routes
},
// Replay
replay: {
latency: "none", // 'none' | 'recorded' | ms | { min, max }
},
// Per-route overrides — first match wins
routes: [
{ pattern: "GET /api/flags", mode: "live" },
{ pattern: "/api/analytics/**", ignore: true },
],
// Sanitization (applied before anything hits disk)
sanitize: {
disable: false,
allowRequestHeaders: ["content-type", "accept"],
headers: ["set-cookie", "authorization", "x-api-key"],
bodyPaths: ["**.password", "**.token", "**.apiKey"],
queryParams: ["token", "key", "access_token"],
placeholder: "«redacted»",
},
// Last-chance hook before a recording hits disk. Return null to drop.
onRecord: (exchange) => exchange,
})createRuntime(config)
Creates a Runtime instance that holds the fixture store, middleware, and event bus.
interface Runtime {
config: CoreConfig;
counters: SessionCounters; // hits, misses, recorded this session
init(): Promise<void>; // scaffold dirs, load state
middleware: NodeMiddleware; // (req, res, next) => void
mode(): Mode; // current mode
setMode(mode: Mode): Promise<void>;
store: FsStore; // direct fixture store access
onEvent(listener): () => void; // subscribe to runtime events
handleWatcherEvent( // feed file-watcher events
event: "add" | "change" | "unlink",
file: string
): boolean;
}FsStore
Reads and writes fixture files under config.dir/fixtures/.
const store = runtime.store;
// Load all fixtures
const fixtures = await store.load();
// Find best match for a request
const match = await store.resolve(normalizedRequest, config);
// Save a fixture
await store.save(fixtureFile, config);State management
import { readState, writeState, resolveMode } from "@mockingbirdjs/core";
const state = await readState(config.dir); // reads .state.json
const mode = resolveMode(state, config); // applies env var override
await writeState(config.dir, { mode: "mock" });Key types
type Mode = "live" | "mock" | "hybrid";
interface RouteOverride {
pattern: string; // 'GET /api/users/**' or glob
mode?: Mode;
ignore?: boolean;
match?: Partial<MatchConfig>;
record?: Partial<RecordConfig>;
replay?: Partial<ReplayConfig>;
}
interface RecordedExchange {
meta: { recordedAt: string; origin: string };
request: { method: string; path: string; url: string; params; query; headers; body? };
response: { status: number; headers; body: unknown; latencyMs: number };
}
type OnRecordHook = (exchange: RecordedExchange) => RecordedExchange | null | undefined;See the full type definitions for the complete surface.
