Skip to Content

Standard solutions for repeated infrastructure pains.

Stop re-solving authorization, identifiers, and dynamic layouts from scratch in every project. Our small, focused libraries solve these specific problems once, so you can focus on your product.

Rendering from data

Stop hard-coding complex layouts with conditional logic. Describe your UI as data and render it with React or Astro, with props checked at compile time in React and by validateItems before an Astro build.

Read the docs →
BaizeWeek 38
38Games in+6
31Sold+2
2.4 dTurnaround−0.3

Tonight at the tables

TableGamePartyState
OneBrass: BirminghamHanna Lind, +3Playing
TwoSpirit IslandOtto Ruane, +2Playing
ThreeRootSigrid Vall, +3Teaching
FourCrokinoleEmil Norrby, +1Booked, 20:00

Reprints on order

TitleDue
Wingspan, OceaniaTuesday
Hive PocketThursday
Azul, Summer PavilionNext week

itemsMove one and the page is composed again

[  { "id": "week", "type": "columns", "props": {}, "children": [    { "id": "intake", "type": "metric", "props": { "figure": "38", "label": "Games in", "delta": "+6" } },    { "id": "sold", "type": "metric", "props": { "figure": "31", "label": "Sold", "delta": "+2" } },    { "id": "turnaround", "type": "metric", "props": { "figure": "2.4 d", "label": "Turnaround", "delta": "−0.3" } }  ] },  { "id": "counter", "type": "columns", "props": {}, "children": [    { "id": "tables", "type": "tables", "props": { "title": "Tonight at the tables" }, "meta": { "span": 2 } },    { "id": "reprints", "type": "reprints", "props": { "title": "Reprints on order" } }  ] }]
Every block is a component somebody wrote once. The items decide which blocks the page has, what sits inside what, and how wide each one is — so a row moves on a CMS save rather than a deploy. Move a container and everything nested under it goes with it. This page is itself a Widget region, built the same way.

Authorization from one policy

Stop duplicating authorization logic between your frontend and backend. Define your policy once as a serializable document and evaluate it locally, on the server and in the browser.

Read the docs →
Mika Persson

Brass: Birminghamdraft

Network building on the canals and railways of the Midlands, two to four players, about two hours. Complexity 3.9 of 5. A copy is on the shelf and another sits on table three most evenings.

  • Jo VainioPlayed it twice at the back tables before buying. Worth the shelf space.
Signed in as Mika Persson, bookseller. Review, Edit.

access

const access = policy<Shopper, ShopObjects, ShopVerbs>()
  .for('listing', (p) =>
    p.allow('review', p.always)
      .allow('edit',
        p.in('subject.role', [, , ]))
      .allow('publish',
        p.in('subject.role', [, , ]))
      .deny('edit', p.eq('object.status', 'published'))
      .id('published-is-locked'),
  )
  .build();
That is the whole policy, and every control on the toolbar is one of its answers. Change who is signed in, or take a role out of a grant, and the interface is rebuilt around what is left.

Feature flags in your repo

Define flags as a file in your repository. One library evaluates these definitions across your API, your build, and the browser without a network call per check.

Read the docs →

Decided before deploy

Set once for every visitor when the site builds.

Brass: Birmingham

Brass: Birmingham is a strategy game, so the rollout can reach its visitors.

Old gallery
New gallery

The new gallery waits for the visitor.

Decided when a visitor arrives

Set for each visitor when they arrive.

11 of 48 visitors see the new gallery.

Raising the share only adds visitors; nobody who has the new gallery loses it.

Each dot is a visitor, told apart by their id. Filled means they see the new gallery. The same visitor always gets the same answer.

Tap or hover a dot to see that visitor.

11 of 48 visitors see the new gallery.

Your flags

createFeatures([
  { key: 'new-gallery', enabled: true,
    rules: [{
      when: [{ field: 'category', op: 'eq', value: 'strategy' }],
      rollout: { percent: 25, by: 'targetingKey' },
    }] },
])

// before deploy: one call per page
features.plan({ game, category: 'strategy' })
// when a visitor arrives: one call per request
features.resolve({ game, category, targetingKey: visitor.id })
Some decisions are made before deploy; for the Azul family game, it is decided that no one sees the new gallery. Others are decided when a visitor arrives; for the Brass strategy game, each visitor is evaluated upon arrival. Raising the share for Brass simply increases the number of visitors who see the feature.

Identifiers and codes

Stop letting typos in identifiers reach your database. Add check characters to IDs and mint human-readable codes that catch errors at the edge.

  • scheme Always the same three letters, and they say what the rest of the string is: a name for something, not an address where it lives. A URL tells you where to go; this tells you what you mean.:namespace What kind of thing this names. Two systems can both number their records from 1, and this is what keeps those two 1s apart.:name The identifier itself, in whatever form the system it came from uses. Unique inside the namespace above, and nowhere else.urn:game:brass-birmingham

    Attach

    Identifiers that carry their own namespace, so an id is never just a number. RFC 8141, with an API shaped like the JSON class.

    @evanion/urnuniversal
  • Issued

    accepted
    foo5 is accepted.
    Break it

    The last character is the check. Break the code and it stops matching.

    A check character for anything a person types by hand, so a typo is rejected before it reaches your database. Any alphabet.

    @evanion/luhnuniversal
  • a4kp-9mxa

    Say it as
    Drawn from

    35 bits, so a collision is even odds at 218,000 codes.

    Short codes a user can easily communicate without confusion, with validation built in.

    @evanion/tokenuniversal

On their own

Focused solutions for specific infrastructure pains, from request tracing to provider trees.
  • Compose

    A React component for composing providers: a tree of nested wrappers becomes one flat, readable list.

    @evanion/composeReact
  • Correlation ID

    Correlation ID middleware for NestJS. Carries one id from the incoming request through everything it awaits and onto outgoing HTTP calls, so log lines across services line up.

    @evanion/nestjs-correlation-idNestJS
  • UI

    A stateless, native-first React UI core: one layered stylesheet with a neutral theme, and components that render the same under SSR, a SPA and Server Components.

    @evanion/uiReact