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

@byollm/server

v0.1.4

Published

Framework-agnostic BYOLLM protocol handlers, a reference in-memory store, a Next.js mount, and a Supabase adapter.

Readme

0.1.4 is documentation only — nothing to upgrade. PROTOCOL_VERSION is still 2, so a 0.1.0 party and a 0.1.1 party talk to each other in both directions. No dependency, schema, wire field or on-disk shape moved.

This README used to open with a stack of release notes instead of with the package. The history moved to docs/release-notes/ and CHANGELOG.md, where none of it was lost. Full note: docs/release-notes/0.1.1.md.

@byollm/server

What app developers drop into their backend: framework-agnostic protocol handlers, a reference in-memory store, a Next.js mount, and a Supabase adapter.

npm install @byollm/server

The three-file integration

1. Mount the protocol.

// app/byollm/[...route]/route.ts
import { createHandler } from "@byollm/server/next";
import { siteKeysFromEnv } from "@byollm/server";
import { getStore } from "@/lib/byollm";

export const { POST } = createHandler(() => ({
  store: getStore(),
  siteKeys: siteKeysFromEnv("BYOLLM_SITE_KEYS"),
  verificationUrl: "https://your-app.com/settings/runners",
}));

Pass a function, not an object. next build imports every route module to collect page data, in an environment that has no secrets. A config object is constructed during that import, so the build fails on credentials it cannot have. A function is not called until the first request.

Then pair against the origin — byollm connect https://your-app.com.

