@newtalaria/browser 0.1.18 → 0.1.19

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.
@@ -272,6 +272,250 @@
272
272
  return base;
273
273
  }
274
274
 
275
+ // src/utils/tags.ts
276
+ var MAX_TAGS_PER_EVENT = 20;
277
+ var MAX_TAG_KEY_LENGTH = 64;
278
+ var MAX_TAG_VALUE_LENGTH = 128;
279
+ var MAX_TAG_TOTAL_UTF8_BYTES = 2048;
280
+ var KEY_PATTERN = /^[a-z0-9_.-]+$/;
281
+ var HIGH_CARDINALITY_TAG_KEYS = /* @__PURE__ */ new Set([
282
+ "user_id",
283
+ "userid",
284
+ "request_id",
285
+ "requestid",
286
+ "business_id",
287
+ "order_id",
288
+ "email",
289
+ "url",
290
+ "uuid",
291
+ "session_id",
292
+ "trace_id",
293
+ "span_id"
294
+ ]);
295
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
296
+ var EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
297
+ var LONG_NUMERIC_RE = /^\d{8,}$/;
298
+ function utf8Bytes(s) {
299
+ if (typeof TextEncoder !== "undefined") {
300
+ return new TextEncoder().encode(s).length;
301
+ }
302
+ return unescape(encodeURIComponent(s)).length;
303
+ }
304
+ function normalizeKey(raw) {
305
+ const key = raw.trim().toLowerCase();
306
+ if (!key || key.length > MAX_TAG_KEY_LENGTH) return null;
307
+ if (!KEY_PATTERN.test(key)) return null;
308
+ return key;
309
+ }
310
+ function normalizeValue(raw) {
311
+ if (raw == null) return null;
312
+ const value = String(raw).trim();
313
+ if (!value) return null;
314
+ return value.length <= MAX_TAG_VALUE_LENGTH ? value : value.slice(0, MAX_TAG_VALUE_LENGTH);
315
+ }
316
+ function normalizeTags(tags) {
317
+ if (!tags) return {};
318
+ const result2 = {};
319
+ let totalBytes = 0;
320
+ for (const [rawKey, rawValue] of Object.entries(tags)) {
321
+ if (Object.keys(result2).length >= MAX_TAGS_PER_EVENT) break;
322
+ const key = normalizeKey(rawKey);
323
+ if (!key) continue;
324
+ const value = normalizeValue(rawValue);
325
+ if (value == null) continue;
326
+ if (result2[key] != null) {
327
+ totalBytes -= utf8Bytes(key) + utf8Bytes(result2[key]);
328
+ }
329
+ const entryBytes = utf8Bytes(key) + utf8Bytes(value);
330
+ if (totalBytes + entryBytes > MAX_TAG_TOTAL_UTF8_BYTES) continue;
331
+ result2[key] = value;
332
+ totalBytes += entryBytes;
333
+ }
334
+ return result2;
335
+ }
336
+ function mergeTags(...parts) {
337
+ const merged = {};
338
+ for (const part of parts) {
339
+ if (!part) continue;
340
+ Object.assign(merged, part);
341
+ }
342
+ return normalizeTags(merged);
343
+ }
344
+ function looksHighCardinalityValue(value) {
345
+ return UUID_RE.test(value) || EMAIL_RE.test(value) || LONG_NUMERIC_RE.test(value);
346
+ }
347
+ function warnSuspiciousTags(tags, environment) {
348
+ if (!environment || environment === "production") return;
349
+ if (typeof console === "undefined" || typeof console.warn !== "function") {
350
+ return;
351
+ }
352
+ for (const [key, value] of Object.entries(tags)) {
353
+ if (HIGH_CARDINALITY_TAG_KEYS.has(key)) {
354
+ console.warn(
355
+ `@newtalaria/browser: Tag "${key}" appears to have high cardinality. Consider moving it to context/extra.`
356
+ );
357
+ continue;
358
+ }
359
+ if (looksHighCardinalityValue(value)) {
360
+ console.warn(
361
+ `@newtalaria/browser: Tag "${key}" value looks high-cardinality. Consider moving it to context/extra.`
362
+ );
363
+ }
364
+ }
365
+ }
366
+
367
+ // src/utils/stacktrace.ts
368
+ var V8_FRAME = /^\s*at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?\s*$/;
369
+ var V8_FRAME_BARE = /^\s*at\s+(.+)\s*$/;
370
+ var EXTENSION_URL2 = /(?:chrome|moz|safari|safari-web|ms-browser)-extension:\/\//i;
371
+ function parseStackTrace(stack, inAppOptions) {
372
+ if (!stack || !stack.trim()) return void 0;
373
+ const parsed = [];
374
+ for (const line of stack.split("\n")) {
375
+ const frame = parseStackLine(line, inAppOptions);
376
+ if (frame) parsed.push(frame);
377
+ }
378
+ if (parsed.length === 0) return void 0;
379
+ parsed.reverse();
380
+ return { frames: parsed };
381
+ }
382
+ function parseStackLine(line, inAppOptions) {
383
+ if (!/^\s*at\s+/.test(line)) return null;
384
+ const v8 = V8_FRAME.exec(line);
385
+ if (v8) {
386
+ const functionName = cleanFunction(v8[1]);
387
+ const absPath = stripQuery(v8[2] ?? "");
388
+ const lineno = Number.parseInt(v8[3] ?? "", 10);
389
+ const colno = Number.parseInt(v8[4] ?? "", 10);
390
+ return {
391
+ functionName,
392
+ absPath: absPath || void 0,
393
+ filename: basename(absPath),
394
+ lineno: Number.isFinite(lineno) ? lineno : void 0,
395
+ colno: Number.isFinite(colno) ? colno : void 0,
396
+ inApp: isInAppFrame(absPath, inAppOptions),
397
+ platform: "javascript"
398
+ };
399
+ }
400
+ const bare = V8_FRAME_BARE.exec(line);
401
+ if (bare) {
402
+ const functionName = cleanFunction(bare[1]);
403
+ if (!functionName) return null;
404
+ return {
405
+ functionName,
406
+ inApp: false,
407
+ platform: "javascript"
408
+ };
409
+ }
410
+ return null;
411
+ }
412
+ function applySourceLocation(stacktrace, source, inAppOptions) {
413
+ if (!source) return stacktrace;
414
+ const filename = source.filename?.trim() || void 0;
415
+ const lineno = typeof source.lineno === "number" && source.lineno > 0 ? source.lineno : void 0;
416
+ const colno = typeof source.colno === "number" && source.colno >= 0 ? source.colno : void 0;
417
+ if (!filename && lineno == null && colno == null) return stacktrace;
418
+ if (!stacktrace || stacktrace.frames.length === 0) {
419
+ if (!filename && lineno == null) return stacktrace;
420
+ const absPath = filename;
421
+ return {
422
+ frames: [
423
+ {
424
+ filename: absPath ? basename(absPath) : void 0,
425
+ absPath,
426
+ lineno,
427
+ colno,
428
+ inApp: absPath ? isInAppFrame(absPath, inAppOptions) : true,
429
+ platform: "javascript"
430
+ }
431
+ ]
432
+ };
433
+ }
434
+ const frames = stacktrace.frames.slice();
435
+ const top = { ...frames[frames.length - 1] };
436
+ if (filename) {
437
+ top.absPath = filename;
438
+ top.filename = basename(filename);
439
+ top.inApp = isInAppFrame(filename, inAppOptions);
440
+ }
441
+ if (lineno != null) top.lineno = lineno;
442
+ if (colno != null) top.colno = colno;
443
+ frames[frames.length - 1] = top;
444
+ return { ...stacktrace, frames };
445
+ }
446
+ function isInAppFrame(path, options) {
447
+ const lower = path.toLowerCase();
448
+ if (!lower) return true;
449
+ if (lower.includes("node_modules")) return false;
450
+ if (EXTENSION_URL2.test(path) || lower.includes("webkit-masked-url://")) {
451
+ return false;
452
+ }
453
+ if (lower.includes("@newtalaria/browser")) return false;
454
+ if (matchesUrlList(path, options?.denyUrls)) return false;
455
+ if (matchesUrlList(path, options?.allowUrls)) return true;
456
+ const frameOrigin = tryParseOrigin(path);
457
+ if (frameOrigin != null) {
458
+ const pageOrigin = normalizeOrigin(options?.pageOrigin);
459
+ if (pageOrigin && frameOrigin === pageOrigin) return true;
460
+ const extra = options?.inAppOrigins ?? [];
461
+ for (const origin of extra) {
462
+ if (normalizeOrigin(origin) === frameOrigin) return true;
463
+ }
464
+ return false;
465
+ }
466
+ return true;
467
+ }
468
+ function matchesUrlList(path, patterns) {
469
+ if (!patterns || patterns.length === 0) return false;
470
+ for (const pattern of patterns) {
471
+ if (typeof pattern === "string") {
472
+ if (pattern && path.includes(pattern)) return true;
473
+ } else if (pattern.test(path)) {
474
+ return true;
475
+ }
476
+ }
477
+ return false;
478
+ }
479
+ function tryParseOrigin(path) {
480
+ if (!/^https?:\/\//i.test(path)) return null;
481
+ try {
482
+ return new URL(path).origin;
483
+ } catch {
484
+ return null;
485
+ }
486
+ }
487
+ function normalizeOrigin(origin) {
488
+ if (!origin || !origin.trim()) return null;
489
+ const trimmed = origin.trim();
490
+ try {
491
+ if (/^https?:\/\//i.test(trimmed)) {
492
+ return new URL(trimmed).origin;
493
+ }
494
+ return trimmed;
495
+ } catch {
496
+ return trimmed;
497
+ }
498
+ }
499
+ function resolvePageOrigin(originOrUrl) {
500
+ return normalizeOrigin(originOrUrl) ?? void 0;
501
+ }
502
+ function cleanFunction(raw) {
503
+ if (raw == null) return void 0;
504
+ const value = raw.trim();
505
+ return value.length === 0 ? void 0 : value;
506
+ }
507
+ function stripQuery(path) {
508
+ const q = path.indexOf("?");
509
+ return q >= 0 ? path.slice(0, q) : path;
510
+ }
511
+ function basename(path) {
512
+ if (!path) return void 0;
513
+ const normalized = stripQuery(path);
514
+ const parts = normalized.split(/[/\\]/);
515
+ const last = parts[parts.length - 1];
516
+ return last || normalized;
517
+ }
518
+
275
519
  // src/sdk_meta.ts
276
520
  var SDK_NAME = "@newtalaria/browser";
277
521
  var SDK_VERSION = "0.1.18";
@@ -332,6 +576,9 @@
332
576
  if (params.eventType) input2.eventType = params.eventType;
333
577
  if (params.title) input2.title = params.title;
334
578
  if (params.stackTrace) input2.stackTrace = params.stackTrace;
579
+ if (params.exception) input2.exception = serializeException(params.exception);
580
+ if (params.debugMeta) input2.debugMeta = serializeDebugMeta(params.debugMeta);
581
+ if (params.platform) input2.platform = params.platform;
335
582
  if (params.release) input2.release = params.release;
336
583
  if (params.userId) input2.userId = params.userId;
337
584
  if (params.sessionId) input2.sessionId = params.sessionId;
@@ -348,6 +595,89 @@
348
595
  { keepalive: params.keepalive }
349
596
  );
