securenow 5.18.0 → 6.0.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 (85) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +40 -239
  3. package/cli.js +455 -415
  4. package/console-instrumentation.js +136 -147
  5. package/docs/ALL-FRAMEWORKS-QUICKSTART.md +455 -1339
  6. package/docs/ARCHITECTURE.md +3 -3
  7. package/docs/AUTO-BODY-CAPTURE.md +1 -1
  8. package/docs/AUTO-SETUP.md +4 -4
  9. package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
  10. package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
  11. package/docs/CHANGELOG-NEXTJS.md +35 -1
  12. package/docs/CUSTOMER-GUIDE.md +16 -16
  13. package/docs/EASIEST-SETUP.md +5 -5
  14. package/docs/ENVIRONMENT-VARIABLES.md +652 -880
  15. package/docs/EXPRESS-BODY-CAPTURE.md +12 -13
  16. package/docs/EXPRESS-SETUP-GUIDE.md +720 -719
  17. package/docs/INDEX.md +4 -22
  18. package/docs/LOGGING-GUIDE.md +708 -701
  19. package/docs/LOGGING-QUICKSTART.md +255 -234
  20. package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
  21. package/docs/NEXTJS-GUIDE.md +14 -14
  22. package/docs/NEXTJS-QUICKSTART.md +1 -1
  23. package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
  24. package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
  25. package/docs/REDACTION-EXAMPLES.md +1 -1
  26. package/docs/REQUEST-BODY-CAPTURE.md +10 -19
  27. package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
  28. package/examples/README.md +6 -6
  29. package/examples/instrumentation-with-auto-capture.ts +1 -1
  30. package/examples/nextjs-env-example.txt +2 -2
  31. package/examples/nextjs-instrumentation.js +1 -1
  32. package/examples/nextjs-instrumentation.ts +1 -1
  33. package/examples/nextjs-with-logging-example.md +6 -6
  34. package/examples/nextjs-with-options.ts +1 -1
  35. package/examples/test-nextjs-setup.js +1 -1
  36. package/nextjs-auto-capture.js +207 -199
  37. package/nextjs-middleware.js +181 -186
  38. package/nextjs-webpack-config.js +53 -88
  39. package/nextjs-wrapper.js +158 -158
  40. package/nextjs.d.ts +1 -1
  41. package/nextjs.js +198 -186
  42. package/package.json +45 -67
  43. package/postinstall.js +6 -6
  44. package/register.d.ts +1 -1
  45. package/register.js +4 -39
  46. package/tracing.d.ts +1 -2
  47. package/tracing.js +26 -286
  48. package/web-vite.mjs +156 -239
  49. package/CONSUMING-APPS-GUIDE.md +0 -455
  50. package/NPM_README.md +0 -1933
  51. package/SKILL-API.md +0 -600
  52. package/SKILL-CLI.md +0 -409
  53. package/cidr.js +0 -83
  54. package/cli/apps.js +0 -585
  55. package/cli/auth.js +0 -280
  56. package/cli/client.js +0 -115
  57. package/cli/config.js +0 -173
  58. package/cli/firewall.js +0 -100
  59. package/cli/fp.js +0 -638
  60. package/cli/init.js +0 -201
  61. package/cli/monitor.js +0 -440
  62. package/cli/run.js +0 -133
  63. package/cli/security.js +0 -1064
  64. package/cli/ui.js +0 -386
  65. package/docs/API-KEYS-GUIDE.md +0 -233
  66. package/docs/AUTO-SETUP-SUMMARY.md +0 -331
  67. package/docs/BODY-CAPTURE-FIX.md +0 -261
  68. package/docs/COMPLETION-REPORT.md +0 -408
  69. package/docs/FINAL-SOLUTION.md +0 -335
  70. package/docs/FIREWALL-GUIDE.md +0 -426
  71. package/docs/IMPLEMENTATION-SUMMARY.md +0 -410
  72. package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +0 -323
  73. package/docs/NEXTJS-SETUP-COMPLETE.md +0 -795
  74. package/docs/NUXT-GUIDE.md +0 -166
  75. package/docs/SOLUTION-SUMMARY.md +0 -312
  76. package/firewall-cloud.js +0 -212
  77. package/firewall-iptables.js +0 -139
  78. package/firewall-only.js +0 -38
  79. package/firewall-tcp.js +0 -74
  80. package/firewall.js +0 -720
  81. package/free-trial-banner.js +0 -174
  82. package/nuxt-server-plugin.mjs +0 -423
  83. package/nuxt.d.ts +0 -60
  84. package/nuxt.mjs +0 -75
  85. package/resolve-ip.js +0 -77
