micro-ftch
Version:
Wrappers for built-in fetch() enabling killswitch, logging, concurrency limit and other features
205 lines (203 loc) • 7.21 kB
TypeScript
/**
* Wrappers for [built-in fetch()](https://developer.mozilla.org/en-US/docs/Web/API/fetch) enabling
* killswitch, logging, concurrency limit and other features. fetch is great, however, its usage in secure environments is complicated. The library makes it simple.
* @module
* @example
```js
import { ftch, jsonrpc, replayable } from 'micro-ftch';
let enabled = false;
const net = ftch(fetch, {
isValidRequest: () => enabled,
log: (url, options) => console.log(url, options),
timeout: 5000,
concurrencyLimit: 10,
});
const res = await net('https://example.com');
// Composable
const rpc = jsonrpc(net, 'http://rpc_node/', {
headers: {},
batchSize: 20,
});
const res1 = await rpc.call('method', 'arg0', 'arg1');
const res2 = await rpc.callNamed('method', { arg0: '0', arg1: '1' }); // named arguments
const testRpc = replayable(rpc);
// Basic auth auto-parsing
await net('https://user:pwd@httpbin.org/basic-auth/user/pwd');
```
*/
declare function limit(concurrencyLimit: number): <T>(fn: () => Promise<T>) => Promise<T>;
/** Arguments for built-in fetch, with added timeout method. */
export type FetchOpts = RequestInit & {
timeout?: number;
};
/** Built-in fetch, or function conforming to its interface. */
export type FetchFn = (url: string, opts?: FetchOpts) => Promise<{
headers: Headers;
ok: boolean;
redirected: boolean;
status: number;
statusText: string;
type: ResponseType;
url: string;
json: () => Promise<any>;
text: () => Promise<string>;
arrayBuffer: () => Promise<ArrayBuffer>;
}>;
/** Options for `ftch`. isValidRequest can disable fetching, while log will receive all requests. */
export type FtchOpts = {
isValidRequest?: (url?: string) => boolean;
killswitch?: (url?: string) => boolean;
concurrencyLimit?: number;
timeout?: number;
log?: (url: string, opts: FetchOpts) => void;
};
/**
* Small wrapper over fetch function
*
* @param fn - The fetch function to be wrapped.
* @param opts - Options to control the behavior of the fetch wrapper.
* @param [opts.isValidRequest] - Function to determine if the fetch request should be cancelled.
* @param [opts.concurrencyLimit] - Limit on the number of concurrent fetch requests.
* @param [opts.timeout] - Default timeout for all requests, can be overriden in request opts
* @param [opts.log] - Callback to log all requests
* @returns Wrapped fetch function
* @example
* ```js
* let ENABLED = true;
* const f = ftch(fetch, { isValidRequest: () => ENABLED });
* f('http://localhost'); // ok
* ENABLED = false;
* f('http://localhost'); // throws
* ```
* @example
* ```js
* const f = ftch(fetch, { concurrencyLimit: 1 });
* const res = await Promise.all([f('http://url1/'), f('http://url2/')]); // these would be processed sequentially
* ```
* @example
* ```js
* const f = ftch(fetch);
* const res = await f('http://url/', { timeout: 1000 }); // throws if request takes more than one second
* ```
* @example
* ```js
* const f = ftch(fetch, { timeout: 1000 }); // default timeout for all requests
* const res = await f('http://url/'); // throws if request takes more than one second
* ```
* @example
* ```js
* const f = ftch(fetch);
* const res = await f('https://user:pwd@httpbin.org/basic-auth/user/pwd'); // basic auth
* ```
* @example
* ```js
* const f = ftch(fetch, { log: (url, opts)=>console.log('NET', url, opts) })
* f('http://url/'); // will print request information
* ```
*/
export declare function ftch(fetchFunction: FetchFn, opts?: FtchOpts): FetchFn;
export type JsonrpcInterface = {
call: (method: string, ...args: any[]) => Promise<any>;
callNamed: (method: string, args: Record<string, any>) => Promise<any>;
};
type NetworkOpts = {
batchSize?: number;
headers?: Record<string, string>;
};
/**
* Small utility class for Jsonrpc
* @param fetchFunction - The fetch function
* @param url - The RPC server url
* @param opts - Options to control the behavior of RPC client
* @param [opts.headers] - additional headers to send with requests
* @param [opts.batchSize] - batch parallel requests up to this value into single request
* @example
* ```js
* const rpc = new JsonrpcProvider(fetch, 'http://rpc_node/', { headers: {}, batchSize: 20 });
* const res = await rpc.call('method', 'arg0', 'arg1');
* const res2 = await rpc.callNamed('method', {arg0: '0', arg1: '1'}); // named arguments
* ```
*/
export declare class JsonrpcProvider implements JsonrpcInterface {
private batchSize;
private headers;
private queue;
private fetchFunction;
readonly rpcUrl: string;
constructor(fetchFunction: FetchFn, rpcUrl: string, options?: NetworkOpts);
private fetchJson;
private jsonError;
private batchProcess;
private rpcBatch;
private rpc;
call(method: string, ...args: any[]): Promise<any>;
callNamed(method: string, params: Record<string, any>): Promise<any>;
}
/**
* Batched JSON-RPC functionality.
* @example
```js
const rpc = jsonrpc(fetch, 'http://rpc_node/', {
headers: {},
batchSize: 20,
});
const res = await rpc.call('method', 'arg0', 'arg1');
const res2 = await rpc.callNamed('method', { arg0: '0', arg1: '1' }); // named arguments
```
*/
export declare function jsonrpc(fetchFunction: FetchFn, rpcUrl: string, options?: NetworkOpts): JsonrpcProvider;
type GetKeyFn = (url: string, opt: FetchOpts) => string;
/** Options for replayable() */
export type ReplayOpts = {
offline?: boolean;
getKey?: GetKeyFn;
};
/** replayable() return function, additional methods */
export type ReplayFn = FetchFn & {
logs: Record<string, any>;
accessed: Set<string>;
export: () => string;
};
/**
* Log & replay network requests without actually calling network code.
* @param fetchFunction
* @param logs - captured logs (JSON.parse(fetchReplay(...).export()))
* @param opts
* @param [opts.offline] - Offline mode, throws on non-captured requests
* @param [opts.getKey] - Optional function to modify key information for capture/replay of requests
* @example
* ```js
* // Capture logs
* const ftch = ftch(fetch);
* const replayCapture = replayable(ftch); // wraps fetch
* await replayCapture('http://url/1');
* const logs = replayCapture.export(); // Exports logs
* ```
* @example
* ```js
* // Replay logs
* const replayTest = replayable(ftch, JSON.parse(logs));
* await replayTest('http://url/1'); // cached
* await replayTest('http://url/2'); // real network
* ```
* @example
* ```js
* // Offline mode
* const replayTestOffline = replayable(ftch, JSON.parse(logs), { offline: true });
* await replayTest('http://url/1'); // cached
* await replayTest('http://url/2'); // throws!
* ```
* @example
* ```js
* // Custom log key function
* const getKey = (url, opt) => JSON.stringify({ url: 'https://NODE_URL/', opt }); // use same url for any request
* const replayCapture = replayable(ftch, {}, { getKey });
* ```
*/
export declare function replayable(fetchFunction: FetchFn, logs?: Record<string, string>, opts?: ReplayOpts): ReplayFn;
/** Internal methods for test purposes only. */
export declare const _TEST: {
limit: typeof limit;
};
export {};
//# sourceMappingURL=index.d.ts.map