@umeshindu222/apisnap 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,182 +7,319 @@
7
7
 
8
8
  ---
9
9
 
10
- ## Why APISnap?
10
+ ## Why APISnap?
11
11
 
12
- **The Problem:** Every time you make a change to your Express.js backend, you have to manually open Postman, find every route, and click "Send" one by one. For a project with 20+ endpoints, this is slow, error-prone, and boring.
13
-
14
- **The Solution:** APISnap plugs directly into your Express app, **automatically discovers every route you've registered**, and then health-checks all of them in seconds with zero configuration.
12
+ Every time you change your Express backend, manually testing 20+ endpoints in Postman is slow and error-prone. APISnap **auto-discovers every route** and health-checks all of them in seconds with zero config.
15
13
 
16
14
  ---
17
15
 
18
- ## Features
16
+ ## Features
19
17
 
20
- - **Auto Route Discovery** — Scans your Express router stack, no manual config needed
21
- - **Auth Header Support** — Pass JWT tokens or API keys via `--header`
22
- - **Slow Route Detection** — Flags endpoints that exceed your response time threshold
23
- - **JSON Report Export** — Save results to a file for CI/CD pipelines or sharing
24
- - **Beautiful CLI Output** — Color-coded results with spinners and summary table
25
- - **Express v4 & v5** — Compatible with both versions
18
+ - 🔍 **Auto Route Discovery** — Scans your full Express router stack including sub-routers
19
+ - 🔐 **Full Auth Support** — JWT, API Keys, Cookies, multiple headers simultaneously
20
+ - 🔁 **Retry Logic** Auto-retry failed requests with exponential backoff
21
+ -**Slow Route Detection** — Flags endpoints exceeding your threshold
22
+ - 📊 **HTML Reports** Beautiful visual reports for sharing/archiving
23
+ - 💾 **JSON Export** — Structured output for CI/CD pipelines
24
+ - ⚙️ **Config File** — Persist options in `.apisnaprc.json`
25
+ - 🎯 **Method Filter** — Test only GET, POST, etc.
26
+ - 🧠 **Smart Params** — Auto-replaces `:id`, `:slug`, `:uuid` with safe defaults
27
+ - 🚨 **Auth Hints** — Tells you exactly how to fix 401/403 errors
28
+ - 🏗️ **CI/CD Ready** — Exit code 1 on failures for pipeline integration
26
29
 
27
30
  ---
28
31
 
29
- ## 🚀 Quick Start
32
+ ## Quick Start
33
+
34
+ ### Step 1 — Install & add middleware
30
35
 
31
- ### 1. Install & Add Middleware
32
36
  ```bash
33
37
  npm install @umeshindu222/apisnap
34
38
  ```
35
39
 
36
- In your Express application, initialize APISnap **after** all your routes:
37
40
  ```javascript
38
41
  const express = require('express');
39
42
  const apisnap = require('@umeshindu222/apisnap');
43
+
40
44
  const app = express();
41
45
 
46
+ // ✅ Your routes go here
42
47
  app.get('/users', (req, res) => res.json({ users: [] }));
48
+ app.post('/users', (req, res) => res.json({ message: 'Created' }));
43
49
 
44
- // Add APISnap
50
+ // APISnap goes AFTER your routes (so it can discover them)
51
+ // ✅ APISnap goes BEFORE global auth middleware (to allow discovery)
45
52
  apisnap.init(app);
46
53
 
54
+ // ⚠️ If you use global auth middleware, place it AFTER apisnap.init():
55
+ // app.use(authMiddleware); ← AFTER init, not before
56
+
47
57
  app.listen(3000);
48
58
  ```
49
59
 
50
- ### 2. Initialize Config
51
- Run this once in your project root to generate config templates:
60
+ ### Step 2 Run
61
+
62
+ ```bash
63
+ npx @umeshindu222/apisnap --port 3000
64
+ ```
65
+
66
+ ---
67
+
68
+ ## 🔐 Fixing 401 / 403 Errors
69
+
70
+ This is the most common issue. APISnap sends real HTTP requests, so **protected routes require credentials** just like any client would.
71
+
72
+ ### JWT / Bearer Token
73
+ ```bash
74
+ npx @umeshindu222/apisnap -H "Authorization: Bearer eyJhbGci..."
75
+ ```
76
+
77
+ ### API Key header
52
78
  ```bash
53
- npx @umeshindu222/apisnap init
79
+ npx @umeshindu222/apisnap -H "x-api-key: my-secret-key"
54
80
  ```
55
81
 
56
- ### 3. Run the Check
82
+ ### Cookie / Session auth
83
+ ```bash
84
+ npx @umeshindu222/apisnap --cookie "sessionId=abc123; connect.sid=xyz"
85
+ ```
86
+
87
+ ### Multiple headers at once (`-H` can be repeated)
88
+ ```bash
89
+ npx @umeshindu222/apisnap \
90
+ -H "Authorization: Bearer TOKEN" \
91
+ -H "x-tenant-id: acme" \
92
+ -H "x-api-version: 2"
93
+ ```
94
+
95
+ ### Skip specific protected routes
96
+ ```javascript
97
+ // In your server — skip routes you don't want tested:
98
+ apisnap.init(app, {
99
+ skip: ['/admin', '/internal', '/webhooks']
100
+ });
101
+ ```
102
+
103
+ ### Use a config file (recommended for teams)
104
+
105
+ Create `.apisnaprc.json` in your project root:
106
+
107
+ ```json
108
+ {
109
+ "port": "3000",
110
+ "slow": "300",
111
+ "headers": [
112
+ "Authorization: Bearer YOUR_DEV_TOKEN",
113
+ "x-api-key: YOUR_KEY"
114
+ ],
115
+ "cookie": "sessionId=dev-session-abc",
116
+ "params": {
117
+ "id": "42",
118
+ "slug": "hello-world",
119
+ "uuid": "550e8400-e29b-41d4-a716-446655440000"
120
+ }
121
+ }
122
+ ```
123
+
124
+ Then just run:
57
125
  ```bash
58
126
  npx @umeshindu222/apisnap
59
127
  ```
60
128
 
61
129
  ---
62
130
 
63
- ## ⚙️ Configuration
131
+ ## Middleware Placement (Important!)
132
+
133
+ The order of middleware in Express matters:
134
+
135
+ ```javascript
136
+ // ✅ CORRECT — apisnap can bypass auth because it registers first
137
+ app.use(express.json());
138
+ apisnap.init(app); // ← BEFORE auth middleware
139
+ app.use(authMiddleware); // ← AFTER apisnap.init
140
+
141
+ // ❌ WRONG — auth blocks the discovery endpoint
142
+ app.use(authMiddleware); // ← BEFORE apisnap
143
+ apisnap.init(app); // discovery endpoint gets blocked!
144
+ ```
64
145
 
65
- APISnap uses a dual-config system to keep your secrets safe:
146
+ If you **must** put auth before apisnap, manually whitelist the discovery path:
66
147
 
