@rvanbaalen/roxyproxy 0.1.1

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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +658 -0
  3. package/dist/cli/banner.d.ts +6 -0
  4. package/dist/cli/banner.js +30 -0
  5. package/dist/cli/banner.js.map +1 -0
  6. package/dist/cli/commands/clear.d.ts +2 -0
  7. package/dist/cli/commands/clear.js +35 -0
  8. package/dist/cli/commands/clear.js.map +1 -0
  9. package/dist/cli/commands/proxy-off.d.ts +2 -0
  10. package/dist/cli/commands/proxy-off.js +19 -0
  11. package/dist/cli/commands/proxy-off.js.map +1 -0
  12. package/dist/cli/commands/proxy-on.d.ts +2 -0
  13. package/dist/cli/commands/proxy-on.js +20 -0
  14. package/dist/cli/commands/proxy-on.js.map +1 -0
  15. package/dist/cli/commands/request.d.ts +2 -0
  16. package/dist/cli/commands/request.js +23 -0
  17. package/dist/cli/commands/request.js.map +1 -0
  18. package/dist/cli/commands/requests.d.ts +2 -0
  19. package/dist/cli/commands/requests.js +46 -0
  20. package/dist/cli/commands/requests.js.map +1 -0
  21. package/dist/cli/commands/start.d.ts +2 -0
  22. package/dist/cli/commands/start.js +41 -0
  23. package/dist/cli/commands/start.js.map +1 -0
  24. package/dist/cli/commands/status.d.ts +2 -0
  25. package/dist/cli/commands/status.js +44 -0
  26. package/dist/cli/commands/status.js.map +1 -0
  27. package/dist/cli/commands/stop.d.ts +2 -0
  28. package/dist/cli/commands/stop.js +52 -0
  29. package/dist/cli/commands/stop.js.map +1 -0
  30. package/dist/cli/commands/trust-ca.d.ts +2 -0
  31. package/dist/cli/commands/trust-ca.js +134 -0
  32. package/dist/cli/commands/trust-ca.js.map +1 -0
  33. package/dist/cli/format.d.ts +3 -0
  34. package/dist/cli/format.js +112 -0
  35. package/dist/cli/format.js.map +1 -0
  36. package/dist/cli/index.d.ts +2 -0
  37. package/dist/cli/index.js +35 -0
  38. package/dist/cli/index.js.map +1 -0
  39. package/dist/cli/interactive.d.ts +1 -0
  40. package/dist/cli/interactive.js +408 -0
  41. package/dist/cli/interactive.js.map +1 -0
  42. package/dist/cli/system-proxy.d.ts +14 -0
  43. package/dist/cli/system-proxy.js +115 -0
  44. package/dist/cli/system-proxy.js.map +1 -0
  45. package/dist/server/api.d.ts +10 -0
  46. package/dist/server/api.js +109 -0
  47. package/dist/server/api.js.map +1 -0
  48. package/dist/server/config.d.ts +6 -0
  49. package/dist/server/config.js +66 -0
  50. package/dist/server/config.js.map +1 -0
  51. package/dist/server/events.d.ts +20 -0
  52. package/dist/server/events.js +49 -0
  53. package/dist/server/events.js.map +1 -0
  54. package/dist/server/index.d.ts +20 -0
  55. package/dist/server/index.js +91 -0
  56. package/dist/server/index.js.map +1 -0
  57. package/dist/server/proxy.d.ts +27 -0
  58. package/dist/server/proxy.js +245 -0
  59. package/dist/server/proxy.js.map +1 -0
  60. package/dist/server/ssl.d.ts +17 -0
  61. package/dist/server/ssl.js +88 -0
  62. package/dist/server/ssl.js.map +1 -0
  63. package/dist/shared/types.d.ts +53 -0
  64. package/dist/shared/types.js +10 -0
  65. package/dist/shared/types.js.map +1 -0
  66. package/dist/storage/cleanup.d.ts +11 -0
  67. package/dist/storage/cleanup.js +32 -0
  68. package/dist/storage/cleanup.js.map +1 -0
  69. package/dist/storage/db.d.ts +17 -0
  70. package/dist/storage/db.js +152 -0
  71. package/dist/storage/db.js.map +1 -0
  72. package/dist/ui/assets/index-C8qts74N.js +9 -0
  73. package/dist/ui/assets/index-CrfXQK5U.css +2 -0
  74. package/dist/ui/index.html +13 -0
  75. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robin van Baalen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,658 @@
