@hkdigital/lib-core 0.5.49 → 0.5.51

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.
@@ -1,3 +1,6 @@
1
+ /** @typedef {import('../../../generic/typedef.js').ErrorDetails} ErrorDetails */
2
+ /** @typedef {import('../../typedef.js').LogEvent} LogEvent */
3
+ /** @typedef {import('../../typedef.js').LogEventData} LogEventData */
1
4
  /** @typedef {import('../../typedef.js').LogLevel} LogLevel */
2
5
  /**
3
6
  * Logger class for consistent logging
@@ -63,7 +66,7 @@ export default class Logger extends EventEmitter {
63
66
  */
64
67
  error(errorOrMessage: Error | ErrorEvent | PromiseRejectionEvent | string, errorOrDetails?: Error | ErrorDetails, details?: ErrorDetails, ...args: any[]): boolean;
65
68
  /**
66
- * Create a child logger with additional context
69
+ * New logger with same name, namespaced context, no event forwarding
67
70
  *
68
71
  * @param {string} namespace
69
72
  * Namespace of the context (needed for chaining contexts)
@@ -72,17 +75,33 @@ export default class Logger extends EventEmitter {
72
75
  * @returns {Logger} New logger instance with merged context
73
76
  */
74
77
  context(namespace: string, additionalContext: Object): Logger;
78
+ /**
79
+ * Create a child logger that emits events on the current logger
80
+ *
81
+ * @param {string} name
82
+ * Child logger name (will be appended to parent name)
83
+ *
84
+ * @param {object} [options]
85
+ * @param {LogLevel} [options.level] - Child logger log level
86
+ *
87
+ * @returns {Logger} New child logger instance
88
+ */
89
+ child(name: string, { level }?: {
90
+ level?: import("../../typedef.js").LogLevel | undefined;
91
+ }): Logger;
75
92
  /**
76
93
  * Log an LogEvent emitted by an event emitter
77
94
  *
78
95
  * E.g. an event that was created by another Logger instance and should be
79
96
  * forwarded to this logger.
80
97
  *
81
- * @param {import('../../typedef.js').LogEventData} eventData
98
+ * @param {LogEventData} eventData
82
99
  */
83
- logFromEvent(eventData: import("../../typedef.js").LogEventData): false | undefined;
100
+ logFromEvent(eventData: LogEventData): false | undefined;
84
101
  #private;
85
102
  }
86
103
  export type ErrorDetails = import("../../../generic/typedef.js").ErrorDetails;
104
+ export type LogEvent = import("../../typedef.js").LogEvent;
105
+ export type LogEventData = import("../../typedef.js").LogEventData;
87
106
  export type LogLevel = import("../../typedef.js").LogLevel;
88
107
  import { EventEmitter } from '../../../generic/events.js';
@@ -32,8 +32,6 @@
32
32
  * logger.setLevel(DEBUG); // Now debug messages will also be logged
33
33
  */
34
34
 
35
- /** @typedef {import('../../../generic/typedef.js').ErrorDetails} ErrorDetails */
36
-
37
35
  import * as expect from '../../../util/expect.js';
38
36
 
39
37
  import { EventEmitter } from '../../../generic/events.js';
@@ -61,6 +59,11 @@ import { exportNotNullish } from '../../../util/object.js';
61
59
  import * as is from '../../../util/is.js';
62
60
  import { HttpError } from '../../../network/errors.js';
63
61
 
62
+ /** @typedef {import('../../../generic/typedef.js').ErrorDetails} ErrorDetails */
63
+
64
+ /** @typedef {import('../../typedef.js').LogEvent} LogEvent */
65
+ /** @typedef {import('../../typedef.js').LogEventData} LogEventData */
66
+
64
67
  /** @typedef {import('../../typedef.js').LogLevel} LogLevel */
65
68
 
66
69
  /**
@@ -220,7 +223,7 @@ export default class Logger extends EventEmitter {
220
223
  }
221
224
 
222
225
  /**
223
- * Create a child logger with additional context
226
+ * New logger with same name, namespaced context, no event forwarding
224
227
  *
225
228
  * @param {string} namespace
226
229
  * Namespace of the context (needed for chaining contexts)
@@ -241,13 +244,46 @@ export default class Logger extends EventEmitter {
241
244
  return new Logger(this.name, this.level, mergedContext);
242
245
  }
243
246
 
247
+ /**
248
+ * Create a child logger that emits events on the current logger
249
+ *
250
+ * @param {string} name
251
+ * Child logger name (will be appended to parent name)
252
+ *
253
+ * @param {object} [options]
254
+ * @param {LogLevel} [options.level] - Child logger log level
255
+ *
256
+ * @returns {Logger} New child logger instance
257
+ */
258
+ child(name, { level } = {}) {
259
+ if (typeof name !== 'string') {
260
+ throw new Error('Invalid child logger name');
261
+ }
262
+
263
+ const context = {
264
+ ...this.#defaultContext
265
+ };
266
+
267
+ const childName = `${this.name}:${name}`;
268
+
269
+ const child = new Logger(childName, level ?? this.level, context);
270
+
271
+ // Forward all log events from child to parent
272
+ child.on(LOG, ( /** @type {LogEvent} */ logEvent) => {
273
+ this.emit(logEvent.level, logEvent);
274
+ this.emit(LOG, logEvent);
275
+ });
276
+
277
+ return child;
278
+ }
279
+
244
280
  /**
245
281
  * Log an LogEvent emitted by an event emitter
246
282
  *
247
283
  * E.g. an event that was created by another Logger instance and should be
248
284
  * forwarded to this logger.
249
285
  *
250
- * @param {import('../../typedef.js').LogEventData} eventData
286
+ * @param {LogEventData} eventData
251
287
  */