67
- | File | Purpose | Git Status |
68
- | :--- | :--- | :--- |
69
- | `apisnap.json` | Shared team settings (Port, Slow Threshold) | **Commit to Git** |
70
- | `apisnap.local.json` | Personal secrets (Auth Tokens, API Keys) | **Add to .gitignore** |
148
+ ```javascript
149
+ app.use((req, res, next) => {
150
+ if (req.path === '/__apisnap_discovery') return next(); // bypass
151
+ return authMiddleware(req, res, next);
152
+ });
153
+ ```
71
154
 
72
155
  ---
73
156
 
74
- ## 🛠️ CLI Commands
157
+ ## CLI Reference
75
158
 
76
159
  ```bash
77
160
  npx @umeshindu222/apisnap [options]
78
161
  ```
79
162
 
80
- - `npx @umeshindu222/apisnap init`: Create config templates.
81
- - `npx @umeshindu222/apisnap --port 5000`: Override the port.
82
- - `npx @umeshindu222/apisnap --header "Authorization:Bearer token"`: Add custom header.
83
- - `npx @umeshindu222/apisnap --export report.json`: Export results to JSON.
163
+ | Option | Description | Default |
164
+ |--------|-------------|---------|
165
+ | `-p, --port <n>` | Port your server runs on | `3000` |
166
+ | `-H, --header <str>` | Add auth header (repeatable) | — |
167
+ | `-c, --cookie <str>` | Cookie string for session auth | — |
168
+ | `-s, --slow <n>` | Slow threshold in ms | `200` |
169
+ | `-t, --timeout <n>` | Request timeout in ms | `5000` |
170
+ | `-r, --retry <n>` | Retry failed requests N times | `0` |
171
+ | `-e, --export <file>` | Export JSON report | — |
172
+ | `--html <file>` | Export HTML report | — |
173
+ | `--only <methods>` | Filter methods (e.g. `GET,POST`) | — |
174
+ | `--base-url <url>` | Override base URL (for staging) | `localhost` |
175
+ | `--params <json>` | Path param overrides as JSON | — |
176
+ | `--fail-on-slow` | Exit code 1 if slow routes found | `false` |
84
177
 
85
178
  ---
86
179
 
87
- ## Examples
180
+ ## Examples
88
181
 
89
- ### Basic health check
182
+ ### Basic
90
183
  ```bash
91
184
  npx @umeshindu222/apisnap --port 3000
92
185
  ```
93
186
 
94
- ### With authentication (JWT / Bearer tokens)
187
+ ### With JWT auth
95
188
  ```bash
96
- npx @umeshindu222/apisnap --port 3000 --header "Authorization: Bearer eyJhbGci..."
189
+ npx @umeshindu222/apisnap -p 3000 -H "Authorization: Bearer eyJhbGci..."
97
190
  ```
98
191
 
99
- ### Custom slow threshold (flag routes > 500ms)
192
+ ### Custom path params (for routes like `/users/:id/posts/:postId`)
100
193
  ```bash
101
- npx @umeshindu222/apisnap --port 3000 --slow 500
194
+ npx @umeshindu222/apisnap --params '{"id":"42","postId":"7"}'
102
195
  ```
103
196
 
104
- ### Export report to JSON
197
+ ### Test only GET routes
105
198
  ```bash
106
- npx @umeshindu222/apisnap --port 3000 --export my-report
107
- # Creates: my-report.json
199
+ npx @umeshindu222/apisnap --only GET
108
200
  ```
109
201
 
110
- ### All options together
202
+ ### Test staging server
111
203
  ```bash
112
- npx @umeshindu222/apisnap --port 5000 --header "Authorization: Bearer TOKEN" --slow 300 --export ci-report
204
+ npx @umeshindu222/apisnap --base-url https://staging.myapp.com -H "Authorization: Bearer TOKEN"
113
205
  ```
114
206
 
115
- ---
207
+ ### Generate HTML report
208
+ ```bash
209
+ npx @umeshindu222/apisnap --html report
210
+
211
+ # Mac
212
+ # open report.html
116
213
 
117
- ## Sample Output
214
+ # Windows
215
+ # start report.html
118
216
 
217
+ # Linux
218
+ # xdg-open report.html
119
219
  ```
120
- 📸 APISnap v1.0.0
121
- Slow threshold: 200ms
122
220
 
123
- Connected! Found 6 endpoints.
221
+ ### CI/CD fail pipeline on any broken endpoint
222
+ ```bash
223
+ npx @umeshindu222/apisnap --export ci-report && echo "All healthy!"
224
+ # Exit code 1 if any endpoint fails
225
+ ```
124
226
 
125
- ✔ GET /health [200 OK] 3ms
126
- ✔ GET /users [200 OK] 12ms
127
- ✔ POST /users [200 OK] 8ms
128
- GET /users/1 [200 OK] 15ms
129
- ⚠️ GET /reports [200 OK] 543ms ← slow!
130
- DELETE /users/1 [401]
227
+ ### Full power
228
+ ```bash
229
+ npx @umeshindu222/apisnap \
230
+ -p 5000 \
231
+ -H "Authorization: Bearer TOKEN" \
232
+ -H "x-api-key: SECRET" \
233
+ --cookie "sessionId=abc" \
234
+ --slow 300 \
235
+ --retry 2 \
236
+ --html report \
237
+ --export report \
238
+ --fail-on-slow
239
+ ```
240
+
241
+ ---
242
+
243
+ ## Sample Output
244
+
245
+ ```
246
+ 📸 APISnap v2.0.0
247
+ Target: http://localhost:3000
248
+ Slow: >200ms
249
+ Timeout: 5000ms
250
+ Headers: {"Authorization":"Bearer ••••••"}
251
+
252
+ ✔ Connected! Found 6 endpoints to test.
253
+
254
+ ✔ GET /health [200] 3ms
255
+ ✔ GET /users [200] 12ms
256
+ ✔ POST /users [200] 8ms
257
+ ✔ GET /users/1 [200] 15ms
258
+ ⚠️ GET /reports [200] 543ms ← slow!
259
+ ✖ DELETE /users/1 [401]
260
+ 💡 Hint: 401 Unauthorized — try adding -H "Authorization: Bearer YOUR_TOKEN"
131
261
 
132
262
  📊 Summary:
133
263
  ✅ Passed: 5
134
264
  ❌ Failed: 1
135
265
  ⚠️ Slow: 1 (>200ms)
266
+ ⏱ Avg: 100ms
267
+ 🕐 Total: 600ms
136
268
 
137
269
  ⚠️ Some endpoints are unhealthy!
138
270
  ```
139
271
 
140
272
  ---
141
273
 
142
- ## 💾 JSON Report Format
274
+ ## HTML Report
275
+
276
+ `--html report` generates a beautiful standalone HTML file:
277
+
278
+ - Pass rate progress bar
279
+ - Color-coded result table
280
+ - Per-endpoint timing, status, retry count
281
+ - No external dependencies — works offline
143
282
 
144
- When using `--export`, a structured JSON file is created:
283
+ ---
284
+
285
+ ## JSON Report Format
145
286
 