1
+ # RoxyProxy
2
+
3
+ HTTP/HTTPS intercepting proxy with a CLI and web UI. Captures traffic, stores it in SQLite, and makes it queryable -- by humans and LLMs alike.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Interactive Mode](#interactive-mode)
10
+ - [CLI Commands](#cli-commands)
11
+ - [start](#start)
12
+ - [stop](#stop)
13
+ - [status](#status)
14
+ - [requests](#requests)
15
+ - [request](#request)
16
+ - [clear](#clear)
17
+ - [trust-ca](#trust-ca)
18
+ - [proxy-on](#proxy-on-macos)
19
+ - [proxy-off](#proxy-off-macos)
20
+ - [Web UI](#web-ui)
21
+ - [HTTPS Interception](#https-interception)
22
+ - [System Proxy](#system-proxy-macos)
23
+ - [Configuration](#configuration)
24
+ - [REST API](#rest-api)
25
+ - [Architecture](#architecture)
26
+ - [Development](#development)
27
+
28
+ ---
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ git clone <repo-url>
34
+ cd roxyproxy
35
+ npm install
36
+ npm run build
37
+ ```
38
+
39
+ To make the `roxyproxy` command available globally:
40
+
41
+ ```bash
42
+ npm link
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # Start the proxy (default: proxy on :8080, web UI on :8081)
49
+ roxyproxy start
50
+
51
+ # Route traffic through it
52
+ curl -x http://127.0.0.1:8080 http://httpbin.org/get
53
+
54
+ # View captured traffic
55
+ roxyproxy requests --format table
56
+
57
+ # Open the web UI
58
+ open http://127.0.0.1:8081
59
+
60
+ # Stop
61
+ roxyproxy stop
62
+ ```
63
+
64
+ For HTTPS interception, trust the CA certificate first:
65
+
66
+ ```bash
67
+ roxyproxy start
68
+ roxyproxy trust-ca
69
+ curl -x http://127.0.0.1:8080 https://api.example.com/endpoint
70
+ ```
71
+
72
+ ## Interactive Mode
73
+
74
+ Running `roxyproxy` with no arguments launches an interactive terminal menu:
75
+
76
+ ```bash
77
+ roxyproxy
78
+ ```
79
+
80
+ The interactive menu provides access to all features:
81
+
82
+ - **Start/Stop proxy** -- toggle the proxy server on and off
83
+ - **Status** -- view proxy stats (port, request count, DB size)
84
+ - **View requests** -- browse captured traffic in the terminal
85
+ - **Clear traffic** -- delete all captured requests
86
+ - **Open web UI** -- opens the dashboard in your browser (auto-starts the proxy if needed)
87
+ - **Trust CA certificate** -- install the CA cert for HTTPS interception
88
+ - **Enable/Disable system proxy** -- route all macOS traffic through RoxyProxy
89
+ - **Quit** -- stop the proxy and exit
90
+
91
+ Use arrow keys to navigate and Enter to select. Press `q` or Ctrl+C to quit.
92
+
93
+ The interactive mode stays in sync with the web UI -- if you stop the proxy from the web dashboard, the CLI menu updates within a second, and vice versa.
94
+
95
+ ---
96
+
97
+ ## CLI Commands
98
+
99
+ ### start
100
+
101
+ Start the proxy server in the foreground.
102
+
103
+ ```bash
104
+ roxyproxy start [options]
105
+ ```
106
+
107
+ | Option | Default | Description |
108
+ |---|---|---|
109
+ | `--port <number>` | `8080` | Proxy listening port |
110
+ | `--ui-port <number>` | `8081` | Web UI and API port |
111
+ | `--db-path <path>` | `~/.roxyproxy/data.db` | SQLite database location |
112
+
113
+ ```bash
114
+ # Default ports
115
+ roxyproxy start
116
+
117
+ # Custom ports
118
+ roxyproxy start --port 9000 --ui-port 9001
119
+
120
+ # Custom database location
121
+ roxyproxy start --db-path /tmp/proxy.db
122
+ ```
123
+
124
+ The process writes its PID to `~/.roxyproxy/pid` and responds to SIGINT/SIGTERM for graceful shutdown.
125
+
126
+ ### stop
127
+
128
+ Stop the running proxy server.
129
+
130
+ ```bash
131
+ roxyproxy stop [options]
132
+ ```
133
+
134
+ | Option | Default | Description |
135
+ |---|---|---|
136
+ | `--ui-port <number>` | `8081` | API port to send shutdown request to |
137
+
138
+ Sends a graceful shutdown request via the API. Falls back to SIGTERM via the PID file if the API is unreachable.
139
+
140
+ ```bash
141
+ roxyproxy stop
142
+ roxyproxy stop --ui-port 9001
143
+ ```
144
+
145
+ ### status
146
+
147
+ Show proxy status.
148
+
149
+ ```bash
150
+ roxyproxy status [options]
151
+ ```
152
+
153
+ | Option | Default | Description |
154
+ |---|---|---|
155
+ | `--ui-port <number>` | `8081` | API port to query |
156
+
157
+ ```bash
158
+ roxyproxy status
159
+ ```
160
+
161
+ Output:
162
+
163
+ ```
164
+ Status Running
165
+ Proxy port 8080
166
+ Requests 142
167
+ DB Size 3.2MB
168
+ ```
169
+
170
+ ### requests
171
+
172
+ Query captured requests from the database.
173
+
174
+ ```bash
175
+ roxyproxy requests [options]
176
+ ```
177
+
178
+ | Option | Default | Description |
179
+ |---|---|---|
180
+ | `--host <pattern>` | | Filter by hostname (substring match) |
181
+ | `--status <code>` | | Filter by HTTP status code |
182
+ | `--method <method>` | | Filter by HTTP method |
183
+ | `--search <pattern>` | | Search URLs (substring match) |
184
+ | `--since <time>` | | After this time (Unix ms or ISO date) |
185
+ | `--until <time>` | | Before this time (Unix ms or ISO date) |
186
+ | `--limit <n>` | `100` | Maximum number of results |
187
+ | `--format <format>` | `json` | Output format: `json` or `table` |
188
+ | `--db-path <path>` | `~/.roxyproxy/data.db` | Database location |
189
+
190
+ The default JSON output is designed for piping to `jq` or feeding to LLMs:
191
+
192
+ ```bash
193
+ # All 500 errors
194
+ roxyproxy requests --status 500
195
+
196
+ # POST requests to a specific host
197
+ roxyproxy requests --host api.example.com --method POST
198
+
199
+ # Search URLs
200
+ roxyproxy requests --search "/api/v2"
201
+
202
+ # Human-readable table
203
+ roxyproxy requests --format table --limit 20
204
+
205
+ # Time-bounded query
206
+ roxyproxy requests --since "2024-01-15T00:00:00Z" --until "2024-01-16T00:00:00Z"
207
+
208
+ # Pipe to jq
209
+ roxyproxy requests --host stripe.com | jq '.data[].url'
210
+ ```
211
+
212
+ ### request
213
+
214
+ Show full details of a single captured request, including headers and bodies.
215
+
216
+ ```bash
217
+ roxyproxy request <id> [options]
218
+ ```
219
+
220
+ | Option | Default | Description |
221
+ |---|---|---|
222
+ | `--format <format>` | `json` | Output format: `json` or `table` |
223
+ | `--db-path <path>` | `~/.roxyproxy/data.db` | Database location |
224
+
225
+ ```bash
226
+ roxyproxy request a1b2c3d4-e5f6-7890-abcd-ef1234567890
227
+ roxyproxy request a1b2c3d4-e5f6-7890-abcd-ef1234567890 --format table
228
+ ```
229
+
230
+ ### clear
231
+
232
+ Delete all captured traffic from the database.
233
+
234
+ ```bash
235
+ roxyproxy clear [options]
236
+ ```
237
+
238
+ | Option | Default | Description |
239
+ |---|---|---|
240
+ | `--ui-port <number>` | `8081` | API port |
241
+
242
+ ```bash
243
+ roxyproxy clear
244
+ ```
245
+
246
+ ### trust-ca
247
+
248
+ Install and trust the RoxyProxy CA certificate for HTTPS interception.
249
+
250
+ ```bash
251
+ roxyproxy trust-ca [options]
252
+ ```
253
+
254
+ | Option | Description |
255
+ |---|---|
256
+ | `--no-interactive` | Skip prompts; print cert path and manual instructions |
257
+
258
+ ```bash
259
+ # Interactive (prompts for sudo password)
260
+ roxyproxy trust-ca
261
+
262
+ # Non-interactive (CI, scripts)
263
+ roxyproxy trust-ca --no-interactive
264
+ ```
265
+
266
+ See [HTTPS Interception](#https-interception) for details.
267
+
268
+ ### proxy-on (macOS)
269
+
270
+ Configure RoxyProxy as the system-wide HTTP/HTTPS proxy.
271
+
272
+ ```bash
273
+ roxyproxy proxy-on [options]
274
+ ```
275
+
276
+ | Option | Default | Description |
277
+ |---|---|---|
278
+ | `--port <number>` | `8080` | Proxy port |
279
+ | `--service <name>` | auto-detected | Network service (e.g., "Wi-Fi", "Ethernet") |
280
+
281
+ ```bash
282
+ roxyproxy proxy-on
283
+ roxyproxy proxy-on --port 9000 --service "Wi-Fi"
284
+ ```
285
+
286
+ ### proxy-off (macOS)
287
+
288
+ Remove RoxyProxy from system proxy settings.
289
+
290
+ ```bash
291
+ roxyproxy proxy-off [options]
292
+ ```
293
+
294
+ | Option | Default | Description |
295
+ |---|---|---|
296
+ | `--service <name>` | auto-detected | Network service |
297
+
298
+ ```bash
299
+ roxyproxy proxy-off
300
+ ```
301
+
302
+ ---
303
+
304
+ ## Web UI
305
+
306
+ Available at `http://127.0.0.1:8081` when the proxy is running.
307
+
308
+ ### Features
309
+
310
+ - **Live traffic stream** -- requests appear in real-time via Server-Sent Events
311
+ - **Historical traffic** -- previously captured requests load on page open
312
+ - **Sortable columns** -- click any column header to sort (Time, Method, Status, Host, Path, Duration, Size)
313
+ - **Resizable columns** -- drag column borders to adjust widths
314
+ - **Request detail panel** -- click any row to inspect headers and response body in a resizable side panel
315
+ - **Filters** -- filter by host, status code, HTTP method, or URL search
316
+ - **Proxy controls** -- start/stop the proxy and clear traffic directly from the UI
317
+ - **Live sync** -- start/stop state is synchronized between the web UI and CLI in real-time
318
+
319
+ ### Keyboard Shortcuts
320
+
321
+ The filter bar is always accessible. Type in any filter field to narrow results instantly.
322
+
323
+ ---
324
+
325
+ ## HTTPS Interception
326
+
327
+ RoxyProxy performs HTTPS interception via a local Certificate Authority (CA).
328
+
329
+ ### How it works
330
+
331
+ 1. On first startup, RoxyProxy generates a root CA certificate and private key at `~/.roxyproxy/ca/`
332
+ 2. When a client sends a CONNECT request (HTTPS), RoxyProxy:
333
+ - Accepts the tunnel
334
+ - Generates a per-domain certificate signed by the CA on the fly
335
+ - Terminates TLS with the client using the generated cert
336
+ - Opens a separate TLS connection to the real server
337
+ - Forwards traffic in both directions, capturing it along the way
338
+
339
+ ### Setup
340
+
341
+ **Step 1: Start the proxy** (generates the CA if it doesn't exist)
342
+
343
+ ```bash
344
+ roxyproxy start
345
+ ```
346
+
347
+ **Step 2: Trust the CA certificate**
348
+
349
+ ```bash
350
+ roxyproxy trust-ca
351
+ ```
352
+
353
+ This runs the platform-specific trust command:
354
+
355
+ | Platform | What happens |
356
+ |---|---|
357
+ | **macOS** | Adds to System Keychain via `security add-trusted-cert` (requires sudo) |
358
+ | **Linux** | Copies to `/usr/local/share/ca-certificates/` and runs `update-ca-certificates` (requires sudo) |
359
+ | **Firefox** | Must be done manually: Settings > Privacy & Security > Certificates > View Certificates > Import `~/.roxyproxy/ca/ca.crt` |
360
+
361
+ **Step 3: Route HTTPS traffic through the proxy**
362
+
363
+ ```bash
364
+ # Via explicit proxy flag
365
+ curl -x http://127.0.0.1:8080 https://api.example.com/data
366
+
367
+ # Or enable system-wide proxy (macOS)
368
+ roxyproxy proxy-on
369
+ ```
370
+
371
+ ### Certificate Details
372
+
373
+ | Property | Value |
374
+ |---|---|
375
+ | CA location | `~/.roxyproxy/ca/ca.crt` and `ca.key` |
376
+ | CA validity | 10 years |
377
+ | CA subject | "RoxyProxy CA" |
378
+ | Per-domain cert validity | 1 year |
379
+ | Key size | 2048-bit RSA |
380
+ | Signature algorithm | SHA-256 |
381
+ | Domain cert cache | LRU, default 500 entries (configurable) |
382
+
383
+ ---
384
+
385
+ ## System Proxy (macOS)
386
+
387
+ On macOS, RoxyProxy can configure itself as the system-wide HTTP/HTTPS proxy. This routes all traffic from most applications through the proxy without needing per-app configuration.
388
+
389
+ ```bash
390
+ # Enable
391
+ roxyproxy proxy-on
392
+
393
+ # Disable
394
+ roxyproxy proxy-off
395
+ ```
396
+
397
+ This uses `networksetup` to set the proxy on your active network service (auto-detects Wi-Fi, Ethernet, or the first available interface).
398
+
399
+ ---
400
+
401
+ ## Configuration
402
+
403
+ Configuration is loaded from (highest priority first):
404
+
405
+ 1. CLI flags
406
+ 2. `~/.roxyproxy/config.json`
407
+ 3. Built-in defaults
408
+
409
+ ### Config file
410
+
411
+ Create `~/.roxyproxy/config.json`:
412
+
413
+ ```json
414
+ {
415
+ "proxyPort": 8080,
416
+ "uiPort": 8081,
417
+ "dbPath": "~/.roxyproxy/data.db",
418
+ "maxAge": "7d",
419
+ "maxDbSize": "500MB",
420
+ "maxBodySize": "1MB",
421
+ "certCacheSize": 500
422
+ }
423
+ ```
424
+
425
+ ### Options
426
+
427
+ | Field | Default | Description |
428
+ |---|---|---|
429
+ | `proxyPort` | `8080` | Proxy listening port |
430
+ | `uiPort` | `8081` | Web UI and REST API port |
431
+ | `dbPath` | `~/.roxyproxy/data.db` | SQLite database file path (supports `~`) |
432
+ | `maxAge` | `7d` | Auto-delete requests older than this |
433
+ | `maxDbSize` | `500MB` | Auto-delete oldest requests when DB exceeds this size |
434
+ | `maxBodySize` | `1MB` | Truncate request/response bodies larger than this |
435
+ | `certCacheSize` | `500` | Max per-domain SSL certificates cached in memory |
436
+
437
+ ### Size and duration formats
438
+
439
+ Sizes accept: raw bytes (`1048576`), or human units (`1KB`, `10MB`, `1GB`).
440
+
441
+ Durations accept: raw milliseconds (`86400000`), or human units (`1s`, `5m`, `1h`, `7d`).
442
+
443
+ ### Auto-cleanup
444
+
445
+ A background job runs every 5 minutes to enforce `maxAge` and `maxDbSize`:
446
+
447
+ - Deletes requests older than `maxAge`
448
+ - If the database still exceeds `maxDbSize`, deletes the oldest requests in batches
449
+ - Runs incremental vacuum to reclaim disk space
450
+
451
+ ---
452
+
453
+ ## REST API
454
+
455
+ The API is available at `http://127.0.0.1:8081/api` when the proxy is running.
456
+
457
+ ### Endpoints
458
+
459
+ #### `GET /api/requests`
460
+
461
+ Query captured requests. Returns paginated results.
462
+
463
+ Query parameters match the CLI `requests` command: `host`, `status`, `method`, `content_type`, `search`, `since`, `until`, `limit`, `offset`.
464
+
465
+ ```bash
466
+ # All requests
467
+ curl http://127.0.0.1:8081/api/requests
468
+
469
+ # Filtered
470
+ curl "http://127.0.0.1:8081/api/requests?host=example.com&status=200&limit=50"
471
+ ```
472
+
473
+ Response:
474
+
475
+ ```json
476
+ {
477
+ "data": [ { "id": "...", "timestamp": 1700000000000, "method": "GET", ... } ],
478
+ "total": 142,
479
+ "limit": 100,
480
+ "offset": 0
481
+ }
482
+ ```
483
+
484
+ #### `GET /api/requests/:id`
485
+
486
+ Get full details for a single request, including headers and base64-encoded bodies.
487
+
488
+ ```bash
489
+ curl http://127.0.0.1:8081/api/requests/a1b2c3d4-e5f6-7890-abcd-ef1234567890
490
+ ```
491
+
492
+ #### `DELETE /api/requests`
493
+
494
+ Delete all captured traffic.
495
+
496
+ ```bash
497
+ curl -X DELETE http://127.0.0.1:8081/api/requests
498
+ ```
499
+
500
+ #### `GET /api/status`
501
+
502
+ Get proxy status.
503
+
504
+ ```bash
505
+ curl http://127.0.0.1:8081/api/status
506
+ ```
507
+
508
+ Response:
509
+
510
+ ```json
511
+ {
512
+ "running": true,
513
+ "proxyPort": 8080,
514
+ "requestCount": 142,
515
+ "dbSizeBytes": 3358720
516
+ }
517
+ ```
518
+
519
+ #### `POST /api/proxy/start`
520
+
521
+ Start the proxy server.
522
+
523
+ ```bash
524
+ curl -X POST http://127.0.0.1:8081/api/proxy/start
525
+ ```
526
+
527
+ #### `POST /api/proxy/stop`
528
+
529
+ Stop the proxy server (the API remains available).
530
+
531
+ ```bash
532
+ curl -X POST http://127.0.0.1:8081/api/proxy/stop
533
+ ```
534
+
535
+ #### `POST /api/shutdown`
536
+
537
+ Shut down the entire process (proxy + API + web UI).
538
+
539
+ ```bash
540
+ curl -X POST http://127.0.0.1:8081/api/shutdown
541
+ ```
542
+
543
+ #### `GET /api/events`
544
+
545
+ Server-Sent Events stream for real-time updates.
546
+
547
+ ```bash
548
+ curl -N http://127.0.0.1:8081/api/events
549
+ ```
550
+
551
+ Events are named:
552
+
553
+ - `event: request` -- new captured request (data is the request record as JSON)
554
+ - `event: status` -- proxy state change (data is `{"running": true/false, "proxyPort": 8080}`)
555
+
556
+ ---
557
+
558
+ ## Architecture
559
+
560
+ ```
561
+ ┌─────────────────────────────────────────┐
562
+ │ RoxyProxy │
563
+ │ │
564
+ HTTP/S traffic │ ┌──────────────┐ ┌──────────────┐ │
565
+ ─────────────────► │ │ Proxy Server │───►│ EventManager │ │
566
+ │ │ :8080 │ │ (pub/sub) │──┼──► SSE to Web UI
567
+ │ └──────┬───────┘ └──────────────┘ │
568
+ │ │ │
569
+ │ ▼ │
570
+ │ ┌──────────────┐ ┌──────────────┐ │
571
+ │ │ SQLite DB │◄───│ Cleanup │ │
572
+ │ │ (batched) │ │ (5 min) │ │
573
+ │ └──────┬───────┘ └──────────────┘ │
574
+ │ │ │
575
+ │ ▼ │
576
+ │ ┌──────────────┐ ┌──────────────┐ │
577
+ │ │ REST API │ │ Web UI │ │
578
+ │ │ /api/* │ │ (React) │ │
579
+ │ │ :8081 │ │ :8081 │ │
580
+ │ └──────────────┘ └──────────────┘ │
581
+ └─────────────────────────────────────────┘
582
+ ```
583
+
584
+ ### Key design decisions
585
+
586
+ - **SQLite with WAL mode** -- high write throughput with concurrent reads
587
+ - **Batched writes** -- requests are queued in memory and flushed every 100ms to reduce I/O
588
+ - **Event batching** -- SSE events are buffered for 100ms before flushing to connected clients
589
+ - **Response decompression** -- gzip, deflate, and brotli responses are automatically decompressed before storage
590
+ - **Body truncation** -- configurable max body size prevents storage bloat; a `truncated` flag is set on affected records
591
+ - **Per-domain cert caching** -- LRU cache avoids regenerating SSL certificates for frequently accessed domains
592
+
593
+ ### Data storage
594
+
595
+ All data is stored in `~/.roxyproxy/data.db` (SQLite). The `requests` table has indexes on `timestamp`, `host`, `status`, `path`, and `content_type` for fast querying.
596
+
597
+ Request and response bodies are stored as binary blobs. In the API and SSE stream, they are base64-encoded.
598
+
599
+ ### Files
600
+
601
+ | Path | Purpose |
602
+ |---|---|
603
+ | `~/.roxyproxy/data.db` | SQLite database |
604
+ | `~/.roxyproxy/config.json` | Configuration file (optional) |
605
+ | `~/.roxyproxy/ca/ca.crt` | Root CA certificate |
606
+ | `~/.roxyproxy/ca/ca.key` | Root CA private key |
607
+ | `~/.roxyproxy/pid` | Process ID file |
608
+
609
+ ---
610
+
611
+ ## Development
612
+
613
+ ```bash
614
+ # Run all tests
615
+ npm test
616
+
617
+ # Watch mode
618
+ npm run test:watch
619
+
620
+ # Build server (TypeScript)
621
+ npm run build:server
622
+
623
+ # Build web UI (Vite + React)
624
+ npm run build:ui
625
+
626
+ # Build everything
627
+ npm run build
628
+
629
+ # Vite dev server with API proxy to :8081
630
+ npm run dev:ui
631
+ ```
632
+
633
+ ### Project structure
634
+
635
+ ```
636
+ src/
637
+ ├── cli/ # CLI entry point, commands, interactive mode
638
+ │ ├── index.ts # Command registration (Commander.js)
639
+ │ ├── interactive.tsx # Interactive terminal menu (Ink/React)
640
+ │ ├── commands/ # Individual CLI commands
641
+ │ └── system-proxy.ts # macOS system proxy & CA management
642
+ ├── server/ # Proxy server, API, SSL, events
643
+ │ ├── index.ts # RoxyProxyServer orchestrator
644
+ │ ├── proxy.ts # HTTP/HTTPS intercepting proxy
645
+ │ ├── api.ts # Express REST API + SSE
646
+ │ ├── ssl.ts # CA generation & per-domain cert caching
647
+ │ ├── events.ts # Pub/sub event manager
648
+ │ └── config.ts # Config loading and merging
649
+ ├── storage/ # Database and cleanup
650
+ │ ├── db.ts # SQLite operations (better-sqlite3)
651
+ │ └── cleanup.ts # Auto-cleanup job
652
+ ├── shared/ # Shared TypeScript types
653
+ │ └── types.ts # Config, RequestRecord, RequestFilter
654
+ └── ui/ # React web UI (Vite)
655
+ ├── App.tsx # Main app component
656
+ ├── api.ts # API client + SSE hook
657
+ └── components/ # UI components
658
+ ```
@@ -0,0 +1,6 @@
1
+ export declare function printBanner(): void;
2
+ export declare function printStartInfo(proxyPort: number, uiPort: number): void;
3
+ export declare function printSuccess(msg: string): void;
4
+ export declare function printError(msg: string): void;
5
+ export declare function printInfo(msg: string): void;
6
+ export declare function printWarn(msg: string): void;
@@ -0,0 +1,30 @@
1
+ import pc from 'picocolors';
2
+ export function printBanner() {
3
+ console.log('');
4
+ console.log(pc.cyan(' ___ ___ '));
5
+ console.log(pc.cyan(' | _ \\___ __ ___ _ | _ \\_ _ _____ ___ _ '));
6
+ console.log(pc.cyan(' | / _ \\\\ \\ / || || ___/ \'_/ _ \\ \\ /| || |'));
7
+ console.log(pc.cyan(' |_|_\\___//_\\_\\\\_, ||_| |_| \\___/_\\_\\ \\_, |'));
8
+ console.log(pc.cyan(' |__/ |__/ '));
9
+ console.log('');
10
+ }
11
+ export function printStartInfo(proxyPort, uiPort) {
12
+ console.log(` ${pc.green('●')} Proxy ${pc.cyan(`http://127.0.0.1:${proxyPort}`)}`);
13
+ console.log(` ${pc.green('●')} Web UI ${pc.cyan(`http://127.0.0.1:${uiPort}`)}`);
14
+ console.log('');
15
+ console.log(pc.dim(' Ctrl+C to stop'));
16
+ console.log('');
17
+ }
18
+ export function printSuccess(msg) {
19
+ console.log(` ${pc.green('✔')} ${msg}`);
20
+ }
21
+ export function printError(msg) {
22
+ console.log(` ${pc.red('✖')} ${msg}`);
23
+ }
24
+ export function printInfo(msg) {
25
+ console.log(` ${pc.cyan('›')} ${msg}`);
26
+ }
27
+ export function printWarn(msg) {
28
+ console.log(` ${pc.yellow('!')} ${msg}`);
29
+ }
30
+ //# sourceMappingURL=banner.js.map