phenoml 6.1.0 → 6.3.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/dist/cjs/BaseClient.d.ts +2 -0
- package/dist/cjs/Client.js +3 -3
- package/dist/cjs/api/resources/agent/client/Client.js +8 -0
- package/dist/cjs/api/resources/agent/resources/prompts/client/Client.js +7 -0
- package/dist/cjs/api/resources/cohort/client/Client.js +1 -0
- package/dist/cjs/api/resources/construe/client/Client.js +10 -0
- package/dist/cjs/api/resources/fhir/client/Client.js +6 -0
- package/dist/cjs/api/resources/fhirProvider/client/Client.js +7 -0
- package/dist/cjs/api/resources/lang2Fhir/client/Client.js +5 -0
- package/dist/cjs/api/resources/summary/client/Client.js +6 -0
- package/dist/cjs/api/resources/tools/client/Client.js +4 -0
- package/dist/cjs/api/resources/tools/resources/mcpServer/client/Client.js +4 -0
- package/dist/cjs/api/resources/tools/resources/mcpServer/resources/tools/client/Client.js +4 -0
- package/dist/cjs/api/resources/workflows/client/Client.js +6 -0
- package/dist/cjs/core/exports.d.ts +1 -0
- package/dist/cjs/core/exports.js +17 -0
- package/dist/cjs/core/fetcher/Fetcher.d.ts +2 -0
- package/dist/cjs/core/fetcher/Fetcher.js +192 -1
- package/dist/cjs/core/fetcher/makeRequest.js +0 -2
- package/dist/cjs/core/fetcher/requestWithRetries.js +0 -9
- package/dist/cjs/core/fetcher/signals.d.ts +0 -6
- package/dist/cjs/core/fetcher/signals.js +0 -12
- package/dist/cjs/core/index.d.ts +1 -0
- package/dist/cjs/core/index.js +2 -1
- package/dist/cjs/core/logging/exports.d.ts +18 -0
- package/dist/cjs/core/logging/exports.js +45 -0
- package/dist/cjs/core/logging/index.d.ts +1 -0
- package/dist/cjs/core/logging/index.js +17 -0
- package/dist/cjs/core/logging/logger.d.ts +126 -0
- package/dist/cjs/core/logging/logger.js +144 -0
- package/dist/cjs/core/url/join.js +0 -1
- package/dist/cjs/exports.d.ts +1 -0
- package/dist/cjs/exports.js +17 -0
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/BaseClient.d.mts +2 -0
- package/dist/esm/Client.mjs +3 -3
- package/dist/esm/api/resources/agent/client/Client.mjs +8 -0
- package/dist/esm/api/resources/agent/resources/prompts/client/Client.mjs +7 -0
- package/dist/esm/api/resources/cohort/client/Client.mjs +1 -0
- package/dist/esm/api/resources/construe/client/Client.mjs +10 -0
- package/dist/esm/api/resources/fhir/client/Client.mjs +6 -0
- package/dist/esm/api/resources/fhirProvider/client/Client.mjs +7 -0
- package/dist/esm/api/resources/lang2Fhir/client/Client.mjs +5 -0
- package/dist/esm/api/resources/summary/client/Client.mjs +6 -0
- package/dist/esm/api/resources/tools/client/Client.mjs +4 -0
- package/dist/esm/api/resources/tools/resources/mcpServer/client/Client.mjs +4 -0
- package/dist/esm/api/resources/tools/resources/mcpServer/resources/tools/client/Client.mjs +4 -0
- package/dist/esm/api/resources/workflows/client/Client.mjs +6 -0
- package/dist/esm/core/exports.d.mts +1 -0
- package/dist/esm/core/exports.mjs +1 -0
- package/dist/esm/core/fetcher/Fetcher.d.mts +2 -0
- package/dist/esm/core/fetcher/Fetcher.mjs +192 -1
- package/dist/esm/core/fetcher/makeRequest.mjs +0 -2
- package/dist/esm/core/fetcher/requestWithRetries.mjs +0 -9
- package/dist/esm/core/fetcher/signals.d.mts +0 -6
- package/dist/esm/core/fetcher/signals.mjs +0 -12
- package/dist/esm/core/index.d.mts +1 -0
- package/dist/esm/core/index.mjs +1 -0
- package/dist/esm/core/logging/exports.d.mts +18 -0
- package/dist/esm/core/logging/exports.mjs +9 -0
- package/dist/esm/core/logging/index.d.mts +1 -0
- package/dist/esm/core/logging/index.mjs +1 -0
- package/dist/esm/core/logging/logger.d.mts +126 -0
- package/dist/esm/core/logging/logger.mjs +138 -0
- package/dist/esm/core/url/join.mjs +0 -1
- package/dist/esm/exports.d.mts +1 -0
- package/dist/esm/exports.mjs +1 -0
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/package.json +2 -1
|
@@ -58,6 +58,7 @@ export class McpServer {
|
|
|
58
58
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
59
59
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
60
60
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
61
|
+
logging: this._options.logging,
|
|
61
62
|
});
|
|
62
63
|
if (_response.ok) {
|
|
63
64
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -125,6 +126,7 @@ export class McpServer {
|
|
|
125
126
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
126
127
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
127
128
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
129
|
+
logging: this._options.logging,
|
|
128
130
|
});
|
|
129
131
|
if (_response.ok) {
|
|
130
132
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -191,6 +193,7 @@ export class McpServer {
|
|
|
191
193
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
192
194
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
193
195
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
196
|
+
logging: this._options.logging,
|
|
194
197
|
});
|
|
195
198
|
if (_response.ok) {
|
|
196
199
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -257,6 +260,7 @@ export class McpServer {
|
|
|
257
260
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
258
261
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
259
262
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
263
|
+
logging: this._options.logging,
|
|
260
264
|
});
|
|
261
265
|
if (_response.ok) {
|
|
262
266
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -46,6 +46,7 @@ export class Tools {
|
|
|
46
46
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
47
47
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
48
48
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
49
|
+
logging: this._options.logging,
|
|
49
50
|
});
|
|
50
51
|
if (_response.ok) {
|
|
51
52
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -112,6 +113,7 @@ export class Tools {
|
|
|
112
113
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
113
114
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
114
115
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
116
|
+
logging: this._options.logging,
|
|
115
117
|
});
|
|
116
118
|
if (_response.ok) {
|
|
117
119
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -178,6 +180,7 @@ export class Tools {
|
|
|
178
180
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
179
181
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
180
182
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
183
|
+
logging: this._options.logging,
|
|
181
184
|
});
|
|
182
185
|
if (_response.ok) {
|
|
183
186
|
return { data: _response.body, rawResponse: _response.rawResponse };
|
|
@@ -253,6 +256,7 @@ export class Tools {
|
|
|
253
256
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
254
257
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
255
258
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
259
|
+
logging: this._options.logging,
|
|
256
260
|
});
|
|
257
261
|
if (_response.ok) {
|
|
258
262
|
return {
|
|
@@ -64,6 +64,7 @@ export class Workflows {
|
|
|
64
64
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
65
65
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
66
66
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
67
|
+
logging: this._options.logging,
|
|
67
68
|
});
|
|
68
69
|
if (_response.ok) {
|
|
69
70
|
return {
|
|
@@ -152,6 +153,7 @@ export class Workflows {
|
|
|
152
153
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
153
154
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
154
155
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
156
|
+
logging: this._options.logging,
|
|
155
157
|
});
|
|
156
158
|
if (_response.ok) {
|
|
157
159
|
return {
|
|
@@ -232,6 +234,7 @@ export class Workflows {
|
|
|
232
234
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
233
235
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
234
236
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
237
|
+
logging: this._options.logging,
|
|
235
238
|
});
|
|
236
239
|
if (_response.ok) {
|
|
237
240
|
return {
|
|
@@ -324,6 +327,7 @@ export class Workflows {
|
|
|
324
327
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
325
328
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
326
329
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
330
|
+
logging: this._options.logging,
|
|
327
331
|
});
|
|
328
332
|
if (_response.ok) {
|
|
329
333
|
return {
|
|
@@ -398,6 +402,7 @@ export class Workflows {
|
|
|
398
402
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
399
403
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
400
404
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
405
|
+
logging: this._options.logging,
|
|
401
406
|
});
|
|
402
407
|
if (_response.ok) {
|
|
403
408
|
return {
|
|
@@ -482,6 +487,7 @@ export class Workflows {
|
|
|
482
487
|
maxRetries: (_h = requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.maxRetries) !== null && _h !== void 0 ? _h : (_j = this._options) === null || _j === void 0 ? void 0 : _j.maxRetries,
|
|
483
488
|
abortSignal: requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.abortSignal,
|
|
484
489
|
fetchFn: (_k = this._options) === null || _k === void 0 ? void 0 : _k.fetch,
|
|
490
|
+
logging: this._options.logging,
|
|
485
491
|
});
|
|
486
492
|
if (_response.ok) {
|
|
487
493
|
return {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logging/exports.mjs";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logging/exports.mjs";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LogConfig, type Logger } from "../logging/logger.mjs";
|
|
1
2
|
import type { APIResponse } from "./APIResponse.mjs";
|
|
2
3
|
import type { EndpointMetadata } from "./EndpointMetadata.mjs";
|
|
3
4
|
import { EndpointSupplier } from "./EndpointSupplier.mjs";
|
|
@@ -19,6 +20,7 @@ export declare namespace Fetcher {
|
|
|
19
20
|
duplex?: "half";
|
|
20
21
|
endpointMetadata?: EndpointMetadata;
|
|
21
22
|
fetchFn?: typeof fetch;
|
|
23
|
+
logging?: LogConfig | Logger;
|
|
22
24
|
}
|
|
23
25
|
type Error = FailedStatusCodeError | NonJsonError | TimeoutError | UnknownError;
|
|
24
26
|
interface FailedStatusCodeError {
|
|
@@ -8,6 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { toJson } from "../json.mjs";
|
|
11
|
+
import { createLogger } from "../logging/logger.mjs";
|
|
11
12
|
import { createRequestUrl } from "./createRequestUrl.mjs";
|
|
12
13
|
import { EndpointSupplier } from "./EndpointSupplier.mjs";
|
|
13
14
|
import { getErrorResponseBody } from "./getErrorResponseBody.mjs";
|
|
@@ -17,6 +18,135 @@ import { getResponseBody } from "./getResponseBody.mjs";
|
|
|
17
18
|
import { makeRequest } from "./makeRequest.mjs";
|
|
18
19
|
import { abortRawResponse, toRawResponse, unknownRawResponse } from "./RawResponse.mjs";
|
|
19
20
|
import { requestWithRetries } from "./requestWithRetries.mjs";
|
|
21
|
+
const SENSITIVE_HEADERS = new Set([
|
|
22
|
+
"authorization",
|
|
23
|
+
"www-authenticate",
|
|
24
|
+
"x-api-key",
|
|
25
|
+
"api-key",
|
|
26
|
+
"apikey",
|
|
27
|
+
"x-api-token",
|
|
28
|
+
"x-auth-token",
|
|
29
|
+
"auth-token",
|
|
30
|
+
"cookie",
|
|
31
|
+
"set-cookie",
|
|
32
|
+
"proxy-authorization",
|
|
33
|
+
"proxy-authenticate",
|
|
34
|
+
"x-csrf-token",
|
|
35
|
+
"x-xsrf-token",
|
|
36
|
+
"x-session-token",
|
|
37
|
+
"x-access-token",
|
|
38
|
+
]);
|
|
39
|
+
function redactHeaders(headers) {
|
|
40
|
+
const filtered = {};
|
|
41
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
42
|
+
if (SENSITIVE_HEADERS.has(key.toLowerCase())) {
|
|
43
|
+
filtered[key] = "[REDACTED]";
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
filtered[key] = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return filtered;
|
|
50
|
+
}
|
|
51
|
+
const SENSITIVE_QUERY_PARAMS = new Set([
|
|
52
|
+
"api_key",
|
|
53
|
+
"api-key",
|
|
54
|
+
"apikey",
|
|
55
|
+
"token",
|
|
56
|
+
"access_token",
|
|
57
|
+
"access-token",
|
|
58
|
+
"auth_token",
|
|
59
|
+
"auth-token",
|
|
60
|
+
"password",
|
|
61
|
+
"passwd",
|
|
62
|
+
"secret",
|
|
63
|
+
"api_secret",
|
|
64
|
+
"api-secret",
|
|
65
|
+
"apisecret",
|
|
66
|
+
"key",
|
|
67
|
+
"session",
|
|
68
|
+
"session_id",
|
|
69
|
+
"session-id",
|
|
70
|
+
]);
|
|
71
|
+
function redactQueryParameters(queryParameters) {
|
|
72
|
+
if (queryParameters == null) {
|
|
73
|
+
return queryParameters;
|
|
74
|
+
}
|
|
75
|
+
const redacted = {};
|
|
76
|
+
for (const [key, value] of Object.entries(queryParameters)) {
|
|
77
|
+
if (SENSITIVE_QUERY_PARAMS.has(key.toLowerCase())) {
|
|
78
|
+
redacted[key] = "[REDACTED]";
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
redacted[key] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return redacted;
|
|
85
|
+
}
|
|
86
|
+
function redactUrl(url) {
|
|
87
|
+
const protocolIndex = url.indexOf("://");
|
|
88
|
+
if (protocolIndex === -1)
|
|
89
|
+
return url;
|
|
90
|
+
const afterProtocol = protocolIndex + 3;
|
|
91
|
+
// Find the first delimiter that marks the end of the authority section
|
|
92
|
+
const pathStart = url.indexOf("/", afterProtocol);
|
|
93
|
+
let queryStart = url.indexOf("?", afterProtocol);
|
|
94
|
+
let fragmentStart = url.indexOf("#", afterProtocol);
|
|
95
|
+
const firstDelimiter = Math.min(pathStart === -1 ? url.length : pathStart, queryStart === -1 ? url.length : queryStart, fragmentStart === -1 ? url.length : fragmentStart);
|
|
96
|
+
// Find the LAST @ before the delimiter (handles multiple @ in credentials)
|
|
97
|
+
let atIndex = -1;
|
|
98
|
+
for (let i = afterProtocol; i < firstDelimiter; i++) {
|
|
99
|
+
if (url[i] === "@") {
|
|
100
|
+
atIndex = i;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (atIndex !== -1) {
|
|
104
|
+
url = `${url.slice(0, afterProtocol)}[REDACTED]@${url.slice(atIndex + 1)}`;
|
|
105
|
+
}
|
|
106
|
+
// Recalculate queryStart since url might have changed
|
|
107
|
+
queryStart = url.indexOf("?");
|
|
108
|
+
if (queryStart === -1)
|
|
109
|
+
return url;
|
|
110
|
+
fragmentStart = url.indexOf("#", queryStart);
|
|
111
|
+
const queryEnd = fragmentStart !== -1 ? fragmentStart : url.length;
|
|
112
|
+
const queryString = url.slice(queryStart + 1, queryEnd);
|
|
113
|
+
if (queryString.length === 0)
|
|
114
|
+
return url;
|
|
115
|
+
// FAST PATH: Quick check if any sensitive keywords present
|
|
116
|
+
// Using indexOf is faster than regex for simple substring matching
|
|
117
|
+
const lower = queryString.toLowerCase();
|
|
118
|
+
const hasSensitive = lower.includes("token") ||
|
|
119
|
+
lower.includes("key") ||
|
|
120
|
+
lower.includes("password") ||
|
|
121
|
+
lower.includes("passwd") ||
|
|
122
|
+
lower.includes("secret") ||
|
|
123
|
+
lower.includes("session") ||
|
|
124
|
+
lower.includes("auth");
|
|
125
|
+
if (!hasSensitive) {
|
|
126
|
+
return url;
|
|
127
|
+
}
|
|
128
|
+
// SLOW PATH: Parse and redact
|
|
129
|
+
const redactedParams = [];
|
|
130
|
+
const params = queryString.split("&");
|
|
131
|
+
for (const param of params) {
|
|
132
|
+
const equalIndex = param.indexOf("=");
|
|
133
|
+
if (equalIndex === -1) {
|
|
134
|
+
redactedParams.push(param);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const key = param.slice(0, equalIndex);
|
|
138
|
+
let shouldRedact = SENSITIVE_QUERY_PARAMS.has(key.toLowerCase());
|
|
139
|
+
if (!shouldRedact && key.includes("%")) {
|
|
140
|
+
try {
|
|
141
|
+
const decodedKey = decodeURIComponent(key);
|
|
142
|
+
shouldRedact = SENSITIVE_QUERY_PARAMS.has(decodedKey.toLowerCase());
|
|
143
|
+
}
|
|
144
|
+
catch (_a) { }
|
|
145
|
+
}
|
|
146
|
+
redactedParams.push(shouldRedact ? `${key}=[REDACTED]` : param);
|
|
147
|
+
}
|
|
148
|
+
return url.slice(0, queryStart + 1) + redactedParams.join("&") + url.slice(queryEnd);
|
|
149
|
+
}
|
|
20
150
|
function getHeaders(args) {
|
|
21
151
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
152
|
var _a;
|
|
@@ -50,11 +180,32 @@ export function fetcherImpl(args) {
|
|
|
50
180
|
type: (_a = args.requestType) !== null && _a !== void 0 ? _a : "other",
|
|
51
181
|
});
|
|
52
182
|
const fetchFn = (_b = args.fetchFn) !== null && _b !== void 0 ? _b : (yield getFetchFn());
|
|
183
|
+
const headers = yield getHeaders(args);
|
|
184
|
+
const logger = createLogger(args.logging);
|
|
185
|
+
if (logger.isDebug()) {
|
|
186
|
+
const metadata = {
|
|
187
|
+
method: args.method,
|
|
188
|
+
url: redactUrl(url),
|
|
189
|
+
headers: redactHeaders(headers),
|
|
190
|
+
queryParameters: redactQueryParameters(args.queryParameters),
|
|
191
|
+
hasBody: requestBody != null,
|
|
192
|
+
};
|
|
193
|
+
logger.debug("Making HTTP request", metadata);
|
|
194
|
+
}
|
|
53
195
|
try {
|
|
54
196
|
const response = yield requestWithRetries(() => __awaiter(this, void 0, void 0, function* () {
|
|
55
|
-
return makeRequest(fetchFn, url, args.method,
|
|
197
|
+
return makeRequest(fetchFn, url, args.method, headers, requestBody, args.timeoutMs, args.abortSignal, args.withCredentials, args.duplex);
|
|
56
198
|
}), args.maxRetries);
|
|
57
199
|
if (response.status >= 200 && response.status < 400) {
|
|
200
|
+
if (logger.isDebug()) {
|
|
201
|
+
const metadata = {
|
|
202
|
+
method: args.method,
|
|
203
|
+
url: redactUrl(url),
|
|
204
|
+
statusCode: response.status,
|
|
205
|
+
responseHeaders: redactHeaders(Object.fromEntries(response.headers.entries())),
|
|
206
|
+
};
|
|
207
|
+
logger.debug("HTTP request succeeded", metadata);
|
|
208
|
+
}
|
|
58
209
|
return {
|
|
59
210
|
ok: true,
|
|
60
211
|
body: (yield getResponseBody(response, args.responseType)),
|
|
@@ -63,6 +214,15 @@ export function fetcherImpl(args) {
|
|
|
63
214
|
};
|
|
64
215
|
}
|
|
65
216
|
else {
|
|
217
|
+
if (logger.isError()) {
|
|
218
|
+
const metadata = {
|
|
219
|
+
method: args.method,
|
|
220
|
+
url: redactUrl(url),
|
|
221
|
+
statusCode: response.status,
|
|
222
|
+
responseHeaders: redactHeaders(Object.fromEntries(response.headers.entries())),
|
|
223
|
+
};
|
|
224
|
+
logger.error("HTTP request failed with error status", metadata);
|
|
225
|
+
}
|
|
66
226
|
return {
|
|
67
227
|
ok: false,
|
|
68
228
|
error: {
|
|
@@ -76,6 +236,13 @@ export function fetcherImpl(args) {
|
|
|
76
236
|
}
|
|
77
237
|
catch (error) {
|
|
78
238
|
if ((_c = args.abortSignal) === null || _c === void 0 ? void 0 : _c.aborted) {
|
|
239
|
+
if (logger.isError()) {
|
|
240
|
+
const metadata = {
|
|
241
|
+
method: args.method,
|
|
242
|
+
url: redactUrl(url),
|
|
243
|
+
};
|
|
244
|
+
logger.error("HTTP request was aborted", metadata);
|
|
245
|
+
}
|
|
79
246
|
return {
|
|
80
247
|
ok: false,
|
|
81
248
|
error: {
|
|
@@ -86,6 +253,14 @@ export function fetcherImpl(args) {
|
|
|
86
253
|
};
|
|
87
254
|
}
|
|
88
255
|
else if (error instanceof Error && error.name === "AbortError") {
|
|
256
|
+
if (logger.isError()) {
|
|
257
|
+
const metadata = {
|
|
258
|
+
method: args.method,
|
|
259
|
+
url: redactUrl(url),
|
|
260
|
+
timeoutMs: args.timeoutMs,
|
|
261
|
+
};
|
|
262
|
+
logger.error("HTTP request timed out", metadata);
|
|
263
|
+
}
|
|
89
264
|
return {
|
|
90
265
|
ok: false,
|
|
91
266
|
error: {
|
|
@@ -95,6 +270,14 @@ export function fetcherImpl(args) {
|
|
|
95
270
|
};
|
|
96
271
|
}
|
|
97
272
|
else if (error instanceof Error) {
|
|
273
|
+
if (logger.isError()) {
|
|
274
|
+
const metadata = {
|
|
275
|
+
method: args.method,
|
|
276
|
+
url: redactUrl(url),
|
|
277
|
+
errorMessage: error.message,
|
|
278
|
+
};
|
|
279
|
+
logger.error("HTTP request failed with error", metadata);
|
|
280
|
+
}
|
|
98
281
|
return {
|
|
99
282
|
ok: false,
|
|
100
283
|
error: {
|
|
@@ -104,6 +287,14 @@ export function fetcherImpl(args) {
|
|
|
104
287
|
rawResponse: unknownRawResponse,
|
|
105
288
|
};
|
|
106
289
|
}
|
|
290
|
+
if (logger.isError()) {
|
|
291
|
+
const metadata = {
|
|
292
|
+
method: args.method,
|
|
293
|
+
url: redactUrl(url),
|
|
294
|
+
error: toJson(error),
|
|
295
|
+
};
|
|
296
|
+
logger.error("HTTP request failed with unknown error", metadata);
|
|
297
|
+
}
|
|
107
298
|
return {
|
|
108
299
|
ok: false,
|
|
109
300
|
error: {
|
|
@@ -10,14 +10,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { anySignal, getTimeoutSignal } from "./signals.mjs";
|
|
11
11
|
export const makeRequest = (fetchFn, url, method, headers, requestBody, timeoutMs, abortSignal, withCredentials, duplex) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12
12
|
const signals = [];
|
|
13
|
-
// Add timeout signal
|
|
14
13
|
let timeoutAbortId;
|
|
15
14
|
if (timeoutMs != null) {
|
|
16
15
|
const { signal, abortId } = getTimeoutSignal(timeoutMs);
|
|
17
16
|
timeoutAbortId = abortId;
|
|
18
17
|
signals.push(signal);
|
|
19
18
|
}
|
|
20
|
-
// Add arbitrary signal
|
|
21
19
|
if (abortSignal != null) {
|
|
22
20
|
signals.push(abortSignal);
|
|
23
21
|
}
|
|
@@ -12,25 +12,20 @@ const MAX_RETRY_DELAY = 60000; // in milliseconds
|
|
|
12
12
|
const DEFAULT_MAX_RETRIES = 2;
|
|
13
13
|
const JITTER_FACTOR = 0.2; // 20% random jitter
|
|
14
14
|
function addPositiveJitter(delay) {
|
|
15
|
-
// Generate a random value between 0 and +JITTER_FACTOR
|
|
16
15
|
const jitterMultiplier = 1 + Math.random() * JITTER_FACTOR;
|
|
17
16
|
return delay * jitterMultiplier;
|
|
18
17
|
}
|
|
19
18
|
function addSymmetricJitter(delay) {
|
|
20
|
-
// Generate a random value in a JITTER_FACTOR-sized percentage range around delay
|
|
21
19
|
const jitterMultiplier = 1 + (Math.random() - 0.5) * JITTER_FACTOR;
|
|
22
20
|
return delay * jitterMultiplier;
|
|
23
21
|
}
|
|
24
22
|
function getRetryDelayFromHeaders(response, retryAttempt) {
|
|
25
|
-
// Check for Retry-After header first (RFC 7231), with no jitter
|
|
26
23
|
const retryAfter = response.headers.get("Retry-After");
|
|
27
24
|
if (retryAfter) {
|
|
28
|
-
// Parse as number of seconds...
|
|
29
25
|
const retryAfterSeconds = parseInt(retryAfter, 10);
|
|
30
26
|
if (!Number.isNaN(retryAfterSeconds) && retryAfterSeconds > 0) {
|
|
31
27
|
return Math.min(retryAfterSeconds * 1000, MAX_RETRY_DELAY);
|
|
32
28
|
}
|
|
33
|
-
// ...or as an HTTP date; both are valid
|
|
34
29
|
const retryAfterDate = new Date(retryAfter);
|
|
35
30
|
if (!Number.isNaN(retryAfterDate.getTime())) {
|
|
36
31
|
const delay = retryAfterDate.getTime() - Date.now();
|
|
@@ -39,19 +34,16 @@ function getRetryDelayFromHeaders(response, retryAttempt) {
|
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
}
|
|
42
|
-
// Then check for industry-standard X-RateLimit-Reset header, with positive jitter
|
|
43
37
|
const rateLimitReset = response.headers.get("X-RateLimit-Reset");
|
|
44
38
|
if (rateLimitReset) {
|
|
45
39
|
const resetTime = parseInt(rateLimitReset, 10);
|
|
46
40
|
if (!Number.isNaN(resetTime)) {
|
|
47
|
-
// Assume Unix timestamp in epoch seconds
|
|
48
41
|
const delay = resetTime * 1000 - Date.now();
|
|
49
42
|
if (delay > 0) {
|
|
50
43
|
return addPositiveJitter(Math.min(delay, MAX_RETRY_DELAY));
|
|
51
44
|
}
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
|
-
// Fall back to exponential backoff, with symmetric jitter
|
|
55
47
|
return addSymmetricJitter(Math.min(INITIAL_RETRY_DELAY * Math.pow(2, retryAttempt), MAX_RETRY_DELAY));
|
|
56
48
|
}
|
|
57
49
|
export function requestWithRetries(requestFn_1) {
|
|
@@ -59,7 +51,6 @@ export function requestWithRetries(requestFn_1) {
|
|
|
59
51
|
let response = yield requestFn();
|
|
60
52
|
for (let i = 0; i < maxRetries; ++i) {
|
|
61
53
|
if ([408, 429].includes(response.status) || response.status >= 500) {
|
|
62
|
-
// Get delay with appropriate jitter applied
|
|
63
54
|
const delay = getRetryDelayFromHeaders(response, i);
|
|
64
55
|
yield new Promise((resolve) => setTimeout(resolve, delay));
|
|
65
56
|
response = yield requestFn();
|
|
@@ -2,10 +2,4 @@ export declare function getTimeoutSignal(timeoutMs: number): {
|
|
|
2
2
|
signal: AbortSignal;
|
|
3
3
|
abortId: NodeJS.Timeout;
|
|
4
4
|
};
|
|
5
|
-
/**
|
|
6
|
-
* Returns an abort signal that is getting aborted when
|
|
7
|
-
* at least one of the specified abort signals is aborted.
|
|
8
|
-
*
|
|
9
|
-
* Requires at least node.js 18.
|
|
10
|
-
*/
|
|
11
5
|
export declare function anySignal(...args: AbortSignal[] | [AbortSignal[]]): AbortSignal;
|
|
@@ -4,26 +4,14 @@ export function getTimeoutSignal(timeoutMs) {
|
|
|
4
4
|
const abortId = setTimeout(() => controller.abort(TIMEOUT), timeoutMs);
|
|
5
5
|
return { signal: controller.signal, abortId };
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
8
|
-
* Returns an abort signal that is getting aborted when
|
|
9
|
-
* at least one of the specified abort signals is aborted.
|
|
10
|
-
*
|
|
11
|
-
* Requires at least node.js 18.
|
|
12
|
-
*/
|
|
13
7
|
export function anySignal(...args) {
|
|
14
|
-
// Allowing signals to be passed either as array
|
|
15
|
-
// of signals or as multiple arguments.
|
|
16
8
|
const signals = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args);
|
|
17
9
|
const controller = new AbortController();
|
|
18
10
|
for (const signal of signals) {
|
|
19
11
|
if (signal.aborted) {
|
|
20
|
-
// Exiting early if one of the signals
|
|
21
|
-
// is already aborted.
|
|
22
12
|
controller.abort(signal === null || signal === void 0 ? void 0 : signal.reason);
|
|
23
13
|
break;
|
|
24
14
|
}
|
|
25
|
-
// Listening for signals and removing the listeners
|
|
26
|
-
// when at least one symbol is aborted.
|
|
27
15
|
signal.addEventListener("abort", () => controller.abort(signal === null || signal === void 0 ? void 0 : signal.reason), {
|
|
28
16
|
signal: controller.signal,
|
|
29
17
|
});
|
package/dist/esm/core/index.mjs
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as logger from "./logger.mjs";
|
|
2
|
+
export declare namespace logging {
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for logger instances.
|
|
5
|
+
*/
|
|
6
|
+
type LogConfig = logger.LogConfig;
|
|
7
|
+
type LogLevel = logger.LogLevel;
|
|
8
|
+
const LogLevel: typeof logger.LogLevel;
|
|
9
|
+
type ILogger = logger.ILogger;
|
|
10
|
+
/**
|
|
11
|
+
* Console logger implementation that outputs to the console.
|
|
12
|
+
*/
|
|
13
|
+
type ConsoleLogger = logger.ConsoleLogger;
|
|
14
|
+
/**
|
|
15
|
+
* Console logger implementation that outputs to the console.
|
|
16
|
+
*/
|
|
17
|
+
const ConsoleLogger: typeof logger.ConsoleLogger;
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as logger from "./logger.mjs";
|
|
2
|
+
export var logging;
|
|
3
|
+
(function (logging) {
|
|
4
|
+
logging.LogLevel = logger.LogLevel;
|
|
5
|
+
/**
|
|
6
|
+
* Console logger implementation that outputs to the console.
|
|
7
|
+
*/
|
|
8
|
+
logging.ConsoleLogger = logger.ConsoleLogger;
|
|
9
|
+
})(logging || (logging = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logger.mjs";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./logger.mjs";
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export declare const LogLevel: {
|
|
2
|
+
readonly Debug: "debug";
|
|
3
|
+
readonly Info: "info";
|
|
4
|
+
readonly Warn: "warn";
|
|
5
|
+
readonly Error: "error";
|
|
6
|
+
};
|
|
7
|
+
export type LogLevel = (typeof LogLevel)[keyof typeof LogLevel];
|
|
8
|
+
export interface ILogger {
|
|
9
|
+
/**
|
|
10
|
+
* Logs a debug message.
|
|
11
|
+
* @param message - The message to log
|
|
12
|
+
* @param args - Additional arguments to log
|
|
13
|
+
*/
|
|
14
|
+
debug(message: string, ...args: unknown[]): void;
|
|
15
|
+
/**
|
|
16
|
+
* Logs an info message.
|
|
17
|
+
* @param message - The message to log
|
|
18
|
+
* @param args - Additional arguments to log
|
|
19
|
+
*/
|
|
20
|
+
info(message: string, ...args: unknown[]): void;
|
|
21
|
+
/**
|
|
22
|
+
* Logs a warning message.
|
|
23
|
+
* @param message - The message to log
|
|
24
|
+
* @param args - Additional arguments to log
|
|
25
|
+
*/
|
|
26
|
+
warn(message: string, ...args: unknown[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Logs an error message.
|
|
29
|
+
* @param message - The message to log
|
|
30
|
+
* @param args - Additional arguments to log
|
|
31
|
+
*/
|
|
32
|
+
error(message: string, ...args: unknown[]): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Configuration for logger initialization.
|
|
36
|
+
*/
|
|
37
|
+
export interface LogConfig {
|
|
38
|
+
/**
|
|
39
|
+
* Minimum log level to output.
|
|
40
|
+
* @default LogLevel.Info
|
|
41
|
+
*/
|
|
42
|
+
level?: LogLevel;
|
|
43
|
+
/**
|
|
44
|
+
* Logger implementation to use.
|
|
45
|
+
* @default new ConsoleLogger()
|
|
46
|
+
*/
|
|
47
|
+
logger?: ILogger;
|
|
48
|
+
/**
|
|
49
|
+
* Whether logging should be silenced.
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
silent?: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Default console-based logger implementation.
|
|
56
|
+
*/
|
|
57
|
+
export declare class ConsoleLogger implements ILogger {
|
|
58
|
+
debug(message: string, ...args: unknown[]): void;
|
|
59
|
+
info(message: string, ...args: unknown[]): void;
|
|
60
|
+
warn(message: string, ...args: unknown[]): void;
|
|
61
|
+
error(message: string, ...args: unknown[]): void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Logger class that provides level-based logging functionality.
|
|
65
|
+
*/
|
|
66
|
+
export declare class Logger {
|
|
67
|
+
private readonly level;
|
|
68
|
+
private readonly logger;
|
|
69
|
+
private readonly silent;
|
|
70
|
+
/**
|
|
71
|
+
* Creates a new logger instance.
|
|
72
|
+
* @param config - Logger configuration
|
|
73
|
+
*/
|
|
74
|
+
constructor(config: Required<LogConfig>);
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a log level should be output based on configuration.
|
|
77
|
+
* @param level - The log level to check
|
|
78
|
+
* @returns True if the level should be logged
|
|
79
|
+
*/
|
|
80
|
+
shouldLog(level: LogLevel): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Checks if debug logging is enabled.
|
|
83
|
+
* @returns True if debug logs should be output
|
|
84
|
+
*/
|
|
85
|
+
isDebug(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Logs a debug message if debug logging is enabled.
|
|
88
|
+
* @param message - The message to log
|
|
89
|
+
* @param args - Additional arguments to log
|
|
90
|
+
*/
|
|
91
|
+
debug(message: string, ...args: unknown[]): void;
|
|
92
|
+
/**
|
|
93
|
+
* Checks if info logging is enabled.
|
|
94
|
+
* @returns True if info logs should be output
|
|
95
|
+
*/
|
|
96
|
+
isInfo(): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Logs an info message if info logging is enabled.
|
|
99
|
+
* @param message - The message to log
|
|
100
|
+
* @param args - Additional arguments to log
|
|
101
|
+
*/
|
|
102
|
+
info(message: string, ...args: unknown[]): void;
|
|
103
|
+
/**
|
|
104
|
+
* Checks if warning logging is enabled.
|
|
105
|
+
* @returns True if warning logs should be output
|
|
106
|
+
*/
|
|
107
|
+
isWarn(): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Logs a warning message if warning logging is enabled.
|
|
110
|
+
* @param message - The message to log
|
|
111
|
+
* @param args - Additional arguments to log
|
|
112
|
+
*/
|
|
113
|
+
warn(message: string, ...args: unknown[]): void;
|
|
114
|
+
/**
|
|
115
|
+
* Checks if error logging is enabled.
|
|
116
|
+
* @returns True if error logs should be output
|
|
117
|
+
*/
|
|
118
|
+
isError(): boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Logs an error message if error logging is enabled.
|
|
121
|
+
* @param message - The message to log
|
|
122
|
+
* @param args - Additional arguments to log
|
|
123
|
+
*/
|
|
124
|
+
error(message: string, ...args: unknown[]): void;
|
|
125
|
+
}
|
|
126
|
+
export declare function createLogger(config?: LogConfig | Logger): Logger;
|