securenow 7.5.1 → 7.6.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 (50) hide show
  1. package/CONSUMING-APPS-GUIDE.md +2 -0
  2. package/NPM_README.md +201 -237
  3. package/README.md +73 -26
  4. package/SKILL-API.md +209 -205
  5. package/SKILL-CLI.md +71 -64
  6. package/app-config.js +479 -83
  7. package/cli/apiKey.js +1 -1
  8. package/cli/apps.js +1 -1
  9. package/cli/config.js +31 -12
  10. package/cli/credentials.js +88 -0
  11. package/cli/diagnostics.js +68 -104
  12. package/cli/firewall.js +29 -14
  13. package/cli/init.js +208 -206
  14. package/cli/monitor.js +107 -43
  15. package/cli/security.js +24 -12
  16. package/cli/utils.js +2 -1
  17. package/cli.js +71 -39
  18. package/console-instrumentation.js +1 -1
  19. package/docs/ENVIRONMENT-VARIABLES.md +137 -863
  20. package/docs/ENVIRONMENTS.md +60 -0
  21. package/docs/EXPRESS-SETUP-GUIDE.md +3 -0
  22. package/docs/FIREWALL-GUIDE.md +3 -0
  23. package/docs/INDEX.md +6 -8
  24. package/docs/LOGGING-GUIDE.md +3 -0
  25. package/docs/MCP-GUIDE.md +8 -0
  26. package/docs/NEXTJS-GUIDE.md +3 -0
  27. package/docs/NEXTJS-QUICKSTART.md +24 -16
  28. package/docs/NUXT-GUIDE.md +3 -0
  29. package/docs/QUICKSTART-BODY-CAPTURE.md +3 -0
  30. package/docs/REQUEST-BODY-CAPTURE.md +3 -0
  31. package/firewall-cloud.js +10 -10
  32. package/firewall-only.js +25 -23
  33. package/firewall.js +47 -29
  34. package/free-trial-banner.js +1 -1
  35. package/mcp/catalog.js +104 -17
  36. package/nextjs-auto-capture.d.ts +7 -4
  37. package/nextjs-auto-capture.js +7 -7
  38. package/nextjs-middleware.js +4 -3
  39. package/nextjs-wrapper.js +6 -6
  40. package/nextjs.d.ts +36 -25
  41. package/nextjs.js +47 -55
  42. package/nuxt-server-plugin.mjs +35 -51
  43. package/nuxt.d.ts +29 -23
  44. package/package.json +1 -1
  45. package/postinstall.js +27 -61
  46. package/register.d.ts +19 -33
  47. package/register.js +8 -8
  48. package/resolve-ip.js +4 -5
  49. package/tracing.d.ts +21 -19
  50. package/tracing.js +34 -42
package/nextjs.js CHANGED
@@ -32,24 +32,15 @@
32
32
  * registerSecureNow();
33
33
  * }
34
34
  *
35
- * 3. Set environment variables:
36
- * SECURENOW_APPID=my-nextjs-app
37
- * SECURENOW_INSTANCE=http://your-otlp-backend:4318
35
+ * 3. Run `npx securenow login` and `npx securenow init`.
36
+ * The SDK reads app identity, collector, firewall, capture, and
37
+ * deploymentEnvironment from .securenow/credentials.json.
38
38
  */
39
39
 
40
40
  const { randomUUID } = require('crypto');
41
+ const appConfig = require('./app-config');
41
42
 
42
- const env = k => process.env[k] ?? process.env[k.toUpperCase()] ?? process.env[k.toLowerCase()];
43
-
44
- const parseHeaders = str => {
45
- const out = {}; if (!str) return out;
46
- for (const raw of String(str).split(',')) {
47
- const s = raw.trim(); if (!s) continue;
48
- const i = s.indexOf('='); if (i === -1) continue;
49
- out[s.slice(0, i).trim().toLowerCase()] = s.slice(i + 1).trim();
50
- }
51
- return out;
52
- };
43
+ const env = appConfig.env;
53
44
 
54
45
  let isRegistered = false;
55
46
 
