1import type * as cf from "@cloudflare/workers-types";
2import * as Effect from "effect/Effect";
3import type * as Binding from "./Binding.ts";
4import { makeBindingLayer } from "./BindingLayer.ts";
5import {
6 RateLimit,
7 RateLimitError,
8 type RateLimitClient,
9 type RateLimitPeriod,
10} from "./RateLimit.ts";
11
12/** The binding value produced by calling {@link RateLimit} (declared on `env` or `yield*`-ed). */
13export type RateLimitBinding = Binding.Binding<
14 RateLimit["key"],
15 RateLimitClient,
16 RateLimit
17> & {
18 readonly namespaceId: string;
19 readonly simple: { limit: number; period: RateLimitPeriod };
20};
21
22/**
23 * The layer that provides the Effect-native interface for the Cloudflare
24 * Workers Rate Limit binding.
25 *
26 * Provide it on the Worker effect (`Effect.provide(Cloudflare.Workers.RateLimitBinding)`)
27 * so that yielding a {@link RateLimit} binding attaches the native `ratelimit`
28 * binding to the surrounding Worker at deploy time and, at runtime, resolves to
29 * the Effect-native {@link RateLimitClient}.
30 */
31export const RateLimitBinding = makeBindingLayer<
32 RateLimit,
33 cf.RateLimit,
34 RateLimitClient
35>(RateLimit, (raw) => ({
36 raw,
37 limit: (options) =>
38 raw.pipe(
39 Effect.flatMap((binding) =>
40 Effect.tryPromise({
41 try: () => binding.limit(options),
42 catch: (error) =>
43 new RateLimitError({
44 message:
45 error instanceof Error
46 ? error.message
47 : "Unknown RateLimit error",
48 cause: error,
49 }),
50 }),
51 ),
52 ),
53}));