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

@ouijan/laya-client

v0.2.0

Published

Typed TypeScript client for laya-serve, generated from its OpenAPI spec

Readme

@ouijan/laya-client

Typed client for laya-serve. The types in src/schema.ts are generated from the server's own OpenAPI spec, so they cannot drift from the API.

Names mirror the TypeSafe SDK — systemOne, ChoiceAnswer, ScoreAnswer, NoulAnswer — so swapping between this server and the hosted Jev API is a change of import, not of code.

Quickstart

You need a server. It's a container, so this needs no GPU and no checkpoint download beyond the image:

docker run -d --name laya -p 127.0.0.1:11500:11500 ghcr.io/ouijan/laya-serve
until curl -sf localhost:11500/health >/dev/null; do sleep 2; done

docker run -d returns before the checkpoint is resident, which takes ~30s, hence the wait. Then:

mkdir laya-play && cd laya-play
bun init -y
bun add @ouijan/laya-client

A complete runnable index.ts is in the repo README, and as a folder at examples/typescript-quickstart. The rest of this page is the API surface.

Install

Published to the public npm registry:

npm add @ouijan/laya-client   # or bun add / pnpm add

Also published to GitHub Packages. That registry needs a token even for public packages, so only use it if you specifically want it:

# .npmrc
@ouijan:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

The package ships compiled JS and .d.ts, so it works under Node, bundlers and bun alike. Inside this repo, depend on it by path instead:

bun add file:../laya-serve/clients/typescript

Use

import { createLayaClient, isChoice, isScore, isNoul } from "@ouijan/laya-client";

const laya = createLayaClient({ baseUrl: "http://your-box:11500" });

const { answers, usage, routing } = await laya.systemOne({
  state: "We were billed twice for March. We'll move to a competitor.",
  questions: {
    department: {
      type: "choice",
      instructions: "Which team should handle this?",
      criteria: { billing: "invoices, refunds", technical: "bugs", sales: "pricing" },
    },
    frustration: {
      type: "score",
      instructions: "How frustrated the customer appears",
      criteria: ["Calm", "Frustrated but civil", "Very angry"],
    },
    churn_risk: { type: "noul", instructions: "The customer threatens to leave" },
  },
});

answers is a discriminated union on type. Narrow it and the rest of the fields follow:

for (const [id, answer] of Object.entries(answers)) {
  if (isChoice(answer)) console.log(id, answer.choice, answer.probabilities);
  else if (isScore(answer)) console.log(id, answer.score, answer.legend);
  else if (isNoul(answer)) console.log(id, answer.noul);
}

state accepts a string, an object or a list of conversation turns.

laya extras

Beyond Jev's fields you also get routing (which of the three checkpoints answered, and why) and action.act_probability on each answer. noul answers carry a confidence that the hosted API does not return.

routing?.model;   // "multilingual"
routing?.reason;  // "non-Latin script (cyrillic, 100% of letters); ..."

laya.route(...) returns just that decision, with no forward pass.

Errors

Non-2xx responses throw LayaError, carrying status and detail.

Pass fetch to supply your own implementation, e.g. for timeouts:

createLayaClient({
  baseUrl,
  fetch: (req) => fetch(req, { signal: AbortSignal.timeout(10_000) }),
});

Versioning

The client version tracks the server's, and a single v<semver> tag ships both. @ouijan/[email protected] is built from the same commit as ghcr.io/ouijan/laya-serve:0.1.0, so pin them to the same number. A test fails if package.json and pyproject.toml disagree.

# bump both, then:
git tag v0.2.0 && git push --tags

Regenerating after an API change

bun run build   # spec -> types -> dist

bun run spec alone rewrites openapi.json and needs the Python package; it imports the app but never starts it, so no checkpoint is downloaded and no GPU is needed. bun run compile alone rebuilds dist/ and needs no Python.

Commit both openapi.json and src/schema.ts so consumers don't need Python. See CONTRIBUTING.md for the rest.