@sentry/core 10.50.0 → 10.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/client.js +27 -3
- package/build/cjs/client.js.map +1 -1
- package/build/cjs/envelope.js +4 -1
- package/build/cjs/envelope.js.map +1 -1
- package/build/cjs/index.js +10 -5
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrument/console.js +3 -1
- package/build/cjs/instrument/console.js.map +1 -1
- package/build/cjs/instrument/fetch.js +6 -2
- package/build/cjs/instrument/fetch.js.map +1 -1
- package/build/cjs/instrument/handlers.js +11 -1
- package/build/cjs/instrument/handlers.js.map +1 -1
- package/build/cjs/integrations/console.js +3 -1
- package/build/cjs/integrations/console.js.map +1 -1
- package/build/cjs/integrations/extraerrordata.js +2 -2
- package/build/cjs/integrations/extraerrordata.js.map +1 -1
- package/build/cjs/integrations/postgresjs.js +10 -1
- package/build/cjs/integrations/postgresjs.js.map +1 -1
- package/build/cjs/integrations/requestdata.js +9 -5
- package/build/cjs/integrations/requestdata.js.map +1 -1
- package/build/cjs/integrations/supabase.js +39 -12
- package/build/cjs/integrations/supabase.js.map +1 -1
- package/build/cjs/logs/console-integration.js +3 -1
- package/build/cjs/logs/console-integration.js.map +1 -1
- package/build/cjs/server-runtime-client.js +20 -2
- package/build/cjs/server-runtime-client.js.map +1 -1
- package/build/cjs/tracing/ai/gen-ai-attributes.js +6 -0
- package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
- package/build/cjs/tracing/idleSpan.js +7 -1
- package/build/cjs/tracing/idleSpan.js.map +1 -1
- package/build/cjs/tracing/langchain/index.js +43 -8
- package/build/cjs/tracing/langchain/index.js.map +1 -1
- package/build/cjs/tracing/langchain/utils.js +44 -10
- package/build/cjs/tracing/langchain/utils.js.map +1 -1
- package/build/cjs/tracing/langgraph/index.js +105 -2
- package/build/cjs/tracing/langgraph/index.js.map +1 -1
- package/build/cjs/tracing/langgraph/utils.js +168 -0
- package/build/cjs/tracing/langgraph/utils.js.map +1 -1
- package/build/cjs/tracing/spans/captureSpan.js +125 -0
- package/build/cjs/tracing/spans/captureSpan.js.map +1 -1
- package/build/cjs/tracing/spans/envelope.js +13 -3
- package/build/cjs/tracing/spans/envelope.js.map +1 -1
- package/build/cjs/tracing/trace.js +1 -0
- package/build/cjs/tracing/trace.js.map +1 -1
- package/build/cjs/trpc.js +2 -3
- package/build/cjs/trpc.js.map +1 -1
- package/build/cjs/utils/isSentryRequestUrl.js +9 -1
- package/build/cjs/utils/isSentryRequestUrl.js.map +1 -1
- package/build/cjs/utils/normalizationHints.js +38 -0
- package/build/cjs/utils/normalizationHints.js.map +1 -0
- package/build/cjs/utils/normalize.js +7 -11
- package/build/cjs/utils/normalize.js.map +1 -1
- package/build/cjs/utils/object.js +1 -1
- package/build/cjs/utils/object.js.map +1 -1
- package/build/cjs/utils/request.js +63 -12
- package/build/cjs/utils/request.js.map +1 -1
- package/build/cjs/utils/should-ignore-span.js +27 -8
- package/build/cjs/utils/should-ignore-span.js.map +1 -1
- package/build/cjs/utils/version.js +1 -1
- package/build/esm/client.js +27 -3
- package/build/esm/client.js.map +1 -1
- package/build/esm/envelope.js +4 -1
- package/build/esm/envelope.js.map +1 -1
- package/build/esm/index.js +3 -2
- package/build/esm/index.js.map +1 -1
- package/build/esm/instrument/console.js +3 -1
- package/build/esm/instrument/console.js.map +1 -1
- package/build/esm/instrument/fetch.js +6 -2
- package/build/esm/instrument/fetch.js.map +1 -1
- package/build/esm/instrument/handlers.js +11 -1
- package/build/esm/instrument/handlers.js.map +1 -1
- package/build/esm/integrations/console.js +3 -1
- package/build/esm/integrations/console.js.map +1 -1
- package/build/esm/integrations/extraerrordata.js +2 -2
- package/build/esm/integrations/extraerrordata.js.map +1 -1
- package/build/esm/integrations/postgresjs.js +10 -1
- package/build/esm/integrations/postgresjs.js.map +1 -1
- package/build/esm/integrations/requestdata.js +9 -5
- package/build/esm/integrations/requestdata.js.map +1 -1
- package/build/esm/integrations/supabase.js +39 -12
- package/build/esm/integrations/supabase.js.map +1 -1
- package/build/esm/logs/console-integration.js +3 -1
- package/build/esm/logs/console-integration.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server-runtime-client.js +20 -2
- package/build/esm/server-runtime-client.js.map +1 -1
- package/build/esm/tracing/ai/gen-ai-attributes.js +6 -1
- package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
- package/build/esm/tracing/idleSpan.js +7 -1
- package/build/esm/tracing/idleSpan.js.map +1 -1
- package/build/esm/tracing/langchain/index.js +45 -10
- package/build/esm/tracing/langchain/index.js.map +1 -1
- package/build/esm/tracing/langchain/utils.js +44 -12
- package/build/esm/tracing/langchain/utils.js.map +1 -1
- package/build/esm/tracing/langgraph/index.js +107 -5
- package/build/esm/tracing/langgraph/index.js.map +1 -1
- package/build/esm/tracing/langgraph/utils.js +166 -2
- package/build/esm/tracing/langgraph/utils.js.map +1 -1
- package/build/esm/tracing/spans/captureSpan.js +126 -2
- package/build/esm/tracing/spans/captureSpan.js.map +1 -1
- package/build/esm/tracing/spans/envelope.js +13 -3
- package/build/esm/tracing/spans/envelope.js.map +1 -1
- package/build/esm/tracing/trace.js +1 -0
- package/build/esm/tracing/trace.js.map +1 -1
- package/build/esm/trpc.js +2 -3
- package/build/esm/trpc.js.map +1 -1
- package/build/esm/utils/isSentryRequestUrl.js +9 -1
- package/build/esm/utils/isSentryRequestUrl.js.map +1 -1
- package/build/esm/utils/normalizationHints.js +33 -0
- package/build/esm/utils/normalizationHints.js.map +1 -0
- package/build/esm/utils/normalize.js +7 -11
- package/build/esm/utils/normalize.js.map +1 -1
- package/build/esm/utils/object.js +1 -1
- package/build/esm/utils/object.js.map +1 -1
- package/build/esm/utils/request.js +63 -12
- package/build/esm/utils/request.js.map +1 -1
- package/build/esm/utils/should-ignore-span.js +27 -8
- package/build/esm/utils/should-ignore-span.js.map +1 -1
- package/build/esm/utils/version.js +1 -1
- package/build/types/client.d.ts +12 -1
- package/build/types/client.d.ts.map +1 -1
- package/build/types/envelope.d.ts.map +1 -1
- package/build/types/index.d.ts +4 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrument/console.d.ts +2 -1
- package/build/types/instrument/console.d.ts.map +1 -1
- package/build/types/instrument/fetch.d.ts +4 -2
- package/build/types/instrument/fetch.d.ts.map +1 -1
- package/build/types/instrument/handlers.d.ts +2 -2
- package/build/types/instrument/handlers.d.ts.map +1 -1
- package/build/types/integrations/console.d.ts.map +1 -1
- package/build/types/integrations/postgresjs.d.ts.map +1 -1
- package/build/types/integrations/supabase.d.ts.map +1 -1
- package/build/types/logs/console-integration.d.ts.map +1 -1
- package/build/types/server-runtime-client.d.ts +5 -0
- package/build/types/server-runtime-client.d.ts.map +1 -1
- package/build/types/tracing/idleSpan.d.ts.map +1 -1
- package/build/types/tracing/langchain/index.d.ts.map +1 -1
- package/build/types/tracing/langchain/types.d.ts +8 -0
- package/build/types/tracing/langchain/types.d.ts.map +1 -1
- package/build/types/tracing/langchain/utils.d.ts +2 -0
- package/build/types/tracing/langchain/utils.d.ts.map +1 -1
- package/build/types/tracing/langgraph/index.d.ts +4 -0
- package/build/types/tracing/langgraph/index.d.ts.map +1 -1
- package/build/types/tracing/langgraph/utils.d.ts +18 -2
- package/build/types/tracing/langgraph/utils.d.ts.map +1 -1
- package/build/types/tracing/spans/captureSpan.d.ts +10 -0
- package/build/types/tracing/spans/captureSpan.d.ts.map +1 -1
- package/build/types/tracing/spans/envelope.d.ts.map +1 -1
- package/build/types/trpc.d.ts.map +1 -1
- package/build/types/types-hoist/feedback/config.d.ts +20 -0
- package/build/types/types-hoist/feedback/config.d.ts.map +1 -1
- package/build/types/types-hoist/feedback/index.d.ts +2 -2
- package/build/types/types-hoist/feedback/index.d.ts.map +1 -1
- package/build/types/types-hoist/feedback/sendFeedback.d.ts +3 -0
- package/build/types/types-hoist/feedback/sendFeedback.d.ts.map +1 -1
- package/build/types/types-hoist/options.d.ts +37 -2
- package/build/types/types-hoist/options.d.ts.map +1 -1
- package/build/types/types-hoist/span.d.ts +5 -0
- package/build/types/types-hoist/span.d.ts.map +1 -1
- package/build/types/utils/normalizationHints.d.ts +9 -0
- package/build/types/utils/normalizationHints.d.ts.map +1 -0
- package/build/types/utils/normalize.d.ts.map +1 -1
- package/build/types/utils/object.d.ts +1 -1
- package/build/types/utils/object.d.ts.map +1 -1
- package/build/types/utils/request.d.ts.map +1 -1
- package/build/types/utils/should-ignore-span.d.ts +3 -1
- package/build/types/utils/should-ignore-span.d.ts.map +1 -1
- package/build/types-ts3.8/client.d.ts +12 -1
- package/build/types-ts3.8/index.d.ts +4 -2
- package/build/types-ts3.8/instrument/console.d.ts +2 -1
- package/build/types-ts3.8/instrument/fetch.d.ts +4 -2
- package/build/types-ts3.8/instrument/handlers.d.ts +2 -2
- package/build/types-ts3.8/server-runtime-client.d.ts +5 -0
- package/build/types-ts3.8/tracing/langchain/types.d.ts +8 -0
- package/build/types-ts3.8/tracing/langchain/utils.d.ts +2 -0
- package/build/types-ts3.8/tracing/langgraph/index.d.ts +4 -0
- package/build/types-ts3.8/tracing/langgraph/utils.d.ts +18 -2
- package/build/types-ts3.8/tracing/spans/captureSpan.d.ts +10 -0
- package/build/types-ts3.8/types-hoist/feedback/config.d.ts +20 -0
- package/build/types-ts3.8/types-hoist/feedback/index.d.ts +2 -2
- package/build/types-ts3.8/types-hoist/feedback/sendFeedback.d.ts +3 -0
- package/build/types-ts3.8/types-hoist/options.d.ts +37 -2
- package/build/types-ts3.8/types-hoist/span.d.ts +5 -0
- package/build/types-ts3.8/utils/normalizationHints.d.ts +9 -0
- package/build/types-ts3.8/utils/object.d.ts +1 -1
- package/build/types-ts3.8/utils/should-ignore-span.d.ts +3 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const is = require('./is.js');
|
|
4
|
+
const normalizationHints = require('./normalizationHints.js');
|
|
4
5
|
const object = require('./object.js');
|
|
5
6
|
const stacktrace = require('./stacktrace.js');
|
|
6
7
|
|
|
@@ -88,20 +89,15 @@ function visit(
|
|
|
88
89
|
|
|
89
90
|
// From here on, we can assert that `value` is either an object or an array.
|
|
90
91
|
|
|
91
|
-
// Do not normalize objects that we know have already been normalized.
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
if ((value )['__sentry_skip_normalization__']) {
|
|
92
|
+
// Do not normalize objects that we know have already been normalized. Hints use internal symbols
|
|
93
|
+
// (see normalizationHints.ts) so user-controlled JSON cannot spoof them.
|
|
94
|
+
if (normalizationHints.hasSkipNormalizationHint(value)) {
|
|
95
95
|
return value ;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const remainingDepth =
|
|
102
|
-
typeof (value )['__sentry_override_normalization_depth__'] === 'number'
|
|
103
|
-
? ((value )['__sentry_override_normalization_depth__'] )
|
|
104
|
-
: depth;
|
|
98
|
+
// Override remaining depth from this node (e.g. Redux / Pinia state). Set via setNormalizationDepthOverrideHint.
|
|
99
|
+
const overrideDepth = normalizationHints.getNormalizationDepthOverrideHint(value);
|
|
100
|
+
const remainingDepth = overrideDepth !== undefined ? overrideDepth : depth;
|
|
105
101
|
|
|
106
102
|
// We're also done if we've reached the max depth
|
|
107
103
|
if (remainingDepth === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.js","sources":["../../../src/utils/normalize.ts"],"sourcesContent":["import type { Primitive } from '../types-hoist/misc';\nimport { isSyntheticEvent, isVueViewModel } from './is';\nimport { convertToPlainObject } from './object';\nimport { getFunctionName, getVueInternalName } from './stacktrace';\n\ntype Prototype = { constructor?: (...args: unknown[]) => unknown };\n// This is a hack to placate TS, relying on the fact that technically, arrays are objects with integer keys. Normally we\n// think of those keys as actual numbers, but `arr['0']` turns out to work just as well as `arr[0]`, and doing it this\n// way lets us use a single type in the places where behave as if we are only dealing with objects, even if some of them\n// might be arrays.\ntype ObjOrArray<T> = { [key: string]: T };\n\ntype MemoFunc = [\n // memoize\n (obj: object) => boolean,\n // unmemoize\n (obj: object) => void,\n];\n\n/**\n * Recursively normalizes the given object.\n *\n * - Creates a copy to prevent original input mutation\n * - Skips non-enumerable properties\n * - When stringifying, calls `toJSON` if implemented\n * - Removes circular references\n * - Translates non-serializable values (`undefined`/`NaN`/functions) to serializable format\n * - Translates known global objects/classes to a string representations\n * - Takes care of `Error` object serialization\n * - Optionally limits depth of final output\n * - Optionally limits number of properties/elements included in any single object/array\n *\n * @param input The object to be normalized.\n * @param depth The max depth to which to normalize the object. (Anything deeper stringified whole.)\n * @param maxProperties The max number of elements or properties to be included in any single array or\n * object in the normalized output.\n * @returns A normalized version of the object, or `\"**non-serializable**\"` if any errors are thrown during normalization.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function normalize(input: unknown, depth: number = 100, maxProperties: number = +Infinity): any {\n try {\n // since we're at the outermost level, we don't provide a key\n return visit('', input, depth, maxProperties);\n } catch (err) {\n return { ERROR: `**non-serializable** (${err})` };\n }\n}\n\n/** JSDoc */\nexport function normalizeToSize<T>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n object: { [key: string]: any },\n // Default Node.js REPL depth\n depth: number = 3,\n // 100kB, as 200kB is max payload size, so half sounds reasonable\n maxSize: number = 100 * 1024,\n): T {\n const normalized = normalize(object, depth);\n\n if (jsonSize(normalized) > maxSize) {\n return normalizeToSize(object, depth - 1, maxSize);\n }\n\n return normalized as T;\n}\n\n/**\n * Visits a node to perform normalization on it\n *\n * @param key The key corresponding to the given node\n * @param value The node to be visited\n * @param depth Optional number indicating the maximum recursion depth\n * @param maxProperties Optional maximum number of properties/elements included in any single object/array\n * @param memo Optional Memo class handling decycling\n */\nfunction visit(\n key: string,\n value: unknown,\n depth: number = +Infinity,\n maxProperties: number = +Infinity,\n memo = memoBuilder(),\n): Primitive | ObjOrArray<unknown> {\n const [memoize, unmemoize] = memo;\n\n // Get the simple cases out of the way first\n if (\n value == null || // this matches null and undefined -> eqeq not eqeqeq\n ['boolean', 'string'].includes(typeof value) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n return value as Primitive;\n }\n\n const stringified = stringifyValue(key, value);\n\n // Anything we could potentially dig into more (objects or arrays) will have come back as `\"[object XXXX]\"`.\n // Everything else will have already been serialized, so if we don't see that pattern, we're done.\n if (!stringified.startsWith('[object ')) {\n return stringified;\n }\n\n // From here on, we can assert that `value` is either an object or an array.\n\n // Do not normalize objects that we know have already been normalized. As a general rule, the\n // \"__sentry_skip_normalization__\" property should only be used sparingly and only should only be set on objects that\n // have already been normalized.\n if ((value as ObjOrArray<unknown>)['__sentry_skip_normalization__']) {\n return value as ObjOrArray<unknown>;\n }\n\n // We can set `__sentry_override_normalization_depth__` on an object to ensure that from there\n // We keep a certain amount of depth.\n // This should be used sparingly, e.g. we use it for the redux integration to ensure we get a certain amount of state.\n const remainingDepth =\n typeof (value as ObjOrArray<unknown>)['__sentry_override_normalization_depth__'] === 'number'\n ? ((value as ObjOrArray<unknown>)['__sentry_override_normalization_depth__'] as number)\n : depth;\n\n // We're also done if we've reached the max depth\n if (remainingDepth === 0) {\n // At this point we know `serialized` is a string of the form `\"[object XXXX]\"`. Clean it up so it's just `\"[XXXX]\"`.\n return stringified.replace('object ', '');\n }\n\n // If we've already visited this branch, bail out, as it's circular reference. If not, note that we're seeing it now.\n if (memoize(value)) {\n return '[Circular ~]';\n }\n\n // If the value has a `toJSON` method, we call it to extract more information\n const valueWithToJSON = value as unknown & { toJSON?: () => unknown };\n if (valueWithToJSON && typeof valueWithToJSON.toJSON === 'function') {\n try {\n const jsonValue = valueWithToJSON.toJSON();\n // We need to normalize the return value of `.toJSON()` in case it has circular references\n return visit('', jsonValue, remainingDepth - 1, maxProperties, memo);\n } catch {\n // pass (The built-in `toJSON` failed, but we can still try to do it ourselves)\n }\n }\n\n // At this point we know we either have an object or an array, we haven't seen it before, and we're going to recurse\n // because we haven't yet reached the max depth. Create an accumulator to hold the results of visiting each\n // property/entry, and keep track of the number of items we add to it.\n const normalized = (Array.isArray(value) ? [] : {}) as ObjOrArray<unknown>;\n let numAdded = 0;\n\n // Before we begin, convert`Error` and`Event` instances into plain objects, since some of each of their relevant\n // properties are non-enumerable and otherwise would get missed.\n const visitable = convertToPlainObject(value as ObjOrArray<unknown>);\n\n for (const visitKey in visitable) {\n // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration.\n if (!Object.prototype.hasOwnProperty.call(visitable, visitKey)) {\n continue;\n }\n\n if (numAdded >= maxProperties) {\n normalized[visitKey] = '[MaxProperties ~]';\n break;\n }\n\n // Recursively visit all the child nodes\n const visitValue = visitable[visitKey];\n normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo);\n\n numAdded++;\n }\n\n // Once we've visited all the branches, remove the parent from memo storage\n unmemoize(value);\n\n // Return accumulated values\n return normalized;\n}\n\n/* eslint-disable complexity */\n/**\n * Stringify the given value. Handles various known special values and types.\n *\n * Not meant to be used on simple primitives which already have a string representation, as it will, for example, turn\n * the number 1231 into \"[Object Number]\", nor on `null`, as it will throw.\n *\n * @param value The value to stringify\n * @returns A stringified representation of the given value\n */\nfunction stringifyValue(\n key: unknown,\n // this type is a tiny bit of a cheat, since this function does handle NaN (which is technically a number), but for\n // our internal use, it'll do\n value: Exclude<unknown, string | number | boolean | null>,\n): string {\n try {\n if (key === 'domain' && value && typeof value === 'object' && (value as { _events: unknown })._events) {\n return '[Domain]';\n }\n\n if (key === 'domainEmitter') {\n return '[DomainEmitter]';\n }\n\n // It's safe to use `global`, `window`, and `document` here in this manner, as we are asserting using `typeof` first\n // which won't throw if they are not present.\n\n if (typeof global !== 'undefined' && value === global) {\n return '[Global]';\n }\n\n // eslint-disable-next-line no-restricted-globals\n if (typeof window !== 'undefined' && value === window) {\n return '[Window]';\n }\n\n // eslint-disable-next-line no-restricted-globals\n if (typeof document !== 'undefined' && value === document) {\n return '[Document]';\n }\n\n if (isVueViewModel(value)) {\n return getVueInternalName(value);\n }\n\n // React's SyntheticEvent thingy\n if (isSyntheticEvent(value)) {\n return '[SyntheticEvent]';\n }\n\n if (typeof value === 'number' && !Number.isFinite(value)) {\n return `[${value}]`;\n }\n\n if (typeof value === 'function') {\n return `[Function: ${getFunctionName(value)}]`;\n }\n\n if (typeof value === 'symbol') {\n return `[${String(value)}]`;\n }\n\n // stringified BigInts are indistinguishable from regular numbers, so we need to label them to avoid confusion\n if (typeof value === 'bigint') {\n return `[BigInt: ${String(value)}]`;\n }\n\n // Now that we've knocked out all the special cases and the primitives, all we have left are objects. Simply casting\n // them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as\n // `\"[object Object]\"`. If we instead look at the constructor's name (which is the same as the name of the class),\n // we can make sure that only plain objects come out that way.\n const objName = getConstructorName(value);\n\n // Handle HTML Elements\n if (/^HTML(\\w*)Element$/.test(objName)) {\n return `[HTMLElement: ${objName}]`;\n }\n\n return `[object ${objName}]`;\n } catch (err) {\n return `**non-serializable** (${err})`;\n }\n}\n/* eslint-enable complexity */\n\nfunction getConstructorName(value: unknown): string {\n const prototype: Prototype | null = Object.getPrototypeOf(value);\n\n return prototype?.constructor ? prototype.constructor.name : 'null prototype';\n}\n\n/** Calculates bytes size of input string */\nfunction utf8Length(value: string): number {\n // eslint-disable-next-line no-bitwise\n return ~-encodeURI(value).split(/%..|./).length;\n}\n\n/** Calculates bytes size of input object */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction jsonSize(value: any): number {\n return utf8Length(JSON.stringify(value));\n}\n\n/**\n * Normalizes URLs in exceptions and stacktraces to a base path so Sentry can fingerprint\n * across platforms and working directory.\n *\n * @param url The URL to be normalized.\n * @param basePath The application base path.\n * @returns The normalized URL.\n */\nexport function normalizeUrlToBase(url: string, basePath: string): string {\n const escapedBase = basePath\n // Backslash to forward\n .replace(/\\\\/g, '/')\n // Escape RegExp special characters\n .replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&');\n\n let newUrl = url;\n try {\n newUrl = decodeURI(url);\n } catch {\n // Sometime this breaks\n }\n return (\n newUrl\n .replace(/\\\\/g, '/')\n .replace(/webpack:\\/?/g, '') // Remove intermediate base path\n // oxlint-disable-next-line sdk/no-regexp-constructor\n .replace(new RegExp(`(file://)?/*${escapedBase}/*`, 'ig'), 'app:///')\n );\n}\n\n/**\n * Helper to decycle json objects\n */\nfunction memoBuilder(): MemoFunc {\n const inner = new WeakSet<object>();\n function memoize(obj: object): boolean {\n if (inner.has(obj)) {\n return true;\n }\n inner.add(obj);\n return false;\n }\n\n function unmemoize(obj: object): void {\n inner.delete(obj);\n }\n return [memoize, unmemoize];\n}\n"],"names":["convertToPlainObject","isVueViewModel","getVueInternalName","isSyntheticEvent","getFunctionName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"normalize.js","sources":["../../../src/utils/normalize.ts"],"sourcesContent":["import type { Primitive } from '../types-hoist/misc';\nimport { isSyntheticEvent, isVueViewModel } from './is';\nimport { getNormalizationDepthOverrideHint, hasSkipNormalizationHint } from './normalizationHints';\nimport { convertToPlainObject } from './object';\nimport { getFunctionName, getVueInternalName } from './stacktrace';\n\ntype Prototype = { constructor?: (...args: unknown[]) => unknown };\n// This is a hack to placate TS, relying on the fact that technically, arrays are objects with integer keys. Normally we\n// think of those keys as actual numbers, but `arr['0']` turns out to work just as well as `arr[0]`, and doing it this\n// way lets us use a single type in the places where behave as if we are only dealing with objects, even if some of them\n// might be arrays.\ntype ObjOrArray<T> = { [key: string]: T };\n\ntype MemoFunc = [\n // memoize\n (obj: object) => boolean,\n // unmemoize\n (obj: object) => void,\n];\n\n/**\n * Recursively normalizes the given object.\n *\n * - Creates a copy to prevent original input mutation\n * - Skips non-enumerable properties\n * - When stringifying, calls `toJSON` if implemented\n * - Removes circular references\n * - Translates non-serializable values (`undefined`/`NaN`/functions) to serializable format\n * - Translates known global objects/classes to a string representations\n * - Takes care of `Error` object serialization\n * - Optionally limits depth of final output\n * - Optionally limits number of properties/elements included in any single object/array\n *\n * @param input The object to be normalized.\n * @param depth The max depth to which to normalize the object. (Anything deeper stringified whole.)\n * @param maxProperties The max number of elements or properties to be included in any single array or\n * object in the normalized output.\n * @returns A normalized version of the object, or `\"**non-serializable**\"` if any errors are thrown during normalization.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function normalize(input: unknown, depth: number = 100, maxProperties: number = +Infinity): any {\n try {\n // since we're at the outermost level, we don't provide a key\n return visit('', input, depth, maxProperties);\n } catch (err) {\n return { ERROR: `**non-serializable** (${err})` };\n }\n}\n\n/** JSDoc */\nexport function normalizeToSize<T>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n object: { [key: string]: any },\n // Default Node.js REPL depth\n depth: number = 3,\n // 100kB, as 200kB is max payload size, so half sounds reasonable\n maxSize: number = 100 * 1024,\n): T {\n const normalized = normalize(object, depth);\n\n if (jsonSize(normalized) > maxSize) {\n return normalizeToSize(object, depth - 1, maxSize);\n }\n\n return normalized as T;\n}\n\n/**\n * Visits a node to perform normalization on it\n *\n * @param key The key corresponding to the given node\n * @param value The node to be visited\n * @param depth Optional number indicating the maximum recursion depth\n * @param maxProperties Optional maximum number of properties/elements included in any single object/array\n * @param memo Optional Memo class handling decycling\n */\nfunction visit(\n key: string,\n value: unknown,\n depth: number = +Infinity,\n maxProperties: number = +Infinity,\n memo = memoBuilder(),\n): Primitive | ObjOrArray<unknown> {\n const [memoize, unmemoize] = memo;\n\n // Get the simple cases out of the way first\n if (\n value == null || // this matches null and undefined -> eqeq not eqeqeq\n ['boolean', 'string'].includes(typeof value) ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n return value as Primitive;\n }\n\n const stringified = stringifyValue(key, value);\n\n // Anything we could potentially dig into more (objects or arrays) will have come back as `\"[object XXXX]\"`.\n // Everything else will have already been serialized, so if we don't see that pattern, we're done.\n if (!stringified.startsWith('[object ')) {\n return stringified;\n }\n\n // From here on, we can assert that `value` is either an object or an array.\n\n // Do not normalize objects that we know have already been normalized. Hints use internal symbols\n // (see normalizationHints.ts) so user-controlled JSON cannot spoof them.\n if (hasSkipNormalizationHint(value)) {\n return value as ObjOrArray<unknown>;\n }\n\n // Override remaining depth from this node (e.g. Redux / Pinia state). Set via setNormalizationDepthOverrideHint.\n const overrideDepth = getNormalizationDepthOverrideHint(value);\n const remainingDepth = overrideDepth !== undefined ? overrideDepth : depth;\n\n // We're also done if we've reached the max depth\n if (remainingDepth === 0) {\n // At this point we know `serialized` is a string of the form `\"[object XXXX]\"`. Clean it up so it's just `\"[XXXX]\"`.\n return stringified.replace('object ', '');\n }\n\n // If we've already visited this branch, bail out, as it's circular reference. If not, note that we're seeing it now.\n if (memoize(value)) {\n return '[Circular ~]';\n }\n\n // If the value has a `toJSON` method, we call it to extract more information\n const valueWithToJSON = value as unknown & { toJSON?: () => unknown };\n if (valueWithToJSON && typeof valueWithToJSON.toJSON === 'function') {\n try {\n const jsonValue = valueWithToJSON.toJSON();\n // We need to normalize the return value of `.toJSON()` in case it has circular references\n return visit('', jsonValue, remainingDepth - 1, maxProperties, memo);\n } catch {\n // pass (The built-in `toJSON` failed, but we can still try to do it ourselves)\n }\n }\n\n // At this point we know we either have an object or an array, we haven't seen it before, and we're going to recurse\n // because we haven't yet reached the max depth. Create an accumulator to hold the results of visiting each\n // property/entry, and keep track of the number of items we add to it.\n const normalized = (Array.isArray(value) ? [] : {}) as ObjOrArray<unknown>;\n let numAdded = 0;\n\n // Before we begin, convert`Error` and`Event` instances into plain objects, since some of each of their relevant\n // properties are non-enumerable and otherwise would get missed.\n const visitable = convertToPlainObject(value as ObjOrArray<unknown>);\n\n for (const visitKey in visitable) {\n // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration.\n if (!Object.prototype.hasOwnProperty.call(visitable, visitKey)) {\n continue;\n }\n\n if (numAdded >= maxProperties) {\n normalized[visitKey] = '[MaxProperties ~]';\n break;\n }\n\n // Recursively visit all the child nodes\n const visitValue = visitable[visitKey];\n normalized[visitKey] = visit(visitKey, visitValue, remainingDepth - 1, maxProperties, memo);\n\n numAdded++;\n }\n\n // Once we've visited all the branches, remove the parent from memo storage\n unmemoize(value);\n\n // Return accumulated values\n return normalized;\n}\n\n/* eslint-disable complexity */\n/**\n * Stringify the given value. Handles various known special values and types.\n *\n * Not meant to be used on simple primitives which already have a string representation, as it will, for example, turn\n * the number 1231 into \"[Object Number]\", nor on `null`, as it will throw.\n *\n * @param value The value to stringify\n * @returns A stringified representation of the given value\n */\nfunction stringifyValue(\n key: unknown,\n // this type is a tiny bit of a cheat, since this function does handle NaN (which is technically a number), but for\n // our internal use, it'll do\n value: Exclude<unknown, string | number | boolean | null>,\n): string {\n try {\n if (key === 'domain' && value && typeof value === 'object' && (value as { _events: unknown })._events) {\n return '[Domain]';\n }\n\n if (key === 'domainEmitter') {\n return '[DomainEmitter]';\n }\n\n // It's safe to use `global`, `window`, and `document` here in this manner, as we are asserting using `typeof` first\n // which won't throw if they are not present.\n\n if (typeof global !== 'undefined' && value === global) {\n return '[Global]';\n }\n\n // eslint-disable-next-line no-restricted-globals\n if (typeof window !== 'undefined' && value === window) {\n return '[Window]';\n }\n\n // eslint-disable-next-line no-restricted-globals\n if (typeof document !== 'undefined' && value === document) {\n return '[Document]';\n }\n\n if (isVueViewModel(value)) {\n return getVueInternalName(value);\n }\n\n // React's SyntheticEvent thingy\n if (isSyntheticEvent(value)) {\n return '[SyntheticEvent]';\n }\n\n if (typeof value === 'number' && !Number.isFinite(value)) {\n return `[${value}]`;\n }\n\n if (typeof value === 'function') {\n return `[Function: ${getFunctionName(value)}]`;\n }\n\n if (typeof value === 'symbol') {\n return `[${String(value)}]`;\n }\n\n // stringified BigInts are indistinguishable from regular numbers, so we need to label them to avoid confusion\n if (typeof value === 'bigint') {\n return `[BigInt: ${String(value)}]`;\n }\n\n // Now that we've knocked out all the special cases and the primitives, all we have left are objects. Simply casting\n // them to strings means that instances of classes which haven't defined their `toStringTag` will just come out as\n // `\"[object Object]\"`. If we instead look at the constructor's name (which is the same as the name of the class),\n // we can make sure that only plain objects come out that way.\n const objName = getConstructorName(value);\n\n // Handle HTML Elements\n if (/^HTML(\\w*)Element$/.test(objName)) {\n return `[HTMLElement: ${objName}]`;\n }\n\n return `[object ${objName}]`;\n } catch (err) {\n return `**non-serializable** (${err})`;\n }\n}\n/* eslint-enable complexity */\n\nfunction getConstructorName(value: unknown): string {\n const prototype: Prototype | null = Object.getPrototypeOf(value);\n\n return prototype?.constructor ? prototype.constructor.name : 'null prototype';\n}\n\n/** Calculates bytes size of input string */\nfunction utf8Length(value: string): number {\n // eslint-disable-next-line no-bitwise\n return ~-encodeURI(value).split(/%..|./).length;\n}\n\n/** Calculates bytes size of input object */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction jsonSize(value: any): number {\n return utf8Length(JSON.stringify(value));\n}\n\n/**\n * Normalizes URLs in exceptions and stacktraces to a base path so Sentry can fingerprint\n * across platforms and working directory.\n *\n * @param url The URL to be normalized.\n * @param basePath The application base path.\n * @returns The normalized URL.\n */\nexport function normalizeUrlToBase(url: string, basePath: string): string {\n const escapedBase = basePath\n // Backslash to forward\n .replace(/\\\\/g, '/')\n // Escape RegExp special characters\n .replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&');\n\n let newUrl = url;\n try {\n newUrl = decodeURI(url);\n } catch {\n // Sometime this breaks\n }\n return (\n newUrl\n .replace(/\\\\/g, '/')\n .replace(/webpack:\\/?/g, '') // Remove intermediate base path\n // oxlint-disable-next-line sdk/no-regexp-constructor\n .replace(new RegExp(`(file://)?/*${escapedBase}/*`, 'ig'), 'app:///')\n );\n}\n\n/**\n * Helper to decycle json objects\n */\nfunction memoBuilder(): MemoFunc {\n const inner = new WeakSet<object>();\n function memoize(obj: object): boolean {\n if (inner.has(obj)) {\n return true;\n }\n inner.add(obj);\n return false;\n }\n\n function unmemoize(obj: object): void {\n inner.delete(obj);\n }\n return [memoize, unmemoize];\n}\n"],"names":["hasSkipNormalizationHint","getNormalizationDepthOverrideHint","convertToPlainObject","isVueViewModel","getVueInternalName","isSyntheticEvent","getFunctionName"],"mappings":"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"}
|
|
@@ -64,7 +64,7 @@ function addNonEnumerableProperty(obj, name, value) {
|
|
|
64
64
|
configurable: true,
|
|
65
65
|
});
|
|
66
66
|
} catch {
|
|
67
|
-
debugBuild.DEBUG_BUILD && debugLogger.debug.log(`Failed to add non-enumerable property "${name}" to object`, obj);
|
|
67
|
+
debugBuild.DEBUG_BUILD && debugLogger.debug.log(`Failed to add non-enumerable property "${String(name)}" to object`, obj);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object.js","sources":["../../../src/utils/object.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { DEBUG_BUILD } from '../debug-build';\nimport type { WrappedFunction } from '../types-hoist/wrappedfunction';\nimport { htmlTreeAsString } from './browser';\nimport { debug } from './debug-logger';\nimport { isElement, isError, isEvent, isInstanceOf, isPrimitive } from './is';\n\n/**\n * Replace a method in an object with a wrapped version of itself.\n *\n * If the method on the passed object is not a function, the wrapper will not be applied.\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 */\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 // explicitly casting to unknown because we don't know the type of the method initially at all\n const original = source[name] as unknown;\n\n if (typeof original !== 'function') {\n return;\n }\n\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 try {\n source[name] = wrapped;\n } catch {\n DEBUG_BUILD && debug.log(`Failed to replace method \"${name}\" in object`, source);\n }\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,\n writable: true,\n configurable: true,\n });\n } catch {\n DEBUG_BUILD && debug.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 {} // eslint-disable-line no-empty\n}\n\n/**\n * Wrap a method on an object by name, only if it is not already wrapped.\n *\n * Note: to set the wrapped method as a non-enumerable property, pass\n * false as the `enumerable` argument. This could be detected, but only\n * by either walking up the prototype chain, or iterating over all fields\n * in a `for(in)` loop. Neither are an acceptable performance impact for\n * the rare case where we might patch a non-enumerable method.\n */\nexport function wrapMethod<O extends {}, T extends string & keyof O>(\n obj: O,\n field: T,\n wrapped: WrappedFunction,\n enumerable: boolean = true,\n): void {\n const original = obj[field];\n if (typeof original !== 'function') {\n throw new Error(`Cannot wrap method: ${field} is not a function`);\n }\n if (getOriginalFunction(original)) {\n throw new Error(`Attempting to wrap method ${field} multiple times`);\n }\n markFunctionWrapped(wrapped, original);\n Object.defineProperty(obj, field, {\n writable: true,\n configurable: true,\n enumerable,\n value: wrapped,\n });\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 */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function getOriginalFunction<T extends Function>(func: WrappedFunction<T>): T | undefined {\n return func.__sentry_original__;\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 argument itself, when value is neither an Event nor\n * an Error.\n */\nexport function convertToPlainObject<V>(value: V):\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 {\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 return Object.fromEntries(Object.entries(obj));\n }\n return {};\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>): string {\n const keys = Object.keys(convertToPlainObject(exception));\n keys.sort();\n\n return !keys[0] ? '[object has no keys]' : keys.join(', ');\n}\n\n/**\n * Given any object, return a new object having removed all fields whose value was `undefined`.\n * Works recursively on objects and arrays.\n *\n * Attention: This function keeps circular references in the returned object.\n *\n * @deprecated This function is no longer used by the SDK and will be removed in a future major version.\n */\nexport function dropUndefinedKeys<T>(inputValue: T): T {\n // This map keeps track of what already visited nodes map to.\n // Our Set - based memoBuilder doesn't work here because we want to the output object to have the same circular\n // references as the input object.\n const memoizationMap = new Map<unknown, unknown>();\n\n // This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API\n return _dropUndefinedKeys(inputValue, memoizationMap);\n}\n\nfunction _dropUndefinedKeys<T>(inputValue: T, memoizationMap: Map<unknown, unknown>): T {\n // Early return for primitive values\n if (inputValue === null || typeof inputValue !== 'object') {\n return inputValue;\n }\n\n // Check memo map first for all object types\n const memoVal = memoizationMap.get(inputValue);\n if (memoVal !== undefined) {\n return memoVal as T;\n }\n\n // handle arrays\n if (Array.isArray(inputValue)) {\n const returnValue: unknown[] = [];\n // Store mapping to handle circular references\n memoizationMap.set(inputValue, returnValue);\n\n inputValue.forEach(value => {\n returnValue.push(_dropUndefinedKeys(value, memoizationMap));\n });\n\n return returnValue as unknown as T;\n }\n\n if (isPojo(inputValue)) {\n const returnValue: { [key: string]: unknown } = {};\n // Store mapping to handle circular references\n memoizationMap.set(inputValue, returnValue);\n\n const keys = Object.keys(inputValue);\n\n keys.forEach(key => {\n const val = inputValue[key];\n if (val !== undefined) {\n returnValue[key] = _dropUndefinedKeys(val, memoizationMap);\n }\n });\n\n return returnValue as T;\n }\n\n // For other object types, return as is\n return inputValue;\n}\n\nfunction isPojo(input: unknown): input is Record<string, unknown> {\n // Plain objects have Object as constructor or no constructor\n const constructor = (input as object).constructor;\n return constructor === Object || constructor === undefined;\n}\n\n/**\n * Ensure that something is an object.\n *\n * Turns `undefined` and `null` into `String`s and all other primitives into instances of their respective wrapper\n * classes (String, Boolean, Number, etc.). Acts as the identity function on non-primitives.\n *\n * @param wat The subject of the objectification\n * @returns A version of `wat` which can safely be used with `Object` class methods\n */\nexport function objectify(wat: unknown): typeof Object {\n let objectified;\n switch (true) {\n // this will catch both undefined and null\n case wat == undefined:\n objectified = new String(wat);\n break;\n\n // Though symbols and bigints do have wrapper classes (`Symbol` and `BigInt`, respectively), for whatever reason\n // those classes don't have constructors which can be used with the `new` keyword. We therefore need to cast each as\n // an object in order to wrap it.\n case typeof wat === 'symbol' || typeof wat === 'bigint':\n objectified = Object(wat);\n break;\n\n // this will catch the remaining primitives: `String`, `Number`, and `Boolean`\n case isPrimitive(wat):\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n objectified = new (wat as any).constructor(wat);\n break;\n\n // by process of elimination, at this point we know that `wat` must already be an object\n default:\n objectified = wat;\n break;\n }\n return objectified;\n}\n"],"names":["DEBUG_BUILD","debug","isError","isEvent","isInstanceOf","isElement","htmlTreeAsString","isPrimitive"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"object.js","sources":["../../../src/utils/object.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { DEBUG_BUILD } from '../debug-build';\nimport type { WrappedFunction } from '../types-hoist/wrappedfunction';\nimport { htmlTreeAsString } from './browser';\nimport { debug } from './debug-logger';\nimport { isElement, isError, isEvent, isInstanceOf, isPrimitive } from './is';\n\n/**\n * Replace a method in an object with a wrapped version of itself.\n *\n * If the method on the passed object is not a function, the wrapper will not be applied.\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 */\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 // explicitly casting to unknown because we don't know the type of the method initially at all\n const original = source[name] as unknown;\n\n if (typeof original !== 'function') {\n return;\n }\n\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 try {\n source[name] = wrapped;\n } catch {\n DEBUG_BUILD && debug.log(`Failed to replace method \"${name}\" in object`, source);\n }\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 | symbol, 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,\n writable: true,\n configurable: true,\n });\n } catch {\n DEBUG_BUILD && debug.log(`Failed to add non-enumerable property \"${String(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 {} // eslint-disable-line no-empty\n}\n\n/**\n * Wrap a method on an object by name, only if it is not already wrapped.\n *\n * Note: to set the wrapped method as a non-enumerable property, pass\n * false as the `enumerable` argument. This could be detected, but only\n * by either walking up the prototype chain, or iterating over all fields\n * in a `for(in)` loop. Neither are an acceptable performance impact for\n * the rare case where we might patch a non-enumerable method.\n */\nexport function wrapMethod<O extends {}, T extends string & keyof O>(\n obj: O,\n field: T,\n wrapped: WrappedFunction,\n enumerable: boolean = true,\n): void {\n const original = obj[field];\n if (typeof original !== 'function') {\n throw new Error(`Cannot wrap method: ${field} is not a function`);\n }\n if (getOriginalFunction(original)) {\n throw new Error(`Attempting to wrap method ${field} multiple times`);\n }\n markFunctionWrapped(wrapped, original);\n Object.defineProperty(obj, field, {\n writable: true,\n configurable: true,\n enumerable,\n value: wrapped,\n });\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 */\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport function getOriginalFunction<T extends Function>(func: WrappedFunction<T>): T | undefined {\n return func.__sentry_original__;\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 argument itself, when value is neither an Event nor\n * an Error.\n */\nexport function convertToPlainObject<V>(value: V):\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 {\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 return Object.fromEntries(Object.entries(obj));\n }\n return {};\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>): string {\n const keys = Object.keys(convertToPlainObject(exception));\n keys.sort();\n\n return !keys[0] ? '[object has no keys]' : keys.join(', ');\n}\n\n/**\n * Given any object, return a new object having removed all fields whose value was `undefined`.\n * Works recursively on objects and arrays.\n *\n * Attention: This function keeps circular references in the returned object.\n *\n * @deprecated This function is no longer used by the SDK and will be removed in a future major version.\n */\nexport function dropUndefinedKeys<T>(inputValue: T): T {\n // This map keeps track of what already visited nodes map to.\n // Our Set - based memoBuilder doesn't work here because we want to the output object to have the same circular\n // references as the input object.\n const memoizationMap = new Map<unknown, unknown>();\n\n // This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API\n return _dropUndefinedKeys(inputValue, memoizationMap);\n}\n\nfunction _dropUndefinedKeys<T>(inputValue: T, memoizationMap: Map<unknown, unknown>): T {\n // Early return for primitive values\n if (inputValue === null || typeof inputValue !== 'object') {\n return inputValue;\n }\n\n // Check memo map first for all object types\n const memoVal = memoizationMap.get(inputValue);\n if (memoVal !== undefined) {\n return memoVal as T;\n }\n\n // handle arrays\n if (Array.isArray(inputValue)) {\n const returnValue: unknown[] = [];\n // Store mapping to handle circular references\n memoizationMap.set(inputValue, returnValue);\n\n inputValue.forEach(value => {\n returnValue.push(_dropUndefinedKeys(value, memoizationMap));\n });\n\n return returnValue as unknown as T;\n }\n\n if (isPojo(inputValue)) {\n const returnValue: { [key: string]: unknown } = {};\n // Store mapping to handle circular references\n memoizationMap.set(inputValue, returnValue);\n\n const keys = Object.keys(inputValue);\n\n keys.forEach(key => {\n const val = inputValue[key];\n if (val !== undefined) {\n returnValue[key] = _dropUndefinedKeys(val, memoizationMap);\n }\n });\n\n return returnValue as T;\n }\n\n // For other object types, return as is\n return inputValue;\n}\n\nfunction isPojo(input: unknown): input is Record<string, unknown> {\n // Plain objects have Object as constructor or no constructor\n const constructor = (input as object).constructor;\n return constructor === Object || constructor === undefined;\n}\n\n/**\n * Ensure that something is an object.\n *\n * Turns `undefined` and `null` into `String`s and all other primitives into instances of their respective wrapper\n * classes (String, Boolean, Number, etc.). Acts as the identity function on non-primitives.\n *\n * @param wat The subject of the objectification\n * @returns A version of `wat` which can safely be used with `Object` class methods\n */\nexport function objectify(wat: unknown): typeof Object {\n let objectified;\n switch (true) {\n // this will catch both undefined and null\n case wat == undefined:\n objectified = new String(wat);\n break;\n\n // Though symbols and bigints do have wrapper classes (`Symbol` and `BigInt`, respectively), for whatever reason\n // those classes don't have constructors which can be used with the `new` keyword. We therefore need to cast each as\n // an object in order to wrap it.\n case typeof wat === 'symbol' || typeof wat === 'bigint':\n objectified = Object(wat);\n break;\n\n // this will catch the remaining primitives: `String`, `Number`, and `Boolean`\n case isPrimitive(wat):\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n objectified = new (wat as any).constructor(wat);\n break;\n\n // by process of elimination, at this point we know that `wat` must already be an object\n default:\n objectified = wat;\n break;\n }\n return objectified;\n}\n"],"names":["DEBUG_BUILD","debug","isError","isEvent","isInstanceOf","isElement","htmlTreeAsString","isPrimitive"],"mappings":"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"}
|
|
@@ -136,6 +136,44 @@ const SENSITIVE_HEADER_SNIPPETS = [
|
|
|
136
136
|
'cookie',
|
|
137
137
|
];
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Extra substrings matched only against individual Cookie / Set-Cookie **names** (not header names),
|
|
141
|
+
* so we can cover common session secrets that do not match {@link SENSITIVE_HEADER_SNIPPETS}
|
|
142
|
+
* (e.g. `connect.sid` does not contain `session`) without false positives on arbitrary HTTP headers.
|
|
143
|
+
*
|
|
144
|
+
* Cookie names are checked with the same `includes()` list as headers plus these entries; omit redundant
|
|
145
|
+
* cookie-only snippets that are already implied by a header match (e.g. `oauth` → `auth`, `id_token` → `token`,
|
|
146
|
+
* `next-auth` → `auth`).
|
|
147
|
+
*/
|
|
148
|
+
const SENSITIVE_COOKIE_NAME_SNIPPETS = [
|
|
149
|
+
// Express / Connect default session cookie
|
|
150
|
+
'.sid',
|
|
151
|
+
// Opaque session ids (PHPSESSID, ASPSESSIONID*, BIGipServer*, *sessid*, …)
|
|
152
|
+
'sessid',
|
|
153
|
+
// Laravel etc. "remember me" tokens
|
|
154
|
+
'remember',
|
|
155
|
+
// OIDC / OAuth auxiliary (`oauth*` covered by header snippet `auth`)
|
|
156
|
+
'oidc',
|
|
157
|
+
'pkce',
|
|
158
|
+
'nonce',
|
|
159
|
+
// RFC 6265bis high-security cookie name prefixes
|
|
160
|
+
'__secure-',
|
|
161
|
+
'__host-',
|
|
162
|
+
// Load balancer / CDN sticky-session cookies (opaque routing tokens)
|
|
163
|
+
'awsalb',
|
|
164
|
+
'awselb',
|
|
165
|
+
'akamai',
|
|
166
|
+
// BaaS / IdP session cookies (names often omit "session")
|
|
167
|
+
'__stripe',
|
|
168
|
+
'cognito',
|
|
169
|
+
'firebase',
|
|
170
|
+
'supabase',
|
|
171
|
+
'sb-',
|
|
172
|
+
// Step-up / MFA cookies
|
|
173
|
+
'mfa',
|
|
174
|
+
'2fa',
|
|
175
|
+
];
|
|
176
|
+
|
|
139
177
|
const PII_HEADER_SNIPPETS = ['x-forwarded-', '-user'];
|
|
140
178
|
|
|
141
179
|
/**
|
|
@@ -183,17 +221,23 @@ function httpHeadersToSpanAttributes(
|
|
|
183
221
|
|
|
184
222
|
const lowerCasedCookieKey = cookieKey.toLowerCase();
|
|
185
223
|
|
|
186
|
-
addSpanAttribute(
|
|
224
|
+
addSpanAttribute({
|
|
187
225
|
spanAttributes,
|
|
188
|
-
lowerCasedHeaderKey,
|
|
189
|
-
lowerCasedCookieKey,
|
|
190
|
-
cookieValue,
|
|
226
|
+
headerKey: lowerCasedHeaderKey,
|
|
227
|
+
cookieKey: lowerCasedCookieKey,
|
|
228
|
+
value: cookieValue,
|
|
191
229
|
sendDefaultPii,
|
|
192
230
|
lifecycle,
|
|
193
|
-
);
|
|
231
|
+
});
|
|
194
232
|
}
|
|
195
233
|
} else {
|
|
196
|
-
addSpanAttribute(
|
|
234
|
+
addSpanAttribute({
|
|
235
|
+
spanAttributes,
|
|
236
|
+
headerKey: lowerCasedHeaderKey,
|
|
237
|
+
value,
|
|
238
|
+
sendDefaultPii,
|
|
239
|
+
lifecycle,
|
|
240
|
+
});
|
|
197
241
|
}
|
|
198
242
|
});
|
|
199
243
|
} catch {
|
|
@@ -207,15 +251,17 @@ function normalizeAttributeKey(key) {
|
|
|
207
251
|
return key.replace(/-/g, '_');
|
|
208
252
|
}
|
|
209
253
|
|
|
210
|
-
function addSpanAttribute(
|
|
254
|
+
function addSpanAttribute({
|
|
211
255
|
spanAttributes,
|
|
212
256
|
headerKey,
|
|
213
257
|
cookieKey,
|
|
214
258
|
value,
|
|
215
|
-
|
|
259
|
+
sendDefaultPii,
|
|
216
260
|
lifecycle,
|
|
217
|
-
) {
|
|
218
|
-
const
|
|
261
|
+
}) {
|
|
262
|
+
const isCookieSubKey = Boolean(cookieKey);
|
|
263
|
+
const nameForSensitivity = cookieKey || headerKey;
|
|
264
|
+
const headerValue = handleHttpHeader(nameForSensitivity, value, sendDefaultPii, isCookieSubKey);
|
|
219
265
|
if (headerValue == null) {
|
|
220
266
|
return;
|
|
221
267
|
}
|
|
@@ -228,10 +274,15 @@ function handleHttpHeader(
|
|
|
228
274
|
lowerCasedKey,
|
|
229
275
|
value,
|
|
230
276
|
sendPii,
|
|
277
|
+
isCookieSubKey = false,
|
|
231
278
|
) {
|
|
279
|
+
const snippetsForSensitivity = isCookieSubKey
|
|
280
|
+
? [...SENSITIVE_HEADER_SNIPPETS, ...SENSITIVE_COOKIE_NAME_SNIPPETS]
|
|
281
|
+
: SENSITIVE_HEADER_SNIPPETS;
|
|
282
|
+
|
|
232
283
|
const isSensitive = sendPii
|
|
233
|
-
?
|
|
234
|
-
: [...PII_HEADER_SNIPPETS, ...
|
|
284
|
+
? snippetsForSensitivity.some(snippet => lowerCasedKey.includes(snippet))
|
|
285
|
+
: [...PII_HEADER_SNIPPETS, ...snippetsForSensitivity].some(snippet => lowerCasedKey.includes(snippet));
|
|
235
286
|
|
|
236
287
|
if (isSensitive) {
|
|
237
288
|
return '[Filtered]';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sources":["../../../src/utils/request.ts"],"sourcesContent":["import type { PolymorphicRequest } from '../types-hoist/polymorphics';\nimport type { RequestEventData } from '../types-hoist/request';\nimport type { WebFetchHeaders, WebFetchRequest } from '../types-hoist/webfetchapi';\n\n/**\n * Transforms a `Headers` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into a simple key-value dict.\n * The header keys will be lower case: e.g. A \"Content-Type\" header will be stored as \"content-type\".\n */\nexport function winterCGHeadersToDict(winterCGHeaders: WebFetchHeaders): Record<string, string> {\n const headers: Record<string, string> = {};\n try {\n winterCGHeaders.forEach((value, key) => {\n if (typeof value === 'string') {\n // We check that value is a string even though it might be redundant to make sure prototype pollution is not possible.\n headers[key] = value;\n }\n });\n } catch {\n // just return the empty headers\n }\n\n return headers;\n}\n\n/**\n * Convert common request headers to a simple dictionary.\n */\nexport function headersToDict(reqHeaders: Record<string, string | string[] | undefined>): Record<string, string> {\n const headers: Record<string, string> = Object.create(null);\n\n try {\n Object.entries(reqHeaders).forEach(([key, value]) => {\n if (typeof value === 'string') {\n headers[key] = value;\n }\n });\n } catch {\n // just return the empty headers\n }\n\n return headers;\n}\n\n/**\n * Converts a `Request` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into the format that the `RequestData` integration understands.\n */\nexport function winterCGRequestToRequestData(req: WebFetchRequest): RequestEventData {\n const headers = winterCGHeadersToDict(req.headers);\n\n return {\n method: req.method,\n url: req.url,\n query_string: extractQueryParamsFromUrl(req.url),\n headers,\n // TODO: Can we extract body data from the request?\n };\n}\n\n/**\n * Convert a HTTP request object to RequestEventData to be passed as normalizedRequest.\n * Instead of allowing `PolymorphicRequest` to be passed,\n * we want to be more specific and generally require a http.IncomingMessage-like object.\n */\nexport function httpRequestToRequestData(request: {\n method?: string;\n url?: string;\n headers?: {\n [key: string]: string | string[] | undefined;\n };\n protocol?: string;\n socket?: {\n encrypted?: boolean;\n remoteAddress?: string;\n };\n}): RequestEventData {\n const headers = request.headers || {};\n\n // Check for x-forwarded-host first, then fall back to host header\n const forwardedHost = typeof headers['x-forwarded-host'] === 'string' ? headers['x-forwarded-host'] : undefined;\n const host = forwardedHost || (typeof headers.host === 'string' ? headers.host : undefined);\n\n // Check for x-forwarded-proto first, then fall back to existing protocol detection\n const forwardedProto = typeof headers['x-forwarded-proto'] === 'string' ? headers['x-forwarded-proto'] : undefined;\n const protocol = forwardedProto || request.protocol || (request.socket?.encrypted ? 'https' : 'http');\n\n const url = request.url || '';\n\n const absoluteUrl = getAbsoluteUrl({\n url,\n host,\n protocol,\n });\n\n // This is non-standard, but may be sometimes set\n // It may be overwritten later by our own body handling\n const data = (request as PolymorphicRequest).body || undefined;\n\n // This is non-standard, but may be set on e.g. Next.js or Express requests\n const cookies = (request as PolymorphicRequest).cookies;\n\n return {\n url: absoluteUrl,\n method: request.method,\n query_string: extractQueryParamsFromUrl(url),\n headers: headersToDict(headers),\n cookies,\n data,\n };\n}\n\nfunction getAbsoluteUrl({\n url,\n protocol,\n host,\n}: {\n url?: string;\n protocol: string;\n host?: string;\n}): string | undefined {\n if (url?.startsWith('http')) {\n return url;\n }\n\n if (url && host) {\n return `${protocol}://${host}${url}`;\n }\n\n return undefined;\n}\n\nconst SENSITIVE_HEADER_SNIPPETS = [\n 'auth',\n 'token',\n 'secret',\n 'session', // for the user_session cookie\n 'password',\n 'passwd',\n 'pwd',\n 'key',\n 'jwt',\n 'bearer',\n 'sso',\n 'saml',\n 'csrf',\n 'xsrf',\n 'credentials',\n // Always treat cookie headers as sensitive in case individual key-value cookie pairs cannot properly be extracted\n 'set-cookie',\n 'cookie',\n];\n\nconst PII_HEADER_SNIPPETS = ['x-forwarded-', '-user'];\n\n/**\n * Converts incoming HTTP request or response headers to OpenTelemetry span attributes following semantic conventions.\n * Header names are converted to the format: http.<request|response>.header.<key>\n * where <key> is the header name in lowercase with dashes converted to underscores.\n *\n * @param lifecycle - The lifecycle of the headers, either 'request' or 'response'\n *\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/http/#http-request-header\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/http/#http-response-header\n *\n * @see https://getsentry.github.io/sentry-conventions/attributes/http/#http-request-header-key\n * @see https://getsentry.github.io/sentry-conventions/attributes/http/#http-response-header-key\n */\nexport function httpHeadersToSpanAttributes(\n headers: Record<string, string | string[] | undefined>,\n sendDefaultPii: boolean = false,\n lifecycle: 'request' | 'response' = 'request',\n): Record<string, string> {\n const spanAttributes: Record<string, string> = {};\n\n try {\n Object.entries(headers).forEach(([key, value]) => {\n if (value == null) {\n return;\n }\n\n const lowerCasedHeaderKey = key.toLowerCase();\n const isCookieHeader = lowerCasedHeaderKey === 'cookie' || lowerCasedHeaderKey === 'set-cookie';\n\n if (isCookieHeader && typeof value === 'string' && value !== '') {\n // Set-Cookie: single cookie with attributes (\"name=value; HttpOnly; Secure\")\n // Cookie: multiple cookies separated by \"; \" (\"cookie1=value1; cookie2=value2\")\n const isSetCookie = lowerCasedHeaderKey === 'set-cookie';\n const semicolonIndex = value.indexOf(';');\n const cookieString = isSetCookie && semicolonIndex !== -1 ? value.substring(0, semicolonIndex) : value;\n const cookies = isSetCookie ? [cookieString] : cookieString.split('; ');\n\n for (const cookie of cookies) {\n // Split only at the first '=' to preserve '=' characters in cookie values\n const equalSignIndex = cookie.indexOf('=');\n const cookieKey = equalSignIndex !== -1 ? cookie.substring(0, equalSignIndex) : cookie;\n const cookieValue = equalSignIndex !== -1 ? cookie.substring(equalSignIndex + 1) : '';\n\n const lowerCasedCookieKey = cookieKey.toLowerCase();\n\n addSpanAttribute(\n spanAttributes,\n lowerCasedHeaderKey,\n lowerCasedCookieKey,\n cookieValue,\n sendDefaultPii,\n lifecycle,\n );\n }\n } else {\n addSpanAttribute(spanAttributes, lowerCasedHeaderKey, '', value, sendDefaultPii, lifecycle);\n }\n });\n } catch {\n // Return empty object if there's an error\n }\n\n return spanAttributes;\n}\n\nfunction normalizeAttributeKey(key: string): string {\n return key.replace(/-/g, '_');\n}\n\nfunction addSpanAttribute(\n spanAttributes: Record<string, string>,\n headerKey: string,\n cookieKey: string,\n value: string | string[] | undefined,\n sendPii: boolean,\n lifecycle: 'request' | 'response',\n): void {\n const headerValue = handleHttpHeader(cookieKey || headerKey, value, sendPii);\n if (headerValue == null) {\n return;\n }\n\n const normalizedKey = `http.${lifecycle}.header.${normalizeAttributeKey(headerKey)}${cookieKey ? `.${normalizeAttributeKey(cookieKey)}` : ''}`;\n spanAttributes[normalizedKey] = headerValue;\n}\n\nfunction handleHttpHeader(\n lowerCasedKey: string,\n value: string | string[] | undefined,\n sendPii: boolean,\n): string | undefined {\n const isSensitive = sendPii\n ? SENSITIVE_HEADER_SNIPPETS.some(snippet => lowerCasedKey.includes(snippet))\n : [...PII_HEADER_SNIPPETS, ...SENSITIVE_HEADER_SNIPPETS].some(snippet => lowerCasedKey.includes(snippet));\n\n if (isSensitive) {\n return '[Filtered]';\n } else if (Array.isArray(value)) {\n return value.map(v => (v != null ? String(v) : v)).join(';');\n } else if (typeof value === 'string') {\n return value;\n }\n\n return undefined;\n}\n\n/** Extract the query params from an URL. */\nexport function extractQueryParamsFromUrl(url: string): string | undefined {\n // url is path and query string\n if (!url) {\n return;\n }\n\n try {\n // The `URL` constructor can't handle internal URLs of the form `/some/path/here`, so stick a dummy protocol and\n // hostname as the base. Since the point here is just to grab the query string, it doesn't matter what we use.\n const queryParams = new URL(url, 'http://s.io').search.slice(1);\n return queryParams.length ? queryParams : undefined;\n } catch {\n return undefined;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request.js","sources":["../../../src/utils/request.ts"],"sourcesContent":["import type { PolymorphicRequest } from '../types-hoist/polymorphics';\nimport type { RequestEventData } from '../types-hoist/request';\nimport type { WebFetchHeaders, WebFetchRequest } from '../types-hoist/webfetchapi';\n\n/**\n * Transforms a `Headers` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into a simple key-value dict.\n * The header keys will be lower case: e.g. A \"Content-Type\" header will be stored as \"content-type\".\n */\nexport function winterCGHeadersToDict(winterCGHeaders: WebFetchHeaders): Record<string, string> {\n const headers: Record<string, string> = {};\n try {\n winterCGHeaders.forEach((value, key) => {\n if (typeof value === 'string') {\n // We check that value is a string even though it might be redundant to make sure prototype pollution is not possible.\n headers[key] = value;\n }\n });\n } catch {\n // just return the empty headers\n }\n\n return headers;\n}\n\n/**\n * Convert common request headers to a simple dictionary.\n */\nexport function headersToDict(reqHeaders: Record<string, string | string[] | undefined>): Record<string, string> {\n const headers: Record<string, string> = Object.create(null);\n\n try {\n Object.entries(reqHeaders).forEach(([key, value]) => {\n if (typeof value === 'string') {\n headers[key] = value;\n }\n });\n } catch {\n // just return the empty headers\n }\n\n return headers;\n}\n\n/**\n * Converts a `Request` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into the format that the `RequestData` integration understands.\n */\nexport function winterCGRequestToRequestData(req: WebFetchRequest): RequestEventData {\n const headers = winterCGHeadersToDict(req.headers);\n\n return {\n method: req.method,\n url: req.url,\n query_string: extractQueryParamsFromUrl(req.url),\n headers,\n // TODO: Can we extract body data from the request?\n };\n}\n\n/**\n * Convert a HTTP request object to RequestEventData to be passed as normalizedRequest.\n * Instead of allowing `PolymorphicRequest` to be passed,\n * we want to be more specific and generally require a http.IncomingMessage-like object.\n */\nexport function httpRequestToRequestData(request: {\n method?: string;\n url?: string;\n headers?: {\n [key: string]: string | string[] | undefined;\n };\n protocol?: string;\n socket?: {\n encrypted?: boolean;\n remoteAddress?: string;\n };\n}): RequestEventData {\n const headers = request.headers || {};\n\n // Check for x-forwarded-host first, then fall back to host header\n const forwardedHost = typeof headers['x-forwarded-host'] === 'string' ? headers['x-forwarded-host'] : undefined;\n const host = forwardedHost || (typeof headers.host === 'string' ? headers.host : undefined);\n\n // Check for x-forwarded-proto first, then fall back to existing protocol detection\n const forwardedProto = typeof headers['x-forwarded-proto'] === 'string' ? headers['x-forwarded-proto'] : undefined;\n const protocol = forwardedProto || request.protocol || (request.socket?.encrypted ? 'https' : 'http');\n\n const url = request.url || '';\n\n const absoluteUrl = getAbsoluteUrl({\n url,\n host,\n protocol,\n });\n\n // This is non-standard, but may be sometimes set\n // It may be overwritten later by our own body handling\n const data = (request as PolymorphicRequest).body || undefined;\n\n // This is non-standard, but may be set on e.g. Next.js or Express requests\n const cookies = (request as PolymorphicRequest).cookies;\n\n return {\n url: absoluteUrl,\n method: request.method,\n query_string: extractQueryParamsFromUrl(url),\n headers: headersToDict(headers),\n cookies,\n data,\n };\n}\n\nfunction getAbsoluteUrl({\n url,\n protocol,\n host,\n}: {\n url?: string;\n protocol: string;\n host?: string;\n}): string | undefined {\n if (url?.startsWith('http')) {\n return url;\n }\n\n if (url && host) {\n return `${protocol}://${host}${url}`;\n }\n\n return undefined;\n}\n\nconst SENSITIVE_HEADER_SNIPPETS = [\n 'auth',\n 'token',\n 'secret',\n 'session', // for the user_session cookie\n 'password',\n 'passwd',\n 'pwd',\n 'key',\n 'jwt',\n 'bearer',\n 'sso',\n 'saml',\n 'csrf',\n 'xsrf',\n 'credentials',\n // Always treat cookie headers as sensitive in case individual key-value cookie pairs cannot properly be extracted\n 'set-cookie',\n 'cookie',\n];\n\n/**\n * Extra substrings matched only against individual Cookie / Set-Cookie **names** (not header names),\n * so we can cover common session secrets that do not match {@link SENSITIVE_HEADER_SNIPPETS}\n * (e.g. `connect.sid` does not contain `session`) without false positives on arbitrary HTTP headers.\n *\n * Cookie names are checked with the same `includes()` list as headers plus these entries; omit redundant\n * cookie-only snippets that are already implied by a header match (e.g. `oauth` → `auth`, `id_token` → `token`,\n * `next-auth` → `auth`).\n */\nconst SENSITIVE_COOKIE_NAME_SNIPPETS = [\n // Express / Connect default session cookie\n '.sid',\n // Opaque session ids (PHPSESSID, ASPSESSIONID*, BIGipServer*, *sessid*, …)\n 'sessid',\n // Laravel etc. \"remember me\" tokens\n 'remember',\n // OIDC / OAuth auxiliary (`oauth*` covered by header snippet `auth`)\n 'oidc',\n 'pkce',\n 'nonce',\n // RFC 6265bis high-security cookie name prefixes\n '__secure-',\n '__host-',\n // Load balancer / CDN sticky-session cookies (opaque routing tokens)\n 'awsalb',\n 'awselb',\n 'akamai',\n // BaaS / IdP session cookies (names often omit \"session\")\n '__stripe',\n 'cognito',\n 'firebase',\n 'supabase',\n 'sb-',\n // Step-up / MFA cookies\n 'mfa',\n '2fa',\n];\n\nconst PII_HEADER_SNIPPETS = ['x-forwarded-', '-user'];\n\n/**\n * Converts incoming HTTP request or response headers to OpenTelemetry span attributes following semantic conventions.\n * Header names are converted to the format: http.<request|response>.header.<key>\n * where <key> is the header name in lowercase with dashes converted to underscores.\n *\n * @param lifecycle - The lifecycle of the headers, either 'request' or 'response'\n *\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/http/#http-request-header\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/http/#http-response-header\n *\n * @see https://getsentry.github.io/sentry-conventions/attributes/http/#http-request-header-key\n * @see https://getsentry.github.io/sentry-conventions/attributes/http/#http-response-header-key\n */\nexport function httpHeadersToSpanAttributes(\n headers: Record<string, string | string[] | undefined>,\n sendDefaultPii: boolean = false,\n lifecycle: 'request' | 'response' = 'request',\n): Record<string, string> {\n const spanAttributes: Record<string, string> = {};\n\n try {\n Object.entries(headers).forEach(([key, value]) => {\n if (value == null) {\n return;\n }\n\n const lowerCasedHeaderKey = key.toLowerCase();\n const isCookieHeader = lowerCasedHeaderKey === 'cookie' || lowerCasedHeaderKey === 'set-cookie';\n\n if (isCookieHeader && typeof value === 'string' && value !== '') {\n // Set-Cookie: single cookie with attributes (\"name=value; HttpOnly; Secure\")\n // Cookie: multiple cookies separated by \"; \" (\"cookie1=value1; cookie2=value2\")\n const isSetCookie = lowerCasedHeaderKey === 'set-cookie';\n const semicolonIndex = value.indexOf(';');\n const cookieString = isSetCookie && semicolonIndex !== -1 ? value.substring(0, semicolonIndex) : value;\n const cookies = isSetCookie ? [cookieString] : cookieString.split('; ');\n\n for (const cookie of cookies) {\n // Split only at the first '=' to preserve '=' characters in cookie values\n const equalSignIndex = cookie.indexOf('=');\n const cookieKey = equalSignIndex !== -1 ? cookie.substring(0, equalSignIndex) : cookie;\n const cookieValue = equalSignIndex !== -1 ? cookie.substring(equalSignIndex + 1) : '';\n\n const lowerCasedCookieKey = cookieKey.toLowerCase();\n\n addSpanAttribute({\n spanAttributes,\n headerKey: lowerCasedHeaderKey,\n cookieKey: lowerCasedCookieKey,\n value: cookieValue,\n sendDefaultPii,\n lifecycle,\n });\n }\n } else {\n addSpanAttribute({\n spanAttributes,\n headerKey: lowerCasedHeaderKey,\n value,\n sendDefaultPii,\n lifecycle,\n });\n }\n });\n } catch {\n // Return empty object if there's an error\n }\n\n return spanAttributes;\n}\n\nfunction normalizeAttributeKey(key: string): string {\n return key.replace(/-/g, '_');\n}\n\ntype AddSpanAttributeOptions = {\n spanAttributes: Record<string, string>;\n /** Lowercased HTTP header name (e.g. `cookie`, `set-cookie`, `accept`). */\n headerKey: string;\n /**\n * Lowercased cookie name when this attribute comes from a parsed `Cookie` / `Set-Cookie` value.\n * Omit for non-cookie headers; when present and non-empty, cookie-specific sensitivity rules apply.\n */\n cookieKey?: string;\n value: string | string[] | undefined;\n sendDefaultPii: boolean;\n lifecycle: 'request' | 'response';\n};\n\nfunction addSpanAttribute({\n spanAttributes,\n headerKey,\n cookieKey,\n value,\n sendDefaultPii,\n lifecycle,\n}: AddSpanAttributeOptions): void {\n const isCookieSubKey = Boolean(cookieKey);\n const nameForSensitivity = cookieKey || headerKey;\n const headerValue = handleHttpHeader(nameForSensitivity, value, sendDefaultPii, isCookieSubKey);\n if (headerValue == null) {\n return;\n }\n\n const normalizedKey = `http.${lifecycle}.header.${normalizeAttributeKey(headerKey)}${cookieKey ? `.${normalizeAttributeKey(cookieKey)}` : ''}`;\n spanAttributes[normalizedKey] = headerValue;\n}\n\nfunction handleHttpHeader(\n lowerCasedKey: string,\n value: string | string[] | undefined,\n sendPii: boolean,\n isCookieSubKey: boolean = false,\n): string | undefined {\n const snippetsForSensitivity = isCookieSubKey\n ? [...SENSITIVE_HEADER_SNIPPETS, ...SENSITIVE_COOKIE_NAME_SNIPPETS]\n : SENSITIVE_HEADER_SNIPPETS;\n\n const isSensitive = sendPii\n ? snippetsForSensitivity.some(snippet => lowerCasedKey.includes(snippet))\n : [...PII_HEADER_SNIPPETS, ...snippetsForSensitivity].some(snippet => lowerCasedKey.includes(snippet));\n\n if (isSensitive) {\n return '[Filtered]';\n } else if (Array.isArray(value)) {\n return value.map(v => (v != null ? String(v) : v)).join(';');\n } else if (typeof value === 'string') {\n return value;\n }\n\n return undefined;\n}\n\n/** Extract the query params from an URL. */\nexport function extractQueryParamsFromUrl(url: string): string | undefined {\n // url is path and query string\n if (!url) {\n return;\n }\n\n try {\n // The `URL` constructor can't handle internal URLs of the form `/some/path/here`, so stick a dummy protocol and\n // hostname as the base. Since the point here is just to grab the query string, it doesn't matter what we use.\n const queryParams = new URL(url, 'http://s.io').search.slice(1);\n return queryParams.length ? queryParams : undefined;\n } catch {\n return undefined;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -15,31 +15,37 @@ function shouldIgnoreSpan(
|
|
|
15
15
|
span,
|
|
16
16
|
ignoreSpans,
|
|
17
17
|
) {
|
|
18
|
-
if (!ignoreSpans?.length
|
|
18
|
+
if (!ignoreSpans?.length) {
|
|
19
19
|
return false;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
for (const pattern of ignoreSpans) {
|
|
23
23
|
if (isStringOrRegExp(pattern)) {
|
|
24
|
-
if (string.isMatchingPattern(span.description, pattern)) {
|
|
24
|
+
if (span.description && string.isMatchingPattern(span.description, pattern)) {
|
|
25
25
|
debugBuild.DEBUG_BUILD && logIgnoredSpan(span);
|
|
26
26
|
return true;
|
|
27
27
|
}
|
|
28
28
|
continue;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
const hasAttributes = !!pattern.attributes && Object.keys(pattern.attributes).length > 0;
|
|
32
|
+
if (!pattern.name && !pattern.op && !hasAttributes) {
|
|
32
33
|
continue;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
const nameMatches = pattern.name ? string.isMatchingPattern(span.description, pattern.name) : true;
|
|
36
|
+
const nameMatches = pattern.name ? span.description && string.isMatchingPattern(span.description, pattern.name) : true;
|
|
36
37
|
const opMatches = pattern.op ? span.op && string.isMatchingPattern(span.op, pattern.op) : true;
|
|
38
|
+
const attrsMatch = pattern.attributes
|
|
39
|
+
? Object.entries(pattern.attributes).every(([key, valuePattern]) =>
|
|
40
|
+
_matchesAttributeValue(span.attributes?.[key], valuePattern),
|
|
41
|
+
)
|
|
42
|
+
: true;
|
|
37
43
|
|
|
38
44
|
// This check here is only correct because we can guarantee that we ran `isMatchingPattern`
|
|
39
|
-
// for at least one of `nameMatches`
|
|
40
|
-
// not
|
|
41
|
-
// for all combinations of name and
|
|
42
|
-
if (nameMatches && opMatches) {
|
|
45
|
+
// for at least one of `nameMatches`, `opMatches`, or `attrsMatch`. So in contrary to how this looks,
|
|
46
|
+
// not all of op, name, and attributes actually have to match. This is the most efficient way to check
|
|
47
|
+
// for all combinations of name, op, and attribute patterns.
|
|
48
|
+
if (nameMatches && opMatches && attrsMatch) {
|
|
43
49
|
debugBuild.DEBUG_BUILD && logIgnoredSpan(span);
|
|
44
50
|
return true;
|
|
45
51
|
}
|
|
@@ -48,6 +54,19 @@ function shouldIgnoreSpan(
|
|
|
48
54
|
return false;
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
function _matchesAttributeValue(actual, pat) {
|
|
58
|
+
// String values support pattern matching
|
|
59
|
+
if (typeof actual === 'string' && (typeof pat === 'string' || pat instanceof RegExp)) {
|
|
60
|
+
return string.isMatchingPattern(actual, pat);
|
|
61
|
+
}
|
|
62
|
+
// Arrays: element-wise strict equality
|
|
63
|
+
if (Array.isArray(actual) && Array.isArray(pat)) {
|
|
64
|
+
return actual.length === pat.length && actual.every((v, i) => v === pat[i]);
|
|
65
|
+
}
|
|
66
|
+
// Primitives: strict equality
|
|
67
|
+
return actual === pat;
|
|
68
|
+
}
|
|
69
|
+
|
|
51
70
|
/**
|
|
52
71
|
* Takes a list of spans, and a span that was dropped, and re-parents the child spans of the dropped span to the parent of the dropped span, if possible.
|
|
53
72
|
* This mutates the spans array in place!
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"should-ignore-span.js","sources":["../../../src/utils/should-ignore-span.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport type { ClientOptions } from '../types-hoist/options';\nimport type { SpanJSON } from '../types-hoist/span';\nimport { debug } from './debug-logger';\nimport { isMatchingPattern } from './string';\n\nfunction logIgnoredSpan(droppedSpan: Pick<SpanJSON, 'description' | 'op'>): void {\n debug.log(`Ignoring span ${droppedSpan.op} - ${droppedSpan.description} because it matches \\`ignoreSpans\\`.`);\n}\n\n/**\n * Check if a span should be ignored based on the ignoreSpans configuration.\n */\nexport function shouldIgnoreSpan(\n span: Pick<SpanJSON, 'description' | 'op'
|
|
1
|
+
{"version":3,"file":"should-ignore-span.js","sources":["../../../src/utils/should-ignore-span.ts"],"sourcesContent":["import { DEBUG_BUILD } from '../debug-build';\nimport type { ClientOptions, IgnoreSpanAttributeValue } from '../types-hoist/options';\nimport type { SpanJSON } from '../types-hoist/span';\nimport { debug } from './debug-logger';\nimport { isMatchingPattern } from './string';\n\nfunction logIgnoredSpan(droppedSpan: Pick<SpanJSON, 'description' | 'op'>): void {\n debug.log(`Ignoring span ${droppedSpan.op} - ${droppedSpan.description} because it matches \\`ignoreSpans\\`.`);\n}\n\n/**\n * Check if a span should be ignored based on the ignoreSpans configuration.\n */\nexport function shouldIgnoreSpan(\n span: Pick<SpanJSON, 'description' | 'op'> & { attributes?: Record<string, unknown> },\n ignoreSpans: Required<ClientOptions>['ignoreSpans'],\n): boolean {\n if (!ignoreSpans?.length) {\n return false;\n }\n\n for (const pattern of ignoreSpans) {\n if (isStringOrRegExp(pattern)) {\n if (span.description && isMatchingPattern(span.description, pattern)) {\n DEBUG_BUILD && logIgnoredSpan(span);\n return true;\n }\n continue;\n }\n\n const hasAttributes = !!pattern.attributes && Object.keys(pattern.attributes).length > 0;\n if (!pattern.name && !pattern.op && !hasAttributes) {\n continue;\n }\n\n const nameMatches = pattern.name ? span.description && isMatchingPattern(span.description, pattern.name) : true;\n const opMatches = pattern.op ? span.op && isMatchingPattern(span.op, pattern.op) : true;\n const attrsMatch = pattern.attributes\n ? Object.entries(pattern.attributes).every(([key, valuePattern]) =>\n _matchesAttributeValue(span.attributes?.[key], valuePattern),\n )\n : true;\n\n // This check here is only correct because we can guarantee that we ran `isMatchingPattern`\n // for at least one of `nameMatches`, `opMatches`, or `attrsMatch`. So in contrary to how this looks,\n // not all of op, name, and attributes actually have to match. This is the most efficient way to check\n // for all combinations of name, op, and attribute patterns.\n if (nameMatches && opMatches && attrsMatch) {\n DEBUG_BUILD && logIgnoredSpan(span);\n return true;\n }\n }\n\n return false;\n}\n\nfunction _matchesAttributeValue(actual: unknown, pat: IgnoreSpanAttributeValue): boolean {\n // String values support pattern matching\n if (typeof actual === 'string' && (typeof pat === 'string' || pat instanceof RegExp)) {\n return isMatchingPattern(actual, pat);\n }\n // Arrays: element-wise strict equality\n if (Array.isArray(actual) && Array.isArray(pat)) {\n return actual.length === pat.length && actual.every((v, i) => v === pat[i]);\n }\n // Primitives: strict equality\n return actual === pat;\n}\n\n/**\n * Takes a list of spans, and a span that was dropped, and re-parents the child spans of the dropped span to the parent of the dropped span, if possible.\n * This mutates the spans array in place!\n */\nexport function reparentChildSpans(spans: SpanJSON[], dropSpan: SpanJSON): void {\n const droppedSpanParentId = dropSpan.parent_span_id;\n const droppedSpanId = dropSpan.span_id;\n\n // This should generally not happen, as we do not apply this on root spans\n // but to be safe, we just bail in this case\n if (!droppedSpanParentId) {\n return;\n }\n\n for (const span of spans) {\n if (span.parent_span_id === droppedSpanId) {\n span.parent_span_id = droppedSpanParentId;\n }\n }\n}\n\nfunction isStringOrRegExp(value: unknown): value is string | RegExp {\n return typeof value === 'string' || value instanceof RegExp;\n}\n"],"names":["debug","isMatchingPattern","DEBUG_BUILD"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
|
|
3
3
|
// This is a magic string replaced by rollup
|
|
4
4
|
|
|
5
|
-
const SDK_VERSION = "10.
|
|
5
|
+
const SDK_VERSION = "10.51.0" ;
|
|
6
6
|
|
|
7
7
|
exports.SDK_VERSION = SDK_VERSION;
|
|
8
8
|
//# sourceMappingURL=version.js.map
|
package/build/esm/client.js
CHANGED
|
@@ -598,10 +598,25 @@ class Client {
|
|
|
598
598
|
return {};
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
/**
|
|
602
|
+
* Register a cleanup function to be called when the client is disposed.
|
|
603
|
+
* This is useful for integrations that need to clean up global state.
|
|
604
|
+
*
|
|
605
|
+
* NOTE: This is a no-op in the base `Client` class. Subclasses like `ServerRuntimeClient`
|
|
606
|
+
* override this method to actually register and execute cleanup callbacks.
|
|
607
|
+
*/
|
|
608
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
609
|
+
registerCleanup(callback) {
|
|
610
|
+
// No-op in base class - subclasses override to implement cleanup registration
|
|
611
|
+
}
|
|
612
|
+
|
|
601
613
|
/**
|
|
602
614
|
* Disposes of the client and releases all resources.
|
|
603
615
|
*
|
|
604
|
-
* Subclasses should override this method to clean up their own resources
|
|
616
|
+
* Subclasses should override this method to clean up their own resources, including invoking
|
|
617
|
+
* any callbacks registered via {@link Client.registerCleanup}. The base implementation is a
|
|
618
|
+
* no-op and does NOT execute registered cleanup callbacks.
|
|
619
|
+
*
|
|
605
620
|
* After calling dispose(), the client should not be used anymore.
|
|
606
621
|
*/
|
|
607
622
|
dispose() {
|
|
@@ -1020,7 +1035,13 @@ function processBeforeSend(
|
|
|
1020
1035
|
const rootSpanJson = convertTransactionEventToSpanJson(processedEvent);
|
|
1021
1036
|
|
|
1022
1037
|
// 1.1 If the root span should be ignored, drop the whole transaction
|
|
1023
|
-
if (
|
|
1038
|
+
if (
|
|
1039
|
+
ignoreSpans?.length &&
|
|
1040
|
+
shouldIgnoreSpan(
|
|
1041
|
+
{ description: rootSpanJson.description, op: rootSpanJson.op, attributes: rootSpanJson.data },
|
|
1042
|
+
ignoreSpans,
|
|
1043
|
+
)
|
|
1044
|
+
) {
|
|
1024
1045
|
// dropping the whole transaction!
|
|
1025
1046
|
return null;
|
|
1026
1047
|
}
|
|
@@ -1044,7 +1065,10 @@ function processBeforeSend(
|
|
|
1044
1065
|
|
|
1045
1066
|
for (const span of initialSpans) {
|
|
1046
1067
|
// 2.a If the child span should be ignored, reparent it to the root span
|
|
1047
|
-
if (
|
|
1068
|
+
if (
|
|
1069
|
+
ignoreSpans?.length &&
|
|
1070
|
+
shouldIgnoreSpan({ description: span.description, op: span.op, attributes: span.data }, ignoreSpans)
|
|
1071
|
+
) {
|
|
1048
1072
|
reparentChildSpans(initialSpans, span);
|
|
1049
1073
|
continue;
|
|
1050
1074
|
}
|