@blueking/open-telemetry 0.0.33 → 0.0.35-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +67 -57
  2. package/dist/bk-rum.global.js +2 -2
  3. package/dist/bk-rum.global.js.map +1 -1
  4. package/dist/core/action-activity.d.ts +5 -1
  5. package/dist/core/action-target.d.ts +19 -0
  6. package/dist/core/config.d.ts +15 -5
  7. package/dist/core/event-time.d.ts +7 -0
  8. package/dist/core/performance-timing.d.ts +13 -0
  9. package/dist/core/plugin.d.ts +37 -2
  10. package/dist/core/processor.d.ts +24 -2
  11. package/dist/core/request-timing.d.ts +3 -2
  12. package/dist/core/runtime-context.d.ts +62 -2
  13. package/dist/core/sdk.d.ts +23 -1
  14. package/dist/core/session-transition.d.ts +19 -0
  15. package/dist/core/trace-context.d.ts +6 -7
  16. package/dist/core/view-location.d.ts +10 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +2955 -1483
  19. package/dist/index.js.map +1 -1
  20. package/dist/integrations/vue-router.d.ts +25 -0
  21. package/dist/plugins/action.d.ts +1 -1
  22. package/dist/plugins/blank-screen-detection.d.ts +11 -0
  23. package/dist/plugins/blank-screen.d.ts +10 -18
  24. package/dist/plugins/common.d.ts +4 -2
  25. package/dist/plugins/document-vitals.d.ts +25 -0
  26. package/dist/plugins/page-view.d.ts +1 -1
  27. package/dist/plugins/resource.d.ts +14 -1
  28. package/dist/plugins/session-state.d.ts +14 -2
  29. package/dist/plugins/session-store.d.ts +12 -0
  30. package/dist/plugins/session.d.ts +1 -0
  31. package/dist/plugins/web-vitals-metrics.d.ts +80 -0
  32. package/dist/plugins/web-vitals.d.ts +2 -59
  33. package/dist/schema/attributes.d.ts +63 -0
  34. package/dist/schema/span.d.ts +5 -2
  35. package/package.json +9 -4
  36. package/skills/bk-rum-otele/references/actions.md +54 -37
  37. package/skills/bk-rum-otele/references/api.md +72 -51
  38. package/skills/bk-rum-otele/references/architecture.md +16 -16
  39. package/skills/bk-rum-otele/references/blank-screen.md +72 -142
  40. package/skills/bk-rum-otele/references/capabilities.md +66 -60
  41. package/skills/bk-rum-otele/references/configuration.md +101 -98
  42. package/skills/bk-rum-otele/references/data-model.md +22 -17
  43. package/skills/bk-rum-otele/references/errors-security.md +13 -13
  44. package/skills/bk-rum-otele/references/extensions.md +5 -3
  45. package/skills/bk-rum-otele/references/framework-integration.md +7 -24
  46. package/skills/bk-rum-otele/references/network.md +62 -49
  47. package/skills/bk-rum-otele/references/performance.md +62 -30
  48. package/skills/bk-rum-otele/references/privacy.md +5 -5
  49. package/skills/bk-rum-otele/references/production.md +9 -13
  50. package/skills/bk-rum-otele/references/session-context.md +67 -38
  51. package/skills/bk-rum-otele/references/span-protocol.md +771 -315
  52. package/skills/bk-rum-otele/references/telemetry-reference.md +288 -213
  53. package/skills/bk-rum-otele/references/troubleshooting.md +2 -2
  54. package/skills/bk-rum-otele/references/views-routing.md +103 -27
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../package.json","../src/core/hash.ts","../src/core/id.ts","../src/schema/attributes.ts","../src/plugins/device.ts","../src/core/url.ts","../src/core/config.ts","../src/core/plugin.ts","../src/schema/span.ts","../src/core/processor.ts","../src/core/runtime-context.ts","../src/plugins/action.ts","../src/plugins/activity.ts","../src/core/page-activity.ts","../src/plugins/blank-screen.ts","../src/core/request-timing.ts","../src/core/trace-context.ts","../src/plugins/resource.ts","../src/plugins/common.ts","../src/plugins/csp-violation.ts","../src/plugins/error.ts","../src/plugins/long-task.ts","../src/core/route-observer.ts","../src/plugins/page-view.ts","../src/plugins/session-state.ts","../src/plugins/session.ts","../src/plugins/web-vitals.ts","../src/plugins/websocket.ts","../src/core/action-activity.ts","../src/core/sampling.ts","../src/core/sdk.ts"],"sourcesContent":["{\n \"name\": \"@blueking/open-telemetry\",\n \"version\": \"0.0.33\",\n \"description\": \"OpenTelemetry browser SDK for BK RUM\",\n \"author\": \"TencentCloud Real User Monitoring\",\n \"main\": \"dist/index.js\",\n \"unpkg\": \"dist/bk-rum.global.js\",\n \"jsdelivr\": \"dist/bk-rum.global.js\",\n \"license\": \"MIT\",\n \"files\": [\n \"dist\",\n \"skills\"\n ],\n \"scripts\": {\n \"prepublishOnly\": \"pnpm build && pnpm dts && pnpm skill:refs\",\n \"skill:refs\": \"node scripts/gen-skill-references.mjs\",\n \"test:skill-refs\": \"node --test tests/gen-skill-references.test.mjs\",\n \"build\": \"vite build && vite build --mode cdn && pnpm dts\",\n \"build:cdn\": \"vite build --mode cdn\",\n \"build:esm\": \"vite build\",\n \"docs:build\": \"vitepress build wikis\",\n \"docs:dev\": \"vitepress dev wikis\",\n \"docs:preview\": \"vitepress preview wikis\",\n \"dev\": \"vite dev\",\n \"dts\": \"vue-tsc --project tsconfig.dts.json\",\n \"test:rum-context\": \"node --experimental-default-type=module --experimental-strip-types --test tests/action-plugin.test.mjs tests/consent.test.mjs tests/experience-plugins.test.mjs tests/request-model.test.mjs tests/runtime-context.test.mjs tests/sampling.test.mjs tests/session-state.test.ts tests/session-plugin.test.mjs tests/session-page-view.test.mjs tests/session-processors.test.mjs tests/trace-context.test.mjs tests/web-vitals.test.mjs\"\n },\n \"dependencies\": {\n \"@opentelemetry/api\": \"^1.9.1\",\n \"@opentelemetry/context-zone\": \"2.7.1\",\n \"@opentelemetry/core\": \"^2.7.1\",\n \"@opentelemetry/exporter-trace-otlp-http\": \"^0.217.0\",\n \"@opentelemetry/instrumentation\": \"^0.217.0\",\n \"@opentelemetry/resources\": \"^2.7.1\",\n \"@opentelemetry/sdk-trace-base\": \"^2.7.1\",\n \"@opentelemetry/sdk-trace-web\": \"^2.7.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.38.0\",\n \"web-vitals\": \"^5.0.3\"\n },\n \"devDependencies\": {\n \"@vitejs/plugin-vue\": \"^6.0.6\",\n \"@vue/test-utils\": \"^2.4.6\",\n \"@vue/tsconfig\": \"^0.9.0\",\n \"oxc-minify\": \"^0.133.0\",\n \"vite\": \"^8.0.2\",\n \"vite-bundle-analyzer\": \"^1.3.2\",\n \"vitepress\": \"2.0.0-alpha.16\",\n \"vue\": \"^3.5.34\",\n \"vue-router\": \"^5.0.6\",\n \"vue-tsc\": \"^3.1.4\"\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\n/** 非密码学稳定 hash,仅用于生成浏览器本地 storage key。 */\nexport const hashString = (input: string): string => {\n let hash = 5381;\n for (let index = 0; index < input.length; index++) {\n hash = (hash * 33) ^ input.charCodeAt(index);\n }\n return (hash >>> 0).toString(36);\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * 生成随机 ID。优先用 `crypto.randomUUID`(standards-compliant UUID v4),不可用时回退到\n * `${prefix}-${timestamp}-${rand}` 形式。\n *\n * 注意:fallback 实现使用 Math.random,**不是密码学安全**,仅适用于设备/会话/事件标识等场景,\n * 不要复用此函数生成 token、CSRF 防护等安全相关的值。\n */\nexport const createRandomId = (prefix: string) => {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/**\n * RUM 上报字段 key 集中定义。\n *\n * 插件里不要散落硬编码字符串,后续字段命名调整只改这里,避免采集端与字段文档逐步漂移。\n */\nexport const RUM_ATTRIBUTES = {\n actionFrustrationType: 'action.frustration.type',\n actionId: 'action.id',\n actionName: 'action.name',\n actionTargetName: 'action.target.name',\n actionTargetTag: 'action.target.tag',\n actionType: 'action.type',\n deploymentEnvironmentName: 'deployment.environment.name',\n cacheHit: 'resource.cache.hit',\n deviceType: 'device.type',\n longTaskBlockingDuration: 'long_task.blocking_duration',\n longTaskEntryType: 'long_task.entry_type',\n longTaskId: 'long_task.id',\n networkEffectiveType: 'network.effective_type',\n networkStatus: 'network.status',\n nextHopProtocol: 'resource.protocol',\n outcomeType: 'outcome.type',\n serviceName: 'service.name',\n serviceVersion: 'service.version',\n sessionHasReplay: 'session.has_replay',\n sessionId: 'session.id',\n sessionSampleRate: 'session.sample_rate',\n sessionPhase: 'session.phase',\n sessionType: 'session.type',\n spanType: 'span_type',\n userId: 'user.id',\n userAgentName: 'user_agent.name',\n userAgentOsName: 'user_agent.os.name',\n userAgentVersion: 'user_agent.version',\n vitalMetric: 'vital.metric',\n vitalValue: 'vital.value',\n viewDomComplete: 'view.dom_complete',\n viewDomContentLoaded: 'view.dom_content_loaded',\n viewDomInteractive: 'view.dom_interactive',\n viewFirstByte: 'view.first_byte',\n viewId: 'view.id',\n viewLoadEvent: 'view.load_event',\n viewLoadingTime: 'view.loading_time',\n viewLoadingTimeSource: 'view.loading_time_source',\n viewLoadingType: 'view.loading_type',\n viewName: 'view.name',\n viewPhase: 'view.phase',\n viewPrevious: 'view.previous',\n viewPreviousUrlTemplate: 'view.previous_url_template',\n viewReferrer: 'view.referrer',\n viewStartedAt: 'view.started_at',\n viewUrl: 'view.url',\n viewUrlTemplate: 'view.url_template',\n viewVersion: 'view.version',\n websocketPhase: 'websocket.phase',\n} as const;\n\nexport type RumAttributeKey = (typeof RUM_ATTRIBUTES)[keyof typeof RUM_ATTRIBUTES];\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { hashString } from '../core/hash';\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\nexport interface BkOTDevicePluginOptions {\n /** 是否跨页面持久化匿名设备 ID,默认 false。 */\n persistentId?: boolean;\n storageKey?: string;\n}\n\nconst DEFAULT_DEVICE_STORAGE_KEY = 'BK_RUM_DEVICE_ID';\n// 用户拖窗口时 resize 高频触发,debounce 静默期内只在最后一次更新,避免无谓的 setRuntimeAttributes 风暴\nconst VIEWPORT_DEBOUNCE_MS = 250;\n\ninterface NetworkInformationLike {\n effectiveType?: string;\n type?: string;\n addEventListener?: (type: 'change', listener: () => void) => void;\n removeEventListener?: (type: 'change', listener: () => void) => void;\n}\n\ninterface UserAgentDataLike {\n mobile?: boolean;\n platform?: string;\n}\n\nconst getConnection = (): NetworkInformationLike | undefined =>\n (\n navigator as Navigator & {\n connection?: NetworkInformationLike;\n }\n ).connection;\n\nconst getUserAgentData = (): undefined | UserAgentDataLike =>\n (\n navigator as Navigator & {\n userAgentData?: UserAgentDataLike;\n }\n ).userAgentData;\n\nconst getBrowserInfo = (ua: string) => {\n const matchers: Array<[string, RegExp]> = [\n ['Edge', /Edg\\/([\\d.]+)/],\n ['Chrome', /Chrome\\/([\\d.]+)/],\n ['Firefox', /Firefox\\/([\\d.]+)/],\n ['Safari', /Version\\/([\\d.]+).*Safari/],\n ];\n for (const [name, pattern] of matchers) {\n const matched = ua.match(pattern);\n if (matched?.[1]) {\n return { name, version: matched[1].split('.')[0] };\n }\n }\n return { name: 'Other', version: undefined };\n};\n\nconst getOsName = (ua: string, platform?: string) => {\n const value = `${platform ?? ''} ${ua}`;\n if (/iphone|ipad|ipod/i.test(value)) return 'iOS';\n if (/android/i.test(value)) return 'Android';\n if (/mac/i.test(value)) return 'macOS';\n if (/win/i.test(value)) return 'Windows';\n if (/linux/i.test(value)) return 'Linux';\n return 'Other';\n};\n\nconst readDeviceId = (storageKey: string) => {\n let existed: null | string = null;\n try {\n existed = window.localStorage.getItem(storageKey);\n } catch {\n /* localStorage 不可用(隐私模式 / sandbox iframe),下面会创建一个 in-memory id */\n }\n if (existed) {\n return existed;\n }\n const deviceId = createRandomId('device');\n try {\n window.localStorage.setItem(storageKey, deviceId);\n } catch {\n /* 写不进去也行,至少本次 SDK 生命周期内 deviceId 仍然稳定 */\n }\n return deviceId;\n};\n\n// 视口尺寸:随窗口大小 / 屏幕旋转变化,需要在 resize / orientationchange 时刷新\nconst getViewportAttributes = (): Attributes => {\n if (typeof window === 'undefined') {\n return {};\n }\n return {\n 'browser.viewport.width': window.innerWidth,\n 'browser.viewport.height': window.innerHeight,\n 'browser.screen.width': window.screen?.width,\n 'browser.screen.height': window.screen?.height,\n };\n};\n\n// 网络信息:随 online / offline / connection.change 变化\nconst getNetworkAttributes = (): Attributes => {\n if (typeof navigator === 'undefined') {\n return {};\n }\n const connection = getConnection();\n return {\n [RUM_ATTRIBUTES.networkStatus]: navigator.onLine ? 'connected' : 'not_connected',\n 'network.effective_type': connection?.effectiveType,\n 'network.connection.type': connection?.type,\n };\n};\n\n// 设备与 User Agent 信息:进入页面时一次性读取,运行期不会变化,适合作为 Resource 公共属性。\nexport const getDeviceResourceAttributes = (): Attributes => {\n if (typeof navigator === 'undefined') {\n return {};\n }\n const uaData = getUserAgentData();\n const ua = navigator.userAgent;\n const browser = getBrowserInfo(ua);\n const osName = getOsName(ua, uaData?.platform);\n const deviceType = uaData?.mobile || /mobi|android|iphone|ipad|ipod/i.test(ua) ? 'mobile' : 'desktop';\n return {\n [RUM_ATTRIBUTES.deviceType]: deviceType,\n [RUM_ATTRIBUTES.userAgentName]: browser.name,\n [RUM_ATTRIBUTES.userAgentVersion]: browser.version,\n [RUM_ATTRIBUTES.userAgentOsName]: osName,\n };\n};\n\n// trailing debounce:windowMs 静默期内的多次触发只执行最后一次。\n// 适合 resize 这类\"用户停下来后才需要拿到最终值\"的场景。\nconst createDebounce = (fn: () => void, windowMs: number) => {\n let timer: number | undefined;\n return () => {\n if (timer !== undefined) {\n window.clearTimeout(timer);\n }\n timer = window.setTimeout(() => {\n timer = undefined;\n fn();\n }, windowMs);\n };\n};\n\n/**\n * 设备元数据采集插件。稳定的设备能力由 SDK 写入 Resource;这里只维护设备 ID 和运行期动态属性。\n *\n * 上报字段:\n * - `device.id`:设备级永久标识,存于 localStorage(默认 key 复用旧 session 插件以保留现网用户)。\n * - `user_agent.name` / `user_agent.version` / `user_agent.os.name`:User Agent 信息,写入 Resource。\n * - `browser.viewport.*` / `browser.screen.*`:视口与屏幕尺寸。\n * - `network.status` / `network.effective_type` / `network.connection.type`:网络信息。\n *\n * 实时更新:\n * - viewport 监听 `resize` / `orientationchange`,并经 250ms debounce 合并,避免拖窗口时高频触发;\n * 静默期结束后用最终值刷新 runtimeAttributes。\n * - network 监听 `online` / `offline` / `connection.change`(本身低频,不需要 throttle)。\n * - 二者只更新 in-memory 的 runtimeAttributes,不会主动产生新的 Span;\n * 更新后续生成的 Span 会带最新值。\n *\n * 与 session 插件的关系:device 跨会话持久(终身),session 有过期与续期(连续访问语义)。\n */\nexport const createDevicePlugin = (options: BkOTDevicePluginOptions = {}): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n return {\n name: 'device',\n init(context) {\n const storageKey =\n options.storageKey ?? `${DEFAULT_DEVICE_STORAGE_KEY}_${hashString(context.config.application.name)}`;\n const deviceId =\n typeof window === 'undefined' || options.persistentId !== true\n ? createRandomId('device')\n : readDeviceId(storageKey);\n\n context.setRuntimeAttributes({\n 'device.id': deviceId,\n // createDevicePlugin 作为扩展单独启用时,Resource 没有设备字段,仍回退到原有 runtime attributes 行为。\n ...(context.config.tracking.device === false ? getDeviceResourceAttributes() : {}),\n ...getViewportAttributes(),\n ...getNetworkAttributes(),\n });\n\n if (typeof window === 'undefined') {\n return;\n }\n\n const refreshViewport = createDebounce(() => {\n context.setRuntimeAttributes(getViewportAttributes());\n }, VIEWPORT_DEBOUNCE_MS);\n window.addEventListener('resize', refreshViewport);\n window.addEventListener('orientationchange', refreshViewport);\n teardownCallbacks.push(\n () => window.removeEventListener('resize', refreshViewport),\n () => window.removeEventListener('orientationchange', refreshViewport),\n );\n\n const refreshNetwork = () => {\n context.setRuntimeAttributes(getNetworkAttributes());\n };\n window.addEventListener('online', refreshNetwork);\n window.addEventListener('offline', refreshNetwork);\n teardownCallbacks.push(\n () => window.removeEventListener('online', refreshNetwork),\n () => window.removeEventListener('offline', refreshNetwork),\n );\n\n const connection = getConnection();\n // NetworkInformation 实现了 EventTarget;旧浏览器或某些 polyfill 可能没有 addEventListener,做能力检测\n if (connection && typeof connection.addEventListener === 'function') {\n connection.addEventListener('change', refreshNetwork);\n teardownCallbacks.push(() => {\n connection.removeEventListener?.('change', refreshNetwork);\n });\n }\n },\n shutdown() {\n while (teardownCallbacks.length) {\n teardownCallbacks.pop()?.();\n }\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { BkOTUrlMatcher, ResolvedBkOTConfig } from './config';\n\nconst getBaseUrl = () => (typeof window === 'undefined' ? 'http://localhost' : window.location.origin);\n\nexport const toAbsoluteUrl = (url: string) => {\n try {\n return new URL(url, getBaseUrl()).href;\n } catch {\n return url;\n }\n};\n\nconst DYNAMIC_PATH_SEGMENT = /^(?:\\d+|[0-9a-f]{8}-[0-9a-f-]{27,}|[0-9a-f]{16,})$/i;\n\n/**\n * 常见数字 ID、UUID 和长十六进制段统一折叠为 :id,便于服务端按路由聚合。\n * 同时服务 `view.url_template`(页面路由)与 `url.template`(请求路径)两个维度。\n */\nexport const normalizeUrlPathTemplate = (pathGroup: string) => {\n const path = pathGroup.split(/[?#]/, 1)[0];\n return path\n .split('/')\n .map(segment => (DYNAMIC_PATH_SEGMENT.test(segment) ? ':id' : segment))\n .join('/');\n};\n\n// 去掉 trailing slash,便于 path 边界对齐比较\nconst stripTrailingSlash = (value: string) => (value.length > 1 ? value.replace(/\\/+$/, '') : value);\n\n// 比较两个 URL 是否指向同一资源(忽略 query/fragment 与末尾斜杠)\nconst isSameResource = (left: string, right: string) => {\n const stripped = (value: string) => stripTrailingSlash(value.replace(/[?#].*$/, ''));\n return stripped(left) === stripped(right);\n};\n\nexport const isBkOTEndpoint = (config: ResolvedBkOTConfig, url: string) => {\n const targetUrl = toAbsoluteUrl(url);\n return isSameResource(targetUrl, toAbsoluteUrl(config.transport.endpoint));\n};\n\nexport const shouldIgnoreUrl = (config: ResolvedBkOTConfig, url: string) => isBkOTEndpoint(config, url);\n\nconst matchesUrl = (matcher: BkOTUrlMatcher, url: string) => {\n if (typeof matcher === 'function') return matcher(url);\n if (typeof matcher === 'string') return url.includes(matcher);\n matcher.lastIndex = 0;\n return matcher.test(url);\n};\n\nexport const matchesUrlList = (matchers: BkOTUrlMatcher | BkOTUrlMatcher[] | undefined, url: string) =>\n (Array.isArray(matchers) ? matchers : matchers ? [matchers] : []).some(matcher => matchesUrl(matcher, url));\n\nconst getRequestConfig = (config: ResolvedBkOTConfig) =>\n typeof config.tracking.request === 'object' ? config.tracking.request : undefined;\n\nexport const shouldIgnoreRequest = (config: ResolvedBkOTConfig, url: string) =>\n shouldIgnoreUrl(config, url) || matchesUrlList(getRequestConfig(config)?.excludedUrls, toAbsoluteUrl(url));\n\n// Trace Header 仅向显式白名单注入,避免同源第三方路径被无意注入以及跨域 CORS 预检。\nexport const shouldPropagateTraceHeader = (config: ResolvedBkOTConfig, url: string) =>\n matchesUrlList(getRequestConfig(config)?.allowedTracingUrls, toAbsoluteUrl(url));\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { version as packageVersion } from '../../package.json';\nimport { getDeviceResourceAttributes } from '../plugins/device';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { normalizeUrlPathTemplate } from './url';\n\nimport type { BkOTActionPluginOptions } from '../plugins/action';\nimport type { BkOTBlankScreenPluginOptions } from '../plugins/blank-screen';\nimport type { BkOTDevicePluginOptions } from '../plugins/device';\nimport type { BkOTLongTaskPluginOptions } from '../plugins/long-task';\nimport type { BkOTSessionConfig } from '../plugins/session';\nimport type { RumRequestOutcome } from '../schema/span';\nimport type { BkOTPlugin } from './plugin';\nimport type { BkOTUserContext } from './runtime-context';\nimport type { Attributes } from '@opentelemetry/api';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\n\nexport interface BkOTActionEventPayload {\n attributes?: Attributes;\n name: string;\n}\n\nexport interface BkOTApplicationConfig {\n environment?: string;\n name: string;\n version?: string;\n}\n\nexport interface BkOTAttributesConfig {\n custom?: () => Attributes;\n error?: () => Attributes;\n page?: () => Attributes;\n}\n\nexport type BkOTAttributeValue = boolean | number | string;\n\nexport interface BkOTBatchConfig {\n exportTimeoutMillis?: number;\n maxExportBatchSize?: number;\n maxQueueSize?: number;\n scheduledDelayMillis?: number;\n}\n\nexport interface BkOTBeforeSendEvent {\n attributes: Record<string, unknown>;\n name: string;\n signal: 'span';\n}\n\nexport interface BkOTContextConfig {\n attributes?: BkOTAttributesConfig;\n user?: BkOTUserContext;\n}\n\nexport interface BkOTCustomEventPayload {\n attributes?: Attributes;\n error?: Error;\n name: string;\n}\n\nexport interface BkOTExtensionsConfig {\n instrumentations?: Instrumentation[];\n plugins?: BkOTPlugin[];\n}\n\nexport interface BkOTOptions {\n application: BkOTApplicationConfig;\n autoStart?: boolean;\n context?: BkOTContextConfig;\n debug?: boolean;\n enabled?: boolean;\n extensions?: BkOTExtensionsConfig;\n privacy?: BkOTPrivacyConfig;\n session?: BkOTSessionConfig;\n tracking?: BkOTTrackingConfig;\n transport: BkOTTransportConfig;\n}\n\nexport interface BkOTPrivacyConfig {\n /** 初始化时的采集授权状态;运行期可通过 setTrackingConsent 更新。 */\n trackingConsent?: BkOTTrackingConsent;\n /** 在所有 RUM 自定义插件 emit 前统一过滤属性。 */\n redactAttributes?: (attributes: Attributes) => Attributes;\n /** 所有写入 attribute 的 URL 都会先经过此函数。 */\n redactUrl?: (url: string) => string;\n}\n\nexport interface BkOTRequestConfig {\n allowedTracingUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n excludedUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n beforeSend?: (event: BkOTRequestEvent, context: BkOTRequestContext) => boolean | void;\n /** 返回请求 URL 的低基数模板,例如 `/api/orders/{id}`;返回空值时回退到默认折叠规则。 */\n getUrlTemplate?: (url: string) => string | undefined;\n}\n\nexport type BkOTRequestContext =\n | { error?: unknown; request: Request | RequestInit; response?: Response; type: 'fetch' }\n | { type: 'xhr'; xhr: XMLHttpRequest };\n\nexport interface BkOTRequestEvent {\n attributes: Attributes;\n type: 'resource';\n resource: {\n method?: string;\n outcome: BkOTRequestOutcome;\n transport: 'fetch' | 'xhr';\n url?: string;\n };\n}\n\nexport type BkOTRequestOutcome = RumRequestOutcome;\n\nexport type BkOTSpanProcessorMode = 'batch' | 'simple';\n\nexport interface BkOTTrackingConfig {\n action?: BkOTActionPluginOptions | boolean;\n blankScreen?: BkOTBlankScreenPluginOptions | boolean;\n cspViolation?: boolean;\n device?: BkOTDevicePluginOptions | boolean;\n error?: boolean;\n longTask?: BkOTLongTaskPluginOptions | boolean;\n request?: BkOTRequestConfig | boolean;\n resource?: boolean;\n view?: BkOTViewConfig;\n websocket?: boolean;\n webVitals?: boolean;\n beforeSend?: (event: BkOTBeforeSendEvent) => boolean | void;\n}\n\nexport type BkOTTrackingConsent = 'granted' | 'not-granted';\n\nexport interface BkOTTransportConfig {\n batch?: BkOTBatchConfig;\n concurrencyLimit?: number;\n endpoint: string;\n headers?: Record<string, string>;\n processor?: BkOTSpanProcessorMode;\n timeoutMillis?: number;\n token?: string;\n}\n\nexport type BkOTUrlMatcher = ((url: string) => boolean) | RegExp | string;\n\nexport interface BkOTViewConfig {\n /** 不参与 View loading time 的长轮询、流式请求或埋点 URL。 */\n excludedActivityUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n /** 自动计算初始加载与 SPA 路由的页面稳定耗时,默认开启。 */\n loadingTime?: boolean;\n tracking?: 'auto' | 'manual';\n /** 返回页面路由的低基数模板,例如 `/trace/:id`;返回空值时回退到默认折叠规则。 */\n getUrlTemplate?: (url: string) => string | undefined;\n}\n\nexport interface ResolvedApplicationConfig {\n environment: string;\n name: string;\n version?: string;\n}\n\nexport interface ResolvedBkOTConfig {\n application: ResolvedApplicationConfig;\n autoStart: boolean;\n debug: boolean;\n enabled: boolean;\n extensions: BkOTExtensionsConfig;\n hooks: ResolvedConfigHooks;\n resourceAttributes: Attributes;\n session: ResolvedSessionConfig;\n spanBatch?: BkOTBatchConfig;\n spanProcessor: BkOTSpanProcessorMode;\n tracking: BkOTTrackingConfig;\n trackingConsent: BkOTTrackingConsent;\n transport: ResolvedTransportConfig;\n user?: BkOTUserContext;\n view: ResolvedViewConfig;\n}\n\nexport interface ResolvedConfigHooks {\n beforeSend?: (event: BkOTBeforeSendEvent) => boolean | void;\n getCustomAttributes: () => Attributes;\n getErrorAttributes: () => Attributes;\n getPageAttributes: () => Attributes;\n getRequestUrlTemplate: (url: string) => string;\n getViewUrlTemplate: (url: string) => string;\n redactAttributes: (attributes: Attributes) => Attributes;\n redactUrl: (url: string) => string;\n}\n\nexport interface ResolvedSessionConfig extends BkOTSessionConfig {\n sampleRate: number;\n}\n\nexport interface ResolvedTransportConfig {\n concurrencyLimit?: number;\n endpoint: string;\n headers?: Record<string, string>;\n timeoutMillis?: number;\n}\n\nexport interface ResolvedViewConfig {\n excludedActivityUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n loadingTime: boolean;\n tracking: 'auto' | 'manual';\n}\n\nconst trimTrailingSlash = (value: string) => value.trim().replace(/\\/+$/, '');\n\nconst resolveTransportConfig = (transport: BkOTTransportConfig): ResolvedTransportConfig => {\n // token 只负责提供默认鉴权头;headers 保持显式配置优先,便于特殊场景覆盖。\n const mergedHeaders =\n transport.token || transport.headers\n ? {\n ...(transport.token ? { Authorization: `Bearer ${transport.token}` } : {}),\n ...(transport.headers ?? {}),\n }\n : undefined;\n\n return {\n concurrencyLimit: transport.concurrencyLimit,\n endpoint: `${trimTrailingSlash(transport.endpoint)}/v1/rum`,\n headers: mergedHeaders,\n timeoutMillis: transport.timeoutMillis,\n };\n};\n\nconst clampSampleRate = (sampleRate?: number) => {\n if (typeof sampleRate !== 'number' || !Number.isFinite(sampleRate)) {\n return 1;\n }\n return Math.max(0, Math.min(1, sampleRate));\n};\n\nconst identityRedactAttributes = (attributes: Attributes) => attributes;\n\n// 默认只保留 URL 的定位信息;认证信息、查询参数和 fragment 可能携带用户数据,统一移除。\nconst defaultRedactUrl = (url: string) => {\n if (!url) return url;\n try {\n const parsed = new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n parsed.username = '';\n parsed.password = '';\n parsed.search = '';\n parsed.hash = '';\n return parsed.href;\n } catch {\n return url.replace(/[?#].*$/, '');\n }\n};\n\nconst getUrlPathname = (url: string) => {\n try {\n return new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href).pathname || '/';\n } catch {\n return url || '/';\n }\n};\n\n/**\n * 低基数路径模板,供 `view.url_template` 与 `url.template` 共用同一套折叠规则。\n * 只保留 path:host 维度由 `server.address` 表达,query 由 `normalizeUrlPathTemplate` 去掉。\n */\nconst templatizeUrlPath = (url: string) => normalizeUrlPathTemplate(getUrlPathname(url));\n\n/** 模板 Hook 在每个请求/导航上都会跑,抛错不能影响追踪本身 */\nconst resolveTemplateHook =\n (config: BkOTOptions, custom: ((url: string) => string | undefined) | undefined) => (url: string) => {\n try {\n const templated = custom?.(url);\n if (templated) return templated;\n } catch (error) {\n if (config.debug) globalThis.console?.warn('[bk-ot] url template hook failed:', error);\n }\n return templatizeUrlPath(url);\n };\n\nconst resolveApplicationConfig = (application: BkOTOptions['application']): ResolvedApplicationConfig => ({\n environment: application.environment ?? 'production',\n name: application.name,\n version: application.version,\n});\n\nconst resolveResourceAttributes = (\n application: ResolvedApplicationConfig,\n device: BkOTTrackingConfig['device'],\n sampleRate: number,\n): Attributes => ({\n [RUM_ATTRIBUTES.deploymentEnvironmentName]: application.environment,\n ...(device === false ? {} : getDeviceResourceAttributes()),\n [RUM_ATTRIBUTES.serviceName]: application.name,\n ...(application.version ? { [RUM_ATTRIBUTES.serviceVersion]: application.version } : {}),\n [RUM_ATTRIBUTES.sessionSampleRate]: sampleRate,\n 'telemetry.sdk.language': 'webjs',\n 'telemetry.sdk.name': 'blueking',\n 'telemetry.sdk.version': packageVersion,\n});\n\nconst validateTransportConfig = (transport: BkOTTransportConfig | undefined) => {\n if (!transport) throw new Error('[bk-ot] transport is required.');\n if (!transport.endpoint?.trim()) throw new Error('[bk-ot] transport.endpoint is required.');\n};\n\nconst resolveHooks = (config: BkOTOptions): ResolvedConfigHooks => ({\n beforeSend: config.tracking?.beforeSend,\n getPageAttributes: config.context?.attributes?.page ?? (() => ({})),\n getErrorAttributes: config.context?.attributes?.error ?? (() => ({})),\n getCustomAttributes: config.context?.attributes?.custom ?? (() => ({})),\n getRequestUrlTemplate: resolveTemplateHook(\n config,\n typeof config.tracking?.request === 'object' ? config.tracking.request.getUrlTemplate : undefined,\n ),\n getViewUrlTemplate: resolveTemplateHook(\n config,\n typeof config.tracking?.view === 'object' ? config.tracking.view.getUrlTemplate : undefined,\n ),\n redactAttributes: config.privacy?.redactAttributes ?? identityRedactAttributes,\n redactUrl: config.privacy?.redactUrl ?? defaultRedactUrl,\n});\n\nexport const resolveConfig = (config: BkOTOptions): ResolvedBkOTConfig => {\n if (!config.application?.name?.trim()) {\n throw new Error('[bk-ot] application.name is required.');\n }\n validateTransportConfig(config.transport);\n const application = resolveApplicationConfig(config.application);\n const viewConfig = typeof config.tracking?.view === 'object' ? config.tracking.view : undefined;\n const hooks = resolveHooks(config);\n const sampleRate = clampSampleRate(config.session?.sampleRate);\n\n return {\n application,\n autoStart: config.autoStart ?? true,\n debug: config.debug ?? false,\n enabled: config.enabled ?? true,\n extensions: {\n instrumentations: [...(config.extensions?.instrumentations ?? [])],\n plugins: [...(config.extensions?.plugins ?? [])],\n },\n hooks,\n resourceAttributes: hooks.redactAttributes(\n resolveResourceAttributes(application, config.tracking?.device, sampleRate),\n ),\n session: {\n ...config.session,\n sampleRate,\n },\n spanBatch: config.transport.batch,\n spanProcessor: config.transport.processor ?? 'batch',\n tracking: config.tracking ?? {},\n trackingConsent: config.privacy?.trackingConsent ?? 'granted',\n transport: resolveTransportConfig(config.transport),\n user: config.context?.user,\n view: {\n excludedActivityUrls: viewConfig?.excludedActivityUrls,\n loadingTime: viewConfig?.loadingTime !== false,\n tracking: viewConfig?.tracking === 'manual' ? 'manual' : 'auto',\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { RumSpanType } from '../schema/span';\nimport type { BkOTActivityEvent } from './action-activity';\nimport type { ResolvedBkOTConfig } from './config';\nimport type { BkOTSessionLifecycleEvent, BkOTUserContext, BkOTViewCommand, BkOTViewContext } from './runtime-context';\nimport type { Attributes, Link, Span, SpanKind, TimeInput, Tracer } from '@opentelemetry/api';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\n\nexport interface BkOTPlugin {\n enabled?: ((config: ResolvedBkOTConfig) => boolean) | boolean;\n name: string;\n flush?: () => Promise<void> | void;\n init: (context: BkOTRuntimeContext) => Promise<void> | void;\n shutdown?: () => Promise<void> | void;\n}\n\nexport interface BkOTRuntimeContext {\n config: ResolvedBkOTConfig;\n tracer: Tracer;\n /** 对外提供的属性脱敏入口,所有插件在 emit 前都应过一次 */\n applyRedact: (attributes: Attributes) => Attributes;\n flush: () => Promise<void>;\n getRuntimeAttributes: () => Attributes;\n getRuntimeAttributesAt: (timestamp: number) => Attributes;\n isSampled: () => boolean;\n isSessionActive: () => boolean;\n isViewActive: () => boolean;\n notifyActivity: (event: BkOTActivityEvent) => void;\n notifySessionLifecycle: (event: BkOTSessionLifecycleEvent) => void;\n onActivity: (listener: (event: BkOTActivityEvent) => void) => () => void;\n onSessionLifecycle: (listener: (event: BkOTSessionLifecycleEvent) => void) => () => void;\n onViewChange: (listener: (view: BkOTViewContext) => void) => () => void;\n onViewCommand: (listener: (command: BkOTViewCommand) => void) => () => void;\n registerInstrumentations: (instrumentations: Instrumentation[]) => void;\n setRuntimeAttributes: (attributes: Attributes, changedAt?: number) => void;\n /** 更新用户上下文;user.id 由接入方传入,SDK 原样透传 */\n setUser: (user: BkOTUserContext) => void;\n /** 更新当前 View 上下文,后续 span 会自动带上 view.* 关联字段 */\n setView: (view: BkOTViewContext, changedAt?: number) => void;\n startSpan: (name: string, attributes?: Attributes, options?: BkOTStartSpanOptions) => Span;\n}\n\n/**\n * startSpan 的扩展选项。\n *\n * 用于\"事件实际发生在过去某个时刻,但 span 现在才创建\"的场景:\n * 例如 PerformanceObserver 在条目结束后才回调,但 span 的时间窗仍需反映\n * 条目真实发生的区间,方便 trace 视图与并发请求对齐。\n *\n * startTime 接受 OT TimeInput;常用 epoch 毫秒(performance.timeOrigin + performance.now())。\n * 配合 span.end(endTime?) 可控制结束时间。\n */\nexport interface BkOTStartSpanOptions {\n /** 内置 Span 根据脱敏后的属性生成名称;自定义 startSpan 默认保留传入名称。 */\n rumSpanType?: RumSpanType;\n /** 用于从历史中解析 Session/View/Action 归属;默认复用数字类型 startTime。 */\n contextTime?: number;\n kind?: SpanKind;\n /** 关联其他 trace 的 Span Link;OTel 要求在创建时传入。 */\n links?: Link[];\n startTime?: TimeInput;\n}\n\nexport const isPluginEnabled = (plugin: BkOTPlugin, config: ResolvedBkOTConfig) => {\n if (typeof plugin.enabled === 'function') {\n return plugin.enabled(config);\n }\n return plugin.enabled !== false;\n};\n\nexport const createPlugin = (plugin: BkOTPlugin) => plugin;\n\nexport class PluginManager {\n private readonly plugins: BkOTPlugin[];\n private startedPlugins: BkOTPlugin[] = [];\n\n public constructor(plugins: BkOTPlugin[]) {\n this.plugins = plugins;\n }\n\n public async flush() {\n // 并行 flush,避免单个慢插件拖累整体\n await Promise.all(this.startedPlugins.map(plugin => Promise.resolve().then(() => plugin.flush?.())));\n }\n\n public async shutdown() {\n const plugins = [...this.startedPlugins].reverse();\n for (const plugin of plugins) {\n await plugin.shutdown?.();\n }\n this.startedPlugins = [];\n }\n\n public async start(context: BkOTRuntimeContext) {\n // 每个插件独立 try/catch,单个插件 init 失败不应拖累其他插件:\n // - 失败的插件不会进入 startedPlugins(shutdown 时不会被反向 teardown)\n // - debug 模式打 warn,方便排查;非 debug 静默失败避免污染业务日志\n for (const plugin of this.plugins) {\n if (!isPluginEnabled(plugin, context.config)) {\n continue;\n }\n try {\n await plugin.init(context);\n this.startedPlugins.push(plugin);\n } catch (error) {\n if (context.config.debug) {\n globalThis.console?.warn(`[bk-ot] plugin \"${plugin.name}\" init failed:`, error);\n }\n }\n }\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nimport { RUM_ATTRIBUTES } from './attributes';\n\nimport type { Attributes } from '@opentelemetry/api';\n\n// 所有插件通过同一分类模型生成检索字段,保证错误、资源、Action 等信号可按统一维度聚合。\nexport const RUM_SPAN_OUTCOME = {\n abort: 'abort',\n error: 'error',\n success: 'success',\n timeout: 'timeout',\n warning: 'warning',\n} as const;\n\nexport const RUM_SPAN_TYPE = {\n action: 'action',\n custom: 'custom',\n error: 'error',\n longTask: 'long_task',\n resource: 'resource',\n session: 'session',\n vital: 'vital',\n view: 'view',\n websocket: 'websocket',\n} as const;\n\nexport type RumRequestOutcome =\n | { error?: unknown; type: 'network_error' }\n | { error?: unknown; type: 'timeout' }\n | { statusCode?: number; type: 'response' }\n | { type: 'abort' };\n\nexport interface RumResourceSpanInput {\n initiatorType?: string;\n method?: string;\n outcome?: RumRequestOutcome;\n url: string;\n}\n\nexport interface RumSpanClassification {\n outcome?: RumSpanOutcome;\n spanType: RumSpanType;\n}\n\ninterface RumSpanNameInput {\n attributes: Attributes;\n nameHint?: string;\n spanType: RumSpanType;\n}\n\nexport type RumSpanOutcome = (typeof RUM_SPAN_OUTCOME)[keyof typeof RUM_SPAN_OUTCOME];\n\nexport type RumSpanType = (typeof RUM_SPAN_TYPE)[keyof typeof RUM_SPAN_TYPE];\n\nconst getStringAttribute = (attributes: Attributes, key: string) => {\n const value = attributes[key];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n};\n\n/**\n * 使用稳定的领域字段生成可读 Span 名称。唯一 ID、完整 URL、错误消息和数值不参与命名,避免抬高基数。\n */\nexport const buildRumSpanName = ({ attributes, nameHint, spanType }: RumSpanNameInput): string => {\n if (spanType === RUM_SPAN_TYPE.session) {\n const phase = getStringAttribute(attributes, RUM_ATTRIBUTES.sessionPhase);\n return phase ? `session.${phase}` : 'session';\n }\n if (spanType === RUM_SPAN_TYPE.view) {\n return (\n getStringAttribute(attributes, RUM_ATTRIBUTES.viewName) ??\n getStringAttribute(attributes, RUM_ATTRIBUTES.viewUrlTemplate) ??\n 'view'\n );\n }\n if (spanType === RUM_SPAN_TYPE.resource) {\n const method = getStringAttribute(attributes, 'http.request.method')?.toUpperCase();\n const urlTemplate = getStringAttribute(attributes, 'url.template');\n if (method && urlTemplate) return `${method} ${urlTemplate}`;\n const resourceType = getStringAttribute(attributes, 'resource.type');\n return resourceType ? `resource.${resourceType}` : 'resource';\n }\n if (spanType === RUM_SPAN_TYPE.action) {\n return (\n getStringAttribute(attributes, RUM_ATTRIBUTES.actionName) ??\n getStringAttribute(attributes, RUM_ATTRIBUTES.actionType) ??\n 'action'\n );\n }\n if (spanType === RUM_SPAN_TYPE.error) {\n const blankScreenReason = getStringAttribute(attributes, 'blank_screen.reason');\n if (blankScreenReason) return `blank_screen.${blankScreenReason}`;\n const cspDirective = getStringAttribute(attributes, 'csp.effective_directive');\n if (cspDirective) return `csp.${cspDirective}`;\n return nameHint?.trim() || getStringAttribute(attributes, 'error.source') || 'error';\n }\n if (spanType === RUM_SPAN_TYPE.vital) {\n return getStringAttribute(attributes, RUM_ATTRIBUTES.vitalMetric)?.toUpperCase() ?? 'vital';\n }\n if (spanType === RUM_SPAN_TYPE.longTask) {\n return getStringAttribute(attributes, RUM_ATTRIBUTES.longTaskEntryType) ?? 'long-task';\n }\n if (spanType === RUM_SPAN_TYPE.websocket) {\n const phase = getStringAttribute(attributes, RUM_ATTRIBUTES.websocketPhase);\n return phase ? `websocket.${phase}` : 'websocket';\n }\n if (spanType === RUM_SPAN_TYPE.custom) {\n return nameHint === undefined ? 'custom' : `custom.${nameHint}`;\n }\n return spanType;\n};\n\nexport interface RumUrlTarget {\n serverAddress?: string;\n serverPort?: number;\n}\n\nexport const getHttpOutcome = (statusCode: number | undefined): RumSpanOutcome => {\n if (statusCode === 408 || statusCode === 504) return RUM_SPAN_OUTCOME.timeout;\n if (typeof statusCode === 'number' && statusCode >= 400) return RUM_SPAN_OUTCOME.error;\n return RUM_SPAN_OUTCOME.success;\n};\n\nexport const getVitalOutcome = (rating: string | undefined): RumSpanOutcome =>\n rating === 'good' ? RUM_SPAN_OUTCOME.success : RUM_SPAN_OUTCOME.warning;\n\nexport const getUrlTarget = (url: string | undefined): RumUrlTarget => {\n if (!url) {\n return {};\n }\n try {\n const parsed = new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n return {\n serverAddress: parsed.hostname,\n serverPort: parsed.port ? Number(parsed.port) : undefined,\n };\n } catch {\n return {};\n }\n};\n\nexport const buildRumSpanAttributes = ({\n outcome = RUM_SPAN_OUTCOME.success,\n spanType,\n}: RumSpanClassification): Attributes => ({\n [RUM_ATTRIBUTES.spanType]: spanType,\n [RUM_ATTRIBUTES.outcomeType]: outcome,\n});\n\nexport const buildRumResourceSpanAttributes = ({\n initiatorType = 'other',\n method,\n outcome,\n url,\n}: RumResourceSpanInput): Attributes => {\n const target = getUrlTarget(url);\n const responseStatus =\n outcome?.type === 'response' && typeof outcome.statusCode === 'number' && outcome.statusCode > 0\n ? outcome.statusCode\n : undefined;\n const outcomeType =\n outcome?.type === 'abort'\n ? RUM_SPAN_OUTCOME.abort\n : outcome?.type === 'timeout'\n ? RUM_SPAN_OUTCOME.timeout\n : outcome?.type === 'network_error'\n ? RUM_SPAN_OUTCOME.error\n : typeof responseStatus === 'number'\n ? getHttpOutcome(responseStatus)\n : RUM_SPAN_OUTCOME.success;\n const normalizedMethod = method?.toUpperCase();\n return {\n ...buildRumSpanAttributes({\n outcome: outcomeType,\n spanType: RUM_SPAN_TYPE.resource,\n }),\n ...(target.serverAddress ? { 'server.address': target.serverAddress } : {}),\n ...(target.serverPort !== undefined ? { 'server.port': target.serverPort } : {}),\n 'resource.type': initiatorType,\n ...(normalizedMethod ? { 'http.request.method': normalizedMethod } : {}),\n ...(typeof responseStatus === 'number' ? { 'http.response.status_code': responseStatus } : {}),\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { RUM_SPAN_TYPE } from '../schema/span';\nimport { isBkOTEndpoint } from './url';\n\nimport type { ResolvedBkOTConfig } from './config';\nimport type { Attributes, Context, Span as ApiSpan } from '@opentelemetry/api';\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';\n\nconst SELF_TELEMETRY_URL_KEYS = ['http.url', 'url.full'];\nconst discardedSpans = new WeakSet<object>();\n\nexport const markSpanDiscarded = (span: ApiSpan) => {\n discardedSpans.add(span);\n};\n\nconst getSpanUrl = (span: ReadableSpan): string | undefined => {\n for (const key of SELF_TELEMETRY_URL_KEYS) {\n const value = span.attributes?.[key];\n if (typeof value === 'string') {\n return value;\n }\n }\n return undefined;\n};\n\nconst hasSessionId = (attributes: Record<string, unknown> | undefined) => {\n const sessionId = attributes?.[RUM_ATTRIBUTES.sessionId];\n return typeof sessionId === 'string' && sessionId.length > 0;\n};\n\nconst hasViewId = (attributes: Record<string, unknown> | undefined) => {\n const viewId = attributes?.[RUM_ATTRIBUTES.viewId];\n return typeof viewId === 'string' && viewId.length > 0;\n};\n\nconst hasRumContext = (attributes: Record<string, unknown> | undefined) =>\n hasSessionId(attributes) && hasViewId(attributes);\n\nconst isSessionSpan = (attributes: Record<string, unknown> | undefined) =>\n attributes?.[RUM_ATTRIBUTES.spanType] === RUM_SPAN_TYPE.session;\n\n/**\n * 给所有 span 固化创建时的运行时上下文,并在 onEnd 阶段过滤自身上报请求和无 RUM 上下文 span。\n */\nexport class FilteringSpanProcessor implements SpanProcessor {\n public constructor(\n private readonly inner: SpanProcessor,\n private readonly config: ResolvedBkOTConfig,\n private readonly getRuntimeAttributes: () => Attributes,\n ) {}\n\n public forceFlush(): Promise<void> {\n return this.inner.forceFlush();\n }\n\n public onEnd(span: ReadableSpan): void {\n const url = getSpanUrl(span);\n if (\n discardedSpans.delete(span) ||\n (url && isBkOTEndpoint(this.config, url)) ||\n (!hasRumContext(span.attributes) && !(isSessionSpan(span.attributes) && hasSessionId(span.attributes)))\n ) {\n return;\n }\n try {\n if (\n this.config.hooks?.beforeSend?.({\n attributes: span.attributes,\n name: span.name,\n signal: 'span',\n }) === false\n ) {\n return;\n }\n } catch (error) {\n if (this.config.debug) globalThis.console?.warn('[bk-ot] tracking.beforeSend failed:', error);\n }\n this.inner.onEnd(span);\n }\n\n public onStart(span: Span, parentContext: Context): void {\n const existingAttributes = (span as Span & { attributes?: Attributes }).attributes ?? {};\n const missingRuntimeAttributes: Attributes = {};\n // instrumentation 显式写入的属性优先,只补齐创建时缺失的运行时上下文。\n for (const [key, value] of Object.entries(this.getRuntimeAttributes())) {\n if (existingAttributes[key] === undefined && value !== undefined) missingRuntimeAttributes[key] = value;\n }\n span.setAttributes(missingRuntimeAttributes);\n this.inner.onStart(span, parentContext);\n }\n\n public shutdown(): Promise<void> {\n return this.inner.shutdown();\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\n\nimport type { Attributes } from '@opentelemetry/api';\n\nexport type BkOTSessionLifecycleEvent =\n | {\n expiredAt: number;\n id: string;\n reason: 'external' | 'inactivity' | 'maxLifetime';\n type: 'expired';\n }\n | {\n id: string;\n previousId?: string;\n reason: 'inactivity' | 'init' | 'maxLifetime' | 'shared';\n startedAt: number;\n type: 'renewed';\n };\n\nexport interface BkOTStartViewOptions {\n attributes?: Attributes;\n name?: string;\n url?: string;\n}\n\nexport interface BkOTUserContext {\n /** 由接入方传入并由 SDK 原样透传;SDK 不 hash、不脱敏、不改写。 */\n id?: string;\n}\n\nexport type BkOTViewCommand =\n | { name: string; type: 'set_name' }\n | { options: BkOTStartViewOptions; type: 'start' }\n | { time: number; type: 'set_loading_time' };\n\nexport interface BkOTViewContext {\n attributes?: Attributes;\n id?: string;\n loadingType?: 'bf_cache' | 'initial_load' | 'route_change' | 'session_renewal';\n name?: string;\n startedAt?: number;\n url?: string;\n urlTemplate?: string;\n}\n\nconst PROTECTED_VIEW_ATTRIBUTE_KEYS = new Set<string>(Object.values(RUM_ATTRIBUTES));\n\nconst toActionId = (value: unknown): string | undefined => {\n if (typeof value === 'string' && value.length > 0) return value;\n if (!Array.isArray(value)) return undefined;\n for (let index = value.length - 1; index >= 0; index -= 1) {\n const item = value[index];\n if (typeof item === 'string' && item.length > 0) return item;\n }\n return undefined;\n};\n\n/**\n * 管理 SDK 运行期公共属性快照。\n *\n * 这里仅保存“后续事件都需要带上”的低成本上下文,Session/View/用户切换时更新快照,\n * 插件发 Span 时读取当前快照即可,避免每个插件重复维护公共字段。\n */\nexport class RumRuntimeContext {\n private readonly actionHistory: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }> = [];\n private readonly attributes: Attributes = {};\n private readonly queuedViewCommands: BkOTViewCommand[] = [];\n\n // 保存关联关系的生效区间,供延迟到达的 PerformanceEntry 按事件时间回查原 Session/View/Action。\n private recordAssociation = (\n history: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }>,\n keys: Iterable<string>,\n changedAt: number,\n active: boolean,\n ) => {\n const previous = history.at(-1);\n if (previous && previous.endedAt === undefined) previous.endedAt = Math.max(previous.startedAt, changedAt);\n if (active) {\n const associationAttributes: Attributes = {};\n for (const key of keys) {\n const value = this.attributes[key];\n if (value !== undefined) associationAttributes[key] = value;\n }\n history.push({ attributes: associationAttributes, startedAt: changedAt });\n }\n if (history.length > 100) history.splice(0, history.length - 100);\n };\n private readonly sessionHistory: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }> = [];\n private sampled = false;\n private readonly samplingHistory: Array<{ endedAt?: number; sampled: boolean; startedAt: number }> = [];\n private readonly sessionLifecycleListeners = new Set<(event: BkOTSessionLifecycleEvent) => void>();\n private readonly setOptionalAttribute = (key: string, value: string | undefined) => {\n if (value === undefined) {\n delete this.attributes[key];\n return;\n }\n this.attributes[key] = value;\n };\n private user: BkOTUserContext = {};\n private view: BkOTViewContext = {};\n private readonly viewAttributeKeys = new Set<string>();\n private readonly viewChangeListeners = new Set<(view: BkOTViewContext) => void>();\n private readonly viewCommandListeners = new Set<(command: BkOTViewCommand) => void>();\n\n private readonly viewHistory: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }> = [];\n\n private readonly viewScopedAttributeKeys = new Set<string>();\n\n public dispatchViewCommand = (command: BkOTViewCommand) => {\n // autoStart 下调用方可能早于 page-view 插件发命令,先排队可避免 startView/setViewName 丢失。\n if (this.viewCommandListeners.size === 0) {\n this.queuedViewCommands.push(command);\n return;\n }\n this.viewCommandListeners.forEach(listener => listener(command));\n };\n\n public getAttributes = (): Attributes => ({ ...this.attributes });\n\n public getAttributesAt = (timestamp: number): Attributes => {\n if (!Number.isFinite(timestamp)) return this.getAttributes();\n const result = this.getAttributes();\n const applyHistory = (\n history: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }>,\n keys: Iterable<string>,\n ) => {\n // 先移除当前关联字段,再用目标时间所在的历史快照覆盖,避免把旧事件错误归到当前 View。\n for (const key of keys) delete result[key];\n const matched = [...history]\n .reverse()\n .find(entry => entry.startedAt <= timestamp && (entry.endedAt === undefined || timestamp < entry.endedAt));\n if (matched) Object.assign(result, matched.attributes);\n };\n applyHistory(this.sessionHistory, [RUM_ATTRIBUTES.sessionId, RUM_ATTRIBUTES.sessionHasReplay]);\n applyHistory(this.viewHistory, this.viewScopedAttributeKeys);\n applyHistory(this.actionHistory, [RUM_ATTRIBUTES.actionId]);\n return result;\n };\n\n public getUser = (): BkOTUserContext => ({ ...this.user });\n\n public getView = (): BkOTViewContext => ({ ...this.view });\n\n public isSessionActive = () => typeof this.attributes[RUM_ATTRIBUTES.sessionId] === 'string';\n\n public isSessionSampledAt = (timestamp: number) => {\n if (!Number.isFinite(timestamp)) return this.sampled;\n return (\n [...this.samplingHistory]\n .reverse()\n .find(entry => entry.startedAt <= timestamp && (entry.endedAt === undefined || timestamp < entry.endedAt))\n ?.sampled ?? false\n );\n };\n\n public isViewActive = () => typeof this.attributes[RUM_ATTRIBUTES.viewId] === 'string';\n\n public notifySessionLifecycle = (event: BkOTSessionLifecycleEvent) => {\n this.sessionLifecycleListeners.forEach(listener => listener(event));\n };\n\n public onSessionLifecycle = (listener: (event: BkOTSessionLifecycleEvent) => void) => {\n this.sessionLifecycleListeners.add(listener);\n return () => this.sessionLifecycleListeners.delete(listener);\n };\n\n public onViewChange = (listener: (view: BkOTViewContext) => void) => {\n this.viewChangeListeners.add(listener);\n if (this.view.id) listener(this.getView());\n return () => this.viewChangeListeners.delete(listener);\n };\n\n public onViewCommand = (listener: (command: BkOTViewCommand) => void) => {\n this.viewCommandListeners.add(listener);\n while (this.queuedViewCommands.length) {\n listener(this.queuedViewCommands.shift()!);\n }\n return () => this.viewCommandListeners.delete(listener);\n };\n\n public setAttributes = (attributes: Attributes, changedAt = Date.now()) => {\n for (const [key, value] of Object.entries(attributes)) {\n if (value === undefined) {\n delete this.attributes[key];\n continue;\n }\n this.attributes[key] = value;\n }\n if (RUM_ATTRIBUTES.sessionId in attributes) {\n this.recordAssociation(\n this.sessionHistory,\n [RUM_ATTRIBUTES.sessionId, RUM_ATTRIBUTES.sessionHasReplay],\n changedAt,\n typeof this.attributes[RUM_ATTRIBUTES.sessionId] === 'string',\n );\n }\n if (RUM_ATTRIBUTES.actionId in attributes) {\n const actionId = toActionId(this.attributes[RUM_ATTRIBUTES.actionId]);\n if (actionId === undefined) delete this.attributes[RUM_ATTRIBUTES.actionId];\n else this.attributes[RUM_ATTRIBUTES.actionId] = actionId;\n this.recordAssociation(\n this.actionHistory,\n [RUM_ATTRIBUTES.actionId],\n changedAt,\n typeof this.attributes[RUM_ATTRIBUTES.actionId] === 'string',\n );\n }\n };\n\n public setUser = (user: BkOTUserContext) => {\n this.user = {\n ...this.user,\n ...user,\n };\n\n if ('id' in user) {\n if (user.id === undefined) {\n delete this.attributes[RUM_ATTRIBUTES.userId];\n return;\n }\n this.attributes[RUM_ATTRIBUTES.userId] = user.id;\n }\n };\n\n public setSessionSampled = (sampled: boolean, changedAt = Date.now()) => {\n if (sampled === this.sampled) return;\n const previous = this.samplingHistory.at(-1);\n if (previous && previous.endedAt === undefined) previous.endedAt = Math.max(previous.startedAt, changedAt);\n this.sampled = sampled;\n if (sampled) this.samplingHistory.push({ sampled, startedAt: changedAt });\n if (this.samplingHistory.length > 100) {\n this.samplingHistory.splice(0, this.samplingHistory.length - 100);\n }\n };\n\n public setView = (view: BkOTViewContext, changedAt = view.startedAt ?? Date.now()) => {\n this.viewAttributeKeys.forEach(key => delete this.attributes[key]);\n this.viewAttributeKeys.clear();\n const viewAttributes: Attributes = {};\n for (const [key, value] of Object.entries(view.attributes ?? {})) {\n // 自定义 View 属性不能覆盖 SDK 维护的关联和语义字段。\n if (value === undefined || PROTECTED_VIEW_ATTRIBUTE_KEYS.has(key)) continue;\n viewAttributes[key] = value;\n this.attributes[key] = value;\n this.viewAttributeKeys.add(key);\n this.viewScopedAttributeKeys.add(key);\n }\n this.view = { ...view, attributes: viewAttributes };\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewId, view.id);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewUrl, view.url);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewUrlTemplate, view.urlTemplate);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewLoadingType, view.loadingType);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewName, view.name);\n [\n RUM_ATTRIBUTES.viewId,\n RUM_ATTRIBUTES.viewUrl,\n RUM_ATTRIBUTES.viewUrlTemplate,\n RUM_ATTRIBUTES.viewLoadingType,\n RUM_ATTRIBUTES.viewName,\n ].forEach(key => this.viewScopedAttributeKeys.add(key));\n this.recordAssociation(\n this.viewHistory,\n this.viewScopedAttributeKeys,\n changedAt,\n typeof view.id === 'string' && view.id.length > 0,\n );\n this.viewChangeListeners.forEach(listener => listener(this.getView()));\n };\n\n public constructor(initialAttributes: Attributes = {}, user?: BkOTUserContext) {\n this.setAttributes(initialAttributes);\n if (user) {\n this.setUser(user);\n }\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { createRandomId } from '../core/id';\nimport { matchesUrlList } from '../core/url';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTActivityEvent } from '../core/action-activity';\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\n/**\n * 用户点击采集以“点击后产生的副作用”为 Action 生命周期:关联请求、资源、长任务、DOM 变化和错误,\n * 在活动安静后结束。完成后的 Action 暂缓至连击窗口结束再上报,以便把三次相近点击合并为一次 rage click。\n */\nconst ACTION_VALIDATION_DELAY = 100;\nconst ACTION_END_DELAY = 100;\nconst CLICK_CHAIN_DURATION = 1_000;\nconst CLICK_CHAIN_MAX_DISTANCE = 100;\nconst DEFAULT_ACTION_MAX_DURATION = 10_000;\nconst DEFAULT_ACTION_NAME_ATTRIBUTE = 'data-bk-action-name';\nconst MAX_NAME_LENGTH = 100;\nconst MAX_PARENTS_TO_CONSIDER = 10;\n\nexport interface BkOTActionPluginOptions {\n actionNameAttribute?: string;\n maxDuration?: number;\n /** 默认仅采集显式 data 属性;设为 text 才会读取可访问名称和 DOM 文本。 */\n nameCollection?: 'explicit' | 'text';\n}\n\ntype ActionFrustrationType = 'dead_click' | 'error_click' | 'rage_click';\n\ninterface ActiveAction {\n completed?: { endTime: number; hasLoadingTime: boolean };\n frustrations: Set<ActionFrustrationType>;\n hadActivity: boolean;\n hadError: boolean;\n id: string;\n lastActivityTime: number;\n maxDurationTimer: ReturnType<typeof setTimeout>;\n pendingRequests: Set<string>;\n quietTimer?: ReturnType<typeof setTimeout>;\n reportTimer?: ReturnType<typeof setTimeout>;\n runtimeAttributes: Attributes;\n startTime: number;\n target: Element;\n targetName: string;\n targetTag: string;\n userActivity: { input: boolean; scroll: boolean; selection: boolean };\n validationTimer: ReturnType<typeof setTimeout>;\n}\n\ninterface RecentClick {\n action: ActiveAction;\n target: Element;\n x: number;\n y: number;\n}\n\nconst normalizeText = (value: string) => value.replace(/\\s+/g, ' ').trim().slice(0, MAX_NAME_LENGTH);\n\nconst getParentElement = (element: Element) => {\n if (element.parentElement) {\n return element.parentElement;\n }\n const root = element.getRootNode?.();\n return typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot ? root.host : null;\n};\n\nconst findAttributeOnAncestors = (element: Element, attribute: string) => {\n let current: Element | null = element;\n while (current) {\n const value = current.getAttribute(attribute);\n if (value) {\n return normalizeText(value);\n }\n current = getParentElement(current);\n }\n return undefined;\n};\n\nconst getElementText = (element: Element) =>\n (element as HTMLElement).isContentEditable ? '' : normalizeText(element.textContent ?? '');\n\nconst getPriorityName = (element: Element) => {\n const formElement = element as Element & {\n labels?: HTMLLabelElement[] | NodeListOf<HTMLLabelElement>;\n value?: string;\n };\n const label = formElement.labels?.[0];\n if (label) {\n const labelText = getElementText(label);\n if (labelText) return labelText;\n }\n\n const tagName = element.tagName.toLowerCase();\n const inputType = element.getAttribute('type')?.toLowerCase();\n if (tagName === 'input' && ['button', 'reset', 'submit'].includes(inputType ?? '')) {\n const value = normalizeText(formElement.value ?? '');\n if (value) return value;\n }\n\n if (tagName === 'button' || tagName === 'label' || element.getAttribute('role') === 'button') {\n const text = getElementText(element);\n if (text) return text;\n }\n\n for (const attribute of ['aria-label', 'alt', 'name', 'title', 'placeholder']) {\n const value = normalizeText(element.getAttribute(attribute) ?? '');\n if (value) return value;\n }\n\n return undefined;\n};\n\nexport const getActionNameFromElement = (\n target: Element,\n actionNameAttribute = DEFAULT_ACTION_NAME_ATTRIBUTE,\n includeText = false,\n): string => {\n const explicitName = findAttributeOnAncestors(target, actionNameAttribute);\n if (explicitName) {\n return explicitName;\n }\n if (!includeText) return target.tagName.toLowerCase();\n\n let current: Element | null = target;\n let parentCount = 0;\n while (current && parentCount <= MAX_PARENTS_TO_CONSIDER) {\n const tagName = current.tagName.toLowerCase();\n if (tagName === 'body' || tagName === 'html' || tagName === 'head') break;\n const priorityName = getPriorityName(current);\n if (priorityName) return priorityName;\n if (tagName === 'form') break;\n current = getParentElement(current);\n parentCount += 1;\n }\n\n current = target;\n parentCount = 0;\n while (current && parentCount <= MAX_PARENTS_TO_CONSIDER) {\n const tagName = current.tagName.toLowerCase();\n if (tagName === 'body' || tagName === 'html' || tagName === 'head') break;\n const text = getElementText(current);\n if (text) return text;\n if (tagName === 'form') break;\n current = getParentElement(current);\n parentCount += 1;\n }\n\n return target.tagName.toLowerCase();\n};\n\nconst getElement = (event: Event) => {\n const composedTarget = event.composedPath?.()[0];\n if (composedTarget instanceof Element) return composedTarget;\n return event.target instanceof Element ? event.target : undefined;\n};\n\nconst toEpochTime = (event: Event) => {\n const eventTime = event.timeStamp;\n if (!Number.isFinite(eventTime) || eventTime <= 0) return Date.now();\n if (eventTime > 1_000_000_000_000) return eventTime;\n return typeof performance === 'undefined' ? Date.now() : performance.timeOrigin + eventTime;\n};\n\nconst positiveNumber = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;\n\nexport const isDeadClickExcluded = (target: Element) => {\n let current: Element | null = target;\n if (current.tagName.toLowerCase() === 'label' && current.hasAttribute('for')) {\n current = document.getElementById(current.getAttribute('for') ?? '');\n }\n\n while (current) {\n const tagName = current.tagName.toLowerCase();\n if (\n current.hasAttribute('contenteditable') ||\n tagName === 'canvas' ||\n tagName === 'select' ||\n tagName === 'textarea'\n ) {\n return true;\n }\n if (tagName === 'a' && current.hasAttribute('href')) return true;\n if (tagName === 'input') {\n return !['button', 'checkbox', 'radio', 'range', 'reset', 'submit'].includes(\n current.getAttribute('type')?.toLowerCase() ?? 'text',\n );\n }\n current = getParentElement(current);\n }\n return false;\n};\n\nexport const createActionPlugin = (options: BkOTActionPluginOptions = {}): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n const activeActions = new Map<string, ActiveAction>();\n const pendingActions = new Set<ActiveAction>();\n const actionNameAttribute = options.actionNameAttribute || DEFAULT_ACTION_NAME_ATTRIBUTE;\n const maxDuration = positiveNumber(options.maxDuration, DEFAULT_ACTION_MAX_DURATION);\n let recentClicks: RecentClick[] = [];\n let runtimeContext: BkOTRuntimeContext | undefined;\n\n const updateRuntimeActionId = () => {\n runtimeContext?.setRuntimeAttributes({\n // 重叠窗口只暴露最近一次 Action,保证 action.id 始终是字符串。\n [RUM_ATTRIBUTES.actionId]: [...activeActions.keys()].at(-1),\n });\n };\n\n const isDeadAction = (action: ActiveAction) =>\n !action.hadActivity &&\n !action.userActivity.input &&\n !action.userActivity.scroll &&\n !action.userActivity.selection &&\n !isDeadClickExcluded(action.target);\n\n const reportAction = (action: ActiveAction) => {\n if (!pendingActions.delete(action) || !runtimeContext || !action.completed) return;\n clearTimeout(action.reportTimer);\n if (action.hadError) action.frustrations.add('error_click');\n if (isDeadAction(action)) action.frustrations.add('dead_click');\n const frustrationTypes = ['rage_click', 'dead_click', 'error_click'].filter(type =>\n action.frustrations.has(type as ActionFrustrationType),\n ) as ActionFrustrationType[];\n const { endTime, hasLoadingTime } = action.completed;\n const hasWarning = action.hadError || frustrationTypes.length > 0;\n const actionName = `click ${action.targetName}`;\n const attributes = {\n ...runtimeContext.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n outcome: hasWarning ? RUM_SPAN_OUTCOME.warning : RUM_SPAN_OUTCOME.success,\n spanType: RUM_SPAN_TYPE.action,\n }),\n ...action.runtimeAttributes,\n [RUM_ATTRIBUTES.actionId]: action.id,\n [RUM_ATTRIBUTES.actionName]: actionName,\n [RUM_ATTRIBUTES.actionType]: 'click',\n [RUM_ATTRIBUTES.actionTargetName]: action.targetName,\n [RUM_ATTRIBUTES.actionTargetTag]: action.targetTag,\n ...(frustrationTypes.length ? { [RUM_ATTRIBUTES.actionFrustrationType]: frustrationTypes } : {}),\n };\n const span = runtimeContext.startSpan(\n buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.action }),\n attributes,\n { rumSpanType: RUM_SPAN_TYPE.action, startTime: action.startTime },\n );\n span.end(hasLoadingTime ? endTime : action.startTime);\n };\n\n const finishAction = (action: ActiveAction, endTime: number, hasLoadingTime: boolean) => {\n if (!activeActions.delete(action.id) || !runtimeContext) return;\n clearTimeout(action.validationTimer);\n clearTimeout(action.quietTimer);\n clearTimeout(action.maxDurationTimer);\n updateRuntimeActionId();\n action.completed = { endTime, hasLoadingTime };\n pendingActions.add(action);\n // 等待连击窗口关闭后再落数,否则前两次点击已上报便无法合并为 rage click。\n const reportDelay = Math.max(0, action.startTime + CLICK_CHAIN_DURATION - Date.now());\n action.reportTimer = setTimeout(() => reportAction(action), reportDelay);\n };\n\n const flushPendingActions = () => {\n [...pendingActions].forEach(reportAction);\n };\n\n const scheduleActionEnd = (action: ActiveAction) => {\n clearTimeout(action.quietTimer);\n if (!action.hadActivity || action.pendingRequests.size) return;\n const delay = Math.max(0, action.lastActivityTime + ACTION_END_DELAY - Date.now());\n action.quietTimer = setTimeout(() => finishAction(action, action.lastActivityTime, true), delay);\n };\n\n const markActivity = (action: ActiveAction, time: number) => {\n action.hadActivity = true;\n action.lastActivityTime = Math.max(action.lastActivityTime, time);\n scheduleActionEnd(action);\n };\n\n const isInActionWindow = (action: ActiveAction, time: number) =>\n time >= action.startTime && time <= action.startTime + maxDuration;\n\n const onActivity = (event: BkOTActivityEvent) => {\n for (const action of activeActions.values()) {\n if (event.type === 'request_start') {\n if (event.url && matchesUrlList(runtimeContext?.config.view?.excludedActivityUrls, event.url)) continue;\n if (!isInActionWindow(action, event.time)) continue;\n action.pendingRequests.add(event.id);\n markActivity(action, event.time);\n continue;\n }\n if (event.type === 'request_end') {\n if (!action.pendingRequests.delete(event.id)) continue;\n markActivity(action, event.time);\n continue;\n }\n if (event.type === 'long_task' || event.type === 'resource') {\n if (\n event.type === 'resource' &&\n event.url &&\n matchesUrlList(runtimeContext?.config.view?.excludedActivityUrls, event.url)\n ) {\n continue;\n }\n if (\n event.startTime > action.startTime + maxDuration ||\n (event.type === 'resource' ? event.startTime < action.startTime : event.endTime < action.startTime)\n ) {\n continue;\n }\n markActivity(action, event.endTime);\n continue;\n }\n if (event.type === 'dom_mutation' || event.type === 'window_open') {\n if (isInActionWindow(action, event.time)) markActivity(action, event.time);\n continue;\n }\n if (event.type !== 'error') continue;\n if (!isInActionWindow(action, event.time)) continue;\n action.hadError = true;\n markActivity(action, event.time);\n }\n };\n\n const finishActiveActions = (endTime = Date.now()) => {\n [...activeActions.values()].forEach(action => finishAction(action, endTime, action.hadActivity));\n };\n\n const registerClick = (action: ActiveAction, event: Event) => {\n const x = 'clientX' in event && typeof event.clientX === 'number' ? event.clientX : 0;\n const y = 'clientY' in event && typeof event.clientY === 'number' ? event.clientY : 0;\n recentClicks = recentClicks.filter(click => action.startTime - click.action.startTime <= CLICK_CHAIN_DURATION);\n const lastClick = recentClicks.at(-1);\n const hasInterruptedChain = recentClicks.some(\n click => click.action.userActivity.scroll || click.action.userActivity.selection,\n );\n // 只有同一目标附近、未被滚动或选中文本打断的连续点击才视为同一连击链。\n const isSimilar =\n lastClick?.target === action.target && Math.hypot(lastClick.x - x, lastClick.y - y) <= CLICK_CHAIN_MAX_DISTANCE;\n if (hasInterruptedChain || (lastClick && !isSimilar)) recentClicks = [];\n recentClicks.push({ action, target: action.target, x, y });\n if (\n recentClicks.length >= 3 &&\n action.startTime - recentClicks[recentClicks.length - 3].action.startTime <= CLICK_CHAIN_DURATION\n ) {\n const rageSources = recentClicks.slice(-3).map(click => click.action);\n rageSources.forEach(source => source.frustrations.add('rage_click'));\n recentClicks = [];\n }\n };\n\n return {\n name: 'action',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n runtimeContext = context;\n\n const listenerOptions: AddEventListenerOptions = { capture: true, passive: true };\n\n const startAction = (event: Event) => {\n if (!context.isSampled()) return;\n if ('button' in event && typeof event.button === 'number' && event.button !== 0) return;\n const element = getElement(event);\n if (!element) return;\n const startTime = toEpochTime(event);\n const id = createRandomId('action');\n const action: ActiveAction = {\n frustrations: new Set(),\n hadActivity: false,\n hadError: false,\n id,\n lastActivityTime: startTime,\n maxDurationTimer: setTimeout(() => finishAction(action, startTime + maxDuration, true), maxDuration),\n pendingRequests: new Set(),\n runtimeAttributes: context.getRuntimeAttributes(),\n startTime,\n target: element,\n targetName: getActionNameFromElement(element, actionNameAttribute, options.nameCollection === 'text'),\n targetTag: element.tagName.toLowerCase(),\n userActivity: { input: false, scroll: false, selection: false },\n validationTimer: setTimeout(() => {\n if (!action.hadActivity) finishAction(action, action.startTime, false);\n }, ACTION_VALIDATION_DELAY),\n };\n activeActions.set(id, action);\n registerClick(action, event);\n updateRuntimeActionId();\n };\n\n window.addEventListener('click', startAction, listenerOptions);\n teardownCallbacks.push(() => window.removeEventListener('click', startAction, listenerOptions));\n\n const unsubscribeActivity = context.onActivity(onActivity);\n const unsubscribeSession = context.onSessionLifecycle(event => {\n if (event.type !== 'expired') return;\n finishActiveActions(event.expiredAt);\n flushPendingActions();\n });\n teardownCallbacks.push(unsubscribeActivity, unsubscribeSession);\n\n const finishOnHidden = () => {\n if (document.visibilityState === 'hidden') {\n finishActiveActions();\n flushPendingActions();\n }\n };\n const finishOnPageHide = () => {\n finishActiveActions();\n flushPendingActions();\n };\n window.addEventListener('pagehide', finishOnPageHide);\n document.addEventListener('visibilitychange', finishOnHidden);\n teardownCallbacks.push(\n () => window.removeEventListener('pagehide', finishOnPageHide),\n () => document.removeEventListener('visibilitychange', finishOnHidden),\n );\n\n const markUserActivity = (type: keyof ActiveAction['userActivity']) => {\n const actions = new Set([\n ...activeActions.values(),\n ...pendingActions,\n ...recentClicks.map(click => click.action),\n ]);\n actions.forEach(action => {\n action.userActivity[type] = true;\n // 滚动/选择表明用户仍在正常交互,撤销尚未上报的 rage click 判定。\n if (type !== 'input') action.frustrations.delete('rage_click');\n });\n };\n const onInput = () => markUserActivity('input');\n const onScroll = () => markUserActivity('scroll');\n const onSelectionChange = () => markUserActivity('selection');\n window.addEventListener('input', onInput, listenerOptions);\n window.addEventListener('scroll', onScroll, listenerOptions);\n document.addEventListener('selectionchange', onSelectionChange, listenerOptions);\n teardownCallbacks.push(\n () => window.removeEventListener('input', onInput, listenerOptions),\n () => window.removeEventListener('scroll', onScroll, listenerOptions),\n () => document.removeEventListener('selectionchange', onSelectionChange, listenerOptions),\n );\n },\n shutdown() {\n finishActiveActions();\n flushPendingActions();\n while (teardownCallbacks.length) {\n teardownCallbacks.pop()?.();\n }\n recentClicks = [];\n runtimeContext = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport type { BkOTPlugin } from '../core/plugin';\n\nexport const EXCLUDED_ACTIVITY_MUTATIONS_ATTRIBUTE = 'data-bk-excluded-activity-mutations';\n\nconst isExcludedMutation = (mutation: MutationRecord) => {\n const target = mutation.type === 'characterData' ? mutation.target.parentElement : mutation.target;\n return target instanceof Element && Boolean(target.closest(`[${EXCLUDED_ACTIVITY_MUTATIONS_ATTRIBUTE}]`));\n};\n\n/**\n * 页面级 DOM 活动只观察一次,再通过运行时活动总线分发给 View、Action 和白屏检测。\n */\nexport const createActivityPlugin = (): BkOTPlugin => {\n let mutationObserver: MutationObserver | undefined;\n const teardownCallbacks: Array<() => void> = [];\n\n return {\n name: 'activity',\n init(context) {\n if (typeof document !== 'undefined' && typeof MutationObserver !== 'undefined') {\n mutationObserver = new MutationObserver(mutations => {\n if (mutations.length && !mutations.every(isExcludedMutation)) {\n context.notifyActivity({ time: Date.now(), type: 'dom_mutation' });\n }\n });\n mutationObserver.observe(document, { attributes: true, characterData: true, childList: true, subtree: true });\n }\n\n if (typeof window === 'undefined') return;\n\n if (typeof window.open === 'function') {\n const originalOpen = window.open;\n const patchedOpen = ((...args: Parameters<typeof window.open>) => {\n context.notifyActivity({ time: Date.now(), type: 'window_open' });\n return Reflect.apply(originalOpen, window, args);\n }) as typeof window.open;\n window.open = patchedOpen;\n teardownCallbacks.push(() => {\n if (window.open === patchedOpen) window.open = originalOpen;\n });\n }\n\n },\n shutdown() {\n mutationObserver?.disconnect();\n mutationObserver = undefined;\n while (teardownCallbacks.length) teardownCallbacks.pop()?.();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { matchesUrlList } from './url';\n\nimport type { BkOTActivityEvent } from './action-activity';\nimport type { BkOTRuntimeContext } from './plugin';\n\nexport const PAGE_ACTIVITY_VALIDATION_DELAY = 100;\nexport const PAGE_ACTIVITY_END_DELAY = 100;\n\nexport type PageActivityEnd = { endTime: number; hadActivity: true } | { hadActivity: false };\n\nconst isActivityUrlExcluded = (context: BkOTRuntimeContext, url: string | undefined) =>\n Boolean(url && matchesUrlList(context.config.view.excludedActivityUrls, url));\n\n/**\n * 等待 View/Action 启动后的请求、静态资源和 DOM 变更全部安静 100ms。\n * 请求用 id 精确配对,避免并发请求提前结束等待。\n */\nexport const waitForPageActivityEnd = (\n context: BkOTRuntimeContext,\n startTime: number,\n callback: (result: PageActivityEnd) => void,\n) => {\n const pendingRequests = new Set<string>();\n let completed = false;\n let hadActivity = false;\n let lastActivityTime = startTime;\n let quietTimer: ReturnType<typeof setTimeout> | undefined;\n\n const complete = (result: PageActivityEnd) => {\n if (completed) return;\n completed = true;\n clearTimeout(validationTimer);\n clearTimeout(quietTimer);\n unsubscribe();\n callback(result);\n };\n\n const scheduleEnd = () => {\n clearTimeout(quietTimer);\n if (!hadActivity || pendingRequests.size) return;\n quietTimer = setTimeout(\n () => complete({ endTime: lastActivityTime, hadActivity: true }),\n Math.max(0, lastActivityTime + PAGE_ACTIVITY_END_DELAY - Date.now()),\n );\n };\n\n const markActivity = (time: number) => {\n hadActivity = true;\n lastActivityTime = Math.max(lastActivityTime, time);\n scheduleEnd();\n };\n\n const onActivity = (event: BkOTActivityEvent) => {\n if (event.type === 'error' || event.type === 'long_task') return;\n if (event.type === 'request_start') {\n if (event.time < startTime || isActivityUrlExcluded(context, event.url)) return;\n pendingRequests.add(event.id);\n markActivity(event.time);\n return;\n }\n if (event.type === 'request_end') {\n if (!pendingRequests.delete(event.id)) return;\n markActivity(event.time);\n return;\n }\n if (event.type === 'resource') {\n if (event.endTime < startTime || isActivityUrlExcluded(context, event.url)) return;\n markActivity(event.endTime);\n return;\n }\n if (event.time >= startTime) markActivity(event.time);\n };\n\n const unsubscribe = context.onActivity(onActivity);\n const validationTimer = setTimeout(() => {\n if (!hadActivity) complete({ hadActivity: false });\n }, PAGE_ACTIVITY_VALIDATION_DELAY);\n\n return () => {\n if (completed) return;\n completed = true;\n clearTimeout(validationTimer);\n clearTimeout(quietTimer);\n unsubscribe();\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { waitForPageActivityEnd } from '../core/page-activity';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\n\n/**\n * 通过视口九宫格采样估算空白比例,并在页面稳定后连续确认两次。每个 View 最多上报一次,\n * 避免首屏渲染、路由切换和 loading 状态造成瞬时误报。\n */\nexport interface BkOTBlankScreenPluginOptions {\n /** 页面活动稳定后首次检查的延迟,默认 1000ms。 */\n checkDelay?: number;\n /** 两次空白结果之间的确认间隔,默认 200ms。 */\n confirmationDelay?: number;\n /** loading、骨架屏等不参与空白比例计算的元素。 */\n ignoreSelectors?: string[];\n /** 应用挂载根节点,默认 body。根节点不存在时回退到 body 检测。 */\n rootSelector?: string;\n /** 空白采样点比例阈值,默认 0.8。 */\n threshold?: number;\n}\n\ninterface DetectionResult {\n emptyCount: number;\n ignoredCount: number;\n reason: 'empty_viewport' | 'missing_root';\n score: number;\n validCount: number;\n}\n\nconst DEFAULT_CHECK_DELAY = 1000;\nconst DEFAULT_CONFIRMATION_DELAY = 200;\nconst DEFAULT_ROOT_SELECTOR = 'body';\nconst DEFAULT_THRESHOLD = 0.8;\nconst DEFAULT_IGNORED_SELECTORS = [\n '[data-loading=\"true\"]',\n '[aria-busy=\"true\"]',\n '.loading',\n '.is-loading',\n '.spinner',\n '.skeleton',\n '.bk-loading',\n];\n\nconst SAMPLE_POINTS: ReadonlyArray<readonly [number, number]> = [\n [0.2, 0.2],\n [0.5, 0.2],\n [0.8, 0.2],\n [0.2, 0.5],\n [0.5, 0.5],\n [0.8, 0.5],\n [0.2, 0.8],\n [0.5, 0.8],\n [0.8, 0.8],\n];\n\nconst nonNegativeNumber = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;\n\nconst boundedRatio = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) ? Math.max(0, Math.min(1, value)) : fallback;\n\nconst matchesAny = (element: Element, selectors: string[]) =>\n selectors.some(selector => {\n try {\n return element.matches(selector) || Boolean(element.closest(selector));\n } catch {\n return false;\n }\n });\n\nconst isVisuallyPresent = (element: Element) => {\n if (typeof getComputedStyle !== 'function') return true;\n const style = getComputedStyle(element);\n return style.display !== 'none' && style.visibility !== 'hidden' && Number(style.opacity || 1) > 0;\n};\n\nconst getElementsAtPoint = (x: number, y: number): Element[] => {\n if (typeof document.elementsFromPoint === 'function') return document.elementsFromPoint(x, y);\n const element = document.elementFromPoint(x, y);\n return element ? [element] : [];\n};\n\nexport const detectBlankScreen = (rootSelector: string, ignoredSelectors: string[]): DetectionResult => {\n const configuredRoot = document.querySelector(rootSelector);\n const root = configuredRoot ?? document.body ?? document.documentElement;\n\n let emptyCount = 0;\n let ignoredCount = 0;\n // 采样视口九宫格而非遍历 DOM,检测成本固定;被 loading/骨架屏覆盖的点不进入分母。\n for (const [xRatio, yRatio] of SAMPLE_POINTS) {\n const layers = getElementsAtPoint(window.innerWidth * xRatio, window.innerHeight * yRatio);\n if (layers.some(element => matchesAny(element, ignoredSelectors))) {\n ignoredCount += 1;\n continue;\n }\n const hasContent = layers.some(\n element =>\n element !== root &&\n element !== document.body &&\n element !== document.documentElement &&\n root.contains(element) &&\n isVisuallyPresent(element),\n );\n if (!hasContent) emptyCount += 1;\n }\n\n const validCount = SAMPLE_POINTS.length - ignoredCount;\n return {\n emptyCount,\n ignoredCount,\n reason: configuredRoot ? 'empty_viewport' : 'missing_root',\n score: validCount ? emptyCount / validCount : 0,\n validCount,\n };\n};\n\nexport const createBlankScreenPlugin = (options: BkOTBlankScreenPluginOptions = {}): BkOTPlugin => {\n const checkDelay = nonNegativeNumber(options.checkDelay, DEFAULT_CHECK_DELAY);\n const confirmationDelay = nonNegativeNumber(options.confirmationDelay, DEFAULT_CONFIRMATION_DELAY);\n const rootSelector = options.rootSelector || DEFAULT_ROOT_SELECTOR;\n const threshold = boundedRatio(options.threshold, DEFAULT_THRESHOLD);\n const ignoredSelectors = [...DEFAULT_IGNORED_SELECTORS, ...(options.ignoreSelectors ?? [])];\n let activeViewId: string | undefined;\n let reportedViewId: string | undefined;\n let stopActivityTracking: (() => void) | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let unsubscribeView = () => {};\n let visibilityListener: (() => void) | undefined;\n\n return {\n name: 'blank-screen',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n const clearTimer = () => {\n clearTimeout(timer);\n timer = undefined;\n };\n\n const report = (viewId: string, result: DetectionResult) => {\n if (activeViewId !== viewId || reportedViewId === viewId) return;\n if (!context.isSampled()) return;\n reportedViewId = viewId;\n const occurredAt = Date.now();\n const attributes = {\n ...buildRumSpanAttributes({\n outcome: RUM_SPAN_OUTCOME.error,\n spanType: RUM_SPAN_TYPE.error,\n }),\n 'blank_screen.empty_ratio': result.score,\n 'blank_screen.empty_sample_count': result.emptyCount,\n 'blank_screen.reason': result.reason,\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.error }), attributes, {\n startTime: occurredAt,\n });\n span.end(occurredAt);\n };\n\n const detectAndConfirm = (viewId: string) => {\n if (activeViewId !== viewId || reportedViewId === viewId) return;\n if (document.visibilityState === 'hidden') return;\n let first: DetectionResult;\n try {\n first = detectBlankScreen(rootSelector, ignoredSelectors);\n } catch (error) {\n if (context.config.debug) globalThis.console?.warn('[bk-ot][blank-screen] detection failed:', error);\n return;\n }\n if (!first.validCount || first.score < threshold) return;\n timer = setTimeout(() => {\n if (activeViewId !== viewId || document.visibilityState === 'hidden') return;\n let confirmed: DetectionResult;\n try {\n confirmed = detectBlankScreen(rootSelector, ignoredSelectors);\n } catch (error) {\n if (context.config.debug) globalThis.console?.warn('[bk-ot][blank-screen] confirmation failed:', error);\n return;\n }\n if (confirmed.validCount && confirmed.score >= threshold) report(viewId, confirmed);\n }, confirmationDelay);\n };\n\n const schedule = (viewId: string) => {\n clearTimer();\n if (document.visibilityState === 'hidden' || !context.isSampled()) return;\n timer = setTimeout(() => detectAndConfirm(viewId), checkDelay);\n };\n\n unsubscribeView = context.onViewChange(view => {\n if (view.id === activeViewId) return;\n clearTimer();\n stopActivityTracking?.();\n stopActivityTracking = undefined;\n activeViewId = view.id;\n reportedViewId = undefined;\n if (view.id) {\n const viewId = view.id;\n // 页面活动结束后再延迟检测,避免把正常渲染过程中的短暂空白误报为白屏。\n stopActivityTracking = waitForPageActivityEnd(context, Date.now(), () => {\n stopActivityTracking = undefined;\n schedule(viewId);\n });\n }\n });\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') {\n clearTimer();\n } else if (activeViewId && reportedViewId !== activeViewId) {\n schedule(activeViewId);\n }\n };\n document.addEventListener('visibilitychange', onVisibilityChange);\n visibilityListener = () => document.removeEventListener('visibilitychange', onVisibilityChange);\n },\n shutdown() {\n clearTimeout(timer);\n timer = undefined;\n unsubscribeView();\n stopActivityTracking?.();\n stopActivityTracking = undefined;\n visibilityListener?.();\n visibilityListener = undefined;\n activeViewId = undefined;\n reportedViewId = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\ninterface PendingRequestTiming {\n entry?: PerformanceResourceTiming;\n startTime: number;\n timer?: ReturnType<typeof setTimeout>;\n url: string;\n callback?: (entry?: PerformanceResourceTiming) => void;\n}\n\nconst MAX_PENDING_REQUESTS = 100;\nconst RESOURCE_TIMING_WAIT_MS = 200;\nconst pendingRequests: PendingRequestTiming[] = [];\n\nconst normalizeUrl = (url: string) => url.replace(/#.*$/, '');\n\nconst removePending = (pending: PendingRequestTiming) => {\n const index = pendingRequests.indexOf(pending);\n if (index >= 0) pendingRequests.splice(index, 1);\n if (pending.timer !== undefined) clearTimeout(pending.timer);\n};\n\nconst finishPending = (pending: PendingRequestTiming, entry?: PerformanceResourceTiming) => {\n const callback = pending.callback;\n removePending(pending);\n pending.callback = undefined;\n callback?.(entry);\n};\n\nexport const notifyRequestTiming = (entry: PerformanceResourceTiming) => {\n const entryStartTime = performance.timeOrigin + entry.startTime;\n // 同 URL 并发时选择起始时间最接近的请求;50ms 容差覆盖 JS 调用与浏览器创建 timing entry 的偏差。\n const candidate = pendingRequests\n .filter(\n pending =>\n !pending.entry &&\n normalizeUrl(pending.url) === normalizeUrl(entry.name) &&\n entryStartTime >= pending.startTime - 50,\n )\n .sort((left, right) => Math.abs(left.startTime - entryStartTime) - Math.abs(right.startTime - entryStartTime))[0];\n if (!candidate) return;\n candidate.entry = entry;\n if (candidate.callback) finishPending(candidate, entry);\n};\n\nexport const trackRequestTiming = (url: string, startTime = Date.now()) => {\n const pending: PendingRequestTiming = { startTime, url };\n pendingRequests.push(pending);\n if (pendingRequests.length > MAX_PENDING_REQUESTS) finishPending(pendingRequests[0]);\n return {\n cancel: () => finishPending(pending),\n complete: (callback: (entry?: PerformanceResourceTiming) => void) => {\n pending.callback = callback;\n if (pending.entry) {\n finishPending(pending, pending.entry);\n return;\n }\n // XHR 终止事件/Fetch settle 通常早于 ResourceTiming 回调,短暂等待以补齐 DNS、连接和下载阶段。\n pending.timer = setTimeout(() => finishPending(pending), RESOURCE_TIMING_WAIT_MS);\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/**\n * 被观测请求的 Trace Context 规划。\n *\n * 后端 APM 只解析 W3C `traceparent`,并且要求一个后端 trace 只对应一个 API 请求,因此这里不复用\n * RUM Span 自身的 trace context,而是为每个命中白名单的请求生成独立的 trace-id/span-id,再通过\n * Span Link 把后端 trace 关联回 RUM Span。\n *\n * 如果业务已经自行设置了 trace header(`traceparent`、`sentry-trace`、b3、Datadog、sw8),则完全\n * 不注入,避免破坏业务既有的传播方式,只把已有链路建成 Link。\n *\n * Link 结构恒定:`context` 承载 trace-id/span-id,`attributes` 记录命中的格式与原始 header。\n * sw8 这类无法映射为合法 OTel id 的格式会补一对占位 id,让 Link 结构保持统一。\n */\n\nimport { TraceFlags } from '@opentelemetry/api';\n\nimport type { Attributes, Link } from '@opentelemetry/api';\n\n/** 大小写不敏感地读取一个请求 header */\nexport type BkOTHeaderReader = (name: string) => string | undefined;\n\nexport interface BkOTRequestTracePlan {\n /** 关联后端 trace 的 Span Link,恒为一条 */\n links: Link[];\n /** 需要注入的 traceparent;业务已有 trace header 时为 undefined */\n traceparent?: string;\n}\n\nexport type BkOTUpstreamTraceFormat = 'b3' | 'b3-multi' | 'datadog' | 'sentry-trace' | 'sw8' | 'traceparent';\n\nexport const TRACEPARENT_HEADER = 'traceparent';\n\nconst TRACE_ID_LENGTH = 32;\nconst SPAN_ID_LENGTH = 16;\n\nconst HEX_DIGITS = '0123456789abcdef';\nconst HEX_PATTERN = /^[\\da-f]+$/;\nconst ZERO_PATTERN = /^0+$/;\nconst DECIMAL_PATTERN = /^\\d+$/;\n\n// 00-{trace-id}-{parent-id}-{trace-flags};允许未来版本追加字段,但 ff 是规范保留值\nconst TRACEPARENT_PATTERN = /^([\\da-f]{2})-([\\da-f]{32})-([\\da-f]{16})-([\\da-f]{2})(?:-.*)?$/;\nconst SENTRY_TRACE_PATTERN = /^([\\da-f]{32})-([\\da-f]{16})(?:-([01]))?$/;\n// Datadog 128 位 trace-id 的高 64 位放在 x-datadog-tags 的 _dd.p.tid 里\nconst DATADOG_TRACE_ID_HIGH_PATTERN = /(?:^|,)_dd\\.p\\.tid=([\\da-f]{16})(?:,|$)/;\nconst DATADOG_TRACE_ID_HIGH_DEFAULT = '0000000000000000';\n\n/** OTel 要求 id 为定长小写 hex 且不能全零 */\nconst isValidHexId = (value: string, length: number) =>\n value.length === length && HEX_PATTERN.test(value) && !ZERO_PATTERN.test(value);\n\n// b3 与 Datadog 允许 64 位 trace-id,映射到 OTel 的 128 位时按规范左侧补零\nconst normalizeTraceId = (value: string) => {\n const lower = value.toLowerCase();\n if (isValidHexId(lower, TRACE_ID_LENGTH)) return lower;\n return isValidHexId(lower, SPAN_ID_LENGTH) ? lower.padStart(TRACE_ID_LENGTH, '0') : undefined;\n};\n\nconst normalizeSpanId = (value: string) => {\n const lower = value.toLowerCase();\n return isValidHexId(lower, SPAN_ID_LENGTH) ? lower : undefined;\n};\n\nconst createRandomHexId = (length: number) => {\n const bytes = new Uint8Array(length / 2);\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(bytes);\n } else {\n for (let index = 0; index < bytes.length; index += 1) bytes[index] = Math.floor(Math.random() * 256);\n }\n let hex = '';\n for (const byte of bytes) {\n hex += HEX_DIGITS[byte >> 4] + HEX_DIGITS[byte & 15];\n }\n // 全零是 OTel 的非法 id,概率极低但必须排除\n return ZERO_PATTERN.test(hex) ? `${hex.slice(1)}1` : hex;\n};\n\n/**\n * Datadog 用十进制字符串传 64 位 id。构建目标是 es2015,不能依赖 BigInt,\n * 这里用逐位进位的方式把十进制换算成 16 位 hex。\n */\nconst decimalToHexId = (value: string) => {\n if (!DECIMAL_PATTERN.test(value)) return undefined;\n const nibbles: number[] = [];\n for (let index = 0; index < value.length; index += 1) {\n let carry = value.charCodeAt(index) - 48;\n for (let position = 0; position < nibbles.length; position += 1) {\n const product = nibbles[position] * 10 + carry;\n nibbles[position] = product % 16;\n carry = (product - (product % 16)) / 16;\n }\n while (carry > 0) {\n nibbles.push(carry % 16);\n carry = (carry - (carry % 16)) / 16;\n }\n }\n if (nibbles.length > SPAN_ID_LENGTH) return undefined;\n let hex = '';\n for (let position = nibbles.length - 1; position >= 0; position -= 1) hex += HEX_DIGITS[nibbles[position]];\n return hex.padStart(SPAN_ID_LENGTH, '0');\n};\n\ninterface UpstreamTrace {\n format: BkOTUpstreamTraceFormat;\n /** 命中格式的原始 header,原样写入 Link Attributes */\n headers: Attributes;\n sampled?: boolean;\n /** 规范化后的合法 OTel id;无法映射时两者同时缺失 */\n spanId?: string;\n traceId?: string;\n}\n\n/** 按 header 原名收集实际存在的取值,缺失的不写入 */\nconst collectHeaders = (getHeader: BkOTHeaderReader, names: string[]) => {\n const headers: Attributes = {};\n for (const name of names) {\n const value = getHeader(name)?.trim();\n if (value) headers[name] = value;\n }\n return headers;\n};\n\n/**\n * `traceparent` 与 SDK 注入的是同一个 header,因此格式非法时视作没有既有链路:\n * 这种值后端同样无法接续,覆盖注入比保留它更有价值。\n */\nconst parseTraceparent = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader(TRACEPARENT_HEADER)?.trim().toLowerCase();\n if (!value) return undefined;\n const matched = TRACEPARENT_PATTERN.exec(value);\n if (!matched || matched[1] === 'ff') return undefined;\n const [, , traceId, spanId, flags] = matched;\n if (!isValidHexId(traceId, TRACE_ID_LENGTH) || !isValidHexId(spanId, SPAN_ID_LENGTH)) return undefined;\n return {\n format: 'traceparent',\n headers: collectHeaders(getHeader, [TRACEPARENT_HEADER]),\n sampled: (Number.parseInt(flags, 16) & 1) === 1,\n spanId,\n traceId,\n };\n};\n\nconst parseSentryTrace = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader('sentry-trace')?.trim().toLowerCase();\n if (!value) return undefined;\n const headers = collectHeaders(getHeader, ['sentry-trace']);\n const matched = SENTRY_TRACE_PATTERN.exec(value);\n if (!matched) return { format: 'sentry-trace', headers };\n const [, traceId, spanId, sampled] = matched;\n return {\n format: 'sentry-trace',\n headers,\n ...(sampled === undefined ? {} : { sampled: sampled === '1' }),\n ...(isValidHexId(traceId, TRACE_ID_LENGTH) && isValidHexId(spanId, SPAN_ID_LENGTH) ? { spanId, traceId } : {}),\n };\n};\n\n// b3 单头:{trace-id}-{span-id}[-{sampling-state}[-{parent-span-id}]],也允许只有 0 / 1 / d\nconst parseB3Single = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader('b3')?.trim().toLowerCase();\n if (!value) return undefined;\n const [rawTraceId, rawSpanId, samplingState] = value.split('-');\n const traceId = rawTraceId ? normalizeTraceId(rawTraceId) : undefined;\n const spanId = rawSpanId ? normalizeSpanId(rawSpanId) : undefined;\n return {\n format: 'b3',\n headers: collectHeaders(getHeader, ['b3']),\n ...(traceId && spanId ? { spanId, traceId } : {}),\n ...(samplingState ? { sampled: samplingState === '1' || samplingState === 'd' } : {}),\n };\n};\n\nconst parseB3Multi = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const rawTraceId = getHeader('x-b3-traceid')?.trim().toLowerCase();\n const rawSpanId = getHeader('x-b3-spanid')?.trim().toLowerCase();\n const samplingState = getHeader('x-b3-sampled')?.trim().toLowerCase();\n if (!rawTraceId && !rawSpanId && !samplingState) return undefined;\n const traceId = rawTraceId ? normalizeTraceId(rawTraceId) : undefined;\n const spanId = rawSpanId ? normalizeSpanId(rawSpanId) : undefined;\n return {\n format: 'b3-multi',\n headers: collectHeaders(getHeader, [\n 'x-b3-traceid',\n 'x-b3-spanid',\n 'x-b3-parentspanid',\n 'x-b3-sampled',\n 'x-b3-flags',\n ]),\n ...(traceId && spanId ? { spanId, traceId } : {}),\n ...(samplingState ? { sampled: samplingState === '1' || samplingState === 'd' } : {}),\n };\n};\n\nconst parseDatadog = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const rawTraceId = getHeader('x-datadog-trace-id')?.trim();\n const rawSpanId = getHeader('x-datadog-parent-id')?.trim();\n const samplingPriority = getHeader('x-datadog-sampling-priority')?.trim();\n if (!rawTraceId && !rawSpanId && !samplingPriority) return undefined;\n const tags = getHeader('x-datadog-tags')?.trim().toLowerCase();\n const traceIdHigh =\n (tags ? DATADOG_TRACE_ID_HIGH_PATTERN.exec(tags)?.[1] : undefined) ?? DATADOG_TRACE_ID_HIGH_DEFAULT;\n const traceIdLow = rawTraceId ? decimalToHexId(rawTraceId) : undefined;\n const traceId = traceIdLow ? normalizeTraceId(`${traceIdHigh}${traceIdLow}`) : undefined;\n const spanIdHex = rawSpanId ? decimalToHexId(rawSpanId) : undefined;\n const spanId = spanIdHex ? normalizeSpanId(spanIdHex) : undefined;\n return {\n format: 'datadog',\n headers: collectHeaders(getHeader, [\n 'x-datadog-trace-id',\n 'x-datadog-parent-id',\n 'x-datadog-sampling-priority',\n 'x-datadog-origin',\n 'x-datadog-tags',\n ]),\n ...(traceId && spanId ? { spanId, traceId } : {}),\n ...(samplingPriority ? { sampled: Number(samplingPriority) > 0 } : {}),\n };\n};\n\n/**\n * sw8:{sample}-{trace-id}-{segment-id}-{span-id}-{service}-{instance}-{endpoint}-{peer},\n * 其中 trace-id 与 segment-id 是 base64 后的 SkyWalking id。它们不是 16 字节 hex,无法映射为\n * 合法的 OTel SpanContext,因此不产出 traceId/spanId,由调用方补占位 id。\n */\nconst parseSw8 = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader('sw8')?.trim();\n if (!value) return undefined;\n const samplingState = value.split('-')[0];\n return {\n format: 'sw8',\n headers: collectHeaders(getHeader, ['sw8']),\n ...(samplingState ? { sampled: samplingState === '1' } : {}),\n };\n};\n\n// 按格式明确度排序:先看与 SDK 同名的 traceparent,再看其他厂商格式\nconst UPSTREAM_PARSERS = [parseTraceparent, parseSentryTrace, parseB3Single, parseB3Multi, parseDatadog, parseSw8];\n\nexport const detectUpstreamTrace = (getHeader: BkOTHeaderReader) => {\n for (const parse of UPSTREAM_PARSERS) {\n const upstream = parse(getHeader);\n if (upstream) return upstream;\n }\n return undefined;\n};\n\nconst toLink = (traceId: string, spanId: string, attributes: Attributes, sampled?: boolean): Link => ({\n attributes,\n context: {\n spanId,\n traceFlags: sampled === false ? TraceFlags.NONE : TraceFlags.SAMPLED,\n traceId,\n },\n});\n\nexport const planRequestTrace = (getHeader: BkOTHeaderReader): BkOTRequestTracePlan => {\n const upstream = detectUpstreamTrace(getHeader);\n if (!upstream) {\n // 与 RUM Span 无关的独立 trace,保证后端按 trace-id 检索时只命中这一个 API 请求\n const traceId = createRandomHexId(TRACE_ID_LENGTH);\n const spanId = createRandomHexId(SPAN_ID_LENGTH);\n const traceparent = `00-${traceId}-${spanId}-01`;\n return {\n links: [toLink(traceId, spanId, { format: 'traceparent', injected: true, [TRACEPARENT_HEADER]: traceparent })],\n traceparent,\n };\n }\n // sw8 等格式解析不出合法 OTel id,补占位 id 让 Link 结构统一;此时不注入,后端不会有对应 trace\n return {\n links: [\n toLink(\n upstream.traceId ?? createRandomHexId(TRACE_ID_LENGTH),\n upstream.spanId ?? createRandomHexId(SPAN_ID_LENGTH),\n // injected 恒定写出:业务自带的合法 traceparent 与 SDK 注入的 format 同值,只靠 format 无法区分\n { format: upstream.format, injected: false, ...upstream.headers },\n upstream.sampled,\n ),\n ],\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SpanKind } from '@opentelemetry/api';\n\nimport { notifyRequestTiming } from '../core/request-timing';\nimport { shouldIgnoreUrl } from '../core/url';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumResourceSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\n\n/**\n * Resource Timing 的统一消费端:静态资源按配置生成 span;Fetch/XHR timing 转交 request 插件,\n * 与其已创建的请求 span 合并,避免同一次网络请求重复计数。\n */\ntype ResourceTimingWithStatus = PerformanceResourceTiming & {\n deliveryType?: string;\n renderBlockingStatus?: string;\n responseStatus?: number;\n};\n\nconst getCacheHit = (entry: ResourceTimingWithStatus) =>\n entry.deliveryType === 'cache' || (entry.transferSize === 0 && entry.decodedBodySize > 0) ? true : undefined;\n\nconst hasUnavailableResourceDetails = (entry: ResourceTimingWithStatus) =>\n entry.transferSize === 0 &&\n entry.encodedBodySize === 0 &&\n entry.decodedBodySize === 0 &&\n entry.requestStart === 0 &&\n entry.responseStart === 0 &&\n !entry.nextHopProtocol;\n\nconst areInOrder = (...values: number[]) => values.every((value, index) => index === 0 || values[index - 1] <= value);\n\nconst setTiming = (attributes: Record<string, number>, name: string, origin: number, start: number, end: number) => {\n if (!areInOrder(origin, start, end)) return;\n attributes[`resource.${name}.start`] = start - origin;\n attributes[`resource.${name}.duration`] = end - start;\n};\n\nexport const getResourceTimingAttributes = (entry: ResourceTimingWithStatus) => {\n const attributes: Record<string, number> = {};\n const commonTimings = [\n entry.startTime,\n entry.fetchStart,\n entry.domainLookupStart,\n entry.domainLookupEnd,\n entry.connectStart,\n entry.connectEnd,\n entry.requestStart,\n entry.responseStart,\n entry.responseEnd,\n ];\n // 浏览器因 TAO 或实现差异可能返回缺失/乱序时间点;整组校验可避免产生负 duration。\n if (!commonTimings.every(Number.isFinite) || !areInOrder(...commonTimings)) return attributes;\n\n setTiming(attributes, 'first_byte', entry.startTime, entry.requestStart, entry.responseStart);\n setTiming(attributes, 'download', entry.startTime, entry.responseStart, entry.responseEnd);\n if (entry.workerStart > 0 && entry.workerStart < entry.fetchStart) {\n setTiming(attributes, 'worker', entry.startTime, entry.workerStart, entry.fetchStart);\n }\n if (entry.fetchStart < entry.domainLookupEnd) {\n setTiming(attributes, 'dns', entry.startTime, entry.domainLookupStart, entry.domainLookupEnd);\n }\n if (entry.fetchStart < entry.connectEnd) {\n setTiming(attributes, 'connect', entry.startTime, entry.connectStart, entry.connectEnd);\n if (entry.connectStart <= entry.secureConnectionStart && entry.secureConnectionStart <= entry.connectEnd) {\n setTiming(attributes, 'ssl', entry.startTime, entry.secureConnectionStart, entry.connectEnd);\n }\n }\n if (\n entry.redirectEnd > entry.startTime &&\n areInOrder(entry.startTime, entry.redirectStart, entry.redirectEnd, entry.fetchStart)\n ) {\n setTiming(attributes, 'redirect', entry.startTime, entry.redirectStart, entry.redirectEnd);\n }\n return attributes;\n};\n\nexport const getResourceDuration = (entry: ResourceTimingWithStatus) =>\n entry.duration === 0 && entry.responseEnd > entry.startTime ? entry.responseEnd - entry.startTime : entry.duration;\n\nexport const getResourcePerformanceAttributes = (entry: ResourceTimingWithStatus) => {\n const detailsUnavailable = hasUnavailableResourceDetails(entry);\n const deliveryType = typeof entry.deliveryType === 'string' && entry.deliveryType ? entry.deliveryType : undefined;\n return {\n [RUM_ATTRIBUTES.cacheHit]: getCacheHit(entry),\n ...(entry.nextHopProtocol ? { [RUM_ATTRIBUTES.nextHopProtocol]: entry.nextHopProtocol } : {}),\n ...getResourceTimingAttributes(entry),\n ...(deliveryType ? { 'resource.delivery_type': deliveryType } : {}),\n ...(entry.renderBlockingStatus ? { 'resource.render_blocking_status': entry.renderBlockingStatus } : {}),\n ...(detailsUnavailable\n ? {}\n : {\n // 对齐 Datadog:resource.size 取解压后 body 体积,缓存命中也能反映真实大小;\n // 网络传输量单独用 resource.transfer_size 表达(受缓存/TAO 影响可能为 0)。\n 'resource.size': entry.decodedBodySize,\n 'resource.encoded_body_size': entry.encodedBodySize,\n 'resource.decoded_body_size': entry.decodedBodySize,\n 'resource.transfer_size': entry.transferSize,\n }),\n };\n};\n\nexport const createResourcePlugin = (emitResourceSpans = true): BkOTPlugin => {\n let observer: PerformanceObserver | undefined;\n\n return {\n name: 'resource',\n init(context) {\n if (typeof PerformanceObserver === 'undefined') {\n return;\n }\n if (!PerformanceObserver.supportedEntryTypes?.includes('resource')) {\n return;\n }\n\n const emitEntry = (entry: ResourceTimingWithStatus) => {\n if (!context.isSampled()) return;\n if (!entry.name || shouldIgnoreUrl(context.config, entry.name)) {\n return;\n }\n if (entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest') {\n // Fetch/XHR 已由 request 插件建 span;这里只把 ResourceTiming 回传补齐网络阶段,避免重复上报。\n notifyRequestTiming(entry);\n return;\n }\n if (entry.duration < 0) return;\n const redactedUrl = context.config.hooks.redactUrl(entry.name);\n const duration = getResourceDuration(entry);\n const startTime = performance.timeOrigin + entry.startTime;\n const endTime = startTime + duration;\n if (emitResourceSpans && context.isSampled()) {\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumResourceSpanAttributes({\n initiatorType: entry.initiatorType || 'other',\n method: 'GET',\n outcome:\n typeof entry.responseStatus === 'number'\n ? { statusCode: entry.responseStatus, type: 'response' as const }\n : undefined,\n url: redactedUrl,\n }),\n 'url.full': redactedUrl,\n 'url.template': context.config.hooks.getRequestUrlTemplate(redactedUrl),\n ...getResourcePerformanceAttributes(entry),\n };\n const span = context.startSpan(\n buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.resource }),\n attributes,\n { kind: SpanKind.CLIENT, rumSpanType: RUM_SPAN_TYPE.resource, startTime },\n );\n span.end(endTime);\n }\n context.notifyActivity({ endTime, startTime, type: 'resource', url: entry.name });\n };\n\n try {\n observer = new PerformanceObserver(list => {\n for (const entry of list.getEntries() as ResourceTimingWithStatus[]) {\n emitEntry(entry);\n }\n });\n observer.observe({ type: 'resource', buffered: true });\n } catch {\n observer = undefined;\n }\n },\n shutdown() {\n observer?.disconnect();\n observer = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\n/**\n * Fetch/XHR 请求统一采集入口。\n *\n * 同一层 patch 负责请求 span、Trace Header、页面活动与 beforeSend,避免多套 patch\n * 重复计数,也不依赖 OpenTelemetry instrumentation 的私有方法。\n */\n\nimport { SpanKind, SpanStatusCode } from '@opentelemetry/api';\n\nimport { createRandomId } from '../core/id';\nimport { markSpanDiscarded } from '../core/processor';\nimport { trackRequestTiming } from '../core/request-timing';\nimport { planRequestTrace, TRACEPARENT_HEADER } from '../core/trace-context';\nimport {\n matchesUrlList,\n shouldIgnoreRequest,\n shouldIgnoreUrl,\n shouldPropagateTraceHeader,\n toAbsoluteUrl,\n} from '../core/url';\nimport { buildRumResourceSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\nimport { getResourceDuration, getResourcePerformanceAttributes } from './resource';\n\nimport type { BkOTRequestConfig, BkOTRequestContext, BkOTRequestOutcome } from '../core/config';\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { BkOTHeaderReader, BkOTRequestTracePlan } from '../core/trace-context';\nimport type { Attributes, Span } from '@opentelemetry/api';\n\ninterface RequestDetails {\n method?: string;\n startedAt?: number;\n url?: string;\n}\n\nconst getRequestOptions = (context: BkOTRuntimeContext) =>\n typeof context.config.tracking.request === 'object' ? context.config.tracking.request : undefined;\n\n// 没有白名单时不会注入任何 header,也就不需要为探测既有 trace header 付出 patch 成本。\nconst hasTracingAllowlist = (context: BkOTRuntimeContext) => {\n const allowed = getRequestOptions(context)?.allowedTracingUrls;\n return Array.isArray(allowed) ? allowed.length > 0 : allowed !== undefined;\n};\n\nconst getErrorName = (error: unknown) =>\n typeof error === 'object' && error && 'name' in error && typeof error.name === 'string' ? error.name : '';\n\nconst getFetchFailureOutcome = (requestContext: Request | RequestInit, error: unknown): BkOTRequestOutcome => {\n const signal = requestContext.signal;\n if (getErrorName(signal?.reason) === 'TimeoutError' || getErrorName(error) === 'TimeoutError') {\n return { error, type: 'timeout' };\n }\n if (signal?.aborted || getErrorName(error) === 'AbortError') return { type: 'abort' };\n return { error, type: 'network_error' };\n};\n\nconst getXhrOutcome = (\n completionType: 'abort' | 'error' | 'load' | 'timeout',\n xhr: XMLHttpRequest,\n): BkOTRequestOutcome => {\n if (completionType === 'abort') return { type: 'abort' };\n if (completionType === 'timeout') return { type: 'timeout' };\n if (completionType === 'error' || xhr.status === 0) return { type: 'network_error' };\n return { statusCode: xhr.status, type: 'response' };\n};\n\nconst isErrorOutcome = (outcome: BkOTRequestOutcome) =>\n outcome.type === 'network_error' ||\n outcome.type === 'timeout' ||\n (outcome.type === 'response' && typeof outcome.statusCode === 'number' && outcome.statusCode >= 400);\n\nconst getFetchUrl = (input: RequestInfo | URL) => {\n if (typeof input === 'string' || input instanceof URL) return toAbsoluteUrl(String(input));\n return toAbsoluteUrl(input.url);\n};\n\nconst getFetchMethod = (input: RequestInfo | URL, init?: RequestInit) =>\n (init?.method ?? (typeof Request !== 'undefined' && input instanceof Request ? input.method : 'GET')).toUpperCase();\n\nconst getFetchRequestContext = (input: RequestInfo | URL, init?: RequestInit): Request | RequestInit =>\n typeof Request !== 'undefined' && input instanceof Request ? input : (init ?? {});\n\n/** 取本次请求最终会发出的 header 集合:init.headers 一旦存在就会整体覆盖 Request 上的 header。 */\nconst getFetchRequestHeaders = (input: RequestInfo | URL, init: RequestInit | undefined) => {\n const requestHeaders = typeof Request !== 'undefined' && input instanceof Request ? input.headers : undefined;\n return new Headers(init?.headers ?? requestHeaders);\n};\n\nconst applyFetchTracePlan = (init: RequestInit | undefined, headers: Headers, plan: BkOTRequestTracePlan) => {\n if (!plan.traceparent) return init;\n headers.set(TRACEPARENT_HEADER, plan.traceparent);\n return { ...init, headers };\n};\n\nconst createHeaderReader =\n (headers: Record<string, string> | undefined): BkOTHeaderReader =>\n name =>\n headers?.[name.toLowerCase()];\n\nconst isActivityExcluded = (context: BkOTRuntimeContext, url: string) =>\n shouldIgnoreUrl(context.config, url) || matchesUrlList(context.config.view.excludedActivityUrls, url);\n\nconst startRequestActivity = (context: BkOTRuntimeContext, url: string) => {\n if (isActivityExcluded(context, url)) return () => {};\n const id = createRandomId('request');\n context.notifyActivity({ id, time: Date.now(), type: 'request_start', url });\n let ended = false;\n return () => {\n if (ended) return;\n ended = true;\n context.notifyActivity({ id, time: Date.now(), type: 'request_end' });\n };\n};\n\nconst trackRequestSpanTiming = (context: BkOTRuntimeContext, url: string) =>\n !context.isSampled()\n ? {\n cancel() {},\n complete(callback: (entry?: PerformanceResourceTiming) => void) {\n callback();\n },\n }\n : trackRequestTiming(url);\n\nconst startRequestSpan = (\n context: BkOTRuntimeContext,\n subtype: 'fetch' | 'xhr',\n details: RequestDetails,\n tracePlan?: BkOTRequestTracePlan,\n) => {\n const startedAt = details.startedAt ?? Date.now();\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumResourceSpanAttributes({\n initiatorType: subtype,\n method: details.method,\n url: details.url ?? '',\n }),\n ...(details.url\n ? {\n 'url.full': context.config.hooks.redactUrl(details.url),\n 'url.template': context.config.hooks.getRequestUrlTemplate(details.url),\n }\n : {}),\n };\n return context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.resource }), attributes, {\n kind: SpanKind.CLIENT,\n rumSpanType: RUM_SPAN_TYPE.resource,\n startTime: startedAt,\n ...(tracePlan ? { links: tracePlan.links } : {}),\n });\n};\n\nexport const decorateRequestSpan = (\n context: BkOTRuntimeContext,\n span: Span,\n subtype: 'fetch' | 'xhr',\n domainContext: BkOTRequestContext,\n outcome: BkOTRequestOutcome,\n details: RequestDetails = {},\n) => {\n const sourceUrl = details.url;\n const redactedUrl = sourceUrl ? context.config.hooks.redactUrl(sourceUrl) : undefined;\n const method = details.method;\n const attributes: Attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumResourceSpanAttributes({\n initiatorType: subtype,\n method,\n outcome,\n url: redactedUrl ?? '',\n }),\n ...(redactedUrl ? { 'url.full': redactedUrl } : {}),\n // 模板由原始 URL 推导:Hook 可能需要 query 才能判断路由,产出的模板本身是低基数的\n ...(sourceUrl ? { 'url.template': context.config.hooks.getRequestUrlTemplate(sourceUrl) } : {}),\n };\n\n const event = {\n attributes,\n resource: {\n method,\n outcome,\n transport: subtype,\n url: redactedUrl,\n },\n type: 'resource' as const,\n };\n let shouldSend: boolean | void = true;\n try {\n shouldSend = getRequestOptions(context)?.beforeSend?.(event, domainContext);\n } catch (error) {\n if (context.config.debug) globalThis.console?.warn('[bk-ot] request.beforeSend failed:', error);\n }\n const redactedAttributes = context.applyRedact(event.attributes);\n span.setAttributes(redactedAttributes);\n span.updateName(buildRumSpanName({ attributes: redactedAttributes, spanType: RUM_SPAN_TYPE.resource }));\n if (shouldSend === false) {\n // SpanProcessor 在 onEnd 统一识别内部状态,避免这里绕过正常的 span 结束流程。\n markSpanDiscarded(span);\n return;\n }\n if (isErrorOutcome(outcome)) span.setStatus({ code: SpanStatusCode.ERROR });\n};\n\nexport const createCommonInstrumentationsPlugin = (option: BkOTRequestConfig | boolean | undefined): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n const activeRequestEnds = new Set<() => void>();\n\n return {\n name: 'request',\n enabled: option !== false,\n init(context) {\n if (typeof window === 'undefined') return;\n\n if (typeof window.fetch === 'function') {\n const originalFetch = window.fetch;\n const patchedFetch: typeof window.fetch = async function (this: Window, input, init) {\n const url = getFetchUrl(input);\n if (!context.isSampled() || shouldIgnoreRequest(context.config, url))\n return originalFetch.call(this, input, init);\n const method = getFetchMethod(input, init);\n const details = { method, startedAt: Date.now(), url };\n // Span Link 必须在创建 span 时给出,因此先规划 trace context 再建 span。\n const headers = shouldPropagateTraceHeader(context.config, url)\n ? getFetchRequestHeaders(input, init)\n : undefined;\n const tracePlan = headers ? planRequestTrace(name => headers.get(name) ?? undefined) : undefined;\n const span = startRequestSpan(context, 'fetch', details, tracePlan);\n const timing = trackRequestSpanTiming(context, url);\n const endActivity = startRequestActivity(context, url);\n const requestContext = getFetchRequestContext(input, init);\n const requestInit = headers && tracePlan ? applyFetchTracePlan(init, headers, tracePlan) : init;\n let ended = false;\n const endSpan = (entry?: PerformanceResourceTiming, fallbackEndTime = Date.now()) => {\n if (ended) return;\n ended = true;\n activeRequestEnds.delete(forceEnd);\n if (entry) {\n span.setAttributes(context.applyRedact(getResourcePerformanceAttributes(entry)));\n span.end(performance.timeOrigin + entry.startTime + getResourceDuration(entry));\n return;\n }\n span.end(fallbackEndTime);\n };\n const forceEnd = () => {\n // shutdown 不再等待异步 ResourceTiming,立即结束仍在飞行中的 span。\n timing.cancel();\n endSpan();\n };\n activeRequestEnds.add(forceEnd);\n try {\n const response = await originalFetch.call(this, input, requestInit);\n const outcome: BkOTRequestOutcome = {\n ...(response.status > 0 ? { statusCode: response.status } : {}),\n type: 'response',\n };\n decorateRequestSpan(\n context,\n span,\n 'fetch',\n { request: requestContext, response, type: 'fetch' },\n outcome,\n details,\n );\n const completedAt = Date.now();\n timing.complete(entry => endSpan(entry, completedAt));\n return response;\n } catch (error) {\n const outcome = getFetchFailureOutcome(requestContext, error);\n decorateRequestSpan(\n context,\n span,\n 'fetch',\n { error, request: requestContext, type: 'fetch' },\n outcome,\n details,\n );\n if (outcome.type !== 'abort' && error instanceof Error) span.recordException(error);\n const completedAt = Date.now();\n timing.complete(entry => endSpan(entry, completedAt));\n throw error;\n } finally {\n endActivity();\n }\n };\n window.fetch = patchedFetch;\n teardownCallbacks.push(() => {\n if (window.fetch === patchedFetch) window.fetch = originalFetch;\n });\n }\n\n if (typeof XMLHttpRequest !== 'undefined') {\n const requests = new WeakMap<XMLHttpRequest, RequestDetails>();\n // 浏览器不提供读取 XHR 请求头的 API,只能自己快照业务设置的 header 以便探测既有链路。\n const authorHeaders = new WeakMap<XMLHttpRequest, Record<string, string>>();\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n const patchedOpen: typeof XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest,\n method: string,\n url: string | URL,\n async = true,\n username?: null | string,\n password?: null | string,\n ) {\n requests.set(this, { method: method.toUpperCase(), url: toAbsoluteUrl(String(url)) });\n // open() 会清空已设置的请求头,快照必须同步失效。\n authorHeaders.delete(this);\n return originalOpen.call(this, method, String(url), async, username, password);\n };\n const patchedSend: typeof XMLHttpRequest.prototype.send = function (this: XMLHttpRequest, body) {\n const details = requests.get(this) ?? {};\n if (!context.isSampled() || !details.url || shouldIgnoreRequest(context.config, details.url))\n return originalSend.call(this, body);\n details.startedAt = Date.now();\n const tracePlan = shouldPropagateTraceHeader(context.config, details.url)\n ? planRequestTrace(createHeaderReader(authorHeaders.get(this)))\n : undefined;\n const span = startRequestSpan(context, 'xhr', details, tracePlan);\n const timing = trackRequestSpanTiming(context, details.url);\n const endActivity = startRequestActivity(context, details.url);\n if (tracePlan?.traceparent) this.setRequestHeader(TRACEPARENT_HEADER, tracePlan.traceparent);\n let finishing = false;\n let ended = false;\n let removeTerminalListeners = () => {};\n const forceEnd = () => {\n // XHR 可能永不触发终止事件;SDK 停止时必须清理活动计数并结束 span。\n removeTerminalListeners();\n timing.cancel();\n if (ended) return;\n ended = true;\n activeRequestEnds.delete(forceEnd);\n endActivity();\n span.end();\n };\n activeRequestEnds.add(forceEnd);\n const complete = (completionType: 'abort' | 'error' | 'load' | 'timeout') => {\n if (finishing || ended) return;\n finishing = true;\n removeTerminalListeners();\n const outcome = getXhrOutcome(completionType, this);\n decorateRequestSpan(context, span, 'xhr', { type: 'xhr', xhr: this }, outcome, details);\n endActivity();\n const completedAt = Date.now();\n timing.complete(entry => {\n if (ended) return;\n ended = true;\n activeRequestEnds.delete(forceEnd);\n if (entry) {\n span.setAttributes(context.applyRedact(getResourcePerformanceAttributes(entry)));\n span.end(performance.timeOrigin + entry.startTime + getResourceDuration(entry));\n return;\n }\n span.end(completedAt);\n });\n };\n const onAbort = () => complete('abort');\n const onError = () => complete('error');\n const onLoad = () => complete('load');\n const onTimeout = () => complete('timeout');\n removeTerminalListeners = () => {\n this.removeEventListener('abort', onAbort);\n this.removeEventListener('error', onError);\n this.removeEventListener('load', onLoad);\n this.removeEventListener('timeout', onTimeout);\n };\n this.addEventListener('abort', onAbort, { once: true });\n this.addEventListener('error', onError, { once: true });\n this.addEventListener('load', onLoad, { once: true });\n this.addEventListener('timeout', onTimeout, { once: true });\n try {\n return originalSend.call(this, body);\n } catch (error) {\n if (error instanceof Error) span.recordException(error);\n complete('error');\n throw error;\n }\n };\n XMLHttpRequest.prototype.open = patchedOpen;\n XMLHttpRequest.prototype.send = patchedSend;\n teardownCallbacks.push(() => {\n if (XMLHttpRequest.prototype.open === patchedOpen) XMLHttpRequest.prototype.open = originalOpen;\n if (XMLHttpRequest.prototype.send === patchedSend) XMLHttpRequest.prototype.send = originalSend;\n });\n\n if (hasTracingAllowlist(context) && typeof XMLHttpRequest.prototype.setRequestHeader === 'function') {\n const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;\n const patchedSetRequestHeader: typeof XMLHttpRequest.prototype.setRequestHeader = function (\n this: XMLHttpRequest,\n name: string,\n value: string,\n ) {\n const key = name.toLowerCase();\n const headers = authorHeaders.get(this) ?? {};\n // 浏览器对重复设置的同名 header 做 \", \" 合并,快照保持一致才能正确解析。\n headers[key] = key in headers ? `${headers[key]}, ${value}` : value;\n authorHeaders.set(this, headers);\n return originalSetRequestHeader.call(this, name, value);\n };\n XMLHttpRequest.prototype.setRequestHeader = patchedSetRequestHeader;\n teardownCallbacks.push(() => {\n if (XMLHttpRequest.prototype.setRequestHeader === patchedSetRequestHeader)\n XMLHttpRequest.prototype.setRequestHeader = originalSetRequestHeader;\n });\n }\n }\n },\n shutdown() {\n for (const end of [...activeRequestEnds]) end();\n while (teardownCallbacks.length) teardownCallbacks.pop()?.();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\n\n// blockedURI 除了 URL 还可能是 'inline' / 'eval' / 'wasm-eval' / 'self' 等关键字(CSP spec),\n// 这些不是 URL,不应该走 redactUrl\nconst URL_LIKE_BLOCKED_URI = /^https?:|^\\/\\//i;\n\nconst redactBlockedUri = (redactUrl: (url: string) => string, blockedURI: string | undefined) => {\n if (!blockedURI) return undefined;\n return URL_LIKE_BLOCKED_URI.test(blockedURI) ? redactUrl(blockedURI) : blockedURI;\n};\n\n/**\n * CSP 违规事件采集插件,通过监听 `securitypolicyviolation` 事件捕获被 CSP 策略拦截的脚本/资源,\n * 以 error span 上报,进入统一错误分析口径。\n *\n * URL 处理:\n * - `blockedURI` / `sourceFile` 中的 URL 类值会经 `redactUrl` 脱敏。\n * - `blockedURI` 是 'inline' / 'eval' 等 CSP 关键字时直接保留,不调用 redactUrl。\n */\nexport const createCspViolationPlugin = (): BkOTPlugin => {\n let teardown: (() => void) | undefined;\n\n return {\n name: 'csp-violation',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n const handler = (event: SecurityPolicyViolationEvent) => {\n if (!context.isSampled()) return;\n const occurredAt = Date.now();\n const blockedUri = redactBlockedUri(context.config.hooks.redactUrl, event.blockedURI);\n const sourceFile = event.sourceFile ? context.config.hooks.redactUrl(event.sourceFile) : undefined;\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n outcome: RUM_SPAN_OUTCOME.error,\n spanType: RUM_SPAN_TYPE.error,\n }),\n 'csp.blocked_uri': blockedUri,\n 'csp.violated_directive': event.violatedDirective,\n 'csp.effective_directive': event.effectiveDirective,\n 'csp.disposition': event.disposition,\n 'csp.source_file': sourceFile,\n 'csp.line_number': event.lineNumber,\n 'csp.column_number': event.columnNumber,\n 'csp.status_code': event.statusCode,\n 'csp.original_policy': event.originalPolicy,\n 'error.source': 'csp',\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.error }), attributes, {\n startTime: occurredAt,\n });\n span.end(occurredAt);\n };\n\n document.addEventListener('securitypolicyviolation', handler);\n teardown = () => document.removeEventListener('securitypolicyviolation', handler);\n },\n shutdown() {\n teardown?.();\n teardown = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * 浏览器错误采集插件,负责捕获 JS 运行时错误、未处理的 Promise rejection、资源加载失败三类错误。\n *\n * 上报策略:\n * - 错误分析主数据统一使用 `span_type=error` 的 error span。\n * - 每个浏览器错误只生成一条原始 error Span,错误分组和风暴控制由服务端完成。\n *\n * 关键 attribute:\n * - `error.source`:错误来源,取值 `window.error` / `unhandledrejection` / `resource`。\n * - 资源错误额外带 `url.full`(经 redactUrl 脱敏)。\n * - JS 错误额外带 `code.filepath` / `code.lineno` / `code.column`。\n */\n\nimport { SpanStatusCode } from '@opentelemetry/api';\n\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\n\nconst getErrorMessage = (value: unknown) => {\n if (value instanceof Error) {\n return value.message;\n }\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n};\n\ninterface EmitErrorOptions {\n context: BkOTRuntimeContext;\n error: unknown;\n exceptionType?: string;\n extra?: Record<string, unknown>;\n source: string;\n}\n\nconst emitError = ({ context, error, exceptionType, extra = {}, source }: EmitErrorOptions) => {\n if (!context.isSampled()) return;\n const occurredAt = Date.now();\n const message = getErrorMessage(error);\n context.notifyActivity({ time: occurredAt, type: 'error' });\n\n const resolvedExceptionType = exceptionType ?? (error instanceof Error ? error.name || 'Error' : source);\n const exceptionLike = error instanceof Error ? error : { message, name: resolvedExceptionType };\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...context.config.hooks.getErrorAttributes(),\n ...buildRumSpanAttributes({\n outcome: RUM_SPAN_OUTCOME.error,\n spanType: RUM_SPAN_TYPE.error,\n }),\n 'error.message': message,\n 'error.handled': false,\n 'error.source': source,\n ...extra,\n };\n // 错误分析统一沉淀为 error span;若当前存在 active context,OTel 会自动建立父子关系。\n const errorSpan = context.startSpan(\n buildRumSpanName({ attributes, nameHint: resolvedExceptionType, spanType: RUM_SPAN_TYPE.error }),\n attributes,\n { startTime: occurredAt },\n );\n errorSpan.recordException(exceptionLike);\n errorSpan.setStatus({ code: SpanStatusCode.ERROR, message });\n errorSpan.end();\n};\n\nexport const createErrorPlugin = (): BkOTPlugin => {\n const listeners: Array<() => void> = [];\n\n return {\n name: 'error',\n init(context) {\n if (typeof window === 'undefined') {\n return;\n }\n\n const onError = (event: ErrorEvent) => {\n emitError({\n context,\n source: 'window.error',\n error: event.error ?? event.message,\n extra: {\n 'code.filepath': event.filename,\n 'code.lineno': event.lineno,\n 'code.column': event.colno,\n },\n });\n };\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n emitError({\n context,\n source: 'unhandledrejection',\n error: event.reason,\n exceptionType: event.reason instanceof Error ? event.reason.name : 'UnhandledRejection',\n });\n };\n const onResourceError = (event: Event) => {\n // JS 运行时错误是 ErrorEvent,已由 bubble 阶段的 onError 处理;这里只关心资源加载失败\n if (event instanceof ErrorEvent) return;\n const target = event.target;\n if (!(target instanceof Element)) return;\n const elementWithUrl = target as Element & { href?: string; src?: string };\n const resourceUrl = elementWithUrl.src || elementWithUrl.href || (target as HTMLMediaElement).currentSrc || '';\n emitError({\n context,\n source: 'resource',\n error: new Error(`Resource load failed: ${target.tagName.toLowerCase()} ${resourceUrl}`),\n exceptionType: 'ResourceError',\n extra: {\n 'url.full': context.config.hooks.redactUrl(resourceUrl),\n },\n });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n window.addEventListener('error', onResourceError, true);\n listeners.push(\n () => window.removeEventListener('error', onError),\n () => window.removeEventListener('unhandledrejection', onUnhandledRejection),\n () => window.removeEventListener('error', onResourceError, true),\n );\n },\n shutdown() {\n while (listeners.length) {\n listeners.pop()?.();\n }\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\n/**\n * 主线程阻塞优先使用 Long Animation Frame API 获取脚本归因,不支持时回退到 Long Tasks API;\n * span 保留单次诊断详情,分布与计数由服务端从原始事件计算。\n */\nexport interface BkOTLongTaskPluginOptions {\n /** 采集阈值,默认 50ms。Performance API 本身通常只产生大于 50ms 的条目。 */\n threshold?: number;\n}\n\ninterface LegacyLongTaskEntry extends PerformanceEntry {\n attribution?: Array<{\n containerId?: string;\n containerName?: string;\n containerSrc?: string;\n containerType?: string;\n name?: string;\n }>;\n}\n\ninterface LongAnimationFrameEntry extends PerformanceEntry {\n blockingDuration: number;\n firstUIEventTimestamp: number;\n renderStart: number;\n scripts: ScriptTiming[];\n styleAndLayoutStart: number;\n}\n\ninterface ScriptTiming {\n duration: number;\n executionStart: number;\n forcedStyleAndLayoutDuration: number;\n invoker: string;\n invokerType: string;\n pauseDuration: number;\n sourceCharPosition: number;\n sourceFunctionName: string;\n sourceURL: string;\n startTime: number;\n windowAttribution: string;\n}\n\nconst DEFAULT_THRESHOLD = 50;\n\nconst nonNegativeNumber = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;\n\nconst finiteNumber = (value: number | undefined) => (Number.isFinite(value) ? value : undefined);\n\nconst getLegacyAttributionAttributes = (\n attribution: NonNullable<LegacyLongTaskEntry['attribution']>[number],\n redactUrl: (url: string) => string,\n): Attributes => ({\n ...(attribution.containerId ? { 'long_task.attribution.container_id': attribution.containerId } : {}),\n ...(attribution.containerName ? { 'long_task.attribution.container_name': attribution.containerName } : {}),\n ...(attribution.containerSrc ? { 'long_task.attribution.container_src': redactUrl(attribution.containerSrc) } : {}),\n ...(attribution.containerType ? { 'long_task.attribution.container_type': attribution.containerType } : {}),\n ...(attribution.name ? { 'long_task.attribution.name': attribution.name } : {}),\n});\n\nconst getScriptAttributes = (script: ScriptTiming, redactUrl: (url: string) => string): Attributes => ({\n 'long_task.script.duration': script.duration,\n 'long_task.script.execution_start': script.executionStart,\n 'long_task.script.forced_style_and_layout_duration': script.forcedStyleAndLayoutDuration,\n 'long_task.script.invoker': script.invoker,\n 'long_task.script.invoker_type': script.invokerType,\n 'long_task.script.pause_duration': script.pauseDuration,\n 'long_task.script.source_char_position': script.sourceCharPosition,\n 'long_task.script.source_function_name': script.sourceFunctionName,\n 'long_task.script.source_url': script.sourceURL ? redactUrl(script.sourceURL) : '',\n 'long_task.script.start_time': script.startTime,\n 'long_task.script.window_attribution': script.windowAttribution,\n});\n\nexport const createLongTaskPlugin = (options: BkOTLongTaskPluginOptions = {}): BkOTPlugin => {\n const threshold = nonNegativeNumber(options.threshold, DEFAULT_THRESHOLD);\n let observer: PerformanceObserver | undefined;\n let initialBatchTimer: ReturnType<typeof setTimeout> | undefined;\n let initialEntries: PerformanceEntry[] = [];\n\n return {\n name: 'long-task',\n init(context) {\n if (typeof PerformanceObserver === 'undefined' || typeof performance === 'undefined') return;\n const supportedEntryTypes = PerformanceObserver.supportedEntryTypes ?? [];\n // LoAF 提供脚本归因与 blockingDuration,支持时优先使用;旧浏览器回退到 longtask。\n const entryType = supportedEntryTypes.includes('long-animation-frame')\n ? 'long-animation-frame'\n : supportedEntryTypes.includes('longtask')\n ? 'longtask'\n : undefined;\n if (!entryType) return;\n\n const emitEntry = (entry: LegacyLongTaskEntry | LongAnimationFrameEntry) => {\n if (!context.isSampled()) return;\n if (!Number.isFinite(entry.duration) || entry.duration < threshold) return;\n const isLoaf = entry.entryType === 'long-animation-frame';\n const loaf = isLoaf ? (entry as LongAnimationFrameEntry) : undefined;\n const scripts = loaf?.scripts ?? [];\n const id = createRandomId('long-task');\n const startTime = performance.timeOrigin + entry.startTime;\n const endTime = startTime + entry.duration;\n const entryTypeAttribute = isLoaf ? 'long-animation-frame' : 'long-task';\n const legacyAttributions = isLoaf ? [] : ((entry as LegacyLongTaskEntry).attribution ?? []);\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.longTask,\n }),\n ...(finiteNumber(loaf?.blockingDuration) !== undefined\n ? { [RUM_ATTRIBUTES.longTaskBlockingDuration]: loaf!.blockingDuration }\n : {}),\n [RUM_ATTRIBUTES.longTaskEntryType]: entryTypeAttribute,\n [RUM_ATTRIBUTES.longTaskId]: id,\n 'long_task.name': entry.name,\n ...(finiteNumber(loaf?.firstUIEventTimestamp) !== undefined\n ? { 'long_task.first_ui_event_timestamp': loaf!.firstUIEventTimestamp }\n : {}),\n ...(finiteNumber(loaf?.renderStart) !== undefined ? { 'long_task.render_start': loaf!.renderStart } : {}),\n ...(finiteNumber(loaf?.styleAndLayoutStart) !== undefined\n ? { 'long_task.style_and_layout_start': loaf!.styleAndLayoutStart }\n : {}),\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.longTask }), attributes, {\n startTime,\n });\n scripts.forEach(script => {\n span.addEvent(\n 'long_task.script',\n context.applyRedact(getScriptAttributes(script, context.config.hooks.redactUrl)),\n performance.timeOrigin + script.startTime,\n );\n });\n legacyAttributions.forEach((attribution, index) => {\n span.addEvent(\n 'long_task.attribution',\n context.applyRedact({\n 'long_task.attribution.index': index,\n ...getLegacyAttributionAttributes(attribution, context.config.hooks.redactUrl),\n }),\n startTime,\n );\n });\n span.end(endTime);\n context.notifyActivity({ endTime, startTime, type: 'long_task' });\n };\n\n const emitEntries = (entries: PerformanceEntry[]) =>\n entries.forEach(entry => emitEntry(entry as LegacyLongTaskEntry));\n try {\n let initializing = true;\n observer = new PerformanceObserver(list => {\n const entries = list.getEntries();\n if (initializing) {\n // buffered 条目可能在 observe() 内同步回调,先合并到下一宏任务,等 Session/View 上下文就绪后再归属。\n initialEntries.push(...entries);\n if (!initialBatchTimer) {\n initialBatchTimer = setTimeout(() => {\n const entriesToEmit = initialEntries;\n initialEntries = [];\n initialBatchTimer = undefined;\n emitEntries(entriesToEmit);\n });\n }\n } else {\n emitEntries(entries);\n }\n });\n observer.observe({ type: entryType, buffered: true });\n initializing = false;\n } catch {\n observer = undefined;\n }\n },\n shutdown() {\n observer?.disconnect();\n observer = undefined;\n clearTimeout(initialBatchTimer);\n initialBatchTimer = undefined;\n initialEntries = [];\n },\n };\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nexport interface RouteChangeEvent {\n fromUrl: string;\n source: RouteChangeSource;\n toUrl: string;\n}\n\nexport type RouteChangeSource = 'hashchange' | 'popstate' | 'pushState' | 'replaceState';\n\ntype RouteChangeHandler = (event: RouteChangeEvent) => void;\n\nconst subscribers = new Set<RouteChangeHandler>();\n\n// History 只 patch 一次,多个插件/实例共用订阅集合;最后一个订阅者退出时恢复原方法。\nlet lastUrl = '';\nlet originalPushState: typeof history.pushState | undefined;\nlet originalReplaceState: typeof history.replaceState | undefined;\nlet patched = false;\n\nconst getCurrentUrl = () => (typeof location === 'undefined' ? '' : location.href);\n\nconst emitRouteChange = (source: RouteChangeSource, fromUrl: string) => {\n const toUrl = getCurrentUrl();\n lastUrl = toUrl;\n const event: RouteChangeEvent = { fromUrl, source, toUrl };\n\n for (const subscriber of Array.from(subscribers)) {\n subscriber(event);\n }\n};\n\nconst onPopState = () => {\n emitRouteChange('popstate', lastUrl || getCurrentUrl());\n};\n\nconst onHashChange = () => {\n emitRouteChange('hashchange', lastUrl || getCurrentUrl());\n};\n\nconst patchHistory = () => {\n if (patched || typeof window === 'undefined' || typeof history === 'undefined') {\n return;\n }\n\n patched = true;\n lastUrl = getCurrentUrl();\n originalPushState = history.pushState;\n originalReplaceState = history.replaceState;\n\n history.pushState = function patchedPushState(this: History, data: any, title: string, url?: null | string | URL) {\n const fromUrl = lastUrl || getCurrentUrl();\n // 先执行原方法,让订阅者读取到的 location 与浏览器最终状态一致。\n const result = originalPushState?.apply(this, [data, title, url]);\n emitRouteChange('pushState', fromUrl);\n return result;\n };\n history.replaceState = function patchedReplaceState(\n this: History,\n data: any,\n title: string,\n url?: null | string | URL,\n ) {\n const fromUrl = lastUrl || getCurrentUrl();\n const result = originalReplaceState?.apply(this, [data, title, url]);\n emitRouteChange('replaceState', fromUrl);\n return result;\n };\n window.addEventListener('popstate', onPopState);\n window.addEventListener('hashchange', onHashChange);\n};\n\nconst restoreHistory = () => {\n if (!patched || typeof window === 'undefined' || typeof history === 'undefined') {\n return;\n }\n\n if (originalPushState) {\n history.pushState = originalPushState;\n }\n if (originalReplaceState) {\n history.replaceState = originalReplaceState;\n }\n window.removeEventListener('popstate', onPopState);\n window.removeEventListener('hashchange', onHashChange);\n originalPushState = undefined;\n originalReplaceState = undefined;\n patched = false;\n lastUrl = '';\n};\n\nexport const subscribeRouteChange = (handler: RouteChangeHandler) => {\n if (typeof window === 'undefined' || typeof history === 'undefined') {\n return () => {};\n }\n\n patchHistory();\n subscribers.add(handler);\n\n return () => {\n subscribers.delete(handler);\n if (subscribers.size === 0) {\n restoreHistory();\n }\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Page View 插件\n *\n * 自动模式监听初始加载、SPA 路由和 BFCache;手动模式仅由 startView() 划分 View。\n *\n * 上报形态:使用 view.name 命名的 start/update/end 原始生命周期事件 span。\n *\n * 自动边界与 Datadog 对齐:pathname 或非锚点 hash path 改变才创建 View,query-only 变化不创建。\n *\n * 关键属性:\n * - view.url:当前页面 URL(经 redactUrl 脱敏)\n * - view.previous:跳转前的 URL(来自 route-observer 的 fromUrl,初始 load 为空字符串)\n * - view.previous_url_template:跳转前 URL 的低基数路由模板,初始 load 为空字符串\n * - view.referrer:仅初始加载且值非空时携带\n */\n\nimport { createRandomId } from '../core/id';\nimport { waitForPageActivityEnd } from '../core/page-activity';\nimport { subscribeRouteChange } from '../core/route-observer';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { BkOTStartViewOptions, BkOTViewContext } from '../core/runtime-context';\nimport type { Attributes } from '@opentelemetry/api';\n\ninterface ActiveView {\n attributes: Attributes;\n id: string;\n loadingTime?: number;\n loadingTimeSource?: 'auto' | 'manual';\n loadingType: ViewLoadingType;\n /** 业务显式命名优先;未命名时使用 view.url_template */\n name?: string;\n rawUrl: string;\n snapshotAttributes: Attributes;\n startedAt: number;\n url: string;\n urlTemplate: string;\n version: number;\n stopLoadingTime?: () => void;\n}\n\ntype ViewLoadingType = NonNullable<BkOTViewContext['loadingType']>;\n\nconst PROTECTED_ATTRIBUTE_KEYS = new Set<string>(Object.values(RUM_ATTRIBUTES));\n\nconst getCurrentUrl = () => {\n if (typeof location === 'undefined') {\n return '';\n }\n return location.href;\n};\n\nconst getNavigationTimingAttributes = (): Attributes => {\n if (typeof performance === 'undefined') return {};\n const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined;\n if (!navigation) return {};\n const attributes: Attributes = {};\n const setTiming = (key: string, value: number) => {\n if (Number.isFinite(value) && value > 0) attributes[key] = value;\n };\n setTiming(RUM_ATTRIBUTES.viewFirstByte, navigation.responseStart);\n setTiming(RUM_ATTRIBUTES.viewDomInteractive, navigation.domInteractive);\n setTiming(RUM_ATTRIBUTES.viewDomContentLoaded, navigation.domContentLoadedEventEnd);\n setTiming(RUM_ATTRIBUTES.viewDomComplete, navigation.domComplete);\n setTiming(RUM_ATTRIBUTES.viewLoadEvent, navigation.loadEventEnd);\n return attributes;\n};\n\nconst getHashPath = (hash: string) => {\n const queryIndex = hash.indexOf('?');\n return queryIndex < 0 ? hash : hash.slice(0, queryIndex);\n};\n\nconst isHashAnchor = (hash: string) => {\n const id = hash.slice(1);\n if (!id || typeof document === 'undefined' || typeof document.getElementById !== 'function') return false;\n try {\n return Boolean(document.getElementById(decodeURIComponent(id)));\n } catch {\n return Boolean(document.getElementById(id));\n }\n};\n\nexport const isViewLocationChange = (fromUrl: string, toUrl: string) => {\n try {\n const base = typeof location === 'undefined' ? 'http://localhost' : location.href;\n const from = new URL(fromUrl, base);\n const to = new URL(toUrl, base);\n return from.pathname !== to.pathname || (!isHashAnchor(to.hash) && getHashPath(from.hash) !== getHashPath(to.hash));\n } catch {\n return fromUrl !== toUrl;\n }\n};\n\nexport const createPageViewPlugin = (): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n\n return {\n name: 'page-view',\n init(context) {\n if (typeof window === 'undefined') {\n return;\n }\n\n let activeView: ActiveView | undefined;\n let bfCacheView: Omit<ActiveView, 'stopLoadingTime'> | undefined;\n let renewalView: Omit<ActiveView, 'stopLoadingTime'> | undefined;\n\n const clearViewContext = (changedAt = Date.now()) => context.setView({}, changedAt);\n\n const emitViewEvent = (\n view: ActiveView,\n phase: 'end' | 'start' | 'update',\n timestamp = Date.now(),\n reason?: string,\n ) => {\n view.version += 1;\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...view.attributes,\n ...view.snapshotAttributes,\n [RUM_ATTRIBUTES.viewPhase]: phase,\n [RUM_ATTRIBUTES.viewStartedAt]: view.startedAt,\n [RUM_ATTRIBUTES.viewVersion]: view.version,\n ...(reason ? { 'view.end_reason': reason } : {}),\n ...(view.loadingTime === undefined\n ? {}\n : {\n [RUM_ATTRIBUTES.viewLoadingTime]: view.loadingTime,\n [RUM_ATTRIBUTES.viewLoadingTimeSource]: view.loadingTimeSource,\n }),\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.view }), attributes, {\n contextTime: timestamp,\n rumSpanType: RUM_SPAN_TYPE.view,\n startTime: timestamp,\n });\n span.end(timestamp);\n };\n\n const endActiveView = (reason: string, clearContext = true, endedAt = Date.now()) => {\n if (!activeView) {\n if (clearContext) clearViewContext(endedAt);\n return undefined;\n }\n const snapshot = { ...activeView };\n activeView.stopLoadingTime?.();\n emitViewEvent(activeView, 'end', endedAt, reason);\n activeView = undefined;\n if (clearContext) clearViewContext(endedAt);\n const { stopLoadingTime: _stopLoadingTime, ...rest } = snapshot;\n return rest;\n };\n\n const setLoadingTime = (view: ActiveView, duration: number, source: 'auto' | 'manual') => {\n if (activeView !== view || !Number.isFinite(duration) || duration < 0) return;\n const navigationTimingAttributes = view.loadingType === 'initial_load' ? getNavigationTimingAttributes() : {};\n const updatedAttributes = {\n ...navigationTimingAttributes,\n [RUM_ATTRIBUTES.viewLoadingTime]: duration,\n [RUM_ATTRIBUTES.viewLoadingTimeSource]: source,\n };\n Object.assign(view.snapshotAttributes, updatedAttributes);\n view.loadingTime = duration;\n view.loadingTimeSource = source;\n emitViewEvent(view, 'update');\n };\n\n const startLoadingTimeTracking = (view: ActiveView) => {\n if (!context.config.view.loadingTime || document.visibilityState === 'hidden') return;\n let activityResolved = false;\n let activityCandidate: number | undefined;\n let loadResolved = view.loadingType !== 'initial_load';\n let loadCandidate: number | undefined;\n let loadListener: (() => void) | undefined;\n let hidden = false;\n let visibilityListener: (() => void) | undefined;\n\n const tryComplete = () => {\n if (hidden || !activityResolved || !loadResolved || activeView !== view) return;\n const candidates = [activityCandidate, loadCandidate].filter(\n (candidate): candidate is number => candidate !== undefined,\n );\n if (candidates.length) setLoadingTime(view, Math.max(...candidates), 'auto');\n view.stopLoadingTime?.();\n view.stopLoadingTime = undefined;\n };\n\n const readLoadEvent = () => {\n const navigation = performance.getEntriesByType?.('navigation')[0] as PerformanceNavigationTiming | undefined;\n if (!navigation?.loadEventEnd) return false;\n loadCandidate = Math.max(0, performance.timeOrigin + navigation.loadEventEnd - view.startedAt);\n loadResolved = true;\n return true;\n };\n\n if (!loadResolved && !readLoadEvent()) {\n const onLoad = () => {\n setTimeout(() => {\n if (activeView !== view) return;\n readLoadEvent();\n loadResolved = true;\n tryComplete();\n });\n };\n window.addEventListener('load', onLoad, { once: true });\n loadListener = () => window.removeEventListener('load', onLoad);\n }\n\n const stopActivity = waitForPageActivityEnd(context, view.startedAt, result => {\n activityResolved = true;\n if (result.hadActivity) activityCandidate = Math.max(0, result.endTime - view.startedAt);\n tryComplete();\n });\n const onVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') return;\n hidden = true;\n view.stopLoadingTime?.();\n view.stopLoadingTime = undefined;\n };\n document.addEventListener('visibilitychange', onVisibilityChange);\n visibilityListener = () => document.removeEventListener('visibilitychange', onVisibilityChange);\n view.stopLoadingTime = () => {\n stopActivity();\n loadListener?.();\n loadListener = undefined;\n visibilityListener?.();\n visibilityListener = undefined;\n };\n tryComplete();\n };\n\n const sanitizeViewAttributes = (attributes: Attributes | undefined) => {\n const redacted = context.applyRedact(attributes ?? {});\n return Object.fromEntries(\n Object.entries(redacted).filter(([key, value]) => value !== undefined && !PROTECTED_ATTRIBUTE_KEYS.has(key)),\n ) as Attributes;\n };\n\n const startView = (\n options: BkOTStartViewOptions,\n source: string,\n loadingType: ViewLoadingType,\n previousUrl = activeView?.rawUrl ?? '',\n ) => {\n if (!context.isSessionActive()) return;\n const currentUrl = options.url ?? getCurrentUrl();\n const urlTemplate = context.config.hooks.getViewUrlTemplate(currentUrl);\n const previousUrlTemplate = previousUrl ? context.config.hooks.getViewUrlTemplate(previousUrl) : '';\n const name = options.name ?? urlTemplate;\n const customAttributes = sanitizeViewAttributes(options.attributes);\n endActiveView(source, false);\n\n const viewId = createRandomId('view');\n const redactedCurrentUrl = context.config.hooks.redactUrl(currentUrl);\n const redactedPreviousUrl = context.config.hooks.redactUrl(previousUrl);\n const isInitialLoad = loadingType === 'initial_load';\n const startedAt = isInitialLoad && typeof performance !== 'undefined' ? performance.timeOrigin : Date.now();\n const navigationTimingAttributes = isInitialLoad ? getNavigationTimingAttributes() : {};\n\n context.setView(\n {\n attributes: customAttributes,\n id: viewId,\n loadingType,\n name,\n startedAt,\n url: redactedCurrentUrl,\n urlTemplate,\n },\n startedAt,\n );\n\n const viewAttributes = {\n ...customAttributes,\n ...context.config.hooks.getPageAttributes(),\n ...navigationTimingAttributes,\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.view,\n }),\n [RUM_ATTRIBUTES.viewId]: viewId,\n ...(name ? { [RUM_ATTRIBUTES.viewName]: name } : {}),\n [RUM_ATTRIBUTES.viewUrl]: redactedCurrentUrl,\n [RUM_ATTRIBUTES.viewUrlTemplate]: urlTemplate,\n [RUM_ATTRIBUTES.viewLoadingType]: loadingType,\n [RUM_ATTRIBUTES.viewPrevious]: redactedPreviousUrl,\n [RUM_ATTRIBUTES.viewPreviousUrlTemplate]: previousUrlTemplate,\n ...(isInitialLoad && document.referrer\n ? { [RUM_ATTRIBUTES.viewReferrer]: context.config.hooks.redactUrl(document.referrer) }\n : {}),\n };\n activeView = {\n attributes: customAttributes,\n version: 0,\n id: viewId,\n loadingType,\n name,\n rawUrl: currentUrl,\n snapshotAttributes: viewAttributes,\n startedAt,\n url: redactedCurrentUrl,\n urlTemplate,\n };\n emitViewEvent(activeView, 'start', startedAt);\n startLoadingTimeTracking(activeView);\n };\n\n const unsubscribeViewCommands = context.onViewCommand(command => {\n if (command.type === 'start') {\n startView(command.options, 'manual', activeView ? 'route_change' : 'initial_load');\n return;\n }\n if (!activeView) return;\n if (command.type === 'set_loading_time') {\n activeView.stopLoadingTime?.();\n activeView.stopLoadingTime = undefined;\n setLoadingTime(activeView, Math.max(0, command.time - activeView.startedAt), 'manual');\n return;\n }\n if (activeView.name === command.name) return;\n activeView.name = command.name;\n activeView.snapshotAttributes[RUM_ATTRIBUTES.viewName] = command.name;\n context.setView({\n attributes: activeView.attributes,\n id: activeView.id,\n loadingType: activeView.loadingType,\n name: activeView.name,\n startedAt: activeView.startedAt,\n url: activeView.url,\n urlTemplate: activeView.urlTemplate,\n });\n emitViewEvent(activeView, 'update');\n });\n\n let unsubscribeRoute = () => {};\n if (context.config.view.tracking === 'auto') {\n if (!activeView) startView({}, 'load', 'initial_load');\n unsubscribeRoute = subscribeRouteChange(event => {\n if (isViewLocationChange(event.fromUrl, event.toUrl)) {\n startView({}, event.source, 'route_change', event.fromUrl);\n }\n });\n }\n\n const onPageHide = (event: PageTransitionEvent) => {\n if (event.persisted) {\n bfCacheView = endActiveView('bfcache');\n return;\n }\n bfCacheView = undefined;\n endActiveView('pagehide');\n };\n const onPageShow = (event: PageTransitionEvent) => {\n if (event.persisted && context.config.view.tracking === 'auto') {\n const restoredView = bfCacheView;\n bfCacheView = undefined;\n if (!context.isSessionActive()) {\n renewalView = restoredView;\n return;\n }\n startView(\n restoredView\n ? { attributes: restoredView.attributes, name: restoredView.name, url: restoredView.rawUrl }\n : {},\n 'bfCache',\n 'bf_cache',\n restoredView?.rawUrl,\n );\n }\n };\n const unsubscribeSessionLifecycle = context.onSessionLifecycle(event => {\n if (event.type === 'expired') {\n renewalView = endActiveView('session_expired', true, event.expiredAt) ?? bfCacheView;\n bfCacheView = undefined;\n return;\n }\n if (renewalView) {\n startView(\n { attributes: renewalView.attributes, name: renewalView.name, url: renewalView.rawUrl },\n 'sessionRenewal',\n 'session_renewal',\n renewalView.rawUrl,\n );\n renewalView = undefined;\n }\n });\n window.addEventListener('pagehide', onPageHide);\n window.addEventListener('pageshow', onPageShow);\n\n teardownCallbacks.push(\n unsubscribeRoute,\n unsubscribeSessionLifecycle,\n unsubscribeViewCommands,\n () => window.removeEventListener('pagehide', onPageHide),\n () => window.removeEventListener('pageshow', onPageShow),\n () => endActiveView('shutdown'),\n );\n },\n shutdown() {\n while (teardownCallbacks.length) {\n teardownCallbacks.pop()?.();\n }\n },\n };\n};\n","export interface ActiveSessionRecord {\n expiresAt: number;\n id: string;\n startedAt: number;\n status: 'active';\n}\n\nexport interface ExpiredSessionRecord {\n expiredAt: number;\n previousId: string;\n reason: SessionExpireReason;\n status: 'expired';\n}\n\n/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nexport type SessionExpireReason = 'inactivity' | 'maxLifetime';\n\nexport type SessionRecord = ActiveSessionRecord | ExpiredSessionRecord;\n\nconst FUTURE_CLOCK_TOLERANCE_MS = 5_000;\n\nconst isTimestamp = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value) && value > 0;\n\nexport const createActiveSessionRecord = (\n id: string,\n now: number,\n idleTimeoutMs: number,\n maxDurationMs: number,\n): ActiveSessionRecord => ({\n expiresAt: Math.min(now + idleTimeoutMs, now + maxDurationMs),\n id,\n startedAt: now,\n status: 'active',\n});\n\nexport const getSessionExpireReason = (\n record: ActiveSessionRecord,\n now: number,\n maxDurationMs: number,\n): SessionExpireReason | undefined => {\n if (now >= record.startedAt + maxDurationMs) return 'maxLifetime';\n if (now >= record.expiresAt) return 'inactivity';\n return undefined;\n};\n\nexport const expandActiveSession = (\n record: ActiveSessionRecord,\n now: number,\n idleTimeoutMs: number,\n maxDurationMs: number,\n): ActiveSessionRecord => ({\n ...record,\n expiresAt: Math.min(now + idleTimeoutMs, record.startedAt + maxDurationMs),\n});\n\nexport const parseSessionRecord = (raw: null | string, now: number, maxDurationMs: number): null | SessionRecord => {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<SessionRecord>;\n if (\n parsed.status === 'active' &&\n typeof parsed.id === 'string' &&\n parsed.id.length > 0 &&\n isTimestamp(parsed.startedAt) &&\n // 容忍轻微时钟漂移,但拒绝远期时间与超出最大生命周期的记录,避免脏 storage 永久续期。\n parsed.startedAt <= now + FUTURE_CLOCK_TOLERANCE_MS &&\n isTimestamp(parsed.expiresAt) &&\n parsed.expiresAt >= parsed.startedAt &&\n parsed.expiresAt <= parsed.startedAt + maxDurationMs\n ) {\n return parsed as ActiveSessionRecord;\n }\n if (\n parsed.status === 'expired' &&\n typeof parsed.previousId === 'string' &&\n parsed.previousId.length > 0 &&\n (parsed.reason === 'inactivity' || parsed.reason === 'maxLifetime') &&\n isTimestamp(parsed.expiredAt) &&\n parsed.expiredAt <= now + FUTURE_CLOCK_TOLERANCE_MS\n ) {\n return parsed as ExpiredSessionRecord;\n }\n } catch {\n /* JSON 损坏视为无记录 */\n }\n return null;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Session 插件\n *\n * 生命周期:\n * - 首次访问创建 session;用户交互会续期有效 session,或重建已过期 session\n * - 固定 15 分钟无活动 / 4 小时最长生命周期,任一到达时立即清理运行时 session.id\n * - 页面重新可见时只续期有效 session,不会复活已过期 session\n * - 跨 tab 共享持久化状态;本 tab 过期后不会被其他 tab 的新 session 被动复活\n */\n\nimport { hashString } from '../core/hash';\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\nimport {\n createActiveSessionRecord,\n expandActiveSession,\n getSessionExpireReason,\n parseSessionRecord,\n} from './session-state';\n\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { ActiveSessionRecord, ExpiredSessionRecord, SessionExpireReason, SessionRecord } from './session-state';\n\nexport interface BkOTSessionConfig {\n /** 以 0~1 表示的 Session 采样率,默认 1。 */\n sampleRate?: number;\n // 自定义 storage key;不传则按 endpoint host 自动生成隔离后缀\n storageKey?: string;\n}\n\nconst SESSION_IDLE_TIMEOUT_MS = 15 * 60 * 1000;\nconst SESSION_MAX_DURATION_MS = 4 * 60 * 60 * 1000;\nconst ACTIVITY_THROTTLE_MS = 1_000;\nconst VISIBILITY_CHECK_MS = 60_000;\nconst ACTIVITY_EVENTS: Array<keyof WindowEventMap> = ['click', 'keydown', 'scroll', 'touchstart'];\nconst memoryRecords = new Map<string, string>();\n\ninterface SessionStorage {\n isLocalStorage: () => boolean;\n read: () => null | string;\n write: (record: SessionRecord) => void;\n}\n\nconst createSessionStorage = (storageKey: string): SessionStorage => {\n let localStorageAvailable = typeof window !== 'undefined';\n\n const read = () => {\n if (localStorageAvailable) {\n try {\n return window.localStorage.getItem(storageKey);\n } catch {\n localStorageAvailable = false;\n }\n }\n return memoryRecords.get(storageKey) ?? null;\n };\n\n const write = (record: SessionRecord) => {\n const serialized = JSON.stringify(record);\n memoryRecords.set(storageKey, serialized);\n if (!localStorageAvailable) return;\n try {\n window.localStorage.setItem(storageKey, serialized);\n } catch {\n localStorageAvailable = false;\n }\n };\n\n read();\n return { isLocalStorage: () => localStorageAvailable, read, write };\n};\n\nconst buildDefaultStorageKey = (endpoint: string, applicationName: string) => {\n let suffix = '';\n try {\n suffix = new URL(endpoint).host;\n } catch {\n suffix = endpoint;\n }\n return `bk_ot_session__${hashString(`${applicationName}\\0${suffix || 'default'}`)}`;\n};\n\nconst emitSessionEvent = (\n context: BkOTRuntimeContext,\n phase: 'end' | 'rotate' | 'start',\n sessionId: string,\n timestamp: number,\n) => {\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.session,\n }),\n [RUM_ATTRIBUTES.sessionPhase]: phase,\n [RUM_ATTRIBUTES.sessionHasReplay]: false,\n [RUM_ATTRIBUTES.sessionId]: sessionId,\n [RUM_ATTRIBUTES.sessionType]: 'user',\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.session }), attributes, {\n contextTime: timestamp,\n startTime: timestamp,\n });\n span.end(timestamp);\n};\n\nexport const createSessionPlugin = (options: BkOTSessionConfig = {}): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n\n return {\n name: 'session',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n const now = Date.now();\n const sessionId = createRandomId('session');\n context.setRuntimeAttributes(\n {\n [RUM_ATTRIBUTES.sessionHasReplay]: false,\n [RUM_ATTRIBUTES.sessionId]: sessionId,\n [RUM_ATTRIBUTES.sessionType]: 'user',\n },\n now,\n );\n return;\n }\n\n const storageKey =\n options.storageKey ??\n buildDefaultStorageKey(context.config.transport.endpoint, context.config.application.name);\n const storage = createSessionStorage(storageKey);\n const documentStartedAt =\n typeof performance !== 'undefined' && Number.isFinite(performance.timeOrigin)\n ? performance.timeOrigin\n : Date.now();\n let currentSessionId: string | undefined;\n let expirationTimeout: ReturnType<typeof setTimeout> | undefined;\n\n const readRecord = (now = Date.now()) => parseSessionRecord(storage.read(), now, SESSION_MAX_DURATION_MS);\n\n const clearExpirationTimeout = () => {\n if (expirationTimeout !== undefined) {\n clearTimeout(expirationTimeout);\n expirationTimeout = undefined;\n }\n };\n\n const deactivate = (reason: 'external' | SessionExpireReason, expiredAt = Date.now()) => {\n const expiredSessionId = currentSessionId;\n if (!expiredSessionId) return;\n context.notifySessionLifecycle({\n expiredAt,\n id: expiredSessionId,\n reason,\n type: 'expired',\n });\n emitSessionEvent(context, 'end', expiredSessionId, expiredAt);\n clearExpirationTimeout();\n currentSessionId = undefined;\n context.setRuntimeAttributes(\n {\n [RUM_ATTRIBUTES.sessionHasReplay]: undefined,\n [RUM_ATTRIBUTES.sessionId]: undefined,\n [RUM_ATTRIBUTES.sessionType]: undefined,\n },\n expiredAt,\n );\n void context.flush();\n };\n\n const expireCurrentSession = () => {\n const now = Date.now();\n const record = readRecord(now);\n if (!record) {\n deactivate('external', now);\n return;\n }\n if (record.status === 'expired') {\n deactivate(record.reason, record.expiredAt);\n return;\n }\n if (record.id !== currentSessionId) {\n deactivate('external', now);\n return;\n }\n const reason = getSessionExpireReason(record, now, SESSION_MAX_DURATION_MS);\n if (!reason) {\n scheduleExpiration(record);\n return;\n }\n const expired: ExpiredSessionRecord = {\n expiredAt: now,\n previousId: record.id,\n reason,\n status: 'expired',\n };\n storage.write(expired);\n deactivate(reason, now);\n };\n\n const scheduleExpiration = (record: ActiveSessionRecord) => {\n clearExpirationTimeout();\n const expiresAt = Math.min(record.expiresAt, record.startedAt + SESSION_MAX_DURATION_MS);\n expirationTimeout = setTimeout(expireCurrentSession, Math.max(0, expiresAt - Date.now()));\n };\n\n const activate = (\n record: ActiveSessionRecord,\n lifecycle?: {\n previousId?: string;\n reason: 'inactivity' | 'init' | 'maxLifetime' | 'shared';\n },\n ) => {\n const changed = record.id !== currentSessionId;\n currentSessionId = record.id;\n context.setRuntimeAttributes(\n {\n [RUM_ATTRIBUTES.sessionHasReplay]: false,\n [RUM_ATTRIBUTES.sessionId]: record.id,\n [RUM_ATTRIBUTES.sessionType]: 'user',\n },\n Math.min(record.startedAt, documentStartedAt),\n );\n scheduleExpiration(record);\n if (changed && lifecycle) {\n context.notifySessionLifecycle({\n id: record.id,\n previousId: lifecycle.previousId,\n reason: lifecycle.reason,\n startedAt: record.startedAt,\n type: 'renewed',\n });\n }\n };\n\n const expandOrRenew = (isInitialization = false) => {\n const now = Date.now();\n const record = readRecord(now);\n if (record?.status === 'active' && !getSessionExpireReason(record, now, SESSION_MAX_DURATION_MS)) {\n const expanded = expandActiveSession(record, now, SESSION_IDLE_TIMEOUT_MS, SESSION_MAX_DURATION_MS);\n storage.write(expanded);\n activate(expanded, currentSessionId ? undefined : { reason: 'shared' });\n return;\n }\n\n const previousId = record?.status === 'expired' ? record.previousId : record?.id;\n const reason =\n record?.status === 'expired'\n ? record.reason\n : record\n ? getSessionExpireReason(record, now, SESSION_MAX_DURATION_MS)\n : isInitialization\n ? 'init'\n : undefined;\n const created = createActiveSessionRecord(\n createRandomId('session'),\n now,\n SESSION_IDLE_TIMEOUT_MS,\n SESSION_MAX_DURATION_MS,\n );\n storage.write(created);\n activate(created, {\n previousId,\n reason: reason ?? 'init',\n });\n const lifecycleReason = reason ?? 'init';\n emitSessionEvent(context, lifecycleReason === 'init' ? 'start' : 'rotate', created.id, created.startedAt);\n };\n\n const expandOnly = () => {\n if (!currentSessionId) return;\n const now = Date.now();\n const record = readRecord(now);\n if (\n record?.status !== 'active' ||\n record.id !== currentSessionId ||\n getSessionExpireReason(record, now, SESSION_MAX_DURATION_MS)\n ) {\n expireCurrentSession();\n return;\n }\n const expanded = expandActiveSession(record, now, SESSION_IDLE_TIMEOUT_MS, SESSION_MAX_DURATION_MS);\n storage.write(expanded);\n activate(expanded);\n };\n\n expandOrRenew(true);\n\n let lastActivityAt = 0;\n const onActivity = () => {\n const now = Date.now();\n if (now - lastActivityAt < ACTIVITY_THROTTLE_MS) return;\n lastActivityAt = now;\n expandOrRenew();\n };\n const activityListenerOptions: AddEventListenerOptions = { capture: true, passive: true };\n ACTIVITY_EVENTS.forEach(eventName => window.addEventListener(eventName, onActivity, activityListenerOptions));\n teardownCallbacks.push(() => {\n ACTIVITY_EVENTS.forEach(eventName =>\n window.removeEventListener(eventName, onActivity, activityListenerOptions),\n );\n });\n\n const expandWhenVisible = () => {\n if (document.visibilityState === 'visible') expandOnly();\n };\n document.addEventListener('visibilitychange', expandWhenVisible);\n const visibilityInterval = window.setInterval(expandWhenVisible, VISIBILITY_CHECK_MS);\n teardownCallbacks.push(() => {\n document.removeEventListener('visibilitychange', expandWhenVisible);\n window.clearInterval(visibilityInterval);\n });\n\n const onStorage = (event: StorageEvent) => {\n if (!storage.isLocalStorage() || event.storageArea !== window.localStorage || event.key !== storageKey) return;\n const now = Date.now();\n const record = parseSessionRecord(event.newValue, now, SESSION_MAX_DURATION_MS);\n if (\n record?.status === 'active' &&\n record.id === currentSessionId &&\n !getSessionExpireReason(record, now, SESSION_MAX_DURATION_MS)\n ) {\n scheduleExpiration(record);\n return;\n }\n // 当前 tab 一旦失效,不被其他 tab 新建的 session 被动复活;本 tab 发生交互后再接管共享 session。\n deactivate(\n record?.status === 'expired' ? record.reason : 'external',\n record?.status === 'expired' ? record.expiredAt : now,\n );\n };\n window.addEventListener('storage', onStorage);\n teardownCallbacks.push(() => window.removeEventListener('storage', onStorage));\n teardownCallbacks.push(clearExpirationTimeout);\n },\n shutdown() {\n while (teardownCallbacks.length) teardownCallbacks.pop()?.();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Web Vitals 插件\n *\n * 基于 google/web-vitals 库(attribution 版本)采集 Core Web Vitals:\n * CLS / FCP / INP / LCP / TTFB\n *\n * Span 使用大写 vital.metric 命名,并带 vital.id(唯一)、vital.value 与 attribution 详情\n * (LCP 元素 url / CLS shift target / INP interaction target 等高基数字段),\n * 方便按个例排查\"哪个元素拖累了 LCP\"\n *\n * 数值语义:CLS 是无量纲分数,FCP/INP/LCP/TTFB 的 vital.value 单位为 ms。\n *\n * View 边界:FCP/LCP/TTFB 使用 web-vitals 的条目时间回查历史 View;CLS/INP 按 SDK View 重置,\n * CLS 使用 session window,INP 使用当前 View 的 p98 交互候选。\n *\n * 生命周期保护:\n * - disposed 标志位:shutdown 后所有回调入口 early return,避免向已销毁的 provider 上报\n * - dynamic import 完成后再次检查 disposed:处理\"start() 完成前 shutdown()\"的 race\n * - dynamic import 自身 try/catch:与 PluginManager 的 per-plugin 隔离形成纵深防御,\n * 即使加载失败也不影响整体启动\n */\n\nimport { type Attributes } from '@opentelemetry/api';\n\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, getVitalOutcome, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type * as WebVitalsAttribution from 'web-vitals/attribution';\nimport type { MetricWithAttribution } from 'web-vitals/attribution';\n\ninterface EventTimingEntry extends PerformanceEntry {\n interactionId?: number;\n processingEnd?: number;\n processingStart?: number;\n target?: EventTarget | null;\n}\n\ninterface InpCandidate {\n duration: number;\n inputDelay: number;\n interactionId: number;\n interactionTarget?: string;\n interactionType: string;\n presentationDelay: number;\n processingDuration: number;\n}\n\ninterface LayoutShiftEntry extends PerformanceEntry {\n hadRecentInput?: boolean;\n value?: number;\n}\n\ninterface ViewVitalState {\n cls: number;\n clsWindowEnd?: number;\n clsWindowStart?: number;\n clsWindowValue: number;\n id: string;\n inpCandidates: InpCandidate[];\n interactionCountAtStart?: number;\n interactionIdMax: number;\n interactionIdMin: number;\n runtimeAttributes: Attributes;\n startedAt: number;\n}\n\ntype VitalLike = Pick<MetricWithAttribution, 'attribution' | 'entries' | 'id' | 'name' | 'rating' | 'value'>;\n\nconst MAX_INP_CANDIDATES = 10;\nconst MAX_INP_VALUE = 60_000;\nconst MAX_CLS_WINDOW_DURATION = 5_000;\nconst MAX_CLS_UPDATE_GAP = 1_000;\n\nexport const isSameViewId = (currentViewId: string | undefined, nextViewId: string | undefined) =>\n Boolean(nextViewId) && currentViewId === nextViewId;\n\nconst getRating = (name: 'CLS' | 'INP', value: number): VitalLike['rating'] => {\n const [good, poor] = name === 'CLS' ? [0.1, 0.25] : [200, 500];\n return value <= good ? 'good' : value <= poor ? 'needs-improvement' : 'poor';\n};\n\nconst getTargetName = (target: EventTarget | Node | null | undefined) => {\n if (typeof Element === 'undefined' || !(target instanceof Element)) return undefined;\n return (\n target.getAttribute('data-bk-action-name') ??\n target.getAttribute('aria-label') ??\n target.getAttribute('name') ??\n target.tagName.toLowerCase()\n );\n};\n\nconst getInteractionCount = () => {\n if (typeof performance === 'undefined') return undefined;\n const value = (performance as Performance & { interactionCount?: number }).interactionCount;\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n};\n\nexport const updateViewCls = (view: ViewVitalState, entry: LayoutShiftEntry) => {\n const value = entry.value ?? 0;\n if (entry.hadRecentInput || !Number.isFinite(value)) return;\n const shouldCreateWindow =\n view.clsWindowStart === undefined ||\n entry.startTime - (view.clsWindowEnd ?? entry.startTime) >= MAX_CLS_UPDATE_GAP ||\n entry.startTime - view.clsWindowStart >= MAX_CLS_WINDOW_DURATION;\n if (shouldCreateWindow) {\n view.clsWindowStart = entry.startTime;\n view.clsWindowValue = value;\n } else {\n view.clsWindowValue += value;\n }\n view.clsWindowEnd = entry.startTime;\n if (view.clsWindowValue > view.cls) {\n view.cls = Math.round(view.clsWindowValue * 10_000) / 10_000;\n }\n};\n\nexport const updateViewInp = (view: ViewVitalState, entry: EventTimingEntry) => {\n if (!entry.interactionId || !Number.isFinite(entry.duration)) return;\n view.interactionIdMin = Math.min(view.interactionIdMin, entry.interactionId);\n view.interactionIdMax = Math.max(view.interactionIdMax, entry.interactionId);\n const processingStart = entry.processingStart ?? entry.startTime;\n const processingEnd = entry.processingEnd ?? processingStart;\n const candidate: InpCandidate = {\n duration: Math.min(entry.duration, MAX_INP_VALUE),\n inputDelay: Math.max(0, processingStart - entry.startTime),\n interactionId: entry.interactionId,\n interactionTarget: getTargetName(entry.target),\n interactionType: entry.name,\n presentationDelay: Math.max(0, entry.startTime + entry.duration - processingEnd),\n processingDuration: Math.max(0, processingEnd - processingStart),\n };\n const index = view.inpCandidates.findIndex(item => item.interactionId === entry.interactionId);\n if (index >= 0) {\n if (candidate.duration > view.inpCandidates[index].duration) view.inpCandidates[index] = candidate;\n } else {\n view.inpCandidates.push(candidate);\n }\n view.inpCandidates.sort((left, right) => right.duration - left.duration).splice(MAX_INP_CANDIDATES);\n};\n\nexport const getViewInp = (view: ViewVitalState): InpCandidate | undefined => {\n const nativeCount = getInteractionCount();\n const interactionCount =\n nativeCount !== undefined && view.interactionCountAtStart !== undefined\n ? Math.max(0, nativeCount - view.interactionCountAtStart)\n : view.interactionIdMin === Infinity\n ? 0\n : (view.interactionIdMax - view.interactionIdMin) / 7 + 1;\n if (!view.inpCandidates.length) return undefined;\n return view.inpCandidates[Math.min(view.inpCandidates.length - 1, Math.floor(interactionCount / 50))];\n};\n\n// 把 attribution 中价值最高的字段抽出来写入 Span。\nconst pickAttribution = (metric: VitalLike, redactUrl: (url: string) => string): Attributes => {\n const attr = metric.attribution ?? {};\n const result: Attributes = {};\n const getAttrValue = (key: string) => (attr as Record<string, unknown>)[key];\n\n const setIfDefined = (key: string, value: unknown, transform?: (value: string) => string) => {\n if (value === undefined || value === null) return;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n result[key] = typeof value === 'string' && transform ? transform(value) : value;\n }\n };\n\n switch (metric.name) {\n case 'LCP':\n setIfDefined('vital.lcp.url', getAttrValue('url'), redactUrl);\n setIfDefined('vital.lcp.target', getAttrValue('target'));\n setIfDefined('vital.lcp.element_render_delay', getAttrValue('elementRenderDelay'));\n setIfDefined('vital.lcp.resource_load_duration', getAttrValue('resourceLoadDuration'));\n break;\n case 'CLS':\n setIfDefined('vital.cls.load_state', getAttrValue('loadState'));\n break;\n case 'INP':\n setIfDefined('vital.inp.interaction_target', getAttrValue('interactionTarget'));\n setIfDefined('vital.inp.interaction_type', getAttrValue('interactionType'));\n setIfDefined('vital.inp.input_delay', getAttrValue('inputDelay'));\n setIfDefined('vital.inp.processing_duration', getAttrValue('processingDuration'));\n setIfDefined('vital.inp.presentation_delay', getAttrValue('presentationDelay'));\n break;\n case 'TTFB':\n setIfDefined('vital.ttfb.waiting_duration', getAttrValue('waitingDuration'));\n setIfDefined('vital.ttfb.dns_duration', getAttrValue('dnsDuration'));\n setIfDefined('vital.ttfb.connection_duration', getAttrValue('connectionDuration'));\n setIfDefined('vital.ttfb.request_duration', getAttrValue('requestDuration'));\n break;\n default:\n break;\n }\n return result;\n};\n\nexport const createWebVitalsPlugin = (): BkOTPlugin => {\n let cleanup: (() => void) | undefined;\n let disposed = false;\n\n return {\n name: 'web-vitals',\n async init(context) {\n if (typeof window === 'undefined') {\n return;\n }\n\n // dynamic import 自包 try/catch:与 PluginManager 的 per-plugin 隔离形成纵深防御,\n // 离线 / chunk 加载失败时不影响其他插件,且 debug 模式留下排查痕迹\n let webVitalsModule: typeof WebVitalsAttribution;\n try {\n webVitalsModule = await import('web-vitals/attribution');\n } catch (error) {\n if (context.config.debug) {\n globalThis.console?.warn('[bk-ot] web-vitals load failed:', error);\n }\n return;\n }\n // import 期间用户可能已经 shutdown:此后再注册回调会向已销毁 provider 上报\n if (disposed) return;\n\n const { onFCP, onLCP, onTTFB } = webVitalsModule;\n const recordSpan = (\n metric: VitalLike,\n runtimeAttributes: Attributes,\n contextTime?: number,\n occurredAt = contextTime ?? Date.now(),\n ) => {\n if (!context.isSampled()) return;\n const metricName = metric.name.toLowerCase();\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...runtimeAttributes,\n ...buildRumSpanAttributes({\n outcome: getVitalOutcome(metric.rating),\n spanType: RUM_SPAN_TYPE.vital,\n }),\n [RUM_ATTRIBUTES.vitalMetric]: metricName,\n [RUM_ATTRIBUTES.vitalValue]: metric.value,\n 'vital.id': metric.id,\n ...pickAttribution(metric, context.config.hooks.redactUrl),\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.vital }), attributes, {\n contextTime,\n startTime: occurredAt,\n });\n span.end(occurredAt);\n };\n\n const recordDurationVital = (metric: VitalLike) => {\n // 防御非法值:极端浏览器实现 bug 可能给出 NaN/Infinity,OT 后端会拒收\n if (disposed || !Number.isFinite(metric.value) || !context.isSampled()) return;\n const firstEntry = metric.entries[0];\n const contextTime =\n firstEntry && typeof performance !== 'undefined' ? performance.timeOrigin + firstEntry.startTime : undefined;\n const runtimeAttributes =\n contextTime === undefined ? context.getRuntimeAttributes() : context.getRuntimeAttributesAt(contextTime);\n recordSpan(metric, runtimeAttributes, contextTime);\n };\n\n let currentView: undefined | ViewVitalState;\n let eventObserver: PerformanceObserver | undefined;\n let layoutShiftObserver: PerformanceObserver | undefined;\n\n const recordViewVital = (metric: VitalLike, runtimeAttributes: Attributes, contextTime: number) => {\n recordSpan(metric, runtimeAttributes, contextTime, Date.now());\n };\n\n const finalizeView = () => {\n const view = currentView;\n if (!view || !context.isSampled()) return;\n recordViewVital(\n {\n attribution: {},\n entries: [],\n id: createRandomId('vital'),\n name: 'CLS',\n rating: getRating('CLS', view.cls),\n value: view.cls,\n } as VitalLike,\n view.runtimeAttributes,\n view.startedAt,\n );\n const inp = getViewInp(view);\n if (inp) {\n recordViewVital(\n {\n attribution: {\n inputDelay: inp.inputDelay,\n interactionTarget: inp.interactionTarget,\n interactionType: inp.interactionType,\n presentationDelay: inp.presentationDelay,\n processingDuration: inp.processingDuration,\n },\n entries: [],\n id: createRandomId('vital'),\n name: 'INP',\n rating: getRating('INP', inp.duration),\n value: inp.duration,\n } as VitalLike,\n view.runtimeAttributes,\n view.startedAt,\n );\n }\n };\n\n const unsubscribeView = context.onViewChange(view => {\n const activeVitalView = currentView;\n if (activeVitalView && isSameViewId(activeVitalView.id, view.id)) {\n activeVitalView.runtimeAttributes = {\n ...activeVitalView.runtimeAttributes,\n [RUM_ATTRIBUTES.viewId]: view.id,\n ...(view.name ? { [RUM_ATTRIBUTES.viewName]: view.name } : {}),\n [RUM_ATTRIBUTES.viewUrl]: view.url,\n [RUM_ATTRIBUTES.viewUrlTemplate]: view.urlTemplate,\n };\n return;\n }\n finalizeView();\n currentView = view.id\n ? {\n cls: 0,\n clsWindowValue: 0,\n interactionCountAtStart: getInteractionCount(),\n interactionIdMax: 0,\n interactionIdMin: Infinity,\n inpCandidates: [],\n id: view.id,\n runtimeAttributes: context.getRuntimeAttributes(),\n startedAt: view.startedAt ?? Date.now(),\n }\n : undefined;\n });\n\n if (typeof PerformanceObserver !== 'undefined') {\n if (PerformanceObserver.supportedEntryTypes?.includes('layout-shift')) {\n layoutShiftObserver = new PerformanceObserver(list => {\n if (!currentView) return;\n for (const entry of list.getEntries() as LayoutShiftEntry[]) {\n const startedAt = performance.timeOrigin + entry.startTime;\n if (startedAt < currentView.startedAt) continue;\n updateViewCls(currentView, entry);\n }\n });\n layoutShiftObserver.observe({ buffered: true, type: 'layout-shift' });\n }\n if (PerformanceObserver.supportedEntryTypes?.includes('event')) {\n eventObserver = new PerformanceObserver(list => {\n if (!currentView) return;\n for (const entry of list.getEntries() as EventTimingEntry[]) {\n const startedAt = performance.timeOrigin + entry.startTime;\n if (startedAt < currentView.startedAt || !entry.interactionId || !Number.isFinite(entry.duration))\n continue;\n updateViewInp(currentView, entry);\n }\n });\n eventObserver.observe({ buffered: true, durationThreshold: 40, type: 'event' });\n }\n }\n onFCP(recordDurationVital);\n onLCP(recordDurationVital);\n onTTFB(recordDurationVital);\n\n cleanup = () => {\n finalizeView();\n currentView = undefined;\n unsubscribeView();\n layoutShiftObserver?.disconnect();\n eventObserver?.disconnect();\n };\n },\n shutdown() {\n // web-vitals 的 onXXX 不返回 unsubscribe,无法真正取消订阅;\n // 用 disposed 标志位让回调入口 early return 即可\n disposed = true;\n cleanup?.();\n cleanup = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { SpanKind } from '@opentelemetry/api';\n\nimport { createRandomId } from '../core/id';\nimport { shouldIgnoreUrl } from '../core/url';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\nconst buildWebSocketAttributes = (url: string, redactUrl: (url: string) => string): Attributes => {\n const attributes: Attributes = {\n 'network.protocol.name': 'websocket',\n 'url.full': redactUrl(url),\n };\n try {\n const parsed = new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n attributes['server.address'] = parsed.hostname;\n if (parsed.port) attributes['server.port'] = Number(parsed.port);\n attributes['url.scheme'] = parsed.protocol.replace(':', '');\n } catch {\n // 非法 URL 仍保留脱敏后的原始字符串。\n }\n return attributes;\n};\n\nconst instrumentSocket = (socket: WebSocket, context: BkOTRuntimeContext, url: string, isDisposed: () => boolean) => {\n const connectionId = createRandomId('websocket');\n const baseAttributes = buildWebSocketAttributes(url, context.config.hooks.redactUrl);\n let opened = false;\n\n const emit = (phase: 'close' | 'connect' | 'error' | 'open', timestamp: number, attributes: Attributes = {}) => {\n if (isDisposed() || !context.isSampled()) return;\n const isError = phase === 'error';\n const spanAttributes = {\n ...baseAttributes,\n ...buildRumSpanAttributes({\n outcome: isError ? RUM_SPAN_OUTCOME.error : RUM_SPAN_OUTCOME.success,\n spanType: RUM_SPAN_TYPE.websocket,\n }),\n [RUM_ATTRIBUTES.websocketPhase]: phase,\n 'websocket.connection.id': connectionId,\n ...attributes,\n };\n const span = context.startSpan(\n buildRumSpanName({ attributes: spanAttributes, spanType: RUM_SPAN_TYPE.websocket }),\n spanAttributes,\n { kind: SpanKind.CLIENT, startTime: timestamp },\n );\n span.end(timestamp);\n };\n\n emit('connect', Date.now());\n socket.addEventListener('open', () => {\n opened = true;\n emit('open', Date.now());\n });\n socket.addEventListener('error', () => {\n emit('error', Date.now(), { 'websocket.error.phase': opened ? 'runtime' : 'connect' });\n });\n socket.addEventListener('close', event => {\n emit('close', Date.now(), {\n 'websocket.close.code': event.code,\n 'websocket.close.reason': event.reason,\n 'websocket.close.was_clean': event.wasClean,\n });\n });\n};\n\nexport const createWebSocketPlugin = (): BkOTPlugin => {\n let originalWebSocket: typeof WebSocket | undefined;\n let patchedProxy: typeof WebSocket | undefined;\n let disposed = false;\n\n return {\n name: 'websocket',\n init(context) {\n if (typeof window === 'undefined' || typeof window.WebSocket === 'undefined') return;\n const nativeWebSocket = window.WebSocket;\n originalWebSocket = nativeWebSocket;\n patchedProxy = new Proxy(nativeWebSocket, {\n construct(target, args, newTarget) {\n const socket = Reflect.construct(target, args, newTarget) as WebSocket;\n if (disposed || !context.isSampled()) return socket;\n const url = args[0] == null ? '' : String(args[0]);\n if (url && !shouldIgnoreUrl(context.config, url)) {\n instrumentSocket(socket, context, url, () => disposed);\n }\n return socket;\n },\n });\n window.WebSocket = patchedProxy;\n },\n shutdown() {\n disposed = true;\n if (typeof window !== 'undefined' && originalWebSocket && window.WebSocket === patchedProxy) {\n window.WebSocket = originalWebSocket;\n }\n patchedProxy = undefined;\n originalWebSocket = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nexport type BkOTActivityEvent =\n | { endTime: number; startTime: number; type: 'long_task'; url?: never }\n | { endTime: number; startTime: number; type: 'resource'; url?: string }\n | { id: string; time: number; type: 'request_end' }\n | { id: string; time: number; type: 'request_start'; url?: string }\n | { time: number; type: 'dom_mutation' | 'error' | 'window_open' };\n\nexport class RumActivityObserver {\n private readonly listeners = new Set<(event: BkOTActivityEvent) => void>();\n\n public notify = (event: BkOTActivityEvent) => {\n this.listeners.forEach(listener => listener(event));\n };\n\n public subscribe = (listener: (event: BkOTActivityEvent) => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { ResolvedBkOTConfig } from './config';\n\nconst hashToUnitInterval = (input: string) => {\n let hash = 0x811c9dc5;\n for (let index = 0; index < input.length; index += 1) {\n hash = Math.imul(hash ^ input.charCodeAt(index), 0x01000193);\n }\n hash += hash << 13;\n hash ^= hash >>> 7;\n hash += hash << 3;\n hash ^= hash >>> 17;\n hash += hash << 5;\n return (hash >>> 0) / 0x100000000;\n};\n\n/**\n * 按应用和 RUM Session ID 做确定性采样。采样决定随 Session 更新,不再依赖 Tab 级 sessionStorage。\n */\nexport const isBkOTSampled = (\n { application, session }: Pick<ResolvedBkOTConfig, 'application' | 'session'>,\n sessionId: string,\n) => {\n if (session.sampleRate <= 0) {\n return false;\n }\n if (session.sampleRate >= 1) {\n return true;\n }\n return hashToUnitInterval(`${application.name}\\0${sessionId}`) < session.sampleRate;\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { type Attributes, type Span, context, propagation, SpanKind, SpanStatusCode } from '@opentelemetry/api';\nimport { ZoneContextManager } from '@opentelemetry/context-zone';\nimport { W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { BatchSpanProcessor, SamplingDecision, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { WebTracerProvider } from '@opentelemetry/sdk-trace-web';\n\nimport { createActionPlugin } from '../plugins/action';\nimport { createActivityPlugin } from '../plugins/activity';\nimport { createBlankScreenPlugin } from '../plugins/blank-screen';\nimport { createCommonInstrumentationsPlugin } from '../plugins/common';\nimport { createCspViolationPlugin } from '../plugins/csp-violation';\nimport { createDevicePlugin } from '../plugins/device';\nimport { createErrorPlugin } from '../plugins/error';\nimport { createLongTaskPlugin } from '../plugins/long-task';\nimport { createPageViewPlugin } from '../plugins/page-view';\nimport { createResourcePlugin } from '../plugins/resource';\nimport { createSessionPlugin } from '../plugins/session';\nimport { createWebVitalsPlugin } from '../plugins/web-vitals';\nimport { createWebSocketPlugin } from '../plugins/websocket';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\nimport { RumActivityObserver } from './action-activity';\nimport {\n type BkOTActionEventPayload,\n type BkOTCustomEventPayload,\n type BkOTOptions,\n type BkOTTrackingConfig,\n type BkOTTrackingConsent,\n type ResolvedBkOTConfig,\n type ResolvedTransportConfig,\n resolveConfig,\n} from './config';\nimport { createRandomId } from './id';\nimport { type BkOTPlugin, type BkOTRuntimeContext, type BkOTStartSpanOptions, PluginManager } from './plugin';\nimport { FilteringSpanProcessor } from './processor';\nimport {\n type BkOTSessionLifecycleEvent,\n type BkOTStartViewOptions,\n type BkOTUserContext,\n RumRuntimeContext,\n} from './runtime-context';\nimport { isBkOTSampled } from './sampling';\n\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport type { Sampler } from '@opentelemetry/sdk-trace-base';\n\nexport interface BkOTInstance extends Omit<\n BkOTRuntimeContext,\n 'notifyActivity' | 'onActivity' | 'onViewChange' | 'onViewCommand' | 'registerInstrumentations' | 'setView'\n> {\n flush: () => Promise<void>;\n reportAction: (payload: BkOTActionEventPayload) => void;\n reportCustomEvent: (payload: BkOTCustomEventPayload) => void;\n setTrackingConsent: (consent: BkOTTrackingConsent) => Promise<void>;\n setUser: (user: BkOTUserContext) => void;\n setViewLoadingTime: () => void;\n setViewName: (name: string) => void;\n shutdown: () => Promise<void>;\n start: () => Promise<void>;\n startView: (options?: BkOTStartViewOptions) => void;\n use: (plugin: BkOTPlugin) => BkOTInstance;\n useInstrumentation: (instrumentation: Instrumentation) => BkOTInstance;\n}\n\nconst createExporterOptions = (config: ResolvedTransportConfig) => ({\n url: config.endpoint,\n headers: config.headers,\n concurrencyLimit: config.concurrencyLimit,\n timeoutMillis: config.timeoutMillis,\n});\n\nconst BK_OT_INSTRUMENTATION_NAME = 'bk-rum';\n\nclass RumSessionSampler implements Sampler {\n public constructor(private readonly isSampled: () => boolean) {}\n\n public shouldSample() {\n return {\n decision: this.isSampled() ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,\n };\n }\n\n public toString() {\n return 'RumSessionSampler';\n }\n}\n\n// OTel context manager 和 propagator 是页面级全局对象,多 SDK 实例通过引用计数共享,最后一个实例退出时释放。\nlet globalRegistration:\n | undefined\n | {\n contextManager?: ZoneContextManager;\n ownsContext: boolean;\n ownsPropagator: boolean;\n users: number;\n };\n\nconst acquireOtelGlobals = () => {\n if (globalRegistration) {\n globalRegistration.users += 1;\n } else {\n const contextManager = new ZoneContextManager().enable();\n const ownsContext = context.setGlobalContextManager(contextManager);\n if (!ownsContext) contextManager.disable();\n globalRegistration = {\n contextManager: ownsContext ? contextManager : undefined,\n ownsContext,\n ownsPropagator: propagation.setGlobalPropagator(new W3CTraceContextPropagator()),\n users: 1,\n };\n }\n let released = false;\n return () => {\n if (released || !globalRegistration) return;\n released = true;\n globalRegistration.users -= 1;\n if (globalRegistration.users > 0) return;\n if (globalRegistration.ownsContext) context.disable();\n if (globalRegistration.ownsPropagator) propagation.disable();\n globalRegistration = undefined;\n };\n};\n\n/**\n * 用 Proxy 包装一层 debug 旁路,避免直接 mutate 第三方 exporter 实例(其内部可能含 #private fields)。\n */\nconst wrapWithDebug = <TExporter extends { export: (...args: any[]) => any }>(\n exporter: TExporter,\n enabled: boolean,\n): TExporter => {\n if (!enabled) {\n return exporter;\n }\n return new Proxy(exporter, {\n get(target, prop, receiver) {\n if (prop === 'export') {\n return (records: unknown, callback: unknown) => {\n globalThis.console?.log('[bk-ot][rum]', records);\n return (target as { export: (...args: unknown[]) => unknown }).export(records, callback);\n };\n }\n const value = Reflect.get(target, prop, receiver);\n return typeof value === 'function' ? value.bind(target) : value;\n },\n });\n};\n\n// 请求插件统一负责 Fetch/XHR span、Trace Header 与活动计数。\nconst getCorePlugins = (config: ResolvedBkOTConfig): BkOTPlugin[] => [\n createCommonInstrumentationsPlugin(config.tracking.request),\n];\n\nconst getRumContextPlugins = (config: ResolvedBkOTConfig): BkOTPlugin[] => [\n createSessionPlugin(config.session),\n ...createBuiltInPlugin(config.tracking.device, true, createDevicePlugin),\n createActivityPlugin(),\n createPageViewPlugin(),\n createResourcePlugin(isBuiltInPluginEnabled(config.tracking.resource, true)),\n];\n\nconst isBuiltInPluginEnabled = <TOptions extends object>(\n option: boolean | TOptions | undefined,\n defaultEnabled: boolean,\n) => (option === undefined ? defaultEnabled : option !== false);\n\nconst getBuiltInPluginOptions = <TOptions extends object>(option: boolean | TOptions | undefined) =>\n typeof option === 'object' && option !== null ? option : undefined;\n\nconst createBuiltInPlugin = <TOptions extends object>(\n option: boolean | TOptions | undefined,\n defaultEnabled: boolean,\n factory: (options?: TOptions) => BkOTPlugin,\n) => (isBuiltInPluginEnabled(option, defaultEnabled) ? [factory(getBuiltInPluginOptions(option))] : []);\n\n// 上下文插件先启动,确保后续 span 能带上关联字段;Session sampler 与 processor 负责统一采样。\nconst getRumPlugins = (tracking: BkOTTrackingConfig): BkOTPlugin[] => [\n ...createBuiltInPlugin(tracking.error, true, createErrorPlugin),\n ...createBuiltInPlugin(tracking.webVitals, true, createWebVitalsPlugin),\n ...createBuiltInPlugin(tracking.blankScreen, true, createBlankScreenPlugin),\n ...createBuiltInPlugin(tracking.action, true, createActionPlugin),\n ...createBuiltInPlugin(tracking.websocket, false, createWebSocketPlugin),\n ...createBuiltInPlugin(tracking.longTask, false, createLongTaskPlugin),\n ...createBuiltInPlugin(tracking.cspViolation, false, createCspViolationPlugin),\n];\n\ntype SdkLifecyclePhase = 'idle' | 'started' | 'starting' | 'stopped';\n\n/**\n * 浏览器 RUM SDK 的生命周期入口。Provider 在构造时创建,插件和全局 patch 则随 start、授权变更和\n * shutdown 安装或卸载;Session 决定统一作用于所有 RUM span。\n */\nexport class BkOpenTelemetry implements BkOTInstance {\n private readonly activityObserver = new RumActivityObserver();\n private readonly flushProviders = async () => {\n await this.tracerProvider.forceFlush();\n };\n private phase: SdkLifecyclePhase = 'idle';\n private pluginManager?: PluginManager;\n private readonly registeredInstrumentations: Instrumentation[];\n private releaseOtelGlobals?: () => void;\n private readonly runtimeContext: RumRuntimeContext;\n\n private sampled = false;\n private readonly startCollection = async () => {\n // Provider 始终存在以保持公开 API 稳定;采集插件仅在启用且获得授权后安装。\n if (this.pluginManager || !this.config.enabled || this.config.trackingConsent !== 'granted') return;\n this.releaseOtelGlobals = acquireOtelGlobals();\n const pluginManager = this.createPluginManager();\n this.pluginManager = pluginManager;\n try {\n await pluginManager.start(this.createPluginContext());\n this.registerInstrumentations(this.config.extensions.instrumentations ?? []);\n } catch (error) {\n await pluginManager.shutdown();\n this.pluginManager = undefined;\n while (this.registeredInstrumentations.length) this.registeredInstrumentations.pop()?.disable?.();\n this.releaseOtelGlobals?.();\n this.releaseOtelGlobals = undefined;\n throw error;\n }\n };\n private readonly stopCollection = async (flush: boolean) => {\n const pluginManager = this.pluginManager;\n if (!pluginManager) return;\n await pluginManager.shutdown();\n this.pluginManager = undefined;\n while (this.registeredInstrumentations.length) this.registeredInstrumentations.pop()?.disable?.();\n // 撤销授权后立即清空 Session,防止后续手工 API 继续复用旧采样决定。\n this.setRuntimeAttributes({\n [RUM_ATTRIBUTES.sessionHasReplay]: undefined,\n [RUM_ATTRIBUTES.sessionId]: undefined,\n });\n if (flush) await this.flushProviders();\n this.releaseOtelGlobals?.();\n this.releaseOtelGlobals = undefined;\n };\n private readonly teardownCallbacks: Array<() => void> = [];\n private readonly tracerProvider: WebTracerProvider;\n private assertBeforeStart(method: string) {\n if (this.phase !== 'idle') {\n throw new Error(`[bk-ot] ${method}() must be called before start(); set autoStart: false before registration.`);\n }\n }\n private createPluginContext(): BkOTRuntimeContext {\n return {\n applyRedact: this.applyRedact,\n config: this.config,\n flush: this.flush,\n getRuntimeAttributes: this.getRuntimeAttributes,\n getRuntimeAttributesAt: this.getRuntimeAttributesAt,\n isSampled: this.isSampled,\n isSessionActive: this.isSessionActive,\n isViewActive: this.isViewActive,\n notifySessionLifecycle: this.notifySessionLifecycle,\n notifyActivity: this.activityObserver.notify,\n onActivity: this.activityObserver.subscribe,\n onSessionLifecycle: this.onSessionLifecycle,\n onViewCommand: this.runtimeContext.onViewCommand,\n onViewChange: this.runtimeContext.onViewChange,\n registerInstrumentations: this.registerInstrumentations,\n setRuntimeAttributes: this.setRuntimeAttributes,\n setUser: this.setUser,\n setView: this.runtimeContext.setView,\n startSpan: this.startSpan,\n tracer: this.tracer,\n };\n }\n private createPluginManager() {\n return new PluginManager([\n ...getRumContextPlugins(this.config),\n ...getCorePlugins(this.config),\n ...getRumPlugins(this.config.tracking),\n ...(this.config.extensions.plugins ?? []),\n ]);\n }\n public readonly applyRedact = (attributes: Attributes) => this.config.hooks.redactAttributes(attributes);\n\n public readonly config: ResolvedBkOTConfig;\n\n public readonly flush = async () => {\n await this.pluginManager?.flush();\n await this.flushProviders();\n };\n\n public readonly getRuntimeAttributes = () => this.runtimeContext.getAttributes();\n public readonly getRuntimeAttributesAt = (timestamp: number) => this.runtimeContext.getAttributesAt(timestamp);\n public readonly isSampled = () => this.sampled;\n public readonly isSessionActive = () => this.runtimeContext.isSessionActive();\n public readonly isViewActive = () => this.runtimeContext.isViewActive();\n public readonly notifySessionLifecycle = (event: BkOTSessionLifecycleEvent) => {\n this.runtimeContext.notifySessionLifecycle(event);\n };\n\n public readonly onSessionLifecycle = (listener: (event: BkOTSessionLifecycleEvent) => void) =>\n this.runtimeContext.onSessionLifecycle(listener);\n\n public readonly registerInstrumentations = (instrumentations: Instrumentation[]) => {\n if (!instrumentations.length) return;\n instrumentations.forEach(instrumentation => {\n instrumentation.setTracerProvider(this.tracerProvider);\n if (!instrumentation.getConfig().enabled) instrumentation.enable();\n });\n this.registeredInstrumentations.push(...instrumentations);\n };\n\n public readonly reportAction = ({ attributes = {}, name }: BkOTActionEventPayload) => {\n if (!this.isSampled()) {\n return;\n }\n const actionId = createRandomId('action');\n const occurredAt = Date.now();\n const spanAttributes = {\n ...this.config.hooks.getPageAttributes(),\n ...attributes,\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.action,\n }),\n [RUM_ATTRIBUTES.actionId]: actionId,\n [RUM_ATTRIBUTES.actionName]: name,\n [RUM_ATTRIBUTES.actionType]: 'custom',\n };\n const span = this.startSpan(\n buildRumSpanName({ attributes: spanAttributes, spanType: RUM_SPAN_TYPE.action }),\n spanAttributes,\n { rumSpanType: RUM_SPAN_TYPE.action, startTime: occurredAt },\n );\n span.end(occurredAt);\n };\n\n public readonly reportCustomEvent = ({ attributes = {}, error, name }: BkOTCustomEventPayload) => {\n if (!this.isSampled()) {\n // 未采样时静默丢弃;如需调试请把 debug 选项打开\n if (this.config.debug) {\n globalThis.console?.warn('[bk-ot] custom event dropped (not sampled):', name);\n }\n return;\n }\n\n const occurredAt = Date.now();\n const spanAttributes = {\n ...this.config.hooks.getPageAttributes(),\n ...this.config.hooks.getCustomAttributes(),\n ...attributes,\n ...buildRumSpanAttributes({\n outcome: error ? RUM_SPAN_OUTCOME.error : RUM_SPAN_OUTCOME.success,\n spanType: RUM_SPAN_TYPE.custom,\n }),\n };\n const span = this.startSpan(\n buildRumSpanName({ attributes: spanAttributes, nameHint: name, spanType: RUM_SPAN_TYPE.custom }),\n spanAttributes,\n { startTime: occurredAt },\n );\n\n if (error) {\n span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n }\n\n span.end(occurredAt);\n };\n\n public readonly setRuntimeAttributes = (attributes: Attributes, changedAt?: number) => {\n const nextAttributes = { ...attributes };\n const effectiveChangedAt = changedAt ?? Date.now();\n if (RUM_ATTRIBUTES.sessionId in attributes) {\n // 采样以 Session 为边界重新计算,并保存在运行时私有历史中。\n const sessionId = attributes[RUM_ATTRIBUTES.sessionId];\n this.sampled =\n this.config.enabled && typeof sessionId === 'string' && sessionId.length > 0\n ? isBkOTSampled(this.config, sessionId)\n : false;\n this.runtimeContext.setSessionSampled(this.sampled, effectiveChangedAt);\n }\n this.runtimeContext.setAttributes(nextAttributes, effectiveChangedAt);\n };\n\n public readonly setTrackingConsent = async (consent: BkOTTrackingConsent) => {\n if (this.config.trackingConsent === consent) return;\n this.config.trackingConsent = consent;\n if (this.phase !== 'started') return;\n if (consent === 'granted') await this.startCollection();\n else await this.stopCollection(true);\n };\n\n public readonly setUser = (user: BkOTUserContext) => {\n this.runtimeContext.setUser(user);\n };\n\n public readonly setViewLoadingTime = () => {\n if (this.isSampled()) this.runtimeContext.dispatchViewCommand({ time: Date.now(), type: 'set_loading_time' });\n };\n\n public readonly setViewName = (name: string) => {\n if (this.isSampled()) this.runtimeContext.dispatchViewCommand({ name, type: 'set_name' });\n };\n\n public readonly shutdown = async () => {\n if (this.phase === 'stopped') {\n return;\n }\n await this.stopCollection(false);\n await this.flushProviders();\n while (this.teardownCallbacks.length) {\n this.teardownCallbacks.pop()?.();\n }\n await this.tracerProvider.shutdown();\n this.phase = 'stopped';\n };\n\n public readonly start = async () => {\n if (this.phase === 'started' || this.phase === 'starting') {\n return;\n }\n if (this.phase === 'stopped') {\n // shutdown 已经销毁了 provider/processor,此处禁止再次启动\n throw new Error('[bk-ot] instance has been shut down and cannot be restarted; create a new instance instead.');\n }\n if (!this.config.enabled) {\n this.phase = 'started';\n return;\n }\n this.phase = 'starting';\n try {\n await this.startCollection();\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // 页面进入后台或被丢弃前尽力导出批量数据;两个事件并存以覆盖不同浏览器生命周期。\n const flushOnPageHide = () => {\n void this.flush();\n };\n const flushOnHidden = () => {\n if (document.visibilityState === 'hidden') {\n void this.flush();\n }\n };\n window.addEventListener('pagehide', flushOnPageHide);\n document.addEventListener('visibilitychange', flushOnHidden);\n this.teardownCallbacks.push(\n () => window.removeEventListener('pagehide', flushOnPageHide),\n () => document.removeEventListener('visibilitychange', flushOnHidden),\n );\n }\n } catch (error) {\n while (this.teardownCallbacks.length) {\n this.teardownCallbacks.pop()?.();\n }\n await this.stopCollection(false);\n this.phase = 'idle';\n throw error;\n }\n this.phase = 'started';\n };\n\n public readonly startSpan = (name: string, attributes: Attributes = {}, options?: BkOTStartSpanOptions): Span => {\n const contextTime =\n options?.contextTime ?? (typeof options?.startTime === 'number' ? options.startTime : undefined);\n // 返回 provider 创建的 non-recording span,而不是让每个调用方处理 undefined。\n if (!this.isSampled() || (contextTime !== undefined && !this.runtimeContext.isSessionSampledAt(contextTime))) {\n return this.tracer.startSpan(name);\n }\n const runtimeAttributes =\n contextTime === undefined ? this.getRuntimeAttributes() : this.runtimeContext.getAttributesAt(contextTime);\n const redactedAttributes = this.applyRedact({ ...runtimeAttributes, ...attributes });\n const spanName = options?.rumSpanType\n ? buildRumSpanName({ attributes: redactedAttributes, spanType: options.rumSpanType })\n : name;\n return this.tracer.startSpan(spanName, {\n kind: options?.kind ?? SpanKind.INTERNAL,\n links: options?.links,\n startTime: options?.startTime,\n attributes: redactedAttributes,\n });\n };\n\n public readonly startView = (options: BkOTStartViewOptions = {}) => {\n if (this.isSampled()) this.runtimeContext.dispatchViewCommand({ options, type: 'start' });\n };\n\n public readonly tracer: BkOTRuntimeContext['tracer'];\n\n public readonly use = (plugin: BkOTPlugin): this => {\n this.assertBeforeStart('use');\n this.config.extensions.plugins?.push(plugin);\n return this;\n };\n\n public readonly useInstrumentation = (instrumentation: Instrumentation): this => {\n this.assertBeforeStart('useInstrumentation');\n if (this.config.enabled) this.config.extensions.instrumentations?.push(instrumentation);\n return this;\n };\n\n constructor(inputConfig: BkOTOptions) {\n this.config = resolveConfig(inputConfig);\n this.runtimeContext = new RumRuntimeContext({}, this.config.user);\n\n const resource = resourceFromAttributes(this.config.resourceAttributes);\n const spanProcessors = (() => {\n const exporter = wrapWithDebug(\n new OTLPTraceExporter(createExporterOptions(this.config.transport)),\n this.config.debug,\n );\n const processor =\n this.config.spanProcessor === 'simple'\n ? new SimpleSpanProcessor(exporter)\n : new BatchSpanProcessor(exporter, this.config.spanBatch);\n return [\n new FilteringSpanProcessor(processor, this.config, () =>\n this.applyRedact({\n ...this.runtimeContext.getAttributes(),\n ...this.config.hooks.getPageAttributes(),\n }),\n ),\n ];\n })();\n this.tracerProvider = new WebTracerProvider({\n resource,\n sampler: new RumSessionSampler(this.isSampled),\n spanProcessors,\n });\n this.tracer = this.tracerProvider.getTracer(BK_OT_INSTRUMENTATION_NAME);\n this.registeredInstrumentations = [];\n if (this.config.autoStart) {\n void this.start().catch(error => {\n globalThis.console?.warn('[bk-ot] auto start failed:', error);\n });\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../package.json","../src/core/hash.ts","../src/core/id.ts","../src/schema/attributes.ts","../src/plugins/device.ts","../src/core/url.ts","../src/core/view-location.ts","../src/core/config.ts","../src/core/plugin.ts","../src/schema/span.ts","../src/core/runtime-context.ts","../src/core/processor.ts","../src/core/action-target.ts","../src/core/event-time.ts","../src/plugins/action.ts","../src/plugins/activity.ts","../src/plugins/blank-screen-detection.ts","../src/plugins/blank-screen.ts","../src/core/request-timing.ts","../src/core/trace-context.ts","../src/core/performance-timing.ts","../src/plugins/resource.ts","../src/plugins/common.ts","../src/plugins/csp-violation.ts","../src/plugins/error.ts","../src/plugins/long-task.ts","../src/core/page-activity.ts","../src/core/route-observer.ts","../src/plugins/page-view.ts","../src/plugins/session-state.ts","../src/plugins/session-store.ts","../src/plugins/session.ts","../src/plugins/document-vitals.ts","../src/plugins/web-vitals-metrics.ts","../src/plugins/web-vitals.ts","../src/plugins/websocket.ts","../src/core/action-activity.ts","../src/core/sampling.ts","../src/core/session-transition.ts","../src/core/sdk.ts","../src/integrations/vue-router.ts"],"sourcesContent":["{\n \"name\": \"@blueking/open-telemetry\",\n \"version\": \"0.0.35-beta.1\",\n \"description\": \"OpenTelemetry browser SDK for BK RUM\",\n \"author\": \"TencentCloud Real User Monitoring\",\n \"main\": \"dist/index.js\",\n \"unpkg\": \"dist/bk-rum.global.js\",\n \"jsdelivr\": \"dist/bk-rum.global.js\",\n \"license\": \"MIT\",\n \"files\": [\n \"dist\",\n \"skills\"\n ],\n \"scripts\": {\n \"prepublishOnly\": \"pnpm build && pnpm dts && pnpm skill:refs\",\n \"skill:refs\": \"node scripts/gen-skill-references.mjs\",\n \"test:skill-refs\": \"node --test tests/gen-skill-references.test.mjs\",\n \"build\": \"vite build && vite build --mode cdn && pnpm dts\",\n \"build:cdn\": \"vite build --mode cdn\",\n \"build:esm\": \"vite build\",\n \"docs:build\": \"vitepress build wikis\",\n \"docs:dev\": \"vitepress dev wikis\",\n \"docs:preview\": \"vitepress preview wikis\",\n \"dev\": \"vite dev\",\n \"dts\": \"vue-tsc --project tsconfig.dts.json\",\n \"test:rum-context\": \"node --experimental-strip-types --test tests/action-plugin.test.mjs tests/action-lifecycle.test.mjs tests/action-transition.test.mjs tests/consent.test.mjs tests/event-time.test.mjs tests/experience-plugins.test.mjs tests/init-cancellation.test.mjs tests/late-performance.test.mjs tests/request-model.test.mjs tests/request-lifecycle-regressions.test.mjs tests/request-export-lifecycle.test.mjs tests/resource-context.test.mjs tests/resource-lifecycle.test.mjs tests/request-timing.test.mjs tests/request-capacity.test.mjs tests/resource-fields.test.mjs tests/resource-url.test.mjs tests/runtime-context.test.mjs tests/sampling.test.mjs tests/session-state.test.ts tests/session-plugin.test.mjs tests/session-page-view.test.mjs tests/session-processors.test.mjs tests/session-sdk.test.mjs tests/session-view-metadata.test.mjs tests/trace-context.test.mjs tests/web-vitals.test.mjs tests/web-vitals-metrics.test.mjs tests/web-vitals-context.test.mjs tests/document-vitals.test.mjs tests/view-routing.test.mjs tests/view-lifecycle.test.mjs tests/view-vitals-lifecycle.test.mjs tests/blank-screen-detection.test.mjs tests/blank-screen-lifecycle.test.mjs tests/vue-router-views.test.mjs tests/manual-view-sdk.test.mjs\",\n \"test:action-browser\": \"node node_modules/vite/bin/vite.js build --mode cdn && node --test tests/action-target.test.mjs && node scripts/verify-action-browser.mjs\",\n \"test:request-browser\": \"node node_modules/vite/bin/vite.js build --mode cdn && node scripts/verify-request-browser.mjs\",\n \"test:resource-browser\": \"node node_modules/vite/bin/vite.js build --mode cdn && node scripts/verify-resource-browser.mjs\",\n \"test:vitals-browser\": \"node node_modules/vite/bin/vite.js build --mode cdn && node scripts/verify-vitals-browser.mjs\",\n \"test:view-browser\": \"node node_modules/vite/bin/vite.js build --mode cdn && node scripts/verify-view-browser.mjs\",\n \"test:session-browser\": \"node node_modules/vite/bin/vite.js build --mode cdn && node scripts/verify-session-browser.mjs\"\n },\n \"dependencies\": {\n \"@opentelemetry/api\": \"^1.9.1\",\n \"@opentelemetry/context-zone\": \"2.7.1\",\n \"@opentelemetry/core\": \"^2.7.1\",\n \"@opentelemetry/exporter-trace-otlp-http\": \"^0.217.0\",\n \"@opentelemetry/instrumentation\": \"^0.217.0\",\n \"@opentelemetry/resources\": \"^2.7.1\",\n \"@opentelemetry/sdk-trace-base\": \"^2.7.1\",\n \"@opentelemetry/sdk-trace-web\": \"^2.7.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.38.0\"\n },\n \"devDependencies\": {\n \"@vitejs/plugin-vue\": \"^6.0.6\",\n \"@vue/test-utils\": \"^2.4.6\",\n \"@vue/tsconfig\": \"^0.9.0\",\n \"oxc-minify\": \"^0.133.0\",\n \"vite\": \"^8.0.2\",\n \"vite-bundle-analyzer\": \"^1.3.2\",\n \"vitepress\": \"2.0.0-alpha.16\",\n \"vue\": \"^3.5.34\",\n \"vue-router\": \"^5.0.6\",\n \"vue-tsc\": \"^3.1.4\"\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\n/** 非密码学稳定 hash,仅用于生成浏览器本地 storage key。 */\nexport const hashString = (input: string): string => {\n let hash = 5381;\n for (let index = 0; index < input.length; index++) {\n hash = (hash * 33) ^ input.charCodeAt(index);\n }\n return (hash >>> 0).toString(36);\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * 生成随机 ID。优先用 `crypto.randomUUID`(standards-compliant UUID v4),不可用时回退到\n * `${prefix}-${timestamp}-${rand}` 形式。\n *\n * 注意:fallback 实现使用 Math.random,**不是密码学安全**,仅适用于设备/会话/事件标识等场景,\n * 不要复用此函数生成 token、CSRF 防护等安全相关的值。\n */\nexport const createRandomId = (prefix: string) => {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/**\n * RUM 上报字段 key 集中定义。\n *\n * 插件里不要散落硬编码字符串,后续字段命名调整只改这里,避免采集端与字段文档逐步漂移。\n */\nexport const RUM_ATTRIBUTES = {\n actionFrustrationType: 'action.frustration.type',\n actionId: 'action.id',\n actionIds: 'action.ids',\n actionEndReason: 'action.end_reason',\n actionLoadingTime: 'action.loading_time',\n actionName: 'action.name',\n actionNameSource: 'action.name_source',\n actionPositionX: 'action.position.x',\n actionPositionY: 'action.position.y',\n actionTargetHeight: 'action.target.height',\n actionTargetName: 'action.target.name',\n actionTargetPath: 'action.target.path',\n actionTargetSelector: 'action.target.selector',\n actionTargetTag: 'action.target.tag',\n actionTargetWidth: 'action.target.width',\n actionType: 'action.type',\n deploymentEnvironmentName: 'deployment.environment.name',\n cacheHit: 'resource.cache.hit',\n deviceType: 'device.type',\n longTaskBlockingDuration: 'long_task.blocking_duration',\n longTaskEntryType: 'long_task.entry_type',\n longTaskId: 'long_task.id',\n networkEffectiveType: 'network.effective_type',\n networkStatus: 'network.status',\n nextHopProtocol: 'resource.protocol',\n resourceInitiatorType: 'resource.initiator_type',\n outcomeType: 'outcome.type',\n resourceTimingConnectEnd: 'resource.timing.connect_end',\n resourceTimingConnectStart: 'resource.timing.connect_start',\n resourceTimingDomainLookupEnd: 'resource.timing.domain_lookup_end',\n resourceTimingDomainLookupStart: 'resource.timing.domain_lookup_start',\n resourceTimingFetchStart: 'resource.timing.fetch_start',\n resourceTimingFinalResponseHeadersStart: 'resource.timing.final_response_headers_start',\n resourceTimingRedirectEnd: 'resource.timing.redirect_end',\n resourceTimingRedirectStart: 'resource.timing.redirect_start',\n resourceTimingRequestStart: 'resource.timing.request_start',\n resourceTimingResponseEnd: 'resource.timing.response_end',\n resourceTimingResponseStart: 'resource.timing.response_start',\n resourceTimingSecureConnectionStart: 'resource.timing.secure_connection_start',\n resourceTimingStartTime: 'resource.timing.start_time',\n resourceTimingWorkerCacheLookupStart: 'resource.timing.worker_cache_lookup_start',\n resourceTimingWorkerFinalRouterSource: 'resource.timing.worker_final_router_source',\n resourceTimingWorkerMatchedRouterSource: 'resource.timing.worker_matched_router_source',\n resourceTimingWorkerRouterEvaluationStart: 'resource.timing.worker_router_evaluation_start',\n resourceTimingWorkerStart: 'resource.timing.worker_start',\n serviceName: 'service.name',\n serviceVersion: 'service.version',\n sessionHasReplay: 'session.has_replay',\n sessionId: 'session.id',\n sessionStartTime: 'session.start_time',\n sessionLastActivityTime: 'session.last_activity_time',\n sessionSampleRate: 'session.sample_rate',\n sessionPhase: 'session.phase',\n sessionType: 'session.type',\n spanType: 'span_type',\n tabId: 'tab.id',\n timingActivationStart: 'timing.activation_start',\n timingConnectEnd: 'timing.connect_end',\n timingConnectStart: 'timing.connect_start',\n timingDomContentLoadedEventEnd: 'timing.dom_content_loaded_event_end',\n timingDomContentLoadedEventStart: 'timing.dom_content_loaded_event_start',\n timingDomainLookupEnd: 'timing.domain_lookup_end',\n timingDomainLookupStart: 'timing.domain_lookup_start',\n timingFetchStart: 'timing.fetch_start',\n timingFinalResponseHeadersStart: 'timing.final_response_headers_start',\n timingLoadEventEnd: 'timing.load_event_end',\n timingLoadEventStart: 'timing.load_event_start',\n timingRedirectEnd: 'timing.redirect_end',\n timingRedirectStart: 'timing.redirect_start',\n timingRequestStart: 'timing.request_start',\n timingResponseEnd: 'timing.response_end',\n timingResponseStart: 'timing.response_start',\n timingSecureConnectionStart: 'timing.secure_connection_start',\n timingStartTime: 'timing.start_time',\n timingUnloadEventEnd: 'timing.unload_event_end',\n timingUnloadEventStart: 'timing.unload_event_start',\n timingWorkerCacheLookupStart: 'timing.worker_cache_lookup_start',\n timingWorkerRouterEvaluationStart: 'timing.worker_router_evaluation_start',\n timingWorkerStart: 'timing.worker_start',\n userId: 'user.id',\n userAgentName: 'user_agent.name',\n userAgentOsName: 'user_agent.os.name',\n userAgentVersion: 'user_agent.version',\n vitalMetric: 'vital.metric',\n vitalId: 'vital.id',\n vitalScope: 'vital.scope',\n vitalValue: 'vital.value',\n vitalVersion: 'vital.version',\n viewDomComplete: 'view.dom_complete',\n viewDomContentLoaded: 'view.dom_content_loaded',\n viewDomInteractive: 'view.dom_interactive',\n viewFirstByte: 'view.first_byte',\n viewEndReason: 'view.end_reason',\n viewForegroundTime: 'view.foreground_time',\n viewId: 'view.id',\n viewIsActive: 'view.is_active',\n viewLoadEvent: 'view.load_event',\n viewLoadingTime: 'view.loading_time',\n viewLoadingTimeSource: 'view.loading_time_source',\n viewLoadingType: 'view.loading_type',\n viewName: 'view.name',\n viewPhase: 'view.phase',\n viewPageStates: 'view.page_states',\n viewPrevious: 'view.previous',\n viewPreviousUrlTemplate: 'view.previous_url_template',\n viewReferrer: 'view.referrer',\n viewStartedAt: 'view.started_at',\n viewTimeSpent: 'view.time_spent',\n viewUrl: 'view.url',\n viewUrlTemplate: 'view.url_template',\n viewVersion: 'view.version',\n websocketPhase: 'websocket.phase',\n} as const;\n\nexport type RumAttributeKey = (typeof RUM_ATTRIBUTES)[keyof typeof RUM_ATTRIBUTES];\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { hashString } from '../core/hash';\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\nexport interface BkOTDevicePluginOptions {\n /** 是否跨页面持久化匿名设备 ID,默认 false。 */\n persistentId?: boolean;\n storageKey?: string;\n}\n\nconst DEFAULT_DEVICE_STORAGE_KEY = 'BK_RUM_DEVICE_ID';\n// 用户拖窗口时 resize 高频触发,debounce 静默期内只在最后一次更新,避免无谓的 setRuntimeAttributes 风暴\nconst VIEWPORT_DEBOUNCE_MS = 250;\n\ninterface NetworkInformationLike {\n effectiveType?: string;\n type?: string;\n addEventListener?: (type: 'change', listener: () => void) => void;\n removeEventListener?: (type: 'change', listener: () => void) => void;\n}\n\ninterface UserAgentDataLike {\n mobile?: boolean;\n platform?: string;\n}\n\nconst getConnection = (): NetworkInformationLike | undefined =>\n (\n navigator as Navigator & {\n connection?: NetworkInformationLike;\n }\n ).connection;\n\nconst getUserAgentData = (): undefined | UserAgentDataLike =>\n (\n navigator as Navigator & {\n userAgentData?: UserAgentDataLike;\n }\n ).userAgentData;\n\nconst getBrowserInfo = (ua: string) => {\n const matchers: Array<[string, RegExp]> = [\n ['Edge', /Edg\\/([\\d.]+)/],\n ['Chrome', /Chrome\\/([\\d.]+)/],\n ['Firefox', /Firefox\\/([\\d.]+)/],\n ['Safari', /Version\\/([\\d.]+).*Safari/],\n ];\n for (const [name, pattern] of matchers) {\n const matched = ua.match(pattern);\n if (matched?.[1]) {\n return { name, version: matched[1].split('.')[0] };\n }\n }\n return { name: 'Other', version: undefined };\n};\n\nconst getOsName = (ua: string, platform?: string) => {\n const value = `${platform ?? ''} ${ua}`;\n if (/iphone|ipad|ipod/i.test(value)) return 'iOS';\n if (/android/i.test(value)) return 'Android';\n if (/mac/i.test(value)) return 'macOS';\n if (/win/i.test(value)) return 'Windows';\n if (/linux/i.test(value)) return 'Linux';\n return 'Other';\n};\n\nconst readDeviceId = (storageKey: string) => {\n let existed: null | string = null;\n try {\n existed = window.localStorage.getItem(storageKey);\n } catch {\n /* localStorage 不可用(隐私模式 / sandbox iframe),下面会创建一个 in-memory id */\n }\n if (existed) {\n return existed;\n }\n const deviceId = createRandomId('device');\n try {\n window.localStorage.setItem(storageKey, deviceId);\n } catch {\n /* 写不进去也行,至少本次 SDK 生命周期内 deviceId 仍然稳定 */\n }\n return deviceId;\n};\n\n// 视口尺寸:随窗口大小 / 屏幕旋转变化,需要在 resize / orientationchange 时刷新\nconst getViewportAttributes = (): Attributes => {\n if (typeof window === 'undefined') {\n return {};\n }\n return {\n 'browser.viewport.width': window.innerWidth,\n 'browser.viewport.height': window.innerHeight,\n 'browser.screen.width': window.screen?.width,\n 'browser.screen.height': window.screen?.height,\n };\n};\n\n// 网络信息:随 online / offline / connection.change 变化\nconst getNetworkAttributes = (): Attributes => {\n if (typeof navigator === 'undefined') {\n return {};\n }\n const connection = getConnection();\n return {\n [RUM_ATTRIBUTES.networkStatus]: navigator.onLine ? 'connected' : 'not_connected',\n 'network.effective_type': connection?.effectiveType,\n 'network.connection.type': connection?.type,\n };\n};\n\n// 设备与 User Agent 信息:进入页面时一次性读取,运行期不会变化,适合作为 Resource 公共属性。\nexport const getDeviceResourceAttributes = (): Attributes => {\n if (typeof navigator === 'undefined') {\n return {};\n }\n const uaData = getUserAgentData();\n const ua = navigator.userAgent;\n const browser = getBrowserInfo(ua);\n const osName = getOsName(ua, uaData?.platform);\n const deviceType = uaData?.mobile || /mobi|android|iphone|ipad|ipod/i.test(ua) ? 'mobile' : 'desktop';\n return {\n [RUM_ATTRIBUTES.deviceType]: deviceType,\n [RUM_ATTRIBUTES.userAgentName]: browser.name,\n [RUM_ATTRIBUTES.userAgentVersion]: browser.version,\n [RUM_ATTRIBUTES.userAgentOsName]: osName,\n };\n};\n\n// trailing debounce:windowMs 静默期内的多次触发只执行最后一次。\n// 适合 resize 这类\"用户停下来后才需要拿到最终值\"的场景。\nconst createDebounce = (fn: () => void, windowMs: number) => {\n let timer: number | undefined;\n return () => {\n if (timer !== undefined) {\n window.clearTimeout(timer);\n }\n timer = window.setTimeout(() => {\n timer = undefined;\n fn();\n }, windowMs);\n };\n};\n\n/**\n * 设备元数据采集插件。稳定的设备能力由 SDK 写入 Resource;这里只维护设备 ID 和运行期动态属性。\n *\n * 上报字段:\n * - `device.id`:设备级永久标识,存于 localStorage(默认 key 复用旧 session 插件以保留现网用户)。\n * - `user_agent.name` / `user_agent.version` / `user_agent.os.name`:User Agent 信息,写入 Resource。\n * - `browser.viewport.*` / `browser.screen.*`:视口与屏幕尺寸。\n * - `network.status` / `network.effective_type` / `network.connection.type`:网络信息。\n *\n * 实时更新:\n * - viewport 监听 `resize` / `orientationchange`,并经 250ms debounce 合并,避免拖窗口时高频触发;\n * 静默期结束后用最终值刷新 runtimeAttributes。\n * - network 监听 `online` / `offline` / `connection.change`(本身低频,不需要 throttle)。\n * - 二者只更新 in-memory 的 runtimeAttributes,不会主动产生新的 Span;\n * 更新后续生成的 Span 会带最新值。\n *\n * 与 session 插件的关系:device 跨会话持久(终身),session 有过期与续期(连续访问语义)。\n */\nexport const createDevicePlugin = (options: BkOTDevicePluginOptions = {}): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n return {\n name: 'device',\n init(context) {\n const storageKey =\n options.storageKey ?? `${DEFAULT_DEVICE_STORAGE_KEY}_${hashString(context.config.application.name)}`;\n const deviceId =\n typeof window === 'undefined' || options.persistentId !== true\n ? createRandomId('device')\n : readDeviceId(storageKey);\n\n context.setRuntimeAttributes({\n 'device.id': deviceId,\n // createDevicePlugin 作为扩展单独启用时,Resource 没有设备字段,仍回退到原有 runtime attributes 行为。\n ...(context.config.tracking.device === false ? getDeviceResourceAttributes() : {}),\n ...getViewportAttributes(),\n ...getNetworkAttributes(),\n });\n\n if (typeof window === 'undefined') {\n return;\n }\n\n const refreshViewport = createDebounce(() => {\n context.setRuntimeAttributes(getViewportAttributes());\n }, VIEWPORT_DEBOUNCE_MS);\n window.addEventListener('resize', refreshViewport);\n window.addEventListener('orientationchange', refreshViewport);\n teardownCallbacks.push(\n () => window.removeEventListener('resize', refreshViewport),\n () => window.removeEventListener('orientationchange', refreshViewport),\n );\n\n const refreshNetwork = () => {\n context.setRuntimeAttributes(getNetworkAttributes());\n };\n window.addEventListener('online', refreshNetwork);\n window.addEventListener('offline', refreshNetwork);\n teardownCallbacks.push(\n () => window.removeEventListener('online', refreshNetwork),\n () => window.removeEventListener('offline', refreshNetwork),\n );\n\n const connection = getConnection();\n // NetworkInformation 实现了 EventTarget;旧浏览器或某些 polyfill 可能没有 addEventListener,做能力检测\n if (connection && typeof connection.addEventListener === 'function') {\n connection.addEventListener('change', refreshNetwork);\n teardownCallbacks.push(() => {\n connection.removeEventListener?.('change', refreshNetwork);\n });\n }\n },\n shutdown() {\n while (teardownCallbacks.length) {\n teardownCallbacks.pop()?.();\n }\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { BkOTUrlMatcher, ResolvedBkOTConfig } from './config';\n\n// 与浏览器 Fetch/XHR 使用同一个文档基准,包含页面目录和 <base href>。\nconst getBaseUrl = () =>\n (typeof document !== 'undefined' && document.baseURI) ||\n (typeof window !== 'undefined' && (window.location.href || window.location.origin)) ||\n 'http://localhost';\n\nexport const toAbsoluteUrl = (url: string) => {\n try {\n return new URL(url, getBaseUrl()).href;\n } catch {\n return url;\n }\n};\n\nconst DYNAMIC_PATH_SEGMENT = /^(?:\\d+|[0-9a-f]{8}-[0-9a-f-]{27,}|[0-9a-f]{16,})$/i;\n\n/**\n * 常见数字 ID、UUID 和长十六进制段统一折叠为 :id,便于服务端按路由聚合。\n * 同时服务 `view.url_template`(页面路由)与 `url.template`(请求路径)两个维度。\n */\nexport const normalizeUrlPathTemplate = (pathGroup: string) => {\n const path = pathGroup.split(/[?#]/, 1)[0];\n return path\n .split('/')\n .map(segment => (DYNAMIC_PATH_SEGMENT.test(segment) ? ':id' : segment))\n .join('/');\n};\n\n// 去掉 trailing slash,便于 path 边界对齐比较\nconst stripTrailingSlash = (value: string) => (value.length > 1 ? value.replace(/\\/+$/, '') : value);\n\n// 比较两个 URL 是否指向同一资源(忽略 query/fragment 与末尾斜杠)\nconst isSameResource = (left: string, right: string) => {\n const stripped = (value: string) => stripTrailingSlash(value.replace(/[?#].*$/, ''));\n return stripped(left) === stripped(right);\n};\n\nexport const isBkOTEndpoint = (config: ResolvedBkOTConfig, url: string) => {\n const targetUrl = toAbsoluteUrl(url);\n return isSameResource(targetUrl, toAbsoluteUrl(config.transport.endpoint));\n};\n\nexport const shouldIgnoreUrl = (config: ResolvedBkOTConfig, url: string) => isBkOTEndpoint(config, url);\n\nconst matchesUrl = (matcher: BkOTUrlMatcher, url: string) => {\n if (typeof matcher === 'function') return matcher(url);\n if (typeof matcher === 'string') return url.includes(matcher);\n matcher.lastIndex = 0;\n return matcher.test(url);\n};\n\nexport const matchesUrlList = (matchers: BkOTUrlMatcher | BkOTUrlMatcher[] | undefined, url: string) =>\n (Array.isArray(matchers) ? matchers : matchers ? [matchers] : []).some(matcher => matchesUrl(matcher, url));\n\nconst getRequestConfig = (config: ResolvedBkOTConfig) =>\n typeof config.tracking.request === 'object' ? config.tracking.request : undefined;\n\nexport const shouldIgnoreRequest = (config: ResolvedBkOTConfig, url: string) =>\n shouldIgnoreUrl(config, url) || matchesUrlList(getRequestConfig(config)?.excludedUrls, toAbsoluteUrl(url));\n\n// 注入规则是信任边界,不能复用 excludedUrls 的子串匹配:query 中出现可信 URL 不代表目标可信。\n// 字符串必须是绝对 HTTP(S) URL,仅表达 origin 与路径段;query/hash 条件请显式使用函数。\nconst matchesTracingUrl = (matcher: BkOTUrlMatcher, url: string) => {\n if (typeof matcher !== 'string') return matchesUrl(matcher, url);\n try {\n const allowed = new URL(matcher);\n const target = new URL(url);\n if (\n !['http:', 'https:'].includes(allowed.protocol) ||\n allowed.username || allowed.password || allowed.search || allowed.hash ||\n allowed.origin !== target.origin\n ) return false;\n const path = stripTrailingSlash(allowed.pathname);\n return path === '/' || target.pathname === path || target.pathname.startsWith(`${path}/`);\n } catch {\n return false;\n }\n};\n\n// Trace Header 仅向显式白名单注入,避免同源第三方路径被无意注入以及跨域 CORS 预检。\nexport const shouldPropagateTraceHeader = (config: ResolvedBkOTConfig, url: string) => {\n const allowed = getRequestConfig(config)?.allowedTracingUrls;\n const target = toAbsoluteUrl(url);\n return (Array.isArray(allowed) ? allowed : allowed ? [allowed] : []).some(matcher => matchesTracingUrl(matcher, target));\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport type BkOTViewRouteMode = 'auto' | 'document' | 'hash' | 'history';\n\nconst parseUrl = (url: string) => {\n try {\n return new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n } catch {\n return undefined;\n }\n};\n\nconst hasHashRoutePrefix = (hash: string) => /^#!?\\//.test(hash);\n\n// Hash 中的 query 与页内 fragment 不属于路由路径,不能混进页面模板。\nconst getHashRoutePath = (hash: string) => {\n const path = hash.replace(/^#!/, '').replace(/^#/, '').split(/[?#]/, 1)[0];\n return path.startsWith('/') ? path : `/${path}`;\n};\n\n/** 仅用于身份比较与模板生成;routePath 仍可能含业务 ID,不能当作已脱敏 URL 直接上报。 */\nexport const getViewLocation = (url: string, mode: BkOTViewRouteMode = 'auto') => {\n const parsed = parseUrl(url);\n const pathname = parsed?.pathname || '/';\n const hash = parsed?.hash ?? '';\n const kind: 'hash' | 'history' =\n mode === 'hash' || (mode === 'auto' && hasHashRoutePrefix(hash)) ? 'hash' : 'history';\n return { hash, kind, pathname, routePath: kind === 'hash' ? getHashRoutePath(hash) : pathname };\n};\n\nconst isHashAnchor = (hash: string) => {\n if (!hash || typeof document === 'undefined' || typeof document.getElementById !== 'function') return false;\n try {\n return Boolean(document.getElementById(decodeURIComponent(hash.slice(1))));\n } catch {\n return Boolean(document.getElementById(hash.slice(1)));\n }\n};\n\n/** 同文档导航边界;整页导航由新 Document 初始化产生 initial_load,不经过此比较。 */\nexport const isViewLocationChange = (fromUrl: string, toUrl: string, mode: BkOTViewRouteMode = 'auto') => {\n if (mode === 'document') return false;\n const from = getViewLocation(fromUrl, mode);\n const to = getViewLocation(toUrl, mode);\n if (from.pathname !== to.pathname) return true;\n if (mode === 'history') return false;\n if (mode === 'hash' || from.kind === 'hash' || to.kind === 'hash') {\n return from.kind !== to.kind || from.routePath !== to.routePath;\n }\n // auto 为无框架接入保留非标准 hash 路由的启发式;明确模式/Router 集成无需依赖 DOM。\n if (from.hash === to.hash || isHashAnchor(to.hash) || (!to.hash && isHashAnchor(from.hash))) return false;\n return getHashRoutePath(from.hash) !== getHashRoutePath(to.hash);\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { version as packageVersion } from '../../package.json';\nimport { getDeviceResourceAttributes } from '../plugins/device';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { normalizeUrlPathTemplate } from './url';\nimport { getViewLocation } from './view-location';\n\nimport type { BkOTActionPluginOptions } from '../plugins/action';\nimport type { BkOTBlankScreenPluginOptions } from '../plugins/blank-screen';\nimport type { BkOTDevicePluginOptions } from '../plugins/device';\nimport type { BkOTLongTaskPluginOptions } from '../plugins/long-task';\nimport type { BkOTSessionConfig } from '../plugins/session';\nimport type { RumRequestOutcome } from '../schema/span';\nimport type { BkOTPlugin } from './plugin';\nimport type { BkOTUserContext } from './runtime-context';\nimport type { BkOTViewRouteMode } from './view-location';\nimport type { Attributes, Link } from '@opentelemetry/api';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport type { TimedEvent } from '@opentelemetry/sdk-trace-base';\n\nexport interface BkOTActionEventPayload {\n attributes?: Attributes;\n name: string;\n}\n\nexport interface BkOTApplicationConfig {\n environment?: string;\n name: string;\n version?: string;\n}\n\nexport interface BkOTAttributesConfig {\n custom?: () => Attributes;\n error?: () => Attributes;\n page?: () => Attributes;\n}\n\nexport type BkOTAttributeValue = boolean | number | string;\n\nexport interface BkOTBatchConfig {\n exportTimeoutMillis?: number;\n maxExportBatchSize?: number;\n maxQueueSize?: number;\n scheduledDelayMillis?: number;\n}\n\nexport interface BkOTBeforeSendEvent {\n attributes: Record<string, unknown>;\n /** 脱敏后的导出副本,可原地修改或移除;不改变已结束的原 Span。 */\n events?: TimedEvent[];\n links?: Link[];\n name: string;\n signal: 'span';\n}\n\nexport interface BkOTContextConfig {\n attributes?: BkOTAttributesConfig;\n user?: BkOTUserContext;\n}\n\nexport interface BkOTCustomEventPayload {\n attributes?: Attributes;\n error?: Error;\n name: string;\n}\n\nexport interface BkOTExtensionsConfig {\n instrumentations?: Instrumentation[];\n plugins?: BkOTPlugin[];\n}\n\nexport interface BkOTOptions {\n application: BkOTApplicationConfig;\n autoStart?: boolean;\n context?: BkOTContextConfig;\n debug?: boolean;\n enabled?: boolean;\n extensions?: BkOTExtensionsConfig;\n privacy?: BkOTPrivacyConfig;\n session?: BkOTSessionConfig;\n tracking?: BkOTTrackingConfig;\n transport: BkOTTransportConfig;\n}\n\nexport interface BkOTPrivacyConfig {\n /** 初始化时的采集授权状态;运行期可通过 setTrackingConsent 更新。 */\n trackingConsent?: BkOTTrackingConsent;\n /** 过滤 Span、Event、Link 属性;导出前再次执行,应保持幂等。抛错时丢弃该条遥测。 */\n redactAttributes?: (attributes: Attributes) => Attributes;\n /** 所有写入 attribute 的 URL 都会先经过此函数。 */\n redactUrl?: (url: string) => string;\n}\n\nexport interface BkOTRequestConfig {\n allowedTracingUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n excludedUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n beforeSend?: (event: BkOTRequestEvent, context: BkOTRequestContext) => boolean | void;\n /** 返回请求 URL 的低基数模板,例如 `/api/orders/{id}`;返回空值时回退到默认折叠规则。 */\n getUrlTemplate?: (url: string) => string | undefined;\n}\n\nexport type BkOTRequestContext =\n | {\n /** 本次 send 的终态快照;xhr 原实例可能已被业务复用,不保存正文。 */\n responseSnapshot?: Readonly<Pick<XMLHttpRequest, 'responseType' | 'responseURL' | 'status' | 'statusText'>>;\n type: 'xhr';\n xhr: XMLHttpRequest;\n }\n | { error?: unknown; request: Request | RequestInit; response?: Response; type: 'fetch' };\n\nexport interface BkOTRequestEvent {\n attributes: Attributes;\n type: 'resource';\n resource: {\n method?: string;\n outcome: BkOTRequestOutcome;\n transport: 'fetch' | 'xhr';\n url?: string;\n };\n}\n\nexport type BkOTRequestOutcome = RumRequestOutcome;\n\nexport type BkOTSpanProcessorMode = 'batch' | 'simple';\n\nexport interface BkOTTrackingConfig {\n action?: BkOTActionPluginOptions | boolean;\n blankScreen?: BkOTBlankScreenPluginOptions | boolean;\n cspViolation?: boolean;\n device?: BkOTDevicePluginOptions | boolean;\n error?: boolean;\n longTask?: BkOTLongTaskPluginOptions | boolean;\n request?: BkOTRequestConfig | boolean;\n resource?: boolean;\n view?: BkOTViewConfig;\n websocket?: boolean;\n webVitals?: boolean;\n beforeSend?: (event: BkOTBeforeSendEvent) => boolean | void;\n}\n\nexport type BkOTTrackingConsent = 'granted' | 'not-granted';\n\nexport interface BkOTTransportConfig {\n batch?: BkOTBatchConfig;\n concurrencyLimit?: number;\n endpoint: string;\n headers?: Record<string, string>;\n processor?: BkOTSpanProcessorMode;\n timeoutMillis?: number;\n token?: string;\n}\n\nexport type BkOTUrlMatcher = ((url: string) => boolean) | RegExp | string;\n\nexport interface BkOTViewConfig {\n /** 不参与 View loading time 的长轮询、流式请求或埋点 URL。 */\n excludedActivityUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n /** 自动计算初始加载与 SPA 路由的页面稳定耗时,默认开启。 */\n loadingTime?: boolean;\n /** auto 识别 #/ 与 #!/;history 忽略片段,hash 使用片段内路径,document 不自动划分同文档 View。 */\n routeMode?: BkOTViewRouteMode;\n tracking?: 'auto' | 'manual';\n /** 返回页面路由的低基数模板,例如 `/trace/:id`;返回空值时回退到默认折叠规则。 */\n getUrlTemplate?: (url: string) => string | undefined;\n}\n\nexport interface ResolvedApplicationConfig {\n environment: string;\n name: string;\n version?: string;\n}\n\nexport interface ResolvedBkOTConfig {\n application: ResolvedApplicationConfig;\n autoStart: boolean;\n debug: boolean;\n enabled: boolean;\n extensions: BkOTExtensionsConfig;\n hooks: ResolvedConfigHooks;\n resourceAttributes: Attributes;\n session: ResolvedSessionConfig;\n spanBatch?: BkOTBatchConfig;\n spanProcessor: BkOTSpanProcessorMode;\n tracking: BkOTTrackingConfig;\n trackingConsent: BkOTTrackingConsent;\n transport: ResolvedTransportConfig;\n user?: BkOTUserContext;\n view: ResolvedViewConfig;\n}\n\nexport interface ResolvedConfigHooks {\n beforeSend?: (event: BkOTBeforeSendEvent) => boolean | void;\n getCustomAttributes: () => Attributes;\n getErrorAttributes: () => Attributes;\n getPageAttributes: () => Attributes;\n getRequestUrlTemplate: (url: string) => string;\n getViewUrlTemplate: (url: string) => string;\n redactAttributes: (attributes: Attributes) => Attributes;\n redactUrl: (url: string) => string;\n}\n\nexport interface ResolvedSessionConfig extends BkOTSessionConfig {\n sampleRate: number;\n}\n\nexport interface ResolvedTransportConfig {\n concurrencyLimit?: number;\n endpoint: string;\n headers?: Record<string, string>;\n timeoutMillis?: number;\n}\n\nexport interface ResolvedViewConfig {\n excludedActivityUrls?: BkOTUrlMatcher | BkOTUrlMatcher[];\n loadingTime: boolean;\n routeMode: BkOTViewRouteMode;\n tracking: 'auto' | 'manual';\n}\n\nconst trimTrailingSlash = (value: string) => value.trim().replace(/\\/+$/, '');\n\nconst resolveTransportConfig = (transport: BkOTTransportConfig): ResolvedTransportConfig => {\n // token 只负责提供默认鉴权头;headers 保持显式配置优先,便于特殊场景覆盖。\n const mergedHeaders =\n transport.token || transport.headers\n ? {\n ...(transport.token ? { Authorization: `Bearer ${transport.token}` } : {}),\n ...(transport.headers ?? {}),\n }\n : undefined;\n\n return {\n concurrencyLimit: transport.concurrencyLimit,\n endpoint: `${trimTrailingSlash(transport.endpoint)}/v1/rum`,\n headers: mergedHeaders,\n timeoutMillis: transport.timeoutMillis,\n };\n};\n\nconst clampSampleRate = (sampleRate?: number) => {\n if (typeof sampleRate !== 'number' || !Number.isFinite(sampleRate)) {\n return 1;\n }\n return Math.max(0, Math.min(1, sampleRate));\n};\n\nconst identityRedactAttributes = (attributes: Attributes) => attributes;\n\n// 默认只保留 URL 的定位信息;认证信息、查询参数和 fragment 可能携带用户数据,统一移除。\nconst defaultRedactUrl = (url: string) => {\n if (!url) return url;\n try {\n const parsed = new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n parsed.username = '';\n parsed.password = '';\n parsed.search = '';\n parsed.hash = '';\n return parsed.href;\n } catch {\n return url.replace(/[?#].*$/, '');\n }\n};\n\nconst getUrlPathname = (url: string) => {\n try {\n return new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href).pathname || '/';\n } catch {\n return url || '/';\n }\n};\n\n/**\n * 低基数路径模板,供 `view.url_template` 与 `url.template` 共用同一套折叠规则。\n * 只保留 path:host 维度由 `server.address` 表达,query 由 `normalizeUrlPathTemplate` 去掉。\n */\nconst templatizeUrlPath = (url: string) => normalizeUrlPathTemplate(getUrlPathname(url));\n\n/** 模板 Hook 在每个请求/导航上都会跑,抛错不能影响追踪本身 */\nconst resolveTemplateHook =\n (config: BkOTOptions, custom: ((url: string) => string | undefined) | undefined, fallback = templatizeUrlPath) =>\n (url: string) => {\n try {\n const templated = custom?.(url);\n if (templated) return templated;\n } catch (error) {\n if (config.debug) globalThis.console?.warn('[bk-ot] url template hook failed:', error);\n }\n return fallback(url);\n };\n\nconst resolveApplicationConfig = (application: BkOTOptions['application']): ResolvedApplicationConfig => ({\n environment: application.environment ?? 'production',\n name: application.name,\n version: application.version,\n});\n\nconst resolveResourceAttributes = (\n application: ResolvedApplicationConfig,\n device: BkOTTrackingConfig['device'],\n sampleRate: number,\n): Attributes => ({\n [RUM_ATTRIBUTES.deploymentEnvironmentName]: application.environment,\n ...(device === false ? {} : getDeviceResourceAttributes()),\n [RUM_ATTRIBUTES.serviceName]: application.name,\n ...(application.version ? { [RUM_ATTRIBUTES.serviceVersion]: application.version } : {}),\n [RUM_ATTRIBUTES.sessionSampleRate]: sampleRate,\n 'telemetry.sdk.language': 'webjs',\n 'telemetry.sdk.name': 'blueking',\n 'telemetry.sdk.version': packageVersion,\n});\n\nconst validateTransportConfig = (transport: BkOTTransportConfig | undefined) => {\n if (!transport) throw new Error('[bk-ot] transport is required.');\n if (!transport.endpoint?.trim()) throw new Error('[bk-ot] transport.endpoint is required.');\n};\n\nconst resolveHooks = (config: BkOTOptions): ResolvedConfigHooks => ({\n beforeSend: config.tracking?.beforeSend,\n getPageAttributes: config.context?.attributes?.page ?? (() => ({})),\n getErrorAttributes: config.context?.attributes?.error ?? (() => ({})),\n getCustomAttributes: config.context?.attributes?.custom ?? (() => ({})),\n getRequestUrlTemplate: resolveTemplateHook(\n config,\n typeof config.tracking?.request === 'object' ? config.tracking.request.getUrlTemplate : undefined,\n ),\n getViewUrlTemplate: resolveTemplateHook(\n config,\n typeof config.tracking?.view === 'object' ? config.tracking.view.getUrlTemplate : undefined,\n url => normalizeUrlPathTemplate(getViewLocation(url, config.tracking?.view?.routeMode ?? 'auto').routePath),\n ),\n redactAttributes: config.privacy?.redactAttributes ?? identityRedactAttributes,\n redactUrl: config.privacy?.redactUrl ?? defaultRedactUrl,\n});\n\nexport const resolveConfig = (config: BkOTOptions): ResolvedBkOTConfig => {\n if (!config.application?.name?.trim()) {\n throw new Error('[bk-ot] application.name is required.');\n }\n validateTransportConfig(config.transport);\n const application = resolveApplicationConfig(config.application);\n const viewConfig = typeof config.tracking?.view === 'object' ? config.tracking.view : undefined;\n const hooks = resolveHooks(config);\n const sampleRate = clampSampleRate(config.session?.sampleRate);\n\n return {\n application,\n autoStart: config.autoStart ?? true,\n debug: config.debug ?? false,\n enabled: config.enabled ?? true,\n extensions: {\n instrumentations: [...(config.extensions?.instrumentations ?? [])],\n plugins: [...(config.extensions?.plugins ?? [])],\n },\n hooks,\n resourceAttributes: hooks.redactAttributes(\n resolveResourceAttributes(application, config.tracking?.device, sampleRate),\n ),\n session: {\n ...config.session,\n sampleRate,\n },\n spanBatch: config.transport.batch,\n spanProcessor: config.transport.processor ?? 'batch',\n tracking: config.tracking ?? {},\n trackingConsent: config.privacy?.trackingConsent ?? 'granted',\n transport: resolveTransportConfig(config.transport),\n user: config.context?.user,\n view: {\n excludedActivityUrls: viewConfig?.excludedActivityUrls,\n loadingTime: viewConfig?.loadingTime !== false,\n tracking: viewConfig?.tracking === 'manual' ? 'manual' : 'auto',\n routeMode: viewConfig?.routeMode ?? 'auto',\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { RumSpanType } from '../schema/span';\nimport type { BkOTActivityEvent } from './action-activity';\nimport type { ResolvedBkOTConfig } from './config';\nimport type { BkOTSessionLifecycleEvent, BkOTUserContext, BkOTViewCommand, BkOTViewContext } from './runtime-context';\nimport type { Attributes, Link, Span, SpanKind, TimeInput, Tracer } from '@opentelemetry/api';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\n\nexport interface BkOTPlugin {\n enabled?: ((config: ResolvedBkOTConfig) => boolean) | boolean;\n name: string;\n /** 同步读取浏览器待交付队列;所有插件 drain 后才允许 checkpoint 或停止请求。 */\n drain?: () => void;\n flush?: () => Promise<void> | void;\n init: (context: BkOTRuntimeContext) => Promise<void> | void;\n shutdown?: () => Promise<void> | void;\n}\n\nexport interface BkOTRuntimeContext {\n config: ResolvedBkOTConfig;\n tracer: Tracer;\n /** afterAssociation 加入身份关联队列,按注册顺序执行;默认阶段仍用于先初始化 View。 */\n afterSessionTransition: (callback: () => void, afterAssociation?: boolean) => void;\n /** 对外提供的属性脱敏入口,所有插件在 emit 前都应过一次 */\n applyRedact: (attributes: Attributes) => Attributes;\n beginSessionTransition: (at: number) => () => void;\n /** 关闭该动作的半开关联区间;不会影响其他重叠 Action。 */\n endActionContext: (id: string, endTime: number, relativeEndTime?: number) => void;\n flush: () => Promise<void>;\n getRuntimeAttributes: () => Attributes;\n getRuntimeAttributesAt: (timestamp: number) => Attributes;\n getRuntimeContextAtRelativeTime?: (relativeTime: number) => undefined | { attributes: Attributes; time: number };\n getViewHistory?: () => Array<{ runtimeAttributes: Attributes; view: BkOTViewContext }>;\n isSampled: () => boolean;\n isSessionActive: () => boolean;\n isSessionTransitionPending: () => boolean;\n isViewActive: () => boolean;\n notifyActivity: (event: BkOTActivityEvent) => void;\n notifySessionLifecycle: (event: BkOTSessionLifecycleEvent) => void;\n onActivity: (listener: (event: BkOTActivityEvent) => void) => () => void;\n onSessionLifecycle: (listener: (event: BkOTSessionLifecycleEvent) => void) => () => void;\n onViewChange: (listener: (view: BkOTViewContext) => void) => () => void;\n onViewCommand: (listener: (command: BkOTViewCommand) => void) => () => void;\n /** attributes 保留捕获引用,以支持待定 Session 提交后回填。 */\n registerActionContext: (id: string, startTime: number, attributes: Attributes) => void;\n registerInstrumentations: (instrumentations: Instrumentation[]) => void;\n registerSessionCheck: (check: () => void) => () => void;\n setRuntimeAttributes: (attributes: Attributes, changedAt?: number) => void;\n /** 更新用户上下文;user.id 由接入方传入,SDK 原样透传 */\n setUser: (user: BkOTUserContext) => void;\n /** 更新当前 View 上下文,后续 span 会自动带上 view.* 关联字段 */\n setView: (view: BkOTViewContext, changedAt?: number) => void;\n startSpan: (name: string, attributes?: Attributes, options?: BkOTStartSpanOptions) => Span;\n /** 本次授权采集区间;再次授权不能重新生成物理文档加载指标。 */\n collectionStart?: {\n /** 仅最初即允许采集的实例可读取安装前资源,不补采未授权区间。 */\n allowInitialResourceHistory?: boolean;\n isInitialDocument: boolean;\n relativeStartedAt: number;\n startedAt: number;\n };\n}\n\n/**\n * startSpan 的扩展选项。\n *\n * 用于\"事件实际发生在过去某个时刻,但 span 现在才创建\"的场景:\n * 例如 PerformanceObserver 在条目结束后才回调,但 span 的时间窗仍需反映\n * 条目真实发生的区间,方便 trace 视图与并发请求对齐。\n *\n * startTime 接受 OT TimeInput;常用 epoch 毫秒(performance.timeOrigin + performance.now())。\n * 配合 span.end(endTime?) 可控制结束时间。\n */\nexport interface BkOTStartSpanOptions {\n /** 完整运行时快照;缺失字段表示明确不存在,不再从当前或历史上下文补齐。 */\n contextAttributes?: Attributes;\n /** 用于从历史中解析 Session/View/Action 归属;默认复用数字类型 startTime。 */\n contextTime?: number;\n kind?: SpanKind;\n /** 关联其他 trace 的 Span Link;OTel 要求在创建时传入。 */\n links?: Link[];\n /** 内置 Span 根据脱敏后的属性生成名称;自定义 startSpan 默认保留传入名称。 */\n rumSpanType?: RumSpanType;\n startTime?: TimeInput;\n}\n\nexport const isPluginEnabled = (plugin: BkOTPlugin, config: ResolvedBkOTConfig) => {\n if (typeof plugin.enabled === 'function') {\n return plugin.enabled(config);\n }\n return plugin.enabled !== false;\n};\n\nexport const createPlugin = (plugin: BkOTPlugin) => plugin;\n\nexport class PluginManager {\n private debug = false;\n private readonly plugins: BkOTPlugin[];\n private startedPlugins: BkOTPlugin[] = [];\n private stopped = false;\n private stopping?: Promise<void>;\n\n private drain(plugins: BkOTPlugin[]) {\n for (const plugin of plugins) {\n try {\n plugin.drain?.();\n } catch (error) {\n this.warn(plugin, 'drain', error);\n }\n }\n }\n\n private async invoke(plugin: BkOTPlugin, phase: 'flush' | 'shutdown') {\n try {\n await plugin[phase]?.();\n } catch (error) {\n this.warn(plugin, phase, error);\n }\n }\n\n private warn(plugin: BkOTPlugin, phase: string, error: unknown) {\n if (this.debug) globalThis.console?.warn(`[bk-ot] plugin \"${plugin.name}\" ${phase} failed:`, error);\n }\n\n public constructor(plugins: BkOTPlugin[]) {\n this.plugins = plugins;\n }\n\n public async flush() {\n const plugins = [...this.startedPlugins];\n this.drain(plugins);\n for (const plugin of plugins) await this.invoke(plugin, 'flush');\n }\n\n public async shutdown() {\n if (this.stopping) return this.stopping;\n this.stopped = true;\n const plugins = this.startedPlugins.splice(0);\n this.stopping = (async () => {\n this.drain(plugins);\n for (const plugin of plugins) await this.invoke(plugin, 'flush');\n for (const plugin of plugins.reverse()) await this.invoke(plugin, 'shutdown');\n })();\n return this.stopping;\n }\n\n public async start(context: BkOTRuntimeContext) {\n this.debug = context.config.debug;\n // 每个插件独立 try/catch,单个插件 init 失败不应拖累其他插件:\n // - init 前登记,才能在等待异步初始化时取消;失败时清理已安装的资源\n // - debug 模式打 warn,方便排查;非 debug 静默失败避免污染业务日志\n for (const plugin of this.plugins) {\n if (this.stopped) return;\n if (!isPluginEnabled(plugin, context.config)) {\n continue;\n }\n this.startedPlugins.push(plugin);\n try {\n await plugin.init(context);\n if (this.stopped) {\n // 异步 init 可能在第一次 shutdown 后才返回,再清理它后续安装的资源。\n await plugin.shutdown?.();\n return;\n }\n } catch (error) {\n const index = this.startedPlugins.indexOf(plugin);\n if (index >= 0) {\n this.startedPlugins.splice(index, 1);\n try {\n await plugin.shutdown?.();\n } catch {\n /* 保留原始初始化错误。 */\n }\n }\n if (context.config.debug) {\n globalThis.console?.warn(`[bk-ot] plugin \"${plugin.name}\" init failed:`, error);\n }\n }\n }\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nimport { RUM_ATTRIBUTES } from './attributes';\n\nimport type { Attributes } from '@opentelemetry/api';\n\n// 所有插件通过同一分类模型生成检索字段,保证错误、资源、Action 等信号可按统一维度聚合。\nexport const RUM_SPAN_OUTCOME = {\n abort: 'abort',\n error: 'error',\n success: 'success',\n timeout: 'timeout',\n unknown: 'unknown',\n warning: 'warning',\n} as const;\n\nexport const RUM_SPAN_TYPE = {\n action: 'action',\n custom: 'custom',\n error: 'error',\n longTask: 'long_task',\n resource: 'resource',\n session: 'session',\n vital: 'vital',\n view: 'view',\n websocket: 'websocket',\n} as const;\n\nexport type RumRequestOutcome =\n | { error?: unknown; type: 'network_error' }\n | { error?: unknown; type: 'timeout' }\n | { statusCode?: number; type: 'response' }\n | { type: 'abort' };\n\nexport interface RumResourceSpanInput {\n initiatorType?: string;\n method?: string;\n outcome?: RumRequestOutcome;\n url: string;\n}\n\nexport interface RumSpanClassification {\n outcome?: RumSpanOutcome;\n spanType: RumSpanType;\n}\n\nexport type RumSpanOutcome = (typeof RUM_SPAN_OUTCOME)[keyof typeof RUM_SPAN_OUTCOME];\n\nexport type RumSpanType = (typeof RUM_SPAN_TYPE)[keyof typeof RUM_SPAN_TYPE];\n\ninterface RumSpanNameInput {\n attributes: Attributes;\n nameHint?: string;\n spanType: RumSpanType;\n}\n\nconst getStringAttribute = (attributes: Attributes, key: string) => {\n const value = attributes[key];\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n};\n\n/**\n * 使用稳定的领域字段生成可读 Span 名称。唯一 ID、完整 URL、错误消息和数值不参与命名,避免抬高基数。\n */\nexport const buildRumSpanName = ({ attributes, nameHint, spanType }: RumSpanNameInput): string => {\n if (spanType === RUM_SPAN_TYPE.session) {\n const phase = getStringAttribute(attributes, RUM_ATTRIBUTES.sessionPhase);\n return phase ? `session.${phase}` : 'session';\n }\n if (spanType === RUM_SPAN_TYPE.view) {\n return (\n getStringAttribute(attributes, RUM_ATTRIBUTES.viewName) ??\n getStringAttribute(attributes, RUM_ATTRIBUTES.viewUrlTemplate) ??\n 'view'\n );\n }\n if (spanType === RUM_SPAN_TYPE.resource) {\n const method = getStringAttribute(attributes, 'http.request.method')?.toUpperCase();\n const urlTemplate = getStringAttribute(attributes, 'url.template');\n if (method && urlTemplate) return `${method} ${urlTemplate}`;\n const resourceType = getStringAttribute(attributes, 'resource.type');\n return resourceType ? `resource.${resourceType}` : 'resource';\n }\n if (spanType === RUM_SPAN_TYPE.action) {\n return (\n getStringAttribute(attributes, RUM_ATTRIBUTES.actionName) ??\n getStringAttribute(attributes, RUM_ATTRIBUTES.actionType) ??\n 'action'\n );\n }\n if (spanType === RUM_SPAN_TYPE.error) {\n const blankScreenReason = getStringAttribute(attributes, 'blank_screen.reason');\n if (blankScreenReason) return `blank_screen.${blankScreenReason}`;\n const cspDirective = getStringAttribute(attributes, 'csp.effective_directive');\n if (cspDirective) return `csp.${cspDirective}`;\n return nameHint?.trim() || getStringAttribute(attributes, 'error.source') || 'error';\n }\n if (spanType === RUM_SPAN_TYPE.vital) {\n return getStringAttribute(attributes, RUM_ATTRIBUTES.vitalMetric)?.toUpperCase() ?? 'vital';\n }\n if (spanType === RUM_SPAN_TYPE.longTask) {\n return getStringAttribute(attributes, RUM_ATTRIBUTES.longTaskEntryType) ?? 'long-task';\n }\n if (spanType === RUM_SPAN_TYPE.websocket) {\n const phase = getStringAttribute(attributes, RUM_ATTRIBUTES.websocketPhase);\n return phase ? `websocket.${phase}` : 'websocket';\n }\n if (spanType === RUM_SPAN_TYPE.custom) {\n return nameHint === undefined ? 'custom' : `custom.${nameHint}`;\n }\n return spanType;\n};\n\nexport interface RumUrlTarget {\n serverAddress?: string;\n serverPort?: number;\n}\n\nexport const getHttpOutcome = (statusCode: number | undefined): RumSpanOutcome => {\n if (statusCode === 408 || statusCode === 504) return RUM_SPAN_OUTCOME.timeout;\n if (typeof statusCode === 'number' && statusCode >= 400) return RUM_SPAN_OUTCOME.error;\n return RUM_SPAN_OUTCOME.success;\n};\n\n/** 请求来源与资源内容分类分开;CSS 也能发起图片/字体,不能将 initiator 当作内容类型。 */\nexport const getResourceType = (initiatorType: string, url: string) => {\n if (initiatorType === 'xmlhttprequest' || initiatorType === 'xhr') return 'xhr';\n if (initiatorType === 'fetch' || initiatorType === 'beacon') return initiatorType;\n if (['navigation', 'iframe', 'frame'].includes(initiatorType)) return 'document';\n let path = '';\n try { path = new URL(url, 'http://localhost').pathname; } catch { /* 无法解析的 URL 仅按明确的 initiator 分类。 */ }\n if (/\\.css$/i.test(path)) return 'css';\n if (/\\.(?:m?js)$/i.test(path) || initiatorType === 'script') return 'js';\n if (/\\.(?:png|jpe?g|gif|svg|ico|webp|avif|bmp|tiff?)$/i.test(path) || ['image', 'img', 'icon'].includes(initiatorType)) return 'image';\n if (/\\.(?:woff2?|ttf|otf|eot)$/i.test(path)) return 'font';\n if (/\\.(?:mp[34]|webm|ogg|wav|aac|m4[av]|mov)$/i.test(path) || ['audio', 'video'].includes(initiatorType)) return 'media';\n return 'other';\n};\n\nexport const getVitalOutcome = (rating: string | undefined): RumSpanOutcome =>\n rating === 'good' ? RUM_SPAN_OUTCOME.success : RUM_SPAN_OUTCOME.warning;\n\nexport const getUrlTarget = (url: string | undefined): RumUrlTarget => {\n if (!url) {\n return {};\n }\n try {\n const parsed = new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n return {\n serverAddress: parsed.hostname,\n serverPort: parsed.port ? Number(parsed.port) : undefined,\n };\n } catch {\n return {};\n }\n};\n\nexport const buildRumSpanAttributes = ({\n outcome = RUM_SPAN_OUTCOME.success,\n spanType,\n}: RumSpanClassification): Attributes => ({\n [RUM_ATTRIBUTES.spanType]: spanType,\n [RUM_ATTRIBUTES.outcomeType]: outcome,\n});\n\nexport const buildRumResourceSpanAttributes = ({\n initiatorType = 'other',\n method,\n outcome,\n url,\n}: RumResourceSpanInput): Attributes => {\n const target = getUrlTarget(url);\n const responseStatus =\n outcome?.type === 'response' && typeof outcome.statusCode === 'number' && outcome.statusCode > 0\n ? outcome.statusCode\n : undefined;\n const outcomeType =\n outcome?.type === 'abort'\n ? RUM_SPAN_OUTCOME.abort\n : outcome?.type === 'timeout'\n ? RUM_SPAN_OUTCOME.timeout\n : outcome?.type === 'network_error'\n ? RUM_SPAN_OUTCOME.error\n : typeof responseStatus === 'number'\n ? getHttpOutcome(responseStatus)\n : // 状态不可见可能是 opaque 成功响应,也可能是静态资源网络失败,不能据此确认成功。\n RUM_SPAN_OUTCOME.unknown;\n const normalizedMethod = method?.toUpperCase();\n return {\n ...buildRumSpanAttributes({\n outcome: outcomeType,\n spanType: RUM_SPAN_TYPE.resource,\n }),\n ...(target.serverAddress ? { 'server.address': target.serverAddress } : {}),\n ...(target.serverPort !== undefined ? { 'server.port': target.serverPort } : {}),\n 'resource.type': getResourceType(initiatorType, url),\n [RUM_ATTRIBUTES.resourceInitiatorType]: initiatorType,\n ...(normalizedMethod ? { 'http.request.method': normalizedMethod } : {}),\n ...(typeof responseStatus === 'number' ? { 'http.response.status_code': responseStatus } : {}),\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\n\nimport type { Attributes } from '@opentelemetry/api';\n\nexport type BkOTSessionLifecycleEvent =\n | {\n /** false 表示仅截断本地关联,expiredAt 不是已确认的全局结束时间,不能据此生成结束遥测。 */\n endTimeKnown?: boolean;\n expiredAt: number;\n id: string;\n reason: 'external' | 'inactivity' | 'maxLifetime';\n type: 'expired';\n }\n | {\n /** 本 Tab 绑定该 Session 的生效时间,不等同于共享 Session 的创建时间。 */\n activatedAt?: number;\n id: string;\n previousId?: string;\n reason: 'inactivity' | 'init' | 'maxLifetime' | 'shared';\n startedAt: number;\n type: 'renewed';\n };\n\nexport interface BkOTStartViewOptions {\n attributes?: Attributes;\n name?: string;\n url?: string;\n /** 框架路由定义中的低基数路径,例如 /orders/:orderId;优先于 URL 推断。 */\n urlTemplate?: string;\n}\n\nexport interface BkOTUserContext {\n /** 由接入方传入并由 SDK 原样透传;SDK 不 hash、不脱敏、不改写。 */\n id?: string;\n}\n\nexport type BkOTViewCommand =\n | { attributes: Attributes; type: 'set_context' }\n | { elapsed?: number; name: string; time: number; type: 'add_timing' }\n | { key: string; type: 'set_context_property'; value: Attributes[string] }\n | { name: string; type: 'set_name' }\n | { options: BkOTStartViewOptions; relativeStartedAt?: number; startedAt?: number; type: 'start' }\n | { time: number; type: 'set_loading_time' };\n\nexport interface BkOTViewContext {\n attributes?: Attributes;\n /** 清空 View 时传递已确认的结束边界,供迟到指标归属;不是接收通知的时间。 */\n endedAt?: number;\n id?: string;\n interactionCountAtEnd?: number;\n /** 原生交互计数在 View 边界的快照,供迟安装的 INP 采集器恢复分位数基线。 */\n interactionCountAtStart?: number;\n loadingType?: 'bf_cache' | 'initial_load' | 'route_change' | 'session_renewal';\n name?: string;\n relativeEndedAt?: number;\n /** 与 PerformanceEntry.startTime 同一时钟;不能由 timeOrigin 与墙钟差值推导。 */\n relativeStartedAt?: number;\n startedAt?: number;\n url?: string;\n urlTemplate?: string;\n}\n\nconst PROTECTED_VIEW_ATTRIBUTE_KEYS = new Set<string>(Object.values(RUM_ATTRIBUTES));\n\n/** OTel 属性只允许标量和标量数组;复制数组即可隔离调用方、当前状态与历史快照。 */\nexport const copyAttributes = (attributes: Attributes = {}): Attributes =>\n Object.fromEntries(\n Object.entries(attributes).map(([key, value]) => [key, Array.isArray(value) ? value.slice() : value]),\n );\nconst SESSION_ATTRIBUTE_KEYS = [\n RUM_ATTRIBUTES.sessionId,\n RUM_ATTRIBUTES.sessionHasReplay,\n RUM_ATTRIBUTES.sessionType,\n RUM_ATTRIBUTES.sessionStartTime,\n RUM_ATTRIBUTES.sessionLastActivityTime,\n];\n\n// 只在捕获/结束 Action 时换算一次;迟到 RT 不能再用恢复后的墙钟反推旧动作边界。\nconst captureRelativeTime = (epoch: number) =>\n typeof performance !== 'undefined' ? performance.now() - (Date.now() - epoch) : undefined;\n\n/**\n * 管理 SDK 运行期公共属性快照。\n *\n * 这里仅保存“后续事件都需要带上”的低成本上下文,Session/View/用户切换时更新快照,\n * 插件发 Span 时读取当前快照即可,避免每个插件重复维护公共字段。\n */\nexport class RumRuntimeContext {\n // 每个 Action 独立保留关联区间,结束较早的动作不能截断仍在进行的重叠动作。\n private readonly actionHistory = new Map<\n string,\n {\n attributes: Attributes;\n endedAt?: number;\n relativeEndedAt?: number;\n relativeStartedAt?: number;\n startedAt: number;\n }\n >();\n private appendActionIds = (attributes: Attributes, timestamp: number, relative = false): Attributes => {\n const sessionId = attributes[RUM_ATTRIBUTES.sessionId];\n const viewId = attributes[RUM_ATTRIBUTES.viewId];\n if (typeof sessionId !== 'string' || typeof viewId !== 'string') return attributes;\n const actionIds = [...this.actionHistory]\n .filter(\n ([, entry]) =>\n (relative ? (entry.relativeStartedAt ?? Infinity) : entry.startedAt) <= timestamp &&\n ((relative ? entry.relativeEndedAt : entry.endedAt) === undefined ||\n timestamp < (relative ? entry.relativeEndedAt! : entry.endedAt!)) &&\n entry.attributes[RUM_ATTRIBUTES.sessionId] === sessionId &&\n entry.attributes[RUM_ATTRIBUTES.viewId] === viewId,\n )\n .map(([id]) => id);\n if (actionIds.length) attributes[RUM_ATTRIBUTES.actionIds] = actionIds;\n return attributes;\n };\n private readonly attributes: Attributes = {};\n private readonly queuedViewCommands: BkOTViewCommand[] = [];\n\n // 保存关联关系的生效区间,供延迟到达的 PerformanceEntry 按事件时间回查原 Session/View/Action。\n private recordAssociation = (\n history: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }>,\n keys: Iterable<string>,\n changedAt: number,\n active: boolean,\n ) => {\n const previous = history.at(-1);\n if (previous && previous.endedAt === undefined) previous.endedAt = Math.max(previous.startedAt, changedAt);\n if (active) {\n const associationAttributes: Attributes = {};\n for (const key of keys) {\n const value = this.attributes[key];\n if (value !== undefined) associationAttributes[key] = value;\n }\n history.push({ attributes: associationAttributes, startedAt: changedAt });\n }\n if (history.length > 100) history.splice(0, history.length - 100);\n };\n private sampled = false;\n private readonly samplingHistory: Array<{ endedAt?: number; sampled: boolean; startedAt: number }> = [];\n private readonly sessionHistory: Array<{\n activityTimes?: number[];\n attributes: Attributes;\n endedAt?: number;\n startedAt: number;\n }> = [];\n private readonly sessionLifecycleListeners = new Set<(event: BkOTSessionLifecycleEvent) => void>();\n private readonly setOptionalAttribute = (key: string, value: string | undefined) => {\n if (value === undefined) {\n delete this.attributes[key];\n return;\n }\n this.attributes[key] = value;\n };\n private user: BkOTUserContext = {};\n private view: BkOTViewContext = {};\n private readonly viewAttributeKeys = new Set<string>();\n private readonly viewChangeListeners = new Set<(view: BkOTViewContext) => void>();\n private readonly viewCommandListeners = new Set<(command: BkOTViewCommand) => void>();\n\n private readonly viewHistory: Array<{ attributes: Attributes; endedAt?: number; startedAt: number }> = [];\n\n private readonly viewLifecycles = new Map<string, { runtimeAttributes: Attributes; view: BkOTViewContext }>();\n\n private readonly viewScopedAttributeKeys = new Set<string>();\n\n public dispatchViewCommand = (command: BkOTViewCommand) => {\n if (command.type === 'start')\n command = { ...command, options: { ...command.options, attributes: copyAttributes(command.options.attributes) } };\n else if (command.type === 'set_context') command = { ...command, attributes: copyAttributes(command.attributes) };\n else if (command.type === 'set_context_property' && Array.isArray(command.value))\n command = { ...command, value: command.value.slice() };\n // autoStart 下调用方可能早于 page-view 插件发命令,先排队可避免 startView/setViewName 丢失。\n if (this.viewCommandListeners.size === 0) {\n if (command.type === 'start') {\n const previous = this.queuedViewCommands.findIndex(item => item.type === 'start');\n if (previous >= 0) this.queuedViewCommands.splice(previous, 1);\n }\n this.queuedViewCommands.push(command);\n return;\n }\n this.viewCommandListeners.forEach(listener => listener(command));\n };\n\n public endActionContext = (id: string, endedAt: number, relativeEndedAt?: number) => {\n const entry = this.actionHistory.get(id);\n if (!entry) return;\n // 待定身份回填后可能发现更早的 View 边界,只能进一步截断,不重新开放旧窗口。\n entry.endedAt = Math.min(entry.endedAt ?? Infinity, Math.max(entry.startedAt, endedAt));\n // 历史 View 边界使用当时捕获的相对时刻;普通超时的回填基于动作起点,\n // 且不越过当前相对时间,避免休眠后用新 offset 把旧窗口截到起点。\n const relativeEnd =\n relativeEndedAt ??\n (entry.relativeStartedAt === undefined || typeof performance === 'undefined'\n ? undefined\n : Math.min(performance.now(), entry.relativeStartedAt + endedAt - entry.startedAt));\n if (relativeEnd !== undefined && entry.relativeStartedAt !== undefined) {\n entry.relativeEndedAt = Math.min(\n entry.relativeEndedAt ?? Infinity,\n Math.max(entry.relativeStartedAt, relativeEnd),\n );\n }\n // 只裁剪已关闭的历史;仍在进行的动作不会因为其他动作结束而丢失关联。\n const closed = [...this.actionHistory]\n .filter(([, value]) => value.endedAt !== undefined)\n .sort(([, left], [, right]) => left.endedAt! - right.endedAt!);\n for (const [key] of closed.slice(0, Math.max(0, closed.length - 100))) this.actionHistory.delete(key);\n };\n\n public getAttributes = (): Attributes => this.appendActionIds(copyAttributes(this.attributes), Date.now());\n\n public getAttributesAt = (timestamp: number): Attributes => {\n if (!Number.isFinite(timestamp)) return this.getAttributes();\n const result = { ...this.attributes };\n const applyHistory = <T extends { attributes: Attributes; endedAt?: number; startedAt: number }>(\n history: T[],\n keys: Iterable<string>,\n ) => {\n // 先移除当前关联字段,再用目标时间所在的历史快照覆盖,避免把旧事件错误归到当前 View。\n for (const key of keys) delete result[key];\n const matched = [...history]\n .reverse()\n .find(entry => entry.startedAt <= timestamp && (entry.endedAt === undefined || timestamp < entry.endedAt));\n if (matched) Object.assign(result, matched.attributes);\n return matched;\n };\n const session = applyHistory(this.sessionHistory, SESSION_ATTRIBUTE_KEYS);\n // 活动时间与 Session 身份分别保存,续期不切分身份区间,也不让迟到事件携带未来活动。\n delete result[RUM_ATTRIBUTES.sessionLastActivityTime];\n const lastActivityTime = [...(session?.activityTimes ?? [])].reverse().find(time => time <= timestamp);\n if (lastActivityTime !== undefined) result[RUM_ATTRIBUTES.sessionLastActivityTime] = lastActivityTime;\n applyHistory(this.viewHistory, this.viewScopedAttributeKeys);\n return this.appendActionIds(copyAttributes(result), timestamp);\n };\n\n /** PerformanceEntry 按相对区间选择身份;epoch 只用于最终 Span 时间,不再反查身份。 */\n public getRuntimeContextAtRelativeTime = (\n relativeTime: number,\n ): undefined | { attributes: Attributes; time: number } => {\n if (!Number.isFinite(relativeTime)) return;\n const owner = [...this.viewLifecycles.values()]\n .reverse()\n .find(\n ({ view }) =>\n view.relativeStartedAt !== undefined &&\n view.relativeStartedAt <= relativeTime &&\n (view.relativeEndedAt === undefined || relativeTime < view.relativeEndedAt),\n );\n if (owner?.view.startedAt === undefined) return;\n const time = owner.view.startedAt + relativeTime - owner.view.relativeStartedAt!;\n // 与 getAttributesAt 一样保留当前用户/业务属性,仅按历史固定身份与 View 范围字段。\n // 不能把用户登录后的资源永久绑定到 View 初始化时的匿名快照。\n const attributes = copyAttributes(this.attributes);\n for (const key of [...SESSION_ATTRIBUTE_KEYS, ...this.viewScopedAttributeKeys]) {\n delete attributes[key];\n const value = owner.runtimeAttributes[key];\n if (value !== undefined) attributes[key] = Array.isArray(value) ? value.slice() : value;\n }\n delete attributes[RUM_ATTRIBUTES.sessionLastActivityTime];\n const session = [...this.sessionHistory]\n .reverse()\n .find(entry => entry.attributes[RUM_ATTRIBUTES.sessionId] === attributes[RUM_ATTRIBUTES.sessionId]);\n const activityTime = [...(session?.activityTimes ?? [])].reverse().find(value => value <= time);\n if (activityTime !== undefined) attributes[RUM_ATTRIBUTES.sessionLastActivityTime] = activityTime;\n // View 快照可能在另一个 Action 执行时刷新;资源只能关联其自身起点的动作集合。\n delete attributes[RUM_ATTRIBUTES.actionIds];\n return {\n attributes: this.appendActionIds(attributes, relativeTime, true),\n time,\n };\n };\n\n public getUser = (): BkOTUserContext => ({ ...this.user });\n\n public getView = (): BkOTViewContext => ({ ...this.view, attributes: copyAttributes(this.view.attributes) });\n\n /** 指标插件可能晚于首个路由安装,只保留每个 View 的最后快照与原始边界。 */\n public getViewHistory = () =>\n [...this.viewLifecycles.values()].map(({ view, runtimeAttributes }) => ({\n view: { ...view, attributes: copyAttributes(view.attributes) },\n runtimeAttributes: copyAttributes(runtimeAttributes),\n }));\n\n public isSessionActive = () => typeof this.attributes[RUM_ATTRIBUTES.sessionId] === 'string';\n\n public isSessionSampledAt = (timestamp: number) => {\n if (!Number.isFinite(timestamp)) return this.sampled;\n return (\n [...this.samplingHistory]\n .reverse()\n .find(entry => entry.startedAt <= timestamp && (entry.endedAt === undefined || timestamp < entry.endedAt))\n ?.sampled ?? false\n );\n };\n\n public isViewActive = () => typeof this.attributes[RUM_ATTRIBUTES.viewId] === 'string';\n\n public notifySessionLifecycle = (event: BkOTSessionLifecycleEvent) => {\n this.sessionLifecycleListeners.forEach(listener => listener(event));\n };\n\n public onSessionLifecycle = (listener: (event: BkOTSessionLifecycleEvent) => void) => {\n this.sessionLifecycleListeners.add(listener);\n return () => this.sessionLifecycleListeners.delete(listener);\n };\n\n public onViewChange = (listener: (view: BkOTViewContext) => void) => {\n this.viewChangeListeners.add(listener);\n if (this.view.id) listener(this.getView());\n return () => this.viewChangeListeners.delete(listener);\n };\n\n public onViewCommand = (listener: (command: BkOTViewCommand) => void) => {\n this.viewCommandListeners.add(listener);\n while (this.queuedViewCommands.length) {\n listener(this.queuedViewCommands.shift()!);\n }\n return () => this.viewCommandListeners.delete(listener);\n };\n\n public registerActionContext = (id: string, startedAt: number, attributes: Attributes) => {\n // 保留捕获对象引用:Session 待定期间首次点击的身份会在提交后原地回填。\n if (!this.actionHistory.has(id))\n this.actionHistory.set(id, {\n attributes,\n startedAt,\n relativeStartedAt: captureRelativeTime(startedAt),\n });\n };\n\n public setAttributes = (attributes: Attributes, changedAt = Date.now()) => {\n const previousSessionId = this.attributes[RUM_ATTRIBUTES.sessionId];\n if (RUM_ATTRIBUTES.sessionId in attributes && attributes[RUM_ATTRIBUTES.sessionId] !== previousSessionId) {\n // 新身份和未绑定状态不能继承旧 Session 的起点、活动时间或类型。\n SESSION_ATTRIBUTE_KEYS.forEach(key => delete this.attributes[key]);\n }\n for (const [key, value] of Object.entries(attributes)) {\n // 动作身份属于独立时间区间,禁止通过全局属性入口写入或恢复旧单值关联。\n if (key === RUM_ATTRIBUTES.actionId || key === RUM_ATTRIBUTES.actionIds) continue;\n if (value === undefined) {\n delete this.attributes[key];\n continue;\n }\n this.attributes[key] = Array.isArray(value) ? value.slice() : value;\n }\n const sessionId = this.attributes[RUM_ATTRIBUTES.sessionId];\n if (sessionId !== previousSessionId) {\n this.recordAssociation(this.sessionHistory, SESSION_ATTRIBUTE_KEYS, changedAt, typeof sessionId === 'string');\n }\n if (typeof sessionId === 'string') {\n const session = this.sessionHistory.at(-1);\n const lastActivityTime = this.attributes[RUM_ATTRIBUTES.sessionLastActivityTime];\n if (session && typeof lastActivityTime === 'number' && Number.isFinite(lastActivityTime)) {\n const activityTimes = (session.activityTimes ??= []);\n if (activityTimes.at(-1) !== lastActivityTime) {\n activityTimes.push(lastActivityTime);\n // 长会话仅保留近期活动明细;被裁剪的历史元数据省略,不伪造时间。\n if (activityTimes.length > 100) activityTimes.splice(0, activityTimes.length - 100);\n }\n }\n } else {\n SESSION_ATTRIBUTE_KEYS.forEach(key => delete this.attributes[key]);\n }\n };\n\n public setSessionSampled = (sampled: boolean, changedAt = Date.now()) => {\n if (sampled === this.sampled) return;\n const previous = this.samplingHistory.at(-1);\n if (previous && previous.endedAt === undefined) previous.endedAt = Math.max(previous.startedAt, changedAt);\n this.sampled = sampled;\n if (sampled) this.samplingHistory.push({ sampled, startedAt: changedAt });\n if (this.samplingHistory.length > 100) {\n this.samplingHistory.splice(0, this.samplingHistory.length - 100);\n }\n };\n\n public setUser = (user: BkOTUserContext) => {\n this.user = {\n ...this.user,\n ...user,\n };\n\n if ('id' in user) {\n if (user.id === undefined) {\n delete this.attributes[RUM_ATTRIBUTES.userId];\n return;\n }\n this.attributes[RUM_ATTRIBUTES.userId] = user.id;\n }\n };\n\n public setView = (\n view: BkOTViewContext,\n changedAt = view.id !== this.view.id ? (view.startedAt ?? Date.now()) : Date.now(),\n ) => {\n const previous = this.view.id ? this.viewLifecycles.get(this.view.id) : undefined;\n if (previous && view.id !== this.view.id) {\n previous.view.endedAt = view.endedAt ?? changedAt;\n previous.view.relativeEndedAt = view.relativeEndedAt ?? view.relativeStartedAt;\n previous.view.interactionCountAtEnd = view.interactionCountAtEnd ?? view.interactionCountAtStart;\n const latest = this.getAttributes();\n // Session 可能已经切换或解绑;冻结最新用户/业务属性时保留该 View 原本的身份。\n for (const key of Object.keys(latest)) {\n if (key.startsWith('session.') || key.startsWith('view.') || key === RUM_ATTRIBUTES.tabId) delete latest[key];\n }\n for (const [key, value] of Object.entries(previous.runtimeAttributes)) {\n if (key.startsWith('session.') || key.startsWith('view.') || key === RUM_ATTRIBUTES.tabId) latest[key] = value;\n }\n previous.runtimeAttributes = latest;\n }\n this.viewAttributeKeys.forEach(key => delete this.attributes[key]);\n this.viewAttributeKeys.clear();\n const viewAttributes: Attributes = {};\n for (const [key, value] of Object.entries(copyAttributes(view.attributes))) {\n // 自定义 View 属性不能覆盖 SDK 维护的关联和语义字段。\n if (value === undefined || PROTECTED_VIEW_ATTRIBUTE_KEYS.has(key) || key.startsWith('view.custom_timings.'))\n continue;\n viewAttributes[key] = value;\n this.attributes[key] = value;\n this.viewAttributeKeys.add(key);\n this.viewScopedAttributeKeys.add(key);\n }\n this.view = { ...view, attributes: viewAttributes };\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewId, view.id);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewUrl, view.url);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewUrlTemplate, view.urlTemplate);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewLoadingType, view.loadingType);\n this.setOptionalAttribute(RUM_ATTRIBUTES.viewName, view.name);\n [\n RUM_ATTRIBUTES.viewId,\n RUM_ATTRIBUTES.viewUrl,\n RUM_ATTRIBUTES.viewUrlTemplate,\n RUM_ATTRIBUTES.viewLoadingType,\n RUM_ATTRIBUTES.viewName,\n ].forEach(key => this.viewScopedAttributeKeys.add(key));\n this.recordAssociation(\n this.viewHistory,\n this.viewScopedAttributeKeys,\n changedAt,\n typeof view.id === 'string' && view.id.length > 0,\n );\n if (view.id) {\n this.viewLifecycles.set(view.id, { view: this.getView(), runtimeAttributes: this.getAttributes() });\n if (this.viewLifecycles.size > 100) this.viewLifecycles.delete(this.viewLifecycles.keys().next().value!);\n }\n this.viewChangeListeners.forEach(listener => listener(this.getView()));\n };\n\n public constructor(initialAttributes: Attributes = {}, user?: BkOTUserContext) {\n this.setAttributes(initialAttributes);\n if (user) {\n this.setUser(user);\n }\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { createContextKey } from '@opentelemetry/api';\n\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { RUM_SPAN_TYPE } from '../schema/span';\nimport { copyAttributes } from './runtime-context';\nimport { isBkOTEndpoint } from './url';\n\nimport type { BkOTActivityEvent } from './action-activity';\nimport type { ResolvedBkOTConfig } from './config';\nimport type { Span as ApiSpan, Attributes, Context } from '@opentelemetry/api';\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';\n\n// 仅在 SDK 到 processor 之间传递关联时刻,不进入 Span 属性或公开 API。\nexport const RUM_CONTEXT_TIME = createContextKey('bk-rum-context-time');\n// 指标等显式快照的缺失字段同样具有语义,不能再次用当前/历史属性补齐。\nexport const RUM_CONTEXT_SNAPSHOT = createContextKey('bk-rum-context-snapshot');\n\nconst SELF_TELEMETRY_URL_KEYS = ['http.url', 'url.full'];\nconst discardedSpans = new WeakSet<object>();\nconst attributeReplacements = new WeakMap<object, { attributes: Attributes; keys: Set<string> }>();\n\n/** 请求先创建 Span、后得到最终字段;setAttributes 的合并语义无法表达 Hook 删除。 */\nexport const replaceSpanAttributes = (span: ApiSpan, attributes: Attributes, replacedKeys: Iterable<string>) => {\n attributeReplacements.set(span, { attributes: copyAttributes(attributes), keys: new Set(replacedKeys) });\n};\n\nexport const markSpanDiscarded = (span: ApiSpan) => {\n discardedSpans.add(span);\n};\n\nconst getSpanUrl = (span: ReadableSpan): string | undefined => {\n for (const key of SELF_TELEMETRY_URL_KEYS) {\n const value = span.attributes?.[key];\n if (typeof value === 'string') {\n return value;\n }\n }\n return undefined;\n};\n\nconst hasSessionId = (attributes: Record<string, unknown> | undefined) => {\n const sessionId = attributes?.[RUM_ATTRIBUTES.sessionId];\n return typeof sessionId === 'string' && sessionId.length > 0;\n};\n\nconst hasViewId = (attributes: Record<string, unknown> | undefined) => {\n const viewId = attributes?.[RUM_ATTRIBUTES.viewId];\n return typeof viewId === 'string' && viewId.length > 0;\n};\n\nconst hasRumContext = (attributes: Record<string, unknown> | undefined) =>\n hasSessionId(attributes) && hasViewId(attributes);\n\nconst isSessionSpan = (attributes: Record<string, unknown> | undefined) =>\n attributes?.[RUM_ATTRIBUTES.spanType] === RUM_SPAN_TYPE.session;\n\nconst canAssociateAction = (attributes: Attributes) =>\n [RUM_SPAN_TYPE.resource, RUM_SPAN_TYPE.error, RUM_SPAN_TYPE.longTask].some(\n type => attributes[RUM_ATTRIBUTES.spanType] === type,\n );\n\n/** Action 自身用单值身份,只有有明确类型的子事件携带多 Action 关联。 */\nexport const filterActionAttributes = (attributes: Attributes): Attributes => {\n if (\n attributes[RUM_ATTRIBUTES.spanType] !== RUM_SPAN_TYPE.action ||\n typeof attributes[RUM_ATTRIBUTES.actionId] !== 'string'\n ) {\n delete attributes[RUM_ATTRIBUTES.actionId];\n }\n if (!canAssociateAction(attributes)) delete attributes[RUM_ATTRIBUTES.actionIds];\n return attributes;\n};\n\nconst withAttributes = (span: ReadableSpan, attributes: Attributes): ReadableSpan => ({\n ...span,\n attributes,\n duration: span.duration,\n ended: span.ended,\n droppedAttributesCount: span.droppedAttributesCount,\n droppedEventsCount: span.droppedEventsCount,\n droppedLinksCount: span.droppedLinksCount,\n spanContext: () => span.spanContext(),\n});\n\ninterface SessionAssociation {\n checkSession: () => void;\n getAttributesAt: (at: number) => Attributes;\n isPending: (at?: number) => boolean;\n isSampled: (attributes: Attributes) => boolean;\n whenReady: (callback: () => void) => void;\n}\n\nconst getStartTime = (span: ReadableSpan | Span) =>\n span.startTime ? span.startTime[0] * 1_000 + span.startTime[1] / 1_000_000 : Date.now();\n\n/**\n * 给所有 span 固化创建时的运行时上下文,并在 onEnd 阶段过滤自身上报请求和无 RUM 上下文 span。\n */\nexport class FilteringSpanProcessor implements SpanProcessor {\n // 即使 instrumentation 在结束前才声明 span_type,也按创建时的窗口关联,而不是导出时的当前动作。\n private readonly actionContexts = new WeakMap<object, Attributes>();\n private readonly pending = new WeakMap<object, { attributes?: Attributes; ended?: ReadableSpan }>();\n private redactEnvelope(span: ReadableSpan): ReadableSpan {\n const redact = (attributes?: Attributes) => {\n const copy = copyAttributes(attributes);\n return this.config.hooks?.redactAttributes?.(copy) ?? copy;\n };\n return {\n ...span,\n attributes: redact(span.attributes),\n links: (span.links ?? []).map(link => ({\n ...link,\n context: { ...link.context },\n attributes: redact(link.attributes),\n })),\n events: (span.events ?? []).map(event => ({\n ...event,\n time: [...event.time],\n attributes: redact(event.attributes),\n })),\n spanContext: () => span.spanContext(),\n };\n }\n\n public constructor(\n private readonly inner: SpanProcessor,\n private readonly config: ResolvedBkOTConfig,\n private readonly getRuntimeAttributes: () => Attributes,\n private readonly association?: SessionAssociation,\n private readonly onError?: (event: Extract<BkOTActivityEvent, { type: 'error' }>) => void,\n ) {}\n\n public forceFlush(): Promise<void> {\n return this.inner.forceFlush();\n }\n\n public onEnd(span: ReadableSpan): void {\n const originalSpan = span;\n const pending = this.pending.get(span);\n if (pending) {\n if (!pending.attributes) {\n pending.ended = span;\n return;\n }\n this.pending.delete(span);\n // 已结束的 OTel Span 不可变;仅为导出构建一个带最终关联的只读快照。\n span = withAttributes(span, { ...pending.attributes, ...span.attributes });\n }\n const attributes = copyAttributes(span.attributes);\n const replacement = attributeReplacements.get(originalSpan);\n attributeReplacements.delete(originalSpan);\n if (replacement) {\n for (const key of replacement.keys) delete attributes[key];\n Object.assign(attributes, replacement.attributes);\n }\n filterActionAttributes(attributes);\n if (isSessionSpan(attributes)) {\n for (const key of Object.keys(attributes)) if (key.startsWith('view.')) delete attributes[key];\n }\n const actionContext = this.actionContexts.get(originalSpan);\n this.actionContexts.delete(originalSpan);\n if (canAssociateAction(attributes) && actionContext) {\n delete attributes[RUM_ATTRIBUTES.actionIds];\n if (\n attributes[RUM_ATTRIBUTES.sessionId] === actionContext[RUM_ATTRIBUTES.sessionId] &&\n attributes[RUM_ATTRIBUTES.viewId] === actionContext[RUM_ATTRIBUTES.viewId] &&\n actionContext[RUM_ATTRIBUTES.actionIds] !== undefined\n ) {\n attributes[RUM_ATTRIBUTES.actionIds] = actionContext[RUM_ATTRIBUTES.actionIds];\n }\n }\n span = withAttributes(span, attributes);\n const url = getSpanUrl(span);\n if (\n discardedSpans.delete(originalSpan) ||\n (url && isBkOTEndpoint(this.config, url)) ||\n (!hasRumContext(span.attributes) && !(isSessionSpan(span.attributes) && hasSessionId(span.attributes))) ||\n (this.association && !this.association.isSampled(span.attributes))\n ) {\n return;\n }\n try {\n // instrumentation 可在创建后添加 Event/Link 属性;最终出口统一脱敏,\n // 同时复制数组,避免 Hook 修改已结束 Span 或调用方持有的上下文。\n span = this.redactEnvelope(span);\n const event = {\n attributes: span.attributes,\n events: span.events,\n links: span.links,\n name: span.name,\n signal: 'span' as const,\n };\n if (this.config.hooks?.beforeSend?.(event) === false) return;\n span = this.redactEnvelope({\n ...span,\n attributes: event.attributes,\n name: event.name,\n events: event.events ?? [],\n links: event.links ?? [],\n });\n } catch (error) {\n if (this.config.debug) globalThis.console?.warn('[bk-ot] span filtering failed:', error);\n // 脱敏/过滤失败不能回退发送原始事件,也不能向业务调用栈抛出异常。\n return;\n }\n filterActionAttributes(span.attributes);\n // 错误挫败只统计真正通过采样/过滤的 Error,关联使用事件创建时的动作集合。\n if (span.attributes[RUM_ATTRIBUTES.spanType] === RUM_SPAN_TYPE.error) {\n const ids = span.attributes[RUM_ATTRIBUTES.actionIds];\n this.onError?.({\n type: 'error',\n time: getStartTime(span),\n actionIds: Array.isArray(ids) ? ids.filter((id): id is string => typeof id === 'string') : [],\n });\n }\n this.inner.onEnd(span);\n }\n\n public onStart(span: Span, parentContext: Context): void {\n this.association?.checkSession();\n const existingAttributes = (span as Span & { attributes?: Attributes }).attributes ?? {};\n if (parentContext.getValue?.(RUM_CONTEXT_SNAPSHOT) === true) {\n this.actionContexts.set(span, { ...existingAttributes });\n this.inner.onStart(span, parentContext);\n return;\n }\n const contextTime = parentContext.getValue?.(RUM_CONTEXT_TIME);\n const occurredAt = typeof contextTime === 'number' ? contextTime : getStartTime(span);\n if (!hasSessionId(existingAttributes) && this.association?.isPending(occurredAt)) {\n const snapshot = { ...this.getRuntimeAttributes() };\n for (const key of Object.keys(snapshot)) {\n if (\n key.startsWith('session.') ||\n key.startsWith('view.') ||\n key === RUM_ATTRIBUTES.actionId ||\n key === RUM_ATTRIBUTES.actionIds ||\n key in existingAttributes\n )\n delete snapshot[key];\n }\n span.setAttributes(snapshot);\n const pending: { attributes?: Attributes; ended?: ReadableSpan } = {};\n this.pending.set(span, pending);\n this.association.whenReady(() => {\n pending.attributes = this.association!.getAttributesAt(occurredAt);\n this.actionContexts.set(span, pending.attributes);\n if (pending.ended) this.onEnd(pending.ended);\n });\n this.inner.onStart(span, parentContext);\n return;\n }\n const missingRuntimeAttributes: Attributes = {};\n // instrumentation 显式写入的属性优先,只补齐创建时缺失的运行时上下文。\n const historical = this.association?.getAttributesAt(occurredAt);\n const runtimeAttributes = historical\n ? { ...this.getRuntimeAttributes(), ...historical }\n : this.getRuntimeAttributes();\n if (historical) {\n for (const key of Object.keys(runtimeAttributes)) {\n if (\n (key.startsWith('session.') ||\n key.startsWith('view.') ||\n key === RUM_ATTRIBUTES.actionId ||\n key === RUM_ATTRIBUTES.actionIds) &&\n !(key in historical)\n )\n delete runtimeAttributes[key];\n }\n }\n this.actionContexts.set(span, runtimeAttributes);\n for (const [key, value] of Object.entries(runtimeAttributes)) {\n if (\n key === RUM_ATTRIBUTES.actionId ||\n (key === RUM_ATTRIBUTES.actionIds && !canAssociateAction(existingAttributes))\n )\n continue;\n if (isSessionSpan(existingAttributes) && key.startsWith('view.')) continue;\n if (existingAttributes[key] === undefined && value !== undefined) missingRuntimeAttributes[key] = value;\n }\n span.setAttributes(missingRuntimeAttributes);\n this.inner.onStart(span, parentContext);\n }\n\n public shutdown(): Promise<void> {\n return this.inner.shutdown();\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nexport interface ActionTargetOptions {\n actionNameAttribute?: string;\n nameCollection?: 'explicit' | 'text';\n}\n\nexport interface ActionTargetSnapshot {\n name: string;\n nameSource: 'explicit' | 'accessible_name' | 'text' | 'fallback';\n tag: string;\n /** ::shadow 分隔各自根节点内唯一的 selector;它不是标准 CSS 组合符。 */\n selector?: string;\n path?: string[];\n width?: number;\n height?: number;\n x?: number;\n y?: number;\n}\n\nconst DEFAULT_NAME_ATTRIBUTE = 'data-bk-action-name';\nconst MAX_NAME_LENGTH = 100;\nconst MAX_DEPTH = 20;\nconst MAX_SELECTOR_LENGTH = 512;\nconst MAX_PATH_LENGTH = 2048;\nconst STABLE_ATTRIBUTES = ['data-testid', 'data-test', 'data-qa', 'data-cy', DEFAULT_NAME_ATTRIBUTE];\nconst normalize = (text: string) => text.replace(/\\s+/g, ' ').trim().slice(0, MAX_NAME_LENGTH);\n\nconst parentElement = (element: Element): Element | null => {\n // 隐私与命名沿组合树祖先查询,包含分配到 slot 的节点。\n // selector 构造仍沿各自实际根节点内的 DOM 结构定位。\n if (element.assignedSlot) return element.assignedSlot;\n if (element.parentElement) return element.parentElement;\n const root = element.getRootNode();\n return 'host' in root ? (root as ShadowRoot).host : null;\n};\n\nconst isHidden = (element: Element): boolean => {\n if (element.hasAttribute('hidden') || element.getAttribute('data-bk-privacy') === 'hidden') return true;\n const style = element.ownerDocument.defaultView?.getComputedStyle(element);\n return style?.display === 'none' || style?.visibility === 'hidden' || style?.visibility === 'collapse';\n};\n\nconst hasHiddenAncestor = (element: Element): boolean => {\n for (let current: Element | null = element; current; current = parentElement(current)) {\n if (isHidden(current)) return true;\n }\n return false;\n};\n\nconst blocksText = (element: Element): boolean =>\n isHidden(element) || element.getAttribute('aria-hidden') === 'true' || element.getAttribute('data-bk-privacy') === 'mask' ||\n /^(INPUT|TEXTAREA|SELECT)$/.test(element.tagName) ||\n element.getAttribute('contenteditable') !== null && element.getAttribute('contenteditable') !== 'false';\n\nconst hasTextBlockedAncestor = (element: Element): boolean => {\n for (let current: Element | null = element; current; current = parentElement(current)) {\n if (blocksText(current)) return true;\n }\n return false;\n};\n\nconst safeText = (element: Element): string => {\n if (hasTextBlockedAncestor(element)) return '';\n const queue: Node[] = [element];\n let text = '';\n let visited = 0;\n // 同时限制遍历开销和输出长度,读取文本前先跳过隐私子树。\n while (queue.length && visited++ < 200 && text.length < MAX_NAME_LENGTH * 4) {\n const node = queue.pop()!;\n if (node.nodeType === 3) {\n const textParent = (node as Text).assignedSlot ?? node.parentElement;\n if (textParent && !hasTextBlockedAncestor(textParent)) text += node.textContent ?? '';\n }\n else if (node.nodeType === 1 && !hasTextBlockedAncestor(node as Element)) {\n for (let i = node.childNodes.length - 1; i >= 0; i -= 1) queue.push(node.childNodes[i]!);\n }\n }\n return normalize(text);\n};\n\nconst collectName = (target: Element, options: ActionTargetOptions): Pick<ActionTargetSnapshot, 'name' | 'nameSource'> => {\n const attributes = options.actionNameAttribute ? [options.actionNameAttribute, DEFAULT_NAME_ATTRIBUTE] : [DEFAULT_NAME_ATTRIBUTE];\n let depth = 0;\n for (let current: Element | null = target; current && depth++ < MAX_DEPTH; current = parentElement(current)) {\n for (const attribute of attributes) {\n const explicitName = normalize(current.getAttribute(attribute) ?? '');\n if (explicitName) return { name: explicitName, nameSource: 'explicit' };\n }\n }\n if (options.nameCollection === 'text') {\n let automaticNameBlocked = false;\n for (let current: Element | null = target; current; current = parentElement(current)) {\n if (current.getAttribute('data-bk-privacy') === 'mask' || current.getAttribute('aria-hidden') === 'true' ||\n current.getAttribute('contenteditable') !== null && current.getAttribute('contenteditable') !== 'false') automaticNameBlocked = true;\n }\n if (!automaticNameBlocked) {\n depth = 0;\n for (let current: Element | null = target; current && depth++ < MAX_DEPTH; current = parentElement(current)) {\n if (/^(FORM|BODY|HTML|HEAD)$/.test(current.tagName)) break;\n // aria-hidden 可能只是可见装饰图标,不应因此丢掉整个点击。\n if (current.getAttribute('aria-hidden') === 'true') continue;\n const root = current.getRootNode() as Document | ShadowRoot;\n const labelledBy = (current.getAttribute('aria-labelledby') ?? '').split(/\\s+/).filter(Boolean).slice(0, 10)\n .map(id => root.getElementById?.(id)).filter((element): element is HTMLElement => !!element)\n .map(safeText).filter(Boolean).join(' ');\n const labels = 'labels' in current ? Array.from((current as HTMLInputElement).labels ?? []).slice(0, 10).map(safeText).filter(Boolean).join(' ') : '';\n const accessibleName = normalize(labelledBy || current.getAttribute('aria-label') || labels || current.getAttribute('alt') || current.getAttribute('title') || '');\n if (accessibleName) return { name: accessibleName, nameSource: 'accessible_name' };\n }\n const text = safeText(target);\n if (text) return { name: text, nameSource: 'text' };\n }\n }\n return { name: target.tagName.toLowerCase(), nameSource: 'fallback' };\n};\n\nconst escapeIdentifier = (value: string): string => {\n // 按码点转义,兼容没有 CSS.escape 的环境。\n return Array.from(value, character => `\\\\${character.codePointAt(0)!.toString(16)} `).join('');\n};\n\nconst cssIdentifier = (element: Element, value: string): string =>\n element.ownerDocument.defaultView?.CSS?.escape(value) ?? escapeIdentifier(value);\n\nconst attributeSelector = (element: Element, attribute: string): string | undefined => {\n const value = element.getAttribute(attribute);\n if (!value || value.length > 128 || /[\\u0000-\\u001f\\u007f]/.test(value)) return undefined;\n return `[${cssIdentifier(element, attribute)}=\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"]`;\n};\n\nconst stableId = (id: string): boolean =>\n !!id && id.length <= 128 && !/\\d{3}|[a-f0-9]{8}|[:\\s\\u0000-\\u001f\\u007f]/i.test(id);\n\nconst isMasked = (element: Element): boolean => {\n for (let current: Element | null = element; current; current = parentElement(current)) {\n if (current.getAttribute('data-bk-privacy') === 'mask') return true;\n }\n return false;\n};\n\nconst localSelector = (target: Element, root: Document | ShadowRoot, options: ActionTargetOptions): string | undefined => {\n const nameAttributes = [DEFAULT_NAME_ATTRIBUTE, ...(options.actionNameAttribute ? [options.actionNameAttribute] : [])];\n let suffix = '';\n let depth = 0;\n for (let current: Element | null = target; current && depth++ < MAX_DEPTH; current = current.parentElement) {\n const tag = cssIdentifier(current, current.tagName.toLowerCase());\n let position = 1;\n for (let sibling = current.previousElementSibling; sibling; sibling = sibling.previousElementSibling) {\n if (sibling.tagName === current.tagName) position += 1;\n }\n const structural = `${tag}:nth-of-type(${position})`;\n const masked = isMasked(current);\n // Only an explicitly provided Action label can escape node masking. Other IDs and\n // data attributes can contain user data, so masked nodes use structural selectors.\n const attributes = masked ? nameAttributes : [...STABLE_ATTRIBUTES, ...nameAttributes];\n const candidates = attributes.map(attribute => attributeSelector(current!, attribute)).filter((value): value is string => !!value);\n if (!masked && stableId(current.id)) candidates.push(`#${cssIdentifier(current, current.id)}`);\n candidates.push(structural);\n for (const candidate of candidates) {\n const selector = suffix ? `${candidate} > ${suffix}` : candidate;\n if (selector.length > MAX_SELECTOR_LENGTH) continue;\n const matches = root.querySelectorAll(selector);\n if (matches.length === 1 && matches[0] === target) return selector;\n }\n suffix = suffix ? `${structural} > ${suffix}` : structural;\n if (suffix.length > MAX_SELECTOR_LENGTH) return undefined;\n }\n return undefined;\n};\n\nconst captureSelector = (target: Element, options: ActionTargetOptions): string | undefined => {\n if (!target.isConnected) return undefined;\n const segments: string[] = [];\n let current = target;\n for (let depth = 0; depth < MAX_DEPTH; depth += 1) {\n const root = current.getRootNode() as Document | ShadowRoot;\n const selector = localSelector(current, root, options);\n if (!selector) return undefined;\n segments.unshift(selector);\n const complete = segments.join(' ::shadow ');\n if (complete.length > MAX_SELECTOR_LENGTH) return undefined;\n if (!('host' in root)) return complete;\n current = root.host;\n }\n return undefined;\n};\n\n/** 隐藏/隐私目标返回 undefined,调用方应跳过整个自动 Action。 */\nexport const captureActionTarget = (target: Element, event: Event, options: ActionTargetOptions = {}): ActionTargetSnapshot | undefined => {\n if (hasHiddenAncestor(target)) return undefined;\n const snapshot: ActionTargetSnapshot = { ...collectName(target, options), tag: target.tagName.toLowerCase() };\n const selector = captureSelector(target, options);\n if (selector) snapshot.selector = selector;\n const path: string[] = [];\n let pathLength = 0;\n for (const item of event.composedPath?.() ?? [target]) {\n if ((item as Node).nodeType !== 1 || hasHiddenAncestor(item as Element)) continue;\n const part = item === target ? selector : captureSelector(item as Element, options);\n if (!part) continue;\n if (path.length === 10 || pathLength + part.length > MAX_PATH_LENGTH) break;\n path.push(part);\n pathLength += part.length;\n }\n if (path.length) snapshot.path = path;\n const rect = target.getBoundingClientRect();\n if (Number.isFinite(rect.width)) snapshot.width = rect.width;\n if (Number.isFinite(rect.height)) snapshot.height = rect.height;\n const mouse = event as MouseEvent;\n // 键盘激活没有鼠标位置,事件中的零坐标只是占位值。\n const keyboardClick = mouse.detail === 0 && mouse.clientX === 0 && mouse.clientY === 0;\n if (!keyboardClick && Number.isFinite(mouse.clientX) && Number.isFinite(rect.left)) snapshot.x = mouse.clientX - rect.left;\n if (!keyboardClick && Number.isFinite(mouse.clientY) && Number.isFinite(rect.top)) snapshot.y = mouse.clientY - rect.top;\n return snapshot;\n};\n\nexport const getActionNameFromElement = (target: Element, actionNameAttribute = DEFAULT_NAME_ATTRIBUTE, includeText = false): string => {\n if (hasHiddenAncestor(target)) return target.tagName.toLowerCase();\n return collectName(target, { actionNameAttribute, nameCollection: includeText ? 'text' : 'explicit' }).name;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nconst eventTimes = new WeakMap<Event, number>();\n\n/**\n * Session、Action 和 View 使用同一事件时刻。休眠时 performance.timeOrigin 与墙上时间可能漂移,\n * 因此用当前时间减去事件已流逝时间换算;缓存同一个 Event,避免监听器之间毫秒取整的偏差。\n */\nexport const getEventEpochTime = (event: Event): number => {\n const cached = eventTimes.get(event);\n if (cached !== undefined) return cached;\n const now = Date.now();\n const timestamp = event.timeStamp;\n let occurredAt = now;\n if (Number.isFinite(timestamp) && timestamp > 0) {\n if (timestamp > 1_000_000_000_000) {\n occurredAt = Math.min(now, timestamp);\n } else if (typeof performance !== 'undefined' && typeof performance.now === 'function') {\n const elapsed = performance.now() - timestamp;\n if (Number.isFinite(elapsed) && elapsed >= 0) occurredAt = now - elapsed;\n }\n }\n // Session 历史边界与 OTLP 时间转换统一使用整数 epoch 毫秒,避免浮点回算落到边界前。\n occurredAt = Math.floor(occurredAt);\n eventTimes.set(event, occurredAt);\n return occurredAt;\n};\n\n/** Event.timeStamp 在现代浏览器中直接属于 Performance 时钟,不经墙钟回算。 */\nexport const getEventRelativeTime = (event: Event): number => {\n const now = typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : 0;\n const timestamp = event.timeStamp;\n if (Number.isFinite(timestamp) && timestamp >= 0 && timestamp < 1_000_000_000_000) {\n return Math.min(now, timestamp);\n }\n return Math.max(0, now - (Date.now() - getEventEpochTime(event)));\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { captureActionTarget } from '../core/action-target';\nimport type { ActionTargetSnapshot } from '../core/action-target';\nimport { getEventEpochTime } from '../core/event-time';\nimport { createRandomId } from '../core/id';\nimport { matchesUrlList } from '../core/url';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTActivityEvent } from '../core/action-activity';\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\nexport { getActionNameFromElement } from '../core/action-target';\n\n/**\n * 用户点击采集以“点击后产生的副作用”为 Action 生命周期:请求、资源和 DOM 变化用于判断页面稳定,\n * 错误仅参与关联和挫败判定。完成后的 Action 暂缓至连击窗口结束再上报,保留每次点击的身份。\n */\nconst ACTION_VALIDATION_DELAY = 100;\nconst ACTION_END_DELAY = 100;\nconst CLICK_CHAIN_DURATION = 1_000;\nconst CLICK_CHAIN_MAX_DISTANCE = 100;\nconst DEFAULT_ACTION_MAX_DURATION = 10_000;\nconst DEFAULT_ACTION_NAME_ATTRIBUTE = 'data-bk-action-name';\n\nexport interface BkOTActionPluginOptions {\n actionNameAttribute?: string;\n maxDuration?: number;\n /** 默认仅采集显式 data 属性;设为 text 才会读取可访问名称和 DOM 文本。 */\n nameCollection?: 'explicit' | 'text';\n}\n\ntype ActionFrustrationType = 'dead_click' | 'error_click' | 'rage_click';\ntype ActionEndReason =\n | 'activity_end' | 'no_activity' | 'timeout' | 'view_change'\n | 'session_expired' | 'page_hidden' | 'page_exit' | 'shutdown';\n\ninterface ActiveAction {\n completed?: { endTime: number; loadingTime?: number; reason: ActionEndReason };\n frustrations: Set<ActionFrustrationType>;\n hadActivity: boolean;\n hadError: boolean;\n id: string;\n lastActivityTime: number;\n maxDurationTimer: ReturnType<typeof setTimeout>;\n pendingRequests: Set<string>;\n pendingViews?: Array<{ id: string; time: number; relativeTime?: number }>;\n waitingForAssociation?: boolean;\n quietTimer?: ReturnType<typeof setTimeout>;\n reportTimer?: ReturnType<typeof setTimeout>;\n runtimeAttributes: Attributes;\n startTime: number;\n target: Element;\n targetSnapshot: ActionTargetSnapshot;\n userActivity: { input: boolean; scroll: boolean; selection: boolean };\n validationTimer: ReturnType<typeof setTimeout>;\n}\n\ninterface RecentClick {\n action: ActiveAction;\n target: Element;\n x: number;\n y: number;\n}\n\nconst getParentElement = (element: Element) => {\n if (element.parentElement) {\n return element.parentElement;\n }\n const root = element.getRootNode?.();\n return typeof ShadowRoot !== 'undefined' && root instanceof ShadowRoot ? root.host : null;\n};\n\nconst getElement = (event: Event) => {\n const composedTarget = event.composedPath?.()[0];\n if (composedTarget instanceof Element) return composedTarget;\n return event.target instanceof Element ? event.target : undefined;\n};\n\nconst positiveNumber = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : fallback;\n\nexport const isDeadClickExcluded = (target: Element) => {\n let current: Element | null = target;\n if (current.tagName.toLowerCase() === 'label' && current.hasAttribute('for')) {\n current = document.getElementById(current.getAttribute('for') ?? '');\n }\n\n while (current) {\n const tagName = current.tagName.toLowerCase();\n if (\n current.hasAttribute('contenteditable') ||\n tagName === 'canvas' ||\n tagName === 'select' ||\n tagName === 'textarea'\n ) {\n return true;\n }\n if (tagName === 'a' && current.hasAttribute('href')) return true;\n if (tagName === 'input') {\n return !['button', 'checkbox', 'radio', 'range', 'reset', 'submit'].includes(\n current.getAttribute('type')?.toLowerCase() ?? 'text',\n );\n }\n current = getParentElement(current);\n }\n return false;\n};\n\nexport const createActionPlugin = (options: BkOTActionPluginOptions = {}): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n const activeActions = new Map<string, ActiveAction>();\n const pendingActions = new Set<ActiveAction>();\n const actionNameAttribute = options.actionNameAttribute || DEFAULT_ACTION_NAME_ATTRIBUTE;\n const maxDuration = positiveNumber(options.maxDuration, DEFAULT_ACTION_MAX_DURATION);\n let recentClicks: RecentClick[] = [];\n let runtimeContext: BkOTRuntimeContext | undefined;\n\n const isDeadAction = (action: ActiveAction) =>\n !action.hadActivity &&\n !action.userActivity.input &&\n !action.userActivity.scroll &&\n !action.userActivity.selection &&\n !isDeadClickExcluded(action.target);\n\n const reportAction = (action: ActiveAction) => {\n if (!pendingActions.has(action) || !runtimeContext || !action.completed) return;\n if (runtimeContext.isSessionTransitionPending?.()) {\n if (!action.waitingForAssociation) {\n action.waitingForAssociation = true;\n runtimeContext.afterSessionTransition(() => {\n // 同一轮待定 Error 也要完成过滤/关联,再确定最终挫败字段。\n queueMicrotask(() => { action.waitingForAssociation = false; reportAction(action); });\n }, true);\n }\n return;\n }\n pendingActions.delete(action);\n clearTimeout(action.reportTimer);\n if (action.hadError) action.frustrations.add('error_click');\n if (isDeadAction(action)) action.frustrations.add('dead_click');\n const frustrationTypes = ['rage_click', 'dead_click', 'error_click'].filter(type =>\n action.frustrations.has(type as ActionFrustrationType),\n ) as ActionFrustrationType[];\n const { endTime, loadingTime, reason } = action.completed;\n const target = action.targetSnapshot;\n const hasWarning = action.hadError || frustrationTypes.length > 0;\n const actionName = `click ${target.name}`;\n const attributes = {\n ...runtimeContext.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n outcome: hasWarning ? RUM_SPAN_OUTCOME.warning : RUM_SPAN_OUTCOME.success,\n spanType: RUM_SPAN_TYPE.action,\n }),\n ...action.runtimeAttributes,\n [RUM_ATTRIBUTES.actionId]: action.id,\n [RUM_ATTRIBUTES.actionName]: actionName,\n [RUM_ATTRIBUTES.actionType]: 'click',\n [RUM_ATTRIBUTES.actionTargetName]: target.name,\n [RUM_ATTRIBUTES.actionTargetTag]: target.tag,\n [RUM_ATTRIBUTES.actionNameSource]: target.nameSource,\n [RUM_ATTRIBUTES.actionEndReason]: reason,\n ...(loadingTime === undefined ? {} : { [RUM_ATTRIBUTES.actionLoadingTime]: loadingTime }),\n ...(target.selector === undefined ? {} : { [RUM_ATTRIBUTES.actionTargetSelector]: target.selector }),\n ...(target.path === undefined ? {} : { [RUM_ATTRIBUTES.actionTargetPath]: target.path }),\n ...(target.width === undefined ? {} : { [RUM_ATTRIBUTES.actionTargetWidth]: target.width }),\n ...(target.height === undefined ? {} : { [RUM_ATTRIBUTES.actionTargetHeight]: target.height }),\n ...(target.x === undefined ? {} : { [RUM_ATTRIBUTES.actionPositionX]: target.x }),\n ...(target.y === undefined ? {} : { [RUM_ATTRIBUTES.actionPositionY]: target.y }),\n ...(frustrationTypes.length ? { [RUM_ATTRIBUTES.actionFrustrationType]: frustrationTypes } : {}),\n };\n delete attributes[RUM_ATTRIBUTES.actionIds];\n const span = runtimeContext.startSpan(\n buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.action }),\n attributes,\n { rumSpanType: RUM_SPAN_TYPE.action, startTime: action.startTime },\n );\n span.end(endTime);\n };\n\n const finishAction = (\n action: ActiveAction,\n endTime: number,\n reason: ActionEndReason,\n associationEnd = Date.now(),\n relativeAssociationEnd?: number,\n ) => {\n if (!activeActions.delete(action.id) || !runtimeContext) return;\n clearTimeout(action.validationTimer);\n clearTimeout(action.quietTimer);\n clearTimeout(action.maxDurationTimer);\n // 关联窗口到确认结束时关闭;loading_time 只到最后一次页面活动。\n // 分开二者,避免等待安静期间已关联的 Error 在历史查询中突然失去归属。\n runtimeContext.endActionContext(action.id, Math.max(action.startTime, associationEnd), relativeAssociationEnd);\n action.completed = {\n endTime: Math.max(action.startTime, associationEnd),\n ...(reason === 'activity_end' ? { loadingTime: Math.max(0, endTime - action.startTime) } : {}),\n reason,\n };\n pendingActions.add(action);\n // 延迟发送以便给同一连击窗口中的各次点击标记 rage;不删除单次点击 ID。\n const reportDelay = Math.max(0, action.startTime + CLICK_CHAIN_DURATION - Date.now());\n action.reportTimer = setTimeout(() => reportAction(action), reportDelay);\n };\n\n const flushPendingActions = () => {\n [...pendingActions].forEach(reportAction);\n };\n\n const scheduleActionEnd = (action: ActiveAction) => {\n clearTimeout(action.quietTimer);\n if (!action.hadActivity || action.pendingRequests.size) return;\n const delay = Math.max(0, action.lastActivityTime + ACTION_END_DELAY - Date.now());\n action.quietTimer = setTimeout(() => finishAction(action, action.lastActivityTime, 'activity_end'), delay);\n };\n\n const markActivity = (action: ActiveAction, time: number) => {\n action.hadActivity = true;\n action.lastActivityTime = Math.max(action.lastActivityTime, time);\n scheduleActionEnd(action);\n };\n\n const isInActionWindow = (action: ActiveAction, time: number) =>\n time >= action.startTime && time <= action.startTime + maxDuration;\n\n const onActivity = (event: BkOTActivityEvent) => {\n if (event.type === 'error') {\n // 只消费过滤后 Error 的同一关联结果,不再向所有窗口广播错误归属。\n const ids = new Set(event.actionIds);\n for (const action of [...activeActions.values(), ...pendingActions]) {\n if (ids.has(action.id)) action.hadError = true;\n }\n return;\n }\n if (event.type === 'long_task') return;\n for (const action of activeActions.values()) {\n const deadline = action.startTime + maxDuration;\n if (Date.now() >= deadline) {\n finishAction(action, deadline, 'timeout', deadline);\n continue;\n }\n if (event.type === 'request_start') {\n if (event.url && matchesUrlList(runtimeContext?.config.view?.excludedActivityUrls, event.url)) continue;\n if (!isInActionWindow(action, event.time)) continue;\n action.pendingRequests.add(event.id);\n markActivity(action, event.time);\n continue;\n }\n if (event.type === 'request_end') {\n if (!action.pendingRequests.delete(event.id)) continue;\n markActivity(action, event.time);\n continue;\n }\n if (event.type === 'resource') {\n if (event.url && matchesUrlList(runtimeContext?.config.view?.excludedActivityUrls, event.url)) continue;\n if (!isInActionWindow(action, event.startTime)) continue;\n markActivity(action, Math.min(event.endTime, deadline));\n continue;\n }\n if (isInActionWindow(action, event.time)) markActivity(action, event.time);\n }\n };\n\n const finishActiveActions = (reason: ActionEndReason, endTime = Date.now(), sessionId?: string) => {\n [...activeActions.values()].forEach(action => {\n // 待定的新点击还没有 Session,不能被旧 Session 的迟到过期通知一并结束。\n if (sessionId && action.runtimeAttributes[RUM_ATTRIBUTES.sessionId] !== sessionId) return;\n finishAction(action, endTime, reason, endTime);\n });\n };\n\n const registerClick = (action: ActiveAction, event: Event) => {\n const x = 'clientX' in event && typeof event.clientX === 'number' ? event.clientX : 0;\n const y = 'clientY' in event && typeof event.clientY === 'number' ? event.clientY : 0;\n recentClicks = recentClicks.filter(click => action.startTime - click.action.startTime <= CLICK_CHAIN_DURATION);\n const lastClick = recentClicks.at(-1);\n const hasInterruptedChain = recentClicks.some(\n click => click.action.userActivity.scroll || click.action.userActivity.selection,\n );\n // 只有同一目标附近、未被滚动或选中文本打断的连续点击才视为同一连击链。\n const isSimilar =\n lastClick?.target === action.target && Math.hypot(lastClick.x - x, lastClick.y - y) <= CLICK_CHAIN_MAX_DISTANCE;\n if (hasInterruptedChain || (lastClick && !isSimilar)) recentClicks = [];\n recentClicks.push({ action, target: action.target, x, y });\n if (\n recentClicks.length >= 3 &&\n action.startTime - recentClicks[recentClicks.length - 3].action.startTime <= CLICK_CHAIN_DURATION\n ) {\n const rageSources = recentClicks.slice(-3).map(click => click.action);\n rageSources.forEach(source => source.frustrations.add('rage_click'));\n recentClicks = [];\n }\n };\n\n return {\n name: 'action',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n runtimeContext = context;\n\n const listenerOptions: AddEventListenerOptions = { capture: true, passive: true };\n\n const startAction = (event: Event) => {\n if (!event.isTrusted || document.visibilityState !== 'visible' || !context.isSampled()) return;\n if ('button' in event && typeof event.button === 'number' && event.button !== 0) return;\n const element = getElement(event);\n if (!element) return;\n const targetSnapshot = captureActionTarget(element, event, { actionNameAttribute, nameCollection: options.nameCollection });\n if (!targetSnapshot) return;\n const startTime = getEventEpochTime(event);\n const id = createRandomId('action');\n const action: ActiveAction = {\n frustrations: new Set(),\n hadActivity: false,\n hadError: false,\n id,\n lastActivityTime: startTime,\n maxDurationTimer: setTimeout(() => finishAction(action, startTime + maxDuration, 'timeout', startTime + maxDuration), Math.max(0, startTime + maxDuration - Date.now())),\n pendingRequests: new Set(),\n runtimeAttributes: context.getRuntimeAttributesAt(startTime),\n startTime,\n target: element,\n targetSnapshot,\n userActivity: { input: false, scroll: false, selection: false },\n validationTimer: setTimeout(() => {\n if (!action.hadActivity) finishAction(action, action.startTime, 'no_activity');\n }, ACTION_VALIDATION_DELAY),\n };\n activeActions.set(id, action);\n registerClick(action, event);\n context.registerActionContext(id, startTime, action.runtimeAttributes);\n if (context.isSessionTransitionPending?.()) {\n context.afterSessionTransition(() => {\n if (!activeActions.has(id) && !pendingActions.has(action)) return;\n const viewId = action.runtimeAttributes[RUM_ATTRIBUTES.viewId];\n const boundary = typeof viewId === 'string'\n ? action.pendingViews?.find(view => view.time >= startTime && view.id !== viewId)\n : undefined;\n action.pendingViews = undefined;\n if (!boundary || action.completed && action.completed.endTime <= boundary.time) return;\n if (activeActions.has(id)) finishAction(action, boundary.time, 'view_change', boundary.time, boundary.relativeTime);\n else {\n action.completed = { endTime: boundary.time, reason: 'view_change' };\n context.endActionContext(id, boundary.time, boundary.relativeTime);\n }\n // View callbacks 在 Session 身份回填前执行;回填后重放捕获期间的导航边界。\n queueMicrotask(() => reportAction(action));\n }, true);\n }\n };\n\n window.addEventListener('click', startAction, listenerOptions);\n teardownCallbacks.push(() => window.removeEventListener('click', startAction, listenerOptions));\n\n const unsubscribeActivity = context.onActivity(onActivity);\n const unsubscribeSession = context.onSessionLifecycle(event => {\n if (event.type !== 'expired') return;\n if (event.endTimeKnown === false) {\n // 未完成动作缺少可信结束边界,取消采集;已完成的动作仍保留自身确定的时间。\n for (const action of activeActions.values()) {\n if (action.runtimeAttributes[RUM_ATTRIBUTES.sessionId] !== event.id) continue;\n activeActions.delete(action.id);\n context.endActionContext(action.id, action.startTime);\n clearTimeout(action.validationTimer);\n clearTimeout(action.quietTimer);\n clearTimeout(action.maxDurationTimer);\n }\n } else finishActiveActions('session_expired', event.expiredAt, event.id);\n recentClicks = recentClicks.filter(click => click.action.runtimeAttributes[RUM_ATTRIBUTES.sessionId] !== event.id);\n flushPendingActions();\n });\n const unsubscribeView = context.onViewChange(view => {\n // Session 解绑会先清空 View,再派发 expired;由后者提供可信结束时刻或取消信号。\n if (!view.id) return;\n for (const action of [...activeActions.values(), ...pendingActions]) {\n const viewId = action.runtimeAttributes[RUM_ATTRIBUTES.viewId];\n const endedAt = view.startedAt ?? Date.now();\n if (typeof viewId !== 'string') {\n // 待定首击先保留边界,不能在不知道起始 View 时把初始化当作导航。\n (action.pendingViews ??= []).push({ id: view.id, time: endedAt, relativeTime: view.relativeStartedAt });\n continue;\n }\n if (viewId !== view.id && activeActions.has(action.id)) finishAction(action, endedAt, 'view_change', endedAt, view.relativeStartedAt);\n }\n for (const action of pendingActions) {\n const viewId = action.runtimeAttributes[RUM_ATTRIBUTES.viewId];\n if (typeof viewId === 'string' && viewId !== view.id) reportAction(action);\n }\n recentClicks = recentClicks.filter(click => !click.action.runtimeAttributes[RUM_ATTRIBUTES.viewId] || click.action.runtimeAttributes[RUM_ATTRIBUTES.viewId] === view.id);\n });\n teardownCallbacks.push(unsubscribeActivity, unsubscribeSession, unsubscribeView);\n\n const finishOnHidden = () => {\n if (document.visibilityState === 'hidden') {\n recentClicks = [];\n finishActiveActions('page_hidden');\n flushPendingActions();\n }\n };\n const finishOnPageHide = () => {\n recentClicks = [];\n finishActiveActions('page_exit');\n flushPendingActions();\n };\n window.addEventListener('pagehide', finishOnPageHide);\n document.addEventListener('visibilitychange', finishOnHidden);\n teardownCallbacks.push(\n () => window.removeEventListener('pagehide', finishOnPageHide),\n () => document.removeEventListener('visibilitychange', finishOnHidden),\n );\n\n const markUserActivity = (type: keyof ActiveAction['userActivity']) => {\n const actions = new Set([\n ...activeActions.values(),\n ...pendingActions,\n ...recentClicks.map(click => click.action),\n ]);\n actions.forEach(action => {\n action.userActivity[type] = true;\n // 滚动/选择表明用户仍在正常交互,撤销尚未上报的 rage click 判定。\n if (type !== 'input') action.frustrations.delete('rage_click');\n });\n };\n const onInput = (event: Event) => { if (event.isTrusted) markUserActivity('input'); };\n const onScroll = (event: Event) => { if (event.isTrusted) markUserActivity('scroll'); };\n const onSelectionChange = (event: Event) => { if (event.isTrusted) markUserActivity('selection'); };\n window.addEventListener('input', onInput, listenerOptions);\n window.addEventListener('scroll', onScroll, listenerOptions);\n document.addEventListener('selectionchange', onSelectionChange, listenerOptions);\n teardownCallbacks.push(\n () => window.removeEventListener('input', onInput, listenerOptions),\n () => window.removeEventListener('scroll', onScroll, listenerOptions),\n () => document.removeEventListener('selectionchange', onSelectionChange, listenerOptions),\n );\n },\n shutdown() {\n finishActiveActions('shutdown');\n flushPendingActions();\n while (teardownCallbacks.length) {\n teardownCallbacks.pop()?.();\n }\n recentClicks = [];\n runtimeContext = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport type { BkOTPlugin } from '../core/plugin';\n\nexport const EXCLUDED_ACTIVITY_MUTATIONS_ATTRIBUTE = 'data-bk-excluded-activity-mutations';\n\nconst isExcludedMutation = (mutation: MutationRecord) => {\n const target = mutation.type === 'characterData' ? mutation.target.parentElement : mutation.target;\n return target instanceof Element && Boolean(target.closest(`[${EXCLUDED_ACTIVITY_MUTATIONS_ATTRIBUTE}]`));\n};\n\n/**\n * 页面级 DOM 活动只观察一次,再通过运行时活动总线分发给 View、Action 和白屏检测。\n */\nexport const createActivityPlugin = (): BkOTPlugin => {\n let mutationObserver: MutationObserver | undefined;\n const teardownCallbacks: Array<() => void> = [];\n\n return {\n name: 'activity',\n init(context) {\n if (typeof document !== 'undefined' && typeof MutationObserver !== 'undefined') {\n mutationObserver = new MutationObserver(mutations => {\n if (mutations.length && !mutations.every(isExcludedMutation)) {\n context.notifyActivity({ time: Date.now(), type: 'dom_mutation' });\n }\n });\n mutationObserver.observe(document, { attributes: true, characterData: true, childList: true, subtree: true });\n }\n\n if (typeof window === 'undefined') return;\n\n if (typeof window.open === 'function') {\n const originalOpen = window.open;\n const patchedOpen = ((...args: Parameters<typeof window.open>) => {\n context.notifyActivity({ time: Date.now(), type: 'window_open' });\n return Reflect.apply(originalOpen, window, args);\n }) as typeof window.open;\n window.open = patchedOpen;\n teardownCallbacks.push(() => {\n if (window.open === patchedOpen) window.open = originalOpen;\n });\n }\n\n },\n shutdown() {\n mutationObserver?.disconnect();\n mutationObserver = undefined;\n while (teardownCallbacks.length) teardownCallbacks.pop()?.();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/*\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport interface BlankScreenDetection {\n contentCount: number;\n emptyCount: number;\n ignoredCount: number;\n reason: 'empty_viewport' | 'missing_root';\n score: number;\n state: 'blank' | 'content' | 'loading' | 'unknown';\n unknownCount: number;\n validCount: number;\n}\n\ntype PointState = 'blank' | 'content' | 'loading' | 'unknown';\nconst RATIOS = [0.2, 0.5, 0.8];\nconst MAX_DEPTH = 24;\nconst MAX_LAYERS = 32;\nconst MAX_TEXT_NODES = 32;\nconst MAX_TEXT_RECTS = 32;\n\nconst parentOf = (element: Element): Element | null =>\n element.parentElement ?? (element.getRootNode?.() as ShadowRoot | undefined)?.host ?? null;\n\nconst styleOf = (element: Element) => (typeof getComputedStyle === 'function' ? getComputedStyle(element) : undefined);\nconst alpha = (color: string | undefined) => {\n if (!color || color === 'transparent') return 0;\n const slashAlpha = color.match(/\\/\\s*([\\d.]+)(%)?\\s*\\)$/);\n if (slashAlpha) return Number(slashAlpha[1]) / (slashAlpha[2] ? 100 : 1);\n const rgba = color.match(/^rgba\\([^,]+,[^,]+,[^,]+,\\s*([\\d.]+)\\)$/);\n return rgba ? Number(rgba[1]) : 1;\n};\n\n/** Computed opacity does not include ancestors; a transparent app shell hides its children too. */\nconst visibility = (element: Element): 'hidden' | 'unknown' | 'visible' => {\n let current: Element | null = element;\n for (let depth = 0; current && depth < MAX_DEPTH; depth++, current = parentOf(current)) {\n const style = styleOf(current);\n if (\n style &&\n (style.display === 'none' ||\n style.contentVisibility === 'hidden' ||\n (depth === 0 && (style.visibility === 'hidden' || style.visibility === 'collapse')) ||\n Number(style.opacity || 1) === 0)\n )\n return 'hidden';\n }\n return current ? 'unknown' : 'visible';\n};\n\nconst isIgnored = (element: Element, selectors: string[]) =>\n selectors.some(selector => {\n try {\n return element.matches(selector) || Boolean(element.closest(selector));\n } catch {\n return false;\n }\n });\n\nconst directTextAtPoint = (element: Element, x: number, y: number): boolean | undefined => {\n const nodes = element.childNodes;\n if (!nodes) return false;\n for (let index = 0; index < Math.min(nodes.length, MAX_TEXT_NODES); index++) {\n const node = nodes[index];\n if (node.nodeType !== 3 || !node.textContent?.trim()) continue;\n // Range checks the rendered text, including text owned by the configured root itself.\n if (typeof document.createRange !== 'function') return true;\n const range = document.createRange();\n range.selectNodeContents(node);\n const rects = range.getClientRects();\n for (let rectIndex = 0; rectIndex < Math.min(rects.length, MAX_TEXT_RECTS); rectIndex++) {\n const rect = rects[rectIndex];\n if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) return true;\n }\n if (rects.length > MAX_TEXT_RECTS) return undefined;\n }\n return nodes.length > MAX_TEXT_NODES ? undefined : false;\n};\n\nconst samplePoint = (root: Element, selectors: string[], x: number, y: number): PointState => {\n const layers =\n typeof document.elementsFromPoint === 'function'\n ? document.elementsFromPoint(x, y)\n : [document.elementFromPoint(x, y)].filter((element): element is Element => Boolean(element));\n for (const element of layers.slice(0, MAX_LAYERS)) {\n const visible = visibility(element);\n if (visible === 'hidden') continue;\n if (visible === 'unknown') return 'unknown';\n const withinRoot = element === root || root.contains(element);\n // Only an actually exposed layer can suppress sampling. A spinner underneath a white\n // overlay must not hide the overlay's blank evidence.\n if (withinRoot && isIgnored(element, selectors)) return 'loading';\n const style = styleOf(element);\n const tag = element.tagName.toLowerCase();\n if (['canvas', 'iframe', 'object', 'embed', 'video', 'svg'].includes(tag) || element.shadowRoot) return 'unknown';\n if (typeof getComputedStyle === 'function') {\n for (const pseudo of ['::before', '::after']) {\n const pseudoStyle = getComputedStyle(element, pseudo);\n if (pseudoStyle.content && !['none', 'normal', '\"\"'].includes(pseudoStyle.content)) return 'unknown';\n }\n }\n if (style?.backgroundImage && style.backgroundImage !== 'none') return 'unknown';\n if (tag === 'img') {\n const image = element as HTMLImageElement;\n return image.complete && image.naturalWidth > 0 && withinRoot ? 'content' : 'unknown';\n }\n if (withinRoot && ['input', 'textarea', 'select'].includes(tag)) return 'content';\n const text = directTextAtPoint(element, x, y);\n if (text === undefined) return 'unknown';\n if (text && (!style?.color || alpha(style.color) > 0)) return withinRoot ? 'content' : 'unknown';\n // An opaque empty top layer covers everything below. Transparent layout wrappers alone\n // are never content, regardless of their size or the number of nested elements.\n if (alpha(style?.backgroundColor) >= 1) {\n let opacity = 1;\n let ancestor: Element | null = element;\n for (let depth = 0; ancestor && depth < MAX_DEPTH; depth++, ancestor = parentOf(ancestor)) {\n opacity *= Number(styleOf(ancestor)?.opacity || 1);\n }\n if (opacity >= 1) return 'blank';\n }\n }\n return layers.length > MAX_LAYERS ? 'unknown' : 'blank';\n};\n\nexport const detectBlankScreen = (\n rootSelector: string,\n ignoredSelectors: string[],\n threshold = 0.8,\n): BlankScreenDetection => {\n const configuredRoot = document.querySelector(rootSelector);\n const root = configuredRoot ?? document.body ?? document.documentElement;\n const counts = { blank: 0, content: 0, loading: 0, unknown: 0 };\n const rect = root?.getBoundingClientRect?.();\n // A scoped content root is sampled inside its visible rectangle; empty zero-size roots\n // still use the viewport so an unmounted app does not silently become unobservable.\n const left = rect && rect.width > 0 ? Math.max(0, rect.left) : 0;\n const top = rect && rect.height > 0 ? Math.max(0, rect.top) : 0;\n const right = rect && rect.width > 0 ? Math.min(window.innerWidth, rect.right) : window.innerWidth;\n const bottom = rect && rect.height > 0 ? Math.min(window.innerHeight, rect.bottom) : window.innerHeight;\n for (const y of RATIOS)\n for (const x of RATIOS) {\n const state =\n root && right > left && bottom > top\n ? samplePoint(root, ignoredSelectors, left + (right - left) * x, top + (bottom - top) * y)\n : 'unknown';\n counts[state]++;\n }\n const validCount = counts.blank + counts.content;\n const score = validCount ? counts.blank / validCount : 0;\n // At least half the sample needs interpretable evidence. Unknown media/mostly covered\n // loading regions cannot turn one remaining empty point into a white-screen incident.\n const state: PointState =\n validCount >= 5\n ? score >= threshold\n ? 'blank'\n : 'content'\n : counts.loading > counts.unknown\n ? 'loading'\n : 'unknown';\n return {\n contentCount: counts.content,\n emptyCount: counts.blank,\n ignoredCount: counts.loading,\n unknownCount: counts.unknown,\n reason: configuredRoot ? 'empty_viewport' : 'missing_root',\n score,\n state,\n validCount,\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { createRandomId } from '../core/id';\nimport { matchesUrlList } from '../core/url';\nimport { buildRumSpanAttributes, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\nimport { detectBlankScreen } from './blank-screen-detection';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { BlankScreenDetection } from './blank-screen-detection';\nimport type { Attributes } from '@opentelemetry/api';\n\nexport { detectBlankScreen } from './blank-screen-detection';\n\nexport interface BkOTBlankScreenPluginOptions {\n /** 每次页面活动后的稳定等待,默认 1000ms。 */\n checkDelay?: number;\n /** 空白候选连续确认的间隔,默认 200ms;新活动会取消确认。 */\n confirmationDelay?: number;\n /** loading、骨架屏选择器;追加到内置规则。 */\n ignoreSelectors?: string[];\n /** 文档启动或活动持续未稳定的最长等待,默认 10000ms。超时仅报告 unknown/loading。 */\n maxWait?: number;\n /** 主要业务内容根节点,默认 body;缺失时回退到视口。 */\n rootSelector?: string;\n /** 有效采样点中的空白比例,默认 0.8;有效点至少 5 个才作结论。 */\n threshold?: number;\n}\n\nconst IGNORED_SELECTORS = [\n '[data-loading=\"true\"]',\n '[aria-busy=\"true\"]',\n '.loading',\n '.is-loading',\n '.spinner',\n '.skeleton',\n '.bk-loading',\n];\nconst numberOption = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;\n\n/** Sampling and scheduling share one View-scoped state machine. A healthy or unknown sample\n * is not terminal: subsequent activity, visibility restoration and bounded probes can retry. */\nexport const createBlankScreenPlugin = (options: BkOTBlankScreenPluginOptions = {}): BkOTPlugin => {\n const checkDelay = numberOption(options.checkDelay, 1000);\n const confirmationDelay = numberOption(options.confirmationDelay, 200);\n const maxWait = Math.max(100, numberOption(options.maxWait, 10_000));\n const threshold = Math.min(1, numberOption(options.threshold, 0.8));\n const rootSelector = options.rootSelector || 'body';\n const ignoredSelectors = [...IGNORED_SELECTORS, ...(options.ignoreSelectors ?? [])];\n let cleanup: (() => void) | undefined;\n\n return {\n name: 'blank-screen',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n let disposed = false;\n let frozen = false;\n let viewId: string | undefined;\n let viewSessionId: string | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let cycleStartedAt = Date.now();\n let lastActivityAt = cycleStartedAt;\n let trigger = 'view';\n let candidateAt: number | undefined;\n let incident:\n | undefined\n | { detectedAt: number; firstDetectedAt: number; id: string; reason: BlankScreenDetection['reason'] };\n let lastObservation: string | undefined;\n const pending = new Set<string>();\n const clearTimer = () => {\n clearTimeout(timer);\n timer = undefined;\n };\n const visible = () => !frozen && document.visibilityState !== 'hidden';\n const ready = () => document.readyState !== 'loading';\n const emit = (\n phase: 'detected' | 'observation' | 'recovered',\n result: Partial<BlankScreenDetection>,\n reason: string | undefined = result.reason,\n ) => {\n const capturedId = viewId;\n if (!capturedId || disposed || !context.isSampled() || viewId !== capturedId) return;\n const at = Date.now();\n const runtime = context.getRuntimeAttributesAt?.(at) ?? context.getRuntimeAttributes();\n // 即时观测不能沿用 View 创建时的 user/activity 元数据;Session 校验可能\n // 触发切换,所以在读完动态上下文后再次核对归属,旧故障不能写入新 View。\n if (\n viewId !== capturedId ||\n runtime['view.id'] !== capturedId ||\n typeof runtime['session.id'] !== 'string' ||\n runtime['session.id'] !== viewSessionId\n )\n return;\n const error = phase === 'detected';\n const spanType = error ? RUM_SPAN_TYPE.error : RUM_SPAN_TYPE.custom;\n const attributes: Attributes = {\n ...runtime,\n ...buildRumSpanAttributes({\n spanType,\n outcome: error\n ? RUM_SPAN_OUTCOME.error\n : phase === 'recovered'\n ? RUM_SPAN_OUTCOME.success\n : RUM_SPAN_OUTCOME.unknown,\n }),\n 'blank_screen.phase': phase,\n 'blank_screen.state': result.state ?? 'unknown',\n 'blank_screen.strategy_version': 2,\n 'blank_screen.trigger': trigger,\n ...(reason ? { 'blank_screen.reason': reason } : {}),\n ...(result.score === undefined ? {} : { 'blank_screen.empty_ratio': result.score }),\n ...(result.validCount === undefined\n ? {}\n : {\n 'blank_screen.empty_sample_count': result.emptyCount,\n 'blank_screen.valid_sample_count': result.validCount,\n 'blank_screen.ignored_sample_count': result.ignoredCount,\n 'blank_screen.unknown_sample_count': result.unknownCount,\n }),\n ...(incident\n ? {\n 'blank_screen.id': incident.id,\n 'blank_screen.first_detected_at': incident.firstDetectedAt,\n 'blank_screen.detected_at': incident.detectedAt,\n ...(phase === 'recovered'\n ? {\n 'blank_screen.duration': Math.max(0, at - incident.firstDetectedAt),\n 'blank_screen.recovered_at': at,\n }\n : {}),\n }\n : {}),\n };\n const name = phase === 'detected' ? `blank_screen.${reason}` : `blank_screen.${phase}`;\n const span = context.startSpan(name, attributes, { startTime: at });\n span.end(at);\n };\n const observe = (result: Partial<BlankScreenDetection>, reason?: string) => {\n const key = `${result.state}:${reason ?? result.reason}`;\n if (key !== lastObservation) {\n emit('observation', result, reason);\n lastObservation = key;\n }\n };\n const schedule = () => {\n clearTimer();\n if (disposed || !viewId || !visible()) return;\n const now = Date.now();\n const deadline = Math.max(0, cycleStartedAt + maxWait - now);\n const delay =\n !ready() || pending.size ? deadline : Math.min(deadline, Math.max(0, lastActivityAt + checkDelay - now));\n timer = setTimeout(check, delay);\n };\n const retryLater = () => {\n clearTimer();\n if (!disposed && viewId && visible())\n timer = setTimeout(() => {\n cycleStartedAt = Date.now();\n check();\n }, maxWait);\n };\n const check = () => {\n timer = undefined;\n if (disposed || !viewId || !visible()) return;\n const now = Date.now();\n if (!ready() || pending.size || now - lastActivityAt < checkDelay) {\n candidateAt = undefined;\n if (now - cycleStartedAt >= maxWait) {\n observe({ state: ready() ? 'loading' : 'unknown' }, ready() ? 'activity_timeout' : 'document_not_ready');\n retryLater();\n } else schedule();\n return;\n }\n let result: BlankScreenDetection;\n try {\n result = detectBlankScreen(rootSelector, ignoredSelectors, threshold);\n } catch (error) {\n if (context.config.debug) globalThis.console?.warn('[bk-ot][blank-screen] detection failed:', error);\n observe({ state: 'unknown' }, 'detection_unavailable');\n retryLater();\n return;\n }\n if (result.state === 'blank') {\n if (!incident && candidateAt === undefined) {\n candidateAt = now;\n timer = setTimeout(check, confirmationDelay);\n return;\n }\n if (!incident) {\n incident = {\n id: createRandomId('blank'),\n firstDetectedAt: candidateAt!,\n detectedAt: now,\n reason: result.reason,\n };\n emit('detected', result);\n }\n } else {\n candidateAt = undefined;\n if (result.state === 'content') {\n if (incident) emit('recovered', result, incident.reason);\n incident = undefined;\n lastObservation = undefined;\n } else observe(result, result.state === 'loading' ? 'loading_visible' : 'insufficient_evidence');\n }\n // Bounded probes also cover stylesheet changes/animations without DOM mutation.\n retryLater();\n };\n const changed = (source: string) => {\n candidateAt = undefined;\n trigger = source;\n lastActivityAt = Date.now();\n // A new cycle after a completed/probed sample must get its own bounded wait.\n if (!timer || lastActivityAt - cycleStartedAt >= maxWait) cycleStartedAt = lastActivityAt;\n schedule();\n };\n const unsubscribeActivity = context.onActivity(event => {\n if (disposed || event.type === 'long_task') return;\n if (\n (event.type === 'request_start' || event.type === 'resource') &&\n event.url &&\n matchesUrlList(context.config.view?.excludedActivityUrls, event.url)\n )\n return;\n if (event.type === 'request_start') pending.add(event.id);\n if (event.type === 'request_end' && !pending.delete(event.id)) return;\n if (viewId) changed(event.type);\n });\n const unsubscribeView = context.onViewChange(view => {\n if (view.id === viewId) return;\n clearTimer();\n viewId = view.id;\n const session = context.getRuntimeAttributes()['session.id'];\n viewSessionId = typeof session === 'string' ? session : undefined;\n candidateAt = undefined;\n incident = undefined;\n lastObservation = undefined;\n cycleStartedAt = lastActivityAt = Date.now();\n trigger = 'view';\n schedule();\n });\n const onVisibility = () => {\n clearTimer();\n candidateAt = undefined;\n if (visible()) {\n cycleStartedAt = Date.now();\n changed('visible');\n }\n };\n const onReady = () => {\n cycleStartedAt = Date.now();\n changed('document_ready');\n };\n const onFreeze = () => {\n frozen = true;\n clearTimer();\n candidateAt = undefined;\n };\n const onResume = () => {\n frozen = false;\n onVisibility();\n };\n document.addEventListener('visibilitychange', onVisibility);\n document.addEventListener('DOMContentLoaded', onReady);\n document.addEventListener('freeze', onFreeze);\n document.addEventListener('resume', onResume);\n cleanup = () => {\n disposed = true;\n clearTimer();\n unsubscribeActivity();\n unsubscribeView();\n pending.clear();\n document.removeEventListener('visibilitychange', onVisibility);\n document.removeEventListener('DOMContentLoaded', onReady);\n document.removeEventListener('freeze', onFreeze);\n document.removeEventListener('resume', onResume);\n };\n },\n shutdown() {\n cleanup?.();\n cleanup = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\ninterface PendingRequestTiming {\n callEnd?: number;\n entry?: PerformanceResourceTiming;\n finished: boolean;\n initiatorType: string;\n startTime: number;\n timer?: ReturnType<typeof setTimeout>;\n url: string;\n callback?: (entry?: PerformanceResourceTiming) => void;\n}\n\nconst MAX_REQUESTS = 1000;\nconst RESOURCE_TIMING_WAIT_MS = 200;\n// 对未结束的流、缺失 RT 或浏览器观察器异常提供有界回退,不主动读取/克隆业务响应体。\nconst RESOURCE_BODY_WAIT_MS = 60_000;\nconst requests: PendingRequestTiming[] = [];\nconst normalizeUrl = (url: string) => url.replace(/#.*$/, '');\n\nconst finish = (pending: PendingRequestTiming) => {\n pending.finished = true;\n if (pending.timer !== undefined) clearTimeout(pending.timer);\n const callback = pending.callback;\n pending.callback = undefined;\n // 容量回收也会从另一条业务请求的调用栈进入这里,采集回调异常不能阻断原生请求。\n try {\n callback?.(pending.entry);\n } catch {\n /* 完成清理由请求采集端负责。 */\n }\n};\n\nexport const notifyRequestTiming = (entry: PerformanceResourceTiming) => {\n // 同一 performance 时钟坐标,避免 Date.now 的毫秒取整和系统时钟校准污染匹配。\n // 原生调用窗口之外的条目绝不借给仍在飞行的同 URL 请求。\n const candidates = requests\n .filter(\n pending =>\n normalizeUrl(pending.url) === normalizeUrl(entry.name) &&\n pending.initiatorType === entry.initiatorType &&\n entry.startTime >= pending.startTime &&\n entry.startTime <= (pending.callEnd ?? performance.now()) + 0.1,\n )\n .sort((left, right) => right.startTime - left.startTime);\n const candidate = candidates[0];\n if (!candidate || candidate.finished || candidate.entry) return;\n // 浏览器降低时钟精度时不能凭入队顺序猜测;已结束记录也参与消歧,防止迟到条目被再次认领。\n if (candidates[1]?.startTime === candidate.startTime) return;\n candidate.entry = entry;\n if (candidate.callback) finish(candidate);\n};\n\nexport const trackRequestTiming = (url: string, startTime = performance.now(), initiatorType = 'fetch') => {\n const pending: PendingRequestTiming = { startTime, url, initiatorType, finished: false };\n requests.push(pending);\n if (requests.length > MAX_REQUESTS) finish(requests.shift()!);\n return {\n // 紧贴原生 fetch/send 调用后执行,而非等待 Promise resolve 或响应结束。\n sent: () => {\n pending.callEnd = performance.now();\n },\n cancel: () => {\n finish(pending);\n },\n complete: (callback: (entry?: PerformanceResourceTiming) => void, waitForBody = false) => {\n pending.callback = callback;\n if (pending.finished || pending.entry) {\n finish(pending);\n return;\n }\n // 成功 Fetch 的 resolve 仅代表响应头可用;XHR 终止/失败才可使用短 observer 等待窗口。\n pending.timer = setTimeout(() => finish(pending), waitForBody ? RESOURCE_BODY_WAIT_MS : RESOURCE_TIMING_WAIT_MS);\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/**\n * 被观测请求的 Trace Context 规划。\n *\n * 后端 APM 只解析 W3C `traceparent`,并且要求一个后端 trace 只对应一个 API 请求,因此这里不复用\n * RUM Span 自身的 trace context,而是为每个命中白名单的请求生成独立的 trace-id/span-id,再通过\n * Span Link 把后端 trace 关联回 RUM Span。\n *\n * 如果业务已经自行设置了 trace header(`traceparent`、`sentry-trace`、b3、Datadog、sw8),则完全\n * 不注入,避免破坏业务既有的传播方式;只有可映射的合法链路才建 Link。\n *\n * `context` 承载 trace-id/span-id,`attributes` 只记录命中的格式和是否由 SDK 注入。\n * 原始厂商 header 可能包含业务标签、服务地址等内容,不进入遥测事件。\n * sw8 这类无法映射为合法 OTel id 的格式不建 Link,避免把不存在的链路提供给检索端。\n */\n\nimport { TraceFlags } from '@opentelemetry/api';\n\nimport type { Attributes, Link } from '@opentelemetry/api';\n\n/** 大小写不敏感地读取一个请求 header */\nexport type BkOTHeaderReader = (name: string) => string | undefined;\n\nexport interface BkOTRequestTracePlan {\n /** 关联后端 trace 的 Span Link;既有厂商上下文无法映射时为空 */\n links: Link[];\n /** 需要注入的 traceparent;业务已有 trace header 时为 undefined */\n traceparent?: string;\n}\n\nexport type BkOTUpstreamTraceFormat = 'b3' | 'b3-multi' | 'datadog' | 'sentry-trace' | 'sw8' | 'traceparent';\n\nexport const TRACEPARENT_HEADER = 'traceparent';\n\nconst TRACE_ID_LENGTH = 32;\nconst SPAN_ID_LENGTH = 16;\n\nconst HEX_DIGITS = '0123456789abcdef';\nconst HEX_PATTERN = /^[\\da-f]+$/;\nconst ZERO_PATTERN = /^0+$/;\nconst DECIMAL_PATTERN = /^\\d+$/;\n\n// W3C 已知前缀;是否允许追加字段还要按 version 检查,不能把 00 当作未来版本。\nconst TRACEPARENT_PATTERN = /^([\\da-f]{2})-([\\da-f]{32})-([\\da-f]{16})-([\\da-f]{2})(?:-.*)?$/;\nconst SENTRY_TRACE_PATTERN = /^([\\da-f]{32})-([\\da-f]{16})(?:-([01]))?$/;\n// Datadog 128 位 trace-id 的高 64 位放在 x-datadog-tags 的 _dd.p.tid 里\nconst DATADOG_TRACE_ID_HIGH_PATTERN = /(?:^|,)_dd\\.p\\.tid=([\\da-f]{16})(?:,|$)/;\nconst DATADOG_TRACE_ID_HIGH_DEFAULT = '0000000000000000';\n\n/** OTel 要求 id 为定长小写 hex 且不能全零 */\nconst isValidHexId = (value: string, length: number) =>\n value.length === length && HEX_PATTERN.test(value) && !ZERO_PATTERN.test(value);\n\n// b3 与 Datadog 允许 64 位 trace-id,映射到 OTel 的 128 位时按规范左侧补零\nconst normalizeTraceId = (value: string) => {\n const lower = value.toLowerCase();\n if (isValidHexId(lower, TRACE_ID_LENGTH)) return lower;\n return isValidHexId(lower, SPAN_ID_LENGTH) ? lower.padStart(TRACE_ID_LENGTH, '0') : undefined;\n};\n\nconst normalizeSpanId = (value: string) => {\n const lower = value.toLowerCase();\n return isValidHexId(lower, SPAN_ID_LENGTH) ? lower : undefined;\n};\n\nconst createRandomHexId = (length: number) => {\n const bytes = new Uint8Array(length / 2);\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\n crypto.getRandomValues(bytes);\n } else {\n for (let index = 0; index < bytes.length; index += 1) bytes[index] = Math.floor(Math.random() * 256);\n }\n let hex = '';\n for (const byte of bytes) {\n hex += HEX_DIGITS[byte >> 4] + HEX_DIGITS[byte & 15];\n }\n // 全零是 OTel 的非法 id,概率极低但必须排除\n return ZERO_PATTERN.test(hex) ? `${hex.slice(1)}1` : hex;\n};\n\n/**\n * Datadog 用十进制字符串传 64 位 id。构建目标是 es2015,不能依赖 BigInt,\n * 这里用逐位进位的方式把十进制换算成 16 位 hex。\n */\nconst decimalToHexId = (value: string) => {\n if (!DECIMAL_PATTERN.test(value)) return undefined;\n const nibbles: number[] = [];\n for (let index = 0; index < value.length; index += 1) {\n let carry = value.charCodeAt(index) - 48;\n for (let position = 0; position < nibbles.length; position += 1) {\n const product = nibbles[position] * 10 + carry;\n nibbles[position] = product % 16;\n carry = (product - (product % 16)) / 16;\n }\n while (carry > 0) {\n nibbles.push(carry % 16);\n carry = (carry - (carry % 16)) / 16;\n }\n }\n if (nibbles.length > SPAN_ID_LENGTH) return undefined;\n let hex = '';\n for (let position = nibbles.length - 1; position >= 0; position -= 1) hex += HEX_DIGITS[nibbles[position]];\n return hex.padStart(SPAN_ID_LENGTH, '0');\n};\n\ninterface UpstreamTrace {\n format: BkOTUpstreamTraceFormat;\n sampled?: boolean;\n /** 规范化后的合法 OTel id;无法映射时两者同时缺失 */\n spanId?: string;\n traceId?: string;\n}\n\n/**\n * `traceparent` 与 SDK 注入的是同一个 header,因此格式非法时视作没有既有链路:\n * 这种值后端同样无法接续,覆盖注入比保留它更有价值。\n */\nconst parseTraceparent = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n // Header 名大小写不敏感,但 W3C 的 hex 值只允许小写,不能替业务修正非法值。\n const value = getHeader(TRACEPARENT_HEADER)?.trim();\n if (!value) return undefined;\n const matched = TRACEPARENT_PATTERN.exec(value);\n if (!matched || matched[1] === 'ff' || (matched[1] === '00' && value.length !== 55)) return undefined;\n const [, , traceId, spanId, flags] = matched;\n if (!isValidHexId(traceId, TRACE_ID_LENGTH) || !isValidHexId(spanId, SPAN_ID_LENGTH)) return undefined;\n return {\n format: 'traceparent',\n sampled: (Number.parseInt(flags, 16) & 1) === 1,\n spanId,\n traceId,\n };\n};\n\nconst parseSentryTrace = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader('sentry-trace')?.trim().toLowerCase();\n if (!value) return undefined;\n const matched = SENTRY_TRACE_PATTERN.exec(value);\n if (!matched) return { format: 'sentry-trace' };\n const [, traceId, spanId, sampled] = matched;\n return {\n format: 'sentry-trace',\n ...(sampled === undefined ? {} : { sampled: sampled === '1' }),\n ...(isValidHexId(traceId, TRACE_ID_LENGTH) && isValidHexId(spanId, SPAN_ID_LENGTH) ? { spanId, traceId } : {}),\n };\n};\n\n// b3 单头:{trace-id}-{span-id}[-{sampling-state}[-{parent-span-id}]],也允许只有 0 / 1 / d\nconst parseB3Single = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader('b3')?.trim().toLowerCase();\n if (!value) return undefined;\n const [rawTraceId, rawSpanId, samplingState] = value.split('-');\n const traceId = rawTraceId ? normalizeTraceId(rawTraceId) : undefined;\n const spanId = rawSpanId ? normalizeSpanId(rawSpanId) : undefined;\n return {\n format: 'b3',\n ...(traceId && spanId ? { spanId, traceId } : {}),\n ...(samplingState ? { sampled: samplingState === '1' || samplingState === 'd' } : {}),\n };\n};\n\nconst parseB3Multi = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const rawTraceId = getHeader('x-b3-traceid')?.trim().toLowerCase();\n const rawSpanId = getHeader('x-b3-spanid')?.trim().toLowerCase();\n const samplingState = getHeader('x-b3-sampled')?.trim().toLowerCase();\n if (!rawTraceId && !rawSpanId && !samplingState) return undefined;\n const traceId = rawTraceId ? normalizeTraceId(rawTraceId) : undefined;\n const spanId = rawSpanId ? normalizeSpanId(rawSpanId) : undefined;\n return {\n format: 'b3-multi',\n ...(traceId && spanId ? { spanId, traceId } : {}),\n ...(samplingState ? { sampled: samplingState === '1' || samplingState === 'd' } : {}),\n };\n};\n\nconst parseDatadog = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const rawTraceId = getHeader('x-datadog-trace-id')?.trim();\n const rawSpanId = getHeader('x-datadog-parent-id')?.trim();\n const samplingPriority = getHeader('x-datadog-sampling-priority')?.trim();\n if (!rawTraceId && !rawSpanId && !samplingPriority) return undefined;\n const tags = getHeader('x-datadog-tags')?.trim().toLowerCase();\n const traceIdHigh =\n (tags ? DATADOG_TRACE_ID_HIGH_PATTERN.exec(tags)?.[1] : undefined) ?? DATADOG_TRACE_ID_HIGH_DEFAULT;\n const traceIdLow = rawTraceId ? decimalToHexId(rawTraceId) : undefined;\n const traceId = traceIdLow ? normalizeTraceId(`${traceIdHigh}${traceIdLow}`) : undefined;\n const spanIdHex = rawSpanId ? decimalToHexId(rawSpanId) : undefined;\n const spanId = spanIdHex ? normalizeSpanId(spanIdHex) : undefined;\n return {\n format: 'datadog',\n ...(traceId && spanId ? { spanId, traceId } : {}),\n ...(samplingPriority ? { sampled: Number(samplingPriority) > 0 } : {}),\n };\n};\n\n/**\n * sw8:{sample}-{trace-id}-{segment-id}-{span-id}-{service}-{instance}-{endpoint}-{peer},\n * 其中 trace-id 与 segment-id 是 base64 后的 SkyWalking id。它们不是 16 字节 hex,无法映射为\n * 合法的 OTel SpanContext,因此只用来阻止重复注入,不产出 traceId/spanId。\n */\nconst parseSw8 = (getHeader: BkOTHeaderReader): undefined | UpstreamTrace => {\n const value = getHeader('sw8')?.trim();\n if (!value) return undefined;\n const samplingState = value.split('-')[0];\n return {\n format: 'sw8',\n ...(samplingState ? { sampled: samplingState === '1' } : {}),\n };\n};\n\n// 按格式明确度排序:先看与 SDK 同名的 traceparent,再看其他厂商格式\nconst UPSTREAM_PARSERS = [parseTraceparent, parseSentryTrace, parseB3Single, parseB3Multi, parseDatadog, parseSw8];\n\nexport const detectUpstreamTrace = (getHeader: BkOTHeaderReader) => {\n for (const parse of UPSTREAM_PARSERS) {\n const upstream = parse(getHeader);\n if (upstream) return upstream;\n }\n return undefined;\n};\n\nconst toLink = (traceId: string, spanId: string, attributes: Attributes, sampled?: boolean): Link => ({\n attributes,\n context: {\n spanId,\n traceFlags: sampled === false ? TraceFlags.NONE : TraceFlags.SAMPLED,\n traceId,\n },\n});\n\nexport const planRequestTrace = (getHeader: BkOTHeaderReader): BkOTRequestTracePlan => {\n const upstream = detectUpstreamTrace(getHeader);\n if (!upstream) {\n // 与 RUM Span 无关的独立 trace,保证后端按 trace-id 检索时只命中这一个 API 请求\n const traceId = createRandomHexId(TRACE_ID_LENGTH);\n const spanId = createRandomHexId(SPAN_ID_LENGTH);\n const traceparent = `00-${traceId}-${spanId}-01`;\n return {\n links: [toLink(traceId, spanId, { format: 'traceparent', injected: true })],\n traceparent,\n };\n }\n // 保留既有传播方式,但绝不能用随机 id 冒充后端可查询的链路。\n if (!upstream.traceId || !upstream.spanId) return { links: [] };\n return {\n links: [\n toLink(\n upstream.traceId,\n upstream.spanId,\n // injected 恒定写出:业务自带的合法 traceparent 与 SDK 注入的 format 同值,只靠 format 无法区分\n { format: upstream.format, injected: false },\n upstream.sampled,\n ),\n ],\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\n\ntype NavigationTimingPoints = PerformanceNavigationTiming & {\n activationStart?: number;\n};\n\ntype TimingPoints = PerformanceResourceTiming & {\n finalResponseHeadersStart?: number;\n workerCacheLookupStart?: number;\n workerRouterEvaluationStart?: number;\n};\n\n/** 原样写入有限、非负的浏览器时间点。 */\nconst setTimingPoint = (attributes: Record<string, number>, key: string, value: number | undefined) => {\n if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {\n attributes[key] = value;\n }\n};\n\n/** 采集 Resource 与 Navigation 共用的浏览器原始时间点。 */\nexport const getTimingPointAttributes = (entry: TimingPoints) => {\n const attributes: Record<string, number> = {};\n if (!Number.isFinite(entry.startTime) || entry.startTime < 0) return attributes;\n const setTiming = (key: string, value: number | undefined) => setTimingPoint(attributes, key, value);\n setTiming(RUM_ATTRIBUTES.timingStartTime, entry.startTime);\n setTiming(RUM_ATTRIBUTES.timingRedirectStart, entry.redirectStart);\n setTiming(RUM_ATTRIBUTES.timingRedirectEnd, entry.redirectEnd);\n setTiming(RUM_ATTRIBUTES.timingFetchStart, entry.fetchStart);\n setTiming(RUM_ATTRIBUTES.timingWorkerStart, entry.workerStart);\n setTiming(RUM_ATTRIBUTES.timingWorkerRouterEvaluationStart, entry.workerRouterEvaluationStart);\n setTiming(RUM_ATTRIBUTES.timingWorkerCacheLookupStart, entry.workerCacheLookupStart);\n setTiming(RUM_ATTRIBUTES.timingDomainLookupStart, entry.domainLookupStart);\n setTiming(RUM_ATTRIBUTES.timingDomainLookupEnd, entry.domainLookupEnd);\n setTiming(RUM_ATTRIBUTES.timingConnectStart, entry.connectStart);\n setTiming(RUM_ATTRIBUTES.timingSecureConnectionStart, entry.secureConnectionStart);\n setTiming(RUM_ATTRIBUTES.timingConnectEnd, entry.connectEnd);\n setTiming(RUM_ATTRIBUTES.timingRequestStart, entry.requestStart);\n setTiming(RUM_ATTRIBUTES.timingResponseStart, entry.responseStart);\n setTiming(RUM_ATTRIBUTES.timingFinalResponseHeadersStart, entry.finalResponseHeadersStart);\n setTiming(RUM_ATTRIBUTES.timingResponseEnd, entry.responseEnd);\n return attributes;\n};\n\n/** Navigation 专属时间点,原样上报;请求阶段由 getTimingPointAttributes 提供。 */\nexport const getNavigationTimingPointAttributes = (entry: NavigationTimingPoints) => {\n const attributes: Record<string, number> = {};\n if (!Number.isFinite(entry.startTime) || entry.startTime < 0) return attributes;\n const setTiming = (key: string, value: number | undefined) => setTimingPoint(attributes, key, value);\n setTiming(RUM_ATTRIBUTES.timingUnloadEventStart, entry.unloadEventStart);\n setTiming(RUM_ATTRIBUTES.timingUnloadEventEnd, entry.unloadEventEnd);\n setTiming(RUM_ATTRIBUTES.timingDomContentLoadedEventStart, entry.domContentLoadedEventStart);\n setTiming(RUM_ATTRIBUTES.timingDomContentLoadedEventEnd, entry.domContentLoadedEventEnd);\n setTiming(RUM_ATTRIBUTES.timingLoadEventStart, entry.loadEventStart);\n setTiming(RUM_ATTRIBUTES.timingLoadEventEnd, entry.loadEventEnd);\n setTiming(RUM_ATTRIBUTES.timingActivationStart, entry.activationStart);\n return attributes;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SpanKind } from '@opentelemetry/api';\n\nimport { getTimingPointAttributes } from '../core/performance-timing';\nimport { notifyRequestTiming } from '../core/request-timing';\nimport { shouldIgnoreRequest, shouldIgnoreUrl } from '../core/url';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumResourceSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\n\n/**\n * Resource Timing 的统一消费端:静态资源按配置生成 span;Fetch/XHR timing 转交 request 插件,\n * 与其已创建的请求 span 合并,避免同一次网络请求重复计数。\n * worker 路由相关字段与 finalResponseHeadersStart 为浏览器已提供、但 TS lib.dom 尚未声明的 Resource Timing 字段。\n */\ntype ResourceTimingWithStatus = PerformanceResourceTiming & {\n deliveryType?: string;\n finalResponseHeadersStart?: number;\n renderBlockingStatus?: string;\n responseStatus?: number;\n workerCacheLookupStart?: number;\n workerFinalRouterSource?: string;\n workerFinalSourceType?: string;\n workerMatchedRouterSource?: string;\n workerMatchedSourceType?: string;\n workerRouterEvaluationStart?: number;\n};\n\n// Chromium 的 SourceType 与规范的 RouterSource 表达同一来源;统一读取,避免上报与缓存判断口径不一致。\nconst getWorkerRouterSources = (entry: ResourceTimingWithStatus) => ({\n matched: entry.workerMatchedRouterSource || entry.workerMatchedSourceType,\n final: entry.workerFinalRouterSource || entry.workerFinalSourceType,\n});\n\n/**\n * HTTP 缓存三态语义(含协商缓存):true = 确定使用缓存,false = 确定未使用,undefined = 不确定。\n * 当前只返回 true / undefined;未确认命中不等于确认未命中,不能据此写入 false。\n * SDK 应通过采集浏览器的 deliveryType 与大小字段作为缓存命中事实来源,本字段保留为兼容性的保守判断。\n * 官方缓存观测介绍:https://www.datadoghq.com/blog/javascript-cache/#use-datadog-rum-to-improve-your-cache-setup\n * 不应叠加更复杂的启发式兜底;后续浏览器的 deliveryType 或许能更精确地表达来源,届时优先跟进原生信号。\n */\nconst getCacheHit = (entry: ResourceTimingWithStatus): true | undefined => {\n const workerSources = getWorkerRouterSources(entry);\n // SW 转发网络、合成响应也可能报告 deliveryType=cache,需先排除 SW 路径。\n if (\n entry.workerStart > 0 ||\n (entry.workerRouterEvaluationStart ?? 0) > 0 ||\n (entry.workerCacheLookupStart ?? 0) > 0 ||\n workerSources.matched ||\n workerSources.final\n ) {\n return undefined;\n }\n\n // 保留 HTTP 缓存语义:包含经过网络校验后复用正文的协商缓存。\n if (entry.deliveryType === 'cache') return true;\n if (entry.deliveryType) return undefined;\n\n // 传输量为 0 也可能来自 TAO 限制;仅在正文大小和请求时序可见时采用此兜底。\n return entry.transferSize === 0 && entry.decodedBodySize > 0 && entry.requestStart > 0 && entry.responseStart > 0\n ? true\n : undefined;\n};\n\nconst hasUnavailableResourceDetails = (entry: ResourceTimingWithStatus) =>\n entry.transferSize === 0 &&\n entry.encodedBodySize === 0 &&\n entry.decodedBodySize === 0 &&\n entry.requestStart === 0 &&\n entry.responseStart === 0 &&\n !entry.nextHopProtocol;\n\nconst areInOrder = (...values: number[]) => values.every((value, index) => index === 0 || values[index - 1] <= value);\n\nconst setTiming = (attributes: Record<string, number>, name: string, origin: number, start: number, end: number) => {\n if (!areInOrder(origin, start, end)) return;\n attributes[`resource.${name}.start`] = start - origin;\n attributes[`resource.${name}.duration`] = end - start;\n};\n\nexport const getResourceTimingAttributes = (entry: ResourceTimingWithStatus) => {\n const attributes: Record<string, number> = {};\n const commonTimings = [\n entry.startTime,\n entry.fetchStart,\n entry.domainLookupStart,\n entry.domainLookupEnd,\n entry.connectStart,\n entry.connectEnd,\n entry.requestStart,\n entry.responseStart,\n entry.responseEnd,\n ];\n // 浏览器因 TAO 或实现差异可能返回缺失/乱序时间点;整组校验可避免产生负 duration。\n if (!commonTimings.every(Number.isFinite) || !areInOrder(...commonTimings)) return attributes;\n\n setTiming(attributes, 'first_byte', entry.startTime, entry.requestStart, entry.responseStart);\n setTiming(attributes, 'download', entry.startTime, entry.responseStart, entry.responseEnd);\n if (entry.workerStart > 0 && entry.workerStart < entry.fetchStart) {\n setTiming(attributes, 'worker', entry.startTime, entry.workerStart, entry.fetchStart);\n }\n if (entry.fetchStart < entry.domainLookupEnd) {\n setTiming(attributes, 'dns', entry.startTime, entry.domainLookupStart, entry.domainLookupEnd);\n }\n if (entry.fetchStart < entry.connectEnd) {\n setTiming(attributes, 'connect', entry.startTime, entry.connectStart, entry.connectEnd);\n if (entry.connectStart <= entry.secureConnectionStart && entry.secureConnectionStart <= entry.connectEnd) {\n setTiming(attributes, 'ssl', entry.startTime, entry.secureConnectionStart, entry.connectEnd);\n }\n }\n if (\n entry.redirectEnd > entry.startTime &&\n areInOrder(entry.startTime, entry.redirectStart, entry.redirectEnd, entry.fetchStart)\n ) {\n setTiming(attributes, 'redirect', entry.startTime, entry.redirectStart, entry.redirectEnd);\n }\n return attributes;\n};\n\n/**\n * 瀑布图用:浏览器 Resource Timing 属性 → `resource.timing.*`,按协议字段表顺序排列。\n */\nconst RESOURCE_TIMING_RAW_ATTRIBUTES: ReadonlyArray<readonly [keyof ResourceTimingWithStatus, string]> = [\n ['startTime', RUM_ATTRIBUTES.resourceTimingStartTime],\n ['redirectStart', RUM_ATTRIBUTES.resourceTimingRedirectStart],\n ['redirectEnd', RUM_ATTRIBUTES.resourceTimingRedirectEnd],\n ['fetchStart', RUM_ATTRIBUTES.resourceTimingFetchStart],\n ['workerStart', RUM_ATTRIBUTES.resourceTimingWorkerStart],\n ['workerRouterEvaluationStart', RUM_ATTRIBUTES.resourceTimingWorkerRouterEvaluationStart],\n ['workerCacheLookupStart', RUM_ATTRIBUTES.resourceTimingWorkerCacheLookupStart],\n ['domainLookupStart', RUM_ATTRIBUTES.resourceTimingDomainLookupStart],\n ['domainLookupEnd', RUM_ATTRIBUTES.resourceTimingDomainLookupEnd],\n ['connectStart', RUM_ATTRIBUTES.resourceTimingConnectStart],\n ['secureConnectionStart', RUM_ATTRIBUTES.resourceTimingSecureConnectionStart],\n ['connectEnd', RUM_ATTRIBUTES.resourceTimingConnectEnd],\n ['requestStart', RUM_ATTRIBUTES.resourceTimingRequestStart],\n ['responseStart', RUM_ATTRIBUTES.resourceTimingResponseStart],\n ['finalResponseHeadersStart', RUM_ATTRIBUTES.resourceTimingFinalResponseHeadersStart],\n ['responseEnd', RUM_ATTRIBUTES.resourceTimingResponseEnd],\n];\n\n/**\n * 原样上报 RT 时间点:数值保留 0(未发生或 TAO 不可见,消费端据此选瀑布图);\n * 浏览器未提供(undefined)或空字符串不写入。\n */\nexport const getResourceTimingRawAttributes = (entry: ResourceTimingWithStatus) => {\n const attributes: Record<string, number | string> = {};\n for (const [field, key] of RESOURCE_TIMING_RAW_ATTRIBUTES) {\n const value = entry[field];\n if ((typeof value === 'number' && Number.isFinite(value)) || (typeof value === 'string' && value !== '')) {\n attributes[key] = value;\n }\n }\n const workerSources = getWorkerRouterSources(entry);\n if (workerSources.matched) attributes[RUM_ATTRIBUTES.resourceTimingWorkerMatchedRouterSource] = workerSources.matched;\n if (workerSources.final) attributes[RUM_ATTRIBUTES.resourceTimingWorkerFinalRouterSource] = workerSources.final;\n return attributes;\n};\n\nexport const getResourceDuration = (entry: ResourceTimingWithStatus) =>\n entry.duration === 0 && entry.responseEnd > entry.startTime ? entry.responseEnd - entry.startTime : entry.duration;\n\nexport const getResourcePerformanceAttributes = (entry: ResourceTimingWithStatus) => {\n const detailsUnavailable = hasUnavailableResourceDetails(entry);\n const deliveryType = entry.deliveryType === '' ? 'other' : entry.deliveryType;\n return {\n [RUM_ATTRIBUTES.cacheHit]: getCacheHit(entry),\n ...(entry.nextHopProtocol ? { [RUM_ATTRIBUTES.nextHopProtocol]: entry.nextHopProtocol } : {}),\n ...getResourceTimingAttributes(entry),\n ...getResourceTimingRawAttributes(entry),\n ...getTimingPointAttributes(entry),\n ...(deliveryType ? { 'resource.delivery_type': deliveryType } : {}),\n ...(entry.renderBlockingStatus ? { 'resource.render_blocking_status': entry.renderBlockingStatus } : {}),\n ...(detailsUnavailable\n ? {}\n : {\n // 对齐 Datadog:resource.size 取解压后 body 体积,缓存命中也能反映真实大小;\n // 网络传输量单独用 resource.transfer_size 表达(受缓存/TAO 影响可能为 0)。\n 'resource.size': entry.decodedBodySize,\n 'resource.encoded_body_size': entry.encodedBodySize,\n 'resource.decoded_body_size': entry.decodedBodySize,\n 'resource.transfer_size': entry.transferSize,\n }),\n };\n};\n\n// The runtime getter is stable for an SDK instance across consent cycles. A WeakSet\n// remembers browser entry identity without retaining entries or conflating simultaneous\n// requests that happen to share URL and rounded timestamps.\nconst consumedResources = new WeakMap<object, WeakSet<PerformanceEntry>>();\n\nexport const createResourcePlugin = (emitResourceSpans = true): BkOTPlugin => {\n let observer: PerformanceObserver | undefined;\n let disposed = false;\n let drain = () => {};\n\n return {\n name: 'resource',\n drain: () => drain(),\n flush: () => drain(),\n init(context) {\n if (typeof PerformanceObserver === 'undefined') {\n return;\n }\n if (!PerformanceObserver.supportedEntryTypes?.includes('resource')) {\n return;\n }\n\n const owner = context.getRuntimeAttributes ?? context;\n const consumed = consumedResources.get(owner) ?? new WeakSet<PerformanceEntry>();\n consumedResources.set(owner, consumed);\n const scheduled = new WeakSet<PerformanceEntry>();\n const collection = context.collectionStart;\n // The first authorized document can recover pre-installation timings. Later\n // grants start a new interval; neither old sent entries nor denied-time entries\n // may be replayed merely because the browser still has them buffered.\n const allowHistory = collection?.allowInitialResourceHistory ?? collection?.isInitialDocument ?? true;\n const cutoff = allowHistory ? 0 : collection?.relativeStartedAt ?? performance.now();\n const requestOptions = typeof context.config.tracking?.request === 'object' ? context.config.tracking.request : undefined;\n const processEntry = (entry: ResourceTimingWithStatus) => {\n if (disposed) return;\n if (!entry.name || shouldIgnoreUrl(context.config, entry.name)) {\n return;\n }\n const isApi = entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest';\n if (isApi) {\n notifyRequestTiming(entry);\n // Only requests predating the first collection could never have been\n // intercepted. A runtime miss may be an intentional filter or an already\n // exported fallback, so it must never become a second Resource span.\n if (!allowHistory || !collection || entry.startTime >= collection.relativeStartedAt ||\n context.config.tracking?.request === false || shouldIgnoreRequest(context.config, entry.name) || requestOptions?.beforeSend) return;\n }\n if (!Number.isFinite(entry.startTime) || entry.startTime < cutoff || consumed.has(entry) ||\n !Number.isFinite(entry.duration) || entry.duration < 0) return;\n // 查询可能发现 Session 已过期并启动异步提交。此时身份仍未稳定,\n // 必须等 View 结束边界提交后重新查询,不能提前锁定旧快照或标记已消费。\n const resolved = context.getRuntimeContextAtRelativeTime?.(entry.startTime);\n if (context.isSessionTransitionPending?.()) {\n if (!scheduled.has(entry)) {\n scheduled.add(entry);\n context.afterSessionTransition(() => { scheduled.delete(entry); emitEntry(entry); }, true);\n }\n return;\n }\n const history = context.getRuntimeContextAtRelativeTime ? undefined : context.getViewHistory?.();\n const association = history?.slice().reverse().find(({ view }) =>\n view.relativeStartedAt !== undefined && view.relativeStartedAt <= entry.startTime &&\n (view.relativeEndedAt === undefined || entry.startTime < view.relativeEndedAt));\n // An entry outside retained/authorized View history stays unassociated; it\n // cannot be assigned to the current View just to make it exportable.\n if (context.getRuntimeContextAtRelativeTime ? !resolved : history && !association) return;\n consumed.add(entry);\n const redactedUrl = context.config.hooks.redactUrl(entry.name);\n const duration = getResourceDuration(entry);\n const startTime = resolved?.time ?? (association\n ? association.view.startedAt! + (entry.startTime - association.view.relativeStartedAt!)\n : performance.timeOrigin + entry.startTime);\n const contextAttributes = resolved?.attributes ?? association?.runtimeAttributes;\n const endTime = startTime + duration;\n // PerformanceObserver 可以迟到;由 startSpan 按条目时间查找原 Session 并采样。\n // 当前 Session 的采样结果也不能阻断旧 Fetch/XHR 的 timing 回填。\n if (emitResourceSpans || isApi) {\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumResourceSpanAttributes({\n initiatorType: entry.initiatorType || 'other',\n outcome:\n typeof entry.responseStatus === 'number'\n ? { statusCode: entry.responseStatus, type: 'response' as const }\n : undefined,\n url: redactedUrl,\n }),\n 'url.full': redactedUrl,\n 'url.template': context.config.hooks.getRequestUrlTemplate(redactedUrl),\n ...getResourcePerformanceAttributes(entry),\n };\n const span = context.startSpan(\n buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.resource }),\n attributes,\n {\n kind: SpanKind.CLIENT, rumSpanType: RUM_SPAN_TYPE.resource, startTime,\n ...(contextAttributes ? { contextTime: startTime, contextAttributes } : {}),\n },\n );\n span.end(endTime);\n }\n context.notifyActivity({ endTime, startTime, type: 'resource', url: entry.name });\n };\n const emitEntry = (entry: ResourceTimingWithStatus) => {\n try {\n processEntry(entry);\n } catch {\n // 用户 Hook 的单条异常不能中断其他条目或阻止 shutdown 清理观察器。\n }\n };\n\n drain = () => {\n if (disposed) return;\n for (const entry of (observer?.takeRecords?.() ?? []) as ResourceTimingWithStatus[]) emitEntry(entry);\n };\n\n try {\n observer = new PerformanceObserver(list => {\n for (const entry of list.getEntries() as ResourceTimingWithStatus[]) {\n emitEntry(entry);\n }\n });\n observer.observe({ type: 'resource', buffered: true });\n } catch {\n observer = undefined;\n }\n },\n shutdown() {\n if (disposed) return;\n drain();\n disposed = true;\n observer?.disconnect();\n observer = undefined;\n drain = () => {};\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\n/**\n * Fetch/XHR 请求统一采集入口。\n *\n * 同一层 patch 负责请求 span、Trace Header、页面活动与 beforeSend,避免多套 patch\n * 重复计数,也不依赖 OpenTelemetry instrumentation 的私有方法。\n */\n\nimport { SpanKind, SpanStatusCode } from '@opentelemetry/api';\n\nimport { createRandomId } from '../core/id';\nimport { markSpanDiscarded, replaceSpanAttributes } from '../core/processor';\nimport { trackRequestTiming } from '../core/request-timing';\nimport { detectUpstreamTrace, planRequestTrace, TRACEPARENT_HEADER } from '../core/trace-context';\nimport {\n matchesUrlList,\n shouldIgnoreRequest,\n shouldIgnoreUrl,\n shouldPropagateTraceHeader,\n toAbsoluteUrl,\n} from '../core/url';\nimport { buildRumResourceSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\nimport { getResourceDuration, getResourcePerformanceAttributes } from './resource';\n\nimport type { BkOTRequestConfig, BkOTRequestContext, BkOTRequestOutcome } from '../core/config';\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { BkOTHeaderReader, BkOTRequestTracePlan } from '../core/trace-context';\nimport type { Attributes, Span } from '@opentelemetry/api';\n\ninterface RequestDetails {\n method?: string;\n ownedAttributeKeys?: string[];\n relativeStartedAt?: number;\n startedAt?: number;\n url?: string;\n}\n\nconst getRequestOptions = (context: BkOTRuntimeContext) =>\n typeof context.config.tracking.request === 'object' ? context.config.tracking.request : undefined;\n\n// 没有白名单时不会注入任何 header,也就不需要为探测既有 trace header 付出 patch 成本。\nconst hasTracingAllowlist = (context: BkOTRuntimeContext) => {\n const allowed = getRequestOptions(context)?.allowedTracingUrls;\n return Array.isArray(allowed) ? allowed.length > 0 : allowed !== undefined;\n};\n\nconst getErrorName = (error: unknown) =>\n typeof error === 'object' && error && 'name' in error && typeof error.name === 'string' ? error.name : '';\n\nconst getFetchFailureOutcome = (signal: AbortSignal | null | undefined, error: unknown): BkOTRequestOutcome => {\n if (getErrorName(signal?.reason) === 'TimeoutError' || getErrorName(error) === 'TimeoutError') {\n return { error, type: 'timeout' };\n }\n if (signal?.aborted || getErrorName(error) === 'AbortError') return { type: 'abort' };\n return { error, type: 'network_error' };\n};\n\nconst getXhrOutcome = (\n completionType: 'abort' | 'error' | 'load' | 'timeout',\n xhr: Pick<XMLHttpRequest, 'status'>,\n): BkOTRequestOutcome => {\n if (completionType === 'abort') return { type: 'abort' };\n if (completionType === 'timeout') return { type: 'timeout' };\n if (completionType === 'error' || xhr.status === 0) return { type: 'network_error' };\n return { statusCode: xhr.status, type: 'response' };\n};\n\nconst isErrorOutcome = (outcome: BkOTRequestOutcome) =>\n outcome.type === 'network_error' ||\n outcome.type === 'timeout' ||\n (outcome.type === 'response' && typeof outcome.statusCode === 'number' && outcome.statusCode >= 400);\n\nconst getFetchUrl = (input: RequestInfo | URL) => {\n if (typeof input === 'string' || input instanceof URL) return toAbsoluteUrl(String(input));\n return toAbsoluteUrl(input.url);\n};\n\nconst getFetchMethod = (input: RequestInfo | URL, init?: RequestInit) =>\n (init?.method ?? (typeof Request !== 'undefined' && input instanceof Request ? input.method : 'GET')).toUpperCase();\n\nconst getFetchRequestContext = (input: RequestInfo | URL, init?: RequestInit): Request | RequestInit =>\n typeof Request !== 'undefined' && input instanceof Request ? input : (init ?? {});\n\n// RequestInit.signal 覆盖 Request.signal;null 表示明确移除原来的 signal。\nconst getFetchSignal = (input: RequestInfo | URL, init?: RequestInit) =>\n init?.signal !== undefined ? init.signal : typeof Request !== 'undefined' && input instanceof Request ? input.signal : undefined;\nconst relativeNow = () => typeof performance !== 'undefined' ? performance.now() : Date.now();\nconst requestEndTime = (details: RequestDetails, entry?: PerformanceResourceTiming, endedAt = relativeNow()) =>\n details.startedAt! + Math.max(0, (entry ? entry.startTime + getResourceDuration(entry) : endedAt) - details.relativeStartedAt!);\nconst discardRequest = (span: Span | undefined, endActivity: () => void) => {\n if (span) markSpanDiscarded(span);\n try { endActivity(); } catch { /* 采集清理失败不能阻断原生请求。 */ }\n try { span?.end(); } catch { /* 保留原生调用及其异常。 */ }\n};\n\n/** 取本次请求最终会发出的 header 集合:init.headers 一旦存在就会整体覆盖 Request 上的 header。 */\nconst getFetchRequestHeaders = (input: RequestInfo | URL, init: RequestInit | undefined) => {\n const requestHeaders = typeof Request !== 'undefined' && input instanceof Request ? input.headers : undefined;\n return new Headers(init?.headers ?? requestHeaders);\n};\n\nconst applyFetchTracePlan = (init: RequestInit | undefined, headers: Headers, plan: BkOTRequestTracePlan) => {\n if (!plan.traceparent) return init;\n headers.set(TRACEPARENT_HEADER, plan.traceparent);\n return { ...init, headers };\n};\n\nconst createHeaderReader =\n (headers: Record<string, string> | undefined): BkOTHeaderReader =>\n name =>\n headers?.[name.toLowerCase()];\n\nconst planCollectedRequestTrace = (context: BkOTRuntimeContext, getHeader: BkOTHeaderReader) => {\n // Session 提交前先采集请求,待最终归属确定后再决定是否上报;此时不能替未确定的采样结果注入后端链路。\n // 业务已有的 Trace Header 不受影响,仍保留其 Link,也不阻塞真实网络请求。\n if (context.isSessionTransitionPending?.() && !detectUpstreamTrace(getHeader)) return undefined;\n return planRequestTrace(getHeader);\n};\n\nconst isActivityExcluded = (context: BkOTRuntimeContext, url: string) =>\n shouldIgnoreUrl(context.config, url) || matchesUrlList(context.config.view.excludedActivityUrls, url);\n\nconst startRequestActivity = (context: BkOTRuntimeContext, url: string) => {\n if (isActivityExcluded(context, url)) return () => {};\n const id = createRandomId('request');\n try { context.notifyActivity({ id, time: Date.now(), type: 'request_start', url }); } catch { /* 活动订阅异常不能改变请求结果。 */ }\n let ended = false;\n return () => {\n if (ended) return;\n ended = true;\n try { context.notifyActivity({ id, time: Date.now(), type: 'request_end' }); } catch { /* 保证后续 Span 清理和原生回调继续执行。 */ }\n };\n};\n\nconst trackRequestSpanTiming = (url: string, initiatorType: 'fetch' | 'xmlhttprequest') =>\n typeof PerformanceObserver === 'undefined' || !PerformanceObserver.supportedEntryTypes?.includes('resource')\n ? {\n sent() {},\n cancel() {},\n complete(callback: (entry?: PerformanceResourceTiming) => void, _waitForBody = false) {\n callback();\n },\n }\n : trackRequestTiming(url, performance.now(), initiatorType);\n\nconst startRequestSpan = (\n context: BkOTRuntimeContext,\n subtype: 'fetch' | 'xhr',\n details: RequestDetails,\n tracePlan?: BkOTRequestTracePlan,\n) => {\n const startedAt = details.startedAt ?? Date.now();\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumResourceSpanAttributes({\n initiatorType: subtype === 'xhr' ? 'xmlhttprequest' : subtype,\n method: details.method,\n url: details.url ?? '',\n }),\n ...(details.url\n ? {\n 'url.full': context.config.hooks.redactUrl(details.url),\n 'url.template': context.config.hooks.getRequestUrlTemplate(details.url),\n }\n : {}),\n };\n details.ownedAttributeKeys = Object.keys(attributes);\n return context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.resource }), attributes, {\n kind: SpanKind.CLIENT,\n rumSpanType: RUM_SPAN_TYPE.resource,\n startTime: startedAt,\n ...(tracePlan ? { links: tracePlan.links } : {}),\n });\n};\n\nexport const decorateRequestSpan = (\n context: BkOTRuntimeContext,\n span: Span,\n subtype: 'fetch' | 'xhr',\n domainContext: BkOTRequestContext,\n outcome: BkOTRequestOutcome,\n details: RequestDetails = {},\n performanceAttributes: Attributes = {},\n) => {\n const sourceUrl = details.url;\n const redactedUrl = sourceUrl ? context.config.hooks.redactUrl(sourceUrl) : undefined;\n const method = details.method;\n const attributes: Attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumResourceSpanAttributes({\n initiatorType: subtype === 'xhr' ? 'xmlhttprequest' : subtype,\n method,\n outcome,\n url: redactedUrl ?? '',\n }),\n ...(redactedUrl ? { 'url.full': redactedUrl } : {}),\n // 模板由原始 URL 推导:Hook 可能需要 query 才能判断路由,产出的模板本身是低基数的\n ...(sourceUrl ? { 'url.template': context.config.hooks.getRequestUrlTemplate(sourceUrl) } : {}),\n ...performanceAttributes,\n };\n\n const replacedKeys = new Set([...(details.ownedAttributeKeys ?? []), ...Object.keys(attributes)]);\n const event = {\n attributes,\n resource: {\n method,\n outcome,\n transport: subtype,\n url: redactedUrl,\n },\n type: 'resource' as const,\n };\n let shouldSend: boolean | void = true;\n try {\n shouldSend = getRequestOptions(context)?.beforeSend?.(event, domainContext);\n } catch (error) {\n if (context.config.debug) globalThis.console?.warn('[bk-ot] request.beforeSend failed:', error);\n }\n const redactedAttributes = context.applyRedact(event.attributes);\n span.setAttributes(redactedAttributes);\n replaceSpanAttributes(span, redactedAttributes, replacedKeys);\n span.updateName(buildRumSpanName({ attributes: redactedAttributes, spanType: RUM_SPAN_TYPE.resource }));\n if (shouldSend === false) {\n // SpanProcessor 在 onEnd 统一识别内部状态,避免这里绕过正常的 span 结束流程。\n markSpanDiscarded(span);\n return;\n }\n if (isErrorOutcome(outcome)) span.setStatus({ code: SpanStatusCode.ERROR });\n};\n\nexport const createCommonInstrumentationsPlugin = (option: BkOTRequestConfig | boolean | undefined): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n const activeRequestEnds = new Set<() => void>();\n\n return {\n name: 'request',\n enabled: option !== false,\n init(context) {\n if (typeof window === 'undefined') return;\n\n if (typeof window.fetch === 'function') {\n const originalFetch = window.fetch;\n const patchedFetch: typeof window.fetch = async function (this: Window, input, init) {\n let url = '';\n let details: RequestDetails = {};\n let span: Span | undefined;\n let endActivity = () => {};\n let requestContext: Request | RequestInit = {};\n let requestInit = init;\n let signal: AbortSignal | null | undefined;\n try {\n url = getFetchUrl(input);\n if (context.isSampled() && !shouldIgnoreRequest(context.config, url)) {\n details = { method: getFetchMethod(input, init), startedAt: Date.now(), relativeStartedAt: relativeNow(), url };\n const headers = shouldPropagateTraceHeader(context.config, url) ? getFetchRequestHeaders(input, init) : undefined;\n const tracePlan = headers ? planCollectedRequestTrace(context, name => headers.get(name) ?? undefined) : undefined;\n span = startRequestSpan(context, 'fetch', details, tracePlan);\n endActivity = startRequestActivity(context, url);\n requestContext = getFetchRequestContext(input, init);\n signal = getFetchSignal(input, init);\n requestInit = headers && tracePlan ? applyFetchTracePlan(init, headers, tracePlan) : init;\n }\n } catch {\n discardRequest(span, endActivity);\n return originalFetch.call(this, input, init);\n }\n if (!span) return originalFetch.call(this, input, init);\n let ended = false;\n let domainContext: BkOTRequestContext | undefined;\n let outcome: BkOTRequestOutcome | undefined;\n let completedAt = relativeNow();\n let removeAbortListener = () => {};\n const endSpan = (entry?: PerformanceResourceTiming, fallbackEndTime = relativeNow()) => {\n if (ended) return;\n ended = true;\n activeRequestEnds.delete(forceEnd);\n removeAbortListener();\n try {\n const performanceAttributes = entry\n ? getResourcePerformanceAttributes(entry)\n : { 'resource.timing.incomplete': true };\n if (domainContext && outcome) {\n decorateRequestSpan(context, span, 'fetch', domainContext, outcome, details, performanceAttributes);\n } else {\n span.setAttributes(context.applyRedact(performanceAttributes));\n }\n } catch {\n // 脱敏或页面属性 Hook 失败时丢弃此条采集,不能发送未脱敏数据或影响业务 Promise。\n markSpanDiscarded(span);\n } finally {\n endActivity();\n span.end(requestEndTime(details, entry, fallbackEndTime));\n }\n };\n const forceEnd = () => {\n // shutdown 不再等待异步 ResourceTiming,立即结束仍在飞行中的 span。\n completedAt = relativeNow();\n timing.cancel();\n endSpan();\n };\n const timing = trackRequestSpanTiming(url, 'fetch');\n activeRequestEnds.add(forceEnd);\n try {\n let responsePromise: Promise<Response>;\n try {\n responsePromise = originalFetch.call(this, input, requestInit);\n } finally {\n timing.sent();\n }\n const response = await responsePromise;\n if (ended) return response;\n outcome = {\n ...(response.status > 0 ? { statusCode: response.status } : {}),\n type: 'response',\n };\n domainContext = { request: requestContext, response, type: 'fetch' };\n completedAt = relativeNow();\n timing.complete(entry => endSpan(entry, completedAt), true);\n // Response 仅能证明响应头已到达;等待 RT 期间观察显式取消,\n // 不克隆或读取业务响应流来推断正文是否完整。\n const onAbort = () => {\n if (ended) return;\n completedAt = relativeNow();\n outcome = getFetchFailureOutcome(signal, signal?.reason);\n timing.cancel();\n };\n if (!ended && signal) {\n signal.addEventListener('abort', onAbort, { once: true });\n removeAbortListener = () => signal?.removeEventListener('abort', onAbort);\n if (signal.aborted) onAbort();\n }\n return response;\n } catch (error) {\n if (!ended) {\n outcome = getFetchFailureOutcome(signal, error);\n domainContext = { error, request: requestContext, type: 'fetch' };\n if (outcome.type !== 'abort' && error instanceof Error) span.recordException(error);\n completedAt = relativeNow();\n timing.complete(entry => endSpan(entry, completedAt));\n }\n throw error;\n }\n };\n window.fetch = patchedFetch;\n teardownCallbacks.push(() => {\n if (window.fetch === patchedFetch) window.fetch = originalFetch;\n });\n }\n\n if (typeof XMLHttpRequest !== 'undefined') {\n const requests = new WeakMap<XMLHttpRequest, RequestDetails>();\n const activeXhrs = new WeakMap<XMLHttpRequest, () => void>();\n // 浏览器不提供读取 XHR 请求头的 API,只能自己快照业务设置的 header 以便探测既有链路。\n const authorHeaders = new WeakMap<XMLHttpRequest, Record<string, string>>();\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n const originalAbort = XMLHttpRequest.prototype.abort;\n const patchedOpen: typeof XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest,\n method: string,\n url: string | URL,\n async = true,\n username?: null | string,\n password?: null | string,\n ) {\n // 业务完成回调可能立即复用实例;在原生 open 清空响应信息前,\n // 先结算上一轮 send,并让异步 Hook 使用该轮响应快照。\n try {\n activeXhrs.get(this)?.();\n requests.set(this, { method: method.toUpperCase(), url: toAbsoluteUrl(String(url)) });\n } catch {\n // 请求元数据采集失败时仍由浏览器决定原生 open 的返回值或异常。\n requests.delete(this);\n }\n // open() 会清空已设置的请求头,快照必须同步失效。\n authorHeaders.delete(this);\n return originalOpen.call(this, method, url as string, async, username, password);\n };\n const patchedAbort: typeof XMLHttpRequest.prototype.abort = function (this: XMLHttpRequest) {\n // 比 SDK 更早注册的 DONE 回调可以先执行 abort;原生 abort 会清空状态且\n // 不保证再发终止事件,因此与 open 重用一样,先结算上一轮可见的结果。\n try { activeXhrs.get(this)?.(); } catch { /* 采集不能阻止真实取消。 */ }\n return originalAbort.call(this);\n };\n const patchedSend: typeof XMLHttpRequest.prototype.send = function (this: XMLHttpRequest, body) {\n const details = { ...requests.get(this) };\n let span: Span | undefined;\n let endActivity = () => {};\n try {\n if (context.isSampled() && details.url && !shouldIgnoreRequest(context.config, details.url)) {\n details.startedAt = Date.now();\n details.relativeStartedAt = relativeNow();\n const tracePlan = shouldPropagateTraceHeader(context.config, details.url)\n ? planCollectedRequestTrace(context, createHeaderReader(authorHeaders.get(this))) : undefined;\n span = startRequestSpan(context, 'xhr', details, tracePlan);\n endActivity = startRequestActivity(context, details.url);\n if (tracePlan?.traceparent) this.setRequestHeader(TRACEPARENT_HEADER, tracePlan.traceparent);\n }\n } catch {\n discardRequest(span, endActivity);\n return originalSend.call(this, body);\n }\n if (!span || !details.url) return originalSend.call(this, body);\n let finishing = false;\n let ended = false;\n let removeTerminalListeners = () => {};\n let responseSnapshot: Extract<BkOTRequestContext, { type: 'xhr' }>['responseSnapshot'];\n let completedAt: number | undefined;\n const captureResponse = () => {\n if (responseSnapshot) return;\n completedAt = relativeNow();\n responseSnapshot = { status: this.status, statusText: this.statusText, responseURL: this.responseURL, responseType: this.responseType };\n };\n const forceEnd = () => {\n // XHR 可能永不触发终止事件;SDK 停止时必须清理活动计数并结束 span。\n removeTerminalListeners();\n timing.cancel();\n if (ended) return;\n ended = true;\n activeRequestEnds.delete(forceEnd);\n endActivity();\n span.setAttribute('resource.timing.incomplete', true);\n span.end(requestEndTime(details));\n };\n const complete = (completionType: 'abort' | 'error' | 'load' | 'timeout') => {\n if (finishing || ended) return;\n finishing = true;\n removeTerminalListeners();\n captureResponse();\n const outcome = getXhrOutcome(completionType, responseSnapshot!);\n timing.complete(entry => {\n if (ended) return;\n ended = true;\n activeRequestEnds.delete(forceEnd);\n try {\n decorateRequestSpan(\n context,\n span,\n 'xhr',\n { type: 'xhr', xhr: this, responseSnapshot },\n outcome,\n details,\n entry ? getResourcePerformanceAttributes(entry) : { 'resource.timing.incomplete': true },\n );\n } catch {\n markSpanDiscarded(span);\n } finally {\n endActivity();\n span.end(requestEndTime(details, entry, completedAt));\n }\n });\n };\n const beforeReopen = () => complete(this.readyState === 4 ? 'load' : 'abort');\n const onReadyStateChange = () => {\n if (this.readyState !== 4) return;\n captureResponse();\n // DONE 时已有 HTTP 状态即代表响应完成。业务 onreadystatechange 可能\n // 随即 abort 并清空状态,且浏览器不再发送 load;此时必须先结算。\n // status=0 仍等待 error/abort/timeout,保留失败原因的区别。\n if (responseSnapshot!.status > 0) complete('load');\n };\n const onAbort = () => complete('abort');\n const onError = () => complete('error');\n const onLoad = () => complete('load');\n const onTimeout = () => complete('timeout');\n removeTerminalListeners = () => {\n if (activeXhrs.get(this) === beforeReopen) activeXhrs.delete(this);\n this.removeEventListener('readystatechange', onReadyStateChange, true);\n this.removeEventListener('abort', onAbort, true);\n this.removeEventListener('error', onError, true);\n this.removeEventListener('load', onLoad, true);\n this.removeEventListener('timeout', onTimeout, true);\n };\n activeXhrs.set(this, beforeReopen);\n this.addEventListener('readystatechange', onReadyStateChange, true);\n this.addEventListener('abort', onAbort, { capture: true, once: true });\n this.addEventListener('error', onError, { capture: true, once: true });\n this.addEventListener('load', onLoad, { capture: true, once: true });\n this.addEventListener('timeout', onTimeout, { capture: true, once: true });\n const timing = trackRequestSpanTiming(details.url, 'xmlhttprequest');\n activeRequestEnds.add(forceEnd);\n try {\n return originalSend.call(this, body);\n } catch (error) {\n if (error instanceof Error) span.recordException(error);\n complete('error');\n throw error;\n } finally {\n timing.sent();\n }\n };\n XMLHttpRequest.prototype.open = patchedOpen;\n XMLHttpRequest.prototype.send = patchedSend;\n if (typeof originalAbort === 'function') XMLHttpRequest.prototype.abort = patchedAbort;\n teardownCallbacks.push(() => {\n if (XMLHttpRequest.prototype.open === patchedOpen) XMLHttpRequest.prototype.open = originalOpen;\n if (XMLHttpRequest.prototype.send === patchedSend) XMLHttpRequest.prototype.send = originalSend;\n if (XMLHttpRequest.prototype.abort === patchedAbort) XMLHttpRequest.prototype.abort = originalAbort;\n });\n\n if (hasTracingAllowlist(context) && typeof XMLHttpRequest.prototype.setRequestHeader === 'function') {\n const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;\n const patchedSetRequestHeader: typeof XMLHttpRequest.prototype.setRequestHeader = function (\n this: XMLHttpRequest,\n name: string,\n value: string,\n ) {\n const key = name.toLowerCase();\n const headers = authorHeaders.get(this) ?? {};\n // 浏览器对重复设置的同名 header 做 \", \" 合并,快照保持一致才能正确解析。\n headers[key] = key in headers ? `${headers[key]}, ${value}` : value;\n authorHeaders.set(this, headers);\n return originalSetRequestHeader.call(this, name, value);\n };\n XMLHttpRequest.prototype.setRequestHeader = patchedSetRequestHeader;\n teardownCallbacks.push(() => {\n if (XMLHttpRequest.prototype.setRequestHeader === patchedSetRequestHeader)\n XMLHttpRequest.prototype.setRequestHeader = originalSetRequestHeader;\n });\n }\n }\n },\n shutdown() {\n for (const end of [...activeRequestEnds]) end();\n while (teardownCallbacks.length) teardownCallbacks.pop()?.();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\n\n// blockedURI 除了 URL 还可能是 'inline' / 'eval' / 'wasm-eval' / 'self' 等关键字(CSP spec),\n// 这些不是 URL,不应该走 redactUrl\nconst URL_LIKE_BLOCKED_URI = /^https?:|^\\/\\//i;\n\nconst redactBlockedUri = (redactUrl: (url: string) => string, blockedURI: string | undefined) => {\n if (!blockedURI) return undefined;\n return URL_LIKE_BLOCKED_URI.test(blockedURI) ? redactUrl(blockedURI) : blockedURI;\n};\n\n/**\n * CSP 违规事件采集插件,通过监听 `securitypolicyviolation` 事件捕获被 CSP 策略拦截的脚本/资源,\n * 以 error span 上报,进入统一错误分析口径。\n *\n * URL 处理:\n * - `blockedURI` / `sourceFile` 中的 URL 类值会经 `redactUrl` 脱敏。\n * - `blockedURI` 是 'inline' / 'eval' 等 CSP 关键字时直接保留,不调用 redactUrl。\n */\nexport const createCspViolationPlugin = (): BkOTPlugin => {\n let teardown: (() => void) | undefined;\n\n return {\n name: 'csp-violation',\n init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n const handler = (event: SecurityPolicyViolationEvent) => {\n if (!context.isSampled()) return;\n const occurredAt = Date.now();\n const blockedUri = redactBlockedUri(context.config.hooks.redactUrl, event.blockedURI);\n const sourceFile = event.sourceFile ? context.config.hooks.redactUrl(event.sourceFile) : undefined;\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n outcome: RUM_SPAN_OUTCOME.error,\n spanType: RUM_SPAN_TYPE.error,\n }),\n 'csp.blocked_uri': blockedUri,\n 'csp.violated_directive': event.violatedDirective,\n 'csp.effective_directive': event.effectiveDirective,\n 'csp.disposition': event.disposition,\n 'csp.source_file': sourceFile,\n 'csp.line_number': event.lineNumber,\n 'csp.column_number': event.columnNumber,\n 'csp.status_code': event.statusCode,\n 'csp.original_policy': event.originalPolicy,\n 'error.source': 'csp',\n };\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.error }), attributes, {\n startTime: occurredAt,\n });\n span.end(occurredAt);\n };\n\n document.addEventListener('securitypolicyviolation', handler);\n teardown = () => document.removeEventListener('securitypolicyviolation', handler);\n },\n shutdown() {\n teardown?.();\n teardown = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * 浏览器错误采集插件,负责捕获 JS 运行时错误、未处理的 Promise rejection、资源加载失败三类错误。\n *\n * 上报策略:\n * - 错误分析主数据统一使用 `span_type=error` 的 error span。\n * - 每个浏览器错误只生成一条原始 error Span,错误分组和风暴控制由服务端完成。\n *\n * 关键 attribute:\n * - `error.source`:错误来源,取值 `window.error` / `unhandledrejection` / `resource`。\n * - 资源错误额外带 `url.full`(经 redactUrl 脱敏)。\n * - JS 错误额外带 `code.filepath` / `code.lineno` / `code.column`。\n */\n\nimport { SpanStatusCode } from '@opentelemetry/api';\n\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\n\nconst getErrorMessage = (value: unknown) => {\n if (value instanceof Error) {\n return value.message;\n }\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n};\n\ninterface EmitErrorOptions {\n context: BkOTRuntimeContext;\n error: unknown;\n exceptionType?: string;\n extra?: Record<string, unknown>;\n source: string;\n}\n\nconst emitError = ({ context, error, exceptionType, extra = {}, source }: EmitErrorOptions) => {\n if (!context.isSampled()) return;\n const occurredAt = Date.now();\n const message = getErrorMessage(error);\n\n const resolvedExceptionType = exceptionType ?? (error instanceof Error ? error.name || 'Error' : source);\n const exceptionLike = error instanceof Error ? error : { message, name: resolvedExceptionType };\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...context.config.hooks.getErrorAttributes(),\n ...buildRumSpanAttributes({\n outcome: RUM_SPAN_OUTCOME.error,\n spanType: RUM_SPAN_TYPE.error,\n }),\n 'error.message': message,\n 'error.handled': false,\n 'error.source': source,\n ...extra,\n };\n // 错误分析统一沉淀为 error span;若当前存在 active context,OTel 会自动建立父子关系。\n const errorSpan = context.startSpan(\n buildRumSpanName({ attributes, nameHint: resolvedExceptionType, spanType: RUM_SPAN_TYPE.error }),\n attributes,\n { startTime: occurredAt },\n );\n errorSpan.recordException(exceptionLike);\n errorSpan.setStatus({ code: SpanStatusCode.ERROR, message });\n errorSpan.end();\n};\n\nexport const createErrorPlugin = (): BkOTPlugin => {\n const listeners: Array<() => void> = [];\n\n return {\n name: 'error',\n init(context) {\n if (typeof window === 'undefined') {\n return;\n }\n\n const onError = (event: ErrorEvent) => {\n emitError({\n context,\n source: 'window.error',\n error: event.error ?? event.message,\n extra: {\n 'code.filepath': event.filename,\n 'code.lineno': event.lineno,\n 'code.column': event.colno,\n },\n });\n };\n const onUnhandledRejection = (event: PromiseRejectionEvent) => {\n emitError({\n context,\n source: 'unhandledrejection',\n error: event.reason,\n exceptionType: event.reason instanceof Error ? event.reason.name : 'UnhandledRejection',\n });\n };\n const onResourceError = (event: Event) => {\n // JS 运行时错误是 ErrorEvent,已由 bubble 阶段的 onError 处理;这里只关心资源加载失败\n if (event instanceof ErrorEvent) return;\n const target = event.target;\n if (!(target instanceof Element)) return;\n const elementWithUrl = target as Element & { href?: string; src?: string };\n const resourceUrl = elementWithUrl.src || elementWithUrl.href || (target as HTMLMediaElement).currentSrc || '';\n emitError({\n context,\n source: 'resource',\n error: new Error(`Resource load failed: ${target.tagName.toLowerCase()} ${resourceUrl}`),\n exceptionType: 'ResourceError',\n extra: {\n 'url.full': context.config.hooks.redactUrl(resourceUrl),\n },\n });\n };\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n window.addEventListener('error', onResourceError, true);\n listeners.push(\n () => window.removeEventListener('error', onError),\n () => window.removeEventListener('unhandledrejection', onUnhandledRejection),\n () => window.removeEventListener('error', onResourceError, true),\n );\n },\n shutdown() {\n while (listeners.length) {\n listeners.pop()?.();\n }\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\n/**\n * 主线程阻塞优先使用 Long Animation Frame API 获取脚本归因,不支持时回退到 Long Tasks API;\n * span 保留单次诊断详情,分布与计数由服务端从原始事件计算。\n */\nexport interface BkOTLongTaskPluginOptions {\n /** 采集阈值,默认 50ms。Performance API 本身通常只产生大于 50ms 的条目。 */\n threshold?: number;\n}\n\ninterface LegacyLongTaskEntry extends PerformanceEntry {\n attribution?: Array<{\n containerId?: string;\n containerName?: string;\n containerSrc?: string;\n containerType?: string;\n name?: string;\n }>;\n}\n\ninterface LongAnimationFrameEntry extends PerformanceEntry {\n blockingDuration: number;\n firstUIEventTimestamp: number;\n renderStart: number;\n scripts: ScriptTiming[];\n styleAndLayoutStart: number;\n}\n\ninterface ScriptTiming {\n duration: number;\n executionStart: number;\n forcedStyleAndLayoutDuration: number;\n invoker: string;\n invokerType: string;\n pauseDuration: number;\n sourceCharPosition: number;\n sourceFunctionName: string;\n sourceURL: string;\n startTime: number;\n windowAttribution: string;\n}\n\nconst DEFAULT_THRESHOLD = 50;\n\nconst nonNegativeNumber = (value: number | undefined, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : fallback;\n\nconst finiteNumber = (value: number | undefined) => (Number.isFinite(value) ? value : undefined);\n\nconst getLegacyAttributionAttributes = (\n attribution: NonNullable<LegacyLongTaskEntry['attribution']>[number],\n redactUrl: (url: string) => string,\n): Attributes => ({\n ...(attribution.containerId ? { 'long_task.attribution.container_id': attribution.containerId } : {}),\n ...(attribution.containerName ? { 'long_task.attribution.container_name': attribution.containerName } : {}),\n ...(attribution.containerSrc ? { 'long_task.attribution.container_src': redactUrl(attribution.containerSrc) } : {}),\n ...(attribution.containerType ? { 'long_task.attribution.container_type': attribution.containerType } : {}),\n ...(attribution.name ? { 'long_task.attribution.name': attribution.name } : {}),\n});\n\nconst getScriptAttributes = (script: ScriptTiming, redactUrl: (url: string) => string): Attributes => ({\n 'long_task.script.duration': script.duration,\n 'long_task.script.execution_start': script.executionStart,\n 'long_task.script.forced_style_and_layout_duration': script.forcedStyleAndLayoutDuration,\n 'long_task.script.invoker': script.invoker,\n 'long_task.script.invoker_type': script.invokerType,\n 'long_task.script.pause_duration': script.pauseDuration,\n 'long_task.script.source_char_position': script.sourceCharPosition,\n 'long_task.script.source_function_name': script.sourceFunctionName,\n 'long_task.script.source_url': script.sourceURL ? redactUrl(script.sourceURL) : '',\n 'long_task.script.start_time': script.startTime,\n 'long_task.script.window_attribution': script.windowAttribution,\n});\n\nexport const createLongTaskPlugin = (options: BkOTLongTaskPluginOptions = {}): BkOTPlugin => {\n const threshold = nonNegativeNumber(options.threshold, DEFAULT_THRESHOLD);\n let observer: PerformanceObserver | undefined;\n let initialBatchTimer: ReturnType<typeof setTimeout> | undefined;\n let initialEntries: PerformanceEntry[] = [];\n let disposed = false;\n\n return {\n name: 'long-task',\n init(context) {\n if (typeof PerformanceObserver === 'undefined' || typeof performance === 'undefined') return;\n const supportedEntryTypes = PerformanceObserver.supportedEntryTypes ?? [];\n // LoAF 提供脚本归因与 blockingDuration,支持时优先使用;旧浏览器回退到 longtask。\n const entryType = supportedEntryTypes.includes('long-animation-frame')\n ? 'long-animation-frame'\n : supportedEntryTypes.includes('longtask')\n ? 'longtask'\n : undefined;\n if (!entryType) return;\n\n const emitEntry = (entry: LegacyLongTaskEntry | LongAnimationFrameEntry) => {\n if (disposed) return;\n if (!Number.isFinite(entry.duration) || entry.duration < threshold) return;\n const isLoaf = entry.entryType === 'long-animation-frame';\n const loaf = isLoaf ? (entry as LongAnimationFrameEntry) : undefined;\n const scripts = loaf?.scripts ?? [];\n const id = createRandomId('long-task');\n const startTime = performance.timeOrigin + entry.startTime;\n const endTime = startTime + entry.duration;\n const entryTypeAttribute = isLoaf ? 'long-animation-frame' : 'long-task';\n const legacyAttributions = isLoaf ? [] : ((entry as LegacyLongTaskEntry).attribution ?? []);\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.longTask,\n }),\n ...(finiteNumber(loaf?.blockingDuration) !== undefined\n ? { [RUM_ATTRIBUTES.longTaskBlockingDuration]: loaf!.blockingDuration }\n : {}),\n [RUM_ATTRIBUTES.longTaskEntryType]: entryTypeAttribute,\n [RUM_ATTRIBUTES.longTaskId]: id,\n 'long_task.name': entry.name,\n ...(finiteNumber(loaf?.firstUIEventTimestamp) !== undefined\n ? { 'long_task.first_ui_event_timestamp': loaf!.firstUIEventTimestamp }\n : {}),\n ...(finiteNumber(loaf?.renderStart) !== undefined ? { 'long_task.render_start': loaf!.renderStart } : {}),\n ...(finiteNumber(loaf?.styleAndLayoutStart) !== undefined\n ? { 'long_task.style_and_layout_start': loaf!.styleAndLayoutStart }\n : {}),\n };\n // 迟到条目的采样归属取发生时的 Session,不取 observer 回调时的当前 Session。\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.longTask }), attributes, {\n startTime,\n });\n scripts.forEach(script => {\n span.addEvent(\n 'long_task.script',\n context.applyRedact(getScriptAttributes(script, context.config.hooks.redactUrl)),\n performance.timeOrigin + script.startTime,\n );\n });\n legacyAttributions.forEach((attribution, index) => {\n span.addEvent(\n 'long_task.attribution',\n context.applyRedact({\n 'long_task.attribution.index': index,\n ...getLegacyAttributionAttributes(attribution, context.config.hooks.redactUrl),\n }),\n startTime,\n );\n });\n span.end(endTime);\n context.notifyActivity({ endTime, startTime, type: 'long_task' });\n };\n\n const emitEntries = (entries: PerformanceEntry[]) =>\n entries.forEach(entry => emitEntry(entry as LegacyLongTaskEntry));\n try {\n let initializing = true;\n observer = new PerformanceObserver(list => {\n if (disposed) return;\n const entries = list.getEntries();\n if (initializing) {\n // buffered 条目可能在 observe() 内同步回调,先合并到下一宏任务,等 Session/View 上下文就绪后再归属。\n initialEntries.push(...entries);\n if (!initialBatchTimer) {\n initialBatchTimer = setTimeout(() => {\n const entriesToEmit = initialEntries;\n initialEntries = [];\n initialBatchTimer = undefined;\n emitEntries(entriesToEmit);\n });\n }\n } else {\n emitEntries(entries);\n }\n });\n observer.observe({ type: entryType, buffered: true });\n initializing = false;\n } catch {\n observer = undefined;\n }\n },\n shutdown() {\n disposed = true;\n observer?.disconnect();\n observer = undefined;\n clearTimeout(initialBatchTimer);\n initialBatchTimer = undefined;\n initialEntries = [];\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { matchesUrlList } from './url';\n\nimport type { BkOTActivityEvent } from './action-activity';\nimport type { BkOTRuntimeContext } from './plugin';\n\nexport const PAGE_ACTIVITY_VALIDATION_DELAY = 100;\nexport const PAGE_ACTIVITY_END_DELAY = 100;\n\nexport type PageActivityEnd = { endTime: number; hadActivity: true } | { hadActivity: false };\n\nconst isActivityUrlExcluded = (context: BkOTRuntimeContext, url: string | undefined) =>\n Boolean(url && matchesUrlList(context.config.view.excludedActivityUrls, url));\n\n/**\n * 等待 View/Action 启动后的请求、静态资源和 DOM 变更全部安静 100ms。\n * 请求用 id 精确配对,避免并发请求提前结束等待。\n */\nexport const waitForPageActivityEnd = (\n context: BkOTRuntimeContext,\n startTime: number,\n callback: (result: PageActivityEnd) => void,\n) => {\n const pendingRequests = new Set<string>();\n let completed = false;\n let hadActivity = false;\n let lastActivityTime = startTime;\n let quietTimer: ReturnType<typeof setTimeout> | undefined;\n\n const complete = (result: PageActivityEnd) => {\n if (completed) return;\n completed = true;\n clearTimeout(validationTimer);\n clearTimeout(quietTimer);\n unsubscribe();\n callback(result);\n };\n\n const scheduleEnd = () => {\n clearTimeout(quietTimer);\n if (!hadActivity || pendingRequests.size) return;\n quietTimer = setTimeout(\n () => complete({ endTime: lastActivityTime, hadActivity: true }),\n Math.max(0, lastActivityTime + PAGE_ACTIVITY_END_DELAY - Date.now()),\n );\n };\n\n const markActivity = (time: number) => {\n hadActivity = true;\n lastActivityTime = Math.max(lastActivityTime, time);\n scheduleEnd();\n };\n\n const onActivity = (event: BkOTActivityEvent) => {\n if (event.type === 'error' || event.type === 'long_task') return;\n if (event.type === 'request_start') {\n if (event.time < startTime || isActivityUrlExcluded(context, event.url)) return;\n pendingRequests.add(event.id);\n markActivity(event.time);\n return;\n }\n if (event.type === 'request_end') {\n if (!pendingRequests.delete(event.id)) return;\n markActivity(event.time);\n return;\n }\n if (event.type === 'resource') {\n if (event.endTime < startTime || isActivityUrlExcluded(context, event.url)) return;\n markActivity(event.endTime);\n return;\n }\n if (event.time >= startTime) markActivity(event.time);\n };\n\n const unsubscribe = context.onActivity(onActivity);\n const validationTimer = setTimeout(() => {\n if (!hadActivity) complete({ hadActivity: false });\n }, PAGE_ACTIVITY_VALIDATION_DELAY);\n\n return () => {\n if (completed) return;\n completed = true;\n clearTimeout(validationTimer);\n clearTimeout(quietTimer);\n unsubscribe();\n };\n};\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nexport interface RouteChangeEvent {\n fromUrl: string;\n source: RouteChangeSource;\n toUrl: string;\n}\n\nexport type RouteChangeSource = 'hashchange' | 'popstate' | 'pushState' | 'replaceState';\n\ntype RouteChangeHandler = (event: RouteChangeEvent) => void;\n\nconst subscribers = new Set<RouteChangeHandler>();\n\n// History 只 patch 一次,多个插件/实例共用订阅集合;最后一个订阅者退出时恢复原方法。\nlet lastUrl = '';\nlet restoreHistory: (() => void) | undefined;\n\nconst getCurrentUrl = () => (typeof location === 'undefined' ? '' : location.href);\n\nconst emitRouteChange = (source: RouteChangeSource, fromUrl: string) => {\n const toUrl = getCurrentUrl();\n lastUrl = toUrl;\n if (fromUrl === toUrl) return;\n const event: RouteChangeEvent = { fromUrl, source, toUrl };\n\n for (const subscriber of Array.from(subscribers)) {\n try {\n subscriber(event);\n } catch {\n // 采集失败不能改变原生 History 调用结果,也不能阻止其它 SDK 实例收到导航。\n }\n }\n};\n\nconst patchHistory = () => {\n if (restoreHistory || typeof window === 'undefined' || typeof history === 'undefined') {\n return;\n }\n\n const target = history;\n const eventTarget = window;\n // 第三方可能永久保存这层 wrapper,关闭采集后也必须能继续调用原方法。\n const originalPushState = target.pushState;\n const originalReplaceState = target.replaceState;\n let active = true;\n lastUrl = getCurrentUrl();\n\n const patchedPushState = (target.pushState = function (\n this: History,\n data: any,\n title: string,\n url?: null | string | URL,\n ) {\n const fromUrl = lastUrl || getCurrentUrl();\n // 先执行原方法,让订阅者读取到的 location 与浏览器最终状态一致。\n const result = originalPushState.apply(this, [data, title, url]);\n if (active) emitRouteChange('pushState', fromUrl);\n return result;\n });\n const patchedReplaceState = (target.replaceState = function (\n this: History,\n data: any,\n title: string,\n url?: null | string | URL,\n ) {\n const fromUrl = lastUrl || getCurrentUrl();\n const result = originalReplaceState.apply(this, [data, title, url]);\n if (active) emitRouteChange('replaceState', fromUrl);\n return result;\n });\n const onPopState = () => {\n if (active) emitRouteChange('popstate', lastUrl || getCurrentUrl());\n };\n const onHashChange = () => {\n if (active) emitRouteChange('hashchange', lastUrl || getCurrentUrl());\n };\n eventTarget.addEventListener('popstate', onPopState);\n eventTarget.addEventListener('hashchange', onHashChange);\n restoreHistory = () => {\n active = false;\n if (target.pushState === patchedPushState) target.pushState = originalPushState;\n if (target.replaceState === patchedReplaceState) target.replaceState = originalReplaceState;\n eventTarget.removeEventListener('popstate', onPopState);\n eventTarget.removeEventListener('hashchange', onHashChange);\n restoreHistory = undefined;\n lastUrl = '';\n };\n};\n\nexport const subscribeRouteChange = (handler: RouteChangeHandler) => {\n if (typeof window === 'undefined' || typeof history === 'undefined') {\n return () => {};\n }\n\n patchHistory();\n subscribers.add(handler);\n\n return () => {\n subscribers.delete(handler);\n if (subscribers.size === 0) {\n restoreHistory?.();\n }\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * Page View 插件\n *\n * 自动模式监听初始加载、SPA 路由和 BFCache;手动模式仅由 startView() 划分 View。\n *\n * 上报形态:使用 view.name 命名的 start/update/end 原始生命周期事件 span。\n *\n * 自动边界与 Datadog 对齐:pathname 或非锚点 hash path 改变才创建 View,query-only 变化不创建。\n *\n * 关键属性:\n * - view.url:当前页面 URL(经 redactUrl 脱敏)\n * - view.previous:跳转前的 URL(来自 route-observer 的 fromUrl,初始 load 为空字符串)\n * - view.previous_url_template:跳转前 URL 的低基数路由模板,初始 load 为空字符串\n * - view.referrer:仅初始加载且值非空时携带\n */\n\nimport { getEventEpochTime, getEventRelativeTime } from '../core/event-time';\nimport { createRandomId } from '../core/id';\nimport { waitForPageActivityEnd } from '../core/page-activity';\nimport { getNavigationTimingPointAttributes, getTimingPointAttributes } from '../core/performance-timing';\nimport { subscribeRouteChange } from '../core/route-observer';\nimport { copyAttributes } from '../core/runtime-context';\nimport { isViewLocationChange } from '../core/view-location';\n\nexport { isViewLocationChange } from '../core/view-location';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { BkOTStartViewOptions, BkOTViewContext } from '../core/runtime-context';\nimport type { Attributes } from '@opentelemetry/api';\n\ninterface ActiveView {\n attributes: Attributes;\n customTimings: Attributes;\n foregroundBase: number;\n id: string;\n interactionCountAtStart?: number;\n loadingTime?: number;\n loadingTimeSource?: 'auto' | 'manual';\n loadingType: ViewLoadingType;\n /** 业务显式命名优先;未命名时使用 view.url_template */\n name?: string;\n pageStates: Array<{ start: number; state: PageState }>;\n rawUrl: string;\n relativeStartedAt: number;\n snapshotAttributes: Attributes;\n startedAt: number;\n url: string;\n urlTemplate: string;\n version: number;\n stopLoadingTime?: () => void;\n}\n\ntype ViewLoadingType = NonNullable<BkOTViewContext['loadingType']>;\n\nconst PROTECTED_ATTRIBUTE_KEYS = new Set<string>(Object.values(RUM_ATTRIBUTES));\n\nconst interactionCount = () => {\n const count = typeof performance === 'undefined' ? undefined : (performance as Performance & { interactionCount?: number }).interactionCount;\n return typeof count === 'number' && Number.isFinite(count) && count >= 0 ? count : undefined;\n};\n\nconst relativeNow = () => (typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : 0);\n\nconst getCurrentUrl = () => {\n if (typeof location === 'undefined') {\n return '';\n }\n return location.href;\n};\n\nconst getNavigationTimingAttributes = (): Attributes => {\n if (typeof performance === 'undefined') return {};\n const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined;\n if (!navigation) return {};\n const attributes: Attributes = {};\n const setTiming = (key: string, value: number) => {\n if (Number.isFinite(value) && value > 0) attributes[key] = value;\n };\n setTiming(RUM_ATTRIBUTES.viewFirstByte, navigation.responseStart);\n setTiming(RUM_ATTRIBUTES.viewDomInteractive, navigation.domInteractive);\n setTiming(RUM_ATTRIBUTES.viewDomContentLoaded, navigation.domContentLoadedEventEnd);\n setTiming(RUM_ATTRIBUTES.viewDomComplete, navigation.domComplete);\n setTiming(RUM_ATTRIBUTES.viewLoadEvent, navigation.loadEventEnd);\n return {\n ...attributes,\n ...getTimingPointAttributes(navigation),\n ...getNavigationTimingPointAttributes(navigation),\n };\n};\n\ntype PageState = 'active' | 'frozen' | 'hidden' | 'passive';\nconst getPageState = (): PageState =>\n document.visibilityState === 'hidden' ? 'hidden' : document.hasFocus?.() === false ? 'passive' : 'active';\nconst isForeground = (state: PageState) => state === 'active' || state === 'passive';\n\nexport const createPageViewPlugin = (): BkOTPlugin => {\n const teardownCallbacks: Array<() => void> = [];\n let checkpoint: (() => void) | undefined;\n\n return {\n name: 'page-view',\n flush() {\n checkpoint?.();\n },\n init(context) {\n if (typeof window === 'undefined') {\n return;\n }\n\n let activeView: ActiveView | undefined;\n let bfCacheView: Omit<ActiveView, 'stopLoadingTime'> | undefined;\n let renewalView: Omit<ActiveView, 'stopLoadingTime'> | undefined;\n let manualNavigationFrom: string | undefined;\n let manualIntent: BkOTStartViewOptions | undefined;\n const queuedStarts = new Set<{ interactionCountAtStart?: number; relativeStartedAt: number; startedAt: number }>();\n let sessionActivatedAt: number | undefined;\n let sessionActivatedRelativeAt: number | undefined;\n let manualRestoreAt: number | undefined;\n let manualRestoreRelativeAt: number | undefined;\n let manualRestoreInteractionCount: number | undefined;\n\n let hasCreatedView = false;\n const clearViewContext = (changedAt = Date.now(), relativeEndedAt = relativeNow(), interactionCountAtEnd = interactionCount()) =>\n context.setView({ endedAt: changedAt, relativeEndedAt, interactionCountAtEnd }, changedAt);\n // 历史 Session deadline 只有墙钟时间。时钟已漂移时无法重建休眠期间的相对位置,\n // 此时以本次观察边界关闭,不能用 timeOrigin 把有效的旧条目移到新 View。\n const relativeBoundary = (epoch: number) => {\n const now = relativeNow();\n const wallNow = Date.now();\n const drift = activeView ? wallNow - activeView.startedAt - (now - activeView.relativeStartedAt) : 0;\n return Math.max(activeView?.relativeStartedAt ?? 0, Math.min(now, Math.abs(drift) > 2 ? now : now - (wallNow - epoch)));\n };\n const publishViewContext = (view: ActiveView, changedAt = Date.now()) =>\n context.setView(\n {\n attributes: view.attributes,\n id: view.id,\n interactionCountAtStart: view.interactionCountAtStart,\n loadingType: view.loadingType,\n name: view.name,\n startedAt: view.startedAt,\n relativeStartedAt: view.relativeStartedAt,\n url: view.url,\n urlTemplate: view.urlTemplate,\n },\n changedAt,\n );\n const recordPageState = (state: PageState) => {\n if (!activeView) return;\n const states = activeView.pageStates;\n if (states.at(-1)?.state === state) return;\n states.push({ state, start: Math.max(0, Date.now() - activeView.startedAt) });\n // 保留近期状态明细,同时保留已裁剪区间的前台总时长。\n if (states.length > 100) {\n const first = states.shift()!;\n if (isForeground(first.state)) activeView.foregroundBase += states[0].start - first.start;\n }\n };\n\n const emitViewEvent = (\n view: ActiveView,\n phase: 'end' | 'start' | 'update',\n timestamp = Date.now(),\n reason?: string,\n ) => {\n if (view.loadingType === 'initial_load') {\n Object.assign(view.snapshotAttributes, getNavigationTimingAttributes());\n }\n view.version += 1;\n const duration = Math.max(0, timestamp - view.startedAt);\n const pageStates = view.pageStates.filter(state => state.start <= duration);\n const foregroundTime =\n view.foregroundBase +\n pageStates.reduce(\n (sum, state, index) =>\n sum +\n (isForeground(state.state) ? Math.max(0, (pageStates[index + 1]?.start ?? duration) - state.start) : 0),\n 0,\n );\n const attributes: Attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...view.attributes,\n ...view.snapshotAttributes,\n [RUM_ATTRIBUTES.viewPhase]: phase,\n [RUM_ATTRIBUTES.viewStartedAt]: view.startedAt,\n [RUM_ATTRIBUTES.viewVersion]: view.version,\n [RUM_ATTRIBUTES.viewTimeSpent]: duration,\n [RUM_ATTRIBUTES.viewForegroundTime]: Math.min(duration, foregroundTime),\n [RUM_ATTRIBUTES.viewIsActive]: phase !== 'end',\n [RUM_ATTRIBUTES.viewPageStates]: JSON.stringify(pageStates),\n ...view.customTimings,\n ...(reason ? { [RUM_ATTRIBUTES.viewEndReason]: reason } : {}),\n ...(view.loadingTime === undefined\n ? {}\n : {\n [RUM_ATTRIBUTES.viewLoadingTime]: view.loadingTime,\n [RUM_ATTRIBUTES.viewLoadingTimeSource]: view.loadingTimeSource,\n }),\n };\n const sessionId = attributes[RUM_ATTRIBUTES.sessionId];\n const associationTime = phase === 'end' ? Math.max(view.startedAt, timestamp - 0.001) : timestamp;\n // Reading the history may itself discover an expired Session and begin its transition.\n context.getRuntimeAttributesAt?.(associationTime);\n const send = () => {\n const session = context.getRuntimeAttributesAt?.(associationTime);\n if (phase !== 'end' && session && (!sessionId || session[RUM_ATTRIBUTES.sessionId] !== sessionId)) return;\n if (session && session[RUM_ATTRIBUTES.sessionId] === sessionId) {\n // View identity is fixed, but activity metadata advances within that same Session.\n for (const key of [RUM_ATTRIBUTES.sessionStartTime, RUM_ATTRIBUTES.sessionLastActivityTime]) {\n if (session[key] === undefined) delete attributes[key];\n else attributes[key] = session[key];\n }\n }\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.view }), attributes, {\n contextTime: timestamp,\n rumSpanType: RUM_SPAN_TYPE.view,\n startTime: timestamp,\n });\n span.end(timestamp);\n };\n // Version, attributes and timestamp were captured above; queued updates cannot observe\n // a later rename/version or bypass expiry by carrying their old explicit Session ID.\n if (phase !== 'end' && context.isSessionTransitionPending?.()) context.afterSessionTransition(send);\n else send();\n };\n\n const endActiveView = (reason: string, clearContext = true, endedAt = Date.now(), endTimeKnown = true, relativeEndedAt = relativeBoundary(endedAt), interactionCountAtEnd = interactionCount()) => {\n if (!activeView) {\n if (clearContext) clearViewContext(endedAt, relativeEndedAt, interactionCountAtEnd);\n return undefined;\n }\n const snapshot = { ...activeView };\n activeView.stopLoadingTime?.();\n // 缺少共享结束快照时仍解绑本地 View,但不能把保守截断时间上报成真实结束时间。\n if (endTimeKnown) emitViewEvent(activeView, 'end', endedAt, reason);\n activeView = undefined;\n if (clearContext) clearViewContext(endedAt, relativeEndedAt, interactionCountAtEnd);\n const { stopLoadingTime: _stopLoadingTime, ...rest } = snapshot;\n return rest;\n };\n\n const setLoadingTime = (view: ActiveView, duration: number, source: 'auto' | 'manual') => {\n if (activeView !== view || !Number.isFinite(duration) || duration < 0) return;\n const updatedAttributes = {\n [RUM_ATTRIBUTES.viewLoadingTime]: duration,\n [RUM_ATTRIBUTES.viewLoadingTimeSource]: source,\n };\n Object.assign(view.snapshotAttributes, updatedAttributes);\n view.loadingTime = duration;\n view.loadingTimeSource = source;\n emitViewEvent(view, 'update');\n };\n\n const startLoadingTimeTracking = (view: ActiveView) => {\n if (!context.config.view.loadingTime || document.visibilityState === 'hidden') return;\n let activityResolved = false;\n let activityCandidate: number | undefined;\n let loadResolved = view.loadingType !== 'initial_load';\n let loadCandidate: number | undefined;\n let loadListener: (() => void) | undefined;\n let hidden = false;\n let visibilityListener: (() => void) | undefined;\n\n const tryComplete = () => {\n if (hidden || !activityResolved || !loadResolved || !frameResolved || activeView !== view) return;\n const candidates = [activityCandidate, loadCandidate, frameCandidate].filter(\n (candidate): candidate is number => candidate !== undefined,\n );\n if (candidates.length) setLoadingTime(view, Math.max(...candidates), 'auto');\n view.stopLoadingTime?.();\n view.stopLoadingTime = undefined;\n };\n\n const readLoadEvent = () => {\n const navigation = performance.getEntriesByType?.('navigation')[0] as PerformanceNavigationTiming | undefined;\n if (!navigation?.loadEventEnd) return false;\n loadCandidate = Math.max(0, performance.timeOrigin + navigation.loadEventEnd - view.startedAt);\n loadResolved = true;\n return true;\n };\n\n // BFCache 恢复不会重新触发 load,恢复后也常常没有请求/资源/DOM 变化;\n // 以恢复后首帧(双 rAF,与 web-vitals、Datadog 的 restored FCP 口径一致)作为兜底候选,\n // 保证 bf_cache View 总能产出 loading_time。\n let frameResolved = view.loadingType !== 'bf_cache';\n let frameCandidate: number | undefined;\n let frameListener: (() => void) | undefined;\n if (!frameResolved) {\n if (typeof requestAnimationFrame === 'function') {\n let rafId = requestAnimationFrame(() => {\n rafId = requestAnimationFrame(() => {\n frameListener = undefined;\n frameCandidate = Math.max(0, Date.now() - view.startedAt);\n frameResolved = true;\n tryComplete();\n });\n });\n frameListener = () => cancelAnimationFrame(rafId);\n } else {\n frameResolved = true;\n }\n }\n\n if (!loadResolved && !readLoadEvent()) {\n const onLoad = () => {\n setTimeout(() => {\n if (activeView !== view) return;\n readLoadEvent();\n loadResolved = true;\n tryComplete();\n });\n };\n window.addEventListener('load', onLoad, { once: true });\n loadListener = () => window.removeEventListener('load', onLoad);\n }\n\n const stopActivity = waitForPageActivityEnd(context, view.startedAt, result => {\n activityResolved = true;\n if (result.hadActivity) activityCandidate = Math.max(0, result.endTime - view.startedAt);\n tryComplete();\n });\n const onVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') return;\n hidden = true;\n view.stopLoadingTime?.();\n view.stopLoadingTime = undefined;\n };\n document.addEventListener('visibilitychange', onVisibilityChange);\n visibilityListener = () => document.removeEventListener('visibilitychange', onVisibilityChange);\n view.stopLoadingTime = () => {\n stopActivity();\n loadListener?.();\n loadListener = undefined;\n frameListener?.();\n frameListener = undefined;\n visibilityListener?.();\n visibilityListener = undefined;\n };\n tryComplete();\n };\n\n const sanitizeViewAttributes = (attributes: Attributes | undefined) => {\n const redacted = copyAttributes(context.applyRedact(copyAttributes(attributes)));\n return Object.fromEntries(\n Object.entries(redacted).filter(\n ([key, value]) =>\n value !== undefined && !PROTECTED_ATTRIBUTE_KEYS.has(key) && !key.startsWith('view.custom_timings.'),\n ),\n ) as Attributes;\n };\n\n const startView = (\n options: BkOTStartViewOptions,\n source: string,\n loadingType: ViewLoadingType,\n previousUrl = manualNavigationFrom ?? activeView?.rawUrl ?? '',\n /** 仅供内部使用:BFCache 恢复传入 pageshow 事件时刻 */\n startedAtOverride?: number,\n renewedSessionId?: string,\n relativeStartedAtOverride?: number,\n interactionCountAtStartOverride?: number,\n ) => {\n const capturedCount = interactionCountAtStartOverride ?? interactionCount();\n const capturedAt = startedAtOverride ?? Date.now();\n const capturedRelativeAt = relativeStartedAtOverride ?? (startedAtOverride === undefined ? relativeNow() : relativeBoundary(startedAtOverride));\n const sessionIsActive = context.isSessionActive();\n if (context.isSessionTransitionPending?.() && !renewedSessionId) {\n const captured = { ...options, url: options.url ?? getCurrentUrl() };\n const queuedStart = { startedAt: capturedAt, relativeStartedAt: capturedRelativeAt, interactionCountAtStart: capturedCount };\n queuedStarts.add(queuedStart);\n context.afterSessionTransition(() => {\n queuedStarts.delete(queuedStart);\n startView(captured, source, loadingType, previousUrl, capturedAt, undefined, capturedRelativeAt, capturedCount);\n });\n return;\n }\n if (!sessionIsActive) return;\n if (startedAtOverride !== undefined && sessionActivatedAt !== undefined && startedAtOverride < sessionActivatedAt) {\n startedAtOverride = sessionActivatedAt;\n relativeStartedAtOverride = sessionActivatedRelativeAt;\n }\n const currentUrl = options.url ?? getCurrentUrl();\n const urlTemplate = options.urlTemplate || context.config.hooks.getViewUrlTemplate(currentUrl);\n const previousUrlTemplate = previousUrl\n ? (activeView?.urlTemplate ?? context.config.hooks.getViewUrlTemplate(previousUrl))\n : '';\n const name = options.name ?? urlTemplate;\n const customAttributes = sanitizeViewAttributes(options.attributes);\n\n const viewId = createRandomId('view');\n const redactedCurrentUrl = context.config.hooks.redactUrl(currentUrl);\n const redactedPreviousUrl = context.config.hooks.redactUrl(previousUrl);\n const origin = typeof performance !== 'undefined' ? performance.timeOrigin : Date.now();\n const sessionNow = context.getRuntimeAttributes?.()[RUM_ATTRIBUTES.sessionId];\n const originSession = context.getRuntimeAttributesAt?.(origin)?.[RUM_ATTRIBUTES.sessionId];\n // 只有仍属于当前 Session 的首次文档体验可以回溯导航起点。\n // manual 首次调用可能已跨 Session,不能删除历史校验来伪造导航归属。\n if (loadingType === 'initial_load' && (hasCreatedView || context.collectionStart?.isInitialDocument === false || originSession !== sessionNow))\n loadingType = 'route_change';\n const isInitialLoad = loadingType === 'initial_load';\n const startedAt = startedAtOverride ?? (isInitialLoad ? origin : capturedAt);\n const relativeStartedAt = relativeStartedAtOverride ?? (isInitialLoad && startedAtOverride === undefined ? 0 : capturedRelativeAt);\n const interactionCountAtStart = isInitialLoad ? 0 : capturedCount;\n endActiveView(source, false, startedAt, true, relativeStartedAt, interactionCountAtStart);\n hasCreatedView = true;\n manualNavigationFrom = undefined;\n manualRestoreAt = undefined;\n manualRestoreRelativeAt = undefined;\n manualRestoreInteractionCount = undefined;\n\n context.setView(\n {\n attributes: customAttributes,\n id: viewId,\n interactionCountAtStart,\n loadingType,\n name,\n relativeStartedAt,\n startedAt,\n url: redactedCurrentUrl,\n urlTemplate,\n },\n startedAt,\n );\n\n const viewAttributes = {\n ...Object.fromEntries(\n Object.entries(context.getRuntimeAttributes?.() ?? {}).filter(\n ([key]) => key.startsWith('session.') || key === RUM_ATTRIBUTES.tabId,\n ),\n ),\n ...(renewedSessionId ? { [RUM_ATTRIBUTES.sessionId]: renewedSessionId } : {}),\n ...customAttributes,\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.view,\n }),\n [RUM_ATTRIBUTES.viewId]: viewId,\n ...(name ? { [RUM_ATTRIBUTES.viewName]: name } : {}),\n [RUM_ATTRIBUTES.viewUrl]: redactedCurrentUrl,\n [RUM_ATTRIBUTES.viewUrlTemplate]: urlTemplate,\n [RUM_ATTRIBUTES.viewLoadingType]: loadingType,\n [RUM_ATTRIBUTES.viewPrevious]: redactedPreviousUrl,\n [RUM_ATTRIBUTES.viewPreviousUrlTemplate]: previousUrlTemplate,\n ...(isInitialLoad && document.referrer\n ? { [RUM_ATTRIBUTES.viewReferrer]: context.config.hooks.redactUrl(document.referrer) }\n : {}),\n };\n activeView = {\n attributes: customAttributes,\n customTimings: {},\n pageStates: [{ state: getPageState(), start: Math.max(0, Date.now() - startedAt) }],\n foregroundBase: 0,\n version: 0,\n id: viewId,\n interactionCountAtStart,\n loadingType,\n name,\n rawUrl: currentUrl,\n snapshotAttributes: viewAttributes,\n relativeStartedAt,\n startedAt,\n url: redactedCurrentUrl,\n urlTemplate,\n };\n emitViewEvent(activeView, 'start', startedAt);\n startLoadingTimeTracking(activeView);\n };\n\n const unsubscribeViewCommands = context.onViewCommand(command => {\n if (command.type === 'start') {\n manualIntent = { ...command.options, url: command.options.url ?? getCurrentUrl() };\n const restoredAt = manualRestoreAt;\n const restoredRelativeAt = manualRestoreRelativeAt;\n const restoredInteractionCount = manualRestoreInteractionCount;\n manualRestoreAt = undefined;\n manualRestoreRelativeAt = undefined;\n manualRestoreInteractionCount = undefined;\n if (restoredAt !== undefined) bfCacheView = undefined;\n startView(\n command.options,\n 'manual',\n restoredAt !== undefined\n ? 'bf_cache'\n : activeView || command.startedAt !== undefined\n ? 'route_change'\n : 'initial_load',\n undefined,\n restoredAt ?? command.startedAt,\n undefined,\n restoredRelativeAt ?? command.relativeStartedAt,\n restoredInteractionCount,\n );\n return;\n }\n if (!activeView) return;\n if (command.type === 'set_loading_time') {\n activeView.stopLoadingTime?.();\n activeView.stopLoadingTime = undefined;\n setLoadingTime(activeView, Math.max(0, command.time - activeView.startedAt), 'manual');\n return;\n }\n if (command.type === 'add_timing') {\n const name = command.name\n .trim()\n .replace(/[^a-zA-Z0-9_.-]/g, '_')\n .slice(0, 100);\n const elapsed = command.elapsed ?? command.time - activeView.startedAt;\n if (\n !name ||\n !Number.isFinite(elapsed) ||\n elapsed < 0 ||\n elapsed > Math.max(0, command.time - activeView.startedAt)\n )\n return;\n const key = `view.custom_timings.${name}`;\n if (!(key in activeView.customTimings) && Object.keys(activeView.customTimings).length >= 100) return;\n activeView.customTimings[key] = elapsed;\n } else if (command.type === 'set_context' || command.type === 'set_context_property') {\n const next =\n command.type === 'set_context'\n ? command.attributes\n : { ...activeView.attributes, [command.key]: command.value };\n for (const key of Object.keys(activeView.attributes)) delete activeView.snapshotAttributes[key];\n activeView.attributes = sanitizeViewAttributes(next);\n Object.assign(activeView.snapshotAttributes, activeView.attributes);\n publishViewContext(activeView);\n } else {\n if (activeView.name === command.name) return;\n activeView.name = command.name;\n activeView.snapshotAttributes[RUM_ATTRIBUTES.viewName] = command.name;\n publishViewContext(activeView);\n }\n emitViewEvent(activeView, 'update');\n });\n\n if (context.config.view.tracking === 'auto' && !activeView) {\n const resumed = context.collectionStart?.isInitialDocument === false ? context.collectionStart : undefined;\n startView({}, 'load', 'initial_load', undefined, resumed?.startedAt, undefined, resumed?.relativeStartedAt);\n }\n // URL 变化与 View 身份变化独立;manual 模式更新 URL,只有 startView 创建边界。\n const unsubscribeRoute = subscribeRouteChange(event => {\n const changesView = isViewLocationChange(event.fromUrl, event.toUrl, context.config.view.routeMode);\n if (context.config.view.tracking === 'auto' && changesView) {\n startView({}, event.source, 'route_change', event.fromUrl);\n } else if (activeView) {\n // Router 通常先改地址再提交 View。保留原页面,不能让新 View 的 previous 指向自己。\n if (context.config.view.tracking === 'manual' && changesView) manualNavigationFrom ??= event.fromUrl;\n activeView.rawUrl = event.toUrl;\n const url = context.config.hooks.redactUrl(event.toUrl);\n if (url === activeView.url) return;\n activeView.url = url;\n activeView.snapshotAttributes[RUM_ATTRIBUTES.viewUrl] = url;\n publishViewContext(activeView);\n emitViewEvent(activeView, 'update');\n }\n });\n\n checkpoint = () => {\n if (activeView && context.isSessionActive()) emitViewEvent(activeView, 'update');\n };\n const onVisibility = () => {\n recordPageState(getPageState());\n checkpoint?.();\n };\n const onFocus = () => recordPageState(getPageState());\n const onFreeze = () => {\n recordPageState('frozen');\n checkpoint?.();\n };\n const checkpointTimer = setInterval(() => checkpoint?.(), 60_000);\n document.addEventListener?.('visibilitychange', onVisibility);\n document.addEventListener?.('freeze', onFreeze);\n document.addEventListener?.('resume', onVisibility);\n window.addEventListener('focus', onFocus);\n window.addEventListener('blur', onFocus);\n teardownCallbacks.push(\n () => clearInterval(checkpointTimer),\n () => document.removeEventListener?.('visibilitychange', onVisibility),\n () => document.removeEventListener?.('freeze', onFreeze),\n () => document.removeEventListener?.('resume', onVisibility),\n () => window.removeEventListener('focus', onFocus),\n () => window.removeEventListener('blur', onFocus),\n );\n\n const onPageHide = (event: PageTransitionEvent) => {\n if (event.persisted) {\n bfCacheView = endActiveView('bfcache', true, getEventEpochTime(event), true, getEventRelativeTime(event));\n return;\n }\n bfCacheView = undefined;\n endActiveView('pagehide', true, getEventEpochTime(event), true, getEventRelativeTime(event));\n };\n const onPageShow = (event: PageTransitionEvent) => {\n if (event.persisted && context.config.view.tracking === 'manual') {\n // 手动模式仍由集成显式创建边界,只在它消费恢复意图时标记正确的激活作用域。\n manualRestoreAt = activeView ? undefined : getEventEpochTime(event);\n manualRestoreRelativeAt = activeView ? undefined : getEventRelativeTime(event);\n manualRestoreInteractionCount = activeView ? undefined : interactionCount();\n return;\n }\n if (event.persisted && context.config.view.tracking === 'auto') {\n const restoredAt = getEventEpochTime(event);\n const restoredView = bfCacheView;\n bfCacheView = undefined;\n if (!context.isSessionActive()) {\n renewalView = restoredView;\n return;\n }\n startView(\n restoredView\n ? {\n attributes: restoredView.attributes,\n name: restoredView.name,\n url: restoredView.rawUrl,\n urlTemplate: restoredView.urlTemplate,\n }\n : {},\n 'bfCache',\n 'bf_cache',\n restoredView?.rawUrl,\n restoredAt,\n undefined,\n getEventRelativeTime(event),\n );\n }\n };\n const unsubscribeSessionLifecycle = context.onSessionLifecycle(event => {\n if (event.type === 'expired') {\n if (activeView && manualNavigationFrom) {\n // Router 已更新地址,但新 View 还在等待 Session 提交;结束与恢复的是原页面。\n // 只修正待结束的快照,不回溯 setView,避免覆盖已经记录的 URL 时间历史。\n activeView.rawUrl = manualNavigationFrom;\n activeView.url = context.config.hooks.redactUrl(manualNavigationFrom);\n activeView.snapshotAttributes[RUM_ATTRIBUTES.viewUrl] = activeView.url;\n }\n manualNavigationFrom = undefined;\n renewalView = endActiveView('session_expired', true, event.expiredAt, event.endTimeKnown) ?? bfCacheView;\n bfCacheView = undefined;\n return;\n }\n sessionActivatedAt = event.activatedAt ?? event.startedAt;\n sessionActivatedRelativeAt = [...queuedStarts].find(start => start.startedAt === sessionActivatedAt)?.relativeStartedAt ?? relativeBoundary(sessionActivatedAt);\n const firstQueuedStartAt = Math.min(...Array.from(queuedStarts, start => start.startedAt));\n if (queuedStarts.size && (!renewalView || firstQueuedStartAt <= sessionActivatedAt)) {\n // 与激活同时发生的首个恢复/手动意图由队列消费,避免重复建立 View。\n // 但点击先激活 Session、随后才跳路由时,要保留两者之间的原页面区间,\n // 否则首个 Action 无 View 可关联,不能用未来的路由 View 回填它。\n renewalView = undefined;\n return;\n }\n if (renewalView) {\n startView(\n {\n attributes: renewalView.attributes,\n name: renewalView.name,\n url: renewalView.rawUrl,\n urlTemplate: renewalView.urlTemplate,\n },\n 'sessionRenewal',\n 'session_renewal',\n renewalView.rawUrl,\n event.activatedAt,\n event.id,\n sessionActivatedRelativeAt,\n );\n renewalView = undefined;\n } else if (!activeView && manualIntent) {\n startView(manualIntent, 'manual', 'initial_load', '', event.activatedAt, event.id, sessionActivatedRelativeAt);\n } else if (!activeView && context.config.view.tracking === 'auto') {\n startView({}, 'load', 'initial_load', '', event.activatedAt, event.id, sessionActivatedRelativeAt);\n }\n });\n window.addEventListener('pagehide', onPageHide);\n window.addEventListener('pageshow', onPageShow);\n\n teardownCallbacks.push(\n unsubscribeRoute,\n unsubscribeSessionLifecycle,\n unsubscribeViewCommands,\n () => window.removeEventListener('pagehide', onPageHide),\n () => window.removeEventListener('pageshow', onPageShow),\n () => endActiveView('shutdown'),\n );\n },\n shutdown() {\n checkpoint = undefined;\n while (teardownCallbacks.length) {\n teardownCallbacks.pop()?.();\n }\n },\n };\n};\n","export interface ActiveSessionRecord {\n endedSessions?: SessionEndSnapshot[];\n expiresAt: number;\n id: string;\n lastActivityAt: number;\n previous?: ExpiredSessionRecord;\n schemaVersion: 2;\n startedAt: number;\n status: 'active';\n}\n\nexport interface ExpiredSessionRecord extends SessionEndSnapshot {\n endedSessions?: SessionEndSnapshot[];\n schemaVersion: 2;\n status: 'expired';\n}\n\nexport interface SessionEndSnapshot {\n expiredAt: number;\n previousId: string;\n reason: SessionExpireReason;\n}\n\n/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nexport type SessionExpireReason = 'inactivity' | 'maxLifetime';\n\nexport type SessionRecord = ActiveSessionRecord | ExpiredSessionRecord;\n\nconst FUTURE_CLOCK_TOLERANCE_MS = 5_000;\n// Frozen documents may miss several rotations. Retain only compact boundaries, not nested records.\nexport const MAX_SESSION_END_SNAPSHOTS = 100;\n\nconst isTimestamp = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value) && value > 0;\n\nconst readEndSnapshot = (value: unknown, now: number): SessionEndSnapshot | undefined => {\n if (!value || typeof value !== 'object') return;\n const entry = value as Partial<SessionEndSnapshot>;\n if (\n typeof entry.previousId === 'string' &&\n entry.previousId.length > 0 &&\n (entry.reason === 'inactivity' || entry.reason === 'maxLifetime') &&\n isTimestamp(entry.expiredAt) &&\n entry.expiredAt <= now + FUTURE_CLOCK_TOLERANCE_MS\n )\n return { previousId: entry.previousId, expiredAt: entry.expiredAt, reason: entry.reason };\n};\n\nconst compactEndSnapshots = (entries: SessionEndSnapshot[]) => {\n const byId = new Map<string, SessionEndSnapshot>();\n for (const entry of entries) {\n byId.delete(entry.previousId);\n byId.set(entry.previousId, entry);\n }\n return [...byId.values()].slice(-MAX_SESSION_END_SNAPSHOTS);\n};\n\n/** A known boundary must come from the committed shared state, never a stale local deadline. */\nexport const findSessionEnd = (record: null | SessionRecord, id: string): SessionEndSnapshot | undefined => {\n if (record?.status === 'expired' && record.previousId === id) return record;\n if (record?.status === 'active' && record.previous?.previousId === id) return record.previous;\n return record?.endedSessions?.find(entry => entry.previousId === id);\n};\n\nexport const expireSessionRecord = (record: ActiveSessionRecord, reason: SessionExpireReason): ExpiredSessionRecord => {\n const end = { previousId: record.id, expiredAt: record.expiresAt, reason };\n const previous = record.previous;\n return {\n ...end,\n schemaVersion: 2,\n status: 'expired',\n endedSessions: compactEndSnapshots([\n ...(record.endedSessions ?? []),\n ...(previous\n ? [{ previousId: previous.previousId, expiredAt: previous.expiredAt, reason: previous.reason }]\n : []),\n end,\n ]),\n };\n};\n\nexport const createActiveSessionRecord = (\n id: string,\n now: number,\n idleTimeoutMs: number,\n maxDurationMs: number,\n): ActiveSessionRecord => ({\n schemaVersion: 2,\n expiresAt: Math.min(now + idleTimeoutMs, now + maxDurationMs),\n id,\n lastActivityAt: now,\n startedAt: now,\n status: 'active',\n});\n\nexport const getSessionExpireReason = (\n record: ActiveSessionRecord,\n now: number,\n maxDurationMs: number,\n): SessionExpireReason | undefined => {\n if (now >= record.expiresAt)\n return record.expiresAt >= record.startedAt + maxDurationMs ? 'maxLifetime' : 'inactivity';\n return undefined;\n};\n\nexport const expandActiveSession = (\n record: ActiveSessionRecord,\n now: number,\n idleTimeoutMs: number,\n maxDurationMs: number,\n): ActiveSessionRecord => ({\n ...record,\n lastActivityAt: Math.max(record.lastActivityAt, now),\n expiresAt: Math.min(Math.max(record.lastActivityAt, now) + idleTimeoutMs, record.startedAt + maxDurationMs),\n});\n\nexport const parseSessionRecord = (raw: null | string, now: number, maxDurationMs: number): null | SessionRecord => {\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<SessionRecord>;\n if (!parsed || typeof parsed !== 'object') return null;\n // Invalid history cannot invalidate an otherwise healthy active Session. Bound work and\n // strip nested/unknown fields so a persisted record cannot grow with each rotation.\n const endedSessions = Array.isArray(parsed.endedSessions)\n ? compactEndSnapshots(\n parsed.endedSessions\n .slice(-MAX_SESSION_END_SNAPSHOTS)\n .map(entry => readEndSnapshot(entry, now))\n .filter((entry): entry is SessionEndSnapshot => !!entry),\n )\n : undefined;\n delete parsed.endedSessions;\n if (endedSessions?.length) parsed.endedSessions = endedSessions;\n if (\n parsed.schemaVersion === 2 &&\n parsed.status === 'active' &&\n typeof parsed.id === 'string' &&\n parsed.id.length > 0 &&\n isTimestamp(parsed.startedAt) &&\n // 容忍轻微时钟漂移,但拒绝远期时间与超出最大生命周期的记录,避免脏 storage 永久续期。\n parsed.startedAt <= now + FUTURE_CLOCK_TOLERANCE_MS &&\n isTimestamp(parsed.lastActivityAt) &&\n parsed.lastActivityAt >= parsed.startedAt &&\n parsed.lastActivityAt <= now + FUTURE_CLOCK_TOLERANCE_MS &&\n isTimestamp(parsed.expiresAt) &&\n parsed.expiresAt >= parsed.lastActivityAt &&\n parsed.expiresAt === Math.min(parsed.lastActivityAt + 15 * 60 * 1000, parsed.startedAt + maxDurationMs)\n ) {\n const previous = readEndSnapshot(parsed.previous, now);\n delete parsed.previous;\n if (previous) parsed.previous = { ...previous, schemaVersion: 2, status: 'expired' };\n return parsed as ActiveSessionRecord;\n }\n if (\n parsed.schemaVersion === 2 &&\n parsed.status === 'expired' &&\n typeof parsed.previousId === 'string' &&\n parsed.previousId.length > 0 &&\n (parsed.reason === 'inactivity' || parsed.reason === 'maxLifetime') &&\n isTimestamp(parsed.expiredAt) &&\n parsed.expiredAt <= now + FUTURE_CLOCK_TOLERANCE_MS\n ) {\n return parsed as ExpiredSessionRecord;\n }\n } catch {\n /* JSON 损坏视为无记录 */\n }\n return null;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\nimport { parseSessionRecord } from './session-state';\n\nimport type { SessionRecord } from './session-state';\n\n/** Shared writes are serialized by the browser, never by a localStorage pseudo-lock. */\nexport const createSessionStore = (owner: Window, key: string, maxDuration: number) => {\n let shared = false;\n let memory: null | SessionRecord = null;\n let storage: Storage | undefined;\n let stopped = false;\n const pending = new Set<AbortController>();\n try {\n storage = owner.localStorage;\n shared = !!owner.navigator?.locks;\n if (shared) storage.getItem(key);\n } catch {\n shared = false;\n }\n\n const read = () => {\n if (!shared) return memory ? parseSessionRecord(JSON.stringify(memory), Date.now(), maxDuration) : null;\n try {\n return parseSessionRecord(storage!.getItem(key), Date.now(), maxDuration);\n } catch {\n shared = false;\n return memory;\n }\n };\n\n return {\n isShared: () => shared,\n matches: (event: StorageEvent) =>\n shared && event.storageArea === storage && (event.key === key || event.key === null),\n read,\n async transact<T>(\n operation: (record: null | SessionRecord) => { record: null | SessionRecord; result: T },\n ): Promise<T | undefined> {\n if (stopped) return;\n const apply = () => {\n if (stopped) return;\n const before = read();\n const update = operation(before);\n if (shared) {\n if (update.record !== before) {\n if (update.record) storage!.setItem(key, JSON.stringify(update.record));\n else storage!.removeItem(key);\n }\n } else {\n memory = update.record;\n }\n return update.result;\n };\n if (!shared) return apply();\n const controller = new AbortController();\n pending.add(controller);\n // A frozen lock owner must not indefinitely retain the next page's pending events.\n const timeout = setTimeout(() => controller.abort(), 1000);\n try {\n return await owner.navigator.locks.request(key, { signal: controller.signal }, () => {\n clearTimeout(timeout);\n if (controller.signal.aborted || stopped) return;\n return apply();\n });\n } catch {\n if (stopped) return;\n shared = false;\n return apply();\n } finally {\n clearTimeout(timeout);\n pending.delete(controller);\n }\n },\n stop() {\n stopped = true;\n pending.forEach(controller => controller.abort());\n pending.clear();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/** Session shared state is independent of this document's View/Action binding. */\nimport { getEventEpochTime } from '../core/event-time';\nimport { hashString } from '../core/hash';\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_TYPE } from '../schema/span';\nimport {\n createActiveSessionRecord,\n expandActiveSession,\n expireSessionRecord,\n findSessionEnd,\n getSessionExpireReason,\n parseSessionRecord,\n} from './session-state';\nimport { createSessionStore } from './session-store';\n\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { ActiveSessionRecord, SessionExpireReason, SessionRecord } from './session-state';\n\nexport interface BkOTSessionConfig {\n /** 以 0~1 表示的 Session 采样率,默认 1。 */\n sampleRate?: number;\n /** 应用隔离 key;实际存储增加协议版本后缀,避免旧 SDK 继续续期。 */\n storageKey?: string;\n}\nconst IDLE_TIMEOUT = 15 * 60 * 1000;\nconst MAX_DURATION = 4 * 60 * 60 * 1000;\nconst ACTIVITY_THROTTLE = 1000;\nconst ACTIVITY_EVENTS = ['click', 'pointerdown', 'keydown', 'wheel', 'touchstart', 'touchmove'] as const;\n\nconst buildStorageKey = (endpoint: string, applicationName: string) => {\n let host = endpoint;\n try {\n host = new URL(endpoint).host;\n } catch {\n /* Use the configured endpoint if it is not a URL. */\n }\n return `bk_ot_session__${hashString(`${applicationName}\\0${host || 'default'}`)}`;\n};\nconst sessionAttributes = (record: ActiveSessionRecord) => ({\n [RUM_ATTRIBUTES.sessionId]: record.id,\n [RUM_ATTRIBUTES.sessionType]: 'user',\n [RUM_ATTRIBUTES.sessionHasReplay]: false,\n [RUM_ATTRIBUTES.sessionStartTime]: record.startedAt,\n [RUM_ATTRIBUTES.sessionLastActivityTime]: record.lastActivityAt,\n});\nconst emitSessionEvent = (\n context: BkOTRuntimeContext,\n phase: 'end' | 'rotate' | 'start',\n record: ActiveSessionRecord,\n at: number,\n) => {\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...buildRumSpanAttributes({ spanType: RUM_SPAN_TYPE.session }),\n ...sessionAttributes(record),\n [RUM_ATTRIBUTES.sessionPhase]: phase,\n };\n context\n .startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.session }), attributes, {\n contextTime: at,\n startTime: at,\n })\n .end(at);\n};\ninterface Transition {\n activate?: boolean;\n created?: boolean;\n ended?: ActiveSessionRecord;\n reason?: SessionExpireReason;\n record: null | SessionRecord;\n}\n\nexport const createSessionPlugin = (options: BkOTSessionConfig = {}): BkOTPlugin => {\n const teardown: Array<() => void> = [];\n return {\n name: 'session',\n async init(context) {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n context.setRuntimeAttributes(\n sessionAttributes(\n createActiveSessionRecord(createRandomId('session'), Date.now(), IDLE_TIMEOUT, MAX_DURATION),\n ),\n );\n return;\n }\n const owner = window;\n const page = document;\n const initializedAt = Date.now();\n const navigationAt = typeof performance !== 'undefined' ? performance.timeOrigin : undefined;\n // Only the initial visible visit owns its navigation entries. Later activations must\n // never fill an inactive/background interval with a newly created Session.\n let initialNavigationAt =\n page.visibilityState === 'visible' &&\n navigationAt !== undefined &&\n Number.isFinite(navigationAt) &&\n navigationAt <= initializedAt &&\n initializedAt - navigationAt < IDLE_TIMEOUT\n ? navigationAt\n : undefined;\n const key = `${options.storageKey ?? buildStorageKey(context.config.transport.endpoint, context.config.application.name)}__v2`;\n const store = createSessionStore(owner, key, MAX_DURATION);\n let active: ActiveSessionRecord | undefined;\n let initialized = false;\n let stopped = false;\n let checking = false;\n let expiryTimer: ReturnType<typeof setTimeout> | undefined;\n let activityTimer: ReturnType<typeof setTimeout> | undefined;\n let lastSubmittedAt = -Infinity;\n let pendingActivityAt: number | undefined;\n let pendingActivityId: string | undefined;\n let transactionCount = 0;\n\n const clearExpiry = () => {\n clearTimeout(expiryTimer);\n expiryTimer = undefined;\n };\n const deactivate = (\n id: string,\n reason: 'external' | SessionExpireReason,\n endedAt: number,\n endTimeKnown = true,\n ) => {\n if (active?.id !== id) return;\n active = undefined;\n clearExpiry();\n // Clear the local guard first; listeners may synchronously create final View/Action spans.\n context.notifySessionLifecycle({ id, reason, expiredAt: endedAt, endTimeKnown, type: 'expired' });\n context.setRuntimeAttributes(\n {\n [RUM_ATTRIBUTES.sessionId]: undefined,\n [RUM_ATTRIBUTES.sessionType]: undefined,\n [RUM_ATTRIBUTES.sessionHasReplay]: undefined,\n [RUM_ATTRIBUTES.sessionStartTime]: undefined,\n [RUM_ATTRIBUTES.sessionLastActivityTime]: undefined,\n },\n endedAt,\n );\n void context.flush();\n };\n const previousOf = (record: null | SessionRecord) => {\n if (record?.status === 'expired') return record;\n const previous = record?.previous;\n if (!previous) return;\n const parsed = parseSessionRecord(JSON.stringify(previous), Date.now(), MAX_DURATION);\n return parsed?.status === 'expired' ? parsed : undefined;\n };\n const schedule = (record: ActiveSessionRecord) => {\n clearExpiry();\n expiryTimer = setTimeout(\n () => {\n void reconcile();\n },\n Math.max(0, record.expiresAt - Date.now()),\n );\n };\n const activate = (record: ActiveSessionRecord, at: number, transition: Transition) => {\n const changed = active?.id !== record.id;\n active = record;\n if (changed) {\n const activatedAt = initialNavigationAt ?? at;\n initialNavigationAt = undefined;\n context.setRuntimeAttributes(sessionAttributes(record), activatedAt);\n context.notifySessionLifecycle({\n id: record.id,\n previousId: previousOf(record)?.previousId,\n reason: transition.created ? (transition.reason ?? 'init') : 'shared',\n startedAt: record.startedAt,\n activatedAt,\n type: 'renewed',\n });\n } else {\n // Updating the deadline must not create another Session history interval.\n context.setRuntimeAttributes({ [RUM_ATTRIBUTES.sessionLastActivityTime]: record.lastActivityAt }, at);\n }\n schedule(record);\n };\n const apply = (transition: Transition, at: number) => {\n if (stopped) return;\n const record = transition.record;\n if (active && (record?.status !== 'active' || record.id !== active.id)) {\n const ended = findSessionEnd(record, active.id);\n const known = ended && ended.expiredAt >= active.startedAt;\n // A cleared/evicted boundary is unknown. Locally truncate association at the last\n // known validity limit; consumers must not publish it as an exact global end.\n deactivate(\n active.id,\n known ? ended.reason : 'external',\n known ? ended.expiredAt : Math.min(at, active.expiresAt),\n !!known,\n );\n }\n if (transition.ended) emitSessionEvent(context, 'end', transition.ended, transition.ended.expiresAt);\n if (record?.status === 'active' && (transition.activate || active?.id === record.id)) {\n activate(record, at, transition);\n if (transition.created)\n emitSessionEvent(context, transition.reason ? 'rotate' : 'start', record, record.startedAt);\n }\n };\n const reconcile = async (activityAt?: number, expectedId?: string) => {\n if (stopped) return;\n const at = activityAt ?? Date.now();\n const finish = context.beginSessionTransition(Math.min(at, active?.expiresAt ?? at));\n transactionCount++;\n try {\n const result = await store.transact<Transition>(stored => {\n let record = stored;\n let ended: ActiveSessionRecord | undefined;\n let reason: SessionExpireReason | undefined;\n const now = Date.now();\n if (record?.status === 'active') {\n // A trusted input just before the deadline may be delivered a few milliseconds late.\n // It can extend an unclosed record, but can never cross the four-hour hard limit.\n if (\n activityAt !== undefined &&\n (!expectedId || expectedId === record.id) &&\n activityAt >= record.startedAt &&\n activityAt < record.expiresAt &&\n now < Math.min(activityAt + IDLE_TIMEOUT, record.startedAt + MAX_DURATION)\n ) {\n record = expandActiveSession(record, activityAt, IDLE_TIMEOUT, MAX_DURATION);\n }\n reason = getSessionExpireReason(record, now, MAX_DURATION);\n if (reason) {\n ended = record;\n record = expireSessionRecord(record, reason);\n }\n }\n // A queued trailing write cannot resurrect an expired/replaced Session.\n const canActivate =\n activityAt !== undefined &&\n (!expectedId || (record?.status === 'active' && record.id === expectedId)) &&\n !(record?.status === 'expired' && activityAt < record.expiredAt) &&\n !(record?.status === 'active' && activityAt < record.startedAt);\n if (canActivate) {\n if (record?.status === 'active')\n record = expandActiveSession(record, activityAt, IDLE_TIMEOUT, MAX_DURATION);\n else {\n const previous = record?.status === 'expired' ? record : undefined;\n // Old inputs delivered after their own idle window cannot start an already-expired record.\n if (now - activityAt >= IDLE_TIMEOUT) return { record, result: { record, ended } };\n record = {\n ...createActiveSessionRecord(createRandomId('session'), activityAt, IDLE_TIMEOUT, MAX_DURATION),\n endedSessions: previous?.endedSessions,\n previous: previous\n ? {\n schemaVersion: 2,\n status: 'expired',\n previousId: previous.previousId,\n expiredAt: previous.expiredAt,\n reason: previous.reason,\n }\n : undefined,\n };\n return { record, result: { record, ended, activate: true, created: true, reason: previous?.reason } };\n }\n }\n return { record, result: { record, ended, activate: canActivate } };\n });\n if (result && !stopped) {\n if (context.config.debug) {\n globalThis.console?.debug('[bk-ot] session', {\n trigger: activityAt === undefined ? 'check' : expectedId ? 'activity_flush' : 'activity',\n mode: store.isShared() ? 'shared' : 'memory',\n previousId: active?.id,\n sessionId: result.record?.status === 'active' ? result.record.id : undefined,\n lastActivityAt: result.record?.status === 'active' ? result.record.lastActivityAt : undefined,\n deadline: result.record?.status === 'active' ? result.record.expiresAt : result.record?.expiredAt,\n detectedAt: Date.now(),\n });\n }\n apply(result, at);\n }\n } finally {\n transactionCount--;\n finish();\n }\n };\n const check = () => {\n if (stopped || transactionCount || checking || !active) return;\n const latest = store.read();\n if (\n latest?.status === 'active' &&\n latest.id === active.id &&\n !getSessionExpireReason(latest, Date.now(), MAX_DURATION)\n ) {\n if (latest.lastActivityAt !== active.lastActivityAt) activate(latest, Date.now(), { record: latest });\n return;\n }\n checking = true;\n void reconcile().finally(() => {\n checking = false;\n });\n };\n teardown.push(context.registerSessionCheck(check));\n const onActivity = (event: Event) => {\n if (page.visibilityState !== 'visible' || !event.isTrusted || stopped) return;\n const at = getEventEpochTime(event);\n initialized = true;\n const latest = store.read();\n if (\n !active ||\n latest?.status !== 'active' ||\n latest.id !== active.id ||\n getSessionExpireReason(latest, Date.now(), MAX_DURATION) ||\n at - lastSubmittedAt >= ACTIVITY_THROTTLE\n ) {\n clearTimeout(activityTimer);\n activityTimer = undefined;\n pendingActivityAt = undefined;\n lastSubmittedAt = at;\n void reconcile(at);\n } else {\n pendingActivityAt = at;\n pendingActivityId = active.id;\n if (activityTimer === undefined)\n activityTimer = setTimeout(\n () => {\n activityTimer = undefined;\n const pending = pendingActivityAt;\n pendingActivityAt = undefined;\n if (pending !== undefined) {\n lastSubmittedAt = pending;\n void reconcile(pending, pendingActivityId);\n }\n },\n Math.max(0, lastSubmittedAt + ACTIVITY_THROTTLE - Date.now()),\n );\n }\n };\n const onVisible = () => {\n if (page.visibilityState !== 'visible') return;\n if (!initialized) {\n initialized = true;\n void reconcile(Date.now());\n } else check();\n };\n const onStorage = (event: StorageEvent) => {\n if (store.matches(event)) check();\n };\n const listenerOptions = { capture: true, passive: true };\n ACTIVITY_EVENTS.forEach(type => owner.addEventListener(type, onActivity, listenerOptions));\n page.addEventListener('visibilitychange', onVisible);\n owner.addEventListener('pageshow', onVisible);\n owner.addEventListener('focus', check);\n owner.addEventListener('resume', check);\n owner.addEventListener('storage', onStorage);\n teardown.push(() => {\n stopped = true;\n store.stop();\n clearExpiry();\n clearTimeout(activityTimer);\n ACTIVITY_EVENTS.forEach(type => owner.removeEventListener(type, onActivity, listenerOptions));\n page.removeEventListener('visibilitychange', onVisible);\n owner.removeEventListener('pageshow', onVisible);\n owner.removeEventListener('focus', check);\n owner.removeEventListener('resume', check);\n owner.removeEventListener('storage', onStorage);\n });\n if (page.visibilityState === 'visible') {\n initialized = true;\n await reconcile(Date.now());\n }\n },\n shutdown() {\n while (teardown.length) teardown.pop()?.();\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport interface DocumentVitalMetric {\n activationStart: number;\n attribution: Record<string, number | string | undefined>;\n entries: PerformanceEntry[];\n kind: 'activation' | 'document';\n name: 'FCP' | 'LCP' | 'TTFB';\n rating: 'good' | 'needs-improvement' | 'poor';\n value: number;\n}\n\ninterface DocumentVitalsOptions {\n collectInitialDocument: boolean;\n getTarget: (element: Element) => string | undefined;\n onChange?: () => void;\n onMetric: (metric: DocumentVitalMetric) => void;\n}\n\ntype NavigationEntry = PerformanceNavigationTiming & { activationStart?: number };\ntype LcpEntry = PerformanceEntry & { element?: Element | null; url?: string };\nconst thresholds = { FCP: [1800, 3000], LCP: [2500, 4000], TTFB: [800, 1800] };\n\n/**\n * Each collector owns its observers and listeners, so revoking consent or stopping an\n * SDK actually releases them. Document identity is independent of plugin lifetime;\n * BFCache callbacks carry their activation time instead of consulting a mutable View.\n */\nexport const startDocumentVitals = ({ collectInitialDocument, getTarget, onChange, onMetric }: DocumentVitalsOptions) => {\n let stopped = false;\n let initialStarted = false;\n let initialFinished = false;\n let fcpRecorded = false;\n let ttfbRecorded = false;\n let lcpFinished = false;\n let firstHiddenTime = Infinity;\n let lcpCandidate: DocumentVitalMetric | undefined;\n let lcpPublished: DocumentVitalMetric | undefined;\n let loadTask: ReturnType<typeof setTimeout> | undefined;\n const removers: Array<() => void> = [];\n const frames = new Set<number>();\n const observers: Array<{ observer: PerformanceObserver; process: (entries: PerformanceEntry[]) => void; type: string }> = [];\n const prerendering = () => Boolean((document as Document & { prerendering?: boolean }).prerendering);\n const entries = (type: string) => performance.getEntriesByType(type);\n const navigation = () => {\n const entry = entries('navigation')[0] as NavigationEntry | undefined;\n return entry && Number.isFinite(entry.responseStart) && entry.responseStart > 0 && entry.responseStart < performance.now()\n ? entry\n : undefined;\n };\n const supports = (type: string) =>\n typeof PerformanceObserver !== 'undefined' && PerformanceObserver.supportedEntryTypes?.includes(type);\n let canObserveFcp = Boolean(supports('paint'));\n let canObserveLcp = Boolean(supports('largest-contentful-paint'));\n const listen = (target: Window | Document, type: string, handler: (event: Event) => void) => {\n target.addEventListener(type, handler, true);\n removers.push(() => target.removeEventListener(type, handler, true));\n };\n const makeMetric = (\n name: DocumentVitalMetric['name'], value: number, metricEntries: PerformanceEntry[] = [],\n attribution: DocumentVitalMetric['attribution'] = {}, activationStart = 0,\n kind: DocumentVitalMetric['kind'] = 'document',\n ): DocumentVitalMetric => {\n const [good, poor] = thresholds[name];\n return { name, value, rating: value <= good ? 'good' : value <= poor ? 'needs-improvement' : 'poor',\n entries: metricEntries, attribution, activationStart, kind };\n };\n const emit = (metric: DocumentVitalMetric) => {\n if (!stopped && Number.isFinite(metric.value) && metric.value >= 0) onMetric(metric);\n };\n const publishLcp = () => {\n if (lcpCandidate && lcpCandidate !== lcpPublished) {\n lcpPublished = lcpCandidate;\n emit(lcpCandidate);\n }\n };\n const drain = () => {\n for (const { observer, process } of observers) process(observer.takeRecords());\n };\n const observe = (type: string, process: (entries: PerformanceEntry[]) => void) => {\n let observer: PerformanceObserver | undefined;\n try {\n observer = new PerformanceObserver(list => {\n if (!stopped) process(list.getEntries());\n });\n observer.observe({ type, buffered: true });\n observers.push({ observer, process, type });\n return observer;\n } catch {\n observer?.disconnect();\n return undefined;\n }\n };\n const readTtfb = () => {\n if (stopped || initialFinished || !initialStarted || ttfbRecorded || prerendering() || document.readyState !== 'complete') return;\n const nav = navigation();\n if (!nav) return;\n ttfbRecorded = true;\n const activation = nav.activationStart ?? 0;\n const value = Math.max(0, nav.responseStart - activation);\n // Clamp adjacent boundaries once so all subparts are non-negative, including\n // prerendering and browsers with coarsened/partially unavailable timestamps.\n const boundary = (time: number, floor = 0) => Math.min(value, Math.max(floor, time - activation));\n const waiting = boundary(nav.workerStart || nav.fetchStart);\n const dnsStart = boundary(nav.domainLookupStart, waiting);\n const connectionStart = boundary(nav.connectStart, dnsStart);\n const connectionEnd = boundary(nav.connectEnd, connectionStart);\n emit(makeMetric('TTFB', value, [nav], {\n waitingDuration: waiting, cacheDuration: dnsStart - waiting, dnsDuration: connectionStart - dnsStart,\n connectionDuration: connectionEnd - connectionStart, requestDuration: value - connectionEnd,\n }));\n };\n const queueTtfb = () => {\n if (loadTask === undefined && !ttfbRecorded) {\n loadTask = setTimeout(() => { loadTask = undefined; readTtfb(); }, 0);\n }\n };\n const startInitial = () => {\n if (stopped || initialStarted || initialFinished || !collectInitialDocument || prerendering()) return;\n initialStarted = true;\n const activation = (entries('navigation')[0] as NavigationEntry | undefined)?.activationStart ?? 0;\n firstHiddenTime = entries('visibility-state').find(entry => entry.name === 'hidden' && entry.startTime >= activation)?.startTime\n ?? (document.visibilityState === 'hidden' ? 0 : Infinity);\n if (canObserveFcp) {\n const paint = observe('paint', list => {\n if (initialFinished || fcpRecorded) return;\n const entry = list.find(item => item.name === 'first-contentful-paint');\n if (!entry) return;\n fcpRecorded = true;\n paint?.disconnect();\n if (entry.startTime < firstHiddenTime) emit(makeMetric('FCP', Math.max(0, entry.startTime - activation), [entry]));\n });\n canObserveFcp = Boolean(paint);\n }\n if (canObserveLcp) {\n canObserveLcp = Boolean(observe('largest-contentful-paint', list => {\n if (initialFinished || lcpFinished) return;\n for (const entry of list as LcpEntry[]) {\n if (!Number.isFinite(entry.startTime) || entry.startTime >= firstHiddenTime) continue;\n const value = Math.max(0, entry.startTime - activation);\n const attribution: DocumentVitalMetric['attribution'] = {\n timeToFirstByte: 0, resourceLoadDelay: 0, resourceLoadDuration: 0, elementRenderDelay: value,\n };\n // Capture only the caller's privacy-filtered selector while the element\n // exists. Never fall back to entry.id after it has left the document.\n if (entry.element) attribution.target = getTarget(entry.element);\n if (entry.url) attribution.url = entry.url;\n const nav = navigation();\n if (nav) {\n const resource = entry.url ? entries('resource').filter(item => item.name === entry.url && item.startTime <= entry.startTime)\n .sort((left, right) => right.startTime - left.startTime)[0] as PerformanceResourceTiming | undefined : undefined;\n const ttfb = Math.min(value, Math.max(0, nav.responseStart - activation));\n const requestStart = Math.min(value, Math.max(ttfb, resource ? (resource.requestStart || resource.startTime) - activation : 0));\n const responseEnd = Math.min(value, Math.max(requestStart, resource ? resource.responseEnd - activation : 0));\n Object.assign(attribution, { timeToFirstByte: ttfb, resourceLoadDelay: requestStart - ttfb,\n resourceLoadDuration: responseEnd - requestStart, elementRenderDelay: value - responseEnd });\n }\n lcpCandidate = makeMetric('LCP', value, [entry], attribution);\n onChange?.();\n }\n }));\n }\n if (document.readyState === 'complete') queueTtfb();\n };\n const flush = () => {\n if (stopped) return;\n drain();\n readTtfb();\n publishLcp();\n };\n const finishLcp = () => {\n if (lcpFinished) return;\n drain();\n publishLcp();\n lcpFinished = true;\n // Input ends the LCP observation window, but FCP may not have occurred yet.\n for (const item of observers) if (item.type === 'largest-contentful-paint') item.observer.disconnect();\n };\n const cancelFrames = () => {\n for (const frame of frames) cancelAnimationFrame(frame);\n frames.clear();\n };\n const afterFrame = (callback: () => void) => {\n const id = requestAnimationFrame(() => { frames.delete(id); if (!stopped) callback(); });\n frames.add(id);\n };\n const finishInitial = () => {\n flush();\n initialFinished = true;\n for (const { observer } of observers) observer.disconnect();\n if (loadTask !== undefined) clearTimeout(loadTask);\n loadTask = undefined;\n };\n listen(document, 'prerenderingchange', startInitial);\n listen(window, 'load', queueTtfb);\n listen(document, 'visibilitychange', event => {\n if (document.visibilityState !== 'hidden' || prerendering()) return;\n firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);\n finishLcp();\n });\n for (const type of ['click', 'keydown']) listen(window, type, event => {\n if (event.isTrusted && initialStarted) finishLcp();\n });\n listen(window, 'pagehide', () => { finishInitial(); cancelFrames(); });\n listen(window, 'pageshow', event => {\n if (!(event as PageTransitionEvent).persisted) return;\n finishInitial();\n cancelFrames();\n const activationStart = event.timeStamp;\n if (!Number.isFinite(activationStart) || activationStart < 0) return;\n if (navigation()) emit(makeMetric('TTFB', 0, [], {\n waitingDuration: 0, cacheDuration: 0, dnsDuration: 0, connectionDuration: 0, requestDuration: 0,\n }, activationStart, 'activation'));\n if ((canObserveFcp || canObserveLcp) && typeof requestAnimationFrame === 'function') afterFrame(() => afterFrame(() => {\n if (document.visibilityState === 'hidden') return;\n const duration = Math.max(0, performance.now() - activationStart);\n if (canObserveFcp) emit(makeMetric('FCP', duration, [], {}, activationStart, 'activation'));\n if (canObserveLcp) emit(makeMetric('LCP', duration, [], {\n timeToFirstByte: 0, resourceLoadDelay: 0, resourceLoadDuration: 0, elementRenderDelay: duration,\n }, activationStart, 'activation'));\n }));\n });\n startInitial();\n return {\n flush,\n stop() {\n if (stopped) return;\n finishInitial();\n stopped = true;\n cancelFrames();\n removers.forEach(remove => remove());\n observers.length = removers.length = 0;\n lcpCandidate = lcpPublished = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { type Attributes } from '@opentelemetry/api';\n\nimport { captureActionTarget } from '../core/action-target';\n\nexport interface EventTimingEntry extends PerformanceEntry {\n interactionId?: number;\n processingEnd?: number;\n processingStart?: number;\n target?: EventTarget | null;\n}\n\nexport interface InpCandidate {\n duration: number;\n inputDelay: number;\n interactionId: number;\n interactionTarget?: string;\n interactionType: string;\n presentationDelay: number;\n processingDuration: number;\n rawDuration: number;\n startTime: number;\n targetSelector?: string;\n}\n\ninterface InpProcessingGroup {\n processingEnd: number;\n processingStart: number;\n referenceRenderTime: number;\n startTime: number;\n}\n\nexport type VitalTargetResolver = (\n target: EventTarget | Node | null | undefined,\n entry: EventTimingEntry,\n) => { name?: string; selector?: string } | undefined;\n\nexport interface LayoutShiftEntry extends PerformanceEntry {\n hadRecentInput?: boolean;\n sources?: Array<{ currentRect?: DOMRectReadOnly; node?: Node; previousRect?: DOMRectReadOnly }>;\n value?: number;\n}\n\nexport interface ViewVitalState {\n cls: number;\n clsAttribution?: Attributes;\n clsMaxWindowValue?: number;\n clsWindowEnd?: number;\n clsWindowStart?: number;\n clsWindowValue: number;\n clsWindowLargestShift?: { attribution: Attributes; value: number };\n endedAt?: number;\n foreignInteractionCount?: number;\n id: string;\n inpCandidates: InpCandidate[];\n inpGroups?: Map<number, InpProcessingGroup>;\n interactionCountAtEnd?: number;\n interactionCountAtStart?: number;\n interactionIdMax: number;\n interactionIdMin: number;\n metrics: Map<string, { id: string; signature: string; version: number }>;\n nativeLateCount?: number;\n /** 与 PerformanceEntry.startTime 共用相对时钟;epoch 时间仅用于事件上下文。 */\n relativeEndedAt?: number;\n relativeStartedAt: number;\n retainedUntil?: number;\n runtimeAttributes: Attributes;\n startedAt: number;\n}\nconst MAX_INP_CANDIDATES = 10;\nconst MAX_INP_VALUE = 60_000;\nconst MAX_CLS_WINDOW_DURATION = 5_000;\nconst MAX_CLS_UPDATE_GAP = 1_000;\n\nexport const getRating = (name: 'CLS' | 'INP', value: number): 'good' | 'needs-improvement' | 'poor' => {\n const [good, poor] = name === 'CLS' ? [0.1, 0.25] : [200, 500];\n return value <= good ? 'good' : value <= poor ? 'needs-improvement' : 'poor';\n};\n\n// Use the same node privacy and structural selector policy as automatic Actions.\nexport const getTarget = (target: EventTarget | Node | null | undefined) => {\n if (typeof Element === 'undefined' || !(target instanceof Element)) return undefined;\n try {\n return captureActionTarget(target, new Event('vital'), { nameCollection: 'explicit' });\n } catch {\n return undefined;\n }\n};\n\nexport const countInteraction = (view: ViewVitalState, entry: EventTimingEntry) => {\n if (!Number.isFinite(entry.interactionId) || !entry.interactionId || entry.interactionId < 0) return;\n view.interactionIdMin = Math.min(view.interactionIdMin, entry.interactionId);\n view.interactionIdMax = Math.max(view.interactionIdMax, entry.interactionId);\n};\n\nexport const getInteractionCount = () => {\n if (typeof performance === 'undefined') return undefined;\n const value = (performance as Performance & { interactionCount?: number }).interactionCount;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n};\n\nconst rectArea = (rect: DOMRectReadOnly | undefined): number =>\n rect && [rect.x, rect.y, rect.width, rect.height].every(Number.isFinite) && rect.width >= 0 && rect.height >= 0\n ? rect.width * rect.height\n : 0;\n\nconst impactedArea = (source: NonNullable<LayoutShiftEntry['sources']>[number]): number => {\n const previousArea = rectArea(source.previousRect);\n const currentArea = rectArea(source.currentRect);\n if (!previousArea || !currentArea) return previousArea + currentArea;\n const previous = source.previousRect!;\n const current = source.currentRect!;\n const overlapWidth = Math.max(0, Math.min(previous.x + previous.width, current.x + current.width) - Math.max(previous.x, current.x));\n const overlapHeight = Math.max(0, Math.min(previous.y + previous.height, current.y + current.height) - Math.max(previous.y, current.y));\n // 位移中真正受影响的是两个矩形的并集,不能将包围盒中间的空白算作影响面积。\n return previousArea + currentArea - overlapWidth * overlapHeight;\n};\n\nconst getClsAttribution = (view: ViewVitalState, entry: LayoutShiftEntry): Attributes => {\n const source = entry.sources?.reduce((largest, item) => impactedArea(item) > impactedArea(largest) ? item : largest, entry.sources[0]);\n const selector = getTarget(source?.node)?.selector;\n const dpr = typeof window === 'undefined' ? undefined : window.devicePixelRatio;\n const attribution: Attributes = {\n 'vital.cls.time': Math.max(0, entry.startTime - view.relativeStartedAt),\n ...(selector ? { 'vital.cls.target_selector': selector } : {}),\n ...(typeof dpr === 'number' && Number.isFinite(dpr) && dpr > 0 ? { 'vital.cls.device_pixel_ratio': dpr } : {}),\n };\n for (const [name, rect] of [\n ['previous_rect', source?.previousRect],\n ['current_rect', source?.currentRect],\n ] as const) {\n if (!rect) continue;\n for (const key of ['x', 'y', 'width', 'height'] as const) {\n if (Number.isFinite(rect[key])) attribution[`vital.cls.${name}.${key}`] = rect[key];\n }\n }\n return attribution;\n};\n\nexport const updateViewCls = (view: ViewVitalState, entry: LayoutShiftEntry) => {\n const value = entry.value ?? 0;\n if (entry.hadRecentInput || !Number.isFinite(value) || value < 0 || !Number.isFinite(entry.startTime) || entry.startTime < 0) return;\n const shouldCreateWindow =\n view.clsWindowStart === undefined ||\n entry.startTime - (view.clsWindowEnd ?? entry.startTime) >= MAX_CLS_UPDATE_GAP ||\n entry.startTime - view.clsWindowStart >= MAX_CLS_WINDOW_DURATION;\n if (shouldCreateWindow) {\n view.clsWindowStart = entry.startTime;\n view.clsWindowValue = value;\n view.clsWindowLargestShift = undefined;\n } else {\n view.clsWindowValue += value;\n }\n view.clsWindowEnd = entry.startTime;\n if (!view.clsWindowLargestShift || value > view.clsWindowLargestShift.value) {\n // 立即快照经过隐私策略的归因,不保留 DOM 节点;较小 shift 不能覆盖主要位移来源。\n view.clsWindowLargestShift = { attribution: getClsAttribution(view, entry), value };\n }\n if (view.clsWindowValue > (view.clsMaxWindowValue ?? 0)) {\n view.clsMaxWindowValue = view.clsWindowValue;\n view.cls = Math.round(view.clsWindowValue * 10_000) / 10_000;\n view.clsAttribution = view.clsWindowLargestShift.attribution;\n }\n};\n\nexport const updateViewInp = (\n view: ViewVitalState,\n entries: EventTimingEntry | readonly EventTimingEntry[],\n resolveTarget: VitalTargetResolver = getTarget,\n) => {\n const groups = view.inpGroups ??= new Map();\n const batch: readonly EventTimingEntry[] = Array.isArray(entries) ? entries : [entries as EventTimingEntry];\n for (const entry of batch) {\n const processingStart = entry.processingStart ?? entry.startTime;\n const processingEnd = entry.processingEnd ?? processingStart;\n if (!entry.interactionId || entry.interactionId < 0 || !Number.isFinite(entry.interactionId) ||\n ![entry.duration, entry.startTime, processingStart, processingEnd].every(Number.isFinite) || entry.duration < 0 || entry.startTime < 0) continue;\n countInteraction(view, entry);\n const renderTime = entry.startTime + entry.duration;\n let group = groups.get(entry.interactionId);\n if (!group) group = Array.from(groups.values()).find(item => Math.abs(renderTime - item.referenceRenderTime) <= 8);\n if (group) {\n group.startTime = Math.min(group.startTime, entry.startTime);\n group.processingStart = Math.min(group.processingStart, processingStart);\n group.processingEnd = Math.max(group.processingEnd, processingEnd);\n } else {\n group = { startTime: entry.startTime, processingStart, processingEnd, referenceRenderTime: renderTime };\n }\n // referenceRenderTime 固定在建组时,防止连续相邻事件将 ±8ms 窗口不断拖长。\n groups.set(entry.interactionId, group);\n const index = view.inpCandidates.findIndex(item => item.interactionId === entry.interactionId);\n if (index >= 0 && entry.duration <= view.inpCandidates[index].rawDuration) continue;\n let target: ReturnType<VitalTargetResolver>;\n try { target = resolveTarget(entry.target, entry); } catch { /* 归因失败仅省略目标,不回退到未经过隐私策略的 DOM。 */ }\n const candidate: InpCandidate = {\n startTime: entry.startTime,\n duration: Math.min(entry.duration, MAX_INP_VALUE),\n rawDuration: entry.duration,\n inputDelay: 0,\n interactionId: entry.interactionId,\n interactionTarget: target?.name,\n targetSelector: target?.selector,\n interactionType: entry.name,\n presentationDelay: 0,\n processingDuration: 0,\n };\n if (index >= 0) view.inpCandidates[index] = candidate;\n else view.inpCandidates.push(candidate);\n view.inpCandidates.sort((left, right) => right.rawDuration - left.rawDuration).splice(MAX_INP_CANDIDATES);\n }\n for (const candidate of view.inpCandidates) {\n const group = groups.get(candidate.interactionId)!;\n const nextPaint = group.startTime + candidate.duration;\n const processingStart = Math.max(group.startTime, Math.min(group.processingStart, nextPaint));\n const processingEnd = Math.max(processingStart, Math.min(group.processingEnd, nextPaint));\n candidate.startTime = group.startTime;\n // 上限和三段归因共用一个终点,包括模态对话框使 processingEnd 晚于绘制的情况。\n candidate.inputDelay = processingStart - group.startTime;\n candidate.processingDuration = processingEnd - processingStart;\n candidate.presentationDelay = nextPaint - processingEnd;\n }\n // 同一 observer 批次内,短事件也可影响长事件的处理区间;只在批末清理未保留的交互。\n const tracked = new Set(view.inpCandidates.map(candidate => candidate.interactionId));\n for (const id of groups.keys()) if (!tracked.has(id)) groups.delete(id);\n};\n\nexport const getViewInteractionCount = (view: ViewVitalState) => {\n const nativeCount = view.endedAt === undefined ? getInteractionCount() : view.interactionCountAtEnd;\n const observedCount =\n view.interactionIdMin === Infinity ? 0 : (view.interactionIdMax - view.interactionIdMin) / 7 + 1;\n // Freeze native totals at the View boundary; late entries can reveal an interaction\n // whose rendering finished after that boundary without counting the next View.\n return nativeCount !== undefined && view.interactionCountAtStart !== undefined\n ? Math.max(observedCount, nativeCount - view.interactionCountAtStart - (view.foreignInteractionCount ?? 0))\n : observedCount;\n};\n\nexport const getViewInp = (view: ViewVitalState): InpCandidate | undefined => {\n if (!view.inpCandidates.length) return undefined;\n return view.inpCandidates[Math.min(view.inpCandidates.length - 1, Math.floor(getViewInteractionCount(view) / 50))];\n};\n\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/**\n * PerformanceEntry 与 View 使用同一相对时钟;epoch 仅用于 Session 身份和 OTLP 时间。\n * 文档 / BFCache 指标保留独立生命周期,View 指标按稳定 id + version 修订。\n */\nimport { type Attributes } from '@opentelemetry/api';\n\nimport { createRandomId } from '../core/id';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, getVitalOutcome, RUM_SPAN_TYPE } from '../schema/span';\nimport { startDocumentVitals } from './document-vitals';\nimport { countInteraction, getInteractionCount, getRating, getTarget, getViewInp, updateViewCls, updateViewInp } from './web-vitals-metrics';\n\nimport type { BkOTPlugin } from '../core/plugin';\nimport type { BkOTViewContext } from '../core/runtime-context';\nimport type { DocumentVitalMetric } from './document-vitals';\nimport type { EventTimingEntry, ViewVitalState } from './web-vitals-metrics';\n\nexport { getViewInp, updateViewCls, updateViewInp } from './web-vitals-metrics';\nexport const isSameViewId = (current: string | undefined, next: string | undefined) => Boolean(next) && current === next;\n\ninterface MetricScope {\n kind: 'activation' | 'document' | 'view';\n metrics: ViewVitalState['metrics'];\n runtimeAttributes: Attributes;\n startedAt: number;\n view?: ViewVitalState;\n}\ninterface VitalLike {\n name: string;\n value: number;\n rating: 'good' | 'needs-improvement' | 'poor';\n attribution: Record<string, unknown>;\n}\nconst ENDED_VIEW_RETENTION = 5 * 60_000;\nconst MAX_RETAINED_VIEWS = 100;\nconst CHECKPOINT_INTERVAL = 3_000;\n\n// 把 attribution 中价值最高的字段抽出来写入 Span。\nconst pickAttribution = (metric: VitalLike, redactUrl: (url: string) => string): Attributes => {\n const attr = metric.attribution ?? {};\n const result: Attributes = {};\n const getAttrValue = (key: string) => (attr as Record<string, unknown>)[key];\n\n const setIfDefined = (key: string, value: unknown, transform?: (value: string) => string) => {\n if (value === undefined || value === null || value === '') return;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n result[key] = typeof value === 'string' && transform ? transform(value) : value;\n }\n };\n\n switch (metric.name) {\n case 'LCP':\n setIfDefined('vital.lcp.url', getAttrValue('url'), redactUrl);\n setIfDefined('vital.lcp.target', getAttrValue('target'));\n setIfDefined('vital.lcp.element_render_delay', getAttrValue('elementRenderDelay'));\n setIfDefined('vital.lcp.resource_load_delay', getAttrValue('resourceLoadDelay'));\n setIfDefined('vital.lcp.time_to_first_byte', getAttrValue('timeToFirstByte'));\n setIfDefined('vital.lcp.resource_load_duration', getAttrValue('resourceLoadDuration'));\n break;\n case 'CLS':\n setIfDefined('vital.cls.load_state', getAttrValue('loadState'));\n break;\n case 'INP':\n setIfDefined('vital.inp.interaction_target', getAttrValue('interactionTarget'));\n setIfDefined('vital.inp.target_selector', getAttrValue('targetSelector'));\n setIfDefined('vital.inp.time', getAttrValue('time'));\n setIfDefined('vital.inp.interaction_type', getAttrValue('interactionType'));\n setIfDefined('vital.inp.input_delay', getAttrValue('inputDelay'));\n setIfDefined('vital.inp.processing_duration', getAttrValue('processingDuration'));\n setIfDefined('vital.inp.presentation_delay', getAttrValue('presentationDelay'));\n break;\n case 'TTFB':\n setIfDefined('vital.ttfb.waiting_duration', getAttrValue('waitingDuration'));\n setIfDefined('vital.ttfb.cache_duration', getAttrValue('cacheDuration'));\n setIfDefined('vital.ttfb.dns_duration', getAttrValue('dnsDuration'));\n setIfDefined('vital.ttfb.connection_duration', getAttrValue('connectionDuration'));\n setIfDefined('vital.ttfb.request_duration', getAttrValue('requestDuration'));\n break;\n default:\n break;\n }\n return result;\n};\n\nexport const createWebVitalsPlugin = (): BkOTPlugin => {\n let cleanup: (() => void) | undefined;\n let checkpoint = () => {};\n let disposed = false;\n return {\n name: 'web-vitals',\n flush: () => checkpoint(),\n init(context) {\n if (disposed || typeof window === 'undefined') return;\n const collectDocument = context.collectionStart?.isInitialDocument !== false;\n const views: ViewVitalState[] = [];\n const activationScopes = new Map<number, MetricScope>();\n const pendingDuration = new Map<string, DocumentVitalMetric>();\n let documentScope: MetricScope | undefined;\n let currentView: ViewVitalState | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let documentCollector: ReturnType<typeof startDocumentVitals> | undefined;\n const observers: Array<{ observer: PerformanceObserver; process: (entries: PerformanceEntry[]) => void }> = [];\n const supports = (type: string) =>\n typeof PerformanceObserver !== 'undefined' && PerformanceObserver.supportedEntryTypes?.includes(type);\n const supportsCls = supports('layout-shift');\n let refreshing = false;\n const refreshCurrent = () => {\n if (!currentView || refreshing) return;\n refreshing = true;\n try {\n const attributes = context.getRuntimeAttributes();\n // Reading attributes can synchronously expire a Session and close the View.\n if (currentView && attributes[RUM_ATTRIBUTES.viewId] === currentView.id &&\n attributes[RUM_ATTRIBUTES.sessionId] === currentView.runtimeAttributes[RUM_ATTRIBUTES.sessionId])\n currentView.runtimeAttributes = attributes;\n } finally { refreshing = false; }\n };\n const recordSpan = (metric: VitalLike, scope: MetricScope, extra: Attributes = {}) => {\n const runtimeAttributes = scope.view?.runtimeAttributes ?? scope.runtimeAttributes;\n if (disposed || !Number.isFinite(metric.value) || metric.value < 0 || !runtimeAttributes[RUM_ATTRIBUTES.viewId]) return;\n const attribution = { ...pickAttribution(metric, context.config.hooks.redactUrl), ...extra };\n const signature = JSON.stringify([metric.value, attribution, runtimeAttributes]);\n const previous = scope.metrics.get(metric.name);\n if (previous?.signature === signature) return;\n const snapshot = { id: previous?.id ?? createRandomId('vital'), version: (previous?.version ?? 0) + 1, signature };\n scope.metrics.set(metric.name, snapshot);\n const attributes = {\n ...context.config.hooks.getPageAttributes(),\n ...runtimeAttributes,\n ...buildRumSpanAttributes({ outcome: getVitalOutcome(metric.rating), spanType: RUM_SPAN_TYPE.vital }),\n [RUM_ATTRIBUTES.vitalMetric]: metric.name.toLowerCase(),\n [RUM_ATTRIBUTES.vitalValue]: metric.value,\n [RUM_ATTRIBUTES.vitalId]: snapshot.id,\n [RUM_ATTRIBUTES.vitalVersion]: snapshot.version,\n [RUM_ATTRIBUTES.vitalScope]: scope.kind,\n ...attribution,\n };\n const observedAt = Date.now();\n const span = context.startSpan(buildRumSpanName({ attributes, spanType: RUM_SPAN_TYPE.vital }), attributes, {\n contextAttributes: runtimeAttributes,\n contextTime: scope.startedAt,\n startTime: observedAt,\n });\n span.end(observedAt);\n };\n const publish = (view: ViewVitalState) => {\n const scope: MetricScope = { ...view, kind: 'view' };\n if (supportsCls)\n recordSpan({ name: 'CLS', rating: getRating('CLS', view.cls), value: view.cls, attribution: {} }, scope, view.clsAttribution);\n const inp = getViewInp(view);\n if (inp)\n recordSpan({\n name: 'INP', rating: getRating('INP', inp.duration), value: inp.duration,\n attribution: {\n inputDelay: inp.inputDelay, interactionTarget: inp.interactionTarget, interactionType: inp.interactionType,\n presentationDelay: inp.presentationDelay, processingDuration: inp.processingDuration,\n targetSelector: inp.targetSelector, time: Math.max(0, inp.startTime - view.relativeStartedAt),\n },\n }, scope);\n else if (supports('event') && view.interactionIdMin !== Infinity)\n recordSpan({ name: 'INP', rating: 'good', value: 0, attribution: {} }, scope);\n };\n const schedule = () => {\n if (disposed || timer !== undefined) return;\n timer = setTimeout(() => { timer = undefined; checkpoint(); }, CHECKPOINT_INTERVAL);\n };\n const prune = () => {\n const now = Date.now();\n for (let index = views.length - 1; index >= 0; index--)\n if (views[index].retainedUntil !== undefined && views[index].retainedUntil! <= now) views.splice(index, 1);\n if (views.length > MAX_RETAINED_VIEWS) views.splice(0, views.length - MAX_RETAINED_VIEWS);\n for (const [key, scope] of activationScopes)\n if (scope.view?.retainedUntil !== undefined && scope.view.retainedUntil <= now) activationScopes.delete(key);\n while (activationScopes.size > MAX_RETAINED_VIEWS) activationScopes.delete(activationScopes.keys().next().value!);\n };\n const findView = (entry: PerformanceEntry) => [...views].reverse().find(view =>\n view.relativeStartedAt <= entry.startTime && (view.relativeEndedAt === undefined || entry.startTime < view.relativeEndedAt));\n\n // Capture only privacy-processed strings before application handlers can remove the\n // target. No DOM nodes are retained, and ambiguous event timestamps are not guessed.\n const targets: Array<{ name: string; time: number; target: ReturnType<typeof getTarget> }> = [];\n const targetEvents = ['pointerdown', 'pointerup', 'mousedown', 'mouseup', 'click', 'keydown', 'keyup'];\n const captureTarget = (event: Event) => {\n if (!event.isTrusted) return;\n const node = event.composedPath?.()[0] ?? event.target;\n targets.push({ name: event.type, time: event.timeStamp, target: getTarget(node) });\n const cutoff = performance.now() - 10_000;\n while (targets.length > 100 || (targets[0] && targets[0].time < cutoff)) targets.shift();\n };\n targetEvents.forEach(type => window.addEventListener(type, captureTarget, true));\n const resolveTarget = (target: EventTarget | null | undefined, entry: EventTimingEntry) => {\n const matches = targets.filter(item => item.name === entry.name && Math.abs(item.time - entry.startTime) <= 8 && performance.now() - item.time <= 10_000);\n const exact = matches.filter(item => item.time === entry.startTime);\n const matched = exact.length === 1 ? exact[0] : matches.length === 1 ? matches[0] : undefined;\n // A captured undefined is an intentional privacy decision, not a fallback signal.\n return matched ? matched.target : getTarget(target);\n };\n const pendingEntries: Array<{ entry: PerformanceEntry; type: string }> = [];\n const processEntries = (entries: PerformanceEntry[], type: string) => {\n if (disposed || entries.length === 0) return;\n refreshCurrent();\n prune();\n const grouped = new Map<ViewVitalState, PerformanceEntry[]>();\n for (const entry of entries) {\n const view = findView(entry);\n if (!view) {\n // Manual tracking can establish the first document View after observers run.\n if (collectDocument && !documentScope && views.length === 0) {\n pendingEntries.push({ entry, type });\n if (pendingEntries.length > 200) pendingEntries.shift();\n }\n continue;\n }\n const batch = grouped.get(view) ?? [];\n batch.push(entry);\n grouped.set(view, batch);\n }\n const changed = new Set<ViewVitalState>();\n for (const [view, batch] of grouped) {\n if (type === 'inp') updateViewInp(view, batch as EventTimingEntry[], resolveTarget);\n else for (const entry of batch) (type === 'count' ? countInteraction : updateViewCls)(view, entry);\n if (view.endedAt === undefined) { schedule(); continue; }\n changed.add(view);\n if (view.interactionCountAtEnd === undefined || view.interactionCountAtStart === undefined || view.interactionIdMin === Infinity) continue;\n const observed = (view.interactionIdMax - view.interactionIdMin) / 7 + 1;\n const frozen = view.interactionCountAtEnd - view.interactionCountAtStart - (view.foreignInteractionCount ?? 0);\n const late = Math.max(0, observed - frozen);\n const newlyCounted = Math.max(0, late - (view.nativeLateCount ?? 0));\n view.nativeLateCount = Math.max(view.nativeLateCount ?? 0, late);\n if (newlyCounted) for (const later of views) {\n // Only a unique, unambiguous completion View gets a native-count correction.\n const completions = batch.map(entry => entry.startTime + entry.duration);\n if (later.relativeStartedAt >= view.relativeEndedAt! && later.relativeStartedAt < Math.min(...completions) - 4 &&\n (later.relativeEndedAt === undefined || Math.max(...completions) + 4 < later.relativeEndedAt)) {\n later.foreignInteractionCount = (later.foreignInteractionCount ?? 0) + newlyCounted;\n if (later.endedAt !== undefined) changed.add(later);\n }\n }\n }\n for (const view of changed) publish(view);\n };\n const observe = (type: string, update: string, durationThreshold?: number) => {\n if (!supports(type)) return;\n const process = (entries: PerformanceEntry[]) => processEntries(entries, update);\n const observer = new PerformanceObserver(list => process(list.getEntries()));\n observers.push({ observer, process });\n observer.observe({ type, buffered: true, ...(durationThreshold === undefined ? {} : { durationThreshold }) });\n };\n const drain = () => observers.forEach(({ observer, process }) => process(observer.takeRecords?.() ?? []));\n const recordDurationVital = (metric: DocumentVitalMetric) => {\n if (disposed) return;\n refreshCurrent();\n const scope = metric.kind === 'document' ? documentScope : activationScopes.get(metric.activationStart);\n if (scope) recordSpan(metric, scope);\n else {\n // Three scalar metrics per activation; do not retain entry DOM references.\n pendingDuration.set(`${metric.kind}:${metric.activationStart}:${metric.name}`, { ...metric, entries: [] });\n while (pendingDuration.size > 30) pendingDuration.delete(pendingDuration.keys().next().value!);\n }\n };\n const makeView = (view: BkOTViewContext, runtimeAttributes: Attributes): ViewVitalState => ({\n id: view.id!, startedAt: view.startedAt ?? Date.now(),\n relativeStartedAt: view.relativeStartedAt ?? (view.loadingType === 'initial_load' ? 0 : performance.now()),\n endedAt: view.endedAt, relativeEndedAt: view.relativeEndedAt,\n retainedUntil: view.endedAt === undefined ? undefined : Date.now() + ENDED_VIEW_RETENTION,\n runtimeAttributes, cls: 0, clsWindowValue: 0, inpCandidates: [], metrics: new Map(),\n interactionCountAtStart: view.interactionCountAtStart ?? (view.loadingType === 'initial_load' ? 0 : undefined),\n interactionCountAtEnd: view.interactionCountAtEnd,\n interactionIdMin: Infinity, interactionIdMax: 0,\n });\n const bindScope = (view: BkOTViewContext, state: ViewVitalState) => {\n if (view.loadingType === 'initial_load' && !documentScope && collectDocument)\n documentScope = { ...state, metrics: new Map(), kind: 'document', view: state };\n if (view.loadingType === 'bf_cache')\n activationScopes.set(state.relativeStartedAt, { ...state, metrics: new Map(), kind: 'activation', view: state });\n for (const [key, metric] of pendingDuration) {\n const scope = metric.kind === 'document' ? documentScope : activationScopes.get(metric.activationStart);\n if (scope) { pendingDuration.delete(key); recordSpan(metric, scope); }\n }\n };\n // Restore bounded lifecycle snapshots before requesting buffered performance entries.\n for (const historical of context.getViewHistory?.() ?? []) {\n if (!historical.view.id) continue;\n if (!collectDocument && (historical.view.relativeStartedAt ?? -Infinity) < context.collectionStart!.relativeStartedAt) continue;\n const state = makeView(historical.view, historical.runtimeAttributes);\n views.push(state);\n if (state.endedAt === undefined) currentView = state;\n bindScope(historical.view, state);\n }\n const unsubscribeView = context.onViewChange(view => {\n if (disposed) return;\n if (currentView && isSameViewId(currentView.id, view.id)) { refreshCurrent(); return; }\n drain();\n if (currentView) {\n const previous = currentView;\n previous.endedAt = Math.max(previous.startedAt, view.endedAt ?? view.startedAt ?? Date.now());\n previous.relativeEndedAt = Math.max(previous.relativeStartedAt, view.relativeEndedAt ?? view.relativeStartedAt ?? performance.now());\n previous.retainedUntil = Date.now() + ENDED_VIEW_RETENTION;\n const final = context.getViewHistory?.().find(item => item.view.id === previous.id);\n previous.interactionCountAtEnd = final?.view.interactionCountAtEnd ?? view.interactionCountAtEnd ?? view.interactionCountAtStart ?? getInteractionCount();\n if (final) previous.runtimeAttributes = final.runtimeAttributes;\n publish(previous);\n }\n currentView = view.id ? makeView(view, context.getRuntimeAttributes()) : undefined;\n if (currentView) {\n currentView.interactionCountAtStart ??= getInteractionCount();\n views.push(currentView);\n bindScope(view, currentView);\n const pending = pendingEntries.splice(0);\n for (const type of ['count', 'inp', 'cls']) processEntries(pending.filter(item => item.type === type).map(item => item.entry), type);\n }\n prune();\n });\n checkpoint = () => {\n if (disposed) return;\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n drain();\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n refreshCurrent();\n documentCollector?.flush();\n // Entries drained by either collector are included in this checkpoint already.\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n prune();\n for (const view of views) publish(view);\n };\n const onHidden = () => { if (document.visibilityState === 'hidden') checkpoint(); };\n document.addEventListener?.('visibilitychange', onHidden);\n document.addEventListener?.('freeze', checkpoint);\n const stopFreeze = checkpoint;\n // Install cleanup before collectors: an unsupported observer must not leave listeners.\n cleanup = () => {\n checkpoint();\n documentCollector?.stop();\n unsubscribeView();\n observers.forEach(({ observer }) => observer.disconnect());\n document.removeEventListener?.('visibilitychange', onHidden);\n document.removeEventListener?.('freeze', stopFreeze);\n targetEvents.forEach(type => window.removeEventListener(type, captureTarget, true));\n if (timer !== undefined) clearTimeout(timer);\n views.length = targets.length = pendingEntries.length = 0;\n activationScopes.clear(); pendingDuration.clear();\n currentView = undefined; documentScope = undefined;\n };\n observe('event', 'count', 0);\n observe('event', 'inp', 40);\n observe('first-input', 'inp');\n observe('layout-shift', 'cls');\n documentCollector = startDocumentVitals({ collectInitialDocument: collectDocument, getTarget: target => getTarget(target)?.selector, onMetric: recordDurationVital, onChange: schedule });\n },\n shutdown() {\n if (disposed) return;\n cleanup?.();\n disposed = true;\n cleanup = undefined;\n checkpoint = () => {};\n },\n };\n};\n\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nimport { SpanKind } from '@opentelemetry/api';\n\nimport { createRandomId } from '../core/id';\nimport { shouldIgnoreUrl } from '../core/url';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\n\nimport type { BkOTPlugin, BkOTRuntimeContext } from '../core/plugin';\nimport type { Attributes } from '@opentelemetry/api';\n\nconst buildWebSocketAttributes = (url: string, redactUrl: (url: string) => string): Attributes => {\n const attributes: Attributes = {\n 'network.protocol.name': 'websocket',\n 'url.full': redactUrl(url),\n };\n try {\n const parsed = new URL(url, typeof location === 'undefined' ? 'http://localhost' : location.href);\n attributes['server.address'] = parsed.hostname;\n if (parsed.port) attributes['server.port'] = Number(parsed.port);\n attributes['url.scheme'] = parsed.protocol.replace(':', '');\n } catch {\n // 非法 URL 仍保留脱敏后的原始字符串。\n }\n return attributes;\n};\n\nconst instrumentSocket = (socket: WebSocket, context: BkOTRuntimeContext, url: string, isDisposed: () => boolean) => {\n const connectionId = createRandomId('websocket');\n const baseAttributes = buildWebSocketAttributes(url, context.config.hooks.redactUrl);\n let opened = false;\n\n const emit = (phase: 'close' | 'connect' | 'error' | 'open', timestamp: number, attributes: Attributes = {}) => {\n if (isDisposed() || !context.isSampled()) return;\n const isError = phase === 'error';\n const spanAttributes = {\n ...baseAttributes,\n ...buildRumSpanAttributes({\n outcome: isError ? RUM_SPAN_OUTCOME.error : RUM_SPAN_OUTCOME.success,\n spanType: RUM_SPAN_TYPE.websocket,\n }),\n [RUM_ATTRIBUTES.websocketPhase]: phase,\n 'websocket.connection.id': connectionId,\n ...attributes,\n };\n const span = context.startSpan(\n buildRumSpanName({ attributes: spanAttributes, spanType: RUM_SPAN_TYPE.websocket }),\n spanAttributes,\n { kind: SpanKind.CLIENT, startTime: timestamp },\n );\n span.end(timestamp);\n };\n\n emit('connect', Date.now());\n socket.addEventListener('open', () => {\n opened = true;\n emit('open', Date.now());\n });\n socket.addEventListener('error', () => {\n emit('error', Date.now(), { 'websocket.error.phase': opened ? 'runtime' : 'connect' });\n });\n socket.addEventListener('close', event => {\n emit('close', Date.now(), {\n 'websocket.close.code': event.code,\n 'websocket.close.reason': event.reason,\n 'websocket.close.was_clean': event.wasClean,\n });\n });\n};\n\nexport const createWebSocketPlugin = (): BkOTPlugin => {\n let originalWebSocket: typeof WebSocket | undefined;\n let patchedProxy: typeof WebSocket | undefined;\n let disposed = false;\n\n return {\n name: 'websocket',\n init(context) {\n if (typeof window === 'undefined' || typeof window.WebSocket === 'undefined') return;\n const nativeWebSocket = window.WebSocket;\n originalWebSocket = nativeWebSocket;\n patchedProxy = new Proxy(nativeWebSocket, {\n construct(target, args, newTarget) {\n const socket = Reflect.construct(target, args, newTarget) as WebSocket;\n if (disposed || !context.isSampled()) return socket;\n const url = args[0] == null ? '' : String(args[0]);\n if (url && !shouldIgnoreUrl(context.config, url)) {\n instrumentSocket(socket, context, url, () => disposed);\n }\n return socket;\n },\n });\n window.WebSocket = patchedProxy;\n },\n shutdown() {\n disposed = true;\n if (typeof window !== 'undefined' && originalWebSocket && window.WebSocket === patchedProxy) {\n window.WebSocket = originalWebSocket;\n }\n patchedProxy = undefined;\n originalWebSocket = undefined;\n },\n };\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n */\n\nexport type BkOTActivityEvent =\n | { endTime: number; startTime: number; type: 'long_task'; url?: never }\n | { endTime: number; startTime: number; type: 'resource'; url?: string }\n | { id: string; time: number; type: 'request_end' }\n | { id: string; time: number; type: 'request_start'; url?: string }\n | { actionIds: string[]; time: number; type: 'error' }\n | { time: number; type: 'dom_mutation' | 'window_open' };\n\nexport class RumActivityObserver {\n private readonly listeners = new Set<(event: BkOTActivityEvent) => void>();\n\n public notify = (event: BkOTActivityEvent) => {\n this.listeners.forEach(listener => listener(event));\n };\n\n public subscribe = (listener: (event: BkOTActivityEvent) => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport type { ResolvedBkOTConfig } from './config';\n\nconst hashToUnitInterval = (input: string) => {\n let hash = 0x811c9dc5;\n for (let index = 0; index < input.length; index += 1) {\n hash = Math.imul(hash ^ input.charCodeAt(index), 0x01000193);\n }\n hash += hash << 13;\n hash ^= hash >>> 7;\n hash += hash << 3;\n hash ^= hash >>> 17;\n hash += hash << 5;\n return (hash >>> 0) / 0x100000000;\n};\n\n/**\n * 按应用和 RUM Session ID 做确定性采样。采样决定随 Session 更新,不再依赖 Tab 级 sessionStorage。\n */\nexport const isBkOTSampled = (\n { application, session }: Pick<ResolvedBkOTConfig, 'application' | 'session'>,\n sessionId: string,\n) => {\n if (session.sampleRate <= 0) {\n return false;\n }\n if (session.sampleRate >= 1) {\n return true;\n }\n return hashToUnitInterval(`${application.name}\\0${sessionId}`) < session.sampleRate;\n};\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n/**\n * 串行提交 Session 时先采集事件,再关联会话。View 变更先落地,随后解析待定快照,\n * 防止第一击在 Web Lock 返回前继承旧 ID。停止采集会使所有旧回调失效。\n */\nexport class SessionTransition {\n private readonly associations: Array<() => void> = [];\n private readonly callbacks: Array<() => void> = [];\n private check?: () => void;\n private checking = false;\n private readonly pending = new Set<{ at: number }>();\n\n public begin = (at: number) => {\n const transition = { at };\n this.pending.add(transition);\n return () => {\n if (!this.pending.delete(transition) || this.pending.size) return;\n while (!this.pending.size && this.callbacks.length) this.callbacks.shift()!();\n while (!this.pending.size && this.associations.length) this.associations.shift()!();\n };\n };\n\n public checkSession = () => {\n if (this.checking || this.pending.size) return;\n this.checking = true;\n try {\n this.check?.();\n } finally {\n this.checking = false;\n }\n };\n\n public isPending = (at?: number) => [...this.pending].some(transition => at === undefined || at >= transition.at);\n\n public registerCheck = (check: () => void) => {\n this.check = check;\n return () => {\n if (this.check === check) this.check = undefined;\n };\n };\n\n public reset = () => {\n this.pending.clear();\n this.callbacks.length = 0;\n this.associations.length = 0;\n };\n\n public whenReady = (callback: () => void, association = false) => {\n if (!this.pending.size) {\n callback();\n return;\n }\n const queue = association ? this.associations : this.callbacks;\n if (queue.length >= this.capacity) queue.shift();\n queue.push(callback);\n };\n\n public constructor(private readonly capacity: number) {}\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n *\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n *\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) is licensed under the MIT License.\n *\n * License for 蓝鲸智云PaaS平台 (BlueKing PaaS):\n *\n * ---------------------------------------------------\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n * documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and\n * to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of\n * the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO\n * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\n * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n type Attributes,\n type Span,\n context,\n INVALID_SPAN_CONTEXT,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n} from '@opentelemetry/api';\nimport { ZoneContextManager } from '@opentelemetry/context-zone';\nimport { W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { BatchSpanProcessor, SamplingDecision, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { WebTracerProvider } from '@opentelemetry/sdk-trace-web';\n\nimport { createActionPlugin } from '../plugins/action';\nimport { createActivityPlugin } from '../plugins/activity';\nimport { createBlankScreenPlugin } from '../plugins/blank-screen';\nimport { createCommonInstrumentationsPlugin } from '../plugins/common';\nimport { createCspViolationPlugin } from '../plugins/csp-violation';\nimport { createDevicePlugin } from '../plugins/device';\nimport { createErrorPlugin } from '../plugins/error';\nimport { createLongTaskPlugin } from '../plugins/long-task';\nimport { createPageViewPlugin } from '../plugins/page-view';\nimport { createResourcePlugin } from '../plugins/resource';\nimport { createSessionPlugin } from '../plugins/session';\nimport { createWebVitalsPlugin } from '../plugins/web-vitals';\nimport { createWebSocketPlugin } from '../plugins/websocket';\nimport { RUM_ATTRIBUTES } from '../schema/attributes';\nimport { buildRumSpanAttributes, buildRumSpanName, RUM_SPAN_OUTCOME, RUM_SPAN_TYPE } from '../schema/span';\nimport { RumActivityObserver } from './action-activity';\nimport {\n type BkOTActionEventPayload,\n type BkOTCustomEventPayload,\n type BkOTOptions,\n type BkOTTrackingConfig,\n type BkOTTrackingConsent,\n type ResolvedBkOTConfig,\n type ResolvedTransportConfig,\n resolveConfig,\n} from './config';\nimport { createRandomId } from './id';\nimport { type BkOTPlugin, type BkOTRuntimeContext, type BkOTStartSpanOptions, PluginManager } from './plugin';\nimport { filterActionAttributes, FilteringSpanProcessor, RUM_CONTEXT_SNAPSHOT, RUM_CONTEXT_TIME } from './processor';\nimport {\n type BkOTSessionLifecycleEvent,\n type BkOTStartViewOptions,\n type BkOTUserContext,\n copyAttributes,\n RumRuntimeContext,\n} from './runtime-context';\nimport { isBkOTSampled } from './sampling';\nimport { SessionTransition } from './session-transition';\n\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport type { Sampler } from '@opentelemetry/sdk-trace-base';\n\nexport interface BkOTInstance extends Omit<\n BkOTRuntimeContext,\n | 'endActionContext'\n | 'notifyActivity'\n | 'onActivity'\n | 'onViewChange'\n | 'onViewCommand'\n | 'registerActionContext'\n | 'registerInstrumentations'\n | 'setView'\n> {\n addTiming: (name: string, elapsed?: number) => void;\n flush: () => Promise<void>;\n getViewContext: () => Attributes;\n reportAction: (payload: BkOTActionEventPayload) => void;\n reportCustomEvent: (payload: BkOTCustomEventPayload) => void;\n setTrackingConsent: (consent: BkOTTrackingConsent) => Promise<void>;\n setUser: (user: BkOTUserContext) => void;\n setViewContext: (attributes: Attributes) => void;\n setViewContextProperty: (key: string, value: Attributes[string]) => void;\n setViewLoadingTime: () => void;\n setViewName: (name: string) => void;\n shutdown: () => Promise<void>;\n start: () => Promise<void>;\n startView: (options?: BkOTStartViewOptions) => void;\n use: (plugin: BkOTPlugin) => BkOTInstance;\n useInstrumentation: (instrumentation: Instrumentation) => BkOTInstance;\n}\n\nconst createExporterOptions = (config: ResolvedTransportConfig) => ({\n url: config.endpoint,\n headers: config.headers,\n concurrencyLimit: config.concurrencyLimit,\n timeoutMillis: config.timeoutMillis,\n});\n\nconst BK_OT_INSTRUMENTATION_NAME = 'bk-rum';\n\nclass RumSessionSampler implements Sampler {\n public constructor(private readonly isSampled: (attributes: Attributes) => boolean) {}\n\n public shouldSample(_context: unknown, _traceId: string, _name: string, _kind: SpanKind, attributes: Attributes) {\n return {\n decision: this.isSampled(attributes) ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,\n };\n }\n\n public toString() {\n return 'RumSessionSampler';\n }\n}\n\n// OTel context manager 和 propagator 是页面级全局对象,多 SDK 实例通过引用计数共享,最后一个实例退出时释放。\nlet globalRegistration:\n | undefined\n | {\n contextManager?: ZoneContextManager;\n ownsContext: boolean;\n ownsPropagator: boolean;\n users: number;\n };\n\nconst acquireOtelGlobals = () => {\n if (globalRegistration) {\n globalRegistration.users += 1;\n } else {\n const contextManager = new ZoneContextManager().enable();\n const ownsContext = context.setGlobalContextManager(contextManager);\n if (!ownsContext) contextManager.disable();\n globalRegistration = {\n contextManager: ownsContext ? contextManager : undefined,\n ownsContext,\n ownsPropagator: propagation.setGlobalPropagator(new W3CTraceContextPropagator()),\n users: 1,\n };\n }\n let released = false;\n return () => {\n if (released || !globalRegistration) return;\n released = true;\n globalRegistration.users -= 1;\n if (globalRegistration.users > 0) return;\n if (globalRegistration.ownsContext) context.disable();\n if (globalRegistration.ownsPropagator) propagation.disable();\n globalRegistration = undefined;\n };\n};\n\n/**\n * 用 Proxy 包装一层 debug 旁路,避免直接 mutate 第三方 exporter 实例(其内部可能含 #private fields)。\n */\nconst wrapWithDebug = <TExporter extends { export: (...args: any[]) => any }>(\n exporter: TExporter,\n enabled: boolean,\n): TExporter => {\n if (!enabled) {\n return exporter;\n }\n return new Proxy(exporter, {\n get(target, prop, receiver) {\n if (prop === 'export') {\n return (records: unknown, callback: unknown) => {\n globalThis.console?.log('[bk-ot][rum]', records);\n return (target as { export: (...args: unknown[]) => unknown }).export(records, callback);\n };\n }\n const value = Reflect.get(target, prop, receiver);\n return typeof value === 'function' ? value.bind(target) : value;\n },\n });\n};\n\n// 请求插件统一负责 Fetch/XHR span、Trace Header 与活动计数。\nconst getCorePlugins = (config: ResolvedBkOTConfig): BkOTPlugin[] => [\n createCommonInstrumentationsPlugin(config.tracking.request),\n];\n\nconst getRumContextPlugins = (config: ResolvedBkOTConfig): BkOTPlugin[] => [\n createSessionPlugin(config.session),\n ...createBuiltInPlugin(config.tracking.device, true, createDevicePlugin),\n createActivityPlugin(),\n createPageViewPlugin(),\n createResourcePlugin(isBuiltInPluginEnabled(config.tracking.resource, true)),\n];\n\nconst isBuiltInPluginEnabled = <TOptions extends object>(\n option: boolean | TOptions | undefined,\n defaultEnabled: boolean,\n) => (option === undefined ? defaultEnabled : option !== false);\n\nconst getBuiltInPluginOptions = <TOptions extends object>(option: boolean | TOptions | undefined) =>\n typeof option === 'object' && option !== null ? option : undefined;\n\nconst createBuiltInPlugin = <TOptions extends object>(\n option: boolean | TOptions | undefined,\n defaultEnabled: boolean,\n factory: (options?: TOptions) => BkOTPlugin,\n) => (isBuiltInPluginEnabled(option, defaultEnabled) ? [factory(getBuiltInPluginOptions(option))] : []);\n\n// 上下文插件先启动,确保后续 span 能带上关联字段;Session sampler 与 processor 负责统一采样。\nconst getRumPlugins = (tracking: BkOTTrackingConfig): BkOTPlugin[] => [\n ...createBuiltInPlugin(tracking.error, true, createErrorPlugin),\n ...createBuiltInPlugin(tracking.webVitals, true, createWebVitalsPlugin),\n ...createBuiltInPlugin(tracking.blankScreen, true, createBlankScreenPlugin),\n ...createBuiltInPlugin(tracking.action, true, createActionPlugin),\n ...createBuiltInPlugin(tracking.websocket, false, createWebSocketPlugin),\n ...createBuiltInPlugin(tracking.longTask, false, createLongTaskPlugin),\n ...createBuiltInPlugin(tracking.cspViolation, false, createCspViolationPlugin),\n];\n\ntype SdkLifecyclePhase = 'idle' | 'started' | 'starting' | 'stopped';\n\n/**\n * 浏览器 RUM SDK 的生命周期入口。Provider 在构造时创建,插件和全局 patch 则随 start、授权变更和\n * shutdown 安装或卸载;Session 决定统一作用于所有 RUM span。\n */\nexport class BkOpenTelemetry implements BkOTInstance {\n private readonly activityObserver = new RumActivityObserver();\n private allowInitialResourceHistory: boolean;\n private readonly collectAttributesAt = (timestamp: number, historical: boolean): Attributes => {\n this.sessionTransition.checkSession();\n const attributes = historical\n ? this.runtimeContext.getAttributesAt(timestamp)\n : this.runtimeContext.getAttributes();\n if (!this.sessionTransition.isPending(timestamp)) return attributes;\n // 该对象可被 Action 等延迟上报的采集器持有。先移除旧关联,提交后再填充事件时刻的归属。\n for (const key of Object.keys(attributes)) {\n if (\n key.startsWith('session.') ||\n key.startsWith('view.') ||\n key === RUM_ATTRIBUTES.actionId ||\n key === RUM_ATTRIBUTES.actionIds\n )\n delete attributes[key];\n }\n this.sessionTransition.whenReady(() => {\n const resolved = this.runtimeContext.getAttributesAt(timestamp);\n for (const [key, value] of Object.entries(resolved)) {\n if (\n key.startsWith('session.') ||\n key.startsWith('view.') ||\n key === RUM_ATTRIBUTES.actionId ||\n key === RUM_ATTRIBUTES.actionIds\n )\n attributes[key] = value;\n }\n }, true);\n return attributes;\n };\n private collectionStopping?: Promise<void>;\n private readonly flushProviders = async () => {\n await this.tracerProvider.forceFlush();\n };\n private hasStartedCollection = false;\n private readonly isStopped = () => this.phase === 'stopped';\n private latestManualViewOptions?: BkOTStartViewOptions;\n private phase: SdkLifecyclePhase = 'idle';\n private pluginManager?: PluginManager;\n private readonly registeredInstrumentations: Instrumentation[];\n private releaseOtelGlobals?: () => void;\n private readonly runtimeContext: RumRuntimeContext;\n private sampled = false;\n\n private readonly sessionTransition: SessionTransition;\n private shutdownTask?: Promise<void>;\n private readonly startCollection = async () => {\n // Provider 始终存在以保持公开 API 稳定;采集插件仅在启用且获得授权后安装。\n // 快速撤回再授权时先完成旧插件清理,避免新启动被旧 pluginManager 挡住或被其 teardown 清空。\n await this.collectionStopping;\n if (this.isStopped() || this.pluginManager || !this.config.enabled || this.config.trackingConsent !== 'granted')\n return;\n if (typeof window !== 'undefined') {\n if (!this.tabId) {\n this.tabId = createRandomId('tab');\n try {\n const stored = window.sessionStorage.getItem('bk_ot_tab_id');\n if (stored) this.tabId = stored;\n else window.sessionStorage.setItem('bk_ot_tab_id', this.tabId);\n } catch {\n /* 禁止持久化时,仅在当前 SDK 实例中保留标签页标识。 */\n }\n }\n this.runtimeContext.setAttributes({ [RUM_ATTRIBUTES.tabId]: this.tabId });\n }\n this.releaseOtelGlobals = acquireOtelGlobals();\n const pluginManager = this.createPluginManager();\n this.pluginManager = pluginManager;\n if (this.config.view.tracking === 'manual' && this.latestManualViewOptions) {\n this.runtimeContext.dispatchViewCommand({\n type: 'start',\n options: this.latestManualViewOptions,\n // 撤权后的重新授权建立新的体验区间,不回填到此前不允许采集的文档起点。\n startedAt: this.hasStartedCollection ? Date.now() : undefined,\n relativeStartedAt:\n this.hasStartedCollection && typeof performance !== 'undefined' ? performance.now() : undefined,\n });\n }\n const collectionStart = {\n allowInitialResourceHistory: this.allowInitialResourceHistory && !this.hasStartedCollection,\n isInitialDocument: !this.hasStartedCollection,\n startedAt: Date.now(),\n relativeStartedAt: typeof performance !== 'undefined' ? performance.now() : 0,\n };\n this.hasStartedCollection = true;\n try {\n await pluginManager.start({ ...this.createPluginContext(), collectionStart });\n if (this.isStopped() || this.pluginManager !== pluginManager || this.config.trackingConsent !== 'granted') return;\n this.registerInstrumentations(this.config.extensions.instrumentations ?? []);\n } catch (error) {\n if (this.pluginManager === pluginManager) await this.stopCollection(false);\n else await pluginManager.shutdown();\n throw error;\n }\n };\n private readonly stopCollection = async (flush: boolean) => {\n if (this.collectionStopping) return this.collectionStopping;\n const pluginManager = this.pluginManager;\n this.pluginManager = undefined;\n this.sessionTransition.reset();\n const instrumentations = this.registeredInstrumentations.splice(0);\n const releaseGlobals = this.releaseOtelGlobals;\n this.releaseOtelGlobals = undefined;\n // 撤销授权后立即清空 Session,防止后续手工 API 继续复用旧采样决定。\n this.setRuntimeAttributes({\n [RUM_ATTRIBUTES.sessionHasReplay]: undefined,\n [RUM_ATTRIBUTES.sessionId]: undefined,\n });\n const stopping = (async () => {\n try {\n await pluginManager?.shutdown();\n if (flush) await this.flushProviders();\n } finally {\n while (instrumentations.length) instrumentations.pop()?.disable?.();\n releaseGlobals?.();\n }\n })();\n this.collectionStopping = stopping;\n try {\n await stopping;\n } finally {\n if (this.collectionStopping === stopping) this.collectionStopping = undefined;\n }\n };\n private tabId?: string;\n private readonly teardownCallbacks: Array<() => void> = [];\n private readonly tracerProvider: WebTracerProvider;\n private assertBeforeStart(method: string) {\n if (this.phase !== 'idle') {\n throw new Error(`[bk-ot] ${method}() must be called before start(); set autoStart: false before registration.`);\n }\n }\n private createPluginContext(): BkOTRuntimeContext {\n return {\n applyRedact: this.applyRedact,\n beginSessionTransition: this.beginSessionTransition,\n registerSessionCheck: this.registerSessionCheck,\n isSessionTransitionPending: this.isSessionTransitionPending,\n afterSessionTransition: this.afterSessionTransition,\n config: this.config,\n registerActionContext: this.runtimeContext.registerActionContext,\n endActionContext: this.runtimeContext.endActionContext,\n flush: this.flush,\n getRuntimeAttributes: this.getRuntimeAttributes,\n getRuntimeAttributesAt: this.getRuntimeAttributesAt,\n getRuntimeContextAtRelativeTime: relativeTime => {\n // 先关闭已过期身份,再查历史;不能让显式快照绕过后台资源的过期边界。\n this.sessionTransition.checkSession();\n return this.runtimeContext.getRuntimeContextAtRelativeTime(relativeTime);\n },\n getViewHistory: this.runtimeContext.getViewHistory,\n isSampled: this.isSampled,\n isSessionActive: this.isSessionActive,\n isViewActive: this.isViewActive,\n notifySessionLifecycle: this.notifySessionLifecycle,\n notifyActivity: this.activityObserver.notify,\n onActivity: this.activityObserver.subscribe,\n onSessionLifecycle: this.onSessionLifecycle,\n onViewCommand: this.runtimeContext.onViewCommand,\n onViewChange: this.runtimeContext.onViewChange,\n registerInstrumentations: this.registerInstrumentations,\n setRuntimeAttributes: this.setRuntimeAttributes,\n setUser: this.setUser,\n setView: this.runtimeContext.setView,\n startSpan: this.startSpan,\n tracer: this.tracer,\n };\n }\n private createPluginManager() {\n return new PluginManager([\n ...getRumContextPlugins(this.config),\n ...getCorePlugins(this.config),\n ...getRumPlugins(this.config.tracking),\n ...(this.config.extensions.plugins ?? []),\n ]);\n }\n\n /** elapsed 为相对当前 View 起点的毫秒;省略时使用调用时刻,避免混用 epoch 时间。 */\n public readonly addTiming = (name: string, elapsed?: number) => {\n if (this.isSampled())\n this.runtimeContext.dispatchViewCommand({ name, elapsed, time: Date.now(), type: 'add_timing' });\n };\n\n public readonly afterSessionTransition = (callback: () => void, afterAssociation = false) =>\n this.sessionTransition.whenReady(callback, afterAssociation);\n\n public readonly applyRedact = (attributes: Attributes) => this.config.hooks.redactAttributes(attributes);\n public readonly beginSessionTransition = (at: number) => this.sessionTransition.begin(at);\n public readonly config: ResolvedBkOTConfig;\n public readonly flush = async () => {\n await this.pluginManager?.flush();\n await this.flushProviders();\n };\n\n public readonly getRuntimeAttributes = () => this.collectAttributesAt(Date.now(), false);\n public readonly getRuntimeAttributesAt = (timestamp: number) => this.collectAttributesAt(timestamp, true);\n public readonly getViewContext = (): Attributes => ({ ...this.runtimeContext.getView().attributes });\n public readonly isSampled = () => {\n this.sessionTransition.checkSession();\n return (\n this.config.trackingConsent === 'granted' &&\n this.config.enabled &&\n (this.sampled || this.sessionTransition.isPending())\n );\n };\n public readonly isSessionActive = () => {\n this.sessionTransition.checkSession();\n return this.runtimeContext.isSessionActive();\n };\n public readonly isSessionTransitionPending = () => this.sessionTransition.isPending();\n public readonly isViewActive = () => this.runtimeContext.isViewActive();\n\n public readonly notifySessionLifecycle = (event: BkOTSessionLifecycleEvent) => {\n this.runtimeContext.notifySessionLifecycle(event);\n };\n\n public readonly onSessionLifecycle = (listener: (event: BkOTSessionLifecycleEvent) => void) =>\n this.runtimeContext.onSessionLifecycle(listener);\n\n public readonly registerInstrumentations = (instrumentations: Instrumentation[]) => {\n if (!instrumentations.length) return;\n instrumentations.forEach(instrumentation => {\n instrumentation.setTracerProvider(this.tracerProvider);\n if (!instrumentation.getConfig().enabled) instrumentation.enable();\n });\n this.registeredInstrumentations.push(...instrumentations);\n };\n\n public readonly registerSessionCheck = (check: () => void) => this.sessionTransition.registerCheck(check);\n\n public readonly reportAction = ({ attributes = {}, name }: BkOTActionEventPayload) => {\n if (!this.isSampled()) {\n return;\n }\n const actionId = createRandomId('action');\n const occurredAt = Date.now();\n const spanAttributes = {\n ...this.config.hooks.getPageAttributes(),\n ...attributes,\n ...buildRumSpanAttributes({\n spanType: RUM_SPAN_TYPE.action,\n }),\n [RUM_ATTRIBUTES.actionId]: actionId,\n [RUM_ATTRIBUTES.actionName]: name,\n [RUM_ATTRIBUTES.actionType]: 'custom',\n };\n const span = this.startSpan(\n buildRumSpanName({ attributes: spanAttributes, spanType: RUM_SPAN_TYPE.action }),\n spanAttributes,\n { rumSpanType: RUM_SPAN_TYPE.action, startTime: occurredAt },\n );\n span.end(occurredAt);\n };\n\n public readonly reportCustomEvent = ({ attributes = {}, error, name }: BkOTCustomEventPayload) => {\n if (!this.isSampled()) {\n // 未采样时静默丢弃;如需调试请把 debug 选项打开\n if (this.config.debug) {\n globalThis.console?.warn('[bk-ot] custom event dropped (not sampled):', name);\n }\n return;\n }\n\n const occurredAt = Date.now();\n const spanAttributes = {\n ...this.config.hooks.getPageAttributes(),\n ...this.config.hooks.getCustomAttributes(),\n ...attributes,\n ...buildRumSpanAttributes({\n outcome: error ? RUM_SPAN_OUTCOME.error : RUM_SPAN_OUTCOME.success,\n spanType: RUM_SPAN_TYPE.custom,\n }),\n };\n const span = this.startSpan(\n buildRumSpanName({ attributes: spanAttributes, nameHint: name, spanType: RUM_SPAN_TYPE.custom }),\n spanAttributes,\n { startTime: occurredAt },\n );\n\n if (error) {\n span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n }\n\n span.end(occurredAt);\n };\n\n public readonly setRuntimeAttributes = (attributes: Attributes, changedAt?: number) => {\n const nextAttributes = { ...attributes };\n const effectiveChangedAt = changedAt ?? Date.now();\n if (RUM_ATTRIBUTES.sessionId in attributes) {\n // 采样以 Session 为边界重新计算,并保存在运行时私有历史中。\n const sessionId = attributes[RUM_ATTRIBUTES.sessionId];\n this.sampled =\n this.config.enabled && typeof sessionId === 'string' && sessionId.length > 0\n ? isBkOTSampled(this.config, sessionId)\n : false;\n this.runtimeContext.setSessionSampled(this.sampled, effectiveChangedAt);\n }\n this.runtimeContext.setAttributes(nextAttributes, effectiveChangedAt);\n };\n\n public readonly setTrackingConsent = async (consent: BkOTTrackingConsent) => {\n // 包括 start 前的撤权:之后的首次授权也不能读取曾明确拒绝采集的历史。\n if (consent === 'not-granted') this.allowInitialResourceHistory = false;\n if (this.config.trackingConsent === consent) return;\n this.config.trackingConsent = consent;\n if (this.phase !== 'started' && this.phase !== 'starting') return;\n if (consent === 'granted') await this.startCollection();\n else await this.stopCollection(true);\n };\n\n public readonly setUser = (user: BkOTUserContext) => {\n this.runtimeContext.setUser(user);\n };\n\n public readonly setViewContext = (attributes: Attributes) => {\n if (this.isSampled())\n this.runtimeContext.dispatchViewCommand({ attributes: { ...attributes }, type: 'set_context' });\n };\n\n public readonly setViewContextProperty = (key: string, value: Attributes[string]) => {\n if (this.isSampled()) this.runtimeContext.dispatchViewCommand({ key, value, type: 'set_context_property' });\n };\n\n public readonly setViewLoadingTime = () => {\n if (this.isSampled()) this.runtimeContext.dispatchViewCommand({ time: Date.now(), type: 'set_loading_time' });\n };\n\n public readonly setViewName = (name: string) => {\n if (this.isSampled()) this.runtimeContext.dispatchViewCommand({ name, type: 'set_name' });\n };\n\n public readonly shutdown = async () => {\n if (this.shutdownTask) return this.shutdownTask;\n // 在任何 await 之前封住启动路径,迟到的 start 不得重新安装监听器或恢复 started。\n this.phase = 'stopped';\n this.shutdownTask = (async () => {\n await this.stopCollection(false);\n await this.flushProviders();\n while (this.teardownCallbacks.length) this.teardownCallbacks.pop()?.();\n await this.tracerProvider.shutdown();\n })();\n return this.shutdownTask;\n };\n\n public readonly start = async () => {\n if (this.phase === 'started' || this.phase === 'starting') {\n return;\n }\n if (this.phase === 'stopped') {\n // shutdown 已经销毁了 provider/processor,此处禁止再次启动\n throw new Error('[bk-ot] instance has been shut down and cannot be restarted; create a new instance instead.');\n }\n if (!this.config.enabled) {\n this.phase = 'started';\n return;\n }\n this.phase = 'starting';\n try {\n await this.startCollection();\n if (this.phase !== 'starting') return;\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // 页面进入后台或被丢弃前尽力导出批量数据;两个事件并存以覆盖不同浏览器生命周期。\n const flushOnPageHide = () => {\n void this.flush();\n };\n const flushOnHidden = () => {\n if (document.visibilityState === 'hidden') {\n void this.flush();\n }\n };\n window.addEventListener('pagehide', flushOnPageHide);\n document.addEventListener('visibilitychange', flushOnHidden);\n document.addEventListener('freeze', flushOnPageHide);\n this.teardownCallbacks.push(\n () => window.removeEventListener('pagehide', flushOnPageHide),\n () => document.removeEventListener('visibilitychange', flushOnHidden),\n () => document.removeEventListener('freeze', flushOnPageHide),\n );\n }\n } catch (error) {\n while (this.teardownCallbacks.length) {\n this.teardownCallbacks.pop()?.();\n }\n await this.stopCollection(false);\n if (this.phase === 'starting') this.phase = 'idle';\n throw error;\n }\n if (this.phase === 'starting') this.phase = 'started';\n };\n\n public readonly startSpan = (name: string, attributes: Attributes = {}, options?: BkOTStartSpanOptions): Span => {\n const contextTime =\n options?.contextTime ?? (typeof options?.startTime === 'number' ? options.startTime : undefined);\n const runtimeAttributes =\n options?.contextAttributes ??\n (contextTime === undefined ? this.getRuntimeAttributes() : this.getRuntimeAttributesAt(contextTime));\n const redactedAttributes = filterActionAttributes(this.applyRedact({ ...runtimeAttributes, ...attributes }));\n if (redactedAttributes[RUM_ATTRIBUTES.spanType] === RUM_SPAN_TYPE.session) {\n for (const key of Object.keys(redactedAttributes)) {\n if (key.startsWith('view.') || key === RUM_ATTRIBUTES.actionId || key === RUM_ATTRIBUTES.actionIds)\n delete redactedAttributes[key];\n }\n }\n if (\n typeof redactedAttributes[RUM_ATTRIBUTES.sessionId] !== 'string' &&\n !this.sessionTransition.isPending(contextTime ?? Date.now())\n ) {\n // 历史空白区间不能通过 Tracer 的当前上下文补成一个新的 Session。\n return trace.wrapSpanContext(INVALID_SPAN_CONTEXT);\n }\n const spanName = options?.rumSpanType\n ? buildRumSpanName({ attributes: redactedAttributes, spanType: options.rumSpanType })\n : name;\n let parentContext = context.active();\n if (options?.contextTime !== undefined)\n parentContext = parentContext.setValue(RUM_CONTEXT_TIME, options.contextTime);\n if (options?.contextAttributes !== undefined) parentContext = parentContext.setValue(RUM_CONTEXT_SNAPSHOT, true);\n return this.tracer.startSpan(\n spanName,\n {\n kind: options?.kind ?? SpanKind.INTERNAL,\n links: options?.links?.map(link => ({\n ...link,\n context: { ...link.context },\n attributes: this.applyRedact(copyAttributes(link.attributes)),\n })),\n startTime: options?.startTime,\n attributes: redactedAttributes,\n },\n parentContext,\n );\n };\n\n public readonly startView = (options: BkOTStartViewOptions = {}) => {\n // 保存路由意图与允许采集是两件事。首次 hidden/未授权时不能导出,\n // 但也不能让 Router 去重后永久失去该页面;Page View 在 Session 生效后消费。\n if (this.phase === 'stopped') return;\n const captured = { ...options, attributes: copyAttributes(options.attributes) };\n if (this.config.view.tracking === 'manual') this.latestManualViewOptions = captured;\n this.runtimeContext.dispatchViewCommand({ options: captured, type: 'start' });\n };\n\n public readonly tracer: BkOTRuntimeContext['tracer'];\n\n public readonly use = (plugin: BkOTPlugin): this => {\n this.assertBeforeStart('use');\n this.config.extensions.plugins?.push(plugin);\n return this;\n };\n\n public readonly useInstrumentation = (instrumentation: Instrumentation): this => {\n this.assertBeforeStart('useInstrumentation');\n if (this.config.enabled) this.config.extensions.instrumentations?.push(instrumentation);\n return this;\n };\n\n constructor(inputConfig: BkOTOptions) {\n this.config = resolveConfig(inputConfig);\n this.allowInitialResourceHistory = this.config.trackingConsent === 'granted';\n this.sessionTransition = new SessionTransition(this.config.spanBatch?.maxQueueSize ?? 2048);\n this.runtimeContext = new RumRuntimeContext({}, this.config.user);\n\n const resource = resourceFromAttributes(this.config.resourceAttributes);\n const spanProcessors = (() => {\n const exporter = wrapWithDebug(\n new OTLPTraceExporter(createExporterOptions(this.config.transport)),\n this.config.debug,\n );\n const processor =\n this.config.spanProcessor === 'simple'\n ? new SimpleSpanProcessor(exporter)\n : new BatchSpanProcessor(exporter, this.config.spanBatch);\n return [\n new FilteringSpanProcessor(\n processor,\n this.config,\n () =>\n this.applyRedact({\n ...this.runtimeContext.getAttributes(),\n ...this.config.hooks.getPageAttributes(),\n }),\n {\n checkSession: this.sessionTransition.checkSession,\n isPending: this.sessionTransition.isPending,\n whenReady: callback => this.sessionTransition.whenReady(callback, true),\n getAttributesAt: timestamp => this.applyRedact(this.runtimeContext.getAttributesAt(timestamp)),\n isSampled: attributes =>\n this.config.trackingConsent === 'granted' &&\n this.config.enabled &&\n typeof attributes[RUM_ATTRIBUTES.sessionId] === 'string' &&\n isBkOTSampled(this.config, attributes[RUM_ATTRIBUTES.sessionId] as string),\n },\n this.activityObserver.notify,\n ),\n ];\n })();\n this.tracerProvider = new WebTracerProvider({\n resource,\n sampler: new RumSessionSampler(attributes => {\n this.sessionTransition.checkSession();\n if (!this.config.enabled || this.config.trackingConsent !== 'granted') return false;\n const sessionId = attributes[RUM_ATTRIBUTES.sessionId];\n return typeof sessionId === 'string' ? isBkOTSampled(this.config, sessionId) : this.isSampled();\n }),\n spanProcessors,\n });\n this.tracer = this.tracerProvider.getTracer(BK_OT_INSTRUMENTATION_NAME);\n this.registeredInstrumentations = [];\n if (this.config.autoStart) {\n void this.start().catch(error => {\n globalThis.console?.warn('[bk-ot] auto start failed:', error);\n });\n }\n }\n}\n","/*\n * Tencent is pleased to support the open source community by making\n * 蓝鲸智云PaaS平台 (BlueKing PaaS) available.\n * Copyright (C) 2017-2025 Tencent. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { normalizeUrlPathTemplate } from '../core/url';\n\nimport type { BkOTStartViewOptions } from '../core/runtime-context';\n\n/** 使用结构化接口,Vue Router 的 Hash/History 实例均可传入,无需把 Vue 打包进 SDK。 */\nexport interface BkOTVueRoute {\n matched: readonly { path: string }[];\n path: string;\n}\n\nexport interface BkOTVueRouter {\n currentRoute: { readonly value: BkOTVueRoute };\n afterEach: (guard: (to: BkOTVueRoute, from: BkOTVueRoute, failure?: unknown) => void) => () => void;\n}\n\nexport interface BkOTVueViewClient {\n config: { view: { tracking: 'auto' | 'manual' } };\n isViewActive: () => boolean;\n startView: (options: BkOTStartViewOptions) => void;\n}\n\nconst registrations = new WeakMap<BkOTVueViewClient, WeakMap<BkOTVueRouter, () => void>>();\n\n/** 在 SDK start 完成后接入;成功路由提交定义 View 边界,不代表业务内容已经渲染完成。 */\nexport const trackVueRouterViews = (rum: BkOTVueViewClient, router: BkOTVueRouter): (() => void) => {\n if (rum.config.view.tracking !== 'manual') {\n throw new Error('[bk-ot] trackVueRouterViews requires tracking.view.tracking=\"manual\".');\n }\n const routers = registrations.get(rum) ?? new WeakMap<BkOTVueRouter, () => void>();\n registrations.set(rum, routers);\n const existing = routers.get(router);\n if (existing) return existing;\n\n let stopped = false;\n let lastPath: string | undefined;\n const startRoute = (route: BkOTVueRoute, force = false) => {\n if (stopped || (!force && route.path === lastPath)) return;\n // Vue Router 的 matched.path 是参数化路由定义;不能用浏览器 pathname 推断 Hash 路由。\n const template =\n [...route.matched].reverse().find(record => record.path)?.path ?? normalizeUrlPathTemplate(route.path);\n try {\n rum.startView({ name: template, urlTemplate: template });\n lastPath = route.path;\n } catch {\n // 采集端异常不得让已成功提交的业务导航变成失败;下一次通知仍可重试。\n }\n };\n const unsubscribe = router.afterEach((to, _from, failure) => {\n if (!failure) startRoute(to);\n });\n const onPageShow = (event: PageTransitionEvent) => {\n if (!event.persisted) return;\n // 等同一 pageshow 的核心监听处理恢复时刻;Consent 重启可能改变监听注册顺序。\n void Promise.resolve().then(() => {\n // BFCache 不一定触发 Router 导航;Session 续期已恢复 View 时不能再建立一次。\n if (!stopped && !rum.isViewActive() && router.currentRoute.value.matched.length) {\n startRoute(router.currentRoute.value, true);\n }\n });\n };\n if (typeof window !== 'undefined') window.addEventListener('pageshow', onPageShow);\n const stop = () => {\n if (stopped) return;\n stopped = true;\n unsubscribe();\n if (typeof window !== 'undefined') window.removeEventListener('pageshow', onPageShow);\n routers.delete(router);\n };\n routers.set(router, stop);\n // 空 matched 是 Router 尚未完成首次解析的 START_LOCATION,等待 afterEach 即可。\n if (router.currentRoute.value.matched.length) startRoute(router.currentRoute.value);\n return stop;\n};\n"],"mappings":"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"}