UNPKG

redioactive

Version:

Reactive streams for chaining overlapping promises.

824 lines (823 loc) 42.4 kB
/// <reference types="node" /> import { EventEmitter } from 'events'; import { URL } from 'url'; import { Readable } from 'stream'; import { ReadStream } from 'fs'; import { ServerOptions } from 'https'; import { RequestOptions } from 'https'; /** Type of a value sent down a stream to indicate that it has ended. No values * should follow. */ export declare type RedioEnd = { end: true; }; /** Constant value indicating the [[RedioEnd|end]] of a stream. */ export declare const end: RedioEnd; /** * Test that a value is the end of a stream. * @param t Value to test. * @return True is the value is the end of a stream. */ export declare function isEnd(t: unknown): t is RedioEnd; /** Empty value. Nil values are sent down streams to indicate no value in the * stream at this time. Nil values will be dropped at the earliest opportunity * and should never be received at the end of a stream. * * Nil values can be used in processing stages that consume more values than they * produce. */ export declare type RedioNil = { nil: true; }; /** Constant representing a [[RedioNil|nil]] value. */ export declare const nil: RedioNil; /** * Test a value to see if it is an [[RedioNil|empty value]]. * @param t Value to test. * @return True if the value is the _nil_ empty value. */ export declare function isNil(t: unknown): t is RedioNil; /** * Test a value to see if it is an [[Error]]. * @param t Value to test. * @return True if the value is an error. */ export declare function isAnError(t: unknown): t is Error; /** Types of values that can flow down a stream. Values are either of the given * type, the [[end]] or [[nil]]. */ export declare type Liquid<T> = T | RedioEnd | RedioNil | Error; /** A collection of values that can flow down a stream. This type is used * when a processing stage produces more than it consumes, a _one-to-many_ * function, to represent a sequence of values to be flattened into the stream. */ export declare type LotsOfLiquid<T> = Liquid<T> | Array<Liquid<T | RedioEnd>>; /** * Test a value to see if it is an stream value, not `end`, `nil` or an error. * @param t Value to test * @return True is the value is stream value. */ export declare function isValue<T>(t: Liquid<T>): t is T; /** * A function that can be used to produce a stream of items that is * poured into a stream via a funnel. * @typeparam T Type of the items produced. */ export interface Funnel<T> { /** * Thunk that generates values for a stream. Each call to the function * should create one or more values that are sent on down the stream. This * function should generate an [[end]] value once completed. * @return Promise to produce item(s) or the direct production of item(s). */ (): Promise<LotsOfLiquid<T>> | LotsOfLiquid<T>; } /** * A funciton that can be used to process an incoming stream of liquid and * create a possibly different kind of stream of liquid. * @typeparam S Source type for the itemsconsumed. * @typeparam T Target type for items produced. */ export interface Valve<S, T> { /** * A function that consumes a single item from an incoming stream and produces * values for an outgoing stream. The function an return [[nil]] if the * input produces no output. Set the [[RedioOptions.oneToMany]] flag if the * funciton can produce more than one value per input and the output will * be flattened. * @param s Single item to consume. * @return Promise to produce item(s) or the direct production of item(s). */ (s: S | RedioEnd): Promise<LotsOfLiquid<T>> | LotsOfLiquid<T>; } /** * A funciton that can be used to process an incoming stream of liquid or errors * and create a possibly different kind of stream of liquid. * This is an advanced feature. In normal use, allow redioactive to handle and * propogate errors. * @typeparam S Source type for the itemsconsumed. * @typeparam T Target type for items produced. */ export interface ErrorValve<S, T> { /** * A function that consumes a single item or error from an incoming stream and produces * values for an outgoing stream. The function an return [[nil]] if the * input produces no output. Set the [[RedioOptions.oneToMany]] flag if the * funciton can produce more than one value per input and the output will * be flattened. Also set [[RedioOptions.processError]]. * @param s Single item to consume. * @return Promise to produce item(s) or the direct production of item(s). */ (s: Liquid<S>): Promise<LotsOfLiquid<T>> | LotsOfLiquid<T>; } /** * Function at the end of a pipe for handling the output of a stream. * @typeparam T Type of items at the end of the stream. */ export interface Spout<T> { /** * A function that consumes a single item at the end of a stream, executing * a side effect or operation that acts on the value. * @param t Item to consume. */ (t: T | RedioEnd): Promise<void> | void; } /** * Function at the end of a pipe for handling the output and errors of a stream. * This is an advanced feature. In normal use, allow redioactive to handle and * propogate errors. * @typeparam T Type of items at the end of the stream. */ export interface ErrorSpout<T> { /** * A function that consumes a single item or an error at the end of a stream, * executing a side effect or operation that acts on the value. Also set * [[RedioOptions.processError]]. * This is an advanced feature. In normal use, allow redioactive to handle and * propogate errors. * @param t Item to consume. */ (t: Liquid<T>): Promise<void> | void; } /** * A function that generates an item or items to push onto a stream. The * `push` function is like a standard callback function that can be called * asynchronously to push values into the stream. The generator function will * not be called again until `next` has been called. Remeber to push [[end]] * to complete the stream, otherwise it is infinite. * Note: Set `oneToMany` to true for arrays to be flattened to a stream of * separate values. * @typeparam T Type of values to be pushed onto the stream. */ export interface Generator<T> { /** * Implemented to provided the lazy generation of a stream of values. * @param push Function called to push values onto the stream. * @param next Call when the generator function can be called again. */ (push: (t: LotsOfLiquid<T>) => void, next: () => void): void; } /** * Utility function to create literal values of stream items. * @typeparam T Type of value to create. * @param t Value describing the literal to create. * @return Literal value. */ export declare function literal<T>(o: T): T; /** * Options that can be used to configure each stage of processing. The options * implicitly pass onto the next processing stage unless explicitly overidden. * For example, setting the `debug` flag to true on the first element will cause * all subsequent stages of processing to generate debug unless subsequently * set to false. */ export interface RedioOptions { /** Maximum number of stream items to buffer before pausing the producer. */ bufferSizeMax?: number; /** Factor applied to `maxBufferSize` to apply to determine * how many elements have to drain before the stream is * restarted after pausing. For example, `drainFactor` is `0.7`, `bufferSizeMax` * is `10`, processing is restarted when the buffer size has drained to a * size of `7`. */ drainFactor?: number; /** Set this flag to enerate debugging information for this. */ debug?: boolean; /** Set this flag if the stage can produce arrays of output values * ([[LotsOfLiquid]]) that should be flattened. */ oneToMany?: boolean; /** Set this flag to cause an [unhandled rejection](https://nodejs.org/api/process.html#process_event_unhandledrejection) * at the end of the pipe. The default value is `true`. May cause the process * to crash. */ rejectUnhandled?: boolean; /** Set this flag to allow a valve to process an error. Defaults to `false` and * must be set for each stage that it applies to. Use in conjunction with * [[ErrorValve]] and [[ErrorSpout]]. */ processError?: boolean; } /** Generic properties of any stage in a pipeline. */ interface PipeFitting { /** Unique identifier within this Node instance for a stage in the pipeline. */ readonly fittingId: number; } /** * Configuration options for an endpoint that transports a stream over the * the HTTP protocol. * * HTTP streams consist of a RESTful resource at a given path, the _stream root path_. * This stream has sub-resources that include an optoinal _stream manifest_ and a sequence of * values, where each value in the sequence has an _sequence identifier_ and a reference * to the _next_ value in the sequence, which may be computed from a _delta increment). * Sequence identifiers can be names, timestamps, counters etc.. These options set - or * reference the properties of a stream type `T` - to be used to configure the * stream. * * The size of any buffer used along the path is defined by the `RedioOptions.bufferSizeMax` * property. This includes how many values are available to be pulled. */ export interface HTTPOptions extends RedioOptions { /** HTTP port to use for pull or push. Default is 8765. Set to `-1` to disable. */ httpPort?: number; /** HTTPS port to use for pull or push. Default is 8766. Set to `-1` to disable. */ httpsPort?: number; /** Options required to create an HTTP/S server. For HTTPS, include the `key and `cert` properties. For * self-signed certificates used during testing, set `rejectUnauthorized` to `false`. */ serverOptions?: ServerOptions; /** Additional options required to make HTTP/S requests, such as keys and certificates. */ requestOptions?: RequestOptions; /** Append the first value of the named property of type `T` to complete the stream * root path, e.g. if the URI contains `/fred/ginger` and the property of `T` called * _extraStreamRoot_ has value `streamId` with value `audio/channel3`, the full stream * root is `/fred/ginger/audio/channel3/`. If undefined, then `/fred/ginger/`. */ extraStreamRoot?: string; /** Use the named property of `T` as the identifier for each value flowing down the * stream, for example a timestamp or timestamp generator funciton. If omitted, * a numerical counter will be used. */ seqId?: string; /** Either a number representing an amount to increment the sequence identifier of * the name of a property of `T` to use to provide the delta. Defaults to incrementing * a counter by 1. Note that the referenced property is itself of type `number | string`, * where: * * `number` - the value to add to the previous sequence indentifier * * `string` - the actual sequence identifier of the next item */ delta?: number | string; /** Allow fuzzy matching of stream identifiers. Will allow either a close string match * or numerical window around the _current + delta_ value. The value must be between * `0.0` and `0.9`, with `0.0` being an exact match is required, `0.1` is 10% either side * of the average gap and `0.9` is 90% either side of the average gap. Default is exact * matching with `0.0`. */ fuzzy?: number; /** Provide the optional manifest that is a description of the entire stream. The * manifest will be available from every received value. If set to a string, the * manifest is taken from the first value of property `T` of that name found * in the stream. The default is not to set a manifest. */ manifest?: string | Record<string, unknown>; /** Set if a property of a value of `T` defines the binary payload of an HTTP stream. * If defined, any other properties of the value are carried in the HTTP header. */ blob?: string; /** Content-Type header to use for blob payloads. This defaults to * `application/octet-stream` but can be set to any MIME type. For example, if you * are sending a sequence of JPEG images, use the opportunity to set `image/jpeg` to * help with debugging from a browser. */ contentType?: string; /** Apply back pressure based on how much of the streams has been read. Back pressure * will be based on the the value with the highest sequence identifier being transferred * to a stream receiver. For pull streams, more than one receiver may exist. Wihout back * pressure, the oldest bufferred values may be dropped from the internal buffer without * being transforred. The default is `true` - apply back pressure. */ backPressure?: boolean; /** How many parallel streams should be used to send the stream. This allows a number * of values to be in flight at one time, although the stream will always be * sent and received in order. When undefined, the default value is 1. */ parallel?: number; /** How many chunks should the binary payload be split into. In combination with the * parallel setting, this may allows for low-latency parallel transport of large * binary values, such as video frames. When undefined, the default is 1. */ chunked?: number; /** How often should the stream be checked for for new values. This allows pull clients * to back off their requests to match the natural rythmn of the stream. The value * is measured in miliseconds. */ cadence?: number; /** Maximum time that any HTTP request or response should wait before timing out. * For example, when requesting the next value of a stream by pull, either the next * value is produced within the time interval or a 404/410 response is generated. */ timeout?: number; /** Length of time an HTTP/S keep alive socket is kept open after a request. The default * is 5000ms - which is normally fine - but may cause a delay in a Node.js process * closing. Smaller values may be useful in testing. */ keepAliveTimeout?: number; } /** * Options specific to processing * [Node.JS readable streams](https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_readable_streams). */ interface StreamOptions extends RedioOptions { /** Number of bytes to requests on each read of the stream. Default depends on * platform and stream type. */ chunkSize?: number; /** Encoding to set to convert buffers to strings. Leave unset for buffers. */ encoding?: BufferEncoding; } /** * Options sepcific to streams made from * [Node.JS event emitters](https://nodejs.org/docs/latest-v12.x/api/events.html). */ interface EventOptions extends RedioOptions { /** Name of an event emitted when an event emitter has ended, e.g. `finish`, `close` or * `end`. Defaults to `end` - which might result in a stream never ending! */ endEvent?: string; /** Name of an event emitted when an error occurs, e.g. `error`. Errors are sent * on down the pipe. Defaults to `error`. */ errorEvent?: string; } /** * Reactive streams pipeline carrying liquid of a particular type. * @typeparam T Type of liquid travelling down the pipe. */ export interface RedioPipe<T> extends PipeFitting { redioPipe: 'redioPipe'; /** * Apply a [[Valve|valve]] function to every element of the stream, * transforming the stream from type `T` to type `S`. * @typeparam S Type of elements on the output stream. * @param valve Valve function that transforms an element of an input stream * into zero or more elements of the output stream. * @param options Optional options to apply at this stage. * @returns Pipe containing the stream of transformed elements. */ valve<S>(valve: Valve<T, S> | ErrorValve<T, S>, options?: RedioOptions): RedioPipe<S>; /** * Apply a [[Spout|spout]] function at the end of pipe. * @param spout Spout function to apply to each element. * @returns A completed stream. */ spout(spout: Spout<T> | ErrorSpout<T>, options?: RedioOptions): RedioStream<T>; /** * Append a value to the end of a stream. * ```typescript * redio([1, 2, 3]).append(4) // => 1, 2, 3, 4 * ``` * @param v Value to append to end of stream. * @param options Optional configuration. * @returns Pipe containing stream with the additional element. */ append(v: T | RedioEnd | Promise<T>, options?: RedioOptions): RedioPipe<T>; /** * Takes a stream and batches incoming data into arrays of the given length. * ```typescript * redio([1, 2, 3, 4, 5]).batch(2) // => [1, 2], [3, 4], [5] * ``` * @param n Length of each batch. * @param options Optional configuration. * @returns Batches of values from the input stream. */ batch(n: Promise<number> | number, options?: RedioOptions): RedioPipe<Array<T>>; /** * Group all the values of the incoming stream into and single array. Works like * [[toArray | `toArray()`]] but part way along the pipe as a valve. * ```typescript * redio(new Set([1, 2, 3])).collect().toArray() // [[1, 2, 3]] - single element * ``` * @param options Optional parameters. * @return Stream of collected values made by consuming the complete input stream. */ collect(options?: RedioOptions): RedioPipe<Array<T>>; /** * Removes all non-truthy values from a stream. * ```typescript * redio([1, null, 2, undefined, 0, '', 3]).toArray() // [1, 2, 3] * ``` * @param options Optional configuration. * @returns Stream containing only truthy values. */ compact(options?: RedioOptions): RedioPipe<T>; /** * Function that consumes values from the incoming stream and - using callbacks - * produces zero, one or more values (or Errors) on an output stream. With this toolkit * function, it is possible to contruct other higher-order [[Valve|valves]] using * callbacks. * Note that redioactive prefers the use of promises over callbacks. Conider using * [[RedioPipe.valve]] instead. * The function takes: * * `err` An error if the next value in the stream is an error, or `null`. * * `x` A value if the next value to flow down the stream is a value, the stream * [[RedioEnd|end]] or `null`. * * `push` - Call this when it is time to produce a value, error or end. * * `next` - Call this when ready to receive the next value. * * @param f Function that takes an error, a value, a push function and a next function. * @param options Ooptional parameters. * @returns Stream created with the function and its use of the callbacks. */ consume<M>(f: (err: Error | null, x: T | RedioEnd | null, push: (m: Liquid<M>) => void, next: () => void) => Promise<void> | void, options?: RedioOptions): RedioPipe<M>; /** * Holds off pushing values down the pipe until there has been no more data for * the specified number of milliseconds. Sends the most recently received value before the * delay, discarding all other values. At the end of the source stream, the last value * received value is sent onwards immediately. * ```typescript * let pusher: (v?: number | RedioEnd | PromiseLike<number | RedioEnd> | undefined) => void = () => { } * const funnel: Funnel<number> = () => new Promise<Liquid<number>>((resolve) => { * pusher = resolve * }) * let wait = (t: number) => new Promise<void>((resolve) => { setTimeout(resolve, t) }) * async function run() { * const stream = redio(funnel).debounce(75).toArray() * pusher(1) * await wait(10) * pusher(2) * await wait(100) * pusher(3) * await wait(50) * pusher(end) * } * run() // [2, 3] after 260ms * ``` * @param ms Length of delay before emitting. * @param options Optional parameters. * @returns Stream containing debounced values. */ debounce(ms: Promise<number> | number, options?: RedioOptions): RedioPipe<T>; /** * Execute a function on each value of the stream, emitting the value onto the output * stream. This is useful to take side-effect action such as logging and can be used to * make side-effect modifications to objects in the stream. Errors are not passed to the * function. * Note that although the function can return a promise, it does not wait for that promise * to resolve or apply any back pressure. * ```typescript * redio([1, 2, 3]).doto(console.log).each(() => {}) * // 1 * // 2 * // 3 * * // Mutating values by side-effect - use with caution! * redio([[1], [2], [3]]).doto(x => x.push(1)).toArray() // [[1, 1], [2, 1], [3, 1]] * ``` * @param f Function to apply to each value of the stream. * @param options Optional parameters. * @returns Stream containing the same values as the input stream. */ doto(f: (t: T) => Promise<void> | void, options?: RedioOptions): RedioPipe<T>; /** * Ignores the first `num` values of the stream and emits the rest. * ```typescript * redio([1, 2, 3, 4]).drop(2) // 3, 4 * ``` * @param num Number of values to drop from the source. Default is 1. * @param options Optional configuration. * @returns Pipe containing a stream of values with the first `num` values missing. */ drop(num?: Promise<number> | number, options?: RedioOptions): RedioPipe<T>; /** * Apply the given function to every error in the stream. All other values * are passed on. The error can be transformed into a value of the stream * type, passed on or dropped by returning / resolving to [[RedioNil|`nil`]]/`void`/`null`/`undefined`. * * @param f Function to transform an error into a value or take a side-effect * action. Note that errors can be passed on (return type `Error`) * or dropped (return type [[RedioNil]] or an equivalent falsy value). * @param options Optional configuration. Note the [[RedioOptions.processError|`processError`]] * will always be set. * @returns Stream of values with errors handled. */ errors(f: (err: Error) => Promise<Liquid<T>> | Liquid<T> | void, options?: RedioOptions): RedioPipe<T>; /** * Apply the given filter function to all the values in the stream, keeping * only those that pass the test. * ```typescript * redio([1, 2, 3, 4, 5, 6]).filter(x => x % 2 === 0) // [2, 4, 6] * ``` * @param filter Function returning true for values to keep. * @param options Optional configuration. * @returns Stream of values that pass the test. */ filter(filter: (t: T) => Promise<boolean> | boolean, options?: RedioOptions): RedioPipe<T>; /** * Find the first value in the stream that passes the given filter test, then end the * output stream. * ```typescript * const docs = [{ name: 'one', value: 1 }, { name: 'two', value: 2 }, * { name: 'three', value: 3 }] * redio(docs).find(x => x.value >= 2) // { name: 'two', value: 2 } * ``` * @param filter Function testing positive for input values to be found. * @param options Optional configuration. * @returns Single-element stream with value that passes the filter test. */ find(filter: (t: T) => Promise<boolean> | boolean, options?: RedioOptions): RedioPipe<T>; /** * * @param props * @param options */ findWhere(props: Record<string, unknown>, options?: RedioOptions): RedioPipe<T>; group(f: string | ((t: T) => unknown), options?: RedioOptions): RedioPipe<T>; head(options?: RedioOptions): RedioPipe<T>; intersperse<I>(sep: Promise<I> | I, options?: RedioOptions): RedioPipe<T | I>; invoke<R>(method: string, args: Array<unknown>, options?: RedioOptions): RedioPipe<R>; last(options?: RedioOptions): RedioPipe<T>; latest(options?: RedioOptions): RedioPipe<T>; /** * Transform a stream by applying the given `mapper` function to each element. The * transformation can be one-to-one, or set the [[RedioOptions.oneToMany|one-to-many]] * flag and return an array of values to be flattenned downstream. The function can * be synchronous or asynchronous. * ```typescript * redio([1, 2, 3]).map(x => x * 2) // 2, 4, 6 * redio([1, 2, 3]).map(x => [x, x], { oneToMany: true }) * // 1, 1, 2, 2, 3, 3 * ``` * @typeparam M Type of the values in the output stream. * @param mapper Function to transform each value. * @param options Optional configuration. * @returns Stream of transformed values. */ map<M>(mapper: (t: T) => M | Promise<M> | Array<M | RedioEnd> | Promise<Array<M | RedioEnd>>, options?: RedioOptions): RedioPipe<M>; /** * Allow the pausing of a stream, so that the source stops streaming but stays ready to * flow again, while the output stream consists of repeated copies of the latest source value. * The t value passed to the function is the latest source value * @param paused Function returns whether the stream should be paused. * @param options Optional configuration. */ pause(paused: (t: Liquid<T>) => boolean, options?: RedioOptions): RedioPipe<T>; pick(properties: Array<string>, options?: RedioOptions): RedioPipe<T>; pickBy(f: (key: string, value: unknown) => boolean, options?: RedioOptions): RedioPipe<T>; pluck(prop: string, options?: RedioOptions): RedioPipe<T>; ratelimit(num: number, ms: number, options?: RedioOptions): RedioPipe<T>; reduce<R>(iterator: (a: R, b: T) => R, init: R, options?: RedioOptions): RedioPipe<T>; reduce1<T>(iterator: (a: T, b: T) => T, options?: RedioOptions): RedioPipe<T>; reject(filter: (t: T) => Promise<boolean> | boolean, options?: RedioOptions): RedioPipe<T>; scan<R>(iterator: (a: R, b: T) => R, init: R, options?: RedioOptions): RedioPipe<T>; scan1(iterator: (a: T, b: T) => T, options?: RedioOptions): RedioPipe<T>; slice(start: number, end: number, options?: RedioOptions): RedioPipe<T>; sort(options?: RedioOptions): RedioPipe<T>; sortBy(f: (a: T, b: T) => number, options?: RedioOptions): RedioPipe<T>; split(options?: RedioOptions): RedioPipe<T>; splitBy(sep: string | RegExp, options?: RedioOptions): RedioPipe<T>; stopOnError(f: (err: Error) => void, options?: RedioOptions): RedioPipe<T>; /** * Take the first `num` elements from the stream, drop the rest. * @param num Number of elements to include from the start of the stream. * @param options Optional configuration. * @returns Stream containing only the first `num` elements from the source. */ take(num?: Promise<number> | number, options?: RedioOptions): RedioPipe<T>; tap(f: (t: T) => Promise<void> | void, options?: RedioOptions): RedioPipe<T>; throttle(ms: number, options?: RedioOptions): RedioPipe<T>; uniq(options?: RedioOptions): RedioPipe<T>; uniqBy(f: (a: T, b: T) => boolean, options?: RedioOptions): RedioPipe<T>; where(props: Record<string, unknown>, options?: RedioOptions): RedioPipe<T>; concat(ys: RedioPipe<T> | Array<T>, options?: RedioOptions): RedioPipe<T>; flatFilter(f: (t: T) => RedioPipe<boolean>, options?: RedioOptions): RedioPipe<T>; /** * Create a new stream of values by applying a function to each value, where * that function returns a (possibly empty) stream. Each of the result streams * are then emitted on a single output stream. * Functionally equivalent to `.map<RedioPipe<M>>(f).sequence()`. * ```typescript * redio([1, 2, 3]).flatMap(x => redio([x, x])).toArray() // [1, 1, 2, 2, 3, 3] * ``` * @param f Functions that maps values of type T to streams of type M. * @param options Optional configuration. * @typeparam M Type of values contained in the output stream. * @returns Sequence of values from streams crated by applying `f`. */ flatMap<M>(f: (t: T) => RedioPipe<M>, options?: RedioOptions): RedioPipe<M>; flatten<F>(options?: RedioOptions): RedioPipe<F>; /** * Split the stream into two or more separate streams with shared backpressure. * It is the slowest conumer that regulates how fast the source stream produces * values. Other behaviour may be best achieved using [[observe]]. Call this * method twice or more on the source stream to create branches. * Note that the values passed along the stream are copied by reference. Be * aware that any side effects caused by subsequent pipeline stages on either * branch will modify the value. * @param options Optional configuration. * @returns A stream that is one forked branch of the source stream. */ fork(options?: RedioOptions): RedioPipe<T>; /** * Remove the stream ys as a fork of the source stream * The disconnected stream will have end pushed so that it will exit * @param ys The stream to be disconnected */ unfork(ys: RedioPipe<T>): void; merge<M>(options?: RedioOptions): RedioPipe<M>; observe(options?: RedioOptions): RedioPipe<T>; otherwise<O>(ys: RedioPipe<O> | (() => RedioPipe<O>), options?: RedioOptions): RedioPipe<T | O>; parallel<P>(n: number, options?: RedioOptions): RedioPipe<P>; /** * Reads a stream of streams and pushes each value on each stream in sequence * onto the output pipe. A kind of flatten. Note that the output type `S` is * the union of all input streams' types. * ```typescript * redio([ * redio([1, 2, 3]), * redio([4, 5]), * redio([]), * redio([6]) * ]).sequence<number>().toArray() // [1, 2, 3, 4, 5, 6] * ``` * @param options Optional configuration. * @returns Stream of values in sequence taken one-by-one from each source stream. * @typeparam S Union of all the input stream types. */ sequence<S>(options?: RedioOptions): RedioPipe<S>; series<S>(options?: RedioOptions): RedioPipe<S>; /** * Takes two streams and returns a stream of corresponding pairs. If one stream is * running faster than the other - it produces two values in the time that the other * produces one - then a pair containing one undefined value may be produced. * At stream end, the size of the resulting stream is determined by the smaller of * the two source streams. * @param ys The stream to combine values with * @param options Optional configuration */ zip<Z>(ys: RedioPipe<Z>, options?: RedioOptions): RedioPipe<[T?, Z?]>; /** * Takes a stream and an array of N streams and returns a stream * of the corresponding (N+1)-tuples. * @param ys The array of streams to combine values with TODO: add support for a stream of streams * @param options Optional configuration */ zipEach<Z>(ys: RedioPipe<Z>[], options?: RedioOptions): RedioPipe<[T, ...Z[]]>; /** * Consume the stream by executing a side-effect function on each value. For * example, writing each value of the stream to the console or to a stream. * @param dotoall Optional side-effect function to execute on each value. If * no function is provided, `() => {}` is used, discarding all * values. If the value returns a promise, it must resolve before * the function is called again, applying backpressure to the * stream. * @param options Optional configuration. * @returns The last fitting of a pipeline that consumes all the values. */ each(dotoall?: (t: T) => void | Promise<void>, options?: RedioOptions): RedioStream<T>; pipe(dest: WritableStream<T>, streamOptions: Record<string, unknown>, options?: RedioOptions): RedioStream<T>; /** * Consume the stream by writing each value into an array, then resolving * to that array when the stream ends. Any error in the pipeline will cause * the result to reject. * ```typescript * redio(new Set([1, 2, 3])).toArray() // [1, 2, 3] * ``` * @param options Optional configuration. * @returns Promise to create an array containing the final values of the stream. */ toArray(options?: RedioOptions): Promise<Array<T>>; toCallback(f: (err: Error, value: T) => void): RedioStream<T>; toNodeStream(streamOptions: Record<string, unknown>, options?: RedioOptions): ReadableStream; /** * Connect a stream to another processing node via HTTP/S. A matching funnel can receive * the stream. HTTP/S streams must have a stream identifier root path, a unique identifier * for each element in the sequence (i.e. a counter or timestamp) and a means to identify * the next element (e.g. expected increment).The options provide a way to map the * sequence of elements to HTTP headers and payloads. * Note that not all kinds of payloads can be transported via HTTP, one of: * * serializable to JSON object * * a binary blob (Buffer or equivalent) * * a simple JSON payload that can be serialized to HTTP headers and a nominated * binary blob property * @param uri Depending on the kind of stream: * * for PUSH streams, a URL with protocol, hostname, port and stream * identifier root path * * for PULL streams, the stream identifier root path (protocol set in options) * @param options Configuration with specific details of the HTTP connection. * @returns The last fitting of a local pipeline that connects the pipe to a remote * stream processor. */ http(uri: string | URL, options?: HTTPOptions): RedioStream<T>; } export declare function isPipe<T>(x: unknown): x is RedioPipe<T>; /** * Tests of the given value is a promise, in any state. * @param o Value to test. * @typeparam T Optional type that the promise resolves to. * @return Value is a promise? */ export declare function isAPromise<T>(o: unknown): o is Promise<T>; /** * The end of a pipeline of a reactive stream where the liquid flows out. * Methods `done`, `catch` and `toPromise` decide what happens at the end * of a stream by _registering_ a behaviour. Each can be combined but only * one of each type can be called per stream. * @typeparam T Type of liquid flowing out of the stream. */ export interface RedioStream<T> extends PipeFitting { /** * Provide a callback function that is run when the stream has ended. The * function may be used to close any resources no longer reauired. * If more than one done function is provided, the latest one is called. * ```typescript * redio([1, 2, 3]).each(console.log).done(() => { console.log('The END!') }) * // 1 * // 2 * // 3 * // The END! * ``` * @param thatsAllFolks Function called at the end of the stream. * @returns This stream so that other end-stream behaviour can be specified. */ done(thatsAllFolks: () => void): RedioStream<T>; /** * Function that is called with any unhandled errors that have caysed the * stream to end. If more than one catch function is provided, the latest one * is called. * @param errFn Function called with any unhandled error that has reached the * end of the stream. * @returns This stream so that other end-stream behaviour can be specified. */ catch(errFn: (err: Error) => void): RedioStream<T>; /** * Register a single promise that resolves when the stream has * ended, returning the last value in the stream, or [[nil]] for an empty * stream. Only call this once per stream. Use [[each]] to process each * element of the stream. * @returns Promise that resolves to the last value in the stream. */ toPromise(): Promise<Liquid<T>>; } /** * Create a stream of values from an object that supports the [Javascript _Iterable * protocol_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol). * This includes the standard built-in types [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) * and [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). * * Note that as it is not possible to know reflectively whether a particular object implements * the [_Iterator protocol_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol), * create an Iterable object with an iterator function. * @param iterable Iterable object containing the values for the stream. * @param options Optional configuration. * @returns Stream of values from the iterable provided. */ export default function redio<T>(iterable: Iterable<T>, options?: RedioOptions): RedioPipe<T>; /** * Create a stream of values of type `T` using a lazy [[Generator]] function. A * generator function receives callback functions `push` and `next` that it uses * to create zero or more values to push onto the stream, possibly asynchronously. * Next must be called to request that the function is called again. * @param generator Generator function. * @param options Optional configuration. * @return Stream of values _pushed_ by the generator. */ export default function redio<T>(generator: Generator<T>, options?: RedioOptions): RedioPipe<T>; /** * Create a stream from a [Node.js Readable stream](https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_readable_streams). * Back pressure will be applied as required, slowing stream reading down to the acceptable * rate. Use the `chunkSize` options to requests a specific size of chunk and `encoding` to * specify a string encoding. * @param stream Node.JS readable stream to turn into a redioactive stream. * @param options Optional configuration, including [[StreamOptions|stream details]]. * @typeparam T Normally a `Buffer` or a `string`, but could be `any` in object mode. * @return Stream of values created by consuming a Node.JS stream. */ export default function redio<T>(stream: Readable | ReadStream, options?: StreamOptions): RedioPipe<T>; /** * Create a stream from a [Node.js event emitter](https://nodejs.org/docs/latest-v12.x/api/events.html) * for a specific event name. So that the stream can eventually end, either the event emitter stops * emitting events of the named type after an `end` event or that given by options `endEvent`. * @param emitter Event emitter to use to create a stream from. * @param eventName Name of the events to listen for and push onto the stream. * @param options Optional configuration, including [[EventOptions|event details]]. * @typeparam T Type of values emitted by the first emitted argument. * @return Stream of values created as events of the given name are omitted. */ export default function redio<T>(emitter: EventEmitter, eventName: string, options?: EventOptions): RedioPipe<T>; /** * Create a stream of values from the given array. * @param data Array of data to use to create a stream. * @param options Optional configuration. * @typeparam T Type of values in the source array pushed onto the stream. * @return Stream of values created from the array of data. */ export default function redio<T>(data: Array<T | RedioNil>, options?: RedioOptions): RedioPipe<T>; /** * Receive a stream of values of type `T` from another processing node over HTTP/S. This * is the partner to the [[RedioPipe.http]] method that creates such a stream. Back pressure * will be applied across the stream. * @param url Depending on the kind of stream: * * for PULL streams, a URL with protocol, hostname, port and stream * identifier root path * * for PULL streams, the stream identifier root path (protocol set in options) * @param options Configuration with specific details of the HTTP connection. * @typeparam T Type of values in the stream. * @return Stream of values received-as-pulled from the remote stream processor. */ export default function redio<T>(url: string, options?: HTTPOptions): RedioPipe<T>; /** * Create a stream of values of type `T` using a [[Funnel]] function, a _thunk_ * that is called every time the stream requires a new value. The _thunk_ maybe * asynchronous and by returning a promise to produce a value. The value will be * pushed onto the stream when the promise resolves and only then will the next * value from the stream be requested. * @param funnel Funnel function, a thunk that synchronously or asynchronously * generates a value. * @param options Optional configuration. * @typeparam T Type of values in the stream. * @return Stream of values created by repeatedly calling the funnel function. */ export default function redio<T>(funnel: Funnel<T>, options?: RedioOptions): RedioPipe<T>; export {};