| 1 | import type * as cf from "@cloudflare/workers-types"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import type * as Binding from "./Binding.ts"; |
| 4 | import { makeBindingLayer } from "./BindingLayer.ts"; |
| 5 | import { |
| 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). */ |
| 13 | export 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 | */ |
| 31 | export 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 | })); |