Skip to main content
Home

Built and signed on GitHub Actions

The Radish effect system

This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
This package works with Browsers
JSR Score
100%
Published
a month ago (0.5.0)

Radish effect-system unlocks modularity, testability, simplicity, customizability.

  • Modularity: Decouple effects descriptions from their interpretations
  • Testability: Swap handlers in a test environment to easily mock deep side-effects without modifying your API for testing purposes
  • Simplicity: Think in terms of operations. And avoiding the need to pass context objects or callbacks solely for testing makes code simpler and more focused, with thinner, single responsibility APIs
  • Customizability: Consumers of your library or framework can override effect handlers to suit their needs

Powerful Handler Patterns

Handlers can be:

  • synchronous or asynchronous
  • partial or total

This flexibility enables powerful patterns like handler delegation, dynamic decoration and effect observation.

See handlerFor

AsyncState

In stateful async workflows, you can create AsyncState and take snapshots of HandlerScopes, including their handlers and store, and later restore these scopes, states and handlers across async boundaries, without race conditions or context loss.

See Snapshot and createState

Out-of-the-box Plugin API

As a bonus, you get a Plugin API out-of-the-box: define your own effects and handlers, and allow consumers to extend and override them with their own handlers to suit their needs. This provides flexibility and a high level of control to your users.

Examples

Create a new effect

Use createEffect to create a new effect

import { createEffect } from "@radish/effect-system";

const fs = {
  read: createEffect<(path: string) => string>('fs/read'),
  transform: createEffect<(content: string)=> string>('fs/transform'),
  write: createEffect<(path: string, data: string)=> void>('fs/write'),
}

Perform an effect

We can already use the above effect without providing an implementation yet. This separates definition from implementation.

To perform an effect operation we await it. This allows the sequencing of effects in direct style.

// a sequence of effects
const content = await fs.read("/path/to/input");
const transformed = await fs.transform(content);
await fs.write("/path/to/output", transformed);

Create an effect handler

Use handlerFor to create a handler for a given effect

import { handlerFor } from "@radish/effect-system";

const handleFSRead = handlerFor(fs.read, (path: string) => {
  return "my content";
});

const handleFSTransform = handlerFor(fs.transform, (content: string) => {
  return content.toUpperCase();
});

const handleFSWrite = handlerFor(fs.transform, (path: string, data: string) => {
  console.log(`writing to ${path}: ${data}`);
});

Perform effects with handlers in scope

Use HandlerScope to create a new scope with handlers to run effects in.

{
 using _ = new HandlerScope(handleFSRead, handleFSTransform, handleFSWrite);

 const content = await fs.read("/path/to/input");
 const transformed = await fs.transform(content);
 await fs.write("/path/to/output", transformed);
 // logs "writing to /path/to/output: MY CONTENT"
}

Create a plugin

Export your handlers as a Plugin for the reusability of related functionality. The HandlerScope constructor also accepts plugins as arguments.

const pluginFS = {
  name: "plugin-fs",
  handlers: [handleFSRead, handleFSTransform, handleFSWrite]
};

// Usage
{
 using _ = new HandlerScope(pluginFS);

 const content = await fs.read("/path/to/input");
 const transformed = await fs.transform(content);
 await fs.write("/path/to/output", transformed);
 // logs "writing to /path/to/output: MY CONTENT"
}

Built and signed on
GitHub Actions

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@radish/effect-system

Import symbol

import * as effect_system from "@radish/effect-system";
or

Import directly with a jsr specifier

import * as effect_system from "jsr:@radish/effect-system";

Add Package

pnpm i jsr:@radish/effect-system
or (using pnpm 10.8 or older)
pnpm dlx jsr add @radish/effect-system

Import symbol

import * as effect_system from "@radish/effect-system";

Add Package

yarn add jsr:@radish/effect-system
or (using Yarn 4.8 or older)
yarn dlx jsr add @radish/effect-system

Import symbol

import * as effect_system from "@radish/effect-system";

Add Package

vlt install jsr:@radish/effect-system

Import symbol

import * as effect_system from "@radish/effect-system";

Add Package

npx jsr add @radish/effect-system

Import symbol

import * as effect_system from "@radish/effect-system";

Add Package

bunx jsr add @radish/effect-system

Import symbol

import * as effect_system from "@radish/effect-system";