350
597
  }
598
+ function serializeException(data) {
599
+ return {
600
+ __className__: "ExceptionDataDto",
601
+ values: data.values.map(serializeExceptionValue)
602
+ };
603
+ }
604
+ function serializeExceptionValue(value) {
605
+ const out = {
606
+ __className__: "ExceptionValueDto"
607
+ };
608
+ if (value.type != null) out.type = value.type;
609
+ if (value.value != null) out.value = value.value;
610
+ if (value.module != null) out.module = value.module;
611
+ if (value.threadId != null) out.threadId = value.threadId;
612
+ if (value.code != null) out.code = value.code;
613
+ if (value.mechanism) out.mechanism = serializeMechanism(value.mechanism);
614
+ if (value.stacktrace) out.stacktrace = serializeStackTrace(value.stacktrace);
615
+ return out;
616
+ }
617
+ function serializeMechanism(mechanism) {
618
+ const out = {
619
+ __className__: "ExceptionMechanismDto",
620
+ type: mechanism.type
621
+ };
622
+ if (mechanism.handled != null) out.handled = mechanism.handled;
623
+ if (mechanism.synthetic != null) out.synthetic = mechanism.synthetic;
624
+ return out;
625
+ }
626
+ function serializeStackTrace(stack) {
627
+ const out = {
628
+ __className__: "StackTraceDto",
629
+ frames: stack.frames.map(serializeStackFrame)
630
+ };
631
+ if (stack.registers) out.registers = stack.registers;
632
+ return out;
633
+ }
634
+ function serializeStackFrame(frame) {
635
+ const out = {
636
+ __className__: "StackFrameDto"
637
+ };
638
+ if (frame.filename != null) out.filename = frame.filename;
639
+ if (frame.absPath != null) out.absPath = frame.absPath;
640
+ if (frame.functionName != null) out.functionName = frame.functionName;
641
+ if (frame.rawFunction != null) out.rawFunction = frame.rawFunction;
642
+ if (frame.module != null) out.module = frame.module;
643
+ if (frame.package != null) out.package = frame.package;
644
+ if (frame.platform != null) out.platform = frame.platform;
645
+ if (frame.lineno != null) out.lineno = frame.lineno;
646
+ if (frame.colno != null) out.colno = frame.colno;
647
+ if (frame.inApp != null) out.inApp = frame.inApp;
648
+ if (frame.instructionAddr != null) out.instructionAddr = frame.instructionAddr;
649
+ if (frame.symbolAddr != null) out.symbolAddr = frame.symbolAddr;
650
+ if (frame.imageAddr != null) out.imageAddr = frame.imageAddr;
651
+ if (frame.addrMode != null) out.addrMode = frame.addrMode;
652
+ if (frame.contextLine != null) out.contextLine = frame.contextLine;
653
+ if (frame.preContext != null) out.preContext = frame.preContext;
654
+ if (frame.postContext != null) out.postContext = frame.postContext;
655
+ if (frame.vars != null) out.vars = frame.vars;
656
+ if (frame.stackStart != null) out.stackStart = frame.stackStart;
657
+ return out;
658
+ }
659
+ function serializeDebugMeta(meta) {
660
+ const out = {
661
+ __className__: "DebugMetaDto"
662
+ };
663
+ if (meta.images) {
664
+ out.images = meta.images.map((image) => {
665
+ const img = {
666
+ __className__: "DebugImageDto"
667
+ };
668
+ if (image.type != null) img.type = image.type;
669
+ if (image.imageAddr != null) img.imageAddr = image.imageAddr;
670
+ if (image.imageSize != null) img.imageSize = image.imageSize;
671
+ if (image.debugId != null) img.debugId = image.debugId;
672
+ if (image.debugFile != null) img.debugFile = image.debugFile;
673
+ if (image.codeId != null) img.codeId = image.codeId;
674
+ if (image.codeFile != null) img.codeFile = image.codeFile;
675
+ if (image.arch != null) img.arch = image.arch;
676
+ return img;
677
+ });
678
+ }
679
+ return out;
680
+ }
351
681
 
