@code-pushup/utils
Advanced tools
| import type { PerformanceEntry, PerformanceMark, PerformanceMeasure } from 'node:perf_hooks'; | ||
| import type { UserTimingDetail } from '../user-timing-extensibility-api.type.js'; | ||
| import type { BeginEvent, CompleteEvent, EndEvent, InstantEvent, InstantEventArgs, InstantEventTracingStartedInBrowser, SpanEventArgs, TraceEvent, TraceEventContainer, TraceEventRaw, TraceMetadata, UserTimingTraceEvent } from './trace-file.type.js'; | ||
| /** | ||
| * Generates a unique ID for linking begin and end span events in Chrome traces. | ||
| * @returns Object with local ID string for the id2 field | ||
| */ | ||
| export declare const nextId2: () => { | ||
| local: string; | ||
| }; | ||
| /** | ||
| * Generates a unique frame tree node ID from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Combined numeric ID | ||
| */ | ||
| export declare const frameTreeNodeId: (pid: number, tid: number) => number; | ||
| /** | ||
| * Generates a frame name string from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Formatted frame name | ||
| */ | ||
| export declare const frameName: (pid: number, tid: number) => string; | ||
| /** | ||
| * Creates an instant trace event for marking a point in time. | ||
| * @param opt - Event configuration options | ||
| * @returns InstantEvent object | ||
| */ | ||
| export declare const getInstantEvent: (opt: { | ||
| name: string; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| args?: InstantEventArgs; | ||
| }) => InstantEvent; | ||
| /** | ||
| * Creates a start tracing event with frame information. | ||
| * This event is needed at the beginning of the traceEvents array to make tell the UI profiling has started, and it should visualize the data. | ||
| * @param opt - Tracing configuration options | ||
| * @returns StartTracingEvent object | ||
| */ | ||
| export declare const getInstantEventTracingStartedInBrowser: (opt: { | ||
| url: string; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => InstantEventTracingStartedInBrowser; | ||
| /** | ||
| * Creates a complete trace event with duration. | ||
| * @param opt - Event configuration with name and duration | ||
| * @returns CompleteEvent object | ||
| */ | ||
| export declare const getCompleteEvent: (opt: { | ||
| name: string; | ||
| dur: number; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => CompleteEvent; | ||
| /** Options for creating span events */ | ||
| type SpanOpt = { | ||
| name: string; | ||
| id2: { | ||
| local: string; | ||
| }; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| args?: SpanEventArgs; | ||
| }; | ||
| /** | ||
| * Creates a begin span event. | ||
| * @param ph - Phase ('b' for begin) | ||
| * @param opt - Span event options | ||
| * @returns BeginEvent object | ||
| */ | ||
| export declare function getSpanEvent(ph: 'b', opt: SpanOpt): BeginEvent; | ||
| /** | ||
| * Creates an end span event. | ||
| * @param ph - Phase ('e' for end) | ||
| * @param opt - Span event options | ||
| * @returns EndEvent object | ||
| */ | ||
| export declare function getSpanEvent(ph: 'e', opt: SpanOpt): EndEvent; | ||
| /** | ||
| * Creates a pair of begin and end span events. | ||
| * @param opt - Span configuration with start/end timestamps | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export declare const getSpan: (opt: { | ||
| name: string; | ||
| tsB: number; | ||
| tsE: number; | ||
| id2?: { | ||
| local: string; | ||
| }; | ||
| pid?: number; | ||
| tid?: number; | ||
| args?: SpanEventArgs; | ||
| tsMarkerPadding?: number; | ||
| }) => [BeginEvent, EndEvent]; | ||
| /** | ||
| * Converts a PerformanceMark to an instant trace event. | ||
| * @param entry - Performance mark entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns InstantEvent object | ||
| */ | ||
| export declare const markToInstantEvent: (entry: PerformanceMark, opt?: { | ||
| name?: string; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => InstantEvent; | ||
| /** | ||
| * Converts a PerformanceMeasure to a pair of span events. | ||
| * @param entry - Performance measure entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export declare const measureToSpanEvents: (entry: PerformanceMeasure, opt?: { | ||
| name?: string; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => [BeginEvent, EndEvent]; | ||
| /** | ||
| * Converts a PerformanceEntry to an array of UserTimingTraceEvents. | ||
| * A mark is converted to an instant event, and a measure is converted to a pair of span events. | ||
| * Other entry types are ignored. | ||
| * @param entry - Performance entry | ||
| * @returns UserTimingTraceEvent[] | ||
| */ | ||
| export declare function entryToTraceEvents(entry: PerformanceEntry): UserTimingTraceEvent[]; | ||
| /** | ||
| * Creates trace metadata object with standard DevTools fields and custom metadata. | ||
| * @param startDate - Optional start date for the trace, defaults to current date | ||
| * @param metadata - Optional additional metadata to merge into the trace metadata | ||
| * @returns TraceMetadata object with source, startTime, and merged custom metadata | ||
| */ | ||
| export declare function getTraceMetadata(startDate?: Date, metadata?: Record<string, unknown>): { | ||
| source: string; | ||
| startTime: string; | ||
| hardwareConcurrency: number; | ||
| dataOrigin: string; | ||
| }; | ||
| /** | ||
| * Creates a complete trace file container with metadata. | ||
| * @param opt - Trace file configuration | ||
| * @returns TraceEventContainer with events and metadata | ||
| */ | ||
| export declare const getTraceFile: (opt: { | ||
| traceEvents: TraceEvent[]; | ||
| startTime?: string; | ||
| metadata?: Partial<TraceMetadata>; | ||
| }) => TraceEventContainer; | ||
| /** | ||
| * Decodes a JSON string detail property back to its original object form. | ||
| * @param target - Object containing a detail property as a JSON string | ||
| * @returns UserTimingDetail with the detail property parsed from JSON | ||
| */ | ||
| export declare function decodeDetail(target: { | ||
| detail: string; | ||
| }): UserTimingDetail; | ||
| /** | ||
| * Encodes object detail properties to JSON strings for storage/transmission. | ||
| * @param target - UserTimingDetail object with detail property to encode | ||
| * @returns UserTimingDetail with object details converted to JSON strings | ||
| */ | ||
| export declare function encodeDetail(target: UserTimingDetail): UserTimingDetail; | ||
| /** | ||
| * Decodes a raw trace event with JSON string details back to typed UserTimingTraceEvent. | ||
| * Parses detail properties from JSON strings to objects. | ||
| * @param event - Raw trace event with string-encoded details | ||
| * @returns UserTimingTraceEvent with parsed detail objects | ||
| */ | ||
| export declare function decodeTraceEvent({ args, ...rest }: TraceEventRaw): UserTimingTraceEvent; | ||
| /** | ||
| * Encodes a UserTimingTraceEvent to raw format with JSON string details. | ||
| * Converts object details to JSON strings for storage/transmission. | ||
| * @param event - UserTimingTraceEvent with object details | ||
| * @returns TraceEventRaw with string-encoded details | ||
| */ | ||
| export declare function encodeTraceEvent({ args, ...rest }: UserTimingTraceEvent): TraceEventRaw; | ||
| export {}; |
| import { threadId } from 'node:worker_threads'; | ||
| import { defaultClock } from '../clock-epoch.js'; | ||
| /** Global counter for generating unique span IDs within a trace */ | ||
| // eslint-disable-next-line functional/no-let | ||
| let id2Count = 0; | ||
| /** | ||
| * Generates a unique ID for linking begin and end span events in Chrome traces. | ||
| * @returns Object with local ID string for the id2 field | ||
| */ | ||
| export const nextId2 = () => ({ local: `0x${++id2Count}` }); | ||
| /** | ||
| * Provides default values for trace event properties. | ||
| * @param opt - Optional overrides for process ID, thread ID, and timestamp | ||
| * @param opt.pid - Process ID override, defaults to current process PID | ||
| * @param opt.tid - Thread ID override, defaults to current thread ID | ||
| * @param opt.ts - Timestamp override in microseconds, defaults to current epoch time | ||
| * @returns Object containing pid, tid, and ts with defaults applied | ||
| */ | ||
| const defaults = (opt) => ({ | ||
| pid: opt?.pid ?? process.pid, | ||
| tid: opt?.tid ?? threadId, | ||
| ts: opt?.ts ?? defaultClock.epochNowUs(), | ||
| }); | ||
| /** | ||
| * Generates a unique frame tree node ID from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Combined numeric ID | ||
| */ | ||
| export const frameTreeNodeId = (pid, tid) => Number.parseInt(`${pid}0${tid}`, 10); | ||
| /** | ||
| * Generates a frame name string from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Formatted frame name | ||
| */ | ||
| export const frameName = (pid, tid) => `FRAME0P${pid}T${tid}`; | ||
| /** | ||
| * Creates an instant trace event for marking a point in time. | ||
| * @param opt - Event configuration options | ||
| * @returns InstantEvent object | ||
| */ | ||
| export const getInstantEvent = (opt) => ({ | ||
| cat: 'blink.user_timing', | ||
| ph: 'i', | ||
| name: opt.name, | ||
| ...defaults(opt), | ||
| args: opt.args ?? {}, | ||
| }); | ||
| /** | ||
| * Creates a start tracing event with frame information. | ||
| * This event is needed at the beginning of the traceEvents array to make tell the UI profiling has started, and it should visualize the data. | ||
| * @param opt - Tracing configuration options | ||
| * @returns StartTracingEvent object | ||
| */ | ||
| export const getInstantEventTracingStartedInBrowser = (opt) => { | ||
| const { pid, tid, ts } = defaults(opt); | ||
| const id = frameTreeNodeId(pid, tid); | ||
| return { | ||
| cat: 'devtools.timeline', | ||
| ph: 'i', | ||
| name: 'TracingStartedInBrowser', | ||
| pid, | ||
| tid, | ||
| ts, | ||
| args: { | ||
| data: { | ||
| frameTreeNodeId: id, | ||
| frames: [ | ||
| { | ||
| frame: frameName(pid, tid), | ||
| isInPrimaryMainFrame: true, | ||
| isOutermostMainFrame: true, | ||
| name: '', | ||
| processId: pid, | ||
| url: opt.url, | ||
| }, | ||
| ], | ||
| persistentIds: true, | ||
| }, | ||
| }, | ||
| }; | ||
| }; | ||
| /** | ||
| * Creates a complete trace event with duration. | ||
| * @param opt - Event configuration with name and duration | ||
| * @returns CompleteEvent object | ||
| */ | ||
| export const getCompleteEvent = (opt) => ({ | ||
| cat: 'devtools.timeline', | ||
| ph: 'X', | ||
| name: opt.name, | ||
| dur: opt.dur, | ||
| ...defaults(opt), | ||
| args: {}, | ||
| }); | ||
| /** | ||
| * Creates a span event (begin or end). | ||
| * @param ph - Phase ('b' or 'e') | ||
| * @param opt - Span event options | ||
| * @returns SpanEvent object | ||
| */ | ||
| export function getSpanEvent(ph, opt) { | ||
| return { | ||
| cat: 'blink.user_timing', | ||
| ph, | ||
| name: opt.name, | ||
| id2: opt.id2, | ||
| ...defaults(opt), | ||
| args: opt.args?.data?.detail | ||
| ? { data: { detail: opt.args.data.detail } } | ||
| : {}, | ||
| }; | ||
| } | ||
| /** | ||
| * Creates a pair of begin and end span events. | ||
| * @param opt - Span configuration with start/end timestamps | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export const getSpan = (opt) => { | ||
| // tsMarkerPadding is here to make the measure slightly smaller so the markers align perfectly. | ||
| // Otherwise, the marker is visible at the start of the measure below the frame | ||
| // No padding Padding | ||
| // spans: ======== |======| | ||
| // marks: | | | ||
| const pad = opt.tsMarkerPadding ?? 1; | ||
| // b|e need to share the same id2 | ||
| const id2 = opt.id2 ?? nextId2(); | ||
| return [ | ||
| getSpanEvent('b', { | ||
| ...opt, | ||
| id2, | ||
| ts: opt.tsB + pad, | ||
| }), | ||
| getSpanEvent('e', { | ||
| ...opt, | ||
| id2, | ||
| ts: opt.tsE - pad, | ||
| }), | ||
| ]; | ||
| }; | ||
| /** | ||
| * Converts a PerformanceMark to an instant trace event. | ||
| * @param entry - Performance mark entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns InstantEvent object | ||
| */ | ||
| export const markToInstantEvent = (entry, opt) => getInstantEvent({ | ||
| ...opt, | ||
| name: opt?.name ?? entry.name, | ||
| ts: defaultClock.fromEntry(entry), | ||
| args: entry.detail ? { detail: entry.detail } : undefined, | ||
| }); | ||
| /** | ||
| * Converts a PerformanceMeasure to a pair of span events. | ||
| * @param entry - Performance measure entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export const measureToSpanEvents = (entry, opt) => getSpan({ | ||
| ...opt, | ||
| name: opt?.name ?? entry.name, | ||
| tsB: defaultClock.fromEntry(entry), | ||
| tsE: defaultClock.fromEntry(entry, true), | ||
| args: entry.detail ? { data: { detail: entry.detail } } : undefined, | ||
| }); | ||
| /** | ||
| * Converts a PerformanceEntry to an array of UserTimingTraceEvents. | ||
| * A mark is converted to an instant event, and a measure is converted to a pair of span events. | ||
| * Other entry types are ignored. | ||
| * @param entry - Performance entry | ||
| * @returns UserTimingTraceEvent[] | ||
| */ | ||
| export function entryToTraceEvents(entry) { | ||
| if (entry.entryType === 'mark') { | ||
| return [markToInstantEvent(entry)]; | ||
| } | ||
| if (entry.entryType === 'measure') { | ||
| return measureToSpanEvents(entry); | ||
| } | ||
| return []; | ||
| } | ||
| /** | ||
| * Creates trace metadata object with standard DevTools fields and custom metadata. | ||
| * @param startDate - Optional start date for the trace, defaults to current date | ||
| * @param metadata - Optional additional metadata to merge into the trace metadata | ||
| * @returns TraceMetadata object with source, startTime, and merged custom metadata | ||
| */ | ||
| export function getTraceMetadata(startDate, metadata) { | ||
| return { | ||
| source: 'DevTools', | ||
| startTime: startDate?.toISOString() ?? new Date().toISOString(), | ||
| hardwareConcurrency: 1, | ||
| dataOrigin: 'TraceEvents', | ||
| ...metadata, | ||
| }; | ||
| } | ||
| /** | ||
| * Creates a complete trace file container with metadata. | ||
| * @param opt - Trace file configuration | ||
| * @returns TraceEventContainer with events and metadata | ||
| */ | ||
| export const getTraceFile = (opt) => ({ | ||
| traceEvents: opt.traceEvents, | ||
| displayTimeUnit: 'ms', | ||
| metadata: getTraceMetadata(opt.startTime ? new Date(opt.startTime) : new Date(), opt.metadata), | ||
| }); | ||
| /** | ||
| * Processes the detail property of an object using a custom processor function. | ||
| * @template T - Object type that may contain a detail property | ||
| * @param target - Object containing the detail property to process | ||
| * @param processor - Function to transform the detail value | ||
| * @returns New object with processed detail property, or original object if no detail | ||
| */ | ||
| function processDetail(target, processor) { | ||
| if (target.detail != null && | ||
| (typeof target.detail === 'string' || typeof target.detail === 'object')) { | ||
| return { ...target, detail: processor(target.detail) }; | ||
| } | ||
| return target; | ||
| } | ||
| /** | ||
| * Decodes a JSON string detail property back to its original object form. | ||
| * @param target - Object containing a detail property as a JSON string | ||
| * @returns UserTimingDetail with the detail property parsed from JSON | ||
| */ | ||
| export function decodeDetail(target) { | ||
| return processDetail(target, detail => typeof detail === 'string' | ||
| ? JSON.parse(detail) | ||
| : detail); | ||
| } | ||
| /** | ||
| * Encodes object detail properties to JSON strings for storage/transmission. | ||
| * @param target - UserTimingDetail object with detail property to encode | ||
| * @returns UserTimingDetail with object details converted to JSON strings | ||
| */ | ||
| export function encodeDetail(target) { | ||
| return processDetail(target, (detail) => typeof detail === 'object' | ||
| ? JSON.stringify(detail) | ||
| : detail); | ||
| } | ||
| /** | ||
| * Decodes a raw trace event with JSON string details back to typed UserTimingTraceEvent. | ||
| * Parses detail properties from JSON strings to objects. | ||
| * @param event - Raw trace event with string-encoded details | ||
| * @returns UserTimingTraceEvent with parsed detail objects | ||
| */ | ||
| export function decodeTraceEvent({ args, ...rest }) { | ||
| if (!args) { | ||
| return rest; | ||
| } | ||
| const processedArgs = decodeDetail(args); | ||
| if ('data' in args && args.data && typeof args.data === 'object') { | ||
| // eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
| return { | ||
| ...rest, | ||
| args: { | ||
| ...processedArgs, | ||
| data: decodeDetail(args.data), | ||
| }, | ||
| }; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
| return { ...rest, args: processedArgs }; | ||
| } | ||
| /** | ||
| * Encodes a UserTimingTraceEvent to raw format with JSON string details. | ||
| * Converts object details to JSON strings for storage/transmission. | ||
| * @param event - UserTimingTraceEvent with object details | ||
| * @returns TraceEventRaw with string-encoded details | ||
| */ | ||
| export function encodeTraceEvent({ args, ...rest }) { | ||
| if (!args) { | ||
| return rest; | ||
| } | ||
| const processedArgs = encodeDetail(args); | ||
| if ('data' in args && args.data && typeof args.data === 'object') { | ||
| const result = { | ||
| ...rest, | ||
| args: { | ||
| ...processedArgs, | ||
| data: encodeDetail(args.data), | ||
| }, | ||
| }; | ||
| return result; | ||
| } | ||
| const result = { ...rest, args: processedArgs }; | ||
| return result; | ||
| } | ||
| //# sourceMappingURL=trace-file-utils.js.map |
| {"version":3,"file":"trace-file-utils.js","sourceRoot":"","sources":["../../../../src/lib/profiler/trace-file-utils.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAkBjD,mEAAmE;AACnE,6CAA6C;AAC7C,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,QAAQ,GAAG,CAAC,GAAiD,EAAE,EAAE,CAAC,CAAC;IACvE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG;IAC5B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,QAAQ;IACzB,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,YAAY,CAAC,UAAU,EAAE;CACzC,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE,CAC1D,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE,CAAC,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAM/B,EAAgB,EAAE,CAAC,CAAC;IACnB,GAAG,EAAE,mBAAmB;IACxB,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,GAAG,QAAQ,CAAC,GAAG,CAAC;IAChB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;CACrB,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sCAAsC,GAAG,CAAC,GAKtD,EAAuC,EAAE;IACxC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAErC,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,EAAE,EAAE,GAAG;QACP,IAAI,EAAE,yBAAyB;QAC/B,GAAG;QACH,GAAG;QACH,EAAE;QACF,IAAI,EAAE;YACJ,IAAI,EAAE;gBACJ,eAAe,EAAE,EAAE;gBACnB,MAAM,EAAE;oBACN;wBACE,KAAK,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;wBAC1B,oBAAoB,EAAE,IAAI;wBAC1B,oBAAoB,EAAE,IAAI;wBAC1B,IAAI,EAAE,EAAE;wBACR,SAAS,EAAE,GAAG;wBACd,GAAG,EAAE,GAAG,CAAC,GAAG;qBACb;iBACF;gBACD,aAAa,EAAE,IAAI;aACpB;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAMhC,EAAiB,EAAE,CAAC,CAAC;IACpB,GAAG,EAAE,mBAAmB;IACxB,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,GAAG,EAAE,GAAG,CAAC,GAAG;IACZ,GAAG,QAAQ,CAAC,GAAG,CAAC;IAChB,IAAI,EAAE,EAAE;CACT,CAAC,CAAC;AA0BH;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,EAAa,EAAE,GAAY;IACtD,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,EAAE;QACF,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,GAAG,QAAQ,CAAC,GAAG,CAAC;QAChB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM;YAC1B,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;YAC5C,CAAC,CAAC,EAAE;KACP,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GASvB,EAA0B,EAAE;IAC3B,+FAA+F;IAC/F,+EAA+E;IAC/E,6BAA6B;IAC7B,6BAA6B;IAC7B,kBAAkB;IAClB,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,IAAI,CAAC,CAAC;IACrC,iCAAiC;IACjC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC;IAEjC,OAAO;QACL,YAAY,CAAC,GAAG,EAAE;YAChB,GAAG,GAAG;YACN,GAAG;YACH,EAAE,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG;SAClB,CAAC;QACF,YAAY,CAAC,GAAG,EAAE;YAChB,GAAG,GAAG;YACN,GAAG;YACH,EAAE,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG;SAClB,CAAC;KACH,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAsB,EACtB,GAAmD,EACrC,EAAE,CAChB,eAAe,CAAC;IACd,GAAG,GAAG;IACN,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI;IAC7B,EAAE,EAAE,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC;IACjC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS;CAC1D,CAAC,CAAC;AAEL;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,KAAyB,EACzB,GAAmD,EAC3B,EAAE,CAC1B,OAAO,CAAC;IACN,GAAG,GAAG;IACN,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI;IAC7B,GAAG,EAAE,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC;IAClC,GAAG,EAAE,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC;IACxC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS;CACpE,CAAC,CAAC;AAEL;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAuB;IAEvB,IAAI,KAAK,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;QAC/B,OAAO,CAAC,kBAAkB,CAAC,KAAwB,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,mBAAmB,CAAC,KAA2B,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAgB,EAChB,QAAkC;IAElC,OAAO;QACL,MAAM,EAAE,UAAU;QAClB,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC/D,mBAAmB,EAAE,CAAC;QACtB,UAAU,EAAE,aAAa;QACzB,GAAG,QAAQ;KACZ,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAI5B,EAAuB,EAAE,CAAC,CAAC;IAC1B,WAAW,EAAE,GAAG,CAAC,WAAW;IAC5B,eAAe,EAAE,IAAI;IACrB,QAAQ,EAAE,gBAAgB,CACxB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EACpD,GAAG,CAAC,QAAQ,CACb;CACF,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,SAAS,aAAa,CACpB,MAAS,EACT,SAAuD;IAEvD,IACE,MAAM,CAAC,MAAM,IAAI,IAAI;QACrB,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,EACxE,CAAC;QACD,OAAO,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAA0B;IACrD,OAAO,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CACpC,OAAO,MAAM,KAAK,QAAQ;QACxB,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAqB;QACzC,CAAC,CAAC,MAAM,CACS,CAAC;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,OAAO,aAAa,CAClB,MAAiD,EACjD,CAAC,MAAuB,EAAE,EAAE,CAC1B,OAAO,MAAM,KAAK,QAAQ;QACxB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAA0B,CAAC;QAC5C,CAAC,CAAC,MAAM,CACO,CAAC;AACxB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,IAAI,EACJ,GAAG,IAAI,EACO;IACd,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAA4B,CAAC;IACtC,CAAC;IAED,MAAM,aAAa,GAAG,YAAY,CAAC,IAA0B,CAAC,CAAC;IAC/D,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjE,yEAAyE;QACzE,OAAO;YACL,GAAG,IAAI;YACP,IAAI,EAAE;gBACJ,GAAG,aAAa;gBAChB,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,IAA0B,CAAC;aACpD;SACsB,CAAC;IAC5B,CAAC;IACD,yEAAyE;IACzE,OAAO,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,aAAa,EAA0B,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,IAAI,EACJ,GAAG,IAAI,EACc;IACrB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,IAAqB,CAAC;IAC/B,CAAC;IAED,MAAM,aAAa,GAAG,YAAY,CAAC,IAAwB,CAAC,CAAC;IAC7D,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACjE,MAAM,MAAM,GAAkB;YAC5B,GAAG,IAAI;YACP,IAAI,EAAE;gBACJ,GAAG,aAAa;gBAChB,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,IAAwB,CAAC;aAClD;SACF,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,MAAM,GAAkB,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IAC/D,OAAO,MAAM,CAAC;AAChB,CAAC"} |
| import type { UserTimingDetail } from '../user-timing-extensibility-api.type.js'; | ||
| /** | ||
| * Arguments for instant trace events. | ||
| * @property {UserTimingDetail} [detail] - Optional user timing detail with DevTools payload | ||
| */ | ||
| export type InstantEventArgs = { | ||
| detail?: UserTimingDetail; | ||
| } & { | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Arguments for span trace events (begin/end events). | ||
| * @property {object} [data] - Optional data object | ||
| * @property {UserTimingDetail} [data.detail] - Optional user timing detail with DevTools payload | ||
| */ | ||
| export type SpanEventArgs = { | ||
| data?: { | ||
| detail?: UserTimingDetail; | ||
| }; | ||
| } & { | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Arguments for complete trace events. | ||
| * @property {Record<string, unknown>} [detail] - Optional detail object with arbitrary properties | ||
| */ | ||
| export type CompleteEventArgs = { | ||
| detail?: Record<string, unknown>; | ||
| }; | ||
| /** | ||
| * Arguments for start tracing events. | ||
| * @property {object} data - Tracing initialization data | ||
| * @property {number} data.frameTreeNodeId - Frame tree node identifier | ||
| * @property {Array} data.frames - Array of frame information | ||
| * @property {boolean} data.persistentIds - Whether IDs are persistent | ||
| */ | ||
| export type InstantEventTracingStartedInBrowserArgs = { | ||
| data: { | ||
| frameTreeNodeId: number; | ||
| frames: { | ||
| frame: string; | ||
| isInPrimaryMainFrame: boolean; | ||
| isOutermostMainFrame: boolean; | ||
| name: string; | ||
| processId: number; | ||
| url: string; | ||
| }[]; | ||
| persistentIds: boolean; | ||
| }; | ||
| }; | ||
| /** | ||
| * Union type of all possible trace event arguments. | ||
| */ | ||
| export type TraceArgs = InstantEventArgs | SpanEventArgs | CompleteEventArgs | InstantEventTracingStartedInBrowserArgs; | ||
| /** | ||
| * Base properties shared by all trace events. | ||
| * @property {string} cat - Event category | ||
| * @property {string} name - Event name | ||
| * @property {number} pid - Process ID | ||
| * @property {number} tid - Thread ID | ||
| * @property {number} ts - Timestamp in epoch microseconds | ||
| * @property {TraceArgs} [args] - Optional event arguments | ||
| */ | ||
| export type BaseTraceEvent = { | ||
| cat: string; | ||
| name: string; | ||
| pid: number; | ||
| tid: number; | ||
| ts: number; | ||
| args: TraceArgs; | ||
| }; | ||
| /** | ||
| * Start tracing event for Chrome DevTools tracing. | ||
| */ | ||
| export type InstantEventTracingStartedInBrowser = BaseTraceEvent & { | ||
| cat: 'devtools.timeline'; | ||
| ph: 'i'; | ||
| name: 'TracingStartedInBrowser'; | ||
| args: InstantEventTracingStartedInBrowserArgs; | ||
| }; | ||
| /** | ||
| * Complete trace event with duration. | ||
| * Represents a complete operation with start time and duration. | ||
| * @property {'X'} ph - Phase indicator for complete events | ||
| * @property {number} dur - Duration in microseconds | ||
| */ | ||
| export type CompleteEvent = BaseTraceEvent & { | ||
| ph: 'X'; | ||
| dur: number; | ||
| }; | ||
| /** | ||
| * Instant trace event representing a single point in time. | ||
| * Used for user timing marks and other instantaneous events. | ||
| * @property {'blink.user_timing'} cat - Fixed category for user timing events | ||
| * @property {'i'} ph - Phase indicator for instant events | ||
| * @property {never} [dur] - Duration is not applicable for instant events | ||
| * @property {InstantEventArgs} [args] - Optional event arguments | ||
| */ | ||
| export type InstantEvent = Omit<BaseTraceEvent, 'cat' | 'args'> & { | ||
| cat: 'blink.user_timing'; | ||
| ph: 'i'; | ||
| dur?: never; | ||
| args: InstantEventArgs; | ||
| }; | ||
| /** | ||
| * Core properties for span trace events (begin/end pairs). | ||
| * @property {object} id2 - Span identifier | ||
| * @property {string} id2.local - Local span ID (unique to the process, same for b and e events) | ||
| * @property {SpanEventArgs} [args] - Optional event arguments | ||
| */ | ||
| type SpanCore = Omit<BaseTraceEvent, 'args'> & { | ||
| id2: { | ||
| local: string; | ||
| }; | ||
| args: SpanEventArgs; | ||
| }; | ||
| /** | ||
| * Begin event for a span (paired with an end event). | ||
| * @property {'b'} ph - Phase indicator for begin events | ||
| * @property {never} [dur] - Duration is not applicable for begin events | ||
| */ | ||
| export type BeginEvent = SpanCore & { | ||
| ph: 'b'; | ||
| dur?: never; | ||
| }; | ||
| /** | ||
| * End event for a span (paired with a begin event). | ||
| * @property {'e'} ph - Phase indicator for end events | ||
| * @property {never} [dur] - Duration is not applicable for end events | ||
| */ | ||
| export type EndEvent = SpanCore & { | ||
| ph: 'e'; | ||
| dur?: never; | ||
| }; | ||
| /** | ||
| * Union type for span events (begin or end). | ||
| */ | ||
| export type SpanEvent = BeginEvent | EndEvent; | ||
| /** | ||
| * Union type of all trace event types. | ||
| */ | ||
| export type UserTimingTraceEvent = InstantEvent | SpanEvent; | ||
| /** | ||
| * All trace events including system events added during finalization. | ||
| */ | ||
| export type TraceEvent = UserTimingTraceEvent | CompleteEvent | InstantEventTracingStartedInBrowser; | ||
| /** | ||
| * Raw arguments format for trace events before processing. | ||
| * Either contains a detail string directly or nested in a data object. | ||
| */ | ||
| type RawArgs = { | ||
| detail?: string; | ||
| [key: string]: unknown; | ||
| } | { | ||
| data?: { | ||
| detail?: string; | ||
| }; | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Raw trace event format before type conversion. | ||
| * Similar to TraceEvent but with unprocessed arguments. | ||
| */ | ||
| export type TraceEventRaw = Omit<TraceEvent, 'args'> & { | ||
| args: RawArgs; | ||
| }; | ||
| /** | ||
| * Time window bounds (min, max) in trace time units (e.g. microseconds). | ||
| * @property {number} min - Minimum timestamp in the window | ||
| * @property {number} max - Maximum timestamp in the window | ||
| * @property {number} range - Calculated range (max - min) | ||
| */ | ||
| export type BreadcrumbWindow = { | ||
| min: number; | ||
| max: number; | ||
| range: number; | ||
| }; | ||
| /** | ||
| * Custom label for a specific trace entry. | ||
| * @property {number | string} entryId - ID or index of the trace entry | ||
| * @property {string} label - Label text for the entry | ||
| * @property {string} [color] - Optional display color for the label | ||
| */ | ||
| export type EntryLabel = { | ||
| entryId: number | string; | ||
| label: string; | ||
| color?: string; | ||
| }; | ||
| /** | ||
| * Link or relation between two trace entries. | ||
| * @property {number | string} fromEntryId - Source entry ID for the link | ||
| * @property {number | string} toEntryId - Target entry ID for the link | ||
| * @property {string} [linkType] - Optional type or description of the link | ||
| */ | ||
| export type EntryLink = { | ||
| fromEntryId: number | string; | ||
| toEntryId: number | string; | ||
| linkType?: string; | ||
| }; | ||
| /** | ||
| * A time range annotated with a label. | ||
| * @property {number} startTime - Start timestamp of the range (microseconds) | ||
| * @property {number} endTime - End timestamp of the range (microseconds) | ||
| * @property {string} label - Annotation label for the time range | ||
| * @property {string} [color] - Optional display color for the range | ||
| */ | ||
| export type LabelledTimeRange = { | ||
| startTime: number; | ||
| endTime: number; | ||
| label: string; | ||
| color?: string; | ||
| }; | ||
| /** | ||
| * Hidden or expandable entries information. | ||
| * @property {unknown[]} hiddenEntries - IDs or indexes of hidden entries | ||
| * @property {unknown[]} expandableEntries - IDs or indexes of expandable entries | ||
| */ | ||
| export type EntriesModifications = { | ||
| hiddenEntries: unknown[]; | ||
| expandableEntries: unknown[]; | ||
| }; | ||
| /** | ||
| * Initial breadcrumb information for time ranges and window. | ||
| * @property {BreadcrumbWindow} window - Time window bounds | ||
| * @property {unknown | null} child - Child breadcrumb or null | ||
| */ | ||
| export type InitialBreadcrumb = { | ||
| window: BreadcrumbWindow; | ||
| child: unknown | null; | ||
| }; | ||
| /** | ||
| * Annotations such as labels and links between entries. | ||
| * @property {EntryLabel[]} entryLabels - Custom labels for entries | ||
| * @property {LabelledTimeRange[]} labelledTimeRanges - Time ranges annotated with labels | ||
| * @property {EntryLink[]} linksBetweenEntries - Links or relations between entries | ||
| */ | ||
| export type Annotations = { | ||
| entryLabels: EntryLabel[]; | ||
| labelledTimeRanges: LabelledTimeRange[]; | ||
| linksBetweenEntries: EntryLink[]; | ||
| }; | ||
| /** | ||
| * Modifications made to trace data or UI in DevTools export | ||
| */ | ||
| export type Modifications = { | ||
| entriesModifications: EntriesModifications; | ||
| initialBreadcrumb: InitialBreadcrumb; | ||
| annotations: Annotations; | ||
| }; | ||
| /** | ||
| * Top-level metadata for a trace file exported by Chrome DevTools. | ||
| * DevTools may add new fields over time. | ||
| */ | ||
| export type TraceMetadata = { | ||
| /** Usually "DevTools" for exports from the Performance panel */ | ||
| source: string; | ||
| /** ISO timestamp when trace was recorded */ | ||
| startTime: string; | ||
| /** May be present when recorded with throttling settings */ | ||
| hardwareConcurrency?: number; | ||
| /** Common fields found in DevTools traces */ | ||
| cpuThrottling?: number; | ||
| networkThrottling?: string; | ||
| enhancedTraceVersion?: number; | ||
| /** Allow additional custom metadata properties */ | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Structured container for trace events with metadata. | ||
| * @property {TraceEvent[]} traceEvents - Array of trace events | ||
| * @property {'ms' | 'ns'} [displayTimeUnit] - Time unit for display (milliseconds or nanoseconds) | ||
| * @property {TraceMetadata} [metadata] - Optional metadata about the trace | ||
| */ | ||
| export type TraceEventContainer = { | ||
| traceEvents: TraceEvent[]; | ||
| displayTimeUnit?: 'ms' | 'ns'; | ||
| metadata?: TraceMetadata; | ||
| }; | ||
| /** | ||
| * Trace file format - either an array of events or a structured container. | ||
| */ | ||
| export type TraceFile = TraceEvent[] | TraceEventContainer; | ||
| export {}; |
| export {}; | ||
| //# sourceMappingURL=trace-file.type.js.map |
| {"version":3,"file":"trace-file.type.js","sourceRoot":"","sources":["../../../../src/lib/profiler/trace-file.type.ts"],"names":[],"mappings":""} |
| import type { InvalidEntry } from '../wal.js'; | ||
| import type { UserTimingTraceEvent } from './trace-file.type.js'; | ||
| /** | ||
| * Generates a complete Chrome DevTools trace file content as JSON string. | ||
| * Adds margin events around the trace events and includes metadata. | ||
| * @param events - Array of user timing trace events to include | ||
| * @param metadata - Optional custom metadata to include in the trace file | ||
| * @returns JSON string representation of the complete trace file | ||
| */ | ||
| export declare function generateTraceContent(events: UserTimingTraceEvent[], metadata?: Record<string, unknown>): string; | ||
| /** | ||
| * Creates a WAL (Write-Ahead Logging) format configuration for Chrome DevTools trace files. | ||
| * Automatically finalizes shards into complete trace files with proper metadata and margin events. | ||
| * @returns WalFormat configuration object with baseName, codec, extensions, and finalizer | ||
| */ | ||
| export declare function traceEventWalFormat(): { | ||
| baseName: string; | ||
| walExtension: string; | ||
| finalExtension: string; | ||
| codec: { | ||
| encode: (event: UserTimingTraceEvent) => string; | ||
| decode: (json: string) => UserTimingTraceEvent; | ||
| }; | ||
| finalizer: (records: (UserTimingTraceEvent | InvalidEntry<string>)[], metadata?: Record<string, unknown>) => string; | ||
| }; |
| import { defaultClock } from '../clock-epoch.js'; | ||
| import { decodeTraceEvent, encodeTraceEvent, getCompleteEvent, getInstantEventTracingStartedInBrowser, getTraceFile, } from './trace-file-utils.js'; | ||
| /** Name for the trace start margin event */ | ||
| const TRACE_START_MARGIN_NAME = '[trace padding start]'; | ||
| /** Name for the trace end margin event */ | ||
| const TRACE_END_MARGIN_NAME = '[trace padding end]'; | ||
| /** Microseconds of padding to add before/after trace events (1000ms = 1,000,000μs) */ | ||
| const TRACE_MARGIN_US = 1_000_000; | ||
| /** Duration in microseconds for margin events (20ms = 20,000μs) */ | ||
| const TRACE_MARGIN_DURATION_US = 20_000; | ||
| /** | ||
| * Generates a complete Chrome DevTools trace file content as JSON string. | ||
| * Adds margin events around the trace events and includes metadata. | ||
| * @param events - Array of user timing trace events to include | ||
| * @param metadata - Optional custom metadata to include in the trace file | ||
| * @returns JSON string representation of the complete trace file | ||
| */ | ||
| export function generateTraceContent(events, metadata) { | ||
| const traceContainer = getTraceFile({ | ||
| traceEvents: events, | ||
| startTime: new Date().toISOString(), | ||
| metadata: { | ||
| ...metadata, | ||
| generatedAt: new Date().toISOString(), | ||
| }, | ||
| }); | ||
| const marginUs = TRACE_MARGIN_US; | ||
| const marginDurUs = TRACE_MARGIN_DURATION_US; | ||
| const sortedEvents = [...events].sort((a, b) => a.ts - b.ts); | ||
| const fallbackTs = defaultClock.epochNowUs(); | ||
| const firstTs = sortedEvents.at(0)?.ts ?? fallbackTs; | ||
| const lastTs = sortedEvents.at(-1)?.ts ?? fallbackTs; | ||
| const startTs = firstTs - marginUs; | ||
| const endTs = lastTs + marginUs; | ||
| const traceEvents = [ | ||
| getInstantEventTracingStartedInBrowser({ | ||
| ts: startTs, | ||
| url: events.length === 0 ? 'empty-trace' : 'generated-trace', | ||
| }), | ||
| getCompleteEvent({ | ||
| name: TRACE_START_MARGIN_NAME, | ||
| ts: startTs, | ||
| dur: marginDurUs, | ||
| }), | ||
| ...sortedEvents, | ||
| getCompleteEvent({ | ||
| name: TRACE_END_MARGIN_NAME, | ||
| ts: endTs, | ||
| dur: marginDurUs, | ||
| }), | ||
| ]; | ||
| return JSON.stringify({ ...traceContainer, traceEvents }); | ||
| } | ||
| /** | ||
| * Creates a WAL (Write-Ahead Logging) format configuration for Chrome DevTools trace files. | ||
| * Automatically finalizes shards into complete trace files with proper metadata and margin events. | ||
| * @returns WalFormat configuration object with baseName, codec, extensions, and finalizer | ||
| */ | ||
| export function traceEventWalFormat() { | ||
| const baseName = 'trace'; | ||
| const walExtension = '.jsonl'; | ||
| const finalExtension = '.json'; | ||
| return { | ||
| baseName, | ||
| walExtension, | ||
| finalExtension, | ||
| codec: { | ||
| encode: (event) => JSON.stringify(encodeTraceEvent(event)), | ||
| decode: (json) => decodeTraceEvent(JSON.parse(json)), | ||
| }, | ||
| finalizer: (records, metadata) => { | ||
| const validRecords = records.filter((r) => !(typeof r === 'object' && r != null && '__invalid' in r)); | ||
| return generateTraceContent(validRecords, metadata); | ||
| }, | ||
| }; | ||
| } | ||
| //# sourceMappingURL=wal-json-trace.js.map |
| {"version":3,"file":"wal-json-trace.js","sourceRoot":"","sources":["../../../../src/lib/profiler/wal-json-trace.ts"],"names":[],"mappings":"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"} |
+236
| /** | ||
| * Codec for encoding/decoding values to/from strings for WAL storage. | ||
| * Used to serialize/deserialize records written to and read from WAL files. | ||
| */ | ||
| export type Codec<I, O = string> = { | ||
| /** Encode a value to a string for storage */ | ||
| encode: (v: I) => O; | ||
| /** Decode a string back to the original value type */ | ||
| decode: (data: O) => I; | ||
| }; | ||
| export type InvalidEntry<O = string> = { | ||
| __invalid: true; | ||
| raw: O; | ||
| }; | ||
| /** | ||
| * Interface for sinks that can append items. | ||
| * Allows for different types of appendable storage (WAL, in-memory, etc.) | ||
| */ | ||
| export type AppendableSink<T> = { | ||
| append: (item: T) => void; | ||
| }; | ||
| /** | ||
| * Result of recovering records from a WAL file. | ||
| * Contains successfully recovered records and any errors encountered during parsing. | ||
| */ | ||
| export type RecoverResult<T> = { | ||
| /** Successfully recovered records */ | ||
| records: T[]; | ||
| /** Errors encountered during recovery with line numbers and context */ | ||
| errors: { | ||
| lineNo: number; | ||
| line: string; | ||
| error: Error; | ||
| }[]; | ||
| /** Last incomplete line if file was truncated (null if clean) */ | ||
| partialTail: string | null; | ||
| }; | ||
| /** | ||
| * Statistics about the WAL file state and last recovery operation. | ||
| */ | ||
| export type WalStats<T> = { | ||
| /** File path for this WAL */ | ||
| filePath: string; | ||
| /** Whether the WAL file is currently closed */ | ||
| isClosed: boolean; | ||
| /** Whether the WAL file exists on disk */ | ||
| fileExists: boolean; | ||
| /** File size in bytes (0 if file doesn't exist) */ | ||
| fileSize: number; | ||
| /** Last recovery state from the most recent {@link recover} or {@link repack} operation */ | ||
| lastRecovery: RecoverResult<T | InvalidEntry<string>> | null; | ||
| }; | ||
| export declare const createTolerantCodec: <I, O = string>(codec: { | ||
| encode: (v: I) => O; | ||
| decode: (d: O) => I; | ||
| }) => Codec<I | InvalidEntry<O>, O>; | ||
| export declare function filterValidRecords<T>(records: (T | InvalidEntry<unknown>)[]): T[]; | ||
| /** | ||
| * Pure helper function to recover records from WAL file content. | ||
| * @param content - Raw file content as string | ||
| * @param decode - function for decoding records | ||
| * @returns Recovery result with records, errors, and partial tail | ||
| */ | ||
| export declare function recoverFromContent<T>(content: string, decode: Codec<T>['decode']): RecoverResult<T>; | ||
| /** | ||
| * Write-Ahead Log implementation for crash-safe append-only logging. | ||
| * Provides atomic operations for writing, recovering, and repacking log entries. | ||
| */ | ||
| export declare class WriteAheadLogFile<T> implements AppendableSink<T> { | ||
| #private; | ||
| /** | ||
| * Create a new WAL file instance. | ||
| * @param options - Configuration options | ||
| */ | ||
| constructor(options: { | ||
| file: string; | ||
| codec: Codec<T>; | ||
| }); | ||
| /** Get the file path for this WAL */ | ||
| getPath: () => string; | ||
| /** Open the WAL file for writing (creates directories if needed) */ | ||
| open: () => void; | ||
| /** | ||
| * Append a record to the WAL. | ||
| * @param v - Record to append | ||
| * @throws Error if WAL cannot be opened | ||
| */ | ||
| append: (v: T) => void; | ||
| /** Close the WAL file */ | ||
| close: () => void; | ||
| isClosed: () => boolean; | ||
| /** | ||
| * Recover all records from the WAL file. | ||
| * Handles partial writes and decode errors gracefully. | ||
| * Updates the recovery state (accessible via {@link getStats}). | ||
| * @returns Recovery result with records, errors, and partial tail | ||
| */ | ||
| recover(): RecoverResult<T | InvalidEntry<string>>; | ||
| /** | ||
| * Repack the WAL by recovering all valid records and rewriting cleanly. | ||
| * Removes corrupted entries and ensures clean formatting. | ||
| * Updates the recovery state (accessible via {@link getStats}). | ||
| * @param out - Output path (defaults to current file) | ||
| */ | ||
| repack(out?: string): void; | ||
| /** | ||
| * Get comprehensive statistics about the WAL file state. | ||
| * Includes file information, open/close status, and last recovery state. | ||
| * @returns Statistics object with file info and last recovery state | ||
| */ | ||
| getStats(): WalStats<T>; | ||
| } | ||
| /** | ||
| * Format descriptor that binds codec and file extension together. | ||
| * Prevents misconfiguration by keeping related concerns in one object. | ||
| */ | ||
| export type WalFormat<T extends object | string> = { | ||
| /** Base name for the WAL (e.g., "trace") */ | ||
| baseName: string; | ||
| /** Shard file extension (e.g., ".jsonl") */ | ||
| walExtension: string; | ||
| /** Final file extension (e.g., ".json", ".trace.json") falls back to walExtension if not provided */ | ||
| finalExtension: string; | ||
| /** Codec for encoding/decoding records */ | ||
| codec: Codec<T, string>; | ||
| /** Finalizer for converting records to a string */ | ||
| finalizer: (records: (T | InvalidEntry<string>)[], opt?: Record<string, unknown>) => string; | ||
| }; | ||
| export declare const stringCodec: <T extends string | object = string>() => Codec<T>; | ||
| /** | ||
| * Parses a partial WalFormat configuration and returns a complete WalFormat object. | ||
| * All fallback values are targeting string types. | ||
| * - baseName defaults to 'wal' | ||
| * - walExtension defaults to '.log' | ||
| * - finalExtension defaults to '.log' | ||
| * - codec defaults to stringCodec<T>() | ||
| * - finalizer defaults to encoding each record using codec.encode() and joining with newlines. | ||
| * For object types, this properly JSON-stringifies them (not [object Object]). | ||
| * InvalidEntry records use their raw string value directly. | ||
| * @param format - Partial WalFormat configuration | ||
| * @returns Parsed WalFormat with defaults filled in | ||
| */ | ||
| export declare function parseWalFormat<T extends object | string = object>(format: Partial<WalFormat<T>>): WalFormat<T>; | ||
| /** | ||
| * Determines if this process is the leader WAL process using the origin PID heuristic. | ||
| * | ||
| * The leader is the process that first enabled profiling (the one that set CP_PROFILER_ORIGIN_PID). | ||
| * All descendant processes inherit the environment but have different PIDs. | ||
| * | ||
| * @returns true if this is the leader WAL process, false otherwise | ||
| */ | ||
| export declare function isLeaderWal(envVarName: string, profilerID: string): boolean; | ||
| /** | ||
| * Initialize the origin PID environment variable if not already set. | ||
| * This must be done as early as possible before any user code runs. | ||
| * Sets envVarName to the current process ID if not already defined. | ||
| */ | ||
| export declare function setLeaderWal(envVarName: string, profilerID: string): void; | ||
| /** | ||
| * Generates a human-readable shard ID. | ||
| * This ID is unique per process/thread/shard combination and used in the file name. | ||
| * Format: readable-timestamp.pid.threadId.shardCount | ||
| * Example: "20240101-120000-000.12345.1.1" | ||
| * Becomes file: trace.20240101-120000-000.12345.1.1.log | ||
| */ | ||
| export declare function getShardId(): string; | ||
| /** | ||
| * Generates a human-readable sharded group ID. | ||
| * This ID is a globally unique, sortable, human-readable date string per run. | ||
| * Used directly as the folder name to group shards. | ||
| * Format: yyyymmdd-hhmmss-ms | ||
| * Example: "20240101-120000-000" | ||
| */ | ||
| export declare function getShardedGroupId(): string; | ||
| /** | ||
| * Regex patterns for validating WAL ID formats | ||
| */ | ||
| export declare const WAL_ID_PATTERNS: { | ||
| /** Readable date format: yyyymmdd-hhmmss-ms */ | ||
| readonly READABLE_DATE: RegExp; | ||
| /** Group ID format: yyyymmdd-hhmmss-ms */ | ||
| readonly GROUP_ID: RegExp; | ||
| /** Shard ID format: readable-date.pid.threadId.count */ | ||
| readonly SHARD_ID: RegExp; | ||
| }; | ||
| export declare function sortableReadableDateString(timestampMs: string): string; | ||
| /** | ||
| * Generates a path to a shard file using human-readable IDs. | ||
| * Both groupId and shardId are already in readable date format. | ||
| * | ||
| * Example with groupId "20240101-120000-000" and shardId "20240101-120000-000.12345.1.1": | ||
| * Full path: /base/20240101-120000-000/trace.20240101-120000-000.12345.1.1.log | ||
| * | ||
| * @param opt.dir - The directory to store the shard file | ||
| * @param opt.format - The WalFormat to use for the shard file | ||
| * @param opt.groupId - The human-readable group ID (yyyymmdd-hhmmss-ms format) | ||
| * @param opt.shardId - The human-readable shard ID (readable-timestamp.pid.threadId.count format) | ||
| * @returns The path to the shard file | ||
| */ | ||
| export declare function getShardedPath<T extends object | string = object>(opt: { | ||
| dir?: string; | ||
| format: WalFormat<T>; | ||
| groupId: string; | ||
| shardId: string; | ||
| }): string; | ||
| export declare function getShardedFinalPath<T extends object | string = object>(opt: { | ||
| dir?: string; | ||
| format: WalFormat<T>; | ||
| groupId: string; | ||
| }): string; | ||
| /** | ||
| * Sharded Write-Ahead Log manager for coordinating multiple WAL shards. | ||
| * Handles distributed logging across multiple processes/files with atomic finalization. | ||
| */ | ||
| export declare class ShardedWal<T extends object | string = object> { | ||
| #private; | ||
| readonly groupId: string; | ||
| /** | ||
| * Create a sharded WAL manager. | ||
| */ | ||
| constructor(opt: { | ||
| dir?: string; | ||
| format: Partial<WalFormat<T>>; | ||
| groupId?: string; | ||
| }); | ||
| shard(shardId?: string): WriteAheadLogFile<T>; | ||
| /** Get all shard file paths matching this WAL's base name */ | ||
| private shardFiles; | ||
| /** | ||
| * Finalize all shards by merging them into a single output file. | ||
| * Recovers all records from all shards, validates no errors, and writes merged result. | ||
| * @throws Error if any shard contains decode errors | ||
| */ | ||
| finalize(opt?: Record<string, unknown>): void; | ||
| cleanup(): void; | ||
| } |
+411
| /* eslint-disable max-lines */ | ||
| import * as fs from 'node:fs'; | ||
| import path from 'node:path'; | ||
| import process from 'node:process'; | ||
| import { threadId } from 'node:worker_threads'; | ||
| export const createTolerantCodec = (codec) => { | ||
| const { encode, decode } = codec; | ||
| return { | ||
| encode: v => v && typeof v === 'object' && '__invalid' in v | ||
| ? v.raw | ||
| : encode(v), | ||
| decode: d => { | ||
| try { | ||
| return decode(d); | ||
| } | ||
| catch { | ||
| return { __invalid: true, raw: d }; | ||
| } | ||
| }, | ||
| }; | ||
| }; | ||
| export function filterValidRecords(records) { | ||
| return records | ||
| .filter((r) => !(typeof r === 'object' && r != null && '__invalid' in r)) | ||
| .map(r => r); | ||
| } | ||
| /** | ||
| * Pure helper function to recover records from WAL file content. | ||
| * @param content - Raw file content as string | ||
| * @param decode - function for decoding records | ||
| * @returns Recovery result with records, errors, and partial tail | ||
| */ | ||
| export function recoverFromContent(content, decode) { | ||
| const lines = content.split('\n'); | ||
| const clean = content.endsWith('\n'); | ||
| const out = lines.slice(0, -1).reduce((a, l, i) => { | ||
| if (!l) { | ||
| return a; | ||
| } | ||
| try { | ||
| return { | ||
| ...a, | ||
| records: [...a.records, decode(l)], | ||
| }; | ||
| } | ||
| catch (error) { | ||
| return { | ||
| ...a, | ||
| errors: [ | ||
| ...a.errors, | ||
| { lineNo: i + 1, line: l, error: error }, | ||
| ], | ||
| }; | ||
| } | ||
| }, { records: [], errors: [] }); | ||
| const tail = lines.at(-1); | ||
| return { | ||
| ...out, | ||
| partialTail: clean || !tail ? null : tail, | ||
| }; | ||
| } | ||
| /** | ||
| * Write-Ahead Log implementation for crash-safe append-only logging. | ||
| * Provides atomic operations for writing, recovering, and repacking log entries. | ||
| */ | ||
| export class WriteAheadLogFile { | ||
| #fd = null; | ||
| #file; | ||
| #decode; | ||
| #encode; | ||
| #lastRecoveryState = null; | ||
| /** | ||
| * Create a new WAL file instance. | ||
| * @param options - Configuration options | ||
| */ | ||
| constructor(options) { | ||
| this.#file = options.file; | ||
| const c = createTolerantCodec(options.codec); | ||
| this.#decode = c.decode; | ||
| this.#encode = c.encode; | ||
| } | ||
| /** Get the file path for this WAL */ | ||
| getPath = () => this.#file; | ||
| /** Open the WAL file for writing (creates directories if needed) */ | ||
| open = () => { | ||
| if (this.#fd) { | ||
| return; | ||
| } | ||
| ensureDirectoryExistsSync(path.dirname(this.#file)); | ||
| this.#fd = fs.openSync(this.#file, 'a'); | ||
| }; | ||
| /** | ||
| * Append a record to the WAL. | ||
| * @param v - Record to append | ||
| * @throws Error if WAL cannot be opened | ||
| */ | ||
| append = (v) => { | ||
| if (!this.#fd) { | ||
| throw new Error('WAL not opened'); | ||
| } | ||
| fs.writeSync(this.#fd, `${this.#encode(v)}\n`); | ||
| }; | ||
| /** Close the WAL file */ | ||
| close = () => { | ||
| if (this.#fd) { | ||
| fs.closeSync(this.#fd); | ||
| } | ||
| this.#fd = null; | ||
| }; | ||
| isClosed = () => this.#fd == null; | ||
| /** | ||
| * Recover all records from the WAL file. | ||
| * Handles partial writes and decode errors gracefully. | ||
| * Updates the recovery state (accessible via {@link getStats}). | ||
| * @returns Recovery result with records, errors, and partial tail | ||
| */ | ||
| recover() { | ||
| if (!fs.existsSync(this.#file)) { | ||
| this.#lastRecoveryState = { records: [], errors: [], partialTail: null }; | ||
| return this.#lastRecoveryState; | ||
| } | ||
| const txt = fs.readFileSync(this.#file, 'utf8'); | ||
| this.#lastRecoveryState = recoverFromContent(txt, this.#decode); | ||
| return this.#lastRecoveryState; | ||
| } | ||
| /** | ||
| * Repack the WAL by recovering all valid records and rewriting cleanly. | ||
| * Removes corrupted entries and ensures clean formatting. | ||
| * Updates the recovery state (accessible via {@link getStats}). | ||
| * @param out - Output path (defaults to current file) | ||
| */ | ||
| repack(out = this.#file) { | ||
| this.close(); | ||
| const r = this.recover(); | ||
| if (r.errors.length > 0) { | ||
| // eslint-disable-next-line no-console | ||
| console.log('WAL repack encountered decode errors'); | ||
| } | ||
| // Check if any records are invalid entries (from tolerant codec) | ||
| const hasInvalidEntries = r.records.some(rec => typeof rec === 'object' && rec != null && '__invalid' in rec); | ||
| if (hasInvalidEntries) { | ||
| // eslint-disable-next-line no-console | ||
| console.log('Found invalid entries during WAL repack'); | ||
| } | ||
| const recordsToWrite = hasInvalidEntries | ||
| ? r.records | ||
| : filterValidRecords(r.records); | ||
| ensureDirectoryExistsSync(path.dirname(out)); | ||
| fs.writeFileSync(out, `${recordsToWrite.map(this.#encode).join('\n')}\n`); | ||
| } | ||
| /** | ||
| * Get comprehensive statistics about the WAL file state. | ||
| * Includes file information, open/close status, and last recovery state. | ||
| * @returns Statistics object with file info and last recovery state | ||
| */ | ||
| getStats() { | ||
| const fileExists = fs.existsSync(this.#file); | ||
| return { | ||
| filePath: this.#file, | ||
| isClosed: this.#fd == null, | ||
| fileExists, | ||
| fileSize: fileExists ? fs.statSync(this.#file).size : 0, | ||
| lastRecovery: this.#lastRecoveryState, | ||
| }; | ||
| } | ||
| } | ||
| export const stringCodec = () => ({ | ||
| encode: v => (typeof v === 'string' ? v : JSON.stringify(v)), | ||
| decode: v => { | ||
| try { | ||
| return JSON.parse(v); | ||
| } | ||
| catch { | ||
| return v; | ||
| } | ||
| }, | ||
| }); | ||
| /** | ||
| * Parses a partial WalFormat configuration and returns a complete WalFormat object. | ||
| * All fallback values are targeting string types. | ||
| * - baseName defaults to 'wal' | ||
| * - walExtension defaults to '.log' | ||
| * - finalExtension defaults to '.log' | ||
| * - codec defaults to stringCodec<T>() | ||
| * - finalizer defaults to encoding each record using codec.encode() and joining with newlines. | ||
| * For object types, this properly JSON-stringifies them (not [object Object]). | ||
| * InvalidEntry records use their raw string value directly. | ||
| * @param format - Partial WalFormat configuration | ||
| * @returns Parsed WalFormat with defaults filled in | ||
| */ | ||
| export function parseWalFormat(format) { | ||
| const { baseName = 'wal', walExtension = '.log', finalExtension = walExtension, codec = stringCodec(), } = format; | ||
| const finalizer = format.finalizer ?? | ||
| ((records) => { | ||
| // Encode each record using the codec before joining. | ||
| // For object types, codec.encode() will JSON-stringify them properly. | ||
| // InvalidEntry records use their raw string value directly. | ||
| const encoded = records.map(record => typeof record === 'object' && record != null && '__invalid' in record | ||
| ? record.raw | ||
| : codec.encode(record)); | ||
| return `${encoded.join('\n')}\n`; | ||
| }); | ||
| return { | ||
| baseName, | ||
| walExtension, | ||
| finalExtension, | ||
| codec, | ||
| finalizer, | ||
| }; | ||
| } | ||
| /** | ||
| * Determines if this process is the leader WAL process using the origin PID heuristic. | ||
| * | ||
| * The leader is the process that first enabled profiling (the one that set CP_PROFILER_ORIGIN_PID). | ||
| * All descendant processes inherit the environment but have different PIDs. | ||
| * | ||
| * @returns true if this is the leader WAL process, false otherwise | ||
| */ | ||
| export function isLeaderWal(envVarName, profilerID) { | ||
| return process.env[envVarName] === profilerID; | ||
| } | ||
| /** | ||
| * Initialize the origin PID environment variable if not already set. | ||
| * This must be done as early as possible before any user code runs. | ||
| * Sets envVarName to the current process ID if not already defined. | ||
| */ | ||
| export function setLeaderWal(envVarName, profilerID) { | ||
| if (!process.env[envVarName]) { | ||
| // eslint-disable-next-line functional/immutable-data | ||
| process.env[envVarName] = profilerID; | ||
| } | ||
| } | ||
| // eslint-disable-next-line functional/no-let | ||
| let shardCount = 0; | ||
| /** | ||
| * Generates a human-readable shard ID. | ||
| * This ID is unique per process/thread/shard combination and used in the file name. | ||
| * Format: readable-timestamp.pid.threadId.shardCount | ||
| * Example: "20240101-120000-000.12345.1.1" | ||
| * Becomes file: trace.20240101-120000-000.12345.1.1.log | ||
| */ | ||
| export function getShardId() { | ||
| const timestamp = Math.round(performance.timeOrigin + performance.now()); | ||
| const readableTimestamp = sortableReadableDateString(`${timestamp}`); | ||
| return `${readableTimestamp}.${process.pid}.${threadId}.${++shardCount}`; | ||
| } | ||
| /** | ||
| * Generates a human-readable sharded group ID. | ||
| * This ID is a globally unique, sortable, human-readable date string per run. | ||
| * Used directly as the folder name to group shards. | ||
| * Format: yyyymmdd-hhmmss-ms | ||
| * Example: "20240101-120000-000" | ||
| */ | ||
| export function getShardedGroupId() { | ||
| return sortableReadableDateString(`${Math.round(performance.timeOrigin + performance.now())}`); | ||
| } | ||
| /** | ||
| * Regex patterns for validating WAL ID formats | ||
| */ | ||
| export const WAL_ID_PATTERNS = { | ||
| /** Readable date format: yyyymmdd-hhmmss-ms */ | ||
| READABLE_DATE: /^\d{8}-\d{6}-\d{3}$/, | ||
| /** Group ID format: yyyymmdd-hhmmss-ms */ | ||
| GROUP_ID: /^\d{8}-\d{6}-\d{3}$/, | ||
| /** Shard ID format: readable-date.pid.threadId.count */ | ||
| SHARD_ID: /^\d{8}-\d{6}-\d{3}(?:\.\d+){3}$/, | ||
| }; | ||
| export function sortableReadableDateString(timestampMs) { | ||
| const timestamp = Number.parseInt(timestampMs, 10); | ||
| const date = new Date(timestamp); | ||
| const MILLISECONDS_PER_SECOND = 1000; | ||
| const yyyy = date.getFullYear(); | ||
| const mm = String(date.getMonth() + 1).padStart(2, '0'); | ||
| const dd = String(date.getDate()).padStart(2, '0'); | ||
| const hh = String(date.getHours()).padStart(2, '0'); | ||
| const min = String(date.getMinutes()).padStart(2, '0'); | ||
| const ss = String(date.getSeconds()).padStart(2, '0'); | ||
| // eslint-disable-next-line @typescript-eslint/no-magic-numbers | ||
| const ms = String(timestamp % MILLISECONDS_PER_SECOND).padStart(3, '0'); | ||
| return `${yyyy}${mm}${dd}-${hh}${min}${ss}-${ms}`; | ||
| } | ||
| /** | ||
| * Ensures a directory exists, creating it recursively if necessary using sync methods. | ||
| * @param dirPath - The directory path to ensure exists | ||
| */ | ||
| function ensureDirectoryExistsSync(dirPath) { | ||
| if (!fs.existsSync(dirPath)) { | ||
| fs.mkdirSync(dirPath, { recursive: true }); | ||
| } | ||
| } | ||
| /** | ||
| * Generates a path to a shard file using human-readable IDs. | ||
| * Both groupId and shardId are already in readable date format. | ||
| * | ||
| * Example with groupId "20240101-120000-000" and shardId "20240101-120000-000.12345.1.1": | ||
| * Full path: /base/20240101-120000-000/trace.20240101-120000-000.12345.1.1.log | ||
| * | ||
| * @param opt.dir - The directory to store the shard file | ||
| * @param opt.format - The WalFormat to use for the shard file | ||
| * @param opt.groupId - The human-readable group ID (yyyymmdd-hhmmss-ms format) | ||
| * @param opt.shardId - The human-readable shard ID (readable-timestamp.pid.threadId.count format) | ||
| * @returns The path to the shard file | ||
| */ | ||
| export function getShardedPath(opt) { | ||
| const { dir = '', format, groupId, shardId } = opt; | ||
| const { baseName, walExtension } = format; | ||
| return path.join(dir, groupId, `${baseName}.${shardId}${walExtension}`); | ||
| } | ||
| export function getShardedFinalPath(opt) { | ||
| const { dir = '', format, groupId } = opt; | ||
| const { baseName, finalExtension } = format; | ||
| return path.join(dir, groupId, `${baseName}.${groupId}${finalExtension}`); | ||
| } | ||
| /** | ||
| * Sharded Write-Ahead Log manager for coordinating multiple WAL shards. | ||
| * Handles distributed logging across multiple processes/files with atomic finalization. | ||
| */ | ||
| export class ShardedWal { | ||
| groupId = getShardedGroupId(); | ||
| #format; | ||
| #dir = process.cwd(); | ||
| /** | ||
| * Create a sharded WAL manager. | ||
| */ | ||
| constructor(opt) { | ||
| const { dir, format, groupId } = opt; | ||
| this.groupId = groupId ?? getShardedGroupId(); | ||
| if (dir) { | ||
| this.#dir = dir; | ||
| } | ||
| this.#format = parseWalFormat(format); | ||
| } | ||
| shard(shardId = getShardId()) { | ||
| return new WriteAheadLogFile({ | ||
| file: getShardedPath({ | ||
| dir: this.#dir, | ||
| format: this.#format, | ||
| groupId: this.groupId, | ||
| shardId, | ||
| }), | ||
| codec: this.#format.codec, | ||
| }); | ||
| } | ||
| /** Get all shard file paths matching this WAL's base name */ | ||
| shardFiles() { | ||
| if (!fs.existsSync(this.#dir)) { | ||
| return []; | ||
| } | ||
| const groupIdDir = path.dirname(getShardedFinalPath({ | ||
| dir: this.#dir, | ||
| format: this.#format, | ||
| groupId: this.groupId, | ||
| })); | ||
| // create dir if not existing | ||
| ensureDirectoryExistsSync(groupIdDir); | ||
| return fs | ||
| .readdirSync(groupIdDir) | ||
| .filter(entry => entry.endsWith(this.#format.walExtension)) | ||
| .filter(entry => entry.startsWith(`${this.#format.baseName}`)) | ||
| .map(entry => path.join(groupIdDir, entry)); | ||
| } | ||
| /** | ||
| * Finalize all shards by merging them into a single output file. | ||
| * Recovers all records from all shards, validates no errors, and writes merged result. | ||
| * @throws Error if any shard contains decode errors | ||
| */ | ||
| finalize(opt) { | ||
| const fileRecoveries = this.shardFiles().map(f => ({ | ||
| file: f, | ||
| recovery: new WriteAheadLogFile({ | ||
| file: f, | ||
| codec: this.#format.codec, | ||
| }).recover(), | ||
| })); | ||
| const records = fileRecoveries.flatMap(({ recovery }) => recovery.records); | ||
| // Check if any records are invalid entries (from tolerant codec) | ||
| const hasInvalidEntries = records.some(r => typeof r === 'object' && r != null && '__invalid' in r); | ||
| const recordsToFinalize = hasInvalidEntries | ||
| ? records | ||
| : filterValidRecords(records); | ||
| const out = getShardedFinalPath({ | ||
| dir: this.#dir, | ||
| format: this.#format, | ||
| groupId: this.groupId, | ||
| }); | ||
| ensureDirectoryExistsSync(path.dirname(out)); | ||
| fs.writeFileSync(out, this.#format.finalizer(recordsToFinalize, opt)); | ||
| } | ||
| cleanup() { | ||
| this.shardFiles().forEach(f => { | ||
| // Remove the shard file | ||
| fs.unlinkSync(f); | ||
| // Remove the parent directory (shard group directory) | ||
| const shardDir = path.dirname(f); | ||
| try { | ||
| fs.rmdirSync(shardDir); | ||
| } | ||
| catch { | ||
| // Directory might not be empty or already removed, ignore | ||
| } | ||
| }); | ||
| // Also try to remove the root directory if it becomes empty | ||
| try { | ||
| fs.rmdirSync(this.#dir); | ||
| } | ||
| catch { | ||
| // Directory might not be empty or already removed, ignore | ||
| } | ||
| } | ||
| } | ||
| //# sourceMappingURL=wal.js.map |
| {"version":3,"file":"wal.js","sourceRoot":"","sources":["../../../src/lib/wal.ts"],"names":[],"mappings":"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"} |
+2
-2
| { | ||
| "name": "@code-pushup/utils", | ||
| "version": "0.109.0", | ||
| "version": "0.110.0", | ||
| "description": "Low-level utilities (helper functions, etc.) used by Code PushUp CLI", | ||
@@ -30,3 +30,3 @@ "license": "MIT", | ||
| "dependencies": { | ||
| "@code-pushup/models": "0.109.0", | ||
| "@code-pushup/models": "0.110.0", | ||
| "ansis": "^3.3.0", | ||
@@ -33,0 +33,0 @@ "build-md": "^0.4.2", |
| import { type PerformanceEntry } from 'node:perf_hooks'; | ||
| import type { Buffered, Encoder, Observer, Sink } from './sink-source.type'; | ||
| import type { AppendableSink } from './wal.js'; | ||
| export declare const DEFAULT_FLUSH_THRESHOLD = 20; | ||
| export type PerformanceObserverOptions<T> = { | ||
| sink: Sink<T, unknown>; | ||
| sink: AppendableSink<T>; | ||
| encode: (entry: PerformanceEntry) => T[]; | ||
@@ -10,3 +10,3 @@ buffered?: boolean; | ||
| }; | ||
| export declare class PerformanceObserverSink<T> implements Observer, Buffered, Encoder<PerformanceEntry, T[]> { | ||
| export declare class PerformanceObserverSink<T> { | ||
| #private; | ||
@@ -13,0 +13,0 @@ constructor(options: PerformanceObserverOptions<T>); |
@@ -51,3 +51,3 @@ import { PerformanceObserver, performance, } from 'node:perf_hooks'; | ||
| .flatMap(entry => this.encode(entry)) | ||
| .forEach(item => this.#sink.write(item)); | ||
| .forEach(item => this.#sink.append(item)); | ||
| this.#written.set(t, written + fresh.length); | ||
@@ -54,0 +54,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"performance-observer.js","sourceRoot":"","sources":["../../../src/lib/performance-observer.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"performance-observer.js","sourceRoot":"","sources":["../../../src/lib/performance-observer.ts"],"names":[],"mappings":"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"} |
| export declare const PROFILER_ENABLED_ENV_VAR = "CP_PROFILING"; | ||
| export declare const PROFILER_COORDINATOR_FLAG_ENV_VAR = "CP_PROFILER_COORDINATOR"; | ||
| export declare const PROFILER_ORIGIN_PID_ENV_VAR = "CP_PROFILER_ORIGIN_PID"; | ||
| export declare const PROFILER_DIRECTORY_ENV_VAR = "CP_PROFILER_DIR"; | ||
| export declare const PROFILER_BASE_NAME = "trace"; | ||
| export declare const PROFILER_DIRECTORY = "./tmp/profiles"; |
| export const PROFILER_ENABLED_ENV_VAR = 'CP_PROFILING'; | ||
| export const PROFILER_COORDINATOR_FLAG_ENV_VAR = 'CP_PROFILER_COORDINATOR'; | ||
| export const PROFILER_ORIGIN_PID_ENV_VAR = 'CP_PROFILER_ORIGIN_PID'; | ||
| export const PROFILER_DIRECTORY_ENV_VAR = 'CP_PROFILER_DIR'; | ||
| export const PROFILER_BASE_NAME = 'trace'; | ||
| export const PROFILER_DIRECTORY = './tmp/profiles'; | ||
| //# sourceMappingURL=constants.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/lib/profiler/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,cAAc,CAAC"} | ||
| {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../src/lib/profiler/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,cAAc,CAAC;AACvD,MAAM,CAAC,MAAM,iCAAiC,GAAG,yBAAyB,CAAC;AAC3E,MAAM,CAAC,MAAM,2BAA2B,GAAG,wBAAwB,CAAC;AACpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,iBAAiB,CAAC;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAC1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC"} |
| import { type ActionTrackConfigs, type MeasureCtxOptions, type MeasureOptions } from '../user-timing-extensibility-api-utils.js'; | ||
| import type { ActionTrackEntryPayload, DevToolsColor, EntryMeta } from '../user-timing-extensibility-api.type.js'; | ||
| /** | ||
| * Generates a unique profiler ID based on performance time origin, process ID, thread ID, and instance count. | ||
| */ | ||
| export declare function getProfilerId(): string; | ||
| /** | ||
| * Configuration options for creating a Profiler instance. | ||
@@ -44,2 +48,4 @@ * | ||
| #private; | ||
| static instanceCount: number; | ||
| readonly id: string; | ||
| readonly tracks: Record<keyof T, ActionTrackEntryPayload> | undefined; | ||
@@ -46,0 +52,0 @@ /** |
| import process from 'node:process'; | ||
| import { threadId } from 'node:worker_threads'; | ||
| import { isEnvVarEnabled } from '../env.js'; | ||
@@ -6,2 +7,9 @@ import { asOptions, markerPayload, measureCtx, setupTracks, } from '../user-timing-extensibility-api-utils.js'; | ||
| /** | ||
| * Generates a unique profiler ID based on performance time origin, process ID, thread ID, and instance count. | ||
| */ | ||
| export function getProfilerId() { | ||
| // eslint-disable-next-line functional/immutable-data | ||
| return `${Math.round(performance.timeOrigin)}.${process.pid}.${threadId}.${++Profiler.instanceCount}`; | ||
| } | ||
| /** | ||
| * Performance profiler that creates structured timing measurements with Chrome DevTools Extensibility API payloads. | ||
@@ -14,2 +22,4 @@ * | ||
| export class Profiler { | ||
| static instanceCount = 0; | ||
| id = getProfilerId(); | ||
| #enabled; | ||
@@ -16,0 +26,0 @@ #defaults; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../../../src/lib/profiler/profiler.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAIL,SAAS,EACT,aAAa,EACb,UAAU,EACV,WAAW,GACZ,MAAM,2CAA2C,CAAC;AAMnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAqC1D;;;;;;GAMG;AACH,MAAM,OAAO,QAAQ;IACnB,QAAQ,CAAU;IACT,SAAS,CAA0B;IACnC,MAAM,CAAuD;IAC7D,MAAM,CAAgC;IAE/C;;;;;;;;;;;OAWG;IACH,YAAY,OAA2B;QACrC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC;QACzD,MAAM,QAAQ,GAAG,aAAa,CAAC;QAE/B,IAAI,CAAC,QAAQ,GAAG,OAAO,IAAI,eAAe,CAAC,wBAAwB,CAAC,CAAC;QACrE,IAAI,CAAC,SAAS,GAAG,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,MAAM;YAClB,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC;YAChD,CAAC,CAAC,SAAS,CAAC;QACd,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;YACvB,GAAG,QAAQ;YACX,QAAQ;YACR,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,UAAU,CAAC,OAAgB;QACzB,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,GAAG,GAAG,OAAO,EAAE,CAAC;QACrD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED;;;;;;OAMG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,IAAY,EAAE,GAAmB;QACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QAED,WAAW,CAAC,IAAI,CACd,IAAI,EACJ,SAAS,CACP,aAAa,CAAC;YACZ,gDAAgD;YAChD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,GAAG,GAAG;SACP,CAAC,CACH,CACF,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAI,KAAa,EAAE,IAAa,EAAE,OAA2B;QAClE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9D,KAAK,EAAE,CAAC;QACR,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,CAAC,CAAC,CAAC;YACX,OAAO,CAAC,CAAC;QACX,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,CAAC;YACd,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,YAAY,CAChB,KAAa,EACb,IAAsB,EACtB,OAA2B;QAE3B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,MAAM,IAAI,EAAE,CAAC;QACtB,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC9D,KAAK,EAAE,CAAC;QACR,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,IAAI,EAAE,CAAC;YACvB,OAAO,CAAC,CAAC,CAAC,CAAC;YACX,OAAO,CAAC,CAAC;QACX,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,CAAC;YACd,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;CACF"} | ||
| {"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../../../src/lib/profiler/profiler.ts"],"names":[],"mappings":"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"} |
| export type Encoder<I, O> = { | ||
| encode: (input: I) => O; | ||
| }; | ||
| export type Decoder<O, I> = { | ||
| decode: (output: O) => I; | ||
| }; | ||
| export type Sink<I, O> = { | ||
| open: () => void; | ||
| write: (input: I) => void; | ||
| close: () => void; | ||
| isClosed: () => boolean; | ||
| } & Encoder<I, O>; | ||
| export type Buffered = { | ||
| flush: () => void; | ||
| }; | ||
| export type BufferedSink<I, O> = Sink<I, O> & Buffered; | ||
| export type Source<I, O = unknown> = { | ||
| read?: () => O; | ||
| decode?: (input: I) => O; | ||
| }; | ||
| export type Observer = { | ||
| subscribe: () => void; | ||
| unsubscribe: () => void; | ||
| isSubscribed: () => boolean; | ||
| }; | ||
| export type Recoverable = { | ||
| recover: () => RecoverResult; | ||
| repack: () => void; | ||
| finalize: () => void; | ||
| }; | ||
| export type RecoverResult<T = unknown> = { | ||
| records: T[]; | ||
| errors: { | ||
| lineNo: number; | ||
| line: string; | ||
| error: Error; | ||
| }[]; | ||
| partialTail: string | null; | ||
| }; | ||
| export type RecoverOptions = { | ||
| keepInvalid?: boolean; | ||
| }; | ||
| export type Output<I, O> = {} & BufferedSink<I, O>; |
| export {}; | ||
| //# sourceMappingURL=sink-source.type.js.map |
| {"version":3,"file":"sink-source.type.js","sourceRoot":"","sources":["../../../src/lib/sink-source.type.ts"],"names":[],"mappings":""} |
| import type { PerformanceMark, PerformanceMeasure } from 'node:perf_hooks'; | ||
| import type { BeginEvent, CompleteEvent, EndEvent, InstantEvent, InstantEventArgs, InstantEventTracingStartedInBrowser, SpanEventArgs, TraceEvent, TraceEventContainer } from './trace-file.type.js'; | ||
| /** | ||
| * Generates a unique ID for linking begin and end span events in Chrome traces. | ||
| * @returns Object with local ID string for the id2 field | ||
| */ | ||
| export declare const nextId2: () => { | ||
| local: string; | ||
| }; | ||
| /** | ||
| * Generates a unique frame tree node ID from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Combined numeric ID | ||
| */ | ||
| export declare const frameTreeNodeId: (pid: number, tid: number) => number; | ||
| /** | ||
| * Generates a frame name string from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Formatted frame name | ||
| */ | ||
| export declare const frameName: (pid: number, tid: number) => string; | ||
| /** | ||
| * Creates an instant trace event for marking a point in time. | ||
| * @param opt - Event configuration options | ||
| * @returns InstantEvent object | ||
| */ | ||
| export declare const getInstantEvent: (opt: { | ||
| name: string; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| args?: InstantEventArgs; | ||
| }) => InstantEvent; | ||
| /** | ||
| * Creates a start tracing event with frame information. | ||
| * This event is needed at the beginning of the traceEvents array to make tell the UI profiling has started, and it should visualize the data. | ||
| * @param opt - Tracing configuration options | ||
| * @returns StartTracingEvent object | ||
| */ | ||
| export declare const getInstantEventTracingStartedInBrowser: (opt: { | ||
| url: string; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => InstantEventTracingStartedInBrowser; | ||
| /** | ||
| * Creates a complete trace event with duration. | ||
| * @param opt - Event configuration with name and duration | ||
| * @returns CompleteEvent object | ||
| */ | ||
| export declare const getCompleteEvent: (opt: { | ||
| name: string; | ||
| dur: number; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => CompleteEvent; | ||
| /** Options for creating span events */ | ||
| type SpanOpt = { | ||
| name: string; | ||
| id2: { | ||
| local: string; | ||
| }; | ||
| ts?: number; | ||
| pid?: number; | ||
| tid?: number; | ||
| args?: SpanEventArgs; | ||
| }; | ||
| /** | ||
| * Creates a begin span event. | ||
| * @param ph - Phase ('b' for begin) | ||
| * @param opt - Span event options | ||
| * @returns BeginEvent object | ||
| */ | ||
| export declare function getSpanEvent(ph: 'b', opt: SpanOpt): BeginEvent; | ||
| /** | ||
| * Creates an end span event. | ||
| * @param ph - Phase ('e' for end) | ||
| * @param opt - Span event options | ||
| * @returns EndEvent object | ||
| */ | ||
| export declare function getSpanEvent(ph: 'e', opt: SpanOpt): EndEvent; | ||
| /** | ||
| * Creates a pair of begin and end span events. | ||
| * @param opt - Span configuration with start/end timestamps | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export declare const getSpan: (opt: { | ||
| name: string; | ||
| tsB: number; | ||
| tsE: number; | ||
| id2?: { | ||
| local: string; | ||
| }; | ||
| pid?: number; | ||
| tid?: number; | ||
| args?: SpanEventArgs; | ||
| tsMarkerPadding?: number; | ||
| }) => [BeginEvent, EndEvent]; | ||
| /** | ||
| * Converts a PerformanceMark to an instant trace event. | ||
| * @param entry - Performance mark entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns InstantEvent object | ||
| */ | ||
| export declare const markToInstantEvent: (entry: PerformanceMark, opt?: { | ||
| name?: string; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => InstantEvent; | ||
| /** | ||
| * Converts a PerformanceMeasure to a pair of span events. | ||
| * @param entry - Performance measure entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export declare const measureToSpanEvents: (entry: PerformanceMeasure, opt?: { | ||
| name?: string; | ||
| pid?: number; | ||
| tid?: number; | ||
| }) => [BeginEvent, EndEvent]; | ||
| /** | ||
| * Creates a complete trace file container with metadata. | ||
| * @param opt - Trace file configuration | ||
| * @returns TraceEventContainer with events and metadata | ||
| */ | ||
| export declare const getTraceFile: (opt: { | ||
| traceEvents: TraceEvent[]; | ||
| startTime?: string; | ||
| }) => TraceEventContainer; | ||
| export {}; |
| import os from 'node:os'; | ||
| import { threadId } from 'node:worker_threads'; | ||
| import { defaultClock } from './clock-epoch.js'; | ||
| /** Global counter for generating unique span IDs within a trace */ | ||
| // eslint-disable-next-line functional/no-let | ||
| let id2Count = 0; | ||
| /** | ||
| * Generates a unique ID for linking begin and end span events in Chrome traces. | ||
| * @returns Object with local ID string for the id2 field | ||
| */ | ||
| export const nextId2 = () => ({ local: `0x${++id2Count}` }); | ||
| /** | ||
| * Provides default values for trace event properties. | ||
| * @param opt - Optional overrides for pid, tid, and timestamp | ||
| * @returns Object with pid, tid, and timestamp | ||
| */ | ||
| const defaults = (opt) => ({ | ||
| pid: opt?.pid ?? process.pid, | ||
| tid: opt?.tid ?? threadId, | ||
| ts: opt?.ts ?? defaultClock.epochNowUs(), | ||
| }); | ||
| /** | ||
| * Generates a unique frame tree node ID from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Combined numeric ID | ||
| */ | ||
| export const frameTreeNodeId = (pid, tid) => Number.parseInt(`${pid}0${tid}`, 10); | ||
| /** | ||
| * Generates a frame name string from process and thread IDs. | ||
| * @param pid - Process ID | ||
| * @param tid - Thread ID | ||
| * @returns Formatted frame name | ||
| */ | ||
| export const frameName = (pid, tid) => `FRAME0P${pid}T${tid}`; | ||
| /** | ||
| * Creates an instant trace event for marking a point in time. | ||
| * @param opt - Event configuration options | ||
| * @returns InstantEvent object | ||
| */ | ||
| export const getInstantEvent = (opt) => ({ | ||
| cat: 'blink.user_timing', | ||
| ph: 'i', | ||
| name: opt.name, | ||
| ...defaults(opt), | ||
| args: opt.args ?? {}, | ||
| }); | ||
| /** | ||
| * Creates a start tracing event with frame information. | ||
| * This event is needed at the beginning of the traceEvents array to make tell the UI profiling has started, and it should visualize the data. | ||
| * @param opt - Tracing configuration options | ||
| * @returns StartTracingEvent object | ||
| */ | ||
| export const getInstantEventTracingStartedInBrowser = (opt) => { | ||
| const { pid, tid, ts } = defaults(opt); | ||
| const id = frameTreeNodeId(pid, tid); | ||
| return { | ||
| cat: 'devtools.timeline', | ||
| ph: 'i', | ||
| name: 'TracingStartedInBrowser', | ||
| pid, | ||
| tid, | ||
| ts, | ||
| args: { | ||
| data: { | ||
| frameTreeNodeId: id, | ||
| frames: [ | ||
| { | ||
| frame: frameName(pid, tid), | ||
| isInPrimaryMainFrame: true, | ||
| isOutermostMainFrame: true, | ||
| name: '', | ||
| processId: pid, | ||
| url: opt.url, | ||
| }, | ||
| ], | ||
| persistentIds: true, | ||
| }, | ||
| }, | ||
| }; | ||
| }; | ||
| /** | ||
| * Creates a complete trace event with duration. | ||
| * @param opt - Event configuration with name and duration | ||
| * @returns CompleteEvent object | ||
| */ | ||
| export const getCompleteEvent = (opt) => ({ | ||
| cat: 'devtools.timeline', | ||
| ph: 'X', | ||
| name: opt.name, | ||
| dur: opt.dur, | ||
| ...defaults(opt), | ||
| args: {}, | ||
| }); | ||
| /** | ||
| * Creates a span event (begin or end). | ||
| * @param ph - Phase ('b' or 'e') | ||
| * @param opt - Span event options | ||
| * @returns SpanEvent object | ||
| */ | ||
| export function getSpanEvent(ph, opt) { | ||
| return { | ||
| cat: 'blink.user_timing', | ||
| ph, | ||
| name: opt.name, | ||
| id2: opt.id2, | ||
| ...defaults(opt), | ||
| args: opt.args?.data?.detail | ||
| ? { data: { detail: opt.args.data.detail } } | ||
| : {}, | ||
| }; | ||
| } | ||
| /** | ||
| * Creates a pair of begin and end span events. | ||
| * @param opt - Span configuration with start/end timestamps | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export const getSpan = (opt) => { | ||
| // tsMarkerPadding is here to make the measure slightly smaller so the markers align perfectly. | ||
| // Otherwise, the marker is visible at the start of the measure below the frame | ||
| // No padding Padding | ||
| // spans: ======== |======| | ||
| // marks: | | | ||
| const pad = opt.tsMarkerPadding ?? 1; | ||
| // b|e need to share the same id2 | ||
| const id2 = opt.id2 ?? nextId2(); | ||
| return [ | ||
| getSpanEvent('b', { | ||
| ...opt, | ||
| id2, | ||
| ts: opt.tsB + pad, | ||
| }), | ||
| getSpanEvent('e', { | ||
| ...opt, | ||
| id2, | ||
| ts: opt.tsE - pad, | ||
| }), | ||
| ]; | ||
| }; | ||
| /** | ||
| * Converts a PerformanceMark to an instant trace event. | ||
| * @param entry - Performance mark entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns InstantEvent object | ||
| */ | ||
| export const markToInstantEvent = (entry, opt) => getInstantEvent({ | ||
| ...opt, | ||
| name: opt?.name ?? entry.name, | ||
| ts: defaultClock.fromEntry(entry), | ||
| args: entry.detail ? { detail: entry.detail } : undefined, | ||
| }); | ||
| /** | ||
| * Converts a PerformanceMeasure to a pair of span events. | ||
| * @param entry - Performance measure entry | ||
| * @param opt - Optional overrides for name, pid, and tid | ||
| * @returns Tuple of BeginEvent and EndEvent | ||
| */ | ||
| export const measureToSpanEvents = (entry, opt) => getSpan({ | ||
| ...opt, | ||
| name: opt?.name ?? entry.name, | ||
| tsB: defaultClock.fromEntry(entry), | ||
| tsE: defaultClock.fromEntry(entry, true), | ||
| args: entry.detail ? { data: { detail: entry.detail } } : undefined, | ||
| }); | ||
| /** | ||
| * Creates a complete trace file container with metadata. | ||
| * @param opt - Trace file configuration | ||
| * @returns TraceEventContainer with events and metadata | ||
| */ | ||
| export const getTraceFile = (opt) => ({ | ||
| traceEvents: opt.traceEvents, | ||
| displayTimeUnit: 'ms', | ||
| metadata: { | ||
| source: 'Node.js UserTiming', | ||
| startTime: opt.startTime ?? new Date().toISOString(), | ||
| hardwareConcurrency: os.cpus().length, | ||
| }, | ||
| }); | ||
| //# sourceMappingURL=trace-file-utils.js.map |
| {"version":3,"file":"trace-file-utils.js","sourceRoot":"","sources":["../../../src/lib/trace-file-utils.ts"],"names":[],"mappings":"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"} |
| import type { UserTimingDetail } from './user-timing-extensibility-api.type.js'; | ||
| /** | ||
| * Arguments for instant trace events. | ||
| * @property {UserTimingDetail} [detail] - Optional user timing detail with DevTools payload | ||
| */ | ||
| export type InstantEventArgs = { | ||
| detail?: UserTimingDetail; | ||
| } & { | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Arguments for span trace events (begin/end events). | ||
| * @property {object} [data] - Optional data object | ||
| * @property {UserTimingDetail} [data.detail] - Optional user timing detail with DevTools payload | ||
| */ | ||
| export type SpanEventArgs = { | ||
| data?: { | ||
| detail?: UserTimingDetail; | ||
| }; | ||
| } & { | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Arguments for complete trace events. | ||
| * @property {Record<string, unknown>} [detail] - Optional detail object with arbitrary properties | ||
| */ | ||
| export type CompleteEventArgs = { | ||
| detail?: Record<string, unknown>; | ||
| }; | ||
| /** | ||
| * Arguments for start tracing events. | ||
| * @property {object} data - Tracing initialization data | ||
| * @property {number} data.frameTreeNodeId - Frame tree node identifier | ||
| * @property {Array} data.frames - Array of frame information | ||
| * @property {boolean} data.persistentIds - Whether IDs are persistent | ||
| */ | ||
| export type InstantEventTracingStartedInBrowserArgs = { | ||
| data: { | ||
| frameTreeNodeId: number; | ||
| frames: { | ||
| frame: string; | ||
| isInPrimaryMainFrame: boolean; | ||
| isOutermostMainFrame: boolean; | ||
| name: string; | ||
| processId: number; | ||
| url: string; | ||
| }[]; | ||
| persistentIds: boolean; | ||
| }; | ||
| }; | ||
| /** | ||
| * Union type of all possible trace event arguments. | ||
| */ | ||
| export type TraceArgs = InstantEventArgs | SpanEventArgs | CompleteEventArgs | InstantEventTracingStartedInBrowserArgs; | ||
| /** | ||
| * Base properties shared by all trace events. | ||
| * @property {string} cat - Event category | ||
| * @property {string} name - Event name | ||
| * @property {number} pid - Process ID | ||
| * @property {number} tid - Thread ID | ||
| * @property {number} ts - Timestamp in epoch microseconds | ||
| * @property {TraceArgs} [args] - Optional event arguments | ||
| */ | ||
| export type BaseTraceEvent = { | ||
| cat: string; | ||
| name: string; | ||
| pid: number; | ||
| tid: number; | ||
| ts: number; | ||
| args: TraceArgs; | ||
| }; | ||
| /** | ||
| * Start tracing event for Chrome DevTools tracing. | ||
| */ | ||
| export type InstantEventTracingStartedInBrowser = BaseTraceEvent & { | ||
| cat: 'devtools.timeline'; | ||
| ph: 'i'; | ||
| name: 'TracingStartedInBrowser'; | ||
| args: InstantEventTracingStartedInBrowserArgs; | ||
| }; | ||
| /** | ||
| * Complete trace event with duration. | ||
| * Represents a complete operation with start time and duration. | ||
| * @property {'X'} ph - Phase indicator for complete events | ||
| * @property {number} dur - Duration in microseconds | ||
| */ | ||
| export type CompleteEvent = BaseTraceEvent & { | ||
| ph: 'X'; | ||
| dur: number; | ||
| }; | ||
| /** | ||
| * Instant trace event representing a single point in time. | ||
| * Used for user timing marks and other instantaneous events. | ||
| * @property {'blink.user_timing'} cat - Fixed category for user timing events | ||
| * @property {'i'} ph - Phase indicator for instant events | ||
| * @property {never} [dur] - Duration is not applicable for instant events | ||
| * @property {InstantEventArgs} [args] - Optional event arguments | ||
| */ | ||
| export type InstantEvent = Omit<BaseTraceEvent, 'cat' | 'args'> & { | ||
| cat: 'blink.user_timing'; | ||
| ph: 'i'; | ||
| dur?: never; | ||
| args: InstantEventArgs; | ||
| }; | ||
| /** | ||
| * Core properties for span trace events (begin/end pairs). | ||
| * @property {object} id2 - Span identifier | ||
| * @property {string} id2.local - Local span ID (unique to the process, same for b and e events) | ||
| * @property {SpanEventArgs} [args] - Optional event arguments | ||
| */ | ||
| type SpanCore = Omit<BaseTraceEvent, 'args'> & { | ||
| id2: { | ||
| local: string; | ||
| }; | ||
| args: SpanEventArgs; | ||
| }; | ||
| /** | ||
| * Begin event for a span (paired with an end event). | ||
| * @property {'b'} ph - Phase indicator for begin events | ||
| * @property {never} [dur] - Duration is not applicable for begin events | ||
| */ | ||
| export type BeginEvent = SpanCore & { | ||
| ph: 'b'; | ||
| dur?: never; | ||
| }; | ||
| /** | ||
| * End event for a span (paired with a begin event). | ||
| * @property {'e'} ph - Phase indicator for end events | ||
| * @property {never} [dur] - Duration is not applicable for end events | ||
| */ | ||
| export type EndEvent = SpanCore & { | ||
| ph: 'e'; | ||
| dur?: never; | ||
| }; | ||
| /** | ||
| * Union type for span events (begin or end). | ||
| */ | ||
| export type SpanEvent = BeginEvent | EndEvent; | ||
| /** | ||
| * Union type of all trace event types. | ||
| */ | ||
| export type TraceEvent = InstantEvent | CompleteEvent | SpanEvent | InstantEventTracingStartedInBrowser; | ||
| /** | ||
| * Raw arguments format for trace events before processing. | ||
| * Either contains a detail string directly or nested in a data object. | ||
| */ | ||
| type RawArgs = { | ||
| detail?: string; | ||
| [key: string]: unknown; | ||
| } | { | ||
| data?: { | ||
| detail?: string; | ||
| }; | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Raw trace event format before type conversion. | ||
| * Similar to TraceEvent but with unprocessed arguments. | ||
| */ | ||
| export type TraceEventRaw = Omit<TraceEvent, 'args'> & { | ||
| args: RawArgs; | ||
| }; | ||
| /** | ||
| * Time window bounds (min, max) in trace time units (e.g. microseconds). | ||
| * @property {number} min - Minimum timestamp in the window | ||
| * @property {number} max - Maximum timestamp in the window | ||
| * @property {number} range - Calculated range (max - min) | ||
| */ | ||
| export type BreadcrumbWindow = { | ||
| min: number; | ||
| max: number; | ||
| range: number; | ||
| }; | ||
| /** | ||
| * Custom label for a specific trace entry. | ||
| * @property {number | string} entryId - ID or index of the trace entry | ||
| * @property {string} label - Label text for the entry | ||
| * @property {string} [color] - Optional display color for the label | ||
| */ | ||
| export type EntryLabel = { | ||
| entryId: number | string; | ||
| label: string; | ||
| color?: string; | ||
| }; | ||
| /** | ||
| * Link or relation between two trace entries. | ||
| * @property {number | string} fromEntryId - Source entry ID for the link | ||
| * @property {number | string} toEntryId - Target entry ID for the link | ||
| * @property {string} [linkType] - Optional type or description of the link | ||
| */ | ||
| export type EntryLink = { | ||
| fromEntryId: number | string; | ||
| toEntryId: number | string; | ||
| linkType?: string; | ||
| }; | ||
| /** | ||
| * A time range annotated with a label. | ||
| * @property {number} startTime - Start timestamp of the range (microseconds) | ||
| * @property {number} endTime - End timestamp of the range (microseconds) | ||
| * @property {string} label - Annotation label for the time range | ||
| * @property {string} [color] - Optional display color for the range | ||
| */ | ||
| export type LabelledTimeRange = { | ||
| startTime: number; | ||
| endTime: number; | ||
| label: string; | ||
| color?: string; | ||
| }; | ||
| /** | ||
| * Hidden or expandable entries information. | ||
| * @property {unknown[]} hiddenEntries - IDs or indexes of hidden entries | ||
| * @property {unknown[]} expandableEntries - IDs or indexes of expandable entries | ||
| */ | ||
| export type EntriesModifications = { | ||
| hiddenEntries: unknown[]; | ||
| expandableEntries: unknown[]; | ||
| }; | ||
| /** | ||
| * Initial breadcrumb information for time ranges and window. | ||
| * @property {BreadcrumbWindow} window - Time window bounds | ||
| * @property {unknown | null} child - Child breadcrumb or null | ||
| */ | ||
| export type InitialBreadcrumb = { | ||
| window: BreadcrumbWindow; | ||
| child: unknown | null; | ||
| }; | ||
| /** | ||
| * Annotations such as labels and links between entries. | ||
| * @property {EntryLabel[]} entryLabels - Custom labels for entries | ||
| * @property {LabelledTimeRange[]} labelledTimeRanges - Time ranges annotated with labels | ||
| * @property {EntryLink[]} linksBetweenEntries - Links or relations between entries | ||
| */ | ||
| export type Annotations = { | ||
| entryLabels: EntryLabel[]; | ||
| labelledTimeRanges: LabelledTimeRange[]; | ||
| linksBetweenEntries: EntryLink[]; | ||
| }; | ||
| /** | ||
| * Modifications made to trace data or UI in DevTools export | ||
| */ | ||
| export type Modifications = { | ||
| entriesModifications: EntriesModifications; | ||
| initialBreadcrumb: InitialBreadcrumb; | ||
| annotations: Annotations; | ||
| }; | ||
| /** | ||
| * Top-level metadata for a trace file exported by Chrome DevTools. | ||
| * DevTools may add new fields over time. | ||
| */ | ||
| export type TraceMetadata = { | ||
| /** Usually "DevTools" for exports from the Performance panel */ | ||
| source: string; | ||
| /** ISO timestamp when trace was recorded */ | ||
| startTime: string; | ||
| /** May be present when recorded with throttling settings */ | ||
| hardwareConcurrency?: number; | ||
| /** Common fields found in DevTools traces */ | ||
| cpuThrottling?: number; | ||
| networkThrottling?: string; | ||
| enhancedTraceVersion?: number; | ||
| /** Allow additional custom metadata properties */ | ||
| [key: string]: unknown; | ||
| }; | ||
| /** | ||
| * Structured container for trace events with metadata. | ||
| * @property {TraceEvent[]} traceEvents - Array of trace events | ||
| * @property {'ms' | 'ns'} [displayTimeUnit] - Time unit for display (milliseconds or nanoseconds) | ||
| * @property {TraceMetadata} [metadata] - Optional metadata about the trace | ||
| */ | ||
| export type TraceEventContainer = { | ||
| traceEvents: TraceEvent[]; | ||
| displayTimeUnit?: 'ms' | 'ns'; | ||
| metadata?: TraceMetadata; | ||
| }; | ||
| /** | ||
| * Trace file format - either an array of events or a structured container. | ||
| */ | ||
| export type TraceFile = TraceEvent[] | TraceEventContainer; | ||
| export {}; |
| export {}; | ||
| //# sourceMappingURL=trace-file.type.js.map |
| {"version":3,"file":"trace-file.type.js","sourceRoot":"","sources":["../../../src/lib/trace-file.type.ts"],"names":[],"mappings":""} |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 12 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 12 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
463809
12.56%191
1.6%7395
13.75%24
33.33%+ Added
- Removed
Updated