/**
 * Persistent rate limiting for effects that need to coordinate token
 * consumption through a shared `RateLimiterStore`.
 *
 * The module exposes a `RateLimiter` service that can consume tokens for
 * string keys using either fixed-window counters or token-bucket state. It is
 * useful for protecting external APIs, enforcing per-user or per-tenant quotas,
 * throttling job workers, and coordinating limits across multiple fibers or
 * processes when they share the Redis-backed store. The helpers can fail fast
 * with `RateLimiterError`, return a delay to apply yourself, or wrap an effect
 * so it waits before continuing.
 *
 * Rate-limit keys and Redis prefixes are part of the persistence namespace, so
 * choose stable, collision-free values. The in-memory store is process-local
 * and is only coordinated inside one runtime, while the Redis store uses Lua
 * scripts for atomic updates under concurrent consumers. Time is measured with
 * the Effect `Clock`, windows are clamped to at least one millisecond, and
 * refill calculations use millisecond granularity.
 *
 * Fixed-window state is TTL-driven: rejected `fail` attempts do not extend the
 * current TTL, and Redis fixed-window keys expire automatically. Token-bucket
 * state keeps the remaining token count and last-refill time instead of using a
 * TTL, so high-cardinality dynamic keys may need an external cleanup or bounded
 * key strategy. With `onExceeded: "delay"`, overflow can be recorded so callers
 * should actually sleep for the returned delay, or use the provided accessors.
 *
 * @since 4.0.0
 */
import * as Config from "../../Config.ts";
import * as Context from "../../Context.ts";
import * as Duration from "../../Duration.ts";
import * as Effect from "../../Effect.ts";
import * as Layer from "../../Layer.ts";
import * as Schema from "../../Schema.ts";
import * as Redis from "./Redis.ts";
/**
 * Runtime type identifier for `RateLimiter` values.
 *
 * @category type IDs
 * @since 4.0.0
 */
export declare const TypeId: TypeId;
/**
 * Type-level identifier used to brand `RateLimiter` values.
 *
 * @category type IDs
 * @since 4.0.0
 */
export type TypeId = "~effect/persistence/RateLimiter";
/**
 * Service for consuming rate-limit tokens for a key using fixed-window or
 * token-bucket algorithms.
 *
 * @category models
 * @since 4.0.0
 */
export interface RateLimiter {
    readonly [TypeId]: TypeId;
    readonly consume: (options: {
        readonly algorithm?: "fixed-window" | "token-bucket" | undefined;
        readonly onExceeded?: "delay" | "fail" | undefined;
        readonly window: Duration.Input;
        readonly limit: number;
        readonly key: string;
        readonly tokens?: number | undefined;
    }) => Effect.Effect<ConsumeResult, RateLimiterError>;
}
/**
 * Service tag for persistent token-consumption services.
 *
 * **When to use**
 *
 * Use to access or provide rate-limit checks backed by fixed-window counters or
 * token-bucket state.
 *
 * @category services
 * @since 4.0.0
 */
export declare const RateLimiter: Context.Service<RateLimiter, RateLimiter>;
/**
 * Creates a `RateLimiter` from the current `RateLimiterStore`.
 *
 * **Details**
 *
 * The limiter supports fixed-window and token-bucket algorithms and either
 * fails or returns a delay when a limit is exceeded.
 *
 * @category constructors
 * @since 4.0.0
 */
export declare const make: Effect.Effect<RateLimiter, never, RateLimiterStore>;
/**
 * Provides `RateLimiter` using the current `RateLimiterStore`.
 *
 * @category layers
 * @since 4.0.0
 */
export declare const layer: Layer.Layer<RateLimiter, never, RateLimiterStore>;
/**
 * Accesses a function that applies rate limiting to an effect.
 *
 * **Example** (Applying rate limits to effects)
 *
 * ```ts
 * import { Effect } from "effect"
 * import { RateLimiter } from "effect/unstable/persistence"
 *
 * Effect.gen(function*() {
 *   // Access the `withLimiter` function from the RateLimiter module
 *   const withLimiter = yield* RateLimiter.makeWithRateLimiter
 *
 *   // Apply a rate limiter to an effect
 *   yield* Effect.log("Making a request with rate limiting").pipe(
 *     withLimiter({
 *       key: "some-key",
 *       limit: 10,
 *       onExceeded: "delay",
 *       window: "5 seconds",
 *       algorithm: "fixed-window"
 *     })
 *   )
 * })
 * ```
 *
 * @category accessors
 * @since 4.0.0
 */