The route has to live at /byollm, not under /api. The daemon pairs with an origin: it drops any path it is given (https://your-app.com/api pairs with https://your-app.com) and calls <origin>/byollm/<endpoint>. The handler matches the full path, so a route mounted anywhere else — the Next-conventional app/api/byollm/[...route]/route.ts with basePath: "/api/byollm" included — is one no shipped daemon can reach today. basePath remains for a handler that something other than the daemon must find; leave it out for the daemon.

2. Pick a store.

// lib/byollm.ts
import { ByollmApp, MemoryStore, siteKeysFromEnv } from "@byollm/server";

// Lazily, and memoized, for the same reason the mount takes a function: a
// module-scope `new` runs during `next build`.
let store: MemoryStore | undefined;
export function getStore(): MemoryStore {
  return (store ??= new MemoryStore());
}

let app: ByollmApp | undefined;
export function getApp(): ByollmApp {
  return (app ??= new ByollmApp({
    store: getStore(),
    siteKeys: siteKeysFromEnv("BYOLLM_SITE_KEYS"),
  }));
}

Generate that identity once, and keep it:

npx --package @byollm/server keygen   # prints BYOLLM_SITE_KEYS=...

Once, not per deploy and never at startup — a daemon pins this identity when its owner approves the pairing, and regenerating it means every paired device must pair again. Generating at startup fails only under horizontal scale: each instance would have a different identity, and a daemon would be refused by whichever one it did not pair with.

3. Enqueue.

const job = await getApp().enqueue({
  kind: "llm.generate",
  audience: "private", // this user's own device only — the default
  owner: ownerId, // who this is depends on your mode — see below
  payload: { prompt: `Summarize this transcript:\n\n${transcript}` },
});

const { outcome, fallback } = await job.result({
  timeoutMs: 120_000,
  // A string is enough — it is your own fallback answer, not wire data.
  onNoRunner: () => runOnHostedModel(transcript),
});

// `fallback` is true when nobody's device ran it and this came from your
// own substitute. Say so wherever you show the answer: work that did not run
// on the user's compute must not be presented as though it did.

result() is sugar over your delivery channel with a timeout and a noRunnerAvailable path — never a bare promise that hangs forever. If nobody is online to run the job, you find out and can fall back.

Who owner is — this differs by mode

owner names the person whose devices should do the work, and the two connection modes do not use the same names for people. Getting this wrong is the one integration mistake that produces no error: the job enqueues, returns an id, and never routes.

Direct — daemons reach your own handlers, and you are the only party who knows who anybody is. owner is your own user id, from your session, never from the client. That is what the example above shows.

Cloud — daemons reach hub.byollm.cloud, which has its own identity space: rosters, consents and budgets all speak BYOLLM ids. Your user id means nothing there. owner must be the person's BYOLLM id.

Ask them for it. Every signed-in person can read it on their byollm.cloud account page under Your BYOLLM id, with a copy button. Add a settings field, have them paste it, store it against your own user record.

The id names them and authorises nothing — someone holding it can address work to a person and cannot deliver it, because the consent row is what opens the route. So a pasted id is not a credential you are being trusted with, and a wrong one is harmless. Two things still matter: it must come from the person's own account rather than being inferred by your app, and they must connect your site on byollm.cloud before anything routes.

A wrong id is silence, not an error. The relay routes on a consented (site, owner) pair, so a mistyped id — or one belonging to somebody who has not connected your site — matches no route. The job waits, then expires. So check ids when you receive them rather than when you enqueue:

const { available } = await getApp().runnerAvailability({
  kind: "llm.generate",
  owner: pastedByollmId,
});

if (!available) {
  // Existence-neutral, deliberately.
  return "That id has no devices for you. Check it, or connect this site on byollm.cloud.";
}

Keep that message vague on purpose. A typo'd id and an id belonging to somebody who has not connected you give the same answer, and that is the system working rather than a limitation to route around — telling them apart would make this call an account-existence oracle: probe a guess, sort the answers, enumerate. Never write "no such account". If you ever get an answer that does distinguish them, that is a bug worth reporting.

The approval page

Pairing is a device-code exchange, so you need one page where a signed-in user types the code their daemon showed them:

// The owner comes from YOUR session. A daemon can never assert who it is.
const runner = await getApp().approvePairing({
  userCode: formData.get("code"),
  owner: session.userId,
});

app.pendingPairing(code) tells you what they are about to approve — device label, platform, and which models it is offering — so the page can show it.

Stores

| Store | For | | --------------- | ---------------------------------------------------------------------------------------------------------------- | | MemoryStore | Tests, demos, single-process apps. The reference implementation the conformance kit certifies first. | | supabaseStore | Postgres via Supabase: migrations, an RLS-scoped claim RPC with FOR UPDATE SKIP LOCKED, and Realtime delivery. | | yours | Implement JobStore + RunnerStore and run @byollm/conformance against it. |

Supabase

import {
  supabaseStore,
  supabaseRealtimeDelivery,
} from "@byollm/server/supabase";

const store = supabaseStore({ client: serviceRoleClient });
const app = new ByollmApp({
  store,
  siteKeys: siteKeysFromEnv("BYOLLM_SITE_KEYS"),
  delivery: supabaseRealtimeDelivery(serviceRoleClient),
});

Copy supabase/migrations/*.sql into your project's migrations. It ships the byollm_* tables, RLS policies, the atomic claim RPC, the dependency-unblock trigger and the expiry sweep.

The protocol handler needs the service role key: a runner is not a Supabase user — its requests are signed with its device key, not carried by a Supabase session — so RLS cannot identify it. RLS still governs everything the browser does.

Two things the API makes you confront

Community results are untrusted. A team result came from someone else's device and can be anything. Every result carries provenance, and untrusted is derived from the audience — you cannot mark volunteer output as first-party:

const { outcome, provenance } = await getApp().result(jobId);
if (provenance?.untrusted) {
  // Do not render as trusted HTML. Do not feed to a privileged step.
  // Disclose where it came from.
}

Jobs can depend on each other. dependsOn: [jobId] keeps a job unclaimable until its dependencies are ok. One field and one claim predicate, not a DAG engine — so the two halves of a piece of work can land on two different people's devices, in order, without your app orchestrating the wait.

Certifying an adapter

npm install --save-dev @byollm/conformance
npx byollm-certify ./my-target.js

A server is byollm-compatible when the kit passes. See @byollm/conformance.

MIT

The rest of byollm

Six packages, and they are only interesting together:

  • byollm — the daemon — runs models on your own machine and answers for it
  • @byollm/protocol — the wire: envelopes, signatures and the closed vocabularies both ends validate against
  • @byollm/relay — the broker that holds jobs between a site and a device, and can read neither
  • @byollm/control-plane — who may ask whom, and the policy store behind it
  • @byollm/conformance — the kit that proves an implementation is one — including a posture audit that holds nothing but a URL

Where the rest lives