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

@brixter/core

v0.5.0

Published

Agnostic brix engine: .brix template language, .md page format, schema inference and validation

Readme

@brixter/core

The agnostic brix engine that powers Brixter.

Everything needed to go from files to HTML, with no editor, Svelte or DOM code: the .brix template language, the .md page format, the analyzer that derives a brik's schema from its own markup, and the validator that holds pages to it. It depends only on yaml, so a published site and the authoring dashboard can share the same base.

Install

npm install @brixter/core

Entry points

| Import | Contents | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | @brixter/core | Everything, plus the document model the authoring UI builds on. | | @brixter/core/template | The template engine — parser, interpreter, static analyzer. No authoring helpers. Use this for build/SSR rendering to keep the bundle minimal. | | @brixter/core/schema | buildBrikSchema and the page validator. | | @brixter/core/page | The +page.md format: parse and serialize. | | @brixter/core/sitemap | Route-path → URL translation, per-page sitemap directives, and the XML serializer. | | @brixter/core/redirects | The redirect compiler: alias reading, validation against a route manifest, chain flattening, and serializers for the hosting layers' native formats. |

Rendering a brik

import { renderBrikSource } from '@brixter/core/template';

const html = renderBrikSource(source, props);

The template language is HTML with braces — {path}, {#each xs as x}, {#if}/{:else} — where an interpolation may carry @tag annotations and a ?? fallback:

<h1>{@richtext @required headline}</h1>
<p>{eyebrow ?? 'Pricing'}</p>

{#each plans as plan}
  <article data-featured={plan.featured}>
    <h3>{plan.name}</h3>
    <a href={plan.ctaHref ?? '#'}>{plan.ctaLabel ?? 'Get started'}</a>
  </article>
{/each}

Other exports: render (over a pre-parsed AST), renderToString, parseTemplate, analyzeTemplate, and the expression parsers (parseReference, parseCondition, parseEachHeader).

Rendering emits data-brixter-field and data-brixter-collection-item onto the elements the visual editor binds click-to-edit to — an element whose whole content is one interpolation, and the sole element inside an {#each}. Pass { editorAnchors: false } to leave them out.

The schema is the template

There is no schema document. buildBrikSchema reads a .brix file and derives the props it accepts from the markup that uses them:

import { buildBrikSchema, validateProps } from '@brixter/core/schema';

const { schema, nodes, issues } = buildBrikSchema(source, { file: 'Hero.brix' });
const problems = validateProps(page.brix[0].props, schema, { file: '+page.md' });

A type comes from how a prop is used — the collection of an {#each} is an array, a path with sub-paths is an object, src= implies an image, href= a URL — refined by any explicit @tag. @enum is the one type nothing can infer.

Neither function throws. validateProps returns every issue it finds, each carrying a code, a message already prefixed with the file, and the path of the field at fault; compileBrikSchema is the throwing variant for build-time callers. This mirrors the redirect compiler's analyze* / compile* split.

Attributes and style

An attribute whose value is a lone interpolation disappears when the value is absent or false, so data-featured={plan.featured} is only present on a featured plan. A true is written as ="true", so attribute-value selectors (Tailwind's data-[featured=true]:) still match.

Inside style, a declaration whose interpolation resolves to nothing is dropped while the others stand:

<img style="object-fit: cover; object-position: {position};" src={@image src} />

With no position, this renders style="object-fit: cover;" — the markup's own default survives rather than being clobbered by an empty value.

Escaping / trust model

Only @richtext and @icon emit markup from content, and their values are treated as semi-trusted and are not sanitised. Interpolated style values are: sanitizeStyleValue drops ;, {, }, <, > and folds newlines/tabs to a space, so a per-page value can never inject an extra declaration or break out of the attribute. Quotes and parentheses are kept so url("…") survives; quotes are HTML-escaped to &quot; at serialization time and decoded back inside the value by the browser.

Redirects

@brixter/core/redirects compiles redirect declarations into one flat, ordered map. It takes a list of sources — a page's aliases is the first, and pageAliasSource builds it — plus the routes the app already serves:

import { compileRedirects, pageAliasSource } from '@brixter/core/redirects';

const rules = compileRedirects({
	sources: [pageAliasSource(pages)],
	routes, // `{ id, pattern }`, e.g. SvelteKit's `builder.routes`
	knownPaths // prerendered pages, static assets
});

It throws RedirectCompileError on any inconsistency — an alias that shadows an existing route, is claimed twice, points nowhere, or loops — with every issue carrying the file that declares the rule. analyzeRedirects returns the same result without throwing, for callers that report rather than stop.

Chains are flattened so each rule resolves in one hop, and the output is sorted deterministically. formatRedirectsFile / mergeRedirectsFile serialize to the _redirects format (Netlify, Cloudflare Pages); toVercelRoutes to Vercel's Build Output API. routeIdToPattern builds a route matcher for callers that have no framework manifest to hand.

Document model & authoring helpers

The package root additionally exposes what the visual editor builds on: documentFromPage / pageFromDocument to move between a parsed page and an editable document, previewBindingsFromSchema and collectionsFromSchema to turn an inferred schema into a field list and a set of editable collections, createFallbackProps to synthesise the placeholder content a preview shows before anything is written, and the prop-manipulation primitives (updatePropsAtPath, addCollectionItem, reorderCollectionItem, …).

Consumers rendering finished pages need none of it — @brixter/core/template is enough.

License

MIT