UNPKG

@zendesk/retrace

Version:

define and capture Product Operation Traces along with computed metrics with an optional friendly React beacon API

139 lines 4.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FMP = exports.Check = exports.Idle = exports.LongTask = exports.Render = void 0; exports.makeEntries = makeEntries; exports.getSpansFromTimeline = getSpansFromTimeline; const Render = (name, duration, options = {}) => ({ entryType: 'component-render', name, duration, startTime: options.startTime, isIdle: (options.renderedOutput === 'content' || options.renderedOutput === 'error') ?? options.isIdle, ...options, }); exports.Render = Render; const LongTask = (duration, options = {}) => ({ entryType: 'longtask', duration, startTime: options.start, name: 'task', }); exports.LongTask = LongTask; const Idle = (duration) => ({ entryType: 'idle', duration, }); exports.Idle = Idle; exports.Check = { entryType: 'mark', name: 'check', }; exports.FMP = { entryType: 'fmp', }; function makeEntries(events) { const entries = []; let currentTime = 0; let fmpTime = null; for (const event of events) { const thisEventStartTime = 'startTime' in event && event.startTime !== undefined && event.startTime; const eventStartTime = thisEventStartTime !== false ? thisEventStartTime : currentTime; const eventDuration = 'duration' in event ? event.duration : 0; switch (event.entryType) { case 'idle': break; case 'fmp': fmpTime = eventStartTime; if (event.startTime === undefined) fmpTime = currentTime; // fallthrough on purpose // eslint-disable-next-line no-fallthrough default: entries.push({ entryType: event.entryType, name: 'name' in event ? event.name : event.entryType, startTime: eventStartTime, duration: eventDuration, }); break; } // Update `currentTime` only if `startTime` is not predefined if (thisEventStartTime === false) { currentTime = eventStartTime + eventDuration; } } return { entries, fmpTime }; } function getSpansFromTimeline(_, ...exprs) { const spans = []; let fmpTime = null; const stubs = exprs.filter((expr) => typeof expr !== 'number'); const allNumbers = exprs.filter((expr) => typeof expr === 'number'); let startTime; let time; if (allNumbers.length === stubs.length + 1) { startTime = allNumbers[0]; time = allNumbers.slice(1); } else if (allNumbers.length === stubs.length) { startTime = allNumbers[0]; time = allNumbers; } else { throw new Error('Invalid timeline, mismatch of events and timestamps'); } if (startTime === undefined) { throw new Error('No time provided for the beginning of the timeline'); } for (let i = 0; i < time.length; i++) { const currentTime = time[i]; const stub = stubs[i]; if (!stub || typeof currentTime !== 'number') { throw new Error('Invalid timeline, mismatch of events and timestamps'); } if (stub.entryType === 'fmp') { fmpTime = currentTime; } const now = 'startTime' in stub ? stub.startTime ?? currentTime : currentTime; spans.push({ type: stub.entryType, duration: 0, name: `${stub.entryType}`, ...stub, startTime: { now, epoch: now, }, isIdle: 'isIdle' in stub ? stub.isIdle : 'name' in stub ? stub.name?.includes('idle') : undefined, renderedOutput: 'renderedOutput' in stub ? stub.renderedOutput : 'name' in stub ? stub.name?.includes('idle') ? 'content' : 'loading' : undefined, performanceEntry: { duration: 0, name: `${stub.entryType}`, ...stub, startTime: 'startTime' in stub ? stub.startTime ?? currentTime : currentTime, toJSON: () => { }, }, id: `span-${i}-${now}-${stub.entryType}-${'duration' in stub ? stub.duration : 0}`, }); } return { spans, fmpTime }; } // example usage // const timeline = getEventsFromTimeline` // Events: ----------${FMP}-----${Task(50)}-------${Task(100)}-------${Task(200)}-------${Check} // Time: ${0} ${200} ${300} ${350} ${550} ${700} // ` // console.log(timeline) //# sourceMappingURL=makeTimeline.js.map