352
682
  // src/utils/gzip.ts
353
683
  async function gzipBytes(data) {
@@ -13769,7 +14099,7 @@
13769
14099
  }
13770
14100
  }
13771
14101
  }
13772
- function resolvePageOrigin(pageOrigin) {
14102
+ function resolvePageOrigin2(pageOrigin) {
13773
14103
  if (pageOrigin) {
13774
14104
  try {
13775
14105
  return new URL(pageOrigin).origin;
@@ -13794,12 +14124,12 @@
13794
14124
  if (!requestOrigin) return false;
13795
14125
  const allow = opts.networkErrorOrigins.map(normalizeNetworkOrigin);
13796
14126
  if (allow.includes("*")) return true;
13797
- const page = resolvePageOrigin(opts.pageOrigin);
14127
+ const page = resolvePageOrigin2(opts.pageOrigin);
13798
14128
  if (page && requestOrigin === page) return true;
13799
14129
  return allow.includes(requestOrigin);
13800
14130
  }
13801
14131
  function classifyNetworkParty(requestOrigin, pageOrigin) {
13802
- const page = resolvePageOrigin(pageOrigin);
14132
+ const page = resolvePageOrigin2(pageOrigin);
13803
14133
  if (page && requestOrigin && requestOrigin === page) return "first_party";
13804
14134
  return "third_party";
13805
14135
  }
@@ -14016,6 +14346,16 @@
14016
14346
  }
14017
14347
 
14018
14348
  // src/client.ts
14349
+ var PLATFORM_JAVASCRIPT = "javascript";
14350
+ var EXTRA_LOCATION_KEYS = /* @__PURE__ */ new Set([
14351
+ "exception_class",
14352
+ "file",
14353
+ "line",
14354
+ "code",
14355
+ "filename",
14356
+ "lineno",
14357
+ "colno"
14358
+ ]);
14019
14359
  function networkExceptionClass(failure) {
14020
14360
  if (failure.failureKind === "http") return "HttpError";
14021
14361
  if (failure.failureKind === "timeout") return "TimeoutError";
@@ -14058,14 +14398,59 @@
14058
14398
  aborted: failure.aborted ?? false,
14059
14399
  ok: failure.ok ?? false
14060
14400
  },
14061
- // Top-level for server fingerprint compatibility.
14401
+ // Top-level for server fingerprint compatibility (status only —
14402
+ // exception type lives on first-class `exception.values[0].type`).
14062
14403
  status_code: statusCode,
14063
- exception_class: networkExceptionClass(failure),
14064
14404
  durationMs: failure.durationMs,
14065
14405
  aborted: failure.aborted ?? false,
14066
14406
  ok: failure.ok ?? false
14067
14407
  };
14068
14408
  }
