UNPKG

graphql-sse

Version:

Zero-dependency, HTTP/1 safe, simple, GraphQL over Server-Sent Events Protocol server and client

268 lines (267 loc) 12.8 kB
/** * * client * */ import { RequestParams, Sink, StreamMessage, ExecutionResult, StreamEvent } from './common.mjs'; /** This file is the entry point for browsers, re-export common elements. */ export * from './common.mjs'; /** @category Client */ export interface EventListeners<SingleConnection extends boolean = false> { /** * Emitted when the client starts connecting to the server. * * @param reconnecting - Whether the client is reconnecting after the connection was broken. */ connecting?: (reconnecting: boolean) => void; /** * Emitted when the client receives a message from the server. */ message?: (message: StreamMessage<SingleConnection, StreamEvent>) => void; /** * Emitted when the client has successfully connected to the server. * * @param reconnected - Whether the client has reconnected after the connection was broken. */ connected?: (reconnected: boolean) => void; } /** @category Client */ export interface ClientOptions<SingleConnection extends boolean = false> { /** * Reuses a single SSE connection for all GraphQL operations. * * When instantiating with `false` (default), the client will run * in a "distinct connections mode" mode. Meaning, a new SSE * connection will be established on each subscribe. * * On the other hand, when instantiating with `true`, the client * will run in a "single connection mode" mode. Meaning, a single SSE * connection will be used to transmit all operation results while * separate HTTP requests will be issued to dictate the behaviour. * * @default false */ singleConnection?: SingleConnection; /** * Controls when should the connection be established while using the * client in "single connection mode" (see `singleConnection ` option). * * - `false`: Establish a connection immediately. * - `true`: Establish a connection on first subscribe and close on last unsubscribe. * * Note that the `lazy` option has NO EFFECT when using the client * in "distinct connections mode" (`singleConnection = false`). * * @default true */ lazy?: SingleConnection extends true ? boolean : never; /** * How long should the client wait before closing the connection after the last operation has * completed. You might want to have a calmdown time before actually closing the connection. * * Meant to be used in combination with `lazy`. * * Note that the `lazy` option has NO EFFECT when using the client * in "distinct connections mode" (`singleConnection = false`). * * @default 0 */ lazyCloseTimeout?: SingleConnection extends true ? number : never; /** * Used ONLY when the client is in non-lazy mode (`lazy = false`). When * using this mode, errors might have no sinks to report to; however, * to avoid swallowing errors, `onNonLazyError` will be called when either: * - An unrecoverable error/close event occurs * - Silent retry attempts have been exceeded * * After a client has errored out, it will NOT perform any automatic actions. * * @default console.error */ onNonLazyError?: SingleConnection extends true ? (error: unknown) => void : never; /** * URL of the GraphQL over SSE server to connect. * * If the option is a function, it will be called on each connection attempt. * Returning a Promise is supported too and the connection phase will stall until it * resolves with the URL. * * A good use-case for having a function is when using the URL for authentication, * where subsequent reconnects (due to auth) may have a refreshed identity token in * the URL. * * The request is passed for distinct connections mode only. */ url: string | ((request: SingleConnection extends true ? undefined : RequestParams) => Promise<string> | string); /** * Indicates whether the user agent should send cookies from the other domain in the case * of cross-origin requests. * * Possible options are: * - `omit`: Never send or receive cookies. * - `same-origin`: Send user credentials (cookies, basic http auth, etc..) if the URL is on the same origin as the calling script. * - `include`: Always send user credentials (cookies, basic http auth, etc..), even for cross-origin calls. * * @default same-origin */ credentials?: 'omit' | 'same-origin' | 'include'; /** * A string specifying the referrer of the request. This can be a same-origin URL, about:client, or an empty string. * * @default undefined */ referrer?: string; /** * Specifies the referrer policy to use for the request. * * Possible options are: * - `no-referrer`: Does not send referrer information along with requests to any origin. * - `no-referrer-when-downgrade`: Sends full referrerURL for requests: whose referrerURL and current URL are both potentially trustworthy URLs, or whose referrerURL is a non-potentially trustworthy URL. * - `same-origin`: Sends full referrerURL as referrer information when making same-origin-referrer requests. * - `origin`: Sends only the ASCII serialization of the request’s referrerURL when making both same-origin-referrer requests and cross-origin-referrer requests. * - `strict-origin`: Sends the ASCII serialization of the origin of the referrerURL for requests: whose referrerURL and current URL are both potentially trustworthy URLs, or whose referrerURL is a non-potentially trustworthy URL * - `origin-when-cross-origin`: Sends full referrerURL when making same-origin-referrer requests, and only the ASCII serialization of the origin of the request’s referrerURL is sent when making cross-origin-referrer requests * - `strict-origin-when-cross-origin`: Sends full referrerURL when making same-origin-referrer requests, and only the ASCII serialization of the origin of the request’s referrerURL when making cross-origin-referrer requests: whose referrerURL and current URL are both potentially trustworthy URLs, or whose referrerURL is a non-potentially trustworthy URL. * - `unsafe-url`: Sends full referrerURL along for both same-origin-referrer requests and cross-origin-referrer requests. * * @default undefined */ referrerPolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'same-origin' | 'origin' | 'strict-origin' | 'origin-when-cross-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url'; /** * HTTP headers to pass along the request. * * If the option is a function, it will be called on each connection attempt. * Returning a Promise is supported too and the connection phase will stall until it * resolves with the headers. * * A good use-case for having a function is when using the headers for authentication, * where subsequent reconnects (due to auth) may have a refreshed identity token in * the header. * * The request is passed for distinct connections mode only. */ headers?: Record<string, string> | ((request: SingleConnection extends true ? undefined : RequestParams) => Promise<Record<string, string>> | Record<string, string>); /** * The Fetch function to use. * * For NodeJS environments consider using [`node-fetch`](https://github.com/node-fetch/node-fetch). * * @default global.fetch */ fetchFn?: unknown; /** * The AbortController implementation to use. * * For NodeJS environments before v15 consider using [`node-abort-controller`](https://github.com/southpolesteve/node-abort-controller). * * @default global.AbortController */ abortControllerImpl?: unknown; /** * A custom ID generator for identifying subscriptions. * * The default generates a v4 UUID to be used as the ID using `Math` * as the random number generator. Supply your own generator * in case you need more uniqueness. * * Reference: https://gist.github.com/jed/982883 */ generateID?: () => string; /** * How many times should the client try to reconnect before it errors out? * * @default 5 */ retryAttempts?: number; /** * Control the wait time between retries. You may implement your own strategy * by timing the resolution of the returned promise with the retries count. * * `retries` argument counts actual reconnection attempts, so it will begin with * 0 after the first retryable disconnect. * * @default 'Randomised exponential backoff, 5 times' */ retry?: (retries: number) => Promise<void>; /** * Browsers show stream messages in the DevTools **only** if they're received through the [native EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource), * and because `graphql-sse` implements a custom SSE parser - received messages will **not** appear in browser's DevTools. * * Use this function if you want to inspect valid messages received through the active SSE connection. * * @deprecated Consider using {@link ClientOptions.on} instead. */ onMessage?: (message: StreamMessage<SingleConnection, StreamEvent>) => void; /** * Event listeners for events happening in the SSE connection. * * Will emit events for both the "single connection mode" and the default "distinct connections mode". * * Beware that the `connecting` event will be called for **each** subscription when using with "distinct connections mode". */ on?: EventListeners<SingleConnection>; } /** @category Client */ export interface Client<SingleConnection extends boolean = false> { /** * Subscribes to receive through a SSE connection. * * It uses the `sink` to emit received data or errors. Returns a _dispose_ * function used for dropping the subscription and cleaning up. * * @param on - The event listener for "distinct connections mode". Note that **no events will be emitted** in "single connection mode"; for that, consider using the event listener in {@link ClientOptions}. */ subscribe<Data = Record<string, unknown>, Extensions = unknown>(request: RequestParams, sink: Sink<ExecutionResult<Data, Extensions>>, on?: SingleConnection extends true ? never : EventListeners<false>): () => void; /** * Subscribes and iterates over emitted results from an SSE connection * through the returned async iterator. * * @param on - The event listener for "distinct connections mode". Note that **no events will be emitted** in "single connection mode"; for that, consider using the event listener in {@link ClientOptions}. */ iterate<Data = Record<string, unknown>, Extensions = unknown>(request: RequestParams, on?: SingleConnection extends true ? never : EventListeners<false>): AsyncIterableIterator<ExecutionResult<Data, Extensions>>; /** * Dispose of the client, destroy connections and clean up resources. */ dispose: () => void; } /** * Creates a disposable GraphQL over SSE client to transmit * GraphQL operation results. * * If you have an HTTP/2 server, it is recommended to use the client * in "distinct connections mode" (`singleConnection = false`) which will * create a new SSE connection for each subscribe. This is the default. * * However, when dealing with HTTP/1 servers from a browser, consider using * the "single connection mode" (`singleConnection = true`) which will * use only one SSE connection. * * @category Client */ export declare function createClient<SingleConnection extends boolean = false>(options: ClientOptions<SingleConnection>): Client<SingleConnection>; /** * A network error caused by the client or an unexpected response from the server. * * Network errors are considered retryable, all others error types will be reported * immediately. * * To avoid bundling DOM typings (because the client can run in Node env too), * you should supply the `Response` generic depending on your Fetch implementation. * * @category Client */ export declare class NetworkError<Response extends ResponseLike = ResponseLike> extends Error { /** * The underlying response that's considered an error. * * Will be undefined when no response is received, * instead an unexpected network error. */ response: Response | undefined; constructor(msgOrErrOrResponse: string | Error | Response); } interface ResponseLike { readonly ok: boolean; readonly status: number; readonly statusText: string; }