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

@statedelta-actions/sdk

v0.1.0

Published

Barrel package — re-exports all @statedelta-actions packages with synchronized versions

Readme

@statedelta-actions/sdk

Ponto de entrada unificado para o ecossistema @statedelta-actions. Uma dependência, todos os packages, versões sincronizadas.


Table of Contents

  1. Filosofia
  2. Instalação
  3. Quick Start — Full Stack
  4. Os 4 Componentes
  5. Composição — Como Tudo se Conecta
  6. Dois Modos de Import
  7. Packages Incluídos
  8. Três Modos de Operação
  9. Por que usar o SDK
  10. Documentação dos Packages
  11. Licença

Filosofia

O @statedelta-actions é um sistema de execução declarativa. Ações são objetos JS com diretivas. Handlers dão significado às diretivas. O engine orquestra execução. O analyzer observa e valida.

O SDK não é um framework. É um kit de composição. O consumer monta o sistema que precisa:

  • Só precisa de actions? Use o engine.
  • Quer análise estática? Adicione o analyzer.
  • Precisa de triggers condicionais? Adicione rules.
  • Quer event-driven? Adicione events.
  • Quer tudo junto com versões garantidas? Use o SDK.

Cada componente funciona sozinho. Nenhum assume a existência dos outros. O consumer é quem decide a composição e faz o wiring.

Três metáforas

| Componente | Metáfora | Papel | |-----------|----------|-------| | ActionEngine | V8 | Runtime puro — executa diretivas | | ActionAnalyzer | TypeScript | Análise estática — observa, valida, consulta | | RuleEngine | Cron | Triggers condicionais — when() → invoke() | | EventProcessor | EventEmitter | Dispatch de listeners — on(event) → invoke() |

O engine nunca analisa. O analyzer nunca muta. O RuleEngine nunca executa diretivas (delega pro engine). O EventProcessor é o mesmo — registro de listeners como hidden actions, dispatch via engine.


Instalação

pnpm add @statedelta-actions/sdk

Quick Start — Full Stack

O setup completo: engine processa diretivas, analyzer observa o grafo, rules avaliam triggers, events despacham listeners.

import {
  createActionEngine,
  createActionAnalyzer,
  createRuleEngine,
  createEventProcessor,
} from "@statedelta-actions/sdk";
import { HALT_HANDLER } from "@statedelta-actions/sdk/rules";

// ── 1. Handlers — dão significado aos tipos de diretiva ──

const handlers = {
  state: {
    analyze: () => ({ capabilities: ["write"], dependencies: [] }),
    execute: (directive, frame) => {
      frame.ctx[directive.target] = directive.value;
      return { ok: true, data: directive.value };
    },
  },
  emit: {
    analyze: () => ({ capabilities: ["emit"], dependencies: [] }),
    execute: (directive, frame) => {
      frame.ctx.events.push(directive.event);
      return { ok: true };
    },
  },
  action: {
    analyze: (d) => ({
      capabilities: ["invoke"],
      dependencies: d.id ? [d.id] : [],
    }),
    execute: (directive, frame, engine) => {
      const result = engine.invoke(directive.id, directive.params, frame);
      return { ok: result.success, data: result.data };
    },
  },
  halt: HALT_HANDLER,
};

// ── 2. Engine — runtime de execução ──

const engine = createActionEngine({ handlers });

// ── 3. Analyzer — análise estática (opt-in) ──

const analyzer = createActionAnalyzer({ engine });
engine.on("register", (e) => analyzer.processRegistration(e));
engine.on("unregister", (e) => analyzer.processUnregistration(e));

// ── 4. Rules — triggers condicionais ──

const rules = createRuleEngine({ actionEngine: engine });

// ── 5. Events — dispatch de listeners ──

const events = createEventProcessor({ actionEngine: engine });

// ── 6. Registrar e usar ──

engine.register([
  { id: "heal", directives: [{ type: "state", target: "hp", value: 100 }] },
]);

rules.register([{
  id: "auto-heal",
  priority: 100,
  when: (ctx) => ctx.hp < 50,
  then: [
    { type: "action", id: "heal" },
    { type: "emit", event: "healed" },
  ],
}]);

events.register([{
  id: "on-healed",
  priority: 100,
  on: "healed",
  then: [{ type: "state", target: "healCount", value: 1 }],
}]);

// Runtime
const ctx = { hp: 30, events: [], healCount: 0 };
rules.evaluate(ctx);                               // auto-heal fires → heal + emit
events.processEvents([{ event: "healed" }], ctx);  // on-healed fires

// Análise estática
analyzer.capabilitiesOf("rule:auto-heal");  // Set { "invoke", "write", "emit" }
analyzer.dependenciesOf("rule:auto-heal");  // Set { "heal" }

Os 4 Componentes

ActionEngine — Runtime

Motor de execução. Registra ações (ID + diretivas), valida em register-time, compila executores (interpret/JIT), invoca em O(1). Handlers dão semântica — o engine orquestra.

const engine = createActionEngine({ handlers });

