@jaseeey/request-manager 2.1.4 → 2.2.0
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 +599 -61
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/request-manager/index.d.ts +1 -0
- package/dist/cjs/request-manager/request-manager.d.ts +54 -8
- package/dist/cjs/request-manager/request-manager.js +109 -21
- package/dist/cjs/request-manager/sha256.d.ts +14 -0
- package/dist/cjs/request-manager/sha256.js +106 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/request-manager/index.d.ts +1 -0
- package/dist/esm/request-manager/request-manager.d.ts +54 -8
- package/dist/esm/request-manager/request-manager.js +109 -21
- package/dist/esm/request-manager/sha256.d.ts +14 -0
- package/dist/esm/request-manager/sha256.js +102 -0
- package/package.json +37 -23
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse, Method } from 'axios';
|
|
2
2
|
type RequestKey = string;
|
|
3
3
|
type MaybePromise<T> = T | Promise<T>;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Human-readable identity of an in-flight request (used for inspection and hash input).
|
|
6
|
+
*/
|
|
7
|
+
export interface RequestIdentity {
|
|
8
|
+
clientId: number;
|
|
9
|
+
method: string;
|
|
10
|
+
url: string;
|
|
11
|
+
params: unknown;
|
|
12
|
+
paramsSerialised: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Active in-flight request entry stored in {@link RequestManager.activeRequests}.
|
|
16
|
+
*
|
|
17
|
+
* Map keys are SHA-256 hashes of the stable identity string. `original` and `processed`
|
|
18
|
+
* remain available for callers that inspect in-flight entries.
|
|
19
|
+
*/
|
|
20
|
+
export interface ActiveRequest {
|
|
21
|
+
hash: string;
|
|
22
|
+
identity: RequestIdentity;
|
|
5
23
|
original: Promise<AxiosResponse<unknown>>;
|
|
6
24
|
processed: Promise<unknown>;
|
|
7
25
|
}
|
|
@@ -14,10 +32,10 @@ interface RequestPromise {
|
|
|
14
32
|
*/
|
|
15
33
|
export declare class RequestManager<T = any> {
|
|
16
34
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
35
|
+
* In-flight requests keyed by a short SHA-256 hash of the request identity.
|
|
36
|
+
* Entry values expose `identity` for debugging plus `original` / `processed` promises.
|
|
19
37
|
*/
|
|
20
|
-
activeRequests: Map<RequestKey,
|
|
38
|
+
activeRequests: Map<RequestKey, ActiveRequest>;
|
|
21
39
|
private clientIds;
|
|
22
40
|
private nextClientId;
|
|
23
41
|
/**
|
|
@@ -29,7 +47,8 @@ export declare class RequestManager<T = any> {
|
|
|
29
47
|
/**
|
|
30
48
|
* Executes or retrieves an ongoing HTTP request based on the provided URL, method, payload, and configuration.
|
|
31
49
|
*
|
|
32
|
-
* Requests are de-duplicated
|
|
50
|
+
* Requests are de-duplicated when they target the same client instance, method, URL, and `config.params`.
|
|
51
|
+
* Request bodies and other config fields (headers, timeout, signal, etc.) are not part of the key.
|
|
33
52
|
* If `onSuccess` returns a non-`undefined` value, that value becomes the resolved result.
|
|
34
53
|
*
|
|
35
54
|
* @param client Axios client used to execute the request.
|
|
@@ -38,13 +57,40 @@ export declare class RequestManager<T = any> {
|
|
|
38
57
|
* @param data Optional request payload.
|
|
39
58
|
* @param config Optional Axios request configuration.
|
|
40
59
|
* @param onSuccess Optional callback invoked on success. Returning a value overrides the resolved response.
|
|
41
|
-
* @param onError Optional callback
|
|
60
|
+
* @param onError Optional callback for request failures only. If it throws, the original request error is rethrown.
|
|
42
61
|
*/
|
|
43
62
|
call<TResponse = T, TSuccess = never>(client: AxiosInstance, method: Method, url: string, data?: any, config?: AxiosRequestConfig | null, onSuccess?: ((result: AxiosResponse<TResponse>) => MaybePromise<TSuccess | undefined>) | null, onError?: ((error: unknown) => void) | null): Promise<AxiosResponse<TResponse> | TSuccess | void>;
|
|
44
63
|
/**
|
|
45
|
-
*
|
|
64
|
+
* Builds the stable human-readable identity for an in-flight request.
|
|
65
|
+
*
|
|
66
|
+
* @param client Axios client instance used for the request.
|
|
67
|
+
* @param method HTTP method.
|
|
68
|
+
* @param url Request URL string as passed to `call`.
|
|
69
|
+
* @param params Axios `config.params` value, if any.
|
|
70
|
+
* @returns Identity fields used for hashing and inspection.
|
|
71
|
+
*/
|
|
72
|
+
private buildRequestIdentity;
|
|
73
|
+
/**
|
|
74
|
+
* Hashes a request identity into a fixed-length map key.
|
|
75
|
+
*
|
|
76
|
+
* @param identity Stable request identity.
|
|
77
|
+
* @returns Lowercase hex SHA-256 digest of the identity string.
|
|
78
|
+
*/
|
|
79
|
+
private hashIdentity;
|
|
80
|
+
/**
|
|
81
|
+
* Serialises query params into a deterministic string for request keys.
|
|
82
|
+
*
|
|
83
|
+
* @param params Axios params value (`undefined`, plain object, array, or `URLSearchParams`).
|
|
84
|
+
* @returns A stable serialisation, or an empty string when params are absent.
|
|
85
|
+
*/
|
|
86
|
+
private serializeParams;
|
|
87
|
+
/**
|
|
88
|
+
* JSON-like serialisation with sorted object keys so param order does not affect identity.
|
|
89
|
+
*
|
|
90
|
+
* @param value Value to serialise.
|
|
91
|
+
* @returns Deterministic string form of `value`.
|
|
46
92
|
*/
|
|
47
|
-
private
|
|
93
|
+
private stableStringify;
|
|
48
94
|
}
|
|
49
95
|
declare const requestManager: RequestManager<any>;
|
|
50
96
|
export default requestManager;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RequestManager = void 0;
|
|
4
|
+
const sha256_js_1 = require("./sha256.js");
|
|
4
5
|
/**
|
|
5
6
|
* RequestManager
|
|
6
7
|
*
|
|
@@ -10,8 +11,8 @@ exports.RequestManager = void 0;
|
|
|
10
11
|
*/
|
|
11
12
|
class RequestManager {
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* In-flight requests keyed by a short SHA-256 hash of the request identity.
|
|
15
|
+
* Entry values expose `identity` for debugging plus `original` / `processed` promises.
|
|
15
16
|
*/
|
|
16
17
|
activeRequests = new Map();
|
|
17
18
|
clientIds = new WeakMap();
|
|
@@ -27,7 +28,8 @@ class RequestManager {
|
|
|
27
28
|
/**
|
|
28
29
|
* Executes or retrieves an ongoing HTTP request based on the provided URL, method, payload, and configuration.
|
|
29
30
|
*
|
|
30
|
-
* Requests are de-duplicated
|
|
31
|
+
* Requests are de-duplicated when they target the same client instance, method, URL, and `config.params`.
|
|
32
|
+
* Request bodies and other config fields (headers, timeout, signal, etc.) are not part of the key.
|
|
31
33
|
* If `onSuccess` returns a non-`undefined` value, that value becomes the resolved result.
|
|
32
34
|
*
|
|
33
35
|
* @param client Axios client used to execute the request.
|
|
@@ -36,50 +38,136 @@ class RequestManager {
|
|
|
36
38
|
* @param data Optional request payload.
|
|
37
39
|
* @param config Optional Axios request configuration.
|
|
38
40
|
* @param onSuccess Optional callback invoked on success. Returning a value overrides the resolved response.
|
|
39
|
-
* @param onError Optional callback
|
|
41
|
+
* @param onError Optional callback for request failures only. If it throws, the original request error is rethrown.
|
|
40
42
|
*/
|
|
41
|
-
|
|
43
|
+
call(client, method, url, data = {}, config = {}, onSuccess, onError) {
|
|
44
|
+
if (typeof method !== 'string' || method.length === 0) {
|
|
45
|
+
return Promise.reject(new TypeError('RequestManager.call requires a non-empty HTTP method string'));
|
|
46
|
+
}
|
|
47
|
+
if (typeof url !== 'string') {
|
|
48
|
+
return Promise.reject(new TypeError('RequestManager.call requires a URL string'));
|
|
49
|
+
}
|
|
42
50
|
data ??= {};
|
|
43
51
|
config ??= {};
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
const identity = this.buildRequestIdentity(client, method, url, config.params);
|
|
53
|
+
const hash = this.hashIdentity(identity);
|
|
54
|
+
const existing = this.activeRequests.get(hash);
|
|
55
|
+
if (existing) {
|
|
56
|
+
return existing.processed;
|
|
47
57
|
}
|
|
48
58
|
const processRequest = async (responsePromise) => {
|
|
59
|
+
let requestResult;
|
|
49
60
|
try {
|
|
50
|
-
|
|
51
|
-
const callbackResult = onSuccess && typeof onSuccess === 'function'
|
|
52
|
-
? await onSuccess(requestResult)
|
|
53
|
-
: undefined;
|
|
54
|
-
return callbackResult !== undefined
|
|
55
|
-
? callbackResult
|
|
56
|
-
: requestResult;
|
|
61
|
+
requestResult = await responsePromise;
|
|
57
62
|
}
|
|
58
63
|
catch (err) {
|
|
59
64
|
if (onError && typeof onError === 'function') {
|
|
60
|
-
|
|
65
|
+
try {
|
|
66
|
+
onError(err);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
61
71
|
return;
|
|
62
72
|
}
|
|
63
73
|
throw err;
|
|
64
74
|
}
|
|
75
|
+
if (!(onSuccess && typeof onSuccess === 'function')) {
|
|
76
|
+
return requestResult;
|
|
77
|
+
}
|
|
78
|
+
const callbackResult = await onSuccess(requestResult);
|
|
79
|
+
return callbackResult !== undefined
|
|
80
|
+
? callbackResult
|
|
81
|
+
: requestResult;
|
|
65
82
|
};
|
|
66
83
|
const requestPromise = client.request({ ...config, method, url, data }).finally(() => {
|
|
67
|
-
this.activeRequests.delete(
|
|
84
|
+
this.activeRequests.delete(hash);
|
|
68
85
|
});
|
|
69
86
|
const processedPromise = processRequest(requestPromise);
|
|
70
|
-
this.activeRequests.set(
|
|
87
|
+
this.activeRequests.set(hash, {
|
|
88
|
+
hash,
|
|
89
|
+
identity,
|
|
90
|
+
original: requestPromise,
|
|
91
|
+
processed: processedPromise
|
|
92
|
+
});
|
|
71
93
|
return processedPromise;
|
|
72
94
|
}
|
|
73
95
|
/**
|
|
74
|
-
*
|
|
96
|
+
* Builds the stable human-readable identity for an in-flight request.
|
|
97
|
+
*
|
|
98
|
+
* @param client Axios client instance used for the request.
|
|
99
|
+
* @param method HTTP method.
|
|
100
|
+
* @param url Request URL string as passed to `call`.
|
|
101
|
+
* @param params Axios `config.params` value, if any.
|
|
102
|
+
* @returns Identity fields used for hashing and inspection.
|
|
75
103
|
*/
|
|
76
|
-
|
|
104
|
+
buildRequestIdentity(client, method, url, params) {
|
|
77
105
|
let clientId = this.clientIds.get(client);
|
|
78
106
|
if (!clientId) {
|
|
79
107
|
clientId = this.nextClientId++;
|
|
80
108
|
this.clientIds.set(client, clientId);
|
|
81
109
|
}
|
|
82
|
-
|
|
110
|
+
const normalisedMethod = method.toLowerCase();
|
|
111
|
+
const paramsSerialised = this.serializeParams(params);
|
|
112
|
+
return {
|
|
113
|
+
clientId,
|
|
114
|
+
method: normalisedMethod,
|
|
115
|
+
url,
|
|
116
|
+
params: params ?? null,
|
|
117
|
+
paramsSerialised
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Hashes a request identity into a fixed-length map key.
|
|
122
|
+
*
|
|
123
|
+
* @param identity Stable request identity.
|
|
124
|
+
* @returns Lowercase hex SHA-256 digest of the identity string.
|
|
125
|
+
*/
|
|
126
|
+
hashIdentity(identity) {
|
|
127
|
+
const material = `${identity.clientId}:${identity.method}:${identity.url}:${identity.paramsSerialised}`;
|
|
128
|
+
return (0, sha256_js_1.sha256Hex)(material);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Serialises query params into a deterministic string for request keys.
|
|
132
|
+
*
|
|
133
|
+
* @param params Axios params value (`undefined`, plain object, array, or `URLSearchParams`).
|
|
134
|
+
* @returns A stable serialisation, or an empty string when params are absent.
|
|
135
|
+
*/
|
|
136
|
+
serializeParams(params) {
|
|
137
|
+
if (params == null) {
|
|
138
|
+
return '';
|
|
139
|
+
}
|
|
140
|
+
if (typeof URLSearchParams !== 'undefined' && params instanceof URLSearchParams) {
|
|
141
|
+
if ([...params.keys()].length === 0) {
|
|
142
|
+
return '';
|
|
143
|
+
}
|
|
144
|
+
const asObject = {};
|
|
145
|
+
for (const key of [...params.keys()].sort()) {
|
|
146
|
+
asObject[key] = params.getAll(key);
|
|
147
|
+
}
|
|
148
|
+
return this.stableStringify(asObject);
|
|
149
|
+
}
|
|
150
|
+
if (typeof params === 'object' && !Array.isArray(params) && Object.keys(params).length === 0) {
|
|
151
|
+
return '';
|
|
152
|
+
}
|
|
153
|
+
return this.stableStringify(params);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* JSON-like serialisation with sorted object keys so param order does not affect identity.
|
|
157
|
+
*
|
|
158
|
+
* @param value Value to serialise.
|
|
159
|
+
* @returns Deterministic string form of `value`.
|
|
160
|
+
*/
|
|
161
|
+
stableStringify(value) {
|
|
162
|
+
if (value === null || typeof value !== 'object') {
|
|
163
|
+
return JSON.stringify(value);
|
|
164
|
+
}
|
|
165
|
+
if (Array.isArray(value)) {
|
|
166
|
+
return `[${value.map(entry => this.stableStringify(entry)).join(',')}]`;
|
|
167
|
+
}
|
|
168
|
+
const record = value;
|
|
169
|
+
const keys = Object.keys(record).sort();
|
|
170
|
+
return `{${keys.map(key => `${JSON.stringify(key)}:${this.stableStringify(record[key])}`).join(',')}}`;
|
|
83
171
|
}
|
|
84
172
|
}
|
|
85
173
|
exports.RequestManager = RequestManager;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous SHA-256 hex digest for browser and Node without async WebCrypto.
|
|
3
|
+
*
|
|
4
|
+
* @param message UTF-8 string to hash.
|
|
5
|
+
* @returns Lowercase hex digest.
|
|
6
|
+
*/
|
|
7
|
+
export declare function sha256Hex(message: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Encodes a string as UTF-8 bytes.
|
|
10
|
+
*
|
|
11
|
+
* @param message String to encode.
|
|
12
|
+
* @returns UTF-8 byte array.
|
|
13
|
+
*/
|
|
14
|
+
export declare function utf8ToBytes(message: string): Uint8Array;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sha256Hex = sha256Hex;
|
|
4
|
+
exports.utf8ToBytes = utf8ToBytes;
|
|
5
|
+
/**
|
|
6
|
+
* Synchronous SHA-256 hex digest for browser and Node without async WebCrypto.
|
|
7
|
+
*
|
|
8
|
+
* @param message UTF-8 string to hash.
|
|
9
|
+
* @returns Lowercase hex digest.
|
|
10
|
+
*/
|
|
11
|
+
function sha256Hex(message) {
|
|
12
|
+
const bytes = utf8ToBytes(message);
|
|
13
|
+
const bitLength = bytes.length * 8;
|
|
14
|
+
const withOne = new Uint8Array(((bytes.length + 9 + 63) & ~63));
|
|
15
|
+
withOne.set(bytes);
|
|
16
|
+
withOne[bytes.length] = 0x80;
|
|
17
|
+
const view = new DataView(withOne.buffer);
|
|
18
|
+
view.setUint32(withOne.length - 8, Math.floor(bitLength / 0x100000000), false);
|
|
19
|
+
view.setUint32(withOne.length - 4, bitLength >>> 0, false);
|
|
20
|
+
let h0 = 0x6a09e667;
|
|
21
|
+
let h1 = 0xbb67ae85;
|
|
22
|
+
let h2 = 0x3c6ef372;
|
|
23
|
+
let h3 = 0xa54ff53a;
|
|
24
|
+
let h4 = 0x510e527f;
|
|
25
|
+
let h5 = 0x9b05688c;
|
|
26
|
+
let h6 = 0x1f83d9ab;
|
|
27
|
+
let h7 = 0x5be0cd19;
|
|
28
|
+
const w = new Int32Array(64);
|
|
29
|
+
const k = SHA256_K;
|
|
30
|
+
for (let offset = 0; offset < withOne.length; offset += 64) {
|
|
31
|
+
for (let i = 0; i < 16; i++) {
|
|
32
|
+
w[i] = view.getInt32(offset + i * 4, false);
|
|
33
|
+
}
|
|
34
|
+
for (let i = 16; i < 64; i++) {
|
|
35
|
+
const s0 = rightRotate(w[i - 15], 7) ^ rightRotate(w[i - 15], 18) ^ (w[i - 15] >>> 3);
|
|
36
|
+
const s1 = rightRotate(w[i - 2], 17) ^ rightRotate(w[i - 2], 19) ^ (w[i - 2] >>> 10);
|
|
37
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) | 0;
|
|
38
|
+
}
|
|
39
|
+
let a = h0;
|
|
40
|
+
let b = h1;
|
|
41
|
+
let c = h2;
|
|
42
|
+
let d = h3;
|
|
43
|
+
let e = h4;
|
|
44
|
+
let f = h5;
|
|
45
|
+
let g = h6;
|
|
46
|
+
let h = h7;
|
|
47
|
+
for (let i = 0; i < 64; i++) {
|
|
48
|
+
const S1 = rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25);
|
|
49
|
+
const ch = (e & f) ^ (~e & g);
|
|
50
|
+
const temp1 = (h + S1 + ch + k[i] + w[i]) | 0;
|
|
51
|
+
const S0 = rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22);
|
|
52
|
+
const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
53
|
+
const temp2 = (S0 + maj) | 0;
|
|
54
|
+
h = g;
|
|
55
|
+
g = f;
|
|
56
|
+
f = e;
|
|
57
|
+
e = (d + temp1) | 0;
|
|
58
|
+
d = c;
|
|
59
|
+
c = b;
|
|
60
|
+
b = a;
|
|
61
|
+
a = (temp1 + temp2) | 0;
|
|
62
|
+
}
|
|
63
|
+
h0 = (h0 + a) | 0;
|
|
64
|
+
h1 = (h1 + b) | 0;
|
|
65
|
+
h2 = (h2 + c) | 0;
|
|
66
|
+
h3 = (h3 + d) | 0;
|
|
67
|
+
h4 = (h4 + e) | 0;
|
|
68
|
+
h5 = (h5 + f) | 0;
|
|
69
|
+
h6 = (h6 + g) | 0;
|
|
70
|
+
h7 = (h7 + h) | 0;
|
|
71
|
+
}
|
|
72
|
+
return [h0, h1, h2, h3, h4, h5, h6, h7].map(wordToHex).join('');
|
|
73
|
+
}
|
|
74
|
+
function rightRotate(value, amount) {
|
|
75
|
+
return (value >>> amount) | (value << (32 - amount));
|
|
76
|
+
}
|
|
77
|
+
function wordToHex(value) {
|
|
78
|
+
return (value >>> 0).toString(16).padStart(8, '0');
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Encodes a string as UTF-8 bytes.
|
|
82
|
+
*
|
|
83
|
+
* @param message String to encode.
|
|
84
|
+
* @returns UTF-8 byte array.
|
|
85
|
+
*/
|
|
86
|
+
function utf8ToBytes(message) {
|
|
87
|
+
if (typeof TextEncoder !== 'undefined') {
|
|
88
|
+
return new TextEncoder().encode(message);
|
|
89
|
+
}
|
|
90
|
+
const encoded = unescape(encodeURIComponent(message));
|
|
91
|
+
const bytes = new Uint8Array(encoded.length);
|
|
92
|
+
for (let i = 0; i < encoded.length; i++) {
|
|
93
|
+
bytes[i] = encoded.charCodeAt(i);
|
|
94
|
+
}
|
|
95
|
+
return bytes;
|
|
96
|
+
}
|
|
97
|
+
const SHA256_K = new Int32Array([
|
|
98
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
99
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
100
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
101
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
102
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
103
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
104
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
105
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
|
106
|
+
]);
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse, Method } from 'axios';
|
|
2
2
|
type RequestKey = string;
|
|
3
3
|
type MaybePromise<T> = T | Promise<T>;
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Human-readable identity of an in-flight request (used for inspection and hash input).
|
|
6
|
+
*/
|
|
7
|
+
export interface RequestIdentity {
|
|
8
|
+
clientId: number;
|
|
9
|
+
method: string;
|
|
10
|
+
url: string;
|
|
11
|
+
params: unknown;
|
|
12
|
+
paramsSerialised: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Active in-flight request entry stored in {@link RequestManager.activeRequests}.
|
|
16
|
+
*
|
|
17
|
+
* Map keys are SHA-256 hashes of the stable identity string. `original` and `processed`
|
|
18
|
+
* remain available for callers that inspect in-flight entries.
|
|
19
|
+
*/
|
|
20
|
+
export interface ActiveRequest {
|
|
21
|
+
hash: string;
|
|
22
|
+
identity: RequestIdentity;
|
|
5
23
|
original: Promise<AxiosResponse<unknown>>;
|
|
6
24
|
processed: Promise<unknown>;
|
|
7
25
|
}
|
|
@@ -14,10 +32,10 @@ interface RequestPromise {
|
|
|
14
32
|
*/
|
|
15
33
|
export declare class RequestManager<T = any> {
|
|
16
34
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
35
|
+
* In-flight requests keyed by a short SHA-256 hash of the request identity.
|
|
36
|
+
* Entry values expose `identity` for debugging plus `original` / `processed` promises.
|
|
19
37
|
*/
|
|
20
|
-
activeRequests: Map<RequestKey,
|
|
38
|
+
activeRequests: Map<RequestKey, ActiveRequest>;
|
|
21
39
|
private clientIds;
|
|
22
40
|
private nextClientId;
|
|
23
41
|
/**
|
|
@@ -29,7 +47,8 @@ export declare class RequestManager<T = any> {
|
|
|
29
47
|
/**
|
|
30
48
|
* Executes or retrieves an ongoing HTTP request based on the provided URL, method, payload, and configuration.
|
|
31
49
|
*
|
|
32
|
-
* Requests are de-duplicated
|
|
50
|
+
* Requests are de-duplicated when they target the same client instance, method, URL, and `config.params`.
|
|
51
|
+
* Request bodies and other config fields (headers, timeout, signal, etc.) are not part of the key.
|
|
33
52
|
* If `onSuccess` returns a non-`undefined` value, that value becomes the resolved result.
|
|
34
53
|
*
|
|
35
54
|
* @param client Axios client used to execute the request.
|
|
@@ -38,13 +57,40 @@ export declare class RequestManager<T = any> {
|
|
|
38
57
|
* @param data Optional request payload.
|
|
39
58
|
* @param config Optional Axios request configuration.
|
|
40
59
|
* @param onSuccess Optional callback invoked on success. Returning a value overrides the resolved response.
|
|
41
|
-
* @param onError Optional callback
|
|
60
|
+
* @param onError Optional callback for request failures only. If it throws, the original request error is rethrown.
|
|
42
61
|
*/
|
|
43
62
|
call<TResponse = T, TSuccess = never>(client: AxiosInstance, method: Method, url: string, data?: any, config?: AxiosRequestConfig | null, onSuccess?: ((result: AxiosResponse<TResponse>) => MaybePromise<TSuccess | undefined>) | null, onError?: ((error: unknown) => void) | null): Promise<AxiosResponse<TResponse> | TSuccess | void>;
|
|
44
63
|
/**
|
|
45
|
-
*
|
|
64
|
+
* Builds the stable human-readable identity for an in-flight request.
|
|
65
|
+
*
|
|
66
|
+
* @param client Axios client instance used for the request.
|
|
67
|
+
* @param method HTTP method.
|
|
68
|
+
* @param url Request URL string as passed to `call`.
|
|
69
|
+
* @param params Axios `config.params` value, if any.
|
|
70
|
+
* @returns Identity fields used for hashing and inspection.
|
|
71
|
+
*/
|
|
72
|
+
private buildRequestIdentity;
|
|
73
|
+
/**
|
|
74
|
+
* Hashes a request identity into a fixed-length map key.
|
|
75
|
+
*
|
|
76
|
+
* @param identity Stable request identity.
|
|
77
|
+
* @returns Lowercase hex SHA-256 digest of the identity string.
|
|
78
|
+
*/
|
|
79
|
+
private hashIdentity;
|
|
80
|
+
/**
|
|
81
|
+
* Serialises query params into a deterministic string for request keys.
|
|
82
|
+
*
|
|
83
|
+
* @param params Axios params value (`undefined`, plain object, array, or `URLSearchParams`).
|
|
84
|
+
* @returns A stable serialisation, or an empty string when params are absent.
|
|
85
|
+
*/
|
|
86
|
+
private serializeParams;
|
|
87
|
+
/**
|
|
88
|
+
* JSON-like serialisation with sorted object keys so param order does not affect identity.
|
|
89
|
+
*
|
|
90
|
+
* @param value Value to serialise.
|
|
91
|
+
* @returns Deterministic string form of `value`.
|
|
46
92
|
*/
|
|
47
|
-
private
|
|
93
|
+
private stableStringify;
|
|
48
94
|
}
|
|
49
95
|
declare const requestManager: RequestManager<any>;
|
|
50
96
|
export default requestManager;
|