/** * Broadcasts values from publishers to many subscribers. * * Publishers add messages with `publish` or `publishAll`, and each active * `Subscription` receives its own copy of every accepted message. Unlike a * queue, subscribers do not compete for messages. This module includes bounded, * dropping, sliding, and unbounded hubs, optional replay buffers for late * subscribers, message-taking helpers, capacity and shutdown operations, a * type guard, and low-level types for custom hub strategies. * * @stability stable * @since 2.0.0 */ import * as Arr from "./Array.ts"; import * as Deferred from "./Deferred.ts"; import * as Effect from "./Effect.ts"; import type { LazyArg } from "./Function.ts"; import * as Latch from "./Latch.ts"; import * as MutableList from "./MutableList.ts"; import * as MutableRef from "./MutableRef.ts"; import * as Option from "./Option.ts"; import { type Pipeable } from "./Pipeable.ts"; import * as Scope from "./Scope.ts"; import type { Covariant, Invariant } from "./Types.ts"; declare const TypeId = "~effect/PubSub"; /** * A `PubSub` is an asynchronous message hub into which publishers can publish * messages of type `A` and subscribers can subscribe to take messages of type * `A`. * * **Example** (Publishing and subscribing to messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * // Create a bounded PubSub with capacity 10 * const pubsub = yield* PubSub.bounded(10) * * // Subscribe and consume messages * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish messages * yield* PubSub.publish(pubsub, "Hello") * yield* PubSub.publish(pubsub, "World") * * const message1 = yield* PubSub.take(subscription) * const message2 = yield* PubSub.take(subscription) * return [message1, message2] * })) * * const actual = await Effect.runPromise(program) * actual // => ["Hello", "World"] * ``` * * @stability stable * @category models * @since 2.0.0 */ export interface PubSub extends Pipeable { readonly [TypeId]: { readonly _A: Invariant; }; readonly pubsub: PubSub.Atomic; readonly subscribers: PubSub.Subscribers; readonly scope: Scope.Closeable; readonly shutdownHook: Latch.Latch; readonly shutdownFlag: MutableRef.MutableRef; readonly strategy: PubSub.Strategy; readonly ended: MutableRef.MutableRef>; } /** * Companion namespace containing the low-level building blocks used by * `PubSub`, including atomic implementations, backing subscriptions, replay * windows, and delivery strategies. * * @stability stable * @since 2.0.0 */ export declare namespace PubSub { /** * Low-level atomic PubSub interface that handles the core message storage and retrieval. * * @category models * @since 4.0.0 */ interface Atomic { readonly capacity: number; isEmpty(): boolean; isFull(): boolean; size(): number; publish(value: A): boolean; publishAll(elements: Iterable): Array; slide(): void; subscribe(): BackingSubscription; replayWindow(): ReplayWindow; } /** * Low-level subscription interface that handles message polling for individual subscribers. * * @category models * @since 4.0.0 */ interface BackingSubscription { isEmpty(): boolean; size(): number; poll(): A | MutableList.Empty; pollUpTo(n: number): Array; unsubscribe(): void; } /** * Tracks the pollers currently waiting on each backing subscription. * * **Details** * * This type is part of the low-level `PubSub.Strategy` contract. Most * application code should use `subscribe`, `take`, and the other `PubSub` * operations instead of manipulating subscriber maps directly. * * @category models * @since 4.0.0 */ type Subscribers = Map, Set>>>; /** * Interface for accessing replay buffer contents for late subscribers. * * @category models * @since 4.0.0 */ interface ReplayWindow { take(): A | undefined; takeN(n: number): Array; takeAll(): Array; close(): void; readonly remaining: number; } /** * Strategy interface defining how PubSub handles backpressure and message distribution. * * @category models * @since 4.0.0 */ interface Strategy { /** * Describes any finalization logic associated with this strategy. */ readonly shutdown: Effect.Effect; /** * Describes how publishers should signal to subscribers that they are * waiting for space to become available in the `PubSub`. * * **Details** * * The publisher may have yielded since `publish` checked `ended`, so it * must be checked again before registering or publishing the surplus. */ handleSurplus(pubsub: Atomic, subscribers: Subscribers, elements: Iterable, isShutdown: MutableRef.MutableRef, ended: MutableRef.MutableRef>): Effect.Effect; /** * Describes how subscribers should signal to publishers waiting for space * to become available in the `PubSub` that space may be available. */ onPubSubEmptySpaceUnsafe(pubsub: Atomic, subscribers: Subscribers): void; /** * Describes how subscribers waiting for additional values from the `PubSub` * should take those values and signal to publishers that they are no * longer waiting for additional values. */ completePollersUnsafe(pubsub: Atomic, subscribers: Subscribers, subscription: BackingSubscription, pollers: MutableList.MutableList>): void; /** * Describes how publishers should signal to subscribers waiting for * additional values from the `PubSub` that new values are available. */ completeSubscribersUnsafe(pubsub: Atomic, subscribers: Subscribers): void; } } /** * Returns `true` if a value is a `PubSub`. * * **Details** * * This is a type guard that checks for the `PubSub` runtime marker. * * **Example** (Checking if a value is a PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * return [PubSub.isPubSub(pubsub), PubSub.isPubSub({}), PubSub.isPubSub(null)] * }) * * const actual = await Effect.runPromise(program) * actual // => [true, false, false] * ``` * * @stability stable * @category guards * @since 4.0.0 */ export declare const isPubSub: (u: unknown) => u is PubSub; declare const SubscriptionTypeId = "~effect/PubSub/Subscription"; /** * A subscription represents a consumer's connection to a PubSub, allowing them to take messages. * * **Example** (Taking messages from a subscription) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Subscribe within a scope for automatic cleanup * const subscription: PubSub.Subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"]) * * // Take individual messages * const message = yield* PubSub.take(subscription) * * // Take multiple messages * const messages = yield* PubSub.takeUpTo(subscription, 1) * const allMessages = yield* PubSub.takeAll(subscription) * return { message, messages, allMessages } * })) * * const actual = await Effect.runPromise(program) * actual // => { message: "msg1", messages: ["msg2"], allMessages: ["msg3"] } * ``` * * @stability stable * @category models * @since 4.0.0 */ export interface Subscription extends Pipeable { readonly [SubscriptionTypeId]: { readonly _A: Covariant; }; readonly pubsub: PubSub.Atomic; readonly subscribers: PubSub.Subscribers; readonly subscription: PubSub.BackingSubscription; readonly pollers: MutableList.MutableList>; readonly shutdownHook: Latch.Latch; readonly shutdownFlag: MutableRef.MutableRef; readonly strategy: PubSub.Strategy; readonly replayWindow: PubSub.ReplayWindow; readonly ended: MutableRef.MutableRef>; } /** * Creates a PubSub with a custom atomic implementation and strategy. * * **Example** (Creating a PubSub with a custom strategy) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * // Create custom PubSub with specific atomic implementation and strategy * const pubsub = yield* PubSub.make({ * atomicPubSub: () => PubSub.makeAtomicBounded(100), * strategy: () => new PubSub.BackPressureStrategy() * }) * * // Use the created PubSub * const published = yield* PubSub.publish(pubsub, "Hello") * yield* PubSub.shutdown(pubsub) * return published * }) * * const actual = await Effect.runPromise(program) * actual // => true * ``` * * @stability stable * @category constructors * @since 4.0.0 */ export declare const make: (options: { readonly atomicPubSub: LazyArg>; readonly strategy: LazyArg>; }) => Effect.Effect>; /** * Creates a bounded `PubSub` that applies backpressure when it reaches * capacity. * * **Details** * * Published messages are retained until all current subscribers have taken * them. When the capacity is full, publishers suspend until space is available. * Pass an options object to configure both `capacity` and an optional replay * buffer for late subscribers. * The capacity must be a positive integer or `Infinity` for unbounded storage. * Invalid capacities cause the effect to die. * * **Example** (Creating a bounded PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * // Create bounded PubSub with capacity 100 * const pubsub = yield* PubSub.bounded(100) * * // Create with replay buffer for late subscribers * const pubsubWithReplay = yield* PubSub.bounded({ * capacity: 100, * replay: 10 // Last 10 messages replayed to new subscribers * }) * * const capacities = [PubSub.capacity(pubsub), PubSub.capacity(pubsubWithReplay)] * yield* PubSub.shutdown(pubsub) * yield* PubSub.shutdown(pubsubWithReplay) * return capacities * }) * * const actual = await Effect.runPromise(program) * actual // => [100, 100] * ``` * * @stability stable * @category constructors * @since 2.0.0 */ export declare const bounded: (capacity: number | { readonly capacity: number; readonly replay?: number | undefined; }) => Effect.Effect>; /** * Creates a bounded `PubSub` with the dropping strategy. The `PubSub` will drop new * messages if the `PubSub` is at capacity. * * **Details** * * The capacity must be a positive integer or `Infinity` for unbounded storage. * Invalid capacities cause the effect to die. * For best performance use capacities that are powers of two. * * **Example** (Dropping messages when full) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * // Create dropping PubSub that drops new messages when full * const pubsub = yield* PubSub.dropping(3) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Fill the PubSub and see dropping behavior * yield* PubSub.publish(pubsub, "msg1") // succeeds * yield* PubSub.publish(pubsub, "msg2") // succeeds * yield* PubSub.publish(pubsub, "msg3") // succeeds * const dropped = yield* PubSub.publish(pubsub, "msg4") // returns false (dropped) * * const messages = yield* PubSub.takeAll(subscription) * return { dropped: !dropped, messages } * })) * * const actual = await Effect.runPromise(program) * actual // => { dropped: true, messages: ["msg1", "msg2", "msg3"] } * ``` * * @stability stable * @category constructors * @since 2.0.0 */ export declare const dropping: (capacity: number | { readonly capacity: number; readonly replay?: number | undefined; }) => Effect.Effect>; /** * Creates a bounded `PubSub` with the sliding strategy. The `PubSub` will add new * messages and drop old messages if the `PubSub` is at capacity. * * **Details** * * The capacity must be a positive integer or `Infinity` for unbounded storage. * Invalid capacities cause the effect to die. * For best performance use capacities that are powers of two. * * **Example** (Sliding old messages when full) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * // Create sliding PubSub that evicts old messages when full * const pubsub = yield* PubSub.sliding(3) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Fill and overflow the PubSub * yield* PubSub.publish(pubsub, "msg1") * yield* PubSub.publish(pubsub, "msg2") * yield* PubSub.publish(pubsub, "msg3") * yield* PubSub.publish(pubsub, "msg4") // "msg1" is evicted * * return yield* PubSub.takeAll(subscription) * })) * * const actual = await Effect.runPromise(program) * actual // => ["msg2", "msg3", "msg4"] * ``` * * @stability stable * @category constructors * @since 2.0.0 */ export declare const sliding: (capacity: number | { readonly capacity: number; readonly replay?: number | undefined; }) => Effect.Effect>; /** * Creates an unbounded `PubSub`. * * **Example** (Creating an unbounded PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * // Create unbounded PubSub * const pubsub = yield* PubSub.unbounded() * * const subscription = yield* PubSub.subscribe(pubsub) * * // Can publish unlimited messages * for (let i = 0; i < 3; i++) { * yield* PubSub.publish(pubsub, `message-${i}`) * } * * return yield* PubSub.takeAll(subscription) * })) * * const actual = await Effect.runPromise(program) * actual // => ["message-0", "message-1", "message-2"] * ``` * * @stability stable * @category constructors * @since 2.0.0 */ export declare const unbounded: (options?: { readonly replay?: number | undefined; }) => Effect.Effect>; /** * Creates a bounded atomic PubSub implementation with optional replay buffer. * * **When to use** * * Use to provide bounded message storage when building a custom `PubSub` with * `make` and an explicit delivery strategy. * * **Details** * * Pass either a capacity number or an options object with `capacity` and * optional `replay`. A positive `replay` value enables a replay buffer for late * subscribers, and fractional replay sizes are rounded up. * * **Gotchas** * * The capacity must be a positive integer or `Infinity` for unbounded storage; * invalid capacities throw synchronously before an atomic implementation is * created. * * @see {@link make} for constructing a `PubSub` from an atomic implementation and delivery strategy * @see {@link makeAtomicUnbounded} for an atomic implementation without a bounded capacity * @see {@link bounded} for the higher-level backpressure constructor * @see {@link dropping} for the higher-level dropping constructor * @see {@link sliding} for the higher-level sliding constructor * * @stability stable * @category constructors * @since 4.0.0 */ export declare const makeAtomicBounded: (capacity: number | { readonly capacity: number; readonly replay?: number | undefined; }) => PubSub.Atomic; /** * Creates an unbounded atomic PubSub implementation with optional replay buffer. * * **When to use** * * Use to create the low-level storage layer for a custom `PubSub` whose active * subscribers may retain an unbounded number of pending messages. * * **Gotchas** * * Messages published while subscribers are active can be retained without a * capacity limit until those subscribers take them or unsubscribe. * * @see {@link makeAtomicBounded} for a bounded atomic implementation that enforces capacity * @see {@link make} for wrapping an atomic implementation with a delivery strategy * @see {@link unbounded} for the high-level effectful constructor for unbounded `PubSub` values * * @stability stable * @category constructors * @since 4.0.0 */ export declare const makeAtomicUnbounded: (options?: { readonly replay?: number | undefined; }) => PubSub.Atomic; /** * Returns the number of elements the queue can hold. * * **Example** (Getting PubSub capacity) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(100) * const unboundedPubsub = yield* PubSub.unbounded() * return [PubSub.capacity(pubsub), PubSub.capacity(unboundedPubsub)] * }) * * const actual = await Effect.runPromise(program) * actual // => [100, Number.MAX_SAFE_INTEGER] * ``` * * @stability stable * @category getters * @since 2.0.0 */ export declare const capacity: (self: PubSub) => number; /** * Returns the current number of messages retained by the `PubSub` for active * subscribers. * * **Details** * * If the `PubSub` has been shut down, the returned effect succeeds with `0`. * The size is not a count of waiting subscribers or suspended publishers. * * **Example** (Getting PubSub size) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Initially empty * const initialSize = yield* PubSub.size(pubsub) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish some messages for the active subscription * yield* PubSub.publish(pubsub, "msg1") * yield* PubSub.publish(pubsub, "msg2") * * const afterPublish = yield* PubSub.size(pubsub) * const messages = yield* PubSub.takeAll(subscription) * return { initialSize, afterPublish, messages } * })) * * const actual = await Effect.runPromise(program) * actual // => { initialSize: 0, afterPublish: 2, messages: ["msg1", "msg2"] } * ``` * * @stability stable * @category getters * @since 2.0.0 */ export declare const size: (self: PubSub) => Effect.Effect; /** * Returns the current number of messages retained by the `PubSub` for active * subscribers synchronously. * * **When to use** * * Use when an immediate `PubSub` size snapshot is needed outside effectful code * and concurrent changes between the check and later use are acceptable. * * **Details** * * Returns `0` after shutdown. Because this is an unsafe synchronous snapshot, * prefer `size` in effectful code. * * **Example** (Reading size synchronously) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * return PubSub.sizeUnsafe(pubsub) * }) * * const actual = await Effect.runPromise(program) * actual // => 0 * ``` * * @stability stable * @category getters * @since 4.0.0 */ export declare const sizeUnsafe: (self: PubSub) => number; /** * Returns `true` when the `PubSub` has reached its configured capacity. * * **Details** * * For unbounded PubSubs this is normally `false`. * * **Example** (Checking whether a PubSub is full) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * * // Initially not full * const initiallyFull = yield* PubSub.isFull(pubsub) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Fill the PubSub for the active subscription * yield* PubSub.publish(pubsub, "msg1") * yield* PubSub.publish(pubsub, "msg2") * * const nowFull = yield* PubSub.isFull(pubsub) * const messages = yield* PubSub.takeAll(subscription) * return { initiallyFull, nowFull, messages } * })) * * const actual = await Effect.runPromise(program) * actual // => { initiallyFull: false, nowFull: true, messages: ["msg1", "msg2"] } * ``` * * @stability stable * @category predicates * @since 2.0.0 */ export declare const isFull: (self: PubSub) => Effect.Effect; /** * Returns `true` if the `Pubsub` contains zero elements, `false` otherwise. * * **Example** (Checking whether a PubSub is empty) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Initially empty * const initiallyEmpty = yield* PubSub.isEmpty(pubsub) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish a message for the active subscription * yield* PubSub.publish(pubsub, "Hello") * * const nowEmpty = yield* PubSub.isEmpty(pubsub) * const message = yield* PubSub.take(subscription) * return { initiallyEmpty, nowEmpty, message } * })) * * const actual = await Effect.runPromise(program) * actual // => { initiallyEmpty: true, nowEmpty: false, message: "Hello" } * ``` * * @stability stable * @category predicates * @since 2.0.0 */ export declare const isEmpty: (self: PubSub) => Effect.Effect; /** * Shuts down the `PubSub`, interrupting suspended publishers and subscribers * and finalizing active subscriptions. * * **Details** * * After shutdown, `publish` and `publishAll` succeed with `false`, * `publishUnsafe` returns `false`, and subscription operations such as `take` * interrupt. * * **Example** (Shutting down a PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(1) * * // Shutdown the PubSub * yield* PubSub.shutdown(pubsub) * * const isShutdown = yield* PubSub.isShutdown(pubsub) * * // Publishing after shutdown returns false * const published = yield* PubSub.publish(pubsub, "msg1") * return { isShutdown, published } * }) * * const actual = await Effect.runPromise(program) * actual // => { isShutdown: true, published: false } * ``` * * @stability stable * @category lifecycle * @since 2.0.0 */ export declare const shutdown: (self: PubSub) => Effect.Effect; /** * Ends the `PubSub` with a final message. * * **When to use** * * Use to tell every subscriber that no more messages will follow, without * losing the messages they have not consumed yet. * * **Details** * * Later publishes return `false`, as do publishers waiting for capacity when * `end` is called. Each subscriber receives the messages already buffered * for it, then the final message. Subscribers that arrive * after the end receive the replayed messages, if any, and then the final * message. The final message never occupies capacity, so a bounded `PubSub` * cannot drop it. Returns `false` if the `PubSub` was already ended or shut * down. * * `take`, `takeAll`, and `takeBetween` deliver the final message; * non-suspending `takeUpTo` does not. * * **Gotchas** * * The final message is sticky: subsequent takes return it again. Consumers * must treat it as terminal rather than continuing to take messages. * * **Example** (Ending a PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publish(pubsub, "Hello") * const ended = yield* PubSub.end(pubsub, "Bye") * * // Later publishes are rejected * const published = yield* PubSub.publish(pubsub, "World") * * // Buffered messages are delivered before the final message * const first = yield* PubSub.take(subscription) * const last = yield* PubSub.take(subscription) * * // Late subscribers receive the final message too * const late = yield* PubSub.subscribe(pubsub) * const lateMessage = yield* PubSub.take(late) * return [ended, published, first, last, lateMessage] * })) * * const actual = await Effect.runPromise(program) * actual // => [true, false, "Hello", "Bye", "Bye"] * ``` * * @see {@link shutdown} for interrupting subscribers instead of delivering a final message * * @stability stable * @category lifecycle * @since 4.0.0 */ export declare const end: { /** * Ends the `PubSub` with a final message. * * **When to use** * * Use to tell every subscriber that no more messages will follow, without * losing the messages they have not consumed yet. * * **Details** * * Later publishes return `false`, as do publishers waiting for capacity when * `end` is called. Each subscriber receives the messages already buffered * for it, then the final message. Subscribers that arrive * after the end receive the replayed messages, if any, and then the final * message. The final message never occupies capacity, so a bounded `PubSub` * cannot drop it. Returns `false` if the `PubSub` was already ended or shut * down. * * `take`, `takeAll`, and `takeBetween` deliver the final message; * non-suspending `takeUpTo` does not. * * **Gotchas** * * The final message is sticky: subsequent takes return it again. Consumers * must treat it as terminal rather than continuing to take messages. * * **Example** (Ending a PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publish(pubsub, "Hello") * const ended = yield* PubSub.end(pubsub, "Bye") * * // Later publishes are rejected * const published = yield* PubSub.publish(pubsub, "World") * * // Buffered messages are delivered before the final message * const first = yield* PubSub.take(subscription) * const last = yield* PubSub.take(subscription) * * // Late subscribers receive the final message too * const late = yield* PubSub.subscribe(pubsub) * const lateMessage = yield* PubSub.take(late) * return [ended, published, first, last, lateMessage] * })) * * const actual = await Effect.runPromise(program) * actual // => [true, false, "Hello", "Bye", "Bye"] * ``` * * @see {@link shutdown} for interrupting subscribers instead of delivering a final message * * @stability stable * @category lifecycle * @since 4.0.0 */ (value: A): (self: PubSub) => Effect.Effect; /** * Ends the `PubSub` with a final message. * * **When to use** * * Use to tell every subscriber that no more messages will follow, without * losing the messages they have not consumed yet. * * **Details** * * Later publishes return `false`, as do publishers waiting for capacity when * `end` is called. Each subscriber receives the messages already buffered * for it, then the final message. Subscribers that arrive * after the end receive the replayed messages, if any, and then the final * message. The final message never occupies capacity, so a bounded `PubSub` * cannot drop it. Returns `false` if the `PubSub` was already ended or shut * down. * * `take`, `takeAll`, and `takeBetween` deliver the final message; * non-suspending `takeUpTo` does not. * * **Gotchas** * * The final message is sticky: subsequent takes return it again. Consumers * must treat it as terminal rather than continuing to take messages. * * **Example** (Ending a PubSub) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publish(pubsub, "Hello") * const ended = yield* PubSub.end(pubsub, "Bye") * * // Later publishes are rejected * const published = yield* PubSub.publish(pubsub, "World") * * // Buffered messages are delivered before the final message * const first = yield* PubSub.take(subscription) * const last = yield* PubSub.take(subscription) * * // Late subscribers receive the final message too * const late = yield* PubSub.subscribe(pubsub) * const lateMessage = yield* PubSub.take(late) * return [ended, published, first, last, lateMessage] * })) * * const actual = await Effect.runPromise(program) * actual // => [true, false, "Hello", "Bye", "Bye"] * ``` * * @see {@link shutdown} for interrupting subscribers instead of delivering a final message * * @stability stable * @category lifecycle * @since 4.0.0 */ (self: PubSub, value: A): Effect.Effect; }; /** * Ends the `PubSub` with a final message synchronously. * * **Details** * * See {@link end} for the semantics. * * @stability stable * @category lifecycle * @since 4.0.0 */ export declare const endUnsafe: { /** * Ends the `PubSub` with a final message synchronously. * * **Details** * * See {@link end} for the semantics. * * @stability stable * @category lifecycle * @since 4.0.0 */ (value: A): (self: PubSub) => boolean; /** * Ends the `PubSub` with a final message synchronously. * * **Details** * * See {@link end} for the semantics. * * @stability stable * @category lifecycle * @since 4.0.0 */ (self: PubSub, value: A): boolean; }; /** * Checks effectfully whether `shutdown` has been called, returning `true` * after shutdown and `false` otherwise. * * **Example** (Checking whether a PubSub is shut down) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Initially not shutdown * const initiallyShutdown = yield* PubSub.isShutdown(pubsub) * * // Shutdown the PubSub * yield* PubSub.shutdown(pubsub) * * const nowShutdown = yield* PubSub.isShutdown(pubsub) * return [initiallyShutdown, nowShutdown] * }) * * const actual = await Effect.runPromise(program) * actual // => [false, true] * ``` * * @stability stable * @category predicates * @since 2.0.0 */ export declare const isShutdown: (self: PubSub) => Effect.Effect; /** * Checks synchronously whether `shutdown` has been called, returning `true` * after shutdown and `false` otherwise. * * **When to use** * * Use when an immediate `PubSub` shutdown-state snapshot is needed outside * effectful code and racing shutdown changes are acceptable. * * **Example** (Checking shutdown synchronously) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * const initiallyShutdown = PubSub.isShutdownUnsafe(pubsub) * yield* PubSub.shutdown(pubsub) * return [initiallyShutdown, PubSub.isShutdownUnsafe(pubsub)] * }) * * const actual = await Effect.runPromise(program) * actual // => [false, true] * ``` * * @stability stable * @category predicates * @since 4.0.0 */ export declare const isShutdownUnsafe: (self: PubSub) => boolean; /** * Waits until the queue is shutdown. The `Effect` returned by this method will * not resume until the queue has been shutdown. If the queue is already * shutdown, the `Effect` will resume right away. * * **Example** (Waiting for shutdown) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Start a fiber that waits for shutdown * const waiterFiber = yield* Effect.forkChild( * Effect.gen(function*() { * yield* PubSub.awaitShutdown(pubsub) * return "PubSub has been shutdown!" * }) * ) * * // Shutdown the PubSub * yield* PubSub.shutdown(pubsub) * * // The waiter will now complete * return yield* Fiber.join(waiterFiber) * }) * * const actual = await Effect.runPromise(program) * actual // => "PubSub has been shutdown!" * ``` * * @stability stable * @category lifecycle * @since 2.0.0 */ export declare const awaitShutdown: (self: PubSub) => Effect.Effect; /** * Publishes a message to the `PubSub` as an `Effect`, returning whether the * message was accepted. * * **When to use** * * Use when you need to publish from effectful code and let the configured * PubSub strategy handle surplus messages. * * **Details** * * The effect succeeds with `false` if the `PubSub` is shut down. If the message * cannot be accepted immediately, the configured strategy decides how surplus * messages are handled. * * **Example** (Publishing a message) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Publish a message * const published = yield* PubSub.publish(pubsub, "Hello World") * * const subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publish(pubsub, "Hello") * const message = yield* PubSub.take(subscription) * return { published, message } * })) * * const actual = await Effect.runPromise(program) * actual // => { published: true, message: "Hello" } * ``` * * @see {@link publishUnsafe} for a synchronous non-blocking attempt that does not run effectful surplus handling * * @stability stable * @category publishing * @since 2.0.0 */ export declare const publish: { /** * Publishes a message to the `PubSub` as an `Effect`, returning whether the * message was accepted. * * **When to use** * * Use when you need to publish from effectful code and let the configured * PubSub strategy handle surplus messages. * * **Details** * * The effect succeeds with `false` if the `PubSub` is shut down. If the message * cannot be accepted immediately, the configured strategy decides how surplus * messages are handled. * * **Example** (Publishing a message) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Publish a message * const published = yield* PubSub.publish(pubsub, "Hello World") * * const subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publish(pubsub, "Hello") * const message = yield* PubSub.take(subscription) * return { published, message } * })) * * const actual = await Effect.runPromise(program) * actual // => { published: true, message: "Hello" } * ``` * * @see {@link publishUnsafe} for a synchronous non-blocking attempt that does not run effectful surplus handling * * @stability stable * @category publishing * @since 2.0.0 */ (value: A): (self: PubSub) => Effect.Effect; /** * Publishes a message to the `PubSub` as an `Effect`, returning whether the * message was accepted. * * **When to use** * * Use when you need to publish from effectful code and let the configured * PubSub strategy handle surplus messages. * * **Details** * * The effect succeeds with `false` if the `PubSub` is shut down. If the message * cannot be accepted immediately, the configured strategy decides how surplus * messages are handled. * * **Example** (Publishing a message) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Publish a message * const published = yield* PubSub.publish(pubsub, "Hello World") * * const subscription = yield* PubSub.subscribe(pubsub) * * yield* PubSub.publish(pubsub, "Hello") * const message = yield* PubSub.take(subscription) * return { published, message } * })) * * const actual = await Effect.runPromise(program) * actual // => { published: true, message: "Hello" } * ``` * * @see {@link publishUnsafe} for a synchronous non-blocking attempt that does not run effectful surplus handling * * @stability stable * @category publishing * @since 2.0.0 */ (self: PubSub, value: A): Effect.Effect; }; /** * Attempts to publish a message synchronously without applying the PubSub * strategy's effectful surplus handling. * * **When to use** * * Use when you need a non-blocking synchronous publish attempt where `false` * is an acceptable result when the message cannot be accepted immediately. * * **Details** * * Returns `false` if the `PubSub` is shut down or the message cannot be * accepted immediately, for example when a bounded PubSub is full. Prefer * `publish` when backpressure or sliding behavior should be honored. * * **Example** (Publishing without suspending) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * return PubSub.publishUnsafe(pubsub, "Hello") * }) * * const actual = await Effect.runPromise(program) * actual // => true * ``` * * @see {@link publish} for effectful publishing that honors the configured surplus strategy * * @stability stable * @category publishing * @since 4.0.0 */ export declare const publishUnsafe: { /** * Attempts to publish a message synchronously without applying the PubSub * strategy's effectful surplus handling. * * **When to use** * * Use when you need a non-blocking synchronous publish attempt where `false` * is an acceptable result when the message cannot be accepted immediately. * * **Details** * * Returns `false` if the `PubSub` is shut down or the message cannot be * accepted immediately, for example when a bounded PubSub is full. Prefer * `publish` when backpressure or sliding behavior should be honored. * * **Example** (Publishing without suspending) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * return PubSub.publishUnsafe(pubsub, "Hello") * }) * * const actual = await Effect.runPromise(program) * actual // => true * ``` * * @see {@link publish} for effectful publishing that honors the configured surplus strategy * * @stability stable * @category publishing * @since 4.0.0 */ (value: A): (self: PubSub) => boolean; /** * Attempts to publish a message synchronously without applying the PubSub * strategy's effectful surplus handling. * * **When to use** * * Use when you need a non-blocking synchronous publish attempt where `false` * is an acceptable result when the message cannot be accepted immediately. * * **Details** * * Returns `false` if the `PubSub` is shut down or the message cannot be * accepted immediately, for example when a bounded PubSub is full. Prefer * `publish` when backpressure or sliding behavior should be honored. * * **Example** (Publishing without suspending) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * return PubSub.publishUnsafe(pubsub, "Hello") * }) * * const actual = await Effect.runPromise(program) * actual // => true * ``` * * @see {@link publish} for effectful publishing that honors the configured surplus strategy * * @stability stable * @category publishing * @since 4.0.0 */ (self: PubSub, value: A): boolean; }; /** * Publishes all of the specified messages to the `PubSub`, returning whether they * were published to the `PubSub`. * * **Example** (Publishing multiple messages) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Publish multiple messages at once * const allPublished = yield* PubSub.publishAll(pubsub, ["Hello", "World", "from", "Effect"]) * * // With a smaller capacity and an active subscription * const smallPubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(smallPubsub) * * // Will suspend until space becomes available for all messages * const fiber = yield* Effect.forkChild(PubSub.publishAll(smallPubsub, ["msg1", "msg2", "msg3", "msg4"])) * * const firstBatch = yield* PubSub.takeBetween(subscription, 2, 2) * const result = yield* Fiber.join(fiber) * const secondBatch = yield* PubSub.takeAll(subscription) * return { allPublished, firstBatch, result, secondBatch } * })) * * const actual = await Effect.runPromise(program) * actual // => { allPublished: true, firstBatch: ["msg1", "msg2"], result: true, secondBatch: ["msg3", "msg4"] } * ``` * * @stability stable * @category publishing * @since 2.0.0 */ export declare const publishAll: { /** * Publishes all of the specified messages to the `PubSub`, returning whether they * were published to the `PubSub`. * * **Example** (Publishing multiple messages) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Publish multiple messages at once * const allPublished = yield* PubSub.publishAll(pubsub, ["Hello", "World", "from", "Effect"]) * * // With a smaller capacity and an active subscription * const smallPubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(smallPubsub) * * // Will suspend until space becomes available for all messages * const fiber = yield* Effect.forkChild(PubSub.publishAll(smallPubsub, ["msg1", "msg2", "msg3", "msg4"])) * * const firstBatch = yield* PubSub.takeBetween(subscription, 2, 2) * const result = yield* Fiber.join(fiber) * const secondBatch = yield* PubSub.takeAll(subscription) * return { allPublished, firstBatch, result, secondBatch } * })) * * const actual = await Effect.runPromise(program) * actual // => { allPublished: true, firstBatch: ["msg1", "msg2"], result: true, secondBatch: ["msg3", "msg4"] } * ``` * * @stability stable * @category publishing * @since 2.0.0 */ (elements: Iterable): (self: PubSub) => Effect.Effect; /** * Publishes all of the specified messages to the `PubSub`, returning whether they * were published to the `PubSub`. * * **Example** (Publishing multiple messages) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Publish multiple messages at once * const allPublished = yield* PubSub.publishAll(pubsub, ["Hello", "World", "from", "Effect"]) * * // With a smaller capacity and an active subscription * const smallPubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(smallPubsub) * * // Will suspend until space becomes available for all messages * const fiber = yield* Effect.forkChild(PubSub.publishAll(smallPubsub, ["msg1", "msg2", "msg3", "msg4"])) * * const firstBatch = yield* PubSub.takeBetween(subscription, 2, 2) * const result = yield* Fiber.join(fiber) * const secondBatch = yield* PubSub.takeAll(subscription) * return { allPublished, firstBatch, result, secondBatch } * })) * * const actual = await Effect.runPromise(program) * actual // => { allPublished: true, firstBatch: ["msg1", "msg2"], result: true, secondBatch: ["msg3", "msg4"] } * ``` * * @stability stable * @category publishing * @since 2.0.0 */ (self: PubSub, elements: Iterable): Effect.Effect; }; /** * Subscribes to receive messages from the `PubSub`. The resulting subscription can * be evaluated multiple times within the scope to take a message from the `PubSub` * each time. * * **Example** (Subscribing to messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * // Subscribe within a scope for automatic cleanup * const first = yield* Effect.scoped(Effect.gen(function*() { * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish some messages * yield* PubSub.publish(pubsub, "Hello") * yield* PubSub.publish(pubsub, "World") * * // Take messages one by one * const msg1 = yield* PubSub.take(subscription) * const msg2 = yield* PubSub.take(subscription) * * // Subscription is automatically cleaned up when scope exits * return [msg1, msg2] * })) * * const second = yield* Effect.scoped(Effect.gen(function*() { * const sub1 = yield* PubSub.subscribe(pubsub) * const sub2 = yield* PubSub.subscribe(pubsub) * * // Multiple subscribers can receive the same messages * yield* PubSub.publish(pubsub, "Broadcast") * * return yield* Effect.all([ * PubSub.take(sub1), * PubSub.take(sub2) * ]) * })) * return [first, second] * }) * * const actual = await Effect.runPromise(program) * actual // => [["Hello", "World"], ["Broadcast", "Broadcast"]] * ``` * * @stability stable * @category subscriptions * @since 2.0.0 */ export declare const subscribe: (self: PubSub) => Effect.Effect, never, Scope.Scope>; /** * Takes a single message from the subscription. If no messages are available, * this will suspend until a message becomes available. * * **Example** (Taking a message) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Start a fiber to take a message (will suspend) * const takeFiber = yield* Effect.forkChild(PubSub.take(subscription)) * * // Publish a message * yield* PubSub.publish(pubsub, "Hello") * * // The take will now complete * return yield* Fiber.join(takeFiber) * })) * * const actual = await Effect.runPromise(program) * actual // => "Hello" * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ export declare const take: (self: Subscription) => Effect.Effect; /** * Takes all available messages from the subscription, suspending if no items * are available. * * **Example** (Taking all available messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish multiple messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"]) * * // Take all available messages at once * return yield* PubSub.takeAll(subscription) * })) * * const actual = await Effect.runPromise(program) * actual // => ["msg1", "msg2", "msg3"] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ export declare const takeAll: (self: Subscription) => Effect.Effect>; /** * Takes up to the specified number of messages from the subscription without * suspending. Finite fractional values are rounded down, while `NaN` and * non-positive values are treated as `0`. * * **Example** (Taking up to a maximum number of messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish multiple messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3", "msg4", "msg5"]) * * // Take up to 3 messages * const upTo3 = yield* PubSub.takeUpTo(subscription, 3) * * // Take up to 5 more (only 2 remaining) * const upTo5 = yield* PubSub.takeUpTo(subscription, 5) * * // No more messages available * const noMore = yield* PubSub.takeUpTo(subscription, 10) * return [upTo3, upTo5, noMore] * })) * * const actual = await Effect.runPromise(program) * actual // => [["msg1", "msg2", "msg3"], ["msg4", "msg5"], []] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ export declare const takeUpTo: { /** * Takes up to the specified number of messages from the subscription without * suspending. Finite fractional values are rounded down, while `NaN` and * non-positive values are treated as `0`. * * **Example** (Taking up to a maximum number of messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish multiple messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3", "msg4", "msg5"]) * * // Take up to 3 messages * const upTo3 = yield* PubSub.takeUpTo(subscription, 3) * * // Take up to 5 more (only 2 remaining) * const upTo5 = yield* PubSub.takeUpTo(subscription, 5) * * // No more messages available * const noMore = yield* PubSub.takeUpTo(subscription, 10) * return [upTo3, upTo5, noMore] * })) * * const actual = await Effect.runPromise(program) * actual // => [["msg1", "msg2", "msg3"], ["msg4", "msg5"], []] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ (max: number): (self: Subscription) => Effect.Effect>; /** * Takes up to the specified number of messages from the subscription without * suspending. Finite fractional values are rounded down, while `NaN` and * non-positive values are treated as `0`. * * **Example** (Taking up to a maximum number of messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish multiple messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3", "msg4", "msg5"]) * * // Take up to 3 messages * const upTo3 = yield* PubSub.takeUpTo(subscription, 3) * * // Take up to 5 more (only 2 remaining) * const upTo5 = yield* PubSub.takeUpTo(subscription, 5) * * // No more messages available * const noMore = yield* PubSub.takeUpTo(subscription, 10) * return [upTo3, upTo5, noMore] * })) * * const actual = await Effect.runPromise(program) * actual // => [["msg1", "msg2", "msg3"], ["msg4", "msg5"], []] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ (self: Subscription, max: number): Effect.Effect>; }; /** * Takes between the specified minimum and maximum number of messages from the * subscription. Finite fractional bounds are rounded down, while `NaN` and * non-positive bounds are treated as `0`. Will suspend if the normalized * minimum number is not immediately available. * * **Example** (Taking between a minimum and maximum) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Start taking between 2 and 5 messages (will suspend) * const takeFiber = yield* Effect.forkChild(PubSub.takeBetween(subscription, 2, 5)) * * // Publish 3 messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"]) * * // Now the take will complete with 3 messages * return yield* Fiber.join(takeFiber) * })) * * const actual = await Effect.runPromise(program) * actual // => ["msg1", "msg2", "msg3"] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ export declare const takeBetween: { /** * Takes between the specified minimum and maximum number of messages from the * subscription. Finite fractional bounds are rounded down, while `NaN` and * non-positive bounds are treated as `0`. Will suspend if the normalized * minimum number is not immediately available. * * **Example** (Taking between a minimum and maximum) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Start taking between 2 and 5 messages (will suspend) * const takeFiber = yield* Effect.forkChild(PubSub.takeBetween(subscription, 2, 5)) * * // Publish 3 messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"]) * * // Now the take will complete with 3 messages * return yield* Fiber.join(takeFiber) * })) * * const actual = await Effect.runPromise(program) * actual // => ["msg1", "msg2", "msg3"] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ (min: number, max: number): (self: Subscription) => Effect.Effect>; /** * Takes between the specified minimum and maximum number of messages from the * subscription. Finite fractional bounds are rounded down, while `NaN` and * non-positive bounds are treated as `0`. Will suspend if the normalized * minimum number is not immediately available. * * **Example** (Taking between a minimum and maximum) * * ```ts import.meta.vitest * import { Effect, Fiber, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Start taking between 2 and 5 messages (will suspend) * const takeFiber = yield* Effect.forkChild(PubSub.takeBetween(subscription, 2, 5)) * * // Publish 3 messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"]) * * // Now the take will complete with 3 messages * return yield* Fiber.join(takeFiber) * })) * * const actual = await Effect.runPromise(program) * actual // => ["msg1", "msg2", "msg3"] * ``` * * @stability stable * @category subscriptions * @since 4.0.0 */ (self: Subscription, min: number, max: number): Effect.Effect>; }; /** * Returns the number of messages currently available in the subscription as an * `Effect`. * * **When to use** * * Use when checking a subscription from effectful code and shutdown should * interrupt the effect. * * **Details** * * The count includes replay-buffered messages. If the subscription has been * shut down, the effect interrupts. * * **Example** (Checking remaining messages) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(10) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish some messages * yield* PubSub.publishAll(pubsub, ["msg1", "msg2", "msg3"]) * * // Check how many messages are available * const count = yield* PubSub.remaining(subscription) * * // Take one message * const message = yield* PubSub.take(subscription) * * const remaining = yield* PubSub.remaining(subscription) * return { count, message, remaining } * })) * * const actual = await Effect.runPromise(program) * actual // => { count: 3, message: "msg1", remaining: 2 } * ``` * * @see {@link remainingUnsafe} for a synchronous check that reports shutdown as `Option.none()` * * @stability stable * @category getters * @since 4.0.0 */ export declare const remaining: (self: Subscription) => Effect.Effect; /** * Synchronously returns the number of messages currently available in the * subscription, or `Option.none()` when it is shut down. * * **When to use** * * Use when you need synchronous polling outside a managed workflow and want * shutdown observed as data instead of interruption. * * **Example** (Checking remaining messages synchronously) * * ```ts import.meta.vitest * import { Effect, Option, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * const pubsub = yield* PubSub.bounded(2) * const subscription = yield* PubSub.subscribe(pubsub) * return PubSub.remainingUnsafe(subscription) * })) * * const actual = await Effect.runPromise(program) * actual // => Option.some(0) * ``` * * @see {@link remaining} for the effectful variant that interrupts on shutdown * * @stability stable * @category getters * @since 4.0.0 */ export declare const remainingUnsafe: (self: Subscription) => Option.Option; /** * Represents the back-pressure strategy for bounded `PubSub` values. * * **When to use** * * Use to preserve every message for current subscribers when a bounded custom * `PubSub` should make publishers wait for capacity instead of dropping or * evicting messages. * * **Details** * * Publishers wait when the `PubSub` is at capacity, so all current subscribers * can receive every published message. * * **Gotchas** * * A slow subscriber can slow down publishers and other subscribers. * * @see {@link bounded} for creating bounded PubSubs with back pressure by default * @see {@link DroppingStrategy} for dropping new messages when capacity is full * @see {@link SlidingStrategy} for evicting old messages when capacity is full * * @stability stable * @category models * @since 4.0.0 */ export declare class BackPressureStrategy implements PubSub.Strategy { publishers: MutableList.MutableList, boolean]>; get shutdown(): Effect.Effect; handleSurplus(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers, elements: Iterable, isShutdown: MutableRef.MutableRef, ended: MutableRef.MutableRef>): Effect.Effect; onPubSubEmptySpaceUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers): void; completePollersUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers, subscription: PubSub.BackingSubscription, pollers: MutableList.MutableList>): void; completeSubscribersUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers): void; private offerUnsafe; removeUnsafe(deferred: Deferred.Deferred): void; } /** * Represents the dropping strategy for bounded `PubSub` values. * * **When to use** * * Use to keep publishers fast by dropping new messages when the `PubSub` is at * capacity. * * **Details** * * A publish that arrives while the `PubSub` is full is dropped instead of * waiting for capacity. * * **Gotchas** * * Subscribers may miss messages published while they are subscribed. * * **Example** (Applying a dropping strategy) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * // Explicitly create a PubSub with a dropping strategy * const pubsub = yield* PubSub.make({ * atomicPubSub: () => PubSub.makeAtomicBounded(2), * strategy: () => new PubSub.DroppingStrategy() * }) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Fill the PubSub * const pub1 = yield* PubSub.publish(pubsub, "msg1") // true * const pub2 = yield* PubSub.publish(pubsub, "msg2") // true * const pub3 = yield* PubSub.publish(pubsub, "msg3") // false (dropped) * * // Subscribers will only see the first two messages * const messages = yield* PubSub.takeAll(subscription) * return { published: [pub1, pub2, pub3], messages } * })) * * const actual = await Effect.runPromise(program) * actual // => { published: [true, true, false], messages: ["msg1", "msg2"] } * ``` * * @stability stable * @category models * @since 4.0.0 */ export declare class DroppingStrategy implements PubSub.Strategy { get shutdown(): Effect.Effect; handleSurplus(_pubsub: PubSub.Atomic, _subscribers: PubSub.Subscribers, _elements: Iterable, _isShutdown: MutableRef.MutableRef): Effect.Effect; onPubSubEmptySpaceUnsafe(_pubsub: PubSub.Atomic, _subscribers: PubSub.Subscribers): void; completePollersUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers, subscription: PubSub.BackingSubscription, pollers: MutableList.MutableList>): void; completeSubscribersUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers): void; } /** * Represents the sliding strategy for bounded `PubSub` values. * * **When to use** * * Use to keep the most recent messages when the `PubSub` is at capacity. * * **Details** * * New messages are accepted by evicting older messages from the bounded * `PubSub`. * * **Gotchas** * * Slow subscribers may miss older messages that are evicted before they are * consumed. * * **Example** (Applying a sliding strategy) * * ```ts import.meta.vitest * import { Effect, PubSub } from "effect" * * const program = Effect.scoped(Effect.gen(function*() { * // Explicitly create a PubSub with a sliding strategy * const pubsub = yield* PubSub.make({ * atomicPubSub: () => PubSub.makeAtomicBounded(2), * strategy: () => new PubSub.SlidingStrategy() * }) * * const subscription = yield* PubSub.subscribe(pubsub) * * // Publish messages that exceed capacity * yield* PubSub.publish(pubsub, "msg1") // stored * yield* PubSub.publish(pubsub, "msg2") // stored * yield* PubSub.publish(pubsub, "msg3") // "msg1" evicted, "msg3" stored * yield* PubSub.publish(pubsub, "msg4") // "msg2" evicted, "msg4" stored * * // Subscribers will see the most recent messages * return yield* PubSub.takeAll(subscription) * })) * * const actual = await Effect.runPromise(program) * actual // => ["msg3", "msg4"] * ``` * * @stability stable * @category models * @since 4.0.0 */ export declare class SlidingStrategy implements PubSub.Strategy { get shutdown(): Effect.Effect; handleSurplus(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers, elements: Iterable, _isShutdown: MutableRef.MutableRef, ended: MutableRef.MutableRef>): Effect.Effect; onPubSubEmptySpaceUnsafe(_pubsub: PubSub.Atomic, _subscribers: PubSub.Subscribers): void; completePollersUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers, subscription: PubSub.BackingSubscription, pollers: MutableList.MutableList>): void; completeSubscribersUnsafe(pubsub: PubSub.Atomic, subscribers: PubSub.Subscribers): void; slidingPublishUnsafe(pubsub: PubSub.Atomic, elements: Iterable): void; } export {}; //# sourceMappingURL=PubSub.d.ts.map