export declare const makeWithRateLimiter: Effect.Effect<((options: {
    readonly algorithm?: "fixed-window" | "token-bucket" | undefined;
    readonly onExceeded?: "delay" | "fail" | undefined;
    readonly window: Duration.Input;
    readonly limit: number;
    readonly key: string;
    readonly tokens?: number | undefined;
}) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E | RateLimiterError, R>), never, RateLimiter>;
/**
 * Accesses a function that sleeps when the rate limit is exceeded.
 *
 * **Example** (Sleeping until rate limit permits)
 *
 * ```ts
 * import { Effect } from "effect"
 * import { RateLimiter } from "effect/unstable/persistence"
 *
 * Effect.gen(function*() {
 *   // Access the `sleep` function from the RateLimiter module
 *   const sleep = yield* RateLimiter.makeSleep
 *
 *   // Use the `sleep` function with specific rate limiting parameters.
 *   // This will only sleep if the rate limit has been exceeded.
 *   yield* sleep({
 *     key: "some-key",
 *     limit: 10,
 *     window: "5 seconds",
 *     algorithm: "fixed-window"
 *   })
 * })
 * ```
 *
 * @category accessors
 * @since 4.0.0
 */
export declare const makeSleep: Effect.Effect<((options: {
    readonly algorithm?: "fixed-window" | "token-bucket" | undefined;
    readonly window: Duration.Input;
    readonly limit: number;
    readonly key: string;
    readonly tokens?: number | undefined;
}) => Effect.Effect<ConsumeResult, RateLimiterError>), never, RateLimiter>;
/**
 * Runtime type identifier for `RateLimiterError`.
 *
 * @category type IDs
 * @since 4.0.0
 */
export declare const ErrorTypeId: ErrorTypeId;
/**
 * Type-level identifier used to brand `RateLimiterError` values.
 *
 * @category type IDs
 * @since 4.0.0
 */
export type ErrorTypeId = "~@effect/experimental/RateLimiter/RateLimiterError";
declare const RateLimitExceeded_base: Schema.Class<RateLimitExceeded, Schema.Struct<{
    readonly _tag: Schema.tag<"RateLimitExceeded">;
    readonly retryAfter: Schema.DurationFromMillis;
    readonly key: Schema.String;
    readonly limit: Schema.Number;
    readonly remaining: Schema.Number;
}>, import("../../Cause.ts").YieldableError>;
/**
 * Error reason for a rate-limit check that exceeded the configured limit.
 *
 * **Details**
 *
 * Includes the affected key, limit, remaining token count, and retry delay.
 *
 * @category errors
 * @since 4.0.0
 */
export declare class RateLimitExceeded extends RateLimitExceeded_base {
    /**
     * Public message used when the rate limiter rejects a request.
     *
     * @since 4.0.0
     */
    get message(): string;
}
declare const RateLimitStoreError_base: Schema.Class<RateLimitStoreError, Schema.Struct<{
    readonly _tag: Schema.tag<"RateLimitStoreError">;
    readonly message: Schema.String;
    readonly cause: Schema.optional<Schema.Defect>;
}>, import("../../Cause.ts").YieldableError>;
/**
 * Error reason for failures in the backing `RateLimiterStore`.
 *
 * @category errors
 * @since 4.0.0
 */
export declare class RateLimitStoreError extends RateLimitStoreError_base {
}
/**
 * Union of reasons carried by `RateLimiterError`.
 *
 * @category errors
 * @since 4.0.0
 */
export type RateLimiterErrorReason = RateLimitExceeded | RateLimitStoreError;
/**
 * Schema for all reasons that can be carried by `RateLimiterError`.
 *
 * @category errors
 * @since 4.0.0
 */
export declare const RateLimiterErrorReason: Schema.Union<[
    typeof RateLimitExceeded,
    typeof RateLimitStoreError
]>;
declare const RateLimiterError_base: Schema.Class<RateLimiterError, Schema.Struct<{
    readonly _tag: Schema.tag<"RateLimiterError">;
    readonly reason: Schema.Union<[typeof RateLimitExceeded, typeof RateLimitStoreError]>;
}>, import("../../Cause.ts").YieldableError>;
/**
 * Error raised by rate limiter operations, wrapping a concrete failure
 * `reason`.
 *
 * @category errors
 * @since 4.0.0
 */
export declare class RateLimiterError extends RateLimiterError_base {
    constructor(props: {
        readonly reason: RateLimiterErrorReason;
    });
    /**
     * Marks this value as a rate limiter error for runtime guards.
     *
     * @since 4.0.0
     */
    readonly [ErrorTypeId]: ErrorTypeId;
    get message(): string;
}
/**
 * Metadata returned after consuming tokens from a rate limiter.
 *
 * @category models
 * @since 4.0.0
 */