146
287
  ```json
147
288
  {
148
289
  "tool": "APISnap",
149
- "generatedAt": "2026-03-06T15:56:20.375Z",
290
+ "version": "2.0.0",
291
+ "generatedAt": "2026-03-08T10:00:00.000Z",
150
292
  "config": { "port": "3000", "slowThreshold": 200 },
151
- "summary": { "total": 6, "passed": 5, "failed": 1, "slow": 1 },
293
+ "summary": {
294
+ "total": 6, "passed": 5, "failed": 1,
295
+ "slow": 1, "avgDuration": 100, "totalDuration": 600
296
+ },
152
297
  "results": [
153
- { "method": "GET", "path": "/health", "status": 200, "duration": 3, "success": true, "slow": false },
154
- { "method": "GET", "path": "/users", "status": 200, "duration": 12, "success": true, "slow": false },
155
- { "method": "GET", "path": "/reports", "status": 200, "duration": 543,"success": true, "slow": true }
298
+ { "method": "GET", "path": "/users", "status": 200, "duration": 12, "success": true, "slow": false, "retries": 0 }
156
299
  ]
157
300
  }
158
301
  ```
159
302
 
160
- > **CI/CD tip:** Parse `summary.failed` and fail your pipeline build if it's greater than `0`!
303
+ > **CI/CD tip:** Check `summary.failed > 0` to fail your build.
161
304
 
162
305
  ---
163
306
 
164
- ## 🔧 How It Works
307
+ ## How It Works
165
308
 
166
- APISnap uses a two-part architecture:
309
+ 1. **Middleware** `apisnap.init(app)` registers `/__apisnap_discovery` and patches `app.use` so global auth middleware skips the discovery path automatically.
167
310
 
168
- 1. **Middleware (The Seeker)** — `apisnap.init(app)` injects a hidden endpoint `/__apisnap_discovery` into your Express app. When called, it recursively walks the Express router stack and returns a map of every registered route including nested sub-routers.
311
+ 2. **CLI** — Calls the discovery endpoint, gets the full route map, then pings each route with your headers/cookies. Smart defaults replace `:id` `1`, `:uuid` a valid UUID, `:slug` `"example"`, etc.
169
312
 
170
- 2. **CLI Runner (The Checker)** — `npx @umeshindu222/apisnap` calls the discovery endpoint, gets the route map, then "pings" each route using axios — injecting your headers, replacing path params with safe defaults (`:id` → `1`), and timing each response.
313
+ 3. **Reports** — Results are collected and can be exported as JSON (for CI/CD) or a self-contained HTML file (for humans).
171
314
 
172
315
  ---
173
316
 
174
- ## 🤝 Contributing
175
-
176
- Contributions, issues and feature requests are welcome!
317
+ ## Contributing
177
318
 
178
- 1. Fork the repo
179
- 2. Create your feature branch: `git checkout -b feat/amazing-feature`
180
- 3. Commit your changes: `git commit -m 'feat: add amazing feature'`
181
- 4. Push to the branch: `git push origin feat/amazing-feature`
182
- 5. Open a Pull Request
319
+ 1. Fork `git checkout -b feat/amazing` → commit → push → PR
183
320
 
184
321
  ---
185
322
 
186
- ## 📄 License
323
+ ## License
187
324
 
