securenow 6.0.2 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CONSUMING-APPS-GUIDE.md +455 -0
  2. package/NPM_README.md +2029 -0
  3. package/README.md +297 -40
  4. package/SKILL-API.md +634 -0
  5. package/SKILL-CLI.md +454 -0
  6. package/cidr.js +83 -0
  7. package/cli/apps.js +585 -0
  8. package/cli/auth.js +280 -0
  9. package/cli/client.js +115 -0
  10. package/cli/config.js +173 -0
  11. package/cli/diagnostics.js +387 -0
  12. package/cli/firewall.js +100 -0
  13. package/cli/fp.js +638 -0
  14. package/cli/init.js +201 -0
  15. package/cli/monitor.js +440 -0
  16. package/cli/run.js +148 -0
  17. package/cli/security.js +980 -0
  18. package/cli/ui.js +386 -0
  19. package/cli/utils.js +127 -0
  20. package/cli.js +466 -455
  21. package/console-instrumentation.js +147 -136
  22. package/docs/ALL-FRAMEWORKS-QUICKSTART.md +1377 -455
  23. package/docs/API-KEYS-GUIDE.md +233 -0
  24. package/docs/ARCHITECTURE.md +3 -3
  25. package/docs/AUTO-BODY-CAPTURE.md +1 -1
  26. package/docs/AUTO-SETUP-SUMMARY.md +331 -0
  27. package/docs/AUTO-SETUP.md +4 -4
  28. package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
  29. package/docs/BODY-CAPTURE-FIX.md +261 -0
  30. package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
  31. package/docs/CHANGELOG-NEXTJS.md +1 -35
  32. package/docs/COMPLETION-REPORT.md +408 -0
  33. package/docs/CUSTOMER-GUIDE.md +16 -16
  34. package/docs/EASIEST-SETUP.md +5 -5
  35. package/docs/ENVIRONMENT-VARIABLES.md +880 -652
  36. package/docs/EXPRESS-BODY-CAPTURE.md +13 -12
  37. package/docs/EXPRESS-SETUP-GUIDE.md +719 -720
  38. package/docs/FINAL-SOLUTION.md +335 -0
  39. package/docs/FIREWALL-GUIDE.md +426 -0
  40. package/docs/IMPLEMENTATION-SUMMARY.md +410 -0
  41. package/docs/INDEX.md +22 -4
  42. package/docs/LOGGING-GUIDE.md +701 -708
  43. package/docs/LOGGING-QUICKSTART.md +234 -255
  44. package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +323 -0
  45. package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
  46. package/docs/NEXTJS-GUIDE.md +14 -14
  47. package/docs/NEXTJS-QUICKSTART.md +1 -1
  48. package/docs/NEXTJS-SETUP-COMPLETE.md +795 -0
  49. package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
  50. package/docs/NUXT-GUIDE.md +166 -0
  51. package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
  52. package/docs/REDACTION-EXAMPLES.md +1 -1
  53. package/docs/REQUEST-BODY-CAPTURE.md +19 -10
  54. package/docs/SOLUTION-SUMMARY.md +312 -0
  55. package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
  56. package/examples/README.md +6 -6
  57. package/examples/instrumentation-with-auto-capture.ts +1 -1
  58. package/examples/nextjs-env-example.txt +2 -2
  59. package/examples/nextjs-instrumentation.js +1 -1
  60. package/examples/nextjs-instrumentation.ts +1 -1
  61. package/examples/nextjs-with-logging-example.md +6 -6
  62. package/examples/nextjs-with-options.ts +1 -1
  63. package/examples/test-nextjs-setup.js +1 -1
  64. package/firewall-cloud.js +212 -0
  65. package/firewall-iptables.js +139 -0
  66. package/firewall-only.js +38 -0
  67. package/firewall-tcp.js +74 -0
  68. package/firewall.js +720 -0
  69. package/free-trial-banner.js +174 -0
  70. package/nextjs-auto-capture.js +199 -207
  71. package/nextjs-middleware.js +186 -181
  72. package/nextjs-webpack-config.js +88 -53
  73. package/nextjs-wrapper.js +158 -158
  74. package/nextjs.d.ts +1 -1
  75. package/nextjs.js +639 -647
  76. package/nuxt-server-plugin.mjs +423 -0
  77. package/nuxt.d.ts +60 -0
  78. package/nuxt.mjs +75 -0
  79. package/package.json +186 -164
  80. package/postinstall.js +6 -6
  81. package/register.d.ts +1 -1
  82. package/register.js +39 -4
  83. package/resolve-ip.js +77 -0
  84. package/tracing.d.ts +2 -1
  85. package/tracing.js +295 -34
  86. package/web-vite.mjs +239 -156
  87. package/LICENSE +0 -15
