@xiboplayer/utils 0.7.3 → 0.7.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiboplayer/utils",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "Shared utilities for Xibo Player packages",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -12,7 +12,7 @@
12
12
  "./config": "./src/config.js"
13
13
  },
14
14
  "dependencies": {
15
- "@xiboplayer/crypto": "0.7.3"
15
+ "@xiboplayer/crypto": "0.7.5"
16
16
  },
17
17
  "devDependencies": {
18
18
  "vitest": "^2.1.9"
package/src/config.js CHANGED
@@ -14,6 +14,9 @@
14
14
  */
15
15
  import { generateRsaKeyPair, isValidPemKey } from '@xiboplayer/crypto';
16
16
  import { openIDB } from './idb.js';
17
+ import { createLogger } from './logger.js';
18
+
19
+ const log = createLogger('Config');
17
20
 
18
21
  const GLOBAL_KEY = 'xibo_global'; // Device identity (all CMSes)
19
22
  const CMS_PREFIX = 'xibo_cms:'; // Per-CMS config prefix
@@ -135,7 +138,7 @@ export class Config {
135
138
  try {
136
139
  global = JSON.parse(localStorage.getItem(GLOBAL_KEY) || '{}');
137
140
  } catch (e) {
138
- console.error('[Config] Failed to parse xibo_global:', e);
141
+ log.error('Failed to parse xibo_global:', e);
139
142
  }
140
143
 
141
144
  // Determine active CMS
@@ -148,7 +151,7 @@ export class Config {
148
151
  const cmsJson = localStorage.getItem(CMS_PREFIX + activeCmsId);
149
152
  if (cmsJson) cmsConfig = JSON.parse(cmsJson);
150
153
  } catch (e) {
151
- console.error('[Config] Failed to parse CMS config:', e);
154
+ log.error('Failed to parse CMS config:', e);
152
155
  }
153
156
  }
154
157
 
@@ -175,16 +178,16 @@ export class Config {
175
178
  let changed = false;
176
179
 
177
180
  if (!config.hardwareKey || config.hardwareKey.length < 10) {
178
- console.warn('[Config] Missing/invalid hardwareKey — generating');
181
+ log.warn('Missing/invalid hardwareKey — generating');
179
182
  config.hardwareKey = this.generateStableHardwareKey();
180
183
  this._backupHardwareKey(config.hardwareKey);
181
184
  changed = true;
182
185
  } else {
183
- console.log('[Config] ✓ Loaded existing hardwareKey:', config.hardwareKey);
186
+ log.info('✓ Loaded existing hardwareKey:', config.hardwareKey);
184
187
  }
185
188
 
186
189
  if (!config.xmrChannel) {
187
- console.warn('[Config] Missing xmrChannel — generating');
190
+ log.warn('Missing xmrChannel — generating');
188
191
  config.xmrChannel = this.generateXmrChannel();
189
192
  changed = true;
190
193
  }
@@ -265,12 +268,12 @@ export class Config {
265
268
  try {
266
269
  cmsConfig = JSON.parse(existingJson);
267
270
  isNew = false;
268
- console.log(`[Config] Switching to existing CMS profile: ${newCmsId}`);
271
+ log.info(`Switching to existing CMS profile: ${newCmsId}`);
269
272
  } catch (e) {
270
- console.error('[Config] Failed to parse target CMS config:', e);
273
+ log.error('Failed to parse target CMS config:', e);
271
274
  }
272
275
  } else {
273
- console.log(`[Config] Creating new CMS profile: ${newCmsId}`);
276
+ log.info(`Creating new CMS profile: ${newCmsId}`);
274
277
  cmsConfig = {
275
278
  cmsUrl,
276
279
  cmsKey: '',
@@ -361,7 +364,7 @@ export class Config {
361
364
  store.put(v, k);
362
365
  }
363
366
  tx.oncomplete = () => {
364
- console.log('[Config] Keys backed up to IndexedDB:', Object.keys(keys).join(', '));
367
+ log.info('Keys backed up to IndexedDB:', Object.keys(keys).join(', '));
365
368
  db.close();
366
369
  };
367
370
  } catch (e) {
@@ -395,8 +398,8 @@ export class Config {
395
398
  db.close();
396
399
 
397
400
  if (backedUpKey && backedUpKey !== this.data.hardwareKey) {
398
- console.log('[Config] Restoring hardware key from IndexedDB backup:', backedUpKey);
399
- console.log('[Config] (was:', this.data.hardwareKey, ')');
401
+ log.info('Restoring hardware key from IndexedDB backup:', backedUpKey);
402
+ log.info('(was:', this.data.hardwareKey, ')');
400
403
  this.data.hardwareKey = backedUpKey;
401
404
  this.save();
402
405
  } else if (!backedUpKey && this.data.hardwareKey) {
@@ -417,7 +420,7 @@ export class Config {
417
420
  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
418
421
  const uuid = crypto.randomUUID().replace(/-/g, ''); // Remove dashes
419
422
  const hardwareKey = 'pwa-' + uuid.substring(0, 28);
420
- console.log('[Config] Generated new UUID-based hardware key:', hardwareKey);
423
+ log.info('Generated new UUID-based hardware key:', hardwareKey);
421
424
  return hardwareKey;
422
425
  }
423
426
 
@@ -427,7 +430,7 @@ export class Config {
427
430
  ).join('');
428
431
 
429
432
  const hardwareKey = 'pwa-' + randomHex;
430
- console.log('[Config] Generated new random hardware key:', hardwareKey);
433
+ log.info('Generated new random hardware key:', hardwareKey);
431
434
  return hardwareKey;
432
435
  }
433
436
 
@@ -450,7 +453,7 @@ export class Config {
450
453
  return;
451
454
  }
452
455
 
453
- console.log('[Config] Generating RSA key pair for XMR registration...');
456
+ log.info('Generating RSA key pair for XMR registration...');
454
457
  const { publicKeyPem, privateKeyPem } = await generateRsaKeyPair();
455
458
 
456
459
  this.data.xmrPubKey = publicKeyPem;
@@ -462,7 +465,7 @@ export class Config {
462
465
  this._backupKeys({ xmrPubKey: publicKeyPem, xmrPrivKey: privateKeyPem });
463
466
  }
464
467
 
465
- console.log('[Config] RSA key pair generated and saved');
468
+ log.info('RSA key pair generated and saved');
466
469
  }
467
470
 
468
471
  get cmsUrl() { return this.data.cmsUrl; }
@@ -477,7 +480,7 @@ export class Config {
477
480
  get hardwareKey() {
478
481
  // CRITICAL: Ensure hardware key never becomes undefined
479
482
  if (!this.data.hardwareKey) {
480
- console.error('[Config] CRITICAL: hardwareKey missing! Generating emergency key.');
483
+ log.error('CRITICAL: hardwareKey missing! Generating emergency key.');
481
484
  this.data.hardwareKey = this.generateStableHardwareKey();
482
485
  this.save();
483
486
  }
@@ -485,7 +488,7 @@ export class Config {
485
488
  }
486
489
  get xmrChannel() {
487
490
  if (!this.data.xmrChannel) {
488
- console.warn('[Config] xmrChannel missing at access time — generating');
491
+ log.warn('xmrChannel missing at access time — generating');
489
492
  this.data.xmrChannel = this.generateXmrChannel();
490
493
  this.save();
491
494
  }
@@ -538,8 +541,8 @@ export function warnPlatformMismatch(configObj, platform) {
538
541
  const p = platform.toLowerCase();
539
542
  for (const [key, platforms] of Object.entries(PLATFORM_KEYS)) {
540
543
  if (key in configObj && !platforms.includes(p)) {
541
- console.warn(
542
- `[Config] Key "${key}" is only supported on ${platforms.join('/')}, ` +
544
+ log.warn(
545
+ `Key "${key}" is only supported on ${platforms.join('/')}, ` +
543
546
  `but current platform is ${p} — this key will be ignored`
544
547
  );
545
548
  }
@@ -499,16 +499,18 @@ describe('Config', () => {
499
499
  warnPlatformMismatch({ browser: 'chrome', cmsUrl: 'https://test.com' }, 'electron');
500
500
 
501
501
  expect(warnSpy).toHaveBeenCalledTimes(1);
502
- expect(warnSpy.mock.calls[0][0]).toContain('browser');
503
- expect(warnSpy.mock.calls[0][0]).toContain('chromium');
502
+ // Logger outputs: console.warn(timestamp_prefix, message) — message is in args[1]
503
+ expect(warnSpy.mock.calls[0][1]).toContain('browser');
504
+ expect(warnSpy.mock.calls[0][1]).toContain('chromium');
504
505
  });
505
506
 
506
507
  it('should warn when Electron-only key is used in Chromium', () => {
507
508
  warnPlatformMismatch({ autoLaunch: true }, 'chromium');
508
509
 
509
510
  expect(warnSpy).toHaveBeenCalledTimes(1);
510
- expect(warnSpy.mock.calls[0][0]).toContain('autoLaunch');
511
- expect(warnSpy.mock.calls[0][0]).toContain('electron');
511
+ // Logger outputs: console.warn(timestamp_prefix, message) — message is in args[1]
512
+ expect(warnSpy.mock.calls[0][1]).toContain('autoLaunch');
513
+ expect(warnSpy.mock.calls[0][1]).toContain('electron');
512
514
  });
513
515
 
514
516
  it('should not warn for shared keys', () => {
package/src/idb.js CHANGED
@@ -82,6 +82,7 @@ export function deleteByIds(db, storeName, ids) {
82
82
  if (id) {
83
83
  const req = store.delete(id);
84
84
  req.onsuccess = () => { deleted++; };
85
+ req.onerror = () => { /* individual delete failed — tx.onerror handles fatal */ };
85
86
  }
86
87
  }
87
88
 
package/src/logger.js CHANGED
@@ -132,12 +132,22 @@ if (typeof window !== 'undefined') {
132
132
  const urlLevel = urlParams.get('logLevel');
133
133
  const storageLevel = localStorage.getItem('xibo_log_level');
134
134
 
135
+ // Also check config-injected logLevel (proxy writes xibo_config to localStorage)
136
+ let configLevel = null;
137
+ try {
138
+ const cfg = JSON.parse(localStorage.getItem('xibo_config') || '{}');
139
+ configLevel = cfg.logLevel || null;
140
+ } catch (_) {}
141
+
135
142
  if (urlLevel) {
136
143
  globalConfig.setGlobalLevel(urlLevel);
137
144
  hasLocalOverride = true;
138
145
  } else if (storageLevel) {
139
146
  globalConfig.setGlobalLevel(storageLevel);
140
147
  hasLocalOverride = true;
148
+ } else if (configLevel) {
149
+ globalConfig.setGlobalLevel(configLevel);
150
+ hasLocalOverride = true;
141
151
  } else {
142
152
  globalConfig.setGlobalLevel('WARNING');
143
153
  }