11import process from 'node:process' ;
22import { isEnvVarEnabled } from '../env.js' ;
33import {
4+ type MeasureCtxOptions ,
45 type MeasureOptions ,
56 asOptions ,
67 markerPayload ,
78 measureCtx ,
89 setupTracks ,
910} from '../user-timing-extensibility-api-utils.js' ;
1011import type {
11- ActionColorPayload ,
1212 ActionTrackEntryPayload ,
1313 DevToolsColor ,
1414 EntryMeta ,
15- TrackMeta ,
1615} from '../user-timing-extensibility-api.type.js' ;
1716import { PROFILER_ENABLED } from './constants.js' ;
1817
19- /** Default track configuration combining metadata and color options. */
20- type DefaultTrackOptions = TrackMeta & ActionColorPayload ;
21-
2218/**
2319 * Configuration options for creating a Profiler instance.
2420 *
2521 * @template T - Record type defining available track names and their configurations
2622 */
2723type ProfilerMeasureOptions < T extends Record < string , ActionTrackEntryPayload > > =
28- DefaultTrackOptions & {
24+ MeasureCtxOptions & {
2925 /** Custom track configurations that will be merged with default settings */
30- tracks : Record < keyof T , Partial < ActionTrackEntryPayload > > ;
26+ tracks ? : Record < keyof T , Partial < ActionTrackEntryPayload > > ;
3127 /** Whether profiling should be enabled (defaults to CP_PROFILING env var) */
3228 enabled ?: boolean ;
33- /** Prefix for all performance measurement names to avoid conflicts */
34- prefix : string ;
3529 } ;
3630
3731/**
@@ -51,38 +45,11 @@ export type ProfilerOptions<T extends Record<string, ActionTrackEntryPayload>> =
5145 * integration for Chrome DevTools Performance panel. It supports both synchronous and
5246 * asynchronous operations with customizable track visualization.
5347 *
54- * @example
55- * ```typescript
56- * const profiler = new Profiler({
57- * prefix: 'api',
58- * track: 'backend-calls',
59- * trackGroup: 'api',
60- * color: 'secondary',
61- * tracks: {
62- * database: { track: 'database', color: 'tertiary' },
63- * external: { track: 'external-apis', color: 'primary' }
64- * }
65- * });
66- *
67- * // Measure synchronous operation
68- * const result = profiler.measure('fetch-user', () => api.getUser(id));
69- *
70- * // Measure async operation
71- * const asyncResult = await profiler.measureAsync('save-data',
72- * () => api.saveData(data)
73- * );
74- *
75- * // Add marker
76- * profiler.marker('cache-invalidated', {
77- * color: 'warning',
78- * tooltipText: 'Cache cleared due to stale data'
79- * });
80- * ```
8148 */
8249export class Profiler < T extends Record < string , ActionTrackEntryPayload > > {
8350 #enabled: boolean ;
8451 private readonly defaults : ActionTrackEntryPayload ;
85- readonly tracks : Record < keyof T , ActionTrackEntryPayload > ;
52+ readonly tracks : Record < keyof T , ActionTrackEntryPayload > | undefined ;
8653 private readonly ctxOf : ReturnType < typeof measureCtx > ;
8754
8855 /**
@@ -96,28 +63,16 @@ export class Profiler<T extends Record<string, ActionTrackEntryPayload>> {
9663 * @param options.color - Default color for track entries
9764 * @param options.enabled - Whether profiling is enabled (defaults to CP_PROFILING env var)
9865 *
99- * @example
100- * ```typescript
101- * const profiler = new Profiler({
102- * prefix: 'api',
103- * track: 'backend-calls',
104- * trackGroup: 'api',
105- * color: 'secondary',
106- * enabled: true,
107- * tracks: {
108- * database: { track: 'database', color: 'tertiary' },
109- * cache: { track: 'cache', color: 'primary' }
110- * }
111- * });
112- * ```
11366 */
11467 constructor ( options : ProfilerOptions < T > ) {
11568 const { tracks, prefix, enabled, ...defaults } = options ;
11669 const dataType = 'track-entry' ;
11770
11871 this . #enabled = enabled ?? isEnvVarEnabled ( PROFILER_ENABLED ) ;
11972 this . defaults = { ...defaults , dataType } ;
120- this . tracks = setupTracks ( { ...defaults , dataType } , tracks ) ;
73+ this . tracks = tracks
74+ ? setupTracks ( { ...defaults , dataType } , tracks )
75+ : undefined ;
12176 this . ctxOf = measureCtx ( {
12277 ...defaults ,
12378 dataType,
@@ -157,13 +112,12 @@ export class Profiler<T extends Record<string, ActionTrackEntryPayload>> {
157112 * returns immediately without creating any performance entries.
158113 *
159114 * @param name - Unique name for the marker
160- * @param opt - Optional metadata and styling for the marker
115+ * @param opt - Metadata and styling for the marker
161116 * @param opt.color - Color of the marker line (defaults to profiler default)
162117 * @param opt.tooltipText - Text shown on hover
163118 * @param opt.properties - Key-value pairs for detailed view
164119 *
165120 * @example
166- * ```typescript
167121 * profiler.marker('user-action-start', {
168122 * color: 'primary',
169123 * tooltipText: 'User clicked save button',
@@ -172,7 +126,6 @@ export class Profiler<T extends Record<string, ActionTrackEntryPayload>> {
172126 * ['elementId', 'save-btn']
173127 * ]
174128 * });
175- * ```
176129 */
177130 marker ( name : string , opt ?: EntryMeta & { color : DevToolsColor } ) {
178131 if ( ! this . #enabled) {
@@ -201,26 +154,19 @@ export class Profiler<T extends Record<string, ActionTrackEntryPayload>> {
201154 * @template R - The return type of the work function
202155 * @param event - Name for this measurement event
203156 * @param work - Function to execute and measure
204- * @param options - Optional measurement configuration overrides
157+ * @param options - Measurement configuration overrides
205158 * @returns The result of the work function
206159 *
207- * @example
208- * ```typescript
209- * const user = profiler.measure('fetch-user', () => {
210- * return api.getUser(userId);
211- * }, {
212- * success: (result) => ({
213- * properties: [['userId', result.id], ['loadTime', Date.now()]]
214- * })
215- * });
216- * ```
217160 */
218- measure < R > ( event : string , work : ( ) => R , options ?: MeasureOptions ) : R {
161+ measure < R > ( event : string , work : ( ) => R , options ?: MeasureOptions < R > ) : R {
219162 if ( ! this . #enabled) {
220163 return work ( ) ;
221164 }
222165
223- const { start, success, error } = this . ctxOf ( event , options ) ;
166+ const { start, success, error } = this . ctxOf (
167+ event ,
168+ options as MeasureOptions ,
169+ ) ;
224170 start ( ) ;
225171 try {
226172 const r = work ( ) ;
@@ -242,34 +188,23 @@ export class Profiler<T extends Record<string, ActionTrackEntryPayload>> {
242188 * @template R - The resolved type of the work promise
243189 * @param event - Name for this measurement event
244190 * @param work - Function returning a promise to execute and measure
245- * @param options - Optional measurement configuration overrides
191+ * @param options - Measurement configuration overrides
246192 * @returns Promise that resolves to the result of the work function
247193 *
248- * @example
249- * ```typescript
250- * const data = await profiler.measureAsync('save-form', async () => {
251- * const result = await api.saveForm(formData);
252- * return result;
253- * }, {
254- * success: (result) => ({
255- * properties: [['recordsSaved', result.count]]
256- * }),
257- * error: (err) => ({
258- * properties: [['errorType', err.name]]
259- * })
260- * });
261- * ```
262194 */
263195 async measureAsync < R > (
264196 event : string ,
265197 work : ( ) => Promise < R > ,
266- options ?: MeasureOptions ,
198+ options ?: MeasureOptions < R > ,
267199 ) : Promise < R > {
268200 if ( ! this . #enabled) {
269201 return await work ( ) ;
270202 }
271203
272- const { start, success, error } = this . ctxOf ( event , options ) ;
204+ const { start, success, error } = this . ctxOf (
205+ event ,
206+ options as MeasureOptions ,
207+ ) ;
273208 start ( ) ;
274209 try {
275210 const r = work ( ) ;
0 commit comments