engine.register([{
  id: "checkout",
  directives: [
    { type: "state", target: "status", value: "paid" },
    { type: "emit", event: "payment-processed" },
  ],
}]);

engine.setContext(ctx);
const result = engine.invoke("checkout");
// result.success, result.appliedCount, result.errors

Lifecycle events (register, unregister) permitem que camadas externas (analyzer) observem sem acoplamento.

ActionAnalyzer — Análise Estática

Observa o engine via read-only accessors e lifecycle events. Constrói grafo de dependências, infere capabilities transitivas, detecta ciclos, valida composition control.

const analyzer = createActionAnalyzer({ engine });

// Wire lifecycle events
engine.on("register", (e) => analyzer.processRegistration(e));
engine.on("unregister", (e) => analyzer.processUnregistration(e));

// Queries
analyzer.capabilitiesOf("checkout");   // Set { "write", "emit" }
analyzer.dependenciesOf("checkout");   // Set { ... }
analyzer.inCycle("checkout");          // false
analyzer.getStats();                   // { totalActions, totalEdges, ... }

Opt-in: o engine funciona sem analyzer. Quando presente, valida contratos sem afetar runtime.

RuleEngine — Triggers Condicionais

Loop de when(ctx) → invoke(). Rules são normalizadas em hidden actions (rule:{id}) no engine. O RuleEngine não executa diretivas — delega tudo pro engine.

const rules = createRuleEngine({ actionEngine: engine });

rules.register([{
  id: "heal-when-low",
  priority: 100,
  when: (ctx) => ctx.hp < 50,
  then: [{ type: "state", target: "hp", value: 100 }],
}]);

const result = rules.evaluate(ctx);
// result.matched, result.skipped, result.counters

Sub-rules habilitam branching condicional. Hooks (beforeRule, afterRule) habilitam governança. Halt para a avaliação de forma controlada.

EventProcessor — Dispatch de Listeners

Listeners escutam eventos por nome. Normalizados em hidden actions (event:{id}) no engine. Match por nome, execução por prioridade desc. Halt é scoped ao evento — não contamina o próximo da fila.

const events = createEventProcessor({ actionEngine: engine });

events.defineEvents([{ event: "save", tags: ["domain:billing"] }]);

events.register([{
  id: "on-save",
  priority: 100,
  on: "save",
  then: [{ type: "state", target: "saved", value: true }],
}]);

const result = events.processEvents([{ event: "save" }], ctx);
// result.processedEvents, result.eventResults, result.unprocessedEvents

Composição — Como Tudo se Conecta

Hidden Actions

Rules e listeners são hidden actions no engine. O RuleEngine registra rule:{id}. O EventProcessor registra event:{id}. O engine não sabe a origem — trata todas como actions normais. Isso significa que o analyzer valida tudo no mesmo grafo:

engine.registeredIds:
  "checkout"              ← action direta
  "rule:auto-heal"        ← hidden action da rule
  "event:on-payment"      ← hidden action do listener
  "eventdef:payment"      ← nó de definição de evento

analyzer.graph:
  rule:auto-heal → checkout → eventdef:payment
                              ↑
  event:on-payment ──────────┘

Wiring

O SDK não faz wiring automático. O consumer conecta os componentes:

// Analyzer observa engine
engine.on("register", (e) => analyzer.processRegistration(e));
engine.on("unregister", (e) => analyzer.processUnregistration(e));

// Rules e Events recebem o engine
const rules = createRuleEngine({ actionEngine: engine });
const events = createEventProcessor({ actionEngine: engine });

Máxima flexibilidade: o consumer decide quando e como conectar. O engine não sabe quem escuta. O analyzer não sabe quem o alimenta.

Fluxo Típico de Execução

1. rules.evaluate(ctx)
   │
   ├─ when(ctx) === true   → engine.invoke("rule:{id}")
   │                          ├─ handler "state" → muta ctx
   │                          ├─ handler "emit"  → registra evento
   │                          └─ handler "action" → engine.invoke(child)
   │
   └─ result.matched = ["rule-a", "rule-b"]

2. events.processEvents(queue, ctx)
   │
   ├─ match listeners by event name
   │  └─ engine.invoke("event:{id}")
   │     └─ handlers executam diretivas
   │
   └─ result.processedEvents = 2

3. analyzer.capabilitiesOf("rule:rule-a")
   └─ Set { "write", "emit", "invoke" }

Rules avaliam. Events processam. Engine executa. Analyzer observa. Cada um no seu papel.

Batch — Registro Cruzado

Batch permite registrar actions, rules, events e eventdefs em uma única transação. O engine adia lifecycle events até endBatch(). Forward references resolvem:

engine.beginBatch();
rules.register([...]);           // Usa action que ainda não existe
events.defineEvents([...]);      // Define eventdefs
engine.register([...]);          // Registra a action referenciada
events.register([...]);          // Registra listeners
engine.endBatch();               // Analyzer recebe tudo de uma vez

Dois Modos de Import

Root — factories e tipos essenciais

