@ceeblue/web-utils 6.0.0 → 7.0.1

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.
@@ -322,7 +322,7 @@ type Params = {
322
322
  * If `endPoint` is a complete URL and `streamName` is not provided, {@link buildURL} will set this parameter automatically
323
323
  * using the second part of the URL's path (the first part being the protocol name), or the first path if no other part exists.
324
324
  */
325
- streamName: string;
325
+ streamName?: string;
326
326
  /**
327
327
  * Optional access token to use to join a private stream
328
328
  */
@@ -891,14 +891,26 @@ declare function safePromise<T>(timeout: number, promise: Promise<T>): Promise<u
891
891
  */
892
892
  declare function sleep(ms: number): Promise<unknown>;
893
893
  /**
894
- * Test equality between two value whatever their type, array included
894
+ * Test equality between two value whatever their type, object and array included
895
895
  */
896
- declare function equal(a: any, b: any): boolean;
896
+ declare function equal(a: any, b: any, seen?: WeakMap<WeakKey, any>): boolean;
897
897
  /**
898
- * fetch help method with few usefull fix:
899
- * - throw an string exception if response code is not 200 with the text of the response or uses statusText
898
+ * Fetch help method adding an explicit error property when Response is NOK, with the more accurate textual error inside
900
899
  */
901
- declare function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
900
+ declare function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response & {
901
+ error?: string;
902
+ }>;
903
+ /**
904
+ * Fetch help method adding an explicit error property when Response is NOK, with the more accurate textual error inside
905
+ * Also measure the rtt of fetching and returns it in the property Response.rtt (guaranteed to be ≥ 1),
906
+ * supports subtracting server processing time using either the Response-Delay or CMSD-rd header when available
907
+ *
908
+ * WIP => replace the current implementation to use Resource Timing API
909
+ */
910
+ declare function fetchWithRTT(input: RequestInfo | URL, init?: RequestInit): Promise<Response & {
911
+ rtt: number;
912
+ error?: string;
913
+ }>;
902
914
  /**
903
915
  * Get Extension part from path
904
916
  * @param path path to parse
@@ -942,6 +954,7 @@ declare function trimEnd(value: string, chars?: string): string;
942
954
  declare const Util_EMPTY_FUNCTION: typeof EMPTY_FUNCTION;
943
955
  declare const Util_equal: typeof equal;
944
956
  declare const Util_fetch: typeof fetch;
957
+ declare const Util_fetchWithRTT: typeof fetchWithRTT;
945
958
  declare const Util_getBaseFile: typeof getBaseFile;
946
959
  declare const Util_getExtension: typeof getExtension;
947
960
  declare const Util_getFile: typeof getFile;
@@ -958,7 +971,7 @@ declare const Util_trimEnd: typeof trimEnd;
958
971
  declare const Util_trimStart: typeof trimStart;
959
972
  declare const Util_unixTime: typeof unixTime;
960
973
  declare namespace Util {
961
- export { Util_EMPTY_FUNCTION as EMPTY_FUNCTION, Util_equal as equal, Util_fetch as fetch, Util_getBaseFile as getBaseFile, Util_getExtension as getExtension, Util_getFile as getFile, Util_iterableEntries as iterableEntries, Util_objectFrom as objectFrom, Util_options as options, Util_safePromise as safePromise, Util_sleep as sleep, Util_stringify as stringify, Util_time as time, Util_toBin as toBin, Util_trim as trim, Util_trimEnd as trimEnd, Util_trimStart as trimStart, Util_unixTime as unixTime };
974
+ export { Util_EMPTY_FUNCTION as EMPTY_FUNCTION, Util_equal as equal, Util_fetch as fetch, Util_fetchWithRTT as fetchWithRTT, Util_getBaseFile as getBaseFile, Util_getExtension as getExtension, Util_getFile as getFile, Util_iterableEntries as iterableEntries, Util_objectFrom as objectFrom, Util_options as options, Util_safePromise as safePromise, Util_sleep as sleep, Util_stringify as stringify, Util_time as time, Util_toBin as toBin, Util_trim as trim, Util_trimEnd as trimEnd, Util_trimStart as trimStart, Util_unixTime as unixTime };
962
975
  }
963
976
 
964
977
  /**
package/dist/web-utils.js CHANGED
@@ -371,55 +371,141 @@ function safePromise(timeout, promise) {
371
371
  * Wait in milliseconds, requires a call with await keyword!
372
372
  */
373
373
  function sleep(ms) {
374
- return new Promise(resolve => {
375
- setTimeout(resolve, ms);
374
+ return __awaiter(this, void 0, void 0, function* () {
375
+ return new Promise(resolve => {
376
+ setTimeout(resolve, ms);
377
+ });
376
378
  });
377
379
  }
378
380
  /**
379
- * Test equality between two value whatever their type, array included
381
+ * Test equality between two value whatever their type, object and array included
380
382
  */
381
- function equal(a, b) {
382
- if (Object(a) !== a) {
383
- if (Object(b) === b) {
384
- return false;
385
- }
386
- // both primitive (null and undefined included)
387
- return a === b;
383
+ function equal(a, b, seen = new WeakMap()) {
384
+ // 1. Check primitve identiy or NaN
385
+ if (a === b) {
386
+ return true;
388
387
  }
389
- // complexe object
390
- if (a[Symbol.iterator]) {
391
- if (!b[Symbol.iterator]) {
392
- return false;
388
+ if (Number.isNaN(a) && Number.isNaN(b)) {
389
+ return true;
390
+ }
391
+ // 2. Check the both are complexe object
392
+ if (Object(a) !== a || Object(b) !== b) {
393
+ return false;
394
+ }
395
+ // 3. Catch circular reference
396
+ if (seen.has(a)) {
397
+ return seen.get(a) === b;
398
+ }
399
+ seen.set(a, b);
400
+ // 4. Check « toStringTag » (Date, RegExp, Map, Set…)
401
+ const tagA = Object.prototype.toString.call(a);
402
+ if (tagA !== Object.prototype.toString.call(b)) {
403
+ return false;
404
+ }
405
+ // 5. Special Case
406
+ switch (tagA) {
407
+ case '[object Date]':
408
+ return a.getTime() === b.getTime();
409
+ case '[object RegExp]':
410
+ return a.source === b.source && a.flags === b.flags;
411
+ case '[object Set]':
412
+ case '[object Map]': {
413
+ if (a.size !== b.size) {
414
+ return false;
415
+ }
416
+ const aKeys = a.keys();
417
+ const bKeys = a.keys();
418
+ const aValues = a.values();
419
+ const bValues = b.values();
420
+ let aKey;
421
+ while (!(aKey = aKeys.next()).done) {
422
+ if (!equal(aKey.value, bKeys.next().value)) {
423
+ return false;
424
+ }
425
+ const aValue = aValues.next().value;
426
+ const bValue = bValues.next().value;
427
+ if (aValue !== aKey && !equal(aValue, bValue)) {
428
+ return false;
429
+ }
430
+ }
431
+ return true;
393
432
  }
394
- if (a.length !== b.length) {
433
+ }
434
+ // 6. Arrays
435
+ if (Array.isArray(a)) {
436
+ if (!Array.isArray(b) || a.length !== b.length) {
395
437
  return false;
396
438
  }
397
- for (let i = 0; i !== a.length; ++i) {
398
- if (a[i] !== b[i]) {
439
+ for (let i = 0; i < a.length; i++) {
440
+ if (!equal(a[i], b[i], seen)) {
399
441
  return false;
400
442
  }
401
443
  }
402
444
  return true;
403
445
  }
404
- return a === b;
446
+ // 7. Generic object : keys + symbols
447
+ const keysA = [...Object.keys(a), ...Object.getOwnPropertySymbols(a)];
448
+ if (keysA.length !== Object.keys(b).length + Object.getOwnPropertySymbols(b).length) {
449
+ return false;
450
+ }
451
+ for (const key of keysA) {
452
+ if (!equal(a[key], b[key], seen)) {
453
+ return false;
454
+ }
455
+ }
456
+ return true;
405
457
  }
406
458
  /**
407
- * fetch help method with few usefull fix:
408
- * - throw an string exception if response code is not 200 with the text of the response or uses statusText
459
+ * Fetch help method adding an explicit error property when Response is NOK, with the more accurate textual error inside
409
460
  */
410
461
  function fetch(input, init) {
411
462
  return __awaiter(this, void 0, void 0, function* () {
412
- const response = yield self.fetch(input, init);
413
- if (response.status >= 300) {
414
- let error;
463
+ const response = (yield self.fetch(input, init));
464
+ if (!response.ok) {
415
465
  if (response.body) {
416
- error = yield response.text();
466
+ response.error = yield response.text();
467
+ }
468
+ if (!response.error) {
469
+ response.error = response.statusText || response.status.toString() || 'Unknown error';
417
470
  }
418
- throw (error || response.statusText || response.status).toString();
419
471
  }
420
472
  return response;
421
473
  });
422
474
  }
475
+ /**
476
+ * Fetch help method adding an explicit error property when Response is NOK, with the more accurate textual error inside
477
+ * Also measure the rtt of fetching and returns it in the property Response.rtt (guaranteed to be ≥ 1),
478
+ * supports subtracting server processing time using either the Response-Delay or CMSD-rd header when available
479
+ *
480
+ * WIP => replace the current implementation to use Resource Timing API
481
+ */
482
+ function fetchWithRTT(input, init) {
483
+ return __awaiter(this, void 0, void 0, function* () {
484
+ // A first OPTIONS request to establish a connection (keep-alive)
485
+ yield fetch(input, Object.assign(Object.assign({}, init), { method: 'OPTIONS' }));
486
+ // Actual RTT measurement
487
+ const startTime = time();
488
+ const response = (yield fetch(input, init));
489
+ response.rtt = time() - startTime;
490
+ // remove the ResponseDelay if indicated by the server
491
+ let responseDelay = Number(response.headers.get('Response-Delay')) || 0;
492
+ if (!responseDelay) {
493
+ // search if we have a CMSD info?
494
+ // cmsd-dynamic "fly";rd=1
495
+ const cmsd = response.headers.get('cmsd-dynamic');
496
+ if (cmsd) {
497
+ for (const param of cmsd.split(';')) {
498
+ const [name, value] = param.split('=');
499
+ if (name.trim().toLowerCase() === 'rd') {
500
+ responseDelay = Number(value) || responseDelay;
501
+ }
502
+ }
503
+ }
504
+ }
505
+ response.rtt = Math.max(1, response.rtt - responseDelay);
506
+ return response;
507
+ });
508
+ }
423
509
  /**
424
510
  * Get Extension part from path
425
511
  * @param path path to parse
@@ -500,7 +586,7 @@ function trimEnd(value, chars = ' ') {
500
586
  --i;
501
587
  }
502
588
  return value.substring(0, i);
503
- }var Util=/*#__PURE__*/Object.freeze({__proto__:null,EMPTY_FUNCTION:EMPTY_FUNCTION,equal:equal,fetch:fetch,getBaseFile:getBaseFile,getExtension:getExtension,getFile:getFile,iterableEntries:iterableEntries,objectFrom:objectFrom,options:options,safePromise:safePromise,sleep:sleep,stringify:stringify,time:time,toBin:toBin,trim:trim,trimEnd:trimEnd,trimStart:trimStart,unixTime:unixTime});/**
589
+ }var Util=/*#__PURE__*/Object.freeze({__proto__:null,EMPTY_FUNCTION:EMPTY_FUNCTION,equal:equal,fetch:fetch,fetchWithRTT:fetchWithRTT,getBaseFile:getBaseFile,getExtension:getExtension,getFile:getFile,iterableEntries:iterableEntries,objectFrom:objectFrom,options:options,safePromise:safePromise,sleep:sleep,stringify:stringify,time:time,toBin:toBin,trim:trim,trimEnd:trimEnd,trimStart:trimStart,unixTime:unixTime});/**
504
590
  * Copyright 2024 Ceeblue B.V.
505
591
  * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
506
592
  * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
@@ -1167,7 +1253,21 @@ var Type;
1167
1253
  * @param params The parameters for which the media extension is to be defined
1168
1254
  */
1169
1255
  function defineMediaExt(type, params) {
1256
+ var _a;
1170
1257
  // Compute appropriate mediaExt out parameter
1258
+ if (!params.mediaExt) {
1259
+ try {
1260
+ const url = new URL(params.endPoint);
1261
+ // Set mediaExt with ?ext= param when set OR url extension
1262
+ params.mediaExt = (_a = url.searchParams.get('ext')) !== null && _a !== void 0 ? _a : getExtension(getFile(url.pathname));
1263
+ }
1264
+ catch (_) {
1265
+ // not an URL, it's only a host
1266
+ params.mediaExt = '';
1267
+ }
1268
+ }
1269
+ // Normalize mediaExt in removing the possible '.' prefix and change it to lower case
1270
+ params.mediaExt = trimStart(params.mediaExt, '.').toLowerCase();
1171
1271
  switch (type) {
1172
1272
  case Type.HESP:
1173
1273
  params.mediaExt = 'mp4';
@@ -1176,19 +1276,8 @@ function defineMediaExt(type, params) {
1176
1276
  params.mediaExt = 'rtp';
1177
1277
  break;
1178
1278
  case Type.WRTS: {
1179
- try {
1180
- const url = new URL(params.endPoint);
1181
- const ext = getExtension(getFile(url.pathname));
1182
- // set extension just if not json, json means a manifest file endPoint
1183
- if (ext && ext.toLowerCase() !== '.json') {
1184
- params.mediaExt = ext;
1185
- }
1186
- }
1187
- catch (_) {
1188
- // not an URL, it's only a host => keep mediaExt unchanged to build the URL
1189
- }
1190
- if (!params.mediaExt) {
1191
- // set to its default rts value => always set for WRTS!
1279
+ // json means a manifest file endPoint, replace with default rts media extension
1280
+ if (!params.mediaExt || params.mediaExt === 'json') {
1192
1281
  params.mediaExt = 'rts';
1193
1282
  }
1194
1283
  break;
@@ -1200,12 +1289,9 @@ function defineMediaExt(type, params) {
1200
1289
  params.mediaExt = 'json';
1201
1290
  break;
1202
1291
  default:
1203
- params.mediaExt = ''; // set always a value to know that the parameters have been fixed
1204
- console.warn('Unknown params type ' + type);
1292
+ log('Unknown params type ' + type).warn();
1205
1293
  break;
1206
1294
  }
1207
- // Fix mediaExt in removing the possible '.' prefix
1208
- params.mediaExt = trimStart(params.mediaExt, '.');
1209
1295
  }
1210
1296
  /**
1211
1297
  * Build an URL from {@link Type | type} and {@link Params | params}
@@ -1238,7 +1324,7 @@ function buildURL(type, params, protocol = 'wss') {
1238
1324
  url.pathname = '/' + params.streamName + '.json';
1239
1325
  break;
1240
1326
  default:
1241
- console.warn('Unknown url type ' + type);
1327
+ log('Unknown url type ' + type).warn();
1242
1328
  break;
1243
1329
  }
1244
1330
  }
@@ -2462,4 +2548,4 @@ class UIMetrics {
2462
2548
  * This file is part of https://github.com/CeeblueTV/web-utils which is released under GNU Affero General Public License.
2463
2549
  * See file LICENSE or go to https://spdx.org/licenses/AGPL-3.0-or-later.html for full license details.
2464
2550
  */
2465
- const VERSION = '6.0.0';export{BinaryReader,BinaryWriter,BitReader,ByteRate,Connect,EpochTime,EventEmitter,FixMap,Log,LogLevel,Loggable,NetAddress,Numbers,Queue,SDP,UIMetrics,Util,VERSION,WebSocketReliable,log};//# sourceMappingURL=web-utils.js.map
2551
+ const VERSION = '7.0.1';export{BinaryReader,BinaryWriter,BitReader,ByteRate,Connect,EpochTime,EventEmitter,FixMap,Log,LogLevel,Loggable,NetAddress,Numbers,Queue,SDP,UIMetrics,Util,VERSION,WebSocketReliable,log};//# sourceMappingURL=web-utils.js.map