@flighthq/debug 0.5.1-next.3302.76ece6b → 0.5.1-next.4304.322dc96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/debug`. The `@flight
13
13
  This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
14
14
 
15
15
  - [Flight project](https://github.com/flighthq/flight)
16
- - [Source for @flighthq/debug@0.5.1-next.3302.76ece6b](https://github.com/flighthq/flight/tree/76ece6bee38e3d07816f341b7f017bfcec3e8e29/packages/debug)
17
- - [License](https://github.com/flighthq/flight/blob/76ece6bee38e3d07816f341b7f017bfcec3e8e29/LICENSE.md)
16
+ - [Source for @flighthq/debug@0.5.1-next.4304.322dc96](https://github.com/flighthq/flight/tree/322dc963fc5a404a31bc0cc612e906de504ea024/packages/debug)
17
+ - [License](https://github.com/flighthq/flight/blob/322dc963fc5a404a31bc0cc612e906de504ea024/LICENSE.md)
package/dist/debug.d.ts CHANGED
@@ -1,8 +1,22 @@
1
- import type { DebugOptions, DebugSubsystemHooks, DebugSubsystemName, RenderState } from '@flighthq/types/contract';
2
- export declare function disableDebug(): void;
3
- export declare function enableDebug(options?: Readonly<DebugOptions>): void;
4
- export declare function enableFlightDiagnostics(state: RenderState): void;
5
- export declare function isDebugEnabled(): boolean;
6
- export declare function registerDebugSubsystem(name: DebugSubsystemName, hooks: Readonly<DebugSubsystemHooks>): void;
7
- export declare function unregisterDebugSubsystem(name: DebugSubsystemName): boolean;
1
+ import type { EntityConstruction } from '@flighthq/entity/contract';
2
+ import type { LogState } from '@flighthq/log/contract';
3
+ import type { DebugOptions, DebugSubsystemHooks, DebugSubsystemName, Entity, LogSink, RenderState } from '@flighthq/types/contract';
4
+ import { LogLevel } from '@flighthq/types/contract';
5
+ export interface DebugState extends Entity {
6
+ enabled: boolean;
7
+ enabledSubsystems: Readonly<DebugSubsystemHooks>[];
8
+ frameNumber: number;
9
+ installedSink: LogSink | null;
10
+ savedChannelLevels: Map<string, LogLevel | null>;
11
+ savedGlobalLevel: LogLevel;
12
+ subsystems: Map<string, Readonly<DebugSubsystemHooks>>;
13
+ }
14
+ export declare function createDebugState(): DebugState;
15
+ export declare function disableDebug(state: DebugState, logState: LogState): void;
16
+ export declare function enableDebug(state: DebugState, logState: LogState, options?: Readonly<DebugOptions>): void;
17
+ export declare function enableFlightDiagnostics(debugState: DebugState, logState: LogState, state: RenderState): void;
18
+ export declare function initializeDebugState(out: EntityConstruction<DebugState>): void;
19
+ export declare function isDebugEnabled(state: Readonly<DebugState>): boolean;
20
+ export declare function registerDebugSubsystem(state: DebugState, name: DebugSubsystemName, hooks: Readonly<DebugSubsystemHooks>): void;
21
+ export declare function unregisterDebugSubsystem(state: DebugState, name: DebugSubsystemName): boolean;
8
22
  //# sourceMappingURL=debug.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAElB,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAOlC,wBAAgB,YAAY,IAAI,IAAI,CAOnC;AASD,wBAAgB,WAAW,CAAC,OAAO,GAAE,QAAQ,CAAC,YAAY,CAAM,GAAG,IAAI,CA8CtE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAIhE;AAGD,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAOD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAE3G;AAID,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAE1E"}
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAYvD,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,MAAM,EACN,OAAO,EACP,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIpD,MAAM,WAAW,UAAW,SAAQ,MAAM;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC;IACjD,gBAAgB,EAAE,QAAQ,CAAC;IAC3B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;CACxD;AAGD,wBAAgB,gBAAgB,IAAI,UAAU,CAI7C;AAMD,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAOxE;AASD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,QAAQ,CAAC,YAAY,CAAM,GAAG,IAAI,CA8C7G;AAID,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAI5G;AAID,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,CAAC,UAAU,CAAC,GAAG,IAAI,CAQ9E;AAGD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,CAEnE;AAOD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,kBAAkB,EACxB,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,GACnC,IAAI,CAEN;AAID,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAE7F"}
package/dist/debug.js CHANGED
@@ -1,55 +1,62 @@
1
+ import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
1
2
  import { addLogSink, clearLogChannelLevel, createConsoleLogSink, getLogChannelLevel, getLogLevel, removeLogSink, setLogChannelLevel, setLogLevel, } from '@flighthq/log/contract';
2
3
  import { enableColorAdjustmentGuards, enableRenderRegistriesGuards } from '@flighthq/render/contract';
3
4
  import { LogLevel } from '@flighthq/types/contract';
5
+ // Creates an empty debug state: no registered subsystems and no active session.
6
+ export function createDebugState() {
7
+ const out = allocateEntity();
8
+ initializeDebugState(out);
9
+ return finishEntity(out);
10
+ }
4
11
  // The one call that returns Flight to the zero-debug baseline: removes the sink enableDebug
5
12
  // installed, restores the log levels it raised, and runs the disable-guards binding of every
6
13
  // subsystem it switched on. No-op when debug is not enabled (idempotent, sentinel — not a throw).
7
14
  // After this, importing @flighthq/debug costs nothing and no debug output is produced.
8
- export function disableDebug() {
9
- if (!_enabled)
15
+ export function disableDebug(state, logState) {
16
+ if (!state.enabled)
10
17
  return;
11
- for (const hooks of _enabledSubsystems)
18
+ for (const hooks of state.enabledSubsystems)
12
19
  hooks.disableGuards?.();
13
- _enabledSubsystems.length = 0;
14
- _removeDebugSink();
15
- _restoreDebugLevels();
16
- _enabled = false;
20
+ state.enabledSubsystems.length = 0;
21
+ _removeDebugSink(state, logState);
22
+ _restoreDebugLevels(state, logState);
23
+ state.enabled = false;
17
24
  }
18
- // The friendly entry point to Flight's diagnostics. Installs a dev console LogSink (a text-formatted
19
- // one by default; override with `options.sink`), raises the global log level (default
25
+ // The friendly entry point to Flight's diagnostics. Installs a dev console LogSink on `logState` (a
26
+ // text-formatted one by default; override with `options.sink`), raises the global log level (default
20
27
  // LogLevel.Debug) and the per-channel levels of the selected subsystems plus any explicit
21
28
  // `options.channels`, and runs each selected subsystem's registered guard-enabler. `options.subsystems`
22
29
  // selects which registered subsystems to switch on; omit it to switch on every registered subsystem.
23
30
  // Idempotent: a second call while already enabled is a no-op (disableDebug first to re-enable with
24
31
  // different options).
25
- export function enableDebug(options = {}) {
26
- if (_enabled)
32
+ export function enableDebug(state, logState, options = {}) {
33
+ if (state.enabled)
27
34
  return;
28
35
  const level = options.level ?? LogLevel.Debug;
29
- const subsystems = _resolveDebugSubsystems(options.subsystems);
36
+ const subsystems = _resolveDebugSubsystems(state, options.subsystems);
30
37
  const channels = _collectDebugChannels(subsystems, options.channels);
31
- _savedGlobalLevel = getLogLevel();
32
- const savedChannelLevels = new Map(channels.map((channel) => [channel, getLogChannelLevel(channel)]));
38
+ state.savedGlobalLevel = getLogLevel(logState);
39
+ const savedChannelLevels = new Map(channels.map((channel) => [channel, getLogChannelLevel(logState, channel)]));
33
40
  try {
34
- _applyDebugLevels(level, channels);
35
- _installDebugSink(options.sink ?? createConsoleLogSink());
41
+ _applyDebugLevels(logState, level, channels);
42
+ _installDebugSink(state, logState, options.sink ?? createConsoleLogSink(logState));
36
43
  for (const hooks of subsystems) {
37
- _enabledSubsystems.push(hooks);
44
+ state.enabledSubsystems.push(hooks);
38
45
  hooks.enableGuards?.();
39
46
  }
40
47
  }
41
48
  catch (error) {
42
- for (let index = _enabledSubsystems.length - 1; index >= 0; index--) {
49
+ for (let index = state.enabledSubsystems.length - 1; index >= 0; index--) {
43
50
  try {
44
- _enabledSubsystems[index].disableGuards?.();
51
+ state.enabledSubsystems[index].disableGuards?.();
45
52
  }
46
53
  catch {
47
54
  // Keep unwinding; the original enable error owns this failed transaction.
48
55
  }
49
56
  }
50
- _enabledSubsystems.length = 0;
57
+ state.enabledSubsystems.length = 0;
51
58
  try {
52
- _removeDebugSink();
59
+ _removeDebugSink(state, logState);
53
60
  }
54
61
  catch {
55
62
  // Keep restoring levels; the original enable error must not be masked.
@@ -57,58 +64,65 @@ export function enableDebug(options = {}) {
57
64
  for (const [channel, savedLevel] of savedChannelLevels) {
58
65
  try {
59
66
  if (savedLevel === null)
60
- clearLogChannelLevel(channel);
67
+ clearLogChannelLevel(logState, channel);
61
68
  else
62
- setLogChannelLevel(channel, savedLevel);
69
+ setLogChannelLevel(logState, channel, savedLevel);
63
70
  }
64
71
  catch {
65
72
  // Keep restoring the remaining levels; the original enable error must survive.
66
73
  }
67
74
  }
68
75
  try {
69
- setLogLevel(_savedGlobalLevel);
76
+ setLogLevel(logState, state.savedGlobalLevel);
70
77
  }
71
78
  catch {
72
79
  // The original enable error remains the public failure even if rollback also fails.
73
80
  }
74
81
  throw error;
75
82
  }
76
- _savedChannelLevels = savedChannelLevels;
77
- _enabled = true;
83
+ state.savedChannelLevels = savedChannelLevels;
84
+ state.enabled = true;
85
+ }
86
+ // Enables a debug session with the default options, then the generic render guards for one render
87
+ // state, reporting through the same caller-owned log state.
88
+ export function enableFlightDiagnostics(debugState, logState, state) {
89
+ enableDebug(debugState, logState);
90
+ enableColorAdjustmentGuards(state, logState);
91
+ enableRenderRegistriesGuards(state, logState);
78
92
  }
79
- export function enableFlightDiagnostics(state) {
80
- enableDebug();
81
- enableColorAdjustmentGuards(state);
82
- enableRenderRegistriesGuards(state);
93
+ // Resets a debug state to no registered subsystems and no active session (the construction
94
+ // initializer of createDebugState).
95
+ export function initializeDebugState(out) {
96
+ out.enabled = false;
97
+ out.enabledSubsystems = [];
98
+ out.frameNumber = 0;
99
+ out.installedSink = null;
100
+ out.savedChannelLevels = new Map();
101
+ out.savedGlobalLevel = LogLevel.Verbose;
102
+ out.subsystems = new Map();
83
103
  }
84
104
  // Whether enableDebug is currently in effect (a sink is installed and levels/guards are raised).
85
- export function isDebugEnabled() {
86
- return _enabled;
105
+ export function isDebugEnabled(state) {
106
+ return state.enabled;
87
107
  }
88
108
  // Registers a diagnostic subsystem's wiring — the log channels whose verbosity enableDebug should
89
109
  // raise and the guard-enabler/-disabler bindings it should run for `name`. A package's thin debug
90
110
  // adapter (or the app) calls this so enableDebug(['render']) can drive the subsystem without
91
111
  // @flighthq/debug importing it. Last-write-wins; vendor-prefix custom subsystem names ('acme.Foo')
92
112
  // to avoid colliding with built-ins.
93
- export function registerDebugSubsystem(name, hooks) {
94
- _subsystems.set(name, hooks);
113
+ export function registerDebugSubsystem(state, name, hooks) {
114
+ state.subsystems.set(name, hooks);
95
115
  }
96
116
  // Removes a subsystem registration. Returns false when nothing was registered under `name`
97
117
  // (sentinel, not a throw). Does not affect an already-active debug session.
98
- export function unregisterDebugSubsystem(name) {
99
- return _subsystems.delete(name);
118
+ export function unregisterDebugSubsystem(state, name) {
119
+ return state.subsystems.delete(name);
100
120
  }
101
- const _subsystems = new Map();
102
- const _enabledSubsystems = [];
103
- let _enabled = false;
104
- let _installedSink = null;
105
- let _savedGlobalLevel = LogLevel.Verbose;
106
- let _savedChannelLevels = new Map();
107
121
  // Raises the global level and every selected channel's level to `level` for the session.
108
- function _applyDebugLevels(level, channels) {
109
- setLogLevel(level);
122
+ function _applyDebugLevels(logState, level, channels) {
123
+ setLogLevel(logState, level);
110
124
  for (const channel of channels)
111
- setLogChannelLevel(channel, level);
125
+ setLogChannelLevel(logState, channel, level);
112
126
  }
113
127
  // Gathers the channels to raise: every selected subsystem's channels plus any explicit extras.
114
128
  function _collectDebugChannels(subsystems, extra) {
@@ -122,25 +136,25 @@ function _collectDebugChannels(subsystems, extra) {
122
136
  return channels;
123
137
  }
124
138
  // Installs the debug sink and records it so disableDebug can remove exactly this one.
125
- function _installDebugSink(sink) {
126
- _installedSink = sink;
127
- addLogSink(sink);
139
+ function _installDebugSink(state, logState, sink) {
140
+ state.installedSink = sink;
141
+ addLogSink(logState, sink);
128
142
  }
129
143
  // Removes the installed debug sink, if any.
130
- function _removeDebugSink() {
131
- if (_installedSink === null)
144
+ function _removeDebugSink(state, logState) {
145
+ if (state.installedSink === null)
132
146
  return;
133
- removeLogSink(_installedSink);
134
- _installedSink = null;
147
+ removeLogSink(logState, state.installedSink);
148
+ state.installedSink = null;
135
149
  }
136
150
  // Resolves the subsystem hooks to drive: the named ones when `names` is given (unregistered names
137
151
  // are skipped), otherwise every registered subsystem.
138
- function _resolveDebugSubsystems(names) {
152
+ function _resolveDebugSubsystems(state, names) {
139
153
  if (names === undefined)
140
- return [..._subsystems.values()];
154
+ return [...state.subsystems.values()];
141
155
  const resolved = [];
142
156
  for (const name of names) {
143
- const hooks = _subsystems.get(name);
157
+ const hooks = state.subsystems.get(name);
144
158
  if (hooks !== undefined)
145
159
  resolved.push(hooks);
146
160
  }
@@ -148,14 +162,14 @@ function _resolveDebugSubsystems(names) {
148
162
  }
149
163
  // Restores the global level and per-channel overrides enableDebug saved. Only the channels debug
150
164
  // raised are touched; channel overrides the caller set before the session are preserved.
151
- function _restoreDebugLevels() {
152
- setLogLevel(_savedGlobalLevel);
153
- for (const [channel, savedLevel] of _savedChannelLevels) {
165
+ function _restoreDebugLevels(state, logState) {
166
+ setLogLevel(logState, state.savedGlobalLevel);
167
+ for (const [channel, savedLevel] of state.savedChannelLevels) {
154
168
  if (savedLevel === null)
155
- clearLogChannelLevel(channel);
169
+ clearLogChannelLevel(logState, channel);
156
170
  else
157
- setLogChannelLevel(channel, savedLevel);
171
+ setLogChannelLevel(logState, channel, savedLevel);
158
172
  }
159
- _savedChannelLevels = new Map();
173
+ state.savedChannelLevels = new Map();
160
174
  }
161
175
  //# sourceMappingURL=debug.js.map
package/dist/debug.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
+ import type { LogState } from '@flighthq/log/contract';
1
2
  import type { LogTimer } from '@flighthq/types/contract';
2
- export declare function beginDebugSpan(name: string, channel?: string | null): LogTimer | null;
3
- export declare function endDebugSpan(timer: Readonly<LogTimer> | null): number;
4
- export declare function markDebugFrame(label?: string, channel?: string | null): void;
5
- export declare function measureDebugSpan<T>(name: string, fn: () => T, channel?: string | null): T;
3
+ import type { DebugState } from './debug.ts';
4
+ export declare function beginDebugSpan(state: Readonly<DebugState>, nowMs: number, name: string, channel?: string | null): LogTimer | null;
5
+ export declare function endDebugSpan(logState: LogState, nowMs: number, timer: Readonly<LogTimer> | null): number;
6
+ export declare function markDebugFrame(state: DebugState, logState: LogState, nowMs: number, label?: string, channel?: string | null): void;
7
+ export declare function measureDebugSpan<T>(state: Readonly<DebugState>, logState: LogState, clock: () => number, name: string, fn: () => T, channel?: string | null): T;
6
8
  //# sourceMappingURL=debugTiming.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"debugTiming.d.ts","sourceRoot":"","sources":["../src/debugTiming.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AASzD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,GAAG,IAAW,GAAG,QAAQ,GAAG,IAAI,CAE3F;AAKD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,MAAM,CAErE;AAMD,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,GAAG,IAAW,GAAG,IAAI,CAGlF;AAMD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAE,MAAM,GAAG,IAAW,GAAG,CAAC,CAO/F"}
1
+ {"version":3,"file":"debugTiming.d.ts","sourceRoot":"","sources":["../src/debugTiming.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,wBAAgB,cAAc,CAC5B,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAM,GAAG,IAAW,GAC5B,QAAQ,GAAG,IAAI,CAEjB;AAKD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI,GAAG,MAAM,CAExG;AAOD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,GAAE,MAAM,GAAG,IAAW,GAC5B,IAAI,CAGN;AAMD,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,CAAC,EACX,OAAO,GAAE,MAAM,GAAG,IAAW,GAC5B,CAAC,CAOH"}
@@ -1,42 +1,41 @@
1
1
  import { endLogTimer, logDebug, startLogTimer } from '@flighthq/log/contract';
2
2
  import { isDebugEnabled } from "./debug.js";
3
- // Opens a named timing span, but only while a debug session is active: returns a LogTimer to hand to
4
- // endDebugSpan, or null when debug is disabled (production, or before enableDebug). Gating here is the
5
- // point — with debug off, opening a span is one boolean check and allocates nothing, so span
6
- // instrumentation left in shipping code costs effectively nothing. Pair every non-null result with
7
- // endDebugSpan (measureDebugSpan brackets both for a single synchronous call).
8
- export function beginDebugSpan(name, channel = null) {
9
- return isDebugEnabled() ? startLogTimer(name, channel) : null;
3
+ // Opens a named timing span at the caller's clock reading `nowMs`, but only while a debug session is
4
+ // active: returns a LogTimer to hand to endDebugSpan, or null when debug is disabled (production, or
5
+ // before enableDebug). Gating here is the point — with debug off, opening a span is one boolean check
6
+ // and allocates nothing, so span instrumentation left in shipping code costs effectively nothing. Pair
7
+ // every non-null result with endDebugSpan (measureDebugSpan brackets both for a single synchronous call).
8
+ export function beginDebugSpan(state, nowMs, name, channel = null) {
9
+ return isDebugEnabled(state) ? startLogTimer(name, channel, nowMs) : null;
10
10
  }
11
- // Closes a span opened by beginDebugSpan, emitting its elapsed-time Debug entry through the active
12
- // debug sink and returning the elapsed milliseconds. A null timer — debug was disabled when the span
13
- // opened — is a no-op returning -1, the sentinel for "not measured".
14
- export function endDebugSpan(timer) {
15
- return timer === null ? -1 : endLogTimer(timer);
11
+ // Closes a span opened by beginDebugSpan, emitting its elapsed-time Debug entry through `logState` and
12
+ // returning the elapsed milliseconds. A null timer — debug was disabled when the span opened — is a
13
+ // no-op returning -1, the sentinel for "not measured".
14
+ export function endDebugSpan(logState, nowMs, timer) {
15
+ return timer === null ? -1 : endLogTimer(logState, nowMs, timer);
16
16
  }
17
17
  // Emits a frame-boundary marker while a debug session is active, so the per-frame span entries between
18
18
  // two markers can be read against the frame they fell in. `label` names the frame; omit it to tag the
19
- // marker with a process-monotonic frame counter. No-op (and no counter advance) when debug is disabled,
20
- // so a per-frame call in the app loop costs a single boolean check in production.
21
- export function markDebugFrame(label, channel = null) {
22
- if (!isDebugEnabled())
19
+ // marker with the state's ascending frame counter, which a new session does not reset. No-op (and no
20
+ // counter advance) when debug is disabled, so a per-frame call in the app loop costs a single boolean
21
+ // check in production.
22
+ export function markDebugFrame(state, logState, nowMs, label, channel = null) {
23
+ if (!isDebugEnabled(state))
23
24
  return;
24
- logDebug({ frame: label ?? ++_debugFrameNumber }, channel);
25
+ logDebug(logState, nowMs, { frame: label ?? ++state.frameNumber }, channel);
25
26
  }
26
27
  // Brackets a synchronous function as a timing span: times `fn` while a debug session is active,
27
28
  // emitting one elapsed-time entry, and returns `fn`'s result. When debug is disabled `fn` still runs —
28
29
  // only the timing is skipped — so wrapping a call never changes behavior, only observability. The span
29
- // is closed even if `fn` throws.
30
- export function measureDebugSpan(name, fn, channel = null) {
31
- const timer = beginDebugSpan(name, channel);
30
+ // is closed even if `fn` throws. `clock` is read once when the span opens and once when it closes.
31
+ export function measureDebugSpan(state, logState, clock, name, fn, channel = null) {
32
+ const timer = beginDebugSpan(state, clock(), name, channel);
32
33
  try {
33
34
  return fn();
34
35
  }
35
36
  finally {
36
- endDebugSpan(timer);
37
+ if (timer !== null)
38
+ endDebugSpan(logState, clock(), timer);
37
39
  }
38
40
  }
39
- // Monotonic id handed to unlabeled frame markers. Not reset between sessions — a marker's job is to
40
- // correlate span entries with a frame boundary, for which a unique ascending id suffices.
41
- let _debugFrameNumber = 0;
42
41
  //# sourceMappingURL=debugTiming.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"debugTiming.js","sourceRoot":"","sources":["../src/debugTiming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG9E,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,qGAAqG;AACrG,uGAAuG;AACvG,6FAA6F;AAC7F,mGAAmG;AACnG,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,UAAyB,IAAI;IACxE,OAAO,cAAc,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC;AAED,mGAAmG;AACnG,qGAAqG;AACrG,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,KAAgC;IAC3D,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED,uGAAuG;AACvG,sGAAsG;AACtG,wGAAwG;AACxG,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,UAAyB,IAAI;IAC1E,IAAI,CAAC,cAAc,EAAE;QAAE,OAAO;IAC9B,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,iBAAiB,EAAE,EAAE,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,gGAAgG;AAChG,uGAAuG;AACvG,uGAAuG;AACvG,iCAAiC;AACjC,MAAM,UAAU,gBAAgB,CAAI,IAAY,EAAE,EAAW,EAAE,UAAyB,IAAI;IAC1F,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,oGAAoG;AACpG,0FAA0F;AAC1F,IAAI,iBAAiB,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"debugTiming.js","sourceRoot":"","sources":["../src/debugTiming.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAI9E,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,qGAAqG;AACrG,qGAAqG;AACrG,sGAAsG;AACtG,uGAAuG;AACvG,0GAA0G;AAC1G,MAAM,UAAU,cAAc,CAC5B,KAA2B,EAC3B,KAAa,EACb,IAAY,EACZ,UAAyB,IAAI;IAE7B,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5E,CAAC;AAED,uGAAuG;AACvG,oGAAoG;AACpG,uDAAuD;AACvD,MAAM,UAAU,YAAY,CAAC,QAAkB,EAAE,KAAa,EAAE,KAAgC;IAC9F,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,uGAAuG;AACvG,sGAAsG;AACtG,qGAAqG;AACrG,sGAAsG;AACtG,uBAAuB;AACvB,MAAM,UAAU,cAAc,CAC5B,KAAiB,EACjB,QAAkB,EAClB,KAAa,EACb,KAAc,EACd,UAAyB,IAAI;IAE7B,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO;IACnC,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED,gGAAgG;AAChG,uGAAuG;AACvG,uGAAuG;AACvG,mGAAmG;AACnG,MAAM,UAAU,gBAAgB,CAC9B,KAA2B,EAC3B,QAAkB,EAClB,KAAmB,EACnB,IAAY,EACZ,EAAW,EACX,UAAyB,IAAI;IAE7B,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5D,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,KAAK,KAAK,IAAI;YAAE,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export { beginDebugSpan, disableDebug, enableDebug, enableFlightDiagnostics, endDebugSpan, isDebugEnabled, markDebugFrame, measureDebugSpan, registerDebugSubsystem, unregisterDebugSubsystem, } from './contract.ts';
1
+ export { beginDebugSpan, createDebugState, disableDebug, enableDebug, enableFlightDiagnostics, endDebugSpan, isDebugEnabled, markDebugFrame, measureDebugSpan, registerDebugSubsystem, unregisterDebugSubsystem, } from './contract.ts';
2
+ export type { DebugState } from './contract.ts';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,YAAY,EACZ,WAAW,EACX,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { beginDebugSpan, disableDebug, enableDebug, enableFlightDiagnostics, endDebugSpan, isDebugEnabled, markDebugFrame, measureDebugSpan, registerDebugSubsystem, unregisterDebugSubsystem, } from "./contract.js";
1
+ export { beginDebugSpan, createDebugState, disableDebug, enableDebug, enableFlightDiagnostics, endDebugSpan, isDebugEnabled, markDebugFrame, measureDebugSpan, registerDebugSubsystem, unregisterDebugSubsystem, } from "./contract.js";
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,YAAY,EACZ,WAAW,EACX,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,uBAAuB,EACvB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,eAAe,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/debug",
3
- "version": "0.5.1-next.3302.76ece6b",
3
+ "version": "0.5.1-next.4304.322dc96",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,9 +38,10 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/log": "0.5.1-next.3302.76ece6b",
42
- "@flighthq/render": "0.5.1-next.3302.76ece6b",
43
- "@flighthq/types": "0.5.1-next.3302.76ece6b"
41
+ "@flighthq/entity": "0.5.1-next.4304.322dc96",
42
+ "@flighthq/log": "0.5.1-next.4304.322dc96",
43
+ "@flighthq/render": "0.5.1-next.4304.322dc96",
44
+ "@flighthq/types": "0.5.1-next.4304.322dc96"
44
45
  },
45
46
  "devDependencies": {
46
47
  "typescript": "^5.3.0"
package/src/debug.test.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import type { LogState } from '@flighthq/log/contract';
1
2
  import {
2
3
  clearLogChannelLevels,
3
4
  clearLogSinks,
5
+ createLogState,
4
6
  createMemoryLogSink,
5
7
  getLogChannelLevel,
6
8
  getLogLevel,
@@ -14,14 +16,17 @@ import {
14
16
  areRenderRegistriesGuardsEnabled,
15
17
  createRenderState,
16
18
  } from '@flighthq/render/contract';
17
- import type { MemoryLogSink } from '@flighthq/types/contract';
19
+ import type { LogEntry, MemoryLogSink } from '@flighthq/types/contract';
18
20
  import { LogLevel } from '@flighthq/types/contract';
19
21
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
20
22
 
23
+ import type { DebugState } from './debug.ts';
21
24
  import {
25
+ createDebugState,
22
26
  disableDebug,
23
27
  enableDebug,
24
28
  enableFlightDiagnostics,
29
+ initializeDebugState,
25
30
  isDebugEnabled,
26
31
  registerDebugSubsystem,
27
32
  unregisterDebugSubsystem,
@@ -32,132 +37,170 @@ import {
32
37
  const testSubsystemNames = ['render', 'input', 'audio', 'acme.custom'];
33
38
 
34
39
  function readMemory(sink: MemoryLogSink): readonly unknown[] {
35
- return getMemoryLogSinkEntries(sink);
40
+ return readLogEntries(sink);
41
+ }
42
+
43
+ // Monotonic test clock: each read advances one millisecond, so spans measure a positive duration.
44
+ function clock(): number {
45
+ return ++clockMs;
46
+ }
47
+
48
+ function readLogEntries(sink: Readonly<MemoryLogSink>): LogEntry[] {
49
+ const entries: LogEntry[] = [];
50
+ getMemoryLogSinkEntries(entries, sink);
51
+ return entries;
36
52
  }
37
53
 
38
54
  beforeEach(() => {
39
- if (isDebugEnabled()) disableDebug();
40
- for (const name of testSubsystemNames) unregisterDebugSubsystem(name);
41
- clearLogSinks();
42
- clearLogChannelLevels();
43
- setLogLevel(LogLevel.Verbose);
55
+ clockMs = 0;
56
+ debugState = createDebugState();
57
+ logState = createLogState();
58
+ if (isDebugEnabled(debugState)) disableDebug(debugState, logState);
59
+ for (const name of testSubsystemNames) unregisterDebugSubsystem(debugState, name);
60
+ clearLogSinks(logState);
61
+ clearLogChannelLevels(logState);
62
+ setLogLevel(logState, LogLevel.Verbose);
44
63
  });
45
64
 
46
65
  afterEach(() => {
47
- if (isDebugEnabled()) disableDebug();
48
- for (const name of testSubsystemNames) unregisterDebugSubsystem(name);
49
- clearLogSinks();
50
- clearLogChannelLevels();
51
- setLogLevel(LogLevel.Verbose);
66
+ if (isDebugEnabled(debugState)) disableDebug(debugState, logState);
67
+ for (const name of testSubsystemNames) unregisterDebugSubsystem(debugState, name);
68
+ clearLogSinks(logState);
69
+ clearLogChannelLevels(logState);
70
+ setLogLevel(logState, LogLevel.Verbose);
71
+ });
72
+
73
+ describe('createDebugState', () => {
74
+ it('starts disabled with no frame, sink, saved levels, or subsystems', () => {
75
+ const state = createDebugState();
76
+ expect(state.enabled).toBe(false);
77
+ expect(state.enabledSubsystems).toEqual([]);
78
+ expect(state.frameNumber).toBe(0);
79
+ expect(state.installedSink).toBeNull();
80
+ expect(state.savedChannelLevels.size).toBe(0);
81
+ expect(state.subsystems.size).toBe(0);
82
+ });
83
+
84
+ it('returns independent states', () => {
85
+ expect(createDebugState().subsystems).not.toBe(createDebugState().subsystems);
86
+ });
52
87
  });
53
88
 
54
89
  describe('disableDebug', () => {
55
90
  it('removes the installed sink so a later log does not reach it', () => {
56
91
  const memory = createMemoryLogSink(16);
57
- registerDebugSubsystem('render', { channels: ['render'] });
58
- enableDebug({ subsystems: ['render'], sink: memory.sink });
92
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'] });
93
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: memory.sink });
59
94
 
60
- log(LogLevel.Debug, 'before', 'render');
95
+ log(logState, 0, LogLevel.Debug, 'before', 'render');
61
96
  expect(readMemory(memory)).toHaveLength(1);
62
97
 
63
- disableDebug();
64
- log(LogLevel.Debug, 'after', 'render');
98
+ disableDebug(debugState, logState);
99
+ log(logState, 0, LogLevel.Debug, 'after', 'render');
65
100
  expect(readMemory(memory)).toHaveLength(1);
66
101
  });
67
102
 
68
103
  it('runs each enabled subsystem disableGuards binding', () => {
69
104
  const disableGuards = vi.fn();
70
- registerDebugSubsystem('render', { disableGuards });
71
- enableDebug({ subsystems: ['render'], sink: createMemoryLogSink(1).sink });
105
+ registerDebugSubsystem(debugState, 'render', { disableGuards });
106
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: createMemoryLogSink(1).sink });
72
107
 
73
108
  expect(disableGuards).not.toHaveBeenCalled();
74
- disableDebug();
109
+ disableDebug(debugState, logState);
75
110
  expect(disableGuards).toHaveBeenCalledTimes(1);
76
111
  });
77
112
 
78
113
  it('restores the global level and clears the channel overrides it raised', () => {
79
- setLogLevel(LogLevel.Warn);
80
- registerDebugSubsystem('render', { channels: ['render'] });
81
- enableDebug({ subsystems: ['render'], level: LogLevel.Verbose, sink: createMemoryLogSink(1).sink });
114
+ setLogLevel(logState, LogLevel.Warn);
115
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'] });
116
+ enableDebug(debugState, logState, {
117
+ subsystems: ['render'],
118
+ level: LogLevel.Verbose,
119
+ sink: createMemoryLogSink(1).sink,
120
+ });
82
121
 
83
- disableDebug();
84
- expect(getLogLevel()).toBe(LogLevel.Warn);
85
- expect(getLogChannelLevel('render')).toBeNull();
122
+ disableDebug(debugState, logState);
123
+ expect(getLogLevel(logState)).toBe(LogLevel.Warn);
124
+ expect(getLogChannelLevel(logState, 'render')).toBeNull();
86
125
  });
87
126
 
88
127
  it('preserves channel overrides the caller set before the session', () => {
89
- setLogChannelLevel('unrelated', LogLevel.Error);
90
- registerDebugSubsystem('render', { channels: ['render'] });
91
- enableDebug({ subsystems: ['render'], sink: createMemoryLogSink(1).sink });
128
+ setLogChannelLevel(logState, 'unrelated', LogLevel.Error);
129
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'] });
130
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: createMemoryLogSink(1).sink });
92
131
 
93
- expect(getLogChannelLevel('render')).toBe(LogLevel.Debug);
132
+ expect(getLogChannelLevel(logState, 'render')).toBe(LogLevel.Debug);
94
133
 
95
- disableDebug();
96
- expect(getLogChannelLevel('render')).toBeNull();
97
- expect(getLogChannelLevel('unrelated')).toBe(LogLevel.Error);
134
+ disableDebug(debugState, logState);
135
+ expect(getLogChannelLevel(logState, 'render')).toBeNull();
136
+ expect(getLogChannelLevel(logState, 'unrelated')).toBe(LogLevel.Error);
98
137
  });
99
138
 
100
139
  it('restores a pre-existing override on a channel debug also raised', () => {
101
- setLogChannelLevel('render', LogLevel.Warn);
102
- registerDebugSubsystem('render', { channels: ['render'] });
103
- enableDebug({ subsystems: ['render'], level: LogLevel.Verbose, sink: createMemoryLogSink(1).sink });
140
+ setLogChannelLevel(logState, 'render', LogLevel.Warn);
141
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'] });
142
+ enableDebug(debugState, logState, {
143
+ subsystems: ['render'],
144
+ level: LogLevel.Verbose,
145
+ sink: createMemoryLogSink(1).sink,
146
+ });
104
147
 
105
- expect(getLogChannelLevel('render')).toBe(LogLevel.Verbose);
148
+ expect(getLogChannelLevel(logState, 'render')).toBe(LogLevel.Verbose);
106
149
 
107
- disableDebug();
108
- expect(getLogChannelLevel('render')).toBe(LogLevel.Warn);
150
+ disableDebug(debugState, logState);
151
+ expect(getLogChannelLevel(logState, 'render')).toBe(LogLevel.Warn);
109
152
  });
110
153
 
111
154
  it('is a no-op when debug is not enabled', () => {
112
- expect(isDebugEnabled()).toBe(false);
113
- expect(() => disableDebug()).not.toThrow();
114
- expect(isDebugEnabled()).toBe(false);
155
+ expect(isDebugEnabled(debugState)).toBe(false);
156
+ expect(() => disableDebug(debugState, logState)).not.toThrow();
157
+ expect(isDebugEnabled(debugState)).toBe(false);
115
158
  });
116
159
  });
117
160
 
118
161
  describe('enableDebug', () => {
119
162
  it('runs a selected subsystem enableGuards and raises its channel levels', () => {
120
163
  const enableGuards = vi.fn();
121
- registerDebugSubsystem('render', { channels: ['render', 'render.batch'], enableGuards });
164
+ registerDebugSubsystem(debugState, 'render', { channels: ['render', 'render.batch'], enableGuards });
122
165
 
123
- enableDebug({ subsystems: ['render'], sink: createMemoryLogSink(1).sink });
166
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: createMemoryLogSink(1).sink });
124
167
 
125
168
  expect(enableGuards).toHaveBeenCalledTimes(1);
126
- expect(getLogChannelLevel('render')).toBe(LogLevel.Debug);
127
- expect(getLogChannelLevel('render.batch')).toBe(LogLevel.Debug);
128
- expect(isDebugEnabled()).toBe(true);
169
+ expect(getLogChannelLevel(logState, 'render')).toBe(LogLevel.Debug);
170
+ expect(getLogChannelLevel(logState, 'render.batch')).toBe(LogLevel.Debug);
171
+ expect(isDebugEnabled(debugState)).toBe(true);
129
172
  });
130
173
 
131
174
  it('routes a log on a raised channel to the installed sink', () => {
132
175
  const memory = createMemoryLogSink(16);
133
- registerDebugSubsystem('render', { channels: ['render'] });
134
- enableDebug({ subsystems: ['render'], sink: memory.sink });
176
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'] });
177
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: memory.sink });
135
178
 
136
- log(LogLevel.Debug, { msg: 'draw' }, 'render');
179
+ log(logState, 0, LogLevel.Debug, { msg: 'draw' }, 'render');
137
180
  expect(readMemory(memory)).toHaveLength(1);
138
181
  });
139
182
 
140
183
  it('honors an explicit level and extra channels', () => {
141
- registerDebugSubsystem('render', { channels: ['render'] });
142
- enableDebug({
184
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'] });
185
+ enableDebug(debugState, logState, {
143
186
  subsystems: ['render'],
144
187
  level: LogLevel.Verbose,
145
188
  channels: ['app'],
146
189
  sink: createMemoryLogSink(1).sink,
147
190
  });
148
191
 
149
- expect(getLogLevel()).toBe(LogLevel.Verbose);
150
- expect(getLogChannelLevel('render')).toBe(LogLevel.Verbose);
151
- expect(getLogChannelLevel('app')).toBe(LogLevel.Verbose);
192
+ expect(getLogLevel(logState)).toBe(LogLevel.Verbose);
193
+ expect(getLogChannelLevel(logState, 'render')).toBe(LogLevel.Verbose);
194
+ expect(getLogChannelLevel(logState, 'app')).toBe(LogLevel.Verbose);
152
195
  });
153
196
 
154
197
  it('enables every registered subsystem when none are named', () => {
155
198
  const renderGuards = vi.fn();
156
199
  const inputGuards = vi.fn();
157
- registerDebugSubsystem('render', { enableGuards: renderGuards });
158
- registerDebugSubsystem('input', { enableGuards: inputGuards });
200
+ registerDebugSubsystem(debugState, 'render', { enableGuards: renderGuards });
201
+ registerDebugSubsystem(debugState, 'input', { enableGuards: inputGuards });
159
202
 
160
- enableDebug({ sink: createMemoryLogSink(1).sink });
203
+ enableDebug(debugState, logState, { sink: createMemoryLogSink(1).sink });
161
204
 
162
205
  expect(renderGuards).toHaveBeenCalledTimes(1);
163
206
  expect(inputGuards).toHaveBeenCalledTimes(1);
@@ -165,20 +208,20 @@ describe('enableDebug', () => {
165
208
 
166
209
  it('skips an unregistered subsystem name without throwing', () => {
167
210
  const memory = createMemoryLogSink(1);
168
- expect(() => enableDebug({ subsystems: ['audio'], sink: memory.sink })).not.toThrow();
169
- expect(isDebugEnabled()).toBe(true);
211
+ expect(() => enableDebug(debugState, logState, { subsystems: ['audio'], sink: memory.sink })).not.toThrow();
212
+ expect(isDebugEnabled(debugState)).toBe(true);
170
213
  });
171
214
 
172
215
  it('is idempotent — a second enable while active does not re-run guards or re-install', () => {
173
216
  const enableGuards = vi.fn();
174
217
  const memory = createMemoryLogSink(16);
175
- registerDebugSubsystem('render', { channels: ['render'], enableGuards });
218
+ registerDebugSubsystem(debugState, 'render', { channels: ['render'], enableGuards });
176
219
 
177
- enableDebug({ subsystems: ['render'], sink: memory.sink });
178
- enableDebug({ subsystems: ['render'], sink: memory.sink });
220
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: memory.sink });
221
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: memory.sink });
179
222
 
180
223
  expect(enableGuards).toHaveBeenCalledTimes(1);
181
- log(LogLevel.Debug, 'once', 'render');
224
+ log(logState, 0, LogLevel.Debug, 'once', 'render');
182
225
  expect(readMemory(memory)).toHaveLength(1);
183
226
  });
184
227
 
@@ -200,31 +243,31 @@ describe('enableDebug', () => {
200
243
  if (failEnable) throw originalError;
201
244
  },
202
245
  });
203
- registerDebugSubsystem('render', hooks('render'));
204
- registerDebugSubsystem('input', hooks('input', false, true));
205
- registerDebugSubsystem('audio', hooks('audio', true));
206
- setLogLevel(LogLevel.Warn);
207
- setLogChannelLevel('render', LogLevel.Error);
208
- setLogChannelLevel('input', LogLevel.Info);
209
- setLogChannelLevel('unrelated', LogLevel.Verbose);
246
+ registerDebugSubsystem(debugState, 'render', hooks('render'));
247
+ registerDebugSubsystem(debugState, 'input', hooks('input', false, true));
248
+ registerDebugSubsystem(debugState, 'audio', hooks('audio', true));
249
+ setLogLevel(logState, LogLevel.Warn);
250
+ setLogChannelLevel(logState, 'render', LogLevel.Error);
251
+ setLogChannelLevel(logState, 'input', LogLevel.Info);
252
+ setLogChannelLevel(logState, 'unrelated', LogLevel.Verbose);
210
253
 
211
254
  let thrown: unknown;
212
255
  try {
213
- enableDebug({ subsystems: ['render', 'input', 'audio'], sink: memory.sink });
256
+ enableDebug(debugState, logState, { subsystems: ['render', 'input', 'audio'], sink: memory.sink });
214
257
  } catch (error) {
215
258
  thrown = error;
216
259
  }
217
260
 
218
261
  expect(thrown).toBe(originalError);
219
- expect(isDebugEnabled()).toBe(false);
262
+ expect(isDebugEnabled(debugState)).toBe(false);
220
263
  expect([...activeGuards]).toEqual([]);
221
264
  expect(rollbackOrder).toEqual(['audio', 'input', 'render']);
222
- expect(getLogLevel()).toBe(LogLevel.Warn);
223
- expect(getLogChannelLevel('render')).toBe(LogLevel.Error);
224
- expect(getLogChannelLevel('input')).toBe(LogLevel.Info);
225
- expect(getLogChannelLevel('audio')).toBeNull();
226
- expect(getLogChannelLevel('unrelated')).toBe(LogLevel.Verbose);
227
- log(LogLevel.Error, 'after failed enable');
265
+ expect(getLogLevel(logState)).toBe(LogLevel.Warn);
266
+ expect(getLogChannelLevel(logState, 'render')).toBe(LogLevel.Error);
267
+ expect(getLogChannelLevel(logState, 'input')).toBe(LogLevel.Info);
268
+ expect(getLogChannelLevel(logState, 'audio')).toBeNull();
269
+ expect(getLogChannelLevel(logState, 'unrelated')).toBe(LogLevel.Verbose);
270
+ log(logState, 0, LogLevel.Error, 'after failed enable');
228
271
  expect(readMemory(memory)).toEqual([]);
229
272
  });
230
273
  });
@@ -232,41 +275,55 @@ describe('enableDebug', () => {
232
275
  describe('enableFlightDiagnostics', () => {
233
276
  it('enables the console diagnostics session and every generic render guard for the state', () => {
234
277
  const state = createRenderState();
235
- enableFlightDiagnostics(state);
236
- expect(isDebugEnabled()).toBe(true);
278
+ enableFlightDiagnostics(debugState, logState, state);
279
+ expect(isDebugEnabled(debugState)).toBe(true);
237
280
  expect(areColorAdjustmentGuardsEnabled(state)).toBe(true);
238
281
  expect(areRenderRegistriesGuardsEnabled(state)).toBe(true);
239
282
  });
240
283
  });
241
284
 
285
+ describe('initializeDebugState', () => {
286
+ it('resets a used state to the fresh baseline', () => {
287
+ const state = createDebugState();
288
+ state.enabled = true;
289
+ state.frameNumber = 12;
290
+ state.savedChannelLevels.set('render', null);
291
+ initializeDebugState(state);
292
+ expect(state.enabled).toBe(false);
293
+ expect(state.frameNumber).toBe(0);
294
+ expect(state.savedChannelLevels.size).toBe(0);
295
+ expect(state.savedGlobalLevel).toBe(LogLevel.Verbose);
296
+ });
297
+ });
298
+
242
299
  describe('isDebugEnabled', () => {
243
300
  it('reports the enable/disable lifecycle', () => {
244
- expect(isDebugEnabled()).toBe(false);
245
- enableDebug({ sink: createMemoryLogSink(1).sink });
246
- expect(isDebugEnabled()).toBe(true);
247
- disableDebug();
248
- expect(isDebugEnabled()).toBe(false);
301
+ expect(isDebugEnabled(debugState)).toBe(false);
302
+ enableDebug(debugState, logState, { sink: createMemoryLogSink(1).sink });
303
+ expect(isDebugEnabled(debugState)).toBe(true);
304
+ disableDebug(debugState, logState);
305
+ expect(isDebugEnabled(debugState)).toBe(false);
249
306
  });
250
307
  });
251
308
 
252
309
  describe('registerDebugSubsystem', () => {
253
310
  it('drives a newly registered subsystem through enableDebug', () => {
254
311
  const enableGuards = vi.fn();
255
- registerDebugSubsystem('acme.custom', { channels: ['acme.custom'], enableGuards });
312
+ registerDebugSubsystem(debugState, 'acme.custom', { channels: ['acme.custom'], enableGuards });
256
313
 
257
- enableDebug({ subsystems: ['acme.custom'], sink: createMemoryLogSink(1).sink });
314
+ enableDebug(debugState, logState, { subsystems: ['acme.custom'], sink: createMemoryLogSink(1).sink });
258
315
 
259
316
  expect(enableGuards).toHaveBeenCalledTimes(1);
260
- expect(getLogChannelLevel('acme.custom')).toBe(LogLevel.Debug);
317
+ expect(getLogChannelLevel(logState, 'acme.custom')).toBe(LogLevel.Debug);
261
318
  });
262
319
 
263
320
  it('is last-write-wins for a repeated name', () => {
264
321
  const first = vi.fn();
265
322
  const second = vi.fn();
266
- registerDebugSubsystem('render', { enableGuards: first });
267
- registerDebugSubsystem('render', { enableGuards: second });
323
+ registerDebugSubsystem(debugState, 'render', { enableGuards: first });
324
+ registerDebugSubsystem(debugState, 'render', { enableGuards: second });
268
325
 
269
- enableDebug({ subsystems: ['render'], sink: createMemoryLogSink(1).sink });
326
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: createMemoryLogSink(1).sink });
270
327
 
271
328
  expect(first).not.toHaveBeenCalled();
272
329
  expect(second).toHaveBeenCalledTimes(1);
@@ -276,14 +333,18 @@ describe('registerDebugSubsystem', () => {
276
333
  describe('unregisterDebugSubsystem', () => {
277
334
  it('returns true and stops the subsystem from being driven', () => {
278
335
  const enableGuards = vi.fn();
279
- registerDebugSubsystem('render', { enableGuards });
336
+ registerDebugSubsystem(debugState, 'render', { enableGuards });
280
337
 
281
- expect(unregisterDebugSubsystem('render')).toBe(true);
282
- enableDebug({ subsystems: ['render'], sink: createMemoryLogSink(1).sink });
338
+ expect(unregisterDebugSubsystem(debugState, 'render')).toBe(true);
339
+ enableDebug(debugState, logState, { subsystems: ['render'], sink: createMemoryLogSink(1).sink });
283
340
  expect(enableGuards).not.toHaveBeenCalled();
284
341
  });
285
342
 
286
343
  it('returns false for a name that was never registered', () => {
287
- expect(unregisterDebugSubsystem('audio')).toBe(false);
344
+ expect(unregisterDebugSubsystem(debugState, 'audio')).toBe(false);
288
345
  });
289
346
  });
347
+
348
+ let clockMs = 0;
349
+ let debugState: DebugState = createDebugState();
350
+ let logState: LogState = createLogState();
@@ -1,44 +1,61 @@
1
+ import type { LogState } from '@flighthq/log/contract';
1
2
  import {
2
3
  addLogSink,
3
4
  clearLogChannelLevels,
4
5
  clearLogSinks,
6
+ createLogState,
5
7
  createMemoryLogSink,
6
8
  getMemoryLogSinkEntries,
7
9
  setLogLevel,
8
10
  } from '@flighthq/log/contract';
9
- import type { MemoryLogSink } from '@flighthq/types/contract';
11
+ import type { LogEntry, MemoryLogSink } from '@flighthq/types/contract';
10
12
  import { LogLevel } from '@flighthq/types/contract';
11
13
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
12
14
 
13
- import { disableDebug, enableDebug, isDebugEnabled } from './debug.ts';
15
+ import type { DebugState } from './debug.ts';
16
+ import { createDebugState, disableDebug, enableDebug, isDebugEnabled } from './debug.ts';
14
17
  import { beginDebugSpan, endDebugSpan, markDebugFrame, measureDebugSpan } from './debugTiming.ts';
15
18
 
16
19
  function entryData(sink: MemoryLogSink): Readonly<Record<string, unknown>>[] {
17
- return getMemoryLogSinkEntries(sink).map((entry) => (entry as { data: Record<string, unknown> }).data);
20
+ return readLogEntries(sink).map((entry) => (entry as { data: Record<string, unknown> }).data);
21
+ }
22
+
23
+ // Monotonic test clock: each read advances one millisecond, so spans measure a positive duration.
24
+ function clock(): number {
25
+ return ++clockMs;
26
+ }
27
+
28
+ function readLogEntries(sink: Readonly<MemoryLogSink>): LogEntry[] {
29
+ const entries: LogEntry[] = [];
30
+ getMemoryLogSinkEntries(entries, sink);
31
+ return entries;
18
32
  }
19
33
 
20
34
  beforeEach(() => {
21
- if (isDebugEnabled()) disableDebug();
22
- clearLogSinks();
23
- clearLogChannelLevels();
24
- setLogLevel(LogLevel.Verbose);
35
+ clockMs = 0;
36
+ debugState = createDebugState();
37
+ logState = createLogState();
38
+ if (isDebugEnabled(debugState)) disableDebug(debugState, logState);
39
+ clearLogSinks(logState);
40
+ clearLogChannelLevels(logState);
41
+ setLogLevel(logState, LogLevel.Verbose);
25
42
  });
26
43
 
27
44
  afterEach(() => {
28
- if (isDebugEnabled()) disableDebug();
29
- clearLogSinks();
30
- clearLogChannelLevels();
31
- setLogLevel(LogLevel.Verbose);
45
+ if (isDebugEnabled(debugState)) disableDebug(debugState, logState);
46
+ clearLogSinks(logState);
47
+ clearLogChannelLevels(logState);
48
+ setLogLevel(logState, LogLevel.Verbose);
32
49
  });
33
50
 
34
51
  describe('beginDebugSpan', () => {
35
52
  it('returns null when debug is disabled', () => {
36
- expect(beginDebugSpan('draw')).toBeNull();
53
+ expect(beginDebugSpan(debugState, clock(), 'draw')).toBeNull();
37
54
  });
38
55
 
39
56
  it('returns a running timer when debug is enabled', () => {
40
- enableDebug({ sink: createMemoryLogSink(1).sink });
41
- const timer = beginDebugSpan('draw');
57
+ enableDebug(debugState, logState, { sink: createMemoryLogSink(1).sink });
58
+ const timer = beginDebugSpan(debugState, clock(), 'draw');
42
59
  expect(timer).not.toBeNull();
43
60
  expect(timer!.label).toBe('draw');
44
61
  });
@@ -46,14 +63,15 @@ describe('beginDebugSpan', () => {
46
63
 
47
64
  describe('endDebugSpan', () => {
48
65
  it('is a no-op returning -1 for a null timer', () => {
49
- expect(endDebugSpan(null)).toBe(-1);
66
+ expect(endDebugSpan(logState, clock(), null)).toBe(-1);
50
67
  });
51
68
 
52
69
  it('emits an elapsed-time entry and returns the elapsed milliseconds', () => {
53
70
  const memory = createMemoryLogSink(16);
54
- enableDebug({ sink: memory.sink });
55
- const elapsed = endDebugSpan(beginDebugSpan('draw'));
56
- expect(elapsed).toBeGreaterThanOrEqual(0);
71
+ enableDebug(debugState, logState, { sink: memory.sink });
72
+ const timer = beginDebugSpan(debugState, clock(), 'draw');
73
+ const elapsed = endDebugSpan(logState, clock(), timer);
74
+ expect(elapsed).toBe(1);
57
75
  const data = entryData(memory);
58
76
  expect(data).toHaveLength(1);
59
77
  expect(data[0].label).toBe('draw');
@@ -64,23 +82,23 @@ describe('endDebugSpan', () => {
64
82
  describe('markDebugFrame', () => {
65
83
  it('is a no-op when debug is disabled', () => {
66
84
  const memory = createMemoryLogSink(4);
67
- addLogSink(memory.sink);
68
- markDebugFrame();
69
- expect(getMemoryLogSinkEntries(memory)).toHaveLength(0);
85
+ addLogSink(logState, memory.sink);
86
+ markDebugFrame(debugState, logState, clock());
87
+ expect(readLogEntries(memory)).toHaveLength(0);
70
88
  });
71
89
 
72
90
  it('emits a labeled frame marker when debug is enabled', () => {
73
91
  const memory = createMemoryLogSink(16);
74
- enableDebug({ sink: memory.sink });
75
- markDebugFrame('level-load');
92
+ enableDebug(debugState, logState, { sink: memory.sink });
93
+ markDebugFrame(debugState, logState, clock(), 'level-load');
76
94
  expect(entryData(memory)[0].frame).toBe('level-load');
77
95
  });
78
96
 
79
97
  it('tags an unlabeled marker with an ascending counter', () => {
80
98
  const memory = createMemoryLogSink(16);
81
- enableDebug({ sink: memory.sink });
82
- markDebugFrame();
83
- markDebugFrame();
99
+ enableDebug(debugState, logState, { sink: memory.sink });
100
+ markDebugFrame(debugState, logState, clock());
101
+ markDebugFrame(debugState, logState, clock());
84
102
  const [a, b] = entryData(memory);
85
103
  expect(typeof a.frame).toBe('number');
86
104
  expect(b.frame as number).toBeGreaterThan(a.frame as number);
@@ -89,24 +107,24 @@ describe('markDebugFrame', () => {
89
107
 
90
108
  describe('measureDebugSpan', () => {
91
109
  it('returns the wrapped function result', () => {
92
- expect(measureDebugSpan('compute', () => 42)).toBe(42);
110
+ expect(measureDebugSpan(debugState, logState, clock, 'compute', () => 42)).toBe(42);
93
111
  });
94
112
 
95
113
  it('runs the function but emits nothing when debug is disabled', () => {
96
114
  const memory = createMemoryLogSink(4);
97
- addLogSink(memory.sink);
115
+ addLogSink(logState, memory.sink);
98
116
  let ran = false;
99
- measureDebugSpan('compute', () => {
117
+ measureDebugSpan(debugState, logState, clock, 'compute', () => {
100
118
  ran = true;
101
119
  });
102
120
  expect(ran).toBe(true);
103
- expect(getMemoryLogSinkEntries(memory)).toHaveLength(0);
121
+ expect(readLogEntries(memory)).toHaveLength(0);
104
122
  });
105
123
 
106
124
  it('emits one timing entry named for the span when debug is enabled', () => {
107
125
  const memory = createMemoryLogSink(16);
108
- enableDebug({ sink: memory.sink });
109
- measureDebugSpan('compute', () => 1);
126
+ enableDebug(debugState, logState, { sink: memory.sink });
127
+ measureDebugSpan(debugState, logState, clock, 'compute', () => 1);
110
128
  const data = entryData(memory);
111
129
  expect(data).toHaveLength(1);
112
130
  expect(data[0].label).toBe('compute');
@@ -114,12 +132,16 @@ describe('measureDebugSpan', () => {
114
132
 
115
133
  it('closes the span even when the function throws', () => {
116
134
  const memory = createMemoryLogSink(16);
117
- enableDebug({ sink: memory.sink });
135
+ enableDebug(debugState, logState, { sink: memory.sink });
118
136
  expect(() =>
119
- measureDebugSpan('boom', () => {
137
+ measureDebugSpan(debugState, logState, clock, 'boom', () => {
120
138
  throw new Error('nope');
121
139
  }),
122
140
  ).toThrow('nope');
123
141
  expect(entryData(memory)).toHaveLength(1);
124
142
  });
125
143
  });
144
+
145
+ let clockMs = 0;
146
+ let debugState: DebugState = createDebugState();
147
+ let logState: LogState = createLogState();