@trpc/client
Version:
97 lines (81 loc) • 2.86 kB
text/typescript
import type {
TRPCConnectionParamsMessage,
TRPCRequestInfo,
} from '@trpc/server/unstable-core-do-not-import';
import type {
CallbackOrValue,
UrlOptionsWithConnectionParams,
} from '../../internals/urlWithConnectionParams';
import { resultOf } from '../../internals/urlWithConnectionParams';
import type { Encoder } from './encoder';
export class TRPCWebSocketClosedError extends Error {
constructor(opts: { message: string; cause?: unknown }) {
super(opts.message, {
cause: opts.cause,
});
this.name = 'TRPCWebSocketClosedError';
Object.setPrototypeOf(this, TRPCWebSocketClosedError.prototype);
}
}
/**
* Utility class for managing a timeout that can be started, stopped, and reset.
* Useful for scenarios where the timeout duration is reset dynamically based on events.
*/
export class ResettableTimeout {
private timeout: ReturnType<typeof setTimeout> | undefined;
constructor(
private readonly onTimeout: () => void,
private readonly timeoutMs: number,
) {}
/**
* Resets the current timeout, restarting it with the same duration.
* Does nothing if no timeout is active.
*/
public reset() {
if (!this.timeout) return;
clearTimeout(this.timeout);
this.timeout = setTimeout(this.onTimeout, this.timeoutMs);
}
public start() {
clearTimeout(this.timeout);
this.timeout = setTimeout(this.onTimeout, this.timeoutMs);
}
public stop() {
clearTimeout(this.timeout);
this.timeout = undefined;
}
}
// Ponyfill for Promise.withResolvers https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
export function withResolvers<T>() {
let resolve: (value: T | PromiseLike<T>) => void;
let reject: (reason?: any) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return { promise, resolve: resolve!, reject: reject! };
}
/**
* Resolves a WebSocket URL and optionally appends connection parameters.
*
* If connectionParams are provided, appends 'connectionParams=1' query parameter.
*/
export async function prepareUrl(urlOptions: UrlOptionsWithConnectionParams) {
const url = await resultOf(urlOptions.url);
if (!urlOptions.connectionParams) return url;
// append `?connectionParams=1` when connection params are used
const prefix = url.includes('?') ? '&' : '?';
const connectionParams = `${prefix}connectionParams=1`;
return url + connectionParams;
}
export async function buildConnectionMessage(
connectionParams: CallbackOrValue<TRPCRequestInfo['connectionParams']>,
encoder: Encoder,
) {
const message: TRPCConnectionParamsMessage = {
method: 'connectionParams',
data: await resultOf(connectionParams),
};
return encoder.encode(message);
}