UNPKG

relay-runtime

Version:

A core runtime for building GraphQL-driven applications.

198 lines (177 loc) • 7.77 kB
/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ /** * A Subscription object is returned from .subscribe(), which can be * unsubscribed or checked to see if the resulting subscription has closed. */ export interface Subscription { unsubscribe(): void; readonly closed: boolean; } /** * An Observer is an object of optional callback functions provided to * .subscribe(). Each callback function is invoked when that event occurs. */ export interface Observer<T> { readonly start?: ((subscription: Subscription) => void) | undefined; readonly next?: ((value: T) => void) | undefined; readonly error?: ((error: Error) => void) | undefined; readonly complete?: (() => void) | undefined; readonly unsubscribe?: ((subscription: Subscription) => void) | undefined; } /** * A Sink is an object of methods provided by Observable during construction. * The methods are to be called to trigger each event. It also contains a closed * field to see if the resulting subscription has closed. */ export interface Sink<T> { next(value: T): void; error(error: Error, isUncaughtThrownError?: boolean): void; complete(): void; readonly closed: boolean; } /** * A Source is the required argument when constructing a new Observable. Similar * to a Promise constructor, this is a function which is invoked with a Sink, * and may return either a cleanup function or a Subscription instance (for use * when composing Observables). */ export type Source<T> = (sink: Sink<T>) => void | Subscription | (() => unknown); /** * A Subscribable is an interface describing any object which can be subscribed. * * Note: A sink may be passed directly to .subscribe() as its observer, * allowing for easily composing Subscribables. */ export interface Subscribable<T> { subscribe(observer: Observer<T> | Sink<T>): Subscription; } export type ObservableFromValue<T> = Subscribable<T> | Promise<T> | T; /** * Limited implementation of ESObservable, providing the limited set of behavior * Relay networking requires. * * Observables retain the benefit of callbacks which can be called * synchronously, avoiding any UI jitter, while providing a compositional API, * which simplifies logic and prevents mishandling of errors compared to * the direct use of callback functions. * * ESObservable: https://github.com/tc39/proposal-observable */ export class RelayObservable<T> implements Subscribable<T> { // Use RelayObservable.create(source); private constructor(source: never); static create<V>(source: Source<V>): RelayObservable<V>; /** * When an emitted error event is not handled by an Observer, it is reported * to the host environment (what the ESObservable spec refers to as * "HostReportErrors()"). * * The default implementation in development rethrows thrown errors, and * logs emitted error events to the console, while in production does nothing * (swallowing unhandled errors). * * Called during application initialization, this method allows * application-specific handling of unhandled errors. Allowing, for example, * integration with error logging or developer tools. * * A second parameter `isUncaughtThrownError` is true when the unhandled error * was thrown within an Observer handler, and false when the unhandled error * was an unhandled emitted event. * * - Uncaught thrown errors typically represent avoidable errors thrown from * application code, which should be handled with a try/catch block, and * usually have useful stack traces. * * - Unhandled emitted event errors typically represent unavoidable events in * application flow such as network failure, and may not have useful * stack traces. */ static onUnhandledError(callback: (error: Error, isUncaughtThrownError: boolean) => void): void; /** * Accepts various kinds of data sources, and always returns a RelayObservable * useful for accepting the result of a user-provided FetchFunction. */ static from<V>(obj: ObservableFromValue<V>): RelayObservable<V>; /** * Similar to promise.catch(), observable.catch() handles error events, and * provides an alternative observable to use in it's place. * * If the catch handler throws a new error, it will appear as an error event * on the resulting Observable. */ catch<U>(fn: (error: Error) => RelayObservable<U>): RelayObservable<T | U>; /** * Returns a new Observable which first yields values from this Observable, * then yields values from the next Observable. This is useful for chaining * together Observables of finite length. */ concat<U>(next: RelayObservable<U>): RelayObservable<T | U>; /** * Returns a new Observable which returns the same values as this one, but * modified so that the provided Observer is called to perform a side-effects * for all events emitted by the source. * * Any errors that are thrown in the side-effect Observer are unhandled, and * do not affect the source Observable or its Observer. * * This is useful for when debugging your Observables or performing other * side-effects such as logging or performance monitoring. */ do(observer: Observer<T>): RelayObservable<T>; /** * Returns a new Observable which returns the same values as this one, but * modified so that the finally callback is performed after completion, * whether normal or due to error or unsubscription. * * This is useful for cleanup such as resource finalization. */ finally(fn: () => unknown): RelayObservable<T>; /** * Returns a new Observable which is identical to this one, unless this * Observable completes before yielding any values, in which case the new * Observable will yield the values from the alternate Observable. * * If this Observable does yield values, the alternate is never subscribed to. * * This is useful for scenarios where values may come from multiple sources * which should be tried in order, i.e. from a cache before a network. */ ifEmpty<U>(alternate: RelayObservable<U>): RelayObservable<T | U>; /** * Observable's primary API: returns an unsubscribable Subscription to the * source of this Observable. * * Note: A sink may be passed directly to .subscribe() as its observer, * allowing for easily composing Observables. */ subscribe(observer: Observer<T> | Sink<T>): Subscription; /** * Returns a new Observerable where each value has been transformed by * the mapping function. */ map<U>(fn: (value: T) => U): RelayObservable<U>; /** * Returns a new Observable where each value is replaced with a new Observable * by the mapping function, the results of which returned as a single * merged Observable. */ mergeMap<U>(fn: (value: T) => ObservableFromValue<U>): RelayObservable<U>; /** * Returns a new Observable which first mirrors this Observable, then when it * completes, waits for `pollInterval` milliseconds before re-subscribing to * this Observable again, looping in this manner until unsubscribed. * * The returned Observable never completes. */ poll(pollInterval: number): RelayObservable<T>; /** * Returns a Promise which resolves when this Observable yields a first value * or when it completes with no value. */ toPromise(): Promise<T | undefined>; }