14409
+ function networkExceptionData(failure, message) {
14410
+ return {
14411
+ values: [
14412
+ {
14413
+ type: networkExceptionClass(failure),
14414
+ value: message,
14415
+ mechanism: {
14416
+ type: "http",
14417
+ handled: true,
14418
+ synthetic: true
14419
+ }
14420
+ }
14421
+ ]
14422
+ };
14423
+ }
14424
+ function scrubLegacyExceptionExtra(extra) {
14425
+ if (!extra) return void 0;
14426
+ const out = {};
14427
+ for (const [key, value] of Object.entries(extra)) {
14428
+ if (EXTRA_LOCATION_KEYS.has(key)) continue;
14429
+ out[key] = value;
14430
+ }
14431
+ return Object.keys(out).length ? out : void 0;
14432
+ }
14433
+ function buildExceptionFromError(err, context, inAppOptions) {
14434
+ const mechanism = context?.mechanism ?? {
14435
+ type: "generic",
14436
+ handled: true
14437
+ };
14438
+ const stacktrace = applySourceLocation(
14439
+ parseStackTrace(err.stack, inAppOptions),
14440
+ context?.source,
14441
+ inAppOptions
14442
+ );
14443
+ return {
14444
+ values: [
14445
+ {
14446
+ type: err.name || "Error",
14447
+ value: err.message || err.name || "Error",
14448
+ mechanism,
14449
+ ...stacktrace ? { stacktrace } : {}
14450
+ }
14451
+ ]
14452
+ };
14453
+ }
14069
14454
  function mergeNetworkFailureContext(context, failure) {
14070
14455
  return {
14071
14456
  ...context,
@@ -14102,14 +14487,17 @@
14102
14487
  inlineStylesheet: options.inlineStylesheet ?? false,
14103
14488
  blockSelector: options.blockSelector ?? "",
14104
14489
  userId: options.userId,
14105
- tags: options.tags,
14490
+ tags: mergeTags(options.tags),
14106
14491
  disableDefaultIntegrations: options.disableDefaultIntegrations ?? false,
14107
14492
  captureFailedRequests: options.captureFailedRequests ?? true,
14108
14493
  captureNetworkErrors: options.captureNetworkErrors ?? true,
14109
14494
  networkErrorOrigins: options.networkErrorOrigins ?? [],
14110
14495
  includeNetworkUrlQuery: options.captureRequestQueryParameters ?? options.includeNetworkUrlQuery ?? false,
14111
14496
  failedRequestStatusCodes: options.failedRequestStatusCodes ?? [[500, 599]],
14112
- failedRequestIgnoreUrls: options.failedRequestIgnoreUrls ?? []
14497
+ failedRequestIgnoreUrls: options.failedRequestIgnoreUrls ?? [],
14498
+ inAppAllowUrls: options.inAppAllowUrls ?? [],
14499
+ inAppDenyUrls: options.inAppDenyUrls ?? [],
14500
+ inAppOrigins: options.inAppOrigins ?? []
14113
14501
  };
14114
14502
  }
