securenow 7.7.13 → 7.7.15
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/NPM_README.md +98 -140
- package/README.md +46 -32
- package/SKILL-API.md +495 -491
- package/SKILL-CLI.md +9 -9
- package/app-config.js +99 -42
- package/cli/apps.js +589 -597
- package/cli/auth.js +1 -3
- package/cli/config.js +37 -9
- package/cli/credentials.js +1 -1
- package/cli/diagnostics.js +10 -6
- package/cli/init.js +1 -0
- package/free-trial-banner.js +2 -2
- package/mcp/catalog.js +2 -2
- package/nextjs-webpack-config.js +41 -18
- package/nextjs.d.ts +67 -63
- package/nextjs.js +57 -46
- package/nuxt-server-plugin.mjs +6 -11
- package/nuxt.d.ts +42 -38
- package/nuxt.mjs +1 -1
- package/package.json +1 -1
- package/tracing.d.ts +2 -1
- package/tracing.js +31 -47
- package/web-vite.mjs +102 -15
package/web-vite.mjs
CHANGED
|
@@ -11,9 +11,24 @@ import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-u
|
|
|
11
11
|
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch';
|
|
12
12
|
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
|
|
13
13
|
|
|
14
|
-
// ---- helpers /
|
|
14
|
+
// ---- helpers / browser config ----
|
|
15
15
|
const viteEnv = import.meta.env || {};
|
|
16
16
|
|
|
17
|
+
const ENV_TO_BROWSER_CONFIG_PATH = Object.freeze({
|
|
18
|
+
SECURENOW_APPID: 'app.key',
|
|
19
|
+
SECURENOW_INSTANCE: 'config.otel.endpoint',
|
|
20
|
+
OTEL_SERVICE_NAME: 'app.name',
|
|
21
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: 'config.otel.endpoint',
|
|
22
|
+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: 'config.otel.tracesEndpoint',
|
|
23
|
+
OTEL_EXPORTER_OTLP_HEADERS: 'config.otel.headers',
|
|
24
|
+
SECURENOW_NO_UUID: 'config.runtime.noUuid',
|
|
25
|
+
SECURENOW_STRICT: 'config.runtime.strict',
|
|
26
|
+
SECURENOW_TEST_SPAN: 'config.runtime.testSpan',
|
|
27
|
+
SECURENOW_HIDE_BANNER: 'config.runtime.hideBanner',
|
|
28
|
+
SECURENOW_ENVIRONMENT: 'config.runtime.deploymentEnvironment',
|
|
29
|
+
SECURENOW_DEPLOYMENT_ENVIRONMENT: 'config.runtime.deploymentEnvironment',
|
|
30
|
+
});
|
|
31
|
+
|
|
17
32
|
function createResource(attributes) {
|
|
18
33
|
if (typeof otelResources.resourceFromAttributes === 'function') {
|
|
19
34
|
return otelResources.resourceFromAttributes(attributes);
|
|
@@ -24,17 +39,62 @@ function createResource(attributes) {
|
|
|
24
39
|
throw new Error('Unsupported @opentelemetry/resources version');
|
|
25
40
|
}
|
|
26
41
|
|
|
42
|
+
function legacyViteEnvFallbackEnabled() {
|
|
43
|
+
const raw =
|
|
44
|
+
viteEnv.SECURENOW_ENABLE_LEGACY_ENV ??
|
|
45
|
+
viteEnv.VITE_SECURENOW_ENABLE_LEGACY_ENV ??
|
|
46
|
+
viteEnv.SECURENOW_ALLOW_ENV_CONFIG ??
|
|
47
|
+
viteEnv.VITE_SECURENOW_ALLOW_ENV_CONFIG;
|
|
48
|
+
return /^(1|true|yes)$/i.test(String(raw || '').trim());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getPath(obj, path) {
|
|
52
|
+
if (!obj || !path) return undefined;
|
|
53
|
+
let cur = obj;
|
|
54
|
+
for (const part of String(path).split('.')) {
|
|
55
|
+
if (cur == null || typeof cur !== 'object' || !(part in cur)) return undefined;
|
|
56
|
+
cur = cur[part];
|
|
57
|
+
}
|
|
58
|
+
return cur;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function headersToString(headers) {
|
|
62
|
+
if (!headers || typeof headers !== 'object' || Array.isArray(headers)) return undefined;
|
|
63
|
+
return Object.entries(headers)
|
|
64
|
+
.filter(([, value]) => value !== undefined && value !== null && value !== '')
|
|
65
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
66
|
+
.join(',');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function toConfigString(value) {
|
|
70
|
+
if (value === undefined || value === null || value === '') return undefined;
|
|
71
|
+
if (typeof value === 'boolean') return value ? '1' : '0';
|
|
72
|
+
if (Array.isArray(value)) return value.join(',');
|
|
73
|
+
if (typeof value === 'object') return headersToString(value);
|
|
74
|
+
return String(value);
|
|
75
|
+
}
|
|
76
|
+
|
|
27
77
|
function env(k) {
|
|
28
|
-
//
|
|
78
|
+
// Browser config should be injected as window.__SECURENOW__ by the app.
|
|
79
|
+
const w = globalThis.window;
|
|
80
|
+
const injected = w && w.__SECURENOW__;
|
|
81
|
+
const mappedPath = ENV_TO_BROWSER_CONFIG_PATH[String(k).toUpperCase()];
|
|
82
|
+
if (injected) {
|
|
83
|
+
if (mappedPath) {
|
|
84
|
+
const mappedValue = getPath(injected, mappedPath);
|
|
85
|
+
const resolved = toConfigString(mappedValue);
|
|
86
|
+
if (resolved !== undefined) return resolved;
|
|
87
|
+
}
|
|
88
|
+
if (!mappedPath && k in injected) return toConfigString(injected[k]);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Vite env fallbacks are legacy and disabled by default.
|
|
92
|
+
if (!legacyViteEnvFallbackEnabled()) return undefined;
|
|
29
93
|
const direct =
|
|
30
94
|
viteEnv[k] ??
|
|
31
95
|
viteEnv[k.toUpperCase()] ??
|
|
32
96
|
viteEnv[k.toLowerCase()];
|
|
33
97
|
if (direct != null) return String(direct);
|
|
34
|
-
|
|
35
|
-
// Optionally support runtime overrides via window.__SECURENOW__
|
|
36
|
-
const w = globalThis.window;
|
|
37
|
-
if (w && w.__SECURENOW__ && k in w.__SECURENOW__) return String(w.__SECURENOW__[k]);
|
|
38
98
|
return undefined;
|
|
39
99
|
}
|
|
40
100
|
|
|
@@ -51,20 +111,47 @@ function parseHeaders(str) {
|
|
|
51
111
|
return out;
|
|
52
112
|
}
|
|
53
113
|
|
|
114
|
+
function normalizeEndpointBase(value) {
|
|
115
|
+
const endpoint = String(value || '').trim().replace(/\/$/, '');
|
|
116
|
+
if (!endpoint) return endpoint;
|
|
117
|
+
if (endpoint === 'https://api.securenow.ai/api/otlp') return 'https://ingest.securenow.ai';
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const parseable = /^[a-z][a-z0-9+.-]*:\/\//i.test(endpoint) ? endpoint : `https://${endpoint}`;
|
|
121
|
+
const url = new URL(parseable);
|
|
122
|
+
if (url.port === '4318' && url.hostname.toLowerCase().endsWith('.securenow.ai')) {
|
|
123
|
+
return 'https://ingest.securenow.ai';
|
|
124
|
+
}
|
|
125
|
+
} catch {}
|
|
126
|
+
|
|
127
|
+
return endpoint;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function normalizeSignalEndpoint(value, signalType) {
|
|
131
|
+
if (!value) return value;
|
|
132
|
+
const endpoint = String(value).trim().replace(/\/$/, '');
|
|
133
|
+
const signalPath = `/v1/${signalType}`;
|
|
134
|
+
if (endpoint.endsWith(signalPath)) {
|
|
135
|
+
return `${normalizeEndpointBase(endpoint.slice(0, -signalPath.length))}${signalPath}`;
|
|
136
|
+
}
|
|
137
|
+
return endpoint;
|
|
138
|
+
}
|
|
139
|
+
|
|
54
140
|
// ---- endpoints (same defaults as tracing.js) ----
|
|
55
141
|
const endpointBase =
|
|
56
|
-
(env('SECURENOW_INSTANCE') || env('OTEL_EXPORTER_OTLP_ENDPOINT') || 'https://
|
|
57
|
-
.replace(/\/$/, '');
|
|
142
|
+
normalizeEndpointBase(env('SECURENOW_INSTANCE') || env('OTEL_EXPORTER_OTLP_ENDPOINT') || 'https://ingest.securenow.ai');
|
|
58
143
|
const tracesUrl =
|
|
59
|
-
env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT') || `${endpointBase}/v1/traces`;
|
|
144
|
+
normalizeSignalEndpoint(env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'), 'traces') || `${endpointBase}/v1/traces`;
|
|
60
145
|
const headers = parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS'));
|
|
146
|
+
const deploymentEnvironment =
|
|
147
|
+
env('SECURENOW_DEPLOYMENT_ENVIRONMENT') || env('SECURENOW_ENVIRONMENT') || viteEnv.MODE || 'production';
|
|
61
148
|
|
|
62
149
|
// ---- naming rules (mirrors tracing.js) ----
|
|
63
150
|
const rawBase = (env('OTEL_SERVICE_NAME') || env('SECURENOW_APPID') || '').trim().replace(/^['"]|['"]$/g, '');
|
|
64
151
|
const baseName = rawBase || null;
|
|
65
152
|
// Default to no suffix whenever a baseName is resolved: the dashboard filters
|
|
66
153
|
// service.name by exact match, and browsers have no PM2 cluster problem
|
|
67
|
-
// (each tab has its own service.instance.id). Explicit
|
|
154
|
+
// (each tab has its own service.instance.id). Explicit config.runtime.noUuid=false
|
|
68
155
|
// still re-enables the suffix if someone really wants it.
|
|
69
156
|
const noUuidEnv = env('SECURENOW_NO_UUID');
|
|
70
157
|
const noUuid =
|
|
@@ -95,7 +182,7 @@ if (baseName) {
|
|
|
95
182
|
serviceName = noUuid ? baseName : `${baseName}-${uuidv4()}`;
|
|
96
183
|
} else {
|
|
97
184
|
if (strict) {
|
|
98
|
-
console.error('[securenow/web-vite] FATAL:
|
|
185
|
+
console.error('[securenow/web-vite] FATAL: SecureNow app key missing and config.runtime.strict=true. Tracing disabled.');
|
|
99
186
|
// @ts-expect-error
|
|
100
187
|
window.__SECURENOW_DISABLED__ = true;
|
|
101
188
|
disabled = true;
|
|
@@ -112,7 +199,7 @@ const serviceInstanceId = `${instancePrefix}-${uuidv4()}`;
|
|
|
112
199
|
try {
|
|
113
200
|
// eslint-disable-next-line no-console
|
|
114
201
|
console.log(
|
|
115
|
-
'[securenow] web preload loaded
|
|
202
|
+
'[securenow] web preload loaded app.key=%s app.name=%s config.runtime.noUuid=%s config.runtime.strict=%s → service.name=%s instance.id=%s',
|
|
116
203
|
JSON.stringify(env('SECURENOW_APPID')),
|
|
117
204
|
JSON.stringify(env('OTEL_SERVICE_NAME')),
|
|
118
205
|
JSON.stringify(env('SECURENOW_NO_UUID')),
|
|
@@ -138,7 +225,7 @@ export function startSecurenowWeb() {
|
|
|
138
225
|
resource: createResource({
|
|
139
226
|
[S.SERVICE_NAME]: serviceName,
|
|
140
227
|
[S.SERVICE_INSTANCE_ID]: serviceInstanceId,
|
|
141
|
-
[S.DEPLOYMENT_ENVIRONMENT]:
|
|
228
|
+
[S.DEPLOYMENT_ENVIRONMENT]: deploymentEnvironment,
|
|
142
229
|
[S.SERVICE_VERSION]: viteEnv.VITE_APP_VERSION || undefined,
|
|
143
230
|
}),
|
|
144
231
|
spanProcessors: [new BatchSpanProcessor(exporter)],
|
|
@@ -174,9 +261,9 @@ export function startSecurenowWeb() {
|
|
|
174
261
|
|
|
175
262
|
// ---- Free trial banner (browser DOM injection) ----
|
|
176
263
|
function injectFreeTrialBanner() {
|
|
177
|
-
const
|
|
264
|
+
const FREE_TRIAL_HOSTS = ['ingest.securenow.ai', 'freetrial.securenow.ai'];
|
|
178
265
|
const hideBanner = String(env('SECURENOW_HIDE_BANNER')) === '1';
|
|
179
|
-
if (hideBanner || !endpointBase.includes(
|
|
266
|
+
if (hideBanner || !FREE_TRIAL_HOSTS.some(host => endpointBase.includes(host))) return;
|
|
180
267
|
if (typeof document === 'undefined') return;
|
|
181
268
|
|
|
182
269
|
function create() {
|