/** * Demux utilities for different types of docker streams. * * @since 1.0.0 */ import type * as PlatformError from "@effect/platform/Error"; import type * as HttpClientResponse from "@effect/platform/HttpClientResponse"; import type * as Socket from "@effect/platform/Socket"; import type * as Channel from "effect/Channel"; import type * as Chunk from "effect/Chunk"; import type * as Effect from "effect/Effect"; import type * as ParseResult from "effect/ParseResult"; import type * as Pipeable from "effect/Pipeable"; import type * as Scope from "effect/Scope"; import type * as Sink from "effect/Sink"; import type * as Stream from "effect/Stream"; import * as internalMultiplexed from "./internal/demux/multiplexed.ts"; /** * @since 1.0.0 * @category Types */ export declare const RawContentType: "application/vnd.docker.raw-stream"; /** * @since 1.0.0 * @category Types */ export declare const MultiplexedContentType: "application/vnd.docker.multiplexed-stream"; /** * @since 1.0.0 * @category Type ids */ export declare const RawSocketTypeId: unique symbol; /** * @since 1.0.0 * @category Type ids */ export type RawSocketTypeId = typeof RawSocketTypeId; /** * @since 1.0.0 * @category Type ids */ export declare const RawChannelTypeId: unique symbol; /** * @since 1.0.0 * @category Type ids */ export type RawChannelTypeId = typeof RawChannelTypeId; /** * @since 1.0.0 * @category Type ids */ export declare const MultiplexedSocketTypeId: unique symbol; /** * @since 1.0.0 * @category Type ids */ export type MultiplexedSocketTypeId = typeof MultiplexedSocketTypeId; /** * @since 1.0.0 * @category Type ids */ export declare const MultiplexedChannelTypeId: unique symbol; /** * @since 1.0.0 * @category Type ids */ export type MultiplexedChannelTypeId = typeof MultiplexedChannelTypeId; /** * When the TTY setting is enabled in POST /containers/create, the stream is not * multiplexed. The data exchanged over the hijacked connection is simply the * raw data from the process PTY and client's stdin. * * Note for Leo: This exists because the input error type "IE" might not be * known at the time of converting the Socket to a Channel. * * @since 1.0.0 * @category Branded Types */ export interface RawSocket extends Pipeable.Pipeable { readonly "content-type": typeof RawContentType; readonly [RawSocketTypeId]: typeof RawSocketTypeId; readonly underlying: Socket.Socket; } /** * When the TTY setting is enabled in POST /containers/create, the stream is not * multiplexed. The data exchanged over the hijacked connection is simply the * raw data from the process PTY and client's stdin. * * Note for Leo: This exists because there is no way to convert from a Channel * to a Socket. In fact, with my current effect knowledge, I believe it is * impossible to implement. This is still needed though for the pack and fan * implementations which seek to return these types. * * @since 1.0.0 * @category Branded Types */ export interface RawChannel extends Pipeable.Pipeable { readonly "content-type": typeof RawContentType; readonly [RawChannelTypeId]: typeof RawChannelTypeId; readonly underlying: Channel.Channel, Chunk.Chunk, OE, IE, void, unknown, R>; } /** * When the TTY setting is disabled in POST /containers/create, the HTTP * Content-Type header is set to application/vnd.docker.multiplexed-stream and * the stream over the hijacked connected is multiplexed to separate out stdout * and stderr. The stream consists of a series of frames, each containing a * header and a payload. * * Note for Leo: This exists because the input error type "IE" might not be * known at the time of converting the Socket to a Channel. * * @since 1.0.0 * @category Branded Types */ export interface MultiplexedSocket extends Pipeable.Pipeable { readonly "content-type": typeof MultiplexedContentType; readonly [MultiplexedSocketTypeId]: MultiplexedSocketTypeId; readonly underlying: Socket.Socket; } /** * When the TTY setting is disabled in POST /containers/create, the HTTP * Content-Type header is set to application/vnd.docker.multiplexed-stream and * the stream over the hijacked connected is multiplexed to separate out stdout * and stderr. The stream consists of a series of frames, each containing a * header and a payload. * * Note for Leo: This exists because there is no way to convert from a Channel * to a Socket. In fact, with my current effect knowledge, I believe it is * impossible to implement. This is still needed though for the pack and fan * implementations which seek to return these types. * * @since 1.0.0 * @category Branded Types */ export interface MultiplexedChannel extends Pipeable.Pipeable { readonly "content-type": typeof MultiplexedContentType; readonly [MultiplexedChannelTypeId]: MultiplexedChannelTypeId; readonly underlying: Channel.Channel, Chunk.Chunk, OE, IE, void, unknown, R>; } /** * @since 1.0.0 * @category Types */ export type EitherRawInput = RawSocket | RawChannel; /** * @since 1.0.0 * @category Types */ export type AnyRawInput = EitherRawInput; /** * @since 1.0.0 * @category Types */ export type EitherMultiplexedInput = MultiplexedSocket | MultiplexedChannel; /** * @since 1.0.0 * @category Types */ export type AnyMultiplexedInput = EitherMultiplexedInput; /** * @since 1.0.0 * @category Types */ export type HomogeneousStdioRawSocketInput = { stdin: RawSocket; stdout?: never; stderr?: never; } | { stdin?: never; stdout: RawSocket; stderr?: never; } | { stdin?: never; stdout?: never; stderr: RawSocket; } | { stdin: RawSocket; stdout: RawSocket; stderr?: never; } | { stdin: RawSocket; stdout?: never; stderr: RawSocket; } | { stdin?: never; stdout: RawSocket; stderr: RawSocket; } | { stdin: RawSocket; stdout: RawSocket; stderr: RawSocket; }; /** * @since 1.0.0 * @category Types */ export type HomogeneousStdioRawChannelInput = { stdin: RawChannel; stdout?: never; stderr?: never; } | { stdin?: never; stdout: RawChannel; stderr?: never; } | { stdin?: never; stdout?: never; stderr: RawChannel; } | { stdin: RawChannel; stdout: RawChannel; stderr?: never; } | { stdin: RawChannel; stdout?: never; stderr: RawChannel; } | { stdin?: never; stdout: RawChannel; stderr: RawChannel; } | { stdin: RawChannel; stdout: RawChannel; stderr: RawChannel; }; /** * @since 1.0.0 * @category Types */ export type HeterogeneousStdioRawInput = { stdin: EitherRawInput; stdout?: never; stderr?: never; } | { stdin?: never; stdout: EitherRawInput; stderr?: never; } | { stdin?: never; stdout?: never; stderr: EitherRawInput; } | { stdin: EitherRawInput; stdout: EitherRawInput; stderr?: never; } | { stdin: EitherRawInput; stdout?: never; stderr: EitherRawInput; } | { stdin?: never; stdout: EitherRawInput; stderr: EitherRawInput; } | { stdin: EitherRawInput; stdout: EitherRawInput; stderr: EitherRawInput; }; /** * @since 1.0.0 * @category Types */ export type HeterogeneousStdioTupledRawInput = { stdin: readonly [ Stream.Stream, EitherRawInput ]; stdout?: never; stderr?: never; } | { stdin?: never; stdout: readonly [EitherRawInput, Sink.Sink]; stderr?: never; } | { stdin?: never; stdout?: never; stderr: readonly [EitherRawInput, Sink.Sink]; } | { stdin: readonly [ Stream.Stream, EitherRawInput ]; stdout: readonly [EitherRawInput, Sink.Sink]; stderr?: never; } | { stdin: readonly [ Stream.Stream, EitherRawInput ]; stdout?: never; stderr: readonly [EitherRawInput, Sink.Sink]; } | { stdin?: never; stdout: readonly [EitherRawInput, Sink.Sink]; stderr: readonly [EitherRawInput, Sink.Sink]; } | { stdin: readonly [ Stream.Stream, EitherRawInput ]; stdout: readonly [EitherRawInput, Sink.Sink]; stderr: readonly [EitherRawInput, Sink.Sink]; }; /** * @since 1.0.0 * @category Types */ export type CompressedDemuxOutput = A1 extends undefined | void ? A2 extends undefined | void ? void : readonly [stdout: undefined, stderr: A2] : A2 extends undefined | void ? readonly [stdout: A1, stderr: undefined] : readonly [stdout: A1, stderr: A2]; /** * @since 1.0.0 * @category Constructors */ export declare const makeRawSocket: (underlying: Socket.Socket) => RawSocket; /** * @since 1.0.0 * @category Constructors */ export declare const makeRawChannel: (underlying: Channel.Channel, Chunk.Chunk, OE, IE, void, unknown, R>) => RawChannel; /** * @since 1.0.0 * @category Constructors */ export declare const makeMultiplexedSocket: (underlying: Socket.Socket) => MultiplexedSocket; /** * @since 1.0.0 * @category Constructors */ export declare const makeMultiplexedChannel: (underlying: Channel.Channel, Chunk.Chunk, OE, IE, void, unknown, R>) => MultiplexedChannel; /** * @since 1.0.0 * @category Predicates */ export declare const isRawSocket: (u: unknown) => u is RawSocket; /** * @since 1.0.0 * @category Predicates */ export declare const isRawChannel: (u: unknown) => u is RawChannel; /** * @since 1.0.0 * @category Predicates */ export declare const isMultiplexedSocket: (u: unknown) => u is MultiplexedSocket; /** * @since 1.0.0 * @category Predicates */ export declare const isMultiplexedChannel: (u: unknown) => u is MultiplexedChannel; /** * @since 1.0.0 * @category Constructors */ export declare const rawNever: RawChannel; /** * @since 1.0.0 * @category Constructors */ export declare const rawNeverWith: () => RawChannel; /** * @since 1.0.0 * @category Constructors */ export declare const multiplexedNever: MultiplexedChannel; /** * @since 1.0.0 * @category Constructors */ export declare const multiplexedNeverWith: () => MultiplexedChannel; /** * @since 1.0.0 * @category Predicates */ export declare const responseIsRawResponse: (response: HttpClientResponse.HttpClientResponse) => boolean; /** * @since 1.0.0 * @category Predicates */ export declare const responseIsMultiplexedResponse: (response: HttpClientResponse.HttpClientResponse) => boolean; /** * Hijacks an http response into a socket. * * FIXME: this function relies on a hack to expose the underlying tcp socket * from the http client response. This will only work in NodeJs, not tested in * Bun/Deno yet, and will never work in the browser. * * @since 1.0.0 * @category Transformations */ export declare const hijackResponseUnsafe: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect; /** * Transforms an http response into a multiplexed stream socket or a raw stream * socket. If the response is neither a multiplexed stream socket nor a raw or * can not be transformed, then an error will be returned. * * FIXME: this function relies on a hack to expose the underlying tcp socket * from the http client response. This will only work in NodeJs, not tested in * Bun/Deno yet, and will never work in the browser. * * @since 1.0.0 * @category Predicates */ export declare const responseToStreamingSocketOrFailUnsafe: (response: HttpClientResponse.HttpClientResponse) => Effect.Effect; /** * @since 1.0.0 * @category Conversions */ export declare const asRawChannel: (input: EitherRawInput) => RawChannel; /** * @since 1.0.0 * @category Conversions */ export declare const asMultiplexedChannel: (input: EitherMultiplexedInput) => MultiplexedChannel; /** * @since 1.0.0 * @category Conversions */ export declare const rawToStream: (input: EitherRawInput) => Stream.Stream; /** * @since 1.0.0 * @category Conversions */ export declare const multiplexedToStream: (input: EitherMultiplexedInput) => Stream.Stream; /** * @since 1.0.0 * @category Conversions */ export declare const rawToSink: (input: EitherRawInput) => Sink.Sink; /** * @since 1.0.0 * @category Conversions */ export declare const multiplexedToSink: (input: EitherMultiplexedInput) => Sink.Sink; /** * @since 1.0.0 * @category Conversions */ export declare const rawFromStreamWith: () => (input: Stream.Stream) => RawChannel; /** * @since 1.0.0 * @category Conversions */ export declare const multiplexedFromStreamWith: () => (input: Stream.Stream) => MultiplexedChannel; /** * @since 1.0.0 * @category Conversions */ export declare const rawFromStream: (input: Stream.Stream) => RawChannel; /** * @since 1.0.0 * @category Conversions */ export declare const multiplexedFromStream: (input: Stream.Stream) => MultiplexedChannel; /** * @since 1.0.0 * @category Conversions */ export declare const rawFromSink: (input: Sink.Sink) => RawChannel; /** * @since 1.0.0 * @category Conversions */ export declare const multiplexedFromSink: (input: Sink.Sink) => MultiplexedChannel; /** * @since 1.0.0 * @category Conversions */ export declare const interleaveRaw: (stdout: EitherRawInput, stderr: EitherRawInput) => Stream.Stream; /** * @since 1.0.0 * @category Conversions */ export declare const mergeRawToTaggedStream: (stdout: EitherRawInput, stderr: EitherRawInput, options?: { bufferSize?: number | undefined; } | undefined) => Stream.Stream<{ _tag: "stdout"; value: Uint8Array; } | { _tag: "stderr"; value: Uint8Array; }, IE1 | IE2 | OE1 | OE2, R1 | R2>; /** * Demux a raw socket. When given a raw socket of the remote process's pty, * there is no way to differentiate between stdout and stderr so they are * combined on the same sink. * * @since 1.0.0 * @category Demux */ export declare const demuxRawToSingleSink: ((source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined) => (socket: EitherRawInput) => Effect.Effect | Exclude | Exclude>) & ((socket: EitherRawInput, source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined) => Effect.Effect | Exclude | Exclude>); /** * Demux multiple raw sockets, created from multiple container attach requests. * If no options are provided for a given stream, it will be ignored. This is * really just an Effect.all wrapper around {@link demuxRawSingleSink}. * * To demux a single raw socket, you should use {@link demuxRawSingleSink} * * @since 1.0.0 * @category Demux */ export declare const demuxStdioRawTupled: (sockets: HeterogeneousStdioTupledRawInput, options?: { encoding?: string | undefined; } | undefined) => Effect.Effect, E1 | E2 | E3 | IE1 | IE2 | IE3 | OE1 | OE2 | OE3, Exclude | Exclude | Exclude | Exclude | Exclude | Exclude>; /** * Demux multiple raw sockets, created from multiple container attach requests. * If no options are provided for a given stream, it will be ignored. This is * really just an Effect.all wrapper around {@link demuxRawSingleSink}. * * To demux a single raw socket, you should use {@link demuxRawSingleSink} * * @since 1.0.0 * @category Demux */ export declare const demuxStdioRawToSingleSink: ((source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined) => (sockets: HeterogeneousStdioRawInput) => Effect.Effect | Exclude | Exclude | Exclude | Exclude>) & ((sockets: HeterogeneousStdioRawInput, source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined) => Effect.Effect | Exclude | Exclude | Exclude | Exclude>); /** * Demux multiple raw sockets, created from multiple container attach requests. * If no options are provided for a given stream, it will be ignored. This is * really just an Effect.all wrapper around {@link demuxRawSingleSink}. * * To demux a single raw socket, you should use {@link demuxRawSingleSink} * * @since 1.0.0 * @category Demux */ export declare const demuxStdioRawToSeparateSinks: ((io: { stdin: Stream.Stream; stdout: Sink.Sink; stderr: Sink.Sink; }, options?: { encoding?: string | undefined; } | undefined) => (sockets: HeterogeneousStdioRawInput) => Effect.Effect, E1 | E2 | E3 | IE1 | IE2 | IE3 | OE1 | OE2 | OE3, Exclude | Exclude | Exclude | Exclude | Exclude | Exclude>) & ((sockets: HeterogeneousStdioRawInput, io: { stdin: Stream.Stream; stdout: Sink.Sink; stderr: Sink.Sink; }, options?: { encoding?: string | undefined; } | undefined) => Effect.Effect, E1 | E2 | E3 | IE1 | IE2 | IE3 | OE1 | OE2 | OE3, Exclude | Exclude | Exclude | Exclude | Exclude | Exclude>); /** * Demux a multiplexed socket, all output goes to a single sink. * * @since 1.0.0 * @category Demux */ export declare const demuxMultiplexedToSingleSink: ((source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined) => (socket: EitherMultiplexedInput) => Effect.Effect | Exclude | Exclude>) & ((socket: EitherMultiplexedInput, source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined) => Effect.Effect | Exclude | Exclude>); /** * Demux a multiplexed socket. When given a multiplexed socket, we must parse * the chunks by headers and then forward each chunk based on its datatype to * the correct sink. * * When partitioning the stream into stdout and stderr, the first sink may * advance by up to bufferSize elements further than the slower one. The default * bufferSize is 16. * * @since 1.0.0 * @category Demux */ export declare const demuxMultiplexedToSeparateSinks: ((source: Stream.Stream, sink1: Sink.Sink, sink2: Sink.Sink, options?: { bufferSize?: number | undefined; encoding?: string | undefined; } | undefined) => (socket: EitherMultiplexedInput) => Effect.Effect, E1 | E2 | E3 | IE | OE | ParseResult.ParseError, Exclude | Exclude | Exclude | Exclude>) & ((socket: EitherMultiplexedInput, source: Stream.Stream, sink1: Sink.Sink, sink2: Sink.Sink, options?: { bufferSize?: number | undefined; encoding?: string | undefined; } | undefined) => Effect.Effect, E1 | E2 | E3 | IE | OE | ParseResult.ParseError, Exclude | Exclude | Exclude | Exclude>); /** * Demux either a raw socket or a multiplexed socket to a single sink. * * @since 1.0.0 * @category Demux */ export declare const demuxToSingleSink: { (source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined): (sockets: EitherRawInput | EitherMultiplexedInput) => Effect.Effect | Exclude | Exclude>; (sockets: EitherRawInput | EitherMultiplexedInput, source: Stream.Stream, sink: Sink.Sink, options?: { encoding?: string | undefined; } | undefined): Effect.Effect | Exclude | Exclude>; }; /** * @since 1.0.0 * @category Packing */ export declare const pack: { (options: { readonly requestedCapacity: number | { readonly stdinCapacity: number; readonly stdoutCapacity: number; readonly stderrCapacity: number; }; readonly encoding?: string | undefined; }): (stdio: HeterogeneousStdioRawInput) => Effect.Effect, never, Exclude | Exclude | Exclude>; (stdio: HeterogeneousStdioRawInput, options: { readonly requestedCapacity: number | { readonly stdinCapacity: number; readonly stdoutCapacity: number; readonly stderrCapacity: number; }; readonly encoding?: string | undefined; }): Effect.Effect, never, Exclude | Exclude | Exclude>; }; /** * @since 1.0.0 * @category Fanning */ export declare const fan: { (options: { readonly requestedCapacity: number | { readonly stdinCapacity: number; readonly stdoutCapacity: number; readonly stderrCapacity: number; }; readonly encoding?: string | undefined; }): (multiplexedInput: EitherMultiplexedInput) => Effect.Effect<{ stdin: RawChannel; stdout: RawChannel; stderr: RawChannel; }, never, Exclude>; (multiplexedInput: EitherMultiplexedInput, options: { readonly requestedCapacity: number | { readonly stdinCapacity: number; readonly stdoutCapacity: number; readonly stderrCapacity: number; }; readonly encoding?: string | undefined; }): Effect.Effect<{ stdin: RawChannel; stdout: RawChannel; stderr: RawChannel; }, never, Exclude>; }; /** * Demux either a raw stream socket or a multiplexed stream socket to the * console. If given a raw stream socket, then stdout and stderr will be * combined on the same sink. If given a multiplexed stream socket, then stdout * and stderr will be forwarded to different sinks. If given multiple raw stream * sockets, then you can provide different individual sockets for stdin, stdout, * and stderr. * * If you are looking for a way to demux to stdin, stdout, and stderr instead of * the console then see {@link demuxSocketFromStdinToStdoutAndStderr}. * * @since 1.0.0 * @category DemuxStdio */ export declare const demuxWithInputToConsole: (sockets: EitherMultiplexedInput, input: Stream.Stream, options?: { bufferSize?: number | undefined; encoding?: string | undefined; } | undefined) => Effect.Effect | Exclude>; /** * Demux either a raw stream socket or a multiplexed stream socket from stdin to * stdout and stderr. If given a raw stream socket, then stdout and stderr will * be combined on the same sink. If given a multiplexed stream socket, then * stdout and stderr will be forwarded to different sinks. If given multiple raw * stream sockets, then you can provide different individual sockets for stdin, * stdout, and stderr. * * If you are looking for a way to demux to the console instead of stdin, * stdout, and stderr then see {@link demuxSocketWithInputToConsole}. Since we * are interacting with stdin, stdout, and stderr this function dynamically * imports the `@effect/platform-node` package. * * @since 1.0.0 * @category DemuxStdio */ export declare const demuxFromStdinToStdoutAndStderr: (sockets: EitherMultiplexedInput, options?: { bufferSize?: number | undefined; encoding?: string | undefined; } | undefined) => Effect.Effect>;