14115
14503
  var RECENT_NETWORK_FAILURE_MS = 5e3;
@@ -14256,17 +14644,21 @@
14256
14644
  failureKind: "http",
14257
14645
  aborted: false
14258
14646
  };
14259
- void this.captureMessage(
14260
- `HTTP ${status}: ${method} ${url}`,
14261
- status >= 500 ? "error" : "warning",
14262
- {
14647
+ const message = `HTTP ${status}: ${method} ${url}`;
14648
+ void this.capture({
14649
+ message,
14650
+ level: status >= 500 ? "error" : "warning",
14651
+ title: networkExceptionClass(enriched),
14652
+ exception: networkExceptionData(enriched, message),
14653
+ platform: PLATFORM_JAVASCRIPT,
14654
+ context: {
14263
14655
  tags: {
14264
14656
  ...networkFailureTags(enriched),
14265
14657
  "http.status_code": String(status)
14266
14658
  },
14267
14659
  extra: networkFailureExtra(enriched)
14268
14660
  }
14269
- );
14661
+ });
14270
14662
  },
14271
14663
  onNetworkError: (meta) => {
14272
14664
  this.rememberNetworkFailure(meta, { promoted: true });
@@ -14274,14 +14666,18 @@
14274
14666
  const url = meta.url || "(unknown url)";
14275
14667
  const errLabel = meta.errorName && meta.errorMessage ? `${meta.errorName}: ${meta.errorMessage}` : meta.errorMessage || meta.errorName || "Failed to fetch";
14276
14668
  const prefix = meta.failureKind === "timeout" ? "Timeout error" : "Network error";
14277
- void this.captureMessage(
14278
- `${prefix}: ${method} ${url} \u2014 ${errLabel}`,
14279
- "error",
14280
- {
14669
+ const message = `${prefix}: ${method} ${url} \u2014 ${errLabel}`;
14670
+ void this.capture({
14671
+ message,
14672
+ level: "error",
14673
+ title: networkExceptionClass(meta),
14674
+ exception: networkExceptionData(meta, message),
14675
+ platform: PLATFORM_JAVASCRIPT,
14676
+ context: {
14281
14677
  tags: networkFailureTags(meta),
14282
14678
  extra: networkFailureExtra(meta)
14283
14679
  }
14284
- );
14680
+ });
14285
14681
  }
14286
14682
  }),
