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

@khorum-oss/leyline-dsl

v1.0.0

Published

TypeScript builder DSL emitting validated Leyline schema documents

Readme

@khorum-oss/leyline-dsl

The TypeScript builder that emits schema documents.

It produces the canonical document rather than standing beside it as a second source of truth (AD1) — the test that gates this package asserts its output is byte-identical to the hand-written fixture. What it adds is the compile-time half: node references, capability names, and context fields are checked where they are written.

See the glossary for the document vocabulary this builder emits.

Authoring

const workflow = defineWorkflow({
  id: 'workspace-onboarding',
  name: 'Workspace onboarding',
  entry: 'create-workspace',

  context: {
    workspace: { type: 'object', optional: true },
    tier: { type: 'string' },
  },
  requires: {
    guards: ['needsBilling'],
    services: ['createWorkspace'],
    dataSources: ['workspaceActions'],
  },

  nodes: {
    'create-workspace': {
      kind: 'step',
      invoke: {
        service: 'createWorkspace',
        assignTo: 'workspace',
        onDone: [{ target: 'billing', when: 'needsBilling' }, { target: 'workspace-hub' }],
      },
    },
    billing: {
      kind: 'step',
      invoke: { service: 'submitBilling', onDone: [{ target: 'workspace-hub' }] },
    },
    'workspace-hub': {
      kind: 'hub',
      surfaces: [{ id: 'actions', type: 'datatable', dataSource: 'workspaceActions' }],
    },
  },
});

Nodes are keyed by identifier rather than an array carrying one, so the identifier is written once and the keys become what every reference is checked against.

What the types catch

| Written | Result | | -------------------------- | ----------------------------------------------- | | target: 'nowhere' | Type error: not one of the declared nodes | | entry: 'missing' | Type error: not one of the declared nodes | | children: ['ghost'] | Type error: not one of the declared nodes | | when: 'isSecretlyAdmin' | Type error: not in requires.guards | | service: 'exfiltrate' | Type error: not in requires.services | | dataSource: 'allRecords' | Type error: not in requires.dataSources | | assignTo: 'undeclared' | Type error: not a field of the declared context |

Errors land on the offending property, not on the call.

An unknown surface type is deliberately not an error. A document written for a later version has to remain authorable, so unknown vocabulary warns at validation instead (AD8).

What the types cannot catch

Anything that is a property of the whole graph: a node no path reaches, a section containing itself, a link with no target, a one-at-a-time section that does not say which child starts. defineWorkflow validates before returning and throws WorkflowDefinitionError carrying the same structured issues validation always produces.

Canonical output

defineWorkflow returns the document as authored — identifiers left out stay left out, because a derived identifier is derived (decision 0032). Write it to disk with serializeWorkflow from @khorum-oss/leyline-schema and it will match a hand-written file byte for byte.

That equivalence is also the contract the planned Kotlin DSL is held to (brief §10): both must emit the same bytes for the same reference workflows.