snapreq 0.0.1 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -3
- package/package.json +58 -8
- package/src/errors.js +17 -0
- package/src/response.js +50 -9
- package/src/retry.js +3 -1
- package/src/snap-req.js +153 -11
- package/src/websocket/websocket-client.js +10 -5
- package/types/capabilities.d.ts +47 -0
- package/types/errors.d.ts +81 -0
- package/types/headers.d.ts +50 -0
- package/types/request.d.ts +35 -0
- package/types/response.d.ts +93 -0
- package/types/retry.d.ts +73 -0
- package/types/snap-req.d.ts +303 -0
- package/types/transports/fetch-transport.d.ts +35 -0
- package/types/transports/node-transport.d.ts +112 -0
- package/types/transports/select.d.ts +38 -0
- package/types/transports/xhr-transport.d.ts +25 -0
- package/types/websocket/websocket-channel.d.ts +92 -0
- package/types/websocket/websocket-client.d.ts +364 -0
- package/types/websocket/websocket-connection.d.ts +94 -0
- package/src/index.js +0 -22
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Base class for every error thrown by snapreq. */
|
|
2
|
+
export class SnapReqError extends Error {
|
|
3
|
+
/** @param {string} message - Human readable description. */
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Thrown when a request completes with a non-2xx status and the caller asked
|
|
8
|
+
* snapreq to treat error statuses as failures (`throwOnError`, the default for
|
|
9
|
+
* the high-level helpers). Carries enough metadata to build a friendly message
|
|
10
|
+
* without re-reading the response.
|
|
11
|
+
*/
|
|
12
|
+
export class SnapReqHttpError extends SnapReqError {
|
|
13
|
+
/**
|
|
14
|
+
* @param {object} options - Error metadata.
|
|
15
|
+
* @param {string} options.message - Human readable description.
|
|
16
|
+
* @param {string} options.method - HTTP method used for the request.
|
|
17
|
+
* @param {string} options.url - Fully resolved request URL.
|
|
18
|
+
* @param {number} options.status - HTTP status code returned by the server.
|
|
19
|
+
* @param {string} [options.statusText] - HTTP status text returned by the server.
|
|
20
|
+
* @param {string} [options.responseText] - Decoded response body, when available.
|
|
21
|
+
* @param {import("./response.js").default} [options.response] - The response that failed.
|
|
22
|
+
*/
|
|
23
|
+
constructor({ message, method, url, status, statusText, responseText, response }: {
|
|
24
|
+
message: string;
|
|
25
|
+
method: string;
|
|
26
|
+
url: string;
|
|
27
|
+
status: number;
|
|
28
|
+
statusText?: string;
|
|
29
|
+
responseText?: string;
|
|
30
|
+
response?: import("./response.js").default;
|
|
31
|
+
});
|
|
32
|
+
method: string;
|
|
33
|
+
url: string;
|
|
34
|
+
status: number;
|
|
35
|
+
statusText: string;
|
|
36
|
+
responseText: string;
|
|
37
|
+
response: import("./response.js").default;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when a request asks for a capability the active transport cannot
|
|
41
|
+
* provide on the current platform (for example a Unix socket or request-body
|
|
42
|
+
* compression in a browser). The API stays identical across platforms; this
|
|
43
|
+
* error is how snapreq tells you a specific feature had to be left out.
|
|
44
|
+
*/
|
|
45
|
+
export class SnapReqUnsupportedFeatureError extends SnapReqError {
|
|
46
|
+
/**
|
|
47
|
+
* @param {object} options - Error metadata.
|
|
48
|
+
* @param {string} options.feature - The capability that is not supported.
|
|
49
|
+
* @param {string} options.transport - Name of the active transport.
|
|
50
|
+
* @param {string} [options.detail] - Optional extra context.
|
|
51
|
+
*/
|
|
52
|
+
constructor({ feature, transport, detail }: {
|
|
53
|
+
feature: string;
|
|
54
|
+
transport: string;
|
|
55
|
+
detail?: string;
|
|
56
|
+
});
|
|
57
|
+
feature: string;
|
|
58
|
+
transport: string;
|
|
59
|
+
}
|
|
60
|
+
/** Thrown when a request is aborted via an `AbortSignal`. */
|
|
61
|
+
export class SnapReqAbortError extends SnapReqError {
|
|
62
|
+
/** @param {string} [message] - Human readable description. */
|
|
63
|
+
constructor(message?: string);
|
|
64
|
+
}
|
|
65
|
+
/** Thrown when a request exceeds its configured timeout. */
|
|
66
|
+
export class SnapReqTimeoutError extends SnapReqError {
|
|
67
|
+
/**
|
|
68
|
+
* @param {object} options - Error metadata.
|
|
69
|
+
* @param {string} options.method - HTTP method used for the request.
|
|
70
|
+
* @param {string} options.url - Fully resolved request URL.
|
|
71
|
+
* @param {number} options.timeoutMs - Timeout in milliseconds.
|
|
72
|
+
*/
|
|
73
|
+
constructor({ method, url, timeoutMs }: {
|
|
74
|
+
method: string;
|
|
75
|
+
url: string;
|
|
76
|
+
timeoutMs: number;
|
|
77
|
+
});
|
|
78
|
+
method: string;
|
|
79
|
+
url: string;
|
|
80
|
+
timeoutMs: number;
|
|
81
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A tiny case-insensitive header bag. Works the same on every platform and
|
|
3
|
+
* avoids depending on the DOM `Headers` global (absent in some runtimes) or on
|
|
4
|
+
* Node's header handling. Header values are always stored as strings.
|
|
5
|
+
*/
|
|
6
|
+
export default class SnapReqHeaders {
|
|
7
|
+
/**
|
|
8
|
+
* @param {Record<string, string | number | string[]> | SnapReqHeaders | Iterable<[string, string]>} [init] - Initial headers.
|
|
9
|
+
*/
|
|
10
|
+
constructor(init?: Record<string, string | number | string[]> | SnapReqHeaders | Iterable<[string, string]>);
|
|
11
|
+
/** @type {Map<string, {name: string, value: string}>} - Keyed by lower-cased name. */
|
|
12
|
+
_map: Map<string, {
|
|
13
|
+
name: string;
|
|
14
|
+
value: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} name - Header name (case-insensitive).
|
|
18
|
+
* @param {string | number} value - Header value.
|
|
19
|
+
* @returns {void}
|
|
20
|
+
*/
|
|
21
|
+
set(name: string, value: string | number): void;
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} name - Header name (case-insensitive).
|
|
24
|
+
* @returns {string | null} - The header value or null when absent.
|
|
25
|
+
*/
|
|
26
|
+
get(name: string): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} name - Header name (case-insensitive).
|
|
29
|
+
* @returns {boolean} - Whether the header is present.
|
|
30
|
+
*/
|
|
31
|
+
has(name: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} name - Header name (case-insensitive).
|
|
34
|
+
* @returns {void}
|
|
35
|
+
*/
|
|
36
|
+
delete(name: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* @yields {[string, string]} - Name/value pair preserving original casing.
|
|
39
|
+
* @returns {IterableIterator<[string, string]>} - Name/value pairs preserving original casing.
|
|
40
|
+
*/
|
|
41
|
+
entries(): IterableIterator<[string, string]>;
|
|
42
|
+
/** @returns {[string, string][]} - Name/value pairs preserving original casing. */
|
|
43
|
+
toArray(): [string, string][];
|
|
44
|
+
/**
|
|
45
|
+
* Plain object form keyed by the original header casing. Suitable for
|
|
46
|
+
* passing straight to `http.request` or `fetch`.
|
|
47
|
+
* @returns {Record<string, string>} - Header object.
|
|
48
|
+
*/
|
|
49
|
+
toObject(): Record<string, string>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Joins a base URL and a path and appends query parameters. `path` may be a
|
|
3
|
+
* fully-qualified URL, in which case the base is ignored.
|
|
4
|
+
* @param {string | undefined} baseUrl - Origin (and optional base path).
|
|
5
|
+
* @param {string} path - Path or absolute URL.
|
|
6
|
+
* @param {Record<string, string | number | boolean | null | undefined> | undefined} query - Query parameters.
|
|
7
|
+
* @returns {string} - Resolved absolute URL.
|
|
8
|
+
*/
|
|
9
|
+
export function buildUrl(baseUrl: string | undefined, path: string, query: Record<string, string | number | boolean | null | undefined> | undefined): string;
|
|
10
|
+
/**
|
|
11
|
+
* Determines whether a value should be sent as a streamed request body.
|
|
12
|
+
* @param {unknown} body - Candidate body value.
|
|
13
|
+
* @returns {boolean} - Whether the body is a stream.
|
|
14
|
+
*/
|
|
15
|
+
export function isStreamBody(body: unknown): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Normalizes a user-supplied body into one of a small set of shapes and applies
|
|
18
|
+
* a default `Content-Type` header when the caller did not set one.
|
|
19
|
+
* @param {unknown} body - Raw body value.
|
|
20
|
+
* @param {SnapReqHeaders} headers - Headers to receive a default `Content-Type`.
|
|
21
|
+
* @returns {NormalizedBody} - Normalized body descriptor.
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeBody(body: unknown, headers: SnapReqHeaders): NormalizedBody;
|
|
24
|
+
export type CompressionEncoding = "identity" | "gzip" | "deflate" | "br" | "zstd";
|
|
25
|
+
export type NormalizedBody = {
|
|
26
|
+
/**
|
|
27
|
+
* - Shape of the body payload.
|
|
28
|
+
*/
|
|
29
|
+
kind: "none" | "text" | "bytes" | "stream";
|
|
30
|
+
/**
|
|
31
|
+
* - The payload itself.
|
|
32
|
+
*/
|
|
33
|
+
value: string | Uint8Array | AsyncIterable<Uint8Array> | null;
|
|
34
|
+
};
|
|
35
|
+
import SnapReqHeaders from "./headers.js";
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A platform-agnostic response. Transports build it with either a fully-read
|
|
3
|
+
* body (`bytes`) or a `stream` (an async iterable of `Uint8Array`) that the
|
|
4
|
+
* read helpers buffer on first use. The body can be read exactly once as a
|
|
5
|
+
* stream; the buffering helpers may be called repeatedly because they cache.
|
|
6
|
+
*/
|
|
7
|
+
export default class SnapReqResponse {
|
|
8
|
+
/**
|
|
9
|
+
* @param {object} options - Response data.
|
|
10
|
+
* @param {string} options.url - Fully resolved request URL.
|
|
11
|
+
* @param {string} options.method - HTTP method used for the request.
|
|
12
|
+
* @param {number} options.status - HTTP status code.
|
|
13
|
+
* @param {string} [options.statusText] - HTTP status text.
|
|
14
|
+
* @param {SnapReqHeaders} [options.headers] - Response headers.
|
|
15
|
+
* @param {Uint8Array} [options.bytes] - Fully-read body, when the transport already buffered it.
|
|
16
|
+
* @param {AsyncIterable<Uint8Array>} [options.stream] - Streamed body, when the transport supports streaming.
|
|
17
|
+
* @param {import("node:stream").Readable} [options.nodeStream] - Raw Node stream, when available, for advanced consumers.
|
|
18
|
+
* @param {() => void} [options.onBodyDone] - Callback fired when body reading finishes or fails.
|
|
19
|
+
* @param {(error: unknown) => unknown} [options.mapBodyError] - Maps body read errors before rethrowing.
|
|
20
|
+
*/
|
|
21
|
+
constructor({ url, method, status, statusText, headers, bytes, stream, nodeStream, onBodyDone, mapBodyError }: {
|
|
22
|
+
url: string;
|
|
23
|
+
method: string;
|
|
24
|
+
status: number;
|
|
25
|
+
statusText?: string;
|
|
26
|
+
headers?: SnapReqHeaders;
|
|
27
|
+
bytes?: Uint8Array;
|
|
28
|
+
stream?: AsyncIterable<Uint8Array>;
|
|
29
|
+
nodeStream?: import("node:stream").Readable;
|
|
30
|
+
onBodyDone?: () => void;
|
|
31
|
+
mapBodyError?: (error: unknown) => unknown;
|
|
32
|
+
});
|
|
33
|
+
url: string;
|
|
34
|
+
method: string;
|
|
35
|
+
status: number;
|
|
36
|
+
statusText: string;
|
|
37
|
+
headers: SnapReqHeaders;
|
|
38
|
+
/** @type {Uint8Array | null} */
|
|
39
|
+
_bytes: Uint8Array | null;
|
|
40
|
+
/** @type {AsyncIterable<Uint8Array> | null} */
|
|
41
|
+
_stream: AsyncIterable<Uint8Array> | null;
|
|
42
|
+
/** @type {import("node:stream").Readable | undefined} */
|
|
43
|
+
nodeStream: import("node:stream").Readable | undefined;
|
|
44
|
+
_streamConsumed: boolean;
|
|
45
|
+
_bodyDone: boolean;
|
|
46
|
+
_onBodyDone: () => void;
|
|
47
|
+
_mapBodyError: (error: unknown) => unknown;
|
|
48
|
+
/** @returns {boolean} - Whether the status is in the 2xx range. */
|
|
49
|
+
get ok(): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Returns the response body as an async iterable of byte chunks. Can only be
|
|
52
|
+
* called once and only when the transport provided a stream.
|
|
53
|
+
* @returns {AsyncIterable<Uint8Array>} - The streamed body.
|
|
54
|
+
*/
|
|
55
|
+
stream(): AsyncIterable<Uint8Array>;
|
|
56
|
+
/** @returns {boolean} - Whether the body is available as a stream that has not been read yet. */
|
|
57
|
+
get streamable(): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Reads the whole body into a `Uint8Array`, buffering the stream if needed.
|
|
60
|
+
* @returns {Promise<Uint8Array>} - The full response body.
|
|
61
|
+
*/
|
|
62
|
+
bytes(): Promise<Uint8Array>;
|
|
63
|
+
/**
|
|
64
|
+
* Reads the whole body as a Node `Buffer`. Node-only convenience; throws when
|
|
65
|
+
* the `Buffer` global is unavailable.
|
|
66
|
+
* @returns {Promise<Buffer>} - The full response body as a Buffer.
|
|
67
|
+
*/
|
|
68
|
+
buffer(): Promise<Buffer>;
|
|
69
|
+
/**
|
|
70
|
+
* Reads the whole body and decodes it as a UTF-8 string.
|
|
71
|
+
* @returns {Promise<string>} - The decoded response body.
|
|
72
|
+
*/
|
|
73
|
+
text(): Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* Reads the whole body and parses it as JSON. Returns `null` for an empty
|
|
76
|
+
* body.
|
|
77
|
+
* @returns {Promise<any>} - The parsed JSON body.
|
|
78
|
+
*/
|
|
79
|
+
json(): Promise<any>;
|
|
80
|
+
/**
|
|
81
|
+
* @param {AsyncIterable<Uint8Array>} source - Source response stream.
|
|
82
|
+
* @returns {AsyncIterable<Uint8Array>} - Stream with cleanup/error mapping.
|
|
83
|
+
*/
|
|
84
|
+
_wrappedStream(source: AsyncIterable<Uint8Array>): AsyncIterable<Uint8Array>;
|
|
85
|
+
/**
|
|
86
|
+
* @param {unknown} error - Body read error.
|
|
87
|
+
* @returns {unknown} - Error to rethrow.
|
|
88
|
+
*/
|
|
89
|
+
_mappedBodyError(error: unknown): unknown;
|
|
90
|
+
/** @returns {void} */
|
|
91
|
+
_finishBody(): void;
|
|
92
|
+
}
|
|
93
|
+
import SnapReqHeaders from "./headers.js";
|
package/types/retry.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} RetryOptions
|
|
3
|
+
* @property {number} [tries] - Maximum number of attempts. Defaults to 3.
|
|
4
|
+
* @property {number} [waitMs] - Delay between attempts in milliseconds. Defaults to 500.
|
|
5
|
+
* @property {number[]} [retryableStatuses] - HTTP status codes that should be retried. Defaults to 502/503/504.
|
|
6
|
+
* @property {(error: unknown, attempt: number) => boolean} [shouldRetry] - Override the retryable-error classifier.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {object} NormalizedRetryOptions
|
|
10
|
+
* @property {number} tries - Maximum number of attempts.
|
|
11
|
+
* @property {number} waitMs - Delay between attempts in milliseconds.
|
|
12
|
+
* @property {number[]} retryableStatuses - HTTP status codes that should be retried.
|
|
13
|
+
* @property {(error: unknown, attempt: number) => boolean} shouldRetry - Retryable-error classifier.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* The default network-error classifier. Exposed so callers can compose extra
|
|
17
|
+
* rules on top of it (for example matching server-specific 500 messages).
|
|
18
|
+
* @param {unknown} error - Error thrown by a transport.
|
|
19
|
+
* @returns {boolean} - Whether the error is a transient network failure.
|
|
20
|
+
*/
|
|
21
|
+
export function defaultRetryableError(error: unknown): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Normalizes the `retry` option into a complete set of retry settings, or
|
|
24
|
+
* `null` when retries are disabled.
|
|
25
|
+
* @param {boolean | RetryOptions | undefined} retry - Retry configuration.
|
|
26
|
+
* @returns {NormalizedRetryOptions | null} - Normalized retry settings.
|
|
27
|
+
*/
|
|
28
|
+
export function normalizeRetryOptions(retry: boolean | RetryOptions | undefined): NormalizedRetryOptions | null;
|
|
29
|
+
/**
|
|
30
|
+
* Runs a request attempt, retrying transient network errors and retryable HTTP
|
|
31
|
+
* statuses. Retries are only used for buffered requests — the caller must not
|
|
32
|
+
* apply this to streamed responses.
|
|
33
|
+
* @param {() => Promise<import("./response.js").default>} attempt - Performs one request attempt.
|
|
34
|
+
* @param {NormalizedRetryOptions} retry - Normalized retry settings.
|
|
35
|
+
* @returns {Promise<import("./response.js").default>} - The successful (or final) response.
|
|
36
|
+
*/
|
|
37
|
+
export function runWithRetry(attempt: () => Promise<import("./response.js").default>, retry: NormalizedRetryOptions): Promise<import("./response.js").default>;
|
|
38
|
+
export type RetryOptions = {
|
|
39
|
+
/**
|
|
40
|
+
* - Maximum number of attempts. Defaults to 3.
|
|
41
|
+
*/
|
|
42
|
+
tries?: number;
|
|
43
|
+
/**
|
|
44
|
+
* - Delay between attempts in milliseconds. Defaults to 500.
|
|
45
|
+
*/
|
|
46
|
+
waitMs?: number;
|
|
47
|
+
/**
|
|
48
|
+
* - HTTP status codes that should be retried. Defaults to 502/503/504.
|
|
49
|
+
*/
|
|
50
|
+
retryableStatuses?: number[];
|
|
51
|
+
/**
|
|
52
|
+
* - Override the retryable-error classifier.
|
|
53
|
+
*/
|
|
54
|
+
shouldRetry?: (error: unknown, attempt: number) => boolean;
|
|
55
|
+
};
|
|
56
|
+
export type NormalizedRetryOptions = {
|
|
57
|
+
/**
|
|
58
|
+
* - Maximum number of attempts.
|
|
59
|
+
*/
|
|
60
|
+
tries: number;
|
|
61
|
+
/**
|
|
62
|
+
* - Delay between attempts in milliseconds.
|
|
63
|
+
*/
|
|
64
|
+
waitMs: number;
|
|
65
|
+
/**
|
|
66
|
+
* - HTTP status codes that should be retried.
|
|
67
|
+
*/
|
|
68
|
+
retryableStatuses: number[];
|
|
69
|
+
/**
|
|
70
|
+
* - Retryable-error classifier.
|
|
71
|
+
*/
|
|
72
|
+
shouldRetry: (error: unknown, attempt: number) => boolean;
|
|
73
|
+
};
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("./request.js").CompressionEncoding} CompressionEncoding
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} NormalizedRequest
|
|
6
|
+
* @property {string} method - Upper-cased HTTP method.
|
|
7
|
+
* @property {string} url - Fully resolved request URL.
|
|
8
|
+
* @property {SnapReqHeaders} headers - Request headers.
|
|
9
|
+
* @property {import("./request.js").NormalizedBody} body - Normalized request body.
|
|
10
|
+
* @property {CompressionEncoding} bodyCompression - Request body compression.
|
|
11
|
+
* @property {AbortSignal} [signal] - Abort signal.
|
|
12
|
+
* @property {number} [timeoutMs] - Request timeout in milliseconds.
|
|
13
|
+
* @property {string} [credentials] - Fetch credentials mode ("omit" | "same-origin" | "include").
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} RequestOptions
|
|
17
|
+
* @property {string} [method] - HTTP method. Defaults to GET.
|
|
18
|
+
* @property {string} [path] - Request path (joined with the client `baseUrl`) or absolute URL.
|
|
19
|
+
* @property {string} [url] - Alias for `path`.
|
|
20
|
+
* @property {Record<string, string | number | boolean | null | undefined>} [query] - Query parameters.
|
|
21
|
+
* @property {Record<string, string | number> | SnapReqHeaders} [headers] - Per-request headers.
|
|
22
|
+
* @property {any} [body] - Request body: string, object (JSON), Uint8Array/ArrayBuffer, or a stream/async-iterable.
|
|
23
|
+
* @property {CompressionEncoding} [bodyCompression] - Compress the request body (Node transport only).
|
|
24
|
+
* @property {AbortSignal} [signal] - Abort signal for the request.
|
|
25
|
+
* @property {number} [timeoutMs] - Request timeout in milliseconds. Set to `0` to disable a client default.
|
|
26
|
+
* @property {string} [credentials] - Fetch credentials mode.
|
|
27
|
+
* @property {boolean | import("./retry.js").RetryOptions} [retry] - Retry transient failures.
|
|
28
|
+
* @property {boolean} [throwOnError] - Throw `SnapReqHttpError` on non-2xx responses.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {object} RequestTimeout
|
|
32
|
+
* @property {AbortSignal | undefined} signal - Signal to use for the request.
|
|
33
|
+
* @property {() => void} clear - Clears timeout resources.
|
|
34
|
+
* @property {(response: import("./response.js").default, request: NormalizedRequest) => import("./response.js").default} response - Attaches timeout handling to a response.
|
|
35
|
+
* @property {(error: unknown, request: NormalizedRequest) => unknown} error - Maps a thrown error.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* A cross-platform HTTP client with one API across Node, web, Expo and React
|
|
39
|
+
* Native. The right transport is chosen at runtime; features a platform cannot
|
|
40
|
+
* provide raise `SnapReqUnsupportedFeatureError` rather than silently changing
|
|
41
|
+
* behaviour.
|
|
42
|
+
*/
|
|
43
|
+
export default class SnapReq {
|
|
44
|
+
/**
|
|
45
|
+
* @param {object} [config] - Client configuration.
|
|
46
|
+
* @param {string} [config.baseUrl] - Origin (and optional base path) prepended to relative paths.
|
|
47
|
+
* @param {string} [config.socketPath] - Unix domain socket path (Node transport only).
|
|
48
|
+
* @param {{ca?: string | Buffer, cert?: string | Buffer, key?: string | Buffer, rejectUnauthorized?: boolean}} [config.tls] - TLS material (Node transport only).
|
|
49
|
+
* @param {boolean} [config.keepAlive] - Reuse connections across requests (Node transport only). Defaults to true.
|
|
50
|
+
* @param {Record<string, string | number> | (() => Record<string, string | number>)} [config.headers] - Default headers (object or factory).
|
|
51
|
+
* @param {boolean | import("./retry.js").RetryOptions} [config.retry] - Default retry policy.
|
|
52
|
+
* @param {boolean} [config.throwOnError] - Throw `SnapReqHttpError` on non-2xx responses by default. Defaults to false.
|
|
53
|
+
* @param {number} [config.timeoutMs] - Default request timeout in milliseconds. Set per-request `timeoutMs: 0` to disable.
|
|
54
|
+
* @param {string} [config.credentials] - Default fetch credentials mode.
|
|
55
|
+
* @param {import("./transports/select.js").TransportName | import("./transports/select.js").Transport} [config.transport] - Transport preference or instance. Defaults to "auto".
|
|
56
|
+
*/
|
|
57
|
+
constructor({ baseUrl, socketPath, tls, keepAlive, headers, retry, throwOnError, timeoutMs, credentials, transport }?: {
|
|
58
|
+
baseUrl?: string;
|
|
59
|
+
socketPath?: string;
|
|
60
|
+
tls?: {
|
|
61
|
+
ca?: string | Buffer;
|
|
62
|
+
cert?: string | Buffer;
|
|
63
|
+
key?: string | Buffer;
|
|
64
|
+
rejectUnauthorized?: boolean;
|
|
65
|
+
};
|
|
66
|
+
keepAlive?: boolean;
|
|
67
|
+
headers?: Record<string, string | number> | (() => Record<string, string | number>);
|
|
68
|
+
retry?: boolean | import("./retry.js").RetryOptions;
|
|
69
|
+
throwOnError?: boolean;
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
credentials?: string;
|
|
72
|
+
transport?: import("./transports/select.js").TransportName | import("./transports/select.js").Transport;
|
|
73
|
+
});
|
|
74
|
+
baseUrl: string;
|
|
75
|
+
defaultHeaders: Record<string, string | number> | (() => Record<string, string | number>);
|
|
76
|
+
defaultRetry: boolean | import("./retry.js").RetryOptions;
|
|
77
|
+
throwOnError: boolean;
|
|
78
|
+
timeoutMs: number;
|
|
79
|
+
credentials: string;
|
|
80
|
+
_transportPreference: import("./transports/select.js").TransportName | import("./transports/select.js").Transport;
|
|
81
|
+
_nodeConfig: {
|
|
82
|
+
socketPath: string;
|
|
83
|
+
tls: {
|
|
84
|
+
ca?: string | Buffer;
|
|
85
|
+
cert?: string | Buffer;
|
|
86
|
+
key?: string | Buffer;
|
|
87
|
+
rejectUnauthorized?: boolean;
|
|
88
|
+
};
|
|
89
|
+
keepAlive: boolean;
|
|
90
|
+
};
|
|
91
|
+
/** @type {Promise<import("./transports/select.js").Transport> | null} */
|
|
92
|
+
_transportPromise: Promise<import("./transports/select.js").Transport> | null;
|
|
93
|
+
/** @type {import("./transports/select.js").Transport | null} */
|
|
94
|
+
_transport: import("./transports/select.js").Transport | null;
|
|
95
|
+
/** @returns {Promise<import("./transports/select.js").Transport>} - The resolved transport. */
|
|
96
|
+
_resolveTransport(): Promise<import("./transports/select.js").Transport>;
|
|
97
|
+
/** @returns {Promise<import("./capabilities.js").TransportCapabilities>} - The active transport's capabilities. */
|
|
98
|
+
capabilities(): Promise<import("./capabilities.js").TransportCapabilities>;
|
|
99
|
+
/** @returns {Promise<string>} - The active transport's name. */
|
|
100
|
+
transportName(): Promise<string>;
|
|
101
|
+
/**
|
|
102
|
+
* @param {RequestOptions} options - Request options.
|
|
103
|
+
* @returns {NormalizedRequest} - The normalized request.
|
|
104
|
+
*/
|
|
105
|
+
_normalize(options: RequestOptions): NormalizedRequest;
|
|
106
|
+
/**
|
|
107
|
+
* @param {RequestOptions} options - Request options.
|
|
108
|
+
* @returns {RequestTimeout} - Timeout handling for one request attempt.
|
|
109
|
+
*/
|
|
110
|
+
_requestTimeout(options: RequestOptions): RequestTimeout;
|
|
111
|
+
/**
|
|
112
|
+
* @param {AbortSignal | undefined} callerSignal - Caller-supplied signal.
|
|
113
|
+
* @param {AbortSignal} timeoutSignal - Timeout signal.
|
|
114
|
+
* @returns {{signal: AbortSignal, clear: () => void}} - Signal that aborts when either source aborts.
|
|
115
|
+
*/
|
|
116
|
+
_composeSignal(callerSignal: AbortSignal | undefined, timeoutSignal: AbortSignal): {
|
|
117
|
+
signal: AbortSignal;
|
|
118
|
+
clear: () => void;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* @param {(() => void) | undefined} existing - Existing body-done callback.
|
|
122
|
+
* @param {() => void} next - Callback to add.
|
|
123
|
+
* @returns {() => void} - Combined callback.
|
|
124
|
+
*/
|
|
125
|
+
_chainBodyDone(existing: (() => void) | undefined, next: () => void): () => void;
|
|
126
|
+
/**
|
|
127
|
+
* @param {((error: unknown) => unknown) | undefined} existing - Existing error mapper.
|
|
128
|
+
* @param {(error: unknown) => unknown} next - Mapper to add.
|
|
129
|
+
* @returns {(error: unknown) => unknown} - Combined mapper.
|
|
130
|
+
*/
|
|
131
|
+
_chainBodyError(existing: ((error: unknown) => unknown) | undefined, next: (error: unknown) => unknown): (error: unknown) => unknown;
|
|
132
|
+
/**
|
|
133
|
+
* Performs a request and buffers nothing eagerly — read the body via the
|
|
134
|
+
* returned response (`json()`, `text()`, `bytes()`). Retries transient
|
|
135
|
+
* failures when a retry policy is configured (never for streamed bodies).
|
|
136
|
+
* @param {RequestOptions} options - Request options.
|
|
137
|
+
* @returns {Promise<import("./response.js").default>} - The response.
|
|
138
|
+
*/
|
|
139
|
+
request(options: RequestOptions): Promise<import("./response.js").default>;
|
|
140
|
+
/**
|
|
141
|
+
* Performs a request and returns the response with its body available as a
|
|
142
|
+
* stream (`response.stream()`). Requires a transport that supports response
|
|
143
|
+
* streaming; never retries.
|
|
144
|
+
* @param {RequestOptions} options - Request options.
|
|
145
|
+
* @returns {Promise<import("./response.js").default>} - The streaming response.
|
|
146
|
+
*/
|
|
147
|
+
requestStream(options: RequestOptions): Promise<import("./response.js").default>;
|
|
148
|
+
/**
|
|
149
|
+
* @param {RequestOptions} options - Request options.
|
|
150
|
+
* @param {(request: NormalizedRequest) => Promise<import("./response.js").default>} performRequest - Transport request runner.
|
|
151
|
+
* @returns {Promise<import("./response.js").default>} - Response with timeout handling attached.
|
|
152
|
+
*/
|
|
153
|
+
_requestWithTimeout(options: RequestOptions, performRequest: (request: NormalizedRequest) => Promise<import("./response.js").default>): Promise<import("./response.js").default>;
|
|
154
|
+
/**
|
|
155
|
+
* @param {string} path - Request path or absolute URL.
|
|
156
|
+
* @param {RequestOptions} [options] - Request options.
|
|
157
|
+
* @returns {Promise<import("./response.js").default>} - The response.
|
|
158
|
+
*/
|
|
159
|
+
get(path: string, options?: RequestOptions): Promise<import("./response.js").default>;
|
|
160
|
+
/**
|
|
161
|
+
* @param {string} path - Request path or absolute URL.
|
|
162
|
+
* @param {any} [body] - Request body.
|
|
163
|
+
* @param {RequestOptions} [options] - Request options.
|
|
164
|
+
* @returns {Promise<import("./response.js").default>} - The response.
|
|
165
|
+
*/
|
|
166
|
+
post(path: string, body?: any, options?: RequestOptions): Promise<import("./response.js").default>;
|
|
167
|
+
/**
|
|
168
|
+
* @param {string} path - Request path or absolute URL.
|
|
169
|
+
* @param {any} [body] - Request body.
|
|
170
|
+
* @param {RequestOptions} [options] - Request options.
|
|
171
|
+
* @returns {Promise<import("./response.js").default>} - The response.
|
|
172
|
+
*/
|
|
173
|
+
put(path: string, body?: any, options?: RequestOptions): Promise<import("./response.js").default>;
|
|
174
|
+
/**
|
|
175
|
+
* @param {string} path - Request path or absolute URL.
|
|
176
|
+
* @param {any} [body] - Request body.
|
|
177
|
+
* @param {RequestOptions} [options] - Request options.
|
|
178
|
+
* @returns {Promise<import("./response.js").default>} - The response.
|
|
179
|
+
*/
|
|
180
|
+
patch(path: string, body?: any, options?: RequestOptions): Promise<import("./response.js").default>;
|
|
181
|
+
/**
|
|
182
|
+
* @param {string} path - Request path or absolute URL.
|
|
183
|
+
* @param {RequestOptions} [options] - Request options.
|
|
184
|
+
* @returns {Promise<import("./response.js").default>} - The response.
|
|
185
|
+
*/
|
|
186
|
+
delete(path: string, options?: RequestOptions): Promise<import("./response.js").default>;
|
|
187
|
+
/**
|
|
188
|
+
* @param {import("./response.js").default} response - The failed response.
|
|
189
|
+
* @param {NormalizedRequest} request - The request that produced it.
|
|
190
|
+
* @returns {Promise<SnapReqHttpError>} - An error describing the failure.
|
|
191
|
+
*/
|
|
192
|
+
_httpError(response: import("./response.js").default, request: NormalizedRequest): Promise<SnapReqHttpError>;
|
|
193
|
+
/**
|
|
194
|
+
* Releases transport resources (for example Node keep-alive sockets).
|
|
195
|
+
* @returns {void}
|
|
196
|
+
*/
|
|
197
|
+
close(): void;
|
|
198
|
+
}
|
|
199
|
+
export type CompressionEncoding = import("./request.js").CompressionEncoding;
|
|
200
|
+
export type NormalizedRequest = {
|
|
201
|
+
/**
|
|
202
|
+
* - Upper-cased HTTP method.
|
|
203
|
+
*/
|
|
204
|
+
method: string;
|
|
205
|
+
/**
|
|
206
|
+
* - Fully resolved request URL.
|
|
207
|
+
*/
|
|
208
|
+
url: string;
|
|
209
|
+
/**
|
|
210
|
+
* - Request headers.
|
|
211
|
+
*/
|
|
212
|
+
headers: SnapReqHeaders;
|
|
213
|
+
/**
|
|
214
|
+
* - Normalized request body.
|
|
215
|
+
*/
|
|
216
|
+
body: import("./request.js").NormalizedBody;
|
|
217
|
+
/**
|
|
218
|
+
* - Request body compression.
|
|
219
|
+
*/
|
|
220
|
+
bodyCompression: CompressionEncoding;
|
|
221
|
+
/**
|
|
222
|
+
* - Abort signal.
|
|
223
|
+
*/
|
|
224
|
+
signal?: AbortSignal;
|
|
225
|
+
/**
|
|
226
|
+
* - Request timeout in milliseconds.
|
|
227
|
+
*/
|
|
228
|
+
timeoutMs?: number;
|
|
229
|
+
/**
|
|
230
|
+
* - Fetch credentials mode ("omit" | "same-origin" | "include").
|
|
231
|
+
*/
|
|
232
|
+
credentials?: string;
|
|
233
|
+
};
|
|
234
|
+
export type RequestOptions = {
|
|
235
|
+
/**
|
|
236
|
+
* - HTTP method. Defaults to GET.
|
|
237
|
+
*/
|
|
238
|
+
method?: string;
|
|
239
|
+
/**
|
|
240
|
+
* - Request path (joined with the client `baseUrl`) or absolute URL.
|
|
241
|
+
*/
|
|
242
|
+
path?: string;
|
|
243
|
+
/**
|
|
244
|
+
* - Alias for `path`.
|
|
245
|
+
*/
|
|
246
|
+
url?: string;
|
|
247
|
+
/**
|
|
248
|
+
* - Query parameters.
|
|
249
|
+
*/
|
|
250
|
+
query?: Record<string, string | number | boolean | null | undefined>;
|
|
251
|
+
/**
|
|
252
|
+
* - Per-request headers.
|
|
253
|
+
*/
|
|
254
|
+
headers?: Record<string, string | number> | SnapReqHeaders;
|
|
255
|
+
/**
|
|
256
|
+
* - Request body: string, object (JSON), Uint8Array/ArrayBuffer, or a stream/async-iterable.
|
|
257
|
+
*/
|
|
258
|
+
body?: any;
|
|
259
|
+
/**
|
|
260
|
+
* - Compress the request body (Node transport only).
|
|
261
|
+
*/
|
|
262
|
+
bodyCompression?: CompressionEncoding;
|
|
263
|
+
/**
|
|
264
|
+
* - Abort signal for the request.
|
|
265
|
+
*/
|
|
266
|
+
signal?: AbortSignal;
|
|
267
|
+
/**
|
|
268
|
+
* - Request timeout in milliseconds. Set to `0` to disable a client default.
|
|
269
|
+
*/
|
|
270
|
+
timeoutMs?: number;
|
|
271
|
+
/**
|
|
272
|
+
* - Fetch credentials mode.
|
|
273
|
+
*/
|
|
274
|
+
credentials?: string;
|
|
275
|
+
/**
|
|
276
|
+
* - Retry transient failures.
|
|
277
|
+
*/
|
|
278
|
+
retry?: boolean | import("./retry.js").RetryOptions;
|
|
279
|
+
/**
|
|
280
|
+
* - Throw `SnapReqHttpError` on non-2xx responses.
|
|
281
|
+
*/
|
|
282
|
+
throwOnError?: boolean;
|
|
283
|
+
};
|
|
284
|
+
export type RequestTimeout = {
|
|
285
|
+
/**
|
|
286
|
+
* - Signal to use for the request.
|
|
287
|
+
*/
|
|
288
|
+
signal: AbortSignal | undefined;
|
|
289
|
+
/**
|
|
290
|
+
* - Clears timeout resources.
|
|
291
|
+
*/
|
|
292
|
+
clear: () => void;
|
|
293
|
+
/**
|
|
294
|
+
* - Attaches timeout handling to a response.
|
|
295
|
+
*/
|
|
296
|
+
response: (response: import("./response.js").default, request: NormalizedRequest) => import("./response.js").default;
|
|
297
|
+
/**
|
|
298
|
+
* - Maps a thrown error.
|
|
299
|
+
*/
|
|
300
|
+
error: (error: unknown, request: NormalizedRequest) => unknown;
|
|
301
|
+
};
|
|
302
|
+
import { SnapReqHttpError } from "./errors.js";
|
|
303
|
+
import SnapReqHeaders from "./headers.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport backed by the `fetch` global. Works on web, Expo / React Native and
|
|
3
|
+
* Node 18+. It cannot open Unix sockets, present client certificates or
|
|
4
|
+
* compress request bodies — those raise `SnapReqUnsupportedFeatureError`.
|
|
5
|
+
* Response streaming uses `response.body` where available and otherwise buffers
|
|
6
|
+
* the body once, keeping the same stream interface everywhere.
|
|
7
|
+
*/
|
|
8
|
+
export default class FetchTransport {
|
|
9
|
+
/** @returns {string} - Transport name. */
|
|
10
|
+
static get transportName(): string;
|
|
11
|
+
/** @returns {boolean} - Whether this transport can run in the current environment. */
|
|
12
|
+
static isAvailable(): boolean;
|
|
13
|
+
/** @returns {import("../capabilities.js").TransportCapabilities} - Supported capabilities. */
|
|
14
|
+
get capabilities(): import("../capabilities.js").TransportCapabilities;
|
|
15
|
+
/**
|
|
16
|
+
* @param {import("../snap-req.js").NormalizedRequest} request - Normalized request.
|
|
17
|
+
* @returns {Promise<SnapReqResponse>} - The response.
|
|
18
|
+
*/
|
|
19
|
+
performRequest(request: import("../snap-req.js").NormalizedRequest): Promise<SnapReqResponse>;
|
|
20
|
+
/**
|
|
21
|
+
* @param {Response} response - The fetch response.
|
|
22
|
+
* @returns {SnapReqHeaders} - The response headers.
|
|
23
|
+
*/
|
|
24
|
+
_responseHeaders(response: Response): SnapReqHeaders;
|
|
25
|
+
/**
|
|
26
|
+
* Builds an async iterable of byte chunks over a fetch response. Uses the
|
|
27
|
+
* `ReadableStream` body for true streaming when present and otherwise buffers
|
|
28
|
+
* the whole body once so the stream interface stays identical everywhere.
|
|
29
|
+
* @param {Response} response - The fetch response.
|
|
30
|
+
* @returns {AsyncIterable<Uint8Array>} - The response body stream.
|
|
31
|
+
*/
|
|
32
|
+
_responseStream(response: Response): AsyncIterable<Uint8Array>;
|
|
33
|
+
}
|
|
34
|
+
import SnapReqResponse from "../response.js";
|
|
35
|
+
import SnapReqHeaders from "../headers.js";
|