import { t as Brand } from "./Brand-bfnGXuum.js"; import { d as Type, l as Pipe, o as Serializable, r as Typeable, t as Tuple, u as Foldable } from "./Tuple-B8KM-H8Y.js"; //#region src/conditional/Cond.d.ts /** * Conditional expression that enforces exhaustive returns without early returns. * Similar to Scala's if/else expressions that always return a value. * * @example * const discount = Cond.of() * .when(isPremiumMember, 0.2) * .elseWhen(isRegularMember, 0.1) * .else(0) * * @example * // Chaining multiple conditions * const status = Cond.of() * .when(response.status >= 500, "Server Error") * .elseWhen(response.status >= 400, "Client Error") * .elseWhen(response.status >= 200, "Success") * .else("Unknown") */ type Cond = { /** * Add an if condition */ when: (condition: boolean, value: T | (() => T)) => Cond; /** * Add an else-if condition */ elseWhen: (condition: boolean, value: T | (() => T)) => Cond; /** * Terminal else clause - required to get the result */ else: (value: T | (() => T)) => T; /** * Get the result if a condition was met, throws if no condition met */ orThrow: () => T; }; /** @internal */ type LazyCondChain = { when: (condition: () => boolean, value: () => T) => LazyCondChain; elseWhen: (condition: () => boolean, value: () => T) => LazyCondChain; else: (value: () => T) => T; }; /** * Conditional expression builder for functional if/else chains * @example * // Basic usage * const size = Cond.of() * .when(value > 100, "large") * .elseWhen(value > 50, "medium") * .else("small") * * @example * // Pattern matching * const message = Cond.match(errorCode)({ * 404: "Not Found", * 500: "Server Error", * 200: "OK" * }) * * @example * // Lazy evaluation * const result = Cond.lazy() * .when(() => checkCondition1(), () => "Result 1") * .when(() => checkCondition2(), () => "Result 2") * .else(() => "Default") */ declare const Cond: (() => Cond) & { /** * Create a conditional expression that must end with else * @example * const x = 7 * const result = Cond.of() * .when(x > 10, "large") * .elseWhen(x > 5, "medium") * .else("small") * // result = "medium" * * @example * // With lazy evaluation * const discount = Cond.of() * .when(isPremium, () => calculatePremiumDiscount()) * .when(isLoyal, () => calculateLoyaltyDiscount()) * .else(0) */ of: () => Cond; /** * Pattern matching helper that ensures exhaustiveness * @example * type Status = "pending" | "success" | "error" * const status: Status = "success" * const result = Cond.match(status)({ * "pending": "Waiting...", * "success": "Done!", * "error": "Failed!" * }) * // result = "Done!" * * @example * // With function values * const action = "compute" * const result = Cond.match(action)({ * "compute": () => expensiveComputation(), * "cache": () => getCachedValue(), * "skip": () => defaultValue * }) */ match: (value: T) => (cases: Record R)>) => R; /** * Create a lazy conditional that defers evaluation * @example * // Only evaluates conditions and values when needed * const getMessage = Cond.lazy() * .when(() => isError(), () => computeErrorMessage()) * .when(() => isWarning(), () => computeWarningMessage()) * .else(() => "Success") * * @example * // Complex conditional with expensive checks * const result = Cond.lazy() * .when( * () => user.role === "admin" && checkAdminPermissions(), * () => ({ type: "admin", permissions: loadAdminPermissions() }) * ) * .when( * () => user.role === "user" && user.isActive, * () => ({ type: "user", permissions: loadUserPermissions() }) * ) * .else(() => ({ type: "guest", permissions: [] })) */ lazy: () => LazyCondChain; }; //#endregion //#region src/do/protocol.d.ts /** * Protocol definitions for Do-notation * Separated from main Do module to avoid circular dependencies */ /** * Result type for Do-notation unwrapping * Indicates whether unwrapping succeeded and provides the value or error */ type DoResult = { ok: true; value: T; } | { ok: false; empty: true; } | { ok: false; empty: false; error: unknown; }; /** * Interface for types that support Do-notation * Implementing this interface allows a type to be yielded in Do-comprehensions * * The doUnwrap method should return a DoResult indicating success/failure * and the contained value or error information */ interface Doable { doUnwrap(): DoResult; } //#endregion //#region src/error/ParseError.d.ts declare const ParseError: (message?: string) => Error & { name: "ParseError"; }; type ParseError = Error & { name: "ParseError"; }; //#endregion //#region src/extractable/Extractable.d.ts /** * Interface for operations that can fail with exceptions. * These methods should be used with care as they can throw at runtime. * * @interface Unsafe * @template T The type of value that can be extracted */ interface Unsafe { /** * Extract the value or throw an error * @param error Optional custom error to throw. If not provided, uses type-appropriate default error * @throws {Error} The specified error, container's error, or a sensible default * @returns The contained value */ orThrow(error?: Error): T; } /** * Extractable type class for data structures that can extract their values * with various fallback strategies. * * Covariance: T is declared ``. The fallback methods `orElse` and `or` * widen the result via ``, matching Scala's `getOrElse[B1 >: B](default: => B1): B1` * shape — when the caller passes a T-typed default the result is just T, and when * they pass a wider T2 the result union widens accordingly. * * Implementers that previously overrode `or`/`orElse` with widened signatures * (Option, Either, Try) can inherit from this base directly; their 0.58-era * `Omit, "or" | "orElse">` workarounds are no longer needed. */ interface Extractable extends Unsafe { /** * Returns the contained value or a default value. The default may be of a * different type; the result widens to `T | T2`. * @param defaultValue - The value to return if extraction fails * @returns The contained value or defaultValue */ orElse(defaultValue: T2): T | T2; /** * Returns this container if it has a value, otherwise returns the alternative container. * The alternative may carry a different type; the result widens to `Extractable`. * @param alternative - The alternative container * @returns This container or the alternative */ or(alternative: Extractable): Extractable; /** * Returns the contained value or null * @returns The contained value or null */ orNull(): T | null; /** * Returns the contained value or undefined * @returns The contained value or undefined */ orUndefined(): T | undefined; } /** * Type guard to check if a value implements Extractable */ declare function isExtractable(value: unknown): value is Extractable; //#endregion //#region src/typeclass/ContainerOps.d.ts /** * Universal operations that work on any container (single-value or collection). * These operations make sense for Option, Either, Try, List, Set, etc. * * @typeParam A - The type of value(s) in the container */ interface ContainerOps { /** * Counts elements that satisfy the predicate. * For single-value containers: returns 0 or 1 * For collections: returns the count of matching elements */ count(p: (x: A) => boolean): number; /** * Finds the first element that satisfies the predicate. * For single-value containers: returns Some(value) if predicate matches, None otherwise * For collections: returns the first matching element wrapped in Option */ find(p: (a: A) => boolean): Option; /** * Tests whether any element satisfies the predicate. * For single-value containers: tests the single value * For collections: returns true if any element matches */ exists(p: (a: A) => boolean): boolean; /** * Applies an effect function to each element. * For single-value containers: applies to the value if present * For collections: applies to each element */ forEach(f: (a: A) => void): void; } /** * Operations specific to collections (List, Set, etc.). * These operations don't make sense for single-value containers. * * @typeParam A - The element type * @typeParam Self - The collection type itself for proper return types */ interface CollectionOps { /** * Left-associative fold over all elements using an initial value and combining function. * Unlike foldLeft (which is curried), this provides a convenient uncurried signature. * * @example * ```typescript * List([1, 2, 3]).fold(0, (acc, x) => acc + x) // 6 * ``` * * @param initial - The initial accumulator value * @param fn - A function that combines the accumulator with each element * @returns The final accumulated value */ fold(initial: B, fn: (acc: B, a: A) => B): B; /** * Drops the first n elements from the collection. */ drop(n: number): Self; /** * Drops the last n elements from the collection. */ dropRight(n: number): Self; /** * Drops elements from the start while the predicate is true. */ dropWhile(p: (a: A) => boolean): Self; /** * Flattens a collection of collections into a single collection. */ flatten(): Self; /** * Gets the first element of the collection. */ get head(): A | undefined; /** * Gets the first element wrapped in Option. */ get headOption(): Option; /** * Takes the first n elements from the collection. */ take(n: number): Self; /** * Takes elements from the start while the predicate is true. */ takeWhile(p: (a: A) => boolean): Self; /** * Takes the last n elements from the collection. */ takeRight(n: number): Self; /** * Gets the last element of the collection. */ get last(): A | undefined; /** * Gets the last element wrapped in Option. */ get lastOption(): Option; /** * Gets all elements except the first. */ get tail(): Self; /** * Gets all elements except the last. */ get init(): Self; /** * Converts the collection to an array. */ toArray(): B[]; } //#endregion //#region src/typeclass/Functor.d.ts /** * Functor type class - supports mapping over wrapped values * * Laws: * - Identity: fa.map(x => x) ≡ fa * - Composition: fa.map(f).map(g) ≡ fa.map(x => g(f(x))) */ interface Functor { map(f: (value: A) => B): Functor; } /** * Applicative functor - supports applying wrapped functions to wrapped values * * Laws: * - Identity: pure(x => x).ap(v) ≡ v * - Composition: pure(compose).ap(u).ap(v).ap(w) ≡ u.ap(v.ap(w)) * - Homomorphism: pure(f).ap(pure(x)) ≡ pure(f(x)) * - Interchange: u.ap(pure(y)) ≡ pure(f => f(y)).ap(u) */ interface Applicative extends Functor { ap(ff: Applicative<(value: A) => B>): Applicative; } /** * Monad type class - supports flat mapping (chaining) operations * * Laws: * - Left identity: pure(a).flatMap(f) ≡ f(a) * - Right identity: m.flatMap(pure) ≡ m * - Associativity: m.flatMap(f).flatMap(g) ≡ m.flatMap(x => f(x).flatMap(g)) */ interface Monad extends Applicative { flatMap(f: (value: A) => Monad): Monad; } /** * Async monad - supports asynchronous monadic operations * Extends Monad so it has map, ap, and flatMap in addition to flatMapAsync */ interface AsyncMonad extends Monad { flatMapAsync(f: (value: A) => PromiseLike>): PromiseLike>; } //#endregion //#region src/typeclass/Promisable.d.ts /** * Promisable trait - supports conversion to Promise * * Represents containers or values that can be converted to Promise form. * This enables integration with async/await patterns and Promise-based APIs * while maintaining functional programming principles. * * @template A - The type of value contained within the Promise * * @example * ```typescript * const either: Either = Right(42) * const promise: Promise = either.toPromise() * // Promise resolves with 42 * * const leftEither: Either = Left("error") * const failedPromise: Promise = leftEither.toPromise() * // Promise rejects with "error" * ``` */ interface Promisable { /** * Converts this container to a Promise * * The behavior depends on the implementing container: * - Success/Right/Some containers resolve with their value * - Failure/Left/None containers reject with their error/default error * * @returns A Promise that resolves or rejects based on the container's state */ toPromise(): Promise; } //#endregion //#region src/typeclass/variance.d.ts /** * Variance helpers — small utilities for expressing covariance-safe signatures * when TypeScript's type system doesn't offer the exact constraint we need. * * Motivation: Scala has lower-bound type parameters like `def reduce[B >: A](op: (B, B) => B): B` * — B must be a supertype of A. TypeScript lacks lower bounds, so a naive port * (`reduce(op: (b: B, a: B) => B): B`) lets the caller pick ANY B, including * unrelated types. At runtime that's a footgun: `List.reduce(...)` would * compile but run as number addition typed as string. * * `Widen` closes that gap using a conditional type. When B is truly a supertype * of A (including the default case B = A), `Widen` is B. When B is unrelated, * it resolves to `never`, which makes the callback uncallable and produces a compile * error at the call site. * * @module typeclass/variance */ /** * The TypeScript equivalent of Scala's `B >: A` (B is a supertype of A). * * Resolves to `B` when `A extends B` (i.e., B is a legitimate supertype of A, or B = A). * Resolves to `never` otherwise, which renders any callback position using Widen * uncallable — the user gets a compile-time error rather than a runtime type lie. * * @example * ```ts * // Inside a container interface: * reduce(op: (b: Widen, a: Widen) => Widen): Widen * * // Callers: * list.reduce((a, b) => a + b) // B defaults to A, Widen = A, fine * list.reduce(...) // A extends A | "extra", Widen = B, fine * list.reduce(...) // A doesn't extend Unrelated, Widen = never, compile error * ``` */ type Widen = A extends B ? B : never; /** * Runtime-safe `reduce` over an array whose element type `A` may be narrower than * the accumulator type `B`. Centralizes the single `as unknown as B` cast that's * otherwise spread across every container's implementation. * * Safety: the cast is sound because the `Widen` type-level constraint at the * public API layer guarantees `A <: B`. When that holds, A values flowing into the * callback are valid B values at runtime — exactly what Scala's `[B >: A]` provides. * * @param arr - source array of A values * @param op - accumulator operation typed over B (where B is A or a supertype) * @returns the folded value, typed as B */ declare const reduceWiden: (arr: readonly A[], op: (b: B, a: B) => B) => B; /** * Right-associative variant of {@link reduceWiden}. Same safety argument. */ declare const reduceRightWiden: (arr: readonly A[], op: (b: B, a: B) => B) => B; //#endregion //#region src/either/Either.d.ts /** * Either type module * @module Either * @category Core */ /** * Shared interface for Either variants. Contains all methods and type guards but * does NOT include the discriminant `_tag` or `value` — those are declared on the * variant interfaces (LeftOf / RightOf) so that Either acts as a true discriminated * union. After `if (e.isLeft())`, the else branch narrows `e` to RightOf and * `e.value` narrows to R without a cast. */ interface EitherBase extends FunctypeSum, Promisable, Doable, Reshapeable, Extractable { isLeft(): this is LeftOf; isRight(): this is RightOf; orElse(defaultValue: R2): R | R2; orThrow: (error?: Error) => R; /** * Returns the right value, or calls the never-returning handler with the Left's value. * Use this when you have a helper like `(msg) => fail(msg, 2)` that terminates the * program — the result type is unconditionally `R`, so you avoid the TypeScript * narrowing trap where `if (e.isLeft()) fail(...)` fails to narrow `e.value` when * `fail` is an arrow function typed as `(...): never`. */ expect: (handler: (value: L) => never) => R; or(alternative: Either): Either; orNull: () => R | null; orUndefined: () => R | undefined; readonly map: (f: (value: R) => U) => Either; ap: (ff: Either U>) => Either; merge: (other: Either) => Either; mapAsync: (f: (value: R) => Promise) => Promise>; flatMap: (f: (value: R) => Either) => Either; flatMapAsync: (f: (value: R) => Promise>) => Promise>; toOption: () => Option; toString: () => string; [Symbol.iterator]: () => Iterator; yield: () => Generator; traverse: (f: (value: R) => Either) => Either; tap: (f: (value: R) => void) => Either; tapLeft: (f: (value: L) => void) => Either; mapLeft: (f: (value: L) => L2) => Either; /** * Applies a predicate to the Right value. If the predicate fails, short-circuits * to a Left carrying the value produced by `onUnsatisfied`. Left passes through * unchanged (predicate not evaluated). Lets you turn a value-level guard into the * Left channel without breaking the chain with an `if/return Left(...)` ladder. * @param predicate - The predicate to test the Right value * @param onUnsatisfied - Builds the new Left value when the predicate fails * @returns Right if the predicate holds, Left(onUnsatisfied(value)) otherwise */ filterOrElse: (predicate: (value: R) => boolean, onUnsatisfied: (value: R) => L2) => Either; bimap: (fl: (value: L) => L2, fr: (value: R) => R2) => Either; fold: (onLeft: (value: L) => T, onRight: (value: R) => T) => T; /** * Async variant of fold. Accepts sync or async handlers on either branch and * always returns a Promise, keeping chains fluent when at least one branch is async. */ foldAsync: (onLeft: (value: L) => T | Promise, onRight: (value: R) => T | Promise) => Promise; swap: () => Either; /** * Pipes the value through the provided function based on whether this is a Left or Right */ pipeEither(onLeft: (value: L) => U, onRight: (value: R) => U): U; /** * Pipes the Either value through the provided function */ pipe(f: (value: L | R) => U): U; /** * Pattern matches over the Either, applying a handler function based on the variant */ match(patterns: { Left: (value: L) => T; Right: (value: R) => T; }): T; /** * Returns the value and tag for inspection */ toValue(): { _tag: "Left" | "Right"; value: L | R; }; /** * Custom JSON serialization that excludes getter properties. * Emits the canonical functype envelope with `@functype: "Either"` so * native `JSON.stringify` recursion (e.g. inside a plain object body) * produces a marker-bearing envelope that survives a round-trip through * `Serialization.deserialize`. */ toJSON(): { "@functype": "Either"; _tag: "Left" | "Right"; value: L | R; }; } /** * Left variant of Either. Discriminated by `_tag: "Left"` with `value: L`. */ interface LeftOf extends EitherBase { readonly _tag: "Left"; readonly value: L; } /** * Right variant of Either. Discriminated by `_tag: "Right"` with `value: R`. */ interface RightOf extends EitherBase { readonly _tag: "Right"; readonly value: R; } /** * Either is a discriminated union of LeftOf and RightOf. TypeScript narrows * across both branches of `isLeft()` / `isRight()` and `_tag` checks. Variance * is inherited from LeftOf/RightOf (both covariant in L and R) — union type * aliases cannot carry their own variance annotations in TS. */ type Either = LeftOf | RightOf; type TestEither = Either & AsyncMonad; declare const Right: (value: R) => Either; declare const Left: (value: L) => Either; declare const isRight: (either: Either) => either is RightOf; declare const isLeft: (either: Either) => either is LeftOf; declare const tryCatch: (f: () => R, onError: (error: unknown) => L) => Either; declare const TypeCheckRight: (value: R) => TestEither; declare const TypeCheckLeft: (value: L) => TestEither; declare const tryCatchAsync: (f: () => Promise, onError: (error: unknown) => L) => Promise>; declare const Either: ((value: R | L, isRight: boolean) => Either) & { /** * Creates a Left instance * @param value - The left value * @returns Left Either */ left: (value: L) => Either; /** * Creates a Right instance * @param value - The right value * @returns Right Either */ right: (value: R) => Either; /** * Creates a Right — convenience for "operation succeeded with no meaningful value". * Avoids variance quirks around Either vs Either. * @returns Right Either with void value */ void: () => Either; /** * Type guard to check if an Either is Right * @param either - The Either to check * @returns True if Either is Right */ isRight: (either: Either) => either is RightOf; /** * Type guard to check if an Either is Left * @param either - The Either to check * @returns True if Either is Left */ isLeft: (either: Either) => either is LeftOf; /** * Combines an array of Eithers into a single Either containing an array * @param eithers - Array of Either values * @returns Either with array of values or first Left encountered */ sequence: (eithers: Either[]) => Either; /** * Maps an array through a function that returns Either, then sequences the results * @param arr - Array of values * @param f - Function that returns Either * @returns Either with array of results or first Left encountered */ traverse: (arr: R[], f: (value: R) => Either) => Either; /** * Creates an Either from a nullable value * @param value - The value that might be null or undefined * @param leftValue - The value to use for Left if value is null/undefined * @returns Right if value is not null/undefined, Left otherwise */ fromNullable: (value: R | null | undefined, leftValue: L) => Either; /** * Creates an Either based on a predicate * @param value - The value to test * @param predicate - The predicate function * @param leftValue - The value to use for Left if predicate fails * @returns Right if predicate passes, Left otherwise */ fromPredicate: (value: R, predicate: (value: R) => boolean, leftValue: L) => Either; /** * Applicative apply - applies a wrapped function to a wrapped value * @param eitherF - Either containing a function * @param eitherV - Either containing a value * @returns Either with function applied to value */ ap: (eitherF: Either U>, eitherV: Either) => Either; /** * Creates an Either from a Promise * @param promise - The Promise to convert * @param onRejected - Function to convert rejection reason to Left value * @returns Promise that resolves to Either */ fromPromise: (promise: Promise, onRejected: (reason: unknown) => L) => Promise>; /** * Creates an Either from JSON string * @param json - The JSON string * @returns Either instance */ fromJSON: (json: string) => Either; /** * Creates an Either from YAML string * @param yaml - The YAML string * @returns Either instance */ fromYAML: (yaml: string) => Either; /** * Creates an Either from binary string * @param binary - The binary string * @returns Either instance */ fromBinary: (binary: string) => Either; }; //#endregion //#region src/list/LazyList.d.ts /** * LazyList provides lazy evaluation for list operations. * Operations are deferred until the list is materialized. * * @example * // Basic lazy evaluation * const result = LazyList([1, 2, 3, 4, 5]) * .map(x => x * 2) * .filter(x => x > 5) * .toArray() // [6, 8, 10] * * @example * // Infinite sequences with take * const fibonacci = LazyList.iterate([0, 1], ([a, b]) => [b, a + b]) * .map(([a]) => a) * .take(10) * .toArray() // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] */ interface LazyList extends Foldable, Pipe>, Serializable>, Typeable<"LazyList"> { readonly [Symbol.toStringTag]: string; [Symbol.iterator](): Iterator; map(f: (a: A) => B): LazyList; flatMap(f: (a: A) => LazyList): LazyList; filter(predicate: (a: A) => boolean): LazyList; take(n: number): LazyList; drop(n: number): LazyList; takeWhile(predicate: (a: A) => boolean): LazyList; dropWhile(predicate: (a: A) => boolean): LazyList; /** Concatenate with another lazy list, possibly widening (Scala: `++[B >: A]`). */ concat(other: LazyList): LazyList; zip(other: LazyList): LazyList<[A, B]>; takeRight(n: number): LazyList; reverse(): LazyList; distinct(): LazyList; zipWithIndex(): LazyList<[A, number]>; get head(): A | undefined; get headOption(): Option; get last(): A | undefined; get lastOption(): Option; get tail(): LazyList; get init(): LazyList; fold(initial: B, fn: (acc: B, a: A) => B): B; toList(): List; toArray(): A[]; forEach(f: (a: A) => void): void; reduce(f: (acc: B, a: A) => B, initial: B): B; find(predicate: (a: A) => boolean): Option; some(predicate: (a: A) => boolean): boolean; every(predicate: (a: A) => boolean): boolean; count(): number; toString(): string; } /** * Lazy list implementation for efficient deferred computation * @example * // Process large datasets efficiently * const result = LazyList.range(1, 1000000) * .filter(x => x % 2 === 0) * .map(x => x * x) * .take(5) * .toArray() // [4, 16, 36, 64, 100] * * @example * // Infinite sequences * const primes = LazyList.iterate(2, n => n + 1) * .filter(isPrime) * .take(10) * .toArray() // First 10 prime numbers * * @example * // Combining operations * const evens = LazyList.range(0, 100, 2) * const odds = LazyList.range(1, 100, 2) * const combined = evens.zip(odds) * .map(([e, o]) => e + o) * .take(5) * .toArray() // [1, 5, 9, 13, 17] */ declare const LazyList: ((iterable: Iterable) => LazyList) & { /** * Create an empty LazyList * @example * const empty = LazyList.empty() * empty.toArray() // [] */ empty: () => LazyList; /** * Create a LazyList from a single value * @example * const single = LazyList.of(42) * .map(x => x * 2) * .toArray() // [84] */ of: (value: A) => LazyList; /** * Create a LazyList from multiple values */ from: (...values: A[]) => LazyList; /** * Reconstruct a LazyList from a JSON envelope emitted by `serialize().toJSON()` * or instance `toJSON()`. Verifies `@functype === "LazyList"` when the marker * is present (canonical from 1.2.0). The materialized array becomes the new * LazyList's backing — laziness can't survive JSON serialization. */ fromJSON: (json: string) => LazyList; /** * Create an infinite LazyList by repeatedly applying a function * @example * // Powers of 2 * const powers = LazyList.iterate(1, x => x * 2) * .take(10) * .toArray() // [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] * * @example * // Fibonacci sequence * const fib = LazyList.iterate([0, 1], ([a, b]) => [b, a + b]) * .map(([a]) => a) * .take(8) * .toArray() // [0, 1, 1, 2, 3, 5, 8, 13] */ iterate: (initial: A, f: (a: A) => A) => LazyList; /** * Create an infinite LazyList by repeatedly calling a function */ generate: (f: () => A) => LazyList; /** * Create a LazyList of numbers from start to end (exclusive) * @example * LazyList.range(1, 6).toArray() // [1, 2, 3, 4, 5] * LazyList.range(0, 10, 2).toArray() // [0, 2, 4, 6, 8] * LazyList.range(10, 0, -1).toArray() // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] * * @example * // Sum of squares from 1 to 100 * const sum = LazyList.range(1, 101) * .map(x => x * x) * .reduce((a, b) => a + b, 0) // 338350 */ range: (start: number, end: number, step?: number) => LazyList; /** * Create a LazyList that repeats a value n times (or infinitely if n is not provided) */ repeat: (value: A, n?: number) => LazyList; /** * Create a LazyList that cycles through an iterable infinitely */ cycle: (iterable: Iterable) => LazyList; }; //#endregion //#region src/serialization/error-envelope.d.ts /** * Canonical projection of `Error` to JSON, shared by every Serializable type * that carries an `Error` in its failure branch (`Try.Failure`, `Task.Err`, * `Lazy` with a thrown thunk). * * Round-trip guarantees: * - `err.name` survives (preserves discriminator: `e.name === "TypeError"` works) * - `err.message` survives * - `err.stack` survives if present at serialize time * - `err.cause` survives recursively (arbitrary nesting depth) * * What does NOT survive: * - `instanceof TypeError` and other subclass identity checks (JSON cannot * reconstruct user-defined classes without arbitrary code execution). * - Custom Error-subclass fields (e.g. `HttpError.status`). The generic * projection doesn't know about them; a future registry mechanism may * address this. * * Use `e.name` for discriminator checks across the serialization boundary, * not `e instanceof SomeError`. */ type SerializedError = { readonly name: string; readonly message: string; readonly stack?: string; readonly cause?: SerializedError | string; }; /** * Project an arbitrary thrown value to the canonical SerializedError shape. * Accepts both `Error` instances and non-Error throwables (strings, plain * objects, etc.). Non-Error throwables get `name: "NonErrorThrowable"` and * the best textual representation we can produce. */ declare const serializeError: (err: unknown) => SerializedError; /** * Reconstruct an Error from a SerializedError. The reconstructed Error has * the same `name`, `message`, `stack`, and `cause` chain as the original, * but its prototype is always `Error.prototype` — subclass identity does * not round-trip. * * A `string` is accepted as a shorthand for `{name: "Error", message: }`, * matching what `serializeCause` emits when a `cause` was a bare string. */ declare const deserializeError: (s: SerializedError | string) => Error; //#endregion //#region src/serialization/SerializationCompanion.d.ts /** * Serialization result containing methods for different formats */ interface SerializationResult { /** Serializes to JSON string */ toJSON: () => string; /** Serializes to YAML string */ toYAML: () => string; /** Serializes to base64-encoded binary string */ toBinary: () => string; } /** * The namespaced marker stamped on every functype envelope. Defends against * `_tag` collisions with Effect/fp-ts (which use identical strings like * `"Some"`, `"Left"`, `"Success"`). A value WITHOUT this marker is treated * as "not ours" by `Serialization.deserialize`. * * See `docs/archive/proposals/universal-deserialize-changes.md` Change 0 for the * full rationale. */ declare const FUNCTYPE_MARKER: "@functype"; /** * Shape of every functype JSON envelope. The marker identifies the type, * `_tag` (when present) discriminates variants within that type, and the * remaining payload fields are type-specific (`value` for canonical cases, * `error` for failure branches, etc.). */ type FunctypeEnvelope = { readonly [FUNCTYPE_MARKER]: string; readonly _tag?: string; readonly [key: string]: unknown; }; /** * Build the canonical `{@functype, _tag, value}` envelope OBJECT used by both * the instance `toJSON()` (which returns it directly so native JSON.stringify * can recurse) and the `serialize().toJSON()` method (which stringifies it). * * `_tag` is always emitted — variant-less types pass the same string for * marker and tag (default behavior when tag is omitted). Keeping `_tag` * across the board preserves back-compat for readers that did * `if (parsed._tag === "List")` against 1.1.0 envelopes. * * @param marker - The `@functype` type marker, e.g. `"Either"`, `"Option"`. * @param tag - The variant discriminator, e.g. `"Right"`, `"Some"`. Defaults * to `marker` for types without variants (List, Map, etc.). * @param value - The payload. */ declare const envelope: (marker: string, tag: string | undefined, value: unknown) => FunctypeEnvelope; /** * Build a non-canonical envelope where the payload doesn't fit the standard * `{value}` shape — e.g. `Try.Failure` carries `{error: SerializedError}`, * `Lazy`-with-thrown-thunk carries the same. * * @param marker - The `@functype` type marker. * @param tag - The variant discriminator (may be the same as marker for * variant-less types). * @param fields - Additional payload fields merged into the envelope. */ declare const taggedEnvelope: (marker: string, tag: string, fields: Record) => FunctypeEnvelope; /** * Creates a serializer for the canonical envelope shape, with the `@functype` * marker stamped at the top level (Change 0 of the 1.2.0 universal-deserialize * work). Two forms: * * createSerializer(marker, value) // variant-less types (List, Map, …) * createSerializer(marker, tag, value) // variants (Either, Option, …) * * Variant-less envelopes are `{"@functype": marker, value}`. Variant envelopes * are `{"@functype": marker, _tag: tag, value}`. */ declare function createSerializer(marker: string, value: unknown): SerializationResult; declare function createSerializer(marker: string, tag: string, value: unknown): SerializationResult; /** * Creates a serializer for non-canonical envelopes whose payload doesn't * fit the `{value}` shape — e.g. failure branches that carry a structured * `SerializedError`. The envelope still carries the `@functype` marker * and `_tag` discriminator. * * @param marker - The `@functype` type marker. * @param tag - The variant discriminator. * @param fields - The payload fields (merged after marker + tag). */ declare const createTaggedSerializer: (marker: string, tag: string, fields: Record) => SerializationResult; /** * @deprecated Use `createTaggedSerializer` instead. Retained for backwards * compatibility with any external callers; will be removed in a * future major. The single internal caller (`Try.Failure`) has * been migrated to `createTaggedSerializer`. * * Creates a serializer for complex objects with custom serialization logic. * Note: this variant does NOT stamp the `@functype` marker — callers must * include it in `data` themselves if they want envelope dispatch to work. */ declare const createCustomSerializer: (data: Record) => SerializationResult; /** * Generic deserializer from JSON. The `reconstructor` receives the full * parsed envelope including any `@functype` marker; per-type companions * verify the marker matches their expected value. */ declare const fromJSON: (json: string, reconstructor: (parsed: { _tag?: string; [key: string]: unknown; }) => T) => T; /** * Generic deserializer from YAML (simple format) * @param yaml - The YAML string to parse * @param reconstructor - Function to reconstruct the type from parsed data * @returns Reconstructed instance */ declare const fromYAML: (yaml: string, reconstructor: (parsed: { _tag?: string; [key: string]: unknown; }) => T) => T; /** * Generic deserializer from binary (base64-encoded JSON) * @param binary - The base64-encoded binary string * @param reconstructor - Function to reconstruct the type from parsed data * @returns Reconstructed instance */ declare const fromBinary: (binary: string, reconstructor: (parsed: { _tag?: string; [key: string]: unknown; }) => T) => T; /** * Creates companion serialization methods for a type * @param reconstructor - Function to reconstruct the type from parsed data * @returns Companion methods object with fromJSON, fromYAML, and fromBinary */ declare const createSerializationCompanion: (reconstructor: (parsed: { _tag?: string; [key: string]: unknown; }) => T) => { fromJSON: (json: string) => T; fromYAML: (yaml: string) => T; fromBinary: (binary: string) => T; }; declare namespace Serialization_d_exports { export { JSONValue, deserialize, deserializeStrict, fromEnvelope, isFunctypeValue, serialize, toEnvelope }; } /** * The canonical JSON value type — anything `JSON.parse` can return and * anything `JSON.stringify` can accept as input. Used by `toEnvelope` / * `fromEnvelope` to express the contract precisely: the envelope is a * structured JSON shape, not opaque `unknown`. Lets consumers wiring this * API into another structured serializer (SuperJSON, DBOS custom * transformers) slot it in without a cast at the boundary. * * Added in 1.2.2 — `toEnvelope`/`fromEnvelope` previously typed input/output * as `unknown`, which forced a cast at the consumer side. */ type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue; }; /** * Reconstruct any value from a JSON string. Lenient codec: walks the parsed * structure and rebuilds any value carrying an `@functype` marker via the * dispatch table; plain JSON without the marker walks through unchanged. * Returns `Try` so malformed JSON or unknown markers are expressible values * rather than thrown — matches the functype convention for expected-failure * paths. * * **Pass-through policy:** valid JSON without an `@functype` marker is * returned verbatim as `Success(value)`; only marker-carrying values are * reconstructed. Only malformed JSON (or an unknown marker) yields `Failure`. * For a strict variant that rejects unmarked input, see `deserializeStrict`. * * @example * const result = Serialization.deserialize('{"@functype":"Either","_tag":"Right","value":5}') * result.fold(e => console.error(e), v => console.log(v)) // → Right(5) * * // Plain (non-functype) values pass through: * Serialization.deserialize('{"name":"alice","age":30}') // → Success({name, age}) * * // Embedding in another structured serializer (SuperJSON, DBOS)? See * // `fromEnvelope` — taking a string here forces the consumer through a * // JSON.stringify shim and SuperJSON re-walks strings character-by-character. */ declare const deserialize: (json: string) => Try; /** * Strict variant of `deserialize`: returns `Failure` when the parsed JSON * doesn't carry an `@functype` marker at the top level. Use this at API, * queue, or RPC boundaries where the wire format MUST be a functype value * and pass-through silence would be a bug. * * Implementation note: only the top-level value is checked for the marker. * Nested values inside it follow the same lenient pass-through rules as * `deserialize` — a `Right` containing a plain object still reconstructs * fine, you just can't START with a plain object. * * @example * Serialization.deserializeStrict('{"@functype":"Option","_tag":"Some","value":1}') // → Success(Some(1)) * Serialization.deserializeStrict('{"_tag":"Some","value":1}') // → Failure * Serialization.deserializeStrict('42') // → Failure */ declare const deserializeStrict: (json: string) => Try; /** * Serialize any value to a JSON string. Lenient codec: thin convenience over * `JSON.stringify` — functype instances self-stringify via their instance * `toJSON()` method (which emits the `@functype`-marked envelope), and * non-functype values pass through as plain JSON. Nested functype values * embedded in plain objects/arrays serialize correctly via the standard * JSON.stringify protocol with no walker needed. * * `undefined` is converted to `null` (matching the convention DBOS and * SuperJSON use; `JSON.stringify(undefined)` returns the string `"undefined"` * which is not valid JSON). */ declare const serialize: (value: unknown) => string; /** * Serialize a value to a parsed JSON envelope (object/array/primitive) rather * than a string. Use this when nesting functype values inside another * **structured** serializer (SuperJSON / DBOS custom transformers / similar) * whose custom-transformer hook expects JSON values, not strings — passing a * string to such a hook causes the host to re-walk it character-by-character, * destroying the round-trip. * * Equivalent to `JSON.parse(serialize(value))` but exposed as a named entry * point so consumers don't carry the parse/stringify shim. * * Returns `JSONValue` (tightened from `unknown` in 1.2.2) so consumers can * drop the result straight into a host serializer's `serialize` hook without * a boundary cast. * * @example * // Inside a DBOS custom serialization recipe — zero casts: * DBOS.registerSerialization({ * name: "functype", * isApplicable: Serialization.isFunctypeValue, * serialize: Serialization.toEnvelope, * deserialize: (o) => Serialization.fromEnvelope(o).orThrow(), * }) */ declare const toEnvelope: (value: unknown) => JSONValue; /** * Inverse of `toEnvelope`: reconstruct any value from a parsed JSON envelope * (object/array/primitive). Equivalent to `deserialize(JSON.stringify(envelope))` * but skips the stringify/parse roundtrip — the same `revive` walker is * applied directly. Returns `Try` for the same reasons as `deserialize`. * * Pass-through policy matches `deserialize`: a parsed value without an * `@functype` marker is returned verbatim as `Success(value)`. * * Input is `unknown` (intentionally permissive — Postel's law). Host * serializers typically hand the deserialize callback a JSON-shaped value * that they parsed themselves, but their callback typing varies (some are * `JSONValue`, some are `unknown`, some are `any`). Accepting `unknown` * here means the function slots into any host shape without forcing a * cast at the consumer site. */ declare const fromEnvelope: (envelope: unknown) => Try; /** * Runtime guard: is this a live functype Serializable? Checks for the * `serialize()` method plus the `_tag` field that every Serializable instance * carries. Use this when wrapping `serialize`/`deserialize` in a host * serializer that needs to distinguish functype values from foreign data * (e.g. `isApplicable` in a DBOS recipe). */ declare const isFunctypeValue: (v: unknown) => v is Serializable; //#endregion //#region src/try/Try.d.ts /** * Possible types of Try instances */ type TypeNames = "Success" | "Failure"; interface Try extends FunctypeSum, Extractable, Pipe, Promisable, Doable, Reshapeable { readonly _tag: TypeNames; readonly error: Error | undefined; isSuccess(): this is Try & { readonly _tag: "Success"; error: undefined; }; isFailure(): this is Try & { readonly _tag: "Failure"; error: Error; }; orElse(defaultValue: T2): T | T2; orThrow: (error?: Error) => T; /** * Returns the success value, or calls the never-returning handler with the Failure's error. * Use this when you have a helper like `(msg) => fail(msg, 2)` that terminates the program — * the result type is unconditionally `T`, so you avoid the TypeScript narrowing trap where * `if (t.isFailure()) fail(...)` fails to narrow `t.value` when `fail` is an arrow function * typed as `(...): never`. */ expect: (handler: (error: Error) => never) => T; or(alternative: Try): Try; orNull: () => T | null; orUndefined: () => T | undefined; toOption: () => Option; /** * Converts to a plain readonly array: `[value]` for Success, `[]` for Failure. * Symmetric with `Try.toList()` but skips the List wrapper for code that * just wants to feed Array.prototype methods or spread into another array. */ toArray: () => readonly T[]; /** * Converts to Either. Failure becomes Left(builder(error)) when given a function, * or Left(leftValue) when given a value. Success becomes Right(value). * * Prefer the function form to thread the underlying Error's context into the Left: * * Try.fromYAML(text).toEither((e) => `parse failed: ${e.message}`) */ toEither: (leftOrBuilder: E | ((err: Error) => E)) => Either; toTry: () => Try; map: (f: (value: T) => U) => Try; ap: (ff: Try<(value: T) => U>) => Try; flatMap: (f: (value: T) => Try) => Try; flatMapAsync: (f: (value: T) => Promise>) => Promise>; /** * Pattern matches over the Try, applying onFailure if Failure and onSuccess if Success * @param onFailure - Function to apply if the Try is Failure * @param onSuccess - Function to apply if the Try is Success * @returns The result of applying the appropriate function */ fold: (onFailure: (error: Error) => U, onSuccess: (value: T) => U) => U; /** * Async variant of fold. Accepts sync or async handlers on either branch and * always returns a Promise. */ foldAsync: (onFailure: (error: Error) => U | Promise, onSuccess: (value: T) => U | Promise) => Promise; toString: () => string; /** * Pattern matches over the Try, applying a handler function based on the variant * @param patterns - Object with handler functions for Success and Failure variants * @returns The result of applying the matching handler function */ match(patterns: { Success: (value: T) => R; Failure: (error: Error) => R; }): R; /** * Recovers from a Failure by applying a function to the error, returning a new Try. * The recovery value may be a wider type; the result is `Try`, matching * Scala's `recover[U >: T]` shape so Try stays covariant in T. */ recover(f: (error: Error) => U): Try; /** * Recovers from a Failure by applying a function that returns a new Try. * As with `recover`, the recovery Try may carry a wider type; the result widens accordingly. */ recoverWith(f: (error: Error) => Try): Try; /** * Applies a predicate to the success value. If the predicate fails, short-circuits * to a Failure with the error produced by `onUnsatisfied`. Failure passes through * unchanged (predicate not evaluated). Lets you turn a value-level guard into the * error channel without writing a manual `throw` inside a `Try(() => ...)` body. * @param predicate - The predicate to test the success value * @param onUnsatisfied - Builds the Error for the new Failure when the predicate fails * @returns A Success if the predicate holds, a Failure carrying `onUnsatisfied(value)` otherwise */ filterOrElse(predicate: (value: T) => boolean, onUnsatisfied: (value: T) => Error): Try; toValue(): { _tag: TypeNames; value: T | Error; }; /** * Custom JSON serialization. Success emits `{"@functype":"Try","_tag":"Success","value":T}`. * Failure emits `{"@functype":"Try","_tag":"Failure","error":SerializedError}` where * SerializedError captures `name`, `message`, `stack`, and the full `cause` chain — * `e.name` survives round-trip but `instanceof SomeError` does not. */ toJSON(): { "@functype": "Try"; _tag: "Success"; value: T; } | { "@functype": "Try"; _tag: "Failure"; error: SerializedError; }; } declare const Try: ((f: () => T) => Try) & { /** * Creates a Success directly without needing a callback * @param value - The success value * @returns Try containing the value as Success */ success: (value: T) => Try; /** * Creates a Failure directly without needing to throw * @param error - The error (string or Error instance) * @returns Try containing the error as Failure */ failure: (error: Error | string) => Try; /** * Creates a Try from a Promise, resolving to Success or Failure * @param promise - The promise to convert * @returns Promise resolving to a Try */ fromPromise: (promise: Promise) => Promise>; /** * Creates a Try from a thunk that returns a Promise. The thunk is invoked * when async() is called, so the Promise starts executing under the Try * wrapper — synchronous throws from the thunk are caught the same way * `Try(() => sync)` catches them, and rejections are caught the same way * `Try.fromPromise(promise)` catches them. * * Prefer this over `Try.fromPromise(thunk())` when you want the work to be * deferred until wrapping (e.g. composing a chain of Try-returning thunks * before any of them runs). * * @example * const result = await Try.async(() => fs.readFile(path, "utf8")) * result.fold(err => log(err.message), data => process(data)) * * @param thunk - Function returning a Promise to be wrapped * @returns Promise resolving to a Try */ async: (thunk: () => Promise) => Promise>; /** * Type guard to check if a Try is Success * @param tryValue - The Try to check * @returns True if Try is Success */ isSuccess: (tryValue: Try) => tryValue is Try & { readonly _tag: "Success"; error: undefined; }; /** * Type guard to check if a Try is Failure * @param tryValue - The Try to check * @returns True if Try is Failure */ isFailure: (tryValue: Try) => tryValue is Try & { readonly _tag: "Failure"; error: Error; }; /** * Creates a Try from JSON string * @param json - The JSON string * @returns Try instance */ fromJSON: (json: string) => Try; /** * Creates a Try from YAML string * @param yaml - The YAML string * @returns Try instance */ fromYAML: (yaml: string) => Try; /** * Creates a Try from binary string * @param binary - The binary string * @returns Try instance */ fromBinary: (binary: string) => Try; /** * Combines an array of Trys into a single Try containing an array. * Short-circuits on the first Failure, preserving its error. * @param tries - Array of Try values * @returns Success with array of values, or first Failure */ sequence: (tries: Try[]) => Try; /** * Maps an array through a function returning Try, then sequences the results. * Short-circuits on the first Failure. * @param arr - Array of values * @param f - Function returning Try * @returns Success with array of mapped values, or first Failure */ traverse: (arr: ReadonlyArray, f: (value: T, index: number) => Try) => Try; }; //#endregion //#region src/reshapeable/Reshapeable.d.ts /** * Interface for types that can be reshaped (converted) between different monadic containers. * Provides standard conversion methods to transform between Option, Either, List, and Try types. * * @typeParam T - The type of the value contained in the monad * * @example * // Convert Option to Either * const opt = Option(5) * const either = opt.toEither("None value") // Right(5) * * @example * // Convert Either to Option * const right = Right(10) * const option = right.toOption() // Some(10) * * @example * // Convert List to Try * const list = List([1, 2, 3]) * const tryVal = list.toTry() // Success(1) - uses first element * * @example * // Use with Do comprehensions * const result = Do(function* () { * const x = yield* $(Option(5)) * const y = yield* $(Right(10)) * return x + y * }) * * // Convert to desired type for chaining * const asOption = result.toOption() * asOption.map(x => x * 2).orElse(0) */ interface Reshapeable { /** * Converts this monad to an Option. * * Conversion rules: * - Option: returns self * - Either: Right → Some, Left → None * - List: non-empty → Some(head), empty → None * - Try: Success → Some, Failure → None * * @returns An Option containing the value if present, None otherwise */ toOption(): Option; /** * Converts this monad to an Either. * * Conversion rules: * - Option: Some → Right, None → Left(leftValue) * - Either: returns self * - List: non-empty → Right(head), empty → Left(leftValue) * - Try: Success → Right, Failure → Left(leftValue). Try also accepts a builder * `(err: Error) => E` to thread the underlying Error's context into the Left. * * @param leftValue - The value to use for the Left case when the source is empty/none/failure * @returns An Either with the value as Right or the provided leftValue as Left */ toEither(leftValue: E): Either; /** * Converts this monad to a List. * * Conversion rules: * - Option: Some → List([value]), None → List([]) * - Either: Right → List([value]), Left → List([]) * - List: returns self * - Try: Success → List([value]), Failure → List([]) * * @returns A List containing the value(s) if present, empty List otherwise */ toList(): List; /** * Converts this monad to a Try. * * Conversion rules: * - Option: Some → Success, None → Failure(Error("None")) * - Either: Right → Success, Left → Failure(Error(leftValue)) * - List: non-empty → Success(head), empty → Failure(Error("Empty list")) * - Try: returns self * * @returns A Try containing Success with the value or Failure with an appropriate error */ toTry(): Try; } //#endregion //#region src/list/List.d.ts /** * Immutable List. Covariant in A (``) — mirrors Scala's `List[+A]`. * * Methods that would otherwise force A-invariance use TS equivalents of Scala's * co-variance patterns: * - query/removal ops (`contains`, `indexOf`, `remove`) take `unknown`, matching * Scala's `-(elem: Any)` / `contains(elem: Any)` — if the value can't possibly * be in the list, it's a no-op, not a type error. * - additive ops (`add`, `prepend`, `concat`) widen the element type, matching * Scala's `::[B >: A]` / `++[B >: A]` — `List + B` produces `List`. * - `reduce` / `reduceRight` accept a wider accumulator type, matching Scala's * `reduce[B >: A]`. */ interface List extends FunctypeCollection, Doable, Reshapeable { readonly length: number; readonly [Symbol.iterator]: () => Iterator; map: (f: (a: A) => B) => List; ap: (ff: List<(value: A) => B>) => List; flatMap: (f: (a: A) => Iterable) => List; flatMapAsync: (f: (a: A) => PromiseLike>) => PromiseLike>; filter(predicate: (a: A) => a is S): List; filter(predicate: (a: A) => unknown): List; filterNot: (p: (a: A) => boolean) => List; /** @internal */ filterType: >(tag: string) => List; /** Remove a value. Accepts `unknown` so an unrelated-type arg is a safe no-op (Scala: `-(elem: Any)`). */ remove: (value: unknown) => List; removeAt: (index: number) => List; /** Add a value, possibly widening the element type (Scala: `:+[B >: A]`). */ add(item: B): List; get: (index: number) => Option; /** Concatenate with another list, possibly widening (Scala: `++[B >: A]`). */ concat(other: List): List; take: (n: number) => List; takeWhile: (p: (a: A) => boolean) => List; takeRight: (n: number) => List; get last(): A | undefined; get lastOption(): Option; get tail(): List; get init(): List; reverse: () => List; /** Find the index of a value. Accepts `unknown` (Scala: `indexOf(elem: Any)`). */ indexOf: (value: unknown) => number; /** Prepend a value, possibly widening (Scala: `+:[B >: A]`). */ prepend(item: B): List; distinct: () => List; sorted: (compareFn?: (a: A, b: A) => number) => List; sortBy: (f: (a: A) => B, compareFn?: (a: B, b: B) => number) => List; zip: (other: List) => List<[A, B]>; zipWithIndex: () => List<[A, number]>; groupBy: (f: (a: A) => K) => globalThis.Map>; partition: (p: (a: A) => boolean) => [List, List]; span: (p: (a: A) => boolean) => [List, List]; slice: (start: number, end: number) => List; /** * Pattern matches over the List, applying a handler function based on whether it's empty * @param patterns - Object with handler functions for Empty and NonEmpty variants * @returns The result of applying the matching handler function */ match(patterns: { Empty: () => R; NonEmpty: (values: A[]) => R; }): R; } declare const List: ((values?: Iterable) => List) & { /** * Creates an empty List * Returns a singleton instance for efficiency * @returns An empty List instance */ empty: () => List; /** * Creates a List from variadic arguments * @param values - Values to create list from * @returns A List containing the values */ of: (...values: A[]) => List; /** * Creates a List from JSON string * @param json - The JSON string * @returns List instance */ fromJSON: (json: string) => List; /** * Creates a List from YAML string * @param yaml - The YAML string * @returns List instance */ fromYAML: (yaml: string) => List; /** * Creates a List from binary string * @param binary - The binary string * @returns List instance */ fromBinary: (binary: string) => List; }; //#endregion //#region src/set/Set.d.ts /** * Immutable Set. Covariant in A (``) — while Scala's `Set[A]` is nominally invariant, * functype's Set follows the same pragmatic covariance pattern as List: element-query methods * (`contains`, `has`, `remove`) accept `unknown`, and additions widen via `(B) => Set`. * `reduce`/`reduceRight` follow Scala's `reduce[B >: A]` pattern with a default `B = A`. */ interface Set extends FunctypeCollection, Collection { add(value: B): Set; remove: (value: unknown) => Set; has(value: unknown): boolean; map: (f: (a: A) => B) => Set; flatMap: (f: (a: A) => Iterable) => Set; filter: (p: (a: A) => boolean) => Set; filterNot: (p: (a: A) => boolean) => Set; fold: (initial: B, fn: (acc: B, a: A) => B) => B; toList: () => List; toSet: () => Set; toArray: () => B[]; toString: () => string; } declare const Set: ((iterable?: Iterable) => Set) & { /** * Creates an empty Set * Returns a singleton instance for efficiency * @returns An empty Set instance */ empty: () => Set; /** * Creates a Set from variadic arguments * @param values - Values to create set from * @returns A Set containing the unique values */ of: (...values: A[]) => Set; /** * Creates a Set from JSON string * @param json - The JSON string * @returns Set instance */ fromJSON: (json: string) => Set; /** * Creates a Set from YAML string * @param yaml - The YAML string * @returns Set instance */ fromYAML: (yaml: string) => Set; /** * Creates a Set from binary string * @param binary - The binary string * @returns Set instance */ fromBinary: (binary: string) => Set; }; //#endregion //#region src/collections/index.d.ts /** * Represents a collection with conversion capabilities * @interface * @module Collections * @category Core */ interface Collection { toList(): List; toSet(): Set; toString(): string; } //#endregion //#region src/matchable/Matchable.d.ts /** * Pattern matching interface for functional data types. * * @typeParam A - The type of elements in the data structure * @typeParam Tags - The type of tags used for pattern matching */ interface Matchable { /** * Pattern matches against this data structure, applying handlers for each variant based on tag. * Similar to fold but with stronger type safety for tag-based variants. * * The return type is inferred from the pattern handlers when not explicitly specified. * * @param patterns - An object containing handler functions for each variant * @returns The result of applying the matching handler function */ match(patterns: Record R>): R; } /** * Utility functions for working with Matchable data structures */ declare const MatchableUtils: { /** * Helper function to create a default case for pattern matching * * @param handler - The default handler function to apply * @returns A function that always applies the default handler */ default: (handler: (value: A) => R) => (value: A) => R; /** * Helper function to create a match pattern that guards based on a predicate * * @param predicate - The predicate function for guarding * @param handler - The handler function to apply if the predicate passes * @returns A function that applies the handler only if the predicate passes */ when: (predicate: (value: A) => boolean, handler: (value: A) => R) => (value: A) => R | undefined; }; //#endregion //#region src/traversable/Traversable.d.ts /** * Traversable typeclass for data structures that can be traversed through. * * Covariance: A is declared ``. Query (`contains`) accepts `unknown` — * mirroring Scala's `contains(elem: Any)` — so an unrelated-type arg is a * sound `false` rather than a type error. Aggregations (`reduce`, `reduceRight`) * widen the accumulator via ``, matching Scala's `reduce[B >: A]`; when * called without an explicit type arg the behavior is identical to the pre-0.59 * signature, so existing call sites compile unchanged. * * Implementers that previously overrode these methods with the widened shape * (List, Set) can inherit from this base without a per-type override. */ interface Traversable extends AsyncMonad { get size(): number; get isEmpty(): boolean; contains(value: unknown): boolean; reduce(op: (b: Widen, a: Widen) => Widen): Widen; reduceRight(op: (b: Widen, a: Widen) => Widen): Widen; } //#endregion //#region src/functype/Functype.d.ts /** * Base interface for all functype data structures. * This provides a standard contract with core functional programming traits. * * @typeParam A - The type of value contained in the functor * @typeParam Tag - The type tag for pattern matching (e.g., "Some" | "None" for Option) * * @example * ```typescript * // Implementing FunctypeBase for a custom data structure * class MyContainer implements FunctypeBase { * // Implementation of all required methods... * } * ``` */ interface FunctypeBase extends AsyncMonad, Traversable, Serializable, Foldable, Typeable, ContainerOps { readonly _tag: Tag; readonly [Symbol.toStringTag]: string; } /** * Interface for single-value containers like Option, Either, Try. * Extends FunctypeBase with extraction methods and Pipe. * * @typeParam A - The type of value contained * @typeParam Tag - The type tag for pattern matching */ interface Functype extends FunctypeBase, Extractable, Pipe, Matchable { toValue(): { _tag: Tag; value: A; }; } /** * A version of Functype for collection types that need iteration support. * Extends FunctypeBase with Iterable protocol but without Extractable. * * @typeParam A - The element type of the collection * @typeParam Tag - The type tag for pattern matching */ interface FunctypeCollection extends Omit, "flatMapAsync" | "flatMap">, Iterable, Pipe, Collection, CollectionOps> { toValue(): { _tag: Tag; value: A[]; }; flatMap(f: (value: A) => Iterable): FunctypeCollection; flatMapAsync(f: (value: A) => PromiseLike>): PromiseLike>; } //#endregion //#region src/functype/FunctypeSum.d.ts /** * Base interface for sum-type containers (Either, Try, etc.) that are NOT iterables. * * Unlike `FunctypeBase`, this base deliberately excludes `Traversable` — which bundles * `reduce` / `reduceRight` / `size` / `isEmpty`. Those methods force A-invariance on their * containers (signature `(f: (A, A) => A) => A` puts A in both contravariant and covariant * positions) and have no semantic meaning for disjoint-union types where the "success" * branch is 0-or-1, not a collection. * * Sum types that extend `FunctypeSum` can be declared covariant in their type parameter * (`interface Foo`) without structural check failures. This mirrors Scala's model: * `Either[+L, +R]` and `Try[+T]` do not extend `Iterable`; only `Option[+A]` extends the * lighter `IterableOnce[+A]`. * * Only the covariance-safe subset of `ContainerOps` is included inline: `contains`, * `exists`, and `forEach` all place A only in contravariant (callback input) position. * `find` (returns `Option`) and `count` are intentionally omitted — if a sum type * needs them it can declare them directly. * * @typeParam A - the type of the "success" branch value * @typeParam Tag - the discriminant tag (e.g., `"Left" | "Right"`, `"Success" | "Failure"`) */ interface FunctypeSum extends AsyncMonad, Foldable, Serializable, Typeable { readonly _tag: Tag; readonly [Symbol.toStringTag]: string; contains(value: A): boolean; exists(p: (a: A) => boolean): boolean; forEach(f: (a: A) => void): void; } //#endregion //#region src/branded/ValidatedBrand.d.ts type ValidatedBrand = Brand & { readonly __validated: true; }; interface ValidatedBrandCompanion { readonly brand: K; readonly validate: (value: T) => boolean; readonly of: (value: T) => Option>; readonly from: (value: T) => Either>; readonly unsafeOf: (value: T) => ValidatedBrand; readonly is: (value: unknown) => value is ValidatedBrand; readonly unwrap: (branded: Brand) => T; readonly refine: (brand: K2, validate: (value: Brand) => boolean) => ValidatedBrandCompanion>; } /** * Create a validated brand with runtime validation * @example * const Email = ValidatedBrand("Email", (s: string) => /^[^@]+@[^@]+\.[^@]+$/.test(s)) * const email = Email.of("user@example.com") // Some(Brand<"Email", string>) * * @example * // With Either for error messages * const Port = ValidatedBrand("Port", (n: number) => n >= 1 && n <= 65535) * const result = Port.from(8080) // Right(Brand<"Port", number>) * const error = Port.from(70000) // Left("Invalid Port: validation failed") * * @example * // Type guard usage * const value: unknown = "test@example.com" * if (Email.is(value)) { * // value is Brand<"Email", string> * } * * @example * // Best Practice: Use same brand name for seamless conversion * // ValidatedBrand extends Brand, so when using the same brand name, * // no casting is needed for conversion * const ValidatedUserId = ValidatedBrand("UserId", (s: string) => s.length > 0) * type ValidatedUserId = ReturnType extends Option ? T : never * type UserId = Brand<"UserId", string> * * const toSimpleUserId = (id: ValidatedUserId): UserId => id // No cast needed! * * // Avoid different brand names which require casting: * // ❌ ValidatedBrand("ValidatedUserId", ...) + Brand<"UserId", string> * // ✅ ValidatedBrand("UserId", ...) + Brand<"UserId", string> */ declare function ValidatedBrand(brand: K, validate: (value: T) => boolean): ValidatedBrandCompanion; /** * Positive number brand (> 0) * @example * const price = PositiveNumber.of(19.99) // Some(Brand<"PositiveNumber", number>) * const invalid = PositiveNumber.of(-5) // None * const checked = PositiveNumber.from(0) // Left("Invalid PositiveNumber: validation failed") */ declare const PositiveNumber: ValidatedBrandCompanion<"PositiveNumber", number>; declare const NonNegativeNumber: ValidatedBrandCompanion<"NonNegativeNumber", number>; declare const IntegerNumber: ValidatedBrandCompanion<"IntegerNumber", number>; declare const PositiveInteger: ValidatedBrandCompanion<"PositiveInteger", Brand<"PositiveNumber", number>>; /** * Non-empty string brand * @example * const name = NonEmptyString.of("John") // Some(Brand<"NonEmptyString", string>) * const empty = NonEmptyString.of("") // None */ declare const NonEmptyString: ValidatedBrandCompanion<"NonEmptyString", string>; /** * Email address brand with basic validation * @example * const email = EmailAddress.of("user@example.com") // Some(Brand<"EmailAddress", string>) * const invalid = EmailAddress.of("not-an-email") // None * * @example * // Using with forms * const processEmail = (input: string) => { * return EmailAddress.from(input) * .map(email => sendWelcomeEmail(email)) * .orElse("Invalid email address") * } */ declare const EmailAddress: ValidatedBrandCompanion<"EmailAddress", string>; declare const UrlString: ValidatedBrandCompanion<"UrlString", string>; declare const UUID: ValidatedBrandCompanion<"UUID", string>; declare const ISO8601Date: ValidatedBrandCompanion<"ISO8601Date", string>; /** * Create a number brand with min/max bounds * @example * const Percentage = BoundedNumber("Percentage", 0, 100) * const valid = Percentage.of(75) // Some(Brand<"Percentage", number>) * const invalid = Percentage.of(150) // None * * @example * const Port = BoundedNumber("Port", 1, 65535) * const httpPort = Port.unsafeOf(80) // Brand<"Port", number> * // Port.unsafeOf(70000) // throws Error */ declare function BoundedNumber(brand: string, min: number, max: number): ValidatedBrandCompanion; /** * Create a string brand with length constraints * @example * const Username = BoundedString("Username", 3, 20) * const valid = Username.of("johndoe") // Some(Brand<"Username", string>) * const tooShort = Username.of("jo") // None * const tooLong = Username.of("verylongusernamethatexceedslimit") // None */ declare function BoundedString(brand: string, minLength: number, maxLength: number): ValidatedBrandCompanion; /** * Create a string brand that matches a regex pattern * @example * const HexColor = PatternString("HexColor", /^#[0-9a-f]{6}$/i) * const red = HexColor.of("#ff0000") // Some(Brand<"HexColor", string>) * const invalid = HexColor.of("red") // None * * @example * const PhoneNumber = PatternString("PhoneNumber", /^\+?[1-9]\d{1,14}$/) * const phone = PhoneNumber.from("+1234567890") * .map(p => formatPhoneNumber(p)) * .orElse("Invalid phone number") */ declare function PatternString(brand: string, pattern: RegExp): ValidatedBrandCompanion; //#endregion //#region src/core/base/Base.d.ts /** * Base Object from which most other objects inherit * Now includes automatic Do-notation support via doUnwrap method * @param type - The type name for the object * @param body - The implementation body */ declare function Base>(type: string, body: T): T & { toString(): string; doUnwrap(): DoResult; _tag: string; }; //#endregion //#region src/core/throwable/Throwable.d.ts /** * The identifier name for Throwable type */ declare const NAME: "Throwable"; /** * @internal */ type ThrowableType = Error & Typeable & { readonly data?: unknown; readonly cause?: Error; readonly taskInfo?: { name: string; description: string; }; }; declare class Throwable extends Error implements ThrowableType { readonly _tag: typeof NAME; readonly data?: unknown; readonly cause?: Error; readonly taskInfo?: { name: string; description: string; }; protected constructor(message: string, options?: { data?: unknown | undefined; cause?: Error | undefined; stack?: string | undefined; taskInfo?: { name: string; description: string; } | undefined; }); static apply(srcError: unknown, data?: unknown, taskInfo?: { name: string; description: string; }): ThrowableType; } //#endregion //#region src/core/task/Task.d.ts /** * Type definition for errors with a _tag property that identifies them as Throwables */ type TaggedThrowable = Error & { _tag: "Throwable"; cause?: Error; taskInfo?: { name: string; description: string; }; }; /** * Type guard to check if an error is a TaggedThrowable */ declare function isTaggedThrowable(error: unknown): error is TaggedThrowable; interface TaskParams { readonly name?: string; readonly description?: string; } interface TaskMetadata { readonly name: string; readonly description: string; } interface TaskOutcome extends FunctypeBase, Extractable, AsyncMonad, Promisable, Doable { readonly _tag: "Ok" | "Err"; readonly _meta: TaskMetadata; readonly value?: T; readonly error?: Throwable; readonly map: (f: (value: T) => U) => TaskOutcome; readonly flatMap: (f: (value: T) => TaskOutcome | Either) => TaskOutcome; readonly ap: (ff: TaskOutcome<(value: T) => U>) => TaskOutcome; readonly mapAsync: (f: (value: T) => Promise) => Promise>; readonly flatMapAsync: (f: (value: T) => Promise>) => Promise>; readonly mapError: (f: (error: Throwable) => Throwable) => TaskOutcome; recover(value: U): Ok; recoverWith(f: (error: Throwable) => U): Ok; readonly isSuccess: () => this is Ok; readonly isFailure: () => this is Err; readonly isOk: () => this is Ok; readonly isErr: () => this is Err; readonly toEither: () => Either; readonly toTry: () => Try; readonly toOption: () => Option; readonly toList: () => List; readonly fold: (onErr: (error: Throwable) => U, onOk: (value: T) => U) => U; readonly match: (patterns: { Ok: (value: T) => U; Err: (error: Throwable) => U; }) => U; /** * Custom JSON serialization. Ok emits `{"@functype":"Task","_tag":"Ok","value":T}`. * Err emits `{"@functype":"Task","_tag":"Err","error":SerializedError}` capturing the * Throwable's name, message, stack, and cause chain. See error-envelope.ts — * `instanceof` does NOT survive round-trip but `error.name` does. */ toJSON(): { "@functype": "Task"; _tag: "Ok"; value: T; } | { "@functype": "Task"; _tag: "Err"; error: SerializedError; }; } interface Ok extends TaskOutcome { readonly _tag: "Ok"; readonly value: T; readonly error: undefined; } interface Err extends TaskOutcome { readonly _tag: "Err"; readonly value: undefined; readonly error: Throwable; } type TaskSuccess = Ok; type TaskFailure = Err; /** * Err constructor - Creates a failed TaskOutcome * @param error - The error object * @param data - Additional data related to the error * @param params - Task parameters */ declare const Err: (error: unknown, data?: unknown, params?: TaskParams) => Err; /** * Ok constructor - Creates a successful TaskOutcome * @param data - The successful value * @param params - Task parameters */ declare const Ok: (data: T, params?: TaskParams) => Ok; type TaskResult = Promise>; /** * The CancellationToken is a control structure that allows long-running tasks to be cancelled * Cancellation is cooperative, meaning the task must check the token and respond to cancellation requests */ type CancellationToken = { /** Whether the token has been cancelled */ readonly isCancelled: boolean; /** Signal that can be used with fetch and other abortable APIs */ readonly signal: AbortSignal; /** Register a callback to be called when cancellation occurs */ onCancel(callback: () => void): void; }; /** * Create a cancellation token and controller * The controller can be used to cancel operations that use the token */ type CancellationTokenSource = { /** The token to be passed to cancellable operations */ readonly token: CancellationToken; /** Cancel all operations using this token */ cancel(): void; }; /** * Create a cancellation token source * @returns A CancellationTokenSource that can be used to create and control cancellation tokens */ declare const createCancellationTokenSource: () => CancellationTokenSource; type Sync = TaskOutcome; type Async = TaskResult; declare const Task$1: ((params?: TaskParams) => { _type: string; /** * Run an async operation with explicit try/catch/finally semantics * Returns a raw Promise that can interact with traditional Promise-based code * * @param t - The main operation function that returns a value or Promise * @param e - Optional error handler function * @param f - Optional finally handler function * @param cancellationToken - Optional token for cancellation support */ Async: (t: () => U | Promise | TaskOutcome | Promise>, e?: (error: unknown) => unknown | TaskOutcome, f?: () => Promise | void, cancellationToken?: CancellationToken) => Promise>; /** * Run a synchronous operation with explicit try/catch/finally semantics * Returns a TaskOutcome for functional error handling * * @param t - The main operation function that returns a value * @param e - Optional error handler function * @param f - Optional finally handler function */ Sync: (t: () => U, e?: (error: unknown) => unknown, f?: () => void) => TaskOutcome; /** * Run an async operation with progress tracking capabilities * Returns a Promise and provides progress updates via callback * * @param t - The main operation that receives a progress updater function * @param onProgress - Callback that receives progress updates (0-100) * @param e - Optional error handler function * @param f - Optional finally handler function * @param cancellationToken - Optional token for cancellation support */ AsyncWithProgress: (t: (updateProgress: (percent: number) => void) => U | Promise | TaskOutcome | Promise>, onProgress: (percent: number) => void, e?: (error: unknown) => unknown | TaskOutcome, f?: () => Promise | void, cancellationToken?: CancellationToken) => Promise>; toString(): string; doUnwrap(): DoResult; _tag: string; }) & { /** * Create a successful Task result */ success: (data: T, params?: TaskParams) => Ok; /** * Create a failed Task result */ fail: (error: unknown, data?: unknown, params?: TaskParams) => Err; /** * Create a successful Task result (alias for success) * Preferred for new code */ ok: (data: T, params?: TaskParams) => Ok; /** * Create a failed Task result (alias for fail) * Preferred for new code */ err: (error: unknown, data?: unknown, params?: TaskParams) => Err; /** * Reconstruct a TaskOutcome from a JSON envelope emitted by `serialize().toJSON()` * or instance `toJSON()`. Verifies `@functype === "Task"` and dispatches on `_tag`. * * Err reconstruction goes through `deserializeError` so `name`/`message`/`stack`/`cause` * survive; the resulting Throwable carries the deserialized Error as its underlying * error (subclass identity does NOT round-trip — see error-envelope.ts). */ fromJSON: (json: string) => TaskOutcome; /** * Create TaskOutcome from Either * @param either - Either to convert * @param params - Task parameters */ fromEither: (either: Either, params?: TaskParams) => TaskOutcome; /** * Create TaskOutcome from Try * @param tryValue - Try to convert * @param params - Task parameters */ fromTry: (tryValue: Try, params?: TaskParams) => TaskOutcome; /** * Extract the error chain from a Throwable error * Returns an array of errors from outermost to innermost * * @param error - The error to extract the chain from * @returns An array of errors in the chain, from outermost to innermost */ getErrorChain: (error: Error | undefined) => Error[]; /** * Format the error chain as a string with the option to include task details * * @param error - The error to format * @param options - Formatting options * @returns A formatted string representation of the error chain */ formatErrorChain: (error: Error | undefined, options?: { includeTasks?: boolean; separator?: string; includeStackTrace?: boolean; }) => string; /** * Convert a Promise-returning function to a Task-compatible function */ fromPromise: (promiseFn: (...args: Args) => Promise, params?: TaskParams) => ((...args: Args) => Promise>); /** * Convert a Task result to a Promise */ toPromise: (taskOutcome: TaskOutcome) => Promise; /** * Race multiple tasks and return the result of the first one to complete * Optionally specify a timeout after which the race will fail * * @param tasks - Array of tasks to race (as Promises) * @param timeoutMs - Optional timeout in milliseconds * @param params - Task parameters for the race operation * @returns A promise that resolves with the first task to complete or rejects if all tasks fail */ race: (tasks: Array | Promise>>, timeoutMs?: number, params?: TaskParams) => Promise>; /** * Convert a Node.js style callback function to a Task-compatible function * Node.js callbacks typically have the signature (error, result) => void * * @param nodeFn - Function that accepts a Node.js style callback * @param params - Task parameters * @returns A function that returns a Promise */ fromNodeCallback: (nodeFn: (...args: [...Args, (error: unknown, result: T) => void]) => void, params?: TaskParams) => ((...args: Args) => Promise>); /** * Create a cancellation token source * @returns A cancellation token source that can be used to control task cancellation */ createCancellationTokenSource: () => CancellationTokenSource; /** * Create a task that can be cancelled * * @param task - The task function to make cancellable * @param params - Task parameters * @returns An object with the task and a function to cancel it */ cancellable: (task: (token: CancellationToken) => Promise | Promise>, params?: TaskParams) => { task: Promise>; cancel: () => void; }; /** * Creates a task with progress tracking * * @param task - The task function that accepts a progress updater * @param onProgress - Callback function that receives progress updates * @param params - Task parameters * @returns An object with the task, cancel function, and current progress */ withProgress: (task: (updateProgress: (percent: number) => void, token: CancellationToken) => Promise | Promise>, onProgress?: (percent: number) => void, params?: TaskParams) => { task: Promise>; cancel: () => void; currentProgress: () => number; }; }; type Task$1 = ReturnType; //#endregion //#region src/decoder/DecoderError.d.ts /** * Recursive decoder error. * * `Leaf` represents a single decode failure at some `path` in the input. * `Composite` aggregates child failures (one per failed field of an object, * one per failed element of a list, etc.) and mirrors the structural shape * of the input — making it possible to render `user.name: expected string` * alongside `user.age: expected number` from a single response. * * Accumulation lives in the data, not in the wrapper. Combinators in * `DecoderCompanion` (object/list/map) produce `Composite` when more than * one child decoder fails, unwrapping single-child composites back to a * `Leaf` for cleaner error messages. The plain `Either` * return type of `Decoder` keeps composition with the rest of the * library uniform. * * Named `DecoderError` (not `DecodeError`) to avoid collision with the * existing `HttpError.DecodeError` variant — these are at different layers: * the HTTP variant is the outer wrapper, this is the structural inner cause. */ type DecoderError = DecoderErrorLeaf | DecoderErrorComposite; type DecoderErrorLeaf = { readonly _tag: "Leaf"; readonly path: ReadonlyArray; readonly message: string; readonly cause?: unknown; }; type DecoderErrorComposite = { readonly _tag: "Composite"; readonly path: ReadonlyArray; readonly children: List; }; declare const DecoderError: { readonly _tag: "DecoderError"; } & { leaf: (path: ReadonlyArray, message: string, cause?: unknown) => DecoderErrorLeaf; composite: (path: ReadonlyArray, children: List) => DecoderErrorComposite; isLeaf: (e: DecoderError) => e is DecoderErrorLeaf; isComposite: (e: DecoderError) => e is DecoderErrorComposite; match: (e: DecoderError, patterns: { readonly Leaf: (e: DecoderErrorLeaf) => T; readonly Composite: (e: DecoderErrorComposite) => T; }) => T; prepend: (segment: string, e: DecoderError) => DecoderError; flatten: (e: DecoderError) => List<{ readonly path: ReadonlyArray; readonly message: string; }>; format: (e: DecoderError) => string; }; //#endregion //#region src/decoder/Decoder.d.ts /** * A `Decoder` converts an `unknown` value into either a typed `A` or a * structural `DecoderError`. The shape `(raw) => Either` is * the canonical FP decoder contract (cf. circe `Decoder`, fp-ts `Decoder`, * Effect-TS `Schema.decodeUnknownEither`, Elm `Json.Decode.Decoder`). * * Any function matching this signature IS a decoder — there is no plugin * registration. Zod / TypeBox / Valibot / AJV / hand-rolled adapters are * ~15 lines each. The bundled combinators in `DecoderCompanion` cover the * functype-aware cases (Option, Either, List, etc.) that a generic schema * library cannot express. */ type Decoder$1 = (raw: unknown) => Either; //#endregion //#region src/decoder/index.d.ts /** * A `Decoder` converts an `unknown` value into either a typed `A` or a * structural `DecoderError`. The shape `(raw) => Either` is * the canonical FP decoder contract (cf. circe `Decoder`, fp-ts `Decoder`, * Effect-TS `Schema.decodeUnknownEither`, Elm `Json.Decode.Decoder`). * * Any function matching this signature IS a decoder — there is no plugin * registration. Zod / TypeBox / Valibot / AJV / hand-rolled adapters are * ~15 lines each. The bundled combinators in the `Decoder` value namespace * cover the functype-aware cases (Option, Either, List, etc.) that a * generic schema library cannot express. */ type Decoder = (raw: unknown) => Either; /** * Decoder namespace: combinators for converting `unknown` into typed values. * * - `Decoder.string` / `.number` / `.boolean` / `.unknown` / `.nullable(inner)` — leaf primitives * - `Decoder.option(inner)` — null-bias Option (null → None, else inner → Some) * - `Decoder.either.envelope({ok, err})` / `.discriminated({...}, l, r)` — Either variants * - `Decoder.list(inner)` / `.array(inner)` / `.map(inner)` / `.object(shape)` — composites; accumulate child failures * - `Decoder.tagged.option/either/try/list/map/obj(inner?)` — round-trip the `{_tag, value}` shape * used by functype's built-in `.toJSON()` (for functype-to-functype services) */ declare const Decoder: { readonly _tag: "Decoder"; } & { tagged: { option: (inner: Decoder$1) => Decoder$1>; either: (left: Decoder$1, right: Decoder$1) => Decoder$1>; try: (inner: Decoder$1) => Decoder$1>; list: (inner: Decoder$1) => Decoder$1>; map: (inner: Decoder$1) => Decoder$1>; obj: >(shape: { [K in keyof T]: Decoder$1; }) => Decoder$1; }; string: Decoder$1; number: Decoder$1; boolean: Decoder$1; unknown: Decoder$1; nullable: (inner: Decoder$1) => Decoder$1; option: (inner: Decoder$1) => Decoder$1>; either: { envelope: (shape: { ok: Decoder$1; err: Decoder$1; }) => Decoder$1>; discriminated: (config: { tag: string; leftTag: string; rightTag: string; }, left: Decoder$1, right: Decoder$1) => Decoder$1>; }; list: (inner: Decoder$1) => Decoder$1>; array: (inner: Decoder$1) => Decoder$1; map: (inner: Decoder$1) => Decoder$1>; object: >(shape: { [K in keyof T]: Decoder$1; }) => Decoder$1; }; //#endregion //#region src/do/index.d.ts type OptionLike = { _tag: "Some" | "None"; isSome(): boolean; get(): unknown; }; type EitherLike = { _tag: "Left" | "Right"; isLeft(): boolean; isRight(): boolean; value: unknown; }; type ListLike = { _tag: "List"; toArray(): unknown[]; }; type TryLike = { _tag: "Success" | "Failure"; isSuccess(): boolean; get(): unknown; }; /** * Executes a generator-based monadic comprehension * Returns the same monad type as the first yielded monad (Scala semantics) * * - Option comprehensions return Option (None on short-circuit) * - Either comprehensions return Either (Left with error on short-circuit) * - List comprehensions return List (empty or cartesian product) * - Try comprehensions return Try (Failure with error on short-circuit) * * Type Inference Notes: * - TypeScript infers the correct return type for homogeneous comprehensions * - For mixed monad types, TypeScript returns a union type * - Use DoTyped or type assertions for mixed scenarios * * @example * ```typescript * // Option comprehension returns Option: * const result = Do(function* () { * const x = yield* $(Option(5)); * const y = yield* $(Option(10)); * return x + y; * }); * // result: Option(15) * * // Either comprehension returns Either: * const result = Do(function* () { * const x = yield* $(Right(5)); * const y = yield* $(Left("error")); * return x + y; * }); * // result: Left("error") - error is preserved * * // List comprehension returns List with cartesian product: * const result = Do(function* () { * const x = yield* $(List([1, 2])); * const y = yield* $(List([3, 4])); * return x + y; * }); * // result: List([4, 5, 5, 6]) * * // Mixed types - use type assertion or DoTyped: * const result = Do(function* () { * const x = yield* $(Option(5)); * const y = yield* $(Right(10)); * return x + y; * }) as Option; * // result: Option(15) * ``` * * @param gen - Generator function that yields monads and returns a result * @returns The same monad type as the first yield */ declare function Do(gen: () => Generator): Option; declare function Do(gen: () => Generator): Either; declare function Do(gen: () => Generator): List; declare function Do(gen: () => Generator): Try; declare function Do(gen: () => Generator): Reshapeable; declare function Do(gen: () => Generator): unknown; /** * Executes an async generator-based monadic comprehension * Returns the same monad type as the first yielded monad * * @example * ```typescript * const result = await DoAsync(async function* () { * const user = yield* $(await fetchUser(id)); // Promise> → User * const profile = yield* $(await getProfile(user)); // Promise> → Profile * return { user, profile }; * }); * // result type matches first yield * ``` * * @param gen - Async generator function that yields monads/promises and returns a result * @returns Promise of the same monad type as first yield */ declare function DoAsync(gen: () => AsyncGenerator): Promise>; declare function DoAsync(gen: () => AsyncGenerator): Promise>; declare function DoAsync(gen: () => AsyncGenerator): Promise>; declare function DoAsync(gen: () => AsyncGenerator): Promise>; declare function DoAsync(gen: () => AsyncGenerator): Promise>; declare function DoAsync(gen: () => AsyncGenerator): Promise; /** * Helper function to check if a value implements the Doable interface * @param value - Value to check * @returns True if the value implements Doable */ declare function isDoCapable(value: unknown): value is Doable; /** * Manually unwrap a monad using the Doable interface * Useful for testing or when you need to unwrap outside of a Do-comprehension * * @param monad - Monad to unwrap * @returns The unwrapped value * @throws Error if the monad cannot be unwrapped */ declare function unwrap(monad: Doable): T; /** * Type helper for Do-notation generators. * Provides better type hints in IDEs. * * @example * ```typescript * const result = Do(function* (): DoGenerator { * const x = yield* $(List([1, 2])) // x is still unknown but return type is clear * const y = yield* $(List([3, 4])) * return x + y * }) * ``` */ type DoGenerator = Generator; /** * Extracts values from monads in Do-notation with type inference. * The '$' symbol is the universal extraction operator in functional programming. * * @example * ```typescript * const result = Do(function* () { * const x = yield* $(Option(5)) // x: number * const y = yield* $(List([1, 2, 3])) // y: number (for cartesian product) * const name = yield* $(Right("Alice")) // name: string * return `${name}: ${x + y}` * }) * ``` * * @param monad - Any monad that can be unwrapped (Option, Either, List, Try, etc.) * @returns A generator that yields the monad and returns its extracted value */ declare function $(monad: Option): Generator, T, T>; declare function $(monad: Either): Generator, R, R>; declare function $(monad: List): Generator, T, T>; declare function $(monad: Try): Generator, T, T>; declare function $(monad: Doable): Generator, T, T>; declare function $(monad: M): Generator, InferYieldType>; type InferYieldType = M extends { isSome(): boolean; get(): infer T; } ? T : M extends { isRight(): boolean; value: infer R; } ? R : M extends { toArray(): (infer T)[]; } ? T : M extends { isSuccess(): boolean; get(): infer T; } ? T : M extends Doable ? T : unknown; declare const NoneError: (message?: string) => Error; interface LeftErrorType extends Error { value: L; } declare const LeftError: (value: L, message?: string) => LeftErrorType; declare const EmptyListError: (message?: string) => Error; interface FailureErrorType extends Error { cause: Error; } declare const FailureError: (cause: Error, message?: string) => FailureErrorType; //#endregion //#region src/error/ErrorFormatter.d.ts /** * Type definition for task information that may be attached to errors */ type TaskErrorInfo = { name?: string; description?: string; [key: string]: unknown; }; /** * Type definition for an error with potential task information */ type ErrorWithTaskInfo = Error & { taskInfo?: TaskErrorInfo; data?: unknown; }; /** * Type definition for a structured error chain element */ type ErrorChainElement = { message?: string; name?: string; taskInfo?: TaskErrorInfo; stack?: string; [key: string]: unknown; }; /** * Options for formatting error chains */ type ErrorFormatterOptions = { /** Include task names in the formatted output */ includeTasks?: boolean; /** Include stack traces in the formatted output */ includeStackTrace?: boolean; /** Separator between error lines (default: newline) */ separator?: string; /** Include detailed error data in the output */ includeData?: boolean; /** Maximum number of stack frames to include if stack trace is enabled */ maxStackFrames?: number; /** Title to display at the start of the formatted error */ title?: string; /** Format the output with colors for console display */ colors?: boolean; }; /** * Safely stringify data including BigInt values and circular references */ declare function safeStringify(obj: unknown): string; /** * Format a stack trace string for better readability */ declare function formatStackTrace(stack: string | undefined): string; /** * Create a formatted string representation of an error for better logging and display * * @example * ```typescript * const error = new Error("Something went wrong"); * console.error(formatError(error, { colors: true, includeData: true })); * ``` */ declare function formatError(error: unknown, options?: ErrorFormatterOptions): string; /** * Create a serializer function for Pino or other JSON loggers * to better represent errors with their full context */ declare function createErrorSerializer(): (err: unknown) => unknown; //#endregion //#region src/error/typed/TypedError.d.ts /** * Type-safe error codes using template literal types */ type ErrorCode = "VALIDATION_FAILED" | "NETWORK_ERROR" | "AUTH_REQUIRED" | "NOT_FOUND" | "PERMISSION_DENIED" | "RATE_LIMITED" | "INTERNAL_ERROR" | "BAD_REQUEST" | "CONFLICT" | "TIMEOUT"; /** * Template literal type for error messages based on error code */ type ErrorMessage = T extends "VALIDATION_FAILED" ? `Validation failed: ${string}` : T extends "NETWORK_ERROR" ? `Network error: ${string}` : T extends "AUTH_REQUIRED" ? `Authentication required: ${string}` : T extends "NOT_FOUND" ? `Not found: ${string}` : T extends "PERMISSION_DENIED" ? `Permission denied: ${string}` : T extends "RATE_LIMITED" ? `Rate limit exceeded: ${string}` : T extends "INTERNAL_ERROR" ? `Internal server error: ${string}` : T extends "BAD_REQUEST" ? `Bad request: ${string}` : T extends "CONFLICT" ? `Conflict: ${string}` : T extends "TIMEOUT" ? `Request timeout: ${string}` : never; /** * HTTP status codes mapped to error codes */ type ErrorStatus = T extends "VALIDATION_FAILED" | "BAD_REQUEST" ? 400 : T extends "AUTH_REQUIRED" ? 401 : T extends "PERMISSION_DENIED" ? 403 : T extends "NOT_FOUND" ? 404 : T extends "CONFLICT" ? 409 : T extends "RATE_LIMITED" ? 429 : T extends "TIMEOUT" ? 408 : T extends "INTERNAL_ERROR" ? 500 : T extends "NETWORK_ERROR" ? 503 : 500; /** * Context type for each error code */ type TypedErrorContext = T extends "VALIDATION_FAILED" ? { field: string; value: unknown; rule: string; } : T extends "NETWORK_ERROR" ? { url: string; method: string; statusCode?: number; } : T extends "AUTH_REQUIRED" ? { resource: string; requiredRole?: string; } : T extends "NOT_FOUND" ? { resource: string; id: string | number; } : T extends "PERMISSION_DENIED" ? { action: string; resource: string; userId?: string; } : T extends "RATE_LIMITED" ? { limit: number; window: string; retryAfter?: number; } : T extends "INTERNAL_ERROR" ? { errorId: string; timestamp: string; } : T extends "BAD_REQUEST" ? { reason: string; expected?: string; } : T extends "CONFLICT" ? { resource: string; conflictingValue: string; } : T extends "TIMEOUT" ? { duration: number; operation: string; } : Record; /** * Type-safe error class with template literal types */ interface TypedError extends Throwable { readonly code: T; readonly message: ErrorMessage; readonly status: ErrorStatus; readonly context: TypedErrorContext; readonly timestamp: string; readonly traceId?: string; } declare const TypedError: ((code: T, message: ErrorMessage, context: TypedErrorContext, options?: { cause?: unknown; traceId?: string; }) => TypedError) & { /** * Create a validation error * @example * const error = TypedError.validation("email", "test@", "must be valid email") * // Type: TypedError<"VALIDATION_FAILED"> * // Message must match: "Validation failed: ..." */ validation: (field: string, value: unknown, rule: string) => TypedError<"VALIDATION_FAILED">; /** * Create a network error * @example * const error = TypedError.network("https://api.example.com", "POST", 500) * // Type: TypedError<"NETWORK_ERROR"> */ network: (url: string, method: string, statusCode?: number) => TypedError<"NETWORK_ERROR">; /** * Create an authentication error * @example * const error = TypedError.auth("/api/admin", "admin") * // Type: TypedError<"AUTH_REQUIRED"> */ auth: (resource: string, requiredRole?: string) => TypedError<"AUTH_REQUIRED">; /** * Create a not found error * @example * const error = TypedError.notFound("user", "123") * // Type: TypedError<"NOT_FOUND"> */ notFound: (resource: string, id: string | number) => TypedError<"NOT_FOUND">; /** * Create a permission denied error * @example * const error = TypedError.permission("delete", "post", "user123") * // Type: TypedError<"PERMISSION_DENIED"> */ permission: (action: string, resource: string, userId?: string) => TypedError<"PERMISSION_DENIED">; /** * Create a rate limit error * @example * const error = TypedError.rateLimit(100, "1h", 3600) * // Type: TypedError<"RATE_LIMITED"> */ rateLimit: (limit: number, window: string, retryAfter?: number) => TypedError<"RATE_LIMITED">; /** * Create an internal error * @example * const error = TypedError.internal("ERR-500-ABC123") * // Type: TypedError<"INTERNAL_ERROR"> */ internal: (errorId: string) => TypedError<"INTERNAL_ERROR">; /** * Create a bad request error * @example * const error = TypedError.badRequest("Invalid JSON", "valid JSON object") * // Type: TypedError<"BAD_REQUEST"> */ badRequest: (reason: string, expected?: string) => TypedError<"BAD_REQUEST">; /** * Create a conflict error * @example * const error = TypedError.conflict("email", "user@example.com") * // Type: TypedError<"CONFLICT"> */ conflict: (resource: string, conflictingValue: string) => TypedError<"CONFLICT">; /** * Create a timeout error * @example * const error = TypedError.timeout(30000, "database query") * // Type: TypedError<"TIMEOUT"> */ timeout: (duration: number, operation: string) => TypedError<"TIMEOUT">; /** * Check if a value is a TypedError */ isTypedError: (value: unknown) => value is TypedError; /** * Check if a TypedError has a specific code */ hasCode: (error: TypedError, code: T) => error is TypedError; }; //#endregion //#region src/error/typed/Validation.d.ts /** * Validation rule types using template literal types */ type ValidationRule = `min:${number}` | `max:${number}` | `minLength:${number}` | `maxLength:${number}` | `pattern:${string}` | `email` | `url` | `uuid` | `required` | `numeric` | `alpha` | `alphanumeric` | `date` | `future` | `past` | `in:${string}` | `notIn:${string}`; /** * Validator function type */ type Validator = (value: unknown) => Either, T>; /** * Field validation result */ type FieldValidation = { field: string; value: unknown; result: Either, T>; }; /** * Form validation result */ type FormValidation> = Either>, T>; declare const Validation: ((rule: ValidationRule) => Validator) & { /** * Common pre-built validators */ validators: { email: Validator; url: Validator; uuid: Validator; required: Validator; numeric: Validator; positiveNumber: Validator; nonEmptyString: Validator; }; /** * Create a validator from a rule string * @example * const validator = Validation.rule("min:18") * const result = validator(25) // Right(25) * const error = validator(15) // Left(TypedError) */ rule: (rule: ValidationRule) => Validator; /** * Combine multiple validators * @example * const validator = Validation.combine( * Validation.rule("required"), * Validation.rule("email"), * Validation.rule("maxLength:100") * ) */ combine: (...validators: Validator[]) => Validator; /** * Create a custom validator * @example * const isEven = Validation.custom( * (value) => typeof value === "number" && value % 2 === 0, * "must be an even number" * ) */ custom: (predicate: (value: unknown) => boolean, errorMessage: string) => Validator; /** * Validate a form with multiple fields * @example * const schema = { * name: Validation.rule("required"), * email: Validation.rule("email"), * age: Validation.rule("min:18") * } * const result = Validation.form(schema, { name: "John", email: "john@example.com", age: 25 }) */ form: >(schema: { [K in keyof T]: Validator; }, data: Record) => FormValidation; }; //#endregion //#region src/io/Tag.d.ts /** * Tag module - service identifiers for dependency injection. * @module Tag * @category IO * * Tags are used to identify services in a type-safe way. * Each Tag has a unique identifier and carries the type of the service. */ /** * A Tag identifies a service type and provides a unique identifier. * Used for dependency injection with IO effects. * * @typeParam S - The service type this tag identifies * * @example * ```typescript * // Define service interfaces * interface UserService { * getUser(id: string): IO * } * * // Create a tag for the service * const UserService = Tag("UserService") * * // Use in effects * const getUser = (id: string) => * IO.service(UserService).flatMap(svc => svc.getUser(id)) * ``` */ interface Tag { /** * Unique identifier for this tag */ readonly id: string; /** * Phantom type to carry the service type * @internal */ readonly _S?: S; /** * Type brand to distinguish tags * @internal */ readonly _tag: "Tag"; /** * String representation */ toString(): string; } /** * Creates a Tag for identifying a service type. * * @param id - Unique identifier for this tag (usually the service name) * @returns A Tag that can be used to request the service * * @example * ```typescript * interface Logger { * log(message: string): void * } * * const Logger = Tag("Logger") * * // Now Logger can be used to request the Logger service * const program = IO.service(Logger).flatMap(logger => * IO.sync(() => logger.log("Hello!")) * ) * ``` */ declare const Tag: (id: string) => Tag; /** * Type helper to extract the service type from a Tag */ type TagService = T extends Tag ? S : never; //#endregion //#region src/io/Context.d.ts /** * Context module - service container for dependency injection. * @module Context * @category IO * * Context is an immutable container that holds service implementations * identified by their Tags. */ /** * Context holds service implementations for dependency injection. * It's an immutable container that maps Tags to their implementations. * * @typeParam R - The services contained in this context (intersection type) * * @example * ```typescript * const ctx = Context.empty() * .add(Logger, consoleLogger) * .add(Database, pgDatabase) * * // Access a service * const logger = ctx.get(Logger) // Option * const loggerUnsafe = ctx.unsafeGet(Logger) // Logger (throws if missing) * ``` */ interface Context { /** * Type brand * @internal */ readonly _tag: "Context"; /** * Phantom type for requirements * @internal */ readonly _R?: R; /** * Internal service map * @internal */ readonly services: ReadonlyMap; /** * Gets a service from the context. * @param tag - The tag identifying the service * @returns Some(service) if found, None otherwise */ get(tag: Tag): Option; /** * Gets a service from the context, throwing if not found. * @param tag - The tag identifying the service * @returns The service * @throws Error if service not found */ unsafeGet(tag: Tag): S; /** * Checks if a service exists in the context. * @param tag - The tag to check * @returns true if the service exists */ has(tag: Tag): boolean; /** * Adds a service to the context, returning a new context. * @param tag - The tag for the service * @param service - The service implementation * @returns A new context with the service added */ add(tag: Tag, service: S): Context; /** * Merges another context into this one. * @param other - The context to merge * @returns A new context with all services from both */ merge(other: Context): Context; /** * Returns the number of services in this context. */ readonly size: number; /** * String representation */ toString(): string; } /** * Context companion object with utility methods */ declare const Context: { /** * Creates an empty context with no services. */ empty: () => Context; /** * Creates a context with a single service. * @param tag - The tag for the service * @param service - The service implementation */ make: (tag: Tag, service: S) => Context; /** * Checks if a value is a Context. */ isContext: (value: unknown) => value is Context; }; /** * Type helper to extract requirements from a Context */ type ContextServices = C extends Context ? R : never; /** * Type helper to check if a context provides a service */ type HasService = S extends ContextServices ? true : false; //#endregion //#region src/io/Exit.d.ts /** * Exit type module - represents the outcome of running an IO effect. * @module Exit * @category IO */ /** * Possible outcome types for an Exit */ type ExitTag = "Success" | "Failure" | "Interrupted"; /** * Exit represents the outcome of running an IO effect. * - Success: The effect completed successfully with a value * - Failure: The effect failed with a typed error * - Interrupted: The effect was cancelled/interrupted */ interface Exit { readonly [Symbol.toStringTag]: string; readonly _tag: ExitTag; /** * Type guard to check if this is a Success */ isSuccess(): this is Exit & { readonly _tag: "Success"; value: A; }; /** * Type guard to check if this is a Failure */ isFailure(): this is Exit & { readonly _tag: "Failure"; error: E; }; /** * Type guard to check if this is Interrupted */ isInterrupted(): this is Exit & { readonly _tag: "Interrupted"; fiberId: string; }; /** * Maps the success value */ map(f: (a: A) => B): Exit; /** * Maps the error value */ mapError(f: (e: E) => E2): Exit; /** * Maps both error and success values */ mapBoth(onError: (e: E) => E2, onSuccess: (a: A) => B): Exit; /** * Flat maps the success value */ flatMap(f: (a: A) => Exit): Exit; /** * Pattern matches over the Exit */ fold(onFailure: (e: E) => T, onSuccess: (a: A) => T, onInterrupted?: (fiberId: string) => T): T; /** * Pattern matches over the Exit with object patterns */ match(patterns: { Success: (value: A) => T; Failure: (error: E) => T; Interrupted: (fiberId: string) => T; }): T; /** * Returns the success value or throws */ orThrow(): A; /** * Returns the success value or a default */ orElse(defaultValue: A): A; /** * Converts to Option (Some for Success, None otherwise) */ toOption(): Option; /** * Converts to Either (Right for Success, Left for Failure) * Throws if Interrupted */ toEither(): Either; /** * Returns the raw value for inspection */ toValue(): { _tag: ExitTag; value?: A; error?: E; fiberId?: string; }; /** * String representation */ toString(): string; /** * JSON serialization */ toJSON(): { _tag: ExitTag; value?: A; error?: E; fiberId?: string; }; } /** * Exit type for representing effect outcomes. * * @example * ```typescript * const success = Exit.succeed(42) * const failure = Exit.fail(new Error("oops")) * const interrupted = Exit.interrupt("fiber-123") * * success.fold( * (err) => console.error(err), * (value) => console.log(value), * (fiberId) => console.log("interrupted:", fiberId) * ) * ``` */ declare const Exit: ((value: A) => Exit) & { /** * Creates a Success Exit */ succeed: (value: A) => Exit; /** * Creates a Failure Exit */ fail: (error: E) => Exit; /** * Creates an Interrupted Exit with a fiber ID */ interrupt: (fiberId: string) => Exit; /** * Creates an Interrupted Exit with a default fiber ID */ interrupted: () => Exit; /** * Type guard for Success */ isSuccess: (exit: Exit) => exit is Exit & { readonly _tag: "Success"; value: A; }; /** * Type guard for Failure */ isFailure: (exit: Exit) => exit is Exit & { readonly _tag: "Failure"; error: E; }; /** * Type guard for Interrupted */ isInterrupted: (exit: Exit) => exit is Exit & { readonly _tag: "Interrupted"; fiberId: string; }; /** * Creates an Exit from an Either */ fromEither: (either: Either) => Exit; /** * Creates an Exit from an Option */ fromOption: (option: Option, onNone: () => unknown) => Exit; /** * Combines two Exits, keeping the first failure or combining successes */ zip: (exitA: Exit, exitB: Exit) => Exit; /** * Collects all Exits into an Exit of array */ all: (exits: readonly Exit[]) => Exit; }; //#endregion //#region src/io/Layer.d.ts /** * Layer module - service construction recipes. * @module Layer * @category IO * * Layers describe how to construct services, including their dependencies. * They can be composed to build complex service graphs. */ /** * A Layer describes how to build a service or set of services. * * @typeParam RIn - Required services (dependencies) * @typeParam E - Possible errors during construction * @typeParam ROut - Services provided by this layer * * @example * ```typescript * // A layer that provides a Logger service * const LoggerLive = Layer.succeed(Logger, consoleLogger) * * // A layer that requires Config and provides Database * const DatabaseLive = Layer.fromFunction(Database, (config: Config) => * createDatabase(config.connectionString) * ) * ``` */ interface Layer { /** * Type brand * @internal */ readonly _tag: "Layer"; /** * Phantom types * @internal */ readonly _RIn?: RIn; readonly _E?: E; readonly _ROut?: ROut; /** * The build function that creates the context * @internal */ readonly build: (input: Context) => Promise>; /** * Composes this layer with another, running them in sequence. * The output of this layer becomes available to the next layer. * @param that - Layer to compose with */ provideToAndMerge(that: Layer): Layer, E | E2, ROut | ROut2>; /** * Merges two independent layers. * @param that - Layer to merge with */ merge(that: Layer): Layer; /** * Maps the output of this layer. * @param f - Function to transform the output */ map(f: (ctx: Context) => Context): Layer; /** * String representation */ toString(): string; } /** * Layer companion object with construction methods */ declare const Layer: { /** * Creates a layer that provides a service with a constant value. * @param tag - The service tag * @param service - The service implementation */ succeed: (tag: Tag, service: S) => Layer; /** * Creates a layer from an async function. * @param tag - The service tag * @param f - Async function to create the service */ effect: (tag: Tag, f: () => Promise) => Layer; /** * Creates a layer from a sync function. * @param tag - The service tag * @param f - Function to create the service */ sync: (tag: Tag, f: () => S) => Layer; /** * Creates a layer that depends on another service. * @param tag - The service tag to provide * @param depTag - The dependency tag * @param f - Function to create the service from the dependency */ fromService: (tag: Tag, depTag: Tag, f: (dep: Dep) => S) => Layer; /** * Creates a layer that depends on another service (async). * @param tag - The service tag to provide * @param depTag - The dependency tag * @param f - Async function to create the service from the dependency */ fromServiceEffect: (tag: Tag, depTag: Tag, f: (dep: Dep) => Promise) => Layer; /** * Creates a layer from a context. * @param context - The context to use */ fromContext: (context: Context) => Layer; /** * Creates an empty layer that provides nothing. */ empty: () => Layer; /** * Merges multiple layers into one. * @param layers - Layers to merge */ mergeAll: []>(...layers: Layers) => Layer ? RIn : never, Layers[number] extends Layer ? E : never, Layers[number] extends Layer ? ROut : never>; }; /** * Type helper to extract input requirements from a Layer */ type LayerInput = L extends Layer ? RIn : never; /** * Type helper to extract error type from a Layer */ type LayerError = L extends Layer ? E : never; /** * Type helper to extract output services from a Layer */ type LayerOutput = L extends Layer ? ROut : never; //#endregion //#region src/io/IO.d.ts /** * Error thrown when an effect times out. */ declare class TimeoutError extends Error { readonly duration: number; readonly _tag: "TimeoutError"; constructor(duration: number, message?: string); } /** * Error thrown when an effect is interrupted. */ declare class InterruptedError extends Error { readonly _tag: "InterruptedError"; constructor(message?: string); } /** * Error thrown when a combinator that cannot run on the synchronous interpreter is * reached by `runSync`. `timeout` and `race` are inherently asynchronous — there is no * sync semantics for "wait `ms` then give up", or for racing concurrent effects. * * This is a **programmer error, not a domain failure**: it says the effect was built * wrong for the terminal it was run with, so recovery combinators deliberately do not * catch it (see {@link rethrowIfNonRecoverable}). Before it had its own type it was a * plain `Error`, indistinguishable from a failed effect, so any downstream `.recover()` * absorbed it and silently produced the fallback — `IO.succeed(1).timeoutTo(50, 99)` * returned `Right(99)` under `runSync()`. See #246. */ declare class UnsupportedSyncOperationError extends Error { readonly operation: "timeout" | "race"; readonly _tag: "UnsupportedSyncOperationError"; constructor(operation: "timeout" | "race"); } /** * Error surfaced by value-driven repeat combinators when the iteration bound is * reached without the predicate being satisfied. Carries the last observed * value so callers can report what the loop settled on. * * Type parameter `A` is the value type the loop was producing (or the state * type for `IO.iterate`). * * ## Narrowing when `E` is `unknown` * * If the step effect has `E = unknown` (common when lifting a Promise via * `IO(() => ...)` or `IO.async(...)` — see the JSDoc on those constructors), * TypeScript's union algebra collapses `unknown | RepeatExhausted` back to * `unknown`, and `RepeatExhausted` is lost from the surface type. The * runtime behavior is still correct (the `RepeatExhausted` instance is in the * `Left` at runtime — see reporter's JSON in issue #221) — but consumers need * a narrowing step to recover it. Use `RepeatExhausted.is`: * * @example * ```ts * const res = await IO.iterate(seed, step, done, { max: 20 }).run() * res.fold( * (e) => { * if (RepeatExhausted.is(e)) { * // e is now RepeatExhausted; e.lastValue is StepState * return e.lastValue * } * // e is still the collapsed E channel — handle as the caller sees fit * throw e as Error * }, * (settled) => settled, * ) * ``` * * The alternative — annotating `step`'s error channel so `E` is a concrete * tagged type — also works and preserves `RepeatExhausted` in the union: * * @example * ```ts * const step = (s: S): IO => * IO(() => runOnce(s)).mapError((_e) => _e as never) * // iterate result E channel: never | RepeatExhausted === RepeatExhausted * ``` */ declare class RepeatExhausted extends Error { readonly max: number; readonly lastValue?: A | undefined; readonly _tag: "RepeatExhausted"; constructor(max: number, lastValue?: A | undefined, message?: string); /** * Runtime type guard. Narrows an `unknown` (or wider) value to * `RepeatExhausted` when the tag matches. Use this to recover typed * exhaustion when the `E` channel has collapsed to `unknown` — a common * situation when the step effect is lifted from a Promise via `IO(...)` or * `IO.async(...)`. See the class-level JSDoc for a full example. * * The type parameter `A` is an unchecked assertion — the guard confirms the * shape is a `RepeatExhausted`, but cannot verify `lastValue` matches `A` at * runtime. Callers pass the state/value type they expect the loop to have * been producing. */ static is(e: unknown): e is RepeatExhausted; } /** * IO Effect type module - a lazy, composable effect type with typed errors. * @module IO * @category IO * * IO represents an effectful computation that: * - Requires environment R to run * - May fail with error E * - Produces value A on success * * Key features: * - Lazy execution (nothing runs until explicitly executed) * - Unified sync/async API * - Typed errors at compile time * - Composable via map/flatMap */ /** * Unique symbol for the internal effect representation. * Using a symbol key makes IO structurally opaque — TypeScript won't * deeply compare IOEffect types when checking IO assignability. * This allows IO to be assignable to IO * (needed for IO.gen) without deep variance failures on the effect ADT. * @internal */ declare const IOEffectKey: unique symbol; type IOEffectKey = typeof IOEffectKey; /** * Internal effect representation types */ type IOEffect = { readonly _tag: "Sync"; readonly thunk: () => A; } | { readonly _tag: "Async"; readonly thunk: () => Promise; } | { readonly _tag: "Auto"; readonly thunk: () => A | Promise; } | { readonly _tag: "Succeed"; readonly value: A; } | { readonly _tag: "Fail"; readonly error: E; } | { readonly _tag: "Die"; readonly defect: unknown; } | { readonly _tag: "Interrupt"; } | { readonly _tag: "FlatMap"; readonly effect: IO; readonly f: (a: unknown) => IO; } | { readonly _tag: "Map"; readonly effect: IO; readonly f: (a: unknown) => A; } | { readonly _tag: "MapError"; readonly effect: IO; readonly f: (e: unknown) => E; } | { readonly _tag: "Recover"; readonly effect: IO; readonly fallback: A; } | { readonly _tag: "RecoverWith"; readonly effect: IO; readonly f: (e: unknown) => IO; } | { readonly _tag: "Fold"; readonly effect: IO; readonly onFailure: (e: unknown) => A; readonly onSuccess: (a: unknown) => A; } | { readonly _tag: "Bracket"; readonly acquire: IO; readonly use: (a: unknown) => IO; readonly release: (a: unknown) => IO; } | { readonly _tag: "BracketExit"; readonly acquire: IO; readonly use: (a: unknown) => IO; readonly release: (a: unknown, exit: Exit) => IO; } | { readonly _tag: "Race"; readonly effects: readonly IO[]; } | { readonly _tag: "Timeout"; readonly effect: IO; readonly duration: number; } | { readonly _tag: "Service"; readonly tag: Tag; } | { readonly _tag: "ProvideContext"; readonly effect: IO; readonly context: Context; }; /** * IO represents a lazy, composable effect. * * @typeParam R - Requirements (environment/dependencies needed to run) * @typeParam E - Error type (typed failures) * @typeParam A - Success type (value produced on success) */ /** * Minimal marker interface for IO-like values that can be yielded in IO.gen. * Using this instead of IO avoids deep structural variance * failures when yielding IO in generators. * @internal */ interface IOYieldable { readonly [Symbol.toStringTag]: string; } interface IO { readonly [Symbol.toStringTag]: string; /** * Internal effect representation (symbol-keyed for opacity) * @internal */ readonly [IOEffectKey]: IOEffect; /** * Transforms the success value. * @param f - Function to apply to the success value * @returns New IO with transformed value */ map(f: (a: A) => B): IO; /** * Chains another IO effect based on the success value. * @param f - Function returning next IO effect * @returns New IO with combined effects */ flatMap(f: (a: A) => IO): IO; /** * Applies a side effect without changing the value. * @param f - Side effect function * @returns Same IO for chaining */ tap(f: (a: A) => void): IO; /** * Applies an effectful side effect without changing the value. * @param f - Function returning IO for side effect * @returns Same value after running side effect */ tapEffect(f: (a: A) => IO): IO; /** * Transforms the error value. * @param f - Function to apply to the error * @returns New IO with transformed error */ mapError(f: (e: E) => E2): IO; /** * Executes a side effect on the error without changing it. * Useful for logging errors while preserving the error chain. * * @param f - Side effect function to run on error * @returns Same IO with the side effect attached * * @example * ```typescript * const io = IO.asyncResult(() => query(), toError) * .tapError(err => console.error('Query failed:', err)) * .map(data => transform(data)) * ``` */ tapError(f: (e: E) => void): IO; /** * Recovers from any error with a fallback value. * @param fallback - Value to use on error * @returns New IO that never fails */ recover(fallback: B): IO; /** * Recovers from error by running another effect. * @param f - Function returning recovery effect * @returns New IO with error handling */ recoverWith(f: (e: E) => IO): IO; /** * Pattern matches on success and failure. * @param onFailure - Handler for failures * @param onSuccess - Handler for successes * @returns New IO with handled result */ fold(onFailure: (e: E) => B, onSuccess: (a: A) => B): IO; /** * Pattern matches with object pattern syntax. */ match(patterns: { failure: (e: E) => B; success: (a: A) => B; }): IO; /** * Catches errors with a specific tag and handles them. * @param tag - The error tag to catch * @param handler - Handler for the caught error */ catchTag(tag: K, handler: (e: Extract) => IO): IO | E2, A | B>; /** * Catches all errors (alias for recoverWith). */ catchAll(handler: (e: E) => IO): IO; /** * Retries the effect up to n times on failure. * @param n - Maximum number of retries */ retry(n: number): IO; /** * Retries the effect with a delay between attempts. * @param n - Maximum number of retries * @param delayMs - Delay between retries in milliseconds */ retryWithDelay(n: number, delayMs: number): IO; /** * Retries the effect only while a predicate over the error holds. * * Useful for selective retry policies — e.g. retry HTTP 5xx but not 4xx, * retry network errors but not validation errors. The predicate is evaluated * BEFORE each retry; returning `false` short-circuits and re-fails with the * original error. * * @param opts.n - Maximum number of retry attempts. * @param opts.while - Predicate `(error, attempt) => boolean` (attempt is 1-indexed * for the first retry; if the predicate returns false, the retry is skipped). * @param opts.delayMs - Optional fixed delay between attempts. * * @example * ```ts * Http.get("/api/users", { decode }) * .retryWhile({ * n: 3, * while: (e) => e._tag === "HttpStatusError" && e.status >= 500, * delayMs: 250, * }) * ``` */ retryWhile(opts: { readonly n: number; readonly while: (error: E, attempt: number) => boolean; readonly delayMs?: number; }): IO; /** * Retries the effect with exponential backoff and optional full jitter. * * Delay schedule: `min(maxMs, baseMs * factor^(attempt-1))`. With jitter * enabled, the actual delay is `computed * (0.5 + Math.random() * 0.5)` * (full jitter, 50–100% of the computed value) — prevents thundering herd. * * @param opts.n - Maximum number of retry attempts. * @param opts.baseMs - Initial delay before the first retry. * @param opts.maxMs - Cap on per-attempt delay. Defaults to 30_000. * @param opts.factor - Backoff multiplier per attempt. Defaults to 2. * @param opts.jitter - Apply full jitter (50–100% of computed delay). Defaults to true. * @param opts.while - Optional predicate `(error, attempt) => boolean` gating each retry. * * @example * ```ts * const isRetryable = (e: HttpError): boolean => * e._tag === "NetworkError" || * (e._tag === "HttpStatusError" && (e.status >= 500 || e.status === 429)) * * Http.get("/api/users", { decode }) * .retryWithBackoff({ n: 3, baseMs: 250, while: isRetryable }) * .timeout(10_000) * ``` */ retryWithBackoff(opts: { readonly n: number; readonly baseMs: number; readonly maxMs?: number; readonly factor?: number; readonly jitter?: boolean; readonly while?: (error: E, attempt: number) => boolean; }): IO; /** * Re-runs the effect until its output satisfies `done`, or the `max` bound is hit. * * Value-channel dual of `retryWhile`: this repeats on success values that * haven't yet met the predicate, whereas the retry* family repeats on failure. * The first failure short-circuits and propagates unchanged. Compose the two * axes when both matter: * * @example * ```ts * pollJob * .retry(3) // error axis * .repeatUntil((job) => job.done, { max: 20, delayMs: 500 }) // value axis * ``` * * @param done - Pure sync predicate. Loop stops (successfully) when this returns true. * @param opts.max - Maximum iterations before exhaustion is signaled. * @param opts.delayMs - Optional fixed delay between iterations. * @returns The satisfying value, or `RepeatExhausted` in the error channel * (carrying the last observed value) if the bound is reached first. */ repeatUntil(done: (a: A) => boolean, opts: { readonly max: number; readonly delayMs?: number; }): IO, A>; /** * Re-runs the effect while `cont` holds, or until the `max` bound is hit. * * Symmetric sibling of `repeatUntil` — mirrors the naming of `retryWhile`. * `repeatWhile(cont)` is equivalent to `repeatUntil((a) => !cont(a))`; the * loop stops successfully as soon as `cont` returns false. * * @param cont - Pure sync predicate. Loop continues while this returns true. * @param opts.max - Maximum iterations before exhaustion is signaled. * @param opts.delayMs - Optional fixed delay between iterations. */ repeatWhile(cont: (a: A) => boolean, opts: { readonly max: number; readonly delayMs?: number; }): IO, A>; /** * Sequences two IOs, keeping the second value. */ zipRight(that: IO): IO; /** * Sequences two IOs, keeping the first value. */ zipLeft(that: IO): IO; /** * Zips two IOs into a tuple. */ zip(that: IO): IO; /** * Flattens a nested IO. */ flatten(this: IO>): IO; /** * Provides a context to satisfy the requirements of this effect. * @param context - The context containing required services */ provideContext(context: Context): IO, E, A>; /** * Provides a single service to satisfy part of the requirements. * @param tag - The service tag * @param service - The service implementation */ provideService(tag: Tag, service: S): IO, E, A>; /** * Provides services using a layer. * @param layer - The layer that provides services */ provideLayer(layer: Layer): IO, E | E2, A>; /** * Runs the effect and returns an Either. Never throws. * This is the safe default - all errors become Left. * Requires R = never. */ run(this: IO): Promise>; /** * Runs the effect and returns a Promise of the value. * Throws on any error (typed E, defect, or interrupt). * Requires R = never. */ runOrThrow(this: IO): Promise; /** * Runs a sync effect and returns an Either. Never throws. * This is the safe default - all errors become Left. * Throws only if the effect is async (cannot be made safe synchronously). * Requires R = never. */ runSync(this: IO): Either; /** * Runs a sync effect and returns the value. * Throws on any error or if the effect is async. * Requires R = never. */ runSyncOrThrow(this: IO): A; /** * Runs the effect and returns an Exit. */ runExit(this: IO): Promise>; /** * Runs the effect and returns an Option. * Some(value) on success, None on failure. */ runOption(this: IO): Promise>; /** * Runs the effect and returns a Try. * Success(value) on success, Failure(error) on failure. */ runTry(this: IO): Promise>>; /** * Pipes the IO through a function. */ pipe(f: (self: IO) => B): B; /** * Delays execution by the specified milliseconds. */ delay(ms: number): IO; /** * Fails with TimeoutError if the effect doesn't complete within the specified duration. * @param ms - Maximum time in milliseconds */ timeout(ms: number): IO; /** * Returns a fallback value if the effect doesn't complete within the specified duration. * @param ms - Maximum time in milliseconds * @param fallback - Value to return on timeout */ timeoutTo(ms: number, fallback: B): IO; /** * Converts to string representation. */ toString(): string; /** * Converts to JSON representation. */ toJSON(): { _tag: string; effect: unknown; }; /** * Makes IO iterable for generator do-notation (yield* syntax). * Yields the IO itself, allowing IO.gen to extract the value. */ [Symbol.iterator](): Generator, A, unknown>; } /** * Do-builder interface for chaining binds and maps */ interface DoBuilder> { /** * The underlying IO effect */ readonly effect: IO; /** * Binds the result of an effect to a named property in the context. * @param name - The property name to bind to * @param f - Function that returns an IO effect (receives current context) */ bind(name: Exclude, f: (ctx: Ctx) => IO): DoBuilder>; /** * Binds a pure value to a named property in the context. * @param name - The property name to bind to * @param f - Function that returns a value (receives current context) */ let(name: Exclude, f: (ctx: Ctx) => A): DoBuilder>; /** * Transforms the final context value. * @param f - Function to transform the context */ map(f: (ctx: Ctx) => B): IO; /** * Chains to another IO based on the context. * @param f - Function that returns an IO effect */ flatMap(f: (ctx: Ctx) => IO): IO; /** * Executes a side effect without changing the context. * @param f - Side effect function */ tap(f: (ctx: Ctx) => void): DoBuilder; /** * Executes an effectful side effect without changing the context. * @param f - Function returning an IO for the side effect */ tapEffect(f: (ctx: Ctx) => IO): DoBuilder; /** * Returns the final context as is. */ done(): IO; } /** * IO effect type for lazy, composable effects with typed errors. * * @example * ```typescript * // Basic usage * const program = IO.sync(() => 42) * .map(x => x * 2) * .flatMap(x => IO.succeed(x + 1)) * * const result = await program.run() // 85 * * // Error handling * const safe = IO.tryPromise({ * try: () => fetch('/api/data'), * catch: (e) => new NetworkError(e) * }) * .map(res => res.json()) * .recover({ fallback: 'default' }) * * // Composition * const composed = IO.all([ * IO.succeed(1), * IO.succeed(2), * IO.succeed(3) * ]) // IO * ``` */ declare const IO: ((f: () => A | Promise) => IO) & { /** * Creates an IO from a synchronous thunk. * The function is not executed until the IO is run. */ sync: (f: () => A) => IO; /** * Creates an IO that succeeds with the given value. */ succeed: (value: A) => IO; /** * Creates an IO that fails with the given error. */ fail: (error: E) => IO; /** * Creates an IO that dies with an unrecoverable defect. */ die: (defect: unknown) => IO; /** * Creates an IO from an async thunk. * The Promise is not created until the IO is run. */ async: (f: () => Promise) => IO; /** * Creates an IO from a Promise with error handling. */ tryPromise: (opts: { readonly try: () => Promise; readonly catch: (error: unknown) => E; }) => IO; /** * Creates an IO from a function that might throw. */ tryCatch: (f: () => A, onError: (error: unknown) => E) => IO; /** * Lifts a synchronous function into an IO-returning function. */ liftSync: (f: (...args: Args) => A) => (...args: Args) => IO; /** * Lifts a Promise-returning function into an IO-returning function. */ liftPromise: (f: (...args: Args) => Promise) => (...args: Args) => IO; /** * Creates an IO from an Either. */ fromEither: (either: Either) => IO; /** * Creates an IO from an Option. */ fromOption: (option: Option) => IO; /** * Creates an IO from an Option with custom error. */ fromOptionOrFail: (option: Option, onNone: () => E) => IO; /** * Creates an IO from a Try. */ fromTry: (t: ReturnType>) => IO; /** * Creates an IO from a result object with data/error pattern. * If error is present (truthy), fails with the error. * Otherwise succeeds with Option-wrapped data (None if data is null/undefined). * * This handles the common `{ data, error }` response pattern used by * Supabase, many REST APIs, and similar libraries. * * @example * ```typescript * const response = { data: user, error: null } * const io = IO.fromResult(response) // IO> -> Some(user) * * const emptyResponse = { data: null, error: null } * const emptyIo = IO.fromResult(emptyResponse) // IO> -> None * * const errorResponse = { data: null, error: new Error("Not found") } * const failedIo = IO.fromResult(errorResponse) // IO> -> fails * ``` */ fromResult: (result: { data: D | null; error: E | null; }) => IO>; /** * Creates an IO from an async thunk with typed error handling. * Catches any thrown errors and maps them using the provided function. * Supports cancellation via AbortSignal. * * This is a simpler alternative to `tryPromise` that takes a direct * error mapper function instead of an options object. * * @param f - Async function to execute (receives optional AbortSignal) * @param onError - Function to map caught errors to typed error E * @param signal - Optional AbortSignal for cancellation support * * @example * ```typescript * const io = IO.tryAsync( * () => fetch('/api/users').then(r => r.json()), * (e) => new ApiError(e) * ) * * // With cancellation: * const controller = new AbortController() * const io = IO.tryAsync( * (signal) => fetch('/api/users', { signal }).then(r => r.json()), * (e) => new ApiError(e), * controller.signal * ) * controller.abort() // Cancels the request * ``` */ tryAsync: (f: (signal?: AbortSignal) => Promise, onError: (error: unknown) => E, signal?: AbortSignal) => IO; /** * Creates an IO from an async function that returns { data, error }. * Handles both: * - Thrown errors (mapped via onThrow) * - Returned errors in the result object * Supports cancellation via AbortSignal. * * This is the most ergonomic way to wrap Supabase and similar API calls. * * @param f - Async function returning { data, error } object (receives optional AbortSignal) * @param onThrow - Function to map thrown errors to typed error E * @param config - Optional configuration for custom field names and cancellation * * @example * ```typescript * // Supabase query in one line: * const getUser = (id: string): IO> => * IO.asyncResult( * () => supabase.from('users').select('*').eq('id', id).single(), * toError * ) * * // With custom field names: * const result = IO.asyncResult( * () => customApi.fetch(), * toError, * { dataKey: 'result', errorKey: 'err' } * ) * * // With cancellation: * const controller = new AbortController() * const getUser = IO.asyncResult( * (signal) => supabase.from('users').abortSignal(signal).select('*').single(), * toError, * { signal: controller.signal } * ) * controller.abort() // Cancels the request * ``` */ asyncResult: (f: (signal?: AbortSignal) => Promise>, onThrow: (error: unknown) => E, config?: { dataKey?: string; errorKey?: string; signal?: AbortSignal; }) => IO>; /** * Creates an IO that requires a service identified by the tag. * The service must be provided before the effect can be run. * * @example * ```typescript * interface Logger { * log(message: string): void * } * const Logger = Tag("Logger") * * const program = IO.service(Logger).flatMap(logger => * IO.sync(() => logger.log("Hello!")) * ) * * // Provide the service to run * program.provideService(Logger, consoleLogger).run() * ``` */ service: (tag: Tag) => IO; /** * Accesses a service and applies a function to it. */ serviceWith: (tag: Tag, f: (service: S) => A) => IO; /** * Accesses a service and applies an effectful function to it. */ serviceWithIO: (tag: Tag, f: (service: S) => IO) => IO; /** * Accesses multiple services and applies a function to them. * Provides a convenient way to work with multiple dependencies. * * @example * ```typescript * const program = IO.withServices( * { logger: Logger, db: Database }, * ({ logger, db }) => { * logger.log("Querying...") * return db.query("SELECT * FROM users") * } * ) * ``` */ withServices: >, A extends Type>(services: Services, f: (ctx: { [K in keyof Services]: TagService; }) => A | Promise) => IO, unknown, A>; /** * Runs all IOs in parallel and collects results. */ all: (effects: readonly IO[]) => IO; /** * Runs IOs in sequence, returning the first success or last failure. */ firstSuccessOf: (effects: readonly IO[]) => IO; /** * Creates an IO that sleeps for the specified duration. */ sleep: (ms: number) => IO; /** * Effectful stateful loop — the value-driven dual of the retry family. * * Threads state `S` through an effectful `step` until `done(state)` holds, or * the `max` bound is reached. Semantics: * * - `done(seed)` is evaluated **before** the first `step` — an already-satisfied * seed returns immediately without executing the effect. * - The first `E` failure short-circuits the loop and propagates. * - `max` defaults to `10_000` and caps total step invocations to keep every * loop bounded by construction. Callers running larger iterations must set * `max` explicitly. * - Stack-safe: recursion happens via IO's `flatMap` trampoline, not the JS * call stack. * * @example * ```ts * // Poll for a completed job, threading the response through state. * const settled = await IO.iterate( * { status: "pending" as JobStatus }, * (state) => fetchJob(state.id), * (state) => state.status === "done" || state.status === "failed", * { max: 30 }, * ).runEither() * ``` * * @param seed - Initial state. * @param step - Effect producing the next state from the current state. * @param done - Pure sync predicate over the state. * @param opts.max - Maximum step invocations (default `10_000`). * @returns The satisfying state, or `RepeatExhausted` (carrying the last * observed state) if the bound is reached first. */ iterate: (seed: S, step: (state: S) => IO, done: (state: S) => boolean, opts?: { readonly max?: number; }) => IO, S>; /** * Creates an IO that never completes. */ never: () => IO; /** * Creates a unit IO. */ readonly unit: IO; /** * Converts a nullable value to an IO. */ fromNullable: (value: A | null | undefined) => IO; /** * Creates an IO that is immediately interrupted. */ interrupt: () => IO; /** * Ensures a resource is properly released after use. * The release function always runs, even if use fails. * * @example * ```typescript * const withFile = IO.bracket( * IO.sync(() => openFile("data.txt")), // acquire * file => IO.async(() => file.read()), // use * file => IO.sync(() => file.close()) // release * ) * ``` */ bracket: (acquire: IO, use: (a: A) => IO, release: (a: A) => IO) => IO; /** * Alias for bracket with a more descriptive name. */ acquireRelease: (acquire: IO, use: (a: A) => IO, release: (a: A) => IO) => IO; /** * Like `bracket`, but the release callback receives the Exit of the use-step. * Use this when cleanup needs to branch on whether `use` succeeded or failed — * e.g., emit a different audit event on `Success` vs `Failure`. * * The release effect always runs (whether use succeeded, failed, or was * interrupted). If `acquire` itself fails, release is not called. * * @example * ```typescript * IO.bracketExit( * appendEvent({ event: "job_start" }), * () => body, * (_a, exit) => * exit.isSuccess() * ? appendEvent({ event: "job_complete" }) * : appendEvent({ event: "job_failed", error: String(exit.toValue().value) }) * ) * ``` */ bracketExit: (acquire: IO, use: (a: A) => IO, release: (a: A, exit: Exit) => IO) => IO; /** * Races multiple effects, returning the first to complete. * Note: Other effects are NOT cancelled (JS limitation). * * @example * ```typescript * const result = await IO.race([ * IO.sleep(1000).map(() => "slow"), * IO.sleep(100).map(() => "fast") * ]).run() // "fast" * ``` */ race: (effects: readonly IO[]) => IO; /** * Returns the first effect to succeed, or fails if all fail. * * @example * ```typescript * const result = await IO.any([ * IO.fail("error1"), * IO.succeed("success"), * IO.fail("error2") * ]).run() // "success" * ``` */ any: (effects: readonly IO[]) => IO; /** * Executes an effect for each element in the array, collecting results. * * @example * ```typescript * const results = await IO.forEach([1, 2, 3], n => * IO.sync(() => n * 2) * ).run() // [2, 4, 6] * ``` */ forEach: (items: readonly A[], f: (a: A) => IO) => IO; /** * Executes effects for each element in parallel (limited concurrency coming later). * Alias for forEach. */ forEachPar: (items: readonly A[], f: (a: A) => IO) => IO; /** * Creates a timeout effect that fails with TimeoutError. */ timeout: (effect: IO, ms: number) => IO; /** * Creates an IO from a generator function. * This enables do-notation style programming. * * @example * ```typescript * const program = IO.gen(function* () { * const a = yield* IO.succeed(1) * const b = yield* IO.succeed(2) * return a + b * }) * ``` */ gen: (f: () => Generator) => IO; /** * Starts a Do-builder context for binding values. * This enables do-notation style programming without generators. * * @example * ```typescript * const program = IO.Do * .bind("user", () => getUser("123")) * .bind("posts", ({ user }) => getPosts(user.id)) * .let("count", ({ posts }) => posts.length) * .map(({ user, posts, count }) => ({ user, posts, count })) * ``` */ readonly Do: DoBuilder>; }; /** * An IO with no requirements and no error */ type UIO = IO; /** * An IO with no requirements */ type Task = IO; /** * An IO with no error */ type RIO = IO; //#endregion //#region src/io/TestClock.d.ts /** * TestClock interface for controlling time in tests */ interface TestClock { /** * Current virtual time in milliseconds */ readonly currentTime: number; /** * Advances the clock by the specified duration. * All scheduled tasks with a time <= new current time will be executed. * @param ms - Milliseconds to advance */ advance(ms: number): Promise; /** * Sets the clock to a specific time. * @param ms - The absolute time to set */ setTime(ms: number): Promise; /** * Runs all pending tasks immediately. */ runAll(): Promise; /** * Gets the number of pending scheduled tasks. */ readonly pendingCount: number; /** * Sleeps for the specified duration using virtual time. * @param ms - Milliseconds to sleep */ sleep(ms: number): Promise; } /** * Service tag for TestClock */ declare const TestClockTag: Tag; /** * TestClock companion object with factory methods */ declare const TestClock: { /** * Creates a new TestClock instance */ make: () => TestClock; /** * Tag for dependency injection */ tag: Tag; /** * Creates a test environment with a TestClock and runs the test function. * * @example * ```typescript * await TestClock.test(async (clock) => { * const result = await IO.sleep(100).map(() => "done") * .pipe(clock.runWithClock) * expect(result).toBe("done") * }) * ``` */ test: (f: (clock: TestClock) => Promise) => Promise; /** * Creates an IO that accesses the TestClock from the environment. */ get: IO; /** * Creates an IO that advances the TestClock. */ advance: (ms: number) => IO; /** * Creates an IO that sets the TestClock time. */ setTime: (ms: number) => IO; /** * Creates an IO that runs all pending tasks. */ runAll: IO; /** * Creates a context with a TestClock for testing. */ context: () => { clock: TestClock; context: ReturnType>; }; }; /** * TestContext provides a complete test environment with mocked services. */ interface TestContext { /** * The context containing test services */ readonly context: ReturnType>; /** * The TestClock for controlling time */ readonly clock: TestClock; /** * Adds a service to the test context */ withService(tag: Tag, service: S): TestContext; /** * Provides the test context to an IO effect and runs it */ run(effect: IO): Promise; } /** * Creates a TestContext for testing IO effects with mocked services. * * @example * ```typescript * const ctx = TestContext.make() * .withService(Logger, mockLogger) * .withService(Database, mockDb) * * const result = await ctx.run(myProgram) * ``` */ declare const TestContext: { /** * Creates a new empty TestContext */ make: () => TestContext; /** * Creates a TestContext with a TestClock already provided */ withClock: () => TestContext; }; //#endregion //#region src/fetch/HttpError.d.ts type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS"; type NetworkError = { readonly _tag: "NetworkError"; readonly url: string; readonly method: HttpMethod; readonly cause: unknown; }; type HttpStatusError = { readonly _tag: "HttpStatusError"; readonly url: string; readonly method: HttpMethod; readonly status: number; readonly statusText: string; readonly body: string; }; /** * Raised when a successful HTTP response could not be decoded into the * caller's expected shape — JSON parse failure, a `decode: Decoder` that * returned `Left(DecoderError)`, a throwing `decodeUnsafe` / `validate`, etc. * In practice `cause` is a `DecoderError` (when produced by the `decode` * path) or an `Error` (otherwise) — but the field is typed `unknown` for * back-compat with the 1.0.x runtime. */ type DecodeError = { readonly _tag: "DecodeError"; readonly url: string; readonly method: HttpMethod; readonly body: string; readonly cause: unknown; }; /** * More descriptive alias for `DecodeError` — clarifies that this is the * HTTP-level wrapper for response decoding failures, distinct from the * structural `DecoderError` tree it usually carries in `cause`. Both names * refer to the same `_tag: "DecodeError"` variant. */ type ResponseDecodeError = DecodeError; type HttpError = NetworkError | HttpStatusError | DecodeError; declare const HttpError: { readonly _tag: "HttpError"; } & { networkError: (url: string, method: HttpMethod, cause: unknown) => NetworkError; httpStatusError: (url: string, method: HttpMethod, status: number, statusText: string, body: string) => HttpStatusError; decodeError: (url: string, method: HttpMethod, body: string, cause: unknown) => DecodeError; isNetworkError: (error: HttpError) => error is NetworkError; isHttpStatusError: (error: HttpError) => error is HttpStatusError; isDecodeError: (error: HttpError) => error is DecodeError; match: (error: HttpError, patterns: { readonly NetworkError: (e: NetworkError) => T; readonly HttpStatusError: (e: HttpStatusError) => T; readonly DecodeError: (e: DecodeError) => T; }) => T; }; //#endregion //#region src/fetch/HttpRequest.d.ts type ParseMode = "json" | "text" | "blob" | "arrayBuffer" | "raw"; /** * Typed query-parameter record. Scalar values (string | number | boolean) are * `String()`-coerced; arrays repeat the key (`{ tag: ["a", "b"] }` → `tag=a&tag=b`); * `undefined` and `null` values are dropped (so callers can write * `{ foo: maybe.toNullable() }` without conditionals); special characters are * percent-encoded via `URLSearchParams`. * * Nested objects are not supported (the type prevents them at compile time). */ type HttpQueryParams = Readonly>; interface HttpRequestOptions { readonly url: string; readonly method: HttpMethod; readonly headers?: Record; readonly body?: unknown; readonly signal?: AbortSignal; readonly parseAs?: ParseMode; /** * Query-string parameters appended to the URL. Merges with any query string * already present in `url`. See {@link HttpQueryParams} for encoding rules. */ readonly params?: HttpQueryParams; /** * Either-returning response decoder. Returns `Left(DecoderError)` on * failure; the framework maps that to `HttpError.DecodeError(cause: DecoderError)`. * The recursive `DecoderError` tree preserves structural failure info * (paths, child errors) for diagnosis and rendering. * * For adapters whose primary API throws (e.g. Zod's `.parse`), use an * adapter package (e.g. `functype-zod`'s `Decoder.fromZod(schema)`) or * wrap the throwing function in a tiny custom decoder. The deprecated * `validate` field is also still accepted for back-compat. */ readonly decode?: Decoder$1; /** * @deprecated Use `decode` (Either-returning). For throw-pattern adapters * like Zod's `.parse`, prefer an adapter package (`functype-zod`'s * `Decoder.fromZod`). `validate` is kept for back-compat with the 1.0.x * API and will be removed in a future major release. Throwing maps to * `HttpError.DecodeError(cause: Error)`. */ readonly validate?: (data: unknown) => T; /** * Whether to flatten functype ADTs in the request body to their primitive * projections (Option → nullable, Either → right-value-or-throw-on-Left, * List → array, Try → success-value-or-throw, Map → record) before serializing. * Default `true` — matches the wire shape external JSON APIs expect. * * Set to `false` to emit each ADT's canonical `{_tag, value}` form via * `toValue()` for functype-to-functype services where both ends round-trip * the tagged shape via `Decoder.tagged.*`. */ readonly flatten?: boolean; } interface HttpMethodOptions { readonly headers?: Record; readonly body?: unknown; readonly signal?: AbortSignal; readonly parseAs?: ParseMode; readonly decode?: Decoder$1; /** @deprecated Use `decode` (Either-returning) or an adapter package for throw-pattern validators. */ readonly validate?: (data: unknown) => T; readonly flatten?: boolean; /** * Query-string parameters appended to the URL. See {@link HttpQueryParams}. */ readonly params?: HttpQueryParams; } interface HttpResponse { readonly data: T; readonly status: number; readonly statusText: string; readonly headers: Headers; } /** * The assembled, pre-wire view of a request that `HttpClientConfig.beforeRequest` * receives and may return a transformed copy of. URL is resolved against * `baseUrl`; headers reflect the `defaultHeaders` + per-call merge. The * response-side decoders (`decode` / `validate`) are intentionally not * exposed here — they aren't part of the wire request and apply to the * response. The `flatten` flag IS exposed because it affects how `body` * is serialized. */ interface HttpRequestView { readonly url: string; readonly method: HttpMethod; readonly headers?: Record; readonly body?: unknown; readonly signal?: AbortSignal; readonly parseAs?: ParseMode; readonly flatten?: boolean; } //#endregion //#region src/fetch/HttpClient.d.ts interface HttpClientConfig { readonly baseUrl?: string; readonly defaultHeaders?: Record; readonly fetch?: typeof globalThis.fetch; /** * Effectful transformer that runs after `defaultHeaders` and per-call headers * are merged, but before the request is sent. Returning a failed IO short- * circuits the call with the produced `HttpError`. Compose multiple concerns * (request IDs, auth refresh, logging) with standard IO operators — the * request side becomes symmetric with the response chain (`.tap`, `.map`, * `.flatMap`, `.catchTag`). * * @example * ```ts * const addRequestId = (r: HttpRequestView): HttpRequestView => ({ * ...r, * headers: { ...r.headers, "x-request-id": crypto.randomUUID() }, * }) * * const addBearer = (getToken: () => Promise) => * (r: HttpRequestView): IO => * IO.tryPromise({ * try: () => getToken(), * catch: (e) => HttpError.networkError(r.url, r.method, e), * }).map((token) => ({ * ...r, * headers: { ...r.headers, Authorization: `Bearer ${token}` }, * })) * * const api = Http.client({ * baseUrl: "https://api.example.com", * beforeRequest: (r) => * IO.succeed(r) * .map(addRequestId) * .flatMap(addBearer(getToken)) * .tap((req) => logger.info(req.method, req.url)), * }) * ``` */ readonly beforeRequest?: (request: HttpRequestView) => IO; /** * Effectful transformer that runs after the response is parsed (and the * decoder, if any, succeeds) but before the IO resolves to the caller. * Returning a failed IO surfaces the error in place of the response. * * **Only runs on the success path.** `HttpStatusError` (non-2xx), * `DecodeError` (validation failure), and `NetworkError` (fetch / abort) * skip this hook and surface directly. For *error*-side observability and * recovery (refresh-on-401, error logging), use `.catchTag(...)` / * `.tapError(...)` at the call site. * * The hook receives `HttpResponse` — body shape is opaque here * because hooks are response-shape-agnostic. The per-call decoder narrows * `data` to the typed value before the response reaches the caller, but * the hook itself sees `unknown`. * * @example * ```ts * const api = Http.client({ * baseUrl: "https://api.example.com", * afterResponse: (response) => * IO.succeed(response) * .tap((r) => logger.info("response", { status: r.status })) * .map((r) => ({ ...r, headers: redactSensitiveHeaders(r.headers) })), * }) * * // Refresh-on-401 is a .catchTag pattern, NOT an afterResponse pattern: * api.get("/me", { decode }) * .catchTag("HttpStatusError", (e) => * e.status === 401 ? refreshToken().flatMap(() => api.get("/me", { decode })) : IO.fail(e), * ) * ``` */ readonly afterResponse?: (response: HttpResponse) => IO>; } declare const HttpClient: Tag; //#endregion //#region src/fetch/Http.d.ts type HttpMethods = { readonly request: (options: HttpRequestOptions) => IO>; readonly get: (url: string, options?: HttpMethodOptions) => IO>; readonly post: (url: string, options?: HttpMethodOptions) => IO>; readonly put: (url: string, options?: HttpMethodOptions) => IO>; readonly patch: (url: string, options?: HttpMethodOptions) => IO>; readonly delete: (url: string, options?: HttpMethodOptions) => IO>; readonly head: (url: string, options?: HttpMethodOptions) => IO>; readonly options: (url: string, options?: HttpMethodOptions) => IO>; }; declare const Http: { readonly _tag: "Http"; } & { request: (options: HttpRequestOptions) => IO>; get: (url: string, options?: HttpMethodOptions) => IO>; post: (url: string, options?: HttpMethodOptions) => IO>; put: (url: string, options?: HttpMethodOptions) => IO>; patch: (url: string, options?: HttpMethodOptions) => IO>; delete: (url: string, options?: HttpMethodOptions) => IO>; head: (url: string, options?: HttpMethodOptions) => IO>; options: (url: string, options?: HttpMethodOptions) => IO>; client: (config: HttpClientConfig) => HttpMethods; }; //#endregion //#region src/foldable/index.d.ts /** * Structural type for sum types that support pattern-match fold (Option, Either, Try, etc.). * Uses duck typing so any type with the right fold signature works, without requiring a shared interface. */ type PatternFoldable = { fold(onEmpty: () => B, onValue: (value: A) => B): B; }; /** * Utility functions for working with sum-type Foldable data structures. * These utilities use pattern-match fold semantics and are designed for * sum types (Option, Either, Try) — not collections. */ declare const FoldableUtils: { /** * Converts a sum type to an Option * * @param foldable - The sum type to convert * @returns An Option containing the value, or None if empty */ toOption: (foldable: PatternFoldable) => Option; /** * Converts a sum type to a List * * @param foldable - The sum type to convert * @returns A List containing the value(s), or empty List if empty */ toList: (foldable: PatternFoldable) => List; /** * Converts a sum type to an Either * * @param foldable - The sum type to convert * @param left - The value to use for Left if empty * @returns Either.Right with the value if non-empty, or Either.Left with left if empty */ toEither: (foldable: PatternFoldable, left: E) => Either; /** * Checks if the sum type is empty * * @param foldable - The sum type to check * @returns true if empty, false otherwise */ isEmpty: (foldable: PatternFoldable) => boolean; /** * Calculates the size of the sum type (0 or 1) * * @param foldable - The sum type to measure * @returns The size (0 if empty, 1 if non-empty) */ size: (foldable: PatternFoldable) => number; }; //#endregion //#region src/hkt/index.d.ts /** * Type function for representing higher-kinded types */ type Kind = F extends ((arg: infer T) => infer R) ? R : never; /** * Type constructors for common Functype data types */ type OptionKind = (a: A) => Option; type ListKind = (a: A) => List; type EitherKind = (a: A) => Either; type TryKind = (a: A) => Try; /** * Generic container types for type-safe operations * @internal */ type Mappable = { map(f: (value: T) => U): unknown; }; /** * @internal */ type Flattenable = { flatten(): unknown; }; /** * @internal */ type FlatMappable = { flatMap(f: (value: T) => unknown): unknown; }; /** * Universal type that includes all potential return types from the HKT functions * Used to avoid 'any' usage which the linter prohibits */ type UniversalContainer = Option | List | Either | Try; /** * HKT provides utilities for working with higher-kinded types * This allows writing generic code that works across different * container types like Option, List, Either, etc. */ declare const HKT: { (): { _tag: string; map: (fa: unknown, f: (a: A) => B) => unknown; flatten: (ffa: unknown) => unknown; flatMap: (fa: unknown, f: (a: A) => unknown) => unknown; ap: (ff: unknown, fa: unknown) => unknown; sequence: (fga: unknown) => unknown; traverse: (fa: unknown, f: (a: A) => unknown) => unknown; _type: string; }; map(fa: unknown, f: (a: A) => B): unknown; flatten(ffa: unknown): unknown; flatMap(fa: unknown, f: (a: A) => unknown): unknown; ap(ff: unknown, fa: unknown): unknown; sequence(fga: unknown): unknown; traverse(fa: unknown, f: (a: A) => unknown): unknown; isOption: (value: unknown) => value is Option & Mappable & FlatMappable; isList: (value: unknown) => value is List & Mappable & Flattenable & FlatMappable; isEither: (value: unknown) => value is Either & Mappable & FlatMappable; isTry: (value: unknown) => value is Try & Mappable & FlatMappable; }; //#endregion //#region src/identity/Identity.d.ts /** * Identity — a trivial container carrying a single tagged value. * Covariant in T (``). `isSame` takes `Identity` so that * cross-type equality checks (semantically always `false` for unrelated types) * don't block variance — mirroring the `contains(unknown)` pattern used on * List/Set/Map. */ type Identity = { readonly id: T; isSame?: (other: Identity) => boolean; }; declare const Identity: ((value: T) => Identity) & { /** * Creates an Identity. Alias for Identity constructor. * @param value - The value to wrap * @returns Identity instance */ of: (value: T) => Identity; /** * Creates an Identity. Same as of. * @param value - The value to wrap * @returns Identity instance */ pure: (value: T) => Identity; }; //#endregion //#region src/lazy/Lazy.d.ts /** * Lazy type module * @module Lazy * @category Core */ /** * The Lazy type represents a computation that is deferred until needed. * It provides memoization and safe evaluation with integration to Option, Either, and Try. * @typeParam T - The type of the value to be computed */ interface Lazy extends FunctypeBase, Extractable, Pipe { /** Tag identifying this as a Lazy type */ readonly _tag: "Lazy"; /** Whether the computation has been evaluated */ readonly isEvaluated: boolean; /** * Returns the computed value or a default value if computation fails. * Result widens to `T | T2` (Scala: `getOrElse[B >: A](default: B): B`). */ orElse(defaultValue: T2): T | T2; /** * Returns the computed value or null if computation fails * @returns The computed value or null */ orNull(): T | null; /** * Returns the computed value or throws an error if computation fails * @param error - Optional custom error to throw. If not provided, throws the computation error or a default error * @returns The computed value * @throws The specified error, computation error, or a default error */ orThrow(error?: Error): T; /** * Returns this Lazy if computation succeeds, otherwise returns the alternative Lazy. * The alternative may carry a different type; result is `Lazy`. */ or(alternative: Lazy): Lazy; /** * Maps the value inside the Lazy using the provided function * @param f - The mapping function * @returns A new Lazy containing the mapped value */ map(f: (value: T) => U): Lazy; /** * Applies a wrapped function to a wrapped value (Applicative pattern) * @param ff - A Lazy containing a function from T to U * @returns A new Lazy containing the result */ ap(ff: Lazy<(value: T) => U>): Lazy; /** * Maps the value inside the Lazy using an async function * @param f - The async mapping function * @returns A Promise of a new Lazy containing the mapped value */ mapAsync(f: (value: T) => Promise): Promise>; /** * Maps the value using a function that returns a Lazy * @param f - The mapping function returning a Lazy * @returns A new Lazy containing the flattened result */ flatMap(f: (value: T) => Lazy): Lazy; /** * Maps the value using an async function that returns a Lazy * @param f - The async mapping function returning a Lazy * @returns A Promise of a new Lazy containing the flattened result */ flatMapAsync(f: (value: T) => Promise>): Promise>; /** * Returns a Lazy that filters the value based on a predicate * @param predicate - The predicate function * @returns A Lazy containing an Option of the value */ filter(predicate: (value: T) => boolean): Lazy>; /** * Recovers from a failed computation by providing an alternative value * @param f - Function that takes the error and returns a recovery value * @returns A new Lazy that will use the recovery function if computation fails */ recover(f: (error: unknown) => T): Lazy; /** * Recovers from a failed computation by providing an alternative Lazy * @param f - Function that takes the error and returns a recovery Lazy * @returns A new Lazy that will use the recovery Lazy if computation fails */ recoverWith(f: (error: unknown) => Lazy): Lazy; /** * Evaluates the computation and returns it as an Option * @returns Some containing the value if successful, None if computation fails */ toOption(): Option; /** * Evaluates the computation and returns it as an Either * @returns Right containing the value if successful, Left containing the error if computation fails */ toEither(): Either; /** * Evaluates the computation and returns it as an Either with a mapped error * @param mapError - Function to map the error * @returns Right containing the value if successful, Left containing the mapped error if computation fails */ toEitherWith(mapError: (error: unknown) => E): Either; /** * Evaluates the computation and returns it as a Try * @returns Try containing the result of the computation */ toTry(): Try; /** * Applies an effect function to the value if computation succeeds * @param f - The effect function * @returns This Lazy for chaining */ tap(f: (value: T) => void): Lazy; /** * Applies an effect function to the error if computation fails * @param f - The effect function for errors * @returns This Lazy for chaining */ tapError(f: (error: unknown) => void): Lazy; /** * Pattern matching on the Lazy value * @param f - Function to apply to the computed value * @returns The result of applying f to the computed value */ fold(f: (value: T) => U): U; /** * Pattern matching with success and failure handlers * @param onFailure - Function to handle computation failure * @param onSuccess - Function to handle successful computation * @returns The result of the appropriate handler */ foldWith(onFailure: (error: unknown) => U, onSuccess: (value: T) => U): U; /** * Left fold operation * @param z - Initial value * @returns Function that takes an operator and applies it */ foldLeft: (z: B) => (op: (b: B, a: T) => B) => B; /** * Right fold operation * @param z - Initial value * @returns Function that takes an operator and applies it */ foldRight: (z: B) => (op: (a: T, b: B) => B) => B; /** * Pattern matching for the Lazy type * @param patterns - Object with handler for Lazy pattern * @returns The result of the matched handler */ match(patterns: { Lazy: (value: T) => R; }): R; /** * Creates a string representation of the Lazy * @returns String representation showing evaluation status */ toString(): string; /** * Converts the Lazy to a value object. * * **Forces the thunk** as a side effect — Lazy serialization (and projection * to a plain value object) cannot represent an unevaluated thunk in JSON; * forcing is the only way to produce a complete projection. If the thunk * threw, the failure is captured in the `error` field (real Error, with * full prototype intact for in-memory inspection — `toJSON` projects to * `SerializedError` for the wire). * * Changed in 1.2.0 — pre-1.2.0 Lazy emitted `{_tag, evaluated, value?}` * without forcing. See `docs/archive/proposals/serializable-audit-q1-q2.md`. */ toValue(): { _tag: "Lazy"; value: T; } | { _tag: "Lazy"; error: Error; }; /** * Custom JSON serialization. Forces the thunk (see `toValue` for the * side-effect contract). Emits `{"@functype":"Lazy","_tag":"Lazy","value":T}` * on success, or `{"@functype":"Lazy","_tag":"Lazy","error":SerializedError}` * if the thunk threw — see error-envelope.ts for round-trip semantics. */ toJSON(): { "@functype": "Lazy"; _tag: "Lazy"; value: T; } | { "@functype": "Lazy"; _tag: "Lazy"; error: SerializedError; }; } /** * Creates a Lazy computation that defers evaluation until needed. * Results are memoized after first evaluation. * * @example * // Basic lazy evaluation * const expensive = Lazy(() => { * console.log("Computing...") * return 42 * }) * // Nothing printed yet * const result = expensive.orThrow() // Prints "Computing..." and returns 42 * const cached = expensive.orThrow() // Returns 42 without printing * * @example * // Error handling * const risky = Lazy(() => { * if (Math.random() > 0.5) throw new Error("Failed") * return "Success" * }) * const safe = risky.orElse("Default") // Returns "Success" or "Default" * const option = risky.toOption() // Some("Success") or None * const either = risky.toEither() // Right("Success") or Left(Error) * * @example * // Chaining computations * const result = Lazy(() => 10) * .map(x => x * 2) * .flatMap(x => Lazy(() => x + 5)) * .recover(err => 0) * .orThrow() // 25 * * @example * // Integration with functype * const userOption = Option({ id: 1, name: "Alice" }) * const userName = Lazy.fromOption(userOption, () => ({ id: 0, name: "Anonymous" })) * .map(user => user.name) * .orThrow() // "Alice" */ declare const Lazy: ((thunk: () => T) => Lazy) & { /** * Creates a Lazy from a thunk (deferred computation) * @param thunk - Function that computes the value * @returns A new Lazy instance */ of: (thunk: () => T) => Lazy; /** * Creates a Lazy from an immediate value * @param value - The value to wrap * @returns A new Lazy instance that returns the value */ fromValue: (value: T) => Lazy; /** * Creates a Lazy from an Option * @param option - The Option to convert * @param defaultThunk - Thunk to compute default value if Option is None * @returns A new Lazy instance */ fromOption: (option: Option, defaultThunk: () => T) => Lazy; /** * Creates a Lazy from a Try * @param tryValue - The Try to convert * @returns A new Lazy instance */ fromTry: (tryValue: Try) => Lazy; /** * Creates a Lazy from an Either * @param either - The Either to convert * @returns A new Lazy instance */ fromEither: (either: Either) => Lazy; /** * Creates a Lazy that will throw an error since promises need to be awaited first * @param promise - The Promise to convert * @returns A new Lazy instance that throws an error */ fromPromise: (_promise: Promise) => Lazy; /** * Creates a failed Lazy that will throw when evaluated * @param error - The error to throw * @returns A new Lazy instance that throws the error */ fail: (error: unknown) => Lazy; /** * Creates an already-evaluated Lazy. Used by `fromJSON` to reconstruct a * Lazy whose thunk was forced at serialize time — there is no original * thunk to defer because a closure cannot be JSON-serialized. * * Functionally equivalent to `Lazy.fromValue` but reads with intent at * the call site. */ evaluated: (value: T) => Lazy; /** * Reconstruct a Lazy from a JSON envelope emitted by `serialize().toJSON()` * or instance `toJSON()`. Verifies `@functype === "Lazy"`. Success envelopes * become already-evaluated Lazies via `Lazy.evaluated`; failure envelopes * become Lazies whose forcing rethrows the deserialized Error (see * error-envelope.ts — `instanceof SomeError` does NOT survive but `name` * does). */ fromJSON: (json: string) => Lazy; }; //#endregion //#region src/traversable/KVTraversable.d.ts /** * A traversable interface for key-value containers that excludes map, flatMap, * flatMapAsync, and ap operations. * * Key-value containers (Map, Obj) cannot satisfy Functor's unconstrained * `map` because their type parameter is constrained * (e.g., to Record or Tuple pairs). These containers redefine map/flatMap * with their own tighter constraints. * * @typeParam A - The element type of the traversable */ type KVTraversable = Omit, "map" | "flatMap" | "flatMapAsync" | "ap">; //#endregion //#region src/map/Map.d.ts interface Map$1 extends KVTraversable>, Collection>, Typeable<"Map">, Serializable<[K, V][]>, Pipe<[K, V][]>, Foldable>, Iterable<[K, V]> { readonly [Symbol.toStringTag]: string; readonly _tag: "Map"; add(item: Tuple<[K, V]>): Map$1; remove(value: K): Map$1; map(f: (value: V) => U): Map$1; ap(ff: Map$1 U>): Map$1; flatMap(f: (entry: Tuple<[K, V]>) => Iterable<[K2, V2]>): Map$1; flatMapAsync(f: (value: V) => PromiseLike>): PromiseLike>; get(key: K): Option; getOrElse(key: K, defaultValue: V): V; orElse(key: K, alternative: Option): Option; fold(initial: B, fn: (acc: B, a: Tuple<[K, V]>) => B): B; foldLeft(z: B): (op: (b: B, a: Tuple<[K, V]>) => B) => B; foldRight(z: B): (op: (a: Tuple<[K, V]>, b: B) => B) => B; /** * Pattern matches over the Map, applying a handler function based on whether it's empty * @param patterns - Object with handler functions for Empty and NonEmpty variants * @returns The result of applying the matching handler function */ match(patterns: { Empty: () => R; NonEmpty: (entries: Array>) => R; }): R; toValue(): { _tag: "Map"; value: [K, V][]; }; } declare const Map$1: ((entries?: readonly (readonly [K, V])[] | IterableIterator<[K, V]> | null) => Map$1) & { /** * Creates an empty Map * Returns a singleton instance for efficiency * @returns An empty Map instance */ empty: () => Map$1; /** * Creates a Map from variadic key-value pair arguments * @param entries - Key-value pairs to create map from * @returns A Map containing the entries */ of: (...entries: [K, V][]) => Map$1; /** * Creates a Map from JSON string * @param json - The JSON string * @returns Map instance */ fromJSON: (json: string) => Map$1; /** * Creates a Map from YAML string * @param yaml - The YAML string * @returns Map instance */ fromYAML: (yaml: string) => Map$1; /** * Creates a Map from binary string * @param binary - The binary string * @returns Map instance */ fromBinary: (binary: string) => Map$1; }; //#endregion //#region src/map/shim.d.ts /** * Type alias for the native JavaScript Map * @interface * @module Map * @category Collections */ type ESMapType = Map; /** * Reference to the native JavaScript Map * @module Map * @category Collections */ declare const ESMap: MapConstructor; //#endregion //#region src/obj/Obj.d.ts /** * Obj type module * @module Obj * @category Core */ /** * The Obj type wraps a plain JavaScript object and provides fluent, * immutable operations for building and transforming objects. * * @typeParam T - The record type of the contained object * * @example * ```typescript * // Build HTTP headers immutably with conditional auth * const headers = Obj({ "User-Agent": userAgent }) * .assign(options.headers) * .when(requiresAuth, { Authorization: `Bearer ${token}` }) * .value() * * // Fluent object construction * Obj.of({ name: "John" }) * .set("age", 31) * .merge({ city: "NYC" }) * .value() * ``` */ interface Obj> extends Omit, "map" | "flatMap" | "flatMapAsync" | "ap">, Promisable, Doable, Reshapeable { /** The contained object value */ readonly data: T; /** * Maps the contained object to a new object using the provided function * @param f - The mapping function (must return a Record) * @returns A new Obj containing the mapped value */ map>(f: (value: T) => U): Obj; /** * FlatMaps the contained object using a function that returns an Obj * @param f - The flatMap function * @returns The Obj returned by f */ flatMap>(f: (value: T) => Obj): Obj; /** * Async flatMap for the contained object * @param f - The async flatMap function * @returns A Promise of the Obj returned by f */ flatMapAsync>(f: (value: T) => PromiseLike>): PromiseLike>; /** * Applies a wrapped function to the contained object * @param ff - An Obj containing a function from T to U * @returns A new Obj containing the result */ ap>(ff: Obj>): Obj; /** * Get a value by key, returning Option * @param key - The key to look up * @returns Option containing the value if present */ get(key: K): Option; /** * Set a single key to a new value, returning a new Obj * @param key - The key to set (must exist in T) * @param value - The value to set * @returns A new Obj with the updated key */ set(key: K, value: T[K]): Obj; /** * Merge a partial of the same shape (no new keys) * @param partial - Partial object to merge * @returns A new Obj with merged values */ assign(partial: Partial): Obj; /** * Merge with a potentially wider type (can add new keys) * @param other - Object to merge in * @returns A new Obj with the merged type */ merge>(other: U): Obj; /** * Conditionally merge a partial based on a boolean or predicate * @param condition - Boolean or predicate function * @param partial - Partial to merge if condition is true * @returns A new Obj, with or without the merge applied */ when(condition: boolean | (() => boolean), partial: Partial): Obj; /** * Return a new Obj without the specified keys * @param keys - Keys to remove * @returns A new Obj without the specified keys */ omit(...keys: K[]): Obj>; /** * Return a new Obj with only the specified keys * @param keys - Keys to keep * @returns A new Obj with only the specified keys */ pick(...keys: K[]): Obj>; /** * Return a List of keys * @returns List of string keys */ keys(): List; /** * Return a List of values * @returns List of values */ values(): List; /** * Return a List of [key, value] Tuples * @returns List of key-value Tuples */ entries(): List>>; /** * Unwrap to the plain object * @returns The contained plain object */ value(): T; /** * Check if a key exists * @param key - The key to check * @returns true if the key exists */ has(key: K): boolean; /** * Pattern match fold — applies onEmpty if empty, onValue if non-empty * @param onEmpty - Handler for empty Obj * @param onValue - Handler for non-empty Obj * @returns The result of the matching handler */ fold(onEmpty: () => U, onValue: (value: T) => U): U; /** * Returns a string representation of this Obj * @returns A string representation */ toString(): string; } /** * Obj - Immutable object wrapper with fluent operations. * * Wraps plain JavaScript objects and provides chainable, immutable * operations for building and transforming them. Implements the full * Functype interface (Functor, Foldable, Serializable, Matchable, etc.). * * @example * ```typescript * // Build headers with conditional auth * const headers = Obj({ "User-Agent": "MyApp/1.0" }) * .assign(options.headers) * .when(requiresAuth, { Authorization: `Bearer ${token}` }) * .value() * * // Object manipulation * const user = Obj({ name: "John", age: 30, role: "admin" }) * user.pick("name", "role").value() // { name: "John", role: "admin" } * user.omit("role").value() // { name: "John", age: 30 } * user.get("name") // Some("John") * ``` */ declare const Obj: (>(data: T) => Obj) & { /** * Creates an Obj from a plain object. Alias for Obj(). * @param data - The plain object to wrap * @returns A new Obj instance */ of: >(data: T) => Obj; /** * Creates an empty Obj. * @returns An empty Obj instance */ empty: >() => Obj; /** * Deserializes an Obj from a JSON string. * @param json - The JSON string to parse * @returns A new Obj instance */ fromJSON: >(json: string) => Obj; /** * Deserializes an Obj from a base64-encoded binary string. * @param binary - The base64 string to decode * @returns A new Obj instance */ fromBinary: >(binary: string) => Obj; }; //#endregion //#region src/ref/Ref.d.ts /** * A mutable reference container that holds a value of type A. * This provides controlled mutability in a functional context. * * **Variance: invariant in A by design.** Ref is a mutable cell — `set(A)` * writes A (contravariant) and `get(): A` reads A (covariant), so A is * genuinely invariant. Unlike the other containers in functype, Ref has no * `` annotation and cannot be widened via subtyping. This mirrors * Scala's `scala.concurrent.stm.Ref` and reflects the fundamental nature of * mutable state: you can't safely treat a `Ref[Narrow]` as a `Ref[Wide]` * because someone could `set` a Wide value that isn't a Narrow. * * @example * const counter = Ref(0) * counter.get() // 0 * counter.set(5) * counter.get() // 5 * counter.update(n => n + 1) * counter.get() // 6 */ interface Ref { /** * Get the current value */ get(): A; /** * Set a new value */ set(value: A): void; /** * Update the value using a function */ update(f: (current: A) => A): void; /** * Update and return the old value */ getAndSet(value: A): A; /** * Update and return the new value */ updateAndGet(f: (current: A) => A): A; /** * Update and return the old value */ getAndUpdate(f: (current: A) => A): A; /** * Compare and swap - only updates if current value equals expected */ compareAndSet(expected: A, newValue: A): boolean; /** * Modify the value and return a result */ modify(f: (current: A) => [A, B]): B; } declare const Ref: ((initial: A) => Ref) & { /** * Creates a Ref. Alias for Ref constructor. * @param initial - The initial value * @returns Ref instance */ of: (initial: A) => Ref; }; //#endregion //#region src/valuable/Valuable.d.ts /** * Parameters for creating a Valuable instance */ type ValuableParams = { _tag: Tag; impl: T; value: V; }; /** * Represents a type that can extract its inner value. Creates a Valuable wrapper that adds value extraction capabilities. * @param params - Configuration parameters * @module Valuable * @category Utilities */ declare function Valuable(params: ValuableParams): T & { toValue: () => { _tag: Tag; value: V; }; _tag: Tag; }; type Valuable = Typeable & { toValue: () => { _tag: Tag; value: V; }; }; //#endregion //#region src/stack/Stack.d.ts /** * Stack data structure - Last In, First Out (LIFO) * Implements the Traversable interface for working with ordered collections */ type Stack = { readonly [Symbol.toStringTag]: string; /** * Push a value onto the top of the stack. The value may be a wider type; * the result widens to `Stack` (Scala: `:+[B >: A]`). * @param value - The value to push * @returns A new Stack with the value added */ push(value: B): Stack; /** * Remove and return the top value from the stack * @returns A tuple containing the new Stack and the value */ pop(): [Stack, Option]; /** * Return the top value without removing it * @returns The top value wrapped in an Option */ peek(): Option; /** * Transforms each element in the stack using the provided function * @param f - The mapping function * @returns A new Stack with transformed elements */ map(f: (a: A) => B): Stack; /** * Maps each element to a Stack and flattens the result * @param f - The mapping function returning a Stack * @returns A new flattened Stack */ flatMap(f: (a: A) => Stack): Stack; /** * Applies a Stack of functions to this Stack * @param ff - Stack of functions to apply * @returns A new Stack with applied functions */ ap(ff: Stack<(value: A) => B>): Stack; /** * Maps each element to an async Stack and flattens the result * @param f - The async mapping function returning a Stack * @returns A promise of the new flattened Stack */ flatMapAsync(f: (value: A) => PromiseLike>): PromiseLike>; /** * Convert the stack to a List * @returns A List containing all elements */ toList(): List; /** * Convert the stack to an array * @returns An array of all elements */ toArray(): A[]; /** * Returns a string representation of the stack * @returns A string representation */ toString(): string; /** * Left-associative fold over all elements using an initial value and combining function. */ fold(initial: B, fn: (acc: B, a: A) => B): B; /** * Pattern matches over the Stack, applying a handler function based on whether it's empty * @param patterns - Object with handler functions for Empty and NonEmpty variants * @returns The result of applying the matching handler function */ match(patterns: { Empty: () => R; NonEmpty: (values: A[]) => R; }): R; } & Traversable & Valuable<"Stack", A[]> & Serializable & Pipe & Foldable & Matchable; declare const Stack: ((values?: A[]) => Stack) & { /** * Creates an empty stack * @returns An empty Stack instance */ empty: () => Stack; /** * Creates a Stack from a single value * @param value - The value to create a stack with * @returns A Stack with a single value */ of: (value: A) => Stack; /** * Creates a Stack from JSON string * @param json - The JSON string * @returns Stack instance */ fromJSON: (json: string) => Stack; /** * Creates a Stack from YAML string * @param yaml - The YAML string * @returns Stack instance */ fromYAML: (yaml: string) => Stack; /** * Creates a Stack from binary string * @param binary - The binary string * @returns Stack instance */ fromBinary: (binary: string) => Stack; }; //#endregion //#region src/option/Option.d.ts /** * Option type module * @module Option * @category Core */ /** * The Option type represents a value that may or may not exist. * It's used to handle potentially null or undefined values in a type-safe way. * @typeParam T - The type of the value contained in the Option */ interface Option extends Functype, Promisable, Doable, Reshapeable { /** The contained value (undefined for None) */ readonly value: T | undefined; /** Whether this Option contains no value */ isEmpty: boolean; /** * Returns true if this Option is a Some (contains a value) * @returns true if this Option contains a value, false otherwise */ isSome(): this is Option & { value: T; isEmpty: false; }; /** * Returns true if this Option is a None (contains no value) * @returns true if this Option is empty, false otherwise */ isNone(): this is Option & { value: undefined; isEmpty: true; }; /** * Returns the contained value or a default value if None. The default may be of a * different type; the result widens to `T | T2` so Option stays covariant in T. * @param defaultValue - The value to return if this Option is None * @returns The contained value or defaultValue, typed as `T | T2` */ orElse(defaultValue: T2): T | T2; /** * Returns the contained value or throws an error if None * @param error - Optional custom error to throw. If not provided, throws a default error * @returns The contained value * @throws The specified error or a default error if the Option is None */ orThrow(error?: Error): T; /** * Returns the contained value, or calls the never-returning handler if None. * Use this when you have a helper like `(msg) => fail(msg, 2)` that terminates the * program — the result type is unconditionally `T`, so you avoid the TypeScript * narrowing trap where `if (o.isNone()) fail(...)` fails to narrow `o.value` when * `fail` is an arrow function typed as `(...): never`. */ expect(handler: () => never): T; /** * Returns this Option if it contains a value, otherwise returns the alternative container. * The alternative may hold a different type; the result widens to `Option`. * @param alternative - The alternative Option to return if this is None * @returns This Option or the alternative, typed as `Option` */ or(alternative: Option): Option; /** * Returns the contained value or null if None * @returns The contained value or null */ orNull(): T | null; /** * Returns the contained value or undefined if None * @returns The contained value or undefined */ orUndefined(): T | undefined; /** * Maps the value inside the Option using the provided function * @param f - The mapping function * @returns A new Option containing the mapped value, or None if this Option is None */ map(f: (value: T) => U): Option; /** * Applies a wrapped function to a wrapped value (Applicative pattern) * @param ff - An Option containing a function from T to U * @returns A new Option containing the result of applying the function */ ap(ff: Option<(value: T) => U>): Option; /** * Returns this Option if it contains a value that satisfies the predicate, otherwise returns None * @param predicate - The predicate function to test the value * @returns This Option or None */ filter(predicate: (value: T) => boolean): Option; /** * Maps the value using a function that returns an Option * @param f - The mapping function returning an Option * @returns The result of applying f to the contained value, or None if this Option is None */ flatMap(f: (value: T) => Option): Option; /** * Maps the value using an async function that returns an Option * @param f - The async mapping function returning an Option * @returns Promise of the result of applying f to the contained value, or None if this Option is None */ flatMapAsync(f: (value: T) => Promise>): Promise>; /** * Pattern matches over the Option, applying onNone if None and onSome if Some * @param onNone - Function to apply if the Option is None * @param onSome - Function to apply if the Option has a value * @returns The result of applying the appropriate function */ fold(onNone: () => U, onSome: (value: T) => U): U; /** * Async variant of fold. Accepts sync or async handlers on either branch and * always returns a Promise. */ foldAsync(onNone: () => U | Promise, onSome: (value: T) => U | Promise): Promise; /** * Left-associative fold using the provided zero value and operation * @param z - Zero/identity value * @returns A function that takes an operation to apply */ foldLeft(z: B): (op: (b: B, a: T) => B) => B; /** * Right-associative fold using the provided zero value and operation * @param z - Zero/identity value * @returns A function that takes an operation to apply */ foldRight(z: B): (op: (a: T, b: B) => B) => B; /** * Checks if this Option contains the specified value * @param value - The value to check for * @returns true if this Option contains the value, false otherwise */ contains(value: T): boolean; /** * Converts this Option to a List. * @returns A List containing the value if Some, or empty List if None */ toList(): List; /** * Converts this Option to a plain readonly array. * @returns `[value]` if Some, `[]` if None. Symmetric with `toList()` but * skips the List wrapper for code that just wants Array-prototype methods * or spread into another array. */ toArray(): readonly T[]; /** The number of elements in this Option (0 or 1) */ size: number; /** * Converts this Option to an Either * @param leftOrBuilder - The Left value to use if None, or a thunk producing it. * Pass a thunk when the Left value is expensive to construct or carries * context (e.g. `() => ConfigError(missing)`) so the cost is paid only * on the None path. Eager value is fine for cheap errors. * @returns Right(value) if Some, else Left(leftOrBuilder()) / Left(leftOrBuilder) */ toEither(leftOrBuilder: E | (() => E)): Either; /** * Returns a string representation of this Option * @returns A string representation */ toString(): string; /** * Returns a simple object representation of this Option * @returns An object with _tag and value properties */ toValue(): { _tag: "Some" | "None"; value: T; }; /** * Custom JSON serialization producing the canonical `@functype`-marked * envelope so native `JSON.stringify` recursion (e.g. inside a plain * object) emits a round-trip-able shape. */ toJSON(): { "@functype": "Option"; _tag: "Some" | "None"; value: T | null; }; /** * Pattern matches over the Option, applying a handler function based on the variant * @param patterns - Object with handler functions for Some and None variants * @returns The result of applying the matching handler function */ match(patterns: { Some: (value: T) => R; None: () => R; }): R; } /** * Creates a Some variant of Option containing a value. * @param value - The value to wrap in Some * @returns A new Some instance containing the value * @typeParam T - The type of the value */ declare const Some: (value: T) => Option; /** * Creates a None variant of Option representing absence of a value. * @returns A new None instance * @typeParam T - The type that would be contained if this was a Some */ declare const None: () => Option; /** * Safely wraps a value that might be null or undefined in an Option. * Creates Some if the value is defined, None otherwise. * @param value - The value to wrap (might be null/undefined) * @returns Some(value) if value is defined, None otherwise * @typeParam T - The type of the value */ declare const OptionConstructor: (value: T | null | undefined) => Option; declare const Option: ((value: T | null | undefined) => Option) & { /** * Creates an Option from any value. Alias for Option function. * @param value - The value to wrap * @returns Some(value) if value is defined, None otherwise * @typeParam T - The type of the value */ from: (value: T) => Option; /** * Returns a None instance. Alias for None function. * @returns A None instance * @typeParam T - The type that would be contained if this was a Some */ none: () => Option; /** * Type guard to check if an Option is Some * @param option - The Option to check * @returns True if Option is Some */ isSome: (option: Option) => option is Option & { value: T; isEmpty: false; }; /** * Type guard to check if an Option is None * @param option - The Option to check * @returns True if Option is None */ isNone: (option: Option) => option is Option & { value: undefined; isEmpty: true; }; /** * Creates an Option from JSON string * @param json - The JSON string * @returns Option instance */ fromJSON: (json: string) => Option; /** * Creates an Option from YAML string * @param yaml - The YAML string * @returns Option instance */ fromYAML: (yaml: string) => Option; /** * Creates an Option from binary string * @param binary - The binary string * @returns Option instance */ fromBinary: (binary: string) => Option; /** * Combines an array of Options into a single Option containing an array. * Short-circuits on the first None. * @param options - Array of Option values * @returns Some with array of values, or None if any element is None */ sequence: (options: Option[]) => Option; /** * Maps an array through a function returning Option, then sequences the results. * Short-circuits on the first None — `f` is not invoked for elements after the * first None result. * @param arr - Array of values * @param f - Function returning Option * @returns Some with array of mapped values, or None if any application returned None */ traverse: (arr: ReadonlyArray, f: (value: T, index: number) => Option) => Option; }; //#endregion //#region src/conditional/Match.d.ts /** * Type-level utilities for exhaustiveness checking * @internal */ type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; /** @internal */ type IsUnion = [T] extends [UnionToIntersection] ? false : true; /** @internal */ type RequireExhaustive = IsUnion extends true ? (keyof Cases extends T ? (T extends keyof Cases ? Cases : never) : never) : Cases; /** * Pattern types for nested matching * @internal */ type Pattern = T | { [K in keyof T]?: Pattern; } | ((value: T) => boolean) | { _: (value: T) => boolean; }; /** * Extract result from pattern * @internal */ type PatternResult = R | ((matched: T) => R); /** * Untyped Match (before first case is added). * The result type R is inferred when the first case method is called. * This enables proper type inference without requiring explicit type annotations. * * @internal */ type UntypedMatch = { /** * Match against a pattern - infers result type R from the result parameter */ case: (pattern: Pattern, result: PatternResult) => Match; /** * Match a specific value - infers result type R from the result parameter */ caseValue: (match: T, result: R | (() => R)) => Match; /** * Match multiple values - infers result type R from the result parameter */ caseValues: (matches: T[], result: R | (() => R)) => Match; /** * Match with a guard function - infers result type R from the result parameter */ when: (guard: (value: T) => boolean, result: PatternResult) => Match; /** * Match multiple patterns (OR operation) - infers result type R from the result parameter */ caseAny: (patterns: Pattern[], result: PatternResult) => Match; }; /** * Pattern matching construct similar to Scala's match expressions. * Supports exhaustive matching, nested patterns, and guards. * * @example * // Basic pattern matching * const result = Match(value) * .case(x => x > 100, "large") * .case(x => x > 50, "medium") * .default("small") * * @example * // Matching exact values * const message = Match(status) * .caseValue("pending", "Please wait...") * .caseValue("success", "Completed!") * .caseValue("error", "Failed") * .default("Unknown") * * @example * // Nested pattern matching * const user = { name: "John", age: 30, role: "admin" } * const msg = Match(user) * .case({ role: "admin", age: n => n >= 18 }, "Adult admin") * .case({ role: "user" }, u => `User: ${u.name}`) * .default("Guest") */ type Match = { /** * Match against a pattern (value, nested object, or predicate). * The result type R2 is added to the union of possible results. */ case: (pattern: Pattern, result: PatternResult) => Match; /** * Add a case that matches a specific value. * The result type R2 is added to the union of possible results. */ caseValue: (match: T, result: R2 | (() => R2)) => Match; /** * Add a case that matches multiple values. * The result type R2 is added to the union of possible results. */ caseValues: (matches: T[], result: R2 | (() => R2)) => Match; /** * Match with a guard function (alias for readability). * The result type R2 is added to the union of possible results. */ when: (guard: (value: T) => boolean, result: PatternResult) => Match; /** * Match multiple patterns (OR operation). * The result type R2 is added to the union of possible results. */ caseAny: (patterns: Pattern[], result: PatternResult) => Match; /** * Default case - makes match non-exhaustive. * The result type R2 is added to the union of possible results. */ default: (result: PatternResult) => R | R2; /** * Force exhaustive matching (compile-time check for union types) */ exhaustive: () => R; /** * Get result if matched, throws if no match */ orThrow: (errorMessage?: string) => R; /** * Get result wrapped in Option */ toOption: () => Option; }; /** * Pattern matching utility for type-safe conditional logic with exhaustiveness checking, * nested patterns, and guard support * * @example * // Basic pattern matching * const result = Match(value) * .case(x => x > 0, "positive") * .case(x => x < 0, "negative") * .default("zero") * * @example * // Exhaustive matching for union types * type Color = "red" | "green" | "blue" * const hex = Match.exhaustive({ * red: "#FF0000", * green: "#00FF00", * blue: "#0000FF" * })(color) * * @example * // Nested pattern matching * type User = { name: string; age: number; role: "admin" | "user" } * const user: User = { name: "John", age: 30, role: "admin" } * * const message = Match(user) * .case({ role: "admin", age: (n) => n >= 18 }, "Adult admin") * .case({ role: "user" }, u => `User: ${u.name}`) * .default("Unknown") * * @example * // Using exhaustive() method * type Status = "idle" | "loading" | "success" | "error" * const result = Match("success") * .case("idle", "Waiting...") * .case("loading", "Loading...") * .case("success", "Done!") * .case("error", "Failed!") * .exhaustive() */ declare const Match: ((value: T) => UntypedMatch) & { /** * Create a type-safe exhaustive match for union types * @example * type Status = "pending" | "success" | "error" * const status: Status = "success" * const result = Match.exhaustive({ * pending: "Waiting...", * success: "Done!", * error: "Failed!" * })(status) * // result = "Done!" * * @example * // For function values, wrap in object to prevent execution * type Operation = "add" | "subtract" | "multiply" * const ops = Match.exhaustive number }>({ * add: { fn: (a, b) => a + b }, * subtract: { fn: (a, b) => a - b }, * multiply: { fn: (a, b) => a * b } * }) * const compute = ops("multiply").fn * const result = compute(4, 5) // 20 */ exhaustive: (cases: RequireExhaustive>) => (value: T) => R; /** * Create a partial match that requires a default * @example * const httpCode = 404 * const message = Match.partial({ * 200: "OK", * 201: "Created", * 404: "Not Found", * 500: "Server Error" * }).withDefault("Unknown Status")(httpCode) * // message = "Not Found" * * @example * // With function default * const getMessage = Match.partial({ * 0: "Zero", * 1: "One", * 2: "Two" * }).withDefault((n) => `Number: ${n}`) * getMessage(5) // "Number: 5" */ partial: (cases: Partial R)>>) => { withDefault: (defaultValue: R | ((value: T) => R)) => (value: T) => R; }; /** * Pattern match with guards * @example * const score = 85 * const grade = Match.withGuards([ * [n => n >= 90, "A"], * [n => n >= 80, "B"], * [n => n >= 70, "C"], * [n => n >= 60, "D"] * ]).withDefault("F")(score) * // grade = "B" * * @example * // With function results for custom messages * const age = 25 * const category = Match.withGuards([ * [n => n < 13, n => `Child (${n} years)`], * [n => n < 20, n => `Teenager (${n} years)`], * [n => n < 60, n => `Adult (${n} years)`], * [n => n >= 60, n => `Senior (${n} years)`] * ]).withDefault("Unknown")(age) * // category = "Adult (25 years)" */ withGuards: (guards: Array<[(value: T) => boolean, R | ((value: T) => R)]>) => { withDefault: (defaultValue: R | ((value: T) => R)) => (value: T) => R; }; /** * Pattern matching for objects with specific structure * @example * type Event = * | { type: "click"; x: number; y: number } * | { type: "keypress"; key: string } * | { type: "hover"; element: string } * * const handler = Match.struct() * .case({ type: "click" }, (e) => console.log(`Click at ${e.x}, ${e.y}`)) * .case({ type: "keypress", key: "Enter" }, () => console.log("Enter pressed")) * .case({ type: "hover" }, (e) => console.log(`Hovering over ${e.element}`)) * .build() */ struct: () => { case: (pattern: Pattern, handler: (value: T) => R) => /*elided*/ any; build: () => (value: T) => R; }; /** * Create a pattern matcher with guards and nested patterns * @example * type User = { * name: string * age: number * permissions: string[] * } * * const canAccess = Match.builder() * .when(u => u.permissions.includes("admin"), true) * .case({ age: n => n >= 18, permissions: p => p.length > 0 }, true) * .default(false) * .build() */ builder: () => { case: (pattern: Pattern, result: PatternResult) => /*elided*/ any; when: (guard: (value: T) => boolean, result: PatternResult) => /*elided*/ any; default: (result: PatternResult) => { build: () => (value: T) => R; }; }; }; //#endregion export { LayerError as $, Either as $n, TaskOutcome as $t, HttpQueryParams as A, Collection as An, DoGenerator as At, ResponseDecodeError as B, createCustomSerializer as Bn, DecoderError as Bt, TryKind as C, FunctypeSum as Cn, isExtractable as Cr, createErrorSerializer as Ct, HttpClient as D, Traversable as Dn, Cond as Dr, $ as Dt, Http as E, FunctypeCollection as En, Doable as Er, safeStringify as Et, DecodeError as F, JSONValue as Fn, LeftErrorType as Ft, InterruptedError as G, fromBinary as Gn, CancellationTokenSource as Gt, TestClockTag as H, createSerializer as Hn, DecoderErrorLeaf as Ht, HttpError as I, Serialization_d_exports as In, NoneError as It, Task as J, taggedEnvelope as Jn, Sync as Jt, RIO as K, fromJSON as Kn, Err as Kt, HttpMethod as L, FUNCTYPE_MARKER as Ln, isDoCapable as Lt, HttpRequestView as M, List as Mn, FailureError as Mt, HttpResponse as N, Try as Nn, FailureErrorType as Nt, HttpClientConfig as O, Matchable as On, Do as Ot, ParseMode as P, TypeNames as Pn, LeftError as Pt, Layer as Q, LazyList as Qn, TaskMetadata as Qt, HttpStatusError as R, FunctypeEnvelope as Rn, unwrap as Rt, OptionKind as S, ValidatedBrandCompanion as Sn, Extractable as Sr, TaskErrorInfo as St, FoldableUtils as T, FunctypeBase as Tn, DoResult as Tr, formatStackTrace as Tt, TestContext as U, createTaggedSerializer as Un, Async as Ut, TestClock as V, createSerializationCompanion as Vn, DecoderErrorComposite as Vt, IO as W, envelope as Wn, CancellationToken as Wt, UIO as X, deserializeError as Xn, Task$1 as Xt, TimeoutError as Y, SerializedError as Yn, TaggedThrowable as Yt, UnsupportedSyncOperationError as Z, serializeError as Zn, TaskFailure as Zt, Identity as _, PositiveInteger as _n, AsyncMonad as _r, TypedError as _t, OptionConstructor as a, NAME as an, TestEither as ar, ContextServices as at, Kind as b, UrlString as bn, CollectionOps as br, ErrorFormatterOptions as bt, Valuable as c, Base as cn, isLeft as cr, TagService as ct, Obj as d, EmailAddress as dn, tryCatchAsync as dr, Validation as dt, TaskParams as en, EitherBase as er, LayerInput as et, ESMap as f, ISO8601Date as fn, Widen as fr, ValidationRule as ft, Lazy as g, PatternString as gn, Applicative as gr, ErrorStatus as gt, KVTraversable as h, NonNegativeNumber as hn, Promisable as hr, ErrorMessage as ht, Option as i, isTaggedThrowable as in, RightOf as ir, Context as it, HttpRequestOptions as j, Set as jn, EmptyListError as jt, HttpMethodOptions as k, MatchableUtils as kn, DoAsync as kt, ValuableParams as l, BoundedNumber as ln, isRight as lr, FieldValidation as lt, Map$1 as m, NonEmptyString as mn, reduceWiden as mr, ErrorCode as mt, UntypedMatch as n, TaskSuccess as nn, LeftOf as nr, Exit as nt, Some as o, Throwable as on, TypeCheckLeft as or, HasService as ot, ESMapType as p, IntegerNumber as pn, reduceRightWiden as pr, Validator as pt, RepeatExhausted as q, fromYAML as qn, Ok as qt, None as r, createCancellationTokenSource as rn, Right as rr, ExitTag as rt, Stack as s, ThrowableType as sn, TypeCheckRight as sr, Tag as st, Match as t, TaskResult as tn, Left as tr, LayerOutput as tt, Ref as u, BoundedString as un, tryCatch as ur, FormValidation as ut, EitherKind as v, PositiveNumber as vn, Functor as vr, TypedErrorContext as vt, UniversalContainer as w, Functype as wn, ParseError as wr, formatError as wt, ListKind as x, ValidatedBrand as xn, ContainerOps as xr, ErrorWithTaskInfo as xt, HKT as y, UUID as yn, Monad as yr, ErrorChainElement as yt, NetworkError as z, SerializationResult as zn, Decoder as zt };