securenow 3.0.14 → 4.0.2

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.
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Test script to verify SecureNow Next.js setup
3
+ *
4
+ * Run this to verify your configuration before integrating with Next.js:
5
+ *
6
+ * SECURENOW_APPID=test-app node examples/test-nextjs-setup.js
7
+ */
8
+
9
+ const { registerSecureNow } = require('../nextjs.js');
10
+
11
+ console.log('Testing SecureNow Next.js integration...\n');
12
+
13
+ // Test 1: Basic registration
14
+ console.log('Test 1: Basic registration');
15
+ try {
16
+ const sdk = registerSecureNow({
17
+ serviceName: 'test-nextjs-app',
18
+ endpoint: process.env.SECURENOW_INSTANCE || 'http://localhost:4318',
19
+ });
20
+
21
+ if (sdk) {
22
+ console.log('✅ SDK registered successfully\n');
23
+ } else {
24
+ console.log('⚠️ SDK returned null (expected in Edge runtime)\n');
25
+ }
26
+ } catch (error) {
27
+ console.error('❌ Registration failed:', error);
28
+ process.exit(1);
29
+ }
30
+
31
+ // Test 2: Create a test span
32
+ console.log('Test 2: Creating test span');
33
+ try {
34
+ const api = require('@opentelemetry/api');
35
+ const tracer = api.trace.getTracer('test-tracer');
36
+ const span = tracer.startSpan('test.span');
37
+ span.setAttribute('test.attribute', 'test-value');
38
+ span.setAttribute('test.number', 123);
39
+ span.end();
40
+ console.log('✅ Test span created and ended\n');
41
+ } catch (error) {
42
+ console.error('❌ Span creation failed:', error);
43
+ process.exit(1);
44
+ }
45
+
46
+ // Test 3: Verify configuration
47
+ console.log('Test 3: Configuration verification');
48
+ console.log('- SECURENOW_APPID:', process.env.SECURENOW_APPID || '(not set)');
49
+ console.log('- SECURENOW_INSTANCE:', process.env.SECURENOW_INSTANCE || '(using default)');
50
+ console.log('- NODE_ENV:', process.env.NODE_ENV || 'development');
51
+ console.log('- OTEL_LOG_LEVEL:', process.env.OTEL_LOG_LEVEL || '(none)');
52
+ console.log('✅ Configuration loaded\n');
53
+
54
+ // Test 4: Wait for export
55
+ console.log('Test 4: Waiting for span export...');
56
+ setTimeout(() => {
57
+ console.log('✅ Export should have completed\n');
58
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
59
+ console.log('✅ All tests passed!');
60
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
61
+ console.log('\nCheck your SigNoz dashboard for traces from "test-nextjs-app"\n');
62
+ process.exit(0);
63
+ }, 2000);
64
+
65
+
66
+
67
+
package/nextjs.js ADDED
@@ -0,0 +1,203 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * SecureNow Next.js Integration using @vercel/otel
5
+ *
6
+ * Usage in Next.js app:
7
+ *
8
+ * 1. Create instrumentation.ts (or .js) in your project root:
9
+ *
10
+ * import { registerSecureNow } from 'securenow/nextjs';
11
+ * export function register() {
12
+ * registerSecureNow();
13
+ * }
14
+ *
15
+ * 2. Set environment variables:
16
+ * SECURENOW_APPID=my-nextjs-app
17
+ * SECURENOW_INSTANCE=http://your-signoz-host:4318
18
+ *
19
+ * That's it! 🎉 No webpack warnings!
20
+ */
21
+
22
+ const { v4: uuidv4 } = require('uuid');
23
+
24
+ const env = k => process.env[k] ?? process.env[k.toUpperCase()] ?? process.env[k.toLowerCase()];
25
+
26
+ let isRegistered = false;
27
+
28
+ /**
29
+ * Register SecureNow OpenTelemetry for Next.js using @vercel/otel
30
+ * @param {Object} options - Optional configuration
31
+ * @param {string} options.serviceName - Service name (defaults to SECURENOW_APPID or OTEL_SERVICE_NAME)
32
+ * @param {string} options.endpoint - Traces endpoint (defaults to SECURENOW_INSTANCE)
33
+ * @param {boolean} options.noUuid - Don't append UUID to service name
34
+ */
35
+ function registerSecureNow(options = {}) {
36
+ // Only register once
37
+ if (isRegistered) {
38
+ console.log('[securenow] Already registered, skipping...');
39
+ return;
40
+ }
41
+
42
+ // Skip for Edge runtime
43
+ if (process.env.NEXT_RUNTIME === 'edge') {
44
+ console.log('[securenow] Skipping Edge runtime (Node.js only)');
45
+ return;
46
+ }
47
+
48
+ try {
49
+ console.log('[securenow] Next.js integration loading (pid=%d)', process.pid);
50
+
51
+ // -------- Configuration --------
52
+ const rawBase = (
53
+ options.serviceName ||
54
+ env('OTEL_SERVICE_NAME') ||
55
+ env('SECURENOW_APPID') ||
56
+ ''
57
+ ).trim().replace(/^['"]|['"]$/g, '');
58
+
59
+ const baseName = rawBase || null;
60
+ const noUuid = options.noUuid ?? (String(env('SECURENOW_NO_UUID')) === '1' || String(env('SECURENOW_NO_UUID')).toLowerCase() === 'true');
61
+
62
+ // service.name
63
+ let serviceName;
64
+ if (baseName) {
65
+ serviceName = noUuid ? baseName : `${baseName}-${uuidv4()}`;
66
+ } else {
67
+ serviceName = `nextjs-app-${uuidv4()}`;
68
+ console.warn('[securenow] ⚠️ No SECURENOW_APPID or OTEL_SERVICE_NAME provided. Using fallback: %s', serviceName);
69
+ console.warn('[securenow] 💡 Set SECURENOW_APPID=your-app-name in .env.local for better tracking');
70
+ }
71
+
72
+ // -------- Endpoint Configuration --------
73
+ const endpointBase = (
74
+ options.endpoint ||
75
+ env('SECURENOW_INSTANCE') ||
76
+ env('OTEL_EXPORTER_OTLP_ENDPOINT') ||
77
+ 'http://46.62.173.237:4318'
78
+ ).replace(/\/$/, '');
79
+
80
+ const tracesUrl = env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT') || `${endpointBase}/v1/traces`;
81
+
82
+ // Set environment variables for @vercel/otel to pick up
83
+ process.env.OTEL_SERVICE_NAME = serviceName;
84
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = endpointBase;
85
+ process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = tracesUrl;
86
+
87
+ console.log('[securenow] 🚀 Next.js App → service.name=%s', serviceName);
88
+
89
+ // -------- Use @vercel/otel with enhanced configuration --------
90
+ const { registerOTel } = require('@vercel/otel');
91
+ const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
92
+
93
+ registerOTel({
94
+ serviceName: serviceName,
95
+ attributes: {
96
+ 'deployment.environment': env('NODE_ENV') || env('VERCEL_ENV') || 'development',
97
+ 'service.version': process.env.npm_package_version || process.env.VERCEL_GIT_COMMIT_SHA || undefined,
98
+ 'vercel.region': process.env.VERCEL_REGION || undefined,
99
+ },
100
+ instrumentations: [
101
+ // Add HTTP instrumentation with request hooks to capture IP and headers
102
+ new HttpInstrumentation({
103
+ requireParentforOutgoingSpans: false,
104
+ requireParentforIncomingSpans: false,
105
+ requestHook: (span, request) => {
106
+ try {
107
+ // Capture client IP from various headers
108
+ const headers = request.headers || {};
109
+
110
+ // Try different header sources for IP
111
+ const clientIp =
112
+ headers['x-forwarded-for']?.split(',')[0]?.trim() ||
113
+ headers['x-real-ip'] ||
114
+ headers['cf-connecting-ip'] || // Cloudflare
115
+ headers['x-client-ip'] ||
116
+ request.socket?.remoteAddress ||
117
+ 'unknown';
118
+
119
+ // Add IP and request metadata to span
120
+ span.setAttributes({
121
+ 'http.client_ip': clientIp,
122
+ 'http.user_agent': headers['user-agent'] || 'unknown',
123
+ 'http.referer': headers['referer'] || headers['referrer'] || '',
124
+ 'http.host': headers['host'] || '',
125
+ 'http.scheme': request.socket?.encrypted ? 'https' : 'http',
126
+ 'http.forwarded_for': headers['x-forwarded-for'] || '',
127
+ 'http.real_ip': headers['x-real-ip'] || '',
128
+ 'http.request_id': headers['x-request-id'] || headers['x-trace-id'] || '',
129
+ });
130
+
131
+ // Add geographic headers if available (Vercel/Cloudflare)
132
+ if (headers['x-vercel-ip-country']) {
133
+ span.setAttributes({
134
+ 'http.geo.country': headers['x-vercel-ip-country'],
135
+ 'http.geo.region': headers['x-vercel-ip-country-region'] || '',
136
+ 'http.geo.city': headers['x-vercel-ip-city'] || '',
137
+ });
138
+ }
139
+
140
+ if (headers['cf-ipcountry']) {
141
+ span.setAttribute('http.geo.country', headers['cf-ipcountry']);
142
+ }
143
+ } catch (error) {
144
+ // Silently fail to not break the request
145
+ console.debug('[securenow] Failed to capture request metadata:', error.message);
146
+ }
147
+ },
148
+ responseHook: (span, response) => {
149
+ try {
150
+ // Add response metadata
151
+ if (response.statusCode) {
152
+ span.setAttribute('http.status_code', response.statusCode);
153
+ }
154
+ } catch (error) {
155
+ console.debug('[securenow] Failed to capture response metadata:', error.message);
156
+ }
157
+ },
158
+ }),
159
+ ],
160
+ instrumentationConfig: {
161
+ fetch: {
162
+ // Propagate context to your backend APIs
163
+ propagateContextUrls: [
164
+ /^https?:\/\/localhost/,
165
+ /^https?:\/\/.*\.vercel\.app/,
166
+ // Add your backend domains here
167
+ ],
168
+ // Optionally ignore certain URLs
169
+ ignoreUrls: [
170
+ /_next\/static/,
171
+ /_next\/image/,
172
+ /\.map$/,
173
+ ],
174
+ // Add resource name template for better span naming
175
+ resourceNameTemplate: '{http.method} {http.target}',
176
+ },
177
+ },
178
+ });
179
+
180
+ isRegistered = true;
181
+ console.log('[securenow] ✅ OpenTelemetry started for Next.js → %s', tracesUrl);
182
+ console.log('[securenow] 📊 Auto-capturing: IP, User-Agent, Headers, Geographic data');
183
+
184
+ // Optional test span
185
+ if (String(env('SECURENOW_TEST_SPAN')) === '1') {
186
+ const api = require('@opentelemetry/api');
187
+ const tracer = api.trace.getTracer('securenow-nextjs');
188
+ const span = tracer.startSpan('securenow.nextjs.startup');
189
+ span.setAttribute('next.runtime', process.env.NEXT_RUNTIME || 'nodejs');
190
+ span.end();
191
+ console.log('[securenow] 🧪 Test span created');
192
+ }
193
+
194
+ } catch (error) {
195
+ console.error('[securenow] Failed to initialize OpenTelemetry:', error);
196
+ console.error('[securenow] Make sure you have @vercel/otel installed: npm install @vercel/otel');
197
+ }
198
+ }
199
+
200
+ module.exports = {
201
+ registerSecureNow,
202
+ };
203
+
package/package.json CHANGED
@@ -1,44 +1,90 @@
1
- {
2
- "name": "securenow",
3
- "version": "3.0.14",
4
- "type": "commonjs",
5
- "main": "register.js",
6
- "exports": {
7
- ".": "./register.js",
8
- "./register": "./register.js",
9
- "./tracing": "./tracing.js",
10
- "./register-vite": "./register-vite.js",
11
- "./web-vite": {
12
- "import": "./web-vite.mjs",
13
- "default": "./web-vite.mjs"
14
- }
15
- },
16
- "files": [
17
- "register.js",
18
- "tracing.js",
19
- "register-vite.js",
20
- "web-vite.mjs",
21
- "README.md"
22
- ],
23
- "dependencies": {
24
- "@opentelemetry/api": "1.7.0",
25
- "@opentelemetry/auto-instrumentations-node": "0.47.0",
26
- "@opentelemetry/exporter-trace-otlp-http": "0.47.0",
27
- "@opentelemetry/resources": "1.20.0",
28
- "@opentelemetry/sdk-node": "0.47.0",
29
- "@opentelemetry/semantic-conventions": "1.20.0",
30
- "@opentelemetry/sdk-trace-web": "1.20.0",
31
- "@opentelemetry/instrumentation": "0.47.0",
32
- "@opentelemetry/instrumentation-document-load": "0.47.0",
33
- "@opentelemetry/instrumentation-user-interaction": "0.47.0",
34
- "@opentelemetry/instrumentation-fetch": "0.47.0",
35
- "@opentelemetry/instrumentation-xml-http-request": "0.47.0",
36
- "dotenv": "^17.2.1",
37
- "uuid": "^9.0.0"
38
- },
39
- "overrides": {
40
- "@opentelemetry/api": "1.7.0"
41
- },
42
- "sideEffects": true,
43
- "license": "ISC"
44
- }
1
+ {
2
+ "name": "securenow",
3
+ "version": "4.0.2",
4
+ "description": "OpenTelemetry instrumentation for Node.js and Next.js - Send traces to SigNoz or any OTLP backend",
5
+ "type": "commonjs",
6
+ "main": "register.js",
7
+ "bin": {
8
+ "securenow": "./cli.js"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "node postinstall.js || exit 0"
12
+ },
13
+ "keywords": [
14
+ "opentelemetry",
15
+ "otel",
16
+ "tracing",
17
+ "observability",
18
+ "apm",
19
+ "monitoring",
20
+ "nextjs",
21
+ "next.js",
22
+ "signoz",
23
+ "instrumentation",
24
+ "telemetry",
25
+ "distributed-tracing",
26
+ "node",
27
+ "express",
28
+ "fastify",
29
+ "nestjs"
30
+ ],
31
+ "exports": {
32
+ ".": "./register.js",
33
+ "./register": "./register.js",
34
+ "./tracing": "./tracing.js",
35
+ "./nextjs": "./nextjs.js",
36
+ "./nextjs-webpack-config": "./nextjs-webpack-config.js",
37
+ "./register-vite": "./register-vite.js",
38
+ "./web-vite": {
39
+ "import": "./web-vite.mjs",
40
+ "default": "./web-vite.mjs"
41
+ }
42
+ },
43
+ "files": [
44
+ "register.js",
45
+ "tracing.js",
46
+ "nextjs.js",
47
+ "cli.js",
48
+ "postinstall.js",
49
+ "register-vite.js",
50
+ "web-vite.mjs",
51
+ "examples/",
52
+ "README.md",
53
+ "NEXTJS-GUIDE.md",
54
+ "NEXTJS-QUICKSTART.md",
55
+ "CUSTOMER-GUIDE.md",
56
+ "AUTO-SETUP.md",
57
+ "AUTOMATIC-IP-CAPTURE.md"
58
+ ],
59
+ "dependencies": {
60
+ "@opentelemetry/api": "1.7.0",
61
+ "@opentelemetry/auto-instrumentations-node": "0.47.0",
62
+ "@opentelemetry/exporter-trace-otlp-http": "0.47.0",
63
+ "@opentelemetry/instrumentation": "0.47.0",
64
+ "@opentelemetry/instrumentation-document-load": "0.47.0",
65
+ "@opentelemetry/instrumentation-fetch": "0.47.0",
66
+ "@opentelemetry/instrumentation-http": "^0.208.0",
67
+ "@opentelemetry/instrumentation-user-interaction": "0.47.0",
68
+ "@opentelemetry/instrumentation-xml-http-request": "0.47.0",
69
+ "@opentelemetry/resources": "1.20.0",
70
+ "@opentelemetry/sdk-node": "0.47.0",
71
+ "@opentelemetry/sdk-trace-web": "1.20.0",
72
+ "@opentelemetry/semantic-conventions": "1.20.0",
73
+ "@vercel/otel": "^1.14.0",
74
+ "dotenv": "^17.2.1",
75
+ "uuid": "^9.0.0"
76
+ },
77
+ "peerDependencies": {
78
+ "next": ">=13.0.0"
79
+ },
80
+ "peerDependenciesMeta": {
81
+ "next": {
82
+ "optional": true
83
+ }
84
+ },
85
+ "overrides": {
86
+ "@opentelemetry/api": "1.7.0"
87
+ },
88
+ "sideEffects": true,
89
+ "license": "ISC"
90
+ }
package/postinstall.js ADDED
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * SecureNow Post-Install Script
6
+ *
7
+ * Automatically detects Next.js projects and offers to create instrumentation file
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const readline = require('readline');
13
+
14
+ // Check if we're in a Next.js project
15
+ function isNextJsProject() {
16
+ try {
17
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
18
+ if (!fs.existsSync(packageJsonPath)) return false;
19
+
20
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
21
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
22
+
23
+ return !!deps.next;
24
+ } catch (error) {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ // Check if instrumentation file already exists
30
+ function hasInstrumentationFile() {
31
+ const files = [
32
+ 'instrumentation.ts',
33
+ 'instrumentation.js',
34
+ 'src/instrumentation.ts',
35
+ 'src/instrumentation.js'
36
+ ];
37
+
38
+ return files.some(file => fs.existsSync(path.join(process.cwd(), file)));
39
+ }
40
+
41
+ // Create TypeScript instrumentation file
42
+ function createTsInstrumentation(targetPath) {
43
+ const content = `import { registerSecureNow } from 'securenow/nextjs';
44
+
45
+ export function register() {
46
+ registerSecureNow();
47
+ }
48
+
49
+ /**
50
+ * Configuration via .env.local:
51
+ *
52
+ * Required:
53
+ * SECURENOW_APPID=my-nextjs-app
54
+ *
55
+ * Optional:
56
+ * SECURENOW_INSTANCE=http://your-signoz-server:4318
57
+ * OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-key"
58
+ * OTEL_LOG_LEVEL=info
59
+ */
60
+ `;
61
+
62
+ fs.writeFileSync(targetPath, content, 'utf8');
63
+ }
64
+
65
+ // Create JavaScript instrumentation file
66
+ function createJsInstrumentation(targetPath) {
67
+ const content = `const { registerSecureNow } = require('securenow/nextjs');
68
+
69
+ export function register() {
70
+ registerSecureNow();
71
+ }
72
+
73
+ /**
74
+ * Configuration via .env.local:
75
+ *
76
+ * Required:
77
+ * SECURENOW_APPID=my-nextjs-app
78
+ *
79
+ * Optional:
80
+ * SECURENOW_INSTANCE=http://your-signoz-server:4318
81
+ * OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-key"
82
+ * OTEL_LOG_LEVEL=info
83
+ */
84
+ `;
85
+
86
+ fs.writeFileSync(targetPath, content, 'utf8');
87
+ }
88
+
89
+ // Create .env.local template
90
+ function createEnvTemplate(targetPath) {
91
+ const content = `# SecureNow Configuration
92
+ # Required: Your application identifier
93
+ SECURENOW_APPID=my-nextjs-app
94
+
95
+ # Optional: Your SigNoz/OpenTelemetry collector endpoint
96
+ # Default: http://46.62.173.237:4318
97
+ SECURENOW_INSTANCE=http://your-signoz-server:4318
98
+
99
+ # Optional: API key or authentication headers
100
+ # OTEL_EXPORTER_OTLP_HEADERS="x-api-key=your-api-key-here"
101
+
102
+ # Optional: Log level (debug|info|warn|error)
103
+ # OTEL_LOG_LEVEL=info
104
+ `;
105
+
106
+ fs.writeFileSync(targetPath, content, 'utf8');
107
+ }
108
+
109
+ // Check if TypeScript is used
110
+ function isTypeScriptProject() {
111
+ return fs.existsSync(path.join(process.cwd(), 'tsconfig.json'));
112
+ }
113
+
114
+ // Main setup function
115
+ async function setup() {
116
+ // Skip if not in Next.js project
117
+ if (!isNextJsProject()) {
118
+ console.log('[securenow] Not a Next.js project, skipping auto-setup');
119
+ return;
120
+ }
121
+
122
+ // Skip if instrumentation file already exists
123
+ if (hasInstrumentationFile()) {
124
+ console.log('[securenow] ✅ Instrumentation file already exists');
125
+ return;
126
+ }
127
+
128
+ console.log('\n┌─────────────────────────────────────────────────┐');
129
+ console.log('│ 🎉 SecureNow installed successfully! │');
130
+ console.log('│ Next.js project detected │');
131
+ console.log('└─────────────────────────────────────────────────┘\n');
132
+
133
+ // Check if we're in CI/non-interactive environment
134
+ if (process.env.CI || !process.stdin.isTTY) {
135
+ console.log('[securenow] ℹ️ Non-interactive environment detected');
136
+ console.log('[securenow] 💡 To complete setup, run: npx securenow init');
137
+ return;
138
+ }
139
+
140
+ // Ask user if they want to auto-setup
141
+ const rl = readline.createInterface({
142
+ input: process.stdin,
143
+ output: process.stdout
144
+ });
145
+
146
+ rl.question('Would you like to automatically create instrumentation file? (Y/n) ', (answer) => {
147
+ const shouldCreate = !answer || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
148
+
149
+ if (!shouldCreate) {
150
+ console.log('\n[securenow] No problem! To setup later, run: npx securenow init');
151
+ rl.close();
152
+ return;
153
+ }
154
+
155
+ try {
156
+ const useTypeScript = isTypeScriptProject();
157
+ const srcExists = fs.existsSync(path.join(process.cwd(), 'src'));
158
+
159
+ // Determine file path
160
+ const fileName = useTypeScript ? 'instrumentation.ts' : 'instrumentation.js';
161
+ const filePath = srcExists
162
+ ? path.join(process.cwd(), 'src', fileName)
163
+ : path.join(process.cwd(), fileName);
164
+
165
+ // Create instrumentation file
166
+ if (useTypeScript) {
167
+ createTsInstrumentation(filePath);
168
+ } else {
169
+ createJsInstrumentation(filePath);
170
+ }
171
+
172
+ console.log(`\n✅ Created ${srcExists ? 'src/' : ''}${fileName}`);
173
+
174
+ // Create .env.local if it doesn't exist
175
+ const envPath = path.join(process.cwd(), '.env.local');
176
+ if (!fs.existsSync(envPath)) {
177
+ createEnvTemplate(envPath);
178
+ console.log('✅ Created .env.local template');
179
+ }
180
+
181
+ console.log('\n┌─────────────────────────────────────────────────┐');
182
+ console.log('│ 🚀 Next Steps: │');
183
+ console.log('│ │');
184
+ console.log('│ 1. Edit .env.local and set: │');
185
+ console.log('│ SECURENOW_APPID=your-app-name │');
186
+ console.log('│ SECURENOW_INSTANCE=http://signoz:4318 │');
187
+ console.log('│ │');
188
+ console.log('│ 2. Run your app: npm run dev │');
189
+ console.log('│ │');
190
+ console.log('│ 3. Check SigNoz for traces! │');
191
+ console.log('│ │');
192
+ console.log('│ 📚 Full guide: npm docs securenow │');
193
+ console.log('└─────────────────────────────────────────────────┘\n');
194
+
195
+ } catch (error) {
196
+ console.error('\n❌ Failed to create instrumentation file:', error.message);
197
+ console.log('💡 You can create it manually or run: npx securenow init');
198
+ }
199
+
200
+ rl.close();
201
+ });
202
+ }
203
+
204
+ // Run setup if this is a new installation (not being installed as a dependency of another package)
205
+ if (require.main === module || process.env.npm_config_global !== 'true') {
206
+ setup().catch(err => {
207
+ console.error('[securenow] Setup error:', err);
208
+ });
209
+ }
210
+
211
+ module.exports = { setup };
212
+
213
+
214
+
215
+