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

@xema/omni-protocol

v0.1.65

Published

The Omni protocol: the contract every provider adapter implements

Readme

Omni-Protocol

The contract every provider adapter implements, and the checks that hold adapters to it.

A provider is one independently connected external system — a voice platform, a chat platform, a mail platform. An adapter is the package speaking this contract for one provider. Omni composes several providers into one agent-facing desktop and owns everything outside a provider's own system.

What is here

| Path | | | --- | --- | | guide.md | The protocol. Rules, shapes, and the reasoning behind them. | | src/index.ts | The TypeScript declarations. | | src/validation.ts | Runtime validators Omni applies to adapter output. | | src/testing.ts | Conformance helpers an adapter runs against its own test state. | | tests/ | One test file per source module, plus the guards over the guide and the repository's own text. |

Entry points

import { defineAdapter } from "@xema/omni-protocol";
import { validateSnapshot, assertNoViolations } from "@xema/omni-protocol/validation";
import { exerciseAdapter } from "@xema/omni-protocol/testing";

Validation is not only for tests

An adapter is loaded from a separate package and may be compiled against a different protocol version, so its output is untrusted input. Every validator takes unknown and returns every violation it found rather than throwing on the first, so a caller reports all of them at once. Validating a snapshot before it replaces provider state is what stops a malformed task reaching the agent's workspace; validating a result with validateResult(result, method) before acting on it is what stops a status the host does not know being shown as an outcome.

const violations = validateSnapshot(snapshot, manifest);
assertNoViolations(violations);

A violation carries a stable rule id such as task.browser.url.scheme, the path it was found at such as snapshot.tasks[0].browsers[1].url, and a message.

Some rules need more than the object in hand. A roster never carries the agent it is published to, a lead's snapshot always carries one and nobody else's ever does — and a validator cannot know who is reading, or what their login declares, from the snapshot alone. validateTeamRoster, validateSnapshot, and validateEventEnvelope each take an optional final { self, capabilities } from the authenticated state; given them, they report team.member.self, team.request.self, team.required, team.unentitled, team.requests.capability, and team.requests.required. Without them those rules are not checked. exerciseAdapter always passes both.

const { identity, capabilities } = authenticated;
validateSnapshot(snapshot, manifest, "snapshot", { self: identity.id, capabilities });

Conformance

exerciseAdapter validates the manifest, opens an authenticated session, connects, checks required capability methods, subscribes, validates the snapshot, every delivered event, and every authentication state published during the run — against the latest login — states a capacity, then unsubscribes and disconnects. result.notExercised names what the run never reached — each optional part of a task, of the break state and roster, each contribution, each event type — so a clean result is read for what it covers and not for the whole contract; assertReached(result, subjects) is the paired assertion.

const context = { protocolVersion: OMNI_PROTOCOL_VERSION, loginId: "session-1", host: stillHost(report) };
const result = await exerciseAdapter(adapter, context, { collectOnly: true });
expect(result.violations).toEqual([]);
expect(result.disconnectWasClean).toBe(true);

Run the contract scenarios beside it — authentication restore and expiry, capability withdrawal, reconnect with missed assignments, break denial and retry, a break asked for on a task, who a break asks, wrap timeout, browser isolation.

Assert both directions. Every helper rejects a violating input as well as accepting a conforming one. A suite that only asserts "this conforming case does not throw" passes unchanged if the helper is gutted, so pair every positive case with the violating twin.

Three things TypeScript will not catch for you

All found by adapters against this contract, and all produce a green build over a wrong shape. Two share one cause: TypeScript checks extra keys only on a literal that is the thing directly assigned. Move the literal anywhere else and the check is gone.

Conditional spreads are the blind spot on a task literal. A key inside ...(cond ? { … } : {}) is never checked against the task type, and satisfies Task<C> on the surrounding literal does not reach it. Put the check on the spread operand itself:

const task = {
  id, title, channel: "voice", taskType, capabilities, browsers, phase, completionMode,
  ...(contact ? { contact } satisfies Partial<Task<"voice">> : {}),
};

Switch on command.action with no default. A default turns a future action into whatever the default does, silently; naming every arm means dropping one fails the build — indirectly, as a missing return — and keeps the narrowing that lets you read destinationId without a cast.

switch (command.action) {
  case "cold":     return coldTransfer(command.destinationId);
  case "warm":     return warmTransfer(command.destinationId);
  case "complete": return completeWarmTransfer();
  case "cancel":   return cancelWarmTransfer();
}

A const fixture escapes excess-property checking. Park a literal in a variable and it is no longer the thing directly assigned — the same reason the conditional spread escapes — so a shared test fixture keeps a field the contract has dropped: tsc says nothing and the suite is confidently green over a shape that no longer exists. Annotate the const or satisfies it where it is declared; either names the field on the next build.

take({ reasonId, requestedAt });                                // error: requestedAt
const request = { reasonId, requestedAt }; take(request);      // no error — the hole
const request: BreakRequest = { reasonId, requestedAt };        // error: requestedAt
const request = { reasonId, requestedAt } satisfies BreakRequest; // error: requestedAt

Building

pnpm install
pnpm build        # emits dist/
pnpm test         # type-checks the tests, then runs them

The guide is authoritative

Where guide.md and any code here disagree, the guide is right and the code is a defect. It has been through review and is not edited casually.