@@ -120,8 +111,9 @@ function redactGraphQLQuery(query, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
120
111
  /**
121
112
  * Register SecureNow OpenTelemetry for Next.js using @vercel/otel
122
113
  * @param {Object} options - Optional configuration
123
- * @param {string} options.serviceName - Service name (defaults to SECURENOW_APPID or OTEL_SERVICE_NAME)
124
- * @param {string} options.endpoint - Traces endpoint (defaults to SECURENOW_INSTANCE)
114
+ * @param {string} options.serviceName - Service name (defaults to .securenow/credentials.json app.key/app.name)
115
+ * @param {string} options.endpoint - Traces endpoint (defaults to .securenow/credentials.json app.instance)
116
+ * @param {string} options.environment - deployment.environment override (defaults to config.runtime.deploymentEnvironment)
125
117
  * @param {boolean} options.noUuid - Don't append UUID to service name
126
118
  */
127
119
  function registerSecureNow(options = {}) {
@@ -144,8 +136,7 @@ function registerSecureNow(options = {}) {
144
136
  console.log('[securenow] Next.js integration loading (pid=%d)', process.pid);
145
137
 
146
138
  // -------- Configuration --------
147
- // Resolution order: explicit options env → .securenow/credentials.json package.json#name
148
- const appConfig = require('./app-config');
139
+ // Resolution order: explicit options -> .securenow/credentials.json -> legacy env fallback -> package.json#name
149
140
  const resolvedApp = appConfig.resolveAll();
150
141
 
151
142
  const rawBase = (options.serviceName || resolvedApp.appId || '').trim().replace(/^['"]|['"]$/g, '');
@@ -154,6 +145,9 @@ function registerSecureNow(options = {}) {
154
145
  // and the dashboard does exact match). opts.noUuid or SECURENOW_NO_UUID
155
146
  // override.
156
147
  const noUuid = appConfig.resolveNoUuid({ noUuid: options.noUuid });
148
+ const deploymentEnvironment = appConfig.normalizeDeploymentEnvironment(
149
+ options.environment || resolvedApp.deploymentEnvironment || env('VERCEL_ENV')
150
+ );
157
151
 
158
152
  // service.name
159
153
  let serviceName;
@@ -162,29 +156,25 @@ function registerSecureNow(options = {}) {
162
156
  } else {
163
157
  serviceName = `nextjs-app-${randomUUID()}`;
164
158
  console.warn('[securenow] ⚠️ No app identity resolved. Using fallback: %s', serviceName);
165
- console.warn('[securenow] 💡 Run `npx securenow login` or set SECURENOW_APPID in .env.local');
159
+ console.warn('[securenow] Run `npx securenow login` and `npx securenow init` to write .securenow/credentials.json');
166
160
  }
167
161
 
168
162
  // -------- Endpoint Configuration --------
169
- const endpointBase = (options.endpoint || resolvedApp.instance).replace(/\/$/, '');
170
-
171
- // If credentials file provided an app key, surface it via x-api-key for collector routing.
172
- if (resolvedApp.appKey && !env('OTEL_EXPORTER_OTLP_HEADERS') && !env('SECURENOW_API_KEY')) {
173
- process.env.SECURENOW_API_KEY = resolvedApp.appKey;
174
- process.env.OTEL_EXPORTER_OTLP_HEADERS = `x-api-key=${resolvedApp.appKey}`;
175
- }
176
-
177
- const tracesUrl = env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT') || `${endpointBase}/v1/traces`;
178
- const logsUrl = env('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') || `${endpointBase}/v1/logs`;
163
+ const resolvedEndpoints = appConfig.resolveEndpoints({ endpoint: options.endpoint || resolvedApp.instance });
164
+ const endpointBase = resolvedEndpoints.endpointBase;
165
+ const tracesUrl = resolvedEndpoints.tracesUrl;
166
+ const logsUrl = resolvedEndpoints.logsUrl;
167
+ const headers = resolvedEndpoints.headers;
179
168
 
180
169
  if (!process.env.OTEL_SERVICE_NAME) process.env.OTEL_SERVICE_NAME = serviceName;
181
170
  if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) process.env.OTEL_EXPORTER_OTLP_ENDPOINT = endpointBase;
182
171
  if (!process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = tracesUrl;
183
172
 
184
- console.log('[securenow] 🚀 Next.js App service.name=%s', serviceName);
173
+ console.log('[securenow] Next.js App -> service.name=%s', serviceName);
174
+ console.log('[securenow] Environment: %s', deploymentEnvironment);
185
175
 
186
176
  // -------- Body Capture Configuration --------
187
- // Opt-out default: set SECURENOW_CAPTURE_BODY=0 (or options.captureBody=false) to disable.
177
+ // Opt-out default: set config.capture.body=false (or options.captureBody=false) to disable.
188
178
  const captureBody = options.captureBody ?? !/^(0|false)$/i.test(String(env('SECURENOW_CAPTURE_BODY') ?? ''));
189
179
  const maxBodySize = Math.max(1024, parseInt(env('SECURENOW_MAX_BODY_SIZE'), 10) || 10240);
190
180
  const customSensitiveFields = (env('SECURENOW_SENSITIVE_FIELDS') || '').split(',').map(s => s.trim()).filter(Boolean);
@@ -413,7 +403,7 @@ function registerSecureNow(options = {}) {
413
403
  registerOTel({
414
404
  serviceName: serviceName,
415
405
  attributes: {
416
- 'deployment.environment': env('NODE_ENV') || env('VERCEL_ENV') || 'development',
406
+ 'deployment.environment': deploymentEnvironment,
417
407
  'service.version': process.env.npm_package_version || process.env.VERCEL_GIT_COMMIT_SHA || undefined,
418
408
  'vercel.region': process.env.VERCEL_REGION || undefined,
419
409
  },
@@ -444,7 +434,7 @@ function registerSecureNow(options = {}) {
444
434
 
445
435
  const traceExporter = new OTLPTraceExporter({
446
436
  url: tracesUrl,
447
- headers: parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS'))
437
+ headers
448
438
  });
449
439
 
450
440
  const sdk = new NodeSDK({
@@ -453,7 +443,7 @@ function registerSecureNow(options = {}) {
453
443
  instrumentations: [httpInstrumentation],
454
444
  resource: new Resource({
455
445
  [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
456
- [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || env('VERCEL_ENV') || 'production',
446
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: deploymentEnvironment,
457
447
  [SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version || undefined,
458
448
  }),
459
449
  });
@@ -462,7 +452,7 @@ function registerSecureNow(options = {}) {
462
452
  console.log('[securenow] 🎯 Vanilla SDK initialized for self-hosted environment');
463
453
 
464
454
  // -------- Logging (self-hosted only) --------
465
- // Opt-out default: set SECURENOW_LOGGING_ENABLED=0 to disable.
455
+ // Opt-out default: set config.logging.enabled=false to disable.
466
456
  const loggingEnabled = !/^(0|false)$/i.test(String(env('SECURENOW_LOGGING_ENABLED') ?? ''));
467
457
  if (loggingEnabled) {
468
458
  try {
@@ -471,13 +461,13 @@ function registerSecureNow(options = {}) {
471
461
 
472
462
  const logExporter = new OTLPLogExporter({
473
463
  url: logsUrl,
474
- headers: parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS')),
464
+ headers,
475
465
  });
476
466
 
477
467
  const loggerProvider = new LoggerProvider({
478
468
  resource: new Resource({
479
469
  [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
480
- [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || 'production',
470
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: deploymentEnvironment,
481
471
  }),
482
472
  });
483
473
  loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
@@ -614,25 +604,28 @@ function registerSecureNow(options = {}) {
614
604
  }
615
605
 
616
606
  // Firewall — runs independently from OTel so it works even if tracing fails.
617
- // Key comes from env OR .securenow/credentials.json (set via
618
- // `npx securenow api-key set snk_live_...`), so you don't need a .env entry.
619
- const appConfig = require('./app-config');
620
- const firewallApiKey = appConfig.resolveApiKey();
621
- const firewallAppKey = appConfig.resolveAppKey();
622
- if (firewallApiKey && env('SECURENOW_FIREWALL_ENABLED') !== '0') {
607
+ // Key and environment come from .securenow/credentials.json (written by
608
+ // login/init or credentials runtime), so no .env entry is needed.
609
+ const firewallOptions = appConfig.resolveFirewallOptions();
610
+ if (firewallOptions.apiKey && firewallOptions.enabled) {
623
611
  try {
624
612
  require('./firewall').init({
625
- apiKey: firewallApiKey,
626
- appKey: firewallAppKey || null,
627
- apiUrl: env('SECURENOW_API_URL') || 'https://api.securenow.ai',
628
- versionCheckInterval: parseInt(env('SECURENOW_FIREWALL_VERSION_INTERVAL'), 10) || 10,
629
- syncInterval: parseInt(env('SECURENOW_FIREWALL_SYNC_INTERVAL'), 10) || 300,
630
- failMode: env('SECURENOW_FIREWALL_FAIL_MODE') || 'open',
631
- statusCode: parseInt(env('SECURENOW_FIREWALL_STATUS_CODE'), 10) || 403,
632
- log: env('SECURENOW_FIREWALL_LOG') !== '0',
633
- tcp: env('SECURENOW_FIREWALL_TCP') === '1',
634
- iptables: env('SECURENOW_FIREWALL_IPTABLES') === '1',
635
- cloud: env('SECURENOW_FIREWALL_CLOUD') || null,
613
+ apiKey: firewallOptions.apiKey,
614
+ appKey: firewallOptions.appKey,
615
+ environment: deploymentEnvironment || firewallOptions.environment,
616
+ apiUrl: firewallOptions.apiUrl,
617
+ versionCheckInterval: firewallOptions.versionCheckInterval,
618
+ syncInterval: firewallOptions.syncInterval,
619
+ failMode: firewallOptions.failMode,
620
+ statusCode: firewallOptions.statusCode,
621
+ log: firewallOptions.log,
622
+ tcp: firewallOptions.tcp,
623
+ iptables: firewallOptions.iptables,
624
+ cloud: firewallOptions.cloud,
625
+ cloudDryRun: firewallOptions.cloudDryRun,
626
+ cloudflare: firewallOptions.cloudflare,
627
+ aws: firewallOptions.aws,
628
+ gcp: firewallOptions.gcp,
636
629
  });
637
630
  } catch (e) {
638
631
  console.warn('[securenow] Firewall init failed:', e.message);
@@ -643,4 +636,3 @@ function registerSecureNow(options = {}) {
643
636
  module.exports = {
644
637
  registerSecureNow,
645
638
  };
646
-
@@ -25,21 +25,7 @@ const appConfig = nodeRequire('./app-config');
25
25
 
26
26
  // ── Helpers ──
27
27
 
28
- const env = (k) =>
29
- process.env[k] ?? process.env[k.toUpperCase()] ?? process.env[k.toLowerCase()];
30
-
31
- const parseHeaders = (str) => {
32
- const out = {};
33
- if (!str) return out;
34
- for (const raw of String(str).split(',')) {
35
- const s = raw.trim();
36
- if (!s) continue;
37
- const i = s.indexOf('=');
38
- if (i === -1) continue;
39
- out[s.slice(0, i).trim().toLowerCase()] = s.slice(i + 1).trim();
40
- }
41
- return out;
42
- };
28
+ const env = appConfig.env;
43
29
 
44
30
  const DEFAULT_SENSITIVE_FIELDS = [
45
31
  'password', 'passwd', 'pwd', 'secret', 'token', 'api_key', 'apikey',
@@ -74,10 +60,10 @@ function getRuntimeOptions() {
74
60
 
75
61
  // ── Plugin ──
76
62
 
77
- export default defineNitroPlugin((nitroApp) => {
63
+ export default defineNitroPlugin(async (nitroApp) => {
78
64
  const opts = getRuntimeOptions();
79
65
 
80
- // Resolution order: opts env → .securenow/credentials.json package.json#name
66
+ // Resolution order: opts -> .securenow/credentials.json -> legacy env fallback -> package.json#name
81
67
  const resolvedApp = appConfig.resolveAll();
82
68
 
83
69
  // ── Naming ──
@@ -85,8 +71,11 @@ export default defineNitroPlugin((nitroApp) => {
85
71
  const baseName = rawBase || null;
86
72
  // Default: auto-disable per-worker suffix when logged in (appId is the
87
73
  // routing UUID and the dashboard does exact match). opts.noUuid or
88
- // SECURENOW_NO_UUID override.
74
+ // config.runtime.noUuid or opts.noUuid override.
89
75
  const noUuid = appConfig.resolveNoUuid({ noUuid: opts.noUuid });
76
+ const deploymentEnvironment = appConfig.normalizeDeploymentEnvironment(
77
+ opts.environment || resolvedApp.deploymentEnvironment
78
+ );
90
79
 
91
80
  let serviceName;
92
81
  if (baseName) {
@@ -98,40 +87,31 @@ export default defineNitroPlugin((nitroApp) => {
98
87
  serviceName,
99
88
  );
100
89
  console.warn(
101
- '[securenow] 💡 Run `npx securenow login` or set SECURENOW_APPID in .env',
90
+ '[securenow] Run `npx securenow login` or set app.key in .securenow/credentials.json',
102
91
  );
103
92
  }
104
93
 
105
94
  const serviceInstanceId = `${baseName || 'securenow'}-${uuidv4()}`;
106
95
 
107
96
  // ── Endpoints ──
108
- const endpointBase = (opts.endpoint || resolvedApp.instance).replace(/\/$/, '');
109
-
110
- // Surface credentials-file app key as x-api-key for collector routing.
111
- if (resolvedApp.appKey && !env('OTEL_EXPORTER_OTLP_HEADERS') && !env('SECURENOW_API_KEY')) {
112
- process.env.SECURENOW_API_KEY = resolvedApp.appKey;
113
- process.env.OTEL_EXPORTER_OTLP_HEADERS = `x-api-key=${resolvedApp.appKey}`;
114
- }
115
-
116
- const tracesUrl =
117
- env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT') || `${endpointBase}/v1/traces`;
118
- const logsUrl =
119
- env('OTEL_EXPORTER_OTLP_LOGS_ENDPOINT') || `${endpointBase}/v1/logs`;
120
- const headers = parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS'));
97
+ const resolvedEndpoints = appConfig.resolveEndpoints({ endpoint: opts.endpoint || resolvedApp.instance });
98
+ const endpointBase = resolvedEndpoints.endpointBase;
99
+ const tracesUrl = resolvedEndpoints.tracesUrl;
100
+ const logsUrl = resolvedEndpoints.logsUrl;
101
+ const headers = resolvedEndpoints.headers;
121
102
 
122
103
  // ── Resource ──
123
104
  const resource = new Resource({
124
105
  [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
125
106
  [SemanticResourceAttributes.SERVICE_INSTANCE_ID]: serviceInstanceId,
126
- [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]:
127
- env('NODE_ENV') || 'production',
107
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: deploymentEnvironment,
128
108
  [SemanticResourceAttributes.SERVICE_VERSION]:
129
109
  process.env.npm_package_version || undefined,
130
110
  'framework': 'nuxt',
131
111
  });
132
112
 
133
113
  // ── Body capture config ──
134
- // Opt-out default: set SECURENOW_CAPTURE_BODY=0 (or opts.captureBody=false) to disable.
114
+ // Opt-out default: set config.capture.body=false (or opts.captureBody=false) to disable.
135
115
  const captureBody =
136
116
  opts.captureBody ??
137
117
  !/^(0|false)$/i.test(String(env('SECURENOW_CAPTURE_BODY') ?? ''));
@@ -240,7 +220,7 @@ export default defineNitroPlugin((nitroApp) => {
240
220
  );
241
221
 
242
222
  // ── Logging ──
243
- // Opt-out default: set SECURENOW_LOGGING_ENABLED=0 (or opts.logging=false) to disable.
223
+ // Opt-out default: set config.logging.enabled=false (or opts.logging=false) to disable.
244
224
  const loggingEnabled =
245
225
  opts.logging ??
246
226
  !/^(0|false)$/i.test(String(env('SECURENOW_LOGGING_ENABLED') ?? ''));
@@ -304,7 +284,7 @@ export default defineNitroPlugin((nitroApp) => {
304
284
  }
305
285
  } else {
306
286
  console.log(
307
- '[securenow] 📋 Logging: DISABLED (SECURENOW_LOGGING_ENABLED=0)',
287
+ '[securenow] Logging: DISABLED (config.logging.enabled=false)',
308
288
  );
309
289
  }
310
290
 
@@ -327,23 +307,27 @@ export default defineNitroPlugin((nitroApp) => {
327
307
  }
328
308
 
329
309
  // ── Firewall — runs independently from OTel ──
330
- const firewallApiKey = env('SECURENOW_API_KEY');
331
- const firewallAppKey = env('SECURENOW_APPID') || null;
332
- if (firewallApiKey && env('SECURENOW_FIREWALL_ENABLED') !== '0') {
310
+ const firewallOptions = appConfig.resolveFirewallOptions();
311
+ if (firewallOptions.apiKey && firewallOptions.enabled) {
333
312
  try {
334
313
  const { init: fwInit } = await import('./firewall.js');
335
314
  fwInit({
336
- apiKey: firewallApiKey,
337
- appKey: firewallAppKey,
338
- apiUrl: env('SECURENOW_API_URL') || 'https://api.securenow.ai',
339
- versionCheckInterval: parseInt(env('SECURENOW_FIREWALL_VERSION_INTERVAL'), 10) || 10,
340
- syncInterval: parseInt(env('SECURENOW_FIREWALL_SYNC_INTERVAL'), 10) || 300,
341
- failMode: env('SECURENOW_FIREWALL_FAIL_MODE') || 'open',
342
- statusCode: parseInt(env('SECURENOW_FIREWALL_STATUS_CODE'), 10) || 403,
343
- log: env('SECURENOW_FIREWALL_LOG') !== '0',
344
- tcp: env('SECURENOW_FIREWALL_TCP') === '1',
345
- iptables: env('SECURENOW_FIREWALL_IPTABLES') === '1',
346
- cloud: env('SECURENOW_FIREWALL_CLOUD') || null,
315
+ apiKey: firewallOptions.apiKey,
316
+ appKey: firewallOptions.appKey,
317
+ environment: deploymentEnvironment || firewallOptions.environment,
318
+ apiUrl: firewallOptions.apiUrl,
319
+ versionCheckInterval: firewallOptions.versionCheckInterval,
320
+ syncInterval: firewallOptions.syncInterval,
321
+ failMode: firewallOptions.failMode,
322
+ statusCode: firewallOptions.statusCode,
323
+ log: firewallOptions.log,
324
+ tcp: firewallOptions.tcp,
325
+ iptables: firewallOptions.iptables,
326
+ cloud: firewallOptions.cloud,
327
+ cloudDryRun: firewallOptions.cloudDryRun,
328
+ cloudflare: firewallOptions.cloudflare,
329
+ aws: firewallOptions.aws,
330
+ gcp: firewallOptions.gcp,
347
331
  });
348
332
  } catch (e) {
349
333
  console.warn('[securenow] Firewall init failed:', e.message);
package/nuxt.d.ts CHANGED
@@ -3,17 +3,23 @@
3
3
  */
4
4
 
5
5
  export interface SecureNowNuxtOptions {
6
- /**
7
- * Service name for OpenTelemetry traces.
8
- * @default process.env.SECURENOW_APPID || process.env.OTEL_SERVICE_NAME
9
- */
10
- serviceName?: string;
11
-
12
- /**
13
- * OTLP endpoint base URL.
14
- * @default process.env.SECURENOW_INSTANCE || 'https://freetrial.securenow.ai:4318'
15
- */
16
- endpoint?: string;
6
+ /**
7
+ * Service name for OpenTelemetry traces.
8
+ * @default .securenow/credentials.json app.key/app.name
9
+ */
10
+ serviceName?: string;
11
+
12
+ /**
13
+ * OTLP endpoint base URL.
14
+ * @default .securenow/credentials.json app.instance, or https://freetrial.securenow.ai:4318
15
+ */
16
+ endpoint?: string;
17
+
18
+ /**
19
+ * Deployment environment sent as OpenTelemetry deployment.environment.
20
+ * @default .securenow/credentials.json config.runtime.deploymentEnvironment
21
+ */
22
+ environment?: string;
17
23
 
18
24
  /**
19
25
  * Don't append UUID to service name (useful when running a single instance).
@@ -22,18 +28,18 @@ export interface SecureNowNuxtOptions {
22
28
  noUuid?: boolean;
23
29
 
24
30
  /**
25
- * Capture request bodies (POST/PUT/PATCH) on traced spans.
26
- * Sensitive fields are automatically redacted.
27
- * @default false
28
- */
29
- captureBody?: boolean;
30
-
31
- /**
32
- * Enable console log forwarding as OTLP log records.
33
- * @default false
34
- */
35
- logging?: boolean;
36
- }
31
+ * Capture request bodies (POST/PUT/PATCH) on traced spans.
32
+ * Sensitive fields are automatically redacted.
33
+ * @default true from .securenow/credentials.json secure defaults
34
+ */
35
+ captureBody?: boolean;
36
+
37
+ /**
38
+ * Enable console log forwarding as OTLP log records.
39
+ * @default true from .securenow/credentials.json secure defaults
40
+ */
41
+ logging?: boolean;
42
+ }
37
43
 
38
44
  declare module 'nuxt/schema' {
39
45
  interface NuxtConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securenow",
3
- "version": "7.5.1",
3
+ "version": "7.6.0",
4
4
  "description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
5
5
  "type": "commonjs",
6
6
  "main": "register.js",
package/postinstall.js CHANGED
@@ -69,23 +69,17 @@ function hasInstrumentationFile() {
69
69
 
70
70
  // Create TypeScript instrumentation file
71
71
  function createTsInstrumentation(targetPath) {
72
- const content = `import { registerSecureNow } from 'securenow/nextjs';
72
+ const content = `import { createRequire } from 'node:module';
73
73
 
74
- export function register() {
75
- registerSecureNow();
76
- }
74
+ const require = createRequire(import.meta.url);
77
75
 
78
- /**
79
- * Configuration via .env.local:
80
- *
81
- * Required:
82
- * SECURENOW_APPID=my-nextjs-app
83
- *
84
- * Optional:
85
- * SECURENOW_INSTANCE=http://your-otlp-backend:4318
86
- * OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-key"
87
- * OTEL_LOG_LEVEL=info
88
- */
76
+ export async function register() {
77
+ if (process.env.NEXT_RUNTIME !== 'nodejs') return;
78
+
79
+ const { registerSecureNow } = require('securenow/nextjs');
80
+ registerSecureNow({ captureBody: true });
81
+ require('securenow/nextjs-auto-capture');
82
+ }
89
83
  `;
90
84
 
91
85
  fs.writeFileSync(targetPath, content, 'utf8');
@@ -93,26 +87,17 @@ export function register() {
93
87
 
94
88
  // Create JavaScript instrumentation file
95
89
  function createJsInstrumentation(targetPath) {
96
- const content = `const { registerSecureNow } = require('securenow/nextjs');
90
+ const content = `import { createRequire } from 'node:module';
97
91
 
98
- export function register() {
99
- registerSecureNow();
100
- }
92
+ const require = createRequire(import.meta.url);
101
93
 
102
- /**
103
- * Configuration via .env.local:
104
- *
105
- * Required:
106
- * SECURENOW_APPID=my-nextjs-app
107
- *
108
- * Optional:
109
- * SECURENOW_INSTANCE=http://your-otlp-backend:4318
110
- * OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-key"
111
- * OTEL_LOG_LEVEL=info
112
- *
113
- * Optional: Disable request body capture (enabled by default)
114
- * SECURENOW_CAPTURE_BODY=0
115
- */
94
+ export async function register() {
95
+ if (process.env.NEXT_RUNTIME !== 'nodejs') return;
96
+
97
+ const { registerSecureNow } = require('securenow/nextjs');
98
+ registerSecureNow({ captureBody: true });
99
+ require('securenow/nextjs-auto-capture');
100
+ }
116
101
  `;
117
102
 
118
103
  fs.writeFileSync(targetPath, content, 'utf8');
@@ -133,12 +118,8 @@ export const config = {
133
118
  /**
134
119
  * Bodies are captured with:
135
120
  * - Automatic redaction of passwords, tokens, cards, etc.
136
- * - Size limits (configurable via SECURENOW_MAX_BODY_SIZE)
121
+ * - Size limits from .securenow/credentials.json
137
122
  * - JSON, GraphQL, Form data support
138
- *
139
- * Configure in .env.local:
140
- * SECURENOW_MAX_BODY_SIZE=20480
141
- * SECURENOW_SENSITIVE_FIELDS=email,phone
142
123
  */
143
124
  `;
144
125
 
@@ -160,38 +141,24 @@ export const config = {
160
141
  /**
161
142
  * Bodies are captured with:
162
143
  * - Automatic redaction of passwords, tokens, cards, etc.
163
- * - Size limits (configurable via SECURENOW_MAX_BODY_SIZE)
144
+ * - Size limits from .securenow/credentials.json
164
145
  * - JSON, GraphQL, Form data support
165
- *
166
- * Configure in .env.local:
167
- * SECURENOW_MAX_BODY_SIZE=20480
168
- * SECURENOW_SENSITIVE_FIELDS=email,phone
169
146
  */
170
147
  `;
171
148
 
172
149
  fs.writeFileSync(targetPath, content, 'utf8');
173
150
  }
174
151
 
175
- // Create .env.local template
152
+ // Create a credentials-file reminder for old callers that still import this helper.
176
153
  function createEnvTemplate(targetPath) {
177
- const content = `# SecureNow Configuration
178
- # Required: Your application identifier
179
- SECURENOW_APPID=my-nextjs-app
180
-
181
- # Optional: Your OTLP-compatible backend / collector endpoint
182
- # Default: https://freetrial.securenow.ai:4318
183
- SECURENOW_INSTANCE=http://your-otlp-backend:4318
154
+ const content = `SecureNow no longer needs a .env file for local development.
184
155
 
185
- # Optional: API key or authentication headers
186
- # OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-api-key-here"
156
+ Run:
157
+ npx securenow login
158
+ npx securenow init
187
159
 
188
- # Optional: Log level (debug|info|warn|error)
189
- # OTEL_LOG_LEVEL=info
190
-
191
- # Optional: Disable request body capture (enabled by default)
192
- # SECURENOW_CAPTURE_BODY=0
193
- # SECURENOW_MAX_BODY_SIZE=10240
194
- # SECURENOW_SENSITIVE_FIELDS=email,phone
160
+ The CLI writes .securenow/credentials.json with the selected app, firewall key,
161
+ secure defaults, and explanations for each setting.
195
162
  `;
196
163
 
197
164
  fs.writeFileSync(targetPath, content, 'utf8');
@@ -327,4 +294,3 @@ module.exports = { setup };
327
294
 
328
295
 
329
296
 
330
-
package/register.d.ts CHANGED
@@ -6,27 +6,17 @@
6
6
  */
7
7
 
8
8
  /**
9
- * Environment Variables:
10
- *
11
- * Required:
12
- * - SECURENOW_APPID=your-app-name - Logical service name
13
- * - SECURENOW_INSTANCE=http://host:4318 - OTLP endpoint
14
- *
15
- * Optional:
16
- * - SECURENOW_NO_UUID=1 - Use same service.name across all workers
17
- * - SECURENOW_STRICT=1 - Exit if no appid/name provided in cluster
18
- * - SECURENOW_CAPTURE_BODY=1 - Enable request body capture
19
- * - SECURENOW_MAX_BODY_SIZE=10240 - Max body size in bytes (default: 10KB)
20
- * - SECURENOW_SENSITIVE_FIELDS=field1,field2 - Additional sensitive fields
21
- * - SECURENOW_DISABLE_INSTRUMENTATIONS=pkg1,pkg2 - Disable specific instrumentations
22
- * - OTEL_LOG_LEVEL=info|debug - Logging level
23
- * - SECURENOW_TEST_SPAN=1 - Create test span on startup
24
- *
25
- * Alternative Environment Variables:
26
- * - OTEL_SERVICE_NAME - Alternative to SECURENOW_APPID
27
- * - OTEL_EXPORTER_OTLP_ENDPOINT - Alternative to SECURENOW_INSTANCE
28
- * - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT - Full traces URL
29
- * - OTEL_EXPORTER_OTLP_HEADERS - Headers for OTLP exporter (k=v,k2=v2)
9
+ * Configuration:
10
+ *
11
+ * Local development reads .securenow/credentials.json. Run
12
+ * `npx securenow login` to choose/create an app, then `npx securenow init`
13
+ * to ensure secure defaults and explanations are present.
14
+ *
15
+ * Production uses the same file shape. Run
16
+ * `npx securenow credentials runtime --env production`, then mount/copy the
17
+ * generated JSON to .securenow/credentials.json in the running app.
18
+ *
19
+ * Legacy env vars are fallback-only for existing installs.
30
20
  */
31
21
 
32
22
  // This module has side effects (initializes OpenTelemetry)
@@ -49,18 +39,14 @@ export {};
49
39
  * @example
50
40
  * ```javascript
51
41
  * // ecosystem.config.js
52
- * module.exports = {
53
- * apps: [{
54
- * name: 'my-app',
55
- * script: './app.js',
56
- * node_args: '-r securenow/register',
57
- * env: {
58
- * SECURENOW_APPID: 'my-app',
59
- * SECURENOW_INSTANCE: 'http://your-otlp-backend:4318',
60
- * SECURENOW_CAPTURE_BODY: '1',
61
- * }
62
- * }]
63
- * };
42
+ * module.exports = {
43
+ * apps: [{
44
+ * name: 'my-app',
45
+ * script: './app.js',
46
+ * node_args: '-r securenow/register',
47
+ * // Local and production use .securenow/credentials.json.
48
+ * }]
49
+ * };
64
50
  * ```
65
51
  *
66
52
  * @example