@amplitude/session-replay-browser 1.39.0 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/cjs/version.js.map +1 -1
- package/lib/cjs/worker/index.js +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/esm/version.js.map +1 -1
- package/lib/esm/worker/index.js +1 -1
- package/lib/scripts/console-plugin-min.js.map +1 -1
- package/lib/scripts/index-min.js +1 -1
- package/lib/scripts/index-min.js.gz +0 -0
- package/lib/scripts/index-min.js.map +1 -1
- package/lib/scripts/observers-min.js.map +1 -1
- package/lib/scripts/rrweb-record-min.js +1 -1
- package/lib/scripts/rrweb-record-min.js.gz +0 -0
- package/lib/scripts/rrweb-record-min.js.map +1 -1
- package/lib/scripts/session-replay-browser-min.js +1 -1
- package/lib/scripts/session-replay-browser-min.js.gz +0 -0
- package/lib/scripts/session-replay-browser-min.js.map +1 -1
- package/lib/scripts/targeting-min.js.map +1 -1
- package/lib/scripts/worker-min.js +1 -1
- package/lib/scripts/worker-min.js.gz +0 -0
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observers-min.js","sources":["../../../src/observers.ts"],"sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\n\nexport type ResponseBodyStatus = 'captured' | 'truncated' | 'skipped_binary' | 'error';\n\nexport interface NetworkRequestEvent {\n timestamp: number;\n type: 'fetch';\n method: string;\n url: string;\n status?: number;\n duration?: number;\n requestHeaders?: Record<string, string>;\n responseHeaders?: Record<string, string>;\n requestBody?: string;\n responseBody?: string;\n responseBodyStatus?: ResponseBodyStatus;\n error?: {\n name: string;\n message: string;\n };\n}\n\nexport type NetworkEventCallback = (event: NetworkRequestEvent) => void;\n\nexport interface NetworkBodyConfig {\n request?: boolean;\n response?: boolean;\n maxBodySizeBytes?: number;\n}\n\nexport interface NetworkConfig {\n enabled: boolean;\n body?: NetworkBodyConfig;\n}\n\nconst DEFAULT_MAX_BODY_SIZE_BYTES = 10240; // 10KB\n\nconst BINARY_CONTENT_TYPE_PREFIXES = ['image/', 'audio/', 'video/', 'application/octet-stream', 'font/'];\n\nfunction isBinaryContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n return BINARY_CONTENT_TYPE_PREFIXES.some((prefix) => contentType.toLowerCase().startsWith(prefix));\n}\n\nfunction serializeRequestBody(body: BodyInit | null | undefined): string | undefined {\n if (body === null || body === undefined) return undefined;\n if (typeof body === 'string') return body;\n if (body instanceof URLSearchParams) return body.toString();\n if (body instanceof FormData) {\n const parts: string[] = [];\n body.forEach((value, key) => {\n parts.push(`${key}=${typeof value === 'string' ? value : '[File]'}`);\n });\n return parts.join('&');\n }\n // Blob, ArrayBuffer, ArrayBufferView, ReadableStream — skip\n return undefined;\n}\n\nfunction truncateToByteLimit(str: string, maxBytes: number): { value: string; truncated: boolean } {\n if (new Blob([str]).size <= maxBytes) {\n return { value: str, truncated: false };\n }\n // Binary search for the longest prefix whose UTF-8 byte length fits within maxBytes.\n // Cap hi at maxBytes since each UTF-8 character is at least 1 byte, so no more than\n // maxBytes characters can ever fit — this avoids large intermediate Blob allocations.\n let lo = 0;\n let hi = Math.min(str.length, maxBytes);\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (new Blob([str.slice(0, mid)]).size <= maxBytes) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n // Avoid splitting a surrogate pair: if lo landed after a high surrogate, back up one position\n if (lo > 0 && str.charCodeAt(lo - 1) >= 0xd800 && str.charCodeAt(lo - 1) <= 0xdbff) {\n lo -= 1;\n }\n return { value: str.slice(0, lo), truncated: true };\n}\n\nexport class NetworkObservers {\n private fetchObserver: (() => void) | null = null;\n private eventCallback?: NetworkEventCallback;\n private networkConfig?: NetworkConfig;\n\n start(eventCallback: NetworkEventCallback, networkConfig?: NetworkConfig) {\n this.eventCallback = eventCallback;\n this.networkConfig = networkConfig;\n this.observeFetch();\n }\n\n stop() {\n this.fetchObserver?.();\n this.fetchObserver = null;\n this.eventCallback = undefined;\n this.networkConfig = undefined;\n }\n\n protected notifyEvent(event: NetworkRequestEvent) {\n this.eventCallback?.(event);\n }\n\n private observeFetch() {\n const globalScope = getGlobalScope();\n if (!globalScope) return;\n\n const originalFetch = globalScope.fetch;\n if (!originalFetch) return;\n\n globalScope.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n const startTime = Date.now();\n const requestEvent: NetworkRequestEvent = {\n timestamp: startTime,\n type: 'fetch',\n method: init?.method || 'GET', // Fetch API defaulted to GET when no method is provided\n url: input.toString(),\n requestHeaders: init?.headers as Record<string, string>,\n };\n\n // Capture request body if configured\n const bodyConfig = this.networkConfig?.body;\n if (bodyConfig?.request) {\n const serialized = serializeRequestBody(init?.body);\n if (serialized !== undefined) {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n requestEvent.requestBody = truncateToByteLimit(serialized, maxBytes).value;\n }\n }\n\n try {\n const response = await originalFetch(input, init);\n const endTime = Date.now();\n\n requestEvent.status = response.status;\n requestEvent.duration = endTime - startTime;\n\n // Convert Headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n requestEvent.responseHeaders = headers;\n\n if (bodyConfig?.response) {\n const contentType = headers['content-type'] || null;\n if (isBinaryContentType(contentType)) {\n requestEvent.responseBodyStatus = 'skipped_binary';\n this.notifyEvent(requestEvent);\n } else {\n const cloned = response.clone();\n // Read body without blocking the response return to the caller\n cloned.text().then(\n (text) => {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n const { value, truncated } = truncateToByteLimit(text, maxBytes);\n requestEvent.responseBody = value;\n requestEvent.responseBodyStatus = truncated ? 'truncated' : 'captured';\n this.notifyEvent(requestEvent);\n },\n () => {\n requestEvent.responseBodyStatus = 'error';\n this.notifyEvent(requestEvent);\n },\n );\n }\n } else {\n this.notifyEvent(requestEvent);\n }\n\n return response;\n } catch (error) {\n const endTime = Date.now();\n requestEvent.duration = endTime - startTime;\n\n // Capture error information\n const typedError = error as Error;\n requestEvent.error = {\n name: typedError.name || 'UnknownError',\n message: typedError.message || 'An unknown error occurred',\n };\n\n this.notifyEvent(requestEvent);\n throw error;\n }\n };\n\n this.fetchObserver = () => {\n globalScope.fetch = originalFetch;\n };\n }\n}\n"],"names":["BINARY_CONTENT_TYPE_PREFIXES","truncateToByteLimit","str","maxBytes","Blob","size","value","truncated","lo","hi","Math","min","length","mid","ceil","slice","charCodeAt","NetworkObservers","constructor","this","fetchObserver","start","eventCallback","networkConfig","observeFetch","stop","_a","call","undefined","notifyEvent","event","globalScope","getGlobalScope","originalFetch","fetch","input","init","__awaiter","startTime","Date","now","requestEvent","timestamp","type","method","url","toString","requestHeaders","headers","bodyConfig","body","request","serialized","URLSearchParams","FormData","parts","forEach","key","push","join","serializeRequestBody","_b","maxBodySizeBytes","requestBody","response","endTime","status","duration","responseHeaders","contentType","some","prefix","toLowerCase","startsWith","isBinaryContentType","responseBodyStatus","clone","text","then","responseBody","error","typedError","name","message"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"observers-min.js","sources":["../../../src/observers.ts"],"sourcesContent":["import { getGlobalScope } from '@amplitude/analytics-core';\n\nexport type ResponseBodyStatus = 'captured' | 'truncated' | 'skipped_binary' | 'error';\n\nexport interface NetworkRequestEvent {\n timestamp: number;\n type: 'fetch';\n method: string;\n url: string;\n status?: number;\n duration?: number;\n requestHeaders?: Record<string, string>;\n responseHeaders?: Record<string, string>;\n requestBody?: string;\n responseBody?: string;\n responseBodyStatus?: ResponseBodyStatus;\n error?: {\n name: string;\n message: string;\n };\n}\n\nexport type NetworkEventCallback = (event: NetworkRequestEvent) => void;\n\nexport interface NetworkBodyConfig {\n request?: boolean;\n response?: boolean;\n maxBodySizeBytes?: number;\n}\n\nexport interface NetworkConfig {\n enabled: boolean;\n body?: NetworkBodyConfig;\n}\n\nconst DEFAULT_MAX_BODY_SIZE_BYTES = 10240; // 10KB\n\nconst BINARY_CONTENT_TYPE_PREFIXES = ['image/', 'audio/', 'video/', 'application/octet-stream', 'font/'];\n\nfunction isBinaryContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n return BINARY_CONTENT_TYPE_PREFIXES.some((prefix) => contentType.toLowerCase().startsWith(prefix));\n}\n\nfunction serializeRequestBody(body: BodyInit | null | undefined): string | undefined {\n if (body === null || body === undefined) return undefined;\n if (typeof body === 'string') return body;\n if (body instanceof URLSearchParams) return body.toString();\n if (body instanceof FormData) {\n const parts: string[] = [];\n body.forEach((value, key) => {\n parts.push(`${key}=${typeof value === 'string' ? value : '[File]'}`);\n });\n return parts.join('&');\n }\n // Blob, ArrayBuffer, ArrayBufferView, ReadableStream — skip\n return undefined;\n}\n\nfunction truncateToByteLimit(str: string, maxBytes: number): { value: string; truncated: boolean } {\n if (new Blob([str]).size <= maxBytes) {\n return { value: str, truncated: false };\n }\n // Binary search for the longest prefix whose UTF-8 byte length fits within maxBytes.\n // Cap hi at maxBytes since each UTF-8 character is at least 1 byte, so no more than\n // maxBytes characters can ever fit — this avoids large intermediate Blob allocations.\n let lo = 0;\n let hi = Math.min(str.length, maxBytes);\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (new Blob([str.slice(0, mid)]).size <= maxBytes) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n // Avoid splitting a surrogate pair: if lo landed after a high surrogate, back up one position\n if (lo > 0 && str.charCodeAt(lo - 1) >= 0xd800 && str.charCodeAt(lo - 1) <= 0xdbff) {\n lo -= 1;\n }\n return { value: str.slice(0, lo), truncated: true };\n}\n\nexport class NetworkObservers {\n private fetchObserver: (() => void) | null = null;\n private eventCallback?: NetworkEventCallback;\n private networkConfig?: NetworkConfig;\n\n start(eventCallback: NetworkEventCallback, networkConfig?: NetworkConfig) {\n this.eventCallback = eventCallback;\n this.networkConfig = networkConfig;\n this.observeFetch();\n }\n\n stop() {\n this.fetchObserver?.();\n this.fetchObserver = null;\n this.eventCallback = undefined;\n this.networkConfig = undefined;\n }\n\n protected notifyEvent(event: NetworkRequestEvent) {\n this.eventCallback?.(event);\n }\n\n private observeFetch() {\n const globalScope = getGlobalScope();\n if (!globalScope) return;\n\n const originalFetch = globalScope.fetch;\n if (!originalFetch) return;\n\n globalScope.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n const startTime = Date.now();\n const requestEvent: NetworkRequestEvent = {\n timestamp: startTime,\n type: 'fetch',\n method: init?.method || 'GET', // Fetch API defaulted to GET when no method is provided\n url: input.toString(),\n requestHeaders: init?.headers as Record<string, string>,\n };\n\n // Capture request body if configured\n const bodyConfig = this.networkConfig?.body;\n if (bodyConfig?.request) {\n const serialized = serializeRequestBody(init?.body);\n if (serialized !== undefined) {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n requestEvent.requestBody = truncateToByteLimit(serialized, maxBytes).value;\n }\n }\n\n try {\n const response = await originalFetch(input, init);\n const endTime = Date.now();\n\n requestEvent.status = response.status;\n requestEvent.duration = endTime - startTime;\n\n // Convert Headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n requestEvent.responseHeaders = headers;\n\n if (bodyConfig?.response) {\n const contentType = headers['content-type'] || null;\n if (isBinaryContentType(contentType)) {\n requestEvent.responseBodyStatus = 'skipped_binary';\n this.notifyEvent(requestEvent);\n } else {\n const cloned = response.clone();\n // Read body without blocking the response return to the caller\n cloned.text().then(\n (text) => {\n const maxBytes = bodyConfig.maxBodySizeBytes ?? DEFAULT_MAX_BODY_SIZE_BYTES;\n const { value, truncated } = truncateToByteLimit(text, maxBytes);\n requestEvent.responseBody = value;\n requestEvent.responseBodyStatus = truncated ? 'truncated' : 'captured';\n this.notifyEvent(requestEvent);\n },\n () => {\n requestEvent.responseBodyStatus = 'error';\n this.notifyEvent(requestEvent);\n },\n );\n }\n } else {\n this.notifyEvent(requestEvent);\n }\n\n return response;\n } catch (error) {\n const endTime = Date.now();\n requestEvent.duration = endTime - startTime;\n\n // Capture error information\n const typedError = error as Error;\n requestEvent.error = {\n name: typedError.name || 'UnknownError',\n message: typedError.message || 'An unknown error occurred',\n };\n\n this.notifyEvent(requestEvent);\n throw error;\n }\n };\n\n this.fetchObserver = () => {\n globalScope.fetch = originalFetch;\n };\n }\n}\n"],"names":["BINARY_CONTENT_TYPE_PREFIXES","truncateToByteLimit","str","maxBytes","Blob","size","value","truncated","lo","hi","Math","min","length","mid","ceil","slice","charCodeAt","NetworkObservers","constructor","this","fetchObserver","start","eventCallback","networkConfig","observeFetch","stop","_a","call","undefined","notifyEvent","event","globalScope","getGlobalScope","originalFetch","fetch","input","init","__awaiter","startTime","Date","now","requestEvent","timestamp","type","method","url","toString","requestHeaders","headers","bodyConfig","body","request","serialized","URLSearchParams","FormData","parts","forEach","key","push","join","serializeRequestBody","_b","maxBodySizeBytes","requestBody","response","endTime","status","duration","responseHeaders","contentType","some","prefix","toLowerCase","startsWith","isBinaryContentType","responseBodyStatus","clone","text","then","responseBody","error","typedError","name","message"],"mappings":"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"}
|