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

@minamorl/berylx

v0.2.0

Published

Graphable TypeScript workflows over focused, recoverable state.

Downloads

323

Readme

Berylx (TypeScript)

Graphable TypeScript workflows over focused, recoverable state.

Ruby gem berylx の TypeScript 移植。 多段のビジネス workflow に、TS を DSL 化せずに小さな代数 (algebra) を与える:

Task : Lay -> Result[Lay]

一つの Root がコミット済み状態を所有する。名前つき Task はその状態を Lay (= 焦点つき不変状態 Focus) を通して観測し、不変に変換する。各ステップは Ok(lay)Err(partialLay, error) を返すので、失敗しても診断・補償に足る 文脈が残る。

なぜ Berylx か

  • 境界は一つRoot が workflow 1 回分のコミット済み状態を所有する。
  • 焦点つき不変更新Lay は共有変更なしにネスト値を読み替える。
  • 失敗が状態を保つ — 補償処理は「失われたローカル変数の列」ではなく 部分 Lay を受け取る。
  • 合成は小さいまま — sequence / branch / parallel / merge / rescue を メソッドと値だけで組む。
  • workflow は検査可能 — 名前つき task はグラフオブジェクトと DOT 出力へ コンパイルできる。

Berylx はインプロセスの workflow 合成であり、ジョブキューでも永続スケジューラでも 分散 saga コーディネータでもない。

Install

pnpm add @minamorl/berylx   # (publish 後)
import { Root, Task, task } from '@minamorl/berylx';

Ruby 版の演算子 (>> & |) は TS ではメソッドへ写している:

| Ruby | TypeScript | 意味 | | --------------- | ---------------------- | ------------------------ | | a >> b | a.then(b) | 逐次合成 (Sequence) | | a & b | a.par(b) | 並列合成 (Parallel) | | root \| wf | root.pipe(wf) | 実行してコミット | | state \| t | state.pipe(t) | State 空間で実行 | | state & t | state.and(t) | State にノードを蓄積 | | When[:x] { } | When.of('x', () => …)| 分岐の述語 | | arm \| Else | arm.or(Else.then(…)) | arm の連結 |

実行基盤

上の表層 API があなたの書くすべて。その下では、あらゆる workflow が単一の substrate — darkcore の Effect 木 (Freer monad) — の上で走る。Task / sequence / parallel / branch / rescue は 1 種類のタグ付き effect にコンパイルされ、EffectTree が darkcore の トランポリンで解釈する。ネイティブの第二実行系は存在しない。

darkcore の TS パッケージがまだ無いため、この基盤は src/darkcore.ts として リポジトリ内に同梱している。

実行は「handler マップで解釈される effect 木」でしかないので、横断的関心事 (retry / dry-run / audit) は handler マップを差し替えるだけで足せる。 workflow 本体は書き換えない。

Quick start

import { Root, Task } from '@minamorl/berylx';

const stripName = Task.of('strip_name', (lay) =>
  lay.at('name').update((s) => (s as string).trim()),
);

const greet = Task.of('greet', (lay) =>
  lay.at('greeting').set(`hello ${lay.at('name').get()}`),
);

const workflow = stripName.then(greet);
const root = Root.of({ name: '  mina  ' });
const result = root.pipe(workflow);

result.focus.toObject();
// => { name: 'mina', greeting: 'hello mina' }

root.state();
// => { name: 'mina', greeting: 'hello mina' }

シーケンス全体が root.pipe(workflow) として走ったので、コミットは一度だけ。 どれかのステップが Err を返したら、Root は最後にコミットした状態に留まり、 結果は部分 Lay を保持する。

失敗と回復

import { Root, Task, Catch } from '@minamorl/berylx';

const charge = Task.of('charge', (lay) =>
  lay.at('charged').set(true).reject('payment_failed', 'card declined'),
);

const notify = Task.of('notify', (lay) => lay.at('notified').set(true));

const workflow = charge
  .then(Catch.of('record_failure', null, {}, (error, lay) =>
    lay.at('failure').set((error as Error).message),
  ))
  .then(notify);

const root = Root.of({ charged: false });
const result = root.pipe(workflow);

result.focus.toObject();
// => { charged: true, failure: 'card declined', notified: true }

Catch が無ければ、結果は部分 lay に charged: true を持つ Err となり、 root.state(){ charged: false } のまま残る。

dry-run (計画の列挙)

import { EffectTree } from '@minamorl/berylx';

const dry = EffectTree.dryRun(stripName.then(greet), { name: '  mina  ' });
dry.steps; // => ['strip_name', 'greet']  (Task の block は実行されない)

同じ effect 木を、handler マップの差し替えだけで real 実行 / dry-run へ 切り替えられる。

グラフ化

const graph = stripName.then(greet).compile();
graph.nodes();  // => ['strip_name', 'greet']
graph.toDot();  // => 'digraph "berylx" { ... }'

API 一覧

  • 状態: Focus (別名 Lay) / Root / State / Flow
  • 合成子: Task / AsyncTask / Sequence / Parallel / When / Else / Branch / Catch / Rescue / Workflow
  • 結果: Ok / Err / ResultOps / BerylxError
  • reducer: Merge (keepLeft / keepRight / deep / strict)
  • 基盤: EffectTree (同期 run / 非同期 runAsync) / Darkcore
  • グラフ: Graph#toDot() / Graph#toMermaid()
  • cray 互換ブリッジ: attachRoot / fromCrayResult / toCrayResult / Cray / CraySuccess / CrayFailure
  • ヘルパ: run(workflow, focus) / task(name, block)

Darkcore 名前空間は substrate の Effect (Effect / pure / op / fold / run / foldAsync) に加え、darkcore の全圏を提供する: Maybe (Just / Nothing) / Either (Left / Right) / Result (Ok / Err — berylx の Ok/Err とは別物) / State / Validation (Success / Failure) / IOEffects + VirtualWorld (real / virtual 両圏)。

開発

pnpm install
pnpm run typecheck   # tsc --noEmit
pnpm run build       # tsc -> dist/
pnpm test            # vitest run (53 tests)

Ruby 版からの移行 / cray-root-lay 廃止

root-paradigm の @minamorl/cray + @minamorl/lay ("root + lay" 系ワークフロー 基盤) を berylx-ts へ寄せて廃止する計画は MIGRATION.md を参照。

License

MIT.