smart-load-manager 1.0.0

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/dist/index.cjs ADDED
@@ -0,0 +1,394 @@
1
+ 'use strict';
2
+
3
+ var decorators_js = require('@exadel/esl/modules/esl-utils/decorators.js');
4
+ var async_js = require('@exadel/esl/modules/esl-utils/async.js');
5
+ var dom_js = require('@exadel/esl/modules/esl-utils/dom.js');
6
+
7
+ var __defProp$2 = Object.defineProperty;
8
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
10
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
11
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
12
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __spreadValues$1 = (a, b) => {
14
+ for (var prop in b || (b = {}))
15
+ if (__hasOwnProp$1.call(b, prop))
16
+ __defNormalProp$1(a, prop, b[prop]);
17
+ if (__getOwnPropSymbols$1)
18
+ for (var prop of __getOwnPropSymbols$1(b)) {
19
+ if (__propIsEnum$1.call(b, prop))
20
+ __defNormalProp$1(a, prop, b[prop]);
21
+ }
22
+ return a;
23
+ };
24
+ var __decorateClass$1 = (decorators, target, key, kind) => {
25
+ var result = __getOwnPropDesc$1(target, key) ;
26
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
27
+ if (decorator = decorators[i])
28
+ result = (decorator(target, key, result) ) || result;
29
+ if (result) __defProp$2(target, key, result);
30
+ return result;
31
+ };
32
+ var __async$2 = (__this, __arguments, generator) => {
33
+ return new Promise((resolve, reject) => {
34
+ var fulfilled = (value) => {
35
+ try {
36
+ step(generator.next(value));
37
+ } catch (e) {
38
+ reject(e);
39
+ }
40
+ };
41
+ var rejected = (value) => {
42
+ try {
43
+ step(generator.throw(value));
44
+ } catch (e) {
45
+ reject(e);
46
+ }
47
+ };
48
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
49
+ step((generator = generator.apply(__this, __arguments)).next());
50
+ });
51
+ };
52
+ function applyEarlyHints(options) {
53
+ const link = document.createElement("link");
54
+ link.rel = options.rel;
55
+ options.attrs && Object.entries(options.attrs).forEach(([name, value]) => dom_js.setAttr(link, name, value));
56
+ link.href = options.href;
57
+ document.head.appendChild(link);
58
+ }
59
+ class SmartService {
60
+ constructor(_config) {
61
+ this._config = _config;
62
+ this._loaded = false;
63
+ this._mutex = Promise.resolve();
64
+ }
65
+ static config(options) {
66
+ if (options) this._config = __spreadValues$1(__spreadValues$1({}, this._config), options);
67
+ return this._config;
68
+ }
69
+ /** Create a new instance of SmartService */
70
+ static create(options) {
71
+ return new this(options);
72
+ }
73
+ /** Get the singleton instance of SmartService */
74
+ static get instance() {
75
+ if (!this._instance) {
76
+ this._instance = new this(this._config);
77
+ }
78
+ return this._instance;
79
+ }
80
+ /** Get the load method of the singleton instance */
81
+ static get load() {
82
+ return this.instance.load;
83
+ }
84
+ /** Setup Early Hints for the service */
85
+ static setupEarlyHints(options) {
86
+ return () => {
87
+ setTimeout(() => options.forEach(applyEarlyHints), 1);
88
+ return Promise.resolve();
89
+ };
90
+ }
91
+ /** Get the preload method of the singleton instance */
92
+ static get preload() {
93
+ return this.instance.preload;
94
+ }
95
+ /** Check if the service is loaded */
96
+ get isLoaded() {
97
+ return this._loaded;
98
+ }
99
+ /** Get the current mutex promise */
100
+ get mutex() {
101
+ return this._mutex;
102
+ }
103
+ /** Set a new mutex promise */
104
+ set mutex(value) {
105
+ this._debug("new Mutex: ", this._config.name, value);
106
+ this._mutex = value;
107
+ }
108
+ load() {
109
+ return __async$2(this, null, function* () {
110
+ this._debug("Service load() enter: ", this._config.name, this);
111
+ if (!this._state) {
112
+ this._state = this._loadTask();
113
+ }
114
+ return this._state;
115
+ });
116
+ }
117
+ preload() {
118
+ return __async$2(this, null, function* () {
119
+ this._debug("Service preload(): ", this._config.name);
120
+ const { url, attrs } = this._config;
121
+ if (url) setTimeout(applyEarlyHints.bind(null, { rel: "preload", href: url, attrs: __spreadValues$1({ as: "script" }, attrs) }), 1);
122
+ return Promise.resolve();
123
+ });
124
+ }
125
+ _loadTask() {
126
+ return __async$2(this, null, function* () {
127
+ try {
128
+ yield this._mutex;
129
+ this._debug("Service loading started: ", this._config.name);
130
+ if (!this._config.name) throw new Error("Service name is not specified");
131
+ if (!this._config.url) throw new Error("Service URL is not specified");
132
+ const id = (this._config.name || "").replace(/\s+/g, "").toLowerCase();
133
+ yield dom_js.loadScript(`smart-${id}-script`, this._config.url, this._config.attrs);
134
+ this._onLoadScript();
135
+ return true;
136
+ } catch (e) {
137
+ this._onFailedScript(e);
138
+ return Promise.reject(false);
139
+ }
140
+ });
141
+ }
142
+ _onLoadScript() {
143
+ this._debug("Service script loaded: ", this._config.name);
144
+ this._loaded = true;
145
+ }
146
+ _onFailedScript(e) {
147
+ console.error(`Failed to load ${this._config.name} script`, e instanceof Error ? `: ${e.message}` : "");
148
+ }
149
+ _debug(...args) {
150
+ if (!this._config.debug) return;
151
+ console.log(...args);
152
+ }
153
+ }
154
+ SmartService._config = {
155
+ name: "service",
156
+ debug: false
157
+ };
158
+ __decorateClass$1([
159
+ decorators_js.bind
160
+ ], SmartService.prototype, "load");
161
+ __decorateClass$1([
162
+ decorators_js.bind
163
+ ], SmartService.prototype, "preload");
164
+
165
+ var __defProp$1 = Object.defineProperty;
166
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
167
+ var __decorateClass = (decorators, target, key, kind) => {
168
+ var result = __getOwnPropDesc(target, key) ;
169
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
170
+ if (decorator = decorators[i])
171
+ result = (decorator(target, key, result) ) || result;
172
+ if (result) __defProp$1(target, key, result);
173
+ return result;
174
+ };
175
+ var __async$1 = (__this, __arguments, generator) => {
176
+ return new Promise((resolve, reject) => {
177
+ var fulfilled = (value) => {
178
+ try {
179
+ step(generator.next(value));
180
+ } catch (e) {
181
+ reject(e);
182
+ }
183
+ };
184
+ var rejected = (value) => {
185
+ try {
186
+ step(generator.throw(value));
187
+ } catch (e) {
188
+ reject(e);
189
+ }
190
+ };
191
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
192
+ step((generator = generator.apply(__this, __arguments)).next());
193
+ });
194
+ };
195
+ function onReadyState(readyPredicate) {
196
+ return new Promise((resolve) => {
197
+ if (readyPredicate()) {
198
+ resolve();
199
+ } else {
200
+ const handler = () => {
201
+ if (readyPredicate()) {
202
+ document.removeEventListener("readystatechange", handler);
203
+ resolve();
204
+ }
205
+ };
206
+ document.addEventListener("readystatechange", handler);
207
+ }
208
+ });
209
+ }
210
+ class SmartLoad {
211
+ static defaultMutex() {
212
+ return this.createMutex(this.now);
213
+ }
214
+ static now() {
215
+ return Promise.resolve();
216
+ }
217
+ static onLoaded() {
218
+ return onReadyState(() => document.readyState !== "loading");
219
+ }
220
+ static onComplete() {
221
+ return onReadyState(() => document.readyState === "complete");
222
+ }
223
+ static createMutex(previousTask) {
224
+ return new Promise((resolve) => {
225
+ (() => __async$1(this, null, function* () {
226
+ try {
227
+ yield this._whenStarted.promise;
228
+ yield previousTask();
229
+ } catch (e) {
230
+ } finally {
231
+ resolve();
232
+ }
233
+ }))();
234
+ });
235
+ }
236
+ /** Queue a service to be loaded after the given task */
237
+ static queue(service, after = this.defaultMutex.bind(this)) {
238
+ const serviceInstance = service instanceof SmartService ? service : service.instance;
239
+ serviceInstance.mutex = this.createMutex(after);
240
+ serviceInstance.load().catch(() => void 0);
241
+ }
242
+ /** Start the smart loading process */
243
+ static start() {
244
+ this._whenStarted.resolve();
245
+ }
246
+ }
247
+ SmartLoad._whenStarted = async_js.createDeferred();
248
+ __decorateClass([
249
+ decorators_js.memoize()
250
+ ], SmartLoad, "defaultMutex");
251
+ __decorateClass([
252
+ decorators_js.memoize()
253
+ ], SmartLoad, "now");
254
+ __decorateClass([
255
+ decorators_js.memoize()
256
+ ], SmartLoad, "onLoaded");
257
+ __decorateClass([
258
+ decorators_js.memoize()
259
+ ], SmartLoad, "onComplete");
260
+
261
+ var __defProp = Object.defineProperty;
262
+ var __defProps = Object.defineProperties;
263
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
264
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
265
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
266
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
267
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
268
+ var __spreadValues = (a, b) => {
269
+ for (var prop in b || (b = {}))
270
+ if (__hasOwnProp.call(b, prop))
271
+ __defNormalProp(a, prop, b[prop]);
272
+ if (__getOwnPropSymbols)
273
+ for (var prop of __getOwnPropSymbols(b)) {
274
+ if (__propIsEnum.call(b, prop))
275
+ __defNormalProp(a, prop, b[prop]);
276
+ }
277
+ return a;
278
+ };
279
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
280
+ var __async = (__this, __arguments, generator) => {
281
+ return new Promise((resolve, reject) => {
282
+ var fulfilled = (value) => {
283
+ try {
284
+ step(generator.next(value));
285
+ } catch (e) {
286
+ reject(e);
287
+ }
288
+ };
289
+ var rejected = (value) => {
290
+ try {
291
+ step(generator.throw(value));
292
+ } catch (e) {
293
+ reject(e);
294
+ }
295
+ };
296
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
297
+ step((generator = generator.apply(__this, __arguments)).next());
298
+ });
299
+ };
300
+ const IDLE_THRESHOLD_DURATION = 46.6;
301
+ const IDLE_THRESHOLD_RATIO = 0.9;
302
+ const IDLE_TIMEOUT = 1e4;
303
+ function promisifyIdle(options = {}) {
304
+ var _a, _b;
305
+ const idleThresholdRatio = ((_a = options.thresholds) == null ? void 0 : _a.ratio) || IDLE_THRESHOLD_RATIO;
306
+ const idleThresholdDuration = ((_b = options.thresholds) == null ? void 0 : _b.duration) || IDLE_THRESHOLD_DURATION;
307
+ const idleTimeout = options.timeout || IDLE_TIMEOUT;
308
+ const { debug, signal } = options;
309
+ debug && performance.mark("idle.S");
310
+ return new Promise((resolve, reject) => {
311
+ const start = performance.now();
312
+ let previousFrameEnd = start;
313
+ const log = [];
314
+ const last3 = [0, 0, 0];
315
+ function finish(withResolve, reason) {
316
+ if (debug) {
317
+ console.table(log);
318
+ console.log(`Idle has ${withResolve ? "reached" : "aborted"} after ${performance.now() - start}ms`);
319
+ performance.mark("idle.E");
320
+ performance.measure("idlePromisify", "idle.S", "idle.E");
321
+ }
322
+ return withResolve ? resolve(true) : reject(reason);
323
+ }
324
+ const cb = (deadline) => {
325
+ if (signal == null ? void 0 : signal.aborted) return finish(false, new Error("Rejected by abort signal"));
326
+ const allocated = deadline.timeRemaining();
327
+ const frameEnd = performance.now() + allocated;
328
+ const frameLength = frameEnd - previousFrameEnd;
329
+ const idleRatio = allocated / frameLength;
330
+ const timeout = Math.max(0, idleTimeout - (performance.now() - start));
331
+ const isBadFrame = frameLength < 15;
332
+ if (!isBadFrame) {
333
+ last3.splice(0, 1);
334
+ last3.push(idleRatio > idleThresholdRatio ? allocated : 0);
335
+ }
336
+ const isIdleNow = last3.reduce((acc, val) => acc + val, 0) > idleThresholdDuration;
337
+ debug && !isBadFrame && log.push([timeout, frameLength, allocated, idleRatio, idleRatio > idleThresholdRatio ? 1 : 0, last3.toString()]);
338
+ if (isIdleNow || deadline.didTimeout) return finish(true);
339
+ !isBadFrame && (previousFrameEnd = frameEnd);
340
+ requestIdleCallback(cb, { timeout });
341
+ };
342
+ requestIdleCallback(cb, { timeout: idleTimeout });
343
+ });
344
+ }
345
+ function asyncSeries(tasks) {
346
+ return __async(this, null, function* () {
347
+ for (const task of tasks) {
348
+ yield task().catch();
349
+ }
350
+ });
351
+ }
352
+ function waitAny(tasks, signal) {
353
+ return (abortSignal) => __async(null, null, function* () {
354
+ const activeSignal = signal != null ? signal : abortSignal;
355
+ if (activeSignal) {
356
+ yield Promise.race(tasks.map((task) => task(activeSignal)));
357
+ return;
358
+ }
359
+ const controller = new AbortController();
360
+ try {
361
+ yield Promise.race(tasks.map((task) => task(controller.signal)));
362
+ } finally {
363
+ controller.abort();
364
+ }
365
+ });
366
+ }
367
+ function waitTimeout(timeout) {
368
+ return () => __async(null, null, function* () {
369
+ return async_js.promisifyTimeout(timeout);
370
+ });
371
+ }
372
+ const USER_ACTIVITY_EVENTS = ["keydown", "mousemove", "pointerdown", "wheel"];
373
+ function waitUserActivity() {
374
+ return (abortSignal) => __async(null, null, function* () {
375
+ yield waitAny(
376
+ USER_ACTIVITY_EVENTS.map((event) => (signal) => async_js.promisifyEvent(document, event, null, { passive: true, signal })),
377
+ abortSignal
378
+ )();
379
+ });
380
+ }
381
+ function waitIdle(options = {}) {
382
+ return (abortSignal) => __async(null, null, function* () {
383
+ return promisifyIdle(__spreadProps(__spreadValues({}, options), { signal: abortSignal }));
384
+ });
385
+ }
386
+
387
+ exports.SmartLoad = SmartLoad;
388
+ exports.SmartService = SmartService;
389
+ exports.asyncSeries = asyncSeries;
390
+ exports.promisifyIdle = promisifyIdle;
391
+ exports.waitAny = waitAny;
392
+ exports.waitIdle = waitIdle;
393
+ exports.waitTimeout = waitTimeout;
394
+ exports.waitUserActivity = waitUserActivity;
@@ -0,0 +1,144 @@
1
+ import * as _exadel_esl_modules_esl_utils_async from '@exadel/esl/modules/esl-utils/async';
2
+ import { LoadScriptAttributes } from '@exadel/esl/modules/esl-utils/dom';
3
+
4
+ /** Configuration options for SmartService */
5
+ interface SmartServiceOptions {
6
+ /** Service name */
7
+ name?: string;
8
+ /** Service URL */
9
+ url?: string;
10
+ /** Attributes for the script element */
11
+ attrs?: LoadScriptAttributes;
12
+ /** Enable debug logging */
13
+ debug?: boolean;
14
+ }
15
+ /** Attributes for Early Hints link elements */
16
+ interface EarlyHintsAttributes {
17
+ /** 'as' attribute value */
18
+ as?: string;
19
+ /** 'crossorigin' attribute value */
20
+ crossorigin?: string | boolean | null;
21
+ }
22
+ /** Options for Early Hints link elements */
23
+ interface EarlyHintsOptions {
24
+ /** Link element relationship type */
25
+ rel: 'dns-prefetch' | 'preconnect' | 'prefetch' | 'preload' | 'prerender';
26
+ /** Link element href */
27
+ href: string;
28
+ /** Additional attributes for the link element */
29
+ attrs?: EarlyHintsAttributes;
30
+ }
31
+ /** Base class for smart services that load external scripts */
32
+ declare class SmartService {
33
+ protected _config: SmartServiceOptions;
34
+ protected static _config: SmartServiceOptions;
35
+ protected static _instance: SmartService;
36
+ /** Get or set the service configuration */
37
+ static config<T>(options?: T): T;
38
+ /** Create a new instance of SmartService */
39
+ static create(options: SmartServiceOptions): SmartService;
40
+ /** Get the singleton instance of SmartService */
41
+ static get instance(): SmartService;
42
+ /** Get the load method of the singleton instance */
43
+ static get load(): () => Promise<boolean>;
44
+ /** Setup Early Hints for the service */
45
+ static setupEarlyHints(options: EarlyHintsOptions[]): () => Promise<void>;
46
+ /** Get the preload method of the singleton instance */
47
+ static get preload(): () => Promise<void>;
48
+ protected _loaded: boolean;
49
+ protected _mutex: Promise<void>;
50
+ protected _state: Promise<boolean>;
51
+ protected constructor(_config: SmartServiceOptions);
52
+ /** Check if the service is loaded */
53
+ get isLoaded(): boolean;
54
+ /** Get the current mutex promise */
55
+ get mutex(): Promise<void>;
56
+ /** Set a new mutex promise */
57
+ set mutex(value: Promise<void>);
58
+ /** Load the service script */
59
+ load(): Promise<boolean>;
60
+ /** Preload the service script using Early Hints */
61
+ preload(): Promise<void>;
62
+ protected _loadTask(): Promise<boolean>;
63
+ protected _onLoadScript(): void;
64
+ protected _onFailedScript(e?: Error): void;
65
+ protected _debug(...args: unknown[]): void;
66
+ }
67
+
68
+ /** Manager for smart loading of services */
69
+ declare class SmartLoad {
70
+ protected static _whenStarted: _exadel_esl_modules_esl_utils_async.Deferred<void>;
71
+ /** Get the default mutex promise which resolves immediately */
72
+ static defaultMutex(): Promise<void>;
73
+ /** No wait and resolve immediately */
74
+ static now(): Promise<void>;
75
+ /** Wait until the document is at least interactive and then resolve */
76
+ static onLoaded(): Promise<void>;
77
+ /** Wait until the document is fully loaded and then resolve */
78
+ static onComplete(): Promise<void>;
79
+ protected static createMutex(previousTask: () => Promise<unknown>): Promise<void>;
80
+ /** Queue a service to be loaded after the given task */
81
+ static queue(service: typeof SmartService | SmartService, after?: () => Promise<unknown>): void;
82
+ /** Start the smart loading process */
83
+ static start(): void;
84
+ }
85
+
86
+ type AsyncTask = () => Promise<unknown>;
87
+ type WaitTask = (signal?: AbortSignal) => Promise<unknown>;
88
+ /** Options for promisifyIdle function */
89
+ interface PromisifyIdleOptions {
90
+ /** Thresholds to determine idle state */
91
+ thresholds?: {
92
+ /** Total idle time threshold in ms */
93
+ duration?: number;
94
+ /** Idle time to frame time ratio threshold */
95
+ ratio?: number;
96
+ };
97
+ /** Maximum timeout in ms */
98
+ timeout?: number;
99
+ /** Enable debug logging */
100
+ debug?: boolean;
101
+ /** AbortSignal to cancel the idle detection */
102
+ signal?: AbortSignal;
103
+ }
104
+ /** Promisify requestIdleCallback with enhanced idle detection
105
+ * The promise resolves when the browser is considered idle based on:
106
+ * - ratio of idle time to frame time over a series of frames
107
+ * - total idle time accumulated over a series of frames
108
+ * - maximum timeout
109
+ *
110
+ * @param options - Configuration options for idle detection
111
+ * @returns Promise that resolves when idle state is reached or rejects on abort
112
+ */
113
+ declare function promisifyIdle(options?: PromisifyIdleOptions): Promise<any>;
114
+ /** Executes asynchronous tasks in series
115
+ * Each task starts after the previous one has completed.
116
+ *
117
+ * @param tasks - Array of asynchronous tasks to execute
118
+ * @returns Promise that resolves when all tasks have completed
119
+ */
120
+ declare function asyncSeries(tasks: AsyncTask[]): Promise<void>;
121
+ /** Executes multiple wait tasks in parallel
122
+ * Resolves when any of the tasks completes.
123
+ *
124
+ * @param tasks - Array of wait tasks to execute
125
+ * @param signal - Optional AbortSignal to cancel the wait
126
+ * @returns A wait task that resolves when any of the input tasks completes
127
+ */
128
+ declare function waitAny(tasks: WaitTask[], signal?: AbortSignal): WaitTask;
129
+ /** Creates a wait task that resolves after a specified timeout
130
+ *
131
+ * @param timeout - The timeout duration in milliseconds
132
+ * @returns A wait task that resolves after the specified timeout
133
+ */
134
+ declare function waitTimeout(timeout: number): WaitTask;
135
+ declare function waitUserActivity(): WaitTask;
136
+ /** Creates a wait task that resolves when the browser is idle
137
+ *
138
+ * @param options - Configuration options for idle detection
139
+ * @returns A wait task that resolves when the browser is idle
140
+ */
141
+ declare function waitIdle(options?: PromisifyIdleOptions): WaitTask;
142
+
143
+ export { SmartLoad, SmartService, asyncSeries, promisifyIdle, waitAny, waitIdle, waitTimeout, waitUserActivity };
144
+ export type { EarlyHintsAttributes, EarlyHintsOptions, PromisifyIdleOptions, SmartServiceOptions };
@@ -0,0 +1,144 @@
1
+ import * as _exadel_esl_modules_esl_utils_async from '@exadel/esl/modules/esl-utils/async';
2
+ import { LoadScriptAttributes } from '@exadel/esl/modules/esl-utils/dom';
3
+
4
+ /** Configuration options for SmartService */
5
+ interface SmartServiceOptions {
6
+ /** Service name */
7
+ name?: string;
8
+ /** Service URL */
9
+ url?: string;
10
+ /** Attributes for the script element */
11
+ attrs?: LoadScriptAttributes;
12
+ /** Enable debug logging */
13
+ debug?: boolean;
14
+ }
15
+ /** Attributes for Early Hints link elements */
16
+ interface EarlyHintsAttributes {
17
+ /** 'as' attribute value */
18
+ as?: string;
19
+ /** 'crossorigin' attribute value */
20
+ crossorigin?: string | boolean | null;
21
+ }
22
+ /** Options for Early Hints link elements */
23
+ interface EarlyHintsOptions {
24
+ /** Link element relationship type */
25
+ rel: 'dns-prefetch' | 'preconnect' | 'prefetch' | 'preload' | 'prerender';
26
+ /** Link element href */
27
+ href: string;
28
+ /** Additional attributes for the link element */
29
+ attrs?: EarlyHintsAttributes;
30
+ }
31
+ /** Base class for smart services that load external scripts */
32
+ declare class SmartService {
33
+ protected _config: SmartServiceOptions;
34
+ protected static _config: SmartServiceOptions;
35
+ protected static _instance: SmartService;
36
+ /** Get or set the service configuration */
37
+ static config<T>(options?: T): T;
38
+ /** Create a new instance of SmartService */
39
+ static create(options: SmartServiceOptions): SmartService;
40
+ /** Get the singleton instance of SmartService */
41
+ static get instance(): SmartService;
42
+ /** Get the load method of the singleton instance */
43
+ static get load(): () => Promise<boolean>;
44
+ /** Setup Early Hints for the service */
45
+ static setupEarlyHints(options: EarlyHintsOptions[]): () => Promise<void>;
46
+ /** Get the preload method of the singleton instance */
47
+ static get preload(): () => Promise<void>;
48
+ protected _loaded: boolean;
49
+ protected _mutex: Promise<void>;
50
+ protected _state: Promise<boolean>;
51
+ protected constructor(_config: SmartServiceOptions);
52
+ /** Check if the service is loaded */
53
+ get isLoaded(): boolean;
54
+ /** Get the current mutex promise */
55
+ get mutex(): Promise<void>;
56
+ /** Set a new mutex promise */
57
+ set mutex(value: Promise<void>);
58
+ /** Load the service script */
59
+ load(): Promise<boolean>;
60
+ /** Preload the service script using Early Hints */
61
+ preload(): Promise<void>;
62
+ protected _loadTask(): Promise<boolean>;
63
+ protected _onLoadScript(): void;
64
+ protected _onFailedScript(e?: Error): void;
65
+ protected _debug(...args: unknown[]): void;
66
+ }
67
+
68
+ /** Manager for smart loading of services */
69
+ declare class SmartLoad {
70
+ protected static _whenStarted: _exadel_esl_modules_esl_utils_async.Deferred<void>;
71
+ /** Get the default mutex promise which resolves immediately */
72
+ static defaultMutex(): Promise<void>;
73
+ /** No wait and resolve immediately */
74
+ static now(): Promise<void>;
75
+ /** Wait until the document is at least interactive and then resolve */
76
+ static onLoaded(): Promise<void>;
77
+ /** Wait until the document is fully loaded and then resolve */
78
+ static onComplete(): Promise<void>;
79
+ protected static createMutex(previousTask: () => Promise<unknown>): Promise<void>;
80
+ /** Queue a service to be loaded after the given task */
81
+ static queue(service: typeof SmartService | SmartService, after?: () => Promise<unknown>): void;
82
+ /** Start the smart loading process */
83
+ static start(): void;
84
+ }
85
+
86
+ type AsyncTask = () => Promise<unknown>;
87
+ type WaitTask = (signal?: AbortSignal) => Promise<unknown>;
88
+ /** Options for promisifyIdle function */
89
+ interface PromisifyIdleOptions {
90
+ /** Thresholds to determine idle state */
91
+ thresholds?: {
92
+ /** Total idle time threshold in ms */
93
+ duration?: number;
94
+ /** Idle time to frame time ratio threshold */
95
+ ratio?: number;
96
+ };
97
+ /** Maximum timeout in ms */
98
+ timeout?: number;
99
+ /** Enable debug logging */
100
+ debug?: boolean;
101
+ /** AbortSignal to cancel the idle detection */
102
+ signal?: AbortSignal;
103
+ }
104
+ /** Promisify requestIdleCallback with enhanced idle detection
105
+ * The promise resolves when the browser is considered idle based on:
106
+ * - ratio of idle time to frame time over a series of frames
107
+ * - total idle time accumulated over a series of frames
108
+ * - maximum timeout
109
+ *
110
+ * @param options - Configuration options for idle detection
111
+ * @returns Promise that resolves when idle state is reached or rejects on abort
112
+ */
113
+ declare function promisifyIdle(options?: PromisifyIdleOptions): Promise<any>;
114
+ /** Executes asynchronous tasks in series
115
+ * Each task starts after the previous one has completed.
116
+ *
117
+ * @param tasks - Array of asynchronous tasks to execute
118
+ * @returns Promise that resolves when all tasks have completed
119
+ */
120
+ declare function asyncSeries(tasks: AsyncTask[]): Promise<void>;
121
+ /** Executes multiple wait tasks in parallel
122
+ * Resolves when any of the tasks completes.
123
+ *
124
+ * @param tasks - Array of wait tasks to execute
125
+ * @param signal - Optional AbortSignal to cancel the wait
126
+ * @returns A wait task that resolves when any of the input tasks completes
127
+ */
128
+ declare function waitAny(tasks: WaitTask[], signal?: AbortSignal): WaitTask;
129
+ /** Creates a wait task that resolves after a specified timeout
130
+ *
131
+ * @param timeout - The timeout duration in milliseconds
132
+ * @returns A wait task that resolves after the specified timeout
133
+ */
134
+ declare function waitTimeout(timeout: number): WaitTask;
135
+ declare function waitUserActivity(): WaitTask;
136
+ /** Creates a wait task that resolves when the browser is idle
137
+ *
138
+ * @param options - Configuration options for idle detection
139
+ * @returns A wait task that resolves when the browser is idle
140
+ */
141
+ declare function waitIdle(options?: PromisifyIdleOptions): WaitTask;
142
+
143
+ export { SmartLoad, SmartService, asyncSeries, promisifyIdle, waitAny, waitIdle, waitTimeout, waitUserActivity };
144
+ export type { EarlyHintsAttributes, EarlyHintsOptions, PromisifyIdleOptions, SmartServiceOptions };