@hkdigital/lib-core 0.4.35 → 0.4.36

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/CLAUDE.md CHANGED
@@ -38,6 +38,12 @@ This is a modern SvelteKit library built with Svelte 5 and Skeleton.dev v3 compo
38
38
  - English for all documentation and comments
39
39
  - No dollar signs in variable names (reserved for Svelte)
40
40
 
41
+ ### Testing Commands
42
+ - Run all tests: `pnpm test`
43
+ - Run specific test file: `pnpm test:file path/to/test.js`
44
+ - Run tests in directory: `pnpm test:file src/lib/logging/`
45
+ - Use `pnpm test:file` for single test execution - it's cross-platform compatible
46
+
41
47
  ### ESLint Rule Suppression
42
48
  - Use specific rule suppression instead of blanket disables
43
49
  - For unused variables in method signatures (e.g., base class methods to be overridden):
@@ -103,40 +103,92 @@ export async function handle({ event, resolve }) {
103
103
  ### Client-side logging (src/hooks.client.js)
104
104
 
105
105
  ```javascript
106
- import { createClientLogger } from '@hkdigital/lib-core/logging/index.js';
106
+ import { initClientServices } from '$lib/services/client.js';
107
+ import { getClientLogger } from '$lib/logging/client.js';
107
108
 
108
- const logger = createClientLogger('client');
109
+ export async function init() {
110
+ // Init services
111
+ try {
112
+ await initClientServices();
113
+
114
+ getClientLogger().info('Client initialization complete');
115
+ } catch (error) {
116
+ getClientLogger().error('Client initialization failed',
117
+ /** @type {Error} */ (error));
118
+ // throw error;
119
+ }
120
+ finally {
121
+ getClientLogger().info('Client application initialized', {
122
+ userAgent: navigator.userAgent,
123
+ viewport: `${window.innerWidth}x${window.innerHeight}`
124
+ });
125
+ }
126
+ }
109
127
 
110
128
  /** @type {import('@sveltejs/kit').HandleClientError} */
111
129
  export function handleError({ error, event }) {
112
- logger.error(error, {
113
- url: event.url?.pathname,
114
- userAgent: navigator.userAgent
130
+ // Handle SvelteKit-specific errors:
131
+ // navigation errors, load function failures, component errors, ...
132
+ getClientLogger().error(/** @type {Error} */ (error), {
133
+ url: event.url?.pathname,
134
+ userAgent: navigator.userAgent
115
135
  });
116
136
  }
137
+ ```
117
138
 
118
- // Initialize client-side logging
119
- export function init() {
120
- logger.info('Client application initialized', {
121
- userAgent: navigator.userAgent,
122
- viewport: `${window.innerWidth}x${window.innerHeight}`
123
- });
124
-
125
- // Log unhandled errors
126
- window.addEventListener('error', (event) => {
127
- logger.error(event, { url: window.location.pathname });
128
- });
129
-
130
- // Log unhandled promise rejections
131
- window.addEventListener('unhandledrejection', (event) => {
132
- logger.error(event, { url: window.location.pathname });
133
- });
139
+ ### Client Service Integration
140
+
141
+ When integrating with a service management system, you can set up global
142
+ error handling and forward service logs to the main logger:
143
+
144
+ ```javascript
145
+ import { ServiceManager } from '$hklib-core/services/index.js';
146
+ import { initClientLogger } from '$lib/logging/client.js';
147
+
148
+ /** @type {ServiceManager} */
149
+ let manager;
150
+
151
+ export async function initClientServices() {
152
+ if (!manager) {
153
+ const logger = initClientLogger();
154
+
155
+ // Catch errors and unhandled promise rejections
156
+
157
+ // Log unhandled errors
158
+ window.addEventListener('error', (event) => {
159
+ logger.error(event, { url: window.location.pathname });
160
+ event.preventDefault();
161
+ });
162
+
163
+ // Log unhandled promise rejections
164
+ window.addEventListener('unhandledrejection', (event) => {
165
+ logger.error(event, { url: window.location.pathname });
166
+ // Ignored by Firefox
167
+ event.preventDefault();
168
+ });
169
+
170
+ manager = new ServiceManager({ debug: true });
171
+
172
+ // Listen to all log events and forward them to the logger
173
+ manager.onLogEvent((logEvent) => {
174
+ logger.logFromEvent(logEvent);
175
+ });
176
+
177
+ // Register services
178
+ manager.register(SERVICE_AUDIO, AudioService);
179
+ manager.register(SERVICE_EVENT_LOG, EventLogService);
180
+ manager.register(SERVICE_PLAYER_DATA, PlayerDataService);
181
+ }
182
+
183
+ await manager.startAll();
184
+ return manager;
134
185
  }
135
186
 
136
- // Cleanup when app is destroyed
137
- export function destroy() {
138
- logger.info('Client application destroyed');
139
- // Note: Console adapter doesn't require cleanup
187
+ export function getManager() {
188
+ if (!manager) {
189
+ throw new Error('Client services should be initialised first');
190
+ }
191
+ return manager;
140
192
  }
141
193
  ```
142
194
 
@@ -381,8 +381,22 @@ export class ConsoleAdapter {
381
381
  'node_modules/vite-deps'
382
382
  );
383
383
 
384
+ // Clean up pnpm paths - convert complex pnpm paths to simple package names
385
+ // Before: node_modules/.pnpm/@hkdigital+lib-core@0.4.35_@eslint+js@9.35.0_.../node_modules/@hkdigital/lib-core/dist/...
386
+ // After: @hkdigital/lib-core/dist/...
387
+ cleaned = cleaned.replace(
388
+ /node_modules\/\.pnpm\/([^\/]+)@[^_]+[^\/]*\/node_modules\/([^\/]+(?:\/[^\/]+)?)\//g,
389
+ '$2/'
390
+ );
391
+
392
+ // Clean up regular node_modules paths for known HK packages
393
+ cleaned = cleaned.replace(
394
+ /node_modules\/@hkdigital\/([^\/]+)\//g,
395
+ '@hkdigital/$1/'
396
+ );
397
+
384
398
  // Clean up query parameters on source files
385
- cleaned = cleaned.replace(/\?t=\d+/g, '');
399
+ cleaned = cleaned.replace(/\?[tv]=[a-f0-9]+/g, '');
386
400
 
387
401
  // Skip vite-deps (Svelte framework internals) but keep other node_modules
388
402
  if (cleaned.includes('node_modules/vite-deps')) {
@@ -404,8 +404,6 @@ export function isMeaningfulFunctionName(functionName) {
404
404
  if (
405
405
  !functionName ||
406
406
  functionName === '' ||
407
- functionName.includes('<') ||
408
- functionName.includes('/') ||
409
407
  functionName.startsWith('async ') ||
410
408
  functionName === 'async' ||
411
409
  functionName === 'Promise' ||
@@ -416,6 +414,13 @@ export function isMeaningfulFunctionName(functionName) {
416
414
  return false;
417
415
  }
418
416
 
417
+ // Skip pure anonymous functions (just '<' without a parent function name)
418
+ if (functionName === '<' || functionName === '</') {
419
+ return false;
420
+ }
421
+
422
+ // Allow function names that contain '/<' (anonymous functions within named functions)
423
+ // These are meaningful as they show "parentFunction/<anonymous>"
419
424
  return true;
420
425
  }
421
426
 
@@ -429,17 +434,35 @@ export function parseFunctionName(frame) {
429
434
  // Handle both Firefox format: "functionName@file:line:col"
430
435
  // and Node.js format: "at functionName (file:line:col)" or "at Module.functionName (file:line:col)"
431
436
 
437
+ let functionName = null;
438
+
432
439
  // Firefox format
433
440
  const firefoxMatch = frame.match(/^([^@]+)@/);
434
441
  if (firefoxMatch) {
435
- return firefoxMatch[1];
442
+ functionName = firefoxMatch[1];
443
+ } else {
444
+ // Node.js format
445
+ const nodeMatch = frame.match(/^\s*at\s+(?:Module\.)?([^\s(]+)/);
446
+ if (nodeMatch) {
447
+ functionName = nodeMatch[1];
448
+ }
436
449
  }
437
450
 
438
- // Node.js format
439
- const nodeMatch = frame.match(/^\s*at\s+(?:Module\.)?([^\s(]+)/);
440
- if (nodeMatch) {
441
- return nodeMatch[1];
451
+ if (!functionName) {
452
+ return null;
442
453
  }
443
454
 
444
- return null;
455
+ // Clean up common patterns
456
+ functionName = functionName.trim();
457
+
458
+ // Handle anonymous functions within named functions
459
+ // Convert "functionName/<" to "functionName (anonymous)"
460
+ if (functionName.endsWith('/<')) {
461
+ const baseName = functionName.slice(0, -2);
462
+ if (baseName) {
463
+ functionName = `${baseName} (anonymous)`;
464
+ }
465
+ }
466
+
467
+ return functionName;
445
468
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkdigital/lib-core",
3
- "version": "0.4.35",
3
+ "version": "0.4.36",
4
4
  "author": {
5
5
  "name": "HKdigital",
6
6
  "url": "https://hkdigital.nl"
@@ -27,6 +27,7 @@
27
27
  "format": "prettier --write .",
28
28
  "lint": "run-s lint:*",
29
29
  "test": "run-s test:unit-run",
30
+ "test:file": "vitest run",
30
31
  "prepack": "run-s prepack:*",
31
32
  "publish:npm": "run-s publish:npm:version publish:npm:publish git:push",
32
33
  "upgrade:hk": "run-s upgrade:hk:update pnpm:install",