Skip to content

danieljvdm/effect-cf

Repository files navigation

effect-cf

Effect-native primitives for Cloudflare Workers, Durable Objects, bindings, KV, and Durable Object storage.

Install

effect-cf currently targets Effect 4 beta.

bun add effect-cf "effect@^4.0.0-beta.65"
pnpm add effect-cf "effect@^4.0.0-beta.65"
npm install effect-cf "effect@^4.0.0-beta.65"

Design

effect-cf keeps Cloudflare code inside Effect. Cloudflare services are modeled as Context, Layer, and Effect values, and runtime boundaries live at Worker and Durable Object entrypoints.

Binding types come from code-owned definitions such as Worker.Tag(...) and DurableObject.Tag(...). Generated Wrangler types are only used as local config checks.

A Taste

A Worker can route HTTP with Effect and call a Durable Object through a typed binding:

import { Effect, Layer, Schema as S } from "effect";
import { HttpRouter, HttpServerResponse } from "effect/unstable/http";
import { DurableObject, DurableObjectState, Worker } from "effect-cf";

class Counter extends DurableObject.Tag<Counter>()("Counter", {
  increment: DurableObject.method({ success: S.Number }),
}) {}

const CounterLive = Counter.make(Layer.empty, {
  rpc: {
    increment: () =>
      Effect.gen(function* () {
        const state = yield* DurableObjectState.DurableObjectState;
        const current = yield* state.storage.get<number>("count");
        const next = (current ?? 0) + 1;
        yield* state.storage.put("count", next);
        return next;
      }),
  },
});

export class CounterDurableObject extends CounterLive {}

const CounterLayer = Counter.layer({ binding: "COUNTER" });

const app = Effect.gen(function* () {
  const router = yield* HttpRouter.HttpRouter;
  const counters = yield* Counter;
  const counter = counters.byName("home");

  return yield* router
    .get(
      "/",
      Effect.gen(function* () {
        const count = yield* counter.increment();
        return HttpServerResponse.text(`Viewed ${count} times`);
      }),
    )
    .asHttpEffect();
});

export default Worker.make(Layer.mergeAll(HttpRouter.layer, CounterLayer), app);

COUNTER is still declared in wrangler.jsonc, but the callable API is inferred from the Counter class. The Worker and Durable Object both run through effect-cf runtime boundaries.

Examples

The examples/ directory demonstrates package usage across Workers, Durable Objects, service bindings, and frontend consumers.

Changelog

See packages/effect-cf/CHANGELOG.md.

Contributing

See CONTRIBUTING.md.

License

MIT

About

Effect-native primitives for Cloudflare Workers and bindings.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors