UNPKG

@dash0/sdk-web

Version:

Dash0's Web SDK to collect telemetry from end-users' web browsers

1 lines 172 kB
{"version":3,"file":"dash0.umd.cjs","sources":["modules/utils/fn.js","modules/utils/debug.js","modules/utils/obj.js","modules/utils/globals.js","modules/utils/id.js","modules/utils/listeners.js","modules/utils/local-storage.js","modules/utils/time.js","modules/utils/timers.js","modules/utils/performance.js","modules/utils/constants.js","modules/utils/math.js","modules/utils/url.js","modules/utils/origin.js","modules/utils/wrap.js","modules/vars.js","modules/semantic-conventions.js","modules/utils/session-id.js","modules/api/session.js","../node_modules/.pnpm/web-vitals@5.0.3/node_modules/web-vitals/dist/web-vitals.js","modules/utils/on-last-chance.js","modules/transport/batcher.js","modules/transport/fetch.js","modules/transport/index.js","modules/utils/rate-limit.js","modules/utils/otel/attributes.js","modules/utils/otel/trace-context.js","modules/utils/trace-id.js","modules/utils/crc32.js","modules/utils/span-id.js","modules/utils/otel/span.js","modules/attributes/url.js","modules/utils/session-storage.js","modules/utils/tab-id.js","modules/attributes/common.js","modules/instrumentations/web-vitals.js","modules/utils/ignore-rules.js","modules/instrumentations/errors/unhandled-error.js","modules/instrumentations/errors/unhandled-promise-rejection.js","modules/instrumentations/errors/async-function-wrapping.js","modules/instrumentations/errors/event-handlers.js","modules/instrumentations/errors/timers.js","modules/instrumentations/errors/index.js","modules/instrumentations/http/utils.js","modules/instrumentations/http/fetch.js","modules/utils/otel/http.js","modules/utils/otel/error.js","modules/instrumentations/navigation/event.js","modules/instrumentations/navigation/page-load.js","modules/instrumentations/navigation/page-transition.js","modules/instrumentations/navigation/index.js","../node_modules/.pnpm/ts-deepmerge@7.0.3/node_modules/ts-deepmerge/esm/index.js","modules/api/init.js","modules/utils/pick.js","modules/api/attributes.js","modules/api/debug.js","modules/api/identify.js","modules/entrypoint/npm-package.js","modules/api/report-error.js","modules/api/events.js"],"sourcesContent":["export function noop() {\n // This function is intentionally empty.\n}\nexport function identity(a) {\n return a;\n}\n","import { noop } from \"./fn\";\nconst logLevels = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\nlet activeLogLevel = logLevels.warn;\n/**\n * Changes the logging verbosity of Dash0's web SDK. By default, only warnings and errors are logged.\n */\nexport function setActiveLogLevel(level) {\n activeLogLevel = logLevels[level] ?? logLevels.warn;\n}\nexport const info = createLogger(\"info\");\nexport const warn = createLogger(\"warn\");\nexport const error = createLogger(\"error\");\nexport const debug = createLogger(\"debug\");\nfunction createLogger(logLevel) {\n if (typeof console !== \"undefined\" && console[logLevel] && typeof console[logLevel].apply === \"function\") {\n const numericLogLevel = logLevels[logLevel];\n return function () {\n if (numericLogLevel >= activeLogLevel) {\n console[logLevel].apply(console, arguments);\n }\n };\n }\n return noop;\n}\n","const globalHasOwnProperty = Object.prototype.hasOwnProperty;\n/**\n * protection against hasOwnProperty overrides.\n */\nexport function hasOwnProperty(obj, key) {\n return globalHasOwnProperty.call(obj, key);\n}\nexport function hasKey(obj, key) {\n return key in obj;\n}\n","// aliasing globals for improved minification\n// Avoid blowing up in an ssr context. It is important to check via typeof here because window might not even be declared when imported in ssr.\nexport const win = typeof window !== \"undefined\" ? window : undefined;\nexport const doc = win?.document;\nexport const nav = win?.navigator;\nexport const loc = typeof location !== \"undefined\" ? location : undefined;\nexport const perf = win?.performance || win?.webkitPerformance || win?.msPerformance || win?.mozPerformance;\nexport const encodeURIComponent = win?.encodeURIComponent;\nexport const fetch = win?.fetch;\nexport const localStorage = (function () {\n try {\n return win?.localStorage ?? null;\n }\n catch {\n // localStorage access is not permitted in certain security modes, e.g.\n // when cookies are completely disabled in web browsers.\n return null;\n }\n})();\nexport const sessionStorage = (function () {\n try {\n return win?.sessionStorage ?? null;\n }\n catch {\n // sessionStorage access is not permitted in certain security modes, e.g.\n // when cookies are completely disabled in web browsers.\n return null;\n }\n})();\n/**\n * Exposed via this module to enable testing.\n */\nexport function sendBeacon(url, data) {\n return nav?.sendBeacon(url, data) ?? false;\n}\n/* eslint-enable no-restricted-globals */\n","export const SPAN_ID_BYTES = 8;\nexport const TRACE_ID_BYTES = 16;\nexport const PAGE_LOAD_ID_BYTES = TRACE_ID_BYTES;\nexport const SESSION_ID_BYTES = SPAN_ID_BYTES;\nexport const TAB_ID_BYTES = SPAN_ID_BYTES;\nexport const WEB_EVENT_ID_BYTES = SPAN_ID_BYTES;\nconst SHARED_CHAR_CODES_ARRAY = Array(32);\nexport function generateUniqueId(byteCount) {\n for (let i = 0; i < byteCount * 2; i++) {\n SHARED_CHAR_CODES_ARRAY[i] = Math.floor(Math.random() * 16) + 48;\n // valid hex characters in the range 48-57 and 97-102\n if (SHARED_CHAR_CODES_ARRAY[i] >= 58) {\n SHARED_CHAR_CODES_ARRAY[i] += 39;\n }\n }\n return String.fromCharCode.apply(null, SHARED_CHAR_CODES_ARRAY.slice(0, byteCount * 2));\n}\n","// aliasing the global function for improved minification and\n// protection against hasOwnProperty overrides.\nexport function addEventListener(target, eventType, callback) {\n if (target.addEventListener) {\n target.addEventListener(eventType, callback, false);\n }\n else if (target.attachEvent) {\n target.attachEvent(\"on\" + eventType, callback);\n }\n}\nexport function removeEventListener(target, eventType, callback) {\n if (target.removeEventListener) {\n target.removeEventListener(eventType, callback, false);\n }\n else if (target.detachEvent) {\n target.detachEvent(\"on\" + eventType, callback);\n }\n}\n","// localStorage API re-exposed to allow testing.\nimport { localStorage } from \"./globals\";\nexport const isSupported = localStorage != null && typeof localStorage.getItem === \"function\" && typeof localStorage.setItem === \"function\";\nexport function getItem(k) {\n if (isSupported && localStorage) {\n return localStorage.getItem(k);\n }\n return null;\n}\nexport function setItem(k, v) {\n if (isSupported && localStorage) {\n localStorage.setItem(k, v);\n }\n}\nexport function removeItem(k) {\n if (isSupported && localStorage) {\n localStorage.removeItem(k);\n }\n}\n","import { perf } from \"./globals\";\nexport function now() {\n return new Date().getTime();\n}\nexport function nowNanos() {\n const timeOrigin = getTimeOrigin();\n if (timeOrigin) {\n return String((perf.now() + timeOrigin) * 1000000);\n }\n return toNanosTs(new Date());\n}\nexport function toNanosTs(time) {\n if (typeof time === \"object\") {\n return toNanosTs(time.getTime());\n }\n // We don't multiply, because we want to keep number precision\n return String(time) + \"000000\";\n}\nexport function getTimeOrigin() {\n let timeOrigin = perf?.timeOrigin;\n if (typeof timeOrigin !== \"number\") {\n timeOrigin = perf?.timing?.fetchStart;\n }\n return timeOrigin;\n}\nexport function domHRTimestampToNanos(ts) {\n return String(Math.round((ts + getTimeOrigin()) * 1000000));\n}\n","import { warn, debug } from \"./debug\";\nimport { win } from \"./globals\";\n// This module contains wrappers around the standard timer API. These wrappers can be used to\n// ensure that execution of timers happens outside of any Angular specific zones. This in turn\n// means that this script will never disturb Angular's stabilization phase.\n// https://angular.io/api/core/ApplicationRef#isStable\n// Please note that it may sometimes be necessary to deliberately execute code inside of\n// Angular's Zones. Always take care to make a deliberate decision when to use and when not to\n// use these wrappers.\n// We take a copy of all globals to ensure that no other script will change them all of a sudden.\n// This ensures that when we register a timeout/interval on one global, that we will be able to\n// de-register it again in all cases.\nconst globals = {\n setTimeout: win?.setTimeout,\n clearTimeout: win?.clearTimeout,\n setInterval: win?.setInterval,\n clearInterval: win?.clearInterval,\n};\n// If the globals don't exist at execution time of this file, then we know that the globals stored\n// above are not wrapped by Zone.js. This in turn can mean better performance for Angular users.\nexport const isRunningZoneJs = win != null && win[\"Zone\"] != null && win[\"Zone\"][\"root\"] != null && typeof win[\"Zone\"][\"root\"][\"run\"] === \"function\";\nif (isRunningZoneJs) {\n debug(\"Discovered Zone.js globals. Will attempt to register all timers inside the root Zone.\");\n}\nexport function setTimeout(..._) {\n return executeGlobally.apply(\"setTimeout\", arguments);\n}\nexport function clearTimeout(..._) {\n return executeGlobally.apply(\"clearTimeout\", arguments);\n}\nexport function setInterval(..._) {\n return executeGlobally.apply(\"setInterval\", arguments);\n}\nexport function clearInterval(..._) {\n return executeGlobally.apply(\"clearInterval\", arguments);\n}\nfunction executeGlobally() {\n // We don't want to incur a performance penalty for all users just because some\n // users are relying on zone.js. This API looks quite ridiculous, but it\n // allows for concise and efficient code, e.g. arguments does not need to be\n // translated into an array.\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const globalFunctionName = this;\n if (isRunningZoneJs) {\n try {\n // Incurr a performance overhead for Zone.js users that we just cannot avoid:\n // Copy the arguments passed in here so that we can use them inside the root\n // zone.\n const args = Array.prototype.slice.apply(arguments);\n // @ts-expect-error necessary Zone.js types not added\n return win[\"Zone\"][\"root\"][\"run\"](globals[globalFunctionName], win, args);\n }\n catch (e) {\n warn(\"Failed to execute %s inside of zone (via Zone.js). Falling back to execution inside currently \" +\n \"active zone.\", globalFunctionName, e);\n // failure – maybe zone js not properly initialized? Fall back to execution\n // outside of Zone.js as a last resort (outside of try/catch and if)\n }\n }\n // Note: Explicitly passing win as 'this' even though we are getting the function from 'globals'\n return globals[globalFunctionName]?.apply(win, arguments);\n}\n","import { doc, perf, win } from \"./globals\";\nimport { now } from \"./time\";\nimport { noop } from \"./fn\";\nimport { setTimeout } from \"./timers\";\nimport { addEventListener, removeEventListener } from \"./listeners\";\nconst TEN_MINUTES_IN_MILLIS = 1000 * 60 * 10;\nconst ONE_DAY_IN_MILLIS = 1000 * 60 * 60 * 24;\nconst OBSERVER_WAIT_TIME_MS = 300;\nexport const isResourceTimingAvailable = !!(perf && perf.getEntriesByType);\nexport const isPerformanceObserverAvailable = perf && typeof win[\"PerformanceObserver\"] === \"function\" && typeof perf[\"now\"] === \"function\";\nexport const PerformanceTimingNames = Object.freeze({\n CONNECT_END: \"connectEnd\",\n CONNECT_START: \"connectStart\",\n DECODED_BODY_SIZE: \"decodedBodySize\",\n DOM_COMPLETE: \"domComplete\",\n DOM_CONTENT_LOADED_EVENT_END: \"domContentLoadedEventEnd\",\n DOM_CONTENT_LOADED_EVENT_START: \"domContentLoadedEventStart\",\n DOM_INTERACTIVE: \"domInteractive\",\n DOMAIN_LOOKUP_END: \"domainLookupEnd\",\n DOMAIN_LOOKUP_START: \"domainLookupStart\",\n ENCODED_BODY_SIZE: \"encodedBodySize\",\n FETCH_START: \"fetchStart\",\n LOAD_EVENT_END: \"loadEventEnd\",\n LOAD_EVENT_START: \"loadEventStart\",\n NAVIGATION_START: \"navigationStart\",\n REDIRECT_END: \"redirectEnd\",\n REDIRECT_START: \"redirectStart\",\n REQUEST_START: \"requestStart\",\n RESPONSE_END: \"responseEnd\",\n RESPONSE_START: \"responseStart\",\n SECURE_CONNECTION_START: \"secureConnectionStart\",\n START_TIME: \"startTime\",\n UNLOAD_EVENT_END: \"unloadEventEnd\",\n UNLOAD_EVENT_START: \"unloadEventStart\",\n});\nconst usedResources = new WeakSet();\nexport function observeResourcePerformance(opts) {\n if (!isPerformanceObserverAvailable)\n return observeWithoutPerformanceObserverSupport(opts.onEnd);\n // Used to calculate the duration when no resource was found.\n let startTime;\n let endTime;\n const resources = [];\n // Global resources that will need to be disposed\n let observer;\n let fallbackNoResourceFoundTimerHandle;\n let fallbackEndNeverCalledTimerHandle;\n return {\n start: onStart,\n end: onEnd,\n cancel: disposeGlobalResources,\n };\n function onStart() {\n startTime = perf.now();\n try {\n const PerformanceObserver = win?.PerformanceObserver;\n if (PerformanceObserver) {\n observer = new PerformanceObserver(onResourceFound);\n observer?.observe({ type: \"resource\" });\n }\n }\n catch (_e) {\n // Some browsers may not support the passed entryTypes and decide to throw an error.\n // This would then result in an error with a message like:\n //\n // entryTypes only contained unsupported types\n //\n // Swallow and ignore the error. Treat it like unavailable performance observer data.\n }\n fallbackEndNeverCalledTimerHandle = setTimeout(disposeGlobalResources, TEN_MINUTES_IN_MILLIS);\n }\n function onEnd() {\n endTime = perf.now();\n cancelFallbackEndNeverCalledTimer();\n if (!isWaitingAcceptable()) {\n return end();\n }\n setTimeout(() => end(), Math.min(OBSERVER_WAIT_TIME_MS, opts.maxWaitForResourceMillis));\n addEventListener(doc, \"visibilitychange\", onVisibilityChanged);\n fallbackNoResourceFoundTimerHandle = setTimeout(end, opts.maxWaitForResourceMillis);\n }\n function end() {\n disposeGlobalResources();\n const resource = findBestMatchingResource();\n // In some old web browsers, e.g. Chrome 31, the value provided as the duration\n // can be very wrong. We have seen cases where this value is measured in years.\n // If this does seem be the case, then we will ignore the duration property and\n // instead prefer our approximation.\n if (resource?.duration && resource.duration < ONE_DAY_IN_MILLIS) {\n opts.onEnd({ resource, duration: resource.duration });\n }\n else {\n opts.onEnd({ resource, duration: endTime - startTime });\n }\n }\n function onResourceFound(list) {\n list\n .getEntriesByType(\"resource\")\n .filter((e) => {\n // This polymorphism is not properly represented in the api types. The cast is safe since we're only accessing the resource timings.\n const entry = e;\n return entry.startTime >= startTime && opts.resourceMatcher(entry);\n })\n .forEach((entry) => resources.push(entry));\n }\n function onVisibilityChanged() {\n if (!isWaitingAcceptable())\n end();\n }\n function disposeGlobalResources() {\n disconnectResourceObserver();\n cancelFallbackNoResourceFoundTimer();\n cancelFallbackEndNeverCalledTimer();\n stopVisibilityObservation();\n }\n function disconnectResourceObserver() {\n if (observer) {\n try {\n observer?.disconnect();\n }\n catch (_e) {\n // Observer disconnect may throw when connect attempt wasn't successful. Ignore this.\n }\n observer = undefined;\n }\n }\n function cancelFallbackNoResourceFoundTimer() {\n if (fallbackNoResourceFoundTimerHandle) {\n clearTimeout(fallbackNoResourceFoundTimerHandle);\n fallbackNoResourceFoundTimerHandle = undefined;\n }\n }\n function cancelFallbackEndNeverCalledTimer() {\n if (fallbackEndNeverCalledTimerHandle) {\n clearTimeout(fallbackEndNeverCalledTimerHandle);\n fallbackEndNeverCalledTimerHandle = undefined;\n }\n }\n function stopVisibilityObservation() {\n if (!doc)\n return;\n removeEventListener(doc, \"visibilitychange\", onVisibilityChanged);\n }\n function findBestMatchingResource() {\n if (!resources.length)\n return undefined;\n let bestMatch;\n const matchingResources = resources.filter((res) => res.responseEnd <= endTime + opts.maxToleranceForResourceTimingsMillis && !usedResources.has(res));\n if (!matchingResources.length) {\n return undefined;\n }\n if (matchingResources.length === 1) {\n bestMatch = matchingResources[0];\n }\n let bestScore;\n if (!bestMatch) {\n for (const res of matchingResources) {\n const score = Math.abs(endTime - startTime - res.duration) + Math.abs(res.responseEnd - endTime);\n if (bestScore === undefined || score < bestScore) {\n bestScore = score;\n bestMatch = res;\n }\n }\n }\n if (!bestMatch)\n return;\n usedResources.add(bestMatch);\n return bestMatch;\n }\n}\n// We may only wait for resource data to arrive as long as the document is visible or in the process\n// of becoming visible. In all other cases we might lose data when waiting, e.g. when the document\n// is in the process of being disposed.\nfunction isWaitingAcceptable() {\n return doc?.visibilityState === \"visible\" || doc?.visibilityState === \"prerender\";\n}\nfunction observeWithoutPerformanceObserverSupport(onEnd) {\n let start = 0;\n return {\n start: () => {\n start = now();\n },\n end: () => onEnd({ duration: now() - start }),\n cancel: noop,\n };\n}\n","export const NO_VALUE_FALLBACK = \"undefined\";\nexport const INIT_MESSAGE = \"Initializing Dash0 Web SDK\";\n","export function roundToTwoDecimals(n) {\n return Math.round(n * 100) / 100;\n}\n","import { doc, loc } from \"./globals\";\n/**\n * Parses url using URL constructor. Supports URL objects as passthrough input to simplify implementations\n * May throw if parsing fails\n * @param url\n */\nexport function parseUrl(url) {\n if (typeof url !== \"string\")\n return url;\n return new URL(url, doc?.baseURI ?? loc?.href);\n}\n","import { parseUrl } from \"./url\";\n/** Returns the origin if present (if in browser context). */\nfunction getOrigin() {\n return typeof location !== \"undefined\" ? location.origin : undefined;\n}\nexport function isSameOrigin(url) {\n try {\n const parsedUrl = parseUrl(url);\n return parsedUrl.origin === getOrigin();\n }\n catch (_e) {\n return false;\n }\n}\n","import { debug } from \"./debug\";\nconst INSTRUMENTED_BY_DASH0_SYMBOL = Symbol.for(\"INSTRUMENTED_BY_DASH0\");\nfunction isAlreadyInstrumented(objOrFunction) {\n // @ts-expect-error -- typescript does not know about this hidden marker and we're not going to tell it 🤫\n return objOrFunction[INSTRUMENTED_BY_DASH0_SYMBOL] === true;\n}\nfunction markAsInstrumented(objOrFunction) {\n // @ts-expect-error -- typescript does not know about this hidden marker and we're not going to tell it 🤫\n objOrFunction[INSTRUMENTED_BY_DASH0_SYMBOL] = true;\n}\nexport function wrap(module, target, wrapper) {\n const original = module[target];\n if (!original) {\n debug(`${String(target)} is not defined, unable to instrument`);\n return;\n }\n if (isAlreadyInstrumented(original)) {\n debug(`${String(target)} has already been instrumented, skipping`);\n }\n markAsInstrumented(original);\n module[target] = wrapper(original);\n}\n","import { identity } from \"./utils\";\nexport const vars = {\n endpoints: [],\n resource: {\n attributes: [],\n },\n scope: {\n name: \"dash0-web-sdk\",\n version: __sdkVersion,\n attributes: [],\n },\n signalAttributes: [],\n ignoreUrls: [],\n ignoreErrorMessages: [],\n wrapEventHandlers: true,\n wrapTimers: true,\n propagateTraceHeadersCorsURLs: [],\n maxWaitForResourceTimingsMillis: 10000,\n maxToleranceForResourceTimingsMillis: 50,\n headersToCapture: [],\n urlAttributeScrubber: identity,\n pageViewInstrumentation: {\n trackVirtualPageViews: true,\n includeParts: [],\n },\n};\n","// Resource Attribute Keys\nexport const SERVICE_NAME = \"service.name\";\nexport const SERVICE_VERSION = \"service.version\";\nexport const DEPLOYMENT_ENVIRONMENT_NAME = \"deployment.environment.name\";\nexport const DEPLOYMENT_NAME = \"deployment.name\";\nexport const DEPLOYMENT_ID = \"deployment.id\";\n// Misc Signal Attribute Keys\nexport const EVENT_NAME = \"event.name\";\nexport const WEB_EVENT_TITLE = \"dash0.web.event.title\";\nexport const WEB_EVENT_ID = \"dash0.web.event.id\";\nexport const PAGE_LOAD_ID = \"page.load.id\";\nexport const SESSION_ID = \"session.id\";\nexport const USER_AGENT = \"user_agent.original\";\nexport const BROWSER_TAB_ID = \"browser.tab.id\";\nexport const WINDOW_WIDTH = \"browser.window.width\";\nexport const WINDOW_HEIGHT = \"browser.window.height\";\nexport const NETWORK_CONNECTION_TYPE = \"network.connection.subtype\";\nexport const EXCEPTION_COMPONENT_STACK = \"exception.component_stack\";\n// User Attribute Keys\nexport const USER_ID = \"user.id\";\nexport const USER_NAME = \"user.name\";\nexport const USER_FULL_NAME = \"user.full_name\";\nexport const USER_EMAIL = \"user.email\";\nexport const USER_HASH = \"user.hash\";\nexport const USER_ROLES = \"user.roles\";\n// Exception Attribute Keys\nexport const EXCEPTION_MESSAGE = \"exception.message\";\nexport const EXCEPTION_TYPE = \"exception.type\";\nexport const EXCEPTION_STACKTRACE = \"exception.stacktrace\";\n// Error Attribute Keys\nexport const ERROR_TYPE = \"error.type\";\n// URL Attribute Keys\nexport const PAGE_URL_ATTR_PREFIX = \"page\";\nexport const URL_DOMAIN = \"url.domain\";\nexport const URL_FRAGMENT = \"url.fragment\";\nexport const URL_FULL = \"url.full\";\nexport const URL_PATH = \"url.path\";\nexport const URL_QUERY = \"url.query\";\nexport const URL_SCHEME = \"url.scheme\";\n// Http Attribute Keys\nexport const HTTP_REQUEST_METHOD = \"http.request.method\";\nexport const HTTP_REQUEST_METHOD_ORIGINAL = \"http.request.method_original\";\nexport const HTTP_REQUEST_HEADER = \"http.request.header\";\nexport const HTTP_RESPONSE_STATUS_CODE = \"http.response.status_code\";\nexport const HTTP_RESPONSE_HEADER = \"http.response.header\";\nexport const HTTP_RESPONSE_BODY_SIZE = \"http.response.body.size\";\n// Event Names\nexport const EVENT_NAMES = {\n PAGE_VIEW: \"browser.page_view\",\n NAVIGATION_TIMING: \"browser.navigation_timing\",\n WEB_VITAL: \"browser.web_vital\",\n ERROR: \"browser.error\",\n};\nexport const SPAN_EVENT_NAME_EXCEPTION = \"exception\";\n// Log Severities\nexport const LOG_SEVERITIES = {\n UNSPECIFIED: 0,\n TRACE: 1,\n DEBUG: 5,\n INFO: 9,\n WARN: 13,\n ERROR: 17,\n FATAL: 21,\n};\n// Page View Event Attributes\n// SEE: https://github.com/open-telemetry/semantic-conventions/pull/1910/files\nexport const PAGE_VIEW_TYPE = \"type\";\nexport const PAGE_VIEW_TYPE_VALUES = {\n INITIAL: 0,\n VIRTUAL: 1,\n};\nexport const PAGE_VIEW_CHANGE_STATE = \"change_state\";\nexport const PAGE_VIEW_CHANGE_STATE_VALUES = {\n PUSH: \"pushState\",\n REPLACE: \"replaceState\",\n};\n// Span Status\nexport const SPAN_STATUS_UNSET = 0;\nexport const SPAN_STATUS_OK = 1; // This is here for completion, status ok is reserved for use by application developers\nexport const SPAN_STATUS_ERROR = 2;\n// Span Kind\n// See: https://github.com/open-telemetry/opentelemetry-proto/blob/ac3242b03157295e4ee9e616af53b81517b06559/opentelemetry/proto/trace/v1/trace.proto#L143-L169\nexport const SPAN_KIND_CLIENT = 3;\n","import * as localStorage from \"./local-storage\";\nimport { generateUniqueId, SESSION_ID_BYTES } from \"./id\";\nconst SESSION_FLAGS = {\n EPHEMERAL_SESSION: 0x01, // 00000001 - if the browser does NOT support local storage we count the session as ephemeral because we cannot persist it\n};\nfunction encodeSessionFlags(flags) {\n let byte = 0;\n if (flags.ephemeralSession) {\n byte |= SESSION_FLAGS.EPHEMERAL_SESSION;\n }\n return byte.toString(16).padStart(2, \"0\");\n}\nexport function generateSessionId() {\n const sessionFlags = {\n ephemeralSession: !localStorage.isSupported,\n };\n return `${encodeSessionFlags(sessionFlags)}${generateUniqueId(SESSION_ID_BYTES - 1)}`;\n}\n","import { isSupported, getItem, setItem, removeItem } from \"../utils\";\nimport { debug, now } from \"../utils\";\nimport { info, warn } from \"../utils\";\nimport { generateSessionId } from \"../utils/session-id\";\nconst SESSION_STORAGE_KEY = \"d0_session\";\nconst STORAGE_SEPARATOR_KEY = \"#\";\nconst DEFAULT_SESSION_INACTIVITY_TIMEOUT_MILLIS = 1000 * 60 * 60 * 3;\nconst DEFAULT_SESSION_TERMINATION_TIMEOUT_MILLIS = 1000 * 60 * 60 * 6;\nconst MAX_ALLOWED_SESSION_TIMEOUT_MILLIS = 1000 * 60 * 60 * 24;\nexport let sessionId = null;\nexport function trackSessions(sessionInactivityTimeoutMillis, sessionTerminationTimeoutMillis) {\n if (!isSupported) {\n debug(\"Storage API is not available and session tracking is therefore not supported.\");\n // we still generate a session ID to ensure that the session ID is always available\n sessionId = generateSessionId();\n return;\n }\n if (!sessionInactivityTimeoutMillis) {\n sessionInactivityTimeoutMillis = DEFAULT_SESSION_INACTIVITY_TIMEOUT_MILLIS;\n }\n if (!sessionTerminationTimeoutMillis) {\n sessionTerminationTimeoutMillis = DEFAULT_SESSION_TERMINATION_TIMEOUT_MILLIS;\n }\n sessionInactivityTimeoutMillis = Math.min(sessionInactivityTimeoutMillis, MAX_ALLOWED_SESSION_TIMEOUT_MILLIS);\n sessionTerminationTimeoutMillis = Math.min(sessionTerminationTimeoutMillis, MAX_ALLOWED_SESSION_TIMEOUT_MILLIS);\n try {\n const storedValue = getItem(SESSION_STORAGE_KEY);\n let session = parseSession(storedValue);\n if (session && !isSessionValid(session, sessionInactivityTimeoutMillis, sessionTerminationTimeoutMillis)) {\n session = null;\n }\n if (session) {\n session.lastActivityTime = now();\n }\n else {\n session = {\n id: generateSessionId(),\n startTime: now(),\n lastActivityTime: now(),\n };\n }\n setItem(SESSION_STORAGE_KEY, serializeSession(session));\n sessionId = session.id;\n }\n catch (e) {\n warn(\"Failed to record session information\", e);\n }\n}\n/**\n * The session will be terminated. This only takes effect on the next physical page load.\n */\nexport function terminateSession() {\n if (!isSupported) {\n return;\n }\n try {\n removeItem(SESSION_STORAGE_KEY);\n }\n catch (e) {\n info(\"Failed to terminate session\", e);\n }\n}\nfunction parseSession(storedValue) {\n if (!storedValue) {\n return null;\n }\n const values = storedValue.split(STORAGE_SEPARATOR_KEY);\n if (values.length < 3) {\n return null;\n }\n const id = values[0];\n const startTime = parseInt(values[1], 10);\n const lastActivityTime = parseInt(values[2], 10);\n if (!id || isNaN(startTime) || isNaN(lastActivityTime)) {\n return null;\n }\n return {\n id,\n startTime,\n lastActivityTime,\n };\n}\nfunction serializeSession(session) {\n return session.id + STORAGE_SEPARATOR_KEY + session.startTime + STORAGE_SEPARATOR_KEY + session.lastActivityTime;\n}\nfunction isSessionValid(session, sessionInactivityTimeoutMillis, sessionTerminationTimeoutMillis) {\n const minAllowedLastActivityTime = now() - sessionInactivityTimeoutMillis;\n if (session.lastActivityTime < minAllowedLastActivityTime) {\n return false;\n }\n const minAllowedStartTime = now() - sessionTerminationTimeoutMillis;\n return session.startTime >= minAllowedStartTime;\n}\n","let e=-1;const t=t=>{addEventListener(\"pageshow\",(n=>{n.persisted&&(e=n.timeStamp,t(n))}),!0)},n=(e,t,n,i)=>{let o,s;return r=>{t.value>=0&&(r||i)&&(s=t.value-(o??0),(s||void 0===o)&&(o=t.value,t.delta=s,t.rating=((e,t)=>e>t[1]?\"poor\":e>t[0]?\"needs-improvement\":\"good\")(t.value,n),e(t)))}},i=e=>{requestAnimationFrame((()=>requestAnimationFrame((()=>e()))))},o=()=>{const e=performance.getEntriesByType(\"navigation\")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},s=()=>{const e=o();return e?.activationStart??0},r=(t,n=-1)=>{const i=o();let r=\"navigate\";e>=0?r=\"back-forward-cache\":i&&(document.prerendering||s()>0?r=\"prerender\":document.wasDiscarded?r=\"restore\":i.type&&(r=i.type.replace(/_/g,\"-\")));return{name:t,value:n,rating:\"good\",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:r}},c=new WeakMap;function a(e,t){return c.get(e)||c.set(e,new t),c.get(e)}class d{t;i=0;o=[];h(e){if(e.hadRecentInput)return;const t=this.o[0],n=this.o.at(-1);this.i&&t&&n&&e.startTime-n.startTime<1e3&&e.startTime-t.startTime<5e3?(this.i+=e.value,this.o.push(e)):(this.i=e.value,this.o=[e]),this.t?.(e)}}const h=(e,t,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){const i=new PerformanceObserver((e=>{Promise.resolve().then((()=>{t(e.getEntries())}))}));return i.observe({type:e,buffered:!0,...n}),i}}catch{}},f=e=>{let t=!1;return()=>{t||(e(),t=!0)}};let u=-1;const l=()=>\"hidden\"!==document.visibilityState||document.prerendering?1/0:0,m=e=>{\"hidden\"===document.visibilityState&&u>-1&&(u=\"visibilitychange\"===e.type?e.timeStamp:0,v())},g=()=>{addEventListener(\"visibilitychange\",m,!0),addEventListener(\"prerenderingchange\",m,!0)},v=()=>{removeEventListener(\"visibilitychange\",m,!0),removeEventListener(\"prerenderingchange\",m,!0)},p=()=>{if(u<0){const e=s(),n=document.prerendering?void 0:globalThis.performance.getEntriesByType(\"visibility-state\").filter((t=>\"hidden\"===t.name&&t.startTime>e))[0]?.startTime;u=n??l(),g(),t((()=>{setTimeout((()=>{u=l(),g()}))}))}return{get firstHiddenTime(){return u}}},y=e=>{document.prerendering?addEventListener(\"prerenderingchange\",(()=>e()),!0):e()},b=[1800,3e3],P=(e,o={})=>{y((()=>{const c=p();let a,d=r(\"FCP\");const f=h(\"paint\",(e=>{for(const t of e)\"first-contentful-paint\"===t.name&&(f.disconnect(),t.startTime<c.firstHiddenTime&&(d.value=Math.max(t.startTime-s(),0),d.entries.push(t),a(!0)))}));f&&(a=n(e,d,b,o.reportAllChanges),t((t=>{d=r(\"FCP\"),a=n(e,d,b,o.reportAllChanges),i((()=>{d.value=performance.now()-t.timeStamp,a(!0)}))})))}))},T=[.1,.25],E=(e,o={})=>{P(f((()=>{let s,c=r(\"CLS\",0);const f=a(o,d),u=e=>{for(const t of e)f.h(t);f.i>c.value&&(c.value=f.i,c.entries=f.o,s())},l=h(\"layout-shift\",u);l&&(s=n(e,c,T,o.reportAllChanges),document.addEventListener(\"visibilitychange\",(()=>{\"hidden\"===document.visibilityState&&(u(l.takeRecords()),s(!0))})),t((()=>{f.i=0,c=r(\"CLS\",0),s=n(e,c,T,o.reportAllChanges),i((()=>s()))})),setTimeout(s))})))};let _=0,L=1/0,M=0;const C=e=>{for(const t of e)t.interactionId&&(L=Math.min(L,t.interactionId),M=Math.max(M,t.interactionId),_=M?(M-L)/7+1:0)};let I;const w=()=>I?_:performance.interactionCount??0,F=()=>{\"interactionCount\"in performance||I||(I=h(\"event\",C,{type:\"event\",buffered:!0,durationThreshold:0}))};let k=0;class A{u=[];l=new Map;m;v;p(){k=w(),this.u.length=0,this.l.clear()}P(){const e=Math.min(this.u.length-1,Math.floor((w()-k)/50));return this.u[e]}h(e){if(this.m?.(e),!e.interactionId&&\"first-input\"!==e.entryType)return;const t=this.u.at(-1);let n=this.l.get(e.interactionId);if(n||this.u.length<10||e.duration>t.T){if(n?e.duration>n.T?(n.entries=[e],n.T=e.duration):e.duration===n.T&&e.startTime===n.entries[0].startTime&&n.entries.push(e):(n={id:e.interactionId,entries:[e],T:e.duration},this.l.set(n.id,n),this.u.push(n)),this.u.sort(((e,t)=>t.T-e.T)),this.u.length>10){const e=this.u.splice(10);for(const t of e)this.l.delete(t.id)}this.v?.(n)}}}const B=e=>{const t=globalThis.requestIdleCallback||setTimeout;\"hidden\"===document.visibilityState?e():(e=f(e),document.addEventListener(\"visibilitychange\",e,{once:!0}),t((()=>{e(),document.removeEventListener(\"visibilitychange\",e)})))},N=[200,500],S=(e,i={})=>{globalThis.PerformanceEventTiming&&\"interactionId\"in PerformanceEventTiming.prototype&&y((()=>{F();let o,s=r(\"INP\");const c=a(i,A),d=e=>{B((()=>{for(const t of e)c.h(t);const t=c.P();t&&t.T!==s.value&&(s.value=t.T,s.entries=t.entries,o())}))},f=h(\"event\",d,{durationThreshold:i.durationThreshold??40});o=n(e,s,N,i.reportAllChanges),f&&(f.observe({type:\"first-input\",buffered:!0}),document.addEventListener(\"visibilitychange\",(()=>{\"hidden\"===document.visibilityState&&(d(f.takeRecords()),o(!0))})),t((()=>{c.p(),s=r(\"INP\"),o=n(e,s,N,i.reportAllChanges)})))}))};class q{m;h(e){this.m?.(e)}}const x=[2500,4e3],O=(e,o={})=>{y((()=>{const c=p();let d,u=r(\"LCP\");const l=a(o,q),m=e=>{o.reportAllChanges||(e=e.slice(-1));for(const t of e)l.h(t),t.startTime<c.firstHiddenTime&&(u.value=Math.max(t.startTime-s(),0),u.entries=[t],d())},g=h(\"largest-contentful-paint\",m);if(g){d=n(e,u,x,o.reportAllChanges);const s=f((()=>{m(g.takeRecords()),g.disconnect(),d(!0)}));for(const e of[\"keydown\",\"click\",\"visibilitychange\"])addEventListener(e,(()=>B(s)),{capture:!0,once:!0});t((t=>{u=r(\"LCP\"),d=n(e,u,x,o.reportAllChanges),i((()=>{u.value=performance.now()-t.timeStamp,d(!0)}))}))}}))},$=[800,1800],D=e=>{document.prerendering?y((()=>D(e))):\"complete\"!==document.readyState?addEventListener(\"load\",(()=>D(e)),!0):setTimeout(e)},H=(e,i={})=>{let c=r(\"TTFB\"),a=n(e,c,$,i.reportAllChanges);D((()=>{const d=o();d&&(c.value=Math.max(d.responseStart-s(),0),c.entries=[d],a(!0),t((()=>{c=r(\"TTFB\",0),a=n(e,c,$,i.reportAllChanges),a(!0)})))}))};export{T as CLSThresholds,b as FCPThresholds,N as INPThresholds,x as LCPThresholds,$ as TTFBThresholds,E as onCLS,P as onFCP,S as onINP,O as onLCP,H as onTTFB};\n","import { addEventListener } from \"./listeners\";\nimport { doc, win } from \"./globals\";\nlet isUnloading = false;\n/**\n * Triggers the `fn` when the HTML document is getting unloaded\n * (or when it looks like it might be). Useful to flush batch activities.\n */\nexport function onLastChance(fn) {\n if (isUnloading) {\n fn();\n }\n if (!doc || !win)\n return;\n addEventListener(doc, \"visibilitychange\", function () {\n if (doc.visibilityState !== \"visible\") {\n fn();\n }\n });\n addEventListener(win, \"pagehide\", function () {\n isUnloading = true;\n fn();\n });\n // According to the spec visibilitychange should be a replacement for\n // beforeunload, but the reality is different (as of 2019-04-17). Chrome will\n // close tabs without firing visibilitychange. beforeunload on the other hand\n // is fired.\n addEventListener(win, \"beforeunload\", function () {\n isUnloading = true;\n fn();\n });\n}\n","import { onLastChance } from \"../utils/on-last-chance\";\nimport { doc } from \"../utils\";\nimport { setTimeout } from \"../utils/timers\";\nconst SCHEDULE_DELAY_MILLIS = 1000;\nconst MAX_QUEUE_SIZE = 15;\nexport function newBatcher(sendInternal) {\n const queuedItems = [];\n let pendingFlushTimeout;\n // We attempt batching of messages to be more efficient on the client, network and\n // server-side. While the connection is either a persistent HTTP 2 connection or\n // an HTTP 1.1 connection with keep-alive, there is still some overhead involved\n // in having many small messages.\n //\n // For this reason we attempt batching. When batching we must be careful to\n // force a transmission when the document is unloaded.\n onLastChance(flush);\n return {\n send(item) {\n if (isWindowHidden()) {\n // We cannot guarantee that we will ever get time to transmit data in a batched\n // format when the window is hidden, as this might occur while the document is\n // being unloaded. Immediately force a transmission in these cases.\n sendInternal([item]);\n return;\n }\n queuedItems.push(item);\n if (queuedItems.length >= MAX_QUEUE_SIZE) {\n flush();\n }\n else if (pendingFlushTimeout == null) {\n pendingFlushTimeout = setTimeout(flush, SCHEDULE_DELAY_MILLIS);\n }\n },\n };\n function flush() {\n if (pendingFlushTimeout != null) {\n clearTimeout(pendingFlushTimeout);\n pendingFlushTimeout = null;\n }\n if (queuedItems.length > 0) {\n sendInternal(queuedItems.slice());\n queuedItems.length = 0;\n }\n }\n}\nfunction isWindowHidden() {\n return doc?.visibilityState !== \"visible\";\n}\n","import { vars } from \"../vars\";\nimport { noop, warn, fetch, debug } from \"../utils\";\nconst BEACON_BODY_SIZE_LIMIT = 60000;\nexport async function send(path, body) {\n debug(\"Transmitting telemetry to endpoints\", body);\n const jsonString = JSON.stringify(body);\n let requestBody = jsonString;\n let byteLength = jsonString.length;\n let isCompressed = false;\n // Try to compress if supported\n if (typeof CompressionStream !== \"undefined\") {\n requestBody = await compressWithGzip(jsonString);\n byteLength = requestBody.byteLength;\n isCompressed = true;\n }\n // Send to all endpoints in parallel\n await Promise.all(vars.endpoints.map(async (endpoint) => {\n try {\n const url = new URL(endpoint[\"url\"]);\n url.pathname = url.pathname + (url.pathname.endsWith(\"/\") ? path.substring(1) : path);\n const headers = {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${endpoint[\"authToken\"]}`,\n };\n if (endpoint.dataset) {\n headers[\"Dash0-Dataset\"] = endpoint[\"dataset\"];\n }\n // Try to compress if supported\n if (isCompressed) {\n headers[\"Content-Encoding\"] = \"gzip\";\n }\n if (!fetch) {\n warn(\"Unable to send telemetry, fetch is not defined\");\n return;\n }\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: requestBody,\n // The keepalive flag is related to the window.sendBeacon API. This in turn has size limitations.\n keepalive: byteLength <= BEACON_BODY_SIZE_LIMIT,\n });\n // read the body so the connection can be closed\n response.text().catch(noop);\n if (!response.ok) {\n warn(`Failed to send telemetry to ${url}: ${response.status} ${response.statusText}`);\n }\n }\n catch (error) {\n warn(`Error sending telemetry to ${endpoint.url}${path}:`, error);\n }\n }));\n}\nasync function compressWithGzip(data) {\n const blob = new Blob([data]);\n const stream = blob.stream();\n const compressedStream = stream.pipeThrough(new CompressionStream(\"gzip\"));\n return new Response(compressedStream).arrayBuffer();\n}\n","import { newBatcher } from \"./batcher\";\nimport { send } from \"./fetch\";\nimport { vars } from \"../vars\";\nimport { debug, error, createRateLimiter } from \"../utils\";\nconst logBatcher = newBatcher(sendLogs);\nconst spanBatcher = newBatcher(sendSpans);\nlet rateLimiter;\nfunction isRateLimited() {\n if (!rateLimiter) {\n rateLimiter = createRateLimiter({\n maxCallsPerTenMinutes: 4096,\n maxCallsPerTenSeconds: 128,\n });\n }\n return rateLimiter();\n}\nexport function sendLog(log) {\n if (isRateLimited()) {\n debug(\"Transport rate limit. Will not send item.\", log);\n return;\n }\n logBatcher.send(log);\n}\nfunction sendLogs(logs) {\n send(\"/v1/logs\", {\n resourceLogs: [\n {\n resource: vars.resource,\n scopeLogs: [\n {\n scope: vars.scope,\n logRecords: logs,\n },\n ],\n },\n ],\n }).catch((err) => {\n error(\"Failed to transmit logs\", err);\n });\n}\nexport function sendSpan(span) {\n if (isRateLimited()) {\n debug(\"Transport rate limit. Will not send item.\", span);\n return;\n }\n spanBatcher.send(span);\n}\nfunction sendSpans(spans) {\n send(\"/v1/traces\", {\n resourceSpans: [\n {\n resource: vars.resource,\n scopeSpans: [\n {\n scope: vars.scope,\n spans: spans,\n },\n ],\n },\n ],\n }).catch((err) => {\n error(\"Failed to transmit spans\", err);\n });\n}\n","import { setInterval } from \"./timers\";\nexport function createRateLimiter(opts) {\n const maxCallsPerTenMinutes = opts.maxCallsPerTenMinutes || 128;\n const maxCallsPerTenSeconds = opts.maxCallsPerTenSeconds || 32;\n let totalCallsInLastTenMinutes = 0;\n let totalCallsInLastTenSeconds = 0;\n setInterval(function () {\n totalCallsInLastTenMinutes = 0;\n }, 1000 * 60 * 10);\n setInterval(function () {\n totalCallsInLastTenSeconds = 0;\n }, 1000 * 10);\n return function isExcessiveUsage() {\n return ++totalCallsInLastTenMinutes > maxCallsPerTenMinutes || ++totalCallsInLastTenSeconds > maxCallsPerTenSeconds;\n };\n}\n","const ANY_VALUE_KEYS = [\n \"stringValue\",\n \"boolValue\",\n \"intValue\",\n \"doubleValue\",\n \"arrayValue\",\n \"kvlistValue\",\n \"bytesValue\",\n];\nfunction isAnyValue(value) {\n if (value == null || typeof value !== \"object\")\n return false;\n const keys = Object.keys(value);\n return keys.length === 1 && ANY_VALUE_KEYS.includes(keys[0]);\n}\nexport function toAnyValue(value) {\n if (value == null) {\n return undefined;\n }\n let anyValue = {};\n if (Array.isArray(value)) {\n anyValue[\"arrayValue\"] = { values: value.map((e) => toAnyValue(e)) };\n }\n else if (typeof value === \"string\") {\n anyValue[\"stringValue\"] = value;\n }\n else if (typeof value === \"number\") {\n anyValue[\"doubleValue\"] = value;\n }\n else if (typeof value === \"boolean\") {\n anyValue[\"boolValue\"] = value;\n }\n else if (isAnyValue(value)) {\n anyValue = value;\n }\n else if (typeof value === \"object\") {\n anyValue[\"kvlistValue\"] = { values: Object.entries(value).map(([key, value]) => toKeyValue(key, value)) };\n }\n return anyValue;\n}\nexport function toKeyValue(key, value) {\n return {\n key: key,\n value: toAnyValue(value),\n };\n}\nexport function addAttribute(attributes, key, value) {\n if (!key)\n return;\n attributes.push(toKeyValue(key, value));\n}\nexport function removeAttribute(attributes, key) {\n const index = attributes.findIndex((attr) => attr[\"key\"] === key);\n if (index !== -1) {\n attributes.splice(index, 1);\n }\n}\nexport function withPrefix(prefix) {\n if (!prefix)\n return (attr) => attr;\n if (Array.isArray(prefix)) {\n return (attr) => [...prefix, attr].join(\".\");\n }\n return (attr) => `${prefix}.${attr}`;\n}\n","import { doc } from \"../globals\";\nimport { perf } from \"../globals\";\nconst TRACE_PARENT_HEADER = \"traceparent\";\n/**\n * See https://www.w3.org/TR/trace-context/#traceparent-header\n */\nconst w3cTraceparentFormat = /^00-([a-f0-9]{32})-([a-f0-9]{16})-[0-9]{1,2}$/;\nexport function getTraceContextForPageLoad() {\n const match = getTraceparentFromMetaElement().match(w3cTraceparentFormat) ||\n getTraceparentFromNavigationTiming().match(w3cTraceparentFormat);\n if (match) {\n return {\n traceId: match[1],\n spanId: match[2],\n };\n }\n return undefined;\n}\nfunction getTraceparentFromMetaElement() {\n return (Array.from(doc?.getElementsByTagName(\"meta\") ?? [])\n .find((e) => e.getAttribute(\"name\")?.toLowerCase() === TRACE_PARENT_HEADER)\n ?.content.trim() || \"\");\n}\nfunction getTraceparentFromNavigationTiming() {\n const nt = perf.getEntriesByType(\"navigation\")[0];\n if (!nt) {\n return \"\";\n }\n if (!nt.serverTiming) {\n return \"\";\n }\n return getTraceparentFromServerTiming(nt.serverTiming);\n}\nfunction getTraceparentFromServerTiming(serverTimings) {\n for (const serverEntry of serverTimings) {\n if (serverEntry.name === TRACE_PARENT_HEADER) {\n return serverEntry.description.trim();\n }\n }\n return \"\";\n}\nexport function addW3CTraceContextHttpHeaders(fn, ctx, span) {\n /**\n * W3C Traceparent header.\n * General format is ${version}-${trace-id}-${parent-id}-${trace-flags}\n *\n * The only spec'd version is currently 00\n * Trace flags are an 8 bit field of bit flags:\n * Sampled: 00000001 - Should only be set if a definite decision to record the trace was made.\n * If set downstream processors should also record the trace\n * Random Trace ID: 00000010 - IF set the component guarantees that the seven right most bytes of the trace-id\n * are randomly generated. Downstream processors are then able to rely on this for technical things like shard keys.\n *\n * NOTE: For now we just send the \"sampled\" flag because not all components support the random trace ID flag.\n *\n * References:\n * https://www.w3.org/TR/trace-context-2/#traceparent-header\n * https://www.w3.org/TR/trace-context-2/#trace-flags\n * https://www.w3.org/TR/trace-context-2/#random-trace-id-flag\n */\n fn.call(ctx, \"traceparent\", `00-${span.traceId}-${span.spanId}-01`);\n}\nexport function addXRayTraceContextHttpHeaders(fn, ctx, span) {\n /**\n * AWS X-Ray trace header.\n * General format is Root=${trace-id};Parent=${span-id};Sampled=${sampling-flag}\n *\n * Converts W3C trace ID format to X-Ray format:\n * W3C: 4efaaf4d1e8720b39541901950019ee5 (32 hex chars)\n * X-Ray: 1-4efaaf4d-1e8720b39541901950019ee5 (1-{8chars}-{24chars})\n *\n * References:\n * https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader\n */\n const xrayTraceId = convertW3CTraceIdToXRay(span.traceId);\n const xrayHeader = `Root=${xrayTraceId};Parent=${span.spanId};Sampled=1`;\n fn.call(ctx, \"X-Amzn-Trace-Id\", xrayHeader);\n}\nfunction convertW3CTraceIdToXRay(w3cTraceId) {\n // X-Ray trace ID format: 1-{timestamp}-{unique-id}\n // Split the 32-char W3C trace ID into 8-char timestamp and 24-char unique ID\n const timestamp = w3cTraceId.substring(0, 8);\n const uniqueId = w3cTraceId.substring(8, 32);\n return `1-${timestamp}-${uniqueId}`;\n}\n","import { generateUniqueId, SESSION_ID_BYTES, TRACE_ID_BYTES } from \"./id\";\nconst TRACE_ID_PREFIX = \"d042\";\nconst TRACE_FLAGS = {\n WITHOUT_SESSION: 0x01, // 00000001 - in some edge cases we do not have a session ID, so we need to mark the trace as such\n};\nfunction encodeTraceFlags(flags) {\n let byte = 0;\n if (flags.withoutSession) {\n byte |= TRACE_FLAGS.WITHOUT_SESSION;\n }\n return byte.toString(16).padStart(2, \"0\");\n}\nexport function generateTraceId(sessionId) {\n if (!sessionId) {\n return `${TRACE_ID_PREFIX}${encodeTraceFlags({ withoutSession: true })}${generateUniqueId(TRACE_ID_BYTES - 3)}`;\n }\n return `${TRACE_ID_PREFIX}${encodeTraceFlags({ withoutSession: false })}${sessionId}${generateUniqueId(TRACE_ID_BYTES - SESSION_ID_BYTES - 3)}`;\n}\n","const POLYNOMIAL = 0xedb88320; // This is the standard polynomial used in IEEE 802.3 and must be in sync with the one we are using in the backend.\nconst TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let k = 0; k < 8; k++) {\n c = c & 1 ? POLYNOMIAL ^ (c >>> 1) : c >>> 1;\n }\n TABLE[i] = c >>> 0;\n}\nexport function crc32(hexStr) {\n const bytes = new Uint8Array(hexStr.length / 2);\n for (let i = 0; i < hexStr.length; i += 2) {\n bytes[i / 2] = parseInt(hexStr.substring(i, i + 2), 16);\n }\n let