Para começar rápido. Exporta as 4 factories e os tipos mais usados, sem colisão de nomes entre packages.

// Factories
import {
  createActionEngine,
  createActionAnalyzer,
  createRuleEngine,
  createEventProcessor,
} from "@statedelta-actions/sdk";

// Types
import type {
  HandlerDefinition,
  ActionDefinition,
  IActionEngine,
  IActionAnalyzer,
  RuleDefinition,
  EventListenerDefinition,
  Directive,
  ExecutionFrame,
} from "@statedelta-actions/sdk";

Subpath — acesso completo por package

Para quem precisa de exports específicos (propagators, matching, JIT, etc). Cada subpath re-exporta tudo do package original.

// Core — primitivas (ExecutionFrame, hooks, slots, intercept)
import { createRootFrame, composeHooks } from "@statedelta-actions/sdk/core";

// Graph — grafo de dependências (ciclos, topo sort, propagators)
import { DependencyGraph, DEFAULT_PROPAGATORS } from "@statedelta-actions/sdk/graph";

// Actions — ActionEngine (validação, compilação, invoke)
import { createActionEngine, RESERVED_TYPES } from "@statedelta-actions/sdk/actions";

// Analyzer — análise estática (graph queries, composition control, permissions)
import { createActionAnalyzer, compileManifest } from "@statedelta-actions/sdk/analyzer";

// Rules — RuleEngine (invocação condicional por triggers)
import { createRuleEngine, HALT_HANDLER } from "@statedelta-actions/sdk/rules";

// Events — EventProcessor (dispatch de listeners por evento)
import { createEventProcessor, createEmitAnalyzer } from "@statedelta-actions/sdk/events";

Packages Incluídos

| Subpath | Package | Descrição | |---------|---------|-----------| | /core | @statedelta-actions/core | Primitivas: ExecutionFrame, hooks, slots, intercept | | /graph | @statedelta-actions/graph | Grafo de dependências: ciclos, topo sort, propagators, dirty tracking | | /actions | @statedelta-actions/actions | ActionEngine: validação, compilação JIT, invoke O(1) | | /analyzer | @statedelta-actions/analyzer | ActionAnalyzer: análise estática, capabilities, composition control | | /rules | @statedelta-actions/rules | RuleEngine: invocação condicional por triggers e sub-rules | | /events | @statedelta-actions/events | EventProcessor: dispatch de listeners por nome de evento |


Três Modos de Operação

O consumer escolhe o nível de análise. Cada modo é uma composição incremental:

JS mode — Engine only

const engine = createActionEngine({ handlers });
engine.register([...]);
engine.invoke("action");

Runtime puro. Zero overhead de análise. Funciona: registration, invoke, JIT, hooks, batch.

TS mode — Engine + Analyzer

const engine = createActionEngine({ handlers });
const analyzer = createActionAnalyzer({ engine });
// wire events...

Tudo do JS mode + grafo de dependências, capabilities transitivas, detecção de ciclos, declaration conflicts.

TS strict — Engine + Analyzer + Composition Control

const analyzer = createActionAnalyzer({
  engine,
  accessManifest: {
    rules: [{
      source: { tags: { include: ["write"] } },
      target: { tags: { include: ["readonly"] } },
      effect: "deny",
    }],
  },
  tierValidation: true,
});

Tudo do TS mode + composition control declarativo (quem pode depender de quem) + tier validation (hierarquia numérica de acesso).


Por que usar o SDK

Packages individuais têm versões independentes. Se você instala @statedelta-actions/[email protected] e @statedelta-actions/[email protected], pode haver incompatibilidade de tipos (ex: IAnalyzableEngine mudou entre versões).

O SDK garante que todos os packages estão na versão que foi testada junta. Uma única dependência, zero risco de mismatch.

{
  "dependencies": {
    "@statedelta-actions/sdk": "^0.1.0"
  }
}

Em vez de:

{
  "dependencies": {
    "@statedelta-actions/core": "^0.1.0",
    "@statedelta-actions/graph": "^0.1.0",
    "@statedelta-actions/actions": "^0.1.0",
    "@statedelta-actions/analyzer": "^0.1.0",
    "@statedelta-actions/rules": "^0.1.0",
    "@statedelta-actions/events": "^0.1.0"
  }
}

Além de versões sincronizadas, o SDK inclui uma suite de 91 testes de integração que validam a composição cross-package — cenários que nenhum package individual consegue testar sozinho.


Documentação dos Packages

Cada package tem documentação completa de API, arquitetura interna e decisões de design:

| Package | README | Architecture | Decisions | |---------|--------|-------------|-----------| | actions | README | ARCHITECTURE | DECISIONS | | analyzer | README | ARCHITECTURE | DECISIONS | | rules | README | ARCHITECTURE | DECISIONS | | events | README | ARCHITECTURE | DECISIONS | | graph | — | ARCHITECTURE | DECISIONS | | core | — | — | — |

Para a test architecture do SDK (helpers, test map, decisões), ver docs/ARCHITECTURE.md.


Licença

MIT