export interface ConsumeResult {
    /**
     * The amount of delay to wait before making the next request, when the rate
     * limiter is using the "delay" `onExceeded` strategy. It will be
     * Duration.zero if the request is allowed immediately.
     */
    readonly delay: Duration.Duration;
    /**
     * The maximum number of requests allowed in the current window.
     */
    readonly limit: number;
    /**
     * The number of remaining requests in the current window.
     */
    readonly remaining: number;
    /**
     * The time until the rate limit fully resets.
     */
    readonly resetAfter: Duration.Duration;
}
declare const RateLimiterStore_base: Context.ServiceClass<RateLimiterStore, "effect/persistence/RateLimiter/RateLimiterStore", {
    /**
     * Returns the token count *after* taking the specified `tokens` and time to
     * live for the `key`.
     *
     * If `limit` is provided, the number of taken tokens will be capped at the
     * limit.
     *
     * In the case the limit is exceeded, the returned count will be greater
     * than the limit, but the TTL will not be updated.
     */
    readonly fixedWindow: (options: {
        readonly key: string;
        readonly tokens: number;
        readonly refillRate: Duration.Duration;
        readonly limit: number | undefined;
    }) => Effect.Effect<readonly [count: number, ttl: number], RateLimiterError>;
    /**
     * Returns the current remaining tokens for the `key` after consuming the
     * specified amount of tokens.
     *
     * If `allowOverflow` is true, the number of tokens can drop below zero.
     *
     * In the case of no overflow, the returned token count will only be
     * negative if the requested tokens exceed the available tokens, but the
     * real token count will not be persisted below zero.
     */
    readonly tokenBucket: (options: {
        readonly key: string;
        readonly tokens: number;
        readonly limit: number;
        readonly refillRate: Duration.Duration;
        readonly allowOverflow: boolean;
    }) => Effect.Effect<number, RateLimiterError>;
}>;
/**
 * Defines the low-level backing store for fixed-window counters and token-bucket state.
 *
 * **When to use**
 *
 * Use to provide the shared counter storage used by persistent rate-limit
 * checks.
 *
 * @category store
 * @since 4.0.0
 */
export declare class RateLimiterStore extends RateLimiterStore_base {
}
/**
 * Provides a process-local in-memory `RateLimiterStore`.
 *
 * @category RateLimiterStore
 * @since 4.0.0
 */
export declare const layerStoreMemory: Layer.Layer<RateLimiterStore>;
/**
 * Creates a Redis-backed `RateLimiterStore` using Lua scripts and the
 * configured key prefix.
 *
 * @category RateLimiterStore
 * @since 4.0.0
 */
export declare const makeStoreRedis: (options?: {
    readonly prefix?: string | undefined;
} | undefined) => Effect.Effect<{
    /**
     * Returns the token count *after* taking the specified `tokens` and time to
     * live for the `key`.
     *
     * If `limit` is provided, the number of taken tokens will be capped at the
     * limit.
     *
     * In the case the limit is exceeded, the returned count will be greater
     * than the limit, but the TTL will not be updated.
     */
    readonly fixedWindow: (options: {
        readonly key: string;
        readonly tokens: number;
        readonly refillRate: Duration.Duration;
        readonly limit: number | undefined;
    }) => Effect.Effect<readonly [count: number, ttl: number], RateLimiterError>;
    /**
     * Returns the current remaining tokens for the `key` after consuming the
     * specified amount of tokens.
     *
     * If `allowOverflow` is true, the number of tokens can drop below zero.
     *
     * In the case of no overflow, the returned token count will only be
     * negative if the requested tokens exceed the available tokens, but the
     * real token count will not be persisted below zero.
     */
    readonly tokenBucket: (options: {
        readonly key: string;
        readonly tokens: number;
        readonly limit: number;
        readonly refillRate: Duration.Duration;
        readonly allowOverflow: boolean;
    }) => Effect.Effect<number, RateLimiterError>;
}, never, Redis.Redis>;
/**
 * Provides a Redis-backed `RateLimiterStore` using `makeStoreRedis`.
 *
 * @category layers
 * @since 4.0.0
 */
export declare const layerStoreRedis: (options?: {
    readonly prefix?: string | undefined;
}) => Layer.Layer<RateLimiterStore, never, Redis.Redis>;
/**
 * Provides a Redis-backed `RateLimiterStore` from wrapped configuration
 * options.
 *
 * @category layers
 * @since 4.0.0
 */
export declare const layerStoreRedisConfig: (options: Config.Wrap<{
    readonly prefix?: string | undefined;
}>) => Layer.Layer<RateLimiterStore, Config.ConfigError, Redis.Redis>;
export {};
//# sourceMappingURL=RateLimiter.d.ts.map