@tinkoff/perfume 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/config.ts","../src/constants.ts","../src/isSupported.ts","../src/getNavigationTiming.ts","../src/getNetworkInformation.ts","../src/metrics.ts","../src/observeInstances.ts","../src/onVisibilityChange.ts","../src/performanceObserver.ts","../src/isLowEnd.ts","../src/getNavigatorInfo.ts","../src/utils.ts","../src/reportPerf.ts","../src/totalBlockingTime.ts","../src/types.ts","../src/vitalsScore.ts","../src/log.ts","../src/element-timing.ts","../src/resourceTiming.ts","../src/observe.ts","../src/storageEstimate.ts","../src/steps/steps.ts","../src/steps/setStepsMap.ts","../src/initPerfume.ts","../src/measure.ts","../src/steps/measureStep.ts","../src/steps/navigationSteps.ts","../src/steps/measureSteps.ts","../src/steps/markStep.ts","../src/steps/markStepOnce.ts","../src/markNTBT.ts"],"sourcesContent":["import { IPerfumeConfig } from './types';\n\nexport const config: IPerfumeConfig = {\n // Metrics\n isResourceTiming: false,\n isElementTiming: false,\n // Logging\n maxTime: 30000,\n // web-vitals report options\n reportOptions: {},\n};\n","// Have private variable outside the class,\n// helps drastically reduce the library size\nexport const W = typeof window !== 'undefined' ? window : ({} as typeof window);\nexport const C = W.console;\nexport const WN = W.navigator;\nexport const WP = W.performance;\nexport const getDM = () => (WN as any).deviceMemory;\nexport const getHC = () => (WN as any).hardwareConcurrency;\nexport const M = 'mark.'; // Mark Prefix\nexport const S = 'step.'; // Step Prefix\n","import { WP } from './constants';\n\n/**\n * True if the browser supports the Navigation Timing API,\n * User Timing API and the PerformanceObserver Interface.\n * In Safari, the User Timing API (performance.mark()) is not available,\n * so the DevTools timeline will not be annotated with marks.\n * Support: developer.mozilla.org/en-US/docs/Web/API/Performance/mark\n * Support: developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver\n * Support: developer.mozilla.org/en-US/docs/Web/API/Performance/getEntriesByType\n */\nexport const isPerformanceSupported = (): boolean =>\n WP && !!WP.getEntriesByType && !!WP.now && !!WP.mark;\n","import { WP } from './constants';\nimport { isPerformanceSupported } from './isSupported';\nimport { IPerfumeNavigationTiming } from './types';\n\n/**\n * Navigation Timing API provides performance metrics for HTML documents.\n * w3c.github.io/navigation-timing/\n * developers.google.com/web/fundamentals/performance/navigation-and-resource-timing\n */\nexport const getNavigationTiming = (): IPerfumeNavigationTiming => {\n if (!isPerformanceSupported()) {\n return {};\n }\n // There is an open issue to type correctly getEntriesByType\n // github.com/microsoft/TypeScript/issues/33866\n const n = WP.getEntriesByType('navigation')[0] as any;\n // In Safari version 11.2 Navigation Timing isn't supported yet\n if (!n) {\n return {};\n }\n const responseStart = n.responseStart;\n const responseEnd = n.responseEnd;\n // We cache the navigation time for future times\n return {\n // fetchStart marks when the browser starts to fetch a resource\n // responseEnd is when the last byte of the response arrives\n fetchTime: responseEnd - n.fetchStart,\n // Service worker time plus response time\n workerTime: n.workerStart > 0 ? responseEnd - n.workerStart : 0,\n // Request plus response time (network only)\n totalTime: responseEnd - n.requestStart,\n // Response time only (download)\n downloadTime: responseEnd - responseStart,\n // Time to First Byte (TTFB)\n timeToFirstByte: responseStart - n.requestStart,\n // HTTP header size\n headerSize: n.transferSize - n.encodedBodySize || 0,\n // Measuring DNS lookup time\n dnsLookupTime: n.domainLookupEnd - n.domainLookupStart,\n // redirects could add latency to requests\n redirectTime: n.redirectEnd - n.redirectStart,\n };\n};\n","import { WN } from './constants';\nimport { EffectiveConnectionType, IPerfumeNetworkInformation } from './types';\n\nexport let et: EffectiveConnectionType = '4g';\nexport let sd = false;\n\nexport const getNetworkInformation = (): IPerfumeNetworkInformation => {\n if ('connection' in WN) {\n const dataConnection = (WN as any).connection;\n if (typeof dataConnection !== 'object') {\n return {};\n }\n et = dataConnection.effectiveType;\n sd = !!dataConnection.saveData;\n return {\n downlink: dataConnection.downlink,\n effectiveType: dataConnection.effectiveType,\n rtt: dataConnection.rtt,\n saveData: !!dataConnection.saveData,\n };\n }\n return {};\n};\n","import { IMetricMap, IPerfumeDataConsumption } from './types';\n\nexport const metrics: IMetricMap = {};\nexport const fcp = {\n value: 0,\n};\nexport const rt: { value: IPerfumeDataConsumption } = {\n value: {\n beacon: 0,\n css: 0,\n fetch: 0,\n img: 0,\n other: 0,\n script: 0,\n total: 0,\n xmlhttprequest: 0,\n },\n};\nexport const tbt = {\n value: 0,\n};\nexport const ntbt = {\n value: 0,\n};\n","import { IPerfObservers } from './types';\n\nexport const perfObservers: IPerfObservers = {};\n","export const visibility = {\n isHidden: false,\n didChange: false,\n};\n\n/**\n * From visibilitychange listener it saves only when\n * the page gets hidden, because it's important to not\n * use the wrong \"hidden\" value when send timing or logging.\n */\nexport const didVisibilityChange = function () {\n visibility.isHidden = false;\n if (document.hidden) {\n visibility.isHidden = document.hidden;\n visibility.didChange = true;\n }\n};\n","import { C } from './constants';\nimport { perfObservers } from './observeInstances';\nimport { IPerformanceObserverType } from './types';\n\n/**\n * PerformanceObserver subscribes to performance events as they happen\n * and respond to them asynchronously.\n */\nexport const po = (\n eventType: IPerformanceObserverType,\n cb: (performanceEntries: any[]) => void,\n): PerformanceObserver | null => {\n try {\n const perfObserver = new PerformanceObserver((entryList) => {\n cb(entryList.getEntries());\n });\n // Retrieve buffered events and subscribe to newer events for Paint Timing\n perfObserver.observe({ type: eventType, buffered: true });\n return perfObserver;\n } catch (e) {\n C.warn('Perfume.js:', e);\n }\n return null;\n};\n\nexport const poDisconnect = (observer: any) => {\n if (perfObservers[observer]) {\n perfObservers[observer].disconnect();\n }\n delete perfObservers[observer];\n};\n","import { getDM, getHC } from './constants';\nimport { EffectiveConnectionType } from './types';\n\nexport const getIsLowEndDevice = (): boolean => {\n // If number of logical processors available to run threads <= 4\n if (getHC() && getHC() <= 4) {\n return true;\n }\n // If the approximate amount of RAM client device has <= 4\n if (getDM() && getDM() <= 4) {\n return true;\n }\n return false;\n};\n\nexport const getIsLowEndExperience = (\n et: EffectiveConnectionType,\n sd: boolean,\n): boolean => {\n // If the effective type of the connection meaning\n // one of 'slow-2g', '2g', '3g', or '4g' is !== 4g\n switch (et) {\n case 'slow-2g':\n return true;\n case '2g':\n return true;\n case '3g':\n return true;\n default:\n // Data Saver preference\n return getIsLowEndDevice() || sd;\n }\n};\n","import { getDM, getHC, WN } from './constants';\nimport { et, sd } from './getNetworkInformation';\nimport { getIsLowEndDevice, getIsLowEndExperience } from './isLowEnd';\nimport { INavigatorInfo } from './types';\n\n/**\n * Information coming from window.navigator:\n * 1. Device Memory\n * 2. Hardware Concurency\n * 3. Status of the service worker:\n * - controlled: a service worker is controlling the page\n * - supported: the browser supports service worker\n * - unsupported: the user's browser does not support service worker\n */\nexport const getNavigatorInfo = (): INavigatorInfo => {\n if (WN) {\n return {\n deviceMemory: getDM() || 0,\n hardwareConcurrency: getHC() || 0,\n serviceWorkerStatus:\n 'serviceWorker' in WN\n ? WN.serviceWorker.controller\n ? 'controlled'\n : 'supported'\n : 'unsupported',\n isLowEndDevice: getIsLowEndDevice(),\n isLowEndExperience: getIsLowEndExperience(et, sd),\n };\n }\n return {};\n};\n","import { W } from './constants';\n\nexport const roundByFour = (num: number) => parseFloat(num.toFixed(4));\n\nexport const convertToKB = (bytes: number): number | null => {\n if (typeof bytes !== 'number') {\n return null;\n }\n return roundByFour(bytes / Math.pow(1024, 2));\n};\n\n/**\n * PushTask to requestIdleCallback\n */\nexport const pushTask = (cb: any): void => {\n if ('requestIdleCallback' in W) {\n (W as any).requestIdleCallback(cb, { timeout: 3000 });\n } else {\n cb();\n }\n};\n","import { config } from './config';\nimport { getNavigatorInfo } from './getNavigatorInfo';\nimport { visibility } from './onVisibilityChange';\nimport { IVitalsScore, INavigationType } from './types';\nimport { pushTask } from './utils';\n\n/**\n * Sends the User timing measure to analyticsTracker\n */\nexport const reportPerf = (\n measureName: string,\n data: any,\n rating: IVitalsScore,\n attribution: object,\n navigationType?: INavigationType,\n): void => {\n const reportTask = () => {\n if (!config.analyticsTracker) {\n return;\n }\n // Doesn't send timing when page is hidden\n if (visibility.isHidden && !['CLS', 'INP'].includes(measureName)) {\n return;\n }\n // Send metric to custom Analytics service\n config.analyticsTracker({\n attribution,\n metricName: measureName,\n data,\n navigatorInformation: getNavigatorInfo(),\n rating,\n navigationType,\n });\n };\n\n // Send CLS and INP metrics immediately,\n // because this metrics are reported when page is hidden or closed\n if (['CLS', 'INP'].includes(measureName)) {\n reportTask();\n } else {\n pushTask(reportTask);\n }\n};\n","import { fcp, tbt, ntbt } from './metrics';\nimport { IPerformanceEntry } from './types';\n\nexport const initTotalBlockingTime = (\n performanceEntries: IPerformanceEntry[],\n): void => {\n performanceEntries.forEach((entry) => {\n if (entry.name !== 'self' || entry.startTime < fcp.value) {\n return;\n }\n const blockingTime = entry.duration - 50;\n if (blockingTime > 0) {\n tbt.value += blockingTime;\n ntbt.value += blockingTime;\n }\n });\n};\n","import type { ReportOpts } from 'web-vitals';\n\nexport interface Metric {\n /**\n * The name of the metric (in acronym form).\n */\n name:\n | 'CLS'\n | 'FCP'\n | 'FID'\n | 'LCP'\n | 'TTFB'\n | 'RT'\n | 'TBT'\n | 'NTBT'\n | 'ET'\n | 'INP';\n /**\n * The current value of the metric.\n */\n value: number;\n /**\n * The rating as to whether the metric value is within the \"good\",\n * \"needs improvement\", or \"poor\" thresholds of the metric.\n */\n rating: IVitalsScore;\n /**\n * The delta between the current value and the last-reported value.\n * On the first report, `delta` and `value` will always be the same.\n */\n delta?: number;\n /**\n * A unique ID representing this particular metric instance. This ID can\n * be used by an analytics tool to dedupe multiple values sent for the same\n * metric instance, or to group multiple deltas together and calculate a\n * total. It can also be used to differentiate multiple different metric\n * instances sent from the same page, which can happen if the page is\n * restored from the back/forward cache (in that case new metrics object\n * get created).\n */\n id?: string;\n /**\n * Any performance entries relevant to the metric value calculation.\n * The array may also be empty if the metric value was not based on any\n * entries (e.g. a CLS value of 0 given no layout shifts).\n */\n entries?: PerformanceEntry[];\n /**\n * The type of navigation\n *\n * Navigation Timing API (or `undefined` if the browser doesn't\n * support that API). For pages that are restored from the bfcache, this\n * value will be 'back-forward-cache'.\n */\n navigationType?: INavigationType;\n\n /**\n * An object containing potentially-helpful debugging information that\n * can be sent along with the metric value for the current page visit in\n * order to help identify issues happening to real-users in the field.\n */\n attribution: {\n [key: string]: unknown;\n };\n}\n\nexport interface IAnalyticsTrackerOptions {\n attribution: object;\n data: IPerfumeData;\n metricName: string;\n navigatorInformation: INavigatorInfo;\n rating: IVitalsScore;\n navigationType?: INavigationType;\n}\n\ninterface WebVitalsReportOptions {\n ttfb?: ReportOpts;\n cls?: ReportOpts;\n fcp?: ReportOpts;\n fid?: ReportOpts;\n lcp?: ReportOpts;\n inp?: ReportOpts;\n}\n\nexport interface IPerfumeConfig {\n // Metrics\n isResourceTiming: boolean;\n isElementTiming: boolean;\n // Analytics\n analyticsTracker?: (options: IAnalyticsTrackerOptions) => void;\n // Logging\n maxTime: number;\n // web-vitals report options\n reportOptions: WebVitalsReportOptions;\n // Steps definitions\n steps?: IStepsConfig;\n // Callback that will run each time a mark is called\n onMarkStep?: (mark: string, steps: string[]) => void;\n}\n\nexport interface IPerfumeOptions {\n // Metrics\n resourceTiming?: boolean;\n elementTiming?: boolean;\n // Analytics\n analyticsTracker?: (options: IAnalyticsTrackerOptions) => void;\n // Logging\n maxMeasureTime?: number;\n // web-vitals report options\n reportOptions?: WebVitalsReportOptions;\n // Steps definitions\n steps?: IStepsConfig;\n // Callback that will run each time a mark is called\n onMarkStep?: (mark: string, steps: string[]) => void;\n}\n\nexport interface IMetricMap {\n [measureName: string]: boolean;\n}\n\nexport interface INavigatorInfo {\n deviceMemory?: number;\n hardwareConcurrency?: number;\n isLowEndDevice?: boolean;\n isLowEndExperience?: boolean;\n serviceWorkerStatus?: 'controlled' | 'supported' | 'unsupported';\n}\n\nexport interface IPerfObservers {\n [measureName: string]: any;\n}\n\nexport type IPerformanceObserverType =\n | 'first-input'\n | 'largest-contentful-paint'\n | 'layout-shift'\n | 'longtask'\n | 'measure'\n | 'navigation'\n | 'paint'\n | 'element'\n | 'resource';\n\nexport type IPerformanceEntryInitiatorType =\n 'beacon' | 'css' | 'fetch' | 'img' | 'other' | 'script' | 'xmlhttprequest';\n\nexport declare interface IPerformanceEntry {\n decodedBodySize?: number;\n duration: number;\n entryType: IPerformanceObserverType;\n initiatorType?: IPerformanceEntryInitiatorType;\n loadTime: number;\n name: string;\n renderTime: number;\n startTime: number;\n hadRecentInput?: boolean;\n value?: number;\n identifier?: string;\n}\n\n// https://wicg.github.io/event-timing/#sec-performance-event-timing\nexport interface PerformanceEventTiming extends PerformanceEntry {\n processingStart: DOMHighResTimeStamp;\n target?: Node;\n}\n\nexport interface IPerformancePaintTiming {\n name: string;\n entryType: string;\n startTime: number;\n duration: number;\n}\n\nexport interface IPerfumeNavigationTiming {\n fetchTime?: number;\n workerTime?: number;\n totalTime?: number;\n downloadTime?: number;\n timeToFirstByte?: number;\n headerSize?: number;\n dnsLookupTime?: number;\n redirectTime?: number;\n}\n\nexport type EffectiveConnectionType = '2g' | '3g' | '4g' | 'slow-2g' | 'lte';\n\nexport interface IPerfumeNetworkInformation {\n downlink?: number;\n effectiveType?: EffectiveConnectionType;\n onchange?: () => void;\n rtt?: number;\n saveData?: boolean;\n}\n\nexport interface IPerfumeDataConsumption {\n beacon: number;\n css: number;\n fetch: number;\n img: number;\n other: number;\n script: number;\n total: number;\n xmlhttprequest: number;\n}\n\nexport type IPerfumeData =\n number | IPerfumeNavigationTiming | IPerfumeNetworkInformation;\n\nexport type IVitalsScore = 'good' | 'needsImprovement' | 'poor' | null;\n\nexport type INavigationType =\n 'navigate' | 'reload' | 'back-forward' | 'back-forward-cache' | 'prerender';\n\nexport interface IVitalsThresholds {\n vitalsThresholds: [number, number];\n}\nexport interface IOutlierThreshold {\n maxOutlierThreshold: number;\n}\n\nexport enum IThresholdTier {\n instant = 'instant',\n quick = 'quick',\n moderate = 'moderate',\n slow = 'slow',\n unavoidable = 'unavoidable',\n}\n\nexport type IStepsThresholdConfig = IVitalsThresholds & IOutlierThreshold;\nexport type IStepsThresholds = {\n [key in IThresholdTier]: IStepsThresholdConfig;\n};\n\nexport type ISteps<Steps extends string> = {\n steps: Steps[];\n} & Partial<IOutlierThreshold>;\n\nexport interface IStepMarks<Marks extends string> {\n marks: [Marks | 'launch', Marks];\n}\n\nexport type IStepConfig<Marks extends string> = {\n threshold: IThresholdTier;\n} & IStepMarks<Marks>;\n\nexport type IStepsConfig = Record<string, IStepConfig<string>>;\n","import { IThresholdTier, IStepsThresholds, IVitalsScore } from './types';\n\nconst rtScore = [100, 200];\nconst tbtScore = [200, 600];\nconst ntbtScore = [200, 600];\n\nexport const STEP_THRESHOLDS: IStepsThresholds = {\n [IThresholdTier.instant]: {\n vitalsThresholds: [100, 200],\n maxOutlierThreshold: 10000,\n },\n [IThresholdTier.quick]: {\n vitalsThresholds: [200, 500],\n maxOutlierThreshold: 10000,\n },\n [IThresholdTier.moderate]: {\n vitalsThresholds: [500, 1000],\n maxOutlierThreshold: 10000,\n },\n [IThresholdTier.slow]: {\n vitalsThresholds: [1000, 2000],\n maxOutlierThreshold: 10000,\n },\n [IThresholdTier.unavoidable]: {\n vitalsThresholds: [2000, 5000],\n maxOutlierThreshold: 20000,\n },\n};\n\nexport const webVitalsScore: Record<string, number[]> = {\n RT: rtScore,\n TBT: tbtScore,\n NTBT: ntbtScore,\n};\n\nexport const getRating = (\n value: number,\n vitalsThresholds: [number, number],\n): IVitalsScore => {\n if (value <= vitalsThresholds[0]) {\n return 'good';\n }\n return value <= vitalsThresholds[1] ? 'needsImprovement' : 'poor';\n};\n\nexport const getVitalsScore = (\n measureName: string,\n value: number,\n): IVitalsScore => {\n if (!webVitalsScore[measureName]) {\n return null;\n }\n if (value <= webVitalsScore[measureName][0]) {\n return 'good';\n }\n return value <= webVitalsScore[measureName][1] ? 'needsImprovement' : 'poor';\n};\n","import { config } from './config';\nimport { fcp, rt, tbt } from './metrics';\nimport { perfObservers } from './observeInstances';\nimport { visibility } from './onVisibilityChange';\nimport { po } from './performanceObserver';\nimport { reportPerf } from './reportPerf';\nimport { initTotalBlockingTime } from './totalBlockingTime';\nimport { Metric } from './types';\nimport { roundByFour } from './utils';\nimport { getVitalsScore } from './vitalsScore';\n\nexport const logData = (\n measureName: string,\n metric: any,\n attribution?: object,\n): void => {\n Object.keys(metric).forEach((key) => {\n if (typeof metric[key] === 'number') {\n metric[key] = roundByFour(metric[key]);\n }\n });\n // Sends the metric to an external tracking service\n reportPerf(measureName, metric, null, attribution || {});\n};\n\n/**\n * Dispatches the metric duration into internal logs\n * and the external time tracking service.\n */\nexport const logMetric = ({\n attribution,\n name,\n rating,\n value,\n navigationType,\n}: Metric): void => {\n // TODO Add docs\n if (name === 'FCP') {\n fcp.value = value;\n }\n // TODO Add docs\n // create longtask observer only once, otherwise entries will be duplicated\n if (['FCP', 'LCP'].includes(name) && !perfObservers[0]) {\n perfObservers[0] = po('longtask', initTotalBlockingTime);\n }\n // TODO Add docs\n if ('FID' === name) {\n setTimeout(() => {\n if (visibility.didChange) {\n return;\n }\n logMetric({\n attribution,\n name: 'TBT',\n rating: getVitalsScore('TBT', tbt.value),\n value: tbt.value,\n navigationType,\n });\n logData('dataConsumption', rt.value);\n }, 10000);\n }\n // TODO Add docs\n const duration2Decimal = roundByFour(value);\n if (duration2Decimal <= config.maxTime && duration2Decimal >= 0) {\n // Sends the metric to an external tracking service\n reportPerf(name, duration2Decimal, rating, attribution, navigationType);\n }\n};\n","import { logMetric } from './log';\nimport { IPerformanceEntry } from './types';\n\nexport const initElementTiming = (performanceEntries: IPerformanceEntry[]) => {\n performanceEntries.forEach((entry) => {\n if (entry.identifier) {\n logMetric({\n attribution: {\n identifier: entry.identifier,\n },\n name: 'ET',\n rating: null,\n value: entry.startTime,\n });\n }\n });\n};\n","import { config } from './config';\nimport { logData } from './log';\nimport { rt } from './metrics';\nimport { IPerformanceEntry } from './types';\n\nexport const initResourceTiming = (performanceEntries: IPerformanceEntry[]) => {\n performanceEntries.forEach((entry) => {\n if (config.isResourceTiming) {\n logData('resourceTiming', entry);\n }\n if (entry.decodedBodySize && entry.initiatorType) {\n const bodySize = entry.decodedBodySize / 1000;\n rt.value[entry.initiatorType] += bodySize;\n rt.value.total += bodySize;\n }\n });\n};\n","import {\n onCLS,\n onFCP,\n onFID,\n onINP,\n onLCP,\n onTTFB,\n} from 'web-vitals/attribution';\n\nimport { config } from './config';\nimport { initElementTiming } from './element-timing';\nimport { logMetric } from './log';\nimport { po } from './performanceObserver';\nimport { initResourceTiming } from './resourceTiming';\n\nexport const initPerformanceObserver = (): void => {\n onTTFB((report) => {\n if (report.value > 0) {\n // @ts-ignore\n logMetric(report);\n }\n }, config.reportOptions.ttfb);\n // @ts-ignore\n onCLS((report) => logMetric(report), config.reportOptions.cls);\n // @ts-ignore\n onFCP((report) => logMetric(report), config.reportOptions.fcp);\n // @ts-ignore\n onFID((report) => logMetric(report), config.reportOptions.fid);\n // @ts-ignore\n onLCP((report) => logMetric(report), config.reportOptions.lcp);\n // @ts-ignore\n onINP((report) => logMetric(report), config.reportOptions.inp);\n\n if (config.isResourceTiming) {\n po('resource', initResourceTiming);\n }\n if (config.isElementTiming) {\n po('element', initElementTiming);\n }\n};\n\nexport const disconnectPerfObserversHidden = (): void => {\n // TODO: Use if need it\n};\n","import { logData } from './log';\nimport { convertToKB } from './utils';\n\n/**\n * The estimate() method of the StorageManager interface asks the Storage Manager\n * for how much storage the app takes up (usage),\n * and how much space is available (quota).\n */\nexport const reportStorageEstimate = (storageInfo: StorageEstimate) => {\n const estimateUsageDetails =\n 'usageDetails' in storageInfo ? (storageInfo as any).usageDetails : {};\n logData('storageEstimate', {\n quota: convertToKB((storageInfo as any).quota),\n usage: convertToKB((storageInfo as any).usage),\n caches: convertToKB(estimateUsageDetails.caches),\n indexedDB: convertToKB(estimateUsageDetails.indexedDB),\n serviceWorker: convertToKB(estimateUsageDetails.serviceWorkerRegistrations),\n });\n};\n","export const steps = {\n finalMarkToStepsMap: {} as Record<string, Record<string, string[]>>,\n startMarkToStepsMap: {} as Record<string, Record<string, boolean>>,\n active: {} as Record<string, boolean>,\n /**\n An internal data structure to represent the state of active steps.\n In this data structure, the keys represent the navgiation index, starting at 0 - \n i.e - the initial app launch it's index 0, the first navigation is index 1 and so one.\n The value of each navigation index is a Set of all the first marks for the currently active steps. \n When a start mark is hit - it will be added to this state. \n When a corresponding end mark is hit, the start mark previously added will be removed from this navigation state\n Examples:\n Example of the state when home is loading:\n {\n [0]: ['start_navigate_to_home_screen'] // load home - empty array since home has loaded\n }\n Example of the state during the navigation from home to assets\n {\n [0]: [] // load home - empty array since home has loaded\n [1]: ['start_navigate_to_trade_screen']\n }\n */\n navigationSteps: {} as Record<number, Record<string, boolean>>,\n};\n\n/**\n * This method allows to add new steps by passing the start mark\n */\nexport const addActiveSteps = (startMark: string) => {\n const newSteps = steps.startMarkToStepsMap[startMark] ?? [];\n // adding the new steps to the active map\n Object.keys(newSteps).forEach((step) => {\n if (steps.active[step]) {\n return;\n }\n\n steps.active[step] = true;\n });\n};\n\nexport const resetNavigationSteps = () => {\n steps.navigationSteps = {};\n};\n\n/**\n * Removes one step from active steps\n */\nexport const removeActiveStep = (step: string) => {\n delete steps.active[step];\n};\n\nexport const resetActiveSteps = () => {\n steps.active = {};\n};\n\nexport const resetSteps = () => {\n // reset all values\n steps.startMarkToStepsMap = {};\n steps.finalMarkToStepsMap = {};\n resetActiveSteps();\n resetNavigationSteps();\n};\n\nexport const getNavigationState = () => steps.navigationSteps;\n\nexport const getStepsFromNavigation = (navIndex: number) => {\n const navigationSteps = getNavigationState();\n return navigationSteps[navIndex] ?? {};\n};\n","import { config } from '../config';\nimport { IStepConfig } from '../types';\n\nimport { resetSteps, steps } from './steps';\n\nexport const setStepsMap = () => {\n if (!config.steps) {\n return;\n }\n resetSteps();\n\n Object.entries<IStepConfig<string>>(config.steps).forEach(\n ([step, { marks }]) => {\n const startMark = marks[0];\n const endMark = marks[1];\n // getting the current steps associated with the current start mark\n const currentStartMarks = steps.startMarkToStepsMap[startMark] ?? {};\n currentStartMarks[step] = true;\n steps.startMarkToStepsMap[startMark] = currentStartMarks;\n\n if (!steps.finalMarkToStepsMap[endMark]) {\n // insert when top level end mark is not present\n steps.finalMarkToStepsMap[endMark] = { [startMark]: [step] };\n } else {\n // insert when end mark and start mark are both present\n const currentSteps =\n steps.finalMarkToStepsMap[endMark][startMark] || [];\n currentSteps.push(step);\n steps.finalMarkToStepsMap[endMark][startMark] = currentSteps;\n }\n },\n );\n};\n","/**\n * Perfume.js v9.4.1 (http://zizzamia.github.io/perfume)\n * Copyright 2022 Leonardo Zizzamia (https://github.com/Zizzamia/perfume.js/graphs/contributors)\n * Licensed under MIT (https://github.com/Zizzamia/perfume.js/blob/master/LICENSE)\n *\n * @license\n */\nimport { config } from './config';\nimport { W, WN } from './constants';\nimport { getNavigationTiming } from './getNavigationTiming';\nimport { getNetworkInformation } from './getNetworkInformation';\nimport { isPerformanceSupported } from './isSupported';\nimport { logData, logMetric } from './log';\nimport { initPerformanceObserver } from './observe';\nimport { didVisibilityChange } from './onVisibilityChange';\nimport { reportStorageEstimate } from './storageEstimate';\nimport { IPerfumeOptions } from './types';\nimport { getVitalsScore } from './vitalsScore';\nimport { setStepsMap } from './steps/setStepsMap';\n\nexport const initPerfume = (options: IPerfumeOptions = {}) => {\n // Extend default config with external options\n config.analyticsTracker = options.analyticsTracker;\n config.isResourceTiming = !!options.resourceTiming;\n config.isElementTiming = !!options.elementTiming;\n config.maxTime = options.maxMeasureTime || config.maxTime;\n config.reportOptions = options.reportOptions || config.reportOptions;\n config.steps = options.steps;\n config.onMarkStep = options.onMarkStep;\n\n // Exit from Perfume when basic Web Performance APIs aren't supported\n if (!isPerformanceSupported()) {\n return;\n }\n // Checks if use Performance or the EmulatedPerformance instance\n if ('PerformanceObserver' in W) {\n initPerformanceObserver();\n }\n\n // Init visibilitychange listener\n if (typeof document.hidden !== 'undefined') {\n // Opera 12.10 and Firefox 18 and later support\n document.addEventListener('visibilitychange', didVisibilityChange);\n }\n\n const navigationTiming = getNavigationTiming();\n // Log Navigation Timing\n logData('navigationTiming', navigationTiming);\n if (navigationTiming.redirectTime) {\n logMetric({\n attribution: {},\n name: `RT`,\n rating: getVitalsScore('RT', navigationTiming.redirectTime),\n value: navigationTiming.redirectTime,\n });\n }\n // Log Network Information\n logData('networkInformation', getNetworkInformation());\n // Let's estimate our storage capacity\n if (WN && WN.storage && typeof WN.storage.estimate === 'function') {\n WN.storage\n .estimate()\n .then(reportStorageEstimate)\n .catch(() => {});\n }\n // initializing Steps if present\n if (config.steps) {\n setStepsMap();\n }\n};\n","import { WP } from './constants';\n\n/**\n * Get the duration of the timing metric or -1\n * if there a measurement has not been made by the User Timing API\n */\nexport const performanceMeasure = (measureName: string): number => {\n WP.measure(\n measureName,\n `mark_${measureName}_start`,\n `mark_${measureName}_end`,\n );\n const entry = WP.getEntriesByName(measureName).pop();\n if (entry && entry.entryType === 'measure') {\n return entry.duration;\n }\n return -1;\n};\n","import { M, S, WP } from '../constants';\nimport { reportPerf } from '../reportPerf';\nimport { config } from '../config';\n\nimport { STEP_THRESHOLDS, getRating } from '../vitalsScore';\n\nexport const measureStep = (\n step: string,\n startMark: string,\n endMark: string,\n) => {\n const stepMetricName = S + step;\n const startMarkExists = WP.getEntriesByName(M + startMark).length > 0;\n const endMarkExists = WP.getEntriesByName(M + endMark).length > 0;\n if (\n !endMarkExists ||\n !startMarkExists ||\n !config.steps ||\n !config.steps[step]\n ) {\n return;\n }\n\n const { maxOutlierThreshold, vitalsThresholds } =\n STEP_THRESHOLDS[config.steps[step].threshold];\n\n const stepMeasure = WP.measure(stepMetricName, M + startMark, M + endMark);\n\n // checking to ensure stepMeasure is defined - it can be undefined\n // if measure is called on a mark that has already been measured and cleared\n if (!stepMeasure) {\n return;\n }\n\n const { duration } = stepMeasure;\n if (duration <= maxOutlierThreshold) {\n const score = getRating(duration, vitalsThresholds);\n // Do not want to measure or log negative metrics\n if (duration >= 0) {\n reportPerf(\n 'userJourneyStep',\n duration,\n score,\n { stepName: step },\n undefined,\n );\n WP.measure(`step.${step}_vitals_${score}`, {\n start: stepMeasure.startTime + stepMeasure.duration,\n end: stepMeasure.startTime + stepMeasure.duration,\n detail: {\n type: 'stepVital',\n duration,\n },\n });\n }\n }\n};\n","import { config } from './../config';\nimport { getNavigationState, getStepsFromNavigation, steps } from './steps';\n\n/**\n * We only report the active steps in the last 2 navigation step to prevent\n * Convert the steps.navigationSteps to an array of active steps.\n * \"stale steps\" from being reported.\n *\n * \"stale steps\" are defined as steps where the start mark was executed but the\n * corresponding end mark was never executed - thus leaving it as a \"stale step\"\n */\nexport const getActiveStepsFromNavigationSteps = (): Record<\n string,\n boolean\n> => {\n const navigationSteps = getNavigationState();\n const { startMarkToStepsMap } = steps;\n const numberOfSteps = Object.keys(navigationSteps).length;\n if (numberOfSteps === 0) {\n return {};\n }\n\n const activeSteps: Record<string, boolean> = {};\n const currentNavIndex = numberOfSteps - 1;\n\n const currentNavStep = getStepsFromNavigation(currentNavIndex);\n\n Object.keys(currentNavStep).forEach((startMark: string) => {\n const ongoingSteps = startMarkToStepsMap[startMark] ?? [];\n Object.keys(ongoingSteps).forEach((step) => {\n activeSteps[step] = true;\n });\n });\n\n // if nav length is >1, then check the nav step prior as well\n if (numberOfSteps > 1) {\n const prevNavStep = getStepsFromNavigation(currentNavIndex - 1);\n\n Object.keys(prevNavStep).forEach((startMark: string) => {\n const prevNavSteps = startMarkToStepsMap[startMark] ?? [];\n Object.keys(prevNavSteps).forEach((step) => {\n activeSteps[step] = true;\n });\n });\n }\n\n return activeSteps;\n};\n\n// start mark for navigationSteps data structure\nexport const recordStartMark = (startMark: string) => {\n const { navigationSteps } = steps;\n const numberOfSteps = Object.keys(navigationSteps).length;\n\n // if we don't have any initial states recorded, initialize one\n const navigationLength = numberOfSteps > 0 ? numberOfSteps : 1;\n const lastNavIndex = navigationLength - 1;\n const currentMarks = getStepsFromNavigation(lastNavIndex) || [];\n\n const newCurrentMark = currentMarks;\n newCurrentMark[startMark] = true;\n navigationSteps[lastNavIndex] = newCurrentMark;\n};\n\nexport const recordEndMark = (endMark: string) => {\n const { navigationSteps, finalMarkToStepsMap } = steps;\n\n const navigationLength = Object.keys(navigationSteps).length;\n if (navigationLength === 0) {\n return;\n }\n\n const currentNavIndex = navigationLength - 1;\n const ongoingNavStep = getStepsFromNavigation(currentNavIndex);\n\n if (!ongoingNavStep || !finalMarkToStepsMap[endMark]) {\n return;\n }\n\n const endMarkMap = finalMarkToStepsMap[endMark];\n if (!endMarkMap) {\n return;\n }\n\n /**\n * loop through all steps where end mark is present and check if their start mark is present\n * in the navigation state. If so, remove it to signal that the step has been completed\n */\n Object.keys(endMarkMap).forEach((startMark) => {\n if (ongoingNavStep[startMark]) {\n const currentNavStep = getStepsFromNavigation(currentNavIndex) || {};\n\n // Only remove the startMark, not other ongoing steps\n currentNavStep[startMark] = false;\n // if start mark is in navigation state, remove it to signal that the step has completed\n navigationSteps[currentNavIndex] = currentNavStep;\n }\n\n // if nav length is >1, then check the nav step prior as well\n if (navigationLength > 1) {\n const lastNavIndex = currentNavIndex - 1;\n const lastNavStep = getStepsFromNavigation(lastNavIndex);\n if (lastNavStep[startMark]) {\n lastNavStep[startMark] = false;\n navigationSteps[lastNavIndex] = lastNavStep;\n }\n }\n });\n};\n\n/**\n * An API consumers must use to update internal state based on page/screen navigations.\n * Internal state must be updated when the following are true\n * 1. Journey marks are hit\n * 2. Page navigations occur\n * This function ensures the 2nd case is covered to help prevent \"stale\"\n * steps that don't hit their final mark because the users navigates\n * backwards in journey.\n */\nexport const trackUJNavigation = () => {\n // navigationSteps are 0-index based, so size will give us the next key value\n const navigationLength = Object.keys(steps.navigationSteps).length;\n steps.navigationSteps[navigationLength] = {};\n\n // when navigating, we should notify the user in case stale steps are\n // removed from the state during navigations\n const activeSteps = getActiveStepsFromNavigationSteps();\n config.onMarkStep?.('', Object.keys(activeSteps));\n};\n","import { config } from '../config';\n\nimport { measureStep } from './measureStep';\nimport { steps, addActiveSteps, removeActiveStep } from './steps';\nimport {\n getActiveStepsFromNavigationSteps,\n recordEndMark,\n recordStartMark,\n} from './navigationSteps';\n\nexport const measureSteps = (mark: string) => {\n if (steps.finalMarkToStepsMap[mark]) {\n recordEndMark(mark);\n // this is an end mark so we delete the entry\n const finalSteps = steps.finalMarkToStepsMap[mark];\n Object.keys(finalSteps).forEach((startMark) => {\n const possibleSteps = finalSteps[startMark];\n possibleSteps.forEach(removeActiveStep);\n // Async processing all possible steps\n // needs to be async due to clearing previously measured steps and marks.\n // If we run all concurrently, there is a chance for a race condition\n // where we are adding and deleteing the entries in WP.Performance which caused the measure to fail.\n Promise.all(\n possibleSteps.map(async (step) => {\n // measure\n // eslint-disable-next-line @typescript-eslint/await-thenable\n await measureStep(step, startMark, mark);\n }),\n ).catch(() => {\n // TODO @zizzamia log error\n });\n });\n } else {\n recordStartMark(mark);\n addActiveSteps(mark);\n }\n const navigationBasedActiveSteps = getActiveStepsFromNavigationSteps();\n config.onMarkStep?.(mark, Object.keys(navigationBasedActiveSteps));\n};\n","import { M, WP } from '../constants';\nimport { isPerformanceSupported } from '../isSupported';\nimport { logData } from '../log';\nimport { performanceMeasure } from '../measure';\nimport { metrics } from '../metrics';\nimport { roundByFour } from '../utils';\n\nimport { measureSteps } from './measureSteps';\n\n/**\n * Function which creates a step mark with a name generated\n * from the provided mark when called.\n *\n * The generated mark name has the following format:\n * `mark.${mark}`\n *\n */\nexport const markStep = (mark: string) => {\n if (!isPerformanceSupported()) {\n return;\n }\n WP.mark(M + mark);\n measureSteps(mark);\n};\n\n// --------------------- TMP Location Before Deprecation -----------------\n// For start(), end(), clear()\n\n/**\n * Start performance measurement\n */\nexport const start = (markName: string): void => {\n if (!isPerformanceSupported() || metrics[markName]) {\n return;\n }\n metrics[markName] = true;\n // Creates a timestamp in the browser's performance entry buffer\n WP.mark(`mark_${markName}_start`);\n};\n\n/**\n * End performance measurement\n */\nexport const end = (\n markName: string,\n customProperties = {},\n doLogData = true,\n): void => {\n if (!isPerformanceSupported() || !metrics[markName]) {\n return;\n }\n // End Performance Mark\n WP.mark(`mark_${markName}_end`);\n delete metrics[markName];\n const measure = performanceMeasure(markName);\n if (doLogData) {\n logData(markName, roundByFour(measure), customProperties);\n }\n};\n\n/**\n * Removes the named mark from the browser's performance entry buffer.\n */\nexport const clear = (markName: string): void => {\n delete metrics[markName];\n // Mobile Safari v13 and UC Browser v11\n // don't support clearMarks yet\n if (!WP.clearMarks) {\n return;\n }\n WP.clearMarks(`mark_${markName}_start`);\n WP.clearMarks(`mark_${markName}_end`);\n};\n","import { M, WP } from '../constants';\n\nimport { measureSteps } from './measureSteps';\n\n/**\n * Function which creates a step mark with a name generated\n * from the provided mark if a mark with the same name does not\n * already exist when called.\n *\n * The generated mark name has the following format:\n * `mark.${mark}`\n *\n */\nexport const markStepOnce = (mark: string) => {\n if (WP.getEntriesByName(M + mark).length === 0) {\n WP.mark(M + mark);\n measureSteps(mark);\n }\n};\n","import { ntbt } from './metrics';\nimport { logMetric } from './log';\nimport { getVitalsScore } from './vitalsScore';\n\nimport { end, start } from './steps/markStep';\n\nlet ntbtTimeoutID = 0;\n\n/**\n * NTBT = Navigation Total Blocking Time\n *\n * This metric measures the amount of time the application may be blocked\n * from processing code during the 2s window after a user navigates\n * from page A to page B.\n *\n * Because this library is navigation agnostic, we have this method\n * to mark when the navigation starts.\n *\n * The NTBT metric is the summation of the blocking time of all long tasks\n * in the 2s window after this method is invoked.\n *\n * If this method is called before the 2s window ends; it will trigger a new\n * NTBT measurement and interrupt the previous one.\n *\n * Credit: Thank you Steven Lam for helping with this!\n */\nexport const markNTBT = (): void => {\n start('ntbt');\n // Reset NTBT value\n ntbt.value = 0;\n clearTimeout(ntbtTimeoutID);\n // @ts-ignore\n ntbtTimeoutID = setTimeout(() => {\n end('ntbt', {}, false);\n logMetric({\n attribution: {},\n name: `NTBT`,\n rating: getVitalsScore('NTBT', ntbt.value),\n value: ntbt.value,\n });\n ntbt.value = 0;\n }, 2000);\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,78 @@
1
1
  {
2
2
  "name": "@tinkoff/perfume",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "Web performance library for measuring all User-centric performance metrics, including the latest Web Vitals.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "typings": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "author": "Leonardo Zizzamia",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/tramvaijs/perfume"
16
+ },
17
+ "license": "MIT",
18
+ "engines": {
19
+ "node": ">=22.23.4"
20
+ },
21
+ "scripts": {
22
+ "lint": "eslint src",
23
+ "prebuild": "rimraf dist",
24
+ "build": "tsdown",
25
+ "start": "tsdown -w",
26
+ "test": "jest",
27
+ "test:watch": "jest --watch",
28
+ "typecheck": "tsc --noEmit"
29
+ },
30
+ "dependencies": {
31
+ "web-vitals": "^3.5.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/jest": "^30.0.0",
35
+ "@types/node": "^22.20.5",
36
+ "@typescript-eslint/eslint-plugin": "^8.72.0",
37
+ "@typescript-eslint/parser": "^8.72.0",
38
+ "coveralls": "^3.1.1",
39
+ "eslint": "^10.13.0",
40
+ "eslint-plugin-import": "^2.32.0",
41
+ "eslint-plugin-jsdoc": "^65.3.15",
42
+ "jest": "^30.5.2",
43
+ "jest-environment-jsdom": "^30.5.2",
44
+ "prettier": "^3.9.10",
45
+ "rimraf": "3.0.2",
46
+ "semantic-release": "^25.0.9",
47
+ "ts-jest": "^29.4.15",
48
+ "tsdown": "^0.23.1",
49
+ "typescript": "^6"
50
+ },
51
+ "keywords": [
52
+ "performance",
53
+ "performance-metrics",
54
+ "metrics",
55
+ "navigation-timing",
56
+ "time-to-first-byte",
57
+ "ttfb",
58
+ "navigator-interface",
59
+ "resource-timing",
60
+ "service-worker-status",
61
+ "storageManager-interface",
62
+ "first-paint",
63
+ "fp",
64
+ "first-contentful-paint",
65
+ "fcp",
66
+ "first-input-delay",
67
+ "fid",
68
+ "largest-contentful-paint",
69
+ "lcp",
70
+ "cumulative-layout-shift",
71
+ "cls",
72
+ "total-blocking-time",
73
+ "tbt",
74
+ "element-timing",
75
+ "web-vitals"
76
+ ],
77
+ "packageManager": "yarn@4.18.1"
78
+ }