252
288
  logFromEvent(eventData) {
253
289
  expect.object(eventData);
@@ -295,9 +331,9 @@ export default class Logger extends EventEmitter {
295
331
  }
296
332
 
297
333
  /**
298
- * Internal event loggin method
334
+ * Internal event logging method
299
335
  *
300
- * @param {import('../../typedef.js').LogEvent} logEvent
336
+ * @param {LogEvent} logEvent
301
337
  */
302
338
  #logEvent(logEvent) {
303
339
  // Emit as both specific level event and generic 'log' event
@@ -344,6 +380,7 @@ export default class Logger extends EventEmitter {
344
380
  'colno'
345
381
  ]);
346
382
 
383
+ // @ts-ignore
347
384
  errorEventDetails.type = 'ErrorEvent';
348
385
 
349
386
  let cause = errorEvent.error;
@@ -1,6 +1,3 @@
1
- import { INFO } from '../../../logging/common.js';
2
- import { createClientLogger } from '../../../logging/client.js';
3
-
4
1
  /**
5
2
  * Base class for page state machines with URL route mapping
6
3
  *
@@ -220,17 +217,18 @@ export default class PageMachine {
220
217
  * Normalize onEnterHooks to ensure consistent format
221
218
  * Converts function to {onEnter: function} object
222
219
  *
223
- * @param {Record<string, Function|Object>} hooks - Raw hooks configuration
220
+ * @param {Record<string, Function|{onEnter: Function}>} hooks - Raw hooks configuration
224
221
  * @returns {Record<string, {onEnter: Function}>} Normalized hooks
225
222
  */
226
223
  #normalizeOnEnterHooks(hooks) {
224
+ /** @type {Record<string, {onEnter: Function} */
227
225
  const normalized = {};
228
226
 
229
227
  for (const [state, hook] of Object.entries(hooks)) {
230
228
  if (typeof hook === 'function') {
231
229
  // Simple function -> wrap in object
232
230
  normalized[state] = { onEnter: hook };
233
- } else if (hook && typeof hook === 'object' && hook.onEnter) {
231
+ } else if (hook?.onEnter) {
234
232
  // Already an object with onEnter
235
233
  normalized[state] = hook;
236
234
  }
@@ -253,9 +251,14 @@ export default class PageMachine {
253
251
  const targetState = this.#getStateFromPath(currentPath);
254
252
 
255
253
  if (targetState && targetState !== this.#current) {
254
+ // const oldState = this.#current;
256
255
  this.#current = targetState;
257
256
  this.#visitedStates.add(targetState);
258
257
  this.#revision++;
258
+
259
+ // Log state transition from URL sync
260
+ this.logger?.debug(`syncFromPath: ${currentPath} → targetState: ${targetState}`);
261
+
259
262
  return true;
260
263
  }
261
264
 
@@ -286,14 +289,15 @@ export default class PageMachine {
286
289
  this.#visitedStates.add(newState);
287
290
 
288
291
  // Log state transition
289
- this.logger?.debug(`${oldState} → ${newState}`);
292
+ this.logger?.debug(`setState: ${oldState} → ${newState}`);
290
293
 
291
294
  // Check if this state has an onEnter hook
292
295
  const hookConfig = this.#onEnterHooks[newState];
293
296
  if (hookConfig?.onEnter) {
294
297
  // Create done callback for auto-transition
295
298
  let doneCalled = false;
296
- const done = (nextState) => {
299
+
300
+ const done = ( /** @type {string} */ nextState) => {
297
301
  if (!doneCalled && nextState && nextState !== newState) {
298
302
  doneCalled = true;
299
303
  this.#isTransitioning = false;
@@ -322,7 +326,8 @@ export default class PageMachine {
322
326
  await handler;
323
327
  }
324
328
  } catch (error) {
325
- console.error(`Error in onEnter hook for state ${newState}:`, error);
329
+ const logger = this.logger ?? console;
330
+ logger.error(`Error in onEnter hook for state ${newState}:`, error);
326
331
  }
327
332
  }
328
333
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.5.49",
3
+ "version": "0.5.51",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"