@j0hanz/superfetch 1.0.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 +327 -0
- package/dist/config/index.d.ts +30 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +42 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors/app-error.d.ts +71 -0
- package/dist/errors/app-error.d.ts.map +1 -0
- package/dist/errors/app-error.js +103 -0
- package/dist/errors/app-error.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +179 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +7 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +37 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/rate-limiter.d.ts +33 -0
- package/dist/middleware/rate-limiter.d.ts.map +1 -0
- package/dist/middleware/rate-limiter.js +100 -0
- package/dist/middleware/rate-limiter.js.map +1 -0
- package/dist/prompts/index.d.ts +6 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +81 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +6 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +44 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +39 -0
- package/dist/server.js.map +1 -0
- package/dist/services/cache.d.ts +16 -0
- package/dist/services/cache.d.ts.map +1 -0
- package/dist/services/cache.js +63 -0
- package/dist/services/cache.js.map +1 -0
- package/dist/services/cache.service.d.ts +52 -0
- package/dist/services/cache.service.d.ts.map +1 -0
- package/dist/services/cache.service.js +113 -0
- package/dist/services/cache.service.js.map +1 -0
- package/dist/services/extractor.d.ts +32 -0
- package/dist/services/extractor.d.ts.map +1 -0
- package/dist/services/extractor.js +97 -0
- package/dist/services/extractor.js.map +1 -0
- package/dist/services/extractor.service.d.ts +18 -0
- package/dist/services/extractor.service.d.ts.map +1 -0
- package/dist/services/extractor.service.js +75 -0
- package/dist/services/extractor.service.js.map +1 -0
- package/dist/services/fetcher.d.ts +9 -0
- package/dist/services/fetcher.d.ts.map +1 -0
- package/dist/services/fetcher.js +100 -0
- package/dist/services/fetcher.js.map +1 -0
- package/dist/services/fetcher.service.d.ts +18 -0
- package/dist/services/fetcher.service.d.ts.map +1 -0
- package/dist/services/fetcher.service.js +122 -0
- package/dist/services/fetcher.service.js.map +1 -0
- package/dist/services/logger.d.ts +5 -0
- package/dist/services/logger.d.ts.map +1 -0
- package/dist/services/logger.js +48 -0
- package/dist/services/logger.js.map +1 -0
- package/dist/services/logger.service.d.ts +5 -0
- package/dist/services/logger.service.d.ts.map +1 -0
- package/dist/services/logger.service.js +57 -0
- package/dist/services/logger.service.js.map +1 -0
- package/dist/services/parser.d.ts +6 -0
- package/dist/services/parser.d.ts.map +1 -0
- package/dist/services/parser.js +152 -0
- package/dist/services/parser.js.map +1 -0
- package/dist/services/parser.service.d.ts +42 -0
- package/dist/services/parser.service.d.ts.map +1 -0
- package/dist/services/parser.service.js +209 -0
- package/dist/services/parser.service.js.map +1 -0
- package/dist/tools/handlers/fetch-links.tool.d.ts +20 -0
- package/dist/tools/handlers/fetch-links.tool.d.ts.map +1 -0
- package/dist/tools/handlers/fetch-links.tool.js +91 -0
- package/dist/tools/handlers/fetch-links.tool.js.map +1 -0
- package/dist/tools/handlers/fetch-markdown.tool.d.ts +17 -0
- package/dist/tools/handlers/fetch-markdown.tool.d.ts.map +1 -0
- package/dist/tools/handlers/fetch-markdown.tool.js +99 -0
- package/dist/tools/handlers/fetch-markdown.tool.js.map +1 -0
- package/dist/tools/handlers/fetch-url.tool.d.ts +17 -0
- package/dist/tools/handlers/fetch-url.tool.d.ts.map +1 -0
- package/dist/tools/handlers/fetch-url.tool.js +103 -0
- package/dist/tools/handlers/fetch-url.tool.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +83 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/transformers/jsonl.transformer.d.ts +4 -0
- package/dist/transformers/jsonl.transformer.d.ts.map +1 -0
- package/dist/transformers/jsonl.transformer.js +42 -0
- package/dist/transformers/jsonl.transformer.js.map +1 -0
- package/dist/transformers/markdown.transformer.d.ts +4 -0
- package/dist/transformers/markdown.transformer.d.ts.map +1 -0
- package/dist/transformers/markdown.transformer.js +104 -0
- package/dist/transformers/markdown.transformer.js.map +1 -0
- package/dist/types/content.types.d.ts +63 -0
- package/dist/types/content.types.d.ts.map +1 -0
- package/dist/types/content.types.js +2 -0
- package/dist/types/content.types.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/schemas.d.ts +22 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/schemas.js +5 -0
- package/dist/types/schemas.js.map +1 -0
- package/dist/utils/sanitizer.d.ts +9 -0
- package/dist/utils/sanitizer.d.ts.map +1 -0
- package/dist/utils/sanitizer.js +19 -0
- package/dist/utils/sanitizer.js.map +1 -0
- package/dist/utils/url-validator.d.ts +10 -0
- package/dist/utils/url-validator.d.ts.map +1 -0
- package/dist/utils/url-validator.js +69 -0
- package/dist/utils/url-validator.js.map +1 -0
- package/package.json +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# 🚀 superFetch
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@j0hanz/superfetch)[](LICENSE)[](https://nodejs.org/)[](https://www.typescriptlang.org/)[](https://modelcontextprotocol.io/)
|
|
4
|
+
|
|
5
|
+
A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that fetches, extracts, and transforms web content into AI-optimized formats using Mozilla Readability.
|
|
6
|
+
|
|
7
|
+
[Quick Start](#quick-start) · [Tools](#available-tools) · [Configuration](#configuration) · [Contributing](#contributing)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
> [!CAUTION]
|
|
12
|
+
> This server can access URLs on behalf of AI assistants. Built-in SSRF protection blocks private IP ranges and cloud metadata endpoints, but exercise caution when deploying in sensitive environments.
|
|
13
|
+
|
|
14
|
+
## ✨ Features
|
|
15
|
+
|
|
16
|
+
| Feature | Description |
|
|
17
|
+
| ------------------------- | ------------------------------------------------------------- |
|
|
18
|
+
| 🧠 **Smart Extraction** | Mozilla Readability removes ads, navigation, and boilerplate |
|
|
19
|
+
| 📄 **Multiple Formats** | JSONL semantic blocks or clean Markdown with YAML frontmatter |
|
|
20
|
+
| 🔗 **Link Discovery** | Extract and classify internal/external links |
|
|
21
|
+
| ⚡ **Built-in Caching** | Configurable TTL and max entries |
|
|
22
|
+
| 🛡️ **Security First** | SSRF protection, URL validation, header sanitization |
|
|
23
|
+
| 🔄 **Resilient Fetching** | Exponential backoff with jitter |
|
|
24
|
+
| 📊 **Monitoring** | Stats resource for cache performance and health |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Add superFetch to your MCP client configuration — no installation required!
|
|
31
|
+
|
|
32
|
+
### Claude Desktop
|
|
33
|
+
|
|
34
|
+
Add to your `claude_desktop_config.json`:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"superFetch": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "@j0hanz/superfetch@latest", "--stdio"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### VS Code
|
|
48
|
+
|
|
49
|
+
Add to `.vscode/mcp.json` in your workspace:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"servers": {
|
|
54
|
+
"superFetch": {
|
|
55
|
+
"command": "npx",
|
|
56
|
+
"args": ["-y", "@j0hanz/superfetch@latest", "--stdio"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### With Environment Variables
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"servers": {
|
|
67
|
+
"superFetch": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["-y", "@j0hanz/superfetch@latest", "--stdio"],
|
|
70
|
+
"env": {
|
|
71
|
+
"CACHE_TTL": "7200",
|
|
72
|
+
"LOG_LEVEL": "debug"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Installation (Alternative)
|
|
82
|
+
|
|
83
|
+
### Global Installation
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install -g @j0hanz/superfetch
|
|
87
|
+
|
|
88
|
+
# Run in stdio mode
|
|
89
|
+
superfetch --stdio
|
|
90
|
+
|
|
91
|
+
# Run HTTP server
|
|
92
|
+
superfetch
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### From Source
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
git clone https://github.com/j0hanz/super-fetch-mcp-server.git
|
|
99
|
+
cd super-fetch-mcp-server
|
|
100
|
+
npm install
|
|
101
|
+
npm run build
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Running the Server
|
|
105
|
+
|
|
106
|
+
<details>
|
|
107
|
+
<summary><strong>HTTP Mode</strong> (default)</summary>
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Development with hot reload
|
|
111
|
+
npm run dev
|
|
112
|
+
|
|
113
|
+
# Production
|
|
114
|
+
npm start
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Server runs at `http://127.0.0.1:3000`:
|
|
118
|
+
|
|
119
|
+
- Health check: `GET /health`
|
|
120
|
+
- MCP endpoint: `POST /mcp`
|
|
121
|
+
|
|
122
|
+
</details>
|
|
123
|
+
|
|
124
|
+
<details>
|
|
125
|
+
<summary><strong>stdio Mode</strong> (direct MCP integration)</summary>
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
node dist/index.js --stdio
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
</details>
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Available Tools
|
|
136
|
+
|
|
137
|
+
### `fetch-url`
|
|
138
|
+
|
|
139
|
+
Fetches a webpage and converts it to AI-readable format.
|
|
140
|
+
|
|
141
|
+
| Parameter | Type | Default | Description |
|
|
142
|
+
| -------------------- | ------------------------- | ---------- | -------------------------- |
|
|
143
|
+
| `url` | string | _required_ | URL to fetch |
|
|
144
|
+
| `format` | `'jsonl'` \| `'markdown'` | `'jsonl'` | Output format |
|
|
145
|
+
| `extractMainContent` | boolean | `true` | Use Readability extraction |
|
|
146
|
+
| `includeMetadata` | boolean | `true` | Include page metadata |
|
|
147
|
+
| `maxContentLength` | number | – | Max content length (chars) |
|
|
148
|
+
| `customHeaders` | object | – | Custom HTTP headers |
|
|
149
|
+
|
|
150
|
+
### `fetch-links`
|
|
151
|
+
|
|
152
|
+
Extracts hyperlinks from a webpage with classification.
|
|
153
|
+
|
|
154
|
+
| Parameter | Type | Default | Description |
|
|
155
|
+
| ----------------- | ------- | ---------- | ------------------------- |
|
|
156
|
+
| `url` | string | _required_ | URL to extract links from |
|
|
157
|
+
| `includeExternal` | boolean | `true` | Include external links |
|
|
158
|
+
| `includeInternal` | boolean | `true` | Include internal links |
|
|
159
|
+
|
|
160
|
+
### `fetch-markdown`
|
|
161
|
+
|
|
162
|
+
Fetches a webpage and converts it to clean Markdown.
|
|
163
|
+
|
|
164
|
+
| Parameter | Type | Default | Description |
|
|
165
|
+
| -------------------- | ------- | ---------- | ------------------------- |
|
|
166
|
+
| `url` | string | _required_ | URL to fetch |
|
|
167
|
+
| `extractMainContent` | boolean | `true` | Extract main content only |
|
|
168
|
+
| `includeMetadata` | boolean | `true` | Include YAML frontmatter |
|
|
169
|
+
|
|
170
|
+
### Resources
|
|
171
|
+
|
|
172
|
+
| URI | Description |
|
|
173
|
+
| -------------------- | ----------------------------------- |
|
|
174
|
+
| `superfetch://stats` | Server statistics and cache metrics |
|
|
175
|
+
|
|
176
|
+
### Prompts
|
|
177
|
+
|
|
178
|
+
- **`analyze-web-content`** — Analyze fetched content with optional focus area
|
|
179
|
+
- **`summarize-page`** — Fetch and summarize a webpage concisely
|
|
180
|
+
- **`extract-data`** — Extract structured data from a webpage
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Configuration
|
|
185
|
+
|
|
186
|
+
### Alternative MCP Client Setups
|
|
187
|
+
|
|
188
|
+
<details>
|
|
189
|
+
<summary><strong>VS Code (HTTP mode)</strong> — requires running server separately</summary>
|
|
190
|
+
|
|
191
|
+
First, start the HTTP server:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npx -y @j0hanz/superfetch@latest
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Then add to `.vscode/mcp.json`:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"servers": {
|
|
202
|
+
"superFetch": {
|
|
203
|
+
"type": "http",
|
|
204
|
+
"url": "http://127.0.0.1:3000/mcp"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
</details>
|
|
211
|
+
|
|
212
|
+
<details>
|
|
213
|
+
<summary><strong>Claude Desktop (local path)</strong> — for development</summary>
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"mcpServers": {
|
|
218
|
+
"superFetch": {
|
|
219
|
+
"command": "node",
|
|
220
|
+
"args": ["/path/to/super-fetch-mcp-server/dist/index.js", "--stdio"]
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
</details>
|
|
227
|
+
|
|
228
|
+
### Environment Variables
|
|
229
|
+
|
|
230
|
+
| Variable | Default | Description |
|
|
231
|
+
| -------------------- | -------------------- | ------------------------- |
|
|
232
|
+
| `PORT` | `3000` | HTTP server port |
|
|
233
|
+
| `HOST` | `127.0.0.1` | HTTP server host |
|
|
234
|
+
| `FETCH_TIMEOUT` | `30000` | Request timeout (ms) |
|
|
235
|
+
| `MAX_REDIRECTS` | `5` | Maximum HTTP redirects |
|
|
236
|
+
| `USER_AGENT` | `superFetch-MCP/1.0` | HTTP User-Agent |
|
|
237
|
+
| `MAX_CONTENT_LENGTH` | `10485760` | Max response size (bytes) |
|
|
238
|
+
| `CACHE_ENABLED` | `true` | Enable response caching |
|
|
239
|
+
| `CACHE_TTL` | `3600` | Cache TTL (seconds) |
|
|
240
|
+
| `CACHE_MAX_KEYS` | `100` | Maximum cache entries |
|
|
241
|
+
| `LOG_LEVEL` | `info` | Logging level |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Content Block Types
|
|
246
|
+
|
|
247
|
+
JSONL output includes semantic content blocks:
|
|
248
|
+
|
|
249
|
+
| Type | Description |
|
|
250
|
+
| ----------- | ----------------------------------------------- |
|
|
251
|
+
| `metadata` | Page title, description, author, URL, timestamp |
|
|
252
|
+
| `heading` | Headings (h1-h6) with level indicator |
|
|
253
|
+
| `paragraph` | Text paragraphs |
|
|
254
|
+
| `list` | Ordered/unordered lists |
|
|
255
|
+
| `code` | Code blocks with language |
|
|
256
|
+
| `table` | Tables with headers and rows |
|
|
257
|
+
| `image` | Images with src and alt text |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Security
|
|
262
|
+
|
|
263
|
+
### SSRF Protection
|
|
264
|
+
|
|
265
|
+
Blocked destinations:
|
|
266
|
+
|
|
267
|
+
- Localhost and loopback addresses
|
|
268
|
+
- Private IP ranges (`10.x.x.x`, `172.16-31.x.x`, `192.168.x.x`)
|
|
269
|
+
- Cloud metadata endpoints (AWS, GCP, Azure)
|
|
270
|
+
- IPv6 link-local and unique local addresses
|
|
271
|
+
|
|
272
|
+
### Header Sanitization
|
|
273
|
+
|
|
274
|
+
Blocked headers: `host`, `authorization`, `cookie`, `x-forwarded-for`, `x-real-ip`, `proxy-authorization`
|
|
275
|
+
|
|
276
|
+
### Rate Limiting
|
|
277
|
+
|
|
278
|
+
Default: **100 requests/minute** per IP (configurable)
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Development
|
|
283
|
+
|
|
284
|
+
### Scripts
|
|
285
|
+
|
|
286
|
+
| Command | Description |
|
|
287
|
+
| -------------------- | ---------------------------------- |
|
|
288
|
+
| `npm run dev` | Development server with hot reload |
|
|
289
|
+
| `npm run build` | Compile TypeScript |
|
|
290
|
+
| `npm start` | Production server |
|
|
291
|
+
| `npm run lint` | Run ESLint |
|
|
292
|
+
| `npm run type-check` | TypeScript type checking |
|
|
293
|
+
| `npm run format` | Format with Prettier |
|
|
294
|
+
| `npm test` | Run tests |
|
|
295
|
+
|
|
296
|
+
### Tech Stack
|
|
297
|
+
|
|
298
|
+
| Category | Technology |
|
|
299
|
+
| ------------------ | ------------------------------- |
|
|
300
|
+
| Runtime | Node.js ≥18 |
|
|
301
|
+
| Language | TypeScript 5.9 |
|
|
302
|
+
| MCP SDK | @modelcontextprotocol/sdk 1.0.4 |
|
|
303
|
+
| Content Extraction | @mozilla/readability |
|
|
304
|
+
| HTML Parsing | Cheerio, JSDOM |
|
|
305
|
+
| Markdown | Turndown |
|
|
306
|
+
| HTTP | Express, Axios |
|
|
307
|
+
| Caching | node-cache |
|
|
308
|
+
| Validation | Zod |
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Contributing
|
|
313
|
+
|
|
314
|
+
1. Fork the repository
|
|
315
|
+
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
|
316
|
+
3. Ensure linting passes: `npm run lint`
|
|
317
|
+
4. Commit changes: `git commit -m 'Add amazing feature'`
|
|
318
|
+
5. Push: `git push origin feature/amazing-feature`
|
|
319
|
+
6. Open a Pull Request
|
|
320
|
+
|
|
321
|
+
For examples of other MCP servers, see: [github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers)
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const config: {
|
|
2
|
+
readonly server: {
|
|
3
|
+
readonly name: "superFetch";
|
|
4
|
+
readonly version: "1.0.0";
|
|
5
|
+
readonly port: number;
|
|
6
|
+
readonly host: string;
|
|
7
|
+
};
|
|
8
|
+
readonly fetcher: {
|
|
9
|
+
readonly timeout: number;
|
|
10
|
+
readonly maxRedirects: number;
|
|
11
|
+
readonly userAgent: string;
|
|
12
|
+
readonly maxContentLength: number;
|
|
13
|
+
};
|
|
14
|
+
readonly cache: {
|
|
15
|
+
readonly enabled: boolean;
|
|
16
|
+
readonly ttl: number;
|
|
17
|
+
readonly maxKeys: number;
|
|
18
|
+
};
|
|
19
|
+
readonly extraction: {
|
|
20
|
+
readonly extractMainContent: boolean;
|
|
21
|
+
readonly includeMetadata: boolean;
|
|
22
|
+
readonly maxBlockLength: number;
|
|
23
|
+
readonly minParagraphLength: number;
|
|
24
|
+
};
|
|
25
|
+
readonly logging: {
|
|
26
|
+
readonly level: string;
|
|
27
|
+
readonly enabled: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCT,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely parses an integer from environment variable with validation
|
|
3
|
+
* Environment variables can still be used for deployment overrides (e.g., PORT=8080 npm start)
|
|
4
|
+
*/
|
|
5
|
+
function parseIntEnv(value, defaultValue, min = 0, max = Number.MAX_SAFE_INTEGER) {
|
|
6
|
+
if (!value)
|
|
7
|
+
return defaultValue;
|
|
8
|
+
const parsed = parseInt(value, 10);
|
|
9
|
+
if (isNaN(parsed))
|
|
10
|
+
return defaultValue;
|
|
11
|
+
return Math.max(min, Math.min(max, parsed));
|
|
12
|
+
}
|
|
13
|
+
export const config = {
|
|
14
|
+
server: {
|
|
15
|
+
name: 'superFetch',
|
|
16
|
+
version: '1.0.0',
|
|
17
|
+
port: parseIntEnv(process.env.PORT, 3000, 1, 65535),
|
|
18
|
+
host: process.env.HOST || '127.0.0.1',
|
|
19
|
+
},
|
|
20
|
+
fetcher: {
|
|
21
|
+
timeout: parseIntEnv(process.env.FETCH_TIMEOUT, 30000, 1000, 120000), // 1s-120s
|
|
22
|
+
maxRedirects: parseIntEnv(process.env.MAX_REDIRECTS, 5, 0, 20),
|
|
23
|
+
userAgent: process.env.USER_AGENT || 'superFetch-MCP/1.0',
|
|
24
|
+
maxContentLength: parseIntEnv(process.env.MAX_CONTENT_LENGTH, 10485760, 1024, 52428800), // 1KB-50MB
|
|
25
|
+
},
|
|
26
|
+
cache: {
|
|
27
|
+
enabled: process.env.CACHE_ENABLED !== 'false',
|
|
28
|
+
ttl: parseIntEnv(process.env.CACHE_TTL, 3600, 60, 86400), // 1min-24hr
|
|
29
|
+
maxKeys: parseIntEnv(process.env.CACHE_MAX_KEYS, 100, 10, 10000),
|
|
30
|
+
},
|
|
31
|
+
extraction: {
|
|
32
|
+
extractMainContent: process.env.EXTRACT_MAIN_CONTENT !== 'false',
|
|
33
|
+
includeMetadata: process.env.INCLUDE_METADATA !== 'false',
|
|
34
|
+
maxBlockLength: parseIntEnv(process.env.MAX_BLOCK_LENGTH, 5000, 100, 50000),
|
|
35
|
+
minParagraphLength: parseIntEnv(process.env.MIN_PARAGRAPH_LENGTH, 10, 0, 1000),
|
|
36
|
+
},
|
|
37
|
+
logging: {
|
|
38
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
39
|
+
enabled: process.env.ENABLE_LOGGING !== 'false',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,SAAS,WAAW,CAClB,KAAyB,EACzB,YAAoB,EACpB,GAAG,GAAG,CAAC,EACP,GAAG,GAAG,MAAM,CAAC,gBAAgB;IAE7B,IAAI,CAAC,KAAK;QAAE,OAAO,YAAY,CAAC;IAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,YAAY,CAAC;IACvC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,MAAM,EAAE;QACN,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC;QACnD,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,WAAW;KACtC;IACD,OAAO,EAAE;QACP,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,UAAU;QAChF,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9D,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,oBAAoB;QACzD,gBAAgB,EAAE,WAAW,CAC3B,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAC9B,QAAQ,EACR,IAAI,EACJ,QAAQ,CACT,EAAE,WAAW;KACf;IACD,KAAK,EAAE;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,OAAO;QAC9C,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,YAAY;QACtE,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC;KACjE;IACD,UAAU,EAAE;QACV,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,OAAO;QAChE,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,OAAO;QACzD,cAAc,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC;QAC3E,kBAAkB,EAAE,WAAW,CAC7B,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAChC,EAAE,EACF,CAAC,EACD,IAAI,CACL;KACF;IACD,OAAO,EAAE;QACP,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;QACtC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,OAAO;KAChD;CACO,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base application error class with status code support
|
|
3
|
+
*/
|
|
4
|
+
export declare class AppError extends Error {
|
|
5
|
+
readonly statusCode: number;
|
|
6
|
+
readonly isOperational: boolean;
|
|
7
|
+
readonly code: string;
|
|
8
|
+
constructor(message: string, statusCode?: number, code?: string, isOperational?: boolean);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Not found error (404)
|
|
12
|
+
*/
|
|
13
|
+
export declare class NotFoundError extends AppError {
|
|
14
|
+
constructor(resource: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Validation error (400)
|
|
18
|
+
*/
|
|
19
|
+
export declare class ValidationError extends AppError {
|
|
20
|
+
readonly details?: Record<string, unknown>;
|
|
21
|
+
constructor(message: string, details?: Record<string, unknown>);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* URL validation error (400)
|
|
25
|
+
*/
|
|
26
|
+
export declare class UrlValidationError extends AppError {
|
|
27
|
+
readonly url: string;
|
|
28
|
+
constructor(message: string, url: string);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fetch error - network/HTTP errors during URL fetching
|
|
32
|
+
*/
|
|
33
|
+
export declare class FetchError extends AppError {
|
|
34
|
+
readonly url: string;
|
|
35
|
+
readonly httpStatus?: number;
|
|
36
|
+
constructor(message: string, url: string, httpStatus?: number);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Content extraction error
|
|
40
|
+
*/
|
|
41
|
+
export declare class ExtractionError extends AppError {
|
|
42
|
+
readonly url: string;
|
|
43
|
+
constructor(message: string, url: string);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Unauthorized error (401)
|
|
47
|
+
*/
|
|
48
|
+
export declare class UnauthorizedError extends AppError {
|
|
49
|
+
constructor(message?: string);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Forbidden error (403)
|
|
53
|
+
*/
|
|
54
|
+
export declare class ForbiddenError extends AppError {
|
|
55
|
+
constructor(message?: string);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Rate limit error (429)
|
|
59
|
+
*/
|
|
60
|
+
export declare class RateLimitError extends AppError {
|
|
61
|
+
readonly retryAfter: number;
|
|
62
|
+
constructor(retryAfter: number);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Timeout error (408/504)
|
|
66
|
+
*/
|
|
67
|
+
export declare class TimeoutError extends AppError {
|
|
68
|
+
readonly timeoutMs: number;
|
|
69
|
+
constructor(timeoutMs: number, isGateway?: boolean);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=app-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-error.d.ts","sourceRoot":"","sources":["../../src/errors/app-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,aAAa,EAAE,OAAO,CAAC;IACvC,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAG3B,OAAO,EAAE,MAAM,EACf,UAAU,SAAM,EAChB,IAAI,SAAmB,EACvB,aAAa,UAAO;CASvB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,QAAQ,EAAE,MAAM;CAG7B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,SAAgB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEtC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IAC9C,SAAgB,GAAG,EAAE,MAAM,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAIzC;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,QAAQ;IACtC,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAK9D;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,SAAgB,GAAG,EAAE,MAAM,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAIzC;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;gBACjC,OAAO,SAAiB;CAGrC;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;gBAC9B,OAAO,SAAc;CAGlC;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,SAAgB,UAAU,EAAE,MAAM,CAAC;gBAEvB,UAAU,EAAE,MAAM;CAI/B;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,QAAQ;IACxC,SAAgB,SAAS,EAAE,MAAM,CAAC;gBAEtB,SAAS,EAAE,MAAM,EAAE,SAAS,UAAQ;CAQjD"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base application error class with status code support
|
|
3
|
+
*/
|
|
4
|
+
export class AppError extends Error {
|
|
5
|
+
statusCode;
|
|
6
|
+
isOperational;
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, statusCode = 500, code = 'INTERNAL_ERROR', isOperational = true) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.statusCode = statusCode;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.isOperational = isOperational;
|
|
13
|
+
this.name = this.constructor.name;
|
|
14
|
+
Error.captureStackTrace(this, this.constructor);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Not found error (404)
|
|
19
|
+
*/
|
|
20
|
+
export class NotFoundError extends AppError {
|
|
21
|
+
constructor(resource) {
|
|
22
|
+
super(`${resource} not found`, 404, 'NOT_FOUND');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validation error (400)
|
|
27
|
+
*/
|
|
28
|
+
export class ValidationError extends AppError {
|
|
29
|
+
details;
|
|
30
|
+
constructor(message, details) {
|
|
31
|
+
super(message, 400, 'VALIDATION_ERROR');
|
|
32
|
+
this.details = details;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* URL validation error (400)
|
|
37
|
+
*/
|
|
38
|
+
export class UrlValidationError extends AppError {
|
|
39
|
+
url;
|
|
40
|
+
constructor(message, url) {
|
|
41
|
+
super(message, 400, 'INVALID_URL');
|
|
42
|
+
this.url = url;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Fetch error - network/HTTP errors during URL fetching
|
|
47
|
+
*/
|
|
48
|
+
export class FetchError extends AppError {
|
|
49
|
+
url;
|
|
50
|
+
httpStatus;
|
|
51
|
+
constructor(message, url, httpStatus) {
|
|
52
|
+
super(message, httpStatus ?? 502, 'FETCH_ERROR');
|
|
53
|
+
this.url = url;
|
|
54
|
+
this.httpStatus = httpStatus;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Content extraction error
|
|
59
|
+
*/
|
|
60
|
+
export class ExtractionError extends AppError {
|
|
61
|
+
url;
|
|
62
|
+
constructor(message, url) {
|
|
63
|
+
super(message, 422, 'EXTRACTION_ERROR');
|
|
64
|
+
this.url = url;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Unauthorized error (401)
|
|
69
|
+
*/
|
|
70
|
+
export class UnauthorizedError extends AppError {
|
|
71
|
+
constructor(message = 'Unauthorized') {
|
|
72
|
+
super(message, 401, 'UNAUTHORIZED');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Forbidden error (403)
|
|
77
|
+
*/
|
|
78
|
+
export class ForbiddenError extends AppError {
|
|
79
|
+
constructor(message = 'Forbidden') {
|
|
80
|
+
super(message, 403, 'FORBIDDEN');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Rate limit error (429)
|
|
85
|
+
*/
|
|
86
|
+
export class RateLimitError extends AppError {
|
|
87
|
+
retryAfter;
|
|
88
|
+
constructor(retryAfter) {
|
|
89
|
+
super('Too many requests', 429, 'RATE_LIMITED');
|
|
90
|
+
this.retryAfter = retryAfter;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Timeout error (408/504)
|
|
95
|
+
*/
|
|
96
|
+
export class TimeoutError extends AppError {
|
|
97
|
+
timeoutMs;
|
|
98
|
+
constructor(timeoutMs, isGateway = false) {
|
|
99
|
+
super(`Request timeout after ${timeoutMs}ms`, isGateway ? 504 : 408, 'TIMEOUT');
|
|
100
|
+
this.timeoutMs = timeoutMs;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=app-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../src/errors/app-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjB,UAAU,CAAS;IACnB,aAAa,CAAU;IACvB,IAAI,CAAS;IAE7B,YACE,OAAe,EACf,UAAU,GAAG,GAAG,EAChB,IAAI,GAAG,gBAAgB,EACvB,aAAa,GAAG,IAAI;QAEpB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,QAAQ;IACzC,YAAY,QAAgB;QAC1B,KAAK,CAAC,GAAG,QAAQ,YAAY,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAC3B,OAAO,CAA2B;IAElD,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,QAAQ;IAC9B,GAAG,CAAS;IAE5B,YAAY,OAAe,EAAE,GAAW;QACtC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,QAAQ;IACtB,GAAG,CAAS;IACZ,UAAU,CAAU;IAEpC,YAAY,OAAe,EAAE,GAAW,EAAE,UAAmB;QAC3D,KAAK,CAAC,OAAO,EAAE,UAAU,IAAI,GAAG,EAAE,aAAa,CAAC,CAAC;QACjD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,QAAQ;IAC3B,GAAG,CAAS;IAE5B,YAAY,OAAe,EAAE,GAAW;QACtC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,iBAAkB,SAAQ,QAAQ;IAC7C,YAAY,OAAO,GAAG,cAAc;QAClC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;IACtC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,QAAQ;IAC1C,YAAY,OAAO,GAAG,WAAW;QAC/B,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;IACnC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,QAAQ;IAC1B,UAAU,CAAS;IAEnC,YAAY,UAAkB;QAC5B,KAAK,CAAC,mBAAmB,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,QAAQ;IACxB,SAAS,CAAS;IAElC,YAAY,SAAiB,EAAE,SAAS,GAAG,KAAK;QAC9C,KAAK,CACH,yBAAyB,SAAS,IAAI,EACtC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EACrB,SAAS,CACV,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|