188
325
  MIT © [Umesh Induranga](https://github.com/Umeshinduranga)
@@ -4,191 +4,382 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
7
8
  const axios_1 = __importDefault(require("axios"));
8
9
  const chalk_1 = __importDefault(require("chalk"));
9
10
  const ora_1 = __importDefault(require("ora"));
10
11
  const commander_1 = require("commander");
11
- const path_1 = __importDefault(require("path"));
12
12
  const program = new commander_1.Command();
13
13
  const { version } = require('../../package.json');
14
- program
15
- .name('apisnap')
16
- .description('Instant API health-check CLI for Express.js')
17
- .version(version)
18
- .option('-p, --port <number>', 'Override port')
19
- .option('-H, --header <string>', 'One-time header (Key:Value)')
20
- .option('-s, --slow <number>', 'Override slow threshold (ms)')
21
- .option('-e, --export <filename>', 'Export results to JSON file (e.g., report.json)')
22
- .action(async (options) => {
23
- let config = { port: 3000, slowThreshold: 200, headers: {} };
24
- // Smart Merge: Load shared, then override with local
25
- ['apisnap.json', 'apisnap.local.json'].forEach(file => {
26
- const filePath = path_1.default.join(process.cwd(), file);
14
+ // ─── Config File Loader ───────────────────────────────────────────────────────
15
+ function loadConfigFile() {
16
+ const configNames = ['.apisnaprc', '.apisnaprc.json', 'apisnap.config.json'];
17
+ for (const name of configNames) {
18
+ const filePath = path_1.default.resolve(process.cwd(), name);
27
19
  if (fs_1.default.existsSync(filePath)) {
28
20
  try {
29
- const fileData = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
30
- config = {
31
- ...config,
32
- ...fileData,
33
- headers: { ...config.headers, ...fileData.headers }
34
- };
21
+ // Strip BOM if present (fixes Windows PowerShell encoding issue)
22
+ let raw = fs_1.default.readFileSync(filePath, 'utf-8');
23
+ raw = raw.replace(/^\uFEFF/, '');
24
+ raw = raw.trim();
25
+ console.log(chalk_1.default.gray(` Config: ${name}\n`));
26
+ return JSON.parse(raw);
35
27
  }
36
28
  catch (e) {
37
- console.log(chalk_1.default.yellow(`⚠️ Warning: Failed to parse ${file}`));
29
+ console.warn(chalk_1.default.yellow(`⚠️ Could not parse config file: ${name}`));
38
30
  }
39
31
  }
40
- });
41
- // Final Priority: CLI Flags always win
42
- const port = options.port || config.port;
43
- const slowThreshold = options.slow ? parseInt(options.slow) : config.slowThreshold;
44
- const finalHeaders = { ...config.headers };
45
- if (options.header) {
46
- const [key, ...val] = options.header.split(':');
47
- finalHeaders[key.trim()] = val.join(':').trim();
48
32
  }
33
+ return {};
34
+ }
35
+ // ─── Header Parser ─────────────────────────────────────────────────────────
36
+ function parseHeaders(headerArgs) {
37
+ const headers = {};
38
+ for (const h of headerArgs) {
39
+ const colonIdx = h.indexOf(':');
40
+ if (colonIdx > 0) {
41
+ const key = h.slice(0, colonIdx).trim();
42
+ const value = h.slice(colonIdx + 1).trim();
43
+ headers[key] = value;
44
+ }
45
+ else {
46
+ console.warn(chalk_1.default.yellow(`⚠️ Skipping malformed header: "${h}" (expected "Key: Value")`));
47
+ }
48
+ }
49
+ return headers;
50
+ }
51
+ // ─── Smart Path Param Replacement ────────────────────────────────────────────
52
+ function replacePath(rawPath, paramMap = {}) {
53
+ return rawPath.replace(/:([a-zA-Z0-9_]+)/g, (_, param) => {
54
+ if (paramMap[param])
55
+ return paramMap[param];
56
+ // Smart defaults based on param name
57
+ if (/id$/i.test(param))
58
+ return '1';
59
+ if (/slug$/i.test(param))
60
+ return 'example';
61
+ if (/uuid$/i.test(param))
62
+ return '00000000-0000-0000-0000-000000000001';
63
+ if (/name$/i.test(param))
64
+ return 'test';
65
+ if (/token$/i.test(param))
66
+ return 'abc123';
67
+ if (/page$/i.test(param))
68
+ return '1';
69
+ if (/limit$/i.test(param))
70
+ return '10';
71
+ return '1'; // fallback
72
+ });
73
+ }
74
+ // ─── HTML Report Generator ────────────────────────────────────────────────────
75
+ function generateHTMLReport(data) {
76
+ const passRate = data.summary.total > 0
77
+ ? Math.round((data.summary.passed / data.summary.total) * 100)
78
+ : 0;
79
+ const rowColor = (r) => {
80
+ if (!r.success)
81
+ return '#fee2e2';
82
+ if (r.slow)
83
+ return '#fef9c3';
84
+ return '#f0fdf4';
85
+ };
86
+ const rows = data.results.map(r => `
87
+ <tr style="background:${rowColor(r)}">
88
+ <td><span class="badge badge-${r.method.toLowerCase()}">${r.method}</span></td>
89
+ <td><code>${r.path}</code></td>
90
+ <td>${r.success
91
+ ? `<span class="ok">✔ ${r.status}</span>`
92
+ : `<span class="fail">✖ ${r.status || 'ERR'}</span>`}</td>
93
+ <td>${r.slow ? `<span class="slow">⚠️ ${r.duration}ms</span>` : `${r.duration}ms`}</td>
94
+ <td>${r.retries > 0 ? `${r.retries} retry` : '—'}</td>
95
+ <td>${r.error ? `<span class="errtext">${r.error}</span>` : '—'}</td>
96
+ </tr>
97
+ `).join('');
98
+ return `<!DOCTYPE html>
99
+ <html lang="en">
100
+ <head>
101
+ <meta charset="UTF-8"/>
102
+ <title>APISnap Report — ${data.generatedAt}</title>
103
+ <style>
104
+ *{box-sizing:border-box;margin:0;padding:0}
105
+ body{font-family:'Segoe UI',system-ui,sans-serif;background:#f8fafc;color:#1e293b;padding:2rem}
106
+ h1{font-size:1.8rem;margin-bottom:.25rem}
107
+ .sub{color:#64748b;font-size:.9rem;margin-bottom:2rem}
108
+ .cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1rem;margin-bottom:2rem}
109
+ .card{background:#fff;border-radius:12px;padding:1.2rem;box-shadow:0 1px 4px rgba(0,0,0,.08);text-align:center}
110
+ .card .num{font-size:2rem;font-weight:700}
111
+ .card .lbl{font-size:.8rem;color:#64748b;margin-top:.25rem}
112
+ .green{color:#16a34a}.red{color:#dc2626}.yellow{color:#ca8a04}.blue{color:#2563eb}
113
+ table{width:100%;border-collapse:collapse;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,.08)}
114
+ th{background:#1e293b;color:#f8fafc;padding:.8rem 1rem;text-align:left;font-size:.85rem}
115
+ td{padding:.75rem 1rem;font-size:.875rem;border-bottom:1px solid #f1f5f9}
116
+ .badge{display:inline-block;padding:.15rem .5rem;border-radius:6px;font-weight:600;font-size:.75rem;color:#fff}
117
+ .badge-get{background:#2563eb}.badge-post{background:#16a34a}.badge-put{background:#d97706}
118
+ .badge-delete{background:#dc2626}.badge-patch{background:#7c3aed}
119
+ .ok{color:#16a34a;font-weight:600}.fail{color:#dc2626;font-weight:600}.slow{color:#ca8a04;font-weight:600}
120
+ .errtext{color:#dc2626;font-size:.8rem}
121
+ .progress{background:#e2e8f0;border-radius:999px;height:10px;margin:1rem 0}
122
+ .progress-bar{background:#16a34a;height:10px;border-radius:999px;transition:width .3s}
123
+ footer{margin-top:2rem;color:#94a3b8;font-size:.8rem;text-align:center}
124
+ </style>
125
+ </head>
126
+ <body>
127
+ <h1>📸 APISnap Health Report</h1>
128
+ <p class="sub">Generated: ${data.generatedAt} &nbsp;|&nbsp; Port: ${data.config.port} &nbsp;|&nbsp; v${data.version}</p>
129
+
130
+ <div class="cards">
131
+ <div class="card"><div class="num blue">${data.summary.total}</div><div class="lbl">Total Endpoints</div></div>
132
+ <div class="card"><div class="num green">${data.summary.passed}</div><div class="lbl">Passed</div></div>
133
+ <div class="card"><div class="num red">${data.summary.failed}</div><div class="lbl">Failed</div></div>
134
+ <div class="card"><div class="num yellow">${data.summary.slow}</div><div class="lbl">Slow (&gt;${data.config.slowThreshold}ms)</div></div>
135
+ <div class="card"><div class="num blue">${data.summary.avgDuration}ms</div><div class="lbl">Avg Response</div></div>
136
+ <div class="card"><div class="num ${passRate === 100 ? 'green' : passRate >= 80 ? 'yellow' : 'red'}">${passRate}%</div><div class="lbl">Pass Rate</div></div>
137
+ </div>
138
+
139
+ <div class="progress"><div class="progress-bar" style="width:${passRate}%"></div></div>
140
+
141
+ <table>
142
+ <thead>
143
+ <tr><th>Method</th><th>Path</th><th>Status</th><th>Duration</th><th>Retries</th><th>Error</th></tr>
144
+ </thead>
145
+ <tbody>${rows}</tbody>
146
+ </table>
147
+
148
+ <footer>APISnap v${data.version} — MIT License</footer>
149
+ </body>
150
+ </html>`;
151
+ }
152
+ // ─── Main CLI ─────────────────────────────────────────────────────────────────
153
+ program
154
+ .name('apisnap')
155
+ .description('Instant API health-check CLI for Express.js')
156
+ .version(version)
157
+ .option('-p, --port <number>', 'Port your server is running on')
158
+ .option('-H, --header <string>', 'Custom header — can be used multiple times (e.g. -H "Authorization: Bearer TOKEN" -H "x-api-key: SECRET")', collect, [])
159
+ .option('-c, --cookie <string>', 'Cookie string (e.g. "sessionId=abc; token=xyz")')
160
+ .option('-s, --slow <number>', 'Slow response threshold in ms')
161
+ .option('-t, --timeout <number>', 'Request timeout in ms')
162
+ .option('-r, --retry <number>', 'Retry failed requests N times')
163
+ .option('-e, --export <filename>', 'Export JSON report (e.g. report)')
164
+ .option('--html <filename>', 'Export HTML report (e.g. report)')
165
+ .option('--only <methods>', 'Only test specific methods (e.g. "GET,POST")')
166
+ .option('--base-url <url>', 'Override base URL (e.g. https://staging.myapp.com)')
167
+ .option('--params <json>', 'JSON map of param overrides (e.g. \'{"id":"42"}\')')
168
+ .option('--fail-on-slow', 'Exit with code 1 if any slow routes are found')
169
+ .action(async (options) => {
170
+ // Merge config file with CLI options (CLI takes precedence)
171
+ const fileConfig = loadConfigFile();
172
+ const mergedOptions = { ...fileConfig, ...options };
173
+ const port = mergedOptions.port || '3000';
174
+ const slowThreshold = parseInt(mergedOptions.slow || '200');
175
+ const timeout = parseInt(mergedOptions.timeout || '5000');
176
+ const retryCount = parseInt(mergedOptions.retry || '0');
177
+ const onlyMethods = mergedOptions.only
178
+ ? mergedOptions.only.split(',').map((m) => m.trim().toUpperCase())
179
+ : null;
180
+ const paramOverrides = mergedOptions.params
181
+ ? JSON.parse(mergedOptions.params)
182
+ : (fileConfig.params || {});
183
+ const baseUrl = mergedOptions.baseUrl || mergedOptions['base-url'] || `http://localhost:${port}`;
49
184
  const discoveryUrl = `http://localhost:${port}/__apisnap_discovery`;
50
- const results = []; // Collect all test results here
185
+ // Build headers
186
+ const headerArgs = [
187
+ ...(Array.isArray(mergedOptions.header) ? mergedOptions.header : []),
188
+ ...(Array.isArray(fileConfig.headers) ? fileConfig.headers : []),
189
+ ];
190
+ const customHeaders = {
191
+ ...parseHeaders(headerArgs),
192
+ 'User-Agent': `APISnap/${version}`,
193
+ };
194
+ if (mergedOptions.cookie) {
195
+ customHeaders['Cookie'] = mergedOptions.cookie;
196
+ }
197
+ // ── Banner ──────────────────────────────────────────────────────────────
51
198
  console.log(chalk_1.default.bold.cyan(`\n📸 APISnap v${version}`));
52
- console.log(chalk_1.default.gray(` 🔌 Port: ${port} | 🛡️ Auth: ${finalHeaders.Authorization ? 'Detected' : 'None'}\n`));
53
- const spinner = (0, ora_1.default)('Connecting to your API...').start();
199
+ console.log(chalk_1.default.gray(` Target: ${baseUrl}`));
200
+ console.log(chalk_1.default.gray(` Slow: >${slowThreshold}ms`));
201
+ console.log(chalk_1.default.gray(` Timeout: ${timeout}ms`));
202
+ if (retryCount > 0)
203
+ console.log(chalk_1.default.gray(` Retries: ${retryCount}`));
204
+ if (Object.keys(customHeaders).filter(k => k !== 'User-Agent').length > 0) {
205
+ const safeHeaders = { ...customHeaders };
206
+ // Mask auth tokens in output
207
+ Object.keys(safeHeaders).forEach(k => {
208
+ if (/auth|token|key|secret|cookie/i.test(k)) {
209
+ safeHeaders[k] = safeHeaders[k].slice(0, 8) + '••••••';
210
+ }
211
+ });
212
+ delete safeHeaders['User-Agent'];
213
+ console.log(chalk_1.default.gray(` Headers: ${JSON.stringify(safeHeaders)}`));
214
+ }
215
+ if (onlyMethods)
216
+ console.log(chalk_1.default.gray(` Filter: ${onlyMethods.join(', ')}`));
217
+ console.log();
218
+ const spinner = (0, ora_1.default)('Connecting to discovery endpoint...').start();
219
+ const results = [];
54
220
  try {
55
- // 1. Fetch the route map from the middleware
56
- const response = await axios_1.default.get(discoveryUrl);
57
- const { endpoints } = response.data;
58
- spinner.succeed(chalk_1.default.green(`Connected! Found ${endpoints.length} endpoints.\n`));
59
- // Summary counters
60
- let passed = 0;
61
- let failed = 0;
62
- let slow = 0;
63
- // 2. Loop through each discovered endpoint
221
+ // ── Discovery ───────────────────────────────────────────────────────
222
+ const discovery = await axios_1.default.get(discoveryUrl, { timeout: 5000 });
223
+ let { endpoints } = discovery.data;
224
+ // Filter by method if --only flag provided
225
+ if (onlyMethods) {
226
+ endpoints = endpoints.filter((e) => e.methods.some((m) => onlyMethods.includes(m)));
227
+ }
228
+ spinner.succeed(chalk_1.default.green(`Connected! Found ${endpoints.length} endpoint${endpoints.length !== 1 ? 's' : ''} to test.\n`));
229
+ let passed = 0, failed = 0, slow = 0;
230
+ const allDurations = [];
231
+ // ── Test Each Endpoint ───────────────────────────────────────────────
64
232
  for (const endpoint of endpoints) {
65
- const method = endpoint.methods[0];
66
- let path = endpoint.path;
67
- // Smart Parameter Replacement — :id, :slug → 1
68
- if (path.includes(':')) {
69
- path = path.replace(/:[a-zA-Z0-9]+/g, '1');
70
- }
71
- const fullUrl = `http://localhost:${port}${path}`;
72
- const testSpinner = (0, ora_1.default)(`Testing ${chalk_1.default.bold(method)} ${path}`).start();
73
- // Step 8: Initialize result object for this endpoint
233
+ const method = endpoint.methods[0]; // primary method
234
+ const rawPath = endpoint.path;
235
+ const resolvedPath = replacePath(rawPath, paramOverrides);
236
+ const fullUrl = `${baseUrl}${resolvedPath}`;
74
237
  const testResult = {
75
- method,
76
- path,
77
- fullUrl,
78
- status: 0,
79
- duration: 0,
80
- success: false,
81
- slow: false,
238
+ method, path: rawPath, fullUrl,
239
+ status: 0, statusText: '', duration: 0,
240
+ success: false, slow: false, retries: 0,
82
241
  };
83
- try {
84
- const startTime = Date.now();
85
- const res = await (0, axios_1.default)({
86
- method: method,
87
- url: fullUrl,
88
- headers: {
89
- ...finalHeaders,
90
- 'x-apisnap-key': 'apisnap_secret_handshake_2024',
91
- 'User-Agent': `APISnap/${version}`,
92
- },
93
- timeout: 5000,
94
- });
95
- const duration = Date.now() - startTime;
96
- // Step 8: Populate result
97
- testResult.duration = duration;
98
- testResult.status = res.status;
99
- testResult.success = true;
100
- // Step 7: Performance threshold check
101
- let statusIcon = chalk_1.default.green('✔');
102
- let durationColor = chalk_1.default.gray;
103
- if (duration > slowThreshold) {
104
- statusIcon = chalk_1.default.yellow('⚠️ ');
105
- durationColor = chalk_1.default.yellow.bold;
106
- testResult.slow = true;
107
- slow++;
242
+ const testSpinner = (0, ora_1.default)({ text: `${chalk_1.default.bold(method.padEnd(7))} ${chalk_1.default.dim(rawPath)}`, prefixText: ' ' }).start();
243
+ let lastError = null;
244
+ let attempt = 0;
245
+ while (attempt <= retryCount) {
246
+ try {
247
+ const start = Date.now();
248
+ const res = await (0, axios_1.default)({
249
+ method,
250
+ url: fullUrl,
251
+ headers: customHeaders,
252
+ timeout,
253
+ validateStatus: () => true, // Don't throw on 4xx/5xx — we judge ourselves
254
+ });
255
+ const duration = Date.now() - start;
256
+ testResult.duration = duration;
257
+ testResult.status = res.status;
258
+ testResult.statusText = res.statusText;
259
+ testResult.retries = attempt;
260
+ testResult.success = res.status < 400;
261
+ testResult.slow = duration > slowThreshold;
262
+ allDurations.push(duration);
263
+ if (testResult.success) {
264
+ const durationStr = testResult.slow
265
+ ? chalk_1.default.yellow.bold(`${duration}ms slow!`)
266
+ : chalk_1.default.gray(`${duration}ms`);
267
+ const msg = `${chalk_1.default.bold(method.padEnd(7))} ${chalk_1.default.white(rawPath.padEnd(35))} ` +
268
+ `${chalk_1.default.green(`[${res.status}]`)} ${durationStr}`;
269
+ if (testResult.slow) {
270
+ testSpinner.warn(msg);
271
+ }
272
+ else {
273
+ testSpinner.succeed(msg);
274
+ }
275
+ passed++;
276
+ if (testResult.slow)
277
+ slow++;
278
+ }
279
+ else {
280
+ testSpinner.fail(`${chalk_1.default.bold(method.padEnd(7))} ${chalk_1.default.white(rawPath.padEnd(35))} ` +
281
+ `${chalk_1.default.red(`[${res.status} ${res.statusText}]`)} ${chalk_1.default.gray(`${duration}ms`)}`);
282
+ // Helpful hint for auth errors
283
+ if (res.status === 401) {
284
+ console.log(chalk_1.default.yellow(` 💡 Hint: 401 Unauthorized — try adding -H "Authorization: Bearer YOUR_TOKEN" or --cookie "sessionId=abc"`));
285
+ }
286
+ else if (res.status === 403) {
287
+ console.log(chalk_1.default.yellow(` 💡 Hint: 403 Forbidden — your token may lack permission for this route`));
288
+ }
289
+ else if (res.status === 404) {
290
+ console.log(chalk_1.default.yellow(` 💡 Hint: 404 Not Found — path param replacement may need --params '{"id":"YOUR_ID"}'`));
291
+ }
292
+ failed++;
293
+ }
294
+ lastError = null;
295
+ break; // success, stop retrying
296
+ }
297
+ catch (err) {
298
+ lastError = err;
299
+ attempt++;
300
+ if (attempt <= retryCount) {
301
+ await new Promise(r => setTimeout(r, 500 * attempt)); // backoff
302
+ }
108
303
  }
109
- testSpinner.succeed(`${statusIcon} ${chalk_1.default.bold(method)} ${chalk_1.default.white(path)} ` +
110
- `${chalk_1.default.green(`[${res.status} OK]`)} ` +
111
- `${durationColor(`${duration}ms`)}`);
112
- passed++;
113
304
  }
114
- catch (err) {
115
- testResult.status = err.response?.status || 500;
305
+ if (lastError) {
116
306
  testResult.success = false;
117
- const status = err.response?.status || 'FAIL';
118
- testSpinner.fail(`${chalk_1.default.bold(method)} ${chalk_1.default.white(path)} ` +
119
- `${chalk_1.default.red(`[${status}]`)}`);
307
+ testResult.retries = attempt - 1;
308
+ testResult.error = lastError.code === 'ECONNABORTED' ? 'Timeout' : lastError.message;
309
+ testSpinner.fail(`${chalk_1.default.bold(method.padEnd(7))} ${chalk_1.default.white(rawPath.padEnd(35))} ` +
310
+ chalk_1.default.red(`[${testResult.error}]`));
120
311
  failed++;
121
312
  }
122
- results.push(testResult); // Step 8: Save result to list
313
+ results.push(testResult);
123
314
  }
124
- // Summary Statistics
315
+ // ── Summary ──────────────────────────────────────────────────────────
316
+ const avgDuration = allDurations.length > 0
317
+ ? Math.round(allDurations.reduce((a, b) => a + b, 0) / allDurations.length)
318
+ : 0;
319
+ const totalDuration = allDurations.reduce((a, b) => a + b, 0);
125
320
  console.log(chalk_1.default.bold('\n📊 Summary:'));
126
- console.log(chalk_1.default.green(` ✅ Passed: ${passed}`));
127
- console.log(chalk_1.default.red(` ❌ Failed: ${failed}`));
128
- console.log(chalk_1.default.yellow(` ⚠️ Slow: ${slow} (>${slowThreshold}ms)`));
321
+ console.log(` ${chalk_1.default.green('✅ Passed: ')} ${chalk_1.default.bold(passed)}`);
322
+ console.log(` ${chalk_1.default.red('❌ Failed: ')} ${chalk_1.default.bold(failed)}`);
323
+ console.log(` ${chalk_1.default.yellow('⚠️ Slow: ')} ${chalk_1.default.bold(slow)} (>${slowThreshold}ms)`);
324
+ console.log(` ${chalk_1.default.cyan('⏱ Avg: ')} ${chalk_1.default.bold(avgDuration + 'ms')}`);
325
+ console.log(` ${chalk_1.default.cyan('🕐 Total: ')} ${chalk_1.default.bold(totalDuration + 'ms')}`);
129
326
  if (failed > 0) {
130
327
  console.log(chalk_1.default.red.bold('\n⚠️ Some endpoints are unhealthy!'));
131
328
  }
132
329
  else if (slow > 0) {
133
- console.log(chalk_1.default.yellow.bold('\n🐢 All endpoints alive, but some are slow!'));
330
+ console.log(chalk_1.default.yellow.bold('\n🐢 All alive, but some routes are slow!'));
134
331
  }
135
332
  else {
136
333
  console.log(chalk_1.default.green.bold('\n✨ All systems nominal!'));
137
334
  }
138
- // Step 8: Export report to JSON file
139
- if (options.export) {
140
- const filePath = options.export.endsWith('.json')
141
- ? options.export
142
- : `${options.export}.json`;
143
- const reportData = {
144
- tool: 'APISnap',
145
- generatedAt: new Date().toISOString(),
146
- config: {
147
- port,
148
- slowThreshold,
149
- headers: finalHeaders,
150
- },
151
- summary: {
152
- total: endpoints.length,
153
- passed,
154
- failed,
155
- slow,
156
- },
157
- results,
158
- };
335
+ // ── Auth Troubleshooting Summary ─────────────────────────────────────
336
+ const authFailures = results.filter(r => r.status === 401 || r.status === 403);
337
+ if (authFailures.length > 0 && !headerArgs.length && !mergedOptions.cookie) {
338
+ console.log(chalk_1.default.bgYellow.black.bold('\n🔐 Auth Help'));
339
+ console.log(chalk_1.default.yellow(' You have ' + authFailures.length + ' auth failure(s) and no credentials were provided.'));
340
+ console.log(chalk_1.default.yellow(' Solutions:'));
341
+ console.log(chalk_1.default.gray(' JWT: apisnap -H "Authorization: Bearer YOUR_JWT_TOKEN"'));
342
+ console.log(chalk_1.default.gray(' API Key: apisnap -H "x-api-key: YOUR_KEY"'));
343
+ console.log(chalk_1.default.gray(' Cookie: apisnap --cookie "sessionId=abc123"'));
344
+ console.log(chalk_1.default.gray(' Multi: apisnap -H "Authorization: Bearer TOKEN" -H "x-tenant: acme"'));
345
+ console.log(chalk_1.default.gray(' Config: create .apisnaprc.json (see README)\n'));
346
+ }
347
+ // ── Exports ──────────────────────────────────────────────────────────
348
+ const reportData = {
349
+ tool: 'APISnap', version,
350
+ generatedAt: new Date().toISOString(),
351
+ config: { port, baseUrl, slowThreshold, timeout, headers: Object.keys(customHeaders).filter(k => k !== 'User-Agent') },
352
+ summary: { total: endpoints.length, passed, failed, slow, avgDuration, totalDuration },
353
+ results,
354
+ };
355
+ if (mergedOptions.export) {
356
+ const filePath = mergedOptions.export.endsWith('.json') ? mergedOptions.export : `${mergedOptions.export}.json`;
159
357
  fs_1.default.writeFileSync(filePath, JSON.stringify(reportData, null, 2));
160
- console.log(chalk_1.default.cyan.bold(`\n💾 Report saved to: ${chalk_1.default.white(filePath)}`));
358
+ console.log(chalk_1.default.cyan(`\n💾 JSON report ${chalk_1.default.white(filePath)}`));
161
359
  }
360
+ if (mergedOptions.html) {
361
+ const filePath = mergedOptions.html.endsWith('.html') ? mergedOptions.html : `${mergedOptions.html}.html`;
362
+ fs_1.default.writeFileSync(filePath, generateHTMLReport(reportData));
363
+ console.log(chalk_1.default.cyan(`🌐 HTML report → ${chalk_1.default.white(filePath)}`));
364
+ }
365
+ console.log();
366
+ // Exit codes for CI/CD
367
+ const shouldFail = failed > 0 || (mergedOptions['fail-on-slow'] && slow > 0);
368
+ process.exit(shouldFail ? 1 : 0);
162
369
  }
163
370
  catch (error) {
164
- spinner.fail(chalk_1.default.red(`Failed to connect to ${discoveryUrl}`));
165
- console.log(chalk_1.default.yellow('Is your server running? Make sure apisnap.init(app) is added.\n'));
371
+ spinner.fail(chalk_1.default.red(`Cannot reach discovery endpoint: ${discoveryUrl}`));
372
+ console.log(chalk_1.default.yellow('\n Checklist:'));
373
+ console.log(chalk_1.default.gray(' 1. Is your server running? (e.g. node server.js)'));
374
+ console.log(chalk_1.default.gray(' 2. Did you call apisnap.init(app) in your server?'));
375
+ console.log(chalk_1.default.gray(' 3. Is the port correct? (default 3000, use -p PORT)'));
376
+ console.log(chalk_1.default.gray(' 4. Is apisnap.init(app) placed AFTER your routes?\n'));
166
377
  process.exit(1);
167
378
  }
168
379
  });
169
- program
170
- .command('init')
171
- .description('Initialize APISnap configuration files')
172
- .action(() => {
173
- const sharedConfig = {
174
- port: 3000,
175
- slowThreshold: 200,
176
- description: "Shared project API settings"
177
- };
178
- const localConfig = {
179
- headers: {
180
- Authorization: "Bearer YOUR_PRIVATE_TOKEN_HERE"
181
- }
182
- };
183
- // Create the files in the user's current directory
184
- fs_1.default.writeFileSync('apisnap.json', JSON.stringify(sharedConfig, null, 2));
185
- fs_1.default.writeFileSync('apisnap.local.json', JSON.stringify(localConfig, null, 2));
186
- console.log(chalk_1.default.green.bold('\n✨ APISnap Initialized Successfully!'));
187
- console.log(chalk_1.default.cyan('Created:'));
188
- console.log(` 📄 ${chalk_1.default.white('apisnap.json')} (Shared - Push to GitHub)`);
189
- console.log(` 📄 ${chalk_1.default.yellow('apisnap.local.json')} (Private - DO NOT PUSH)`);
190
- console.log(chalk_1.default.red.bold('\n⚠️ IMPORTANT SECURITY STEP:'));
191
- console.log(`Add ${chalk_1.default.yellow.bold('apisnap.local.json')} to your ${chalk_1.default.white('.gitignore')} file now!\n`);
192
- });
380
+ // Allows -H to be used multiple times
381
+ function collect(val, prev) {
382
+ return prev.concat([val]);
383
+ }
193
384
  program.parse(process.argv);
194
385
  //# sourceMappingURL=runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,12 @@
1
- export declare const init: (app: any) => void;
1
+ export interface APISnapOptions {
2
+ /** Routes to skip during health checks (e.g. ['/admin', '/internal']) */
3
+ skip?: string[];
4
+ /** Custom name shown in discovery response */
5
+ name?: string;
6
+ }
7
+ export declare const init: (app: any, options?: APISnapOptions) => void;
2
8
  declare const _default: {
3
- init: (app: any) => void;
9
+ init: (app: any, options?: APISnapOptions) => void;
4
10
  };
5
11
  export default _default;
6
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,GAAI,KAAK,GAAG,SA2F5B,CAAC;;gBA3FwB,GAAG;;AA6F7B,wBAAwB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC3B,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,IAAI,GAAI,KAAK,GAAG,EAAE,UAAS,cAAmB,SA6F1D,CAAC;;gBA7FwB,GAAG,YAAW,cAAc;;AA+FtD,wBAAwB"}
@@ -1,43 +1,33 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.init = void 0;
4
- const init = (app) => {
5
- const MASTER_KEY = 'apisnap_secret_handshake_2024';
4
+ const init = (app, options = {}) => {
6
5
  const DISCOVERY_PATH = '/__apisnap_discovery';
7
- // --- THE VIP GATE ---
8
- app.use((req, res, next) => {
9
- const clientKey = req.headers['x-apisnap-key'];
10
- const isLocal = req.hostname === 'localhost' || req.hostname === '127.0.0.1';
11
- // If the key matches AND it's local, we bypass ALL other auth (Better Auth, etc.)
12
- if (clientKey === MASTER_KEY && isLocal) {
13
- // We "mock" a dev user so the routes think someone is logged in
14
- req.user = { id: 'dev-bypass', role: 'admin', name: 'APISnap-Bot' };
15
- return next();
16
- }
17
- next();
18
- });
19
- // Recursive function to find ALL routes, even in sub-routers
20
- const splitRoutes = (stack, prefix = '') => {
6
+ const skipList = options.skip || [];
7
+ // ─── Recursive Route Extractor ────────────────────────────────────────────
8
+ const extractRoutes = (stack, prefix = '') => {
21
9
  let routes = [];
22
10
  stack.forEach((layer) => {
23
11
  if (layer.route) {
24
- // Simple direct route
25
- const path = prefix + layer.route.path;
26
- const methods = Object.keys(layer.route.methods).map((m) => m.toUpperCase());
27
- routes.push({ path: path.replace('//', '/'), methods });
12
+ const path = (prefix + layer.route.path).replace('//', '/');
13
+ // Skip the discovery endpoint itself and any user-skipped paths
14
+ if (path === DISCOVERY_PATH)
15
+ return;
16
+ if (skipList.some((s) => path.startsWith(s)))
17
+ return;
18
+ const methods = Object.keys(layer.route.methods)
19
+ .filter((m) => m !== '_all')
20
+ .map((m) => m.toUpperCase());
21
+ routes.push({ path, methods });
28
22
  }
29
23
  else if (layer.handle && layer.handle.stack) {
30
- // Nested Router - GO DEEPER
31
- // Extract the prefix from the regexp (e.g. /api or /api/community)
32
24
  let rStr = layer.regexp.toString();
33
25
  let routerPrefix = '';
34
- // Try to match standard Express router regexp: /^\/api\/?(?=\/|$)/i
35
26
  const standardMatch = rStr.match(/^\/\^\\\/(.*?)\\\/\?\(\?\=\\\/\|\$\)\/i$/);
36
27
  if (standardMatch) {
37
28
  routerPrefix = standardMatch[1];
38
29
  }
39
30
  else {
40
- // Fallback for custom or older regexes
41
31
  const fallbackMatch = rStr.match(/^\/\^\\?(.*?)\\?\/?(?:\(\?=\\\/\|\$\))?\//);
42
32
  routerPrefix = fallbackMatch ? fallbackMatch[1] : '';
43
33
  }
@@ -45,32 +35,31 @@ const init = (app) => {
45
35
  if (routerPrefix && !routerPrefix.startsWith('/')) {
46
36
  routerPrefix = '/' + routerPrefix;
47
37
  }
48
- // Avoid double slashes in concatenation
49
38
  const newPrefix = (prefix + routerPrefix).replace(/\/\//g, '/');
50
- routes = routes.concat(splitRoutes(layer.handle.stack, newPrefix));
39
+ routes = routes.concat(extractRoutes(layer.handle.stack, newPrefix));
51
40
  }
52
41
  });
53
42
  return routes;
54
43
  };
44
+ // ─── Discovery Endpoint ───────────────────────────────────────────────────
45
+ // IMPORTANT: This is registered FIRST so auth middleware added later won't
46
+ // wrap it. If your auth is global (app.use), see the bypass middleware below.
55
47
  app.get(DISCOVERY_PATH, (req, res) => {
56
48
  try {
57
- // Safely get Express router (v4 uses _router, v5 uses router)
58
49
  let router = app._router;
59
50
  if (!router) {
60
51
  try {
61
52
  router = app.router;
62
53
  }
63
- catch (err) {
64
- // Ignore getter deprecation errors from Express 4
65
- }
54
+ catch (_) { }
66
55
  }
67
56
  if (!router) {
68
- res.status(500).json({ error: 'Router not initialized yet' });
69
- return;
57
+ return res.status(500).json({ error: 'Router not initialized yet. Make sure apisnap.init(app) is called after your routes.' });
70
58
  }
71
- const allRoutes = splitRoutes(router.stack);
59
+ const allRoutes = extractRoutes(router.stack);
72
60
  res.json({
73
- name: 'APISnap Discovery',
61
+ tool: 'APISnap',
62
+ appName: options.name || 'Express App',
74
63
  timestamp: new Date().toISOString(),
75
64
  total: allRoutes.length,
76
65
  endpoints: allRoutes,
@@ -80,7 +69,27 @@ const init = (app) => {
80
69
  res.status(500).json({ error: 'Failed to parse routes', detail: e.message });
81
70
  }
82
71
  });
83
- console.log(`\x1b[32m%s\x1b[0m`, `✅ [APISnap] Discovery active at ${DISCOVERY_PATH}`);
72
+ // ─── Auth Bypass Middleware ───────────────────────────────────────────────
73
+ // This intercepts requests to the discovery path and short-circuits any
74
+ // downstream auth middleware the user may have added globally.
75
+ // Works by monkey-patching app.use to detect auth-style middleware.
76
+ const originalUse = app.use.bind(app);
77
+ app.use = function (...args) {
78
+ // If it's a global middleware (no path), wrap it to skip discovery route
79
+ if (typeof args[0] === 'function') {
80
+ const originalMiddleware = args[0];
81
+ args[0] = (req, res, next) => {
82
+ if (req.path === DISCOVERY_PATH)
83
+ return next();
84
+ return originalMiddleware(req, res, next);
85
+ };
86
+ }
87
+ return originalUse(...args);
88
+ };
89
+ console.log(`\x1b[32m✅ [APISnap] Discovery active → http://localhost:PORT${DISCOVERY_PATH}\x1b[0m`);
90
+ if (skipList.length > 0) {
91
+ console.log(`\x1b[33m⏭ [APISnap] Skipping: ${skipList.join(', ')}\x1b[0m`);
92
+ }
84
93
  };
85
94
  exports.init = init;
86
95
  exports.default = { init: exports.init };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,42 +1,42 @@
1
- {
2
- "name": "@umeshindu222/apisnap",
3
- "version": "1.1.2",
4
- "description": "Instant API auto-discovery and health-check CLI for Express.js",
5
- "main": "dist/middleware/index.js",
6
- "types": "dist/middleware/index.d.ts",
7
- "bin": {
8
- "apisnap": "bin/cli.js"
9
- },
10
- "files": [
11
- "dist",
12
- "bin",
13
- "README.md"
14
- ],
15
- "scripts": {
16
- "build": "tsc",
17
- "prepublishOnly": "npm run build"
18
- },
19
- "keywords": [
20
- "express",
21
- "api",
22
- "testing",
23
- "health-check",
24
- "cli",
25
- "automation"
26
- ],
27
- "author": "Umesh Induranga",
28
- "license": "MIT",
29
- "dependencies": {
30
- "axios": "^1.13.6",
31
- "chalk": "^5.6.2",
32
- "commander": "^14.0.3",
33
- "express": "^4.22.1",
34
- "ora": "^9.3.0"
35
- },
36
- "devDependencies": {
37
- "@types/express": "^5.0.6",
38
- "@types/node": "^25.3.3",
39
- "ts-node": "^10.9.2",
40
- "typescript": "^5.9.3"
41
- }
42
- }
1
+ {
2
+ "name": "@umeshindu222/apisnap",
3
+ "version": "1.1.4",
4
+ "description": "Instant API auto-discovery and health-check CLI for Express.js",
5
+ "main": "dist/middleware/index.js",
6
+ "types": "dist/middleware/index.d.ts",
7
+ "bin": {
8
+ "apisnap": "bin/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "bin",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "keywords": [
20
+ "express",
21
+ "api",
22
+ "testing",
23
+ "health-check",
24
+ "cli",
25
+ "automation"
26
+ ],
27
+ "author": "Umesh Induranga",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "axios": "^1.13.6",
31
+ "chalk": "^5.6.2",
32
+ "commander": "^14.0.3",
33
+ "express": "^4.22.1",
34
+ "ora": "^9.3.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/express": "^5.0.6",
38
+ "@types/node": "^25.3.3",
39
+ "ts-node": "^10.9.2",
40
+ "typescript": "^5.9.3"
41
+ }
42
+ }