securenow 7.5.1 → 7.6.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 (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 +205 -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 +211 -212
  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 +72 -40
  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 +22 -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 +48 -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 = {}) {
@@ -139,13 +131,13 @@ function registerSecureNow(options = {}) {
139
131
 
140
132
  // Detect environment outside try block for error handling
141
133
  const isVercel = !!(env('VERCEL') || env('VERCEL_ENV') || env('VERCEL_URL'));
134
+ let deploymentEnvironment = appConfig.resolveDeploymentEnvironment();
142
135
 
143
136
  try {
144
137
  console.log('[securenow] Next.js integration loading (pid=%d)', process.pid);
145
138
 
146
139
  // -------- Configuration --------
147
- // Resolution order: explicit options env → .securenow/credentials.json package.json#name
148
- const appConfig = require('./app-config');
140
+ // Resolution order: explicit options -> .securenow/credentials.json -> legacy env fallback -> package.json#name
149
141
  const resolvedApp = appConfig.resolveAll();
150
142
 
151
143
  const rawBase = (options.serviceName || resolvedApp.appId || '').trim().replace(/^['"]|['"]$/g, '');
@@ -154,6 +146,9 @@ function registerSecureNow(options = {}) {
154
146
  // and the dashboard does exact match). opts.noUuid or SECURENOW_NO_UUID
155
147
  // override.
156
148
  const noUuid = appConfig.resolveNoUuid({ noUuid: options.noUuid });
149
+ deploymentEnvironment = appConfig.normalizeDeploymentEnvironment(
150
+ options.environment || resolvedApp.deploymentEnvironment || env('VERCEL_ENV')
151
+ );
157
152
 
158
153
  // service.name
159
154
  let serviceName;
@@ -162,29 +157,25 @@ function registerSecureNow(options = {}) {
162
157
  } else {
163
158
  serviceName = `nextjs-app-${randomUUID()}`;
164
159
  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');
160
+ console.warn('[securenow] Run `npx securenow login` and `npx securenow init` to write .securenow/credentials.json');
166
161
  }
167
162
 
168
163
  // -------- 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`;
164
+ const resolvedEndpoints = appConfig.resolveEndpoints({ endpoint: options.endpoint || resolvedApp.instance });
165
+ const endpointBase = resolvedEndpoints.endpointBase;
166
+ const tracesUrl = resolvedEndpoints.tracesUrl;
167
+ const logsUrl = resolvedEndpoints.logsUrl;
168
+ const headers = resolvedEndpoints.headers;
179
169
 
180
170
  if (!process.env.OTEL_SERVICE_NAME) process.env.OTEL_SERVICE_NAME = serviceName;
181
171
  if (!process.env.OTEL_EXPORTER_OTLP_ENDPOINT) process.env.OTEL_EXPORTER_OTLP_ENDPOINT = endpointBase;
182
172
  if (!process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = tracesUrl;
183
173
 
184
- console.log('[securenow] 🚀 Next.js App service.name=%s', serviceName);
174
+ console.log('[securenow] Next.js App -> service.name=%s', serviceName);
175
+ console.log('[securenow] Environment: %s', deploymentEnvironment);
185
176
 
186
177
  // -------- Body Capture Configuration --------
187
- // Opt-out default: set SECURENOW_CAPTURE_BODY=0 (or options.captureBody=false) to disable.
178
+ // Opt-out default: set config.capture.body=false (or options.captureBody=false) to disable.
188
179
  const captureBody = options.captureBody ?? !/^(0|false)$/i.test(String(env('SECURENOW_CAPTURE_BODY') ?? ''));
189
180
  const maxBodySize = Math.max(1024, parseInt(env('SECURENOW_MAX_BODY_SIZE'), 10) || 10240);
190
181
  const customSensitiveFields = (env('SECURENOW_SENSITIVE_FIELDS') || '').split(',').map(s => s.trim()).filter(Boolean);
@@ -413,7 +404,7 @@ function registerSecureNow(options = {}) {
413
404
  registerOTel({
414
405
  serviceName: serviceName,
415
406
  attributes: {
416
- 'deployment.environment': env('NODE_ENV') || env('VERCEL_ENV') || 'development',
407
+ 'deployment.environment': deploymentEnvironment,
417
408
  'service.version': process.env.npm_package_version || process.env.VERCEL_GIT_COMMIT_SHA || undefined,
418
409
  'vercel.region': process.env.VERCEL_REGION || undefined,
419
410
  },
@@ -444,7 +435,7 @@ function registerSecureNow(options = {}) {
444
435
 
445
436
  const traceExporter = new OTLPTraceExporter({
446
437
  url: tracesUrl,
447
- headers: parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS'))
438
+ headers
448
439
  });
449
440
 
450
441
  const sdk = new NodeSDK({
@@ -453,7 +444,7 @@ function registerSecureNow(options = {}) {
453
444
  instrumentations: [httpInstrumentation],
454
445
  resource: new Resource({
455
446
  [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
456
- [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || env('VERCEL_ENV') || 'production',
447
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: deploymentEnvironment,
457
448
  [SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version || undefined,
458
449
  }),
459
450
  });
@@ -462,7 +453,7 @@ function registerSecureNow(options = {}) {
462
453
  console.log('[securenow] 🎯 Vanilla SDK initialized for self-hosted environment');
463
454
 
464
455
  // -------- Logging (self-hosted only) --------
465
- // Opt-out default: set SECURENOW_LOGGING_ENABLED=0 to disable.
456
+ // Opt-out default: set config.logging.enabled=false to disable.
466
457
  const loggingEnabled = !/^(0|false)$/i.test(String(env('SECURENOW_LOGGING_ENABLED') ?? ''));
467
458
  if (loggingEnabled) {
468
459
  try {
@@ -471,13 +462,13 @@ function registerSecureNow(options = {}) {
471
462
 
472
463
  const logExporter = new OTLPLogExporter({
473
464
  url: logsUrl,
474
- headers: parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS')),
465
+ headers,
475
466
  });
476
467
 
477
468
  const loggerProvider = new LoggerProvider({
478
469
  resource: new Resource({
479
470
  [SemanticResourceAttributes.SERVICE_NAME]: serviceName,
480
- [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || 'production',
471
+ [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: deploymentEnvironment,
481
472
  }),
482
473
  });
483
474
  loggerProvider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
@@ -614,25 +605,28 @@ function registerSecureNow(options = {}) {
614
605
  }
615
606
 
616
607
  // 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') {
608
+ // Key and environment come from .securenow/credentials.json (written by
609
+ // login/init or credentials runtime), so no .env entry is needed.
610
+ const firewallOptions = appConfig.resolveFirewallOptions();
611
+ if (firewallOptions.apiKey && firewallOptions.enabled) {
623
612
  try {
624
613
  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,
614
+ apiKey: firewallOptions.apiKey,
615
+ appKey: firewallOptions.appKey,
616
+ environment: deploymentEnvironment || firewallOptions.environment,
617
+ apiUrl: firewallOptions.apiUrl,
618
+ versionCheckInterval: firewallOptions.versionCheckInterval,
619
+ syncInterval: firewallOptions.syncInterval,
620
+ failMode: firewallOptions.failMode,
621
+ statusCode: firewallOptions.statusCode,
622
+ log: firewallOptions.log,
623
+ tcp: firewallOptions.tcp,
624
+ iptables: firewallOptions.iptables,
625
+ cloud: firewallOptions.cloud,
626
+ cloudDryRun: firewallOptions.cloudDryRun,
627
+ cloudflare: firewallOptions.cloudflare,
628
+ aws: firewallOptions.aws,
629
+ gcp: firewallOptions.gcp,
636
630
  });
637
631
  } catch (e) {
638
632
  console.warn('[securenow] Firewall init failed:', e.message);
@@ -643,4 +637,3 @@ function registerSecureNow(options = {}) {
643
637
  module.exports = {
644
638
  registerSecureNow,
645
639
  };
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.1",
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