@omniaura/scenario-sim weekly downloads statistics
By omniaura (4 listings) · npm · Vite plugins
Deterministic scenario simulator for frontend QA: stateful CRUD routes, seeded RNG, virtual clock, response sequences, faults and overrides, SSE and WebSocket routes with scheduled events and resume, per-run isolation, inspectable event log. Runtime-neutr
@omniaura/scenario-sim has 658 recorded weekly downloads on npm, ranking #1541 of 2,391 tracked listings.
About @omniaura/scenario-sim
@omniaura/scenario-sim
· pairs with
@omniaura/solid-pulse (the panel/CLI that drives it) — see docs/migrating-header-driven-mocks.md to migrate an existing mock.
A mock backend that behaves like a backend: stateful, seeded, reproducible, streaming — and controllable by humans and agents alike.
Most mock layers return fixtures. scenario-sim runs scenarios: a seeded world with CRUD state, a virtual clock, response sequences and faults, SSE and WebSocket routes whose events come from state mutations, and a control plane to select/reset/step/inspect everything. The core is runtime-neutral (Web Request/Response) so the same scenario runs as a Bun/Node server, inside the Vite dev server, or entirely inside the browser.
Define a scenario
Smart local ports
The CLI starts at port 4100 and tries the next port if it is occupied. It prints the actual control URL; pass that URL to subsequent commands with --url (or SCENARIO_SIM_URL). Explicit --port N and --strict-port never silently move. No existing listener is stopped or reused.
Programmatic servers preserve strict-port behavior by default. Opt in with serveSimulator(sim, { port: 4100, strictPort: false }); the returned port, url and controlUrl describe the real bound listener. Port 0 requests an OS-assigned port. The Node-only @omniaura/scenario-sim/ports export provides withPortFallback(bind, options) for other adapters: retry only EADDRINUSE, bound attempts, and bind the real service instead of probing and releasing a temporary socket. A rejected bind callback must clean up its own partial resources.
Browser devtools cannot allocate listening ports. The launcher/server selects them before boot and passes the actual API URL to the panel and command adapters. Vite integrations should use Vite's own strictPort: false and read httpServer.address() after listen(), rather than probing an unrelated HTTP server for readiness.
import { defineScenario, crud, route, json, problem, sequence, malformed, ws, sse } from "@omniaura/scenario-sim";
export const happy = defineScenario({
name: "notes-happy",
seed: "notes-happy", // same seed → same ids, same fixtures, same jitter
clock: { mode: "realtime" }, // or "manual": nothing time-based happens until stepped
faults: { latencyMs: 0 },
setup({ state, rng, clock, streams }) {
for (let i = 0; i < 8; i++) state.insert("notes", { id: rng.id("note"), title: rng.pick(WORDS), done: false, createdAt: clock.iso() });
// Mutations → stream events. Routes mutate state; streams subscribe to it.
state.on((e) => e.collection === "notes" && streams.publish("notes", { type: `notes.${e.kind}`, id: e.id, note: e.record ?? null }));
},
routes: [
...crud("/api/notes", "notes", { create: (body, ctx) => ({ id: ctx.rng.id("note"), title: String(body.title), done: false, createdAt: ctx.clock.iso() }) }),
route.get("/api/flaky", (ctx) => (ctx.calls % 3 === 0 ? problem(503, "flaky upstream") : json({ ok: true }))),
route.get("/api/drift", sequence([() => malformed("invalid-json"), () => malformed("schema-drift"), () => json({ ok: true })])),
],
streams: [
sse("/api/notes/events", (ctx, stream) => stream.subscribe("notes")), // resumes from Last-Event-ID
ws("/api/chat/ws", {
protocols: ["chat-v1"],
onOpen: (ctx, socket) => socket.send({ type: "ready" }),
onMessage(ctx, socket, raw) {
const frame = JSON.parse(String(raw));
if (frame.type === "subscribe") {
const r = socket.subscribe(frame.topic, { since: frame.sinceEventID }); // replay > sinceEventID, then live
socket.send({ type: "subscribed", replayed: r.replayed, last: r.last });
if (r.missed) socket.send({ type: "resume.miss" });
}
},
}),
],
actions: { burst: ({ state, rng, args }) => { /* insert N notes */ } }, // POST /__sim/action {name:"burst"}
});
Everything in a scenario is deterministic given the seed: rng.id(), rng.pick(), jitter, virtual timestamps (clock.iso() starts at 2026-01-01T00:00:00Z). Streams carry a per-topic monotonic eventID with a bounded replay log; subscribe(topic, { since }) replays what a reconnecting client missed and reports missed when the resume point fell out of the window (so you can send the protocol's "resync" frame).
crud(path, collection, …) gives you GET /path, POST /path → 201, GET/PATCH/PUT/DELETE /path/:id with 404/422 handling and store events for every mutation.
Run it
// as a server
import { Simulator } from "@omniaura/scenario-sim";
import { serveSimulator } from "@omniaura/scenario-sim/server";
const sim = new Simulator({ scenarios: [happy, slow, flaky] });
await serveSimulator(sim, { port: 4100 }); // http://127.0.0.1:4100/__sim/status
// inside Vite (same origin as the app, WebSocket upgrades included)
import scenarioSim from "@omniaura/scenario-sim/vite";
plugins: [scenarioSim({ scenarios: () => import("./scenarios"), match: (p) => p.startsWith("/api/") })]
// entirely in the browser (static builds, demo islands, Playwright against `vite preview`)
import { installBrowserSimulator } from "@omniaura/scenario-sim/browser";
const { sim } = installBrowserSimulator({ scenarios, run: "tab-1" }); // patches fetch/WebSocket/EventSource for matching URLs
scenario-sim serve ./scenarios.ts --port 4100 --scenario notes-happy
Control plane (HTTP, CLI, JS, pulse panel — the same operations)…
Description from the npm listing.
- mock
- simulator
- scenario
- msw
- sse
- websocket
- deterministic
- seeded
- qa
- vite-plugin
- solid
- tanstack-query
README badge
Show your rank in a README or on your website. The badge updates automatically.
Charts
Images: 30d · 1y · all time · 1600×900 dark
Adoption over time
7/30/90-day growth
Ranking history
Listing placement
Listing placement
Filled points are observed values; hollow points come from Internet Archive snapshots of the listing page. Dashed segments span periods with no observations — values between points are not interpolated.
Each band is one page of 20. Weekly downloads on a linear scale. Placement is projected from weekly downloads, so it can differ from the marketplace's own sort order. Hover a dot to see the listing.
Recent observations
Full history (1)Similar npm Vite plugins plugins
All 20 @omniaura/scenario-sim alternativesData source
Weekly downloads (trailing 7 complete days) come from the official npm downloads API. Downloads include CI and mirrors and are not equivalent to installs or users. npm publishes no ratings.
Listing: https://www.npmjs.com/package/@omniaura/scenario-sim. First seen Oct 21, 2026; last successful collection Oct 21, 2026. See the methodology.