package/NPM_README.md ADDED
@@ -0,0 +1,2029 @@
1
+ # SecureNow - Complete OpenTelemetry Observability for Node.js
2
+
3
+ OpenTelemetry instrumentation library for Node.js, Next.js, and Nuxt applications. Send distributed traces and logs to any OTLP-compatible observability backend.
4
+
5
+ **Features:**
6
+ - Zero-config automatic instrumentation
7
+ - Distributed tracing for all popular frameworks
8
+ - Automatic logging with console instrumentation
9
+ - Built-in sensitive data redaction
10
+ - Request body capture for debugging
11
+ - Multi-layer firewall -- auto-blocks IPs from your SecureNow blocklist
12
+ - `withSecureNow()` config wrapper for Next.js -- eliminates manual `serverExternalPackages`
13
+ - `securenow init` CLI scaffolds instrumentation files for any framework
14
+ - `securenow/firewall-only` entry point for firewall without tracing overhead
15
+ - Fully configurable via environment variables
16
+ - Single `-r securenow/register` flag -- works for both CJS and ESM apps
17
+ - Native Nuxt 3 module (`securenow/nuxt`)
18
+
19
+ ---
20
+
21
+ ## Table of Contents
22
+
23
+ - [Installation](#installation)
24
+ - [Quick Start](#quick-start)
25
+ - [CLI -- Command Line Interface](#cli--command-line-interface)
26
+ - [Framework-Specific Setup](#framework-specific-setup)
27
+ - [Express.js](#expressjs)
28
+ - [Next.js](#nextjs)
29
+ - [Nuxt 3](#nuxt-3)
30
+ - [Fastify](#fastify)
31
+ - [NestJS](#nestjs)
32
+ - [Koa](#koa)
33
+ - [Hapi](#hapi)
34
+ - [Firewall -- Automatic IP Blocking](#firewall--automatic-ip-blocking)
35
+ - [Environment Variables Reference](#environment-variables-reference)
36
+ - [Logging Setup](#logging-setup)
37
+ - [Request Body Capture](#request-body-capture)
38
+ - [Advanced Configuration](#advanced-configuration)
39
+ - [TypeScript Support](#typescript-support)
40
+ - [Troubleshooting](#troubleshooting)
41
+
42
+ ---
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ npm install securenow
48
+ ```
49
+
50
+ Or with yarn:
51
+
52
+ ```bash
53
+ yarn add securenow
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Quick Start
59
+
60
+ ### 1. Automatic Setup (Recommended)
61
+
62
+ Run the init command after installing:
63
+
64
+ ```bash
65
+ npx securenow init --key snk_live_abc123...
66
+ ```
67
+
68
+ This detects your framework and:
69
+ - **Next.js**: Creates `instrumentation.ts`, suggests `withSecureNow()` for `next.config.js`
70
+ - **Nuxt 3**: Suggests adding `securenow/nuxt` to modules
71
+ - **Express / Node.js**: Shows how to add `-r securenow/register` to your start script
72
+ - **All**: Writes `SECURENOW_API_KEY` to `.env.local` when `--key` is provided
73
+
74
+ ### 2. Manual Setup
75
+
76
+ #### Set Environment Variables
77
+
78
+ ```bash
79
+ # Required: Your application identifier
80
+ export SECURENOW_APPID=my-app
81
+
82
+ # Required: Your OTLP collector endpoint
83
+ export SECURENOW_INSTANCE=http://your-otlp-collector:4318
84
+
85
+ # Optional: Enable logging
86
+ export SECURENOW_LOGGING_ENABLED=1
87
+
88
+ # Optional: Enable the firewall (set your API key)
89
+ export SECURENOW_API_KEY=snk_live_abc123...
90
+ ```
91
+
92
+ #### Run Your Application
93
+
94
+ Add `-r securenow/register` to your start command -- that's the only change:
95
+
96
+ ```bash
97
+ node -r securenow/register app.js
98
+ ```
99
+
100
+ ESM and CJS apps are both handled automatically (Node >=20.6 auto-registers the ESM loader hook via `module.register()`).
101
+
102
+ **package.json** example:
103
+
104
+ ```json
105
+ "scripts": {
106
+ "start": "node -r securenow/register app.js",
107
+ "dev": "node -r securenow/register --watch app.js"
108
+ }
109
+ ```
110
+
111
+ **Alternative: Use NODE_OPTIONS** so your existing scripts stay unchanged:
112
+
113
+ ```bash
114
+ NODE_OPTIONS="-r securenow/register" npm start
115
+ ```
116
+
117
+ **CJS only: Code-based initialization**
118
+
119
+ ```javascript
120
+ // At the very top of your main file, before any other require
121
+ require('securenow/register');
122
+
123
+ const express = require('express');
124
+ const app = express();
125
+ // ...
126
+ ```
127
+
128
+ You'll see confirmation in the console:
129
+
130
+ ```
131
+ [securenow] OTel SDK started -> http://your-otlp-collector:4318/v1/traces
132
+ [securenow] Firewall: ENABLED
133
+ [securenow] Firewall: synced 142 blocked IPs (138 exact + 4 CIDR ranges)
134
+ ```
135
+
136
+ ---
137
+
138
+ ## CLI -- Command Line Interface
139
+
140
+ The `securenow` CLI gives you full access to the SecureNow platform from the terminal -- no browser required for day-to-day workflows. Zero additional dependencies.
141
+
142
+ **Full CLI/SDK parity (v6.1.0+):** every SDK export has a matching CLI command. `redactSensitiveData` → `securenow redact`, `createMatcher` → `securenow cidr match`, `getLogger().emit()` → `securenow log send`, `SECURENOW_TEST_SPAN` → `securenow test-span`, `node -r securenow/firewall-only` → `securenow run --firewall-only`. False-positive triage (`fp create`, `fp ai-fill`, `fp mark`) works from the terminal without the web dashboard.
143
+
144
+ ### Getting Started
145
+
146
+ ```bash
147
+ # Log in (opens browser for OAuth)
148
+ npx securenow login
149
+
150
+ # Or use a token for CI/headless environments
151
+ npx securenow login --token <YOUR_JWT>
152
+
153
+ # Log in for this project only (per-project credentials)
154
+ npx securenow login --local
155
+
156
+ # Check who you're logged in as (shows auth source)
157
+ npx securenow whoami
158
+ ```
159
+
160
+ ### Project Setup
161
+
162
+ ```bash
163
+ # Auto-detect framework and scaffold instrumentation files
164
+ npx securenow init
165
+
166
+ # Pass your API key to auto-write it to .env.local
167
+ npx securenow init --key snk_live_abc123...
168
+ ```
169
+
170
+ For Next.js projects, `init` creates `instrumentation.ts` (or `.js` if no TypeScript) and tells you how to update `next.config.js` with `withSecureNow()`. For Nuxt, it suggests adding `securenow/nuxt` to your modules. For Express/Node, it shows the `-r securenow/register` flag.
171
+
172
+ ### Managing Applications
173
+
174
+ ```bash
175
+ # List all applications
176
+ npx securenow apps
177
+
178
+ # Create a new application
179
+ npx securenow apps create my-production-app --hosts api.example.com,app.example.com
180
+
181
+ # Get application details (including the app key)
182
+ npx securenow apps info <app-id>
183
+
184
+ # Set a default app so you don't need --app on every command
185
+ npx securenow apps default <app-key>
186
+
187
+ # Delete an application
188
+ npx securenow apps delete <app-id> --force
189
+ ```
190
+
191
+ ### Viewing Traces
192
+
193
+ ```bash
194
+ # List recent traces (uses default app, or specify --app)
195
+ npx securenow traces
196
+ npx securenow traces --app <key> --limit 50
197
+
198
+ # Show detailed spans for a trace
199
+ npx securenow traces show <traceId>
200
+
201
+ # AI-powered security analysis of a trace
202
+ npx securenow traces analyze <traceId>
203
+ ```
204
+
205
+ ### Viewing Logs
206
+
207
+ ```bash
208
+ # List recent logs
209
+ npx securenow logs
210
+ npx securenow logs --app <key> --minutes 30 --level error
211
+
212
+ # Show logs for a specific trace
213
+ npx securenow logs trace <traceId>
214
+ ```
215
+
216
+ ### Notifications
217
+
218
+ ```bash
219
+ # List notifications
220
+ npx securenow notifications
221
+
222
+ # Check unread count
223
+ npx securenow notifications unread
224
+
225
+ # Mark as read
226
+ npx securenow notifications read <id>
227
+ npx securenow notifications read-all
228
+ ```
229
+
230
+ ### Alerting
231
+
232
+ ```bash
233
+ # View alert rules, channels, and history
234
+ npx securenow alerts rules
235
+ npx securenow alerts rules show <rule-id>
236
+ npx securenow alerts rules update <rule-id> --applications-all
237
+ npx securenow alerts rules update <rule-id> --apps key1,key2
238
+ npx securenow alerts channels
239
+ npx securenow alerts history --limit 20
240
+ ```
241
+
242
+ ### IP Intelligence & Blocklist
243
+
244
+ ```bash
245
+ # Look up any IP -- geo, abuse score, verdict, risk factors
246
+ npx securenow ip 203.0.113.42
247
+
248
+ # Show traces from a specific IP
249
+ npx securenow ip traces 203.0.113.42
250
+
251
+ # Manage the blocklist
252
+ npx securenow blocklist
253
+ npx securenow blocklist add 203.0.113.42 --reason "Brute force scanner"
254
+ npx securenow blocklist remove <id>
255
+ npx securenow blocklist stats
256
+
257
+ # Manage trusted IPs
258
+ npx securenow trusted
259
+ npx securenow trusted add 10.0.0.1 --label "Office VPN"
260
+ npx securenow trusted remove <id>
261
+ ```
262
+
263
+ ### Forensic Queries
264
+
265
+ Ask questions in plain English -- the AI translates them to SQL and runs them against your data.
266
+
267
+ ```bash
268
+ # Run a forensic query
269
+ npx securenow forensics "show top 10 attacking IPs in the last hour"
270
+ npx securenow forensics "which endpoints had 5xx errors today"
271
+
272
+ # Browse the saved query library
273
+ npx securenow forensics library
274
+ ```
275
+
276
+ ### API Map
277
+
278
+ ```bash
279
+ # View all discovered API endpoints
280
+ npx securenow api-map
281
+
282
+ # API map statistics
283
+ npx securenow api-map stats
284
+ ```
285
+
286
+ ### Analytics & Dashboard
287
+
288
+ ```bash
289
+ # Response code analytics
290
+ npx securenow analytics --app <key>
291
+
292
+ # Full dashboard overview (apps, protection status, unread alerts)
293
+ npx securenow status
294
+ ```
295
+
296
+ ### Instances
297
+
298
+ ```bash
299
+ # List ClickHouse instances
300
+ npx securenow instances
301
+
302
+ # Test an instance connection
303
+ npx securenow instances test <id>
304
+ ```
305
+
306
+ ### False-Positive Management
307
+
308
+ Full FP triage from the terminal — no dashboard required.
309
+
310
+ ```bash
311
+ # Browse & inspect rules
312
+ npx securenow fp
313
+ npx securenow fp show <rule-id>
314
+
315
+ # Create a rule from AI-drafted conditions
316
+ npx securenow fp ai-fill --description "Stripe webhook POST to /api/stripe/webhook"
317
+ npx securenow fp create --conditions '<ai-output>' --rule-scope any_rule --reason "Stripe webhook"
318
+
319
+ # Create with safe-value presets (shorthand)
320
+ npx securenow fp create \
321
+ --path /api/events --method POST \
322
+ --path-safe standard --ua-safe standard --headers-safe standard \
323
+ --query-keys page,limit --reason "Event webhook"
324
+
325
+ # Test & dry-run before committing
326
+ npx securenow fp test-body '{"user":"admin"}' --conditions '[...]'
327
+ npx securenow fp dry-run --conditions '[...]' # last 3 days of live traces
328
+
329
+ # Mark a notification's IP as FP in one shot
330
+ npx securenow fp mark <notification-id> <ip> --rule-scope this_rule --reason "Known partner IP"
331
+
332
+ # Edit / delete
333
+ npx securenow fp edit <id> --active false
334
+ npx securenow fp delete <id> --yes
335
+ ```
336
+
337
+ ### Telemetry -- Emit Logs and Spans From the Shell
338
+
339
+ Mirrors the SDK's `getLogger()` and tracing APIs. Useful for cron jobs, shell scripts, and CI pipelines that need to push events into SecureNow **without booting the full OTel SDK**.
340
+
341
+ ```bash
342
+ # Send a structured log record to your OTLP collector
343
+ npx securenow log send "Deployment completed" --level info --attrs version=1.2.3,service=api
344
+ npx securenow log send "Backup failed" --level error --attrs host=db-01
345
+
346
+ # Emit a test span to verify the collector accepts OTLP traffic
347
+ npx securenow test-span
348
+ npx securenow test-span "ci.smoke-test" # custom span name
349
+ ```
350
+
351
+ Both commands use the resolved `SECURENOW_INSTANCE` / `OTEL_EXPORTER_OTLP_*` endpoints and honor `OTEL_EXPORTER_OTLP_HEADERS` for API-key auth. Non-zero exit on HTTP errors so CI/cron can detect failures.
352
+
353
+ ### Utilities -- Redaction, CIDR, Diagnostics
354
+
355
+ SDK helpers surfaced as CLI commands so agents (and humans) can validate behavior without writing Node.
356
+
357
+ ```bash
358
+ # Redact sensitive fields (password, token, card, ssn, etc.)
359
+ npx securenow redact '{"user":"alice","password":"s3cret","card":"4242"}'
360
+ npx securenow redact @request.json --fields internal_id,sessionHash
361
+
362
+ # CIDR — match an IP against a list, or parse a range
363
+ npx securenow cidr match 10.0.0.5 10.0.0.0/8,192.168.1.0/24 # exit 0 = hit, 2 = miss
364
+ npx securenow cidr parse 10.0.0.0/24 # network, broadcast, mask, size
365
+
366
+ # Show resolved config (service name, endpoints, env vars, firewall layers)
367
+ npx securenow env # human-readable
368
+ npx securenow env --json # pipe to jq
369
+
370
+ # End-to-end diagnostic: probe OTLP + API endpoints
371
+ npx securenow doctor # exits 0 if healthy, 1 otherwise
372
+ npx securenow doctor --json
373
+ ```
374
+
375
+ ### Configuration
376
+
377
+ ```bash
378
+ # View all config
379
+ npx securenow config get
380
+
381
+ # Set values
382
+ npx securenow config set apiUrl https://custom-api.example.com
383
+ npx securenow config set defaultApp <app-key>
384
+ npx securenow config set format json
385
+
386
+ # Show config file paths
387
+ npx securenow config path
388
+ ```
389
+
390
+ Config files are stored in `~/.securenow/` (global) or `.securenow/` in the project root (per-project):
391
+
392
+ | File | Description |
393
+ |------|-------------|
394
+ | `~/.securenow/config.json` | API URL, default app, output format |
395
+ | `~/.securenow/credentials.json` | Auth token — global (file permissions: 0600) |
396
+ | `.securenow/credentials.json` | Auth token — project-local (use `login --local`) |
397
+
398
+ **Resolution order:** `SECURENOW_TOKEN` env var → project `.securenow/credentials.json` → global `~/.securenow/credentials.json`.
399
+
400
+ ### Global Flags
401
+
402
+ Every command supports these flags:
403
+
404
+ | Flag | Short | Description |
405
+ |------|-------|-------------|
406
+ | `--json` | `-j` | Output as JSON for scripting and CI/CD |
407
+ | `--help` | | Show help for the command |
408
+ | `--app <key>` | | Override the default application key |
409
+
410
+ ### Environment Variables
411
+
412
+ | Variable | Description |
413
+ |----------|-------------|
414
+ | `SECURENOW_TOKEN` | JWT token — overrides all file-based credentials |
415
+ | `SECURENOW_API_URL` | Override the API base URL |
416
+ | `SECURENOW_DEBUG` | Show stack traces on errors |
417
+ | `NO_COLOR` | Disable colored output |
418
+
419
+ ### Multi-Project Sessions
420
+
421
+ Use `--local` to maintain separate logins per project on the same machine:
422
+
423
+ ```bash
424
+ # In project A — log in as user-a@company.com
425
+ cd ~/projects/project-a
426
+ npx securenow login --local
427
+
428
+ # In project B — log in as user-b@company.com
429
+ cd ~/projects/project-b
430
+ npx securenow login --local
431
+
432
+ # Each project uses its own credentials independently
433
+ npx securenow whoami # Shows auth source: project (.securenow/)
434
+ ```
435
+
436
+ You can also use the `SECURENOW_TOKEN` env var for per-terminal sessions without touching any files.
437
+
438
+ ### CI/CD Integration
439
+
440
+ ```bash
441
+ # Authenticate with a token in CI (env var — no file needed)
442
+ SECURENOW_TOKEN=$MY_SECRET npx securenow logs --json
443
+
444
+ # Or use login with explicit token
445
+ npx securenow login --token $SECURENOW_TOKEN
446
+
447
+ # Use --json for machine-readable output
448
+ npx securenow logs --json --level error | jq '.logs'
449
+ ```
450
+
451
+ ### Complete Command Reference
452
+
453
+ | Category | Command | Description |
454
+ |----------|---------|-------------|
455
+ | **Setup** | `init` | Auto-scaffold instrumentation for your framework |
456
+ | **Auth** | `login` | Authenticate via browser, `--token`, or `--local` |
457
+ | | `logout` | Clear credentials (`--local` for project only) |
458
+ | | `whoami` | Show session info and auth source |
459
+ | **Apps** | `apps` | List applications |
460
+ | | `apps create <name>` | Create application |
461
+ | | `apps info <id>` | Application details |
462
+ | | `apps delete <id>` | Delete application |
463
+ | | `apps default <key>` | Set default app |
464
+ | **Observe** | `traces` | List traces |
465
+ | | `traces show <id>` | Trace details |
466
+ | | `traces analyze <id>` | AI trace analysis |
467
+ | | `logs` | List logs |
468
+ | | `logs trace <id>` | Logs for a trace |
469
+ | | `analytics` | Response analytics |
470
+ | | `status` | Dashboard overview |
471
+ | **Detect** | `notifications` | List notifications |
472
+ | | `notifications unread` | Unread count |
473
+ | | `notifications read <id>` | Mark read |
474
+ | | `notifications read-all` | Mark all read |
475
+ | | `alerts rules` | List rules (status, apps, schedule) |
476
+ | | `alerts rules show <id>` | Rule detail |
477
+ | | `alerts rules update <id> --applications-all` / `--apps k1,k2` | Application scope |
478
+ | | `alerts channels` | Alert channels |
479
+ | | `alerts history` | Alert history |
480
+ | **Investigate** | `ip <addr>` | IP intelligence |
481
+ | | `ip traces <addr>` | Traces from IP |
482
+ | | `forensics "<query>"` | NL forensic query |
483
+ | | `forensics library` | Saved queries |
484
+ | | `api-map` | API endpoints |
485
+ | | `api-map stats` | API stats |
486
+ | **Firewall** | `firewall status` | Firewall status and API key info |
487
+ | | `firewall test-ip <ip>` | Check if an IP would be blocked |
488
+ | | `run --firewall-only <script>` | Preload firewall without OTel tracing overhead |
489
+ | **Remediate** | `blocklist` | Blocked IPs |
490
+ | | `blocklist add <ip>` | Block IP |
491
+ | | `blocklist remove <id>` | Unblock IP |
492
+ | | `blocklist stats` | Block stats |
493
+ | | `allowlist` | Allowed IPs (restrict-mode) |
494
+ | | `allowlist add <ip>` | Allow IP (`--label`, `--reason`) |
495
+ | | `allowlist remove <id>` | Remove from allowlist |
496
+ | | `trusted` | Trusted IPs |
497
+ | | `trusted add <ip>` | Add trusted IP |
498
+ | | `trusted remove <id>` | Remove trusted |
499
+ | **False Positives** | `fp` / `fp list` | List exclusion rules |
500
+ | | `fp show <id>` | Rule detail |
501
+ | | `fp create --conditions '[...]'` | Create raw exclusion rule |
502
+ | | `fp create --path /api/events --method POST --path-safe standard` | Safe-value preset helper |
503
+ | | `fp edit <id>` | Edit rule (`--active`, `--conditions`) |
504
+ | | `fp delete <id>` | Delete rule |
505
+ | | `fp test-body '<json>' --conditions '[...]'` | Test conditions against a payload |
506
+ | | `fp dry-run --conditions '[...]'` | Dry-run against last 3 days of traces |
507
+ | | `fp ai-fill --description "..."` | AI-generate exclusion conditions |
508
+ | | `fp mark <notification-id> <ip>` | Mark an IP as FP on a notification |
509
+ | **Telemetry** | `log send "<msg>" --level info --attrs k=v` | Emit an OTLP log record |
510
+ | | `test-span [<name>]` | Emit a test span to the collector |
511
+ | **Utilities** | `redact '<json>' [--fields f1,f2]` | Redact sensitive fields (accepts `@file.json`) |
512
+ | | `cidr match <ip> <cidrs>` | IP vs. CIDR list (exit 0 hit / 2 miss) |
513
+ | | `cidr parse <cidr>` | Parse CIDR (network, broadcast, mask, size) |
514
+ | | `env [--json]` | Show resolved config (service name, endpoints, env vars) |
515
+ | | `doctor [--json]` | Probe OTLP + API endpoints, check config |
516
+ | **Settings** | `instances` | List instances |
517
+ | | `instances test <id>` | Test connection |
518
+ | | `config get` | Show config |
519
+ | | `config set <k> <v>` | Set config value |
520
+ | | `config path` | Config file paths |
521
+ | | `version` | Show version |
522
+
523
+ ---
524
+
525
+ ## Framework-Specific Setup
526
+
527
+ > **v5.6.0+:** When `SECURENOW_LOGGING_ENABLED=1`, all `console.log`/`warn`/`error`/`info`/`debug` calls
528
+ > are **automatically** forwarded as OTLP log records. The separate `require('securenow/console-instrumentation')` is no longer needed (but still available for backward compat).
529
+
530
+ ### Express.js
531
+
532
+ ```bash
533
+ npm install securenow express
534
+ ```
535
+
536
+ ```javascript
537
+ // app.js
538
+ require('securenow/register');
539
+ const express = require('express');
540
+
541
+ const app = express();
542
+ app.use(express.json());
543
+
544
+ app.get('/health', (req, res) => res.json({ status: 'ok' }));
545
+
546
+ app.post('/tasks', (req, res) => {
547
+ console.log('Created task:', req.body.title);
548
+ res.status(201).json({ id: '1', title: req.body.title });
549
+ });
550
+
551
+ app.listen(3000, () => console.log('Express running on port 3000'));
552
+ ```
553
+
554
+ ```bash
555
+ node app.js
556
+ ```
557
+
558
+ #### With PM2
559
+
560
+ ```javascript
561
+ // ecosystem.config.cjs
562
+ module.exports = {
563
+ apps: [{
564
+ name: 'my-app',
565
+ script: './app.js',
566
+ node_args: '-r securenow/register',
567
+ env: {
568
+ SECURENOW_APPID: 'your-app-key',
569
+ SECURENOW_INSTANCE: 'https://freetrial.securenow.ai:4318',
570
+ SECURENOW_API_KEY: 'snk_live_abc123...',
571
+ SECURENOW_LOGGING_ENABLED: '1',
572
+ SECURENOW_NO_UUID: '1',
573
+ SECURENOW_CAPTURE_BODY: '1',
574
+ }
575
+ }]
576
+ };
577
+ ```
578
+
579
+ > **Important:** Always use `node_args: '-r securenow/register'` in PM2 configs. Without it, PM2 restarts won't load the SDK, and the firewall won't activate.
580
+
581
+ ---
582
+
583
+ ### Fastify
584
+
585
+ ```bash
586
+ npm install securenow fastify
587
+ ```
588
+
589
+ ```javascript
590
+ // app.js
591
+ require('securenow/register');
592
+ const Fastify = require('fastify');
593
+ const fastify = Fastify({ logger: true });
594
+
595
+ fastify.get('/health', async () => ({ status: 'ok' }));
596
+
597
+ fastify.post('/tasks', {
598
+ schema: { body: { type: 'object', required: ['title'], properties: { title: { type: 'string' } } } }
599
+ }, async (request) => {
600
+ console.log('Created task:', request.body.title);
601
+ return { id: '1', title: request.body.title };
602
+ });
603
+
604
+ fastify.listen({ port: 3000 }, (err) => {
605
+ if (err) { fastify.log.error(err); process.exit(1); }
606
+ console.log('Fastify running on port 3000');
607
+ });
608
+ ```
609
+
610
+ > **Important:** Set `SECURENOW_CAPTURE_BODY=0` with Fastify -- the body capture hook conflicts with Fastify's internal stream handling.
611
+
612
+ ---
613
+
614
+ ### Koa
615
+
616
+ ```bash
617
+ npm install securenow koa @koa/router koa-bodyparser
618
+ ```
619
+
620
+ ```javascript
621
+ // app.js
622
+ require('securenow/register');
623
+ const Koa = require('koa');
624
+ const Router = require('@koa/router');
625
+ const bodyParser = require('koa-bodyparser');
626
+
627
+ const app = new Koa();
628
+ const router = new Router();
629
+
630
+ router.get('/health', (ctx) => { ctx.body = { status: 'ok' }; });
631
+
632
+ router.post('/tasks', (ctx) => {
633
+ console.log('Created task:', ctx.request.body.title);
634
+ ctx.status = 201;
635
+ ctx.body = { id: '1', title: ctx.request.body.title };
636
+ });
637
+
638
+ app.use(bodyParser());
639
+ app.use(router.routes());
640
+ app.use(router.allowedMethods());
641
+
642
+ app.listen(3000, () => console.log('Koa running on port 3000'));
643
+ ```
644
+
645
+ ---
646
+
647
+ ### NestJS
648
+
649
+ ```bash
650
+ npm install securenow @nestjs/core @nestjs/common reflect-metadata ts-node typescript
651
+ ```
652
+
653
+ NestJS uses TypeScript -- securenow is loaded via `-r` flags instead of in-code `require()`:
654
+
655
+ ```typescript
656
+ // app.ts
657
+ import 'reflect-metadata';
658
+ import { NestFactory } from '@nestjs/core';
659
+ import { Module, Controller, Get, Post, Body } from '@nestjs/common';
660
+
661
+ @Controller()
662
+ class AppController {
663
+ @Get('health')
664
+ health() { return { status: 'ok' }; }
665
+
666
+ @Post('tasks')
667
+ create(@Body() body: { title: string }) {
668
+ console.log('Created task:', body.title);
669
+ return { id: '1', title: body.title };
670
+ }
671
+ }
672
+
673
+ @Module({ controllers: [AppController] })
674
+ class AppModule {}
675
+
676
+ async function bootstrap() {
677
+ const app = await NestFactory.create(AppModule);
678
+ await app.listen(3000);
679
+ console.log('NestJS running on port 3000');
680
+ }
681
+ bootstrap();
682
+ ```
683
+
684
+ ```bash
685
+ node -r securenow/register -r ts-node/register app.ts
686
+ ```
687
+
688
+ PM2 config:
689
+
690
+ ```javascript
691
+ {
692
+ name: 'my-nestjs-app',
693
+ script: 'app.ts',
694
+ interpreter: 'node',
695
+ node_args: '-r securenow/register -r ts-node/register',
696
+ }
697
+ ```
698
+
699
+ ---
700
+
701
+ ### Hapi
702
+
703
+ ```bash
704
+ npm install securenow @hapi/hapi
705
+ ```
706
+
707
+ ```javascript
708
+ // app.js
709
+ require('securenow/register');
710
+ const Hapi = require('@hapi/hapi');
711
+
712
+ const init = async () => {
713
+ const server = Hapi.server({ port: 3000, host: '0.0.0.0' });
714
+
715
+ server.route({ method: 'GET', path: '/health', handler: () => ({ status: 'ok' }) });
716
+
717
+ server.route({
718
+ method: 'POST', path: '/tasks',
719
+ options: { payload: { parse: true, allow: 'application/json' } },
720
+ handler: (request, h) => {
721
+ console.log('Created task:', request.payload.title);
722
+ return h.response({ id: '1', title: request.payload.title }).code(201);
723
+ }
724
+ });
725
+
726
+ await server.start();
727
+ console.log('Hapi running on port 3000');
728
+ };
729
+
730
+ init().catch((err) => { console.error(err); process.exit(1); });
731
+ ```
732
+
733
+ > **Important:** Set `SECURENOW_CAPTURE_BODY=0` with Hapi -- the body capture hook consumes the request stream before Hapi's payload parser.
734
+
735
+ ---
736
+
737
+ ### h3 (UnJS / Nitro)
738
+
739
+ ```bash
740
+ npm install securenow h3
741
+ ```
742
+
743
+ ```javascript
744
+ // app.js
745
+ require('securenow/register');
746
+ const { createApp, createRouter, defineEventHandler, readBody, setResponseStatus, toNodeListener } = require('h3');
747
+ const http = require('http');
748
+
749
+ const app = createApp();
750
+ const router = createRouter();
751
+
752
+ router.get('/health', defineEventHandler(() => ({ status: 'ok' })));
753
+
754
+ router.post('/tasks', defineEventHandler(async (event) => {
755
+ const body = await readBody(event);
756
+ console.log('Created task:', body.title);
757
+ setResponseStatus(event, 201);
758
+ return { id: '1', title: body.title };
759
+ }));
760
+
761
+ app.use(router);
762
+
763
+ http.createServer(toNodeListener(app)).listen(3000, () => {
764
+ console.log('h3 running on port 3000');
765
+ });
766
+ ```
767
+
768
+ ---
769
+
770
+ ### Polka
771
+
772
+ ```bash
773
+ npm install securenow polka
774
+ ```
775
+
776
+ Polka is minimalist -- no built-in body parser:
777
+
778
+ ```javascript
779
+ // app.js
780
+ require('securenow/register');
781
+ const polka = require('polka');
782
+
783
+ function jsonBody(req, res, next) {
784
+ if (req.method === 'GET' || req.method === 'DELETE') return next();
785
+ let data = '';
786
+ req.on('data', chunk => { data += chunk; });
787
+ req.on('end', () => { try { req.body = JSON.parse(data); } catch { req.body = {}; } next(); });
788
+ }
789
+
790
+ function sendJson(res, status, body) {
791
+ res.writeHead(status, { 'Content-Type': 'application/json' });
792
+ res.end(JSON.stringify(body));
793
+ }
794
+
795
+ polka()
796
+ .use(jsonBody)
797
+ .get('/health', (req, res) => sendJson(res, 200, { status: 'ok' }))
798
+ .post('/tasks', (req, res) => {
799
+ console.log('Created task:', req.body.title);
800
+ sendJson(res, 201, { id: '1', title: req.body.title });
801
+ })
802
+ .listen(3000, () => console.log('Polka running on port 3000'));
803
+ ```
804
+
805
+ ---
806
+
807
+ ### Micro / Raw HTTP
808
+
809
+ For apps using Node's bare `http` module:
810
+
811
+ ```bash
812
+ npm install securenow
813
+ ```
814
+
815
+ ```javascript
816
+ // app.js
817
+ require('securenow/register');
818
+ const http = require('http');
819
+
820
+ function sendJson(res, status, body) {
821
+ res.writeHead(status, { 'Content-Type': 'application/json' });
822
+ res.end(JSON.stringify(body));
823
+ }
824
+
825
+ function readBody(req) {
826
+ return new Promise((resolve) => {
827
+ let d = ''; req.on('data', c => { d += c; }); req.on('end', () => { try { resolve(JSON.parse(d)); } catch { resolve({}); } });
828
+ });
829
+ }
830
+
831
+ async function handler(req, res) {
832
+ const url = new URL(req.url, `http://${req.headers.host}`);
833
+ if (url.pathname === '/health') return sendJson(res, 200, { status: 'ok' });
834
+ if (url.pathname === '/tasks' && req.method === 'POST') {
835
+ const body = await readBody(req);
836
+ console.log('Created task:', body.title);
837
+ return sendJson(res, 201, { id: '1', title: body.title });
838
+ }
839
+ sendJson(res, 404, { error: 'Not found' });
840
+ }
841
+
842
+ http.createServer(handler).listen(3000, () => console.log('HTTP running on port 3000'));
843
+ ```
844
+
845
+ ---
846
+
847
+ ### Hono (ESM)
848
+
849
+ ```bash
850
+ npm install securenow hono @hono/node-server
851
+ ```
852
+
853
+ Hono uses ESM -- preload via `-r` flag (the ESM hook is auto-registered on Node >=20.6):
854
+
855
+ ```javascript
856
+ // app.mjs
857
+ import { serve } from '@hono/node-server';
858
+ import { Hono } from 'hono';
859
+
860
+ const app = new Hono();
861
+
862
+ app.get('/health', (c) => c.json({ status: 'ok' }));
863
+
864
+ app.post('/tasks', async (c) => {
865
+ const body = await c.req.json();
866
+ console.log('Created task:', body.title);
867
+ return c.json({ id: '1', title: body.title }, 201);
868
+ });
869
+
870
+ serve({ fetch: app.fetch, port: 3000 }, () => console.log('Hono running on port 3000'));
871
+ ```
872
+
873
+ ```bash
874
+ node -r securenow/register app.mjs
875
+ ```
876
+
877
+ > **Important:** Set `SECURENOW_CAPTURE_BODY=0` with Hono. Do **not** add `require('securenow/register')` inside `.mjs` files.
878
+
879
+ ---
880
+
881
+ ### Feathers
882
+
883
+ ```bash
884
+ npm install securenow @feathersjs/feathers @feathersjs/express @feathersjs/errors
885
+ ```
886
+
887
+ Feathers uses Express transport -- same setup as Express:
888
+
889
+ ```javascript
890
+ // app.js
891
+ require('securenow/register');
892
+ const feathers = require('@feathersjs/feathers');
893
+ const express = require('@feathersjs/express');
894
+ const errors = require('@feathersjs/errors');
895
+
896
+ class TaskService {
897
+ constructor() { this.tasks = []; this.nextId = 1; }
898
+ async find() { return this.tasks; }
899
+ async create(data) {
900
+ if (!data.title) throw new errors.BadRequest('title is required');
901
+ const task = { id: String(this.nextId++), title: data.title };
902
+ this.tasks.push(task);
903
+ console.log('Created task:', task.id);
904
+ return task;
905
+ }
906
+ }
907
+
908
+ const app = express(feathers());
909
+ app.use(express.json());
910
+ app.configure(express.rest());
911
+ app.get('/health', (req, res) => res.json({ status: 'ok' }));
912
+ app.use('/tasks', new TaskService());
913
+ app.use(express.errorHandler());
914
+
915
+ app.listen(3000, () => console.log('Feathers running on port 3000'));
916
+ ```
917
+
918
+ ---
919
+
920
+ ### Next.js
921
+
922
+ See [Next.js Complete Guide](./docs/NEXTJS-SETUP-COMPLETE.md) for the full reference.
923
+
924
+ #### Option A: `withSecureNow()` wrapper (v5.13.0+ -- Recommended)
925
+
926
+ One wrapper handles everything: `serverExternalPackages` (Next 15) or `experimental.serverComponentsExternalPackages` (Next 14), `instrumentationHook`, and webpack warning suppression.
927
+
928
+ **1. Update `next.config.js`:**
929
+
930
+ ```javascript
931
+ const { withSecureNow } = require('securenow/nextjs-webpack-config');
932
+
933
+ module.exports = withSecureNow({
934
+ // your existing config -- reactStrictMode, images, rewrites, etc.
935
+ });
936
+ ```
937
+
938
+ **2. Create `instrumentation.ts` (or `.js`):**
939
+
940
+ ```typescript
941
+ export async function register() {
942
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
943
+ const { registerSecureNow } = require('securenow/nextjs');
944
+ registerSecureNow();
945
+ }
946
+ }
947
+ ```
948
+
949
+ Or run `npx securenow init` to auto-generate this file.
950
+
951
+ **3. Set environment variables in `.env.local`:**
952
+
953
+ ```env
954
+ SECURENOW_APPID=my-nextjs-app
955
+ SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
956
+ SECURENOW_API_KEY=snk_live_abc123...
957
+ SECURENOW_LOGGING_ENABLED=1
958
+ SECURENOW_NO_UUID=1
959
+ ```
960
+
961
+ That's it. `withSecureNow()` auto-detects your Next.js version and configures:
962
+ - **Next.js 15+**: Sets `serverExternalPackages` with all 13 required OTel packages
963
+ - **Next.js 14**: Sets `experimental.serverComponentsExternalPackages` and `experimental.instrumentationHook: true`
964
+ - **Both**: Suppresses webpack warnings from OpenTelemetry instrumentation packages
965
+
966
+ #### Option B: Manual configuration
967
+
968
+ If you prefer not to use the wrapper, manually add the packages:
969
+
970
+ ```javascript
971
+ // next.config.js (Next.js 15+)
972
+ module.exports = {
973
+ serverExternalPackages: [
974
+ 'securenow',
975
+ '@opentelemetry/sdk-node',
976
+ '@opentelemetry/auto-instrumentations-node',
977
+ '@opentelemetry/instrumentation-http',
978
+ '@opentelemetry/exporter-trace-otlp-http',
979
+ '@opentelemetry/exporter-logs-otlp-http',
980
+ '@opentelemetry/sdk-logs',
981
+ '@opentelemetry/instrumentation',
982
+ '@opentelemetry/resources',
983
+ '@opentelemetry/semantic-conventions',
984
+ '@opentelemetry/api',
985
+ '@opentelemetry/api-logs',
986
+ '@vercel/otel',
987
+ ],
988
+ };
989
+ ```
990
+
991
+ ```javascript
992
+ // next.config.js (Next.js 14)
993
+ module.exports = {
994
+ experimental: {
995
+ instrumentationHook: true,
996
+ serverComponentsExternalPackages: [
997
+ 'securenow',
998
+ '@opentelemetry/sdk-node',
999
+ '@opentelemetry/auto-instrumentations-node',
1000
+ '@opentelemetry/instrumentation-http',
1001
+ '@opentelemetry/exporter-trace-otlp-http',
1002
+ '@opentelemetry/exporter-logs-otlp-http',
1003
+ '@opentelemetry/sdk-logs',
1004
+ '@opentelemetry/instrumentation',
1005
+ '@opentelemetry/resources',
1006
+ '@opentelemetry/semantic-conventions',
1007
+ '@opentelemetry/api',
1008
+ '@opentelemetry/api-logs',
1009
+ '@vercel/otel',
1010
+ ],
1011
+ },
1012
+ };
1013
+ ```
1014
+
1015
+ **Why is this needed?** Next.js bundles server code with webpack, which breaks OpenTelemetry's dynamic `require()` calls and monkey-patching. Externalizing these packages keeps them as normal Node.js `require()` calls at runtime. The `withSecureNow()` wrapper handles this automatically.
1016
+
1017
+ ---
1018
+
1019
+ ### Nuxt 3
1020
+
1021
+ ```bash
1022
+ npm install securenow
1023
+ ```
1024
+
1025
+ Add the module to `nuxt.config.ts`:
1026
+
1027
+ ```typescript
1028
+ export default defineNuxtConfig({
1029
+ modules: ['securenow/nuxt'],
1030
+ });
1031
+ ```
1032
+
1033
+ `.env`:
1034
+
1035
+ ```env
1036
+ SECURENOW_APPID=my-nuxt-app
1037
+ SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318
1038
+ SECURENOW_API_KEY=snk_live_abc123...
1039
+ ```
1040
+
1041
+ That's it -- the Nuxt module handles OTel SDK initialization, Nitro externalization, firewall activation, and request tracing automatically. Optional config:
1042
+
1043
+ ```typescript
1044
+ export default defineNuxtConfig({
1045
+ modules: ['securenow/nuxt'],
1046
+ securenow: {
1047
+ captureBody: true,
1048
+ logging: true,
1049
+ noUuid: true,
1050
+ },
1051
+ });
1052
+ ```
1053
+
1054
+ The Nuxt server plugin (v5.13.0+) initializes the firewall independently from OpenTelemetry, so IP blocking works even if tracing encounters an error.
1055
+
1056
+ ---
1057
+
1058
+ ### Compatibility Matrix
1059
+
1060
+ | Framework | Traces | Logs | Body Capture | Firewall | Notes |
1061
+ |-----------|--------|------|--------------|----------|-------|
1062
+ | Express | Yes | Yes | Yes | Yes | Fully compatible |
1063
+ | Fastify | Yes | Yes | **No** | Yes | `SECURENOW_CAPTURE_BODY=0` required |
1064
+ | Koa | Yes | Yes | Yes | Yes | Needs `koa-bodyparser` |
1065
+ | NestJS | Yes | Yes | Yes | Yes | Use `-r ts-node/register` |
1066
+ | Hapi | Yes | Yes | **No** | Yes | `SECURENOW_CAPTURE_BODY=0` required |
1067
+ | h3 | Yes | Yes | Yes | Yes | Uses `toNodeListener()` |
1068
+ | Polka | Yes | Yes | Yes | Yes | Needs manual body parser |
1069
+ | Micro/HTTP | Yes | Yes | Yes | Yes | Full control |
1070
+ | Hono | Yes | Yes | **No** | Yes | `SECURENOW_CAPTURE_BODY=0`; ESM `-r` flag |
1071
+ | Feathers | Yes | Yes | Yes | Yes | Uses Express transport |
1072
+ | Next.js | Yes | Yes | Yes | Yes | Use `instrumentation.ts` + `withSecureNow()` |
1073
+ | Nuxt 3 | Yes | Yes | Yes | Yes | Use `securenow/nuxt` module |
1074
+
1075
+ ---
1076
+
1077
+ ## Firewall -- Automatic IP Blocking
1078
+
1079
+ SecureNow can automatically block IPs from your blocklist at the application layer. No code changes -- just set an API key and the firewall activates.
1080
+
1081
+ ### Enable the Firewall
1082
+
1083
+ ```bash
1084
+ # Add to your .env
1085
+ SECURENOW_API_KEY=snk_live_abc123...
1086
+ ```
1087
+
1088
+ That's it. On startup, you'll see:
1089
+
1090
+ ```
1091
+ [securenow] Firewall: ENABLED
1092
+ [securenow] Firewall: Layer 1 (HTTP 403) active
1093
+ [securenow] Firewall: synced 142 blocked IPs (138 exact + 4 CIDR ranges)
1094
+ ```
1095
+
1096
+ ### How It Works
1097
+
1098
+ The firewall uses a version-based sync protocol for efficiency:
1099
+
1100
+ 1. **Version check** every 10 seconds (lightweight HEAD-like request with ETag)
1101
+ 2. **Full blocklist sync** only when the version changes (or every 5 minutes as a safety net)
1102
+ 3. **In-memory matching** with a pre-compiled set (exact IPs) and sorted CIDR list for sub-millisecond lookups
1103
+ 4. **Exponential backoff** with jitter when the API is temporarily unreachable
1104
+ 5. **Allowlist support** -- trusted IPs are never blocked, even if they appear on the blocklist
1105
+ 6. **Localhost fallback** -- when the configured API URL is unreachable (ECONNREFUSED), the SDK automatically tries `http://localhost:4000` for co-located deployments
1106
+
1107
+ After you block an IP in the dashboard or CLI, it typically takes 10-15 seconds to propagate to all running instances.
1108
+
1109
+ ### Firewall-Only Mode (No Tracing)
1110
+
1111
+ If you only need IP blocking without OpenTelemetry tracing overhead, use the standalone entry point:
1112
+
1113
+ ```bash
1114
+ # Manual preload flag
1115
+ node -r securenow/firewall-only app.js
1116
+
1117
+ # Or via the CLI (v6.1.0+) — same effect, clearer intent
1118
+ securenow run --firewall-only app.js
1119
+ ```
1120
+
1121
+ Or in `package.json`:
1122
+
1123
+ ```json
1124
+ "scripts": {
1125
+ "start": "node -r securenow/firewall-only app.js"
1126
+ }
1127
+ ```
1128
+
1129
+ This is useful when:
1130
+ - You only need IP blocking, not observability
1131
+ - You want to minimize startup time and memory footprint
1132
+ - You're adding the firewall to a project that uses a different tracing solution
1133
+ - For Next.js, this avoids the need for `serverExternalPackages` entirely
1134
+
1135
+ Environment variables for firewall-only mode:
1136
+
1137
+ ```bash
1138
+ SECURENOW_API_KEY=snk_live_abc123... # Required
1139
+ SECURENOW_API_URL=https://api.securenow.ai # Optional (auto-detected)
1140
+ SECURENOW_FIREWALL_ENABLED=1 # Default: 1
1141
+ SECURENOW_FIREWALL_TCP=1 # Optional: Layer 2
1142
+ SECURENOW_FIREWALL_IPTABLES=1 # Optional: Layer 3
1143
+ SECURENOW_FIREWALL_CLOUD=cloudflare # Optional: Layer 4
1144
+ ```
1145
+
1146
+ ### Blocking Layers
1147
+
1148
+ The firewall supports four layers -- Layer 1 is always on, the rest are opt-in:
1149
+
1150
+ | Layer | Env Var | Description |
1151
+ |-------|---------|-------------|
1152
+ | **Layer 1: HTTP** | *(always on)* | Returns 403 Forbidden with a security alert page. Works with proxy headers. |
1153
+ | **Layer 2: TCP** | `SECURENOW_FIREWALL_TCP=1` | `socket.destroy()` -- zero bytes sent back |
1154
+ | **Layer 3: iptables** | `SECURENOW_FIREWALL_IPTABLES=1` | Kernel-level DROP (Linux, requires root) |
1155
+ | **Layer 4: Cloud WAF** | `SECURENOW_FIREWALL_CLOUD=cloudflare` | Pushes to Cloudflare, AWS WAF, or GCP Cloud Armor |
1156
+
1157
+ ### Blocked Page
1158
+
1159
+ When an IP is blocked at Layer 1, the user sees a full-page security alert with:
1160
+ - Their detected IP address
1161
+ - A warning that malicious activity was detected
1162
+ - Contact information (`contact@securenow.ai`) for false positives
1163
+
1164
+ ### Get an API Key
1165
+
1166
+ ```bash
1167
+ npx securenow login
1168
+ npx securenow firewall status
1169
+ ```
1170
+
1171
+ Or create one from the dashboard with the `firewall:read` scope.
1172
+
1173
+ See the [Firewall Guide](./docs/FIREWALL-GUIDE.md) for the full reference.
1174
+
1175
+ ---
1176
+
1177
+ ## Environment Variables Reference
1178
+
1179
+ ### Required Variables
1180
+
1181
+ | Variable | Description | Example |
1182
+ |----------|-------------|---------|
1183
+ | `SECURENOW_APPID` | Your application identifier. Used as the service name in traces. | `my-app` |
1184
+ | `SECURENOW_INSTANCE` | Base URL of your OTLP collector endpoint. | `http://localhost:4318` |
1185
+
1186
+ ### Optional Configuration
1187
+
1188
+ #### Service Naming
1189
+
1190
+ | Variable | Description | Default |
1191
+ |----------|-------------|---------|
1192
+ | `OTEL_SERVICE_NAME` | Alternative to SECURENOW_APPID. Standard OpenTelemetry variable. | - |
1193
+ | `SECURENOW_NO_UUID` | Set to `1` to disable UUID suffix on service name. Useful for clustered apps. | `0` |
1194
+ | `SECURENOW_STRICT` | Set to `1` to exit process if SECURENOW_APPID is not set in cluster mode. | `0` |
1195
+
1196
+ #### Connection Settings
1197
+
1198
+ | Variable | Description | Default |
1199
+ |----------|-------------|---------|
1200
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | Alternative to SECURENOW_INSTANCE. Standard OpenTelemetry variable. | - |
1201
+ | `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | Override traces endpoint specifically. | `{SECURENOW_INSTANCE}/v1/traces` |
1202
+ | `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` | Override logs endpoint specifically. | `{SECURENOW_INSTANCE}/v1/logs` |
1203
+ | `OTEL_EXPORTER_OTLP_HEADERS` | Headers to send with OTLP exports. Format: `key1=value1,key2=value2` | - |
1204
+
1205
+ #### Logging
1206
+
1207
+ | Variable | Description | Default |
1208
+ |----------|-------------|---------|
1209
+ | `SECURENOW_LOGGING_ENABLED` | Enable automatic logging to OTLP backend. Set to `1` to enable, `0` to disable. | `1` |
1210
+
1211
+ #### Request Body Capture
1212
+
1213
+ | Variable | Description | Default |
1214
+ |----------|-------------|---------|
1215
+ | `SECURENOW_CAPTURE_BODY` | Enable request body capture in traces. Set to `1` to enable. | `0` |
1216
+ | `SECURENOW_MAX_BODY_SIZE` | Maximum body size to capture in bytes. Bodies larger than this are truncated. | `10240` (10KB) |
1217
+ | `SECURENOW_SENSITIVE_FIELDS` | Comma-separated list of additional field names to redact. | - |
1218
+ | `SECURENOW_CAPTURE_MULTIPART` | Enable multipart/form-data capture. Streams through the request to extract text field values and file metadata (name, filename, content-type, size) without buffering file content. Set to `1` to enable. | `0` |
1219
+
1220
+ **Default sensitive fields (auto-redacted):** `password`, `passwd`, `pwd`, `secret`, `token`, `api_key`, `apikey`, `access_token`, `auth`, `credentials`, `mysql_pwd`, `stripeToken`, `card`, `cardnumber`, `ccv`, `cvc`, `cvv`, `ssn`, `pin`
1221
+
1222
+ #### Instrumentation Control
1223
+
1224
+ | Variable | Description | Default |
1225
+ |----------|-------------|---------|
1226
+ | `SECURENOW_DISABLE_INSTRUMENTATIONS` | Comma-separated list of instrumentation packages to disable. | - |
1227
+
1228
+ **Example:** `SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns` disables filesystem and DNS instrumentations.
1229
+
1230
+ #### Firewall
1231
+
1232
+ | Variable | Description | Default |
1233
+ |----------|-------------|---------|
1234
+ | `SECURENOW_API_KEY` | API key with `firewall:read` scope. Enables the firewall when set. | - |
1235
+ | `SECURENOW_API_URL` | SecureNow API base URL. Auto-detected for co-located deployments (falls back to `http://localhost:4000` on ECONNREFUSED). | `https://api.securenow.ai` |
1236
+ | `SECURENOW_FIREWALL_ENABLED` | Master kill-switch. Set to `0` to disable. | `1` |
1237
+ | `SECURENOW_FIREWALL_VERSION_INTERVAL` | Seconds between version checks (lightweight ETag-based). | `10` |
1238
+ | `SECURENOW_FIREWALL_SYNC_INTERVAL` | Full blocklist refresh interval in seconds (safety net). | `300` |
1239
+ | `SECURENOW_FIREWALL_FAIL_MODE` | `open` (allow when unavailable) or `closed` (block all). | `open` |
1240
+ | `SECURENOW_FIREWALL_STATUS_CODE` | HTTP status code for blocked requests. | `403` |
1241
+ | `SECURENOW_FIREWALL_LOG` | Log blocked requests and sync events to console. Set to `0` to silence. | `1` |
1242
+ | `SECURENOW_FIREWALL_TCP` | Enable Layer 2 TCP blocking. | `0` |
1243
+ | `SECURENOW_FIREWALL_IPTABLES` | Enable Layer 3 iptables blocking. | `0` |
1244
+ | `SECURENOW_FIREWALL_CLOUD` | Cloud WAF provider: `cloudflare`, `aws`, or `gcp`. | - |
1245
+ | `SECURENOW_FIREWALL_CLOUD_DRY_RUN` | Log cloud pushes without applying changes. | `0` |
1246
+ | `SECURENOW_TRUSTED_PROXIES` | Comma-separated trusted proxy IPs. | - |
1247
+
1248
+ See [Firewall Guide](./docs/FIREWALL-GUIDE.md) for complete details on all layers.
1249
+
1250
+ #### Debugging
1251
+
1252
+ | Variable | Description | Default |
1253
+ |----------|-------------|---------|
1254
+ | `OTEL_LOG_LEVEL` | OpenTelemetry SDK log level. Options: `debug`, `info`, `warn`, `error` | `none` |
1255
+ | `SECURENOW_TEST_SPAN` | Set to `1` to emit a test span on startup. | `0` |
1256
+
1257
+ #### Environment
1258
+
1259
+ | Variable | Description | Default |
1260
+ |----------|-------------|---------|
1261
+ | `NODE_ENV` | Deployment environment name. Sent as `deployment.environment` attribute. | `production` |
1262
+
1263
+ ---
1264
+
1265
+ ## Entry Points Reference
1266
+
1267
+ SecureNow provides multiple entry points depending on your needs:
1268
+
1269
+ | Entry Point | Usage | Includes Tracing | Includes Firewall | Notes |
1270
+ |-------------|-------|-------------------|-------------------|-------|
1271
+ | `securenow/register` | `node -r securenow/register app.js` | Yes | Yes | Default -- full tracing + firewall |
1272
+ | `securenow/firewall-only` | `node -r securenow/firewall-only app.js` | No | Yes | Firewall only, no OTel overhead |
1273
+ | `securenow/nextjs` | `require('securenow/nextjs').registerSecureNow()` | Yes | Yes | Next.js instrumentation hook |
1274
+ | `securenow/nuxt` | `modules: ['securenow/nuxt']` | Yes | Yes | Nuxt 3 module |
1275
+ | `securenow/nextjs-webpack-config` | `withSecureNow(config)` | - | - | Next.js config wrapper |
1276
+ | `securenow/firewall` | `require('securenow/firewall').init({...})` | No | Yes | Programmatic firewall API |
1277
+ | `securenow/tracing` | `require('securenow/tracing')` | Yes | No | Programmatic tracing API |
1278
+
1279
+ ---
1280
+
1281
+ ## Logging Setup
1282
+
1283
+ ### Automatic Console Logging
1284
+
1285
+ Since **v5.6.0**, when `SECURENOW_LOGGING_ENABLED=1`, all console calls are automatically forwarded as OTLP log records:
1286
+
1287
+ ```javascript
1288
+ // At the top of your main file
1289
+ require('securenow/register');
1290
+
1291
+ // With SECURENOW_LOGGING_ENABLED=1, all console logs are automatically sent
1292
+ console.log('Application started');
1293
+ console.info('User action', { userId: 123, action: 'login' });
1294
+ console.warn('Deprecation warning');
1295
+ console.error('Error occurred', { error: 'Something failed' });
1296
+ console.debug('Debug info');
1297
+ ```
1298
+
1299
+ **Severity mapping:**
1300
+ - `console.log()` -> INFO
1301
+ - `console.info()` -> INFO
1302
+ - `console.warn()` -> WARN
1303
+ - `console.error()` -> ERROR
1304
+ - `console.debug()` -> DEBUG
1305
+
1306
+ **Environment variable:**
1307
+ ```bash
1308
+ SECURENOW_LOGGING_ENABLED=1
1309
+ ```
1310
+
1311
+ ### Direct Logger API
1312
+
1313
+ For more control, use the OpenTelemetry logger API:
1314
+
1315
+ ```javascript
1316
+ require('securenow/register');
1317
+ const { getLogger } = require('securenow/tracing');
1318
+
1319
+ // Get a logger instance
1320
+ const logger = getLogger('my-module', '1.0.0');
1321
+
1322
+ // Emit structured logs
1323
+ logger.emit({
1324
+ severityNumber: 9, // INFO
1325
+ severityText: 'INFO',
1326
+ body: 'User logged in',
1327
+ attributes: {
1328
+ userId: 123,
1329
+ username: 'john',
1330
+ sessionId: 'abc123',
1331
+ },
1332
+ });
1333
+ ```
1334
+
1335
+ **Severity numbers:**
1336
+ - `5` - DEBUG
1337
+ - `9` - INFO
1338
+ - `13` - WARN
1339
+ - `17` - ERROR
1340
+
1341
+ ### Using with NODE_OPTIONS
1342
+
1343
+ ```bash
1344
+ # Enable tracing + logging (console auto-forwarding is built-in since v5.6.0)
1345
+ NODE_OPTIONS="-r securenow/register" \
1346
+ SECURENOW_APPID=my-app \
1347
+ SECURENOW_INSTANCE=https://freetrial.securenow.ai:4318 \
1348
+ SECURENOW_LOGGING_ENABLED=1 \
1349
+ node app.js
1350
+ ```
1351
+
1352
+ ---
1353
+
1354
+ ## Request Body Capture
1355
+
1356
+ SecureNow can capture HTTP request bodies in traces for debugging purposes. This is disabled by default.
1357
+
1358
+ ### Enable Body Capture
1359
+
1360
+ ```bash
1361
+ export SECURENOW_CAPTURE_BODY=1
1362
+ export SECURENOW_MAX_BODY_SIZE=10240 # 10KB (optional)
1363
+ ```
1364
+
1365
+ ### Supported Content Types
1366
+
1367
+ - `application/json`
1368
+ - `application/x-www-form-urlencoded`
1369
+ - `application/graphql`
1370
+ - `multipart/form-data` (requires `SECURENOW_CAPTURE_MULTIPART=1`)
1371
+
1372
+ ### Multipart Body Capture (v5.8.0+)
1373
+
1374
+ Enable with `SECURENOW_CAPTURE_MULTIPART=1` to capture multipart/form-data requests. Uses a streaming parser that never buffers file content -- memory stays at ~few KB regardless of upload size.
1375
+
1376
+ **What gets captured:**
1377
+ - **Text fields** -- field name and value (up to 1000 chars), with sensitive fields auto-redacted
1378
+ - **File fields** -- metadata only: field name, filename, content-type, and size in bytes
1379
+
1380
+ **Example trace attribute:**
1381
+ ```json
1382
+ {
1383
+ "fields": { "description": "My upload", "token": "[REDACTED]" },
1384
+ "files": [
1385
+ { "field": "avatar", "filename": "photo.jpg", "contentType": "image/jpeg", "size": 524288 },
1386
+ { "field": "resume", "filename": "cv.pdf", "contentType": "application/pdf", "size": 1048576 }
1387
+ ]
1388
+ }
1389
+ ```
1390
+
1391
+ File binary content is never stored in traces.
1392
+
1393
+ ### Sensitive Data Redaction
1394
+
1395
+ All request bodies are automatically scanned and sensitive fields are redacted:
1396
+
1397
+ **Automatically redacted fields:** `password`, `secret`, `token`, `api_key`, `card`, `cvv`, `ssn`, and more.
1398
+
1399
+ **Add custom fields to redact:**
1400
+
1401
+ ```bash
1402
+ export SECURENOW_SENSITIVE_FIELDS="custom_secret,internal_token"
1403
+ ```
1404
+
1405
+ ### Example
1406
+
1407
+ ```javascript
1408
+ // POST /api/users with body:
1409
+ {
1410
+ "email": "user@example.com",
1411
+ "password": "secret123",
1412
+ "name": "John Doe"
1413
+ }
1414
+
1415
+ // Captured in trace as:
1416
+ {
1417
+ "email": "user@example.com",
1418
+ "password": "[REDACTED]",
1419
+ "name": "John Doe"
1420
+ }
1421
+ ```
1422
+
1423
+ ---
1424
+
1425
+ ## Advanced Configuration
1426
+
1427
+ ### Complete Example with All Options
1428
+
1429
+ ```bash
1430
+ # Service identification
1431
+ export SECURENOW_APPID=my-production-app
1432
+ export SECURENOW_NO_UUID=1
1433
+ export SECURENOW_STRICT=1
1434
+
1435
+ # OTLP backend
1436
+ export SECURENOW_INSTANCE=http://collector.example.com:4318
1437
+ export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-api-key"
1438
+
1439
+ # Logging
1440
+ export SECURENOW_LOGGING_ENABLED=1
1441
+
1442
+ # Request body capture
1443
+ export SECURENOW_CAPTURE_BODY=1
1444
+ export SECURENOW_MAX_BODY_SIZE=20480
1445
+ export SECURENOW_SENSITIVE_FIELDS="internal_id,session_key"
1446
+
1447
+ # Firewall
1448
+ export SECURENOW_API_KEY=snk_live_abc123...
1449
+ export SECURENOW_FIREWALL_TCP=1
1450
+ export SECURENOW_FIREWALL_VERSION_INTERVAL=10
1451
+ export SECURENOW_FIREWALL_SYNC_INTERVAL=300
1452
+
1453
+ # Environment
1454
+ export NODE_ENV=production
1455
+
1456
+ # Debugging
1457
+ export OTEL_LOG_LEVEL=info
1458
+
1459
+ # Disable specific instrumentations
1460
+ export SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns
1461
+
1462
+ # Run application
1463
+ NODE_OPTIONS="-r securenow/register" node app.js
1464
+ ```
1465
+
1466
+ ### Using Multiple Logger Instances
1467
+
1468
+ ```javascript
1469
+ const { getLogger } = require('securenow/tracing');
1470
+
1471
+ const authLogger = getLogger('auth-service', '1.0.0');
1472
+ const dbLogger = getLogger('database', '1.0.0');
1473
+ const apiLogger = getLogger('api-handler', '1.0.0');
1474
+
1475
+ authLogger.emit({
1476
+ severityNumber: 9,
1477
+ severityText: 'INFO',
1478
+ body: 'User authenticated',
1479
+ attributes: { userId: 123 },
1480
+ });
1481
+
1482
+ dbLogger.emit({
1483
+ severityNumber: 13,
1484
+ severityText: 'WARN',
1485
+ body: 'Slow query detected',
1486
+ attributes: { queryTime: 5000 },
1487
+ });
1488
+ ```
1489
+
1490
+ ### Check if Logging is Enabled
1491
+
1492
+ ```javascript
1493
+ const { isLoggingEnabled } = require('securenow/tracing');
1494
+
1495
+ if (isLoggingEnabled()) {
1496
+ console.log('Logging is enabled');
1497
+ } else {
1498
+ console.log('Logging is disabled');
1499
+ }
1500
+ ```
1501
+
1502
+ ### Programmatic Configuration
1503
+
1504
+ While environment variables are recommended, you can also configure programmatically:
1505
+
1506
+ ```javascript
1507
+ // Set environment variables before requiring securenow
1508
+ process.env.SECURENOW_APPID = 'my-app';
1509
+ process.env.SECURENOW_INSTANCE = 'http://localhost:4318';
1510
+ process.env.SECURENOW_LOGGING_ENABLED = '1';
1511
+
1512
+ // Then initialize (console log forwarding is automatic since v5.6.0)
1513
+ require('securenow/register');
1514
+ ```
1515
+
1516
+ ---
1517
+
1518
+ ## TypeScript Support
1519
+
1520
+ SecureNow includes full TypeScript definitions.
1521
+
1522
+ ### Type Definitions
1523
+
1524
+ ```typescript
1525
+ import { getLogger, isLoggingEnabled, Logger, LogRecord } from 'securenow/tracing';
1526
+
1527
+ // Get a typed logger
1528
+ const logger: Logger | null = getLogger('my-service', '1.0.0');
1529
+
1530
+ // Emit a log with type checking
1531
+ if (logger) {
1532
+ const logRecord: LogRecord = {
1533
+ severityNumber: 9,
1534
+ severityText: 'INFO',
1535
+ body: 'User action',
1536
+ attributes: {
1537
+ userId: 123,
1538
+ action: 'login',
1539
+ },
1540
+ };
1541
+
1542
+ logger.emit(logRecord);
1543
+ }
1544
+
1545
+ // Check if enabled
1546
+ const enabled: boolean = isLoggingEnabled();
1547
+ ```
1548
+
1549
+ ### Next.js with TypeScript
1550
+
1551
+ ```typescript
1552
+ // instrumentation.ts
1553
+ export async function register() {
1554
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
1555
+ const { registerSecureNow } = require('securenow/nextjs');
1556
+ registerSecureNow();
1557
+ }
1558
+ }
1559
+ ```
1560
+
1561
+ ```javascript
1562
+ // next.config.js
1563
+ const { withSecureNow } = require('securenow/nextjs-webpack-config');
1564
+
1565
+ module.exports = withSecureNow({
1566
+ reactStrictMode: true,
1567
+ });
1568
+ ```
1569
+
1570
+ ### NestJS with TypeScript
1571
+
1572
+ Use `-r securenow/register -r ts-node/register` flags instead of in-code require:
1573
+
1574
+ ```typescript
1575
+ // main.ts (run with: node -r securenow/register -r ts-node/register main.ts)
1576
+ import { NestFactory } from '@nestjs/core';
1577
+ import { AppModule } from './app.module';
1578
+
1579
+ async function bootstrap() {
1580
+ const app = await NestFactory.create(AppModule);
1581
+ await app.listen(3000);
1582
+ }
1583
+
1584
+ bootstrap();
1585
+ ```
1586
+
1587
+ ---
1588
+
1589
+ ## Troubleshooting
1590
+
1591
+ ### Traces Not Appearing
1592
+
1593
+ **Check 1: Verify environment variables**
1594
+
1595
+ ```bash
1596
+ echo $SECURENOW_APPID
1597
+ echo $SECURENOW_INSTANCE
1598
+ ```
1599
+
1600
+ Both should output values.
1601
+
1602
+ **Check 2: Verify OTLP collector is running**
1603
+
1604
+ ```bash
1605
+ curl http://localhost:4318/v1/traces
1606
+ # Should return 200 or 405 (method not allowed)
1607
+ ```
1608
+
1609
+ **Check 3: Enable debug logging**
1610
+
1611
+ ```bash
1612
+ export OTEL_LOG_LEVEL=debug
1613
+ node app.js
1614
+ ```
1615
+
1616
+ Look for lines like:
1617
+ ```
1618
+ [securenow] OTel SDK started -> http://localhost:4318/v1/traces
1619
+ ```
1620
+
1621
+ **Check 4: Verify initialization order**
1622
+
1623
+ SecureNow must be required BEFORE any other modules:
1624
+
1625
+ ```javascript
1626
+ // Correct
1627
+ require('securenow/register');
1628
+ const express = require('express');
1629
+
1630
+ // Wrong -- too late!
1631
+ const express = require('express');
1632
+ require('securenow/register');
1633
+ ```
1634
+
1635
+ ### Firewall Not Blocking IPs
1636
+
1637
+ **Check 1: Is `SECURENOW_API_KEY` set?**
1638
+
1639
+ ```bash
1640
+ echo $SECURENOW_API_KEY
1641
+ ```
1642
+
1643
+ **Check 2: Is the IP in the blocklist?**
1644
+
1645
+ ```bash
1646
+ npx securenow blocklist
1647
+ npx securenow firewall test-ip 1.2.3.4
1648
+ ```
1649
+
1650
+ **Check 3: Check startup logs for sync status**
1651
+
1652
+ You should see:
1653
+ ```
1654
+ [securenow] Firewall: ENABLED
1655
+ [securenow] Firewall: synced 142 blocked IPs
1656
+ ```
1657
+
1658
+ If you see `initial sync failed`, check the API URL and key.
1659
+
1660
+ **Check 4: Wait for propagation**
1661
+
1662
+ After blocking an IP, it takes 10-15 seconds to propagate (one version-check interval).
1663
+
1664
+ **Check 5: Are you behind a proxy?**
1665
+
1666
+ Set `SECURENOW_TRUSTED_PROXIES` to your proxy's IP so the firewall sees the real client IP.
1667
+
1668
+ **Check 6: Using PM2?**
1669
+
1670
+ Make sure `node_args: '-r securenow/register'` is in your `ecosystem.config.cjs`. Without it, PM2 restarts skip the SDK entirely.
1671
+
1672
+ ### Logs Not Appearing
1673
+
1674
+ **Check 1: Is logging enabled?**
1675
+
1676
+ ```bash
1677
+ echo $SECURENOW_LOGGING_ENABLED
1678
+ # Should output: 1
1679
+ ```
1680
+
1681
+ **Check 2: Verify console instrumentation is loaded**
1682
+
1683
+ ```javascript
1684
+ require('securenow/register');
1685
+ ```
1686
+
1687
+ **Check 3: Check console output**
1688
+
1689
+ You should see:
1690
+ ```
1691
+ [securenow] Logging: ENABLED -> http://localhost:4318/v1/logs
1692
+ ```
1693
+
1694
+ **Check 4: Verify OTLP logs endpoint**
1695
+
1696
+ ```bash
1697
+ curl http://localhost:4318/v1/logs
1698
+ # Should return 200 or 405
1699
+ ```
1700
+
1701
+ ### Request Body Not Captured
1702
+
1703
+ **Check 1: Is body capture enabled?**
1704
+
1705
+ ```bash
1706
+ export SECURENOW_CAPTURE_BODY=1
1707
+ ```
1708
+
1709
+ **Check 2: Verify content type**
1710
+
1711
+ Body capture only works for:
1712
+ - `application/json`
1713
+ - `application/x-www-form-urlencoded`
1714
+ - `application/graphql`
1715
+
1716
+ **Check 3: Check body size**
1717
+
1718
+ Bodies larger than `SECURENOW_MAX_BODY_SIZE` are truncated:
1719
+
1720
+ ```bash
1721
+ export SECURENOW_MAX_BODY_SIZE=20480 # Increase to 20KB
1722
+ ```
1723
+
1724
+ ### High Memory Usage
1725
+
1726
+ **Option 1: Disable body capture**
1727
+
1728
+ ```bash
1729
+ export SECURENOW_CAPTURE_BODY=0
1730
+ ```
1731
+
1732
+ **Option 2: Reduce body size limit**
1733
+
1734
+ ```bash
1735
+ export SECURENOW_MAX_BODY_SIZE=5120 # 5KB
1736
+ ```
1737
+
1738
+ **Option 3: Disable specific instrumentations**
1739
+
1740
+ ```bash
1741
+ export SECURENOW_DISABLE_INSTRUMENTATIONS=fs,dns,net
1742
+ ```
1743
+
1744
+ ### Next.js Instrumentation Not Working
1745
+
1746
+ **Check 1: Using `withSecureNow()`?**
1747
+
1748
+ ```javascript
1749
+ const { withSecureNow } = require('securenow/nextjs-webpack-config');
1750
+ module.exports = withSecureNow({ /* your config */ });
1751
+ ```
1752
+
1753
+ This auto-handles `serverExternalPackages` / `experimental.serverComponentsExternalPackages` and `instrumentationHook` based on your Next.js version.
1754
+
1755
+ **Check 2: Verify instrumentation file location**
1756
+
1757
+ `instrumentation.ts` or `instrumentation.js` must be in the project root (same level as `app/` or `pages/`).
1758
+
1759
+ **Check 3: Check for OTel MODULE_NOT_FOUND errors**
1760
+
1761
+ If you see `MODULE_NOT_FOUND` for `@opentelemetry/*` packages, your `next.config.js` is missing the externalization. Use `withSecureNow()` to fix this automatically.
1762
+
1763
+ **Check 4: Restart dev server**
1764
+
1765
+ ```bash
1766
+ # Kill the server and restart
1767
+ npm run dev
1768
+ ```
1769
+
1770
+ ### PM2 Cluster Issues
1771
+
1772
+ **Problem: Different service names for each worker**
1773
+
1774
+ **Solution: Use SECURENOW_NO_UUID**
1775
+
1776
+ ```bash
1777
+ export SECURENOW_NO_UUID=1
1778
+ ```
1779
+
1780
+ This uses the same service name for all workers.
1781
+
1782
+ **Problem: Workers not instrumented / firewall not active**
1783
+
1784
+ **Solution: Use node_args in PM2 config**
1785
+
1786
+ ```javascript
1787
+ // ecosystem.config.cjs
1788
+ module.exports = {
1789
+ apps: [{
1790
+ name: 'my-app',
1791
+ script: './app.js',
1792
+ instances: 4,
1793
+ node_args: '-r securenow/register',
1794
+ env: {
1795
+ SECURENOW_APPID: 'my-app',
1796
+ SECURENOW_INSTANCE: 'http://localhost:4318',
1797
+ SECURENOW_API_KEY: 'snk_live_abc123...',
1798
+ }
1799
+ }]
1800
+ };
1801
+ ```
1802
+
1803
+ Without `node_args`, PM2 starts your script directly without the securenow preload, so neither tracing nor the firewall will be active.
1804
+
1805
+ ---
1806
+
1807
+ ## Best Practices
1808
+
1809
+ ### 1. Use Environment Variables
1810
+
1811
+ Don't hardcode configuration. Use environment variables:
1812
+
1813
+ ```javascript
1814
+ // Bad
1815
+ process.env.SECURENOW_APPID = 'hardcoded-value';
1816
+
1817
+ // Good -- use .env file or export
1818
+ // .env
1819
+ SECURENOW_APPID=my-app
1820
+ SECURENOW_INSTANCE=http://localhost:4318
1821
+ ```
1822
+
1823
+ ### 2. Use Structured Logging
1824
+
1825
+ Pass objects to console methods for better filtering:
1826
+
1827
+ ```javascript
1828
+ // Less useful
1829
+ console.log('User 123 logged in');
1830
+
1831
+ // Better -- structured attributes
1832
+ console.log('User logged in', {
1833
+ userId: 123,
1834
+ email: 'user@example.com',
1835
+ timestamp: new Date().toISOString(),
1836
+ });
1837
+ ```
1838
+
1839
+ ### 3. Choose Appropriate Severity Levels
1840
+
1841
+ ```javascript
1842
+ // Normal operations
1843
+ console.log('Request processed');
1844
+ console.info('User created', { userId: 123 });
1845
+
1846
+ // Warnings
1847
+ console.warn('API rate limit approaching', { remaining: 10 });
1848
+
1849
+ // Errors
1850
+ console.error('Database connection failed', { error: err.message });
1851
+
1852
+ // Debug (only in development)
1853
+ console.debug('Cache hit', { key: 'user:123' });
1854
+ ```
1855
+
1856
+ ### 4. Don't Log Sensitive Data
1857
+
1858
+ Even though SecureNow automatically redacts common sensitive fields, avoid logging:
1859
+
1860
+ ```javascript
1861
+ // Bad
1862
+ console.log('Login attempt', {
1863
+ email: 'user@example.com',
1864
+ password: 'secret123', // Will be redacted, but don't log it!
1865
+ });
1866
+
1867
+ // Good
1868
+ console.log('Login attempt', {
1869
+ email: 'user@example.com',
1870
+ timestamp: Date.now(),
1871
+ });
1872
+ ```
1873
+
1874
+ ### 5. Use Different Logger Instances for Different Modules
1875
+
1876
+ ```javascript
1877
+ // auth-service.js
1878
+ const authLogger = getLogger('auth-service', '1.0.0');
1879
+
1880
+ // database.js
1881
+ const dbLogger = getLogger('database', '1.0.0');
1882
+
1883
+ // api.js
1884
+ const apiLogger = getLogger('api', '1.0.0');
1885
+ ```
1886
+
1887
+ ### 6. Enable Body Capture Only in Development
1888
+
1889
+ ```bash
1890
+ # .env.development
1891
+ SECURENOW_CAPTURE_BODY=1
1892
+
1893
+ # .env.production
1894
+ SECURENOW_CAPTURE_BODY=0
1895
+ ```
1896
+
1897
+ ---
1898
+
1899
+ ## Supported Runtimes
1900
+
1901
+ - **Node.js:** 18+
1902
+ - **Frameworks:** Express, Next.js, Nuxt 3, Fastify, NestJS, Koa, Hapi, and more
1903
+ - **Databases:** PostgreSQL, MySQL, MongoDB, Redis
1904
+ - **HTTP Clients:** axios, fetch, node-fetch, got, request
1905
+ - **GraphQL:** Apollo Server, GraphQL.js
1906
+ - **Message Queues:** Redis, BullMQ
1907
+ - **And many more via OpenTelemetry auto-instrumentation**
1908
+
1909
+ ---
1910
+
1911
+ ## Automatic Instrumentations
1912
+
1913
+ SecureNow automatically instruments:
1914
+
1915
+ - HTTP/HTTPS (incoming and outgoing)
1916
+ - Express.js
1917
+ - Fastify
1918
+ - Koa
1919
+ - Hapi
1920
+ - Next.js
1921
+ - PostgreSQL
1922
+ - MySQL/MySQL2
1923
+ - MongoDB
1924
+ - Redis
1925
+ - GraphQL
1926
+ - gRPC
1927
+ - DNS
1928
+ - File System
1929
+ - And 50+ more libraries
1930
+
1931
+ No code changes needed!
1932
+
1933
+ ---
1934
+
1935
+ ## Architecture
1936
+
1937
+ ```
1938
+ Your Application
1939
+ (Express/Next.js/etc)
1940
+ |
1941
+ v
1942
+ +---------------------------+
1943
+ | SecureNow Library |
1944
+ | +---------------------+ |
1945
+ | | Firewall Layer | | <-- Blocks IPs before they reach your app
1946
+ | +---------------------+ |
1947
+ | | Auto-instrumentation | |
1948
+ | | Console wrapper | |
1949
+ | | Body capture | |
1950
+ | +---------------------+ |
1951
+ +---------------------------+
1952
+ |
1953
+ +---------+---------+
1954
+ | |
1955
+ v v
1956
+ +-----------+ +-----------+
1957
+ | OTel SDK | | SecureNow |
1958
+ | OTLP | | API |
1959
+ | Exporters | | (blocklist|
1960
+ +-----------+ | sync) |
1961
+ | +-----------+
1962
+ v
1963
+ +-----------+
1964
+ | Your OTLP |
1965
+ | Backend |
1966
+ +-----------+
1967
+ ```
1968
+
1969
+ ---
1970
+
1971
+ ## Performance
1972
+
1973
+ - **Minimal overhead:** < 1% CPU and memory impact
1974
+ - **Batch export:** Traces and logs are batched before sending
1975
+ - **Async processing:** No blocking of application threads
1976
+ - **Configurable:** Disable instrumentations you don't need
1977
+ - **Firewall:** Sub-millisecond IP lookups using pre-compiled hash sets and sorted CIDR lists
1978
+ - **Smart sync:** Version-based polling with ETag/304 eliminates unnecessary data transfer
1979
+
1980
+ ---
1981
+
1982
+ ## Security
1983
+
1984
+ - **Automatic redaction** of sensitive fields (passwords, tokens, keys)
1985
+ - **Configurable** sensitive field patterns
1986
+ - **No data stored** locally -- everything sent to your OTLP backend
1987
+ - **Multi-layer firewall** -- blocks IPs at HTTP, TCP, OS, and cloud-edge levels
1988
+ - **API keys** with granular scopes, IP allowlisting, and SHA-256 hashing
1989
+ - **Allowlist support** -- trusted IPs are never blocked
1990
+ - **Fail-open by default** -- network issues never accidentally block legitimate traffic
1991
+ - **Open source** -- audit the code yourself
1992
+
1993
+ ---
1994
+
1995
+ ## License
1996
+
1997
+ ISC
1998
+
1999
+ ---
2000
+
2001
+ ## Support
2002
+
2003
+ - **Documentation:** [GitHub Docs](https://github.com/your-repo/securenow-npm/tree/main/docs)
2004
+ - **Issues:** [GitHub Issues](https://github.com/your-repo/securenow-npm/issues)
2005
+ - **Examples:** [GitHub Examples](https://github.com/your-repo/securenow-npm/tree/main/examples)
2006
+
2007
+ ---
2008
+
2009
+ ## Changelog
2010
+
2011
+ See [CHANGELOG.md](CHANGELOG.md) for version history.
2012
+
2013
+ ---
2014
+
2015
+ ## Contributing
2016
+
2017
+ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
2018
+
2019
+ ---
2020
+
2021
+ ## Related Packages
2022
+
2023
+ - [@opentelemetry/sdk-node](https://www.npmjs.com/package/@opentelemetry/sdk-node) - Core OpenTelemetry SDK
2024
+ - [@opentelemetry/auto-instrumentations-node](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) - Auto-instrumentation
2025
+ - [@opentelemetry/exporter-trace-otlp-http](https://www.npmjs.com/package/@opentelemetry/exporter-trace-otlp-http) - OTLP exporter
2026
+
2027
+ ---
2028
+
2029
+ **Made with care for the Node.js community**