npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sanity-labs/workflow-engine-explore-test

v0.4.0

Published

In-memory test bench (`createBench`) for [`@sanity-labs/workflow-engine-explore`](https://www.npmjs.com/package/@sanity-labs/workflow-engine-explore). Wraps the engine and a [test-client](https://www.npmjs.com/package/@sanity-labs/workflow-engine-explore-

Readme

@sanity-labs/workflow-engine-explore-test

In-memory test bench (createBench) for @sanity-labs/workflow-engine-explore. Wraps the engine and a test-client so test call sites stay tight — no client wiring, no actor boilerplate per call.

Status: 0.x POC. API surface mirrors the engine; tracks engine changes minor-for-minor.

npm install -D @sanity-labs/workflow-engine-explore-test

What the bench is

The bench is the only place in the engine ecosystem that fabricates an actor identity. The engine requires an explicit actor on every call; the bench provides a default ALL_ACCESS_USER so tests don't have to thread one. It also wires:

  • A fresh TestClient (in-memory, groq-js-backed) per createBench()
  • A WILDCARD_GRANTS array as the default for ACL-gated calls
  • A tags: ["bench"] engine scope (override to test multi-tenant isolation)

The result: test call sites look like end-user call sites without the auth/scope overhead.

import { createBench } from "@sanity-labs/workflow-engine-explore-test";
import { defineWorkflow } from "@sanity-labs/workflow-engine-explore/define";

const bench = createBench();

const def = defineWorkflow({
  workflowId: "article-review",
  version: 1,
  name: "Article review",
  initialStageId: "draft",
  stages: [
    { id: "draft", tasks: [{ id: "write", actions: [{ name: "submit", setStatus: "done" }] }],
      transitions: [{ to: "published" }] },
    { id: "published", kind: "terminal" },
  ],
});

await bench.deployDefinitions({ definitions: [def] });
const inst = await bench.startInstance({ workflowId: "article-review" });
await bench.fireAction({ instanceId: inst._id, taskId: "write", action: "submit" });

expect(await bench.currentStage(inst._id)).toBe("published");

API

createBench(options?: CreateBenchOptions): Bench

| Option | Type | Default | What | |---|---|---|---| | tags | string[] | ["bench"] | Engine-scope tags. See Tag scoping. | | client | TestClient | fresh one | Pass to share a store between two benches. | | currentUser | Actor | ALL_ACCESS_USER | Actor injected into every wrapped engine call. | | grants | Grant[] | WILDCARD_GRANTS | Sanity ACL grants supplied to fireAction / evaluate. | | documents | { _id, _type, … }[] | [] | Seed documents into the store at construction. |

Engine wrappers

These mirror the engine API one-for-one, minus client, tags, actor, and grants (all injected by the bench):

bench.deployDefinitions({ definitions })
bench.startInstance({ workflowId, version?, subject?, ancestors?, effectsContext?, instanceId? })
bench.fireAction({ instanceId, taskId, action, idempotent?, grants? /* override */ })
bench.completeEffect({ instanceId, effectKey, status, outputs?, … })
bench.tick({ instanceId })
bench.evaluate({ instanceId, grants? /* override */ })

Override the bench's currentUser per-call by passing an actor:

await bench.fireAction({
  instanceId, taskId: "approve", action: "approve",
  actor: { kind: "user", id: "alice", roles: ["editor"] }, // overrides bench.currentUser
});

Read helpers (DX sugar)

bench.getInstance(instanceId)        // throws if missing or tag-mismatched
bench.currentStage(instanceId)       // → string
bench.pendingEffects(instanceId)     // → PendingEffect[]
bench.taskStatus(instanceId, taskId) // → "pending" | "active" | "done" | "skipped" | "failed" | undefined
bench.effectsContextMap(instanceId)  // → Record<key, value>
bench.children(parentId, taskId?)    // → WorkflowInstance[] (tag-filtered)
bench.instancesForSubject(ref)       // → WorkflowInstance[] (tag-filtered)
bench.instancesByStage(workflowId, stageId, { openOnly? })
bench.snapshot()                     // raw store contents
bench.seedDocuments([...])           // add docs after construction

All read helpers respect the bench's tags — disjoint-tag benches sharing a client cannot see each other's data through any helper.


Tag scoping

import { createTestClient } from "@sanity-labs/workflow-engine-explore-test-client";

const sharedClient = createTestClient();
const benchA = createBench({ client: sharedClient, tags: ["tenant-a"] });
const benchB = createBench({ client: sharedClient, tags: ["tenant-b"] });

await benchA.deployDefinitions({ definitions: [def] });
const instA = await benchA.startInstance({ workflowId: "article-review" });

await benchB.getInstance(instA._id); // throws: tag mismatch
await benchA.getInstance(instA._id); // returns it

Two benches without a shared client are completely isolated regardless of tags — they have separate stores. The interesting case is shared client + different tags; that's what proves multi-tenant isolation in production.

Tag validation

tags must match /^[a-z0-9][a-z0-9-]*$/. Validated at construction:

createBench({ tags: [] });            // throws: empty
createBench({ tags: ["foo.bar"] });   // throws: dots reserved as ID separator
createBench({ tags: ["FooBar"] });    // throws: ASCII lowercase only
createBench({ tags: ["-leading"] });  // throws: no leading dash

Denial-path testing

Pass a non-wildcard currentUser + scoped grants to test what happens when an action is denied:

import { ActionDisabledError } from "@sanity-labs/workflow-engine-explore";

const restricted = createBench({
  currentUser: { kind: "user", id: "viewer", roles: ["viewer"] },
  grants: [{ filter: '_type == "workflow.instance"', permissions: ["read"] }], // read-only
});

await restricted.deployDefinitions({ definitions: [def] });
const inst = await restricted.startInstance({ workflowId: "article-review" });

await expect(
  restricted.fireAction({ instanceId: inst._id, taskId: "approve", action: "approve" }),
).rejects.toBeInstanceOf(ActionDisabledError);

License

UNLICENSED — internal Sanity labs exploration.