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

@affino/projection-engine

v0.2.1

Published

Internal projection stage graph runtime for Affino headless cores

Readme

@affino/projection-engine

Small, framework-agnostic runtime for projection pipelines modeled as a declarative DAG.

Designed for Affino core packages (datagrid-core, treeview-core, and future engines) where data transformations are split into dependent stages (for example: filter -> sort -> group -> paginate -> visible).

Think of it as a minimal spreadsheet-style recalculation engine for ordered projection pipelines.

Problem It Solves

When a source update happens, not every stage must be recomputed. This package provides:

  • stage dependency graph with automatic topological execution order
  • dirty stage propagation from requested roots
  • selective recompute with optional blocked stages
  • stale tracking (requested > computed) for diagnostics and deferred healing

Core Model

Graph is declared by nodes and upstream dependencies:

const graph = {
  nodes: {
    filter: {},
    sort: { dependsOn: ["filter"] },
    group: { dependsOn: ["sort"] },
    paginate: { dependsOn: ["group"] },
    visible: { dependsOn: ["paginate"] },
  },
} as const

Engine derives:

  • stageOrder (topological order)
  • dependents (downstream edges)
  • downstreamByStage closure for fast invalidation

API

createProjectionStageEngine(options)

Creates runtime with:

  • requestStages(stages, { trackRequested? })
  • requestRefreshPass()
  • recompute(executeStage, { blockedStages? })
  • recomputeFromStage(stage, executeStage, options?)
  • expandStages(stages)
  • getStaleStages()

Optional: pass preparedGraph from prepareProjectionStageGraph(...) to reuse prevalidated topology in engine creation.

prepareProjectionStageGraph(graph, options?)

Prepares and validates graph once. Use this for repeated expansion operations to avoid repeated graph resolution/validation.

expandProjectionStages(stages, graphOrPreparedGraph)

Returns downstream closure for the requested roots.

Important contract:

  • expansion is inclusive, so each requested stage is included in result together with its downstream dependents.

Example

import { createProjectionStageEngine } from "@affino/projection-engine"

type Stage = "filter" | "sort" | "group" | "visible"

const engine = createProjectionStageEngine<Stage>({
  nodes: {
    filter: {},
    sort: { dependsOn: ["filter"] },
    group: { dependsOn: ["sort"] },
    visible: { dependsOn: ["group"] },
  },
  refreshEntryStage: "filter",
})

const state = {
  filterApplied: false,
  sortApplied: false,
  groupApplied: false,
  visibleApplied: false,
}

function executeStage(stage: Stage, shouldRecompute: boolean): boolean {
  if (!shouldRecompute) {
    return false
  }
  if (stage === "filter") state.filterApplied = true
  if (stage === "sort") state.sortApplied = true
  if (stage === "group") state.groupApplied = true
  if (stage === "visible") state.visibleApplied = true
  return true
}

// 1) Incoming row update affects filter roots
engine.requestStages(["filter"])

// 2) Run recompute cycle
const meta = engine.recompute(executeStage)
// meta.recomputedStages -> ["filter", "sort", "group", "visible"]

// 3) Deferred mode: block sort/group for one cycle
engine.requestStages(["filter"])
engine.recompute(executeStage, { blockedStages: ["sort", "group"] })

// 4) Check unresolved stages and heal later
const stale = engine.getStaleStages()
if (stale.length > 0) {
  engine.recompute(executeStage)
}

Recompute Contract

recompute calls executeStage(stage, shouldRecompute) only for dirty stages in topological order.

  • shouldRecompute = false for blocked stages
  • if a stage is stale (requested > computed) and not actually recomputed, it stays dirty
  • if a stage is actually recomputed, computed catches up to requested

This allows deferred projection updates without losing consistency diagnostics.

Validation Rules

Graph validation fails fast on:

  • empty graph
  • unknown dependency references
  • duplicate dependencies in one node
  • cycles
  • refreshEntryStage not present in graph

Intended Usage

Use this package in core engines where:

  • projection is a DAG
  • updates frequently touch only part of the pipeline
  • you need deterministic recompute and stale diagnostics

Designed for small to medium DAGs (typically 5-50 stages).

Non-goals (Current)

  • async stage orchestration
  • built-in memoization/hashing of stage inputs
  • domain-specific projection logic

Build / Test

pnpm --filter @affino/projection-engine build
pnpm --filter @affino/projection-engine test