14287
14683
  installVisibilityResumeHook(() => this.onForegroundResume())
@@ -14318,7 +14714,7 @@
14318
14714
  if (this.capturing || this.ingestDisabled) return;
14319
14715
  const err = error instanceof Error ? error : new Error(typeof error === "string" ? error : "Unknown error");
14320
14716
  if (isAbortError(err)) return;
14321
- const filename = typeof context?.extra?.filename === "string" ? context.extra.filename : void 0;
14717
+ const filename = context?.source?.filename;
14322
14718
  if (isBrowserExtensionNoise({
14323
14719
  message: err.message,
14324
14720
  stack: err.stack,
@@ -14340,6 +14736,12 @@
14340
14736
  level: "error",
14341
14737
  title: err.name || "Error",
14342
14738
  stackTrace: err.stack,
14739
+ exception: buildExceptionFromError(
14740
+ err,
14741
+ mergedContext,
14742
+ this.inAppFrameOptions()
14743
+ ),
14744
+ platform: PLATFORM_JAVASCRIPT,
14343
14745
  context: mergedContext
14344
14746
  });
14345
14747
  } finally {
@@ -14355,6 +14757,13 @@
14355
14757
  context
14356
14758
  });
14357
14759
  }
14760
+ /**
14761
+ * Returns a scoped capture facade that merges [tags] into every event.
14762
+ * Nested `withTags` calls merge further (later keys win).
14763
+ */
14764
+ withTags(tags) {
14765
+ return createScopedTalaria(this, mergeTags(tags));
14766
+ }
14358
14767
  async flush(opts) {
14359
14768
  if (!this.options || !this.transport || this.closed) return;
14360
14769
  const keepalive = opts?.keepalive ?? false;
@@ -14519,13 +14928,17 @@
14519
14928
  }
14520
14929
  const queuedMs = Math.max(0, Date.now() - occurredAt.getTime());
14521
14930
  const tags = applyReplayCaptureTags(
14522
- {
14523
- ...this.browserContext ? browserContextTags(this.browserContext) : {},
14524
- ...this.options.tags ?? {},
14525
- ...args.context?.tags ?? {}
14526
- },
14931
+ mergeTags(
14932
+ this.browserContext ? browserContextTags(this.browserContext) : {},
14933
+ this.options.tags,
14934
+ args.context?.tags
14935
+ ),
14527
14936
  errorClipOutcome
14528
14937
  );