package/nextjs.js CHANGED
@@ -5,39 +5,21 @@
5
5
  *
6
6
  * Usage in Next.js app:
7
7
  *
8
- * 1. Add serverExternalPackages to next.config.js (REQUIRED to avoid webpack bundling issues):
9
- *
10
- * const nextConfig = {
11
- * serverExternalPackages: [
12
- * "securenow",
13
- * "@opentelemetry/sdk-node",
14
- * "@opentelemetry/auto-instrumentations-node",
15
- * "@opentelemetry/instrumentation-http",
16
- * "@opentelemetry/exporter-trace-otlp-http",
17
- * "@opentelemetry/exporter-logs-otlp-http",
18
- * "@opentelemetry/sdk-logs",
19
- * "@opentelemetry/instrumentation",
20
- * "@opentelemetry/resources",
21
- * "@opentelemetry/semantic-conventions",
22
- * "@opentelemetry/api",
23
- * "@opentelemetry/api-logs",
24
- * "@vercel/otel",
25
- * ],
26
- * };
27
- *
28
- * 2. Create instrumentation.ts (or .js) in your project root:
8
+ * 1. Create instrumentation.ts (or .js) in your project root:
29
9
  *
30
10
  * import { registerSecureNow } from 'securenow/nextjs';
31
11
  * export function register() {
32
12
  * registerSecureNow();
33
13
  * }
34
14
  *
35
- * 3. Set environment variables:
15
+ * 2. Set environment variables:
36
16
  * SECURENOW_APPID=my-nextjs-app
37
- * SECURENOW_INSTANCE=http://your-otlp-backend:4318
17
+ * SECURENOW_INSTANCE=http://your-signoz-host:4318
18
+ *
19
+ * That's it! 🎉 No webpack warnings!
38
20
  */
39
21
 
40
- const { randomUUID } = require('crypto');
22
+ const { v4: uuidv4 } = require('uuid');
41
23
 
42
24
  const env = k => process.env[k] ?? process.env[k.toUpperCase()] ?? process.env[k.toLowerCase()];
43
25
 
