@xyo-network/event-kit-vitest-config
An opt-in Vitest preset with a real, test-owned local event stack: an XL1 dev-chain child process, hash-addressed REST datalake, resident event publisher, and authenticated HTTPS receivers. Node.js 26 or newer is required; the repository pins Node 26.9.0.
pnpm add -D @xyo-network/event-kit-vitest-config vitest
// vitest.config.ts
import { defineEventKitVitestConfig } from '@xyo-network/event-kit-vitest-config'
export default defineEventKitVitestConfig({
installers: { localEventStack: true },
})
Put integration specs in src/**/spec/local-event-stack/**/*.spec.ts (or
packages/*/src/**/spec/local-event-stack/**/*.spec.ts in a workspace):
import { getLocalEventStack } from '@xyo-network/event-kit-vitest-config'
import { expect, it } from 'vitest'
it('receives finalized heads', async () => {
const stack = getLocalEventStack()
const subscription = await stack.subscribe({
deploymentId: 'my-indexer',
queueId: 'heads', // optional
fromPosition: 0, // explicit historical floor; default is the source head at creation
maxPositionsPerWake: 16,
})
const active = await subscription.waitForActive()
const wake = await subscription.waitForWake()
expect(wake.publisher).toBe(stack.publisher)
expect(active.activeFromBlock).toBeGreaterThan(0)
expect(wake.fromPosition).toBe(0)
expect(wake.event.source).toEqual({ kind: 'xl1-finalized', chainId: stack.chainId })
await subscription.revoke()
})
pnpm vitest run --project local-event-stack
Plain vitest run does not boot the stack. Its specs are excluded from ordinary
Node/browser projects even when the installer is disabled. Set
localEventStack: { optInOnly: false } to include it in ordinary runs.
defineEventKitVitestProjects and defineEventKitInstallerProjects support
composition with other presets. When composing only installer projects, also
apply LOCAL_EVENT_STACK_EXCLUDE to your base projects.
What runs
Each spec file owns a fresh chain ID, ephemeral loopback ports and temporary
directory. Tests within that file share the stack; do not stop it until the
file's final test. Setup publishes the publisher's service and dedicated HPKE
encryption key. subscribe() creates and funds an independent dev identity,
starts a TLS receiver, and publishes an encrypted subscription plus grant via
an elevated, subject-bearing Claim.
The background publisher discovers the finalized tuple through Statement Graph
replay, decrypts the endpoint, performs its HTTPS ownership challenge, publishes
acceptance and becomes eligible at authorization block acceptance block + 1.
Each wake uses the canonical unversioned source-aware envelope and begins from
the independently declared fromPosition, in batches of maxPositionsPerWake.
Each subscriber has a durable cursor and outbox. Receivers independently replay
the chain and perform real JWT, grant, lifecycle and atomic inbox checks before
durable enqueue. No HTTP handler runs a reducer.
waitForWake() claims and acknowledges one queued wake. For explicit lease or
reducer tests use subscription.queue.claim() and its ack() / release()
methods. dropNextDeliveryResponses() simulates a lost response after durable
admission; retries keep the same wake ID/hash under a fresh JWT. stats() exposes
test-only delivery evidence. Treat its JWTs and fixture account/key state as
sensitive test data; do not log or reuse them on real networks.
Lifecycle and lower-level access
- Setup/teardown owns startup failures, publisher stop, gateways, receivers,
datalake, child process and temporary directories.
stop()is idempotent. getLocalEventStack()is available inside tests/hooks, not at module scope. Alternatively import@xyo-network/event-kit-vitest-config/globalsas a type to type the setup-ownedeventStackglobal.startLocalEventStack({ pollIntervalMs?, readyTimeoutMs? })supports manual ownership. Alwaysawait stack.stop()in afinallyblock.publisherClient,createSubscriber().client,viewer,rpcUrl,dataLakeUrlandadvertisementexpose the real public APIs for custom tests.- For your own receiver, call
registerEndpoint(exactHttpsUrl, certificatePem)before publishing through a fundedcreateSubscriber()client. The return value unregisters it. You own that custom server's cleanup and challenge, admission and queue implementation.
Boundaries
This is a local integration harness, not a mock-based unit-test fixture and not
the production event-kit publisher run command. Like dApp Kit's fixture, it
launches the published XL1 CLI; it additionally disables shared health/metrics
listeners so concurrent stacks do not collide. No apiLocal installer is
required. No chain credentials,
public datalake, Sequence or Mainnet access is needed. All XL1_* environment
overrides and NODE_TLS_REJECT_UNAUTHORIZED=0 must be unset to prevent ambient
wallet/network configuration leaking into the child process.
Only exact, explicitly registered HTTPS URLs on literal 127.0.0.1 are callable.
TLS verification remains enabled with per-endpoint certificate trust. DNS names,
redirects and implicit LAN access are rejected. This test-only allowance does
not change production endpoint rules. Each challenge nonce permits one outbound
attempt. A failed or ambiguous HTTP attempt retries on a later publisher pass
with a fresh challenge; a received proof is retained for acceptance retries.
The chain uses simplified dev consensus and in-memory chain state; publisher, datalake and inbox files exist only until teardown. This does not qualify production supervision, restart recovery, SQLite, multiple VMs, Sequence or Mainnet. Hosted production qualification remains separate.
Repository API-local qualification
This repository keeps the opt-in api-local project name and existing protocol
specs, with a repository-owned setupFiles override in the root Vitest config.
Each file launches the same public XL1 CLI dev chain used by the event stack,
then supplies its actually observed rpcUrl and chainId globals. The config
resolves the setup source relative to its own URL, so package-scoped test runs
use the same setup. Test wallets use the public dev mnemonic; no internal locator
global or provider-ID modification is supplied.
pnpm test:api-local
pnpm test:api-local-statements
pnpm test:live
The published xl1-vitest-config/chain-test 5.5.0 in-process producer imports a
SimpleBlockRunner without the stable provider ID required by XL1 SDK 5.8.0.
The supported setup override changes the chain runtime to the public CLI; it
does not patch dependencies, downgrade the application SDK or restore constructor
name provider identity. Results from this gate are CLI-backed local-chain evidence,
distinct from historical in-process apiLocal evidence and hosted qualification.
The repository's pnpm test:packed-event-stack gate installs from the local
pnpm cache with strict peer checks, typechecks a separate consumer, then runs
two spec files through the packed setup entry. Populate the dependency cache
before running it; this gate is not a registry publication check.
License: LGPL-3.0-only.