@monterosa/sdk-util 0.17.1-rc.6

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.
@@ -0,0 +1,751 @@
1
+ import mitt from 'mitt';
2
+
3
+ /**
4
+ * @license
5
+ * subscribe.ts
6
+ * util
7
+ *
8
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2022-02-22
9
+ * Copyright © 2022 Monterosa. All rights reserved.
10
+ *
11
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
12
+ */
13
+ class Emitter {
14
+ constructor() {
15
+ this.handlers = new Map();
16
+ this.emitter = mitt();
17
+ }
18
+ on(event, handler) {
19
+ const mittHandler = (args) => {
20
+ handler(...(Array.isArray(args) ? args : [args]));
21
+ };
22
+ this.handlers.set(handler, mittHandler);
23
+ this.emitter.on(event, mittHandler);
24
+ return () => this.off(event, handler);
25
+ }
26
+ off(event, handler) {
27
+ if (handler === undefined) {
28
+ this.emitter.off(event);
29
+ return;
30
+ }
31
+ const mittHandler = this.handlers.get(handler);
32
+ if (mittHandler) {
33
+ this.emitter.off(event, mittHandler);
34
+ this.handlers.delete(handler);
35
+ }
36
+ }
37
+ emit(event, ...args) {
38
+ this.emitter.emit(event, args);
39
+ }
40
+ once(event, handler) {
41
+ const mittHandler = (args) => {
42
+ handler(...(Array.isArray(args) ? args : [args]));
43
+ this.off(event, handler);
44
+ };
45
+ this.handlers.set(handler, mittHandler);
46
+ this.emitter.on(event, mittHandler);
47
+ return () => this.off(event, handler);
48
+ }
49
+ }
50
+ /**
51
+ * @internal
52
+ */
53
+ const subscribe = (emitter, event, callback) => {
54
+ emitter.on(event, callback);
55
+ return () => emitter.off(event, callback);
56
+ };
57
+
58
+ /**
59
+ * @license
60
+ * delay.ts
61
+ * util
62
+ *
63
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2022-03-24
64
+ * Copyright © 2022 Monterosa. All rights reserved.
65
+ *
66
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
67
+ */
68
+ /**
69
+ * @internal
70
+ */
71
+ const delay = async (timeout) => {
72
+ await new Promise((resolve) => setTimeout(resolve, timeout));
73
+ };
74
+
75
+ /**
76
+ * @license
77
+ * memoize-promise.ts
78
+ * util
79
+ *
80
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2022-09-20
81
+ * Copyright © 2022 Monterosa. All rights reserved.
82
+ *
83
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
84
+ */
85
+ /**
86
+ * Creates a function that memoizes the result of `func`.
87
+ *
88
+ * @internal
89
+ *
90
+ * @param func - A function that returns a promise. The results of its work will be memoized.
91
+ * @param resolver - A function that determines the cache key.
92
+ * @param config - A configuration object with the following optional properties:
93
+ * `clearOnResolve` - Deletes memoized result upon promise resolve. Defaults to `false`.
94
+ * `clearOnReject` - Deletes memoized result upon promise reject. Defaults to `true`.
95
+ */
96
+ const memoizePromise = (func, resolver, config = {}) => {
97
+ var _a, _b;
98
+ const clearOnResolve = (_a = config.clearOnResolve) !== null && _a !== void 0 ? _a : false;
99
+ const clearOnReject = (_b = config.clearOnReject) !== null && _b !== void 0 ? _b : true;
100
+ const cache = new Map();
101
+ const memoized = (...args) => {
102
+ const key = resolver(...args);
103
+ if (cache.has(key)) {
104
+ return cache.get(key);
105
+ }
106
+ const promise = func(...args);
107
+ cache.set(key, promise);
108
+ promise.then(() => clearOnResolve && cache.delete(key));
109
+ promise.catch(() => clearOnReject && cache.delete(key));
110
+ return promise;
111
+ };
112
+ memoized.cache = cache;
113
+ return memoized;
114
+ };
115
+
116
+ /**
117
+ * @license
118
+ * global.ts
119
+ * util
120
+ *
121
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2022-04-21
122
+ * Copyright © 2022 Monterosa. All rights reserved.
123
+ *
124
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
125
+ */
126
+ /* eslint no-restricted-globals: "off" */
127
+ /**
128
+ * Global object polyfill.
129
+ * Based on MDN article: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis
130
+ *
131
+ * @internal
132
+ *
133
+ * @returns typeof globalThis
134
+ */
135
+ function getGlobal() {
136
+ if (typeof self !== 'undefined') {
137
+ return self;
138
+ }
139
+ if (typeof globalThis !== 'undefined') {
140
+ return globalThis;
141
+ }
142
+ if (typeof window !== 'undefined') {
143
+ return window;
144
+ }
145
+ if (typeof global !== 'undefined') {
146
+ return global;
147
+ }
148
+ throw new Error('Unable to locate global object.');
149
+ }
150
+
151
+ /**
152
+ * @license
153
+ * storage.ts
154
+ * util
155
+ *
156
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2022-04-21
157
+ * Copyright © 2022 Monterosa. All rights reserved.
158
+ *
159
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
160
+ */
161
+ const PREFIX = 'monterosa_sdk_';
162
+ const BAIT = 'bait';
163
+ const globals = getGlobal();
164
+ /**
165
+ * @internal
166
+ */
167
+ const getKey = (name) => `${PREFIX}${name}`;
168
+ /**
169
+ * @internal
170
+ */
171
+ function getItem(key) {
172
+ return globals.localStorage.getItem(getKey(key));
173
+ }
174
+ /**
175
+ * @internal
176
+ */
177
+ function setItem(key, value) {
178
+ return globals.localStorage.setItem(getKey(key), value);
179
+ }
180
+ /**
181
+ * @internal
182
+ */
183
+ function removeItem(key) {
184
+ return globals.localStorage.removeItem(getKey(key));
185
+ }
186
+ /**
187
+ * @internal
188
+ */
189
+ function clear() {
190
+ return globals.localStorage.clear();
191
+ }
192
+ /**
193
+ * Checks locastorage availability.
194
+ * Based on MDN article: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
195
+ * and Paul Irish gists: https://gist.github.com/paulirish/5558557
196
+ *
197
+ * @internal
198
+ *
199
+ * @returns boolean
200
+ */
201
+ function checkAvailability() {
202
+ try {
203
+ setItem(BAIT, BAIT);
204
+ getItem(BAIT);
205
+ removeItem(BAIT);
206
+ return true;
207
+ }
208
+ catch (e) {
209
+ return false;
210
+ }
211
+ }
212
+
213
+ /**
214
+ * @license
215
+ * error.ts
216
+ * util
217
+ *
218
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2022-03-31
219
+ * Copyright © 2022 Monterosa. All rights reserved.
220
+ *
221
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
222
+ */
223
+ /* eslint max-classes-per-file: ["error", 2] */
224
+ /**
225
+ * MonterosaError extends the standard JavaScript `Error` object. It has
226
+ * an error code so that user can identify the error. Also it has it's own
227
+ * specific `name` "MonterosaError"
228
+ */
229
+ class MonterosaError extends Error {
230
+ /**
231
+ * @param code - Error code string
232
+ * @param message - A descriptive message for the error
233
+ */
234
+ constructor(code, message) {
235
+ super(message);
236
+ /**
237
+ * The name property represents a name for the type of error.
238
+ */
239
+ this.name = 'MonterosaError';
240
+ this.code = code;
241
+ // Fix For ES5
242
+ // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
243
+ Object.setPrototypeOf(this, MonterosaError.prototype);
244
+ }
245
+ }
246
+ /**
247
+ * @internal
248
+ */
249
+ function createError(code, messages, ...params) {
250
+ const message = messages[code](...params);
251
+ return new MonterosaError(code, message);
252
+ }
253
+
254
+ /**
255
+ * @license
256
+ * throttle.ts
257
+ * util
258
+ *
259
+ * Created by Josep Rodriguez <josep.rodriguez@monterosa.co.uk> on 2022-07-13
260
+ * Copyright © 2022 Monterosa. All rights reserved.
261
+ *
262
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
263
+ */
264
+ /* eslint-disable */
265
+ // @ts-nocheck
266
+ /**
267
+ * lodash (Custom Build) <https://lodash.com/>
268
+ * Build: `lodash modularize exports="npm" -o ./`
269
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
270
+ * Released under MIT license <https://lodash.com/license>
271
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
272
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
273
+ */
274
+ /** Used as the `TypeError` message for "Functions" methods. */
275
+ var FUNC_ERROR_TEXT = 'Expected a function';
276
+ /** Used as references for various `Number` constants. */
277
+ var NAN = 0 / 0;
278
+ /** `Object#toString` result references. */
279
+ var symbolTag = '[object Symbol]';
280
+ /** Used to match leading and trailing whitespace. */
281
+ var reTrim = /^\s+|\s+$/g;
282
+ /** Used to detect bad signed hexadecimal string values. */
283
+ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
284
+ /** Used to detect binary string values. */
285
+ var reIsBinary = /^0b[01]+$/i;
286
+ /** Used to detect octal string values. */
287
+ var reIsOctal = /^0o[0-7]+$/i;
288
+ /** Built-in method references without a dependency on `root`. */
289
+ var freeParseInt = parseInt;
290
+ /** Detect free variable `global` from Node.js. */
291
+ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
292
+ /** Detect free variable `self`. */
293
+ var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
294
+ /** Used as a reference to the global object. */
295
+ var root = freeGlobal || freeSelf || Function('return this')();
296
+ /** Used for built-in method references. */
297
+ var objectProto = Object.prototype;
298
+ /**
299
+ * Used to resolve the
300
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
301
+ * of values.
302
+ */
303
+ var objectToString = objectProto.toString;
304
+ /* Built-in method references for those with the same name as other `lodash` methods. */
305
+ var nativeMax = Math.max, nativeMin = Math.min;
306
+ /**
307
+ * Gets the timestamp of the number of milliseconds that have elapsed since
308
+ * the Unix epoch (1 January 1970 00:00:00 UTC).
309
+ *
310
+ * @static
311
+ * @memberOf _
312
+ * @since 2.4.0
313
+ * @category Date
314
+ * @returns {number} Returns the timestamp.
315
+ * @example
316
+ *
317
+ * _.defer(function(stamp) {
318
+ * console.log(_.now() - stamp);
319
+ * }, _.now());
320
+ * // => Logs the number of milliseconds it took for the deferred invocation.
321
+ */
322
+ var now$1 = function () {
323
+ return root.Date.now();
324
+ };
325
+ /**
326
+ * Creates a debounced function that delays invoking `func` until after `wait`
327
+ * milliseconds have elapsed since the last time the debounced function was
328
+ * invoked. The debounced function comes with a `cancel` method to cancel
329
+ * delayed `func` invocations and a `flush` method to immediately invoke them.
330
+ * Provide `options` to indicate whether `func` should be invoked on the
331
+ * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
332
+ * with the last arguments provided to the debounced function. Subsequent
333
+ * calls to the debounced function return the result of the last `func`
334
+ * invocation.
335
+ *
336
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
337
+ * invoked on the trailing edge of the timeout only if the debounced function
338
+ * is invoked more than once during the `wait` timeout.
339
+ *
340
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
341
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
342
+ *
343
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
344
+ * for details over the differences between `_.debounce` and `_.throttle`.
345
+ *
346
+ * @static
347
+ * @memberOf _
348
+ * @since 0.1.0
349
+ * @category Function
350
+ * @param {Function} func The function to debounce.
351
+ * @param {number} [wait=0] The number of milliseconds to delay.
352
+ * @param {Object} [options={}] The options object.
353
+ * @param {boolean} [options.leading=false]
354
+ * Specify invoking on the leading edge of the timeout.
355
+ * @param {number} [options.maxWait]
356
+ * The maximum time `func` is allowed to be delayed before it's invoked.
357
+ * @param {boolean} [options.trailing=true]
358
+ * Specify invoking on the trailing edge of the timeout.
359
+ * @returns {Function} Returns the new debounced function.
360
+ * @example
361
+ *
362
+ * // Avoid costly calculations while the window size is in flux.
363
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
364
+ *
365
+ * // Invoke `sendMail` when clicked, debouncing subsequent calls.
366
+ * jQuery(element).on('click', _.debounce(sendMail, 300, {
367
+ * 'leading': true,
368
+ * 'trailing': false
369
+ * }));
370
+ *
371
+ * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
372
+ * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
373
+ * var source = new EventSource('/stream');
374
+ * jQuery(source).on('message', debounced);
375
+ *
376
+ * // Cancel the trailing debounced invocation.
377
+ * jQuery(window).on('popstate', debounced.cancel);
378
+ */
379
+ function debounce(func, wait, options) {
380
+ var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true;
381
+ if (typeof func != 'function') {
382
+ throw new TypeError(FUNC_ERROR_TEXT);
383
+ }
384
+ wait = toNumber(wait) || 0;
385
+ if (isObject(options)) {
386
+ leading = !!options.leading;
387
+ maxing = 'maxWait' in options;
388
+ maxWait = maxing
389
+ ? nativeMax(toNumber(options.maxWait) || 0, wait)
390
+ : maxWait;
391
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
392
+ }
393
+ function invokeFunc(time) {
394
+ var args = lastArgs, thisArg = lastThis;
395
+ lastArgs = lastThis = undefined;
396
+ lastInvokeTime = time;
397
+ result = func.apply(thisArg, args);
398
+ return result;
399
+ }
400
+ function leadingEdge(time) {
401
+ // Reset any `maxWait` timer.
402
+ lastInvokeTime = time;
403
+ // Start the timer for the trailing edge.
404
+ timerId = setTimeout(timerExpired, wait);
405
+ // Invoke the leading edge.
406
+ return leading ? invokeFunc(time) : result;
407
+ }
408
+ function remainingWait(time) {
409
+ var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall;
410
+ return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
411
+ }
412
+ function shouldInvoke(time) {
413
+ var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime;
414
+ // Either this is the first call, activity has stopped and we're at the
415
+ // trailing edge, the system time has gone backwards and we're treating
416
+ // it as the trailing edge, or we've hit the `maxWait` limit.
417
+ return (lastCallTime === undefined ||
418
+ timeSinceLastCall >= wait ||
419
+ timeSinceLastCall < 0 ||
420
+ (maxing && timeSinceLastInvoke >= maxWait));
421
+ }
422
+ function timerExpired() {
423
+ var time = now$1();
424
+ if (shouldInvoke(time)) {
425
+ return trailingEdge(time);
426
+ }
427
+ // Restart the timer.
428
+ timerId = setTimeout(timerExpired, remainingWait(time));
429
+ }
430
+ function trailingEdge(time) {
431
+ timerId = undefined;
432
+ // Only invoke if we have `lastArgs` which means `func` has been
433
+ // debounced at least once.
434
+ if (trailing && lastArgs) {
435
+ return invokeFunc(time);
436
+ }
437
+ lastArgs = lastThis = undefined;
438
+ return result;
439
+ }
440
+ function cancel() {
441
+ if (timerId !== undefined) {
442
+ clearTimeout(timerId);
443
+ }
444
+ lastInvokeTime = 0;
445
+ lastArgs = lastCallTime = lastThis = timerId = undefined;
446
+ }
447
+ function flush() {
448
+ return timerId === undefined ? result : trailingEdge(now$1());
449
+ }
450
+ function debounced() {
451
+ var time = now$1(), isInvoking = shouldInvoke(time);
452
+ lastArgs = arguments;
453
+ lastThis = this;
454
+ lastCallTime = time;
455
+ if (isInvoking) {
456
+ if (timerId === undefined) {
457
+ return leadingEdge(lastCallTime);
458
+ }
459
+ if (maxing) {
460
+ // Handle invocations in a tight loop.
461
+ timerId = setTimeout(timerExpired, wait);
462
+ return invokeFunc(lastCallTime);
463
+ }
464
+ }
465
+ if (timerId === undefined) {
466
+ timerId = setTimeout(timerExpired, wait);
467
+ }
468
+ return result;
469
+ }
470
+ debounced.cancel = cancel;
471
+ debounced.flush = flush;
472
+ return debounced;
473
+ }
474
+ /**
475
+ * Creates a throttled function that only invokes `func` at most once per
476
+ * every `wait` milliseconds. The throttled function comes with a `cancel`
477
+ * method to cancel delayed `func` invocations and a `flush` method to
478
+ * immediately invoke them. Provide `options` to indicate whether `func`
479
+ * should be invoked on the leading and/or trailing edge of the `wait`
480
+ * timeout. The `func` is invoked with the last arguments provided to the
481
+ * throttled function. Subsequent calls to the throttled function return the
482
+ * result of the last `func` invocation.
483
+ *
484
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
485
+ * invoked on the trailing edge of the timeout only if the throttled function
486
+ * is invoked more than once during the `wait` timeout.
487
+ *
488
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
489
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
490
+ *
491
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
492
+ * for details over the differences between `_.throttle` and `_.debounce`.
493
+ *
494
+ * @internal
495
+ *
496
+ * @static
497
+ * @memberOf _
498
+ * @since 0.1.0
499
+ * @category Function
500
+ * @param {Function} func The function to throttle.
501
+ * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
502
+ * @param {Object} [options={}] The options object.
503
+ * @param {boolean} [options.leading=true]
504
+ * Specify invoking on the leading edge of the timeout.
505
+ * @param {boolean} [options.trailing=true]
506
+ * Specify invoking on the trailing edge of the timeout.
507
+ * @returns {Function} Returns the new throttled function.
508
+ * @example
509
+ *
510
+ * // Avoid excessively updating the position while scrolling.
511
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
512
+ *
513
+ * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
514
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
515
+ * jQuery(element).on('click', throttled);
516
+ *
517
+ * // Cancel the trailing throttled invocation.
518
+ * jQuery(window).on('popstate', throttled.cancel);
519
+ */
520
+ function throttle(func, wait, options) {
521
+ var leading = true, trailing = true;
522
+ if (typeof func != 'function') {
523
+ throw new TypeError(FUNC_ERROR_TEXT);
524
+ }
525
+ if (isObject(options)) {
526
+ leading = 'leading' in options ? !!options.leading : leading;
527
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
528
+ }
529
+ return debounce(func, wait, {
530
+ leading: leading,
531
+ maxWait: wait,
532
+ trailing: trailing,
533
+ });
534
+ }
535
+ /**
536
+ * Checks if `value` is the
537
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
538
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
539
+ *
540
+ * @static
541
+ * @memberOf _
542
+ * @since 0.1.0
543
+ * @category Lang
544
+ * @param {*} value The value to check.
545
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
546
+ * @example
547
+ *
548
+ * _.isObject({});
549
+ * // => true
550
+ *
551
+ * _.isObject([1, 2, 3]);
552
+ * // => true
553
+ *
554
+ * _.isObject(_.noop);
555
+ * // => true
556
+ *
557
+ * _.isObject(null);
558
+ * // => false
559
+ */
560
+ function isObject(value) {
561
+ var type = typeof value;
562
+ return !!value && (type == 'object' || type == 'function');
563
+ }
564
+ /**
565
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
566
+ * and has a `typeof` result of "object".
567
+ *
568
+ * @static
569
+ * @memberOf _
570
+ * @since 4.0.0
571
+ * @category Lang
572
+ * @param {*} value The value to check.
573
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
574
+ * @example
575
+ *
576
+ * _.isObjectLike({});
577
+ * // => true
578
+ *
579
+ * _.isObjectLike([1, 2, 3]);
580
+ * // => true
581
+ *
582
+ * _.isObjectLike(_.noop);
583
+ * // => false
584
+ *
585
+ * _.isObjectLike(null);
586
+ * // => false
587
+ */
588
+ function isObjectLike(value) {
589
+ return !!value && typeof value == 'object';
590
+ }
591
+ /**
592
+ * Checks if `value` is classified as a `Symbol` primitive or object.
593
+ *
594
+ * @static
595
+ * @memberOf _
596
+ * @since 4.0.0
597
+ * @category Lang
598
+ * @param {*} value The value to check.
599
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
600
+ * @example
601
+ *
602
+ * _.isSymbol(Symbol.iterator);
603
+ * // => true
604
+ *
605
+ * _.isSymbol('abc');
606
+ * // => false
607
+ */
608
+ function isSymbol(value) {
609
+ return (typeof value == 'symbol' ||
610
+ (isObjectLike(value) && objectToString.call(value) == symbolTag));
611
+ }
612
+ /**
613
+ * Converts `value` to a number.
614
+ *
615
+ * @static
616
+ * @memberOf _
617
+ * @since 4.0.0
618
+ * @category Lang
619
+ * @param {*} value The value to process.
620
+ * @returns {number} Returns the number.
621
+ * @example
622
+ *
623
+ * _.toNumber(3.2);
624
+ * // => 3.2
625
+ *
626
+ * _.toNumber(Number.MIN_VALUE);
627
+ * // => 5e-324
628
+ *
629
+ * _.toNumber(Infinity);
630
+ * // => Infinity
631
+ *
632
+ * _.toNumber('3.2');
633
+ * // => 3.2
634
+ */
635
+ function toNumber(value) {
636
+ if (typeof value == 'number') {
637
+ return value;
638
+ }
639
+ if (isSymbol(value)) {
640
+ return NAN;
641
+ }
642
+ if (isObject(value)) {
643
+ var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
644
+ value = isObject(other) ? other + '' : other;
645
+ }
646
+ if (typeof value != 'string') {
647
+ return value === 0 ? value : +value;
648
+ }
649
+ value = value.replace(reTrim, '');
650
+ var isBinary = reIsBinary.test(value);
651
+ return isBinary || reIsOctal.test(value)
652
+ ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
653
+ : reIsBadHex.test(value)
654
+ ? NAN
655
+ : +value;
656
+ }
657
+
658
+ /**
659
+ * @license
660
+ * time.ts
661
+ * util
662
+ *
663
+ * Created by Rygor Kharytanovich <rygor@monterosa.co.uk> on 2025-03-24
664
+ * Copyright © 2025 Monterosa. All rights reserved.
665
+ *
666
+ * More details on the license can be found at https://www.monterosa.co/sdk/license
667
+ */
668
+ const emitter = new Emitter();
669
+ let serverTimestamp = 0;
670
+ let lastTickTimestamp = 0;
671
+ let tickTimeoutId;
672
+ /**
673
+ * Returns local timestamp in seconds
674
+ */
675
+ function getCurrentTimestamp() {
676
+ return Date.now() / 1000;
677
+ }
678
+ /**
679
+ * Normalizes the timestamp to reduce fluctuations due to `setTimeout` delays.
680
+ * Ensures the fractional part is around 0.5 to avoid skipping a second.
681
+ *
682
+ * Returns half-second timestamp. It is used to be sure that timestamp will not
683
+ * fluctuate more than in 1 second after each tick due to longer delays.
684
+ * https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified
685
+ *
686
+ * For example if the initial timestamp has a fractional part 0.9999 then with
687
+ * the setTimeout (tick) longer than specified we might jump over a one second.
688
+ * Lets imaging setTimeout took 1.0002 second, then our timestamp will be 2.0001.
689
+ * Thats why we are trying to keep fractional part in the middle of the second.
690
+ */
691
+ function getMiddleTimestamp(timestamp) {
692
+ return Math.floor(timestamp) + 0.5;
693
+ }
694
+ /**
695
+ * Calculates the delay for the next tick to keep timestamps stable.
696
+ */
697
+ function calculateNextTickDelay() {
698
+ const expectedNextTick = getMiddleTimestamp(serverTimestamp) + 1;
699
+ return (expectedNextTick - serverTimestamp) * 1000;
700
+ }
701
+ /**
702
+ * Main function that maintains current timestamp
703
+ */
704
+ function tick() {
705
+ clearTimeout(tickTimeoutId);
706
+ const currentTimestamp = getCurrentTimestamp();
707
+ const timeSinceLastTick = currentTimestamp - lastTickTimestamp;
708
+ serverTimestamp += timeSinceLastTick;
709
+ lastTickTimestamp = currentTimestamp;
710
+ tickTimeoutId = setTimeout(tick, calculateNextTickDelay());
711
+ emitter.emit('tick', serverTimestamp);
712
+ }
713
+ /**
714
+ * @internal
715
+ *
716
+ * Sets or updates current timestamp
717
+ *
718
+ * @param timestamp - Current timestamp in seconds
719
+ */
720
+ function setTimestamp(timestamp) {
721
+ lastTickTimestamp = getCurrentTimestamp();
722
+ serverTimestamp = getMiddleTimestamp(timestamp);
723
+ }
724
+ /**
725
+ * Returns current timestamp that is preserved by `tick()` function
726
+ *
727
+ * @returns Current timestamp in seconds
728
+ */
729
+ function now() {
730
+ return Math.floor(serverTimestamp);
731
+ }
732
+ /**
733
+ * Subscribes listener to the timestamp increment
734
+ *
735
+ * @param callback - A handler that executes when the timestamp is incremented
736
+ *
737
+ * @returns A function that unsubscribes the listener
738
+ */
739
+ function onTick(callback) {
740
+ return subscribe(emitter, 'tick', callback);
741
+ }
742
+ // Initially timestamp is set based on a local date
743
+ // Later on it can be overriden outside at any moment
744
+ // in our case it is populated with the server timestamp
745
+ // which comes from Enmasse session handshake message
746
+ setTimestamp(getCurrentTimestamp());
747
+ // Kicking in timestamp maintaining
748
+ tick();
749
+
750
+ export { Emitter, MonterosaError, checkAvailability, clear, createError, delay, getGlobal, getItem, getKey, memoizePromise, now, onTick, removeItem, setItem, setTimestamp, subscribe, throttle, tick };
751
+ //# sourceMappingURL=index.esm2017.js.map