@genn-inc/cluebase-frontend-sdk 0.0.2 → 0.0.6

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.
Files changed (76) hide show
  1. package/README.md +21 -0
  2. package/dist/_generated/{identity-pii-policy.d.ts → identity-pii-policy-text-contains.d.ts} +1 -1
  3. package/dist/_generated/{identity-pii-policy.js → identity-pii-policy-text-contains.js} +1 -1
  4. package/dist/_generated/identity-pii-policy-whole-value.d.ts +37 -0
  5. package/dist/_generated/identity-pii-policy-whole-value.js +106 -0
  6. package/dist/_generated/otel-span-conversion.js +1 -9
  7. package/dist/context/action-context.js +27 -7
  8. package/dist/context/browser-storage.js +1 -2
  9. package/dist/context/environment.js +5 -3
  10. package/dist/context/identity.js +5 -9
  11. package/dist/context/organization.d.ts +1 -1
  12. package/dist/context/organization.js +6 -8
  13. package/dist/context/session.js +6 -8
  14. package/dist/context/tab.js +8 -12
  15. package/dist/context/trace.js +2 -1
  16. package/dist/exporter/batch.d.ts +3 -1
  17. package/dist/exporter/batch.js +6 -10
  18. package/dist/exporter/browser-outbox-records.d.ts +1 -1
  19. package/dist/exporter/browser-outbox-records.js +15 -6
  20. package/dist/exporter/browser-outbox.d.ts +5 -2
  21. package/dist/exporter/browser-outbox.js +48 -11
  22. package/dist/exporter/client.d.ts +2 -2
  23. package/dist/exporter/client.js +15 -30
  24. package/dist/exporter/delivery-response-contract.js +67 -17
  25. package/dist/exporter/delivery-response.d.ts +3 -1
  26. package/dist/exporter/delivery-response.js +31 -20
  27. package/dist/exporter/diagnostics.d.ts +1 -1
  28. package/dist/exporter/diagnostics.js +4 -1
  29. package/dist/exporter/event-id.js +1 -3
  30. package/dist/exporter/frontend-resource.js +5 -4
  31. package/dist/exporter/observation-source-event-exporter.d.ts +1 -0
  32. package/dist/exporter/observation-source-event-exporter.js +5 -2
  33. package/dist/exporter/path-template.js +3 -1
  34. package/dist/exporter/raw-event-to-source-signal.js +4 -2
  35. package/dist/exporter/sanitize.d.ts +3 -2
  36. package/dist/exporter/sanitize.js +4 -3
  37. package/dist/exporter/sdk-core-wasm.d.ts +5 -0
  38. package/dist/exporter/sdk-core-wasm.js +18 -0
  39. package/dist/exporter/source-event.d.ts +1 -0
  40. package/dist/exporter/span-to-source-signal.d.ts +1 -1
  41. package/dist/exporter/span-to-source-signal.js +122 -82
  42. package/dist/index.d.ts +5 -4
  43. package/dist/index.js +23 -11
  44. package/dist/instrumentation/action.js +9 -8
  45. package/dist/instrumentation/dom.js +13 -21
  46. package/dist/instrumentation/drag.js +0 -3
  47. package/dist/instrumentation/error.js +3 -1
  48. package/dist/instrumentation/form.js +5 -6
  49. package/dist/instrumentation/input.js +4 -8
  50. package/dist/instrumentation/location.js +3 -1
  51. package/dist/instrumentation/network-request.js +1 -1
  52. package/dist/instrumentation/network-span-attributes.js +2 -2
  53. package/dist/instrumentation/network.js +7 -3
  54. package/dist/instrumentation/performance.js +1 -2
  55. package/dist/internal/internal-log.js +2 -1
  56. package/dist/provider/_version.d.ts +1 -1
  57. package/dist/provider/_version.js +1 -1
  58. package/dist/provider/config.js +0 -1
  59. package/dist/provider/constants.d.ts +1 -1
  60. package/dist/provider/constants.js +0 -1
  61. package/dist/provider/sdk-error.d.ts +7 -0
  62. package/dist/provider/sdk-error.js +48 -0
  63. package/dist/provider/sdk-event-pipeline.d.ts +2 -1
  64. package/dist/provider/sdk-event-pipeline.js +6 -3
  65. package/dist/provider/sdk-input-normalization.js +2 -2
  66. package/dist/provider/sdk-otel-pipeline.js +5 -4
  67. package/dist/provider/sdk-runtime-surfaces.d.ts +15 -12
  68. package/dist/provider/sdk-runtime-surfaces.js +8 -7
  69. package/dist/provider/sdk.js +81 -12
  70. package/dist/provider/types.d.ts +6 -5
  71. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.d.ts +41 -0
  72. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm.js +267 -0
  73. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm +0 -0
  74. package/dist/wasm/pkg-web/cluebase_sdk_core_wasm_bg.wasm.d.ts +12 -0
  75. package/dist/wasm/pkg-web/package.json +15 -0
  76. package/package.json +10 -3