@@ -68,9 +50,10 @@ function redactSensitiveData(obj, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
68
50
 
69
51
  const redacted = Array.isArray(obj) ? [...obj] : { ...obj };
70
52
 
71
- for (const key of Object.keys(redacted)) {
53
+ for (const key in redacted) {
72
54
  const lowerKey = key.toLowerCase();
73
55
 
56
+ // Check if field is sensitive
74
57
  if (sensitiveFields.some(field => lowerKey.includes(field.toLowerCase()))) {
75
58
  redacted[key] = '[REDACTED]';
76
59
  } else if (typeof redacted[key] === 'object' && redacted[key] !== null) {
@@ -82,10 +65,6 @@ function redactSensitiveData(obj, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
82
65
  return redacted;
83
66
  }
84
67
 
85
- function escapeRegex(str) {
86
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
87
- }
88
-
89
68
  /**
90
69
  * Redact sensitive data from GraphQL query strings
91
70
  */
@@ -97,10 +76,10 @@ function redactGraphQLQuery(query, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
97
76
  // Redact sensitive fields in GraphQL arguments and variables
98
77
  // Matches patterns like: password: "value" or password:"value" or password:'value'
99
78
  sensitiveFields.forEach(field => {
100
- const escaped = escapeRegex(field);
79
+ // Match field: "value" or field: 'value' or field:"value" (with optional spaces)
101
80
  const patterns = [
102
- new RegExp(`(${escaped}\\s*:\\s*["'])([^"']+)(["'])`, 'gi'),
103
- new RegExp(`(${escaped}\\s*:\\s*)([^\\s,})\n]+)`, 'gi'),
81
+ new RegExp(`(${field}\\s*:\\s*["'])([^"']+)(["'])`, 'gi'),
82
+ new RegExp(`(${field}\\s*:\\s*)([^\\s,})\n]+)`, 'gi'),
104
83
  ];
105
84
 
106
85
  patterns.forEach(pattern => {
@@ -117,6 +96,115 @@ function redactGraphQLQuery(query, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
117
96
  return redacted;
118
97
  }
119
98
 
99
+ /**
100
+ * Parse and capture request body safely
101
+ */
102
+ async function captureRequestBody(request, maxSize = 10240) {
103
+ try {
104
+ const contentType = request.headers['content-type'] || '';
105
+ let body = '';
106
+
107
+ // Collect body chunks
108
+ const chunks = [];
109
+ let size = 0;
110
+
111
+ return new Promise((resolve) => {
112
+ request.on('data', (chunk) => {
113
+ size += chunk.length;
114
+ if (size <= maxSize) {
115
+ chunks.push(chunk);
116
+ }
117
+ });
118
+
119
+ request.on('end', () => {
120
+ if (size > maxSize) {
121
+ resolve({
122
+ captured: false,
123
+ reason: `Body too large (${size} bytes > ${maxSize} bytes)`,
124
+ size
125
+ });
126
+ return;
127
+ }
128
+
129
+ body = Buffer.concat(chunks).toString('utf8');
130
+
131
+ // Parse based on content type
132
+ if (contentType.includes('application/json')) {
133
+ try {
134
+ const parsed = JSON.parse(body);
135
+ resolve({
136
+ captured: true,
137
+ type: 'json',
138
+ body: parsed,
139
+ size
140
+ });
141
+ } catch (e) {
142
+ resolve({
143
+ captured: true,
144
+ type: 'json',
145
+ body: body.substring(0, 1000),
146
+ parseError: true,
147
+ size
148
+ });
149
+ }
150
+ } else if (contentType.includes('application/graphql')) {
151
+ // GraphQL queries need redaction too!
152
+ resolve({
153
+ captured: true,
154
+ type: 'graphql',
155
+ body: body, // Will be redacted later
156
+ size
157
+ });
158
+ } else if (contentType.includes('multipart/form-data')) {
159
+ // Multipart is NOT captured (files can be huge)
160
+ resolve({
161
+ captured: false,
162
+ type: 'multipart',
163
+ reason: 'Multipart data not captured (file uploads)',
164
+ size
165
+ });
166
+ } else if (contentType.includes('application/x-www-form-urlencoded')) {
167
+ try {
168
+ const params = new URLSearchParams(body);
169
+ const parsed = Object.fromEntries(params);
170
+ resolve({
171
+ captured: true,
172
+ type: 'form',
173
+ body: parsed,
174
+ size
175
+ });
176
+ } catch (e) {
177
+ resolve({
178
+ captured: true,
179
+ type: 'form',
180
+ body: body.substring(0, 1000),
181
+ size
182
+ });
183
+ }
184
+ } else {
185
+ resolve({
186
+ captured: true,
187
+ type: 'text',
188
+ body: body.substring(0, 1000),
189
+ size
190
+ });
191
+ }
192
+ });
193
+
194
+ request.on('error', () => {
195
+ resolve({ captured: false, reason: 'Stream error' });
196
+ });
197
+
198
+ // Timeout after 100ms
199
+ setTimeout(() => {
200
+ resolve({ captured: false, reason: 'Timeout' });
201
+ }, 100);
202
+ });
203
+ } catch (error) {
204
+ return { captured: false, reason: error.message };
205
+ }
206
+ }
207
+
120
208
  /**
121
209
  * Register SecureNow OpenTelemetry for Next.js using @vercel/otel
122
210
  * @param {Object} options - Optional configuration
@@ -157,9 +245,9 @@ function registerSecureNow(options = {}) {
157
245
  // service.name
158
246
  let serviceName;
159
247
  if (baseName) {
160
- serviceName = noUuid ? baseName : `${baseName}-${randomUUID()}`;
248
+ serviceName = noUuid ? baseName : `${baseName}-${uuidv4()}`;
161
249
  } else {
162
- serviceName = `nextjs-app-${randomUUID()}`;
250
+ serviceName = `nextjs-app-${uuidv4()}`;
163
251
  console.warn('[securenow] ⚠️ No SECURENOW_APPID or OTEL_SERVICE_NAME provided. Using fallback: %s', serviceName);
164
252
  console.warn('[securenow] 💡 Set SECURENOW_APPID=your-app-name in .env.local for better tracking');
165
253
  }
@@ -173,11 +261,17 @@ function registerSecureNow(options = {}) {
173
261
  ).replace(/\/$/, '');
174
262
 
175
263
  const tracesUrl = env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT') || `${endpointBase}/v1/traces`;
176
- const logsUrl = env('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') || `${endpointBase}/v1/logs`;
264
+ const logsUrl = env('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') || `${endpointBase}/v1/logs`;
177
265
 
178
- if (!process.env.OTEL_SERVICE_NAME) process.env.OTEL_SERVICE_NAME = serviceName;
179
- if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) process.env.OTEL_EXPORTER_OTLP_ENDPOINT = endpointBase;
180
- if (!process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = tracesUrl;
266
+ // Set environment variables for @vercel/otel to pick up
267
+ process.env.OTEL_SERVICE_NAME = serviceName;
268
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = endpointBase;
269
+ process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = tracesUrl;
270
+
271
+ // -------- Logging Configuration --------
272
+ // Opt-in: SECURENOW_LOGGING_ENABLED=1 (or "true").
273
+ const loggingEnabled = String(env('SECURENOW_LOGGING_ENABLED')) === '1' ||
274
+ String(env('SECURENOW_LOGGING_ENABLED')).toLowerCase() === 'true';
181
275
 
182
276
  console.log('[securenow] 🚀 Next.js App → service.name=%s', serviceName);
183
277
 
@@ -185,7 +279,7 @@ function registerSecureNow(options = {}) {
185
279
  const captureBody = String(env('SECURENOW_CAPTURE_BODY')) === '1' ||
186
280
  String(env('SECURENOW_CAPTURE_BODY')).toLowerCase() === 'true' ||
187
281
  options.captureBody === true;
188
- const maxBodySize = Math.max(1024, parseInt(env('SECURENOW_MAX_BODY_SIZE'), 10) || 10240);
282
+ const maxBodySize = parseInt(env('SECURENOW_MAX_BODY_SIZE') || '10240'); // 10KB default
189
283
  const customSensitiveFields = (env('SECURENOW_SENSITIVE_FIELDS') || '').split(',').map(s => s.trim()).filter(Boolean);
190
284
  const allSensitiveFields = [...DEFAULT_SENSITIVE_FIELDS, ...customSensitiveFields];
191
285
 
@@ -219,19 +313,14 @@ function registerSecureNow(options = {}) {
219
313
  const clientIp = headers['x-client-ip'];
220
314
  const socketIp = request.socket?.remoteAddress;
221
315
 
222
- const PRIVATE_RE = /^(127\.|::1$|::ffff:127\.|10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.|f[cd][0-9a-f]{2}:)/;
223
- const isProxied = socketIp && PRIVATE_RE.test(socketIp);
224
- let primaryIp = socketIp || 'unknown';
225
- if (isProxied) {
226
- if (forwardedFor) {
227
- const chain = forwardedFor.split(',').map(s => s.trim()).filter(Boolean);
228
- for (let i = chain.length - 1; i >= 0; i--) {
229
- if (!PRIVATE_RE.test(chain[i])) { primaryIp = chain[i]; break; }
230
- }
231
- } else {
232
- primaryIp = realIp || cfConnectingIp || clientIp || primaryIp;
233
- }
234
- }
316
+ // Primary IP (first in chain is the real client)
317
+ const primaryIp =
318
+ (forwardedFor ? forwardedFor.split(',')[0]?.trim() : null) ||
319
+ realIp ||
320
+ cfConnectingIp ||
321
+ clientIp ||
322
+ socketIp ||
323
+ 'unknown';
235
324
 
236
325
  // ======== PROTOCOL & CONNECTION ========
237
326
  const scheme = headers['x-forwarded-proto'] ||
@@ -421,126 +510,70 @@ function registerSecureNow(options = {}) {
421
510
 
422
511
  sdk.start();
423
512
  console.log('[securenow] 🎯 Vanilla SDK initialized for self-hosted environment');
513
+ }
424
514
 
425
- // -------- Logging (self-hosted only) --------
426
- const loggingEnabled = String(env('SECURENOW_LOGGING_ENABLED')) === '1' || String(env('SECURENOW_LOGGING_ENABLED')).toLowerCase() === 'true';
427
- if (loggingEnabled) {
428
- try {
429
- const { OTLPLogExporter } = require('@opentelemetry/exporter-logs-otlp-http');
430
- const { LoggerProvider, BatchLogRecordProcessor } = require('@opentelemetry/sdk-logs');
515
+ // -------- Logging pipeline (both Vercel and self-hosted) --------
516
+ // Neither @vercel/otel nor NodeSDK 0.47.x wires OTLP logs for us, so we
517
+ // create the LoggerProvider ourselves, register a BatchLogRecordProcessor
518
+ // (addLogRecordProcessor — the `processors` constructor option was only
519
+ // added in sdk-logs 0.52 and is silently ignored in 0.47), publish it as
520
+ // the global logger provider, and auto-patch console.* to emit records.
521
+ if (loggingEnabled) {
522
+ const { LoggerProvider, BatchLogRecordProcessor } = require('@opentelemetry/sdk-logs');
523
+ const { OTLPLogExporter } = require('@opentelemetry/exporter-logs-otlp-http');
524
+ const { logs } = require('@opentelemetry/api-logs');
525
+ const { Resource } = require('@opentelemetry/resources');
526
+ const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
431
527
 
432
- const logExporter = new OTLPLogExporter({
433
- url: logsUrl,
434
- headers: parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS')),
435
- });
528
+ const logResource = new Resource({
529
+ [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
530
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || env('VERCEL_ENV') || 'production',
531
+ [SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version || process.env.VERCEL_GIT_COMMIT_SHA || undefined,
532
+ });
436
533
 
437
- const loggerProvider = new LoggerProvider({
438
- resource: new Resource({
439
- [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
440
- [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || 'production',
441
- }),
534
+ const logExporter = new OTLPLogExporter({
535
+ url: logsUrl,
536
+ headers: parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS')),
537
+ });
538
+ const loggerProvider = new LoggerProvider({ resource: logResource });
539
+ loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
540
+ logs.setGlobalLoggerProvider(loggerProvider);
541
+
542
+ const _logger = loggerProvider.getLogger('console', '1.0.0');
543
+ const _orig = { log: console.log, info: console.info, warn: console.warn, error: console.error, debug: console.debug };
544
+ const SEV = { DEBUG: 5, INFO: 9, WARN: 13, ERROR: 17 };
545
+ const _emit = (sn, st, args) => {
546
+ try {
547
+ _logger.emit({
548
+ severityNumber: sn,
549
+ severityText: st,
550
+ body: args.map(a => (typeof a === 'object' && a !== null)
551
+ ? (() => { try { return JSON.stringify(a); } catch { return String(a); } })()
552
+ : String(a)).join(' '),
553
+ attributes: { 'log.source': 'console', 'log.method': st.toLowerCase() },
442
554
  });
443
- loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
444
-
445
- // Patch console to forward logs as OTLP log records
446
- const logger = loggerProvider.getLogger('console', '1.0.0');
447
- const SeverityNumber = { INFO: 9, WARN: 13, ERROR: 17 };
448
- const origLog = console.log;
449
- const origWarn = console.warn;
450
- const origError = console.error;
451
-
452
- const { context: otelContext, trace: otelTrace } = require('@opentelemetry/api');
453
- function _emitLog(sn, st, args) {
454
- try {
455
- const activeCtx = otelContext.active();
456
- const spanCtx = otelTrace.getSpanContext(activeCtx);
457
- logger.emit({
458
- severityNumber: sn,
459
- severityText: st,
460
- body: args.map(String).join(' '),
461
- ...(spanCtx && { context: activeCtx }),
462
- });
463
- } catch (_) {}
464
- }
465
- console.log = (...args) => {
466
- origLog.apply(console, args);
467
- _emitLog(SeverityNumber.INFO, 'INFO', args);
468
- };
469
- console.warn = (...args) => {
470
- origWarn.apply(console, args);
471
- _emitLog(SeverityNumber.WARN, 'WARN', args);
472
- };
473
- console.error = (...args) => {
474
- origError.apply(console, args);
475
- _emitLog(SeverityNumber.ERROR, 'ERROR', args);
476
- };
477
-
478
- console.log('[securenow] 📋 Logging: ENABLED → %s', logsUrl);
479
-
480
- // Auto-log every incoming HTTP request/response
481
- try {
482
- const http = require('http');
483
- const originalEmit = http.Server.prototype.emit;
484
- http.Server.prototype.emit = function (event, req, res) {
485
- if (event === 'request' && req && res) {
486
- const start = Date.now();
487
- const method = req.method;
488
- const url = req.url;
489
- res.on('finish', () => {
490
- const reqCtx = otelContext.active();
491
- const reqSpanCtx = otelTrace.getSpanContext(reqCtx);
492
- const duration = Date.now() - start;
493
- const status = res.statusCode;
494
- const ip = req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.socket?.remoteAddress || '-';
495
- const ua = req.headers['user-agent'] || '-';
496
- const body = `${method} ${url} ${status} ${duration}ms ip=${ip} ua=${ua}`;
497
- const severity = status >= 500 ? SeverityNumber.ERROR : status >= 400 ? SeverityNumber.WARN : SeverityNumber.INFO;
498
- const severityText = status >= 500 ? 'ERROR' : status >= 400 ? 'WARN' : 'INFO';
499
- origLog.call(console, '[securenow] %s %s %d %dms', method, url, status, duration);
500
- try {
501
- logger.emit({
502
- severityNumber: severity,
503
- severityText,
504
- body,
505
- attributes: {
506
- 'http.method': method,
507
- 'http.url': url,
508
- 'http.status_code': status,
509
- 'http.duration_ms': duration,
510
- 'http.client_ip': String(ip).split(',')[0].trim(),
511
- 'http.user_agent': ua,
512
- },
513
- ...(reqSpanCtx && { context: reqCtx }),
514
- });
515
- } catch (_) {}
516
- });
517
- }
518
- return originalEmit.apply(this, arguments);
519
- };
520
- console.log('[securenow] 📋 HTTP request logging: ENABLED');
521
- } catch (_) {}
522
-
523
- // Graceful shutdown for logs
524
- process.on('SIGTERM', async () => { try { await loggerProvider.shutdown(); } catch (_) {} try { require('./firewall').shutdown(); } catch (_) {} });
525
- process.on('SIGINT', async () => { try { await loggerProvider.shutdown(); } catch (_) {} try { require('./firewall').shutdown(); } catch (_) {} });
526
- } catch (e) {
527
- console.warn('[securenow] ⚠️ Logging setup failed (missing @opentelemetry/exporter-logs-otlp-http or @opentelemetry/sdk-logs):', e.message);
528
- }
529
- } else {
530
- console.log('[securenow] 📋 Logging: DISABLED (set SECURENOW_LOGGING_ENABLED=1 to enable)');
531
- }
555
+ } catch (_) {}
556
+ };
557
+ console.log = function (...a) { _emit(SEV.INFO, 'INFO', a); _orig.log.apply(console, a); };
558
+ console.info = function (...a) { _emit(SEV.INFO, 'INFO', a); _orig.info.apply(console, a); };
559
+ console.warn = function (...a) { _emit(SEV.WARN, 'WARN', a); _orig.warn.apply(console, a); };
560
+ console.error = function (...a) { _emit(SEV.ERROR, 'ERROR', a); _orig.error.apply(console, a); };
561
+ console.debug = function (...a) { _emit(SEV.DEBUG, 'DEBUG', a); _orig.debug.apply(console, a); };
562
+
563
+ const _shutdownLogs = async () => {
564
+ try { await Promise.resolve(loggerProvider.forceFlush?.()); } catch (_) {}
565
+ try { await Promise.resolve(loggerProvider.shutdown?.()); } catch (_) {}
566
+ };
567
+ process.on('SIGINT', _shutdownLogs);
568
+ process.on('SIGTERM', _shutdownLogs);
569
+ process.on('beforeExit', _shutdownLogs);
570
+
571
+ console.log('[securenow] 📋 Logging: ENABLED → %s', logsUrl);
572
+ } else {
573
+ console.log('[securenow] 📋 Logging: DISABLED (set SECURENOW_LOGGING_ENABLED=1 to enable)');
532
574
  }
533
575
 
534
576
  isRegistered = true;
535
-
536
- // Free trial banner (optional — may not be bundled in standalone builds)
537
- try {
538
- const { isFreeTrial, patchHttpForBanner } = require('./free-trial-banner');
539
- if (isFreeTrial(endpointBase) && String(env('SECURENOW_HIDE_BANNER')) !== '1') {
540
- patchHttpForBanner();
541
- }
542
- } catch (_) {}
543
-
544
577
  console.log('[securenow] ✅ OpenTelemetry started for Next.js → %s', tracesUrl);
545
578
  console.log('[securenow] 📊 Auto-capturing comprehensive request metadata:');
546
579
  console.log('[securenow] • IP addresses (x-forwarded-for, x-real-ip, socket)');
@@ -572,27 +605,6 @@ function registerSecureNow(options = {}) {
572
605
  console.error('[securenow] Make sure OpenTelemetry dependencies are installed');
573
606
  }
574
607
  }
575
-
576
- // Firewall — runs independently from OTel so it works even if tracing fails
577
- const firewallApiKey = env('SECURENOW_API_KEY');
578
- if (firewallApiKey && env('SECURENOW_FIREWALL_ENABLED') !== '0') {
579
- try {
580
- require('./firewall').init({
581
- apiKey: firewallApiKey,
582
- apiUrl: env('SECURENOW_API_URL') || 'https://api.securenow.ai',
583
- versionCheckInterval: parseInt(env('SECURENOW_FIREWALL_VERSION_INTERVAL'), 10) || 10,
584
- syncInterval: parseInt(env('SECURENOW_FIREWALL_SYNC_INTERVAL'), 10) || 300,
585
- failMode: env('SECURENOW_FIREWALL_FAIL_MODE') || 'open',
586
- statusCode: parseInt(env('SECURENOW_FIREWALL_STATUS_CODE'), 10) || 403,
587
- log: env('SECURENOW_FIREWALL_LOG') !== '0',
588
- tcp: env('SECURENOW_FIREWALL_TCP') === '1',
589
- iptables: env('SECURENOW_FIREWALL_IPTABLES') === '1',
590
- cloud: env('SECURENOW_FIREWALL_CLOUD') || null,
591
- });
592
- } catch (e) {
593
- console.warn('[securenow] Firewall init failed:', e.message);
594
- }
595
- }
596
608
  }
597
609
 
598
610
  module.exports = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "securenow",
3
- "version": "5.18.0",
4
- "description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
3
+ "version": "6.0.1",
4
+ "description": "OpenTelemetry instrumentation for Node.js and Next.js - Send traces and logs to SigNoz or any OTLP backend",
5
5
  "type": "commonjs",
6
6
  "main": "register.js",
7
7
  "types": "register.d.ts",
@@ -11,6 +11,16 @@
11
11
  "scripts": {
12
12
  "postinstall": "node postinstall.js || exit 0"
13
13
  },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/securenow-ai/securenow-npm.git"
17
+ },
18
+ "homepage": "https://securenow.ai",
19
+ "bugs": {
20
+ "url": "https://github.com/securenow-ai/securenow-npm/issues",
21
+ "email": "support@securenow.ai"
22
+ },
23
+ "author": "SecureNow <support@securenow.ai> (https://securenow.ai)",
14
24
  "keywords": [
15
25
  "opentelemetry",
16
26
  "otel",
@@ -20,24 +30,16 @@
20
30
  "observability",
21
31
  "apm",
22
32
  "monitoring",
23
- "cli",
24
33
  "nextjs",
25
34
  "next.js",
35
+ "signoz",
26
36
  "instrumentation",
27
37
  "telemetry",
28
38
  "distributed-tracing",
29
39
  "node",
30
40
  "express",
31
41
  "fastify",
32
- "nestjs",
33
- "nuxt",
34
- "nuxt3",
35
- "nitro",
36
- "vue",
37
- "firewall",
38
- "ip-blocking",
39
- "waf",
40
- "security"
42
+ "nestjs"
41
43
  ],
42
44
  "exports": {
43
45
  ".": {
@@ -72,24 +74,6 @@
72
74
  "default": "./nextjs-wrapper.js"
73
75
  },
74
76
  "./nextjs-webpack-config": "./nextjs-webpack-config.js",
75
- "./package.json": "./package.json",
76
- "./nuxt": {
77
- "types": "./nuxt.d.ts",
78
- "import": "./nuxt.mjs",
79
- "default": "./nuxt.mjs"
80
- },
81
- "./firewall": {
82
- "default": "./firewall.js"
83
- },
84
- "./firewall-only": {
85
- "default": "./firewall-only.js"
86
- },
87
- "./cidr": {
88
- "default": "./cidr.js"
89
- },
90
- "./resolve-ip": {
91
- "default": "./resolve-ip.js"
92
- },
93
77
  "./register-vite": "./register-vite.js",
94
78
  "./web-vite": {
95
79
  "import": "./web-vite.mjs",
@@ -111,45 +95,52 @@
111
95
  "nextjs-wrapper.js",
112
96
  "nextjs-wrapper.d.ts",
113
97
  "nextjs-webpack-config.js",
114
- "nuxt.mjs",
115
- "nuxt.d.ts",
116
- "nuxt-server-plugin.mjs",
117
98
  "cli.js",
118
- "cli/",
119
- "free-trial-banner.js",
120
- "resolve-ip.js",
121
- "cidr.js",
122
- "firewall.js",
123
- "firewall-only.js",
124
- "firewall-tcp.js",
125
- "firewall-iptables.js",
126
- "firewall-cloud.js",
127
99
  "postinstall.js",
128
100
  "register-vite.js",
129
101
  "web-vite.mjs",
130
102
  "examples/",
131
- "docs/",
103
+ "docs/ALL-FRAMEWORKS-QUICKSTART.md",
104
+ "docs/ARCHITECTURE.md",
105
+ "docs/AUTO-BODY-CAPTURE.md",
106
+ "docs/CHANGELOG-NEXTJS.md",
107
+ "docs/NEXTJS-WEBPACK-WARNINGS.md",
108
+ "docs/AUTO-SETUP.md",
109
+ "docs/AUTOMATIC-IP-CAPTURE.md",
110
+ "docs/BODY-CAPTURE-QUICKSTART.md",
111
+ "docs/CUSTOMER-GUIDE.md",
112
+ "docs/EASIEST-SETUP.md",
113
+ "docs/ENVIRONMENT-VARIABLES.md",
114
+ "docs/EXPRESS-BODY-CAPTURE.md",
115
+ "docs/EXPRESS-SETUP-GUIDE.md",
116
+ "docs/INDEX.md",
117
+ "docs/LOGGING-GUIDE.md",
118
+ "docs/LOGGING-QUICKSTART.md",
119
+ "docs/NEXTJS-BODY-CAPTURE.md",
120
+ "docs/NEXTJS-GUIDE.md",
121
+ "docs/NEXTJS-QUICKSTART.md",
122
+ "docs/NEXTJS-WRAPPER-APPROACH.md",
123
+ "docs/QUICKSTART-BODY-CAPTURE.md",
124
+ "docs/REDACTION-EXAMPLES.md",
125
+ "docs/REQUEST-BODY-CAPTURE.md",
126
+ "docs/VERCEL-OTEL-MIGRATION.md",
132
127
  "README.md",
133
- "NPM_README.md",
134
- "CONSUMING-APPS-GUIDE.md",
135
- "SKILL-CLI.md",
136
- "SKILL-API.md"
128
+ "LICENSE"
137
129
  ],
138
130
  "dependencies": {
139
131
  "@opentelemetry/api": "1.7.0",
140
- "@opentelemetry/api-logs": "0.47.0",
132
+ "@opentelemetry/api-logs": "^0.47.0",
141
133
  "@opentelemetry/auto-instrumentations-node": "0.47.0",
142
- "@opentelemetry/exporter-logs-otlp-http": "0.47.0",
134
+ "@opentelemetry/exporter-logs-otlp-http": "^0.47.0",
143
135
  "@opentelemetry/exporter-trace-otlp-http": "0.47.0",
144
136
  "@opentelemetry/instrumentation": "0.47.0",
145
137
  "@opentelemetry/instrumentation-document-load": "0.47.0",
146
138
  "@opentelemetry/instrumentation-fetch": "0.47.0",
147
- "@opentelemetry/instrumentation-http": "0.47.0",
148
- "@opentelemetry/instrumentation-mongodb": "0.46.0",
139
+ "@opentelemetry/instrumentation-http": "^0.208.0",
149
140
  "@opentelemetry/instrumentation-user-interaction": "0.47.0",
150
141
  "@opentelemetry/instrumentation-xml-http-request": "0.47.0",
151
142
  "@opentelemetry/resources": "1.20.0",
152
- "@opentelemetry/sdk-logs": "0.47.0",
143
+ "@opentelemetry/sdk-logs": "^0.47.0",
153
144
  "@opentelemetry/sdk-node": "0.47.0",
154
145
  "@opentelemetry/sdk-trace-web": "1.20.0",
155
146
  "@opentelemetry/semantic-conventions": "1.20.0",
@@ -158,28 +149,15 @@
158
149
  "uuid": "^9.0.0"
159
150
  },
160
151
  "peerDependencies": {
161
- "next": ">=13.0.0",
162
- "nuxt": ">=3.0.0",
163
- "@aws-sdk/client-wafv2": ">=3.0.0",
164
- "@google-cloud/compute": ">=4.0.0"
152
+ "next": ">=13.0.0"
165
153
  },
166
154
  "peerDependenciesMeta": {
167
155
  "next": {
168
156
  "optional": true
169
- },
170
- "nuxt": {
171
- "optional": true
172
- },
173
- "@aws-sdk/client-wafv2": {
174
- "optional": true
175
- },
176
- "@google-cloud/compute": {
177
- "optional": true
178
157
  }
179
158
  },
180
159
  "overrides": {
181
- "@opentelemetry/api": "1.7.0",
182
- "@opentelemetry/api-logs": "0.47.0"
160
+ "@opentelemetry/api": "1.7.0"
183
161
  },
184
162
  "sideEffects": true,
185
163
  "license": "ISC"