securenow 6.0.2 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONSUMING-APPS-GUIDE.md +455 -0
- package/NPM_README.md +2029 -0
- package/README.md +297 -40
- package/SKILL-API.md +634 -0
- package/SKILL-CLI.md +454 -0
- package/cidr.js +83 -0
- package/cli/apps.js +585 -0
- package/cli/auth.js +280 -0
- package/cli/client.js +115 -0
- package/cli/config.js +173 -0
- package/cli/diagnostics.js +387 -0
- package/cli/firewall.js +100 -0
- package/cli/fp.js +638 -0
- package/cli/init.js +201 -0
- package/cli/monitor.js +440 -0
- package/cli/run.js +148 -0
- package/cli/security.js +980 -0
- package/cli/ui.js +386 -0
- package/cli/utils.js +127 -0
- package/cli.js +466 -455
- package/console-instrumentation.js +147 -136
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +1377 -455
- package/docs/API-KEYS-GUIDE.md +233 -0
- package/docs/ARCHITECTURE.md +3 -3
- package/docs/AUTO-BODY-CAPTURE.md +1 -1
- package/docs/AUTO-SETUP-SUMMARY.md +331 -0
- package/docs/AUTO-SETUP.md +4 -4
- package/docs/AUTOMATIC-IP-CAPTURE.md +5 -5
- package/docs/BODY-CAPTURE-FIX.md +261 -0
- package/docs/BODY-CAPTURE-QUICKSTART.md +2 -2
- package/docs/CHANGELOG-NEXTJS.md +1 -35
- package/docs/COMPLETION-REPORT.md +408 -0
- package/docs/CUSTOMER-GUIDE.md +16 -16
- package/docs/EASIEST-SETUP.md +5 -5
- package/docs/ENVIRONMENT-VARIABLES.md +880 -652
- package/docs/EXPRESS-BODY-CAPTURE.md +13 -12
- package/docs/EXPRESS-SETUP-GUIDE.md +719 -720
- package/docs/FINAL-SOLUTION.md +335 -0
- package/docs/FIREWALL-GUIDE.md +426 -0
- package/docs/IMPLEMENTATION-SUMMARY.md +410 -0
- package/docs/INDEX.md +22 -4
- package/docs/LOGGING-GUIDE.md +701 -708
- package/docs/LOGGING-QUICKSTART.md +234 -255
- package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +323 -0
- package/docs/NEXTJS-BODY-CAPTURE.md +2 -2
- package/docs/NEXTJS-GUIDE.md +14 -14
- package/docs/NEXTJS-QUICKSTART.md +1 -1
- package/docs/NEXTJS-SETUP-COMPLETE.md +795 -0
- package/docs/NEXTJS-WRAPPER-APPROACH.md +1 -1
- package/docs/NUXT-GUIDE.md +166 -0
- package/docs/QUICKSTART-BODY-CAPTURE.md +2 -2
- package/docs/REDACTION-EXAMPLES.md +1 -1
- package/docs/REQUEST-BODY-CAPTURE.md +19 -10
- package/docs/SOLUTION-SUMMARY.md +312 -0
- package/docs/VERCEL-OTEL-MIGRATION.md +3 -3
- package/examples/README.md +6 -6
- package/examples/instrumentation-with-auto-capture.ts +1 -1
- package/examples/nextjs-env-example.txt +2 -2
- package/examples/nextjs-instrumentation.js +1 -1
- package/examples/nextjs-instrumentation.ts +1 -1
- package/examples/nextjs-with-logging-example.md +6 -6
- package/examples/nextjs-with-options.ts +1 -1
- package/examples/test-nextjs-setup.js +1 -1
- package/firewall-cloud.js +212 -0
- package/firewall-iptables.js +139 -0
- package/firewall-only.js +38 -0
- package/firewall-tcp.js +74 -0
- package/firewall.js +720 -0
- package/free-trial-banner.js +174 -0
- package/nextjs-auto-capture.js +199 -207
- package/nextjs-middleware.js +186 -181
- package/nextjs-webpack-config.js +88 -53
- package/nextjs-wrapper.js +158 -158
- package/nextjs.d.ts +1 -1
- package/nextjs.js +639 -647
- package/nuxt-server-plugin.mjs +423 -0
- package/nuxt.d.ts +60 -0
- package/nuxt.mjs +75 -0
- package/package.json +186 -164
- package/postinstall.js +6 -6
- package/register.d.ts +1 -1
- package/register.js +39 -4
- package/resolve-ip.js +77 -0
- package/tracing.d.ts +2 -1
- package/tracing.js +295 -34
- package/web-vite.mjs +239 -156
- package/LICENSE +0 -15
package/nextjs-middleware.js
CHANGED
|
@@ -1,181 +1,186 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SecureNow Next.js Middleware for Body Capture
|
|
3
|
-
*
|
|
4
|
-
* OPTIONAL: Import this in your Next.js app to enable automatic body capture
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
*
|
|
8
|
-
* Create middleware.ts in your Next.js app root:
|
|
9
|
-
*
|
|
10
|
-
* export { middleware } from 'securenow/nextjs-middleware';
|
|
11
|
-
* export const config = {
|
|
12
|
-
* matcher: '/api/:path*', // Apply to API routes only
|
|
13
|
-
* };
|
|
14
|
-
*
|
|
15
|
-
* That's it! Bodies are now captured with sensitive data redacted.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const { trace, context, SpanStatusCode } = require('@opentelemetry/api');
|
|
19
|
-
|
|
20
|
-
// Default sensitive fields to redact
|
|
21
|
-
const DEFAULT_SENSITIVE_FIELDS = [
|
|
22
|
-
'password', 'passwd', 'pwd', 'secret', 'token', 'api_key', 'apikey',
|
|
23
|
-
'access_token', 'auth', 'credentials', 'mysql_pwd', 'stripeToken',
|
|
24
|
-
'card', 'cardnumber', 'ccv', 'cvc', 'cvv', 'ssn', 'pin',
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Redact sensitive fields from an object
|
|
29
|
-
*/
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
patterns
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
span.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
1
|
+
/**
|
|
2
|
+
* SecureNow Next.js Middleware for Body Capture
|
|
3
|
+
*
|
|
4
|
+
* OPTIONAL: Import this in your Next.js app to enable automatic body capture
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
*
|
|
8
|
+
* Create middleware.ts in your Next.js app root:
|
|
9
|
+
*
|
|
10
|
+
* export { middleware } from 'securenow/nextjs-middleware';
|
|
11
|
+
* export const config = {
|
|
12
|
+
* matcher: '/api/:path*', // Apply to API routes only
|
|
13
|
+
* };
|
|
14
|
+
*
|
|
15
|
+
* That's it! Bodies are now captured with sensitive data redacted.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const { trace, context, SpanStatusCode } = require('@opentelemetry/api');
|
|
19
|
+
|
|
20
|
+
// Default sensitive fields to redact
|
|
21
|
+
const DEFAULT_SENSITIVE_FIELDS = [
|
|
22
|
+
'password', 'passwd', 'pwd', 'secret', 'token', 'api_key', 'apikey',
|
|
23
|
+
'access_token', 'auth', 'credentials', 'mysql_pwd', 'stripeToken',
|
|
24
|
+
'card', 'cardnumber', 'ccv', 'cvc', 'cvv', 'ssn', 'pin',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Redact sensitive fields from an object
|
|
29
|
+
*/
|
|
30
|
+
function escapeRegex(str) {
|
|
31
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function redactSensitiveData(obj, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
|
|
35
|
+
if (!obj || typeof obj !== 'object') return obj;
|
|
36
|
+
|
|
37
|
+
const redacted = Array.isArray(obj) ? [...obj] : { ...obj };
|
|
38
|
+
|
|
39
|
+
for (const key of Object.keys(redacted)) {
|
|
40
|
+
const lowerKey = key.toLowerCase();
|
|
41
|
+
|
|
42
|
+
if (sensitiveFields.some(field => lowerKey.includes(field.toLowerCase()))) {
|
|
43
|
+
redacted[key] = '[REDACTED]';
|
|
44
|
+
} else if (typeof redacted[key] === 'object' && redacted[key] !== null) {
|
|
45
|
+
redacted[key] = redactSensitiveData(redacted[key], sensitiveFields);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return redacted;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Redact sensitive data from GraphQL query strings
|
|
54
|
+
*/
|
|
55
|
+
function redactGraphQLQuery(query, sensitiveFields = DEFAULT_SENSITIVE_FIELDS) {
|
|
56
|
+
if (!query || typeof query !== 'string') return query;
|
|
57
|
+
|
|
58
|
+
let redacted = query;
|
|
59
|
+
|
|
60
|
+
sensitiveFields.forEach(field => {
|
|
61
|
+
const escaped = escapeRegex(field);
|
|
62
|
+
const patterns = [
|
|
63
|
+
new RegExp(`(${escaped}\\s*:\\s*["'])([^"']+)(["'])`, 'gi'),
|
|
64
|
+
new RegExp(`(${escaped}\\s*:\\s*)([^\\s,})\n]+)`, 'gi'),
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
patterns.forEach(pattern => {
|
|
68
|
+
redacted = redacted.replace(pattern, (match, prefix, value, suffix) => {
|
|
69
|
+
return suffix ? `${prefix}[REDACTED]${suffix}` : `${prefix}[REDACTED]`;
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return redacted;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Next.js Middleware for Body Capture
|
|
79
|
+
*/
|
|
80
|
+
async function middleware(request) {
|
|
81
|
+
const { NextResponse } = require('next/server');
|
|
82
|
+
|
|
83
|
+
// Only capture for POST/PUT/PATCH
|
|
84
|
+
if (!['POST', 'PUT', 'PATCH'].includes(request.method)) {
|
|
85
|
+
return NextResponse.next();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Get or create a tracer
|
|
89
|
+
const tracer = trace.getTracer('securenow-middleware');
|
|
90
|
+
let span = trace.getActiveSpan();
|
|
91
|
+
let createdSpan = false;
|
|
92
|
+
|
|
93
|
+
// If no active span, create one for this middleware
|
|
94
|
+
if (!span) {
|
|
95
|
+
const url = new URL(request.url);
|
|
96
|
+
span = tracer.startSpan(`middleware ${request.method} ${url.pathname}`);
|
|
97
|
+
createdSpan = true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const contentType = request.headers.get('content-type') || '';
|
|
102
|
+
const maxBodySize = Math.max(1024, parseInt(process.env.SECURENOW_MAX_BODY_SIZE, 10) || 10240);
|
|
103
|
+
const customSensitiveFields = (process.env.SECURENOW_SENSITIVE_FIELDS || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
104
|
+
const allSensitiveFields = [...DEFAULT_SENSITIVE_FIELDS, ...customSensitiveFields];
|
|
105
|
+
|
|
106
|
+
// Only capture supported types
|
|
107
|
+
if (contentType.includes('application/json') ||
|
|
108
|
+
contentType.includes('application/graphql')) {
|
|
109
|
+
|
|
110
|
+
// Clone the request to read body without consuming the original
|
|
111
|
+
const clonedRequest = request.clone();
|
|
112
|
+
const bodyText = await clonedRequest.text();
|
|
113
|
+
|
|
114
|
+
if (bodyText.length <= maxBodySize) {
|
|
115
|
+
let redactedBody;
|
|
116
|
+
|
|
117
|
+
if (contentType.includes('application/graphql')) {
|
|
118
|
+
// GraphQL: redact query string
|
|
119
|
+
redactedBody = redactGraphQLQuery(bodyText, allSensitiveFields);
|
|
120
|
+
} else {
|
|
121
|
+
// JSON: parse and redact
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(bodyText);
|
|
124
|
+
const redacted = redactSensitiveData(parsed, allSensitiveFields);
|
|
125
|
+
redactedBody = JSON.stringify(redacted);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
redactedBody = '[UNPARSEABLE - REDACTED FOR SAFETY]';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
span.setAttributes({
|
|
132
|
+
'http.request.body': redactedBody.substring(0, maxBodySize),
|
|
133
|
+
'http.request.body.type': contentType.includes('graphql') ? 'graphql' : 'json',
|
|
134
|
+
'http.request.body.size': bodyText.length,
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
span.setAttribute('http.request.body', `[TOO LARGE: ${bodyText.length} bytes]`);
|
|
138
|
+
}
|
|
139
|
+
} else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
140
|
+
const clonedRequest = request.clone();
|
|
141
|
+
const formData = await clonedRequest.formData();
|
|
142
|
+
const parsed = Object.fromEntries(formData);
|
|
143
|
+
const redacted = redactSensitiveData(parsed, allSensitiveFields);
|
|
144
|
+
|
|
145
|
+
span.setAttributes({
|
|
146
|
+
'http.request.body': JSON.stringify(redacted).substring(0, maxBodySize),
|
|
147
|
+
'http.request.body.type': 'form',
|
|
148
|
+
'http.request.body.size': JSON.stringify(parsed).length,
|
|
149
|
+
});
|
|
150
|
+
} else if (contentType.includes('multipart/form-data')) {
|
|
151
|
+
span.setAttribute('http.request.body', '[MULTIPART - NOT CAPTURED]');
|
|
152
|
+
span.setAttribute('http.request.body.type', 'multipart');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// End span if we created it
|
|
156
|
+
if (createdSpan) {
|
|
157
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
158
|
+
span.end();
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
// Silently fail - don't break the request
|
|
162
|
+
console.debug('[securenow] Body capture failed:', error.message);
|
|
163
|
+
|
|
164
|
+
// End span with error if we created it
|
|
165
|
+
if (createdSpan && span) {
|
|
166
|
+
span.setStatus({
|
|
167
|
+
code: SpanStatusCode.ERROR,
|
|
168
|
+
message: error.message
|
|
169
|
+
});
|
|
170
|
+
span.end();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return NextResponse.next();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
middleware,
|
|
179
|
+
redactSensitiveData,
|
|
180
|
+
redactGraphQLQuery,
|
|
181
|
+
DEFAULT_SENSITIVE_FIELDS,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
package/nextjs-webpack-config.js
CHANGED
|
@@ -1,33 +1,100 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Next.js configuration helpers for SecureNow
|
|
5
|
+
*
|
|
6
|
+
* Usage (recommended — zero-list approach):
|
|
7
|
+
*
|
|
8
|
+
* const { withSecureNow } = require('securenow/nextjs-webpack-config');
|
|
9
|
+
* module.exports = withSecureNow({
|
|
10
|
+
* // your existing next.config options
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* Legacy webpack-only helper (still exported for backwards compat):
|
|
14
|
+
*
|
|
15
|
+
* const { getSecureNowWebpackConfig } = require('securenow/nextjs-webpack-config');
|
|
16
|
+
* module.exports = { webpack: (config, opts) => getSecureNowWebpackConfig(config, opts) };
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const EXTERNAL_PACKAGES = [
|
|
20
|
+
'securenow',
|
|
21
|
+
'@opentelemetry/sdk-node',
|
|
22
|
+
'@opentelemetry/auto-instrumentations-node',
|
|
23
|
+
'@opentelemetry/instrumentation-http',
|
|
24
|
+
'@opentelemetry/exporter-trace-otlp-http',
|
|
25
|
+
'@opentelemetry/exporter-logs-otlp-http',
|
|
26
|
+
'@opentelemetry/sdk-logs',
|
|
27
|
+
'@opentelemetry/instrumentation',
|
|
28
|
+
'@opentelemetry/resources',
|
|
29
|
+
'@opentelemetry/semantic-conventions',
|
|
30
|
+
'@opentelemetry/api',
|
|
31
|
+
'@opentelemetry/api-logs',
|
|
32
|
+
'@vercel/otel',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
function detectNextMajor() {
|
|
36
|
+
try {
|
|
37
|
+
const pkg = require('next/package.json');
|
|
38
|
+
return parseInt(pkg.version, 10) || 14;
|
|
39
|
+
} catch {
|
|
40
|
+
return 14;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
1
44
|
/**
|
|
2
|
-
* Next.js
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* const { getSecureNowWebpackConfig } = require('securenow/nextjs-webpack-config');
|
|
8
|
-
*
|
|
9
|
-
* module.exports = {
|
|
10
|
-
* webpack: (config, options) => {
|
|
11
|
-
* return getSecureNowWebpackConfig(config, options);
|
|
12
|
-
* }
|
|
13
|
-
* };
|
|
45
|
+
* Wrap a Next.js config object to auto-externalize SecureNow + OTel
|
|
46
|
+
* packages and enable the instrumentation hook.
|
|
47
|
+
*
|
|
48
|
+
* module.exports = withSecureNow({ reactStrictMode: true });
|
|
14
49
|
*/
|
|
50
|
+
function withSecureNow(userConfig) {
|
|
51
|
+
if (typeof userConfig === 'function') {
|
|
52
|
+
return (...args) => withSecureNow(userConfig(...args));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cfg = { ...userConfig };
|
|
56
|
+
const major = detectNextMajor();
|
|
57
|
+
|
|
58
|
+
if (major >= 15) {
|
|
59
|
+
cfg.serverExternalPackages = dedup([
|
|
60
|
+
...(cfg.serverExternalPackages || []),
|
|
61
|
+
...EXTERNAL_PACKAGES,
|
|
62
|
+
]);
|
|
63
|
+
} else {
|
|
64
|
+
cfg.experimental = { ...(cfg.experimental || {}) };
|
|
65
|
+
cfg.experimental.instrumentationHook = true;
|
|
66
|
+
cfg.experimental.serverComponentsExternalPackages = dedup([
|
|
67
|
+
...(cfg.experimental.serverComponentsExternalPackages || []),
|
|
68
|
+
...EXTERNAL_PACKAGES,
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const origWebpack = cfg.webpack;
|
|
73
|
+
cfg.webpack = (config, options) => {
|
|
74
|
+
const c = origWebpack ? origWebpack(config, options) : config;
|
|
75
|
+
return getSecureNowWebpackConfig(c, options);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return cfg;
|
|
79
|
+
}
|
|
15
80
|
|
|
81
|
+
function dedup(arr) {
|
|
82
|
+
return [...new Set(arr)];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Legacy: suppress OTel webpack warnings and add externals.
|
|
87
|
+
*/
|
|
16
88
|
function getSecureNowWebpackConfig(config, options) {
|
|
17
89
|
const { isServer } = options;
|
|
18
|
-
|
|
19
|
-
// Only apply to server-side builds
|
|
90
|
+
|
|
20
91
|
if (isServer) {
|
|
21
|
-
// Suppress warnings for OpenTelemetry instrumentations
|
|
22
92
|
config.ignoreWarnings = config.ignoreWarnings || [];
|
|
23
|
-
|
|
24
93
|
config.ignoreWarnings.push(
|
|
25
|
-
// Ignore "Critical dependency" warnings from instrumentations
|
|
26
94
|
{
|
|
27
95
|
module: /@opentelemetry\/instrumentation/,
|
|
28
96
|
message: /Critical dependency: the request of a dependency is an expression/,
|
|
29
97
|
},
|
|
30
|
-
// Ignore missing optional peer dependencies
|
|
31
98
|
{
|
|
32
99
|
module: /@opentelemetry/,
|
|
33
100
|
message: /Module not found.*@opentelemetry\/winston-transport/,
|
|
@@ -35,43 +102,11 @@ function getSecureNowWebpackConfig(config, options) {
|
|
|
35
102
|
{
|
|
36
103
|
module: /@opentelemetry/,
|
|
37
104
|
message: /Module not found.*@opentelemetry\/exporter-jaeger/,
|
|
38
|
-
}
|
|
105
|
+
},
|
|
39
106
|
);
|
|
40
|
-
|
|
41
|
-
// Externalize problematic packages (don't bundle them)
|
|
42
|
-
config.externals = config.externals || [];
|
|
43
|
-
|
|
44
|
-
// Add OpenTelemetry packages as externals
|
|
45
|
-
if (typeof config.externals === 'function') {
|
|
46
|
-
const originalExternals = config.externals;
|
|
47
|
-
config.externals = async (...args) => {
|
|
48
|
-
const result = await originalExternals(...args);
|
|
49
|
-
if (result) return result;
|
|
50
|
-
|
|
51
|
-
const [context, request] = args;
|
|
52
|
-
|
|
53
|
-
// Externalize OpenTelemetry instrumentation packages
|
|
54
|
-
if (request.startsWith('@opentelemetry/')) {
|
|
55
|
-
return `commonjs ${request}`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return undefined;
|
|
59
|
-
};
|
|
60
|
-
} else if (Array.isArray(config.externals)) {
|
|
61
|
-
config.externals.push(/@opentelemetry\//);
|
|
62
|
-
} else {
|
|
63
|
-
config.externals = [/@opentelemetry\//];
|
|
64
|
-
}
|
|
65
107
|
}
|
|
66
|
-
|
|
108
|
+
|
|
67
109
|
return config;
|
|
68
110
|
}
|
|
69
111
|
|
|
70
|
-
module.exports = { getSecureNowWebpackConfig };
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
112
|
+
module.exports = { withSecureNow, getSecureNowWebpackConfig, EXTERNAL_PACKAGES };
|