@@ -1,9 +1,9 @@
1
1
  import { buildLocalTextDescriptor } from "../exporter/local-minimization.js";
2
- import { extractFieldName, extractFieldType, getElementAriaLabel, getElementClassList, getElementLabel, getElementPlaceholder, getElementRole, getElementSectionHeading, isEditableElement, resolveClickDisplayTarget, resolveInteractionScopeDescriptor, resolveStableKeyDescriptor, } from "./dom.js";
2
+ import { fingerprintText } from "../exporter/text-fingerprint.js";
3
3
  import { buildPrimaryActionKey } from "./common.js";
4
+ import { extractFieldName, extractFieldType, getElementAriaLabel, getElementClassList, getElementLabel, getElementPlaceholder, getElementRole, getElementSectionHeading, isEditableElement, resolveClickDisplayTarget, resolveInteractionScopeDescriptor, resolveStableKeyDescriptor, } from "./dom.js";
4
5
  import { getCurrentPageSnapshot } from "./location.js";
5
6
  import { buildScreenActionNamingEvidence } from "./naming-evidence.js";
6
- import { fingerprintText } from "../exporter/text-fingerprint.js";
7
7
  const VALIDATION_REASON_KEYS = [
8
8
  "valueMissing",
9
9
  "typeMismatch",
@@ -57,9 +57,6 @@ export const startFormCapture = (context) => {
57
57
  if (!(target instanceof HTMLFormElement)) {
58
58
  return;
59
59
  }
60
- if (context.shouldIgnoreElement?.(target)) {
61
- return;
62
- }
63
60
  try {
64
61
  const formKey = target.id || target.getAttribute("name") || null;
65
62
  const interactionScope = resolveInteractionScopeDescriptor(target);
@@ -75,14 +72,16 @@ export const startFormCapture = (context) => {
75
72
  ? "validation_blocked"
76
73
  : "unknown";
77
74
  const resultSource = validationEvidence.invalidFieldCount > 0 ? "browser_validation" : null;
75
+ const pageSnapshot = getCurrentPageSnapshot();
78
76
  context.onEvent({
79
77
  type: "form_submitted",
80
78
  occurredAtMs: Date.now(),
81
79
  payload: {
82
80
  viewId: context.getViewId(),
81
+ screenKey: pageSnapshot.screenKey,
83
82
  formId: target.id || null,
84
83
  formKey,
85
- primaryActionKey: buildPrimaryActionKey(getCurrentPageSnapshot().screenKey, formKey ?? submitterStableKey?.stableKey ?? null),
84
+ primaryActionKey: buildPrimaryActionKey(pageSnapshot.screenKey, formKey ?? submitterStableKey?.stableKey ?? null),
86
85
  formName: target.getAttribute("name"),
87
86
  interactionScopeKind: interactionScope?.interactionScopeKind ?? null,
88
87
  interactionScopeKey: interactionScope?.interactionScopeKey ?? null,
@@ -1,6 +1,6 @@
1
1
  import { buildLocalTextDescriptor, buildLocalValueDescriptor, } from "../exporter/local-minimization.js";
2
- import { extractFieldName, extractFieldType, getElementAriaLabel, getElementLabel, getElementPlaceholder, getElementRole, getElementSectionHeading, getElementValue, resolveInteractionScopeDescriptor, resolveStableKeyDescriptor, } from "./dom.js";
3
2
  import { buildPrimaryActionKey } from "./common.js";
3
+ import { extractFieldName, extractFieldType, getElementAriaLabel, getElementLabel, getElementPlaceholder, getElementRole, getElementSectionHeading, getElementValue, resolveInteractionScopeDescriptor, resolveStableKeyDescriptor, } from "./dom.js";
4
4
  import { getCurrentPageSnapshot } from "./location.js";
5
5
  import { buildScreenActionNamingEvidence } from "./naming-evidence.js";
6
6
  const buildFileDescriptors = (input) => {
@@ -28,23 +28,22 @@ export const startInputCapture = (context) => {
28
28
  if (context.getConsent() === "denied") {
29
29
  return;
30
30
  }
31
- if (context.shouldIgnoreElement?.(target)) {
32
- return;
33
- }
34
31
  if (target instanceof HTMLInputElement && target.type === "password") {
35
32
  return;
36
33
  }
37
34
  try {
38
35
  const stableKey = resolveStableKeyDescriptor(target);
39
36
  const interactionScope = resolveInteractionScopeDescriptor(target);
37
+ const pageSnapshot = getCurrentPageSnapshot();
40
38
  const commonPayload = {
41
39
  viewId: context.getViewId(),
40
+ screenKey: pageSnapshot.screenKey,
42
41
  formId: stableKey.formKey,
43
42
  formKey: stableKey.formKey,
44
43
  fieldType: extractFieldType(target),
45
44
  elementTag: target.tagName.toLowerCase(),
46
45
  elementRole: getElementRole(target),
47
- primaryActionKey: buildPrimaryActionKey(getCurrentPageSnapshot().screenKey, stableKey.stableKey),
46
+ primaryActionKey: buildPrimaryActionKey(pageSnapshot.screenKey, stableKey.stableKey),
48
47
  stableKey: stableKey.stableKey,
49
48
  stableKeyQuality: stableKey.stableKeyQuality,
50
49
  interactionScopeKind: interactionScope?.interactionScopeKind ?? null,
@@ -138,9 +137,6 @@ export const startInputCapture = (context) => {
138
137
  if (context.getConsent() === "denied") {
139
138
  return;
140
139
  }
141
- if (context.shouldIgnoreElement?.(target)) {
142
- return;
143
- }
144
140
  dirtyControls.add(target);
145
141
  };
146
142
  const changeHandler = (event) => {
@@ -53,7 +53,9 @@ export const getPageSnapshotFromUrl = (href) => {
53
53
  }
54
54
  let path = null;
55
55
  try {
56
- path = href ? new URL(href, globalThis.location?.origin).pathname || "/" : null;
56
+ path = href
57
+ ? new URL(href, globalThis.location?.origin).pathname || "/"
58
+ : null;
57
59
  }
58
60
  catch {
59
61
  path = null;
@@ -1,9 +1,9 @@
1
1
  import { buildLocalQuerySummary, buildLocalStructuredSummary, } from "../exporter/local-minimization.js";
2
2
  import { buildParameterSnapshotBundle, } from "../exporter/parameter-snapshot.js";
3
- import { allowedValuePathsFor } from "../provider/privacy-policy-store.js";
4
3
  import { toPathTemplate } from "../exporter/path-template.js";
5
4
  import { maybeParseJson, sanitizeHeaders } from "../exporter/sanitize.js";
6
5
  import { buildSchemaEvidence, deriveOutcomeClass, extractErrorCodeCandidate, extractGraphqlEvidence, } from "../exporter/schema-evidence.js";
6
+ import { allowedValuePathsFor } from "../provider/privacy-policy-store.js";
7
7
  import { currentPageUrl, resolveUrlAgainstCurrentLocation, stripQueryFromUrl, } from "./common.js";
8
8
  const MAX_CAPTURED_RESPONSE_BODY_BYTES = 16 * 1024;
9
9
  export const headersToRecord = (headers) => {
@@ -1,10 +1,10 @@
1
1
  import { SpanStatusCode } from "@opentelemetry/api";
2
2
  import { buildLocalStructuredSummary } from "../exporter/local-minimization.js";
3
- import { cluebaseAuthoredMetricAttribute, cluebaseAuthoredPropertyAttribute, } from "./cluebase-authored-attributes.js";
3
+ import { buildParameterSnapshotBundle } from "../exporter/parameter-snapshot.js";
4
4
  import { sanitizeHeaders } from "../exporter/sanitize.js";
5
5
  import { FRONTEND_EVENT_CATEGORY, FRONTEND_EVENT_NAME, FRONTEND_EVENT_STATUS, } from "../provider/contracts.js";
6
- import { buildParameterSnapshotBundle } from "../exporter/parameter-snapshot.js";
7
6
  import { allowedValuePathsFor } from "../provider/privacy-policy-store.js";
7
+ import { cluebaseAuthoredMetricAttribute, cluebaseAuthoredPropertyAttribute, } from "./cluebase-authored-attributes.js";
8
8
  import { buildResponseShapeEvidence, } from "./network-request.js";
9
9
  const PRIVACY_POLICY_VERSION = 1;
10
10
  const setOptionalString = (span, key, value) => {
@@ -324,9 +324,12 @@ const failOpenRequestLifecycles = (failureType) => {
324
324
  }
325
325
  pendingRequestLifecycles.clear();
326
326
  };
327
- const trackFetchSpanEndWait = () => {
327
+ const trackFetchSpanEndWait = (capture) => {
328
328
  const wait = new Promise((resolve) => {
329
- setTimeout(resolve, FETCH_SPAN_END_SETTLE_MS);
329
+ setTimeout(() => {
330
+ capture.context.requestFlush?.();
331
+ resolve();
332
+ }, FETCH_SPAN_END_SETTLE_MS);
330
333
  });
331
334
  pendingFetchSpanEndWaits.add(wait);
332
335
  void wait.finally(() => pendingFetchSpanEndWaits.delete(wait));
@@ -400,7 +403,7 @@ const configureFetchInstrumentation = (capture) => {
400
403
  observationContext: capture.context.getObservationContext?.() ?? null,
401
404
  deniedKeys: capture.deniedKeys,
402
405
  });
403
- trackFetchSpanEndWait();
406
+ trackFetchSpanEndWait(capture);
404
407
  markRequestLifecycleTerminal(meta);
405
408
  capture.context.requestFlush?.();
406
409
  },
@@ -448,6 +451,7 @@ const configureXhrInstrumentation = (capture) => {
448
451
  observationContext: capture.context.getObservationContext?.() ?? null,
449
452
  deniedKeys: capture.deniedKeys,
450
453
  });
454
+ trackFetchSpanEndWait(capture);
451
455
  markRequestLifecycleTerminal(meta);
452
456
  capture.context.requestFlush?.();
453
457
  },
@@ -91,8 +91,7 @@ const observeEntryType = (observers, entryType, callback) => {
91
91
  observer.observe({ type: entryType, buffered: true });
92
92
  observers.push(observer);
93
93
  }
94
- catch {
95
- }
94
+ catch { }
96
95
  };
97
96
  const readPerformanceNavigation = () => {
98
97
  if (typeof performance === "undefined") {
@@ -26,7 +26,8 @@ export function logSwallowed(operation, _cause, context = {}) {
26
26
  const details = {};
27
27
  for (const [key, value] of Object.entries(context)) {
28
28
  if (SAFE_CONTEXT_KEYS.has(key) &&
29
- (value === null || typeof value === "boolean" ||
29
+ (value === null ||
30
+ typeof value === "boolean" ||
30
31
  (typeof value === "number" && Number.isFinite(value)) ||
31
32
  (typeof value === "string" && SAFE_TOKEN.test(value)))) {
32
33
  details[key] = value;
@@ -1 +1 @@
1
- export declare const SDK_VERSION: "0.0.2";
1
+ export declare const SDK_VERSION: "0.0.6";
@@ -1,3 +1,3 @@
1
1
  // This file is generated by scripts/generate-version-module.mjs.
2
2
  // Do NOT edit by hand. The source of truth is `package.json` `version`.
3
- export const SDK_VERSION = "0.0.2";
3
+ export const SDK_VERSION = "0.0.6";
@@ -104,7 +104,6 @@ export const resolveConfig = (options) => {
104
104
  localSetupCheckEndpoint: null,
105
105
  projectKey: options.projectKey?.trim() ?? "",
106
106
  producerId: DEFAULT_FRONTEND_SOURCE_IDENTIFIER,
107
- transportProfile: DEFAULT_CONFIG.transportProfile,
108
107
  autocapture: options.autocapture ?? DEFAULT_CONFIG.autocapture,
109
108
  captureNetwork: options.captureNetwork ?? DEFAULT_CONFIG.captureNetwork,
110
109
  captureErrors: options.captureErrors ?? DEFAULT_CONFIG.captureErrors,
@@ -1,5 +1,5 @@
1
- import type { CluebaseConsentState, ResolvedCluebaseConfig } from "./types.js";
2
1
  import { SDK_VERSION } from "./_version.js";
2
+ import type { CluebaseConsentState, ResolvedCluebaseConfig } from "./types.js";
3
3
  export { SDK_VERSION };
4
4
  export declare const SDK_NAME = "@genn-inc/cluebase-frontend-sdk";
5
5
  export declare const EVENT_SOURCE: "frontend_sdk";
@@ -44,7 +44,6 @@ export const DEFAULT_CONFIG = {
44
44
  localSetupCheckEndpoint: null,
45
45
  projectKey: "",
46
46
  producerId: DEFAULT_FRONTEND_SOURCE_IDENTIFIER,
47
- transportProfile: "standard",
48
47
  autocapture: true,
49
48
  captureNetwork: true,
50
49
  captureErrors: true,
@@ -0,0 +1,7 @@
1
+ export type SdkErrorDetails = {
2
+ error_name: string;
3
+ error_message: string;
4
+ error_stack?: string;
5
+ };
6
+ export declare const getSdkErrorDetails: (error: unknown) => SdkErrorDetails;
7
+ export declare const reportSdkError: (operation: string, error: unknown) => SdkErrorDetails;
@@ -0,0 +1,48 @@
1
+ const redactSensitiveText = (value) => value
2
+ .replace(/\bpk_[A-Za-z0-9_-]+\b/g, "[redacted-project-key]")
3
+ .replace(/\b(Bearer|Basic)\s+[A-Za-z0-9._~+/-]+=*/gi, "$1 [redacted]")
4
+ .replace(/(https?:\/\/[^\s?]+)\?[^\s]*/gi, "$1?[redacted]")
5
+ .slice(0, 500);
6
+ const readErrorField = (error, field) => {
7
+ try {
8
+ const value = error?.[field];
9
+ return typeof value === "string" ? value : undefined;
10
+ }
11
+ catch {
12
+ return undefined;
13
+ }
14
+ };
15
+ export const getSdkErrorDetails = (error) => {
16
+ let fallbackMessage;
17
+ try {
18
+ fallbackMessage = String(error);
19
+ }
20
+ catch {
21
+ fallbackMessage = "Unknown thrown value";
22
+ }
23
+ const stack = readErrorField(error, "stack");
24
+ return {
25
+ error_name: readErrorField(error, "name") || "UnknownError",
26
+ error_message: redactSensitiveText(readErrorField(error, "message") || fallbackMessage),
27
+ ...(stack
28
+ ? {
29
+ error_stack: stack
30
+ .split(/\r?\n/)
31
+ .slice(1, 9)
32
+ .map(redactSensitiveText)
33
+ .join("\n"),
34
+ }
35
+ : {}),
36
+ };
37
+ };
38
+ export const reportSdkError = (operation, error) => {
39
+ const details = getSdkErrorDetails(error);
40
+ try {
41
+ if (typeof console !== "undefined" && typeof console.error === "function") {
42
+ const stack = details.error_stack ? `\n${details.error_stack}` : "";
43
+ console.error(`[cluebase] ${operation} failed (${details.error_name}): ${details.error_message}${stack}`);
44
+ }
45
+ }
46
+ catch { }
47
+ return details;
48
+ };
@@ -1,9 +1,9 @@
1
- import { TraceManager } from "../context/trace.js";
2
1
  import type { EnvironmentManager } from "../context/environment.js";
3
2
  import type { IdentityManager } from "../context/identity.js";
4
3
  import type { OrganizationManager } from "../context/organization.js";
5
4
  import type { SessionManager } from "../context/session.js";
6
5
  import type { TabManager } from "../context/tab.js";
6
+ import { TraceManager } from "../context/trace.js";
7
7
  import type { BatchTransport } from "../exporter/batch.js";
8
8
  import type { InternalMetricsStore } from "../internal/metrics.js";
9
9
  import type { CluebaseConsentState, CluebaseContext, CluebaseInternalLogger, IngestUsageGovernorFeedback, RawCapturedEvent, ResolvedCluebaseConfig } from "./types.js";
@@ -11,6 +11,7 @@ export declare const OFFICIAL_CUSTOM_EVENT_NAME: {
11
11
  readonly identityIdentified: "identity_identified";
12
12
  readonly identityReset: "identity_reset";
13
13
  readonly organizationAssociated: "organization_associated";
14
+ readonly externalAccountLinked: "external_account_linked";
14
15
  readonly sdkInitialized: "sdk_initialized";
15
16
  };
16
17
  export type OfficialCustomEventProperties = Record<string, string | string[] | number>;
@@ -1,12 +1,12 @@
1
1
  import { TraceManager } from "../context/trace.js";
2
2
  import { generateViewId } from "../exporter/event-id.js";
3
- import { rawEventToSourceSignalEvent } from "../exporter/raw-event-to-source-signal.js";
4
3
  import { createFrontendResourceAttributes } from "../exporter/frontend-resource.js";
4
+ import { rawEventToSourceSignalEvent } from "../exporter/raw-event-to-source-signal.js";
5
5
  import { sanitizeObject, } from "../exporter/sanitize.js";
6
- import { DEFAULT_INGEST_USAGE_GOVERNOR_FEEDBACK, hasUsageGovernorFeedbackChanged, isCostCapabilityDisabled, normalizeIngestUsageGovernorFeedback, } from "./usage-governor.js";
7
6
  import { FRONTEND_EVENT_NAME } from "./contracts.js";
8
7
  import { shouldSampleSession } from "./sampling.js";
9
8
  import { stripQueryAndHashFromUrl, toStringOrNull, toSubjectProfile, } from "./sdk-input-normalization.js";
9
+ import { DEFAULT_INGEST_USAGE_GOVERNOR_FEEDBACK, hasUsageGovernorFeedbackChanged, isCostCapabilityDisabled, normalizeIngestUsageGovernorFeedback, } from "./usage-governor.js";
10
10
  const TRACE_ROOT_EVENTS = new Set([
11
11
  "page_view",
12
12
  "route_change",
@@ -23,6 +23,7 @@ export const OFFICIAL_CUSTOM_EVENT_NAME = {
23
23
  identityIdentified: "identity_identified",
24
24
  identityReset: "identity_reset",
25
25
  organizationAssociated: "organization_associated",
26
+ externalAccountLinked: "external_account_linked",
26
27
  sdkInitialized: "sdk_initialized",
27
28
  };
28
29
  const OFFICIAL_CUSTOM_EVENT_NAMES = new Set(Object.values(OFFICIAL_CUSTOM_EVENT_NAME));
@@ -458,7 +459,9 @@ export class ProviderEventPipeline {
458
459
  }
459
460
  function sanitizeContextTraits(traits, deniedKeys, excludedKeys = new Set(), summary, pathPrefix = "", maskIdentityPii = true, preserveExplicitTraits = false) {
460
461
  const sanitized = sanitizeObject(traits, deniedKeys, summary, pathPrefix, maskIdentityPii, preserveExplicitTraits);
461
- if (typeof sanitized !== "object" || sanitized === null || Array.isArray(sanitized)) {
462
+ if (typeof sanitized !== "object" ||
463
+ sanitized === null ||
464
+ Array.isArray(sanitized)) {
462
465
  return {};
463
466
  }
464
467
  return Object.fromEntries(Object.entries(sanitized).filter(([key]) => !excludedKeys.has(key)));
@@ -1,4 +1,4 @@
1
- import { detectIdentityPII, hashIdentityValue } from "../exporter/sanitize.js";
1
+ import { detectWholeValuePII, hashIdentityValue } from "../exporter/sanitize.js";
2
2
  const PUBLIC_CUSTOM_EVENT_NAME_PATTERN = /^[A-Za-z0-9_.:-]{1,128}$/;
3
3
  const SAFE_DATA_IMAGE_MIME_TYPES = new Set([
4
4
  "image/png",
@@ -80,7 +80,7 @@ const normalizeEmailTrait = (raw) => {
80
80
  return null;
81
81
  }
82
82
  const normalized = value.trim().toLowerCase();
83
- return detectIdentityPII(normalized) === "email" ? normalized : null;
83
+ return detectWholeValuePII(normalized) === "email" ? normalized : null;
84
84
  };
85
85
  const emailDomain = (email) => {
86
86
  if (email === null) {
@@ -3,8 +3,8 @@ import { resourceFromAttributes } from "@opentelemetry/resources";
3
3
  import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
4
4
  import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
5
5
  import { resolveBrowserTokenEndpoint, resolveCanonicalIngestEndpoint, } from "../exporter/client.js";
6
- import { ObservationSourceEventExporter } from "../exporter/observation-source-event-exporter.js";
7
6
  import { createFrontendResourceAttributes } from "../exporter/frontend-resource.js";
7
+ import { ObservationSourceEventExporter } from "../exporter/observation-source-event-exporter.js";
8
8
  import { createCluebaseNetworkPropagator } from "../instrumentation/network.js";
9
9
  import { getSessionCaptureEligibility } from "./sdk-event-pipeline.js";
10
10
  const globalSnapshots = new WeakMap();
@@ -88,7 +88,9 @@ export const createCluebaseOtelPipeline = ({ resolved, getTransport, getContext,
88
88
  propagator: createCluebaseNetworkPropagator(),
89
89
  });
90
90
  globalSnapshots.set(provider, {
91
- installedTracer: getTracerDelegate(trace.getTracerProvider()) === provider ? provider : null,
91
+ installedTracer: getTracerDelegate(trace.getTracerProvider()) === provider
92
+ ? provider
93
+ : null,
92
94
  installedContextManager: isNoopContextManager(contextBeforeRegister)
93
95
  ? readContextManager()
94
96
  : null,
@@ -162,8 +164,7 @@ export const forceFlushCluebaseOtelProvider = async (provider, signal) => {
162
164
  try {
163
165
  await awaitWithAbort(provider.forceFlush(), signal);
164
166
  }
165
- catch {
166
- }
167
+ catch { }
167
168
  };
168
169
  const awaitWithAbort = async (promise, signal) => {
169
170
  if (!signal)
@@ -1,22 +1,26 @@
1
1
  import { TraceManager } from "../context/trace.js";
2
- import { type IngestClient } from "../exporter/client.js";
3
2
  import type { BatchTransport } from "../exporter/batch.js";
3
+ import { type IngestClient } from "../exporter/client.js";
4
4
  import type { InternalMetricsStore } from "../internal/metrics.js";
5
- import type { CluebaseOtelProvider } from "./sdk-otel-pipeline.js";
5
+ import { type CluebaseOtelProvider } from "./sdk-otel-pipeline.js";
6
6
  import type { CaptureModuleContext, CluebaseConsentState, CluebaseInternalLogger, RawCapturedEvent, ResolvedCluebaseConfig } from "./types.js";
7
+ type RuntimeSurfacesObservationContext = {
8
+ anonymousId: string | null;
9
+ userId: string | null;
10
+ organizationId?: string | null;
11
+ sessionId: string | null;
12
+ tabId: string | null;
13
+ };
14
+ type RuntimeSurfacesEventPipeline = {
15
+ getViewId: () => string | null;
16
+ getObservationContext: () => RuntimeSurfacesObservationContext;
17
+ };
7
18
  type ProviderRuntimeSurfacesOptions = {
8
19
  internalMetrics: InternalMetricsStore;
9
20
  logger: CluebaseInternalLogger;
10
21
  enqueueRawEvent: (event: RawCapturedEvent) => void;
11
- getViewId: () => string | null;
22
+ eventPipeline: RuntimeSurfacesEventPipeline;
12
23
  getConsent: () => CluebaseConsentState;
13
- getObservationContext: () => {
14
- anonymousId: string | null;
15
- userId: string | null;
16
- organizationId?: string | null;
17
- sessionId: string | null;
18
- tabId: string | null;
19
- };
20
24
  getTraceManager: () => TraceManager | null;
21
25
  getTransport: () => BatchTransport | null;
22
26
  getTracerProvider: () => CluebaseOtelProvider | null;
@@ -25,9 +29,8 @@ export declare class ProviderRuntimeSurfaces {
25
29
  private readonly internalMetrics;
26
30
  private readonly logger;
27
31
  private readonly enqueueRawEvent;
28
- private readonly getViewId;
32
+ private readonly eventPipeline;
29
33
  private readonly getConsent;
30
- private readonly getObservationContext;
31
34
  private readonly getTraceManager;
32
35
  private readonly getTransport;
33
36
  private readonly getTracerProvider;
@@ -9,6 +9,7 @@ import { startNavigationCapture } from "../instrumentation/navigation.js";
9
9
  import { startNetworkCapture } from "../instrumentation/network.js";
10
10
  import { startPageCapture } from "../instrumentation/page.js";
11
11
  import { startPerformanceCapture } from "../instrumentation/performance.js";
12
+ import { forceFlushCluebaseOtelProvider, } from "./sdk-otel-pipeline.js";
12
13
  const FLUSH_DEBOUNCE_MS = 200;
13
14
  export class ProviderRuntimeSurfaces {
14
15
  constructor(options) {
@@ -19,9 +20,8 @@ export class ProviderRuntimeSurfaces {
19
20
  this.internalMetrics = options.internalMetrics;
20
21
  this.logger = options.logger;
21
22
  this.enqueueRawEvent = options.enqueueRawEvent;
22
- this.getViewId = options.getViewId;
23
+ this.eventPipeline = options.eventPipeline;
23
24
  this.getConsent = options.getConsent;
24
- this.getObservationContext = options.getObservationContext;
25
25
  this.getTraceManager = options.getTraceManager;
26
26
  this.getTransport = options.getTransport;
27
27
  this.getTracerProvider = options.getTracerProvider;
@@ -38,10 +38,9 @@ export class ProviderRuntimeSurfaces {
38
38
  error_code: "capture_module_error",
39
39
  });
40
40
  },
41
- getViewId: () => this.getViewId(),
41
+ getViewId: () => this.eventPipeline.getViewId(),
42
42
  getConsent: () => this.getConsent(),
43
- getObservationContext: () => this.getObservationContext(),
44
- shouldIgnoreElement: () => false,
43
+ getObservationContext: () => this.eventPipeline.getObservationContext(),
45
44
  startInteraction: (input) => {
46
45
  return (this.getTraceManager()?.startInteraction(input) ??
47
46
  input.interactionId ??
@@ -56,6 +55,7 @@ export class ProviderRuntimeSurfaces {
56
55
  return;
57
56
  this.flushDebounceTimer = setTimeout(() => {
58
57
  this.flushDebounceTimer = null;
58
+ void forceFlushCluebaseOtelProvider(this.getTracerProvider());
59
59
  const transport = this.getTransport();
60
60
  if (!transport)
61
61
  return;
@@ -177,12 +177,14 @@ export class ProviderRuntimeSurfaces {
177
177
  }
178
178
  handled = true;
179
179
  onUnloadSessionEnd();
180
+ void forceFlushCluebaseOtelProvider(this.getTracerProvider());
180
181
  this.getTransport()?.flushOnUnload();
181
182
  };
182
183
  const visibilityHandler = () => {
183
184
  if (document.visibilityState !== "hidden") {
184
185
  return;
185
186
  }
187
+ void forceFlushCluebaseOtelProvider(this.getTracerProvider());
186
188
  this.getTransport()?.flushOnUnload();
187
189
  };
188
190
  window.addEventListener("pagehide", handler, { capture: true });
@@ -210,8 +212,7 @@ export class ProviderRuntimeSurfaces {
210
212
  try {
211
213
  dispose();
212
214
  }
213
- catch {
214
- }
215
+ catch { }
215
216
  }
216
217
  this.unloadHandlers = [];
217
218
  }