UNPKG

@cloudflare/workers-shared

Version:

Package that is used at Cloudflare to power some internal features of Cloudflare Workers.

4 lines • 480 kB
{ "version": 3, "sources": ["../asset-worker/src/index.ts", "../utils/performance.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/is.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/string.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/version.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/worldwide.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/browser.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/debug-build.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/logger.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/dsn.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/error.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/object.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/stacktrace.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/instrument/handlers.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/time.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/instrument/globalError.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/instrument/globalUnhandledRejection.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/memo.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/misc.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/normalize.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/path.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/syncpromise.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/promisebuffer.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/node-stack-trace.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/envelope.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/ratelimit.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/eventbuilder.ts", "../../../node_modules/.pnpm/@sentry+utils@8.9.2/node_modules/@sentry/src/propagationContext.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/debug-build.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/carrier.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/session.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/utils/spanOnScope.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/scope.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/defaultScopes.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/asyncContext/stackStrategy.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/asyncContext/index.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/currentScopes.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/metrics/metric-summary.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/semanticAttributes.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/utils/spanUtils.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/tracing/errors.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/constants.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/tracing/dynamicSamplingContext.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/utils/parseSampleRate.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/envelope.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/eventProcessors.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/utils/applyScopeDataToEvent.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/utils/prepareEvent.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/sessionflusher.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/api.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/integration.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/baseclient.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/checkin.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/server-runtime-client.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/transports/base.ts", "../../../node_modules/.pnpm/@sentry+core@8.9.2/node_modules/@sentry/src/integrations/rewriteframes.ts", "../../../node_modules/.pnpm/toucan-js@4.0.0_patch_hash=qxsfpdzvzbhq2ecirbu5xq4vlq/node_modules/toucan-js/dist/index.esm.js", "../utils/sentry.ts", "../utils/tracing.ts", "../asset-worker/src/analytics.ts", "../asset-worker/src/assets-manifest.ts", "../asset-worker/src/compatibility-flags.ts", "../asset-worker/src/configuration.ts", "../asset-worker/src/experiment-analytics.ts", "../utils/responses.ts", "../asset-worker/src/constants.ts", "../asset-worker/src/utils/rules-engine.ts", "../asset-worker/src/utils/headers.ts", "../asset-worker/src/handler.ts", "../asset-worker/src/utils/final-operations.ts", "../asset-worker/src/utils/kv.ts"], "sourcesContent": ["import { WorkerEntrypoint } from \"cloudflare:workers\";\nimport { PerformanceTimer } from \"../../utils/performance\";\nimport { setupSentry } from \"../../utils/sentry\";\nimport { mockJaegerBinding } from \"../../utils/tracing\";\nimport { Analytics } from \"./analytics\";\nimport { AssetsManifest } from \"./assets-manifest\";\nimport { normalizeConfiguration } from \"./configuration\";\nimport { ExperimentAnalytics } from \"./experiment-analytics\";\nimport { canFetch, handleRequest } from \"./handler\";\nimport { handleError, submitMetrics } from \"./utils/final-operations\";\nimport { getAssetWithMetadataFromKV } from \"./utils/kv\";\nimport type {\n\tAssetConfig,\n\tColoMetadata,\n\tJaegerTracing,\n\tUnsafePerformanceTimer,\n} from \"../../utils/types\";\nimport type { Environment, ReadyAnalytics } from \"./types\";\n\nexport type Env = {\n\t/*\n\t * ASSETS_MANIFEST is a pipeline binding to an ArrayBuffer containing the\n\t * binary-encoded site manifest\n\t */\n\tASSETS_MANIFEST: ArrayBuffer;\n\n\t/*\n\t * ASSETS_KV_NAMESPACE is a pipeline binding to the KV namespace that the\n\t * assets are in.\n\t */\n\tASSETS_KV_NAMESPACE: KVNamespace;\n\n\tCONFIG: AssetConfig;\n\n\tSENTRY_DSN: string;\n\tSENTRY_ACCESS_CLIENT_ID: string;\n\tSENTRY_ACCESS_CLIENT_SECRET: string;\n\n\tJAEGER: JaegerTracing;\n\n\tENVIRONMENT: Environment;\n\tEXPERIMENT_ANALYTICS: ReadyAnalytics;\n\tANALYTICS: ReadyAnalytics;\n\tCOLO_METADATA: ColoMetadata;\n\tUNSAFE_PERFORMANCE: UnsafePerformanceTimer;\n\tVERSION_METADATA: WorkerVersionMetadata;\n};\n\n/*\n * The Asset Worker is currently set up as a `WorkerEntrypoint` class so\n * that it is able to accept RPC calls to any of its public methods. There\n * are currently four such public methods defined on this Worker:\n * `canFetch`, `getByETag`, `getByPathname` and `exists`. While we are\n * stabilising the implementation details of these methods, we would like\n * to prevent developers from having their Workers call these methods\n * directly. To that end, we are adopting the `unstable_<method_name>`\n * naming convention for all of the aforementioned methods, to indicate that\n * they are still in flux and that they are not an established API contract.\n */\nexport default class extends WorkerEntrypoint<Env> {\n\tasync fetch(request: Request): Promise<Response> {\n\t\tlet sentry: ReturnType<typeof setupSentry> | undefined;\n\t\tconst analytics = new Analytics(this.env.ANALYTICS);\n\t\tconst performance = new PerformanceTimer(this.env.UNSAFE_PERFORMANCE);\n\t\tconst startTimeMs = performance.now();\n\n\t\ttry {\n\t\t\t// TODO: Mock this with Miniflare\n\t\t\tthis.env.JAEGER ??= mockJaegerBinding();\n\n\t\t\tsentry = setupSentry(\n\t\t\t\trequest,\n\t\t\t\tthis.ctx,\n\t\t\t\tthis.env.SENTRY_DSN,\n\t\t\t\tthis.env.SENTRY_ACCESS_CLIENT_ID,\n\t\t\t\tthis.env.SENTRY_ACCESS_CLIENT_SECRET,\n\t\t\t\tthis.env.COLO_METADATA,\n\t\t\t\tthis.env.VERSION_METADATA,\n\t\t\t\tthis.env.CONFIG?.account_id,\n\t\t\t\tthis.env.CONFIG?.script_id\n\t\t\t);\n\n\t\t\tconst config = normalizeConfiguration(this.env.CONFIG);\n\t\t\tsentry?.setContext(\"compatibilityOptions\", {\n\t\t\t\tcompatibilityDate: config.compatibility_date,\n\t\t\t\tcompatibilityFlags: config.compatibility_flags,\n\t\t\t\toriginalCompatibilityFlags: this.env.CONFIG.compatibility_flags,\n\t\t\t});\n\t\t\tconst userAgent = request.headers.get(\"user-agent\") ?? \"UA UNKNOWN\";\n\n\t\t\tconst url = new URL(request.url);\n\t\t\tif (\n\t\t\t\tthis.env.COLO_METADATA &&\n\t\t\t\tthis.env.VERSION_METADATA &&\n\t\t\t\tthis.env.CONFIG\n\t\t\t) {\n\t\t\t\tanalytics.setData({\n\t\t\t\t\taccountId: this.env.CONFIG.account_id,\n\t\t\t\t\tscriptId: this.env.CONFIG.script_id,\n\n\t\t\t\t\tcoloId: this.env.COLO_METADATA.coloId,\n\t\t\t\t\tmetalId: this.env.COLO_METADATA.metalId,\n\t\t\t\t\tcoloTier: this.env.COLO_METADATA.coloTier,\n\n\t\t\t\t\tcoloRegion: this.env.COLO_METADATA.coloRegion,\n\t\t\t\t\tversion: this.env.VERSION_METADATA.tag,\n\t\t\t\t\thostname: url.hostname,\n\t\t\t\t\thtmlHandling: config.html_handling,\n\t\t\t\t\tnotFoundHandling: config.not_found_handling,\n\t\t\t\t\tcompatibilityFlags: config.compatibility_flags,\n\t\t\t\t\tuserAgent: userAgent,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn await this.env.JAEGER.enterSpan(\"handleRequest\", async (span) => {\n\t\t\t\tspan.setTags({\n\t\t\t\t\thostname: url.hostname,\n\t\t\t\t\teyeballPath: url.pathname,\n\t\t\t\t\tenv: this.env.ENVIRONMENT,\n\t\t\t\t\tversion: this.env.VERSION_METADATA?.id,\n\t\t\t\t});\n\n\t\t\t\tconst response = await handleRequest(\n\t\t\t\t\trequest,\n\t\t\t\t\tthis.env,\n\t\t\t\t\tconfig,\n\t\t\t\t\tthis.unstable_exists.bind(this),\n\t\t\t\t\tthis.unstable_getByETag.bind(this),\n\t\t\t\t\tanalytics\n\t\t\t\t);\n\n\t\t\t\tanalytics.setData({ status: response.status });\n\n\t\t\t\treturn response;\n\t\t\t});\n\t\t} catch (err) {\n\t\t\treturn handleError(sentry, analytics, err);\n\t\t} finally {\n\t\t\tsubmitMetrics(analytics, performance, startTimeMs);\n\t\t}\n\t}\n\n\tasync unstable_canFetch(request: Request): Promise<boolean> {\n\t\t// TODO: Mock this with Miniflare\n\t\tthis.env.JAEGER ??= mockJaegerBinding();\n\n\t\treturn canFetch(\n\t\t\trequest,\n\t\t\tthis.env,\n\t\t\tnormalizeConfiguration(this.env.CONFIG),\n\t\t\tthis.unstable_exists.bind(this)\n\t\t);\n\t}\n\n\tasync unstable_getByETag(\n\t\teTag: string,\n\t\t_request?: Request\n\t): Promise<{\n\t\treadableStream: ReadableStream;\n\t\tcontentType: string | undefined;\n\t\tcacheStatus: \"HIT\" | \"MISS\";\n\t}> {\n\t\tconst performance = new PerformanceTimer(this.env.UNSAFE_PERFORMANCE);\n\t\tconst jaeger = this.env.JAEGER ?? mockJaegerBinding();\n\t\treturn jaeger.enterSpan(\"unstable_getByETag\", async (span) => {\n\t\t\tconst startTime = performance.now();\n\t\t\tconst asset = await getAssetWithMetadataFromKV(\n\t\t\t\tthis.env.ASSETS_KV_NAMESPACE,\n\t\t\t\teTag\n\t\t\t);\n\t\t\tconst endTime = performance.now();\n\t\t\tconst assetFetchTime = endTime - startTime;\n\n\t\t\tif (!asset || !asset.value) {\n\t\t\t\tspan.setTags({\n\t\t\t\t\terror: true,\n\t\t\t\t});\n\t\t\t\tspan.addLogs({\n\t\t\t\t\terror: `Requested asset ${eTag} exists in the asset manifest but not in the KV namespace.`,\n\t\t\t\t});\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Requested asset ${eTag} exists in the asset manifest but not in the KV namespace.`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// KV does not yet provide a way to check if a value was fetched from cache\n\t\t\t// so we assume that if the fetch time is less than 100ms, it was a cache hit.\n\t\t\t// This is a reasonable assumption given the data we have and how KV works.\n\t\t\tconst cacheStatus = assetFetchTime <= 100 ? \"HIT\" : \"MISS\";\n\n\t\t\tspan.setTags({\n\t\t\t\tetag: eTag,\n\t\t\t\tcontentType: asset.metadata?.contentType ?? \"unknown\",\n\t\t\t\tcacheStatus,\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\treadableStream: asset.value,\n\t\t\t\tcontentType: asset.metadata?.contentType,\n\t\t\t\tcacheStatus,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync unstable_getByPathname(\n\t\tpathname: string,\n\t\trequest?: Request\n\t): Promise<{\n\t\treadableStream: ReadableStream;\n\t\tcontentType: string | undefined;\n\t\tcacheStatus: \"HIT\" | \"MISS\";\n\t} | null> {\n\t\tconst jaeger = this.env.JAEGER ?? mockJaegerBinding();\n\t\treturn jaeger.enterSpan(\"unstable_getByPathname\", async (span) => {\n\t\t\tconst eTag = await this.unstable_exists(pathname, request);\n\n\t\t\tspan.setTags({\n\t\t\t\tpath: pathname,\n\t\t\t\tfound: eTag !== null,\n\t\t\t});\n\n\t\t\tif (!eTag) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn this.unstable_getByETag(eTag, request);\n\t\t});\n\t}\n\n\tasync unstable_exists(\n\t\tpathname: string,\n\t\t_request?: Request\n\t): Promise<string | null> {\n\t\tconst analytics = new ExperimentAnalytics(this.env.EXPERIMENT_ANALYTICS);\n\t\tconst performance = new PerformanceTimer(this.env.UNSAFE_PERFORMANCE);\n\t\tconst jaeger = this.env.JAEGER ?? mockJaegerBinding();\n\t\treturn jaeger.enterSpan(\"unstable_exists\", async (span) => {\n\t\t\tif (\n\t\t\t\tthis.env.COLO_METADATA &&\n\t\t\t\tthis.env.VERSION_METADATA &&\n\t\t\t\tthis.env.CONFIG\n\t\t\t) {\n\t\t\t\tanalytics.setData({\n\t\t\t\t\taccountId: this.env.CONFIG.account_id,\n\t\t\t\t\texperimentName: \"manifest-read-timing\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst startTimeMs = performance.now();\n\t\t\ttry {\n\t\t\t\tconst assetsManifest = new AssetsManifest(this.env.ASSETS_MANIFEST);\n\t\t\t\tconst eTag = await assetsManifest.get(pathname);\n\n\t\t\t\tspan.setTags({\n\t\t\t\t\tpath: pathname,\n\t\t\t\t\tfound: eTag !== null,\n\t\t\t\t\tetag: eTag ?? \"\",\n\t\t\t\t});\n\n\t\t\t\treturn eTag;\n\t\t\t} finally {\n\t\t\t\tanalytics.setData({\n\t\t\t\t\tmanifestReadTime: performance.now() - startTimeMs,\n\t\t\t\t});\n\t\t\t\tanalytics.write();\n\t\t\t}\n\t\t});\n\t}\n}\n", "import type { UnsafePerformanceTimer } from \"./types\";\n\nexport class PerformanceTimer {\n\tprivate performanceTimer;\n\n\tconstructor(performanceTimer?: UnsafePerformanceTimer) {\n\t\tthis.performanceTimer = performanceTimer;\n\t}\n\n\tnow() {\n\t\tif (this.performanceTimer) {\n\t\t\treturn this.performanceTimer.timeOrigin + this.performanceTimer.now();\n\t\t}\n\t\treturn Date.now();\n\t}\n}\n", "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { ParameterizedString, PolymorphicEvent, Primitive } from '@sentry/types';\n\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst objectToString = Object.prototype.toString;\n\n/**\n * Checks whether given value's type is one of a few Error or Error-like\n * {@link isError}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isError(wat: unknown): wat is Error {\n switch (objectToString.call(wat)) {\n case '[object Error]':\n case '[object Exception]':\n case '[object DOMException]':\n return true;\n default:\n return isInstanceOf(wat, Error);\n }\n}\n/**\n * Checks whether given value is an instance of the given built-in class.\n *\n * @param wat The value to be checked\n * @param className\n * @returns A boolean representing the result.\n */\nfunction isBuiltin(wat: unknown, className: string): boolean {\n return objectToString.call(wat) === `[object ${className}]`;\n}\n\n/**\n * Checks whether given value's type is ErrorEvent\n * {@link isErrorEvent}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isErrorEvent(wat: unknown): boolean {\n return isBuiltin(wat, 'ErrorEvent');\n}\n\n/**\n * Checks whether given value's type is DOMError\n * {@link isDOMError}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isDOMError(wat: unknown): boolean {\n return isBuiltin(wat, 'DOMError');\n}\n\n/**\n * Checks whether given value's type is DOMException\n * {@link isDOMException}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isDOMException(wat: unknown): boolean {\n return isBuiltin(wat, 'DOMException');\n}\n\n/**\n * Checks whether given value's type is a string\n * {@link isString}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isString(wat: unknown): wat is string {\n return isBuiltin(wat, 'String');\n}\n\n/**\n * Checks whether given string is parameterized\n * {@link isParameterizedString}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isParameterizedString(wat: unknown): wat is ParameterizedString {\n return (\n typeof wat === 'object' &&\n wat !== null &&\n '__sentry_template_string__' in wat &&\n '__sentry_template_values__' in wat\n );\n}\n\n/**\n * Checks whether given value is a primitive (undefined, null, number, boolean, string, bigint, symbol)\n * {@link isPrimitive}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isPrimitive(wat: unknown): wat is Primitive {\n return wat === null || isParameterizedString(wat) || (typeof wat !== 'object' && typeof wat !== 'function');\n}\n\n/**\n * Checks whether given value's type is an object literal, or a class instance.\n * {@link isPlainObject}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isPlainObject(wat: unknown): wat is Record<string, unknown> {\n return isBuiltin(wat, 'Object');\n}\n\n/**\n * Checks whether given value's type is an Event instance\n * {@link isEvent}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isEvent(wat: unknown): wat is PolymorphicEvent {\n return typeof Event !== 'undefined' && isInstanceOf(wat, Event);\n}\n\n/**\n * Checks whether given value's type is an Element instance\n * {@link isElement}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isElement(wat: unknown): boolean {\n return typeof Element !== 'undefined' && isInstanceOf(wat, Element);\n}\n\n/**\n * Checks whether given value's type is an regexp\n * {@link isRegExp}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isRegExp(wat: unknown): wat is RegExp {\n return isBuiltin(wat, 'RegExp');\n}\n\n/**\n * Checks whether given value has a then function.\n * @param wat A value to be checked.\n */\nexport function isThenable(wat: any): wat is PromiseLike<any> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n return Boolean(wat && wat.then && typeof wat.then === 'function');\n}\n\n/**\n * Checks whether given value's type is a SyntheticEvent\n * {@link isSyntheticEvent}.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isSyntheticEvent(wat: unknown): boolean {\n return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat;\n}\n\n/**\n * Checks whether given value's type is an instance of provided constructor.\n * {@link isInstanceOf}.\n *\n * @param wat A value to be checked.\n * @param base A constructor to be used in a check.\n * @returns A boolean representing the result.\n */\nexport function isInstanceOf(wat: any, base: any): boolean {\n try {\n return wat instanceof base;\n } catch (_e) {\n return false;\n }\n}\n\ninterface VueViewModel {\n // Vue3\n __isVue?: boolean;\n // Vue2\n _isVue?: boolean;\n}\n/**\n * Checks whether given value's type is a Vue ViewModel.\n *\n * @param wat A value to be checked.\n * @returns A boolean representing the result.\n */\nexport function isVueViewModel(wat: unknown): boolean {\n // Not using Object.prototype.toString because in Vue 3 it would read the instance's Symbol(Symbol.toStringTag) property.\n return !!(typeof wat === 'object' && wat !== null && ((wat as VueViewModel).__isVue || (wat as VueViewModel)._isVue));\n}\n", "import { isRegExp, isString, isVueViewModel } from './is';\n\nexport { escapeStringForRegex } from './vendor/escapeStringForRegex';\n\n/**\n * Truncates given string to the maximum characters count\n *\n * @param str An object that contains serializable values\n * @param max Maximum number of characters in truncated string (0 = unlimited)\n * @returns string Encoded\n */\nexport function truncate(str: string, max: number = 0): string {\n if (typeof str !== 'string' || max === 0) {\n return str;\n }\n return str.length <= max ? str : `${str.slice(0, max)}...`;\n}\n\n/**\n * This is basically just `trim_line` from\n * https://github.com/getsentry/sentry/blob/master/src/sentry/lang/javascript/processor.py#L67\n *\n * @param str An object that contains serializable values\n * @param max Maximum number of characters in truncated string\n * @returns string Encoded\n */\nexport function snipLine(line: string, colno: number): string {\n let newLine = line;\n const lineLength = newLine.length;\n if (lineLength <= 150) {\n return newLine;\n }\n if (colno > lineLength) {\n // eslint-disable-next-line no-param-reassign\n colno = lineLength;\n }\n\n let start = Math.max(colno - 60, 0);\n if (start < 5) {\n start = 0;\n }\n\n let end = Math.min(start + 140, lineLength);\n if (end > lineLength - 5) {\n end = lineLength;\n }\n if (end === lineLength) {\n start = Math.max(end - 140, 0);\n }\n\n newLine = newLine.slice(start, end);\n if (start > 0) {\n newLine = `'{snip} ${newLine}`;\n }\n if (end < lineLength) {\n newLine += ' {snip}';\n }\n\n return newLine;\n}\n\n/**\n * Join values in array\n * @param input array of values to be joined together\n * @param delimiter string to be placed in-between values\n * @returns Joined values\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function safeJoin(input: any[], delimiter?: string): string {\n if (!Array.isArray(input)) {\n return '';\n }\n\n const output = [];\n // eslint-disable-next-line @typescript-eslint/prefer-for-of\n for (let i = 0; i < input.length; i++) {\n const value = input[i];\n try {\n // This is a hack to fix a Vue3-specific bug that causes an infinite loop of\n // console warnings. This happens when a Vue template is rendered with\n // an undeclared variable, which we try to stringify, ultimately causing\n // Vue to issue another warning which repeats indefinitely.\n // see: https://github.com/getsentry/sentry-javascript/pull/8981\n if (isVueViewModel(value)) {\n output.push('[VueViewModel]');\n } else {\n output.push(String(value));\n }\n } catch (e) {\n output.push('[value cannot be serialized]');\n }\n }\n\n return output.join(delimiter);\n}\n\n/**\n * Checks if the given value matches a regex or string\n *\n * @param value The string to test\n * @param pattern Either a regex or a string against which `value` will be matched\n * @param requireExactStringMatch If true, `value` must match `pattern` exactly. If false, `value` will match\n * `pattern` if it contains `pattern`. Only applies to string-type patterns.\n */\nexport function isMatchingPattern(\n value: string,\n pattern: RegExp | string,\n requireExactStringMatch: boolean = false,\n): boolean {\n if (!isString(value)) {\n return false;\n }\n\n if (isRegExp(pattern)) {\n return pattern.test(value);\n }\n if (isString(pattern)) {\n return requireExactStringMatch ? value === pattern : value.includes(pattern);\n }\n\n return false;\n}\n\n/**\n * Test the given string against an array of strings and regexes. By default, string matching is done on a\n * substring-inclusion basis rather than a strict equality basis\n *\n * @param testString The string to test\n * @param patterns The patterns against which to test the string\n * @param requireExactStringMatch If true, `testString` must match one of the given string patterns exactly in order to\n * count. If false, `testString` will match a string pattern if it contains that pattern.\n * @returns\n */\nexport function stringMatchesSomePattern(\n testString: string,\n patterns: Array<string | RegExp> = [],\n requireExactStringMatch: boolean = false,\n): boolean {\n return patterns.some(pattern => isMatchingPattern(testString, pattern, requireExactStringMatch));\n}\n", "export const SDK_VERSION = '8.9.2';\n", "/**\n * NOTE: In order to avoid circular dependencies, if you add a function to this module and it needs to print something,\n * you must either a) use `console.log` rather than the logger, or b) put your function elsewhere.\n *\n * Note: This file was originally called `global.ts`, but was changed to unblock users which might be doing\n * string replaces with bundlers like Vite for `global` (would break imports that rely on importing from utils/src/global).\n *\n * Why worldwide?\n *\n * Why not?\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { Client, MetricsAggregator, Scope } from '@sentry/types';\n\nimport type { SdkSource } from './env';\nimport { SDK_VERSION } from './version';\n\ninterface SentryCarrier {\n acs?: any;\n stack?: any;\n\n globalScope?: Scope;\n defaultIsolationScope?: Scope;\n defaultCurrentScope?: Scope;\n globalMetricsAggregators: WeakMap<Client, MetricsAggregator> | undefined;\n\n /** Overwrites TextEncoder used in `@sentry/utils`, need for `react-native@0.73` and older */\n encodePolyfill?: (input: string) => Uint8Array;\n /** Overwrites TextDecoder used in `@sentry/utils`, need for `react-native@0.73` and older */\n decodePolyfill?: (input: Uint8Array) => string;\n}\n\n// TODO(v9): Clean up or remove this type\ntype BackwardsCompatibleSentryCarrier = SentryCarrier & {\n // pre-v7 hub (replaced by .stack)\n hub: any;\n integrations?: any[];\n logger: any;\n extensions?: {\n /** Extension methods for the hub, which are bound to the current Hub instance */\n // eslint-disable-next-line @typescript-eslint/ban-types\n [key: string]: Function;\n };\n};\n\n/** Internal global with common properties and Sentry extensions */\nexport type InternalGlobal = {\n navigator?: { userAgent?: string };\n console: Console;\n Sentry?: any;\n onerror?: {\n (event: object | string, source?: string, lineno?: number, colno?: number, error?: Error): any;\n __SENTRY_INSTRUMENTED__?: true;\n __SENTRY_LOADER__?: true;\n };\n onunhandledrejection?: {\n (event: unknown): boolean;\n __SENTRY_INSTRUMENTED__?: true;\n __SENTRY_LOADER__?: true;\n };\n SENTRY_ENVIRONMENT?: string;\n SENTRY_DSN?: string;\n SENTRY_RELEASE?: {\n id?: string;\n };\n SENTRY_SDK_SOURCE?: SdkSource;\n /**\n * Debug IDs are indirectly injected by Sentry CLI or bundler plugins to directly reference a particular source map\n * for resolving of a source file. The injected code will place an entry into the record for each loaded bundle/JS\n * file.\n */\n _sentryDebugIds?: Record<string, string>;\n __SENTRY__: Record<Exclude<string, 'version'>, SentryCarrier> & {\n version?: string;\n } & BackwardsCompatibleSentryCarrier;\n /**\n * Raw module metadata that is injected by bundler plugins.\n *\n * Keys are `error.stack` strings, values are the metadata.\n */\n _sentryModuleMetadata?: Record<string, any>;\n _sentryEsmLoaderHookRegistered?: boolean;\n};\n\n/** Get's the global object for the current JavaScript runtime */\nexport const GLOBAL_OBJ = globalThis as unknown as InternalGlobal;\n\n/**\n * Returns a global singleton contained in the global `__SENTRY__[]` object.\n *\n * If the singleton doesn't already exist in `__SENTRY__`, it will be created using the given factory\n * function and added to the `__SENTRY__` object.\n *\n * @param name name of the global singleton on __SENTRY__\n * @param creator creator Factory function to create the singleton if it doesn't already exist on `__SENTRY__`\n * @param obj (Optional) The global object on which to look for `__SENTRY__`, if not `GLOBAL_OBJ`'s return value\n * @returns the singleton\n */\nexport function getGlobalSingleton<T>(name: keyof SentryCarrier, creator: () => T, obj?: unknown): T {\n const gbl = (obj || GLOBAL_OBJ) as InternalGlobal;\n const __SENTRY__ = (gbl.__SENTRY__ = gbl.__SENTRY__ || {});\n const versionedCarrier = (__SENTRY__[SDK_VERSION] = __SENTRY__[SDK_VERSION] || {});\n return versionedCarrier[name] || (versionedCarrier[name] = creator());\n}\n", "import { isString } from './is';\nimport { GLOBAL_OBJ } from './worldwide';\n\nconst WINDOW = GLOBAL_OBJ as unknown as Window;\n\nconst DEFAULT_MAX_STRING_LENGTH = 80;\n\ntype SimpleNode = {\n parentNode: SimpleNode;\n} | null;\n\n/**\n * Given a child DOM element, returns a query-selector statement describing that\n * and its ancestors\n * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]\n * @returns generated DOM path\n */\nexport function htmlTreeAsString(\n elem: unknown,\n options: string[] | { keyAttrs?: string[]; maxStringLength?: number } = {},\n): string {\n if (!elem) {\n return '<unknown>';\n }\n\n // try/catch both:\n // - accessing event.target (see getsentry/raven-js#838, #768)\n // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly\n // - can throw an exception in some circumstances.\n try {\n let currentElem = elem as SimpleNode;\n const MAX_TRAVERSE_HEIGHT = 5;\n const out = [];\n let height = 0;\n let len = 0;\n const separator = ' > ';\n const sepLength = separator.length;\n let nextStr;\n const keyAttrs = Array.isArray(options) ? options : options.keyAttrs;\n const maxStringLength = (!Array.isArray(options) && options.maxStringLength) || DEFAULT_MAX_STRING_LENGTH;\n\n while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {\n nextStr = _htmlElementAsString(currentElem, keyAttrs);\n // bail out if\n // - nextStr is the 'html' element\n // - the length of the string that would be created exceeds maxStringLength\n // (ignore this limit if we are on the first iteration)\n if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= maxStringLength)) {\n break;\n }\n\n out.push(nextStr);\n\n len += nextStr.length;\n currentElem = currentElem.parentNode;\n }\n\n return out.reverse().join(separator);\n } catch (_oO) {\n return '<unknown>';\n }\n}\n\n/**\n * Returns a simple, query-selector representation of a DOM element\n * e.g. [HTMLElement] => input#foo.btn[name=baz]\n * @returns generated DOM path\n */\nfunction _htmlElementAsString(el: unknown, keyAttrs?: string[]): string {\n const elem = el as {\n tagName?: string;\n id?: string;\n className?: string;\n getAttribute(key: string): string;\n };\n\n const out = [];\n let className;\n let classes;\n let key;\n let attr;\n let i;\n\n if (!elem || !elem.tagName) {\n return '';\n }\n\n // @ts-expect-error WINDOW has HTMLElement\n if (WINDOW.HTMLElement) {\n // If using the component name annotation plugin, this value may be available on the DOM node\n if (elem instanceof HTMLElement && elem.dataset) {\n if (elem.dataset['sentryComponent']) {\n return elem.dataset['sentryComponent'];\n }\n if (elem.dataset['sentryElement']) {\n return elem.dataset['sentryElement'];\n }\n }\n }\n\n out.push(elem.tagName.toLowerCase());\n\n // Pairs of attribute keys defined in `serializeAttribute` and their values on element.\n const keyAttrPairs =\n keyAttrs && keyAttrs.length\n ? keyAttrs.filter(keyAttr => elem.getAttribute(keyAttr)).map(keyAttr => [keyAttr, elem.getAttribute(keyAttr)])\n : null;\n\n if (keyAttrPairs && keyAttrPairs.length) {\n keyAttrPairs.forEach(keyAttrPair => {\n out.push(`[${keyAttrPair[0]}=\"${keyAttrPair[1]}\"]`);\n });\n } else {\n if (elem.id) {\n out.push(`#${elem.id}`);\n }\n\n className = elem.className;\n if (className && isString(className)) {\n classes = className.split(/\\s+/);\n for (i = 0; i < classes.length; i++) {\n out.push(`.${classes[i]}`);\n }\n }\n }\n const allowedAttrs = ['aria-label', 'type', 'name', 'title', 'alt'];\n for (i = 0; i < allowedAttrs.length; i++) {\n key = allowedAttrs[i];\n attr = elem.getAttribute(key);\n if (attr) {\n out.push(`[${key}=\"${attr}\"]`);\n }\n }\n return out.join('');\n}\n\n/**\n * A safe form of location.href\n */\nexport function getLocationHref(): string {\n try {\n return WINDOW.document.location.href;\n } catch (oO) {\n return '';\n }\n}\n\n/**\n * Gets a DOM element by using document.querySelector.\n *\n * This wrapper will first check for the existance of the function before\n * actually calling it so that we don't have to take care of this check,\n * every time we want to access the DOM.\n *\n * Reason: DOM/querySelector is not available in all environments.\n *\n * We have to cast to any because utils can be consumed by a variety of environments,\n * and we don't want to break TS users. If you know what element will be selected by\n * `document.querySelector`, specify it as part of the generic call. For example,\n * `const element = getDomElement<Element>('selector');`\n *\n * @param selector the selector string passed on to document.querySelector\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function getDomElement<E = any>(selector: string): E | null {\n if (WINDOW.document && WINDOW.document.querySelector) {\n return WINDOW.document.querySelector(selector) as unknown as E;\n }\n return null;\n}\n\n/**\n * Given a DOM element, traverses up the tree until it finds the first ancestor node\n * that has the `data-sentry-component` or `data-sentry-element` attribute with `data-sentry-component` taking\n * precendence. This attribute is added at build-time by projects that have the component name annotation plugin installed.\n *\n * @returns a string representation of the component for the provided DOM element, or `null` if not found\n */\nexport function getComponentName(elem: unknown): string | null {\n // @ts-expect-error WINDOW has HTMLElement\n if (!WINDOW.HTMLElement) {\n return null;\n }\n\n let currentElem = elem as SimpleNode;\n const MAX_TRAVERSE_HEIGHT = 5;\n for (let i = 0; i < MAX_TRAVERSE_HEIGHT; i++) {\n if (!currentElem) {\n return null;\n }\n\n if (currentElem instanceof HTMLElement) {\n if (currentElem.dataset['sentryComponent']) {\n return currentElem.dataset['sentryComponent'];\n }\n if (currentElem.dataset['sentryElement']) {\n return currentElem.dataset['sentryElement'];\n }\n }\n\n currentElem = currentElem.parentNode;\n }\n\n return null;\n}\n", "declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n", "import type { ConsoleLevel } from '@sentry/types';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { GLOBAL_OBJ } from './worldwide';\n\n/** Prefix for logging strings */\nconst PREFIX = 'Sentry Logger ';\n\nexport const CONSOLE_LEVELS: readonly ConsoleLevel[] = [\n 'debug',\n 'info',\n 'warn',\n 'error',\n 'log',\n 'assert',\n 'trace',\n] as const;\n\ntype LoggerMethod = (...args: unknown[]) => void;\ntype LoggerConsoleMethods = Record<ConsoleLevel, LoggerMethod>;\n\n/** This may be mutated by the console instrumentation. */\nexport const originalConsoleMethods: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key in ConsoleLevel]?: (...args: any[]) => void;\n} = {};\n\n/** JSDoc */\ninterface Logger extends LoggerConsoleMethods {\n disable(): void;\n enable(): void;\n isEnabled(): boolean;\n}\n\n/**\n * Temporarily disable sentry console instrumentations.\n *\n * @param callback The function to run against the original `console` messages\n * @returns The results of the callback\n */\nexport function consoleSandbox<T>(callback: () => T): T {\n if (!('console' in GLOBAL_OBJ)) {\n return callback();\n }\n\n const console = GLOBAL_OBJ.console as Console;\n const wrappedFuncs: Partial<LoggerConsoleMethods> = {};\n\n const wrappedLevels = Object.keys(originalConsoleMethods) as ConsoleLevel[];\n\n // Restore all wrapped console methods\n wrappedLevels.forEach(level => {\n const originalConsoleMethod = originalConsoleMethods[level] as LoggerMethod;\n wrappedFuncs[level] = console[level] as LoggerMethod | undefined;\n console[level] = originalConsoleMethod;\n });\n\n try {\n return callback();\n } finally {\n // Revert restoration to wrapped state\n wrappedLevels.forEach(level => {\n console[level] = wrappedFuncs[level] as LoggerMethod;\n });\n }\n}\n\nfunction makeLogger(): Logger {\n let enabled = false;\n const logger: Partial<Logger> = {\n enable: () => {\n enabled = true;\n },\n disable: () => {\n enabled = false;\n },\n isEnabled: () => enabled,\n };\n\n if (DEBUG_BUILD) {\n CONSOLE_LEVELS.forEach(name => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n logger[name] = (...args: any[]) => {\n if (enabled) {\n consoleSandbox(() => {\n GLOBAL_OBJ.console[name](`${PREFIX}[${name}]:`, ...args);\n });\n }\n };\n });\n } else {\n CONSOLE_LEVELS.forEach(name => {\n logger[name] = () => undefined;\n });\n }\n\n return logger as Logger;\n}\n\nexport const logger = makeLogger();\n", "import type { DsnComponents, DsnLike, DsnProtocol } from '@sentry/types';\n\nimport { DEBUG_BUILD } from './debug-build';\nimport { consoleSandbox, logger } from './logger';\n\n/** Regular expression used to parse a Dsn. */\nconst DSN_REGEX = /^(?:(\\w+):)\\/\\/(?:(\\w+)(?::(\\w+)?)?@)([\\w.-]+)(?::(\\d+))?\\/(.+)/;\n\nfunction isValidProtocol(protocol?: string): protocol is DsnProtocol {\n return protocol === 'http' || protocol === 'https';\n}\n\n/**\n * Renders the string representation of this Dsn.\n *\n * By default, this will render the public representation without the password\n * component. To get the deprecated private representation, set `withPassword`\n * to true.\n *\n * @param withPassword When set to true, the password will be included.\n */\nexport function dsnToString(dsn: DsnComponents, withPassword: boolean = false): string {\n const { host, path, pass, port, projectId, protocol, publicKey } = dsn;\n return (\n `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ''}` +\n `@${host}${port ? `:${port}` : ''}/${path ? `${path}/` : path}${projectId}`\n );\n}\n\n/**\n * Parses a Dsn from a given string.\n *\n * @param str A Dsn as string\n * @returns Dsn as DsnComponents or undefined if @param str is not a valid DSN string\n */\nexport function dsnFromString(str: string): DsnComponents | undefined {\n const match = DSN_REGEX.exec(str);\n\n if (!match) {\n // This should be logged to the console\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.error(`Invalid Sentry Dsn: ${str}`);\n });\n return undefined;\n }\n\n const [protocol, publicKey, pass = '', host, port = '', lastPath] = match.slice(1);\n let path = '';\n let projectId = lastPath;\n\n const split = projectId.split('/');\n if (split.length > 1) {\n path = split.slice(0, -1).join('/');\n projectId = split.pop() as string;\n }\n\n if (projectId) {\n const projectMatch = projectId.match(/^\\d+/);\n if (projectMatch) {\n projectId = projectMatch[0];\n }\n }\n\n return dsnFromComponents({ host, pass, path, projectId, port, protocol: protocol as DsnProtocol, publicKey });\n}\n\nfunction dsnFromComponents(components: DsnComponents): DsnComponents {\n return {\n protocol: components.protocol,\n publicKey: components.publicKey || '',\n pass: components.pass || '',\n host: components.host,\n port: components.port || '',\n path: components.path || '',\n projectId: components.projectId,\n };\n}\n\nfunction validateDsn(dsn: DsnComponents): boolean {\n if (!DEBUG_BUILD) {\n return true;\n }\n\n const { port, projectId, protocol } = dsn;\n\n const requiredComponents: ReadonlyArray<keyof DsnComponents> = ['protocol', 'publicKey', 'host', 'projectId'];\n const hasMissingRequiredComponent = requiredComponents.find(component => {\n if (!dsn[component]) {\n logger.error(`Invalid Sentry Dsn: ${component} missing`);\n return true;\n }\n return false;\n });\n\n if (hasMissingRequiredComponent) {\n return false;\n }\n\n if (!projectId.match(/^\\d+$/)) {\n logger.error(`Invalid Sentry Dsn: Invalid projectId ${projectId}`);\n return false;\n }\n\n if (!isValidProtocol(protocol)) {\n logger.error(`Invalid Sentry Dsn: Invalid protocol ${protocol}`);\n return false;\n }\n\n if (port && isNaN(parseInt(port, 10))) {\n logger.error(`Invalid Sentry Dsn: Invalid port ${port}`);\n return false;\n }\n\n return true;\n}\n\n/**\n * Creates a valid Sentry Dsn object, identifying a Sentry instance and project.\n * @returns a valid DsnComponents object or `undefined` if @param from is an invalid DSN source\n */\nexport function makeDsn(from: DsnLike): DsnComponents | undefined {\n const components = typeof from === 'string' ? dsnFromString(from) : dsnFromComponents(from);\n if (!components || !validateDsn(components)) {\n return undefined;\n }\n return components;\n}\n", "import type { ConsoleLevel } from '@sentry/types';\n\n/** An error emitted by Sentry SDKs and related utilities. */\nexport class SentryError extends Error {\n /** Display name of this error instance. */\n public name: string;\n\n public logLevel: ConsoleLevel;\n\n public constructor(public message: string, logLevel: ConsoleLevel = 'warn') {\n super(message);\n\n this.name = new.target.prototype.constructor.name;\n // This sets the prototype to be `Error`, not `SentryError`. It's unclear why we do this, but commenting this line\n // out causes various (seemingly totally unrelated) playwright tests consistently time out. FYI, this makes\n // instances of `SentryError` fail `obj instanceof SentryError` checks.\n Object.setPrototypeOf(this, new.target.prototype);\n this.logLevel = logLevel;\n }\n}\n", "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type { WrappedFunction } from '@sentry/types';\n\nimport { htmlTreeAsString } from './browser';\nimport { DEBUG_BUILD } from './debug-build';\nimport { isElement, isError, isEvent, isInstanceOf, isPlainObject, isPrimitive } from './is';\nimport { logger } from './logger';\nimport { truncate } from './string';\n\n/**\n * Replace a method in an object with a wrapped version of itself.\n *\n * @param source An object that contains a method to be wrapped.\n * @param name The name of the method to be wrapped.\n * @param replacementFactory A higher-order function that takes the original version of the given method and returns a\n * wrapped version. Note: The function returned by `replacementFactory` needs to be a non-arrow function, in order to\n * preserve the correct value of `this`, and the original method must be called using `origMethod.call(this, <other\n * args>)` or `origMethod.apply(this, [<other args>])` (rather than being called directly), again to preserve `this`.\n * @returns void\n */\nexport function fill(source: { [key: string]: any }, name: string, replacementFactory: (...args: any[]) => any): void {\n if (!(name in source)) {\n return;\n }\n\n const original = source[name] as () => any;\n const wrapped = replacementFactory(original) as WrappedFunction;\n\n // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work\n // otherwise it'll throw \"TypeError: Object.defineProperties called on non-object\"\n if (typeof wrapped === 'function') {\n markFunctionWrapped(wrapped, original);\n }\n\n source[name] = wrapped;\n}\n\n/**\n * Defines a non-enumerable property on the given object.\n *\n * @param obj The object on which to set the property\n * @param name The name of the property to be set\n * @param value The value to which to set the property\n */\nexport function addNonEnumerableProperty(obj: object, name: string, value: unknown): void {\n try {\n Object.defineProperty(obj, name, {\n // enumerable: false, // the default, so we can save on bundle size by not explicitly setting it\n value: value,\n writable: true,\n configurable: true,\n });\n } catch (o_O) {\n DEBUG_BUILD && logger.log(`Failed to add non-enumerable property \"${name}\" to object`, obj);\n }\n}\n\n/**\n * Remembers the original function on the wrapped function and\n * patches up the prototype.\n *\n * @param wrapped the wrapper function\n * @param original the original function that gets wrapped\n */\nexport function markFunctionWrapped(wrapped: WrappedFunction, original: WrappedFunction): void {\n try {\n const proto = original.prototype || {};\n wrapped.prototype = original.prototype = proto;\n addNonEnumerableProperty(wrapped, '__sentry_original__', original);\n } catch (o_O) {} // eslint-disable-line no-empty\n}\n\n/**\n * This extracts the original function if available. See\n * `markFunctionWrapped` for more information.\n *\n * @param func the function to unwrap\n * @returns the unwrapped version of the function if available.\n */\nexport function getOriginalFunction(func: WrappedFunction): WrappedFunction | undefined {\n return func.__sentry_original__;\n}\n\n/**\n * Encodes given object into url-friendly format\n *\n * @param object An object that contains serializable values\n * @returns string Encoded\n */\nexport function urlEncode(object: { [key: string]: any }): string {\n return Object.keys(object)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(object[key])}`)\n .join('&');\n}\n\n/**\n * Transforms any `Error` or `Event` into a plain object with all of their enumerable properties, and some of their\n * non-enumerable properties attached.\n *\n * @param value Initial source that we have to transform in order for it to be usable by the serializer\n * @returns An Event or Error turned into an object - or the value argurment itself, when value is neither an Event nor\n * an Error.\n */\nexport function convertToPlainObject<V>(\n value: V,\n):\n | {\n [ownProps: string]: unknown;\n type: string;\n target: string;\n currentTarget: string;\n detail?: unknown;\n }\n | {\n [ownProps: string]: unknown;\n message: string;\n name: string;\n stack?: string;\n }\n | V {\n if (isError(value)) {\n return {\n message: value.message,\n name: value.name,\n stack: value.stack,\n ...getOwnProperties(value),\n };\n } else if (isEvent(value)) {\n const newObj: {\n [ownProps: string]: unknown;\n type: string;\n target: string;\n currentTarget: string;\n detail?: unknown;\n } = {\n type: value.type,\n target: serializeEventTarget(value.target),\n currentTarget: serializeEventTarget(value.currentTarget),\n ...getOwnProperties(value),\n };\n\n if (typeof CustomEvent !== 'undefined' && isInstanceOf(value, CustomEvent)) {\n newObj.detail = value.detail;\n }\n\n return newObj;\n } else {\n return value;\n }\n}\n\n/** Creates a string representation of the target of an `Event` object */\nfunction serializeEventTarget(target: unknown): string {\n try {\n return isElement(target) ? htmlTreeAsString(target) : Object.prototype.toString.call(target);\n } catch (_oO) {\n return '<unknown>';\n }\n}\n\n/** Filters out all but an object's own properties */\nfunction getOwnProperties(obj: unknown): { [key: string]: unknown } {\n if (typeof obj === 'object' && obj !== null) {\n const extractedProps: { [key: string]: unknown } = {};\n for (const property in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, property)) {\n extractedProps[property] = (obj as Record<string, unknown>)[property];\n }\n }\n return extractedProps;\n } else {\n return {};\n }\n}\n\n/**\n * Given any captured exception, extract its keys and create a sorted\n * and truncated list that will be used inside the event message.\n * eg. `Non-error exception captured with keys: foo, bar, baz`\n */\nexport function extractExceptionKeysForMessage(exception: Record<string, unknown>, maxLength: number = 40): string {\n const keys = Object.keys(convertToPlainObject(exception));\n keys.sort();\n\n if (!keys.length) {\n return '[object has no keys]';\n }\n\n if (keys[0].length >= maxLength) {\n return truncate(keys[0], maxLength);\n }\n\n for (