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

@statelyjs/schema

v0.5.0

Published

Type definitions and schema parser for Stately

Readme

🏰 @statelyjs/schema

Type definitions and schema parsing for Stately applications

npm License

This package provides the foundational type system for Stately's frontend. It parses OpenAPI schemas into a typed AST (Abstract Syntax Tree) that powers the UI's form generation, validation, and type safety.

This 'schema' package is a low-level package used internally by Stately. See @statelyjs/stately for the user facing package.

Installation

pnpm add @statelyjs/schema

Note: Most users should use @statelyjs/ui which re-exports this package with additional UI integration. Use @statelyjs/schema directly only if building custom tooling or plugins without the UI layer.

Core Concepts

Schema Nodes

OpenAPI schemas are parsed into nodes - typed representations of each schema element:

// A string field
{ nodeType: 'string', nullable: false }

// An object with properties
{ 
  nodeType: 'object',
  properties: {
    name: { nodeType: 'string', nullable: false },
    age: { nodeType: 'integer', nullable: true },
  },
  required: ['name'],
}

// A reference to another entity
{ nodeType: 'link', inner: { nodeType: 'ref', $ref: '#/components/schemas/SourceConfig' } }

The Schemas Type

The Schemas type is the single source of truth for your application's type system. It combines:

  1. Config: Your OpenAPI-generated types (components, paths, operations)
  2. Plugins: Type augmentations from installed plugins
  3. Derived Types: EntityData, StateEntry, and other computed types
import type { StatelySchemas, DefineConfig } from '@statelyjs/schema';
import type { components, paths, operations } from './generated/types';

type MySchemas = StatelySchemas<DefineConfig<components, paths, operations, typeof PARSED_SCHEMAS>>;

Plugin System

Plugins extend the schema with additional node types:

import type { DefinePlugin, NodeMap, StatelySchemas } from '@statelyjs/schema';

// Define custom nodes
interface MyNodes extends NodeMap {
  myCustomType: { nodeType: 'myCustomType'; value: string };
}

// Create plugin type
export type MyPlugin = DefinePlugin<'my-plugin', MyNodes>;

// Use with Schemas
type AppSchemas = StatelySchemas<MyConfig, readonly [MyPlugin]>;

Usage

Creating a Stately Runtime

import { createStately } from '@statelyjs/schema';
import { PARSED_SCHEMAS } from './generated/schemas';
import openapiDoc from './openapi.json';

const stately = createStately<MySchemas>(openapiDoc, PARSED_SCHEMAS);

// Access schema utilities
const entityNode = stately.utils.getNode('Pipeline');
const isValid = stately.utils.validate(data, 'Pipeline');

With Code Splitting

When using @statelyjs/codegen with entry points, some schemas are split into a separate runtime bundle for lazy loading. Configure the loader to enable this:

import { createStately } from '@statelyjs/schema';
import { PARSED_SCHEMAS } from './generated/schemas';
import openapiDoc from './openapi.json';

const stately = createStately<MySchemas>(openapiDoc, PARSED_SCHEMAS, {
  // Enable lazy loading for code-split schemas
  runtimeSchemas: () => import('./generated/schemas.runtime').then(m => m.RUNTIME_SCHEMAS),
});

This is optional - if no schemas.runtime.ts was generated, you don't need this option.

With Plugins

import { createStately } from '@statelyjs/schema';
import { filesPlugin } from '@statelyjs/files';

const stately = createStately<MySchemas>(openapiDoc, PARSED_SCHEMAS)
  .withPlugin(filesPlugin());

// Plugin utilities are now available
stately.plugins.files.utils.formatPath('/some/path');

Type Helpers

DefineConfig

Combines your generated types into a schema configuration:

type MyConfig = DefineConfig<
  components,           // OpenAPI components
  DefinePaths<paths>,   // API paths
  DefineOperations<operations>,  // Operations
  typeof PARSED_SCHEMAS // Generated schema nodes
>;

DefinePlugin

Declares a plugin's type augmentations:

type MyPlugin = DefinePlugin<
  'my-plugin',     // Unique name (string literal)
  MyNodes,         // Node map
  MyTypes,         // Additional types
  MyData,          // Data utilities
  MyUtils          // Utility functions
>;

Extracting Types

import type { Schemas } from '@statelyjs/schema';

// Get the StateEntry union (entity type names)
type StateEntry = MySchemas['config']['components']['schemas']['StateEntry'];

// Get entity data types
type EntityData = MySchemas['types']['EntityData'];

// Get all nodes from plugins
type AllNodes = MySchemas['plugin']['AnyNode'];

Integration with @statelyjs/codegen

The @statelyjs/codegen CLI generates the files this package consumes:

pnpx @statelyjs/codegen ./openapi.json ./src/generated

This produces:

  • types.ts - TypeScript interfaces matching your OpenAPI spec
  • schemas.ts - Parsed PARSED_SCHEMAS object for runtime use

Validation

import type { ValidationResult } from '@statelyjs/schema';

const result: ValidationResult = stately.utils.validate(data, 'Pipeline');

if (!result.valid) {
  console.log(result.errors);
  // [{ path: ['name'], message: 'Required field missing' }]
}

API Reference

createStately(openapiDoc, parsedSchemas, createStatelyOptions)

Creates a Stately schema runtime.

isNodeOfType(node, nodeType)

Type guard for checking node types:

if (isNodeOfType(node, NodeType.Primitive)) {
  // node is typed as Primitive 
}

createOperationBindingsFactory()

Creates typed API operation bindings from paths.

License

Apache-2.0