@bedolla/enriweb 0.1.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.
Files changed (35) hide show
  1. package/LICENSE +619 -0
  2. package/README.md +182 -0
  3. package/dist/client/EnriProxyClient.d.ts +271 -0
  4. package/dist/client/EnriProxyClient.d.ts.map +1 -0
  5. package/dist/client/EnriProxyClient.js +221 -0
  6. package/dist/client/EnriProxyClient.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +148 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/package-info.d.ts +8 -0
  12. package/dist/package-info.d.ts.map +1 -0
  13. package/dist/package-info.js +28 -0
  14. package/dist/package-info.js.map +1 -0
  15. package/dist/server/EnriWebServer.d.ts +70 -0
  16. package/dist/server/EnriWebServer.d.ts.map +1 -0
  17. package/dist/server/EnriWebServer.js +218 -0
  18. package/dist/server/EnriWebServer.js.map +1 -0
  19. package/dist/shared/validation.d.ts +54 -0
  20. package/dist/shared/validation.d.ts.map +1 -0
  21. package/dist/shared/validation.js +112 -0
  22. package/dist/shared/validation.js.map +1 -0
  23. package/dist/tools/WebFetchTool.d.ts +232 -0
  24. package/dist/tools/WebFetchTool.d.ts.map +1 -0
  25. package/dist/tools/WebFetchTool.js +429 -0
  26. package/dist/tools/WebFetchTool.js.map +1 -0
  27. package/dist/tools/WebSearchRegistryVerifier.d.ts +323 -0
  28. package/dist/tools/WebSearchRegistryVerifier.d.ts.map +1 -0
  29. package/dist/tools/WebSearchRegistryVerifier.js +890 -0
  30. package/dist/tools/WebSearchRegistryVerifier.js.map +1 -0
  31. package/dist/tools/WebSearchTool.d.ts +132 -0
  32. package/dist/tools/WebSearchTool.d.ts.map +1 -0
  33. package/dist/tools/WebSearchTool.js +101 -0
  34. package/dist/tools/WebSearchTool.js.map +1 -0
  35. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,182 @@
