Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@trpc/client

Package Overview
Dependencies
Maintainers
3
Versions
1065
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@trpc/client - npm Package Compare versions

Comparing version 11.0.0-alpha-tmp-rethrow-next-errors.386 to 11.0.0-alpha-tmp-subscription-connection-state.485

dist/links/httpSubscriptionLink.d.ts

199

dist/bundle-analysis.json
{
"bundleSize": 46599,
"bundleOrigSize": 63289,
"bundleReduction": 26.37,
"bundleSize": 57149,
"bundleOrigSize": 76725,
"bundleReduction": 25.51,
"modules": [
{
"id": "/src/links/wsLink.ts",
"size": 12058,
"origSize": 13652,
"size": 16017,
"origSize": 17038,
"renderedExports": [

@@ -16,9 +16,9 @@ "createWSClient",

"dependents": [],
"percent": 25.88,
"reduction": 11.68
"percent": 28.03,
"reduction": 5.99
},
{
"id": "/src/links/httpBatchStreamLink.ts",
"size": 5776,
"origSize": 6023,
"size": 5861,
"origSize": 6074,
"renderedExports": [

@@ -29,6 +29,18 @@ "unstable_httpBatchStreamLink"

"dependents": [],
"percent": 12.4,
"reduction": 4.1
"percent": 10.26,
"reduction": 3.51
},
{
"id": "/src/links/httpSubscriptionLink.ts",
"size": 5727,
"origSize": 5459,
"renderedExports": [
"unstable_httpSubscriptionLink"
],
"removedExports": [],
"dependents": [],
"percent": 10.02,
"reduction": 0
},
{
"id": "/src/links/loggerLink.ts",

@@ -42,9 +54,33 @@ "size": 5457,

"dependents": [],
"percent": 11.71,
"percent": 9.55,
"reduction": 18.48
},
{
"id": "/src/links/internals/httpUtils.ts",
"size": 4465,
"origSize": 6646,
"renderedExports": [
"resolveHTTPLinkOptions",
"getInput",
"getUrl",
"getBody",
"jsonHttpRequester",
"fetchHTTPResponse",
"httpRequest",
"mergeAbortSignals"
],
"removedExports": [],
"dependents": [
"/src/links/httpBatchLink.ts",
"/src/links/httpLink.ts",
"/src/links/httpBatchStreamLink.ts",
"/src/links/httpSubscriptionLink.ts"
],
"percent": 7.81,
"reduction": 32.82
},
{
"id": "/src/internals/dataLoader.ts",
"size": 4504,
"origSize": 4809,
"size": 4084,
"origSize": 4328,
"renderedExports": [

@@ -58,9 +94,9 @@ "dataLoader"

],
"percent": 9.67,
"reduction": 6.34
"percent": 7.15,
"reduction": 5.64
},
{
"id": "/src/links/httpBatchLink.ts",
"size": 3906,
"origSize": 4074,
"size": 3925,
"origSize": 4118,
"renderedExports": [

@@ -71,31 +107,9 @@ "httpBatchLink"

"dependents": [],
"percent": 8.38,
"reduction": 4.12
"percent": 6.87,
"reduction": 4.69
},
{
"id": "/src/links/internals/httpUtils.ts",
"size": 3469,
"origSize": 5927,
"renderedExports": [
"resolveHTTPLinkOptions",
"getInput",
"getUrl",
"getBody",
"jsonHttpRequester",
"fetchHTTPResponse",
"httpRequest"
],
"removedExports": [],
"dependents": [
"/src/links/httpLink.ts",
"/src/links/httpBatchLink.ts",
"/src/links/httpBatchStreamLink.ts"
],
"percent": 7.44,
"reduction": 41.47
},
{
"id": "/src/links/httpLink.ts",
"size": 2939,
"origSize": 3459,
"size": 3184,
"origSize": 3709,
"renderedExports": [

@@ -106,9 +120,9 @@ "httpLink"

"dependents": [],
"percent": 6.31,
"reduction": 15.03
"percent": 5.57,
"reduction": 14.15
},
{
"id": "/src/internals/TRPCUntypedClient.ts",
"size": 2299,
"origSize": 4207,
"size": 2284,
"origSize": 4330,
"renderedExports": [

@@ -122,9 +136,9 @@ "TRPCUntypedClient"

],
"percent": 4.93,
"reduction": 45.35
"percent": 4,
"reduction": 47.25
},
{
"id": "/src/TRPCClientError.ts",
"size": 1866,
"origSize": 3437,
"size": 1940,
"origSize": 3555,
"renderedExports": [

@@ -136,16 +150,16 @@ "TRPCClientError"

"/src/index.ts",
"/src/links/httpBatchLink.ts",
"/src/links/httpLink.ts",
"/src/links/httpBatchLink.ts",
"/src/links/wsLink.ts",
"/src/links/httpBatchStreamLink.ts",
"/src/internals/TRPCUntypedClient.ts",
"/src/links/internals/httpUtils.ts"
"/src/links/httpSubscriptionLink.ts",
"/src/internals/TRPCUntypedClient.ts"
],
"percent": 4,
"reduction": 45.71
"percent": 3.39,
"reduction": 45.43
},
{
"id": "/src/createTRPCClient.ts",
"size": 1206,
"origSize": 4369,
"size": 1187,
"origSize": 4428,
"renderedExports": [

@@ -161,4 +175,4 @@ "clientCallTypeToProcedureType",

],
"percent": 2.59,
"reduction": 72.4
"percent": 2.08,
"reduction": 73.19
},

@@ -177,3 +191,3 @@ {

],
"percent": 1.48,
"percent": 1.21,
"reduction": 32.75

@@ -190,3 +204,3 @@ },

"dependents": [],
"percent": 1.31,
"percent": 1.07,
"reduction": 44.95

@@ -205,3 +219,3 @@ },

],
"percent": 1.21,
"percent": 0.99,
"reduction": 66.75

@@ -221,20 +235,6 @@ },

],
"percent": 0.92,
"percent": 0.75,
"reduction": 33.54
},
{
"id": "/src/internals/getAbortController.ts",
"size": 396,
"origSize": 569,
"renderedExports": [
"getAbortController"
],
"removedExports": [],
"dependents": [
"/src/links/internals/httpUtils.ts"
],
"percent": 0.85,
"reduction": 30.4
},
{
"id": "/src/links/internals/contentTypes.ts",

@@ -249,7 +249,39 @@ "size": 330,

"removedExports": [],
"dependents": [],
"percent": 0.71,
"dependents": [
"/src/links/types.ts"
],
"percent": 0.58,
"reduction": 15.17
},
{
"id": "/src/links/internals/urlWithConnectionParams.ts",
"size": 158,
"origSize": 864,
"renderedExports": [
"resultOf"
],
"removedExports": [],
"dependents": [
"/src/links/wsLink.ts",
"/src/links/httpSubscriptionLink.ts"
],
"percent": 0.28,
"reduction": 81.71
},
{
"id": "/src/links/types.ts",
"size": 137,
"origSize": 3413,
"renderedExports": [
"isConnectionStateMessage"
],
"removedExports": [],
"dependents": [
"/src/links/httpLink.ts",
"/src/links/wsLink.ts"
],
"percent": 0.24,
"reduction": 95.99
},
{
"id": "/src/createTRPCUntypedClient.ts",

@@ -265,3 +297,3 @@ "size": 100,

],
"percent": 0.21,
"percent": 0.17,
"reduction": 82.58

@@ -287,2 +319,3 @@ },

"/src/links/wsLink.ts",
"/src/links/httpSubscriptionLink.ts",
"/src/links/internals/httpUtils.ts"

@@ -294,3 +327,3 @@ ],

],
"moduleCount": 19
"moduleCount": 21
}

@@ -17,2 +17,10 @@ 'use strict';

*/ function createTRPCClientProxy(client) {
const proxy = unstableCoreDoNotImport.createRecursiveProxy(({ path , args })=>{
const pathCopy = [
...path
];
const procedureType = clientCallTypeToProcedureType(pathCopy.pop());
const fullPath = pathCopy.join('.');
return client[procedureType](fullPath, ...args);
});
return unstableCoreDoNotImport.createFlatProxy((key)=>{

@@ -25,11 +33,3 @@ if (client.hasOwnProperty(key)) {

}
return unstableCoreDoNotImport.createRecursiveProxy(({ path , args })=>{
const pathCopy = [
key,
...path
];
const procedureType = clientCallTypeToProcedureType(pathCopy.pop());
const fullPath = pathCopy.join('.');
return client[procedureType](fullPath, ...args);
});
return proxy[key];
});

@@ -36,0 +36,0 @@ }

@@ -7,3 +7,3 @@ 'use strict';

var TRPCClientError = require('./TRPCClientError.js');
var contentTypes = require('./links/internals/contentTypes.js');
var types = require('./links/types.js');
var httpBatchLink = require('./links/httpBatchLink.js');

@@ -15,3 +15,5 @@ var httpBatchStreamLink = require('./links/httpBatchStreamLink.js');

var wsLink = require('./links/wsLink.js');
var httpSubscriptionLink = require('./links/httpSubscriptionLink.js');
var TRPCUntypedClient = require('./internals/TRPCUntypedClient.js');
var contentTypes = require('./links/internals/contentTypes.js');

