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

@syncropel/projections

v0.8.0

Published

TypeScript schema + validators for the Syncropel Rendering Protocol (SRP v0.8) — declarative UI documents for query-driven and AI-generated interfaces. v0.8 adds five visual-atom nodes (glyph, status-dot, pulse, link, code) on top of the v0.7 grammar (39

Downloads

1,622

Readme

@syncropel/projections

TypeScript schema and runtime validators for the Syncropel Rendering Protocol (SRP) — declarative UI documents composed from a constrained palette of block-level primitives, designed for query-driven and AI-generated interfaces.

import { validateSRP, type SRPDocument } from "@syncropel/projections";

const doc: SRPDocument = {
  srp: "0.1",
  root: {
    type: "column",
    props: { gap: "md" },
    children: [
      { type: "heading", props: { level: 1, text: "Session summary" } },
      {
        type: "grid",
        props: { cols: 3, gap: "sm" },
        children: [
          { type: "stat", props: { label: "Tracks played", value: 47 } },
          { type: "stat", props: { label: "Artists", value: 14, delta: 3 } },
          { type: "stat", props: { label: "Transitions", value: 12 } },
        ],
      },
    ],
  },
};

const result = validateSRP(doc);
if (!result.valid) {
  for (const err of result.errors) {
    console.warn(`${err.path}: ${err.message}`);
  }
}

Features

  • 19 block-level primitives — containers, record-rendering, data display, interactive, feedback. Closed palette; growth happens through reviewed spec proposals, not consumer-side overrides.
  • TypeScript schema — every primitive has a typed node interface with discriminated-union dispatching.
  • Runtime validatorsvalidateSRP() walks a document and returns structured errors (JSON-pointer-style paths + machine-readable codes) for anything that doesn't conform.
  • Markdown subset parser — inline **bold**, *italic*, `code`, [link](url), ~~strike~~ in text-valued props, rendered via the corresponding typography atoms.
  • Zero runtime dependencies — uses the platform only.
  • Universal runtime — Node 18+, Deno, Bun, Cloudflare Workers, modern browsers.

Install

npm install @syncropel/projections

Ships compiled JavaScript + TypeScript declarations. ESM only.


What's in the box

Schema types

The 25 node types are exported as a discriminated union keyed on type:

| Category | Nodes | |---|---| | Containers | column, row, grid, card, divider | | Record rendering | record-line, record-line-list, chip | | Data display | heading, text, stat, key-value | | Interactive | button, icon-button, copy-button, select | | Feedback | empty-state, error-state, skeleton | | Interactive containers + inputs (v0.2) | tabs, data-table, board, text-input, form | | Choice control (v0.3) | segmented |

Every node has a matching TypeScript interface (e.g., ButtonNode, StatNode). Import the ones you need, or use SRPNode for the full union.

Validators

validateSRP(doc) accepts an unknown and returns:

type ValidationResult =
  | { valid: true }
  | { valid: false; errors: ValidationError[] };

interface ValidationError {
  path: string;                      // JSON-pointer-style path
  message: string;                   // human-readable
  code: ValidationErrorCode;         // machine-readable
}

Error codes: SRP_VERSION_INVALID, ROOT_MISSING, NODE_NOT_OBJECT, NODE_TYPE_MISSING, NODE_TYPE_UNKNOWN, PROPS_MISSING_REQUIRED, PROPS_INVALID_VALUE, CHILDREN_NOT_ARRAY, CHILDREN_NOT_ALLOWED, BIND_MISSING_REQUIRED, BIND_INVALID_SHAPE.

Use isSRPDocument(x) or isSRPNode(x) as type guards in adapter code that receives untrusted JSON.

Markdown subset

Text-valued props (text, label, message, etc.) accept a narrow markdown subset for inline formatting. Parse it with parseInline(text) to get an AST you can render:

import { parseInline, type InlineNode } from "@syncropel/projections";

const nodes = parseInline("Visit **example.com** or read the [docs](/docs).");
// → [
//     { kind: "text", text: "Visit " },
//     { kind: "bold", children: [{ kind: "text", text: "example.com" }] },
//     { kind: "text", text: " or read the " },
//     { kind: "link", url: "/docs", children: [{ kind: "text", text: "docs" }] },
//     { kind: "text", text: "." }
//   ]

Supported constructs: **bold**, *italic*, `code`, [label](url), ~~strike~~. Unbalanced delimiters render as literal text (no silent drops). Block-level markdown (headings, lists, tables, etc.) is NOT parsed — use SRP block-level nodes for structural content.

Strip formatting for aria-labels / plain-text search with stripFormatting(nodes).


Who uses this

  • Adapter authors — emit projection documents as record bodies; the schema guarantees your document renders across every Syncropel surface.
  • Renderer authors@syncropel/react consumes this package for its prop types; future renderers (Vue, Svelte, server-side HTML, etc.) will too.
  • Backend servers — validate projection documents before storing them, without pulling in a React runtime.

Related packages

See CHANGELOG.md for release notes.


License

Apache-2.0.