1
+ # EnriWeb
2
+
3
+ EnriWeb is a **Model Context Protocol (MCP)** server over `stdio` that exposes **web search** and **URL fetching** tools by delegating execution to **EnriProxy**.
4
+
5
+ If your MCP client can call MCP tools, it can do web search / fetch in a consistent way without implementing provider-specific scraping logic.
6
+
7
+ ## What this project is
8
+
9
+ - An MCP server process your MCP host launches (OpenCode, Claude Code, Codex, etc.)
10
+ - A thin client for EnriProxy (input validation + structured output)
11
+
12
+ ## Requirements
13
+
14
+ - Node.js `>= 22` (recommended: Node 24 LTS)
15
+ - A reachable EnriProxy server with:
16
+ - `POST /v1/tools/web_search`
17
+ - `POST /v1/tools/web_fetch`
18
+ - An EnriProxy API key (configured on the EnriProxy side)
19
+
20
+ ## Install
21
+
22
+ ```powershell
23
+ # Global install
24
+ npm install -g @bedolla/enriweb
25
+
26
+ # Or run without installing
27
+ npx -y @bedolla/enriweb@latest --help
28
+ ```
29
+
30
+ ## Build
31
+
32
+ ```powershell
33
+ npm install
34
+ npm run typecheck
35
+ npm run build
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ### 1) Configure your MCP host
41
+
42
+ EnriWeb runs as an MCP server over `stdio`. Your MCP host is responsible for launching the process.
43
+
44
+ Example: global install
45
+
46
+ ```jsonc
47
+ {
48
+ "EnriWeb": {
49
+ "type": "stdio",
50
+ "command": "enriweb",
51
+ "args": [],
52
+ "env": {
53
+ "ENRIPROXY_URL": "http://127.0.0.1:8787",
54
+ "ENRIPROXY_API_KEY": "YOUR_ENRIPROXY_API_KEY"
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ Example: no install (always uses whatever npm currently tags as `latest`)
61
+
62
+ ```jsonc
63
+ {
64
+ "EnriWeb": {
65
+ "type": "stdio",
66
+ "command": "npx",
67
+ "args": ["-y", "@bedolla/enriweb@latest"],
68
+ "env": {
69
+ "ENRIPROXY_URL": "http://127.0.0.1:8787",
70
+ "ENRIPROXY_API_KEY": "YOUR_ENRIPROXY_API_KEY"
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ <details>
77
+ <summary>Use a local dev checkout</summary>
78
+
79
+ ```jsonc
80
+ {
81
+ "EnriWeb": {
82
+ "type": "stdio",
83
+ "command": "node",
84
+ "args": ["C:\\\\Users\\\\Administrator\\\\Projects\\\\EnriWeb\\\\dist\\\\index.js"],
85
+ "env": {
86
+ "ENRIPROXY_URL": "http://127.0.0.1:8787",
87
+ "ENRIPROXY_API_KEY": "YOUR_ENRIPROXY_API_KEY"
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ </details>
94
+
95
+ ## Configuration
96
+
97
+ EnriWeb is configured via environment variables:
98
+
99
+ - `ENRIPROXY_URL` (`string`, optional, default: `http://127.0.0.1:8787`)
100
+ - `ENRIPROXY_API_KEY` (`string`, required)
101
+ - `ENRIWEB_TIMEOUT_MS` (`string`, optional, default: `60000`)
102
+ - Parsed as an integer (milliseconds).
103
+ - `ENRIWEB_WEB_FETCH_DEFAULT_MAX_CHARS` (`string`, optional, default: `200000`)
104
+ - Parsed as an integer.
105
+ - `ENRIWEB_GITHUB_TOKEN` (`string`, optional)
106
+ - Used for GitHub API enrichment to improve rate limits.
107
+
108
+ ## MCP tools
109
+
110
+ EnriWeb exposes these MCP tools:
111
+
112
+ - `web_search`
113
+ - `web_fetch`
114
+
115
+ <details>
116
+ <summary>Tool inputs (option-by-option)</summary>
117
+
118
+ General notes:
119
+
120
+ - All tools accept a single JSON object as their input (the MCP `arguments` for that tool).
121
+ - EnriWeb returns both:
122
+ - a short human-readable preview (`content`)
123
+ - the full result payload (`structuredContent`)
124
+
125
+ ---
126
+
127
+ ### `web_search`
128
+
129
+ Search the web via EnriProxy.
130
+
131
+ Inputs:
132
+
133
+ - `query` (`string`, required): search query string.
134
+ - `max_results` (`number`, optional)
135
+ - Must be `>= 1`.
136
+ - If omitted, EnriProxy uses its configured default.
137
+ - The upper limit is enforced server-side (EnriWeb does not hardcode a max).
138
+ - `recency` (`string`, optional, default: `noLimit`)
139
+ - One of: `oneDay` | `oneWeek` | `oneMonth` | `oneYear` | `noLimit`
140
+ - `allowed_domains` (`string[]`, optional): allowlist of domains to include.
141
+ - `blocked_domains` (`string[]`, optional): blocklist of domains to exclude.
142
+ - `search_prompt` (`string`, optional): extra context to refine the search intent.
143
+
144
+ Example `arguments` object:
145
+
146
+ ```jsonc
147
+ {
148
+ "query": "qdrant docker compose autostart systemd",
149
+ "max_results": 10,
150
+ "recency": "oneMonth"
151
+ }
152
+ ```
153
+
154
+ ---
155
+
156
+ ### `web_fetch`
157
+
158
+ Fetch and read content from a URL via EnriProxy.
159
+
160
+ Inputs:
161
+
162
+ - `url` (`string`, required unless `cursor` is provided): full URL (`http://` or `https://`).
163
+ - `cursor` (`string`, optional): opaque cursor returned by a previous `web_fetch` call.
164
+ - `offset` (`number`, optional, default: `0`): cursor read offset in characters.
165
+ - `limit` (`number`, optional): cursor read limit in characters (default: `max_chars`).
166
+ - `prompt` (`string`, optional): extraction hint (what to focus on).
167
+ - `max_chars` (`number`, optional): maximum content length (default: `ENRIWEB_WEB_FETCH_DEFAULT_MAX_CHARS`).
168
+
169
+ Notes:
170
+
171
+ - If the response includes a `cursor`, you can page through the captured content by calling `web_fetch` again with `cursor` + `offset` + `limit`.
172
+
173
+ Example `arguments` object:
174
+
175
+ ```jsonc
176
+ {
177
+ "url": "https://example.com/docs",
178
+ "max_chars": 200000
179
+ }
180
+ ```
181
+
182
+ </details>
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Connection configuration for {@link EnriProxyClient}.
3
+ */
4
+ export interface EnriProxyClientConfig {
5
+ /**
6
+ * EnriProxy base URL (e.g., https://proxy.example.com).
7
+ */
8
+ readonly baseUrl: string;
9
+ /**
10
+ * EnriProxy API key (sent as Authorization: Bearer ...).
11
+ */
12
+ readonly apiKey: string;
13
+ /**
14
+ * Default request timeout in milliseconds.
15
+ */
16
+ readonly timeoutMs: number;
17
+ }
18
+ /**
19
+ * Web search request parameters.
20
+ */
21
+ export interface WebSearchRequest {
22
+ /**
23
+ * Search query string.
24
+ */
25
+ readonly query: string;
26
+ /**
27
+ * Maximum number of results.
28
+ */
29
+ readonly maxResults?: number;
30
+ /**
31
+ * Recency filter.
32
+ */
33
+ readonly recency?: string;
34
+ /**
35
+ * Allowed domains filter.
36
+ */
37
+ readonly allowedDomains?: string[];
38
+ /**
39
+ * Blocked domains filter.
40
+ */
41
+ readonly blockedDomains?: string[];
42
+ /**
43
+ * Optional search prompt context.
44
+ */
45
+ readonly searchPrompt?: string;
46
+ }
47
+ /**
48
+ * Web search result entry.
49
+ */
50
+ export interface WebSearchResultEntry {
51
+ /**
52
+ * Result URL.
53
+ */
54
+ readonly url: string;
55
+ /**
56
+ * Result title.
57
+ */
58
+ readonly title?: string;
59
+ /**
60
+ * Result snippet.
61
+ */
62
+ readonly snippet?: string;
63
+ /**
64
+ * Optional publication date.
65
+ */
66
+ readonly published_at?: string;
67
+ }
68
+ /**
69
+ * Web search response.
70
+ */
71
+ export interface WebSearchResponse {
72
+ /**
73
+ * Search results array.
74
+ */
75
+ readonly results: WebSearchResultEntry[];
76
+ /**
77
+ * Number of results returned.
78
+ */
79
+ readonly count: number;
80
+ }
81
+ /**
82
+ * Web fetch request parameters.
83
+ */
84
+ export interface WebFetchUrlRequest {
85
+ /**
86
+ * URL to fetch.
87
+ */
88
+ readonly url: string;
89
+ /**
90
+ * Optional extraction prompt.
91
+ */
92
+ readonly prompt?: string;
93
+ /**
94
+ * Maximum content length in characters.
95
+ */
96
+ readonly maxChars?: number;
97
+ }
98
+ /**
99
+ * Web fetch cursor pagination parameters.
100
+ */
101
+ export interface WebFetchCursorRequest {
102
+ /**
103
+ * Cursor identifier returned by a previous fetch.
104
+ */
105
+ readonly cursor: string;
106
+ /**
107
+ * Offset in characters.
108
+ */
109
+ readonly offsetChars?: number;
110
+ /**
111
+ * Limit in characters.
112
+ */
113
+ readonly limitChars?: number;
114
+ /**
115
+ * Optional maximum content length in characters.
116
+ *
117
+ * @remarks
118
+ * When reading a cursor slice, EnriProxy may treat `maxChars` as a fallback
119
+ * limit if `limitChars` is not provided.
120
+ */
121
+ readonly maxChars?: number;
122
+ }
123
+ /**
124
+ * Web fetch request union.
125
+ */
126
+ export type WebFetchRequest = WebFetchUrlRequest | WebFetchCursorRequest;
127
+ /**
128
+ * Web fetch response.
129
+ */
130
+ export interface WebFetchResponse {
131
+ /**
132
+ * Fetched content.
133
+ */
134
+ readonly content: string;
135
+ /**
136
+ * HTTP status code.
137
+ */
138
+ readonly status: number;
139
+ /**
140
+ * Content type from the response.
141
+ */
142
+ readonly content_type: string;
143
+ /**
144
+ * Whether content was truncated.
145
+ */
146
+ readonly truncated: boolean;
147
+ /**
148
+ * URL that was fetched (when available).
149
+ */
150
+ readonly url?: string;
151
+ /**
152
+ * Opaque cursor identifier for pagination (when content is truncated/reduced).
153
+ */
154
+ readonly cursor?: string;
155
+ /**
156
+ * Offset in characters (cursor reads).
157
+ */
158
+ readonly offset_chars?: number;
159
+ /**
160
+ * Limit in characters (cursor reads).
161
+ */
162
+ readonly limit_chars?: number;
163
+ /**
164
+ * Total captured characters available for this cursor.
165
+ */
166
+ readonly total_chars?: number;
167
+ /**
168
+ * Whether more content exists beyond this slice.
169
+ */
170
+ readonly has_more?: boolean;
171
+ /**
172
+ * Whether the response content was reduced (excerpt pack).
173
+ */
174
+ readonly reduced?: boolean;
175
+ /**
176
+ * Whether the upstream fetch was truncated (download/capture limits).
177
+ */
178
+ readonly fetched_truncated?: boolean;
179
+ }
180
+ /**
181
+ * Error thrown when EnriProxy returns a non-2xx HTTP response.
182
+ */
183
+ export declare class EnriProxyHttpError extends Error {
184
+ /**
185
+ * HTTP status code returned by the server.
186
+ */
187
+ readonly status: number;
188
+ /**
189
+ * Response headers returned by the server.
190
+ */
191
+ readonly headers: Record<string, string | string[] | undefined>;
192
+ /**
193
+ * Response body returned by the server (best-effort UTF-8).
194
+ */
195
+ readonly body: string;
196
+ /**
197
+ * Creates a new {@link EnriProxyHttpError}.
198
+ *
199
+ * @param message - Error message
200
+ * @param status - HTTP status code
201
+ * @param headers - Response headers
202
+ * @param body - Response body
203
+ */
204
+ constructor(message: string, status: number, headers: Record<string, string | string[] | undefined>, body: string);
205
+ }
206
+ /**
207
+ * Minimal client for EnriProxy web tool endpoints.
208
+ */
209
+ export declare class EnriProxyClient {
210
+ /**
211
+ * EnriProxy base URL.
212
+ */
213
+ private readonly baseUrl;
214
+ /**
215
+ * API key for Authorization header.
216
+ */
217
+ private readonly apiKey;
218
+ /**
219
+ * Default timeout for requests.
220
+ */
221
+ private readonly timeoutMs;
222
+ /**
223
+ * Creates a new {@link EnriProxyClient}.
224
+ *
225
+ * @param config - Client configuration
226
+ */
227
+ constructor(config: EnriProxyClientConfig);
228
+ /**
229
+ * Executes a web search via EnriProxy.
230
+ *
231
+ * @param params - Search parameters
232
+ * @returns Search response
233
+ */
234
+ webSearch(params: WebSearchRequest): Promise<WebSearchResponse>;
235
+ /**
236
+ * Executes a web fetch via EnriProxy.
237
+ *
238
+ * @param params - Fetch parameters
239
+ * @returns Fetch response
240
+ */
241
+ webFetch(params: WebFetchRequest): Promise<WebFetchResponse>;
242
+ /**
243
+ * Builds an absolute URL relative to the configured base URL.
244
+ *
245
+ * @param pathname - Pathname to append
246
+ * @returns URL instance
247
+ */
248
+ private buildUrl;
249
+ /**
250
+ * Sends a JSON request and returns the response.
251
+ *
252
+ * @param method - HTTP method
253
+ * @param url - Target URL
254
+ * @param jsonBody - JSON payload
255
+ * @param timeoutMs - Timeout in milliseconds
256
+ * @returns HTTP result
257
+ */
258
+ private requestJson;
259
+ /**
260
+ * Sends an HTTP request with optional headers and body.
261
+ *
262
+ * @param method - HTTP method
263
+ * @param url - Target URL
264
+ * @param headers - Request headers
265
+ * @param body - Request body
266
+ * @param timeoutMs - Timeout in milliseconds
267
+ * @returns HTTP result
268
+ */
269
+ private requestRaw;
270
+ }
271
+ //# sourceMappingURL=EnriProxyClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnriProxyClient.d.ts","sourceRoot":"","sources":["../../src/client/EnriProxyClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * ENRIPROXY CLIENT
3
+ *
4
+ * Minimal HTTP client for EnriProxy web tool endpoints:
5
+ * - POST /v1/tools/web_search
6
+ * - POST /v1/tools/web_fetch
7
+ *
8
+ * @module client/EnriProxyClient
9
+ */
10
+ import { request as httpRequest } from "node:http";
11
+ import { request as httpsRequest } from "node:https";
12
+ import { URL } from "node:url";
13
+ /**
14
+ * Error thrown when EnriProxy returns a non-2xx HTTP response.
15
+ */
16
+ export class EnriProxyHttpError extends Error {
17
+ /**
18
+ * HTTP status code returned by the server.
19
+ */
20
+ status;
21
+ /**
22
+ * Response headers returned by the server.
23
+ */
24
+ headers;
25
+ /**
26
+ * Response body returned by the server (best-effort UTF-8).
27
+ */
28
+ body;
29
+ /**
30
+ * Creates a new {@link EnriProxyHttpError}.
31
+ *
32
+ * @param message - Error message
33
+ * @param status - HTTP status code
34
+ * @param headers - Response headers
35
+ * @param body - Response body
36
+ */
37
+ constructor(message, status, headers, body) {
38
+ super(message);
39
+ this.name = "EnriProxyHttpError";
40
+ this.status = status;
41
+ this.headers = headers;
42
+ this.body = body;
43
+ }
44
+ }
45
+ /**
46
+ * Minimal client for EnriProxy web tool endpoints.
47
+ */
48
+ export class EnriProxyClient {
49
+ /**
50
+ * EnriProxy base URL.
51
+ */
52
+ baseUrl;
53
+ /**
54
+ * API key for Authorization header.
55
+ */
56
+ apiKey;
57
+ /**
58
+ * Default timeout for requests.
59
+ */
60
+ timeoutMs;
61
+ /**
62
+ * Creates a new {@link EnriProxyClient}.
63
+ *
64
+ * @param config - Client configuration
65
+ */
66
+ constructor(config) {
67
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
68
+ this.apiKey = config.apiKey;
69
+ this.timeoutMs = config.timeoutMs;
70
+ }
71
+ /**
72
+ * Executes a web search via EnriProxy.
73
+ *
74
+ * @param params - Search parameters
75
+ * @returns Search response
76
+ */
77
+ async webSearch(params) {
78
+ const url = this.buildUrl("/v1/tools/web_search");
79
+ const payload = {
80
+ query: params.query
81
+ };
82
+ if (typeof params.maxResults === "number") {
83
+ payload["max_results"] = params.maxResults;
84
+ }
85
+ if (typeof params.recency === "string" && params.recency.trim()) {
86
+ payload["recency"] = params.recency.trim();
87
+ }
88
+ if (Array.isArray(params.allowedDomains) && params.allowedDomains.length > 0) {
89
+ payload["allowed_domains"] = params.allowedDomains;
90
+ }
91
+ if (Array.isArray(params.blockedDomains) && params.blockedDomains.length > 0) {
92
+ payload["blocked_domains"] = params.blockedDomains;
93
+ }
94
+ if (typeof params.searchPrompt === "string" && params.searchPrompt.trim()) {
95
+ payload["search_prompt"] = params.searchPrompt.trim();
96
+ }
97
+ const result = await this.requestJson("POST", url, payload, this.timeoutMs);
98
+ if (result.status < 200 || result.status >= 300) {
99
+ throw new EnriProxyHttpError(`Web search failed (HTTP ${result.status}).`, result.status, result.headers, result.body);
100
+ }
101
+ return JSON.parse(result.body);
102
+ }
103
+ /**
104
+ * Executes a web fetch via EnriProxy.
105
+ *
106
+ * @param params - Fetch parameters
107
+ * @returns Fetch response
108
+ */
109
+ async webFetch(params) {
110
+ const url = this.buildUrl("/v1/tools/web_fetch");
111
+ const payload = {};
112
+ if ("cursor" in params) {
113
+ const cursor = params.cursor.trim();
114
+ if (!cursor) {
115
+ throw new Error("webFetch requires a non-empty cursor.");
116
+ }
117
+ payload["cursor"] = cursor;
118
+ if (typeof params.offsetChars === "number" && Number.isFinite(params.offsetChars)) {
119
+ payload["offset_chars"] = Math.max(0, Math.trunc(params.offsetChars));
120
+ }
121
+ if (typeof params.limitChars === "number" && Number.isFinite(params.limitChars)) {
122
+ payload["limit_chars"] = Math.max(1, Math.trunc(params.limitChars));
123
+ }
124
+ if (typeof params.maxChars === "number" && Number.isFinite(params.maxChars)) {
125
+ payload["max_chars"] = Math.max(1, Math.trunc(params.maxChars));
126
+ }
127
+ }
128
+ else {
129
+ payload["url"] = params.url;
130
+ if (typeof params.prompt === "string" && params.prompt.trim()) {
131
+ payload["prompt"] = params.prompt.trim();
132
+ }
133
+ if (typeof params.maxChars === "number") {
134
+ payload["max_chars"] = params.maxChars;
135
+ }
136
+ }
137
+ const result = await this.requestJson("POST", url, payload, this.timeoutMs);
138
+ if (result.status < 200 || result.status >= 300) {
139
+ throw new EnriProxyHttpError(`Web fetch failed (HTTP ${result.status}).`, result.status, result.headers, result.body);
140
+ }
141
+ return JSON.parse(result.body);
142
+ }
143
+ /**
144
+ * Builds an absolute URL relative to the configured base URL.
145
+ *
146
+ * @param pathname - Pathname to append
147
+ * @returns URL instance
148
+ */
149
+ buildUrl(pathname) {
150
+ return new URL(pathname, this.baseUrl);
151
+ }
152
+ /**
153
+ * Sends a JSON request and returns the response.
154
+ *
155
+ * @param method - HTTP method
156
+ * @param url - Target URL
157
+ * @param jsonBody - JSON payload
158
+ * @param timeoutMs - Timeout in milliseconds
159
+ * @returns HTTP result
160
+ */
161
+ async requestJson(method, url, jsonBody, timeoutMs) {
162
+ const body = JSON.stringify(jsonBody);
163
+ const headers = {
164
+ "Content-Type": "application/json",
165
+ "Content-Length": String(Buffer.byteLength(body))
166
+ };
167
+ return this.requestRaw(method, url, headers, Buffer.from(body, "utf8"), timeoutMs);
168
+ }
169
+ /**
170
+ * Sends an HTTP request with optional headers and body.
171
+ *
172
+ * @param method - HTTP method
173
+ * @param url - Target URL
174
+ * @param headers - Request headers
175
+ * @param body - Request body
176
+ * @param timeoutMs - Timeout in milliseconds
177
+ * @returns HTTP result
178
+ */
179
+ async requestRaw(method, url, headers, body, timeoutMs) {
180
+ const isHttps = url.protocol === "https:";
181
+ const reqFn = isHttps ? httpsRequest : httpRequest;
182
+ const requestHeaders = {
183
+ Authorization: `Bearer ${this.apiKey}`,
184
+ ...(headers ?? {})
185
+ };
186
+ return await new Promise((resolve, reject) => {
187
+ const req = reqFn(url, {
188
+ method,
189
+ headers: requestHeaders
190
+ }, (res) => {
191
+ const chunks = [];
192
+ let received = 0;
193
+ const maxResponseBytes = 20 * 1024 * 1024;
194
+ res.on("data", (chunk) => {
195
+ received += chunk.length;
196
+ if (received > maxResponseBytes) {
197
+ req.destroy(new Error("Response exceeded maximum allowed size."));
198
+ return;
199
+ }
200
+ chunks.push(chunk);
201
+ });
202
+ res.on("end", () => {
203
+ resolve({
204
+ status: res.statusCode ?? 0,
205
+ headers: res.headers,
206
+ body: Buffer.concat(chunks).toString("utf8")
207
+ });
208
+ });
209
+ });
210
+ req.on("error", (error) => reject(error));
211
+ req.setTimeout(timeoutMs, () => {
212
+ req.destroy(new Error(`Request timed out after ${timeoutMs}ms`));
213
+ });
214
+ if (body && body.length > 0) {
215
+ req.write(body);
216
+ }
217
+ req.end();
218
+ });
219
+ }
220
+ }
221
+ //# sourceMappingURL=EnriProxyClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnriProxyClient.js","sourceRoot":"","sources":["../../src/client/EnriProxyClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}