@@ -28,5 +30,3 @@

exports.TRPCClientError = TRPCClientError.TRPCClientError;
exports.isFormData = contentTypes.isFormData;
exports.isNonJsonSerializable = contentTypes.isNonJsonSerializable;
exports.isOctetType = contentTypes.isOctetType;
exports.isConnectionStateMessage = types.isConnectionStateMessage;
exports.httpBatchLink = httpBatchLink.httpBatchLink;

@@ -39,2 +39,6 @@ exports.unstable_httpBatchStreamLink = httpBatchStreamLink.unstable_httpBatchStreamLink;

exports.wsLink = wsLink.wsLink;
exports.unstable_httpSubscriptionLink = httpSubscriptionLink.unstable_httpSubscriptionLink;
exports.TRPCUntypedClient = TRPCUntypedClient.TRPCUntypedClient;
exports.isFormData = contentTypes.isFormData;
exports.isNonJsonSerializable = contentTypes.isNonJsonSerializable;
exports.isOctetType = contentTypes.isOctetType;

@@ -1,8 +0,4 @@

import type { CancelFn, PromiseAndCancel } from '../links/types';
export type BatchLoader<TKey, TValue> = {
validate: (keys: TKey[]) => boolean;
fetch: (keys: TKey[]) => {
promise: Promise<TValue[] | Promise<TValue>[]>;
cancel: CancelFn;
};
fetch: (keys: TKey[]) => Promise<TValue[] | Promise<TValue>[]>;
};

@@ -15,4 +11,4 @@ /**

export declare function dataLoader<TKey, TValue>(batchLoader: BatchLoader<TKey, TValue>): {
load: (key: TKey) => PromiseAndCancel<TValue>;
load: (key: TKey) => Promise<TValue>;
};
//# sourceMappingURL=dataLoader.d.ts.map

@@ -64,4 +64,3 @@ 'use strict';

const batch = {
items,
cancel: throwFatalError
items
};

@@ -71,4 +70,3 @@ for (const item of items){

}
const { promise , cancel } = batchLoader.fetch(batch.items.map((_item)=>_item.key));
batch.cancel = cancel;
const promise = batchLoader.fetch(batch.items.map((_item)=>_item.key));
promise.then(async (result)=>{

@@ -118,14 +116,3 @@ await Promise.all(result.map(async (valueOrPromise, index)=>{

}
const cancel = ()=>{
item.aborted = true;
if (item.batch?.items.every((item)=>item.aborted)) {
// All items in the batch have been cancelled
item.batch.cancel();
item.batch = null;
}
};
return {
promise,
cancel
};
return promise;
}

@@ -132,0 +119,0 @@ return {

import type { Unsubscribable } from '@trpc/server/observable';
import type { AnyRouter, InferrableClientTypes, TypeError } from '@trpc/server/unstable-core-do-not-import';
import type { OperationContext, TRPCClientRuntime, TRPCLink } from '../links/types';
import type { OperationContext, TRPCClientRuntime, TRPCConnectionStateMessage, TRPCLink } from '../links/types';
import { TRPCClientError } from '../TRPCClientError';

@@ -13,3 +13,5 @@ export interface TRPCRequestOptions {

export interface TRPCSubscriptionObserver<TValue, TError> {
onStarted: () => void;
onStarted: (opts: {
context: OperationContext | undefined;
}) => void;
onData: (value: TValue) => void;

@@ -19,2 +21,3 @@ onError: (err: TError) => void;

onComplete: () => void;
onStateChange: (state: TRPCConnectionStateMessage<TError>) => void;
}

@@ -21,0 +24,0 @@ /** @internal */

@@ -8,11 +8,9 @@ 'use strict';

