import { Json } from "atom.io/foundations/json"; import * as AtomIO from "atom.io"; import * as React from "react"; import * as RT from "atom.io/realtime"; import { Clock, Socket, UserKey } from "atom.io/realtime"; import * as SocketIO from "socket.io"; import { Server } from "socket.io"; import { Socket as Socket$1, io } from "socket.io-client"; import { RenderResult } from "@testing-library/react"; //#region src/realtime-testing/virtual-clock.d.ts type VirtualClockTask = { readonly dueAt: number; readonly id: number; readonly label: string | undefined; }; type VirtualClockOptions = { /** Guards tests from accidentally scheduling work forever. */ readonly maxTasksPerRun?: number; readonly startAt?: number; }; /** * A synchronous, harness-owned clock for realtime protocol tests. * * Callbacks scheduled for the same instant execute in insertion order. Callbacks * may schedule more callbacks, including callbacks for the current instant. */ declare class VirtualClock implements Clock { #private; constructor(options?: VirtualClockOptions); /** The current virtual timestamp. */ now(): number; /** Schedule synchronous work after a non-negative virtual delay. */ schedule(callback: () => void, delay?: number, label?: string): number; /** Cancel pending work. Returns whether the task was still pending. */ cancel(id: number): boolean; /** Return pending tasks ordered exactly as the clock will run them. */ pending(): readonly VirtualClockTask[]; /** Advance by a duration, running every task due within the interval. */ advance(duration: number, maxTasks?: number): number; /** Advance to an absolute virtual timestamp. */ advanceTo(timestamp: number, maxTasks?: number): number; /** * Jump through every scheduled timestamp until no work remains. * * Throws with pending-task diagnostics when the safety limit is exceeded. */ runUntilIdle(maxTasks?: number): number; } //#endregion //#region src/realtime-testing/deterministic-transport.d.ts type DeterministicTransportMode = `automatic` | `manual`; type TransportEndpointRole = `client` | `peer` | `server`; type TransportDirection = `client-to-server` | `peer-to-peer` | `server-to-client`; type TransportEndpoint = { readonly id: string; readonly role: TransportEndpointRole; readonly session: string; }; type TransportEnvelope = { readonly args: readonly Json.Serializable[]; readonly createdAt: number; readonly direction: TransportDirection; readonly event: string; readonly id: number; readonly source: TransportEndpoint; readonly target: TransportEndpoint; }; type EnvelopeFilter = { readonly direction?: TransportDirection; readonly event?: string | readonly string[]; readonly from?: string | readonly string[]; readonly predicate?: (envelope: TransportEnvelope) => boolean; readonly session?: string | readonly string[]; readonly to?: string | readonly string[]; }; type FaultEffect = { readonly type: `delay`; readonly by: number; } | { readonly copies?: number; readonly spacing?: number; readonly type: `duplicate`; } | { readonly type: `drop`; } | { readonly type: `partition`; } | { readonly type: `reorder`; readonly window: number; }; type FaultPolicy = { readonly chance?: number; readonly effect: FaultEffect; readonly filter?: EnvelopeFilter; readonly name?: string; }; type DeliveryOutcome = { readonly delays: readonly number[]; readonly disposition: `deliver` | `drop` | `partition`; readonly reasons: readonly string[]; readonly reorderBucket: string | null; readonly reorderWindow: number | null; }; type ScheduleDecision = { readonly envelope: Pick; readonly outcome: DeliveryOutcome; }; /** A JSON-serializable record that can replay resolved network decisions. */ type TransportSchedule = { readonly decisions: readonly ScheduleDecision[]; readonly seed: number; readonly version: 1; }; type PendingDelivery = { readonly copy: number; readonly dueAt: number; readonly envelope: TransportEnvelope; readonly id: number; /** The current queue order, or null while held for reordering. */ readonly order: number | null; readonly state: `held` | `queued` | `scheduled`; }; type DeterministicTransportOptions = { readonly clock?: VirtualClock; readonly mode?: DeterministicTransportMode; readonly policies?: readonly FaultPolicy[]; readonly replay?: TransportSchedule; readonly seed?: number; }; type DuplexEndpointOptions = { readonly id: string; readonly role: TransportEndpointRole; readonly session?: string; }; type DeterministicDuplex = { readonly left: DeterministicSocket; readonly right: DeterministicSocket; }; type Listener = (...args: Json.Serializable[]) => void; type AnyListener = (event: string, ...args: Json.Serializable[]) => void; /** A minimal atom.io Socket implementation backed by deterministic memory. */ declare class DeterministicSocket implements Socket { #private; readonly id: string; readonly endpoint: TransportEndpoint; constructor(endpoint: TransportEndpoint); on(event: string, listener: Listener): void; onAny(listener: AnyListener): void; onAnyOutgoing(listener: AnyListener): void; off(event: string, listener?: Listener): void; offAny(listener: AnyListener): void; emit(event: string, ...args: Json.Serializable[]): void; /** @internal Connect this endpoint to its transport controller. */ connect(route: (event: string, args: readonly Json.Serializable[]) => void): void; /** @internal Deliver an incoming transport envelope. */ receive(event: string, args: readonly Json.Serializable[]): void; } /** * A deterministic, transport-neutral network for realtime protocol tests. * * Manual mode queues every delivery for explicit selection. Automatic mode * immediately delivers zero-delay traffic and uses the virtual clock for delay. * Reorder policies hold a window and release it in reverse arrival order. */ declare class DeterministicTransport { #private; readonly clock: VirtualClock; readonly mode: DeterministicTransportMode; readonly seed: number; constructor(options?: DeterministicTransportOptions); /** Create two Socket-compatible endpoints connected only to each other. */ createDuplex(leftOptions: DuplexEndpointOptions, rightOptions: DuplexEndpointOptions): DeterministicDuplex; /** Install a fault policy. The disposer removes only this occurrence. */ use(policy: FaultPolicy): () => void; /** Inspect outstanding traffic in deterministic delivery order. */ pending(): readonly PendingDelivery[]; /** Deliver one due queued envelope in manual mode. */ deliverNext(filter?: EnvelopeFilter): PendingDelivery | null; /** Deliver all currently due queued envelopes in manual mode. */ deliverDue(filter?: EnvelopeFilter): number; /** Release incomplete reorder windows, retaining their reverse ordering. */ flushReordering(): void; /** * Drain all transport and clock work, advancing virtual time as necessary. */ runUntilIdle(maxDeliveries?: number): number; /** Export all resolved fault decisions as replayable JSON data. */ exportSchedule(): TransportSchedule; /** Assert that every decision supplied for replay was consumed. */ assertReplayComplete(): void; } /** Create a deterministic in-memory network without affecting Socket.IO tests. */ declare const createDeterministicTransport: (options?: DeterministicTransportOptions) => DeterministicTransport; //#endregion //#region src/realtime-testing/diagnostics.d.ts /** A collection of lazily evaluated state selectors used only on failure. */ declare class RealtimeTestInspectors { #private; /** Register selected application state for timeout diagnostics. */ register(label: string, read: () => unknown): () => void; /** Render all registered selectors without allowing one failed selector to hide others. */ transcript(): string; } //#endregion //#region src/realtime-testing/event-journal.d.ts /** A cursor points immediately after the journal entries observed so far. */ type RealtimeTestEventCursor = number; /** The transport boundary at which a realtime test event was observed. */ type RealtimeTestEventDirection = `client:incoming` | `client:outgoing` | `server:incoming` | `server:outgoing`; /** One occurrence in a realtime test scenario's ordered transport journal. */ type RealtimeTestEvent = { /** A monotonically increasing, scenario-local sequence number. */ sequence: number; /** The wall-clock timestamp. A future virtual clock may supply this value. */ timestamp: number; direction: RealtimeTestEventDirection; event: string; args: readonly unknown[]; userKey: UserKey; sessionId: string; source: string; destination: string; }; /** Select occurrences from a realtime test event journal. */ type RealtimeTestEventFilter = { /** Only match entries recorded at or after this cursor. */ after?: RealtimeTestEventCursor; direction?: RealtimeTestEventDirection; event?: string; userKey?: UserKey; sessionId?: string; predicate?: (entry: RealtimeTestEvent) => boolean; }; type WaitForRealtimeTestEventOptions = { /** Maximum wall-clock wait. Defaults to 1,000 milliseconds. */ timeout?: number; }; /** * An occurrence-aware, append-only journal shared by all actors in one test. * * Cursors make assertions unambiguous when an event name is emitted repeatedly: * capture {@link cursor} before an action, then pass it as `after`. */ declare class RealtimeTestEventJournal { #private; constructor(options?: { diagnostics?: () => string; }); /** Return a cursor that excludes all entries currently in the journal. */ cursor(): RealtimeTestEventCursor; /** Return a stable snapshot of matching entries in occurrence order. */ entries(filter?: RealtimeTestEventFilter): readonly RealtimeTestEvent[]; /** Count matching occurrences, rather than merely checking event-name presence. */ count(filter?: RealtimeTestEventFilter): number; /** * Wait for the first matching occurrence, including one already in the journal. * Timeout errors include a compact transcript for diagnosis. */ waitForEvent(filter: RealtimeTestEventFilter, options?: WaitForRealtimeTestEventOptions): Promise; /** Format the newest matching entries as a compact diagnostic transcript. */ transcript(options?: RealtimeTestEventFilter & { limit?: number; }): string; /** @internal Record a transport observation. */ record(entry: Omit): RealtimeTestEvent; /** @internal Reject pending waits when their scenario is torn down. */ dispose(): void; } //#endregion //#region src/realtime-testing/execution-realms.d.ts type RealtimeRealmKind = `browser` | `in-process` | `process` | `worker`; /** Per-client counters reported by execution-realm and load fixtures. */ type RealtimeRealmMetrics = { readonly memoryBytes: number | null; readonly peakPending: number; readonly pending: number; readonly received: number; readonly sent: number; }; /** Common lifecycle and message boundary for every optional execution realm. */ type RealtimeRealmBridge = { close: () => Promise; metrics: () => RealtimeRealmMetrics; send: (message: ToRealm) => Promise; subscribe: (listener: (message: FromRealm) => void) => () => void; }; type RealtimeExecutionRealmClient = { readonly bridge: RealtimeRealmBridge; dispose: () => Promise; readonly id: string; readonly kind: RealtimeRealmKind; }; /** Factory shared by fast in-process, worker, process and browser fixtures. */ interface RealtimeExecutionRealmAdapter { readonly kind: RealtimeRealmKind; create(id: string): Promise>; } /** * Structural endpoint implemented by MessagePort, child-process IPC, or a thin * Playwright `page.exposeFunction`/`page.evaluate` bridge. */ type RealtimeRealmEndpoint = { close?: () => void | Promise; memoryUsage?: () => number | null | Promise; post: (message: ToRealm) => void | Promise; subscribe: (listener: (message: FromRealm) => void) => () => void; }; type BridgedRealmLaunch = (id: string) => RealtimeRealmEndpoint | Promise>; /** Adapt any structural message endpoint into the common execution-realm API. */ declare function createBridgedExecutionRealmAdapter(kind: Exclude, launch: BridgedRealmLaunch): RealtimeExecutionRealmAdapter; type InProcessRealmRuntime = { dispose?: () => void | Promise; memoryUsage?: () => number | null; receive: (message: ToRealm) => void | Promise; }; type InProcessRealmContext = { emit: (message: FromRealm) => void; id: string; }; /** Create the default fast realm adapter with no serialization or DOM cost. */ declare function createInProcessExecutionRealmAdapter(createRuntime: (context: InProcessRealmContext) => InProcessRealmRuntime): RealtimeExecutionRealmAdapter; /** Worker-style alias preserving the common structural endpoint contract. */ declare const createWorkerExecutionRealmAdapter: (launch: BridgedRealmLaunch) => RealtimeExecutionRealmAdapter; /** Child-process IPC alias preserving the common structural endpoint contract. */ declare const createProcessExecutionRealmAdapter: (launch: BridgedRealmLaunch) => RealtimeExecutionRealmAdapter; /** * Browser alias. Playwright remains optional: callers adapt a page to * {@link RealtimeRealmEndpoint} with `exposeFunction` and `evaluate`. */ declare const createBrowserExecutionRealmAdapter: (launch: BridgedRealmLaunch) => RealtimeExecutionRealmAdapter; type RealtimeLoadClientMetrics = RealtimeRealmMetrics & { readonly convergenceMs: number; readonly id: string; }; type RealtimeLoadReport = { readonly clientCount: number; readonly clients: readonly RealtimeLoadClientMetrics[]; readonly convergenceMs: number; readonly memoryBytes: number | null; }; type RealtimeLoadFixtureOptions = { adapter: RealtimeExecutionRealmAdapter; /** Defaults to 200. */ clients?: number; /** Exercise one client after all realms have started. */ exercise?: (client: RealtimeExecutionRealmClient, index: number) => void | Promise; /** CI safety bound. Defaults to 1,000. */ maxClients?: number; /** Injectable monotonic timer. */ now?: () => number; /** Resolve only when application-specific convergence is established. */ waitForConvergence: (clients: readonly RealtimeExecutionRealmClient[]) => void | Promise; /** Optional per-client convergence probe used for individual timing. */ waitForClientConvergence?: (client: RealtimeExecutionRealmClient, index: number) => void | Promise; }; /** Run a bounded load fixture and report queue, memory, and convergence metrics. */ declare function runRealtimeLoadFixture(options: RealtimeLoadFixtureOptions): Promise; //#endregion //#region src/realtime-testing/transport-adapter.d.ts type TestTransportEndpointOptions = { /** Logical test identifier; transport-generated socket IDs remain unchanged. */ readonly id: string; /** Logical session identifier, useful for modeling multiple tabs or reconnects. */ readonly session?: string; }; type TestTransportConnection = { readonly client: Socket; readonly dispose: () => Promise; readonly endpoints: { readonly client: TestTransportEndpoint; readonly server: TestTransportEndpoint; }; readonly server: Socket; }; type TestTransportEndpoint = { readonly id: string; readonly session: string; }; type TestTransportConnectionOptions = { readonly client?: TestTransportEndpointOptions; readonly server?: TestTransportEndpointOptions; }; /** * Shared boundary implemented by deterministic memory and real Socket.IO. * * Harness features should depend on this contract when they only require a * connected duplex. Transport-specific controllers remain available through * their concrete adapter types. */ interface RealtimeTestTransportAdapter { readonly kind: `deterministic` | `socket.io`; connect(options?: TestTransportConnectionOptions): Promise; } declare class DeterministicTransportAdapter implements RealtimeTestTransportAdapter { readonly kind: "deterministic"; readonly transport: DeterministicTransport; constructor(options?: DeterministicTransportOptions); connect(options?: TestTransportConnectionOptions): Promise; } type SocketIOTransportAdapterOptions = { readonly clientOptions?: Parameters[1]; }; type SocketIOHarness = { readonly port: number; readonly server: Server; readonly serverEndpoint: TestTransportEndpoint; }; type SocketIOHarnessClientOptions = { readonly auth?: Record; readonly autoConnect?: boolean; readonly endpoint: TestTransportEndpointOptions; }; declare const SOCKET_IO_TEST_ENDPOINT_AUTH = "__atomIoRealtimeTestEndpoint"; type SocketIOTestEndpointAuth = { readonly client: TestTransportEndpoint; readonly server: TestTransportEndpoint; }; /** Real transport integration adapter used by the same contract as memory. */ declare class SocketIOTransportAdapter implements RealtimeTestTransportAdapter { #private; readonly kind: "socket.io"; constructor(options?: SocketIOTransportAdapterOptions); connect(options?: TestTransportConnectionOptions): Promise; /** * Open the real Socket.IO host used by the legacy React harness. * * This intentionally remains synchronous to preserve `singleClient` and * `multiClient`; Socket.IO begins accepting clients on the returned port. */ openHarness(serverOptions?: TestTransportEndpointOptions): SocketIOHarness; /** Connect one legacy-harness client through the same endpoint semantics. */ connectHarnessClient(harness: SocketIOHarness, options: SocketIOHarnessClientOptions): Socket$1; /** Validate logical identity at the server boundary, independent of socket ID. */ validateHarnessEndpoint(auth: Record, expectedClient: TestTransportEndpointOptions, expectedServer: TestTransportEndpointOptions): SocketIOTestEndpointAuth; } declare const createDeterministicTransportAdapter: (options?: DeterministicTransportOptions) => DeterministicTransportAdapter; declare const createSocketIOTransportAdapter: (options?: SocketIOTransportAdapterOptions) => SocketIOTransportAdapter; //#endregion //#region src/realtime-testing/work-tracker.d.ts /** Context supplied to application-work drain adapters. */ type RealtimeTestDrainContext = { /** Aborted only when the enclosing wait times out. */ signal: AbortSignal; /** Absolute deadline on the enclosing scenario's clock. */ deadline: number; /** Read the enclosing scenario's system or virtual clock. */ now: () => number; }; /** * An application-owned drain seam. Use it for queues that cannot be represented * by one Promise, such as an actor mailbox or framework scheduler. */ type RealtimeTestWorkDrain = (context: RealtimeTestDrainContext) => Promise | void; /** * Tracks application work separately from transport delivery. * * Promise work can be registered with {@link track}; queue-like systems can * register a drain adapter with {@link registerDrain}. Draining repeats until no * adapter call or tracked Promise creates more work. */ declare class RealtimeTestWorkTracker { #private; /** Track a Promise and return the original Promise for convenient composition. */ track(work: PromiseLike, label?: string): Promise; /** Register a queue/scheduler drain adapter and return its disposer. */ registerDrain(drain: RealtimeTestWorkDrain): () => void; /** Labels for work still pending, suitable for timeout diagnostics. */ pendingLabels(): readonly string[]; /** @internal Drain adapters and tracked Promises until the tracker is stable. */ drain(context: RealtimeTestDrainContext): Promise; } //#endregion //#region src/realtime-testing/model-scenario.d.ts /** A deterministic source used by model-based scenario generators. */ declare class SeededScenarioRandom { #private; readonly seed: number; constructor(seed: number); /** Return a floating-point value in [0, 1). */ next(): number; /** Select an integer in [0, exclusiveMaximum). */ integer(exclusiveMaximum: number): number; /** Select one item without modifying the supplied collection. */ pick(values: readonly Value[]): Value; } type ModelScenarioStep = { readonly action: Action; readonly clientId: string; readonly type: `action`; } | { readonly fault: Fault; readonly type: `fault`; }; /** Serializable input sufficient to reproduce a generated scenario. */ type ModelScenarioSchedule = { readonly seed: number; readonly steps: readonly ModelScenarioStep[]; readonly version: 1; }; type ModelScenarioGenerationContext = { readonly clientId: string; readonly clientIds: readonly string[]; readonly index: number; readonly random: SeededScenarioRandom; }; type ModelScenarioGenerationOptions = { /** Number of client actions. Defaults to 100 and is bounded by `maxSteps`. */ actions?: number; clientIds: readonly string[]; /** Number of fault schedule changes. Defaults to zero. */ faults?: number; generateAction: (context: ModelScenarioGenerationContext) => Action; generateFault?: (context: Omit) => Fault; /** CI safety bound. Defaults to 1,000 clients. */ maxClients?: number; /** CI safety bound. Defaults to 10,000 total steps. */ maxSteps?: number; seed: number; }; /** Generate an interleaved, replayable action and network-fault schedule. */ declare function generateModelScenario(options: ModelScenarioGenerationOptions): ModelScenarioSchedule; type ModelScenarioCheckpoint = { /** -1 for the initial quiescent state, otherwise the last applied step. */ readonly stepIndex: number; readonly totalSteps: number; }; type ModelScenarioRuntime = { applyAction: (clientId: string, action: Action) => void | Promise; applyFault?: (fault: Fault) => void | Promise; assertInvariants: (checkpoint: ModelScenarioCheckpoint) => void | Promise; dispose?: () => void | Promise; /** Drain the deterministic clock, transport and application work. */ quiesce: () => void | Promise; }; type ModelScenarioRunOptions = { createRuntime: (schedule: ModelScenarioSchedule) => ModelScenarioRuntime | Promise>; schedule: ModelScenarioSchedule; }; /** Failure with a JSON replay payload and the precise failing checkpoint. */ declare class ModelScenarioFailure extends Error { readonly schedule: ModelScenarioSchedule; readonly stepIndex: number; constructor(message: string, schedule: ModelScenarioSchedule, stepIndex: number, options?: ErrorOptions); /** JSON text suitable for a fixture, issue, or CI artifact. */ replay(): string; } /** Replay one schedule and assert invariants at every quiescent point. */ declare function runModelScenario(options: ModelScenarioRunOptions): Promise; type ModelScenarioShrinkOptions = { /** Return true only when the candidate reproduces the failure. */ fails: (candidate: ModelScenarioSchedule) => Promise; /** Optional domain-specific smaller replacements for an individual step. */ shrinkStep?: (step: ModelScenarioStep) => Iterable>; }; /** Minimize a failing schedule using deterministic chunk removal and value shrinking. */ declare function shrinkModelScenario(schedule: ModelScenarioSchedule, options: ModelScenarioShrinkOptions): Promise>; type SeededModelScenarioOptions = ModelScenarioGenerationOptions & Pick, `createRuntime`> & { shrinkStep?: ModelScenarioShrinkOptions[`shrinkStep`]; }; /** Generate, run and automatically minimize a reproducible scenario failure. */ declare function runSeededModelScenario(options: SeededModelScenarioOptions): Promise>; //#endregion //#region src/realtime-testing/reference-replicated-sequence.d.ts /** Actor-attributed edit group used by the reference replicated sequence. */ type ReferenceEditGroup = { readonly actor: string; readonly id: string; }; type ReferenceSequenceInsert = { readonly after: string | null; readonly group: ReferenceEditGroup; readonly id: string; readonly nodeId: string; readonly type: `insert`; readonly value: string; }; type ReferenceSequenceDelete = { readonly group: ReferenceEditGroup; readonly id: string; readonly nodeId: string; readonly type: `delete`; }; type ReferenceSequenceToggle = { readonly active: boolean; readonly group: ReferenceEditGroup; readonly id: string; readonly type: `toggle-group`; }; /** Immutable operations understood by {@link ReferenceSequenceReplica}. */ type ReferenceSequenceOperation = ReferenceSequenceDelete | ReferenceSequenceInsert | ReferenceSequenceToggle; type ReferenceSequenceNode = { readonly after: string | null; readonly id: string; readonly value: string; readonly visible: boolean; }; type ReferenceSequenceState = { readonly nodes: readonly ReferenceSequenceNode[]; readonly text: string; }; /** * A deliberately small operation-set reference model for harness conformance. * * Inserts use stable predecessor anchors, sibling IDs provide deterministic * order, deletes are actor-owned marks, and group toggles provide selective * history. It is useful for exercising convergence infrastructure; it is not a * production text CRDT and intentionally uses JavaScript strings as node values. */ declare class ReferenceSequenceReplica { #private; /** Apply an operation idempotently. Conflicting reuse of an ID fails closed. */ apply(operation: ReferenceSequenceOperation): boolean; /** Apply any operation order; materialization depends only on the final set. */ applyAll(operations: Iterable): void; /** Stable snapshot of accepted operations, suitable for replication. */ operations(): readonly ReferenceSequenceOperation[]; /** Anchors or delete targets not present in the accepted operation set. */ invalidAnchors(): readonly string[]; /** Materialize deterministic text and visibility without mutating the log. */ state(): ReferenceSequenceState; } //#endregion //#region src/realtime-testing/headless/index.d.ts type RealtimeTestServerTools = { socket: SocketIO.Socket; silo: AtomIO.Silo; userKey: RT.UserKey; /** Identifies one connection independently from its authenticated identity. */ sessionId: string; enableLogging: () => void; /** Register selected server state to include in timeout diagnostics. */ inspect: (label: string, read: () => unknown) => () => void; /** Track or drain application work that transport barriers cannot observe. */ work: RealtimeTestWorkTracker; }; type TestSetupOptions = { /** Clock used for wait deadlines and convergence polling. */ clock?: RT.Clock; immortal?: { server?: boolean; }; /** Stable namespace for generated identities and sessions. */ scenarioId?: string; server: (tools: RealtimeTestServerTools) => (() => void) | void; /** @internal Override the real transport seam for conformance tests. */ transportAdapter?: SocketIOTransportAdapter; }; type RealtimeTestTools = { name: string; silo: AtomIO.Silo; }; /** Options for a dynamically created, independently owned test client. */ type RealtimeTestClientOptions = { name: string; /** Defaults to a unique identity derived from `name`. */ userKey?: RT.UserKey; /** Defaults to a unique session. Supply this only when replaying a scenario. */ sessionId?: string; /** Defaults to true. */ autoConnect?: boolean; }; /** A headless client with its own store, identity, session, socket and lifecycle. */ type HeadlessRealtimeTestClient = RealtimeTestTools & { /** Drain registered client application work without touching transport queues. */ drainApplication: (options?: WaitOptions) => Promise; /** * Explicitly drain messages ordered before a bidirectional transport barrier. * Socket.IO cannot retract a packet after timeout; the harness removes its * waiter and safely ignores any response that arrives later. */ drainTransport: (options?: WaitForIdleOptions) => Promise; dispose: () => Promise; enableLogging: () => void; /** Register selected client state to include in timeout diagnostics. */ inspect: (label: string, read: () => unknown) => () => void; journal: RealtimeTestEventJournal; sessionId: string; socket: Socket$1; userKey: RT.UserKey; /** * Wait until all transport work ordered before a bidirectional barrier has run. * Timed work scheduled by application code is deliberately outside this contract. */ waitForIdle: (options?: WaitForIdleOptions) => Promise; /** Track or drain application work that transport barriers cannot observe. */ work: RealtimeTestWorkTracker; }; type WaitOptions = { /** Maximum wait on the scenario's clock. Defaults to 1,000 milliseconds. */ timeout?: number; }; type WaitForIdleOptions = WaitOptions & { /** Consecutive unchanged barrier rounds required. Defaults to two. */ stableRounds?: number; }; type RealtimeTestServer = RealtimeTestTools & { /** @deprecated Prefer `journal.waitForEvent`, which returns the occurrence. */ awaitEvent: (consumer: RT.UserKey, event: string, after?: RealtimeTestEventCursor) => Promise; dispose: () => Promise; inspect: (label: string, read: () => unknown) => () => void; journal: RealtimeTestEventJournal; port: number; /** Namespace used for generated identities and sessions. */ scenarioId: string; work: RealtimeTestWorkTracker; }; /** One selected participant in a convergence barrier. */ type RealtimeTestConvergenceParticipant = { label: string; read: () => State; }; type WaitForConvergenceOptions = WaitForIdleOptions & { /** Compare states after application and transport queues have drained. */ equals?: (left: State, right: State) => boolean; participants: readonly RealtimeTestConvergenceParticipant[]; }; type RealtimeTestAPI = { /** Drain registered application work on the server and all live clients. */ drainApplication: (options?: WaitOptions) => Promise; /** Drain transport queues for every live client. */ drainTransport: (options?: WaitForIdleOptions) => Promise; server: RealtimeTestServer; teardown: () => Promise; waitForIdle: (options?: WaitForIdleOptions) => Promise; /** Repeatedly drain all work and compare selected participant state. */ waitForConvergence: (options: WaitForConvergenceOptions) => Promise; }; type RealtimeTestAPI__Headless = RealtimeTestAPI & { /** Create a client at any point in the scenario. */ createClient: (options: RealtimeTestClientOptions) => HeadlessRealtimeTestClient; }; declare const setupRealtimeTestServer: (options: TestSetupOptions) => RealtimeTestServer; /** Create a renderer-free client connected to an existing realtime test server. */ declare const setupHeadlessRealtimeTestClient: (options: RealtimeTestClientOptions, server: RealtimeTestServer) => HeadlessRealtimeTestClient; /** * Create a scenario with dynamically creatable clients and no renderer. * * Multiple clients may deliberately share a `userKey`; their `sessionId`, socket, * silo, and disposal remain independent. */ declare const headless: (options: TestSetupOptions) => RealtimeTestAPI__Headless; //#endregion //#region src/realtime-testing/restartable-server.d.ts /** A value or a promise for that value. */ type MaybePromise = Promise | T; /** Why a running test server was stopped. */ type TestServerStopMode = `crash` | `graceful`; /** Whether a restart retains the server's durable fixture. */ type TestServerDurability = `discard` | `preserve`; /** Lifecycle information supplied to restartable server hooks. */ type RestartableServerContext = { /** State that survives restarts unless it is explicitly discarded. */ durable: DurableState; /** State recreated for every server generation. */ ephemeral: EphemeralState; /** Starts at one and increases every time the server starts. */ generation: number; /** Stable name used to identify this fixture in diagnostics. */ name: string; }; /** Hooks used to adapt an arbitrary server to the restartable test fixture. */ type RestartableServerHooks = { /** Create a fresh durable fixture, initially and after a discarded restart. */ createDurableState: () => MaybePromise; /** Create generation-local state. This is called on every start. */ createEphemeralState: (context: Pick, `durable` | `generation` | `name`>) => MaybePromise; /** Start the adapted server and return its running interface. */ start: (context: RestartableServerContext) => MaybePromise; /** Gracefully stop a running server. */ stop?: (runtime: Runtime, context: RestartableServerContext) => MaybePromise; /** Simulate abrupt termination without invoking graceful cleanup. */ crash?: (runtime: Runtime, context: RestartableServerContext) => MaybePromise; }; /** A lifecycle event emitted by a restartable server fixture. */ type RestartableServerEvent = { generation: number; name: string; sequence: number; type: `crashed` | `durable-discarded` | `started` | `stopped`; }; /** Options for {@link createRestartableServerFixture}. */ type RestartableServerOptions = RestartableServerHooks & { name: string; onEvent?: (event: RestartableServerEvent) => void; }; /** Options accepted by {@link RestartableServerFixture.restart}. */ type RestartServerOptions = { /** Defaults to a graceful stop. */ mode?: TestServerStopMode; /** Defaults to retaining durable state. */ durability?: TestServerDurability; }; /** Lifecycle surface consumed by topology routers. */ type RestartableServerController = { readonly generation: number; readonly running: boolean; crash: () => Promise; getRuntime: () => Runtime; restart: (options?: RestartServerOptions) => Promise; stop: () => Promise; }; /** * A transport-independent server lifecycle fixture. * * Durable state belongs to the fixture; ephemeral state and the runtime belong * to one generation. This distinction makes restart tests state their * persistence assumptions directly. */ declare class RestartableServerFixture { #private; readonly name: string; constructor(options: RestartableServerOptions); /** The generation number, starting at zero before the first start. */ get generation(): number; /** Whether the adapted server currently has a running generation. */ get running(): boolean; /** Obtain the durable fixture, including while the server is stopped. */ getDurableState(): Promise; /** Obtain the current generation's ephemeral state. */ getEphemeralState(): EphemeralState; /** Obtain the current running interface. */ getRuntime(): Runtime; /** Start a new generation. */ start(): Promise; /** Gracefully stop the current generation. */ stop(): Promise; /** Abruptly terminate the current generation without graceful cleanup. */ crash(): Promise; /** Stop or crash, optionally discard durable state, then start again. */ restart(options?: RestartServerOptions): Promise; /** Replace durable state with a fresh fixture while the server is stopped. */ discardDurableState(): Promise; } /** Create a restartable server fixture for an arbitrary server adapter. */ declare function createRestartableServerFixture(options: RestartableServerOptions): RestartableServerFixture; //#endregion //#region src/realtime-testing/setup-realtime-test.d.ts type TestSetupOptions__SingleClient = TestSetupOptions & { client: React.FC; }; type TestSetupOptions__MultiClient = TestSetupOptions & { clients: { [K in ClientNames]: React.FC; }; }; type RealtimeTestClient = HeadlessRealtimeTestClient & { renderResult: RenderResult; prettyPrint: () => void; }; type RealtimeTestClientBuilder = { /** Dispose every still-live instance created by this builder. */ dispose: () => Promise; /** Create a new independent instance. It is valid to call `init` repeatedly. */ init: (options?: Partial) => RealtimeTestClient; /** Wait for every still-live instance created by this builder. */ waitForIdle: (options?: WaitForIdleOptions) => Promise; }; type RealtimeTestAPI__SingleClient = RealtimeTestAPI & { client: RealtimeTestClientBuilder; }; type RealtimeTestAPI__MultiClient = RealtimeTestAPI & { clients: Record; }; /** Create a React-rendered client builder against an existing test server. */ declare const setupRealtimeTestClient: (options: TestSetupOptions__SingleClient, name: string, server: RealtimeTestServer) => RealtimeTestClientBuilder; declare const singleClient: (options: TestSetupOptions__SingleClient) => RealtimeTestAPI__SingleClient; declare const multiClient: (options: TestSetupOptions__MultiClient) => RealtimeTestAPI__MultiClient; //#endregion //#region src/realtime-testing/topology.d.ts /** A logical socket session. Reconnecting always creates a new session ID. */ type TopologyClientSession = { clientId: string; nodeId: string; sessionId: string; }; /** Why a topology client lost its route. */ type TopologyDisconnectReason = `client` | `migrate` | `node-crash` | `node-stop`; /** A replication envelope exchanged between server nodes. */ type TopologyReplicationEnvelope = { from: string; message: ReplicationMessage; to: string; }; /** Context supplied whenever the topology invokes a server node. */ type TopologyNodeContext = { /** Replicate a message to all peers or to the selected nodes. */ replicate: (message: ReplicationMessage, to?: readonly string[]) => Promise; /** Send a message to a connected client session. */ send: (session: TopologyClientSession, message: ServerMessage) => void; }; /** Minimal interface a server runtime implements to participate in a topology. */ type RealtimeTestTopologyNode = { connect?: (session: TopologyClientSession, context: TopologyNodeContext) => MaybePromise; disconnect?: (session: TopologyClientSession, reason: TopologyDisconnectReason, context: TopologyNodeContext) => MaybePromise; receive: (session: TopologyClientSession, message: ClientMessage, context: TopologyNodeContext) => MaybePromise; receiveReplication?: (envelope: TopologyReplicationEnvelope, context: TopologyNodeContext) => MaybePromise; }; /** Adapter seam for shared streams, brokers, or deliberately partitioned logs. */ type RealtimeTestReplicationAdapter = { deliver: (envelope: TopologyReplicationEnvelope, next: () => MaybePromise) => MaybePromise; }; /** Immediately deliver replication envelopes when the topology permits them. */ declare function createImmediateReplicationAdapter(): RealtimeTestReplicationAdapter; /** Client callbacks used by {@link RealtimeTestTopology.addClient}. */ type RealtimeTestTopologyClient = { disconnected?: (reason: TopologyDisconnectReason, session: TopologyClientSession) => void; receive: (message: ServerMessage, session: TopologyClientSession) => void; }; /** A structured diagnostic emitted by a realtime test topology. */ type RealtimeTestTopologyEvent = { details: Readonly>; sequence: number; type: `client-connected` | `client-disconnected` | `client-message` | `node-crashed` | `node-restarted` | `node-stopped` | `partition-created` | `partition-healed` | `replication-blocked` | `replication-delivered`; }; /** A point-in-time view of routes, nodes, and network partitions. */ type RealtimeTestTopologyState = { nodes: Readonly>; partitions: readonly { left: string; right: string; }[]; routes: readonly TopologyClientSession[]; }; /** Options for {@link createRealtimeTestTopology}. */ type RealtimeTestTopologyOptions = { nodes: Record>>; onEvent?: (event: RealtimeTestTopologyEvent) => void; replication?: RealtimeTestReplicationAdapter; }; /** * A controllable, transport-independent multi-node router for realtime tests. * * It owns logical client sessions and routing while applications retain their * own protocol, persistence, retry, acknowledgement, and merge semantics. */ declare class RealtimeTestTopology { #private; constructor(options: RealtimeTestTopologyOptions); /** Add a client endpoint. Client IDs must be unique. */ addClient(clientId: string, client: RealtimeTestTopologyClient): void; /** Connect a client to a running node and allocate a fresh socket session. */ connect(clientId: string, nodeId: string): Promise; /** Disconnect a client from its current node. */ disconnect(clientId: string): Promise; /** Move a client to another node, producing a new socket session. */ migrate(clientId: string, nodeId: string): Promise; /** Route a client protocol message to its connected node. */ send(clientId: string, message: ClientMessage): Promise; /** Stop a node and detach all clients routed to it. */ stopNode(nodeId: string): Promise; /** Crash a node and detach clients without invoking node disconnect hooks. */ crashNode(nodeId: string): Promise; /** Restart a node, preserving durable state unless requested otherwise. */ restartNode(nodeId: string, options?: RestartServerOptions): Promise; /** Block replication in both directions between two nodes. */ partitionNodes(left: string, right: string): void; /** Restore replication in both directions between two nodes. */ healNodes(left: string, right: string): void; /** Restore every inter-node replication route. */ healAll(): void; /** Return a stable snapshot of structured topology diagnostics. */ getEvents(): readonly RealtimeTestTopologyEvent[]; /** Return the current routes, node generations, and network partitions. */ getState(): RealtimeTestTopologyState; /** Render topology diagnostics for assertion failures and test reports. */ formatEvents(): string; } /** Create a controllable multi-node realtime test topology. */ declare function createRealtimeTestTopology(options: RealtimeTestTopologyOptions): RealtimeTestTopology; //#endregion export { BridgedRealmLaunch, DeliveryOutcome, DeterministicDuplex, DeterministicSocket, DeterministicTransport, DeterministicTransportAdapter, DeterministicTransportMode, DeterministicTransportOptions, DuplexEndpointOptions, EnvelopeFilter, FaultEffect, FaultPolicy, HeadlessRealtimeTestClient, InProcessRealmContext, InProcessRealmRuntime, MaybePromise, ModelScenarioCheckpoint, ModelScenarioFailure, ModelScenarioGenerationContext, ModelScenarioGenerationOptions, ModelScenarioRunOptions, ModelScenarioRuntime, ModelScenarioSchedule, ModelScenarioShrinkOptions, ModelScenarioStep, PendingDelivery, RealtimeExecutionRealmAdapter, RealtimeExecutionRealmClient, RealtimeLoadClientMetrics, RealtimeLoadFixtureOptions, RealtimeLoadReport, RealtimeRealmBridge, RealtimeRealmEndpoint, RealtimeRealmKind, RealtimeRealmMetrics, RealtimeTestAPI, RealtimeTestAPI__Headless, RealtimeTestAPI__MultiClient, RealtimeTestAPI__SingleClient, RealtimeTestClient, RealtimeTestClientBuilder, RealtimeTestClientOptions, RealtimeTestConvergenceParticipant, RealtimeTestDrainContext, RealtimeTestEvent, RealtimeTestEventCursor, RealtimeTestEventDirection, RealtimeTestEventFilter, RealtimeTestEventJournal, RealtimeTestInspectors, RealtimeTestReplicationAdapter, RealtimeTestServer, RealtimeTestServerTools, RealtimeTestTools, RealtimeTestTopology, RealtimeTestTopologyClient, RealtimeTestTopologyEvent, RealtimeTestTopologyNode, RealtimeTestTopologyOptions, RealtimeTestTopologyState, RealtimeTestTransportAdapter, RealtimeTestWorkDrain, RealtimeTestWorkTracker, ReferenceEditGroup, ReferenceSequenceDelete, ReferenceSequenceInsert, ReferenceSequenceNode, ReferenceSequenceOperation, ReferenceSequenceReplica, ReferenceSequenceState, ReferenceSequenceToggle, RestartServerOptions, RestartableServerContext, RestartableServerController, RestartableServerEvent, RestartableServerFixture, RestartableServerHooks, RestartableServerOptions, SOCKET_IO_TEST_ENDPOINT_AUTH, ScheduleDecision, SeededModelScenarioOptions, SeededScenarioRandom, SocketIOHarness, SocketIOHarnessClientOptions, SocketIOTestEndpointAuth, SocketIOTransportAdapter, SocketIOTransportAdapterOptions, TestServerDurability, TestServerStopMode, TestSetupOptions, TestSetupOptions__MultiClient, TestSetupOptions__SingleClient, TestTransportConnection, TestTransportConnectionOptions, TestTransportEndpoint, TestTransportEndpointOptions, TopologyClientSession, TopologyDisconnectReason, TopologyNodeContext, TopologyReplicationEnvelope, TransportDirection, TransportEndpoint, TransportEndpointRole, TransportEnvelope, TransportSchedule, VirtualClock, VirtualClockOptions, VirtualClockTask, WaitForConvergenceOptions, WaitForIdleOptions, WaitForRealtimeTestEventOptions, WaitOptions, createBridgedExecutionRealmAdapter, createBrowserExecutionRealmAdapter, createDeterministicTransport, createDeterministicTransportAdapter, createImmediateReplicationAdapter, createInProcessExecutionRealmAdapter, createProcessExecutionRealmAdapter, createRealtimeTestTopology, createRestartableServerFixture, createSocketIOTransportAdapter, createWorkerExecutionRealmAdapter, generateModelScenario, headless, multiClient, runModelScenario, runRealtimeLoadFixture, runSeededModelScenario, setupHeadlessRealtimeTestClient, setupRealtimeTestClient, setupRealtimeTestServer, shrinkModelScenario, singleClient }; //# sourceMappingURL=index.d.ts.map