From 79590b6a24618ae9f4b4254f7a7457035f351884 Mon Sep 17 00:00:00 2001 From: John Doe Date: Sat, 10 Jan 2026 01:49:49 +0100 Subject: [PATCH 01/17] feat: add performance type extensions --- packages/utils/src/perf_hooks.d.ts | 60 +++++++++++++++++++++ packages/utils/src/perf_hooks.type.ts | 76 +++++++++++++++++++++++++++ packages/utils/tsconfig.lib.json | 2 +- packages/utils/tsconfig.test.json | 3 +- 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 packages/utils/src/perf_hooks.d.ts create mode 100644 packages/utils/src/perf_hooks.type.ts diff --git a/packages/utils/src/perf_hooks.d.ts b/packages/utils/src/perf_hooks.d.ts new file mode 100644 index 000000000..abc873751 --- /dev/null +++ b/packages/utils/src/perf_hooks.d.ts @@ -0,0 +1,60 @@ +// perf_hooks.d.ts - Custom type definitions for performance.mark() and performance.measure() +import type { + MarkOptions, + MeasureOptions, + Performance, + PerformanceMark, + PerformanceMarkOptions, + PerformanceMeasure, + PerformanceMeasureOptions, +} from 'node:perf_hooks'; +import type { + MarkOptionsWithDevtools, + MarkerPayload, + MeasureOptionsWithDevtools, + TrackEntryPayload, + WithDevToolsPayload, +} from './lib/user-timing-extensibility-api.type'; + +export {}; + +type DetailPayloadWithDevtools = WithDevToolsPayload< + TrackEntryPayload | MarkerPayload +>; + +declare module 'node:perf_hooks' { + export interface PerformanceMarkOptions { + detail?: DetailPayloadWithDevtools; + startTime?: DOMHighResTimeStamp; + } + + export interface PerformanceMeasureOptions { + detail?: DetailPayloadWithDevtools; + start?: string | number; + end?: string | number; + duration?: number; + } + + const performance: { + mark( + name: string, + options?: { + detail?: DetailPayloadWithDevtools; + }, + ): PerformanceMark; + + measure( + name: string, + startOrOptions?: + | string + | number + | { + detail?: DetailPayloadWithDevtools; + start?: string | number; + end?: string | number; + duration?: number; + }, + end?: string | number, + ): PerformanceMeasure; + }; +} diff --git a/packages/utils/src/perf_hooks.type.ts b/packages/utils/src/perf_hooks.type.ts new file mode 100644 index 000000000..fb50c1fdd --- /dev/null +++ b/packages/utils/src/perf_hooks.type.ts @@ -0,0 +1,76 @@ +import { type PerformanceMarkOptions, performance } from 'node:perf_hooks'; +import { describe, expectTypeOf, it } from 'vitest'; + +describe('perf_hooks.type', () => { + it('PerformanceMarkOptions should be type safe', () => { + expectTypeOf<{ + startTime: number; + detail: { + devtools: { + dataType: 'marker'; + color: 'error'; + }; + }; + }>().toMatchTypeOf(); + + expectTypeOf<{ + startTime: number; + detail: { + devtools: { + dataType: 'markerr'; + }; + }; + }>().not.toMatchTypeOf(); + }); + + it('perf_hooks.mark should be type safe', () => { + performance.mark('name', { + detail: { + devtools: { + dataType: 'marker', + color: 'error', + }, + }, + }); + + performance.mark('name', { + detail: { + devtools: { + /* @ts-expect-error - dataType should be marker | track */ + dataType: 'markerrr', + color: 'error', + }, + }, + }); + }); + + it('PerformanceMeasureOptions should be type safe', () => { + expectTypeOf<{ + start: string; + end: string; + detail: { + devtools: { + dataType: 'track-entry'; + track: 'test-track'; + color: 'primary'; + }; + }; + }>().toMatchTypeOf(); + }); + + it('perf_hooks.measure should be type safe', () => { + performance.measure('measure-name', 'start-mark', 'end-mark'); + + performance.measure('measure-name', { + start: 'start-mark', + end: 'end-mark', + detail: { + /* @ts-expect-error - track is required */ + devtools: { + dataType: 'track-entry', + color: 'primary', + }, + }, + }); + }); +}); diff --git a/packages/utils/tsconfig.lib.json b/packages/utils/tsconfig.lib.json index 17dadcedf..973149960 100644 --- a/packages/utils/tsconfig.lib.json +++ b/packages/utils/tsconfig.lib.json @@ -5,7 +5,7 @@ "declaration": true, "types": ["node"] }, - "include": ["src/**/*.ts"], + "include": ["src/**/*.{ts,d.ts}"], "exclude": [ "vitest.unit.config.ts", "vitest.int.config.ts", diff --git a/packages/utils/tsconfig.test.json b/packages/utils/tsconfig.test.json index 54cacd82f..65a45077f 100644 --- a/packages/utils/tsconfig.test.json +++ b/packages/utils/tsconfig.test.json @@ -13,6 +13,7 @@ "src/**/*.test.js", "src/**/*.test.jsx", "src/**/*.d.ts", - "../../testing/test-setup/src/vitest.d.ts" + "../../testing/test-setup/src/vitest.d.ts", + "src/perf_hooks.type.ts" ] } From 70ad6cdd453d771039f2716ed958aae54916bd9f Mon Sep 17 00:00:00 2001 From: John Doe Date: Mon, 12 Jan 2026 02:59:49 +0100 Subject: [PATCH 02/17] fix: wip --- packages/utils/src/perf_hooks.d.ts | 12 ------------ .../{perf_hooks.type.ts => perf_hooks.type.test.ts} | 0 2 files changed, 12 deletions(-) rename packages/utils/src/{perf_hooks.type.ts => perf_hooks.type.test.ts} (100%) diff --git a/packages/utils/src/perf_hooks.d.ts b/packages/utils/src/perf_hooks.d.ts index abc873751..e3bf6fb1a 100644 --- a/packages/utils/src/perf_hooks.d.ts +++ b/packages/utils/src/perf_hooks.d.ts @@ -1,17 +1,5 @@ -// perf_hooks.d.ts - Custom type definitions for performance.mark() and performance.measure() import type { - MarkOptions, - MeasureOptions, - Performance, - PerformanceMark, - PerformanceMarkOptions, - PerformanceMeasure, - PerformanceMeasureOptions, -} from 'node:perf_hooks'; -import type { - MarkOptionsWithDevtools, MarkerPayload, - MeasureOptionsWithDevtools, TrackEntryPayload, WithDevToolsPayload, } from './lib/user-timing-extensibility-api.type'; diff --git a/packages/utils/src/perf_hooks.type.ts b/packages/utils/src/perf_hooks.type.test.ts similarity index 100% rename from packages/utils/src/perf_hooks.type.ts rename to packages/utils/src/perf_hooks.type.test.ts From 5f1c67a8a12693741876e7debd39c6efba989991 Mon Sep 17 00:00:00 2001 From: John Doe Date: Mon, 12 Jan 2026 16:03:45 +0100 Subject: [PATCH 03/17] fix: wip --- packages/utils/tsconfig.test.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/utils/tsconfig.test.json b/packages/utils/tsconfig.test.json index 65a45077f..54cacd82f 100644 --- a/packages/utils/tsconfig.test.json +++ b/packages/utils/tsconfig.test.json @@ -13,7 +13,6 @@ "src/**/*.test.js", "src/**/*.test.jsx", "src/**/*.d.ts", - "../../testing/test-setup/src/vitest.d.ts", - "src/perf_hooks.type.ts" + "../../testing/test-setup/src/vitest.d.ts" ] } From c95589d4049e284ac61f88a99d7b13b29f1c90f7 Mon Sep 17 00:00:00 2001 From: John Doe Date: Mon, 12 Jan 2026 19:16:54 +0100 Subject: [PATCH 04/17] refactor: fix lint --- .../src/{perf_hooks.d.ts => perf-hooks.d.ts} | 17 ++--------------- ...oks.type.test.ts => perf-hooks.unit.test.ts} | 3 +-- 2 files changed, 3 insertions(+), 17 deletions(-) rename packages/utils/src/{perf_hooks.d.ts => perf-hooks.d.ts} (65%) rename packages/utils/src/{perf_hooks.type.test.ts => perf-hooks.unit.test.ts} (97%) diff --git a/packages/utils/src/perf_hooks.d.ts b/packages/utils/src/perf-hooks.d.ts similarity index 65% rename from packages/utils/src/perf_hooks.d.ts rename to packages/utils/src/perf-hooks.d.ts index e3bf6fb1a..cf32771fb 100644 --- a/packages/utils/src/perf_hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -24,24 +24,11 @@ declare module 'node:perf_hooks' { } const performance: { - mark( - name: string, - options?: { - detail?: DetailPayloadWithDevtools; - }, - ): PerformanceMark; + mark(name: string, options?: PerformanceMarkOptions): PerformanceMark; measure( name: string, - startOrOptions?: - | string - | number - | { - detail?: DetailPayloadWithDevtools; - start?: string | number; - end?: string | number; - duration?: number; - }, + startOrOptions?: string | number | PerformanceMeasureOptions, end?: string | number, ): PerformanceMeasure; }; diff --git a/packages/utils/src/perf_hooks.type.test.ts b/packages/utils/src/perf-hooks.unit.test.ts similarity index 97% rename from packages/utils/src/perf_hooks.type.test.ts rename to packages/utils/src/perf-hooks.unit.test.ts index fb50c1fdd..b8245d0b4 100644 --- a/packages/utils/src/perf_hooks.type.test.ts +++ b/packages/utils/src/perf-hooks.unit.test.ts @@ -1,7 +1,7 @@ import { type PerformanceMarkOptions, performance } from 'node:perf_hooks'; import { describe, expectTypeOf, it } from 'vitest'; -describe('perf_hooks.type', () => { +describe('perf-hooks definitions', () => { it('PerformanceMarkOptions should be type safe', () => { expectTypeOf<{ startTime: number; @@ -12,7 +12,6 @@ describe('perf_hooks.type', () => { }; }; }>().toMatchTypeOf(); - expectTypeOf<{ startTime: number; detail: { From 5d779e8ed8b417a276fc1d70bfd83a36775105dc Mon Sep 17 00:00:00 2001 From: John Doe Date: Mon, 12 Jan 2026 19:22:20 +0100 Subject: [PATCH 05/17] refactor: revert ts cfg --- packages/utils/tsconfig.lib.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/tsconfig.lib.json b/packages/utils/tsconfig.lib.json index 973149960..17dadcedf 100644 --- a/packages/utils/tsconfig.lib.json +++ b/packages/utils/tsconfig.lib.json @@ -5,7 +5,7 @@ "declaration": true, "types": ["node"] }, - "include": ["src/**/*.{ts,d.ts}"], + "include": ["src/**/*.ts"], "exclude": [ "vitest.unit.config.ts", "vitest.int.config.ts", From 2aff8770fce9e41842497d16fca88c58c2d924a0 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 14 Jan 2026 00:20:54 +0100 Subject: [PATCH 06/17] refactor: add APIs --- packages/utils/src/perf-hooks.d.ts | 23 +++- packages/utils/src/perf-hooks.unit.test.ts | 119 ++++++++++++--------- 2 files changed, 87 insertions(+), 55 deletions(-) diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index cf32771fb..7f71c4010 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -11,6 +11,23 @@ type DetailPayloadWithDevtools = WithDevToolsPayload< >; declare module 'node:perf_hooks' { + interface PerformanceEntry { + readonly detail?: DetailPayloadWithDevtools; + } + + interface MarkEntry extends PerformanceMark { + readonly entryType: 'mark'; + readonly detail?: DetailPayloadWithDevtools; + } + + interface MeasureEntry extends PerformanceMeasure { + readonly entryType: 'measure'; + readonly detail?: DetailPayloadWithDevtools; + } + + interface PerformanceMark extends PerformanceEntry {} + interface PerformanceMeasure extends PerformanceEntry {} + export interface PerformanceMarkOptions { detail?: DetailPayloadWithDevtools; startTime?: DOMHighResTimeStamp; @@ -24,12 +41,12 @@ declare module 'node:perf_hooks' { } const performance: { - mark(name: string, options?: PerformanceMarkOptions): PerformanceMark; + mark: (name: string, options?: PerformanceMarkOptions) => PerformanceMark; - measure( + measure: ( name: string, startOrOptions?: string | number | PerformanceMeasureOptions, end?: string | number, - ): PerformanceMeasure; + ) => PerformanceMeasure; }; } diff --git a/packages/utils/src/perf-hooks.unit.test.ts b/packages/utils/src/perf-hooks.unit.test.ts index b8245d0b4..1f11ac07f 100644 --- a/packages/utils/src/perf-hooks.unit.test.ts +++ b/packages/utils/src/perf-hooks.unit.test.ts @@ -1,75 +1,90 @@ import { type PerformanceMarkOptions, performance } from 'node:perf_hooks'; -import { describe, expectTypeOf, it } from 'vitest'; +import { describe, expect, expectTypeOf, it } from 'vitest'; describe('perf-hooks definitions', () => { it('PerformanceMarkOptions should be type safe', () => { - expectTypeOf<{ - startTime: number; - detail: { - devtools: { - dataType: 'marker'; - color: 'error'; + expect(() => + expectTypeOf<{ + startTime: number; + detail: { + devtools: { + dataType: 'marker'; + color: 'error'; + }; }; - }; - }>().toMatchTypeOf(); - expectTypeOf<{ - startTime: number; - detail: { - devtools: { - dataType: 'markerr'; + }>().toMatchTypeOf(), + ).not.toThrow(); + + expect(() => + expectTypeOf<{ + startTime: number; + detail: { + devtools: { + dataType: 'markerr'; + }; }; - }; - }>().not.toMatchTypeOf(); + }>().not.toMatchTypeOf(), + ).not.toThrow(); }); it('perf_hooks.mark should be type safe', () => { - performance.mark('name', { - detail: { - devtools: { - dataType: 'marker', - color: 'error', + expect(() => + performance.mark('name', { + detail: { + devtools: { + dataType: 'marker', + color: 'error', + }, }, - }, - }); + }), + ).not.toThrow(); - performance.mark('name', { - detail: { - devtools: { - /* @ts-expect-error - dataType should be marker | track */ - dataType: 'markerrr', - color: 'error', + expect(() => + performance.mark('name', { + detail: { + devtools: { + // @ts-expect-error - dataType should be marker | track + dataType: 'markerrr', + color: 'error', + }, }, - }, - }); + }), + ).not.toThrow(); }); it('PerformanceMeasureOptions should be type safe', () => { - expectTypeOf<{ - start: string; - end: string; - detail: { - devtools: { - dataType: 'track-entry'; - track: 'test-track'; - color: 'primary'; + expect(() => + expectTypeOf<{ + start: string; + end: string; + detail: { + devtools: { + dataType: 'track-entry'; + track: 'test-track'; + color: 'primary'; + }; }; - }; - }>().toMatchTypeOf(); + }>().toMatchTypeOf(), + ).not.toThrow(); }); it('perf_hooks.measure should be type safe', () => { - performance.measure('measure-name', 'start-mark', 'end-mark'); + expect(() => + performance.measure('measure-name', 'start-mark', 'end-mark'), + ).not.toThrow(); - performance.measure('measure-name', { - start: 'start-mark', - end: 'end-mark', - detail: { - /* @ts-expect-error - track is required */ - devtools: { - dataType: 'track-entry', - color: 'primary', + expect(() => + performance.measure('measure-name', { + start: 'start-mark', + end: 'end-mark', + detail: { + // @ts-expect-error - track is required + devtools: { + dataType: 'track-entry', + color: 'primary', + }, }, - }, - }); + }), + ).not.toThrow(); }); }); From be3d41da34f8eeb1435b1529f168cce9c9c427f8 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 14 Jan 2026 00:33:51 +0100 Subject: [PATCH 07/17] refactor: add types --- packages/utils/src/lib/performance-observer.ts | 7 ++++--- packages/utils/src/perf-hooks.d.ts | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/lib/performance-observer.ts b/packages/utils/src/lib/performance-observer.ts index 6b360d0da..53b9176d8 100644 --- a/packages/utils/src/lib/performance-observer.ts +++ b/packages/utils/src/lib/performance-observer.ts @@ -24,9 +24,10 @@ export class PerformanceObserverSink #flushThreshold: number; #sink: Sink; #observer: PerformanceObserver | undefined; - #observedTypes: EntryType[] = ['mark', 'measure']; - #getEntries = (list: PerformanceObserverEntryList) => - this.#observedTypes.flatMap(t => list.getEntriesByType(t)); + readonly #observedTypes: EntryType[] = ['mark', 'measure']; + #getEntries = (list: { + getEntriesByType: (t: EntryType) => PerformanceEntry[]; + }) => this.#observedTypes.flatMap(t => list.getEntriesByType(t)); #observedCount: number = 0; constructor(options: PerformanceObserverOptions) { diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index 7f71c4010..4ebbb5b17 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -40,6 +40,10 @@ declare module 'node:perf_hooks' { duration?: number; } + export interface PerformanceObserverEntryList { + getEntriesByType: (type: EntryType) => PerformanceEntry[]; + } + const performance: { mark: (name: string, options?: PerformanceMarkOptions) => PerformanceMark; @@ -48,5 +52,7 @@ declare module 'node:perf_hooks' { startOrOptions?: string | number | PerformanceMeasureOptions, end?: string | number, ) => PerformanceMeasure; + + getEntriesByType: (type: EntryType) => PerformanceEntry[]; }; } From a46bb31f5c6fdbbcd031e38d2207e1323757939c Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 14 Jan 2026 00:40:58 +0100 Subject: [PATCH 08/17] refactor: fix lint --- packages/utils/src/lib/performance-observer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/utils/src/lib/performance-observer.ts b/packages/utils/src/lib/performance-observer.ts index 53b9176d8..126ec849c 100644 --- a/packages/utils/src/lib/performance-observer.ts +++ b/packages/utils/src/lib/performance-observer.ts @@ -2,7 +2,6 @@ import { type EntryType, type PerformanceEntry, PerformanceObserver, - type PerformanceObserverEntryList, performance, } from 'node:perf_hooks'; import type { Buffered, Encoder, Observer, Sink } from './sink-source.types.js'; From d78d3488b43f3b398e6783ea1c720b2d347bb777 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 14 Jan 2026 00:44:35 +0100 Subject: [PATCH 09/17] refactor: wip --- packages/utils/src/lib/performance-observer.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/performance-observer.ts b/packages/utils/src/lib/performance-observer.ts index 126ec849c..827e5c4e5 100644 --- a/packages/utils/src/lib/performance-observer.ts +++ b/packages/utils/src/lib/performance-observer.ts @@ -24,9 +24,9 @@ export class PerformanceObserverSink #sink: Sink; #observer: PerformanceObserver | undefined; readonly #observedTypes: EntryType[] = ['mark', 'measure']; - #getEntries = (list: { + #getEntries = (listOrGlobal: { getEntriesByType: (t: EntryType) => PerformanceEntry[]; - }) => this.#observedTypes.flatMap(t => list.getEntriesByType(t)); + }) => this.#observedTypes.flatMap(t => listOrGlobal.getEntriesByType(t)); #observedCount: number = 0; constructor(options: PerformanceObserverOptions) { @@ -72,9 +72,6 @@ export class PerformanceObserverSink }); }); - // In real PerformanceObserver, entries remain in the global buffer - // They are only cleared when explicitly requested via performance.clearMarks/clearMeasures - this.#observedCount = 0; } From 16511eb23e5db7b6f23bac5f13a31ee3fdf20c50 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 14 Jan 2026 01:27:39 +0100 Subject: [PATCH 10/17] refactor: move types --- .../src/lib/user-timing-extensibility-api.type.ts | 6 ++++++ packages/utils/src/perf-hooks.d.ts | 10 +--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/utils/src/lib/user-timing-extensibility-api.type.ts b/packages/utils/src/lib/user-timing-extensibility-api.type.ts index 0e75be77b..149852ec3 100644 --- a/packages/utils/src/lib/user-timing-extensibility-api.type.ts +++ b/packages/utils/src/lib/user-timing-extensibility-api.type.ts @@ -117,6 +117,12 @@ export type WithDevToolsPayload = { devtools?: T; }; +/** + * Combined detail payload type for performance entries with DevTools support. + */ +export type DetailPayloadWithDevtools = WithDevToolsPayload< + TrackEntryPayload | MarkerPayload +>; /** * Extended MarkOptions that supports DevTools payload in detail. * @example diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index 4ebbb5b17..5307f1e54 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -1,15 +1,7 @@ -import type { - MarkerPayload, - TrackEntryPayload, - WithDevToolsPayload, -} from './lib/user-timing-extensibility-api.type'; +import type { DetailPayloadWithDevtools } from './lib/user-timing-extensibility-api.type'; export {}; -type DetailPayloadWithDevtools = WithDevToolsPayload< - TrackEntryPayload | MarkerPayload ->; - declare module 'node:perf_hooks' { interface PerformanceEntry { readonly detail?: DetailPayloadWithDevtools; From c45d91ffc59e330cbf4e42757cf377973a3cae51 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 14 Jan 2026 06:14:44 +0100 Subject: [PATCH 11/17] refactor: docs --- packages/utils/src/perf-hooks.d.ts | 142 +++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index 5307f1e54..5501bdb4c 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -2,49 +2,191 @@ import type { DetailPayloadWithDevtools } from './lib/user-timing-extensibility- export {}; +/** + * Type definitions extending Node.js perf_hooks module to enable Chrome DevTools UserTiming Extensibility API. + * + * The `detail` property allows custom payloads to be attached to performance marks and measures, + * which are then accessible in Chrome DevTools and visualized in as custom tracks right under UserTiming. + * This enables richer performance instrumentation with structured data that DevTools can display. + */ declare module 'node:perf_hooks' { + /** + * Extends the base PerformanceEntry interface with optional custom detail payload. + * + * The detail property enables Chrome DevTools UserTiming Extensibility API by allowing + * structured data to be attached to performance entries for enhanced debugging visualization. + * This augmentation only ensures the payload is preserved and visible to DevTools. + * + * @example + * ```typescript + * // Preserved entries with entry.detail + * const entry = performance.getEntriesByType('mark').at(0); + * ``` + */ interface PerformanceEntry { + /** Custom payload accessible in Chrome DevTools for enhanced performance analysis. */ readonly detail?: DetailPayloadWithDevtools; } + /** + * Represents a performance mark entry with custom detail support for DevTools extensibility. + * + * Mark entries with detail payloads enable Chrome DevTools to display additional context + * and structured data alongside the mark in the Performance tab. Markers create vertical + * lines that span all tracks and appear at the top of the timeline. + * + * @example + * ```typescript + * // Preserved mark entries with entry.detail + * const entry = performance.getEntriesByType('mark').at(0); + * ``` + */ interface MarkEntry extends PerformanceMark { readonly entryType: 'mark'; + /** Custom payload displayed in Chrome DevTools for enhanced mark visualization. */ readonly detail?: DetailPayloadWithDevtools; } + /** + * Represents a performance measure entry with custom detail support for DevTools extensibility. + * + * Measure entries with detail payloads allow Chrome DevTools to show additional metadata + * and context information alongside the measured performance duration. Track entries appear + * in custom tracks below the main UserTiming track. + * + * @example + * ```typescript + * // Preserved measure entries with entry.detail + * const entry = performance.getEntriesByType('measure').at(0); + * ``` + */ interface MeasureEntry extends PerformanceMeasure { readonly entryType: 'measure'; + /** Custom payload displayed in Chrome DevTools for enhanced measure visualization. */ readonly detail?: DetailPayloadWithDevtools; } + /** + * Extends Node.js PerformanceMark to include the custom detail payload support. + * + * This interface ensures that performance marks created through the extended API + * have access to the `detail` property for Chrome DevTools UserTiming Extensibility. + */ interface PerformanceMark extends PerformanceEntry {} + + /** + * Extends Node.js PerformanceMeasure to include the custom detail payload support. + * + * This interface ensures that performance measures created through the extended API + * have access to the `detail` property for Chrome DevTools UserTiming Extensibility. + */ interface PerformanceMeasure extends PerformanceEntry {} + /** + * Options for creating performance marks with custom detail payload for DevTools integration. + * + * The detail property enables attaching structured data that Chrome DevTools can display + * alongside the mark, providing richer debugging context. + * + * @example + * ```typescript + * // Options include detail property + * const options: PerformanceMarkOptions = { detail: { devtools: {} } }; + * ``` + */ export interface PerformanceMarkOptions { + /** Custom payload that will be accessible in Chrome DevTools UserTiming visualization. */ detail?: DetailPayloadWithDevtools; startTime?: DOMHighResTimeStamp; } + /** + * Options for creating performance measures with custom detail payload for DevTools integration. + * + * The detail property allows attaching metadata that Chrome DevTools will display + * with the measure, enabling better performance analysis and debugging. + * + * @example + * ```typescript + * // Options include detail property + * const options: PerformanceMeasureOptions = { detail: { devtools: {} } }; + * ``` + */ export interface PerformanceMeasureOptions { + /** Custom payload that will be accessible in Chrome DevTools UserTiming visualization. */ detail?: DetailPayloadWithDevtools; start?: string | number; end?: string | number; duration?: number; } + /** + * Extended performance observer entry list with typed entry retrieval. + */ export interface PerformanceObserverEntryList { getEntriesByType: (type: EntryType) => PerformanceEntry[]; } + /** + * Extended performance object with Chrome DevTools UserTiming Extensibility API support. + * + * Enables creating performance marks and measures with custom detail payloads that are + * displayed in Chrome DevTools, providing enhanced debugging and performance analysis capabilities. + */ const performance: { + /** + * Creates a performance mark with optional custom detail payload for DevTools visualization. + * + * The detail payload will be accessible in Chrome DevTools Performance tab, + * enabling richer debugging context for the mark. + * + * @example + * ```typescript + * // Accepts detail options + * performance.mark('checkpoint', { detail: { devtools: {} } }); + * ``` + * + * @param name - The name of the mark displayed in DevTools + * @param options - Optional configuration including detail payload for DevTools + * @returns The created performance mark with DevTools-compatible detail + */ mark: (name: string, options?: PerformanceMarkOptions) => PerformanceMark; + /** + * Creates a performance measure with optional custom detail payload for DevTools visualization. + * + * The detail payload enables Chrome DevTools to display additional metadata + * alongside the measured performance duration for enhanced analysis. + * + * @example + * ```typescript + * // Accepts detail options + * performance.measure('task', { detail: { devtools: {} } }); + * ``` + * + * @param name - The name of the measure displayed in DevTools + * @param startOrOptions - Start mark name/number or full options object with DevTools detail + * @param end - End mark name/number (when startOrOptions is not options object) + * @returns The created performance measure with DevTools-compatible detail + */ measure: ( name: string, startOrOptions?: string | number | PerformanceMeasureOptions, end?: string | number, ) => PerformanceMeasure; + /** + * Retrieves performance entries of the specified type, including DevTools detail payloads. + * + * @example + * ```typescript + * // Returns entries with preserved entry.detail + * const entry = performance.getEntriesByType('mark').at(0); + * ``` + * + * @param type - The entry type to filter by ('mark' or 'measure') + * @returns Array of performance entries with DevTools detail payloads + */ getEntriesByType: (type: EntryType) => PerformanceEntry[]; }; } From 2db06ff9e0d7821cf0236948f0324c203e71beda Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 19 Jan 2026 01:49:33 +0100 Subject: [PATCH 12/17] refactor: fix d.ts overloads and test them --- packages/utils/src/perf-hooks.d.ts | 284 +++++++-------------- packages/utils/src/perf-hooks.type.test.ts | 205 +++++++++++++++ packages/utils/src/perf-hooks.unit.test.ts | 90 ------- 3 files changed, 302 insertions(+), 277 deletions(-) create mode 100644 packages/utils/src/perf-hooks.type.test.ts delete mode 100644 packages/utils/src/perf-hooks.unit.test.ts diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index 5501bdb4c..be23fff12 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -1,192 +1,102 @@ +import type { + Performance, + PerformanceEntry, + PerformanceMark, + PerformanceMeasure, + PerformanceObserverEntryList, +} from 'node:perf_hooks'; import type { DetailPayloadWithDevtools } from './lib/user-timing-extensibility-api.type'; -export {}; +export type EntryType = 'mark' | 'measure'; + +export type DOMHighResTimeStamp = number; + +/* == Internal Overrides Start == */ +interface PerformanceEntryExtended extends PerformanceEntry { + readonly detail?: DetailPayloadWithDevtools; +} + +interface MarkEntryExtended extends PerformanceMark { + readonly entryType: 'mark'; +} + +interface MeasureEntryExtended extends PerformanceMeasure { + readonly entryType: 'measure'; +} + +interface PerformanceMarkExtended extends PerformanceMark { + readonly detail?: DetailPayloadWithDevtools; +} + +interface PerformanceMeasureExtended extends PerformanceMeasure { + readonly detail?: DetailPayloadWithDevtools; +} + +interface PerformanceObserverEntryListExtended + extends PerformanceObserverEntryList { + getEntries(): PerformanceEntryExtended[]; + getEntriesByName(name: string, type?: EntryType): PerformanceEntryExtended[]; + getEntriesByType(type: EntryType): PerformanceEntryExtended[]; +} + +interface PerformanceMarkOptionsExtended { + detail?: DetailPayloadWithDevtools; + startTime?: DOMHighResTimeStamp; +} + +interface PerformanceMeasureOptionsExtended { + detail?: DetailPayloadWithDevtools; + start?: string | number; + end?: string | number; + duration?: number; +} + +interface PerformanceEntryListExtended { + getEntries(): PerformanceEntryExtended[]; + getEntriesByName(name: string, type?: EntryType): PerformanceEntryExtended[]; + getEntriesByType(type: EntryType): PerformanceEntryExtended[]; +} + +interface PerformanceExtended extends Performance { + mark: ( + name: string, + options?: PerformanceMarkOptionsExtended, + ) => PerformanceMarkExtended; + measure: ( + name: string, + startOrOptions?: string | number | PerformanceMeasureOptionsExtended, + end?: string | number, + ) => PerformanceMeasureExtended; + getEntriesByType: (type: EntryType) => PerformanceEntryExtended[]; + getEntries(): PerformanceEntryExtended[]; + getEntriesByName(name: string, type?: EntryType): PerformanceEntryExtended[]; + takeRecords(): PerformanceEntryExtended[]; +} +/* == Internal Overrides End == */ -/** - * Type definitions extending Node.js perf_hooks module to enable Chrome DevTools UserTiming Extensibility API. - * - * The `detail` property allows custom payloads to be attached to performance marks and measures, - * which are then accessible in Chrome DevTools and visualized in as custom tracks right under UserTiming. - * This enables richer performance instrumentation with structured data that DevTools can display. - */ declare module 'node:perf_hooks' { - /** - * Extends the base PerformanceEntry interface with optional custom detail payload. - * - * The detail property enables Chrome DevTools UserTiming Extensibility API by allowing - * structured data to be attached to performance entries for enhanced debugging visualization. - * This augmentation only ensures the payload is preserved and visible to DevTools. - * - * @example - * ```typescript - * // Preserved entries with entry.detail - * const entry = performance.getEntriesByType('mark').at(0); - * ``` - */ - interface PerformanceEntry { - /** Custom payload accessible in Chrome DevTools for enhanced performance analysis. */ - readonly detail?: DetailPayloadWithDevtools; - } - - /** - * Represents a performance mark entry with custom detail support for DevTools extensibility. - * - * Mark entries with detail payloads enable Chrome DevTools to display additional context - * and structured data alongside the mark in the Performance tab. Markers create vertical - * lines that span all tracks and appear at the top of the timeline. - * - * @example - * ```typescript - * // Preserved mark entries with entry.detail - * const entry = performance.getEntriesByType('mark').at(0); - * ``` - */ - interface MarkEntry extends PerformanceMark { - readonly entryType: 'mark'; - /** Custom payload displayed in Chrome DevTools for enhanced mark visualization. */ - readonly detail?: DetailPayloadWithDevtools; - } - - /** - * Represents a performance measure entry with custom detail support for DevTools extensibility. - * - * Measure entries with detail payloads allow Chrome DevTools to show additional metadata - * and context information alongside the measured performance duration. Track entries appear - * in custom tracks below the main UserTiming track. - * - * @example - * ```typescript - * // Preserved measure entries with entry.detail - * const entry = performance.getEntriesByType('measure').at(0); - * ``` - */ - interface MeasureEntry extends PerformanceMeasure { - readonly entryType: 'measure'; - /** Custom payload displayed in Chrome DevTools for enhanced measure visualization. */ - readonly detail?: DetailPayloadWithDevtools; - } - - /** - * Extends Node.js PerformanceMark to include the custom detail payload support. - * - * This interface ensures that performance marks created through the extended API - * have access to the `detail` property for Chrome DevTools UserTiming Extensibility. - */ - interface PerformanceMark extends PerformanceEntry {} - - /** - * Extends Node.js PerformanceMeasure to include the custom detail payload support. - * - * This interface ensures that performance measures created through the extended API - * have access to the `detail` property for Chrome DevTools UserTiming Extensibility. - */ - interface PerformanceMeasure extends PerformanceEntry {} - - /** - * Options for creating performance marks with custom detail payload for DevTools integration. - * - * The detail property enables attaching structured data that Chrome DevTools can display - * alongside the mark, providing richer debugging context. - * - * @example - * ```typescript - * // Options include detail property - * const options: PerformanceMarkOptions = { detail: { devtools: {} } }; - * ``` - */ - export interface PerformanceMarkOptions { - /** Custom payload that will be accessible in Chrome DevTools UserTiming visualization. */ - detail?: DetailPayloadWithDevtools; - startTime?: DOMHighResTimeStamp; - } - - /** - * Options for creating performance measures with custom detail payload for DevTools integration. - * - * The detail property allows attaching metadata that Chrome DevTools will display - * with the measure, enabling better performance analysis and debugging. - * - * @example - * ```typescript - * // Options include detail property - * const options: PerformanceMeasureOptions = { detail: { devtools: {} } }; - * ``` - */ - export interface PerformanceMeasureOptions { - /** Custom payload that will be accessible in Chrome DevTools UserTiming visualization. */ - detail?: DetailPayloadWithDevtools; - start?: string | number; - end?: string | number; - duration?: number; - } - - /** - * Extended performance observer entry list with typed entry retrieval. - */ - export interface PerformanceObserverEntryList { - getEntriesByType: (type: EntryType) => PerformanceEntry[]; - } - - /** - * Extended performance object with Chrome DevTools UserTiming Extensibility API support. - * - * Enables creating performance marks and measures with custom detail payloads that are - * displayed in Chrome DevTools, providing enhanced debugging and performance analysis capabilities. - */ - const performance: { - /** - * Creates a performance mark with optional custom detail payload for DevTools visualization. - * - * The detail payload will be accessible in Chrome DevTools Performance tab, - * enabling richer debugging context for the mark. - * - * @example - * ```typescript - * // Accepts detail options - * performance.mark('checkpoint', { detail: { devtools: {} } }); - * ``` - * - * @param name - The name of the mark displayed in DevTools - * @param options - Optional configuration including detail payload for DevTools - * @returns The created performance mark with DevTools-compatible detail - */ - mark: (name: string, options?: PerformanceMarkOptions) => PerformanceMark; - - /** - * Creates a performance measure with optional custom detail payload for DevTools visualization. - * - * The detail payload enables Chrome DevTools to display additional metadata - * alongside the measured performance duration for enhanced analysis. - * - * @example - * ```typescript - * // Accepts detail options - * performance.measure('task', { detail: { devtools: {} } }); - * ``` - * - * @param name - The name of the measure displayed in DevTools - * @param startOrOptions - Start mark name/number or full options object with DevTools detail - * @param end - End mark name/number (when startOrOptions is not options object) - * @returns The created performance measure with DevTools-compatible detail - */ - measure: ( - name: string, - startOrOptions?: string | number | PerformanceMeasureOptions, - end?: string | number, - ) => PerformanceMeasure; - - /** - * Retrieves performance entries of the specified type, including DevTools detail payloads. - * - * @example - * ```typescript - * // Returns entries with preserved entry.detail - * const entry = performance.getEntriesByType('mark').at(0); - * ``` - * - * @param type - The entry type to filter by ('mark' or 'measure') - * @returns Array of performance entries with DevTools detail payloads - */ - getEntriesByType: (type: EntryType) => PerformanceEntry[]; - }; + export interface PerformanceEntry extends PerformanceEntryExtended {} + + export interface PerformanceEntryList extends PerformanceEntryListExtended {} + + export interface MarkEntry extends PerformanceMark, MarkEntryExtended {} + + export interface MeasureEntry + extends PerformanceMeasure, + MeasureEntryExtended {} + + export interface PerformanceMark extends PerformanceMarkExtended {} + + export interface PerformanceMeasure extends PerformanceMeasureExtended {} + + export interface PerformanceMarkOptions + extends PerformanceMarkOptionsExtended {} + + export interface PerformanceMeasureOptions + extends PerformanceMeasureOptionsExtended {} + + export interface PerformanceObserverEntryList + extends PerformanceObserverEntryListExtended {} + + const performance: PerformanceExtended; } diff --git a/packages/utils/src/perf-hooks.type.test.ts b/packages/utils/src/perf-hooks.type.test.ts new file mode 100644 index 000000000..b171971aa --- /dev/null +++ b/packages/utils/src/perf-hooks.type.test.ts @@ -0,0 +1,205 @@ +import { + type PerformanceEntry, + type PerformanceMarkOptions, + type PerformanceMeasureOptions, + performance, +} from 'node:perf_hooks'; +import { describe, expect, it } from 'vitest'; + +describe('interfaces', () => { + it('PerformanceMarkOptions should be type safe', () => { + // Valid complete example + expect( + () => + ({ + startTime: 0, + detail: { + devtools: { + color: 'error', + track: 'test-track', + trackGroup: 'test-trackGroup', + properties: [['Key', '42']], + tooltipText: 'test-tooltipText', + }, + }, + }) satisfies PerformanceMarkOptions, + ).not.toThrow(); + // Invalid Examples + expect( + () => + ({ + startTime: 0, + detail: { + devtools: { + // @ts-expect-error - dataType should be marker | track + dataType: 'markerr', + // @ts-expect-error - color should be DevToolsColor + color: 'other', + // @ts-expect-error - properties should be an array of [string, string] + properties: { wrong: 'shape' }, + }, + }, + }) satisfies PerformanceMarkOptions, + ).not.toThrow(); + }); + + it('PerformanceMeasureOptions should be type safe', () => { + // Valid complete example + expect( + () => + ({ + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + dataType: 'track-entry', + track: 'test-track', + color: 'primary', + }, + }, + }) satisfies PerformanceMeasureOptions, + ).not.toThrow(); + // Invalid Examples + expect( + () => + ({ + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + // @ts-expect-error - dataType should be track-entry | marker + dataType: 'markerr', + track: 'test-track', + color: 'primary', + }, + }, + }) satisfies PerformanceMeasureOptions, + ).not.toThrow(); + }); + + it.todo('PerformanceEntry should be type safe', () => { + // Valid complete example + expect( + () => + ({ + name: 'test-entry', + entryType: 'mark', + startTime: 0, + duration: 0, + toJSON: () => ({}), + detail: { + devtools: { + dataType: 'marker', + color: 'primary', + }, + }, + }) satisfies PerformanceEntry, + ).not.toThrow(); + // Invalid Examples + expect( + () => + ({ + name: 'test-entry', + entryType: 'mark', + startTime: 0, + duration: 0, + toJSON: () => ({}), + detail: { + devtools: { + dataType: 'invalid-type', // Should fail + color: 'invalid-color', // Should fail + properties: { wrong: 'shape' }, // Should fail + }, + }, + }) satisfies PerformanceEntry, + ).not.toThrow(); + }); + + it('performance.getEntriesByType returns extended entries', () => { + const entries = performance.getEntriesByType('mark'); + + entries.forEach(e => { + e.detail?.devtools; + }); + }); +}); + +describe('API', () => { + it('performance.mark should be type safe', () => { + // Valid complete example + expect(() => + performance.mark('name', { + detail: { + devtools: { + dataType: 'marker', + color: 'error', + }, + }, + }), + ).not.toThrow(); + // Invalid Examples + expect(() => + performance.mark('name', { + detail: { + devtools: { + // @ts-expect-error - dataType should be marker | track + dataType: 'markerrr', + // @ts-expect-error - color should be DevToolsColor + color: 'invalid-color', + // @ts-expect-error - properties should be an array of [string, string] + properties: 'invalid-properties', + }, + }, + }), + ).not.toThrow(); + }); + + it('performance.measure should be type safe', () => { + // Create marks for measurement + performance.mark('start-mark'); + performance.mark('end-mark'); + + // Valid examples + expect(() => + performance.measure('measure-name', 'start-mark', 'end-mark'), + ).not.toThrow(); + expect(() => + performance.measure('measure-name', { + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + dataType: 'track-entry', + track: 'test-track', + color: 'primary', + }, + }, + }), + ).not.toThrow(); + // Invalid Examples + expect(() => + performance.measure('measure-name', { + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + // @ts-expect-error - dataType should be track-entry | marker + dataType: 'invalid-type', + // @ts-expect-error - color should be DevToolsColor + color: 'invalid-color', + }, + }, + }), + ).not.toThrow(); + }); + + it('performance.getEntriesByType should be type safe', () => { + // Invalid Examples + expect(() => + performance.getEntriesByType('mark').forEach(e => { + // @ts-expect-error - dataType should be valid + e.detail?.devtools?.dataType === 'markerr'; + }), + ).not.toThrow(); + }); +}); diff --git a/packages/utils/src/perf-hooks.unit.test.ts b/packages/utils/src/perf-hooks.unit.test.ts deleted file mode 100644 index 1f11ac07f..000000000 --- a/packages/utils/src/perf-hooks.unit.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { type PerformanceMarkOptions, performance } from 'node:perf_hooks'; -import { describe, expect, expectTypeOf, it } from 'vitest'; - -describe('perf-hooks definitions', () => { - it('PerformanceMarkOptions should be type safe', () => { - expect(() => - expectTypeOf<{ - startTime: number; - detail: { - devtools: { - dataType: 'marker'; - color: 'error'; - }; - }; - }>().toMatchTypeOf(), - ).not.toThrow(); - - expect(() => - expectTypeOf<{ - startTime: number; - detail: { - devtools: { - dataType: 'markerr'; - }; - }; - }>().not.toMatchTypeOf(), - ).not.toThrow(); - }); - - it('perf_hooks.mark should be type safe', () => { - expect(() => - performance.mark('name', { - detail: { - devtools: { - dataType: 'marker', - color: 'error', - }, - }, - }), - ).not.toThrow(); - - expect(() => - performance.mark('name', { - detail: { - devtools: { - // @ts-expect-error - dataType should be marker | track - dataType: 'markerrr', - color: 'error', - }, - }, - }), - ).not.toThrow(); - }); - - it('PerformanceMeasureOptions should be type safe', () => { - expect(() => - expectTypeOf<{ - start: string; - end: string; - detail: { - devtools: { - dataType: 'track-entry'; - track: 'test-track'; - color: 'primary'; - }; - }; - }>().toMatchTypeOf(), - ).not.toThrow(); - }); - - it('perf_hooks.measure should be type safe', () => { - expect(() => - performance.measure('measure-name', 'start-mark', 'end-mark'), - ).not.toThrow(); - - expect(() => - performance.measure('measure-name', { - start: 'start-mark', - end: 'end-mark', - detail: { - // @ts-expect-error - track is required - devtools: { - dataType: 'track-entry', - color: 'primary', - }, - }, - }), - ).not.toThrow(); - }); -}); From fefaed65a3ea52768a3bcbb1411c1199efa90baf Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sun, 1 Feb 2026 21:47:52 +0100 Subject: [PATCH 13/17] refactor: wip --- .../src/lib/profiler/trace-file-utils.ts | 30 +- .../profiler/trace-file-utils.unit.test.ts | 62 ++- .../src/lib/reports/load-report.unit.test.ts | 3 + .../lib/user-timing-extensibility-api.type.ts | 2 +- packages/utils/src/perf-hooks.d.ts | 132 ++++-- packages/utils/src/perf-hooks.type.test.ts | 392 +++++++++--------- packages/utils/tsconfig.lib.json | 8 +- packages/utils/tsconfig.test.json | 1 + 8 files changed, 382 insertions(+), 248 deletions(-) diff --git a/packages/utils/src/lib/profiler/trace-file-utils.ts b/packages/utils/src/lib/profiler/trace-file-utils.ts index 1061062d3..b5deed7bc 100644 --- a/packages/utils/src/lib/profiler/trace-file-utils.ts +++ b/packages/utils/src/lib/profiler/trace-file-utils.ts @@ -335,17 +335,27 @@ function processDetail( return target; } +function encodeDetailToString( + target: T, +): T & { detail?: string } { + return processDetail(target, (detail: string | object) => + typeof detail === 'object' ? JSON.stringify(detail) : detail, + ) as T & { detail?: string }; +} + /** * 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: { detail: string }): UserTimingDetail { +export function decodeDetail( + target: T, +): T { return processDetail(target, detail => typeof detail === 'string' ? (JSON.parse(detail) as string | object) : detail, - ) as UserTimingDetail; + ); } /** @@ -353,14 +363,14 @@ export function decodeDetail(target: { detail: string }): UserTimingDetail { * @param target - UserTimingDetail object with detail property to encode * @returns UserTimingDetail with object details converted to JSON strings */ -export function encodeDetail(target: UserTimingDetail): UserTimingDetail { +export function encodeDetail( + target: T, +): T { return processDetail( - target as UserTimingDetail & { detail?: unknown }, + target as T & { detail?: unknown }, (detail: string | object) => - typeof detail === 'object' - ? JSON.stringify(detail as UserTimingDetail) - : detail, - ) as UserTimingDetail; + typeof detail === 'object' ? JSON.stringify(detail) : detail, + ); } /** @@ -406,13 +416,13 @@ export function encodeTraceEvent({ return rest as TraceEventRaw; } - const processedArgs = encodeDetail(args as UserTimingDetail); + const processedArgs = encodeDetailToString(args as { detail?: unknown }); if ('data' in args && args.data && typeof args.data === 'object') { const result: TraceEventRaw = { ...rest, args: { ...processedArgs, - data: encodeDetail(args.data as UserTimingDetail), + data: encodeDetailToString(args.data as { detail?: unknown }), }, }; return result; diff --git a/packages/utils/src/lib/profiler/trace-file-utils.unit.test.ts b/packages/utils/src/lib/profiler/trace-file-utils.unit.test.ts index aa21887af..2ae974c81 100644 --- a/packages/utils/src/lib/profiler/trace-file-utils.unit.test.ts +++ b/packages/utils/src/lib/profiler/trace-file-utils.unit.test.ts @@ -623,16 +623,18 @@ describe('getTraceMetadata', () => { describe('decodeDetail', () => { it('should decode string detail back to object', () => { - const input = { detail: '{"key": "value"}' }; + const input = { + detail: '{"devtools":{"dataType":"marker","color":"primary"}}', + }; const result = decodeDetail(input); expect(result).toStrictEqual({ - detail: { key: 'value' }, + detail: { devtools: { dataType: 'marker', color: 'primary' } }, }); }); it('should return object detail unchanged', () => { - const input = { detail: { key: 'value' } }; + const input = { detail: { devtools: { dataType: 'marker' as const } } }; const result = decodeDetail(input); expect(result).toStrictEqual(input); @@ -655,11 +657,11 @@ describe('decodeDetail', () => { describe('encodeDetail', () => { it('should encode object detail to JSON string', () => { - const input = { detail: { key: 'value' } }; + const input = { detail: { devtools: { dataType: 'marker' as const } } }; const result = encodeDetail(input); expect(result).toStrictEqual({ - detail: '{"key":"value"}', + detail: '{"devtools":{"dataType":"marker"}}', }); }); @@ -695,8 +697,11 @@ describe('decodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: '{"custom": "data"}', - data: { detail: '{"nested": "value"}' }, + detail: '{"devtools":{"dataType":"marker","color":"primary"}}', + data: { + detail: + '{"devtools":{"dataType":"track-entry","track":"test-track"}}', + }, }, }; @@ -710,8 +715,14 @@ describe('decodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: { custom: 'data' }, - data: { detail: { nested: 'value' } }, + detail: { + devtools: { dataType: 'marker' as const, color: 'primary' as const }, + }, + data: { + detail: { + devtools: { dataType: 'track-entry' as const, track: 'test-track' }, + }, + }, }, }); }); @@ -724,6 +735,7 @@ describe('decodeTraceEvent', () => { pid: 123, tid: 456, ts: 1000, + args: {}, }; const result = decodeTraceEvent(rawEvent); @@ -735,6 +747,7 @@ describe('decodeTraceEvent', () => { pid: 123, tid: 456, ts: 1000, + args: {}, }); }); @@ -747,7 +760,7 @@ describe('decodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: '{"custom": "data"}', + detail: '{"devtools":{"dataType":"marker","color":"primary"}}', }, }; @@ -761,7 +774,9 @@ describe('decodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: { custom: 'data' }, + detail: { + devtools: { dataType: 'marker' as const, color: 'primary' as const }, + }, }, }); }); @@ -777,8 +792,14 @@ describe('encodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: { custom: 'data' }, - data: { detail: { nested: 'value' } }, + detail: { + devtools: { dataType: 'marker' as const, color: 'primary' as const }, + }, + data: { + detail: { + devtools: { dataType: 'track-entry' as const, track: 'test-track' }, + }, + }, }, }; @@ -792,8 +813,11 @@ describe('encodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: '{"custom":"data"}', - data: { detail: '{"nested":"value"}' }, + detail: '{"devtools":{"dataType":"marker","color":"primary"}}', + data: { + detail: + '{"devtools":{"dataType":"track-entry","track":"test-track"}}', + }, }, }); }); @@ -806,6 +830,7 @@ describe('encodeTraceEvent', () => { pid: 123, tid: 456, ts: 1000, + args: {}, }; const result = encodeTraceEvent(event); @@ -817,6 +842,7 @@ describe('encodeTraceEvent', () => { pid: 123, tid: 456, ts: 1000, + args: {}, }); }); @@ -829,7 +855,9 @@ describe('encodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: { custom: 'data' }, + detail: { + devtools: { dataType: 'marker' as const, color: 'primary' as const }, + }, }, }; @@ -843,7 +871,7 @@ describe('encodeTraceEvent', () => { tid: 456, ts: 1000, args: { - detail: '{"custom":"data"}', + detail: '{"devtools":{"dataType":"marker","color":"primary"}}', }, }); }); diff --git a/packages/utils/src/lib/reports/load-report.unit.test.ts b/packages/utils/src/lib/reports/load-report.unit.test.ts index acafeb61c..0fa3c3b92 100644 --- a/packages/utils/src/lib/reports/load-report.unit.test.ts +++ b/packages/utils/src/lib/reports/load-report.unit.test.ts @@ -19,6 +19,7 @@ describe('loadReport', () => { outputDir: MEMFS_VOLUME, filename: 'report', format: 'json', + skipReports: false, }), ).resolves.toEqual(reportMock()); }); @@ -38,6 +39,7 @@ describe('loadReport', () => { outputDir: MEMFS_VOLUME, format: 'md', filename: 'report', + skipReports: false, }), ).resolves.toBe('test-42'); }); @@ -58,6 +60,7 @@ describe('loadReport', () => { outputDir: MEMFS_VOLUME, filename: 'report', format: 'json', + skipReports: false, }), ).rejects.toThrow('slug has to follow the pattern'); }); diff --git a/packages/utils/src/lib/user-timing-extensibility-api.type.ts b/packages/utils/src/lib/user-timing-extensibility-api.type.ts index ed93242ad..3877f260d 100644 --- a/packages/utils/src/lib/user-timing-extensibility-api.type.ts +++ b/packages/utils/src/lib/user-timing-extensibility-api.type.ts @@ -132,7 +132,7 @@ export type ActionTrackEntryPayload = TrackEntryPayload & ActionColorPayload; * Utility type that adds an optional devtools payload property. */ export type WithDevToolsPayload = { - devtools?: T; + devtools: T; }; /** diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index be23fff12..92d1146ab 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -1,10 +1,16 @@ import type { - Performance, - PerformanceEntry, - PerformanceMark, - PerformanceMeasure, - PerformanceObserverEntryList, -} from 'node:perf_hooks'; + EventLoopUtilityFunction, + MeasureOptions as OriginalMeasureOptions, + Performance as OriginalPerformance, + PerformanceEntry as OriginalPerformanceEntry, + PerformanceMark as OriginalPerformanceMark, + PerformanceMeasure as OriginalPerformanceMeasure, + PerformanceObserverEntryList as OriginalPerformanceObserverEntryList, + PerformanceNodeTiming, + PerformanceResourceTiming, + TimerifyOptions, + performance, +} from 'perf_hooks'; import type { DetailPayloadWithDevtools } from './lib/user-timing-extensibility-api.type'; export type EntryType = 'mark' | 'measure'; @@ -12,28 +18,35 @@ export type EntryType = 'mark' | 'measure'; export type DOMHighResTimeStamp = number; /* == Internal Overrides Start == */ -interface PerformanceEntryExtended extends PerformanceEntry { +// This is needed to get pickedup by the IDE. We cand directly do this in the exported definitions +interface PerformanceEntryExtended { + name: string; + entryType: string; + startTime: number; + duration: number; readonly detail?: DetailPayloadWithDevtools; + toJSON(): any; } -interface MarkEntryExtended extends PerformanceMark { +interface MarkEntryExtended extends OriginalPerformanceMark { readonly entryType: 'mark'; } -interface MeasureEntryExtended extends PerformanceMeasure { +interface MeasureEntryExtended extends OriginalPerformanceMeasure { readonly entryType: 'measure'; } -interface PerformanceMarkExtended extends PerformanceMark { - readonly detail?: DetailPayloadWithDevtools; +interface PerformanceMarkExtended extends PerformanceEntryExtended { + readonly entryType: 'mark'; + readonly duration: 0; } -interface PerformanceMeasureExtended extends PerformanceMeasure { - readonly detail?: DetailPayloadWithDevtools; +interface PerformanceMeasureExtended extends PerformanceEntryExtended { + readonly entryType: 'measure'; } interface PerformanceObserverEntryListExtended - extends PerformanceObserverEntryList { + extends OriginalPerformanceObserverEntryList { getEntries(): PerformanceEntryExtended[]; getEntriesByName(name: string, type?: EntryType): PerformanceEntryExtended[]; getEntriesByType(type: EntryType): PerformanceEntryExtended[]; @@ -50,32 +63,91 @@ interface PerformanceMeasureOptionsExtended { end?: string | number; duration?: number; } - interface PerformanceEntryListExtended { getEntries(): PerformanceEntryExtended[]; getEntriesByName(name: string, type?: EntryType): PerformanceEntryExtended[]; getEntriesByType(type: EntryType): PerformanceEntryExtended[]; } -interface PerformanceExtended extends Performance { - mark: ( +declare class PerformanceExtended { + clearMarks(name?: string): void; + clearMeasures(name?: string): void; + clearResourceTimings(name?: string): void; + eventLoopUtilization: EventLoopUtilityFunction; + + mark( name: string, options?: PerformanceMarkOptionsExtended, - ) => PerformanceMarkExtended; - measure: ( + ): PerformanceMarkExtended; + + markResourceTiming( + timingInfo: object, + requestedUrl: string, + initiatorType: string, + global: object, + cacheMode: '' | 'local', + bodyInfo: object, + responseStatus: number, + deliveryType?: string, + ): PerformanceResourceTiming; + + measure( name: string, - startOrOptions?: string | number | PerformanceMeasureOptionsExtended, - end?: string | number, - ) => PerformanceMeasureExtended; + startMarkOrOptions?: string | PerformanceMeasureOptionsExtended, + endMark?: string, + ): PerformanceMeasureExtended; + + readonly nodeTiming: PerformanceNodeTiming; + now(): number; + setResourceTimingBufferSize(maxSize: number): void; + readonly timeOrigin: number; + timerify any>( + fn: T, + options?: TimerifyOptions, + ): T; + toJSON(): any; + getEntriesByType: (type: EntryType) => PerformanceEntryExtended[]; getEntries(): PerformanceEntryExtended[]; getEntriesByName(name: string, type?: EntryType): PerformanceEntryExtended[]; - takeRecords(): PerformanceEntryExtended[]; } /* == Internal Overrides End == */ +declare module 'perf_hooks' { + export interface PerformanceEntry extends OriginalPerformanceEntry { + readonly detail?: DetailPayloadWithDevtools; + } + + export interface PerformanceEntryList extends PerformanceEntryListExtended {} + + export interface MarkEntry extends PerformanceMark, MarkEntryExtended {} + + export interface MeasureEntry + extends PerformanceMeasure, + MeasureEntryExtended {} + + export interface PerformanceMark extends PerformanceMarkExtended {} + + export interface PerformanceMeasure extends PerformanceMeasureExtended {} + + export interface MarkOptions extends PerformanceMarkOptionsExtended {} + + export interface MeasureOptions extends PerformanceMeasureOptionsExtended {} + + export type PerformanceMarkOptions = PerformanceMarkOptionsExtended; + + export type PerformanceMeasureOptions = PerformanceMeasureOptionsExtended; + + export interface PerformanceObserverEntryList + extends PerformanceObserverEntryListExtended {} + + export const performance: PerformanceExtended; +} + declare module 'node:perf_hooks' { - export interface PerformanceEntry extends PerformanceEntryExtended {} + export interface PerformanceEntry extends OriginalPerformanceEntry { + readonly detail?: DetailPayloadWithDevtools; + } export interface PerformanceEntryList extends PerformanceEntryListExtended {} @@ -89,14 +161,16 @@ declare module 'node:perf_hooks' { export interface PerformanceMeasure extends PerformanceMeasureExtended {} - export interface PerformanceMarkOptions - extends PerformanceMarkOptionsExtended {} + export interface MarkOptions extends PerformanceMarkOptionsExtended {} + + export interface MeasureOptions extends PerformanceMeasureOptionsExtended {} + + export type PerformanceMarkOptions = PerformanceMarkOptionsExtended; - export interface PerformanceMeasureOptions - extends PerformanceMeasureOptionsExtended {} + export type PerformanceMeasureOptions = PerformanceMeasureOptionsExtended; export interface PerformanceObserverEntryList extends PerformanceObserverEntryListExtended {} - const performance: PerformanceExtended; + export const performance: PerformanceExtended; } diff --git a/packages/utils/src/perf-hooks.type.test.ts b/packages/utils/src/perf-hooks.type.test.ts index b171971aa..e461c4488 100644 --- a/packages/utils/src/perf-hooks.type.test.ts +++ b/packages/utils/src/perf-hooks.type.test.ts @@ -2,204 +2,218 @@ import { type PerformanceEntry, type PerformanceMarkOptions, type PerformanceMeasureOptions, + PerformanceObserver, performance, -} from 'node:perf_hooks'; -import { describe, expect, it } from 'vitest'; +} from 'perf_hooks'; +import type { DetailPayloadWithDevtools } from './lib/user-timing-extensibility-api.type'; -describe('interfaces', () => { - it('PerformanceMarkOptions should be type safe', () => { - // Valid complete example - expect( - () => - ({ - startTime: 0, - detail: { - devtools: { - color: 'error', - track: 'test-track', - trackGroup: 'test-trackGroup', - properties: [['Key', '42']], - tooltipText: 'test-tooltipText', - }, - }, - }) satisfies PerformanceMarkOptions, - ).not.toThrow(); - // Invalid Examples - expect( - () => - ({ - startTime: 0, - detail: { - devtools: { - // @ts-expect-error - dataType should be marker | track - dataType: 'markerr', - // @ts-expect-error - color should be DevToolsColor - color: 'other', - // @ts-expect-error - properties should be an array of [string, string] - properties: { wrong: 'shape' }, - }, - }, - }) satisfies PerformanceMarkOptions, - ).not.toThrow(); - }); +// interfaces: PerformanceMarkOptions should be type safe +// Valid complete example +({ + startTime: 0, + detail: { + devtools: { + color: 'error', + track: 'test-track', + trackGroup: 'test-trackGroup', + properties: [['Key', '42']], + tooltipText: 'test-tooltipText', + }, + }, +}) satisfies PerformanceMarkOptions; +// Invalid examples +({ + startTime: 0, + detail: { + devtools: { + // @ts-expect-error - dataType should be marker | track + dataType: 'markerr', + // @ts-expect-error - color should be DevToolsColor + color: 'other', + // @ts-expect-error - properties should be an array of [string, string] + properties: { wrong: 'shape' }, + }, + }, +}) satisfies PerformanceMarkOptions; - it('PerformanceMeasureOptions should be type safe', () => { - // Valid complete example - expect( - () => - ({ - start: 'start-mark', - end: 'end-mark', - detail: { - devtools: { - dataType: 'track-entry', - track: 'test-track', - color: 'primary', - }, - }, - }) satisfies PerformanceMeasureOptions, - ).not.toThrow(); - // Invalid Examples - expect( - () => - ({ - start: 'start-mark', - end: 'end-mark', - detail: { - devtools: { - // @ts-expect-error - dataType should be track-entry | marker - dataType: 'markerr', - track: 'test-track', - color: 'primary', - }, - }, - }) satisfies PerformanceMeasureOptions, - ).not.toThrow(); - }); +// interfaces: PerformanceMeasureOptions should be type safe +// Valid complete example +({ + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + dataType: 'track-entry', + track: 'test-track', + color: 'primary', + }, + }, +}) satisfies PerformanceMeasureOptionsWithDevtools; +// Invalid examples +({ + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + // @ts-expect-error - dataType should be track-entry | marker + dataType: 'markerr', + track: 'test-track', + color: 'primary', + }, + }, +}) satisfies PerformanceMeasureOptionsWithDevtools; - it.todo('PerformanceEntry should be type safe', () => { - // Valid complete example - expect( - () => - ({ - name: 'test-entry', - entryType: 'mark', - startTime: 0, - duration: 0, - toJSON: () => ({}), - detail: { - devtools: { - dataType: 'marker', - color: 'primary', - }, - }, - }) satisfies PerformanceEntry, - ).not.toThrow(); - // Invalid Examples - expect( - () => - ({ - name: 'test-entry', - entryType: 'mark', - startTime: 0, - duration: 0, - toJSON: () => ({}), - detail: { - devtools: { - dataType: 'invalid-type', // Should fail - color: 'invalid-color', // Should fail - properties: { wrong: 'shape' }, // Should fail - }, - }, - }) satisfies PerformanceEntry, - ).not.toThrow(); - }); +// interfaces: PerformanceEntry should be type safe (todo) +// Valid complete example +({ + name: 'test-entry', + entryType: 'mark', + startTime: 0, + duration: 0, + toJSON: () => ({}), + detail: { + devtools: { + dataType: 'marker', + color: 'primary', + }, + }, +}) satisfies PerformanceEntryWithDevtools; +// Invalid examples +({ + name: 'test-entry', + entryType: 'mark', + startTime: 0, + duration: 0, + toJSON: () => ({}), + detail: { + devtools: { + // @ts-expect-error - dataType should be valid + dataType: 'invalid-type', + // @ts-expect-error - color should be DevToolsColor + color: 'invalid-color', + // @ts-expect-error - properties should be an array of [string, string] + properties: { wrong: 'shape' }, + }, + }, +}) satisfies PerformanceEntryWithDevtools; - it('performance.getEntriesByType returns extended entries', () => { - const entries = performance.getEntriesByType('mark'); +// interfaces: performance.getEntriesByType returns extended entries +const entries = performance.getEntriesByType('mark'); - entries.forEach(e => { - e.detail?.devtools; - }); - }); +entries.forEach(e => { + e.detail?.devtools; }); -describe('API', () => { - it('performance.mark should be type safe', () => { - // Valid complete example - expect(() => - performance.mark('name', { - detail: { - devtools: { - dataType: 'marker', - color: 'error', - }, - }, - }), - ).not.toThrow(); - // Invalid Examples - expect(() => - performance.mark('name', { - detail: { - devtools: { - // @ts-expect-error - dataType should be marker | track - dataType: 'markerrr', - // @ts-expect-error - color should be DevToolsColor - color: 'invalid-color', - // @ts-expect-error - properties should be an array of [string, string] - properties: 'invalid-properties', - }, - }, - }), - ).not.toThrow(); - }); +// API: performance.mark should be type safe +// Valid complete example +performance.mark('name', { + detail: { + devtools: { + dataType: 'marker', + color: 'error', + }, + }, +}); +// Invalid examples +performance.mark('name', { + detail: { + devtools: { + // @ts-expect-error - dataType should be marker | track + dataType: 'markerrr', + // @ts-expect-error - color should be DevToolsColor + color: 'invalid-color', + // @ts-expect-error - properties should be an array of [string, string] + properties: 'invalid-properties', + }, + }, +}); + +// API: performance.measure should be type safe +// Create marks for measurement +performance.mark('start-mark'); +performance.mark('end-mark'); + +// Valid examples +performance.measure('measure-name', 'start-mark', 'end-mark'); +performance.measure('measure-name', { + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + dataType: 'track-entry', + track: 'test-track', + color: 'primary', + }, + }, +}); +// Invalid examples +performance.measure('measure-name', { + start: 'start-mark', + end: 'end-mark', + detail: { + devtools: { + // @ts-expect-error - dataType should be track-entry | marker + dataType: 'invalid-type', + // @ts-expect-error - color should be DevToolsColor + color: 'invalid-color', + }, + }, +}); + +// API: performance.getEntriesByType should be type safe +// Valid examples +performance.getEntriesByType('mark').forEach(e => { + e.detail?.devtools?.dataType === 'marker'; +}); +// Invalid examples +performance.getEntriesByType('mark').forEach(e => { + // @ts-expect-error - dataType should be valid + e.detail?.devtools?.dataType === 'markerr'; +}); - it('performance.measure should be type safe', () => { - // Create marks for measurement - performance.mark('start-mark'); - performance.mark('end-mark'); +// API: performance.getEntriesByName should be type safe +// Valid examples +performance.getEntriesByName('name', 'mark').forEach(e => { + e.detail?.devtools?.dataType === 'marker'; +}); +// Invalid examples +performance.getEntriesByName('name', 'mark').forEach(e => { + // @ts-expect-error - dataType should be valid + e.detail?.devtools?.dataType === 'markerr'; +}); - // Valid examples - expect(() => - performance.measure('measure-name', 'start-mark', 'end-mark'), - ).not.toThrow(); - expect(() => - performance.measure('measure-name', { - start: 'start-mark', - end: 'end-mark', - detail: { - devtools: { - dataType: 'track-entry', - track: 'test-track', - color: 'primary', - }, - }, - }), - ).not.toThrow(); - // Invalid Examples - expect(() => - performance.measure('measure-name', { - start: 'start-mark', - end: 'end-mark', - detail: { - devtools: { - // @ts-expect-error - dataType should be track-entry | marker - dataType: 'invalid-type', - // @ts-expect-error - color should be DevToolsColor - color: 'invalid-color', - }, - }, - }), - ).not.toThrow(); - }); +// API: performance.getEntries should be type safe +// Valid examples +performance.getEntries().forEach(e => { + e.detail?.devtools?.dataType === 'marker'; +}); +// Invalid examples +performance.getEntries().forEach(e => { + // @ts-expect-error - dataType should be valid + e.detail?.devtools?.dataType === 'markerr'; +}); - it('performance.getEntriesByType should be type safe', () => { - // Invalid Examples - expect(() => - performance.getEntriesByType('mark').forEach(e => { - // @ts-expect-error - dataType should be valid - e.detail?.devtools?.dataType === 'markerr'; - }), - ).not.toThrow(); - }); +// API: PerformanceObserver.takeRecords should be type safe +const observerRecords = new PerformanceObserver( + () => {}, +).takeRecords() as PerformanceEntryWithDevtools[]; +// Valid examples +observerRecords.forEach(e => { + e.detail?.devtools?.dataType === 'marker'; +}); +// Invalid examples +observerRecords.forEach(e => { + // @ts-expect-error - dataType should be valid + e.detail?.devtools?.dataType === 'markerr'; }); + +// API: performance.clearMarks should be type safe +// Valid examples +performance.clearMarks(); +// Invalid examples +performance.clearMarks('name'); + +// API: performance.clearMeasures should be type safe +// Valid examples +performance.clearMeasures(); +// Invalid examples diff --git a/packages/utils/tsconfig.lib.json b/packages/utils/tsconfig.lib.json index 17dadcedf..a4607dabe 100644 --- a/packages/utils/tsconfig.lib.json +++ b/packages/utils/tsconfig.lib.json @@ -1,11 +1,15 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "../../dist/out-tsc", + "outDir": "dist", "declaration": true, "types": ["node"] }, - "include": ["src/**/*.ts"], + "include": [ + "src/**/*.ts", + "src/*.d.ts", + "src/**/*.d.ts" + ], "exclude": [ "vitest.unit.config.ts", "vitest.int.config.ts", diff --git a/packages/utils/tsconfig.test.json b/packages/utils/tsconfig.test.json index 54cacd82f..0c4f6d806 100644 --- a/packages/utils/tsconfig.test.json +++ b/packages/utils/tsconfig.test.json @@ -12,6 +12,7 @@ "src/**/*.test.tsx", "src/**/*.test.js", "src/**/*.test.jsx", + "src/*.d.ts", "src/**/*.d.ts", "../../testing/test-setup/src/vitest.d.ts" ] From 48d72d1ebd6caeebc25dfb813f2cf7bc555ef611 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sun, 1 Feb 2026 21:49:24 +0100 Subject: [PATCH 14/17] refactor: wip --- packages/utils/src/perf-hooks.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/perf-hooks.d.ts b/packages/utils/src/perf-hooks.d.ts index 92d1146ab..fe0b7c35b 100644 --- a/packages/utils/src/perf-hooks.d.ts +++ b/packages/utils/src/perf-hooks.d.ts @@ -10,7 +10,7 @@ import type { PerformanceResourceTiming, TimerifyOptions, performance, -} from 'perf_hooks'; +} from 'node:perf_hooks'; import type { DetailPayloadWithDevtools } from './lib/user-timing-extensibility-api.type'; export type EntryType = 'mark' | 'measure'; From f4566fd7bd54ddd5f7d6077045a5380caea41774 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Sun, 1 Feb 2026 21:49:48 +0100 Subject: [PATCH 15/17] refactor: wip --- packages/utils/tsconfig.lib.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/utils/tsconfig.lib.json b/packages/utils/tsconfig.lib.json index a4607dabe..a9e4fc5be 100644 --- a/packages/utils/tsconfig.lib.json +++ b/packages/utils/tsconfig.lib.json @@ -5,11 +5,7 @@ "declaration": true, "types": ["node"] }, - "include": [ - "src/**/*.ts", - "src/*.d.ts", - "src/**/*.d.ts" - ], + "include": ["src/**/*.ts", "src/*.d.ts", "src/**/*.d.ts"], "exclude": [ "vitest.unit.config.ts", "vitest.int.config.ts", From 54f5b0129f943faccfdb8913b0030f921d7f71e2 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Sun, 1 Feb 2026 22:46:47 +0100 Subject: [PATCH 16/17] Update packages/utils/src/lib/user-timing-extensibility-api.type.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/utils/src/lib/user-timing-extensibility-api.type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/lib/user-timing-extensibility-api.type.ts b/packages/utils/src/lib/user-timing-extensibility-api.type.ts index 3877f260d..ed93242ad 100644 --- a/packages/utils/src/lib/user-timing-extensibility-api.type.ts +++ b/packages/utils/src/lib/user-timing-extensibility-api.type.ts @@ -132,7 +132,7 @@ export type ActionTrackEntryPayload = TrackEntryPayload & ActionColorPayload; * Utility type that adds an optional devtools payload property. */ export type WithDevToolsPayload = { - devtools: T; + devtools?: T; }; /** From a08b22706e08ca8db80f0d8707490377ec4d16c4 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Sun, 1 Feb 2026 22:46:57 +0100 Subject: [PATCH 17/17] Update packages/utils/src/perf-hooks.type.test.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/utils/src/perf-hooks.type.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/utils/src/perf-hooks.type.test.ts b/packages/utils/src/perf-hooks.type.test.ts index e461c4488..50b5cd9c7 100644 --- a/packages/utils/src/perf-hooks.type.test.ts +++ b/packages/utils/src/perf-hooks.type.test.ts @@ -210,7 +210,6 @@ observerRecords.forEach(e => { // API: performance.clearMarks should be type safe // Valid examples performance.clearMarks(); -// Invalid examples performance.clearMarks('name'); // API: performance.clearMeasures should be type safe