14938
+ warnSuspiciousTags(tags, this.options.environment);
14939
+ const scrubbedContextExtra = scrubLegacyExceptionExtra(
14940
+ args.context?.extra
14941
+ );
14529
14942
  const extra = mergeReplayCaptureExtra(
14530
14943
  {
14531
14944
  ...this.browserContext ? {
@@ -14547,7 +14960,7 @@
14547
14960
  // Time spent in capture() before ingest (mostly replay flush).
14548
14961
  ...queuedMs >= 50 ? { queuedMs } : {}
14549
14962
  },
14550
- ...args.context?.extra
14963
+ ...scrubbedContextExtra ?? {}
14551
14964
  },
14552
14965
  errorClipOutcome
14553
14966
  );
@@ -14559,6 +14972,8 @@
14559
14972
  eventType: levelToEventType(args.level),
14560
14973
  title: args.title ?? args.context?.title,
14561
14974
  stackTrace: args.stackTrace,
14975
+ exception: args.exception,
14976
+ platform: args.platform,
14562
14977
  release: this.options.release,
14563
14978
  userId: args.context?.userId ?? this.options.userId,
14564
14979
  sessionId: this.sessionId ?? void 0,
@@ -14808,6 +15223,23 @@
14808
15223
  this.resetToBufferMode();
14809
15224
  }
14810
15225
  }
15226
+ inAppFrameOptions() {
15227
+ const opts = this.options;
15228
+ let pageOrigin;
15229
+ try {
15230
+ pageOrigin = resolvePageOrigin(
15231
+ typeof window !== "undefined" ? window.location?.origin : void 0
15232
+ );
15233
+ } catch {
15234
+ pageOrigin = void 0;
15235
+ }
15236
+ return {
15237
+ pageOrigin,
15238
+ allowUrls: opts?.inAppAllowUrls,
15239
+ denyUrls: opts?.inAppDenyUrls,
15240
+ inAppOrigins: opts?.inAppOrigins
15241
+ };
15242
+ }
14811
15243
  pruneRecentNetworkFailures(now = Date.now()) {
14812
15244
  this.recentNetworkFailures = this.recentNetworkFailures.filter(
14813
15245
  (f) => now - f.at <= RECENT_NETWORK_FAILURE_MS
@@ -14882,7 +15314,8 @@
14882
15314
  return;
14883
15315
  }
14884
15316
  void this.captureException(error, {
14885
- extra: {
15317
+ mechanism: { type: "onerror", handled: false },
15318
+ source: {
14886
15319
  filename: event.filename,
14887
15320
  lineno: event.lineno,
14888
15321
  colno: event.colno
@@ -14904,7 +15337,9 @@
14904
15337
  })) {
14905
15338
  return;
14906
15339
  }
14907
- void this.captureException(reason);
15340
+ void this.captureException(reason, {
15341
+ mechanism: { type: "unhandledrejection", handled: false }
15342
+ });
14908
15343
  };
14909
15344
  window.addEventListener("error", onError);
14910
15345
  window.addEventListener("unhandledrejection", onRejection);
@@ -15166,6 +15601,23 @@
15166
15601
  }
15167
15602
  }
15168
15603
  };
15604
+ function createScopedTalaria(client2, scopeTags) {
15605
+ const mergeContext = (context) => ({
15606
+ ...context,
15607
+ tags: mergeTags(scopeTags, context?.tags)
15608
+ });
15609
+ return {
15610
+ captureException(error, context) {
15611
+ return client2.captureException(error, mergeContext(context));
15612
+ },
15613
+ captureMessage(message, level, context) {
15614
+ return client2.captureMessage(message, level, mergeContext(context));
15615
+ },
15616
+ withTags(tags) {
15617
+ return createScopedTalaria(client2, mergeTags(scopeTags, tags));
15618
+ }
15619
+ };
15620
+ }
15169
15621
 
15170
15622
  // src/index.ts
15171
15623
  var client = new TalariaClient();
@@ -15179,6 +15631,9 @@
15179
15631
  captureMessage(message, level, context) {
15180
15632
  return client.captureMessage(message, level, context);
15181
15633
  },
15634
+ withTags(tags) {
15635
+ return client.withTags(tags);
15636
+ },
15182
15637
  getReplayId() {
15183
15638
  return client.getReplayId();
15184
15639
  },