class TRPCUntypedClient {
$request({ type , input , path , context ={} }) {
$request(opts) {
const chain$ = createChain.createChain({
links: this.links,
op: {
id: ++this.requestId,
type,
path,
input,
context
...opts,
context: opts.context ?? {},
id: ++this.requestId
}

@@ -22,14 +20,11 @@ });

}
requestAsPromise(opts) {
const req$ = this.$request(opts);
const { promise , abort } = observable.observableToPromise(req$);
const abortablePromise = new Promise((resolve, reject)=>{
opts.signal?.addEventListener('abort', abort);
promise.then((envelope)=>{
resolve(envelope.result.data);
}).catch((err)=>{
reject(TRPCClientError.TRPCClientError.from(err));
});
});
return abortablePromise;
async requestAsPromise(opts) {
try {
const req$ = this.$request(opts);
const envelope = await observable.observableToPromise(req$);
const data = envelope.result.data;
return data;
} catch (err) {
throw TRPCClientError.TRPCClientError.from(err);
}
}

@@ -59,3 +54,4 @@ query(path, input, opts) {

input,
context: opts?.context
context: opts?.context,
signal: null
});

@@ -65,5 +61,9 @@ return observable$.subscribe({

if (envelope.result.type === 'started') {
opts.onStarted?.();
opts.onStarted?.({
context: envelope.context
});
} else if (envelope.result.type === 'stopped') {
opts.onStopped?.();
} else if (envelope.result.type === 'state') {
opts.onStateChange?.(envelope.result);
} else {

@@ -70,0 +70,0 @@ opts.onData?.(envelope.result.data);

@@ -1,17 +0,2 @@

export type AbortControllerEsque = new () => AbortControllerInstanceEsque;
/**
* Allows you to abort one or more requests.
*/
export interface AbortControllerInstanceEsque {
/**
* The AbortSignal object associated with this object.
*/
readonly signal: AbortSignal;
/**
* Sets this object's AbortSignal's aborted flag and signals to
* any observers that the associated activity is to be aborted.
*/
abort(): void;
}
/**
* A subset of the standard fetch function type needed by tRPC internally.

@@ -18,0 +3,0 @@ * @see fetch from lib.dom.d.ts

@@ -9,2 +9,3 @@ export * from './links/types';

export * from './links/wsLink';
export * from './links/httpSubscriptionLink';
//# sourceMappingURL=links.d.ts.map

@@ -28,10 +28,12 @@ 'use strict';

path,
inputs
inputs,
signal: null
});
return url.length <= maxURLLength;
},
fetch (batchOps) {
async fetch (batchOps) {
const path = batchOps.map((op)=>op.path).join(',');
const inputs = batchOps.map((op)=>op.input);
const requester = httpUtils.jsonHttpRequester({
const ac = httpUtils.mergeAbortSignals(batchOps);
const res = await httpUtils.jsonHttpRequester({
...resolvedOpts,

@@ -51,15 +53,11 @@ path,

return opts.headers;
}
},
signal: ac.signal
});
return {
cancel: requester.cancel,
promise: requester.promise.then((res)=>{
const resJSON = Array.isArray(res.json) ? res.json : batchOps.map(()=>res.json);
const result = resJSON.map((item)=>({
meta: res.meta,
json: item
}));
return result;
})
};
const resJSON = Array.isArray(res.json) ? res.json : batchOps.map(()=>res.json);
const result = resJSON.map((item)=>({
meta: res.meta,
json: item
}));
return result;
}

@@ -70,6 +68,4 @@ };

const mutation = dataLoader.dataLoader(batchLoader('mutation'));
const subscription = dataLoader.dataLoader(batchLoader('subscription'));
const loaders = {
query,
subscription,
mutation

@@ -79,4 +75,7 @@ };

return observable.observable((observer)=>{
/* istanbul ignore if -- @preserve */ if (op.type === 'subscription') {
throw new Error('Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`');
}
const loader = loaders[op.type];
const { promise , cancel } = loader.load(op);
const promise = loader.load(op);
let _res = undefined;

@@ -103,3 +102,3 @@ promise.then((res)=>{

return ()=>{
cancel();
// noop
};

@@ -106,0 +105,0 @@ });

@@ -32,12 +32,14 @@ 'use strict';

path,
inputs
inputs,
signal: null
});
return url.length <= maxURLLength;
},
fetch (batchOps) {
async fetch (batchOps) {
const path = batchOps.map((op)=>op.path).join(',');
const inputs = batchOps.map((op)=>op.input);
const ac = resolvedOpts.AbortController ? new resolvedOpts.AbortController() : null;
const ac = httpUtils.mergeAbortSignals(batchOps);
const responsePromise = httpUtils.fetchHTTPResponse({
...resolvedOpts,
signal: ac.signal,
type,

@@ -61,38 +63,38 @@ contentTypeHeader: 'application/json',

}
}, ac);
return {
promise: responsePromise.then(async (res)=>{
if (!res.body) {
throw new Error('Received response without body');
}
const [head] = await unstableCoreDoNotImport.jsonlStreamConsumer({
from: res.body,
deserialize: resolvedOpts.transformer.output.deserialize
});
const res = await responsePromise;
const [head] = await unstableCoreDoNotImport.jsonlStreamConsumer({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
from: res.body,
deserialize: resolvedOpts.transformer.output.deserialize,
// onError: console.error,
formatError (opts) {
const error = opts.error;
return TRPCClientError.TRPCClientError.from({
error
});
const promises = Object.keys(batchOps).map(async (key)=>{
let json = await head[key];
if ('result' in json) {
/**
* Not very pretty, but we need to unwrap nested data as promises
* Our stream producer will only resolve top-level async values or async values that are directly nested in another async value
*/ const result = await Promise.resolve(json.result);
json = {
result: {
data: await Promise.resolve(result.data)
}
};
},
abortController: ac
});
const promises = Object.keys(batchOps).map(async (key)=>{
let json = await Promise.resolve(head[key]);
if ('result' in json) {
/**
* Not very pretty, but we need to unwrap nested data as promises
* Our stream producer will only resolve top-level async values or async values that are directly nested in another async value
*/ const result = await Promise.resolve(json.result);
json = {
result: {
data: await Promise.resolve(result.data)
}
return {
json,
meta: {
response: res
}
};
});
return promises;
}),
cancel () {
ac?.abort();
};
}
};
return {
json,
meta: {
response: res
}
};
});
return promises;
}

@@ -103,6 +105,4 @@ };

const mutation = dataLoader.dataLoader(batchLoader('mutation'));
const subscription = dataLoader.dataLoader(batchLoader('subscription'));
const loaders = {
query,
subscription,
mutation

@@ -112,4 +112,7 @@ };

return observable.observable((observer)=>{
/* istanbul ignore if -- @preserve */ if (op.type === 'subscription') {
throw new Error('Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`');
}
const loader = loaders[op.type];
const { promise , cancel } = loader.load(op);
const promise = loader.load(op);
let _res = undefined;

@@ -138,3 +141,3 @@ promise.then((res)=>{

return ()=>{
cancel();
// noop
};

@@ -141,0 +144,0 @@ });

@@ -1,5 +0,5 @@

import type { AnyRootTypes, AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import type { AnyClientTypes, AnyRouter } from '@trpc/server/unstable-core-do-not-import';
import type { HTTPLinkBaseOptions } from './internals/httpUtils';
import { type HTTPHeaders, type Operation, type TRPCLink } from './types';
export type HTTPLinkOptions<TRoot extends AnyRootTypes> = HTTPLinkBaseOptions<TRoot> & {
export type HTTPLinkOptions<TRoot extends AnyClientTypes> = HTTPLinkBaseOptions<TRoot> & {
/**

@@ -6,0 +6,0 @@ * Headers to be set on outgoing requests or a callback that of said headers

@@ -44,2 +44,5 @@ 'use strict';

const { path , input , type } = op;
/* istanbul ignore if -- @preserve */ if (type === 'subscription') {
throw new Error('Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`');
}
const request = universalRequester({

@@ -50,2 +53,3 @@ ...resolvedOpts,

input,
signal: op.signal,
headers () {

@@ -64,3 +68,3 @@ if (!opts.headers) {

let meta = undefined;
request.promise.then((res)=>{
request.then((res)=>{
meta = res.meta;

@@ -85,3 +89,3 @@ const transformed = unstableCoreDoNotImport.transformResult(res.json, resolvedOpts.transformer.output);

return ()=>{
request.cancel();
// noop
};

@@ -88,0 +92,0 @@ });

@@ -1,4 +0,4 @@

export declare function isOctetType(input: unknown): boolean;
export declare function isFormData(input: unknown): boolean;
export declare function isNonJsonSerializable(input: unknown): boolean;
export declare function isOctetType(input: unknown): input is Uint8Array | Blob;
export declare function isFormData(input: unknown): input is FormData;
export declare function isNonJsonSerializable(input: unknown): input is Uint8Array | Blob | FormData;
//# sourceMappingURL=contentTypes.d.ts.map

@@ -1,9 +0,9 @@

import type { AnyRootTypes, CombinedDataTransformer, ProcedureType, TRPCResponse } from '@trpc/server/unstable-core-do-not-import';
import type { AbortControllerEsque, AbortControllerInstanceEsque, FetchEsque, RequestInitEsque, ResponseEsque } from '../../internals/types';
import type { AnyClientTypes, CombinedDataTransformer, Maybe, ProcedureType, TRPCAcceptHeader, TRPCResponse } from '@trpc/server/unstable-core-do-not-import';
import type { FetchEsque, RequestInitEsque, ResponseEsque } from '../../internals/types';
import type { TransformerOptions } from '../../unstable-internals';
import type { HTTPHeaders, PromiseAndCancel } from '../types';
import type { HTTPHeaders } from '../types';
/**
* @internal
*/
export type HTTPLinkBaseOptions<TRoot extends Pick<AnyRootTypes, 'transformer'>> = {
export type HTTPLinkBaseOptions<TRoot extends Pick<AnyClientTypes, 'transformer'>> = {
url: string | URL;

@@ -15,6 +15,2 @@ /**

/**
* Add ponyfill for AbortController
*/
AbortController?: AbortControllerEsque | null;
/**
* Send all requests `as POST`s requests regardless of the procedure type

@@ -29,7 +25,6 @@ * The HTTP handler must separately allow overriding the method. See:

fetch?: FetchEsque;
AbortController: AbortControllerEsque | null;
transformer: CombinedDataTransformer;
methodOverride?: 'POST';
}
export declare function resolveHTTPLinkOptions(opts: HTTPLinkBaseOptions<AnyRootTypes>): ResolvedHTTPLinkOptions;
export declare function resolveHTTPLinkOptions(opts: HTTPLinkBaseOptions<AnyClientTypes>): ResolvedHTTPLinkOptions;
export interface HTTPResult {

@@ -53,2 +48,3 @@ json: TRPCResponse;

path: string;
signal: Maybe<AbortSignal>;
};

@@ -58,3 +54,3 @@ type GetUrl = (opts: HTTPBaseRequestOptions) => string;

export type ContentOptions = {
trpcAcceptHeader?: 'application/jsonl';
trpcAcceptHeader?: TRPCAcceptHeader;
contentTypeHeader?: string;

@@ -68,3 +64,3 @@ getUrl: GetUrl;

headers: () => HTTPHeaders | Promise<HTTPHeaders>;
}) => PromiseAndCancel<HTTPResult>;
}) => Promise<HTTPResult>;
export declare const jsonHttpRequester: Requester;

@@ -74,5 +70,12 @@ export type HTTPRequestOptions = ContentOptions & HTTPBaseRequestOptions & {

};
export declare function fetchHTTPResponse(opts: HTTPRequestOptions, ac?: AbortControllerInstanceEsque | null): Promise<ResponseEsque>;
export declare function httpRequest(opts: HTTPRequestOptions): PromiseAndCancel<HTTPResult>;
export declare function fetchHTTPResponse(opts: HTTPRequestOptions): Promise<ResponseEsque>;
export declare function httpRequest(opts: HTTPRequestOptions): Promise<HTTPResult>;
/**
* Merges multiple abort signals into a single one
* - When all signals have been aborted, the merged signal will be aborted
*/
export declare function mergeAbortSignals(opts: {
signal: Maybe<AbortSignal>;
}[]): AbortController;
export {};
//# sourceMappingURL=httpUtils.d.ts.map
'use strict';
var getFetch = require('../../getFetch.js');
var getAbortController = require('../../internals/getAbortController.js');
var TRPCClientError = require('../../TRPCClientError.js');
var transformer = require('../../internals/transformer.js');

@@ -10,5 +8,4 @@

return {
url: opts.url.toString().replace(/\/$/, ''),
url: opts.url.toString(),
fetch: opts.fetch,
AbortController: getAbortController.getAbortController(opts.AbortController),
transformer: transformer.getTransformer(opts.transformer),

@@ -29,3 +26,4 @@ methodOverride: opts.methodOverride

query: 'GET',
mutation: 'POST'
mutation: 'POST',
subscription: 'PATCH'
};

@@ -36,8 +34,13 @@ function getInput(opts) {

const getUrl = (opts)=>{
let url = opts.url + '/' + opts.path;
const parts = opts.url.split('?');
const base = parts[0].replace(/\/$/, ''); // Remove any trailing slashes
let url = base + '/' + opts.path;
const queryParts = [];
if (parts[1]) {
queryParts.push(parts[1]);
}
if ('inputs' in opts) {
queryParts.push('batch=1');
}
if (opts.type === 'query') {
if (opts.type === 'query' || opts.type === 'subscription') {
const input = getInput(opts);

@@ -68,3 +71,31 @@ if (input !== undefined && opts.methodOverride !== 'POST') {

};
async function fetchHTTPResponse(opts, ac) {
/**
* Polyfill for DOMException with AbortError name
*/ class AbortError extends Error {
constructor(){
const name = 'AbortError';
super(name);
this.name = name;
this.message = name;
}
}
/**
* Polyfill for `signal.throwIfAborted()`
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted
*/ const throwIfAborted = (signal)=>{
if (!signal?.aborted) {
return;
}
// If available, use the native implementation
signal.throwIfAborted?.();
// If we have `DOMException`, use it
if (typeof DOMException !== 'undefined') {
throw new DOMException('AbortError', 'AbortError');
}
// Otherwise, use our own implementation
throw new AbortError();
};
async function fetchHTTPResponse(opts) {
throwIfAborted(opts.signal);
const url = opts.getUrl(opts);

@@ -80,5 +111,2 @@ const body = opts.getBody(opts);

})();
/* istanbul ignore if -- @preserve */ if (type === 'subscription') {
throw new Error('Subscriptions should use wsLink');
}
const headers = {

@@ -95,3 +123,3 @@ ...opts.contentTypeHeader ? {

method: opts.methodOverride ?? METHOD[type],
signal: ac?.signal,
signal: opts.signal,
body,

@@ -101,34 +129,41 @@ headers

}
function httpRequest(opts) {
const ac = opts.AbortController ? new opts.AbortController() : null;
async function httpRequest(opts) {
const meta = {};
let done = false;
const promise = new Promise((resolve, reject)=>{
fetchHTTPResponse(opts, ac).then((_res)=>{
meta.response = _res;
done = true;
return _res.json();
}).then((json)=>{
meta.responseJSON = json;
resolve({
json: json,
meta
});
}).catch((err)=>{
done = true;
reject(TRPCClientError.TRPCClientError.from(err, {
meta
}));
});
});
const cancel = ()=>{
if (!done) {
ac?.abort();
}
};
const res = await fetchHTTPResponse(opts);
meta.response = res;
const json = await res.json();
meta.responseJSON = json;
return {
promise,
cancel
json: json,
meta
};
}
/**
* Merges multiple abort signals into a single one
* - When all signals have been aborted, the merged signal will be aborted
*/ function mergeAbortSignals(opts) {
const ac = new AbortController();
if (opts.some((o)=>!o.signal)) {
return ac;
}
const count = opts.length;
let abortedCount = 0;
const onAbort = ()=>{
if (++abortedCount === count) {
ac.abort();
}
};
for (const o of opts){
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const signal = o.signal;
if (signal.aborted) {
onAbort();
} else {
signal.addEventListener('abort', onAbort, {
once: true
});
}
}
return ac;
}

@@ -141,2 +176,3 @@ exports.fetchHTTPResponse = fetchHTTPResponse;

exports.jsonHttpRequester = jsonHttpRequester;
exports.mergeAbortSignals = mergeAbortSignals;
exports.resolveHTTPLinkOptions = resolveHTTPLinkOptions;

@@ -1,2 +0,1 @@

/// <reference lib="dom.iterable" />
import type { AnyRouter } from '@trpc/server/unstable-core-do-not-import';

@@ -3,0 +2,0 @@ import type { TRPCClientError } from '../TRPCClientError';

import type { Observable, Observer } from '@trpc/server/observable';
import type { InferrableClientTypes, TRPCResultMessage, TRPCSuccessResponse } from '@trpc/server/unstable-core-do-not-import';
import type { InferrableClientTypes, Maybe, TRPCResultMessage, TRPCSuccessResponse } from '@trpc/server/unstable-core-do-not-import';
import type { ResponseEsque } from '../internals/types';

@@ -9,13 +9,2 @@ import type { TRPCClientError } from '../TRPCClientError';

*/
export type CancelFn = () => void;
/**
* @internal
*/
export type PromiseAndCancel<TValue> = {
promise: Promise<TValue>;
cancel: CancelFn;
};
/**
* @internal
*/
export interface OperationContext extends Record<string, unknown> {

@@ -32,2 +21,3 @@ }

context: OperationContext;
signal: Maybe<AbortSignal>;
};

@@ -48,7 +38,27 @@ interface HeadersInitEsque {

}
export type ConnectionState = 'idle' | 'connecting' | 'pending' | 'error';
export interface ConnectionStateMessageBase {
type: 'state';
}
export interface IdleStateMessage extends ConnectionStateMessageBase {
state: 'idle';
}
export interface ConnectingStateMessage<TError> extends ConnectionStateMessageBase {
state: 'connecting';
data: TError | null;
}
export interface PendingStateMessage extends ConnectionStateMessageBase {
state: 'pending';
}
export interface ErrorStateMessage<TError> extends ConnectionStateMessageBase {
state: 'error';
data: TError;
}
export type TRPCConnectionStateMessage<TError> = IdleStateMessage | ConnectingStateMessage<TError> | PendingStateMessage | ErrorStateMessage<TError>;
export declare const isConnectionStateMessage: <TError>(msg: unknown) => msg is TRPCConnectionStateMessage<TError>;
/**
* @internal
*/
export interface OperationResultEnvelope<TOutput> {
result: TRPCResultMessage<TOutput>['result'] | TRPCSuccessResponse<TOutput>['result'];
export interface OperationResultEnvelope<TOutput, TError = unknown> {
result: TRPCConnectionStateMessage<TError> | TRPCResultMessage<TOutput>['result'] | TRPCSuccessResponse<TOutput>['result'];
context?: OperationContext;

@@ -59,3 +69,3 @@ }

*/
export type OperationResultObservable<TInferrable extends InferrableClientTypes, TOutput> = Observable<OperationResultEnvelope<TOutput>, TRPCClientError<TInferrable>>;
export type OperationResultObservable<TInferrable extends InferrableClientTypes, TOutput> = Observable<OperationResultEnvelope<TOutput, TRPCClientError<TInferrable>>, TRPCClientError<TInferrable>>;
/**

@@ -62,0 +72,0 @@ * @internal

import type { Observer, UnsubscribeFn } from '@trpc/server/observable';
import type { AnyRouter, inferClientTypes, inferRouterError, MaybePromise, TRPCResponseMessage } from '@trpc/server/unstable-core-do-not-import';
import type { AnyRouter, inferClientTypes, inferRouterError, TRPCResponseMessage } from '@trpc/server/unstable-core-do-not-import';
import { TRPCClientError } from '../TRPCClientError';
import type { TransformerOptions } from '../unstable-internals';
import type { Operation, TRPCLink } from './types';
type WSCallbackResult<TRouter extends AnyRouter, TOutput> = TRPCResponseMessage<TOutput, inferRouterError<TRouter>>;
import { type UrlOptionsWithConnectionParams } from './internals/urlWithConnectionParams';
import { type Operation, type TRPCConnectionStateMessage, type TRPCLink } from './types';
type WSCallbackResult<TRouter extends AnyRouter, TOutput> = TRPCResponseMessage<TOutput, inferRouterError<TRouter>> | {
result: TRPCConnectionStateMessage<inferRouterError<TRouter>>;
};
type WSCallbackObserver<TRouter extends AnyRouter, TOutput> = Observer<WSCallbackResult<TRouter, TOutput>, TRPCClientError<TRouter>>;
declare const exponentialBackoff: (attemptIndex: number) => number;
export interface WebSocketClientOptions {
export interface WebSocketClientOptions extends UrlOptionsWithConnectionParams {
/**
* The URL to connect to (can be a function that returns a URL)
*/
url: string | (() => MaybePromise<string>);
/**
* Ponyfill which WebSocket implementation to use

@@ -55,11 +54,15 @@ */

} & ({
state: 'open';
state: "open";
ws: WebSocket;
} | {
state: 'closed';
state: "closed";
ws: WebSocket;
} | {
state: 'connecting';
ws?: WebSocket | undefined;
state: "connecting";
ws?: WebSocket;
})) | null;
/**
* Reconnect to the WebSocket server
*/
reconnect: (cause: Error | null) => void;
};

@@ -66,0 +69,0 @@ export type TRPCWebSocketClient = ReturnType<typeof createWSClient>;

@@ -7,2 +7,4 @@ 'use strict';

var transformer = require('../internals/transformer.js');
var urlWithConnectionParams = require('./internals/urlWithConnectionParams.js');
var types = require('./types.js');

@@ -16,3 +18,3 @@ const run = (fn)=>fn();

function createWSClient(opts) {
const { url , WebSocket: WebSocketImpl = WebSocket , retryDelayMs: retryDelayFn = exponentialBackoff , onOpen , onClose , } = opts;
const { WebSocket: WebSocketImpl = WebSocket , retryDelayMs: retryDelayFn = exponentialBackoff , onOpen , onClose , } = opts;
const lazyOpts = {

@@ -33,3 +35,3 @@ ...lazyDefaults,

let lazyDisconnectTimer = undefined;
let activeConnection = lazyOpts.enabled ? null : createConnection();
let activeConnection = lazyOpts.enabled ? null : createConnection(null);
/**

@@ -39,3 +41,3 @@ * tries to send the list of messages

if (!activeConnection) {
activeConnection = createConnection();
activeConnection = createConnection(null);
return;

@@ -65,3 +67,3 @@ }

}
function tryReconnect(conn) {
function tryReconnect(conn, cause) {
if (!!connectTimer) {

@@ -72,3 +74,3 @@ return;

const timeout = retryDelayFn(connectAttempt++);
reconnectInMs(timeout);
reconnectInMs(timeout, cause);
}

@@ -82,3 +84,3 @@ function hasPendingRequests(conn) {

}
function reconnect() {
function reconnect(cause) {
if (lazyOpts.enabled && !hasPendingRequests()) {

@@ -89,10 +91,10 @@ // Skip reconnecting if there are pending requests and we're in lazy mode

const oldConnection = activeConnection;
activeConnection = createConnection();
activeConnection = createConnection(cause);
oldConnection && closeIfNoPending(oldConnection);
}
function reconnectInMs(ms) {
function reconnectInMs(ms, cause) {
if (connectTimer) {
return;
}
connectTimer = setTimeout(reconnect, ms);
connectTimer = setTimeout(reconnect, ms, cause);
}

@@ -126,3 +128,3 @@ function closeIfNoPending(conn) {

};
function createConnection() {
function createConnection(cause) {
const self = {

@@ -132,12 +134,28 @@ id: ++connectionIndex,

};
for (const req of Object.values(pendingRequests)){
if (req.type === 'subscription') {
req.callbacks.next?.({
result: {
type: 'state',
state: 'connecting',
data: cause ?? null
}
});
}
}
clearTimeout(lazyDisconnectTimer);
const onError = ()=>{
const onError = (cause)=>{
self.state = 'closed';
if (self === activeConnection) {
tryReconnect(self);
tryReconnect(self, cause);
}
};
run(async ()=>{
const urlString = typeof url === 'function' ? await url() : url;
const ws = new WebSocketImpl(urlString);
let url = await urlWithConnectionParams.resultOf(opts.url);
if (opts.connectionParams) {
// append `?connectionParams=1` when connection params are used
const prefix = url.includes('?') ? '&' : '?';
url += prefix + 'connectionParams=1';
}
const ws = new WebSocketImpl(url);
self.ws = ws;

@@ -147,11 +165,40 @@ clearTimeout(connectTimer);

ws.addEventListener('open', ()=>{
/* istanbul ignore next -- @preserve */ if (activeConnection?.ws !== ws) {
return;
run(async ()=>{
/* istanbul ignore next -- @preserve */ if (activeConnection?.ws !== ws) {
return;
}
if (opts.connectionParams) {
const connectMsg = {
method: 'connectionParams',
data: await urlWithConnectionParams.resultOf(opts.connectionParams)
};
ws.send(JSON.stringify(connectMsg));
}
connectAttempt = 0;
self.state = 'open';
for (const req of Object.values(pendingRequests)){
if (req.type === 'subscription') {
req.callbacks.next?.({
result: {
type: 'state',
state: 'pending'
}
});
}
}
onOpen?.();
dispatch();
}).catch((cause)=>{
ws.close(// "Status codes in the range 3000-3999 are reserved for use by libraries, frameworks, and applications"
3000, cause);
onError(cause);
});
});
ws.addEventListener('error', (event)=>{
if (event instanceof ErrorEvent) {
onError(event.error);
} else {
onError(new Error('Unknown WebSocket error'));
}
connectAttempt = 0;
self.state = 'open';
onOpen?.();
dispatch();
});
ws.addEventListener('error', onError);
const handleIncomingRequest = (req)=>{

@@ -162,3 +209,3 @@ if (self !== activeConnection) {

if (req.method === 'reconnect') {
reconnect();
reconnect(new Error('Server requested reconnect'));
// notify subscribers

@@ -202,3 +249,3 @@ for (const pendingReq of Object.values(pendingRequests)){

});
ws.addEventListener('close', ({ code })=>{
ws.addEventListener('close', ({ code , reason })=>{
if (self.state === 'open') {

@@ -212,3 +259,3 @@ onClose?.({

// connection might have been replaced already
tryReconnect(self);
tryReconnect(self, new Error(reason));
}

@@ -292,3 +339,6 @@ for (const [key, req] of Object.entries(pendingRequests)){

return activeConnection;
}
},
/**
* Reconnect to the WebSocket server
*/ reconnect
};

@@ -318,6 +368,15 @@ }

id,
context
context,
signal: null
}, {
error (err) {
observer.error(err);
observer.next({
result: {
type: 'state',
state: 'error',
data: err
},
context: context
});
unsub();

@@ -327,6 +386,31 @@ },

observer.complete();
observer.next({
result: {
type: 'state',
state: 'idle'
},
context: context
});
},
next (message) {
if ('result' in message && types.isConnectionStateMessage(message.result)) {
message.result;
observer.next({
result: message.result,
context: context
});
return;
}
if (!('id' in message)) return;
const transformed = unstableCoreDoNotImport.transformResult(message, transformer$1.output);
if (!transformed.ok) {
const error = TRPCClientError.TRPCClientError.from(transformed.error);
observer.next({
result: {
type: 'state',
state: 'error',
data: error
},
context: context
});
observer.error(TRPCClientError.TRPCClientError.from(transformed.error));

@@ -336,3 +420,4 @@ return;

observer.next({
result: transformed.result
result: transformed.result,
context: context
});

@@ -348,2 +433,9 @@ if (op.type !== 'subscription') {

unsub();
observer.next({
result: {
type: 'state',
state: 'idle'
},
context: context
});
};

@@ -350,0 +442,0 @@ });

@@ -14,2 +14,11 @@ 'use strict';

}
function getMessageFromUnknownError(err, fallback) {
if (typeof err === 'string') {
return err;
}
if (unstableCoreDoNotImport.isObject(err) && typeof err['message'] === 'string') {
return err['message'];
}
return fallback;
}
class TRPCClientError extends Error {

@@ -34,11 +43,5 @@ static from(_cause, opts = {}) {

}
if (!(cause instanceof Error)) {
return new TRPCClientError('Unknown error', {
...opts,
cause: cause
});
}
return new TRPCClientError(cause.message, {
return new TRPCClientError(getMessageFromUnknownError(cause, 'Unknown error'), {
...opts,
cause: unstableCoreDoNotImport.getCauseFromUnknown(cause)
cause: cause
});

@@ -45,0 +48,0 @@ }

{
"name": "@trpc/client",
"version": "11.0.0-alpha-tmp-rethrow-next-errors.386+a4f5d8541",
"version": "11.0.0-alpha-tmp-subscription-connection-state.485+386eae02c",
"description": "The tRPC client library",

@@ -79,6 +79,6 @@ "author": "KATT",

"peerDependencies": {
"@trpc/server": "11.0.0-alpha-tmp-rethrow-next-errors.386+a4f5d8541"
"@trpc/server": "11.0.0-alpha-tmp-subscription-connection-state.485+386eae02c"
},
"devDependencies": {
"@trpc/server": "11.0.0-alpha-tmp-rethrow-next-errors.386+a4f5d8541",
"@trpc/server": "11.0.0-alpha-tmp-subscription-connection-state.485+386eae02c",
"@types/isomorphic-fetch": "^0.0.39",

@@ -100,3 +100,3 @@ "@types/node": "^20.10.0",

],
"gitHead": "a4f5d854168964a872610d94d4aa359789db760b"
"gitHead": "386eae02c675ba0fe0feda78188b6975e56d0e49"
}

@@ -129,2 +129,12 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */

): CreateTRPCClient<TRouter> {
const proxy = createRecursiveProxy<CreateTRPCClient<TRouter>>(
({ path, args }) => {
const pathCopy = [...path];
const procedureType = clientCallTypeToProcedureType(pathCopy.pop()!);
const fullPath = pathCopy.join('.');
return (client as any)[procedureType](fullPath, ...args);
},
);
return createFlatProxy<CreateTRPCClient<TRouter>>((key) => {

@@ -137,10 +147,3 @@ if (client.hasOwnProperty(key)) {

}
return createRecursiveProxy(({ path, args }) => {
const pathCopy = [key, ...path];
const procedureType = clientCallTypeToProcedureType(pathCopy.pop()!);
const fullPath = pathCopy.join('.');
return (client as any)[procedureType](fullPath, ...args);
});
return proxy[key];
});

@@ -147,0 +150,0 @@ }

/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { CancelFn, PromiseAndCancel } from '../links/types';

@@ -13,10 +12,6 @@ type BatchItem<TKey, TValue> = {

items: BatchItem<TKey, TValue>[];
cancel: CancelFn;
};
export type BatchLoader<TKey, TValue> = {
validate: (keys: TKey[]) => boolean;
fetch: (keys: TKey[]) => {
promise: Promise<TValue[] | Promise<TValue>[]>;
cancel: CancelFn;
};
fetch: (keys: TKey[]) => Promise<TValue[] | Promise<TValue>[]>;
};

@@ -103,3 +98,2 @@

items,
cancel: throwFatalError,
};

@@ -109,6 +103,3 @@ for (const item of items) {

}
const { promise, cancel } = batchLoader.fetch(
batch.items.map((_item) => _item.key),
);
batch.cancel = cancel;
const promise = batchLoader.fetch(batch.items.map((_item) => _item.key));

@@ -147,3 +138,3 @@ promise

}
function load(key: TKey): PromiseAndCancel<TValue> {
function load(key: TKey): Promise<TValue> {
const item: BatchItem<TKey, TValue> = {

@@ -170,13 +161,4 @@ aborted: false,

}
const cancel = () => {
item.aborted = true;
if (item.batch?.items.every((item) => item.aborted)) {
// All items in the batch have been cancelled
item.batch.cancel();
item.batch = null;
}
};
return { promise, cancel };
return promise;
}

@@ -183,0 +165,0 @@

@@ -9,2 +9,3 @@ import type {

InferrableClientTypes,
Maybe,
TypeError,

@@ -17,2 +18,3 @@ } from '@trpc/server/unstable-core-do-not-import';

TRPCClientRuntime,
TRPCConnectionStateMessage,
TRPCLink,

@@ -32,3 +34,3 @@ } from '../links/types';

export interface TRPCSubscriptionObserver<TValue, TError> {
onStarted: () => void;
onStarted: (opts: { context: OperationContext | undefined }) => void;
onData: (value: TValue) => void;

@@ -38,2 +40,3 @@ onError: (err: TError) => void;

onComplete: () => void;
onStateChange: (state: TRPCConnectionStateMessage<TError>) => void;
}

@@ -72,8 +75,3 @@

private $request<TInput = unknown, TOutput = unknown>({
type,
input,
path,
context = {},
}: {
private $request<TInput = unknown, TOutput = unknown>(opts: {
type: TRPCType;

@@ -83,2 +81,3 @@ input: TInput;

context?: OperationContext;
signal: Maybe<AbortSignal>;
}) {

@@ -88,7 +87,5 @@ const chain$ = createChain<AnyRouter, TInput, TOutput>({

op: {
...opts,
context: opts.context ?? {},
id: ++this.requestId,
type,
path,
input,
context,
},

@@ -98,3 +95,4 @@ });

}
private requestAsPromise<TInput = unknown, TOutput = unknown>(opts: {
private async requestAsPromise<TInput = unknown, TOutput = unknown>(opts: {
type: TRPCType;

@@ -104,21 +102,14 @@ input: TInput;

context?: OperationContext;
signal?: AbortSignal;
signal: Maybe<AbortSignal>;
}): Promise<TOutput> {
const req$ = this.$request<TInput, TOutput>(opts);
type TValue = inferObservableValue<typeof req$>;
const { promise, abort } = observableToPromise<TValue>(req$);
try {
const req$ = this.$request<TInput, TOutput>(opts);
type TValue = inferObservableValue<typeof req$>;
const abortablePromise = new Promise<TOutput>((resolve, reject) => {
opts.signal?.addEventListener('abort', abort);
promise
.then((envelope) => {
resolve((envelope.result as any).data);
})
.catch((err) => {
reject(TRPCClientError.from(err));
});
});
return abortablePromise;
const envelope = await observableToPromise<TValue>(req$);
const data = (envelope.result as any).data;
return data;
} catch (err) {
throw TRPCClientError.from(err as Error);
}
}

@@ -156,2 +147,3 @@ public query(path: string, input?: unknown, opts?: TRPCRequestOptions) {

context: opts?.context,
signal: null,
});

@@ -161,5 +153,9 @@ return observable$.subscribe({

if (envelope.result.type === 'started') {
opts.onStarted?.();
opts.onStarted?.({
context: envelope.context,
});
} else if (envelope.result.type === 'stopped') {
opts.onStopped?.();
} else if (envelope.result.type === 'state') {
opts.onStateChange?.(envelope.result);
} else {

@@ -166,0 +162,0 @@ opts.onData?.(envelope.result.data);

@@ -1,20 +0,2 @@

export type AbortControllerEsque = new () => AbortControllerInstanceEsque;
/**
* Allows you to abort one or more requests.
*/
export interface AbortControllerInstanceEsque {
/**
* The AbortSignal object associated with this object.
*/
readonly signal: AbortSignal;
/**
* Sets this object's AbortSignal's aborted flag and signals to
* any observers that the associated activity is to be aborted.
*/
abort(): void;
}
/**
* A subset of the standard fetch function type needed by tRPC internally.

@@ -21,0 +3,0 @@ * @see fetch from lib.dom.d.ts

@@ -10,2 +10,3 @@ export * from './links/types';

export * from './links/wsLink';
export * from './links/httpSubscriptionLink';

@@ -12,0 +13,0 @@ // These are not public (yet) as we get this functionality from tanstack query

@@ -13,2 +13,3 @@ import type { AnyRouter, ProcedureType } from '@trpc/server';

jsonHttpRequester,
mergeAbortSignals,
resolveHTTPLinkOptions,

@@ -45,2 +46,3 @@ } from './internals/httpUtils';

inputs,
signal: null,
});

@@ -50,7 +52,8 @@

},
fetch(batchOps) {
async fetch(batchOps) {
const path = batchOps.map((op) => op.path).join(',');
const inputs = batchOps.map((op) => op.input);
const ac = mergeAbortSignals(batchOps);
const requester = jsonHttpRequester({
const res = await jsonHttpRequester({
...resolvedOpts,

@@ -71,18 +74,12 @@ path,

},
signal: ac.signal,
});
return {
cancel: requester.cancel,
promise: requester.promise.then((res) => {
const resJSON = Array.isArray(res.json)
? res.json
: batchOps.map(() => res.json);
const result = resJSON.map((item) => ({
meta: res.meta,
json: item,
}));
return result;
}),
};
const resJSON = Array.isArray(res.json)
? res.json
: batchOps.map(() => res.json);
const result = resJSON.map((item) => ({
meta: res.meta,
json: item,
}));
return result;
},

@@ -93,12 +90,15 @@ };

const query = dataLoader(batchLoader('query'));
const mutation = dataLoader<Operation, HTTPResult>(batchLoader('mutation'));
const subscription = dataLoader<Operation, HTTPResult>(
batchLoader('subscription'),
);
const mutation = dataLoader(batchLoader('mutation'));
const loaders = { query, subscription, mutation };
const loaders = { query, mutation };
return ({ op }) => {
return observable((observer) => {
/* istanbul ignore if -- @preserve */
if (op.type === 'subscription') {
throw new Error(
'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',
);
}
const loader = loaders[op.type];
const { promise, cancel } = loader.load(op);
const promise = loader.load(op);

@@ -137,3 +137,3 @@ let _res = undefined as HTTPResult | undefined;

return () => {
cancel();
// noop
};

@@ -140,0 +140,0 @@ });

import type { AnyRouter, ProcedureType } from '@trpc/server';
import { observable } from '@trpc/server/observable';
import type { TRPCResponse } from '@trpc/server/rpc';
import type { TRPCErrorShape, TRPCResponse } from '@trpc/server/rpc';
import type { AnyRootTypes } from '@trpc/server/unstable-core-do-not-import';

@@ -16,2 +16,3 @@ import { jsonlStreamConsumer } from '@trpc/server/unstable-core-do-not-import';

getUrl,
mergeAbortSignals,
resolveHTTPLinkOptions,

@@ -61,2 +62,3 @@ } from './internals/httpUtils';

inputs,
signal: null,
});

@@ -66,78 +68,73 @@

},
fetch(batchOps) {
async fetch(batchOps) {
const path = batchOps.map((op) => op.path).join(',');
const inputs = batchOps.map((op) => op.input);
const ac = resolvedOpts.AbortController
? new resolvedOpts.AbortController()
: null;
const responsePromise = fetchHTTPResponse(
{
...resolvedOpts,
type,
contentTypeHeader: 'application/json',
trpcAcceptHeader: 'application/jsonl',
getUrl,
getBody,
inputs,
path,
headers() {
if (!opts.headers) {
return {};
}
if (typeof opts.headers === 'function') {
return opts.headers({
opList: batchOps as NonEmptyArray<Operation>,
});
}
return opts.headers;
},
const ac = mergeAbortSignals(batchOps);
const responsePromise = fetchHTTPResponse({
...resolvedOpts,
signal: ac.signal,
type,
contentTypeHeader: 'application/json',
trpcAcceptHeader: 'application/jsonl',
getUrl,
getBody,
inputs,
path,
headers() {
if (!opts.headers) {
return {};
}
if (typeof opts.headers === 'function') {
return opts.headers({
opList: batchOps as NonEmptyArray<Operation>,
});
}
return opts.headers;
},
ac,
);
});
return {
promise: responsePromise.then(async (res) => {
if (!res.body) {
throw new Error('Received response without body');
}
const [head] = await jsonlStreamConsumer<
Record<string, Promise<any>>
>({
from: res.body,
deserialize: resolvedOpts.transformer.output.deserialize,
// onError: console.error,
const res = await responsePromise;
const [head] = await jsonlStreamConsumer<
Record<string, Promise<any>>
>({
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
from: res.body!,
deserialize: resolvedOpts.transformer.output.deserialize,
// onError: console.error,
formatError(opts) {
const error = opts.error as TRPCErrorShape;
return TRPCClientError.from({
error,
});
},
abortController: ac,
});
const promises = Object.keys(batchOps).map(
async (key): Promise<HTTPResult> => {
let json: TRPCResponse = await Promise.resolve(head[key]);
const promises = Object.keys(batchOps).map(
async (key): Promise<HTTPResult> => {
let json: TRPCResponse = await head[key];
if ('result' in json) {
/**
* Not very pretty, but we need to unwrap nested data as promises
* Our stream producer will only resolve top-level async values or async values that are directly nested in another async value
*/
const result = await Promise.resolve(json.result);
json = {
result: {
data: await Promise.resolve(result.data),
},
};
}
if ('result' in json) {
/**
* Not very pretty, but we need to unwrap nested data as promises
* Our stream producer will only resolve top-level async values or async values that are directly nested in another async value
*/
const result = await Promise.resolve(json.result);
json = {
result: {
data: await Promise.resolve(result.data),
},
};
}
return {
json,
meta: {
response: res,
},
};
return {
json,
meta: {
response: res,
},
);
return promises;
}),
cancel() {
ac?.abort();
};
},
};
);
return promises;
},

@@ -149,9 +146,14 @@ };

const mutation = dataLoader(batchLoader('mutation'));
const subscription = dataLoader(batchLoader('subscription'));
const loaders = { query, subscription, mutation };
const loaders = { query, mutation };
return ({ op }) => {
return observable((observer) => {
/* istanbul ignore if -- @preserve */
if (op.type === 'subscription') {
throw new Error(
'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',
);
}
const loader = loaders[op.type];
const { promise, cancel } = loader.load(op);
const promise = loader.load(op);

@@ -189,3 +191,3 @@ let _res = undefined as HTTPResult | undefined;

return () => {
cancel();
// noop
};

@@ -192,0 +194,0 @@ });

import { observable } from '@trpc/server/observable';
import type {
AnyRootTypes,
AnyClientTypes,
AnyRouter,

@@ -28,3 +28,3 @@ } from '@trpc/server/unstable-core-do-not-import';

export type HTTPLinkOptions<TRoot extends AnyRootTypes> =
export type HTTPLinkOptions<TRoot extends AnyClientTypes> =
HTTPLinkBaseOptions<TRoot> & {

@@ -84,2 +84,8 @@ /**

const { path, input, type } = op;
/* istanbul ignore if -- @preserve */
if (type === 'subscription') {
throw new Error(
'Subscriptions are unsupported by `httpLink` - use `httpSubscriptionLink` or `wsLink`',
);
}

@@ -91,2 +97,3 @@ const request = universalRequester({

input,
signal: op.signal,
headers() {

@@ -105,3 +112,3 @@ if (!opts.headers) {

let meta: HTTPResult['meta'] | undefined = undefined;
request.promise
request
.then((res) => {

@@ -133,3 +140,3 @@ meta = res.meta;

return () => {
request.cancel();
// noop
};

@@ -136,0 +143,0 @@ });

import type {
AnyRootTypes,
AnyClientTypes,
CombinedDataTransformer,
Maybe,
ProcedureType,
TRPCAcceptHeader,
TRPCResponse,
} from '@trpc/server/unstable-core-do-not-import';
import { getFetch } from '../../getFetch';
import { getAbortController } from '../../internals/getAbortController';
import type {
AbortControllerEsque,
AbortControllerInstanceEsque,
FetchEsque,

@@ -16,6 +15,5 @@ RequestInitEsque,

} from '../../internals/types';
import { TRPCClientError } from '../../TRPCClientError';
import type { TransformerOptions } from '../../unstable-internals';
import { getTransformer } from '../../unstable-internals';
import type { HTTPHeaders, PromiseAndCancel } from '../types';
import type { HTTPHeaders } from '../types';

@@ -26,3 +24,3 @@ /**

export type HTTPLinkBaseOptions<
TRoot extends Pick<AnyRootTypes, 'transformer'>,
TRoot extends Pick<AnyClientTypes, 'transformer'>,
> = {

@@ -35,6 +33,2 @@ url: string | URL;

/**
* Add ponyfill for AbortController
*/
AbortController?: AbortControllerEsque | null;
/**
* Send all requests `as POST`s requests regardless of the procedure type

@@ -50,3 +44,2 @@ * The HTTP handler must separately allow overriding the method. See:

fetch?: FetchEsque;
AbortController: AbortControllerEsque | null;
transformer: CombinedDataTransformer;

@@ -57,8 +50,7 @@ methodOverride?: 'POST';

export function resolveHTTPLinkOptions(
opts: HTTPLinkBaseOptions<AnyRootTypes>,
opts: HTTPLinkBaseOptions<AnyClientTypes>,
): ResolvedHTTPLinkOptions {
return {
url: opts.url.toString().replace(/\/$/, ''), // Remove any trailing slashes
url: opts.url.toString(),
fetch: opts.fetch,
AbortController: getAbortController(opts.AbortController),
transformer: getTransformer(opts.transformer),

@@ -82,2 +74,3 @@ methodOverride: opts.methodOverride,

mutation: 'POST',
subscription: 'PATCH',
} as const;

@@ -109,2 +102,3 @@

path: string;
signal: Maybe<AbortSignal>;
};

@@ -116,3 +110,3 @@

export type ContentOptions = {
trpcAcceptHeader?: 'application/jsonl';
trpcAcceptHeader?: TRPCAcceptHeader;
contentTypeHeader?: string;

@@ -124,8 +118,15 @@ getUrl: GetUrl;

export const getUrl: GetUrl = (opts) => {
let url = opts.url + '/' + opts.path;
const parts = opts.url.split('?') as [string, string?];
const base = parts[0].replace(/\/$/, ''); // Remove any trailing slashes
let url = base + '/' + opts.path;
const queryParts: string[] = [];
if (parts[1]) {
queryParts.push(parts[1]);
}
if ('inputs' in opts) {
queryParts.push('batch=1');
}
if (opts.type === 'query') {
if (opts.type === 'query' || opts.type === 'subscription') {
const input = getInput(opts);

@@ -154,3 +155,3 @@ if (input !== undefined && opts.methodOverride !== 'POST') {

},
) => PromiseAndCancel<HTTPResult>;
) => Promise<HTTPResult>;

@@ -166,2 +167,14 @@ export const jsonHttpRequester: Requester = (opts) => {

/**
* Polyfill for DOMException with AbortError name
*/
class AbortError extends Error {
constructor() {
const name = 'AbortError';
super(name);
this.name = name;
this.message = name;
}
}
export type HTTPRequestOptions = ContentOptions &

@@ -172,6 +185,26 @@ HTTPBaseRequestOptions & {

export async function fetchHTTPResponse(
opts: HTTPRequestOptions,
ac?: AbortControllerInstanceEsque | null,
) {
/**
* Polyfill for `signal.throwIfAborted()`
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted
*/
const throwIfAborted = (signal: Maybe<AbortSignal>) => {
if (!signal?.aborted) {
return;
}
// If available, use the native implementation
signal.throwIfAborted?.();
// If we have `DOMException`, use it
if (typeof DOMException !== 'undefined') {
throw new DOMException('AbortError', 'AbortError');
}
// Otherwise, use our own implementation
throw new AbortError();
};
export async function fetchHTTPResponse(opts: HTTPRequestOptions) {
throwIfAborted(opts.signal);
const url = opts.getUrl(opts);

@@ -187,6 +220,2 @@ const body = opts.getBody(opts);

})();
/* istanbul ignore if -- @preserve */
if (type === 'subscription') {
throw new Error('Subscriptions should use wsLink');
}
const headers = {

@@ -204,3 +233,3 @@ ...(opts.contentTypeHeader

method: opts.methodOverride ?? METHOD[type],
signal: ac?.signal,
signal: opts.signal,
body,

@@ -211,34 +240,58 @@ headers,

export function httpRequest(
export async function httpRequest(
opts: HTTPRequestOptions,
): PromiseAndCancel<HTTPResult> {
const ac = opts.AbortController ? new opts.AbortController() : null;
): Promise<HTTPResult> {
const meta = {} as HTTPResult['meta'];
let done = false;
const promise = new Promise<HTTPResult>((resolve, reject) => {
fetchHTTPResponse(opts, ac)
.then((_res) => {
meta.response = _res;
done = true;
return _res.json();
})
.then((json) => {
meta.responseJSON = json;
resolve({
json: json as TRPCResponse,
meta,
});
})
.catch((err) => {
done = true;
reject(TRPCClientError.from(err, { meta }));
const res = await fetchHTTPResponse(opts);
meta.response = res;
const json = await res.json();
meta.responseJSON = json;
return {
json: json as TRPCResponse,
meta,
};
}
/**
* Merges multiple abort signals into a single one
* - When all signals have been aborted, the merged signal will be aborted
*/
export function mergeAbortSignals(
opts: {
signal: Maybe<AbortSignal>;
}[],
): AbortController {
const ac = new AbortController();
if (opts.some((o) => !o.signal)) {
return ac;
}
const count = opts.length;
let abortedCount = 0;
const onAbort = () => {
if (++abortedCount === count) {
ac.abort();
}
};
for (const o of opts) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const signal = o.signal!;
if (signal.aborted) {
onAbort();
} else {
signal.addEventListener('abort', onAbort, {
once: true,
});
});
const cancel = () => {
if (!done) {
ac?.abort();
}
};
return { promise, cancel };
}
return ac;
}
import type { Observable, Observer } from '@trpc/server/observable';
import type {
InferrableClientTypes,
Maybe,
TRPCResultMessage,

@@ -19,15 +20,2 @@ TRPCSuccessResponse,

*/
export type CancelFn = () => void;
/**
* @internal
*/
export type PromiseAndCancel<TValue> = {
promise: Promise<TValue>;
cancel: CancelFn;
};
/**
* @internal
*/
export interface OperationContext extends Record<string, unknown> {}

@@ -44,2 +32,3 @@

context: OperationContext;
signal: Maybe<AbortSignal>;
};

@@ -71,7 +60,50 @@

export type ConnectionState = 'idle' | 'connecting' | 'pending' | 'error';
export interface ConnectionStateMessageBase {
type: 'state';
}
export interface IdleStateMessage extends ConnectionStateMessageBase {
state: 'idle';
}
export interface ConnectingStateMessage<TError>
extends ConnectionStateMessageBase {
state: 'connecting';
data: TError | null;
}
export interface PendingStateMessage extends ConnectionStateMessageBase {
state: 'pending';
}
export interface ErrorStateMessage<TError> extends ConnectionStateMessageBase {
state: 'error';
data: TError;
}
export type TRPCConnectionStateMessage<TError> =
| IdleStateMessage
| ConnectingStateMessage<TError>
| PendingStateMessage
| ErrorStateMessage<TError>;
export const isConnectionStateMessage = <TError>(
msg: unknown,
): msg is TRPCConnectionStateMessage<TError> => {
return (
typeof msg === 'object' &&
msg !== null &&
'type' in msg &&
msg.type === 'state'
);
};
/**
* @internal
*/
export interface OperationResultEnvelope<TOutput> {
export interface OperationResultEnvelope<TOutput, TError = unknown> {
result:
| TRPCConnectionStateMessage<TError>
| TRPCResultMessage<TOutput>['result']

@@ -88,3 +120,6 @@ | TRPCSuccessResponse<TOutput>['result'];

TOutput,
> = Observable<OperationResultEnvelope<TOutput>, TRPCClientError<TInferrable>>;
> = Observable<
OperationResultEnvelope<TOutput, TRPCClientError<TInferrable>>,
TRPCClientError<TInferrable>
>;

@@ -91,0 +126,0 @@ /**

import type { Observer, UnsubscribeFn } from '@trpc/server/observable';
import { observable } from '@trpc/server/observable';
import type { TRPCConnectionParamsMessage } from '@trpc/server/rpc';
import type {

@@ -7,3 +8,2 @@ AnyRouter,

inferRouterError,
MaybePromise,
ProcedureType,

@@ -20,10 +20,18 @@ TRPCClientIncomingMessage,

import { getTransformer } from '../unstable-internals';
import type { Operation, TRPCLink } from './types';
import {
resultOf,
type UrlOptionsWithConnectionParams,
} from './internals/urlWithConnectionParams';
import {
isConnectionStateMessage,
type Operation,
type TRPCConnectionStateMessage,
type TRPCLink,
} from './types';
const run = <TResult>(fn: () => TResult): TResult => fn();
type WSCallbackResult<TRouter extends AnyRouter, TOutput> = TRPCResponseMessage<
TOutput,
inferRouterError<TRouter>
>;
type WSCallbackResult<TRouter extends AnyRouter, TOutput> =
| TRPCResponseMessage<TOutput, inferRouterError<TRouter>>
| { result: TRPCConnectionStateMessage<inferRouterError<TRouter>> };

@@ -38,8 +46,4 @@ type WSCallbackObserver<TRouter extends AnyRouter, TOutput> = Observer<

export interface WebSocketClientOptions {
export interface WebSocketClientOptions extends UrlOptionsWithConnectionParams {
/**
* The URL to connect to (can be a function that returns a URL)
*/
url: string | (() => MaybePromise<string>);
/**
* Ponyfill which WebSocket implementation to use

@@ -85,3 +89,2 @@ */

const {
url,
WebSocket: WebSocketImpl = WebSocket,

@@ -129,3 +132,3 @@ retryDelayMs: retryDelayFn = exponentialBackoff,

? null
: createConnection();
: createConnection(null);

@@ -154,3 +157,3 @@ type Connection = {

if (!activeConnection) {
activeConnection = createConnection();
activeConnection = createConnection(null);
return;

@@ -181,3 +184,3 @@ }

}
function tryReconnect(conn: Connection) {
function tryReconnect(conn: Connection, cause: Error | null) {
if (!!connectTimer) {

@@ -189,3 +192,3 @@ return;

const timeout = retryDelayFn(connectAttempt++);
reconnectInMs(timeout);
reconnectInMs(timeout, cause);
}

@@ -200,3 +203,3 @@ function hasPendingRequests(conn?: Connection) {

function reconnect() {
function reconnect(cause: Error | null) {
if (lazyOpts.enabled && !hasPendingRequests()) {

@@ -207,10 +210,10 @@ // Skip reconnecting if there are pending requests and we're in lazy mode

const oldConnection = activeConnection;
activeConnection = createConnection();
activeConnection = createConnection(cause);
oldConnection && closeIfNoPending(oldConnection);
}
function reconnectInMs(ms: number) {
function reconnectInMs(ms: number, cause: Error | null) {
if (connectTimer) {
return;
}
connectTimer = setTimeout(reconnect, ms);
connectTimer = setTimeout(reconnect, ms, cause);
}

@@ -249,3 +252,3 @@

function createConnection(): Connection {
function createConnection(cause: Error | null): Connection {
const self: Connection = {

@@ -256,13 +259,31 @@ id: ++connectionIndex,

for (const req of Object.values(pendingRequests)) {
if (req.type === 'subscription') {
req.callbacks.next?.({
result: {
type: 'state',
state: 'connecting',
data: cause ?? null,
},
});
}
}
clearTimeout(lazyDisconnectTimer);
const onError = () => {
const onError = (cause: Error | null) => {
self.state = 'closed';
if (self === activeConnection) {
tryReconnect(self);
tryReconnect(self, cause);
}
};
run(async () => {
const urlString = typeof url === 'function' ? await url() : url;
const ws = new WebSocketImpl(urlString);
let url = await resultOf(opts.url);
if (opts.connectionParams) {
// append `?connectionParams=1` when connection params are used
const prefix = url.includes('?') ? '&' : '?';
url += prefix + 'connectionParams=1';
}
const ws = new WebSocketImpl(url);
self.ws = ws;

@@ -274,13 +295,48 @@

ws.addEventListener('open', () => {
/* istanbul ignore next -- @preserve */
if (activeConnection?.ws !== ws) {
return;
}
connectAttempt = 0;
self.state = 'open';
run(async () => {
/* istanbul ignore next -- @preserve */
if (activeConnection?.ws !== ws) {
return;
}
if (opts.connectionParams) {
const connectMsg: TRPCConnectionParamsMessage = {
method: 'connectionParams',
data: await resultOf(opts.connectionParams),
};
onOpen?.();
dispatch();
ws.send(JSON.stringify(connectMsg));
}
connectAttempt = 0;
self.state = 'open';
for (const req of Object.values(pendingRequests)) {
if (req.type === 'subscription') {
req.callbacks.next?.({
result: {
type: 'state',
state: 'pending',
},
});
}
}
onOpen?.();
dispatch();
}).catch((cause) => {
ws.close(
// "Status codes in the range 3000-3999 are reserved for use by libraries, frameworks, and applications"
3000,
cause,
);
onError(cause);
});
});
ws.addEventListener('error', onError);
ws.addEventListener('error', (event) => {
if (event instanceof ErrorEvent) {
onError(event.error);
} else {
onError(new Error('Unknown WebSocket error'));
}
});
const handleIncomingRequest = (req: TRPCClientIncomingRequest) => {

@@ -292,3 +348,3 @@ if (self !== activeConnection) {

if (req.method === 'reconnect') {
reconnect();
reconnect(new Error('Server requested reconnect'));
// notify subscribers

@@ -341,3 +397,3 @@ for (const pendingReq of Object.values(pendingRequests)) {

ws.addEventListener('close', ({ code }) => {
ws.addEventListener('close', ({ code, reason }) => {
if (self.state === 'open') {

@@ -350,3 +406,3 @@ onClose?.({ code });

// connection might have been replaced already
tryReconnect(self);
tryReconnect(self, new Error(reason));
}

@@ -447,2 +503,6 @@

},
/**
* Reconnect to the WebSocket server
*/
reconnect,
};

@@ -479,6 +539,16 @@ }

const unsub = client.request(
{ type, path, input, id, context },
{ type, path, input, id, context, signal: null },
{
error(err) {
observer.error(err as TRPCClientError<any>);
observer.next({
result: {
type: 'state',
state: 'error',
data: err,
},
context: context,
});
unsub();

@@ -488,7 +558,43 @@ },

observer.complete();
observer.next({
result: {
type: 'state',
state: 'idle',
},
context: context,
});
},
next(message) {
if (
'result' in message &&
isConnectionStateMessage<TRPCClientError<TRouter>>(
message.result,
)
) {
message.result;
observer.next({
result: message.result,
context: context,
});
return;
}
if (!('id' in message)) return;
const transformed = transformResult(message, transformer.output);
if (!transformed.ok) {
const error = TRPCClientError.from(transformed.error);
observer.next({
result: {
type: 'state',
state: 'error',
data: error,
},
context: context,
});
observer.error(TRPCClientError.from(transformed.error));

@@ -499,2 +605,3 @@ return;

result: transformed.result,
context: context,
});

@@ -513,2 +620,9 @@

unsub();
observer.next({
result: {
type: 'state',
state: 'idle',
},
context: context,
});
};

@@ -515,0 +629,0 @@ });

@@ -8,3 +8,2 @@ import type {

import {
getCauseFromUnknown,
isObject,

@@ -44,2 +43,12 @@ type DefaultErrorShape,

function getMessageFromUnknownError(err: unknown, fallback: string): string {
if (typeof err === 'string') {
return err;
}
if (isObject(err) && typeof err['message'] === 'string') {
return err['message'];
}
return fallback;
}
export class TRPCClientError<TRouterOrProcedure extends InferrableClientTypes>

@@ -107,14 +116,10 @@ extends Error

}
if (!(cause instanceof Error)) {
return new TRPCClientError('Unknown error', {
return new TRPCClientError(
getMessageFromUnknownError(cause, 'Unknown error'),
{
...opts,
cause: cause as any,
});
}
return new TRPCClientError(cause.message, {
...opts,
cause: getCauseFromUnknown(cause),
});
},
);
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc