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/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 / env ----
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
- // Accept both Vite envs (VITE_*) and raw names for window.__SECURENOW__
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://freetrial.securenow.ai:4318')
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 SECURENOW_NO_UUID=0
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: SECURENOW_APPID/OTEL_SERVICE_NAME missing and SECURENOW_STRICT=1. Tracing disabled.');
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 SECURENOW_APPID=%s OTEL_SERVICE_NAME=%s SECURENOW_NO_UUID=%s SECURENOW_STRICT=%s → service.name=%s instance.id=%s',
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]: viteEnv.MODE || 'production',
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 FREETRIAL_HOST = 'freetrial.securenow.ai';
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(FREETRIAL_HOST)) return;
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() {