posthog-js 1.158.0 → 1.158.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.full.js +2 -2
- package/dist/array.full.js.map +1 -1
- package/dist/array.js +1 -1
- package/dist/array.js.map +1 -1
- package/dist/exception-autocapture.js.map +1 -1
- package/dist/lib/src/entrypoints/web-vitals.d.ts +4 -4
- package/dist/lib/src/extensions/replay/config.d.ts +1 -1
- package/dist/lib/src/extensions/replay/sessionrecording.d.ts +4 -0
- package/dist/lib/src/extensions/surveys.d.ts +2 -2
- package/dist/lib/src/utils/globals.d.ts +6 -6
- package/dist/lib/src/utils/logger.d.ts +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/module.d.ts +4 -0
- package/dist/module.js +1 -1
- package/dist/module.js.map +1 -1
- package/dist/recorder-v2.js.map +1 -1
- package/dist/recorder.js.map +1 -1
- package/lib/package.json +14 -9
- package/lib/src/autocapture-utils.js.map +1 -1
- package/lib/src/autocapture.js.map +1 -1
- package/lib/src/consent.js +1 -1
- package/lib/src/consent.js.map +1 -1
- package/lib/src/decide.js.map +1 -1
- package/lib/src/entrypoints/exception-autocapture.js.map +1 -1
- package/lib/src/entrypoints/recorder.js +12 -12
- package/lib/src/entrypoints/recorder.js.map +1 -1
- package/lib/src/entrypoints/surveys.js.map +1 -1
- package/lib/src/entrypoints/tracing-headers.js.map +1 -1
- package/lib/src/entrypoints/web-vitals.d.ts +4 -4
- package/lib/src/extensions/exception-autocapture/error-conversion.js +2 -2
- package/lib/src/extensions/exception-autocapture/error-conversion.js.map +1 -1
- package/lib/src/extensions/exception-autocapture/index.js.map +1 -1
- package/lib/src/extensions/exception-autocapture/stack-trace.js.map +1 -1
- package/lib/src/extensions/exception-autocapture/type-checking.js +1 -1
- package/lib/src/extensions/exception-autocapture/type-checking.js.map +1 -1
- package/lib/src/extensions/rageclick.js.map +1 -1
- package/lib/src/extensions/replay/config.d.ts +1 -1
- package/lib/src/extensions/replay/config.js.map +1 -1
- package/lib/src/extensions/replay/external/denylist.js.map +1 -1
- package/lib/src/extensions/replay/mutation-rate-limiter.js.map +1 -1
- package/lib/src/extensions/replay/rrweb-plugins/patch.js.map +1 -1
- package/lib/src/extensions/replay/sessionrecording-utils.js.map +1 -1
- package/lib/src/extensions/replay/sessionrecording.d.ts +4 -0
- package/lib/src/extensions/replay/sessionrecording.js +22 -13
- package/lib/src/extensions/replay/sessionrecording.js.map +1 -1
- package/lib/src/extensions/segment-integration.js.map +1 -1
- package/lib/src/extensions/sentry-integration.js.map +1 -1
- package/lib/src/extensions/surveys/action-matcher.js.map +1 -1
- package/lib/src/extensions/surveys/components/BottomSection.jsx.map +1 -1
- package/lib/src/extensions/surveys/components/ConfirmationMessage.jsx.map +1 -1
- package/lib/src/extensions/surveys/components/QuestionTypes.jsx.map +1 -1
- package/lib/src/extensions/surveys/hooks/useContrastingTextColor.js.map +1 -1
- package/lib/src/extensions/surveys/surveys-utils.jsx.map +1 -1
- package/lib/src/extensions/surveys.d.ts +2 -2
- package/lib/src/extensions/surveys.jsx.map +1 -1
- package/lib/src/extensions/toolbar.js +2 -2
- package/lib/src/extensions/toolbar.js.map +1 -1
- package/lib/src/extensions/tracing-headers.js.map +1 -1
- package/lib/src/extensions/web-vitals/index.js.map +1 -1
- package/lib/src/heatmaps.js.map +1 -1
- package/lib/src/page-view.js.map +1 -1
- package/lib/src/posthog-core.js +5 -5
- package/lib/src/posthog-core.js.map +1 -1
- package/lib/src/posthog-featureflags.js.map +1 -1
- package/lib/src/posthog-persistence.js.map +1 -1
- package/lib/src/posthog-surveys.js.map +1 -1
- package/lib/src/rate-limiter.js.map +1 -1
- package/lib/src/request-queue.js.map +1 -1
- package/lib/src/request.js +2 -2
- package/lib/src/request.js.map +1 -1
- package/lib/src/retry-queue.js.map +1 -1
- package/lib/src/scroll-manager.js.map +1 -1
- package/lib/src/session-props.js.map +1 -1
- package/lib/src/sessionid.js.map +1 -1
- package/lib/src/storage.js +10 -10
- package/lib/src/storage.js.map +1 -1
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/blocked-uas.js.map +1 -1
- package/lib/src/utils/event-utils.js +13 -13
- package/lib/src/utils/event-utils.js.map +1 -1
- package/lib/src/utils/globals.d.ts +6 -6
- package/lib/src/utils/index.js +3 -3
- package/lib/src/utils/index.js.map +1 -1
- package/lib/src/utils/logger.d.ts +1 -1
- package/lib/src/utils/logger.js.map +1 -1
- package/lib/src/utils/request-router.js +11 -2
- package/lib/src/utils/request-router.js.map +1 -1
- package/lib/src/utils/request-utils.js +1 -1
- package/lib/src/utils/request-utils.js.map +1 -1
- package/lib/src/utils/simple-event-emitter.js.map +1 -1
- package/lib/src/utils/survey-event-receiver.js.map +1 -1
- package/lib/src/utils/type-utils.js.map +1 -1
- package/lib/src/utils/user-agent-utils.js.map +1 -1
- package/lib/src/uuidv7.js.map +1 -1
- package/package.json +14 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/extensions/replay/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { CapturedNetworkRequest, NetworkRecordOptions, PostHogConfig } from '../../types'\nimport { isFunction, isNullish, isString, isUndefined } from '../../utils/type-utils'\nimport { convertToURL } from '../../utils/request-utils'\nimport { logger } from '../../utils/logger'\nimport { shouldCaptureValue } from '../../autocapture-utils'\nimport { each } from '../../utils'\n\nconst LOGGER_PREFIX = '[SessionRecording]'\nconst REDACTED = 'redacted'\n\nexport const defaultNetworkOptions: Required<NetworkRecordOptions> = {\n initiatorTypes: [\n 'audio',\n 'beacon',\n 'body',\n 'css',\n 'early-hint',\n 'embed',\n 'fetch',\n 'frame',\n 'iframe',\n 'icon',\n 'image',\n 'img',\n 'input',\n 'link',\n 'navigation',\n 'object',\n 'ping',\n 'script',\n 'track',\n 'video',\n 'xmlhttprequest',\n ],\n maskRequestFn: (data: CapturedNetworkRequest) => data,\n recordHeaders: false,\n recordBody: false,\n recordInitialRequests: false,\n recordPerformance: false,\n performanceEntryTypeToObserve: [\n // 'event', // This is too noisy as it covers all browser events\n 'first-input',\n // 'mark', // Mark is used too liberally. We would need to filter for specific marks\n // 'measure', // Measure is used too liberally. We would need to filter for specific measures\n 'navigation',\n 'paint',\n 'resource',\n ],\n payloadSizeLimitBytes: 1000000,\n payloadHostDenyList: ['.lr-ingest.io', '.ingest.sentry.io'],\n}\n\nconst HEADER_DENY_LIST = [\n 'authorization',\n 'x-forwarded-for',\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-real-ip',\n 'remote-addr',\n 'forwarded',\n 'proxy-authorization',\n 'x-csrf-token',\n 'x-csrftoken',\n 'x-xsrf-token',\n]\n\nconst PAYLOAD_CONTENT_DENY_LIST = [\n 'password',\n 'secret',\n 'passwd',\n 'api_key',\n 'apikey',\n 'auth',\n 'credentials',\n 'mysql_pwd',\n 'privatekey',\n 'private_key',\n 'token',\n]\n\n// we always remove headers on the deny list because we never want to capture this sensitive data\nconst removeAuthorizationHeader = (data: CapturedNetworkRequest): CapturedNetworkRequest => {\n const headers = data.requestHeaders\n if (!isNullish(headers)) {\n each(Object.keys(headers ?? {}), (header) => {\n if (HEADER_DENY_LIST.includes(header.toLowerCase())) {\n headers[header] = REDACTED\n }\n })\n }\n return data\n}\n\nconst POSTHOG_PATHS_TO_IGNORE = ['/s/', '/e/', '/i/']\n// want to ignore posthog paths when capturing requests, or we can get trapped in a loop\n// because calls to PostHog would be reported using a call to PostHog which would be reported....\nconst ignorePostHogPaths = (data: CapturedNetworkRequest): CapturedNetworkRequest | undefined => {\n const url = convertToURL(data.name)\n if (url && url.pathname && POSTHOG_PATHS_TO_IGNORE.some((path) => url.pathname.indexOf(path) === 0)) {\n return undefined\n }\n return data\n}\n\nfunction estimateBytes(payload: string): number {\n return new Blob([payload]).size\n}\n\nfunction enforcePayloadSizeLimit(\n payload: string | null | undefined,\n headers: Record<string, any> | undefined,\n limit: number,\n description: string\n): string | null | undefined {\n if (isNullish(payload)) {\n return payload\n }\n\n let requestContentLength: string | number = headers?.['content-length'] || estimateBytes(payload)\n if (isString(requestContentLength)) {\n requestContentLength = parseInt(requestContentLength)\n }\n\n if (requestContentLength > limit) {\n return LOGGER_PREFIX + ` ${description} body too large to record (${requestContentLength} bytes)`\n }\n\n return payload\n}\n\n// people can have arbitrarily large payloads on their site, but we don't want to ingest them\nconst limitPayloadSize = (\n options: NetworkRecordOptions\n): ((data: CapturedNetworkRequest | undefined) => CapturedNetworkRequest | undefined) => {\n // the smallest of 1MB or the specified limit if there is one\n const limit = Math.min(1000000, options.payloadSizeLimitBytes ?? 1000000)\n\n return (data) => {\n if (data?.requestBody) {\n data.requestBody = enforcePayloadSizeLimit(data.requestBody, data.requestHeaders, limit, 'Request')\n }\n\n if (data?.responseBody) {\n data.responseBody = enforcePayloadSizeLimit(data.responseBody, data.responseHeaders, limit, 'Response')\n }\n\n return data\n }\n}\n\nfunction scrubPayload(payload: string | null | undefined, label: 'Request' | 'Response'): string | null | undefined {\n if (isNullish(payload)) {\n return payload\n }\n let scrubbed = payload\n\n if (!shouldCaptureValue(scrubbed, false)) {\n scrubbed = LOGGER_PREFIX + ' ' + label + ' body ' + REDACTED\n }\n each(PAYLOAD_CONTENT_DENY_LIST, (text) => {\n if (scrubbed?.length && scrubbed?.indexOf(text) !== -1) {\n scrubbed = LOGGER_PREFIX + ' ' + label + ' body ' + REDACTED + ' as might contain: ' + text\n }\n })\n\n return scrubbed\n}\n\nfunction scrubPayloads(capturedRequest: CapturedNetworkRequest | undefined): CapturedNetworkRequest | undefined {\n if (isUndefined(capturedRequest)) {\n return undefined\n }\n\n capturedRequest.requestBody = scrubPayload(capturedRequest.requestBody, 'Request')\n capturedRequest.responseBody = scrubPayload(capturedRequest.responseBody, 'Response')\n\n return capturedRequest\n}\n\n/**\n * whether a maskRequestFn is provided or not,\n * we ensure that we remove the denied header from requests\n * we _never_ want to record that header by accident\n * if someone complains then we'll add an opt-in to let them override it\n */\nexport const buildNetworkRequestOptions = (\n instanceConfig: PostHogConfig,\n remoteNetworkOptions: Pick<\n NetworkRecordOptions,\n 'recordHeaders' | 'recordBody' | 'recordPerformance' | 'payloadHostDenyList'\n >\n): NetworkRecordOptions => {\n const config: NetworkRecordOptions = {\n payloadSizeLimitBytes: defaultNetworkOptions.payloadSizeLimitBytes,\n performanceEntryTypeToObserve: [...defaultNetworkOptions.performanceEntryTypeToObserve],\n payloadHostDenyList: [\n ...(remoteNetworkOptions.payloadHostDenyList || []),\n ...defaultNetworkOptions.payloadHostDenyList,\n ],\n }\n // client can always disable despite remote options\n const canRecordHeaders =\n instanceConfig.session_recording.recordHeaders === false ? false : remoteNetworkOptions.recordHeaders\n const canRecordBody =\n instanceConfig.session_recording.recordBody === false ? false : remoteNetworkOptions.recordBody\n const canRecordPerformance =\n instanceConfig.capture_performance === false ? false : remoteNetworkOptions.recordPerformance\n\n const payloadLimiter = limitPayloadSize(config)\n\n const enforcedCleaningFn: NetworkRecordOptions['maskRequestFn'] = (d: CapturedNetworkRequest) =>\n payloadLimiter(ignorePostHogPaths(removeAuthorizationHeader(d)))\n\n const hasDeprecatedMaskFunction = isFunction(instanceConfig.session_recording.maskNetworkRequestFn)\n\n if (hasDeprecatedMaskFunction && isFunction(instanceConfig.session_recording.maskCapturedNetworkRequestFn)) {\n logger.warn(\n 'Both `maskNetworkRequestFn` and `maskCapturedNetworkRequestFn` are defined. `maskNetworkRequestFn` will be ignored.'\n )\n }\n\n if (hasDeprecatedMaskFunction) {\n instanceConfig.session_recording.maskCapturedNetworkRequestFn = (data: CapturedNetworkRequest) => {\n const cleanedURL = instanceConfig.session_recording.maskNetworkRequestFn!({ url: data.name })\n return {\n ...data,\n name: cleanedURL?.url,\n } as CapturedNetworkRequest\n }\n }\n\n config.maskRequestFn = isFunction(instanceConfig.session_recording.maskCapturedNetworkRequestFn)\n ? (data) => {\n const cleanedRequest = enforcedCleaningFn(data)\n return cleanedRequest\n ? instanceConfig.session_recording.maskCapturedNetworkRequestFn?.(cleanedRequest) ?? undefined\n : undefined\n }\n : (data) => scrubPayloads(enforcedCleaningFn(data))\n\n return {\n ...defaultNetworkOptions,\n ...config,\n recordHeaders: canRecordHeaders,\n recordBody: canRecordBody,\n recordPerformance: canRecordPerformance,\n recordInitialRequests: canRecordPerformance,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/extensions/replay/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { CapturedNetworkRequest, NetworkRecordOptions, PostHogConfig } from '../../types'\nimport { isFunction, isNullish, isString, isUndefined } from '../../utils/type-utils'\nimport { convertToURL } from '../../utils/request-utils'\nimport { logger } from '../../utils/logger'\nimport { shouldCaptureValue } from '../../autocapture-utils'\nimport { each } from '../../utils'\n\nconst LOGGER_PREFIX = '[SessionRecording]'\nconst REDACTED = 'redacted'\n\nexport const defaultNetworkOptions: Required<NetworkRecordOptions> = {\n initiatorTypes: [\n 'audio',\n 'beacon',\n 'body',\n 'css',\n 'early-hint',\n 'embed',\n 'fetch',\n 'frame',\n 'iframe',\n 'icon',\n 'image',\n 'img',\n 'input',\n 'link',\n 'navigation',\n 'object',\n 'ping',\n 'script',\n 'track',\n 'video',\n 'xmlhttprequest',\n ],\n maskRequestFn: (data: CapturedNetworkRequest) => data,\n recordHeaders: false,\n recordBody: false,\n recordInitialRequests: false,\n recordPerformance: false,\n performanceEntryTypeToObserve: [\n // 'event', // This is too noisy as it covers all browser events\n 'first-input',\n // 'mark', // Mark is used too liberally. We would need to filter for specific marks\n // 'measure', // Measure is used too liberally. We would need to filter for specific measures\n 'navigation',\n 'paint',\n 'resource',\n ],\n payloadSizeLimitBytes: 1000000,\n payloadHostDenyList: ['.lr-ingest.io', '.ingest.sentry.io'],\n}\n\nconst HEADER_DENY_LIST = [\n 'authorization',\n 'x-forwarded-for',\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-real-ip',\n 'remote-addr',\n 'forwarded',\n 'proxy-authorization',\n 'x-csrf-token',\n 'x-csrftoken',\n 'x-xsrf-token',\n]\n\nconst PAYLOAD_CONTENT_DENY_LIST = [\n 'password',\n 'secret',\n 'passwd',\n 'api_key',\n 'apikey',\n 'auth',\n 'credentials',\n 'mysql_pwd',\n 'privatekey',\n 'private_key',\n 'token',\n]\n\n// we always remove headers on the deny list because we never want to capture this sensitive data\nconst removeAuthorizationHeader = (data: CapturedNetworkRequest): CapturedNetworkRequest => {\n const headers = data.requestHeaders\n if (!isNullish(headers)) {\n each(Object.keys(headers ?? {}), (header) => {\n if (HEADER_DENY_LIST.includes(header.toLowerCase())) {\n headers[header] = REDACTED\n }\n })\n }\n return data\n}\n\nconst POSTHOG_PATHS_TO_IGNORE = ['/s/', '/e/', '/i/']\n// want to ignore posthog paths when capturing requests, or we can get trapped in a loop\n// because calls to PostHog would be reported using a call to PostHog which would be reported....\nconst ignorePostHogPaths = (data: CapturedNetworkRequest): CapturedNetworkRequest | undefined => {\n const url = convertToURL(data.name)\n if (url && url.pathname && POSTHOG_PATHS_TO_IGNORE.some((path) => url.pathname.indexOf(path) === 0)) {\n return undefined\n }\n return data\n}\n\nfunction estimateBytes(payload: string): number {\n return new Blob([payload]).size\n}\n\nfunction enforcePayloadSizeLimit(\n payload: string | null | undefined,\n headers: Record<string, any> | undefined,\n limit: number,\n description: string\n): string | null | undefined {\n if (isNullish(payload)) {\n return payload\n }\n\n let requestContentLength: string | number = headers?.['content-length'] || estimateBytes(payload)\n if (isString(requestContentLength)) {\n requestContentLength = parseInt(requestContentLength)\n }\n\n if (requestContentLength > limit) {\n return LOGGER_PREFIX + ` ${description} body too large to record (${requestContentLength} bytes)`\n }\n\n return payload\n}\n\n// people can have arbitrarily large payloads on their site, but we don't want to ingest them\nconst limitPayloadSize = (\n options: NetworkRecordOptions\n): ((data: CapturedNetworkRequest | undefined) => CapturedNetworkRequest | undefined) => {\n // the smallest of 1MB or the specified limit if there is one\n const limit = Math.min(1000000, options.payloadSizeLimitBytes ?? 1000000)\n\n return (data) => {\n if (data?.requestBody) {\n data.requestBody = enforcePayloadSizeLimit(data.requestBody, data.requestHeaders, limit, 'Request')\n }\n\n if (data?.responseBody) {\n data.responseBody = enforcePayloadSizeLimit(data.responseBody, data.responseHeaders, limit, 'Response')\n }\n\n return data\n }\n}\n\nfunction scrubPayload(payload: string | null | undefined, label: 'Request' | 'Response'): string | null | undefined {\n if (isNullish(payload)) {\n return payload\n }\n let scrubbed = payload\n\n if (!shouldCaptureValue(scrubbed, false)) {\n scrubbed = LOGGER_PREFIX + ' ' + label + ' body ' + REDACTED\n }\n each(PAYLOAD_CONTENT_DENY_LIST, (text) => {\n if (scrubbed?.length && scrubbed?.indexOf(text) !== -1) {\n scrubbed = LOGGER_PREFIX + ' ' + label + ' body ' + REDACTED + ' as might contain: ' + text\n }\n })\n\n return scrubbed\n}\n\nfunction scrubPayloads(capturedRequest: CapturedNetworkRequest | undefined): CapturedNetworkRequest | undefined {\n if (isUndefined(capturedRequest)) {\n return undefined\n }\n\n capturedRequest.requestBody = scrubPayload(capturedRequest.requestBody, 'Request')\n capturedRequest.responseBody = scrubPayload(capturedRequest.responseBody, 'Response')\n\n return capturedRequest\n}\n\n/**\n * whether a maskRequestFn is provided or not,\n * we ensure that we remove the denied header from requests\n * we _never_ want to record that header by accident\n * if someone complains then we'll add an opt-in to let them override it\n */\nexport const buildNetworkRequestOptions = (\n instanceConfig: PostHogConfig,\n remoteNetworkOptions: Pick<\n NetworkRecordOptions,\n 'recordHeaders' | 'recordBody' | 'recordPerformance' | 'payloadHostDenyList'\n >\n): NetworkRecordOptions => {\n const config: NetworkRecordOptions = {\n payloadSizeLimitBytes: defaultNetworkOptions.payloadSizeLimitBytes,\n performanceEntryTypeToObserve: [...defaultNetworkOptions.performanceEntryTypeToObserve],\n payloadHostDenyList: [\n ...(remoteNetworkOptions.payloadHostDenyList || []),\n ...defaultNetworkOptions.payloadHostDenyList,\n ],\n }\n // client can always disable despite remote options\n const canRecordHeaders =\n instanceConfig.session_recording.recordHeaders === false ? false : remoteNetworkOptions.recordHeaders\n const canRecordBody =\n instanceConfig.session_recording.recordBody === false ? false : remoteNetworkOptions.recordBody\n const canRecordPerformance =\n instanceConfig.capture_performance === false ? false : remoteNetworkOptions.recordPerformance\n\n const payloadLimiter = limitPayloadSize(config)\n\n const enforcedCleaningFn: NetworkRecordOptions['maskRequestFn'] = (d: CapturedNetworkRequest) =>\n payloadLimiter(ignorePostHogPaths(removeAuthorizationHeader(d)))\n\n const hasDeprecatedMaskFunction = isFunction(instanceConfig.session_recording.maskNetworkRequestFn)\n\n if (hasDeprecatedMaskFunction && isFunction(instanceConfig.session_recording.maskCapturedNetworkRequestFn)) {\n logger.warn(\n 'Both `maskNetworkRequestFn` and `maskCapturedNetworkRequestFn` are defined. `maskNetworkRequestFn` will be ignored.'\n )\n }\n\n if (hasDeprecatedMaskFunction) {\n instanceConfig.session_recording.maskCapturedNetworkRequestFn = (data: CapturedNetworkRequest) => {\n const cleanedURL = instanceConfig.session_recording.maskNetworkRequestFn!({ url: data.name })\n return {\n ...data,\n name: cleanedURL?.url,\n } as CapturedNetworkRequest\n }\n }\n\n config.maskRequestFn = isFunction(instanceConfig.session_recording.maskCapturedNetworkRequestFn)\n ? (data) => {\n const cleanedRequest = enforcedCleaningFn(data)\n return cleanedRequest\n ? instanceConfig.session_recording.maskCapturedNetworkRequestFn?.(cleanedRequest) ?? undefined\n : undefined\n }\n : (data) => scrubPayloads(enforcedCleaningFn(data))\n\n return {\n ...defaultNetworkOptions,\n ...config,\n recordHeaders: canRecordHeaders,\n recordBody: canRecordBody,\n recordPerformance: canRecordPerformance,\n recordInitialRequests: canRecordPerformance,\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"denylist.js","sourceRoot":"","sources":["../../../../../src/extensions/replay/external/denylist.ts"],"names":[],"mappings":";;;;;;;;;;;AAEA,SAAS,eAAe,CAAC,GAA+B;IACpD,IAAI;
|
|
1
|
+
{"version":3,"file":"denylist.js","sourceRoot":"","sources":["../../../../../src/extensions/replay/external/denylist.ts"],"names":[],"mappings":";;;;;;;;;;;AAEA,SAAS,eAAe,CAAC,GAA+B;IACpD,IAAI,CAAC;QACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAA;QAChC,CAAC;QACD,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;YACf,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAA;QACpC,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,CAAA;IACvB,CAAC;IAAC,WAAM,CAAC;QACL,OAAO,IAAI,CAAA;IACf,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAA2B,EAAE,OAA6B;;;IACvF,IAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IACrC,IAAM,gBAAgB,GAAG,EAAE,QAAQ,UAAA,EAAE,YAAY,EAAE,KAAK,EAAE,CAAA;IAE1D,IAAI,CAAC,CAAA,MAAA,OAAO,CAAC,mBAAmB,0CAAE,MAAM,CAAA,IAAI,CAAC,CAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,IAAI,GAAG,MAAM,CAAA,EAAE,CAAC;QACnE,OAAO,gBAAgB,CAAA;IAC3B,CAAC;;QAED,KAAmB,IAAA,KAAA,SAAA,OAAO,CAAC,mBAAmB,CAAA,gBAAA,4BAAE,CAAC;YAA5C,IAAM,IAAI,WAAA;YACX,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,OAAO,EAAE,QAAQ,UAAA,EAAE,YAAY,EAAE,IAAI,EAAE,CAAA;YAC3C,CAAC;QACL,CAAC;;;;;;;;;IAED,OAAO,gBAAgB,CAAA;AAC3B,CAAC","sourcesContent":["import { NetworkRecordOptions } from '../../../types'\n\nfunction hostnameFromURL(url: string | URL | RequestInfo): string | null {\n try {\n if (typeof url === 'string') {\n return new URL(url).hostname\n }\n if ('url' in url) {\n return new URL(url.url).hostname\n }\n return url.hostname\n } catch {\n return null\n }\n}\n\nexport function isHostOnDenyList(url: string | URL | Request, options: NetworkRecordOptions) {\n const hostname = hostnameFromURL(url)\n const defaultNotDenied = { hostname, isHostDenied: false }\n\n if (!options.payloadHostDenyList?.length || !hostname?.trim().length) {\n return defaultNotDenied\n }\n\n for (const deny of options.payloadHostDenyList) {\n if (hostname.endsWith(deny)) {\n return { hostname, isHostDenied: true }\n }\n }\n\n return defaultNotDenied\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation-rate-limiter.js","sourceRoot":"","sources":["../../../../src/extensions/replay/mutation-rate-limiter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AACA,OAAO,EAAE,+BAA+B,EAAE,oBAAoB,EAAe,MAAM,0BAA0B,CAAA;AAE7G;IAMI,6BACqB,KAAkB,EAClB,OAIX;QAJW,wBAAA,EAAA,YAIX;QANV,iBAaC;;QAZoB,UAAK,GAAL,KAAK,CAAa;QAClB,YAAO,GAAP,OAAO,CAIlB;QAXF,eAAU,GAAG,GAAG,CAAA;QAChB,eAAU,GAAG,EAAE,CAAA;QACf,oBAAe,GAA2B,EAAE,CAAA;QAC5C,kBAAa,GAA4B,EAAE,CAAA;QAiB3C,kBAAa,GAAG;YACpB,MAAM,CAAC,IAAI,CAAC,KAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,UAAC,GAAG;gBAC1C,KAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,KAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,KAAI,CAAC,UAAU,CAAA;gBAEvE,IAAI,KAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,KAAI,CAAC,UAAU,EAAE;
|
|
1
|
+
{"version":3,"file":"mutation-rate-limiter.js","sourceRoot":"","sources":["../../../../src/extensions/replay/mutation-rate-limiter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { eventWithTime, mutationCallbackParam } from '@rrweb/types'\nimport { INCREMENTAL_SNAPSHOT_EVENT_TYPE, MUTATION_SOURCE_TYPE, rrwebRecord } from './sessionrecording-utils'\n\nexport class MutationRateLimiter {\n private bucketSize = 100\n private refillRate = 10\n private mutationBuckets: Record<string, number> = {}\n private loggedTracker: Record<string, boolean> = {}\n\n constructor(\n private readonly rrweb: rrwebRecord,\n private readonly options: {\n bucketSize?: number\n refillRate?: number\n onBlockedNode?: (id: number, node: Node | null) => void\n } = {}\n ) {\n this.refillRate = this.options.refillRate ?? this.refillRate\n this.bucketSize = this.options.bucketSize ?? this.bucketSize\n setInterval(() => {\n this.refillBuckets()\n }, 1000)\n }\n\n private refillBuckets = () => {\n Object.keys(this.mutationBuckets).forEach((key) => {\n this.mutationBuckets[key] = this.mutationBuckets[key] + this.refillRate\n\n if (this.mutationBuckets[key] >= this.bucketSize) {\n delete this.mutationBuckets[key]\n }\n })\n }\n\n private getNodeOrRelevantParent = (id: number): [number, Node | null] => {\n // For some nodes we know they are part of a larger tree such as an SVG.\n // For those we want to block the entire node, not just the specific attribute\n\n const node = this.rrweb.mirror.getNode(id)\n\n // Check if the node is an Element and then find the closest parent that is an SVG\n if (node?.nodeName !== 'svg' && node instanceof Element) {\n const closestSVG = node.closest('svg')\n\n if (closestSVG) {\n return [this.rrweb.mirror.getId(closestSVG), closestSVG]\n }\n }\n\n return [id, node]\n }\n\n private numberOfChanges = (data: Partial<mutationCallbackParam>) => {\n return (\n (data.removes?.length ?? 0) +\n (data.attributes?.length ?? 0) +\n (data.texts?.length ?? 0) +\n (data.adds?.length ?? 0)\n )\n }\n\n public throttleMutations = (event: eventWithTime) => {\n if (event.type !== INCREMENTAL_SNAPSHOT_EVENT_TYPE || event.data.source !== MUTATION_SOURCE_TYPE) {\n return event\n }\n\n const data = event.data as Partial<mutationCallbackParam>\n const initialMutationCount = this.numberOfChanges(data)\n\n if (data.attributes) {\n // Most problematic mutations come from attrs where the style or minor properties are changed rapidly\n data.attributes = data.attributes.filter((attr) => {\n const [nodeId, node] = this.getNodeOrRelevantParent(attr.id)\n\n if (this.mutationBuckets[nodeId] === 0) {\n return false\n }\n\n this.mutationBuckets[nodeId] = this.mutationBuckets[nodeId] ?? this.bucketSize\n this.mutationBuckets[nodeId] = Math.max(this.mutationBuckets[nodeId] - 1, 0)\n\n if (this.mutationBuckets[nodeId] === 0) {\n if (!this.loggedTracker[nodeId]) {\n this.loggedTracker[nodeId] = true\n this.options.onBlockedNode?.(nodeId, node)\n }\n }\n\n return attr\n })\n }\n\n // Check if every part of the mutation is empty in which case there is nothing to do\n const mutationCount = this.numberOfChanges(data)\n\n if (mutationCount === 0 && initialMutationCount !== mutationCount) {\n // If we have modified the mutation count and the remaining count is 0, then we don't need the event.\n return\n }\n return event\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch.js","sourceRoot":"","sources":["../../../../../src/extensions/replay/rrweb-plugins/patch.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,+HAA+H;AAC/H,kJAAkJ;AAClJ,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAEtD,MAAM,UAAU,KAAK,CACjB,MAA8B,EAC9B,IAAY,EACZ,WAA4C;IAE5C,IAAI;
|
|
1
|
+
{"version":3,"file":"patch.js","sourceRoot":"","sources":["../../../../../src/extensions/replay/rrweb-plugins/patch.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,+HAA+H;AAC/H,kJAAkJ;AAClJ,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAEtD,MAAM,UAAU,KAAK,CACjB,MAA8B,EAC9B,IAAY,EACZ,WAA4C;IAE5C,IAAI,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO;gBACH,EAAE;YACN,CAAC,CAAA;QACL,CAAC;QAED,IAAM,UAAQ,GAAG,MAAM,CAAC,IAAI,CAAkB,CAAA;QAC9C,IAAM,OAAO,GAAG,WAAW,CAAC,UAAQ,CAAC,CAAA;QAErC,0GAA0G;QAC1G,kFAAkF;QAClF,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACtB,mEAAmE;YACnE,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAA;YAC3C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE;gBAC7B,mBAAmB,EAAE;oBACjB,UAAU,EAAE,KAAK;oBACjB,KAAK,EAAE,IAAI;iBACd;aACJ,CAAC,CAAA;QACN,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAA;QAEtB,OAAO;YACH,MAAM,CAAC,IAAI,CAAC,GAAG,UAAQ,CAAA;QAC3B,CAAC,CAAA;IACL,CAAC;IAAC,WAAM,CAAC;QACL,OAAO;YACH,EAAE;QACN,CAAC,CAAA;QACD,iFAAiF;QACjF,mEAAmE;IACvE,CAAC;AACL,CAAC","sourcesContent":["// import { patch } from 'rrweb/typings/utils'\n// copied from https://github.com/rrweb-io/rrweb/blob/8aea5b00a4dfe5a6f59bd2ae72bb624f45e51e81/packages/rrweb/src/utils.ts#L129\n// which was copied from https://github.com/getsentry/sentry-javascript/blob/b2109071975af8bf0316d3b5b38f519bdaf5dc15/packages/utils/src/object.ts\nimport { isFunction } from '../../../utils/type-utils'\n\nexport function patch(\n source: { [key: string]: any },\n name: string,\n replacement: (...args: unknown[]) => unknown\n): () => void {\n try {\n if (!(name in source)) {\n return () => {\n //\n }\n }\n\n const original = source[name] as () => unknown\n const wrapped = replacement(original)\n\n // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work\n // otherwise it'll throw \"TypeError: Object.defineProperties called on non-object\"\n if (isFunction(wrapped)) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n wrapped.prototype = wrapped.prototype || {}\n Object.defineProperties(wrapped, {\n __posthog_wrapped__: {\n enumerable: false,\n value: true,\n },\n })\n }\n\n source[name] = wrapped\n\n return () => {\n source[name] = original\n }\n } catch {\n return () => {\n //\n }\n // This can throw if multiple fill happens on a global object like XMLHttpRequest\n // Fixes https://github.com/getsentry/sentry-javascript/issues/2043\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionrecording-utils.js","sourceRoot":"","sources":["../../../../src/extensions/replay/sessionrecording-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n blockClass,\n eventWithTime,\n hooksParam,\n KeepIframeSrcFn,\n listenerHandler,\n maskTextClass,\n pluginEvent,\n RecordPlugin,\n SamplingStrategy,\n} from '@rrweb/types'\nimport type { DataURLOptions, MaskInputFn, MaskInputOptions, MaskTextFn, Mirror, SlimDOMOptions } from 'rrweb-snapshot'\n\nimport { isObject } from '../../utils/type-utils'\nimport { SnapshotBuffer } from './sessionrecording'\n\n// taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references\nexport function circularReferenceReplacer() {\n const ancestors: any[] = []\n return function (this: any, _key: string, value: any) {\n if (isObject(value)) {\n // `this` is the object that value is contained in,\n // i.e., its direct parent.\n while (ancestors.length > 0 && ancestors.at(-1) !== this) {\n ancestors.pop()\n }\n if (ancestors.includes(value)) {\n return '[Circular]'\n }\n ancestors.push(value)\n return value\n } else {\n return value\n }\n }\n}\n\nexport function estimateSize(sizeable: unknown): number {\n return JSON.stringify(sizeable, circularReferenceReplacer()).length\n}\n\nexport const replacementImageURI =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNOCAwSDE2TDAgMTZWOEw4IDBaIiBmaWxsPSIjMkQyRDJEIi8+CjxwYXRoIGQ9Ik0xNiA4VjE2SDhMMTYgOFoiIGZpbGw9IiMyRDJEMkQiLz4KPC9zdmc+Cg=='\n\nexport const FULL_SNAPSHOT_EVENT_TYPE = 2\nexport const META_EVENT_TYPE = 4\nexport const INCREMENTAL_SNAPSHOT_EVENT_TYPE = 3\nexport const PLUGIN_EVENT_TYPE = 6\nexport const MUTATION_SOURCE_TYPE = 0\n\nexport const MAX_MESSAGE_SIZE = 5000000 // ~5mb\n\nexport type rrwebRecord = {\n (options: recordOptions<eventWithTime>): listenerHandler\n addCustomEvent: (tag: string, payload: any) => void\n takeFullSnapshot: () => void\n mirror: Mirror\n}\n\nexport declare type recordOptions<T> = {\n emit?: (e: T, isCheckout?: boolean) => void\n checkoutEveryNth?: number\n checkoutEveryNms?: number\n blockClass?: blockClass\n blockSelector?: string\n ignoreClass?: string\n maskTextClass?: maskTextClass\n maskTextSelector?: string\n maskAllInputs?: boolean\n maskInputOptions?: MaskInputOptions\n maskInputFn?: MaskInputFn\n maskTextFn?: MaskTextFn\n slimDOMOptions?: SlimDOMOptions | 'all' | true\n ignoreCSSAttributes?: Set<string>\n inlineStylesheet?: boolean\n hooks?: hooksParam\n // packFn?: PackFn\n sampling?: SamplingStrategy\n dataURLOptions?: DataURLOptions\n recordCanvas?: boolean\n recordCrossOriginIframes?: boolean\n recordAfter?: 'DOMContentLoaded' | 'load'\n userTriggeredOnInput?: boolean\n collectFonts?: boolean\n inlineImages?: boolean\n plugins?: RecordPlugin[]\n mousemoveWait?: number\n keepIframeSrcFn?: KeepIframeSrcFn\n // errorHandler?: ErrorHandler\n}\n\n/*\n * Check whether a data payload is nearing 5mb. If it is, it checks the data for\n * data URIs (the likely culprit for large payloads). If it finds data URIs, it either replaces\n * it with a generic image (if it's an image) or removes it.\n * @data {object} the rr-web data object\n * @returns {object} the rr-web data object with data uris filtered out\n */\nexport function ensureMaxMessageSize(data: eventWithTime): { event: eventWithTime; size: number } {\n let stringifiedData = JSON.stringify(data)\n // Note: with compression, this limit may be able to be increased\n // but we're assuming most of the size is from a data uri which\n // is unlikely to be compressed further\n\n if (stringifiedData.length > MAX_MESSAGE_SIZE) {\n // Regex that matches the pattern for a dataURI with the shape 'data:{mime type};{encoding},{data}'. It:\n // 1) Checks if the pattern starts with 'data:' (potentially, not at the start of the string)\n // 2) Extracts the mime type of the data uri in the first group\n // 3) Determines when the data URI ends.Depending on if it's used in the src tag or css, it can end with a ) or \"\n const dataURIRegex = /data:([\\w/\\-.]+);(\\w+),([^)\"]*)/gim\n const matches = stringifiedData.matchAll(dataURIRegex)\n for (const match of matches) {\n if (match[1].toLocaleLowerCase().slice(0, 6) === 'image/') {\n stringifiedData = stringifiedData.replace(match[0], replacementImageURI)\n } else {\n stringifiedData = stringifiedData.replace(match[0], '')\n }\n }\n }\n return { event: JSON.parse(stringifiedData), size: stringifiedData.length }\n}\n\nexport const CONSOLE_LOG_PLUGIN_NAME = 'rrweb/console@1' // The name of the rr-web plugin that emits console logs\n\n// Console logs can be really large. This function truncates large logs\n// It's a simple function that just truncates long strings.\n// TODO: Ideally this function would have better handling of objects + lists,\n// so they could still be rendered in a pretty way after truncation.\nexport function truncateLargeConsoleLogs(_event: eventWithTime) {\n const event = _event as pluginEvent<{ payload: string[] }>\n\n const MAX_STRING_SIZE = 2000 // Maximum number of characters allowed in a string\n const MAX_STRINGS_PER_LOG = 10 // A log can consist of multiple strings (e.g. consol.log('string1', 'string2'))\n\n if (\n event &&\n isObject(event) &&\n event.type === PLUGIN_EVENT_TYPE &&\n isObject(event.data) &&\n event.data.plugin === CONSOLE_LOG_PLUGIN_NAME\n ) {\n // Note: event.data.payload.payload comes from rr-web, and is an array of strings\n if (event.data.payload.payload.length > MAX_STRINGS_PER_LOG) {\n event.data.payload.payload = event.data.payload.payload.slice(0, MAX_STRINGS_PER_LOG)\n event.data.payload.payload.push('...[truncated]')\n }\n const updatedPayload = []\n for (let i = 0; i < event.data.payload.payload.length; i++) {\n if (\n event.data.payload.payload[i] && // Value can be null\n event.data.payload.payload[i].length > MAX_STRING_SIZE\n ) {\n updatedPayload.push(event.data.payload.payload[i].slice(0, MAX_STRING_SIZE) + '...[truncated]')\n } else {\n updatedPayload.push(event.data.payload.payload[i])\n }\n }\n event.data.payload.payload = updatedPayload\n // Return original type\n return _event\n }\n return _event\n}\n\nexport const SEVEN_MEGABYTES = 1024 * 1024 * 7 * 0.9 // ~7mb (with some wiggle room)\n\n// recursively splits large buffers into smaller ones\n// uses a pretty high size limit to avoid splitting too much\nexport function splitBuffer(buffer: SnapshotBuffer, sizeLimit: number = SEVEN_MEGABYTES): SnapshotBuffer[] {\n if (buffer.size >= sizeLimit && buffer.data.length > 1) {\n const half = Math.floor(buffer.data.length / 2)\n const firstHalf = buffer.data.slice(0, half)\n const secondHalf = buffer.data.slice(half)\n return [\n splitBuffer({\n size: estimateSize(firstHalf),\n data: firstHalf,\n sessionId: buffer.sessionId,\n windowId: buffer.windowId,\n }),\n splitBuffer({\n size: estimateSize(secondHalf),\n data: secondHalf,\n sessionId: buffer.sessionId,\n windowId: buffer.windowId,\n }),\n ].flatMap((x) => x)\n } else {\n return [buffer]\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sessionrecording-utils.js","sourceRoot":"","sources":["../../../../src/extensions/replay/sessionrecording-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n blockClass,\n eventWithTime,\n hooksParam,\n KeepIframeSrcFn,\n listenerHandler,\n maskTextClass,\n pluginEvent,\n RecordPlugin,\n SamplingStrategy,\n} from '@rrweb/types'\nimport type { DataURLOptions, MaskInputFn, MaskInputOptions, MaskTextFn, Mirror, SlimDOMOptions } from 'rrweb-snapshot'\n\nimport { isObject } from '../../utils/type-utils'\nimport { SnapshotBuffer } from './sessionrecording'\n\n// taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#circular_references\nexport function circularReferenceReplacer() {\n const ancestors: any[] = []\n return function (this: any, _key: string, value: any) {\n if (isObject(value)) {\n // `this` is the object that value is contained in,\n // i.e., its direct parent.\n while (ancestors.length > 0 && ancestors.at(-1) !== this) {\n ancestors.pop()\n }\n if (ancestors.includes(value)) {\n return '[Circular]'\n }\n ancestors.push(value)\n return value\n } else {\n return value\n }\n }\n}\n\nexport function estimateSize(sizeable: unknown): number {\n return JSON.stringify(sizeable, circularReferenceReplacer()).length\n}\n\nexport const replacementImageURI =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2IiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNOCAwSDE2TDAgMTZWOEw4IDBaIiBmaWxsPSIjMkQyRDJEIi8+CjxwYXRoIGQ9Ik0xNiA4VjE2SDhMMTYgOFoiIGZpbGw9IiMyRDJEMkQiLz4KPC9zdmc+Cg=='\n\nexport const FULL_SNAPSHOT_EVENT_TYPE = 2\nexport const META_EVENT_TYPE = 4\nexport const INCREMENTAL_SNAPSHOT_EVENT_TYPE = 3\nexport const PLUGIN_EVENT_TYPE = 6\nexport const MUTATION_SOURCE_TYPE = 0\n\nexport const MAX_MESSAGE_SIZE = 5000000 // ~5mb\n\nexport type rrwebRecord = {\n (options: recordOptions<eventWithTime>): listenerHandler\n addCustomEvent: (tag: string, payload: any) => void\n takeFullSnapshot: () => void\n mirror: Mirror\n}\n\nexport declare type recordOptions<T> = {\n emit?: (e: T, isCheckout?: boolean) => void\n checkoutEveryNth?: number\n checkoutEveryNms?: number\n blockClass?: blockClass\n blockSelector?: string\n ignoreClass?: string\n maskTextClass?: maskTextClass\n maskTextSelector?: string\n maskAllInputs?: boolean\n maskInputOptions?: MaskInputOptions\n maskInputFn?: MaskInputFn\n maskTextFn?: MaskTextFn\n slimDOMOptions?: SlimDOMOptions | 'all' | true\n ignoreCSSAttributes?: Set<string>\n inlineStylesheet?: boolean\n hooks?: hooksParam\n // packFn?: PackFn\n sampling?: SamplingStrategy\n dataURLOptions?: DataURLOptions\n recordCanvas?: boolean\n recordCrossOriginIframes?: boolean\n recordAfter?: 'DOMContentLoaded' | 'load'\n userTriggeredOnInput?: boolean\n collectFonts?: boolean\n inlineImages?: boolean\n plugins?: RecordPlugin[]\n mousemoveWait?: number\n keepIframeSrcFn?: KeepIframeSrcFn\n // errorHandler?: ErrorHandler\n}\n\n/*\n * Check whether a data payload is nearing 5mb. If it is, it checks the data for\n * data URIs (the likely culprit for large payloads). If it finds data URIs, it either replaces\n * it with a generic image (if it's an image) or removes it.\n * @data {object} the rr-web data object\n * @returns {object} the rr-web data object with data uris filtered out\n */\nexport function ensureMaxMessageSize(data: eventWithTime): { event: eventWithTime; size: number } {\n let stringifiedData = JSON.stringify(data)\n // Note: with compression, this limit may be able to be increased\n // but we're assuming most of the size is from a data uri which\n // is unlikely to be compressed further\n\n if (stringifiedData.length > MAX_MESSAGE_SIZE) {\n // Regex that matches the pattern for a dataURI with the shape 'data:{mime type};{encoding},{data}'. It:\n // 1) Checks if the pattern starts with 'data:' (potentially, not at the start of the string)\n // 2) Extracts the mime type of the data uri in the first group\n // 3) Determines when the data URI ends.Depending on if it's used in the src tag or css, it can end with a ) or \"\n const dataURIRegex = /data:([\\w/\\-.]+);(\\w+),([^)\"]*)/gim\n const matches = stringifiedData.matchAll(dataURIRegex)\n for (const match of matches) {\n if (match[1].toLocaleLowerCase().slice(0, 6) === 'image/') {\n stringifiedData = stringifiedData.replace(match[0], replacementImageURI)\n } else {\n stringifiedData = stringifiedData.replace(match[0], '')\n }\n }\n }\n return { event: JSON.parse(stringifiedData), size: stringifiedData.length }\n}\n\nexport const CONSOLE_LOG_PLUGIN_NAME = 'rrweb/console@1' // The name of the rr-web plugin that emits console logs\n\n// Console logs can be really large. This function truncates large logs\n// It's a simple function that just truncates long strings.\n// TODO: Ideally this function would have better handling of objects + lists,\n// so they could still be rendered in a pretty way after truncation.\nexport function truncateLargeConsoleLogs(_event: eventWithTime) {\n const event = _event as pluginEvent<{ payload: string[] }>\n\n const MAX_STRING_SIZE = 2000 // Maximum number of characters allowed in a string\n const MAX_STRINGS_PER_LOG = 10 // A log can consist of multiple strings (e.g. consol.log('string1', 'string2'))\n\n if (\n event &&\n isObject(event) &&\n event.type === PLUGIN_EVENT_TYPE &&\n isObject(event.data) &&\n event.data.plugin === CONSOLE_LOG_PLUGIN_NAME\n ) {\n // Note: event.data.payload.payload comes from rr-web, and is an array of strings\n if (event.data.payload.payload.length > MAX_STRINGS_PER_LOG) {\n event.data.payload.payload = event.data.payload.payload.slice(0, MAX_STRINGS_PER_LOG)\n event.data.payload.payload.push('...[truncated]')\n }\n const updatedPayload = []\n for (let i = 0; i < event.data.payload.payload.length; i++) {\n if (\n event.data.payload.payload[i] && // Value can be null\n event.data.payload.payload[i].length > MAX_STRING_SIZE\n ) {\n updatedPayload.push(event.data.payload.payload[i].slice(0, MAX_STRING_SIZE) + '...[truncated]')\n } else {\n updatedPayload.push(event.data.payload.payload[i])\n }\n }\n event.data.payload.payload = updatedPayload\n // Return original type\n return _event\n }\n return _event\n}\n\nexport const SEVEN_MEGABYTES = 1024 * 1024 * 7 * 0.9 // ~7mb (with some wiggle room)\n\n// recursively splits large buffers into smaller ones\n// uses a pretty high size limit to avoid splitting too much\nexport function splitBuffer(buffer: SnapshotBuffer, sizeLimit: number = SEVEN_MEGABYTES): SnapshotBuffer[] {\n if (buffer.size >= sizeLimit && buffer.data.length > 1) {\n const half = Math.floor(buffer.data.length / 2)\n const firstHalf = buffer.data.slice(0, half)\n const secondHalf = buffer.data.slice(half)\n return [\n splitBuffer({\n size: estimateSize(firstHalf),\n data: firstHalf,\n sessionId: buffer.sessionId,\n windowId: buffer.windowId,\n }),\n splitBuffer({\n size: estimateSize(secondHalf),\n data: secondHalf,\n sessionId: buffer.sessionId,\n windowId: buffer.windowId,\n }),\n ].flatMap((x) => x)\n } else {\n return [buffer]\n }\n}\n"]}
|
|
@@ -48,6 +48,10 @@ export declare class SessionRecording {
|
|
|
48
48
|
*/
|
|
49
49
|
private get status();
|
|
50
50
|
constructor(instance: PostHog);
|
|
51
|
+
private _onBeforeUnload;
|
|
52
|
+
private _onOffline;
|
|
53
|
+
private _onOnline;
|
|
54
|
+
private _onVisibilityChange;
|
|
51
55
|
startIfEnabledOrStop(): void;
|
|
52
56
|
stopRecording(): void;
|
|
53
57
|
private makeSamplingDecision;
|
|
@@ -94,26 +94,26 @@ var SessionRecording = /** @class */ (function () {
|
|
|
94
94
|
this._linkedFlag = null;
|
|
95
95
|
// Util to help developers working on this feature manually override
|
|
96
96
|
this._forceAllowLocalhostNetworkCapture = false;
|
|
97
|
-
this.
|
|
98
|
-
this._captureStarted = false;
|
|
99
|
-
this._endpoint = BASE_ENDPOINT;
|
|
100
|
-
this.stopRrweb = undefined;
|
|
101
|
-
this.receivedDecide = false;
|
|
102
|
-
window === null || window === void 0 ? void 0 : window.addEventListener('beforeunload', function () {
|
|
97
|
+
this._onBeforeUnload = function () {
|
|
103
98
|
_this._flushBuffer();
|
|
104
|
-
}
|
|
105
|
-
|
|
99
|
+
};
|
|
100
|
+
this._onOffline = function () {
|
|
106
101
|
_this._tryAddCustomEvent('browser offline', {});
|
|
107
|
-
}
|
|
108
|
-
|
|
102
|
+
};
|
|
103
|
+
this._onOnline = function () {
|
|
109
104
|
_this._tryAddCustomEvent('browser online', {});
|
|
110
|
-
}
|
|
111
|
-
|
|
105
|
+
};
|
|
106
|
+
this._onVisibilityChange = function () {
|
|
112
107
|
if (document === null || document === void 0 ? void 0 : document.visibilityState) {
|
|
113
108
|
var label = 'window ' + document.visibilityState;
|
|
114
109
|
_this._tryAddCustomEvent(label, {});
|
|
115
110
|
}
|
|
116
|
-
}
|
|
111
|
+
};
|
|
112
|
+
this._samplingSessionListener = null;
|
|
113
|
+
this._captureStarted = false;
|
|
114
|
+
this._endpoint = BASE_ENDPOINT;
|
|
115
|
+
this.stopRrweb = undefined;
|
|
116
|
+
this.receivedDecide = false;
|
|
117
117
|
if (!this.instance.sessionManager) {
|
|
118
118
|
logger.error(LOGGER_PREFIX + ' started without valid sessionManager');
|
|
119
119
|
throw new Error(LOGGER_PREFIX + ' started without valid sessionManager. This is a bug.');
|
|
@@ -280,6 +280,10 @@ var SessionRecording = /** @class */ (function () {
|
|
|
280
280
|
SessionRecording.prototype.startIfEnabledOrStop = function () {
|
|
281
281
|
if (this.isRecordingEnabled) {
|
|
282
282
|
this._startCapture();
|
|
283
|
+
window === null || window === void 0 ? void 0 : window.addEventListener('beforeunload', this._onBeforeUnload);
|
|
284
|
+
window === null || window === void 0 ? void 0 : window.addEventListener('offline', this._onOffline);
|
|
285
|
+
window === null || window === void 0 ? void 0 : window.addEventListener('online', this._onOnline);
|
|
286
|
+
window === null || window === void 0 ? void 0 : window.addEventListener('visibilitychange', this._onVisibilityChange);
|
|
283
287
|
logger.info(LOGGER_PREFIX + ' started');
|
|
284
288
|
}
|
|
285
289
|
else {
|
|
@@ -292,6 +296,10 @@ var SessionRecording = /** @class */ (function () {
|
|
|
292
296
|
this.stopRrweb();
|
|
293
297
|
this.stopRrweb = undefined;
|
|
294
298
|
this._captureStarted = false;
|
|
299
|
+
window === null || window === void 0 ? void 0 : window.removeEventListener('beforeunload', this._onBeforeUnload);
|
|
300
|
+
window === null || window === void 0 ? void 0 : window.removeEventListener('offline', this._onOffline);
|
|
301
|
+
window === null || window === void 0 ? void 0 : window.removeEventListener('online', this._onOnline);
|
|
302
|
+
window === null || window === void 0 ? void 0 : window.removeEventListener('visibilitychange', this._onVisibilityChange);
|
|
295
303
|
logger.info(LOGGER_PREFIX + ' stopped');
|
|
296
304
|
}
|
|
297
305
|
};
|
|
@@ -824,6 +832,7 @@ var SessionRecording = /** @class */ (function () {
|
|
|
824
832
|
_url: this.instance.requestRouter.endpointFor('api', this._endpoint),
|
|
825
833
|
_noTruncate: true,
|
|
826
834
|
_batchKey: SESSION_RECORDING_BATCH_KEY,
|
|
835
|
+
skip_client_rate_limiting: true,
|
|
827
836
|
});
|
|
828
837
|
};
|
|
829
838
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionrecording.js","sourceRoot":"","sources":["../../../../src/extensions/replay/sessionrecording.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE,\n SESSION_RECORDING_CANVAS_RECORDING,\n SESSION_RECORDING_ENABLED_SERVER_SIDE,\n SESSION_RECORDING_IS_SAMPLED,\n SESSION_RECORDING_MINIMUM_DURATION,\n SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE,\n SESSION_RECORDING_SAMPLE_RATE,\n} from '../../constants'\nimport {\n estimateSize,\n FULL_SNAPSHOT_EVENT_TYPE,\n INCREMENTAL_SNAPSHOT_EVENT_TYPE,\n META_EVENT_TYPE,\n recordOptions,\n rrwebRecord,\n splitBuffer,\n truncateLargeConsoleLogs,\n} from './sessionrecording-utils'\nimport { PostHog } from '../../posthog-core'\nimport { DecideResponse, FlagVariant, NetworkRecordOptions, NetworkRequest, Properties } from '../../types'\nimport { EventType, type eventWithTime, IncrementalSource, type listenerHandler, RecordPlugin } from '@rrweb/types'\nimport Config from '../../config'\nimport { timestamp } from '../../utils'\n\nimport {\n isBoolean,\n isFunction,\n isNull,\n isNullish,\n isNumber,\n isObject,\n isString,\n isUndefined,\n} from '../../utils/type-utils'\nimport { logger } from '../../utils/logger'\nimport { assignableWindow, document, window } from '../../utils/globals'\nimport { buildNetworkRequestOptions } from './config'\nimport { isLocalhost } from '../../utils/request-utils'\nimport { MutationRateLimiter } from './mutation-rate-limiter'\n\nconst BASE_ENDPOINT = '/s/'\n\nconst FIVE_MINUTES = 1000 * 60 * 5\nconst TWO_SECONDS = 2000\nexport const RECORDING_IDLE_ACTIVITY_TIMEOUT_MS = FIVE_MINUTES\nexport const RECORDING_MAX_EVENT_SIZE = 1024 * 1024 * 0.9 // ~1mb (with some wiggle room)\nexport const RECORDING_BUFFER_TIMEOUT = 2000 // 2 seconds\nexport const SESSION_RECORDING_BATCH_KEY = 'recordings'\n\n// NOTE: Importing this type is problematic as we can't safely bundle it to a TS definition so, instead we redefine.\n// import type { record } from 'rrweb2/typings'\n// import type { recordOptions } from 'rrweb/typings/types'\n\nconst ACTIVE_SOURCES = [\n IncrementalSource.MouseMove,\n IncrementalSource.MouseInteraction,\n IncrementalSource.Scroll,\n IncrementalSource.ViewportResize,\n IncrementalSource.Input,\n IncrementalSource.TouchMove,\n IncrementalSource.MediaInteraction,\n IncrementalSource.Drag,\n]\n\n/**\n * Session recording starts in buffering mode while waiting for decide response\n * Once the response is received it might be disabled, active or sampled\n * When sampled that means a sample rate is set and the last time the session id was rotated\n * the sample rate determined this session should be sent to the server.\n */\ntype SessionRecordingStatus = 'disabled' | 'sampled' | 'active' | 'buffering'\n\nexport interface SnapshotBuffer {\n size: number\n data: any[]\n sessionId: string\n windowId: string\n}\n\ninterface QueuedRRWebEvent {\n rrwebMethod: () => void\n attempt: number\n // the timestamp this was first put into this queue\n enqueuedAt: number\n}\n\nconst newQueuedEvent = (rrwebMethod: () => void): QueuedRRWebEvent => ({\n rrwebMethod,\n enqueuedAt: Date.now(),\n attempt: 1,\n})\n\nconst LOGGER_PREFIX = '[SessionRecording]'\n\nexport class SessionRecording {\n private _endpoint: string\n private flushBufferTimer?: any\n\n // we have a buffer - that contains PostHog snapshot events ready to be sent to the server\n private buffer: SnapshotBuffer\n // and a queue - that contains rrweb events that we want to send to rrweb, but rrweb wasn't able to accept them yet\n private queuedRRWebEvents: QueuedRRWebEvent[] = []\n\n private mutationRateLimiter?: MutationRateLimiter\n private _captureStarted: boolean\n private stopRrweb: listenerHandler | undefined\n private receivedDecide: boolean\n private isIdle = false\n\n private _linkedFlagSeen: boolean = false\n private _lastActivityTimestamp: number = Date.now()\n private windowId: string\n private sessionId: string\n private _linkedFlag: string | FlagVariant | null = null\n\n private _fullSnapshotTimer?: ReturnType<typeof setInterval>\n\n // if pageview capture is disabled\n // then we can manually track href changes\n private _lastHref?: string\n\n // Util to help developers working on this feature manually override\n _forceAllowLocalhostNetworkCapture = false\n\n private get rrwebRecord(): rrwebRecord | undefined {\n return assignableWindow?.rrweb?.record\n }\n\n public get started(): boolean {\n // TODO could we use status instead of _captureStarted?\n return this._captureStarted\n }\n\n private get sessionManager() {\n if (!this.instance.sessionManager) {\n throw new Error(LOGGER_PREFIX + ' must be started with a valid sessionManager.')\n }\n\n return this.instance.sessionManager\n }\n\n private get fullSnapshotIntervalMillis(): number {\n return this.instance.config.session_recording?.full_snapshot_interval_millis || FIVE_MINUTES\n }\n\n private get isSampled(): boolean | null {\n const currentValue = this.instance.get_property(SESSION_RECORDING_IS_SAMPLED)\n return isBoolean(currentValue) ? currentValue : null\n }\n\n private get sessionDuration(): number | null {\n const mostRecentSnapshot = this.buffer?.data[this.buffer?.data.length - 1]\n const { sessionStartTimestamp } = this.sessionManager.checkAndGetSessionAndWindowId(true)\n return mostRecentSnapshot ? mostRecentSnapshot.timestamp - sessionStartTimestamp : null\n }\n\n private get isRecordingEnabled() {\n const enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE)\n const enabled_client_side = !this.instance.config.disable_session_recording\n return window && enabled_server_side && enabled_client_side\n }\n\n private get isConsoleLogCaptureEnabled() {\n const enabled_server_side = !!this.instance.get_property(CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE)\n const enabled_client_side = this.instance.config.enable_recording_console_log\n return enabled_client_side ?? enabled_server_side\n }\n\n private get canvasRecording(): { enabled: boolean; fps: number; quality: number } | undefined {\n const canvasRecording_server_side = this.instance.get_property(SESSION_RECORDING_CANVAS_RECORDING)\n return canvasRecording_server_side && canvasRecording_server_side.fps && canvasRecording_server_side.quality\n ? {\n enabled: canvasRecording_server_side.enabled,\n fps: canvasRecording_server_side.fps,\n quality: canvasRecording_server_side.quality,\n }\n : undefined\n }\n\n // network payload capture config has three parts\n // each can be configured server side or client side\n private get networkPayloadCapture():\n | Pick<NetworkRecordOptions, 'recordHeaders' | 'recordBody' | 'recordPerformance'>\n | undefined {\n const networkPayloadCapture_server_side = this.instance.get_property(SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE)\n const networkPayloadCapture_client_side = {\n recordHeaders: this.instance.config.session_recording?.recordHeaders,\n recordBody: this.instance.config.session_recording?.recordBody,\n }\n const headersEnabled =\n networkPayloadCapture_client_side?.recordHeaders || networkPayloadCapture_server_side?.recordHeaders\n const bodyEnabled =\n networkPayloadCapture_client_side?.recordBody || networkPayloadCapture_server_side?.recordBody\n const clientConfigForPerformanceCapture = isObject(this.instance.config.capture_performance)\n ? this.instance.config.capture_performance.network_timing\n : this.instance.config.capture_performance\n const networkTimingEnabled = !!(isBoolean(clientConfigForPerformanceCapture)\n ? clientConfigForPerformanceCapture\n : networkPayloadCapture_server_side?.capturePerformance)\n\n return headersEnabled || bodyEnabled || networkTimingEnabled\n ? { recordHeaders: headersEnabled, recordBody: bodyEnabled, recordPerformance: networkTimingEnabled }\n : undefined\n }\n\n private get sampleRate(): number | null {\n const rate = this.instance.get_property(SESSION_RECORDING_SAMPLE_RATE)\n return isNumber(rate) ? rate : null\n }\n\n private get minimumDuration(): number | null {\n const duration = this.instance.get_property(SESSION_RECORDING_MINIMUM_DURATION)\n return isNumber(duration) ? duration : null\n }\n\n /**\n * defaults to buffering mode until a decide response is received\n * once a decide response is received status can be disabled, active or sampled\n */\n private get status(): SessionRecordingStatus {\n if (!this.receivedDecide) {\n return 'buffering'\n }\n\n if (!this.isRecordingEnabled) {\n return 'disabled'\n }\n\n if (!isNullish(this._linkedFlag) && !this._linkedFlagSeen) {\n return 'buffering'\n }\n\n if (isBoolean(this.isSampled)) {\n return this.isSampled ? 'sampled' : 'disabled'\n } else {\n return 'active'\n }\n }\n\n constructor(private readonly instance: PostHog) {\n this._captureStarted = false\n this._endpoint = BASE_ENDPOINT\n this.stopRrweb = undefined\n this.receivedDecide = false\n\n window?.addEventListener('beforeunload', () => {\n this._flushBuffer()\n })\n\n window?.addEventListener('offline', () => {\n this._tryAddCustomEvent('browser offline', {})\n })\n\n window?.addEventListener('online', () => {\n this._tryAddCustomEvent('browser online', {})\n })\n\n window?.addEventListener('visibilitychange', () => {\n if (document?.visibilityState) {\n const label = 'window ' + document.visibilityState\n this._tryAddCustomEvent(label, {})\n }\n })\n\n if (!this.instance.sessionManager) {\n logger.error(LOGGER_PREFIX + ' started without valid sessionManager')\n throw new Error(LOGGER_PREFIX + ' started without valid sessionManager. This is a bug.')\n }\n\n // we know there's a sessionManager, so don't need to start without a session id\n const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId()\n this.sessionId = sessionId\n this.windowId = windowId\n\n this.buffer = this.clearBuffer()\n\n // on reload there might be an already sampled session that should be continued before decide response,\n // so we call this here _and_ in the decide response\n this._setupSampling()\n }\n\n startIfEnabledOrStop() {\n if (this.isRecordingEnabled) {\n this._startCapture()\n logger.info(LOGGER_PREFIX + ' started')\n } else {\n this.stopRecording()\n this.clearBuffer()\n }\n }\n\n stopRecording() {\n if (this._captureStarted && this.stopRrweb) {\n this.stopRrweb()\n this.stopRrweb = undefined\n this._captureStarted = false\n logger.info(LOGGER_PREFIX + ' stopped')\n }\n }\n\n private makeSamplingDecision(sessionId: string): void {\n const sessionIdChanged = this.sessionId !== sessionId\n\n // capture the current sample rate,\n // because it is re-used multiple times\n // and the bundler won't minimise any of the references\n const currentSampleRate = this.sampleRate\n\n if (!isNumber(currentSampleRate)) {\n this.instance.persistence?.register({\n [SESSION_RECORDING_IS_SAMPLED]: null,\n })\n return\n }\n\n const storedIsSampled = this.isSampled\n\n /**\n * if we get this far then we should make a sampling decision.\n * When the session id changes or there is no stored sampling decision for this session id\n * then we should make a new decision.\n *\n * Otherwise, we should use the stored decision.\n */\n let shouldSample: boolean\n const makeDecision = sessionIdChanged || !isBoolean(storedIsSampled)\n if (makeDecision) {\n const randomNumber = Math.random()\n shouldSample = randomNumber < currentSampleRate\n } else {\n shouldSample = storedIsSampled\n }\n\n if (!shouldSample && makeDecision) {\n logger.warn(\n LOGGER_PREFIX +\n ` Sample rate (${currentSampleRate}) has determined that this sessionId (${sessionId}) will not be sent to the server.`\n )\n }\n this._tryAddCustomEvent('samplingDecisionMade', {\n sampleRate: currentSampleRate,\n })\n\n this.instance.persistence?.register({\n [SESSION_RECORDING_IS_SAMPLED]: shouldSample,\n })\n }\n\n afterDecideResponse(response: DecideResponse) {\n this._persistDecideResponse(response)\n\n this._linkedFlag = response.sessionRecording?.linkedFlag || null\n\n if (response.sessionRecording?.endpoint) {\n this._endpoint = response.sessionRecording?.endpoint\n }\n\n this._setupSampling()\n\n if (!isNullish(this._linkedFlag) && !this._linkedFlagSeen) {\n const linkedFlag = isString(this._linkedFlag) ? this._linkedFlag : this._linkedFlag.flag\n const linkedVariant = isString(this._linkedFlag) ? null : this._linkedFlag.variant\n this.instance.onFeatureFlags((_flags, variants) => {\n const flagIsPresent = isObject(variants) && linkedFlag in variants\n const linkedFlagMatches = linkedVariant ? variants[linkedFlag] === linkedVariant : flagIsPresent\n if (linkedFlagMatches) {\n const payload = {\n linkedFlag,\n linkedVariant,\n }\n const tag = 'linked flag matched'\n logger.info(LOGGER_PREFIX + ' ' + tag, payload)\n this._tryAddCustomEvent(tag, payload)\n }\n this._linkedFlagSeen = linkedFlagMatches\n })\n }\n\n this.receivedDecide = true\n this.startIfEnabledOrStop()\n }\n\n private _samplingSessionListener: (() => void) | null = null\n\n /**\n * This might be called more than once so needs to be idempotent\n */\n private _setupSampling() {\n if (isNumber(this.sampleRate) && isNull(this._samplingSessionListener)) {\n this._samplingSessionListener = this.sessionManager.onSessionId((sessionId) => {\n this.makeSamplingDecision(sessionId)\n })\n }\n }\n\n private _persistDecideResponse(response: DecideResponse): void {\n if (this.instance.persistence) {\n const persistence = this.instance.persistence\n\n const persistResponse = () => {\n const receivedSampleRate = response.sessionRecording?.sampleRate\n\n const parsedSampleRate = isNullish(receivedSampleRate) ? null : parseFloat(receivedSampleRate)\n const receivedMinimumDuration = response.sessionRecording?.minimumDurationMilliseconds\n\n persistence.register({\n [SESSION_RECORDING_ENABLED_SERVER_SIDE]: !!response['sessionRecording'],\n [CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE]: response.sessionRecording?.consoleLogRecordingEnabled,\n [SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE]: {\n capturePerformance: response.capturePerformance,\n ...response.sessionRecording?.networkPayloadCapture,\n },\n [SESSION_RECORDING_CANVAS_RECORDING]: {\n enabled: response.sessionRecording?.recordCanvas,\n fps: response.sessionRecording?.canvasFps,\n quality: response.sessionRecording?.canvasQuality,\n },\n [SESSION_RECORDING_SAMPLE_RATE]: parsedSampleRate,\n [SESSION_RECORDING_MINIMUM_DURATION]: isUndefined(receivedMinimumDuration)\n ? null\n : receivedMinimumDuration,\n })\n }\n\n persistResponse()\n this.sessionManager.onSessionId(persistResponse)\n }\n }\n\n log(message: string, level: 'log' | 'warn' | 'error' = 'log') {\n this.instance.sessionRecording?.onRRwebEmit({\n type: 6,\n data: {\n plugin: 'rrweb/console@1',\n payload: {\n level,\n trace: [],\n // Even though it is a string we stringify it as that's what rrweb expects\n payload: [JSON.stringify(message)],\n },\n },\n timestamp: timestamp(),\n })\n }\n\n private _startCapture() {\n if (isUndefined(Object.assign)) {\n // According to the rrweb docs, rrweb is not supported on IE11 and below:\n // \"rrweb does not support IE11 and below because it uses the MutationObserver API which was supported by these browsers.\"\n // https://github.com/rrweb-io/rrweb/blob/master/guide.md#compatibility-note\n //\n // However, MutationObserver does exist on IE11, it just doesn't work well and does not detect all changes.\n // Instead, when we load \"recorder.js\", the first JS error is about \"Object.assign\" being undefined.\n // Thus instead of MutationObserver, we look for this function and block recording if it's undefined.\n return\n }\n\n // We do not switch recorder versions midway through a recording.\n // do not start if explicitly disabled or if the user has opted out\n if (\n this._captureStarted ||\n this.instance.config.disable_session_recording ||\n this.instance.consent.isOptedOut()\n ) {\n return\n }\n\n this._captureStarted = true\n // We want to ensure the sessionManager is reset if necessary on load of the recorder\n this.sessionManager.checkAndGetSessionAndWindowId()\n\n // If recorder.js is already loaded (if array.full.js snippet is used or posthog-js/dist/recorder is\n // imported), don't load script. Otherwise, remotely import recorder.js from cdn since it hasn't been loaded.\n if (!this.rrwebRecord) {\n this.instance.requestRouter.loadScript(`/static/recorder.js?v=${Config.LIB_VERSION}`, (err) => {\n if (err) {\n return logger.error(LOGGER_PREFIX + ` could not load recorder.js`, err)\n }\n\n this._onScriptLoaded()\n })\n } else {\n this._onScriptLoaded()\n }\n }\n\n private isInteractiveEvent(event: eventWithTime) {\n return (\n event.type === INCREMENTAL_SNAPSHOT_EVENT_TYPE &&\n ACTIVE_SOURCES.indexOf(event.data?.source as IncrementalSource) !== -1\n )\n }\n\n private _updateWindowAndSessionIds(event: eventWithTime) {\n // Some recording events are triggered by non-user events (e.g. \"X minutes ago\" text updating on the screen).\n // We don't want to extend the session or trigger a new session in these cases. These events are designated by event\n // type -> incremental update, and source -> mutation.\n\n const isUserInteraction = this.isInteractiveEvent(event)\n\n if (!isUserInteraction && !this.isIdle) {\n // We check if the lastActivityTimestamp is old enough to go idle\n if (event.timestamp - this._lastActivityTimestamp > RECORDING_IDLE_ACTIVITY_TIMEOUT_MS) {\n this.isIdle = true\n // don't take full snapshots while idle\n clearTimeout(this._fullSnapshotTimer)\n // proactively flush the buffer in case the session is idle for a long time\n this._flushBuffer()\n }\n }\n\n let returningFromIdle = false\n if (isUserInteraction) {\n this._lastActivityTimestamp = event.timestamp\n if (this.isIdle) {\n // Remove the idle state\n this.isIdle = false\n this._tryAddCustomEvent('sessionNoLongerIdle', {\n reason: 'user activity',\n type: event.type,\n })\n returningFromIdle = true\n }\n }\n\n if (this.isIdle) {\n return\n }\n\n // We only want to extend the session if it is an interactive event.\n const { windowId, sessionId } = this.sessionManager.checkAndGetSessionAndWindowId(\n !isUserInteraction,\n event.timestamp\n )\n\n const sessionIdChanged = this.sessionId !== sessionId\n const windowIdChanged = this.windowId !== windowId\n\n this.windowId = windowId\n this.sessionId = sessionId\n\n if (\n returningFromIdle ||\n ([FULL_SNAPSHOT_EVENT_TYPE, META_EVENT_TYPE].indexOf(event.type) === -1 &&\n (windowIdChanged || sessionIdChanged || isUndefined(this._fullSnapshotTimer)))\n ) {\n this._tryTakeFullSnapshot()\n }\n }\n\n private _tryRRWebMethod(queuedRRWebEvent: QueuedRRWebEvent): boolean {\n try {\n queuedRRWebEvent.rrwebMethod()\n return true\n } catch (e) {\n // Sometimes a race can occur where the recorder is not fully started yet\n if (this.queuedRRWebEvents.length < 10) {\n this.queuedRRWebEvents.push({\n enqueuedAt: queuedRRWebEvent.enqueuedAt || Date.now(),\n attempt: queuedRRWebEvent.attempt++,\n rrwebMethod: queuedRRWebEvent.rrwebMethod,\n })\n } else {\n logger.warn(LOGGER_PREFIX + ' could not emit queued rrweb event.', e, queuedRRWebEvent)\n }\n\n return false\n }\n }\n\n private _tryAddCustomEvent(tag: string, payload: any): boolean {\n return this._tryRRWebMethod(newQueuedEvent(() => this.rrwebRecord!.addCustomEvent(tag, payload)))\n }\n\n private _tryTakeFullSnapshot(): boolean {\n return this._tryRRWebMethod(newQueuedEvent(() => this.rrwebRecord!.takeFullSnapshot()))\n }\n\n private _onScriptLoaded() {\n // rrweb config info: https://github.com/rrweb-io/rrweb/blob/7d5d0033258d6c29599fb08412202d9a2c7b9413/src/record/index.ts#L28\n const sessionRecordingOptions: recordOptions<eventWithTime> = {\n // select set of rrweb config options we expose to our users\n // see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n blockClass: 'ph-no-capture',\n blockSelector: undefined,\n ignoreClass: 'ph-ignore-input',\n maskTextClass: 'ph-mask',\n maskTextSelector: undefined,\n maskTextFn: undefined,\n maskAllInputs: true,\n maskInputOptions: { password: true },\n maskInputFn: undefined,\n slimDOMOptions: {},\n collectFonts: false,\n inlineStylesheet: true,\n recordCrossOriginIframes: false,\n }\n\n // only allows user to set our allow-listed options\n const userSessionRecordingOptions = this.instance.config.session_recording\n for (const [key, value] of Object.entries(userSessionRecordingOptions || {})) {\n if (key in sessionRecordingOptions) {\n if (key === 'maskInputOptions') {\n // ensure password is set if not included\n sessionRecordingOptions.maskInputOptions = { password: true, ...value }\n } else {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n sessionRecordingOptions[key] = value\n }\n }\n }\n\n if (this.canvasRecording && this.canvasRecording.enabled) {\n sessionRecordingOptions.recordCanvas = true\n sessionRecordingOptions.sampling = { canvas: this.canvasRecording.fps }\n sessionRecordingOptions.dataURLOptions = { type: 'image/webp', quality: this.canvasRecording.quality }\n }\n\n if (!this.rrwebRecord) {\n logger.error(\n LOGGER_PREFIX +\n 'onScriptLoaded was called but rrwebRecord is not available. This indicates something has gone wrong.'\n )\n return\n }\n\n this.mutationRateLimiter =\n this.mutationRateLimiter ??\n new MutationRateLimiter(this.rrwebRecord, {\n onBlockedNode: (id, node) => {\n const message = `Too many mutations on node '${id}'. Rate limiting. This could be due to SVG animations or something similar`\n logger.info(message, {\n node: node,\n })\n\n this.log(LOGGER_PREFIX + ' ' + message, 'warn')\n },\n })\n\n const activePlugins = this._gatherRRWebPlugins()\n this.stopRrweb = this.rrwebRecord({\n emit: (event) => {\n this.onRRwebEmit(event)\n },\n plugins: activePlugins,\n ...sessionRecordingOptions,\n })\n\n // :TRICKY: rrweb does not capture navigation within SPA-s, so hook into our $pageview events to get access to all events.\n // Dropping the initial event is fine (it's always captured by rrweb).\n this.instance._addCaptureHook((eventName) => {\n // If anything could go wrong here it has the potential to block the main loop,\n // so we catch all errors.\n try {\n if (eventName === '$pageview') {\n const href = window ? this._maskUrl(window.location.href) : ''\n if (!href) {\n return\n }\n this._tryAddCustomEvent('$pageview', { href })\n }\n } catch (e) {\n logger.error('Could not add $pageview to rrweb session', e)\n }\n })\n\n // We reset the last activity timestamp, resetting the idle timer\n this._lastActivityTimestamp = Date.now()\n this.isIdle = false\n\n this._tryAddCustomEvent('$session_options', {\n sessionRecordingOptions,\n activePlugins: activePlugins.map((p) => p?.name),\n })\n\n this._tryAddCustomEvent('$posthog_config', {\n config: this.instance.config,\n })\n }\n\n private _scheduleFullSnapshot(): void {\n if (this._fullSnapshotTimer) {\n clearInterval(this._fullSnapshotTimer)\n }\n // we don't schedule snapshots while idle\n if (this.isIdle) {\n return\n }\n\n const interval = this.fullSnapshotIntervalMillis\n if (!interval) {\n return\n }\n\n this._fullSnapshotTimer = setInterval(() => {\n this._tryTakeFullSnapshot()\n }, interval)\n }\n\n private _gatherRRWebPlugins() {\n const plugins: RecordPlugin<unknown>[] = []\n\n if (assignableWindow.rrwebConsoleRecord && this.isConsoleLogCaptureEnabled) {\n plugins.push(assignableWindow.rrwebConsoleRecord.getRecordConsolePlugin())\n }\n\n if (this.networkPayloadCapture && isFunction(assignableWindow.getRecordNetworkPlugin)) {\n const canRecordNetwork = !isLocalhost() || this._forceAllowLocalhostNetworkCapture\n\n if (canRecordNetwork) {\n plugins.push(\n assignableWindow.getRecordNetworkPlugin(\n buildNetworkRequestOptions(this.instance.config, this.networkPayloadCapture)\n )\n )\n } else {\n logger.info(LOGGER_PREFIX + ' NetworkCapture not started because we are on localhost.')\n }\n }\n\n return plugins\n }\n\n onRRwebEmit(rawEvent: eventWithTime) {\n this._processQueuedEvents()\n\n if (!rawEvent || !isObject(rawEvent)) {\n return\n }\n\n if (rawEvent.type === EventType.Meta) {\n const href = this._maskUrl(rawEvent.data.href)\n this._lastHref = href\n if (!href) {\n return\n }\n rawEvent.data.href = href\n } else {\n this._pageViewFallBack()\n }\n\n // we're processing a full snapshot, so we should reset the timer\n if (rawEvent.type === EventType.FullSnapshot) {\n this._scheduleFullSnapshot()\n }\n\n const throttledEvent = this.mutationRateLimiter\n ? this.mutationRateLimiter.throttleMutations(rawEvent)\n : rawEvent\n\n if (!throttledEvent) {\n return\n }\n\n // TODO: Re-add ensureMaxMessageSize once we are confident in it\n const event = truncateLargeConsoleLogs(throttledEvent)\n const size = estimateSize(event)\n\n this._updateWindowAndSessionIds(event)\n\n // When in an idle state we keep recording, but don't capture the events\n // but we allow custom events even when idle\n if (this.isIdle && event.type !== EventType.Custom) {\n return\n }\n\n const properties = {\n $snapshot_bytes: size,\n $snapshot_data: event,\n $session_id: this.sessionId,\n $window_id: this.windowId,\n }\n\n if (this.status !== 'disabled') {\n this._captureSnapshotBuffered(properties)\n } else {\n this.clearBuffer()\n }\n }\n\n private _pageViewFallBack() {\n if (this.instance.config.capture_pageview || !window) {\n return\n }\n const currentUrl = this._maskUrl(window.location.href)\n if (this._lastHref !== currentUrl) {\n this._tryAddCustomEvent('$url_changed', { href: currentUrl })\n this._lastHref = currentUrl\n }\n }\n\n private _processQueuedEvents() {\n if (this.queuedRRWebEvents.length) {\n // if rrweb isn't ready to accept events earlier then we queued them up\n // now that emit has been called rrweb should be ready to accept them\n // so, before we process this event, we try our queued events _once_ each\n // we don't want to risk queuing more things and never exiting this loop!\n // if they fail here, they'll be pushed into a new queue,\n // and tried on the next loop.\n // there is a risk of this queue growing in an uncontrolled manner,\n // so its length is limited elsewhere\n // for now this is to help us ensure we can capture events that happen\n // and try to identify more about when it is failing\n const itemsToProcess = [...this.queuedRRWebEvents]\n this.queuedRRWebEvents = []\n itemsToProcess.forEach((queuedRRWebEvent) => {\n if (Date.now() - queuedRRWebEvent.enqueuedAt <= TWO_SECONDS) {\n this._tryRRWebMethod(queuedRRWebEvent)\n }\n })\n }\n }\n\n private _maskUrl(url: string): string | undefined {\n const userSessionRecordingOptions = this.instance.config.session_recording\n\n if (userSessionRecordingOptions.maskNetworkRequestFn) {\n let networkRequest: NetworkRequest | null | undefined = {\n url,\n }\n\n // TODO we should deprecate this and use the same function for this masking and the rrweb/network plugin\n // TODO or deprecate this and provide a new clearer name so this would be `maskURLPerformanceFn` or similar\n networkRequest = userSessionRecordingOptions.maskNetworkRequestFn(networkRequest)\n\n return networkRequest?.url\n }\n\n return url\n }\n\n private clearBuffer(): SnapshotBuffer {\n this.buffer = {\n size: 0,\n data: [],\n sessionId: this.sessionId,\n windowId: this.windowId,\n }\n return this.buffer\n }\n\n private _flushBuffer(): SnapshotBuffer {\n if (this.flushBufferTimer) {\n clearTimeout(this.flushBufferTimer)\n this.flushBufferTimer = undefined\n }\n\n const minimumDuration = this.minimumDuration\n const sessionDuration = this.sessionDuration\n // if we have old data in the buffer but the session has rotated then the\n // session duration might be negative, in that case we want to flush the buffer\n const isPositiveSessionDuration = isNumber(sessionDuration) && sessionDuration >= 0\n const isBelowMinimumDuration =\n isNumber(minimumDuration) && isPositiveSessionDuration && sessionDuration < minimumDuration\n\n if (this.status === 'buffering' || isBelowMinimumDuration) {\n this.flushBufferTimer = setTimeout(() => {\n this._flushBuffer()\n }, RECORDING_BUFFER_TIMEOUT)\n return this.buffer\n }\n\n if (this.buffer.data.length > 0) {\n const snapshotEvents = splitBuffer(this.buffer)\n snapshotEvents.forEach((snapshotBuffer) => {\n this._captureSnapshot({\n $snapshot_bytes: snapshotBuffer.size,\n $snapshot_data: snapshotBuffer.data,\n $session_id: snapshotBuffer.sessionId,\n $window_id: snapshotBuffer.windowId,\n })\n })\n }\n\n // buffer is empty, we clear it in case the session id has changed\n return this.clearBuffer()\n }\n\n private _captureSnapshotBuffered(properties: Properties) {\n const additionalBytes = 2 + (this.buffer?.data.length || 0) // 2 bytes for the array brackets and 1 byte for each comma\n if (\n this.buffer.size + properties.$snapshot_bytes + additionalBytes > RECORDING_MAX_EVENT_SIZE ||\n this.buffer.sessionId !== this.sessionId\n ) {\n this.buffer = this._flushBuffer()\n }\n\n this.buffer.size += properties.$snapshot_bytes\n this.buffer.data.push(properties.$snapshot_data)\n\n if (!this.flushBufferTimer) {\n this.flushBufferTimer = setTimeout(() => {\n this._flushBuffer()\n }, RECORDING_BUFFER_TIMEOUT)\n }\n }\n\n private _captureSnapshot(properties: Properties) {\n // :TRICKY: Make sure we batch these requests, use a custom endpoint and don't truncate the strings.\n this.instance.capture('$snapshot', properties, {\n _url: this.instance.requestRouter.endpointFor('api', this._endpoint),\n _noTruncate: true,\n _batchKey: SESSION_RECORDING_BATCH_KEY,\n })\n }\n\n /**\n * this ignores the linked flag config and causes capture to start\n * (if recording would have started had the flag been received i.e. it does not override other config).\n *\n * It is not usual to call this directly,\n * instead call `posthog.startSessionRecording({linked_flag: true})`\n * */\n public overrideLinkedFlag() {\n this._linkedFlagSeen = true\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sessionrecording.js","sourceRoot":"","sources":["../../../../src/extensions/replay/sessionrecording.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE,\n SESSION_RECORDING_CANVAS_RECORDING,\n SESSION_RECORDING_ENABLED_SERVER_SIDE,\n SESSION_RECORDING_IS_SAMPLED,\n SESSION_RECORDING_MINIMUM_DURATION,\n SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE,\n SESSION_RECORDING_SAMPLE_RATE,\n} from '../../constants'\nimport {\n estimateSize,\n FULL_SNAPSHOT_EVENT_TYPE,\n INCREMENTAL_SNAPSHOT_EVENT_TYPE,\n META_EVENT_TYPE,\n recordOptions,\n rrwebRecord,\n splitBuffer,\n truncateLargeConsoleLogs,\n} from './sessionrecording-utils'\nimport { PostHog } from '../../posthog-core'\nimport { DecideResponse, FlagVariant, NetworkRecordOptions, NetworkRequest, Properties } from '../../types'\nimport { EventType, type eventWithTime, IncrementalSource, type listenerHandler, RecordPlugin } from '@rrweb/types'\nimport Config from '../../config'\nimport { timestamp } from '../../utils'\n\nimport {\n isBoolean,\n isFunction,\n isNull,\n isNullish,\n isNumber,\n isObject,\n isString,\n isUndefined,\n} from '../../utils/type-utils'\nimport { logger } from '../../utils/logger'\nimport { assignableWindow, document, window } from '../../utils/globals'\nimport { buildNetworkRequestOptions } from './config'\nimport { isLocalhost } from '../../utils/request-utils'\nimport { MutationRateLimiter } from './mutation-rate-limiter'\n\nconst BASE_ENDPOINT = '/s/'\n\nconst FIVE_MINUTES = 1000 * 60 * 5\nconst TWO_SECONDS = 2000\nexport const RECORDING_IDLE_ACTIVITY_TIMEOUT_MS = FIVE_MINUTES\nexport const RECORDING_MAX_EVENT_SIZE = 1024 * 1024 * 0.9 // ~1mb (with some wiggle room)\nexport const RECORDING_BUFFER_TIMEOUT = 2000 // 2 seconds\nexport const SESSION_RECORDING_BATCH_KEY = 'recordings'\n\n// NOTE: Importing this type is problematic as we can't safely bundle it to a TS definition so, instead we redefine.\n// import type { record } from 'rrweb2/typings'\n// import type { recordOptions } from 'rrweb/typings/types'\n\nconst ACTIVE_SOURCES = [\n IncrementalSource.MouseMove,\n IncrementalSource.MouseInteraction,\n IncrementalSource.Scroll,\n IncrementalSource.ViewportResize,\n IncrementalSource.Input,\n IncrementalSource.TouchMove,\n IncrementalSource.MediaInteraction,\n IncrementalSource.Drag,\n]\n\n/**\n * Session recording starts in buffering mode while waiting for decide response\n * Once the response is received it might be disabled, active or sampled\n * When sampled that means a sample rate is set and the last time the session id was rotated\n * the sample rate determined this session should be sent to the server.\n */\ntype SessionRecordingStatus = 'disabled' | 'sampled' | 'active' | 'buffering'\n\nexport interface SnapshotBuffer {\n size: number\n data: any[]\n sessionId: string\n windowId: string\n}\n\ninterface QueuedRRWebEvent {\n rrwebMethod: () => void\n attempt: number\n // the timestamp this was first put into this queue\n enqueuedAt: number\n}\n\nconst newQueuedEvent = (rrwebMethod: () => void): QueuedRRWebEvent => ({\n rrwebMethod,\n enqueuedAt: Date.now(),\n attempt: 1,\n})\n\nconst LOGGER_PREFIX = '[SessionRecording]'\n\nexport class SessionRecording {\n private _endpoint: string\n private flushBufferTimer?: any\n\n // we have a buffer - that contains PostHog snapshot events ready to be sent to the server\n private buffer: SnapshotBuffer\n // and a queue - that contains rrweb events that we want to send to rrweb, but rrweb wasn't able to accept them yet\n private queuedRRWebEvents: QueuedRRWebEvent[] = []\n\n private mutationRateLimiter?: MutationRateLimiter\n private _captureStarted: boolean\n private stopRrweb: listenerHandler | undefined\n private receivedDecide: boolean\n private isIdle = false\n\n private _linkedFlagSeen: boolean = false\n private _lastActivityTimestamp: number = Date.now()\n private windowId: string\n private sessionId: string\n private _linkedFlag: string | FlagVariant | null = null\n\n private _fullSnapshotTimer?: ReturnType<typeof setInterval>\n\n // if pageview capture is disabled\n // then we can manually track href changes\n private _lastHref?: string\n\n // Util to help developers working on this feature manually override\n _forceAllowLocalhostNetworkCapture = false\n\n private get rrwebRecord(): rrwebRecord | undefined {\n return assignableWindow?.rrweb?.record\n }\n\n public get started(): boolean {\n // TODO could we use status instead of _captureStarted?\n return this._captureStarted\n }\n\n private get sessionManager() {\n if (!this.instance.sessionManager) {\n throw new Error(LOGGER_PREFIX + ' must be started with a valid sessionManager.')\n }\n\n return this.instance.sessionManager\n }\n\n private get fullSnapshotIntervalMillis(): number {\n return this.instance.config.session_recording?.full_snapshot_interval_millis || FIVE_MINUTES\n }\n\n private get isSampled(): boolean | null {\n const currentValue = this.instance.get_property(SESSION_RECORDING_IS_SAMPLED)\n return isBoolean(currentValue) ? currentValue : null\n }\n\n private get sessionDuration(): number | null {\n const mostRecentSnapshot = this.buffer?.data[this.buffer?.data.length - 1]\n const { sessionStartTimestamp } = this.sessionManager.checkAndGetSessionAndWindowId(true)\n return mostRecentSnapshot ? mostRecentSnapshot.timestamp - sessionStartTimestamp : null\n }\n\n private get isRecordingEnabled() {\n const enabled_server_side = !!this.instance.get_property(SESSION_RECORDING_ENABLED_SERVER_SIDE)\n const enabled_client_side = !this.instance.config.disable_session_recording\n return window && enabled_server_side && enabled_client_side\n }\n\n private get isConsoleLogCaptureEnabled() {\n const enabled_server_side = !!this.instance.get_property(CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE)\n const enabled_client_side = this.instance.config.enable_recording_console_log\n return enabled_client_side ?? enabled_server_side\n }\n\n private get canvasRecording(): { enabled: boolean; fps: number; quality: number } | undefined {\n const canvasRecording_server_side = this.instance.get_property(SESSION_RECORDING_CANVAS_RECORDING)\n return canvasRecording_server_side && canvasRecording_server_side.fps && canvasRecording_server_side.quality\n ? {\n enabled: canvasRecording_server_side.enabled,\n fps: canvasRecording_server_side.fps,\n quality: canvasRecording_server_side.quality,\n }\n : undefined\n }\n\n // network payload capture config has three parts\n // each can be configured server side or client side\n private get networkPayloadCapture():\n | Pick<NetworkRecordOptions, 'recordHeaders' | 'recordBody' | 'recordPerformance'>\n | undefined {\n const networkPayloadCapture_server_side = this.instance.get_property(SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE)\n const networkPayloadCapture_client_side = {\n recordHeaders: this.instance.config.session_recording?.recordHeaders,\n recordBody: this.instance.config.session_recording?.recordBody,\n }\n const headersEnabled =\n networkPayloadCapture_client_side?.recordHeaders || networkPayloadCapture_server_side?.recordHeaders\n const bodyEnabled =\n networkPayloadCapture_client_side?.recordBody || networkPayloadCapture_server_side?.recordBody\n const clientConfigForPerformanceCapture = isObject(this.instance.config.capture_performance)\n ? this.instance.config.capture_performance.network_timing\n : this.instance.config.capture_performance\n const networkTimingEnabled = !!(isBoolean(clientConfigForPerformanceCapture)\n ? clientConfigForPerformanceCapture\n : networkPayloadCapture_server_side?.capturePerformance)\n\n return headersEnabled || bodyEnabled || networkTimingEnabled\n ? { recordHeaders: headersEnabled, recordBody: bodyEnabled, recordPerformance: networkTimingEnabled }\n : undefined\n }\n\n private get sampleRate(): number | null {\n const rate = this.instance.get_property(SESSION_RECORDING_SAMPLE_RATE)\n return isNumber(rate) ? rate : null\n }\n\n private get minimumDuration(): number | null {\n const duration = this.instance.get_property(SESSION_RECORDING_MINIMUM_DURATION)\n return isNumber(duration) ? duration : null\n }\n\n /**\n * defaults to buffering mode until a decide response is received\n * once a decide response is received status can be disabled, active or sampled\n */\n private get status(): SessionRecordingStatus {\n if (!this.receivedDecide) {\n return 'buffering'\n }\n\n if (!this.isRecordingEnabled) {\n return 'disabled'\n }\n\n if (!isNullish(this._linkedFlag) && !this._linkedFlagSeen) {\n return 'buffering'\n }\n\n if (isBoolean(this.isSampled)) {\n return this.isSampled ? 'sampled' : 'disabled'\n } else {\n return 'active'\n }\n }\n\n constructor(private readonly instance: PostHog) {\n this._captureStarted = false\n this._endpoint = BASE_ENDPOINT\n this.stopRrweb = undefined\n this.receivedDecide = false\n\n if (!this.instance.sessionManager) {\n logger.error(LOGGER_PREFIX + ' started without valid sessionManager')\n throw new Error(LOGGER_PREFIX + ' started without valid sessionManager. This is a bug.')\n }\n\n // we know there's a sessionManager, so don't need to start without a session id\n const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId()\n this.sessionId = sessionId\n this.windowId = windowId\n\n this.buffer = this.clearBuffer()\n\n // on reload there might be an already sampled session that should be continued before decide response,\n // so we call this here _and_ in the decide response\n this._setupSampling()\n }\n\n private _onBeforeUnload = (): void => {\n this._flushBuffer()\n }\n\n private _onOffline = (): void => {\n this._tryAddCustomEvent('browser offline', {})\n }\n\n private _onOnline = (): void => {\n this._tryAddCustomEvent('browser online', {})\n }\n\n private _onVisibilityChange = (): void => {\n if (document?.visibilityState) {\n const label = 'window ' + document.visibilityState\n this._tryAddCustomEvent(label, {})\n }\n }\n\n startIfEnabledOrStop() {\n if (this.isRecordingEnabled) {\n this._startCapture()\n\n window?.addEventListener('beforeunload', this._onBeforeUnload)\n window?.addEventListener('offline', this._onOffline)\n window?.addEventListener('online', this._onOnline)\n window?.addEventListener('visibilitychange', this._onVisibilityChange)\n\n logger.info(LOGGER_PREFIX + ' started')\n } else {\n this.stopRecording()\n this.clearBuffer()\n }\n }\n\n stopRecording() {\n if (this._captureStarted && this.stopRrweb) {\n this.stopRrweb()\n this.stopRrweb = undefined\n this._captureStarted = false\n\n window?.removeEventListener('beforeunload', this._onBeforeUnload)\n window?.removeEventListener('offline', this._onOffline)\n window?.removeEventListener('online', this._onOnline)\n window?.removeEventListener('visibilitychange', this._onVisibilityChange)\n\n logger.info(LOGGER_PREFIX + ' stopped')\n }\n }\n\n private makeSamplingDecision(sessionId: string): void {\n const sessionIdChanged = this.sessionId !== sessionId\n\n // capture the current sample rate,\n // because it is re-used multiple times\n // and the bundler won't minimise any of the references\n const currentSampleRate = this.sampleRate\n\n if (!isNumber(currentSampleRate)) {\n this.instance.persistence?.register({\n [SESSION_RECORDING_IS_SAMPLED]: null,\n })\n return\n }\n\n const storedIsSampled = this.isSampled\n\n /**\n * if we get this far then we should make a sampling decision.\n * When the session id changes or there is no stored sampling decision for this session id\n * then we should make a new decision.\n *\n * Otherwise, we should use the stored decision.\n */\n let shouldSample: boolean\n const makeDecision = sessionIdChanged || !isBoolean(storedIsSampled)\n if (makeDecision) {\n const randomNumber = Math.random()\n shouldSample = randomNumber < currentSampleRate\n } else {\n shouldSample = storedIsSampled\n }\n\n if (!shouldSample && makeDecision) {\n logger.warn(\n LOGGER_PREFIX +\n ` Sample rate (${currentSampleRate}) has determined that this sessionId (${sessionId}) will not be sent to the server.`\n )\n }\n this._tryAddCustomEvent('samplingDecisionMade', {\n sampleRate: currentSampleRate,\n })\n\n this.instance.persistence?.register({\n [SESSION_RECORDING_IS_SAMPLED]: shouldSample,\n })\n }\n\n afterDecideResponse(response: DecideResponse) {\n this._persistDecideResponse(response)\n\n this._linkedFlag = response.sessionRecording?.linkedFlag || null\n\n if (response.sessionRecording?.endpoint) {\n this._endpoint = response.sessionRecording?.endpoint\n }\n\n this._setupSampling()\n\n if (!isNullish(this._linkedFlag) && !this._linkedFlagSeen) {\n const linkedFlag = isString(this._linkedFlag) ? this._linkedFlag : this._linkedFlag.flag\n const linkedVariant = isString(this._linkedFlag) ? null : this._linkedFlag.variant\n this.instance.onFeatureFlags((_flags, variants) => {\n const flagIsPresent = isObject(variants) && linkedFlag in variants\n const linkedFlagMatches = linkedVariant ? variants[linkedFlag] === linkedVariant : flagIsPresent\n if (linkedFlagMatches) {\n const payload = {\n linkedFlag,\n linkedVariant,\n }\n const tag = 'linked flag matched'\n logger.info(LOGGER_PREFIX + ' ' + tag, payload)\n this._tryAddCustomEvent(tag, payload)\n }\n this._linkedFlagSeen = linkedFlagMatches\n })\n }\n\n this.receivedDecide = true\n this.startIfEnabledOrStop()\n }\n\n private _samplingSessionListener: (() => void) | null = null\n\n /**\n * This might be called more than once so needs to be idempotent\n */\n private _setupSampling() {\n if (isNumber(this.sampleRate) && isNull(this._samplingSessionListener)) {\n this._samplingSessionListener = this.sessionManager.onSessionId((sessionId) => {\n this.makeSamplingDecision(sessionId)\n })\n }\n }\n\n private _persistDecideResponse(response: DecideResponse): void {\n if (this.instance.persistence) {\n const persistence = this.instance.persistence\n\n const persistResponse = () => {\n const receivedSampleRate = response.sessionRecording?.sampleRate\n\n const parsedSampleRate = isNullish(receivedSampleRate) ? null : parseFloat(receivedSampleRate)\n const receivedMinimumDuration = response.sessionRecording?.minimumDurationMilliseconds\n\n persistence.register({\n [SESSION_RECORDING_ENABLED_SERVER_SIDE]: !!response['sessionRecording'],\n [CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE]: response.sessionRecording?.consoleLogRecordingEnabled,\n [SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE]: {\n capturePerformance: response.capturePerformance,\n ...response.sessionRecording?.networkPayloadCapture,\n },\n [SESSION_RECORDING_CANVAS_RECORDING]: {\n enabled: response.sessionRecording?.recordCanvas,\n fps: response.sessionRecording?.canvasFps,\n quality: response.sessionRecording?.canvasQuality,\n },\n [SESSION_RECORDING_SAMPLE_RATE]: parsedSampleRate,\n [SESSION_RECORDING_MINIMUM_DURATION]: isUndefined(receivedMinimumDuration)\n ? null\n : receivedMinimumDuration,\n })\n }\n\n persistResponse()\n this.sessionManager.onSessionId(persistResponse)\n }\n }\n\n log(message: string, level: 'log' | 'warn' | 'error' = 'log') {\n this.instance.sessionRecording?.onRRwebEmit({\n type: 6,\n data: {\n plugin: 'rrweb/console@1',\n payload: {\n level,\n trace: [],\n // Even though it is a string we stringify it as that's what rrweb expects\n payload: [JSON.stringify(message)],\n },\n },\n timestamp: timestamp(),\n })\n }\n\n private _startCapture() {\n if (isUndefined(Object.assign)) {\n // According to the rrweb docs, rrweb is not supported on IE11 and below:\n // \"rrweb does not support IE11 and below because it uses the MutationObserver API which was supported by these browsers.\"\n // https://github.com/rrweb-io/rrweb/blob/master/guide.md#compatibility-note\n //\n // However, MutationObserver does exist on IE11, it just doesn't work well and does not detect all changes.\n // Instead, when we load \"recorder.js\", the first JS error is about \"Object.assign\" being undefined.\n // Thus instead of MutationObserver, we look for this function and block recording if it's undefined.\n return\n }\n\n // We do not switch recorder versions midway through a recording.\n // do not start if explicitly disabled or if the user has opted out\n if (\n this._captureStarted ||\n this.instance.config.disable_session_recording ||\n this.instance.consent.isOptedOut()\n ) {\n return\n }\n\n this._captureStarted = true\n // We want to ensure the sessionManager is reset if necessary on load of the recorder\n this.sessionManager.checkAndGetSessionAndWindowId()\n\n // If recorder.js is already loaded (if array.full.js snippet is used or posthog-js/dist/recorder is\n // imported), don't load script. Otherwise, remotely import recorder.js from cdn since it hasn't been loaded.\n if (!this.rrwebRecord) {\n this.instance.requestRouter.loadScript(`/static/recorder.js?v=${Config.LIB_VERSION}`, (err) => {\n if (err) {\n return logger.error(LOGGER_PREFIX + ` could not load recorder.js`, err)\n }\n\n this._onScriptLoaded()\n })\n } else {\n this._onScriptLoaded()\n }\n }\n\n private isInteractiveEvent(event: eventWithTime) {\n return (\n event.type === INCREMENTAL_SNAPSHOT_EVENT_TYPE &&\n ACTIVE_SOURCES.indexOf(event.data?.source as IncrementalSource) !== -1\n )\n }\n\n private _updateWindowAndSessionIds(event: eventWithTime) {\n // Some recording events are triggered by non-user events (e.g. \"X minutes ago\" text updating on the screen).\n // We don't want to extend the session or trigger a new session in these cases. These events are designated by event\n // type -> incremental update, and source -> mutation.\n\n const isUserInteraction = this.isInteractiveEvent(event)\n\n if (!isUserInteraction && !this.isIdle) {\n // We check if the lastActivityTimestamp is old enough to go idle\n if (event.timestamp - this._lastActivityTimestamp > RECORDING_IDLE_ACTIVITY_TIMEOUT_MS) {\n this.isIdle = true\n // don't take full snapshots while idle\n clearTimeout(this._fullSnapshotTimer)\n // proactively flush the buffer in case the session is idle for a long time\n this._flushBuffer()\n }\n }\n\n let returningFromIdle = false\n if (isUserInteraction) {\n this._lastActivityTimestamp = event.timestamp\n if (this.isIdle) {\n // Remove the idle state\n this.isIdle = false\n this._tryAddCustomEvent('sessionNoLongerIdle', {\n reason: 'user activity',\n type: event.type,\n })\n returningFromIdle = true\n }\n }\n\n if (this.isIdle) {\n return\n }\n\n // We only want to extend the session if it is an interactive event.\n const { windowId, sessionId } = this.sessionManager.checkAndGetSessionAndWindowId(\n !isUserInteraction,\n event.timestamp\n )\n\n const sessionIdChanged = this.sessionId !== sessionId\n const windowIdChanged = this.windowId !== windowId\n\n this.windowId = windowId\n this.sessionId = sessionId\n\n if (\n returningFromIdle ||\n ([FULL_SNAPSHOT_EVENT_TYPE, META_EVENT_TYPE].indexOf(event.type) === -1 &&\n (windowIdChanged || sessionIdChanged || isUndefined(this._fullSnapshotTimer)))\n ) {\n this._tryTakeFullSnapshot()\n }\n }\n\n private _tryRRWebMethod(queuedRRWebEvent: QueuedRRWebEvent): boolean {\n try {\n queuedRRWebEvent.rrwebMethod()\n return true\n } catch (e) {\n // Sometimes a race can occur where the recorder is not fully started yet\n if (this.queuedRRWebEvents.length < 10) {\n this.queuedRRWebEvents.push({\n enqueuedAt: queuedRRWebEvent.enqueuedAt || Date.now(),\n attempt: queuedRRWebEvent.attempt++,\n rrwebMethod: queuedRRWebEvent.rrwebMethod,\n })\n } else {\n logger.warn(LOGGER_PREFIX + ' could not emit queued rrweb event.', e, queuedRRWebEvent)\n }\n\n return false\n }\n }\n\n private _tryAddCustomEvent(tag: string, payload: any): boolean {\n return this._tryRRWebMethod(newQueuedEvent(() => this.rrwebRecord!.addCustomEvent(tag, payload)))\n }\n\n private _tryTakeFullSnapshot(): boolean {\n return this._tryRRWebMethod(newQueuedEvent(() => this.rrwebRecord!.takeFullSnapshot()))\n }\n\n private _onScriptLoaded() {\n // rrweb config info: https://github.com/rrweb-io/rrweb/blob/7d5d0033258d6c29599fb08412202d9a2c7b9413/src/record/index.ts#L28\n const sessionRecordingOptions: recordOptions<eventWithTime> = {\n // select set of rrweb config options we expose to our users\n // see https://github.com/rrweb-io/rrweb/blob/master/guide.md\n blockClass: 'ph-no-capture',\n blockSelector: undefined,\n ignoreClass: 'ph-ignore-input',\n maskTextClass: 'ph-mask',\n maskTextSelector: undefined,\n maskTextFn: undefined,\n maskAllInputs: true,\n maskInputOptions: { password: true },\n maskInputFn: undefined,\n slimDOMOptions: {},\n collectFonts: false,\n inlineStylesheet: true,\n recordCrossOriginIframes: false,\n }\n\n // only allows user to set our allow-listed options\n const userSessionRecordingOptions = this.instance.config.session_recording\n for (const [key, value] of Object.entries(userSessionRecordingOptions || {})) {\n if (key in sessionRecordingOptions) {\n if (key === 'maskInputOptions') {\n // ensure password is set if not included\n sessionRecordingOptions.maskInputOptions = { password: true, ...value }\n } else {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n sessionRecordingOptions[key] = value\n }\n }\n }\n\n if (this.canvasRecording && this.canvasRecording.enabled) {\n sessionRecordingOptions.recordCanvas = true\n sessionRecordingOptions.sampling = { canvas: this.canvasRecording.fps }\n sessionRecordingOptions.dataURLOptions = { type: 'image/webp', quality: this.canvasRecording.quality }\n }\n\n if (!this.rrwebRecord) {\n logger.error(\n LOGGER_PREFIX +\n 'onScriptLoaded was called but rrwebRecord is not available. This indicates something has gone wrong.'\n )\n return\n }\n\n this.mutationRateLimiter =\n this.mutationRateLimiter ??\n new MutationRateLimiter(this.rrwebRecord, {\n onBlockedNode: (id, node) => {\n const message = `Too many mutations on node '${id}'. Rate limiting. This could be due to SVG animations or something similar`\n logger.info(message, {\n node: node,\n })\n\n this.log(LOGGER_PREFIX + ' ' + message, 'warn')\n },\n })\n\n const activePlugins = this._gatherRRWebPlugins()\n this.stopRrweb = this.rrwebRecord({\n emit: (event) => {\n this.onRRwebEmit(event)\n },\n plugins: activePlugins,\n ...sessionRecordingOptions,\n })\n\n // :TRICKY: rrweb does not capture navigation within SPA-s, so hook into our $pageview events to get access to all events.\n // Dropping the initial event is fine (it's always captured by rrweb).\n this.instance._addCaptureHook((eventName) => {\n // If anything could go wrong here it has the potential to block the main loop,\n // so we catch all errors.\n try {\n if (eventName === '$pageview') {\n const href = window ? this._maskUrl(window.location.href) : ''\n if (!href) {\n return\n }\n this._tryAddCustomEvent('$pageview', { href })\n }\n } catch (e) {\n logger.error('Could not add $pageview to rrweb session', e)\n }\n })\n\n // We reset the last activity timestamp, resetting the idle timer\n this._lastActivityTimestamp = Date.now()\n this.isIdle = false\n\n this._tryAddCustomEvent('$session_options', {\n sessionRecordingOptions,\n activePlugins: activePlugins.map((p) => p?.name),\n })\n\n this._tryAddCustomEvent('$posthog_config', {\n config: this.instance.config,\n })\n }\n\n private _scheduleFullSnapshot(): void {\n if (this._fullSnapshotTimer) {\n clearInterval(this._fullSnapshotTimer)\n }\n // we don't schedule snapshots while idle\n if (this.isIdle) {\n return\n }\n\n const interval = this.fullSnapshotIntervalMillis\n if (!interval) {\n return\n }\n\n this._fullSnapshotTimer = setInterval(() => {\n this._tryTakeFullSnapshot()\n }, interval)\n }\n\n private _gatherRRWebPlugins() {\n const plugins: RecordPlugin<unknown>[] = []\n\n if (assignableWindow.rrwebConsoleRecord && this.isConsoleLogCaptureEnabled) {\n plugins.push(assignableWindow.rrwebConsoleRecord.getRecordConsolePlugin())\n }\n\n if (this.networkPayloadCapture && isFunction(assignableWindow.getRecordNetworkPlugin)) {\n const canRecordNetwork = !isLocalhost() || this._forceAllowLocalhostNetworkCapture\n\n if (canRecordNetwork) {\n plugins.push(\n assignableWindow.getRecordNetworkPlugin(\n buildNetworkRequestOptions(this.instance.config, this.networkPayloadCapture)\n )\n )\n } else {\n logger.info(LOGGER_PREFIX + ' NetworkCapture not started because we are on localhost.')\n }\n }\n\n return plugins\n }\n\n onRRwebEmit(rawEvent: eventWithTime) {\n this._processQueuedEvents()\n\n if (!rawEvent || !isObject(rawEvent)) {\n return\n }\n\n if (rawEvent.type === EventType.Meta) {\n const href = this._maskUrl(rawEvent.data.href)\n this._lastHref = href\n if (!href) {\n return\n }\n rawEvent.data.href = href\n } else {\n this._pageViewFallBack()\n }\n\n // we're processing a full snapshot, so we should reset the timer\n if (rawEvent.type === EventType.FullSnapshot) {\n this._scheduleFullSnapshot()\n }\n\n const throttledEvent = this.mutationRateLimiter\n ? this.mutationRateLimiter.throttleMutations(rawEvent)\n : rawEvent\n\n if (!throttledEvent) {\n return\n }\n\n // TODO: Re-add ensureMaxMessageSize once we are confident in it\n const event = truncateLargeConsoleLogs(throttledEvent)\n const size = estimateSize(event)\n\n this._updateWindowAndSessionIds(event)\n\n // When in an idle state we keep recording, but don't capture the events\n // but we allow custom events even when idle\n if (this.isIdle && event.type !== EventType.Custom) {\n return\n }\n\n const properties = {\n $snapshot_bytes: size,\n $snapshot_data: event,\n $session_id: this.sessionId,\n $window_id: this.windowId,\n }\n\n if (this.status !== 'disabled') {\n this._captureSnapshotBuffered(properties)\n } else {\n this.clearBuffer()\n }\n }\n\n private _pageViewFallBack() {\n if (this.instance.config.capture_pageview || !window) {\n return\n }\n const currentUrl = this._maskUrl(window.location.href)\n if (this._lastHref !== currentUrl) {\n this._tryAddCustomEvent('$url_changed', { href: currentUrl })\n this._lastHref = currentUrl\n }\n }\n\n private _processQueuedEvents() {\n if (this.queuedRRWebEvents.length) {\n // if rrweb isn't ready to accept events earlier then we queued them up\n // now that emit has been called rrweb should be ready to accept them\n // so, before we process this event, we try our queued events _once_ each\n // we don't want to risk queuing more things and never exiting this loop!\n // if they fail here, they'll be pushed into a new queue,\n // and tried on the next loop.\n // there is a risk of this queue growing in an uncontrolled manner,\n // so its length is limited elsewhere\n // for now this is to help us ensure we can capture events that happen\n // and try to identify more about when it is failing\n const itemsToProcess = [...this.queuedRRWebEvents]\n this.queuedRRWebEvents = []\n itemsToProcess.forEach((queuedRRWebEvent) => {\n if (Date.now() - queuedRRWebEvent.enqueuedAt <= TWO_SECONDS) {\n this._tryRRWebMethod(queuedRRWebEvent)\n }\n })\n }\n }\n\n private _maskUrl(url: string): string | undefined {\n const userSessionRecordingOptions = this.instance.config.session_recording\n\n if (userSessionRecordingOptions.maskNetworkRequestFn) {\n let networkRequest: NetworkRequest | null | undefined = {\n url,\n }\n\n // TODO we should deprecate this and use the same function for this masking and the rrweb/network plugin\n // TODO or deprecate this and provide a new clearer name so this would be `maskURLPerformanceFn` or similar\n networkRequest = userSessionRecordingOptions.maskNetworkRequestFn(networkRequest)\n\n return networkRequest?.url\n }\n\n return url\n }\n\n private clearBuffer(): SnapshotBuffer {\n this.buffer = {\n size: 0,\n data: [],\n sessionId: this.sessionId,\n windowId: this.windowId,\n }\n return this.buffer\n }\n\n private _flushBuffer(): SnapshotBuffer {\n if (this.flushBufferTimer) {\n clearTimeout(this.flushBufferTimer)\n this.flushBufferTimer = undefined\n }\n\n const minimumDuration = this.minimumDuration\n const sessionDuration = this.sessionDuration\n // if we have old data in the buffer but the session has rotated then the\n // session duration might be negative, in that case we want to flush the buffer\n const isPositiveSessionDuration = isNumber(sessionDuration) && sessionDuration >= 0\n const isBelowMinimumDuration =\n isNumber(minimumDuration) && isPositiveSessionDuration && sessionDuration < minimumDuration\n\n if (this.status === 'buffering' || isBelowMinimumDuration) {\n this.flushBufferTimer = setTimeout(() => {\n this._flushBuffer()\n }, RECORDING_BUFFER_TIMEOUT)\n return this.buffer\n }\n\n if (this.buffer.data.length > 0) {\n const snapshotEvents = splitBuffer(this.buffer)\n snapshotEvents.forEach((snapshotBuffer) => {\n this._captureSnapshot({\n $snapshot_bytes: snapshotBuffer.size,\n $snapshot_data: snapshotBuffer.data,\n $session_id: snapshotBuffer.sessionId,\n $window_id: snapshotBuffer.windowId,\n })\n })\n }\n\n // buffer is empty, we clear it in case the session id has changed\n return this.clearBuffer()\n }\n\n private _captureSnapshotBuffered(properties: Properties) {\n const additionalBytes = 2 + (this.buffer?.data.length || 0) // 2 bytes for the array brackets and 1 byte for each comma\n if (\n this.buffer.size + properties.$snapshot_bytes + additionalBytes > RECORDING_MAX_EVENT_SIZE ||\n this.buffer.sessionId !== this.sessionId\n ) {\n this.buffer = this._flushBuffer()\n }\n\n this.buffer.size += properties.$snapshot_bytes\n this.buffer.data.push(properties.$snapshot_data)\n\n if (!this.flushBufferTimer) {\n this.flushBufferTimer = setTimeout(() => {\n this._flushBuffer()\n }, RECORDING_BUFFER_TIMEOUT)\n }\n }\n\n private _captureSnapshot(properties: Properties) {\n // :TRICKY: Make sure we batch these requests, use a custom endpoint and don't truncate the strings.\n this.instance.capture('$snapshot', properties, {\n _url: this.instance.requestRouter.endpointFor('api', this._endpoint),\n _noTruncate: true,\n _batchKey: SESSION_RECORDING_BATCH_KEY,\n skip_client_rate_limiting: true,\n })\n }\n\n /**\n * this ignores the linked flag config and causes capture to start\n * (if recording would have started had the flag been received i.e. it does not override other config).\n *\n * It is not usual to call this directly,\n * instead call `posthog.startSessionRecording({linked_flag: true})`\n * */\n public overrideLinkedFlag() {\n this._linkedFlagSeen = true\n }\n}\n"]}
|