@grafana/faro-web-sdk 2.7.1 → 2.8.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/dist/bundle/faro-web-sdk.iife.js +1 -1
- package/dist/bundle/types/config/types.d.ts +1 -0
- package/dist/bundle/types/instrumentations/console/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/csp/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/errors/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/navigation/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/performance/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/session/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/userActions/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/view/instrumentation.d.ts +1 -1
- package/dist/bundle/types/instrumentations/webVitals/instrumentation.d.ts +1 -1
- package/dist/bundle/types/transports/console/transport.d.ts +1 -1
- package/dist/bundle/types/transports/fetch/transport.d.ts +3 -1
- package/dist/bundle/types/transports/fetch/types.d.ts +1 -0
- package/dist/cjs/config/makeCoreConfig.js +1 -0
- package/dist/cjs/config/makeCoreConfig.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/instrumentations/performance/performanceUtils.js +4 -1
- package/dist/cjs/instrumentations/performance/performanceUtils.js.map +1 -1
- package/dist/cjs/transports/fetch/transport.js +42 -6
- package/dist/cjs/transports/fetch/transport.js.map +1 -1
- package/dist/cjs/transports/fetch/types.js.map +1 -1
- package/dist/esm/config/makeCoreConfig.js +1 -0
- package/dist/esm/config/makeCoreConfig.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/instrumentations/performance/performanceUtils.js +4 -1
- package/dist/esm/instrumentations/performance/performanceUtils.js.map +1 -1
- package/dist/esm/transports/fetch/transport.js +42 -6
- package/dist/esm/transports/fetch/transport.js.map +1 -1
- package/dist/esm/transports/fetch/types.js.map +1 -1
- package/dist/types/config/types.d.ts +1 -0
- package/dist/types/instrumentations/console/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/csp/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/errors/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/navigation/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/performance/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/session/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/userActions/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/view/instrumentation.d.ts +1 -1
- package/dist/types/instrumentations/webVitals/instrumentation.d.ts +1 -1
- package/dist/types/transports/console/transport.d.ts +1 -1
- package/dist/types/transports/fetch/transport.d.ts +3 -1
- package/dist/types/transports/fetch/types.d.ts +1 -0
- package/package.json +5 -5
|
@@ -4,7 +4,7 @@ import type { ConsoleTransportOptions } from './types';
|
|
|
4
4
|
export declare class ConsoleTransport extends BaseTransport {
|
|
5
5
|
private options;
|
|
6
6
|
readonly name = "@grafana/faro-web-sdk:transport-console";
|
|
7
|
-
readonly version = "2.
|
|
7
|
+
readonly version = "2.8.0";
|
|
8
8
|
constructor(options?: ConsoleTransportOptions);
|
|
9
9
|
send(item: TransportItem): void;
|
|
10
10
|
}
|
|
@@ -4,15 +4,17 @@ import type { FetchTransportOptions } from './types';
|
|
|
4
4
|
export declare class FetchTransport extends BaseTransport {
|
|
5
5
|
private options;
|
|
6
6
|
readonly name = "@grafana/faro-web-sdk:transport-fetch";
|
|
7
|
-
readonly version = "2.
|
|
7
|
+
readonly version = "2.8.0";
|
|
8
8
|
promiseBuffer: PromiseBuffer<Response | void>;
|
|
9
9
|
private readonly rateLimitBackoffMs;
|
|
10
10
|
private readonly getNow;
|
|
11
|
+
private readonly compressionEnabled;
|
|
11
12
|
private disabledUntil;
|
|
12
13
|
constructor(options: FetchTransportOptions);
|
|
13
14
|
send(items: TransportItem[]): Promise<void>;
|
|
14
15
|
getIgnoreUrls(): Patterns;
|
|
15
16
|
isBatched(): boolean;
|
|
16
17
|
private getRetryAfterDate;
|
|
18
|
+
private compress;
|
|
17
19
|
private extendFaroSession;
|
|
18
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeCoreConfig.js","sourceRoot":"","sources":["../../../src/config/makeCoreConfig.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAyBA,
|
|
1
|
+
{"version":3,"file":"makeCoreConfig.js","sourceRoot":"","sources":["../../../src/config/makeCoreConfig.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createInternalLogger,\n defaultBatchingConfig,\n defaultGlobalObjectKey,\n defaultInternalLoggerLevel,\n defaultLogArgsSerializer,\n defaultUnpatchedConsole,\n isBoolean,\n isEmpty,\n isObject,\n} from '@grafana/faro-core';\nimport type { Config, Instrumentation, MetaItem, MetaSession, Transport } from '@grafana/faro-core';\n\nimport { defaultEventDomain } from '../consts';\nimport { parseStacktrace } from '../instrumentations';\nimport { defaultSessionTrackingConfig } from '../instrumentations/session';\nimport { userActionDataAttribute } from '../instrumentations/userActions/const';\nimport { browserMeta, osMeta, sdkMeta } from '../metas';\nimport { k6Meta } from '../metas/k6';\nimport { createPageMeta } from '../metas/page';\nimport { FetchTransport } from '../transports';\n\nimport { getWebInstrumentations } from './getWebInstrumentations';\nimport type { BrowserConfig } from './types';\n\nexport function makeCoreConfig(browserConfig: BrowserConfig): Config {\n const transports: Transport[] = [];\n\n const internalLogger = createInternalLogger(browserConfig.unpatchedConsole, browserConfig.internalLoggerLevel);\n\n if (browserConfig.transports) {\n if (browserConfig.url || browserConfig.apiKey) {\n internalLogger.error('if \"transports\" is defined, \"url\" and \"apiKey\" should not be defined');\n }\n\n transports.push(...browserConfig.transports);\n } else if (browserConfig.url) {\n transports.push(\n new FetchTransport({\n url: browserConfig.url,\n apiKey: browserConfig.apiKey,\n requestCompression: browserConfig.requestCompression,\n })\n );\n } else {\n internalLogger.error('either \"url\" or \"transports\" must be defined');\n }\n\n const {\n // properties with default values\n dedupe = true,\n eventDomain = defaultEventDomain,\n globalObjectKey = defaultGlobalObjectKey,\n instrumentations = getWebInstrumentations(),\n internalLoggerLevel = defaultInternalLoggerLevel,\n isolate = false,\n logArgsSerializer = defaultLogArgsSerializer,\n metas = createDefaultMetas(browserConfig),\n paused = false,\n preventGlobalExposure = false,\n unpatchedConsole = defaultUnpatchedConsole,\n url: browserConfigUrl,\n experimental,\n // Properties without default values or which aren't used to create derived config\n ...restProperties\n }: BrowserConfig = browserConfig;\n\n // Extract experimental features with defaults\n const trackNavigation = experimental?.trackNavigation ?? false;\n\n // Extract user actions instrumentation with defaults\n const userActionsInstrumentation = {\n dataAttributeName: browserConfig.userActionsInstrumentation?.dataAttributeName ?? userActionDataAttribute,\n excludeItem: browserConfig.userActionsInstrumentation?.excludeItem,\n };\n\n return {\n ...restProperties,\n\n batching: {\n ...defaultBatchingConfig,\n ...browserConfig.batching,\n },\n dedupe: dedupe,\n globalObjectKey,\n instrumentations: getFilteredInstrumentations(instrumentations, browserConfig),\n internalLoggerLevel,\n isolate,\n logArgsSerializer,\n metas,\n parseStacktrace,\n paused,\n preventGlobalExposure,\n transports,\n unpatchedConsole,\n eventDomain,\n ignoreUrls: [\n ...(browserConfig.ignoreUrls ?? []),\n // ignore configured cloud collector url by default\n ...(browserConfigUrl ? [browserConfigUrl] : []),\n // Try our best to exclude collector URLs form other Faro instances. By default these are URLs ending with /collect or /collect/ followed by alphanumeric characters.\n /\\/collect(?:\\/[\\w]*)?$/,\n ],\n sessionTracking: {\n ...defaultSessionTrackingConfig,\n ...browserConfig.sessionTracking,\n ...crateSessionMeta({\n trackGeolocation: browserConfig.trackGeolocation,\n sessionTracking: browserConfig.sessionTracking,\n }),\n },\n userActionsInstrumentation,\n experimental: {\n trackNavigation,\n },\n };\n}\n\nfunction getFilteredInstrumentations(\n instrumentations: Instrumentation[],\n { experimental }: BrowserConfig\n): Instrumentation[] {\n const trackNavigation = experimental?.trackNavigation ?? false;\n\n return instrumentations.filter((instr) => {\n if (instr.name === '@grafana/faro-web-sdk:instrumentation-navigation' && !trackNavigation) {\n return false;\n }\n return true;\n });\n}\n\nfunction createDefaultMetas(browserConfig: BrowserConfig): MetaItem[] {\n const { page, generatePageId } = browserConfig?.pageTracking ?? {};\n\n const initialMetas: MetaItem[] = [\n browserMeta,\n osMeta,\n createPageMeta({ generatePageId, initialPageMeta: page }),\n ...(browserConfig.metas ?? []),\n sdkMeta,\n ];\n\n const isK6BrowserSession = isObject((window as any)?.k6);\n if (isK6BrowserSession) {\n return [...initialMetas, k6Meta];\n }\n\n return initialMetas;\n}\n\nfunction crateSessionMeta({\n trackGeolocation,\n sessionTracking,\n}: Pick<BrowserConfig, 'trackGeolocation' | 'sessionTracking'>): { session: MetaSession } | {} {\n const overrides: MetaSession['overrides'] = {};\n\n if (isBoolean(trackGeolocation)) {\n overrides.geoLocationTrackingEnabled = trackGeolocation;\n }\n\n if (isEmpty(overrides)) {\n return {};\n }\n\n return {\n session: {\n ...(sessionTracking?.session ?? {}),\n overrides,\n },\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Config } from '@grafana/faro-core';\n\nexport interface BrowserConfig extends Partial<Omit<Config, 'app' | 'parseStacktrace'>>, Pick<Config, 'app'> {\n url?: string;\n apiKey?: string;\n}\n\nexport interface GetWebInstrumentationsOptions {\n captureConsole?: boolean;\n enablePerformanceInstrumentation?: boolean;\n enableContentSecurityPolicyInstrumentation?: boolean;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Config } from '@grafana/faro-core';\n\nexport interface BrowserConfig extends Partial<Omit<Config, 'app' | 'parseStacktrace'>>, Pick<Config, 'app'> {\n url?: string;\n apiKey?: string;\n requestCompression?: boolean;\n}\n\nexport interface GetWebInstrumentationsOptions {\n captureConsole?: boolean;\n enablePerformanceInstrumentation?: boolean;\n enableContentSecurityPolicyInstrumentation?: boolean;\n}\n"]}
|
|
@@ -71,7 +71,10 @@ function createFaroResourceTiming(resourceEntryRaw) {
|
|
|
71
71
|
requestTime: toFaroPerformanceTimingString(responseStart - requestStart),
|
|
72
72
|
responseTime: toFaroPerformanceTimingString(responseEnd - responseStart),
|
|
73
73
|
fetchTime: toFaroPerformanceTimingString(responseEnd - fetchStart),
|
|
74
|
-
|
|
74
|
+
// workerStart is 0 when the request is not intercepted by a service worker (W3C Resource Timing spec).
|
|
75
|
+
// fetchStart is a timeOrigin-relative timestamp, not a duration, so guard against reporting it as the
|
|
76
|
+
// service worker time when no service worker handled the request.
|
|
77
|
+
serviceWorkerTime: toFaroPerformanceTimingString(workerStart > 0 ? fetchStart - workerStart : 0),
|
|
75
78
|
decodedBodySize: toFaroPerformanceTimingString(decodedBodySize),
|
|
76
79
|
encodedBodySize: toFaroPerformanceTimingString(encodedBodySize),
|
|
77
80
|
cacheHitStatus: getCacheType(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"performanceUtils.js","sourceRoot":"","sources":["../../../../src/instrumentations/performance/performanceUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { isArray, type PushEventOptions, unknownString } from '@grafana/faro-core';\n\nimport type { CacheType, FaroNavigationTiming, FaroResourceTiming } from './types';\n\nconst w3cTraceparentFormat = /^00-[a-f0-9]{32}-[a-f0-9]{16}-[0-9]{1,2}$/;\n\ntype SpanContext = PushEventOptions['spanContext'];\n\n// Extract traceparent from serverTiming, if present\nexport function getSpanContextFromServerTiming(serverTimings: PerformanceServerTiming[] = []): SpanContext | undefined {\n for (const serverEntry of serverTimings) {\n if (serverEntry.name === 'traceparent') {\n if (!w3cTraceparentFormat.test(serverEntry.description)) {\n continue;\n }\n\n const [, traceId, spanId] = serverEntry.description.split('-');\n if (traceId != null && spanId != null) {\n return { traceId, spanId };\n }\n\n break;\n }\n }\n\n return undefined;\n}\n\nexport function performanceObserverSupported(): boolean {\n return 'PerformanceObserver' in window;\n}\n\nexport function onDocumentReady(handleReady: () => void) {\n if (document.readyState === 'complete') {\n handleReady();\n } else {\n const readyStateCompleteHandler = () => {\n if (document.readyState === 'complete') {\n handleReady();\n document.removeEventListener('readystatechange', readyStateCompleteHandler);\n }\n };\n\n document.addEventListener('readystatechange', readyStateCompleteHandler);\n }\n}\n\ntype PerformanceEntryAllowProperties = Record<string, Array<string | number> | string | number>;\n\nexport function includePerformanceEntry(\n performanceEntryJSON: Record<string, any>,\n allowProps: PerformanceEntryAllowProperties = {}\n): boolean {\n for (const [allowPropKey, allowPropValue] of Object.entries(allowProps)) {\n const perfEntryPropVal = performanceEntryJSON[allowPropKey];\n\n if (perfEntryPropVal == null) {\n return false;\n }\n\n if (isArray(allowPropValue)) {\n return allowPropValue.includes(perfEntryPropVal);\n }\n\n return perfEntryPropVal === allowPropValue;\n }\n\n // empty object allows all\n return true;\n}\n\nexport function createFaroResourceTiming(resourceEntryRaw: PerformanceResourceTiming): FaroResourceTiming {\n const {\n connectEnd,\n connectStart,\n decodedBodySize,\n domainLookupEnd,\n domainLookupStart,\n duration,\n encodedBodySize,\n fetchStart,\n initiatorType,\n name,\n nextHopProtocol,\n redirectEnd,\n redirectStart,\n // @ts-expect-error the renderBlockingStatus property is not available in all browsers\n renderBlockingStatus: rbs,\n requestStart,\n responseEnd,\n responseStart,\n responseStatus,\n secureConnectionStart,\n transferSize,\n workerStart,\n } = resourceEntryRaw;\n\n return {\n name: name,\n httpHost: getHostFromUrl(name),\n duration: toFaroPerformanceTimingString(duration),\n tcpHandshakeTime: toFaroPerformanceTimingString(connectEnd - connectStart),\n dnsLookupTime: toFaroPerformanceTimingString(domainLookupEnd - domainLookupStart),\n tlsNegotiationTime: toFaroPerformanceTimingString(connectEnd - secureConnectionStart),\n responseStatus: toFaroPerformanceTimingString(responseStatus),\n redirectTime: toFaroPerformanceTimingString(redirectEnd - redirectStart),\n requestTime: toFaroPerformanceTimingString(responseStart - requestStart),\n responseTime: toFaroPerformanceTimingString(responseEnd - responseStart),\n fetchTime: toFaroPerformanceTimingString(responseEnd - fetchStart),\n serviceWorkerTime: toFaroPerformanceTimingString(fetchStart - workerStart),\n decodedBodySize: toFaroPerformanceTimingString(decodedBodySize),\n encodedBodySize: toFaroPerformanceTimingString(encodedBodySize),\n cacheHitStatus: getCacheType(),\n renderBlockingStatus: toFaroPerformanceTimingString(rbs) as FaroResourceTiming['renderBlockingStatus'],\n protocol: nextHopProtocol,\n initiatorType: initiatorType,\n visibilityState: document.visibilityState,\n ttfb: toFaroPerformanceTimingString(responseStart - requestStart),\n transferSize: toFaroPerformanceTimingString(transferSize),\n\n // TODO: add in future iteration, ideally after nested objects are supported by the collector.\n // serverTiming: resourceEntryRaw.serverTiming,\n };\n\n function getCacheType(): CacheType {\n let cacheType: CacheType = 'fullLoad';\n if (transferSize === 0) {\n if (decodedBodySize > 0) {\n cacheType = 'cache';\n }\n } else {\n if (responseStatus != null) {\n if (responseStatus === 304) {\n cacheType = 'conditionalFetch';\n }\n } else if (encodedBodySize > 0 && transferSize < encodedBodySize) {\n cacheType = 'conditionalFetch';\n }\n }\n return cacheType;\n }\n}\n\nexport function createFaroNavigationTiming(navigationEntryRaw: PerformanceNavigationTiming): FaroNavigationTiming {\n const {\n activationStart,\n domComplete,\n domContentLoadedEventEnd,\n domContentLoadedEventStart,\n domInteractive,\n fetchStart,\n loadEventEnd,\n loadEventStart,\n responseStart,\n type,\n } = navigationEntryRaw;\n\n const parserStart = getDocumentParsingTime();\n\n return {\n ...createFaroResourceTiming(navigationEntryRaw),\n pageLoadTime: toFaroPerformanceTimingString(domComplete - fetchStart),\n documentParsingTime: toFaroPerformanceTimingString(parserStart ? domInteractive - parserStart : null),\n domProcessingTime: toFaroPerformanceTimingString(domComplete - domInteractive),\n domContentLoadHandlerTime: toFaroPerformanceTimingString(domContentLoadedEventEnd - domContentLoadedEventStart),\n onLoadTime: toFaroPerformanceTimingString(loadEventEnd - loadEventStart),\n\n // For navigation entries we can calculate the TTFB based on activationStart. We overwrite the TTFB value coming with the resource entry.\n // For more accuracy on prerendered pages page we calculate relative top the activationStart instead of the start of the navigation.\n // clamp to 0 if activationStart occurs after first byte is received.\n ttfb: toFaroPerformanceTimingString(Math.max(responseStart - (activationStart ?? 0), 0)),\n type: type,\n };\n}\n\nfunction getDocumentParsingTime(): number | null {\n if (performance.timing?.domLoading != null) {\n // the browser is about to start parsing the first received bytes of the HTML document.\n // This property is deprecated but there isn't a really good alternative atm.\n // For now we stick with domLoading and keep researching a better alternative.\n return performance.timing.domLoading - performance.timeOrigin;\n }\n\n return null;\n}\n\nfunction getHostFromUrl(url: string): string {\n try {\n return new URL(url).host || unknownString;\n } catch {\n return unknownString;\n }\n}\n\nfunction toFaroPerformanceTimingString(v: unknown): string {\n if (v == null) {\n return unknownString;\n }\n\n if (typeof v === 'number') {\n return Math.round(v > 0 ? v : 0).toString();\n }\n\n return v.toString();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"performanceUtils.js","sourceRoot":"","sources":["../../../../src/instrumentations/performance/performanceUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { isArray, type PushEventOptions, unknownString } from '@grafana/faro-core';\n\nimport type { CacheType, FaroNavigationTiming, FaroResourceTiming } from './types';\n\nconst w3cTraceparentFormat = /^00-[a-f0-9]{32}-[a-f0-9]{16}-[0-9]{1,2}$/;\n\ntype SpanContext = PushEventOptions['spanContext'];\n\n// Extract traceparent from serverTiming, if present\nexport function getSpanContextFromServerTiming(serverTimings: PerformanceServerTiming[] = []): SpanContext | undefined {\n for (const serverEntry of serverTimings) {\n if (serverEntry.name === 'traceparent') {\n if (!w3cTraceparentFormat.test(serverEntry.description)) {\n continue;\n }\n\n const [, traceId, spanId] = serverEntry.description.split('-');\n if (traceId != null && spanId != null) {\n return { traceId, spanId };\n }\n\n break;\n }\n }\n\n return undefined;\n}\n\nexport function performanceObserverSupported(): boolean {\n return 'PerformanceObserver' in window;\n}\n\nexport function onDocumentReady(handleReady: () => void) {\n if (document.readyState === 'complete') {\n handleReady();\n } else {\n const readyStateCompleteHandler = () => {\n if (document.readyState === 'complete') {\n handleReady();\n document.removeEventListener('readystatechange', readyStateCompleteHandler);\n }\n };\n\n document.addEventListener('readystatechange', readyStateCompleteHandler);\n }\n}\n\ntype PerformanceEntryAllowProperties = Record<string, Array<string | number> | string | number>;\n\nexport function includePerformanceEntry(\n performanceEntryJSON: Record<string, any>,\n allowProps: PerformanceEntryAllowProperties = {}\n): boolean {\n for (const [allowPropKey, allowPropValue] of Object.entries(allowProps)) {\n const perfEntryPropVal = performanceEntryJSON[allowPropKey];\n\n if (perfEntryPropVal == null) {\n return false;\n }\n\n if (isArray(allowPropValue)) {\n return allowPropValue.includes(perfEntryPropVal);\n }\n\n return perfEntryPropVal === allowPropValue;\n }\n\n // empty object allows all\n return true;\n}\n\nexport function createFaroResourceTiming(resourceEntryRaw: PerformanceResourceTiming): FaroResourceTiming {\n const {\n connectEnd,\n connectStart,\n decodedBodySize,\n domainLookupEnd,\n domainLookupStart,\n duration,\n encodedBodySize,\n fetchStart,\n initiatorType,\n name,\n nextHopProtocol,\n redirectEnd,\n redirectStart,\n // @ts-expect-error the renderBlockingStatus property is not available in all browsers\n renderBlockingStatus: rbs,\n requestStart,\n responseEnd,\n responseStart,\n responseStatus,\n secureConnectionStart,\n transferSize,\n workerStart,\n } = resourceEntryRaw;\n\n return {\n name: name,\n httpHost: getHostFromUrl(name),\n duration: toFaroPerformanceTimingString(duration),\n tcpHandshakeTime: toFaroPerformanceTimingString(connectEnd - connectStart),\n dnsLookupTime: toFaroPerformanceTimingString(domainLookupEnd - domainLookupStart),\n tlsNegotiationTime: toFaroPerformanceTimingString(connectEnd - secureConnectionStart),\n responseStatus: toFaroPerformanceTimingString(responseStatus),\n redirectTime: toFaroPerformanceTimingString(redirectEnd - redirectStart),\n requestTime: toFaroPerformanceTimingString(responseStart - requestStart),\n responseTime: toFaroPerformanceTimingString(responseEnd - responseStart),\n fetchTime: toFaroPerformanceTimingString(responseEnd - fetchStart),\n // workerStart is 0 when the request is not intercepted by a service worker (W3C Resource Timing spec).\n // fetchStart is a timeOrigin-relative timestamp, not a duration, so guard against reporting it as the\n // service worker time when no service worker handled the request.\n serviceWorkerTime: toFaroPerformanceTimingString(workerStart > 0 ? fetchStart - workerStart : 0),\n decodedBodySize: toFaroPerformanceTimingString(decodedBodySize),\n encodedBodySize: toFaroPerformanceTimingString(encodedBodySize),\n cacheHitStatus: getCacheType(),\n renderBlockingStatus: toFaroPerformanceTimingString(rbs) as FaroResourceTiming['renderBlockingStatus'],\n protocol: nextHopProtocol,\n initiatorType: initiatorType,\n visibilityState: document.visibilityState,\n ttfb: toFaroPerformanceTimingString(responseStart - requestStart),\n transferSize: toFaroPerformanceTimingString(transferSize),\n\n // TODO: add in future iteration, ideally after nested objects are supported by the collector.\n // serverTiming: resourceEntryRaw.serverTiming,\n };\n\n function getCacheType(): CacheType {\n let cacheType: CacheType = 'fullLoad';\n if (transferSize === 0) {\n if (decodedBodySize > 0) {\n cacheType = 'cache';\n }\n } else {\n if (responseStatus != null) {\n if (responseStatus === 304) {\n cacheType = 'conditionalFetch';\n }\n } else if (encodedBodySize > 0 && transferSize < encodedBodySize) {\n cacheType = 'conditionalFetch';\n }\n }\n return cacheType;\n }\n}\n\nexport function createFaroNavigationTiming(navigationEntryRaw: PerformanceNavigationTiming): FaroNavigationTiming {\n const {\n activationStart,\n domComplete,\n domContentLoadedEventEnd,\n domContentLoadedEventStart,\n domInteractive,\n fetchStart,\n loadEventEnd,\n loadEventStart,\n responseStart,\n type,\n } = navigationEntryRaw;\n\n const parserStart = getDocumentParsingTime();\n\n return {\n ...createFaroResourceTiming(navigationEntryRaw),\n pageLoadTime: toFaroPerformanceTimingString(domComplete - fetchStart),\n documentParsingTime: toFaroPerformanceTimingString(parserStart ? domInteractive - parserStart : null),\n domProcessingTime: toFaroPerformanceTimingString(domComplete - domInteractive),\n domContentLoadHandlerTime: toFaroPerformanceTimingString(domContentLoadedEventEnd - domContentLoadedEventStart),\n onLoadTime: toFaroPerformanceTimingString(loadEventEnd - loadEventStart),\n\n // For navigation entries we can calculate the TTFB based on activationStart. We overwrite the TTFB value coming with the resource entry.\n // For more accuracy on prerendered pages page we calculate relative top the activationStart instead of the start of the navigation.\n // clamp to 0 if activationStart occurs after first byte is received.\n ttfb: toFaroPerformanceTimingString(Math.max(responseStart - (activationStart ?? 0), 0)),\n type: type,\n };\n}\n\nfunction getDocumentParsingTime(): number | null {\n if (performance.timing?.domLoading != null) {\n // the browser is about to start parsing the first received bytes of the HTML document.\n // This property is deprecated but there isn't a really good alternative atm.\n // For now we stick with domLoading and keep researching a better alternative.\n return performance.timing.domLoading - performance.timeOrigin;\n }\n\n return null;\n}\n\nfunction getHostFromUrl(url: string): string {\n try {\n return new URL(url).host || unknownString;\n } catch {\n return unknownString;\n }\n}\n\nfunction toFaroPerformanceTimingString(v: unknown): string {\n if (v == null) {\n return unknownString;\n }\n\n if (typeof v === 'number') {\n return Math.round(v > 0 ? v : 0).toString();\n }\n\n return v.toString();\n}\n"]}
|
|
@@ -32,7 +32,7 @@ const TOO_MANY_REQUESTS = 429;
|
|
|
32
32
|
const ACCEPTED = 202;
|
|
33
33
|
class FetchTransport extends faro_core_1.BaseTransport {
|
|
34
34
|
constructor(options) {
|
|
35
|
-
var _a, _b, _c, _d;
|
|
35
|
+
var _a, _b, _c, _d, _e;
|
|
36
36
|
super();
|
|
37
37
|
this.options = options;
|
|
38
38
|
this.name = '@grafana/faro-web-sdk:transport-fetch';
|
|
@@ -40,9 +40,17 @@ class FetchTransport extends faro_core_1.BaseTransport {
|
|
|
40
40
|
this.disabledUntil = new Date(0);
|
|
41
41
|
this.rateLimitBackoffMs = (_a = options.defaultRateLimitBackoffMs) !== null && _a !== void 0 ? _a : DEFAULT_RATE_LIMIT_BACKOFF_MS;
|
|
42
42
|
this.getNow = (_b = options.getNow) !== null && _b !== void 0 ? _b : (() => Date.now());
|
|
43
|
+
const requestCompression = (_c = options.requestCompression) !== null && _c !== void 0 ? _c : false;
|
|
44
|
+
if (requestCompression && typeof CompressionStream === 'undefined') {
|
|
45
|
+
this.compressionEnabled = false;
|
|
46
|
+
this.logWarn('requestCompression is enabled but CompressionStream is not available. Falling back to uncompressed.');
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.compressionEnabled = requestCompression;
|
|
50
|
+
}
|
|
43
51
|
this.promiseBuffer = (0, faro_core_1.createPromiseBuffer)({
|
|
44
|
-
size: (
|
|
45
|
-
concurrency: (
|
|
52
|
+
size: (_d = options.bufferSize) !== null && _d !== void 0 ? _d : DEFAULT_BUFFER_SIZE,
|
|
53
|
+
concurrency: (_e = options.concurrency) !== null && _e !== void 0 ? _e : DEFAULT_CONCURRENCY,
|
|
46
54
|
});
|
|
47
55
|
}
|
|
48
56
|
send(items) {
|
|
@@ -53,7 +61,7 @@ class FetchTransport extends faro_core_1.BaseTransport {
|
|
|
53
61
|
return Promise.resolve();
|
|
54
62
|
}
|
|
55
63
|
yield this.promiseBuffer.add(() => __awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
const
|
|
64
|
+
const jsonBody = JSON.stringify((0, faro_core_1.getTransportBody)(items));
|
|
57
65
|
const { url, requestOptions, apiKey } = this.options;
|
|
58
66
|
const _a = requestOptions !== null && requestOptions !== void 0 ? requestOptions : {}, { headers = {} } = _a, restOfRequestOptions = __rest(_a, ["headers"]);
|
|
59
67
|
let sessionId;
|
|
@@ -65,7 +73,15 @@ class FetchTransport extends faro_core_1.BaseTransport {
|
|
|
65
73
|
for (const [key, value] of Object.entries(headers)) {
|
|
66
74
|
resolvedHeaders[key] = typeof value === 'function' ? yield Promise.resolve(value()) : value;
|
|
67
75
|
}
|
|
68
|
-
|
|
76
|
+
let body = jsonBody;
|
|
77
|
+
let bodySize = jsonBody.length;
|
|
78
|
+
const compressionHeaders = {};
|
|
79
|
+
if (this.compressionEnabled) {
|
|
80
|
+
body = yield this.compress(jsonBody);
|
|
81
|
+
bodySize = body.size;
|
|
82
|
+
compressionHeaders['Content-Encoding'] = 'gzip';
|
|
83
|
+
}
|
|
84
|
+
return fetch(url, Object.assign({ method: 'POST', headers: Object.assign(Object.assign(Object.assign(Object.assign({ 'Content-Type': 'application/json' }, compressionHeaders), resolvedHeaders), (apiKey ? { 'x-api-key': apiKey } : {})), (sessionId ? { 'x-faro-session-id': sessionId } : {})), body, keepalive: bodySize <= BEACON_BODY_SIZE_LIMIT }, (restOfRequestOptions !== null && restOfRequestOptions !== void 0 ? restOfRequestOptions : {})))
|
|
69
85
|
.then((response) => __awaiter(this, void 0, void 0, function* () {
|
|
70
86
|
if (response.status === ACCEPTED) {
|
|
71
87
|
const sessionExpired = response.headers.get('X-Faro-Session-Status') === 'invalid';
|
|
@@ -82,7 +98,7 @@ class FetchTransport extends faro_core_1.BaseTransport {
|
|
|
82
98
|
return response;
|
|
83
99
|
}))
|
|
84
100
|
.catch((err) => {
|
|
85
|
-
this.logError('Failed sending payload to the receiver\n', JSON.parse(
|
|
101
|
+
this.logError('Failed sending payload to the receiver\n', JSON.parse(jsonBody), err);
|
|
86
102
|
});
|
|
87
103
|
}));
|
|
88
104
|
}
|
|
@@ -113,6 +129,26 @@ class FetchTransport extends faro_core_1.BaseTransport {
|
|
|
113
129
|
}
|
|
114
130
|
return new Date(now + this.rateLimitBackoffMs);
|
|
115
131
|
}
|
|
132
|
+
compress(body) {
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
const stream = new ReadableStream({
|
|
135
|
+
start(controller) {
|
|
136
|
+
controller.enqueue(new TextEncoder().encode(body));
|
|
137
|
+
controller.close();
|
|
138
|
+
},
|
|
139
|
+
}).pipeThrough(new CompressionStream('gzip'));
|
|
140
|
+
const reader = stream.getReader();
|
|
141
|
+
const chunks = [];
|
|
142
|
+
for (;;) {
|
|
143
|
+
const { done, value } = yield reader.read();
|
|
144
|
+
if (done) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
chunks.push(value);
|
|
148
|
+
}
|
|
149
|
+
return new Blob(chunks);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
116
152
|
extendFaroSession(config, logDebug) {
|
|
117
153
|
const SessionExpiredString = `Session expired`;
|
|
118
154
|
const sessionTrackingConfig = config.sessionTracking;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/fetch/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseExtension, BaseTransport, createPromiseBuffer, getTransportBody, noop, VERSION } from '@grafana/faro-core';\nimport type { Config, Patterns, PromiseBuffer, TransportItem } from '@grafana/faro-core';\n\nimport { getSessionManagerByConfig } from '../../instrumentations/session/sessionManager';\nimport { getUserSessionUpdater } from '../../instrumentations/session/sessionManager/sessionManagerUtils';\n\nimport type { FetchTransportOptions } from './types';\n\nconst DEFAULT_BUFFER_SIZE = 30;\nconst DEFAULT_CONCURRENCY = 5; // chrome supports 10 total, firefox 17\nconst DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;\n\nconst BEACON_BODY_SIZE_LIMIT = 60000;\nconst TOO_MANY_REQUESTS = 429;\nconst ACCEPTED = 202;\n\nexport class FetchTransport extends BaseTransport {\n readonly name = '@grafana/faro-web-sdk:transport-fetch';\n readonly version = VERSION;\n\n promiseBuffer: PromiseBuffer<Response | void>;\n\n private readonly rateLimitBackoffMs: number;\n private readonly getNow: () => number;\n private disabledUntil: Date = new Date(0);\n\n constructor(private options: FetchTransportOptions) {\n super();\n\n this.rateLimitBackoffMs = options.defaultRateLimitBackoffMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS;\n this.getNow = options.getNow ?? (() => Date.now());\n\n this.promiseBuffer = createPromiseBuffer({\n size: options.bufferSize ?? DEFAULT_BUFFER_SIZE,\n concurrency: options.concurrency ?? DEFAULT_CONCURRENCY,\n });\n }\n\n async send(items: TransportItem[]): Promise<void> {\n try {\n if (this.disabledUntil > new Date(this.getNow())) {\n this.logWarn(`Dropping transport item due to too many requests. Backoff until ${this.disabledUntil}`);\n\n return Promise.resolve();\n }\n\n await this.promiseBuffer.add(async () => {\n const body = JSON.stringify(getTransportBody(items));\n\n const { url, requestOptions, apiKey } = this.options;\n\n const { headers = {}, ...restOfRequestOptions } = requestOptions ?? {};\n\n let sessionId;\n const sessionMeta = this.metas.value.session;\n if (sessionMeta != null) {\n sessionId = sessionMeta.id;\n }\n\n const resolvedHeaders: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n resolvedHeaders[key] = typeof value === 'function' ? await Promise.resolve(value()) : value;\n }\n\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...resolvedHeaders,\n ...(apiKey ? { 'x-api-key': apiKey } : {}),\n ...(sessionId ? { 'x-faro-session-id': sessionId } : {}),\n },\n body,\n keepalive: body.length <= BEACON_BODY_SIZE_LIMIT,\n ...(restOfRequestOptions ?? {}),\n })\n .then(async (response) => {\n if (response.status === ACCEPTED) {\n const sessionExpired = response.headers.get('X-Faro-Session-Status') === 'invalid';\n\n if (sessionExpired) {\n this.extendFaroSession(this.config, this.logDebug);\n }\n }\n\n if (response.status === TOO_MANY_REQUESTS) {\n this.disabledUntil = this.getRetryAfterDate(response);\n this.logWarn(`Too many requests, backing off until ${this.disabledUntil}`);\n }\n\n // read the body so the connection can be closed\n response.text().catch(noop);\n return response;\n })\n .catch((err) => {\n this.logError('Failed sending payload to the receiver\\n', JSON.parse(body), err);\n });\n });\n } catch (err) {\n this.logError(err);\n }\n }\n\n override getIgnoreUrls(): Patterns {\n return ([this.options.url] as Patterns).concat(this.config.ignoreUrls ?? []);\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n private getRetryAfterDate(response: Response): Date {\n const now = this.getNow();\n const retryAfterHeader = response.headers.get('Retry-After');\n\n if (retryAfterHeader) {\n const delay = Number(retryAfterHeader);\n\n if (!isNaN(delay)) {\n return new Date(delay * 1000 + now);\n }\n\n const date = Date.parse(retryAfterHeader);\n\n if (!isNaN(date)) {\n return new Date(date);\n }\n }\n\n return new Date(now + this.rateLimitBackoffMs);\n }\n\n private extendFaroSession(config: Config, logDebug: BaseExtension['logDebug']) {\n const SessionExpiredString = `Session expired`;\n\n const sessionTrackingConfig = config.sessionTracking;\n\n if (sessionTrackingConfig?.enabled) {\n const { fetchUserSession, storeUserSession } = getSessionManagerByConfig(sessionTrackingConfig);\n\n getUserSessionUpdater({ fetchUserSession, storeUserSession })({ forceSessionExtend: true });\n\n logDebug(`${SessionExpiredString} created new session.`);\n } else {\n logDebug(`${SessionExpiredString}.`);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../src/transports/fetch/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseExtension, BaseTransport, createPromiseBuffer, getTransportBody, noop, VERSION } from '@grafana/faro-core';\nimport type { Config, Patterns, PromiseBuffer, TransportItem } from '@grafana/faro-core';\n\nimport { getSessionManagerByConfig } from '../../instrumentations/session/sessionManager';\nimport { getUserSessionUpdater } from '../../instrumentations/session/sessionManager/sessionManagerUtils';\n\nimport type { FetchTransportOptions } from './types';\n\nconst DEFAULT_BUFFER_SIZE = 30;\nconst DEFAULT_CONCURRENCY = 5; // chrome supports 10 total, firefox 17\nconst DEFAULT_RATE_LIMIT_BACKOFF_MS = 5000;\n\nconst BEACON_BODY_SIZE_LIMIT = 60000;\nconst TOO_MANY_REQUESTS = 429;\nconst ACCEPTED = 202;\n\nexport class FetchTransport extends BaseTransport {\n readonly name = '@grafana/faro-web-sdk:transport-fetch';\n readonly version = VERSION;\n\n promiseBuffer: PromiseBuffer<Response | void>;\n\n private readonly rateLimitBackoffMs: number;\n private readonly getNow: () => number;\n private readonly compressionEnabled: boolean;\n private disabledUntil: Date = new Date(0);\n\n constructor(private options: FetchTransportOptions) {\n super();\n\n this.rateLimitBackoffMs = options.defaultRateLimitBackoffMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS;\n this.getNow = options.getNow ?? (() => Date.now());\n\n const requestCompression = options.requestCompression ?? false;\n\n if (requestCompression && typeof CompressionStream === 'undefined') {\n this.compressionEnabled = false;\n this.logWarn(\n 'requestCompression is enabled but CompressionStream is not available. Falling back to uncompressed.'\n );\n } else {\n this.compressionEnabled = requestCompression;\n }\n\n this.promiseBuffer = createPromiseBuffer({\n size: options.bufferSize ?? DEFAULT_BUFFER_SIZE,\n concurrency: options.concurrency ?? DEFAULT_CONCURRENCY,\n });\n }\n\n async send(items: TransportItem[]): Promise<void> {\n try {\n if (this.disabledUntil > new Date(this.getNow())) {\n this.logWarn(`Dropping transport item due to too many requests. Backoff until ${this.disabledUntil}`);\n\n return Promise.resolve();\n }\n\n await this.promiseBuffer.add(async () => {\n const jsonBody = JSON.stringify(getTransportBody(items));\n\n const { url, requestOptions, apiKey } = this.options;\n\n const { headers = {}, ...restOfRequestOptions } = requestOptions ?? {};\n\n let sessionId;\n const sessionMeta = this.metas.value.session;\n if (sessionMeta != null) {\n sessionId = sessionMeta.id;\n }\n\n const resolvedHeaders: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n resolvedHeaders[key] = typeof value === 'function' ? await Promise.resolve(value()) : value;\n }\n\n let body: string | Blob = jsonBody;\n let bodySize = jsonBody.length;\n const compressionHeaders: Record<string, string> = {};\n\n if (this.compressionEnabled) {\n body = await this.compress(jsonBody);\n bodySize = body.size;\n compressionHeaders['Content-Encoding'] = 'gzip';\n }\n\n return fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...compressionHeaders,\n ...resolvedHeaders,\n ...(apiKey ? { 'x-api-key': apiKey } : {}),\n ...(sessionId ? { 'x-faro-session-id': sessionId } : {}),\n },\n body,\n keepalive: bodySize <= BEACON_BODY_SIZE_LIMIT,\n ...(restOfRequestOptions ?? {}),\n })\n .then(async (response) => {\n if (response.status === ACCEPTED) {\n const sessionExpired = response.headers.get('X-Faro-Session-Status') === 'invalid';\n\n if (sessionExpired) {\n this.extendFaroSession(this.config, this.logDebug);\n }\n }\n\n if (response.status === TOO_MANY_REQUESTS) {\n this.disabledUntil = this.getRetryAfterDate(response);\n this.logWarn(`Too many requests, backing off until ${this.disabledUntil}`);\n }\n\n // read the body so the connection can be closed\n response.text().catch(noop);\n return response;\n })\n .catch((err) => {\n this.logError('Failed sending payload to the receiver\\n', JSON.parse(jsonBody), err);\n });\n });\n } catch (err) {\n this.logError(err);\n }\n }\n\n override getIgnoreUrls(): Patterns {\n return ([this.options.url] as Patterns).concat(this.config.ignoreUrls ?? []);\n }\n\n override isBatched(): boolean {\n return true;\n }\n\n private getRetryAfterDate(response: Response): Date {\n const now = this.getNow();\n const retryAfterHeader = response.headers.get('Retry-After');\n\n if (retryAfterHeader) {\n const delay = Number(retryAfterHeader);\n\n if (!isNaN(delay)) {\n return new Date(delay * 1000 + now);\n }\n\n const date = Date.parse(retryAfterHeader);\n\n if (!isNaN(date)) {\n return new Date(date);\n }\n }\n\n return new Date(now + this.rateLimitBackoffMs);\n }\n\n private async compress(body: string): Promise<Blob> {\n const stream = new ReadableStream({\n start(controller) {\n controller.enqueue(new TextEncoder().encode(body));\n controller.close();\n },\n }).pipeThrough(new CompressionStream('gzip'));\n\n const reader = stream.getReader();\n const chunks: BlobPart[] = [];\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n chunks.push(value);\n }\n return new Blob(chunks);\n }\n\n private extendFaroSession(config: Config, logDebug: BaseExtension['logDebug']) {\n const SessionExpiredString = `Session expired`;\n\n const sessionTrackingConfig = config.sessionTracking;\n\n if (sessionTrackingConfig?.enabled) {\n const { fetchUserSession, storeUserSession } = getSessionManagerByConfig(sessionTrackingConfig);\n\n getUserSessionUpdater({ fetchUserSession, storeUserSession })({ forceSessionExtend: true });\n\n logDebug(`${SessionExpiredString} created new session.`);\n } else {\n logDebug(`${SessionExpiredString}.`);\n }\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/transports/fetch/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface FetchTransportRequestOptions extends Omit<RequestInit, 'body' | 'headers'> {\n /**\n * Headers to include in every request.\n * Each value can be:\n * - a string (static value)\n * - a function returning a string (dynamic value, sync)\n * - a function returning a Promise of string (dynamic value, async)\n */\n headers?: Record<string, string | (() => string | Promise<string>)>;\n}\n\nexport interface FetchTransportOptions {\n // url of the collector endpoint\n url: string;\n\n // will be added as `x-api-key` header\n apiKey?: string;\n // how many requests to buffer in total\n bufferSize?: number;\n // how many requests to execute concurrently\n concurrency?: number;\n // if rate limit response does not include a Retry-After header,\n // how many milliseconds to back off before attempting a request.\n // intermediate events will be dropped, not buffered\n defaultRateLimitBackoffMs?: number;\n // get current date. for mocking purposes in tests\n getNow?: ClockFn;\n // addition options for global.Fetch\n requestOptions?: FetchTransportRequestOptions;\n}\n\nexport type ClockFn = () => number;\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/transports/fetch/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface FetchTransportRequestOptions extends Omit<RequestInit, 'body' | 'headers'> {\n /**\n * Headers to include in every request.\n * Each value can be:\n * - a string (static value)\n * - a function returning a string (dynamic value, sync)\n * - a function returning a Promise of string (dynamic value, async)\n */\n headers?: Record<string, string | (() => string | Promise<string>)>;\n}\n\nexport interface FetchTransportOptions {\n // url of the collector endpoint\n url: string;\n\n // will be added as `x-api-key` header\n apiKey?: string;\n // how many requests to buffer in total\n bufferSize?: number;\n // how many requests to execute concurrently\n concurrency?: number;\n // if rate limit response does not include a Retry-After header,\n // how many milliseconds to back off before attempting a request.\n // intermediate events will be dropped, not buffered\n defaultRateLimitBackoffMs?: number;\n // get current date. for mocking purposes in tests\n getNow?: ClockFn;\n // addition options for global.Fetch\n requestOptions?: FetchTransportRequestOptions;\n // compress request bodies with gzip using the native CompressionStream API.\n // falls back to uncompressed if CompressionStream is not available.\n requestCompression?: boolean;\n}\n\nexport type ClockFn = () => number;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeCoreConfig.js","sourceRoot":"","sources":["../../../src/config/makeCoreConfig.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,SAAS,EACT,OAAO,EACP,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,MAAM,UAAU,cAAc,CAAC,aAA4B;;IACzD,MAAM,UAAU,GAAgB,EAAE,CAAC;IAEnC,MAAM,cAAc,GAAG,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAE/G,IAAI,aAAa,CAAC,UAAU,EAAE,CAAC;QAC7B,IAAI,aAAa,CAAC,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;YAC9C,cAAc,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC/F,CAAC;QAED,UAAU,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;SAAM,IAAI,aAAa,CAAC,GAAG,EAAE,CAAC;QAC7B,UAAU,CAAC,IAAI,CACb,IAAI,cAAc,CAAC;YACjB,GAAG,EAAE,aAAa,CAAC,GAAG;YACtB,MAAM,EAAE,aAAa,CAAC,MAAM;
|
|
1
|
+
{"version":3,"file":"makeCoreConfig.js","sourceRoot":"","sources":["../../../src/config/makeCoreConfig.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createInternalLogger,\n defaultBatchingConfig,\n defaultGlobalObjectKey,\n defaultInternalLoggerLevel,\n defaultLogArgsSerializer,\n defaultUnpatchedConsole,\n isBoolean,\n isEmpty,\n isObject,\n} from '@grafana/faro-core';\nimport type { Config, Instrumentation, MetaItem, MetaSession, Transport } from '@grafana/faro-core';\n\nimport { defaultEventDomain } from '../consts';\nimport { parseStacktrace } from '../instrumentations';\nimport { defaultSessionTrackingConfig } from '../instrumentations/session';\nimport { userActionDataAttribute } from '../instrumentations/userActions/const';\nimport { browserMeta, osMeta, sdkMeta } from '../metas';\nimport { k6Meta } from '../metas/k6';\nimport { createPageMeta } from '../metas/page';\nimport { FetchTransport } from '../transports';\n\nimport { getWebInstrumentations } from './getWebInstrumentations';\nimport type { BrowserConfig } from './types';\n\nexport function makeCoreConfig(browserConfig: BrowserConfig): Config {\n const transports: Transport[] = [];\n\n const internalLogger = createInternalLogger(browserConfig.unpatchedConsole, browserConfig.internalLoggerLevel);\n\n if (browserConfig.transports) {\n if (browserConfig.url || browserConfig.apiKey) {\n internalLogger.error('if \"transports\" is defined, \"url\" and \"apiKey\" should not be defined');\n }\n\n transports.push(...browserConfig.transports);\n } else if (browserConfig.url) {\n transports.push(\n new FetchTransport({\n url: browserConfig.url,\n apiKey: browserConfig.apiKey,\n requestCompression: browserConfig.requestCompression,\n })\n );\n } else {\n internalLogger.error('either \"url\" or \"transports\" must be defined');\n }\n\n const {\n // properties with default values\n dedupe = true,\n eventDomain = defaultEventDomain,\n globalObjectKey = defaultGlobalObjectKey,\n instrumentations = getWebInstrumentations(),\n internalLoggerLevel = defaultInternalLoggerLevel,\n isolate = false,\n logArgsSerializer = defaultLogArgsSerializer,\n metas = createDefaultMetas(browserConfig),\n paused = false,\n preventGlobalExposure = false,\n unpatchedConsole = defaultUnpatchedConsole,\n url: browserConfigUrl,\n experimental,\n // Properties without default values or which aren't used to create derived config\n ...restProperties\n }: BrowserConfig = browserConfig;\n\n // Extract experimental features with defaults\n const trackNavigation = experimental?.trackNavigation ?? false;\n\n // Extract user actions instrumentation with defaults\n const userActionsInstrumentation = {\n dataAttributeName: browserConfig.userActionsInstrumentation?.dataAttributeName ?? userActionDataAttribute,\n excludeItem: browserConfig.userActionsInstrumentation?.excludeItem,\n };\n\n return {\n ...restProperties,\n\n batching: {\n ...defaultBatchingConfig,\n ...browserConfig.batching,\n },\n dedupe: dedupe,\n globalObjectKey,\n instrumentations: getFilteredInstrumentations(instrumentations, browserConfig),\n internalLoggerLevel,\n isolate,\n logArgsSerializer,\n metas,\n parseStacktrace,\n paused,\n preventGlobalExposure,\n transports,\n unpatchedConsole,\n eventDomain,\n ignoreUrls: [\n ...(browserConfig.ignoreUrls ?? []),\n // ignore configured cloud collector url by default\n ...(browserConfigUrl ? [browserConfigUrl] : []),\n // Try our best to exclude collector URLs form other Faro instances. By default these are URLs ending with /collect or /collect/ followed by alphanumeric characters.\n /\\/collect(?:\\/[\\w]*)?$/,\n ],\n sessionTracking: {\n ...defaultSessionTrackingConfig,\n ...browserConfig.sessionTracking,\n ...crateSessionMeta({\n trackGeolocation: browserConfig.trackGeolocation,\n sessionTracking: browserConfig.sessionTracking,\n }),\n },\n userActionsInstrumentation,\n experimental: {\n trackNavigation,\n },\n };\n}\n\nfunction getFilteredInstrumentations(\n instrumentations: Instrumentation[],\n { experimental }: BrowserConfig\n): Instrumentation[] {\n const trackNavigation = experimental?.trackNavigation ?? false;\n\n return instrumentations.filter((instr) => {\n if (instr.name === '@grafana/faro-web-sdk:instrumentation-navigation' && !trackNavigation) {\n return false;\n }\n return true;\n });\n}\n\nfunction createDefaultMetas(browserConfig: BrowserConfig): MetaItem[] {\n const { page, generatePageId } = browserConfig?.pageTracking ?? {};\n\n const initialMetas: MetaItem[] = [\n browserMeta,\n osMeta,\n createPageMeta({ generatePageId, initialPageMeta: page }),\n ...(browserConfig.metas ?? []),\n sdkMeta,\n ];\n\n const isK6BrowserSession = isObject((window as any)?.k6);\n if (isK6BrowserSession) {\n return [...initialMetas, k6Meta];\n }\n\n return initialMetas;\n}\n\nfunction crateSessionMeta({\n trackGeolocation,\n sessionTracking,\n}: Pick<BrowserConfig, 'trackGeolocation' | 'sessionTracking'>): { session: MetaSession } | {} {\n const overrides: MetaSession['overrides'] = {};\n\n if (isBoolean(trackGeolocation)) {\n overrides.geoLocationTrackingEnabled = trackGeolocation;\n }\n\n if (isEmpty(overrides)) {\n return {};\n }\n\n return {\n session: {\n ...(sessionTracking?.session ?? {}),\n overrides,\n },\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Config } from '@grafana/faro-core';\n\nexport interface BrowserConfig extends Partial<Omit<Config, 'app' | 'parseStacktrace'>>, Pick<Config, 'app'> {\n url?: string;\n apiKey?: string;\n}\n\nexport interface GetWebInstrumentationsOptions {\n captureConsole?: boolean;\n enablePerformanceInstrumentation?: boolean;\n enableContentSecurityPolicyInstrumentation?: boolean;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/config/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Config } from '@grafana/faro-core';\n\nexport interface BrowserConfig extends Partial<Omit<Config, 'app' | 'parseStacktrace'>>, Pick<Config, 'app'> {\n url?: string;\n apiKey?: string;\n requestCompression?: boolean;\n}\n\nexport interface GetWebInstrumentationsOptions {\n captureConsole?: boolean;\n enablePerformanceInstrumentation?: boolean;\n enableContentSecurityPolicyInstrumentation?: boolean;\n}\n"]}
|
|
@@ -63,7 +63,10 @@ export function createFaroResourceTiming(resourceEntryRaw) {
|
|
|
63
63
|
requestTime: toFaroPerformanceTimingString(responseStart - requestStart),
|
|
64
64
|
responseTime: toFaroPerformanceTimingString(responseEnd - responseStart),
|
|
65
65
|
fetchTime: toFaroPerformanceTimingString(responseEnd - fetchStart),
|
|
66
|
-
|
|
66
|
+
// workerStart is 0 when the request is not intercepted by a service worker (W3C Resource Timing spec).
|
|
67
|
+
// fetchStart is a timeOrigin-relative timestamp, not a duration, so guard against reporting it as the
|
|
68
|
+
// service worker time when no service worker handled the request.
|
|
69
|
+
serviceWorkerTime: toFaroPerformanceTimingString(workerStart > 0 ? fetchStart - workerStart : 0),
|
|
67
70
|
decodedBodySize: toFaroPerformanceTimingString(decodedBodySize),
|
|
68
71
|
encodedBodySize: toFaroPerformanceTimingString(encodedBodySize),
|
|
69
72
|
cacheHitStatus: getCacheType(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"performanceUtils.js","sourceRoot":"","sources":["../../../../src/instrumentations/performance/performanceUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { isArray, type PushEventOptions, unknownString } from '@grafana/faro-core';\n\nimport type { CacheType, FaroNavigationTiming, FaroResourceTiming } from './types';\n\nconst w3cTraceparentFormat = /^00-[a-f0-9]{32}-[a-f0-9]{16}-[0-9]{1,2}$/;\n\ntype SpanContext = PushEventOptions['spanContext'];\n\n// Extract traceparent from serverTiming, if present\nexport function getSpanContextFromServerTiming(serverTimings: PerformanceServerTiming[] = []): SpanContext | undefined {\n for (const serverEntry of serverTimings) {\n if (serverEntry.name === 'traceparent') {\n if (!w3cTraceparentFormat.test(serverEntry.description)) {\n continue;\n }\n\n const [, traceId, spanId] = serverEntry.description.split('-');\n if (traceId != null && spanId != null) {\n return { traceId, spanId };\n }\n\n break;\n }\n }\n\n return undefined;\n}\n\nexport function performanceObserverSupported(): boolean {\n return 'PerformanceObserver' in window;\n}\n\nexport function onDocumentReady(handleReady: () => void) {\n if (document.readyState === 'complete') {\n handleReady();\n } else {\n const readyStateCompleteHandler = () => {\n if (document.readyState === 'complete') {\n handleReady();\n document.removeEventListener('readystatechange', readyStateCompleteHandler);\n }\n };\n\n document.addEventListener('readystatechange', readyStateCompleteHandler);\n }\n}\n\ntype PerformanceEntryAllowProperties = Record<string, Array<string | number> | string | number>;\n\nexport function includePerformanceEntry(\n performanceEntryJSON: Record<string, any>,\n allowProps: PerformanceEntryAllowProperties = {}\n): boolean {\n for (const [allowPropKey, allowPropValue] of Object.entries(allowProps)) {\n const perfEntryPropVal = performanceEntryJSON[allowPropKey];\n\n if (perfEntryPropVal == null) {\n return false;\n }\n\n if (isArray(allowPropValue)) {\n return allowPropValue.includes(perfEntryPropVal);\n }\n\n return perfEntryPropVal === allowPropValue;\n }\n\n // empty object allows all\n return true;\n}\n\nexport function createFaroResourceTiming(resourceEntryRaw: PerformanceResourceTiming): FaroResourceTiming {\n const {\n connectEnd,\n connectStart,\n decodedBodySize,\n domainLookupEnd,\n domainLookupStart,\n duration,\n encodedBodySize,\n fetchStart,\n initiatorType,\n name,\n nextHopProtocol,\n redirectEnd,\n redirectStart,\n // @ts-expect-error the renderBlockingStatus property is not available in all browsers\n renderBlockingStatus: rbs,\n requestStart,\n responseEnd,\n responseStart,\n responseStatus,\n secureConnectionStart,\n transferSize,\n workerStart,\n } = resourceEntryRaw;\n\n return {\n name: name,\n httpHost: getHostFromUrl(name),\n duration: toFaroPerformanceTimingString(duration),\n tcpHandshakeTime: toFaroPerformanceTimingString(connectEnd - connectStart),\n dnsLookupTime: toFaroPerformanceTimingString(domainLookupEnd - domainLookupStart),\n tlsNegotiationTime: toFaroPerformanceTimingString(connectEnd - secureConnectionStart),\n responseStatus: toFaroPerformanceTimingString(responseStatus),\n redirectTime: toFaroPerformanceTimingString(redirectEnd - redirectStart),\n requestTime: toFaroPerformanceTimingString(responseStart - requestStart),\n responseTime: toFaroPerformanceTimingString(responseEnd - responseStart),\n fetchTime: toFaroPerformanceTimingString(responseEnd - fetchStart),\n serviceWorkerTime: toFaroPerformanceTimingString(fetchStart - workerStart),\n decodedBodySize: toFaroPerformanceTimingString(decodedBodySize),\n encodedBodySize: toFaroPerformanceTimingString(encodedBodySize),\n cacheHitStatus: getCacheType(),\n renderBlockingStatus: toFaroPerformanceTimingString(rbs) as FaroResourceTiming['renderBlockingStatus'],\n protocol: nextHopProtocol,\n initiatorType: initiatorType,\n visibilityState: document.visibilityState,\n ttfb: toFaroPerformanceTimingString(responseStart - requestStart),\n transferSize: toFaroPerformanceTimingString(transferSize),\n\n // TODO: add in future iteration, ideally after nested objects are supported by the collector.\n // serverTiming: resourceEntryRaw.serverTiming,\n };\n\n function getCacheType(): CacheType {\n let cacheType: CacheType = 'fullLoad';\n if (transferSize === 0) {\n if (decodedBodySize > 0) {\n cacheType = 'cache';\n }\n } else {\n if (responseStatus != null) {\n if (responseStatus === 304) {\n cacheType = 'conditionalFetch';\n }\n } else if (encodedBodySize > 0 && transferSize < encodedBodySize) {\n cacheType = 'conditionalFetch';\n }\n }\n return cacheType;\n }\n}\n\nexport function createFaroNavigationTiming(navigationEntryRaw: PerformanceNavigationTiming): FaroNavigationTiming {\n const {\n activationStart,\n domComplete,\n domContentLoadedEventEnd,\n domContentLoadedEventStart,\n domInteractive,\n fetchStart,\n loadEventEnd,\n loadEventStart,\n responseStart,\n type,\n } = navigationEntryRaw;\n\n const parserStart = getDocumentParsingTime();\n\n return {\n ...createFaroResourceTiming(navigationEntryRaw),\n pageLoadTime: toFaroPerformanceTimingString(domComplete - fetchStart),\n documentParsingTime: toFaroPerformanceTimingString(parserStart ? domInteractive - parserStart : null),\n domProcessingTime: toFaroPerformanceTimingString(domComplete - domInteractive),\n domContentLoadHandlerTime: toFaroPerformanceTimingString(domContentLoadedEventEnd - domContentLoadedEventStart),\n onLoadTime: toFaroPerformanceTimingString(loadEventEnd - loadEventStart),\n\n // For navigation entries we can calculate the TTFB based on activationStart. We overwrite the TTFB value coming with the resource entry.\n // For more accuracy on prerendered pages page we calculate relative top the activationStart instead of the start of the navigation.\n // clamp to 0 if activationStart occurs after first byte is received.\n ttfb: toFaroPerformanceTimingString(Math.max(responseStart - (activationStart ?? 0), 0)),\n type: type,\n };\n}\n\nfunction getDocumentParsingTime(): number | null {\n if (performance.timing?.domLoading != null) {\n // the browser is about to start parsing the first received bytes of the HTML document.\n // This property is deprecated but there isn't a really good alternative atm.\n // For now we stick with domLoading and keep researching a better alternative.\n return performance.timing.domLoading - performance.timeOrigin;\n }\n\n return null;\n}\n\nfunction getHostFromUrl(url: string): string {\n try {\n return new URL(url).host || unknownString;\n } catch {\n return unknownString;\n }\n}\n\nfunction toFaroPerformanceTimingString(v: unknown): string {\n if (v == null) {\n return unknownString;\n }\n\n if (typeof v === 'number') {\n return Math.round(v > 0 ? v : 0).toString();\n }\n\n return v.toString();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"performanceUtils.js","sourceRoot":"","sources":["../../../../src/instrumentations/performance/performanceUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import { isArray, type PushEventOptions, unknownString } from '@grafana/faro-core';\n\nimport type { CacheType, FaroNavigationTiming, FaroResourceTiming } from './types';\n\nconst w3cTraceparentFormat = /^00-[a-f0-9]{32}-[a-f0-9]{16}-[0-9]{1,2}$/;\n\ntype SpanContext = PushEventOptions['spanContext'];\n\n// Extract traceparent from serverTiming, if present\nexport function getSpanContextFromServerTiming(serverTimings: PerformanceServerTiming[] = []): SpanContext | undefined {\n for (const serverEntry of serverTimings) {\n if (serverEntry.name === 'traceparent') {\n if (!w3cTraceparentFormat.test(serverEntry.description)) {\n continue;\n }\n\n const [, traceId, spanId] = serverEntry.description.split('-');\n if (traceId != null && spanId != null) {\n return { traceId, spanId };\n }\n\n break;\n }\n }\n\n return undefined;\n}\n\nexport function performanceObserverSupported(): boolean {\n return 'PerformanceObserver' in window;\n}\n\nexport function onDocumentReady(handleReady: () => void) {\n if (document.readyState === 'complete') {\n handleReady();\n } else {\n const readyStateCompleteHandler = () => {\n if (document.readyState === 'complete') {\n handleReady();\n document.removeEventListener('readystatechange', readyStateCompleteHandler);\n }\n };\n\n document.addEventListener('readystatechange', readyStateCompleteHandler);\n }\n}\n\ntype PerformanceEntryAllowProperties = Record<string, Array<string | number> | string | number>;\n\nexport function includePerformanceEntry(\n performanceEntryJSON: Record<string, any>,\n allowProps: PerformanceEntryAllowProperties = {}\n): boolean {\n for (const [allowPropKey, allowPropValue] of Object.entries(allowProps)) {\n const perfEntryPropVal = performanceEntryJSON[allowPropKey];\n\n if (perfEntryPropVal == null) {\n return false;\n }\n\n if (isArray(allowPropValue)) {\n return allowPropValue.includes(perfEntryPropVal);\n }\n\n return perfEntryPropVal === allowPropValue;\n }\n\n // empty object allows all\n return true;\n}\n\nexport function createFaroResourceTiming(resourceEntryRaw: PerformanceResourceTiming): FaroResourceTiming {\n const {\n connectEnd,\n connectStart,\n decodedBodySize,\n domainLookupEnd,\n domainLookupStart,\n duration,\n encodedBodySize,\n fetchStart,\n initiatorType,\n name,\n nextHopProtocol,\n redirectEnd,\n redirectStart,\n // @ts-expect-error the renderBlockingStatus property is not available in all browsers\n renderBlockingStatus: rbs,\n requestStart,\n responseEnd,\n responseStart,\n responseStatus,\n secureConnectionStart,\n transferSize,\n workerStart,\n } = resourceEntryRaw;\n\n return {\n name: name,\n httpHost: getHostFromUrl(name),\n duration: toFaroPerformanceTimingString(duration),\n tcpHandshakeTime: toFaroPerformanceTimingString(connectEnd - connectStart),\n dnsLookupTime: toFaroPerformanceTimingString(domainLookupEnd - domainLookupStart),\n tlsNegotiationTime: toFaroPerformanceTimingString(connectEnd - secureConnectionStart),\n responseStatus: toFaroPerformanceTimingString(responseStatus),\n redirectTime: toFaroPerformanceTimingString(redirectEnd - redirectStart),\n requestTime: toFaroPerformanceTimingString(responseStart - requestStart),\n responseTime: toFaroPerformanceTimingString(responseEnd - responseStart),\n fetchTime: toFaroPerformanceTimingString(responseEnd - fetchStart),\n // workerStart is 0 when the request is not intercepted by a service worker (W3C Resource Timing spec).\n // fetchStart is a timeOrigin-relative timestamp, not a duration, so guard against reporting it as the\n // service worker time when no service worker handled the request.\n serviceWorkerTime: toFaroPerformanceTimingString(workerStart > 0 ? fetchStart - workerStart : 0),\n decodedBodySize: toFaroPerformanceTimingString(decodedBodySize),\n encodedBodySize: toFaroPerformanceTimingString(encodedBodySize),\n cacheHitStatus: getCacheType(),\n renderBlockingStatus: toFaroPerformanceTimingString(rbs) as FaroResourceTiming['renderBlockingStatus'],\n protocol: nextHopProtocol,\n initiatorType: initiatorType,\n visibilityState: document.visibilityState,\n ttfb: toFaroPerformanceTimingString(responseStart - requestStart),\n transferSize: toFaroPerformanceTimingString(transferSize),\n\n // TODO: add in future iteration, ideally after nested objects are supported by the collector.\n // serverTiming: resourceEntryRaw.serverTiming,\n };\n\n function getCacheType(): CacheType {\n let cacheType: CacheType = 'fullLoad';\n if (transferSize === 0) {\n if (decodedBodySize > 0) {\n cacheType = 'cache';\n }\n } else {\n if (responseStatus != null) {\n if (responseStatus === 304) {\n cacheType = 'conditionalFetch';\n }\n } else if (encodedBodySize > 0 && transferSize < encodedBodySize) {\n cacheType = 'conditionalFetch';\n }\n }\n return cacheType;\n }\n}\n\nexport function createFaroNavigationTiming(navigationEntryRaw: PerformanceNavigationTiming): FaroNavigationTiming {\n const {\n activationStart,\n domComplete,\n domContentLoadedEventEnd,\n domContentLoadedEventStart,\n domInteractive,\n fetchStart,\n loadEventEnd,\n loadEventStart,\n responseStart,\n type,\n } = navigationEntryRaw;\n\n const parserStart = getDocumentParsingTime();\n\n return {\n ...createFaroResourceTiming(navigationEntryRaw),\n pageLoadTime: toFaroPerformanceTimingString(domComplete - fetchStart),\n documentParsingTime: toFaroPerformanceTimingString(parserStart ? domInteractive - parserStart : null),\n domProcessingTime: toFaroPerformanceTimingString(domComplete - domInteractive),\n domContentLoadHandlerTime: toFaroPerformanceTimingString(domContentLoadedEventEnd - domContentLoadedEventStart),\n onLoadTime: toFaroPerformanceTimingString(loadEventEnd - loadEventStart),\n\n // For navigation entries we can calculate the TTFB based on activationStart. We overwrite the TTFB value coming with the resource entry.\n // For more accuracy on prerendered pages page we calculate relative top the activationStart instead of the start of the navigation.\n // clamp to 0 if activationStart occurs after first byte is received.\n ttfb: toFaroPerformanceTimingString(Math.max(responseStart - (activationStart ?? 0), 0)),\n type: type,\n };\n}\n\nfunction getDocumentParsingTime(): number | null {\n if (performance.timing?.domLoading != null) {\n // the browser is about to start parsing the first received bytes of the HTML document.\n // This property is deprecated but there isn't a really good alternative atm.\n // For now we stick with domLoading and keep researching a better alternative.\n return performance.timing.domLoading - performance.timeOrigin;\n }\n\n return null;\n}\n\nfunction getHostFromUrl(url: string): string {\n try {\n return new URL(url).host || unknownString;\n } catch {\n return unknownString;\n }\n}\n\nfunction toFaroPerformanceTimingString(v: unknown): string {\n if (v == null) {\n return unknownString;\n }\n\n if (typeof v === 'number') {\n return Math.round(v > 0 ? v : 0).toString();\n }\n\n return v.toString();\n}\n"]}
|
|
@@ -29,7 +29,7 @@ const TOO_MANY_REQUESTS = 429;
|
|
|
29
29
|
const ACCEPTED = 202;
|
|
30
30
|
export class FetchTransport extends BaseTransport {
|
|
31
31
|
constructor(options) {
|
|
32
|
-
var _a, _b, _c, _d;
|
|
32
|
+
var _a, _b, _c, _d, _e;
|
|
33
33
|
super();
|
|
34
34
|
this.options = options;
|
|
35
35
|
this.name = '@grafana/faro-web-sdk:transport-fetch';
|
|
@@ -37,9 +37,17 @@ export class FetchTransport extends BaseTransport {
|
|
|
37
37
|
this.disabledUntil = new Date(0);
|
|
38
38
|
this.rateLimitBackoffMs = (_a = options.defaultRateLimitBackoffMs) !== null && _a !== void 0 ? _a : DEFAULT_RATE_LIMIT_BACKOFF_MS;
|
|
39
39
|
this.getNow = (_b = options.getNow) !== null && _b !== void 0 ? _b : (() => Date.now());
|
|
40
|
+
const requestCompression = (_c = options.requestCompression) !== null && _c !== void 0 ? _c : false;
|
|
41
|
+
if (requestCompression && typeof CompressionStream === 'undefined') {
|
|
42
|
+
this.compressionEnabled = false;
|
|
43
|
+
this.logWarn('requestCompression is enabled but CompressionStream is not available. Falling back to uncompressed.');
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.compressionEnabled = requestCompression;
|
|
47
|
+
}
|
|
40
48
|
this.promiseBuffer = createPromiseBuffer({
|
|
41
|
-
size: (
|
|
42
|
-
concurrency: (
|
|
49
|
+
size: (_d = options.bufferSize) !== null && _d !== void 0 ? _d : DEFAULT_BUFFER_SIZE,
|
|
50
|
+
concurrency: (_e = options.concurrency) !== null && _e !== void 0 ? _e : DEFAULT_CONCURRENCY,
|
|
43
51
|
});
|
|
44
52
|
}
|
|
45
53
|
send(items) {
|
|
@@ -50,7 +58,7 @@ export class FetchTransport extends BaseTransport {
|
|
|
50
58
|
return Promise.resolve();
|
|
51
59
|
}
|
|
52
60
|
yield this.promiseBuffer.add(() => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
-
const
|
|
61
|
+
const jsonBody = JSON.stringify(getTransportBody(items));
|
|
54
62
|
const { url, requestOptions, apiKey } = this.options;
|
|
55
63
|
const _a = requestOptions !== null && requestOptions !== void 0 ? requestOptions : {}, { headers = {} } = _a, restOfRequestOptions = __rest(_a, ["headers"]);
|
|
56
64
|
let sessionId;
|
|
@@ -62,7 +70,15 @@ export class FetchTransport extends BaseTransport {
|
|
|
62
70
|
for (const [key, value] of Object.entries(headers)) {
|
|
63
71
|
resolvedHeaders[key] = typeof value === 'function' ? yield Promise.resolve(value()) : value;
|
|
64
72
|
}
|
|
65
|
-
|
|
73
|
+
let body = jsonBody;
|
|
74
|
+
let bodySize = jsonBody.length;
|
|
75
|
+
const compressionHeaders = {};
|
|
76
|
+
if (this.compressionEnabled) {
|
|
77
|
+
body = yield this.compress(jsonBody);
|
|
78
|
+
bodySize = body.size;
|
|
79
|
+
compressionHeaders['Content-Encoding'] = 'gzip';
|
|
80
|
+
}
|
|
81
|
+
return fetch(url, Object.assign({ method: 'POST', headers: Object.assign(Object.assign(Object.assign(Object.assign({ 'Content-Type': 'application/json' }, compressionHeaders), resolvedHeaders), (apiKey ? { 'x-api-key': apiKey } : {})), (sessionId ? { 'x-faro-session-id': sessionId } : {})), body, keepalive: bodySize <= BEACON_BODY_SIZE_LIMIT }, (restOfRequestOptions !== null && restOfRequestOptions !== void 0 ? restOfRequestOptions : {})))
|
|
66
82
|
.then((response) => __awaiter(this, void 0, void 0, function* () {
|
|
67
83
|
if (response.status === ACCEPTED) {
|
|
68
84
|
const sessionExpired = response.headers.get('X-Faro-Session-Status') === 'invalid';
|
|
@@ -79,7 +95,7 @@ export class FetchTransport extends BaseTransport {
|
|
|
79
95
|
return response;
|
|
80
96
|
}))
|
|
81
97
|
.catch((err) => {
|
|
82
|
-
this.logError('Failed sending payload to the receiver\n', JSON.parse(
|
|
98
|
+
this.logError('Failed sending payload to the receiver\n', JSON.parse(jsonBody), err);
|
|
83
99
|
});
|
|
84
100
|
}));
|
|
85
101
|
}
|
|
@@ -110,6 +126,26 @@ export class FetchTransport extends BaseTransport {
|
|
|
110
126
|
}
|
|
111
127
|
return new Date(now + this.rateLimitBackoffMs);
|
|
112
128
|
}
|
|
129
|
+
compress(body) {
|
|
130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
const stream = new ReadableStream({
|
|
132
|
+
start(controller) {
|
|
133
|
+
controller.enqueue(new TextEncoder().encode(body));
|
|
134
|
+
controller.close();
|
|
135
|
+
},
|
|
136
|
+
}).pipeThrough(new CompressionStream('gzip'));
|
|
137
|
+
const reader = stream.getReader();
|
|
138
|
+
const chunks = [];
|
|
139
|
+
for (;;) {
|
|
140
|
+
const { done, value } = yield reader.read();
|
|
141
|
+
if (done) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
chunks.push(value);
|
|
145
|
+
}
|
|
146
|
+
return new Blob(chunks);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
113
149
|
extendFaroSession(config, logDebug) {
|
|
114
150
|
const SessionExpiredString = `Session expired`;
|
|
115
151
|
const sessionTrackingConfig = config.sessionTracking;
|