@quietsapa/qsl 0.1.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/qsl.mjs ADDED
@@ -0,0 +1,1800 @@
1
+ const core = {
2
+ /**
3
+ * Constants
4
+ */
5
+ VERSION: "0.1.0",
6
+ PREFIX: "qsl-",
7
+ FLOW_TYPE: {
8
+ DEFAULT: "default",
9
+ ORDERED: "ordered"
10
+ },
11
+ FLOW_STATE: {
12
+ READY: "READY",
13
+ RUNNING: "RUNNING",
14
+ COMPLETED: "COMPLETED"
15
+ },
16
+ FLOW_OPTIONS: {
17
+ delay: 0,
18
+ priority: 0,
19
+ between: null,
20
+ trigger: null,
21
+ condition: null,
22
+ beforeStart: null,
23
+ onComplete: null,
24
+ group: null,
25
+ paused: false,
26
+ preload: false,
27
+ fireEvents: true,
28
+ depends: []
29
+ },
30
+ EVENTS: {
31
+ STARTED: "QSL:started",
32
+ COMPLETED: "QSL:completed",
33
+ ERROR: "QSL:error",
34
+ FLOW_STARTED: "QSL:flow:started",
35
+ FLOW_COMPLETED: "QSL:flow:completed",
36
+ ALL_COMPLETED: "QSL:all:completed",
37
+ SKIPPED: "QSL:skipped",
38
+ DOMREADY: "QSL:domready",
39
+ LOADED: "QSL:loaded"
40
+ },
41
+ LIFECYCLE: {
42
+ DOMREADY: document.readyState === "interactive" || document.readyState === "complete",
43
+ LOADED: false
44
+ },
45
+ CALLBACK: "QSLReady",
46
+ /**
47
+ * Properties
48
+ */
49
+ types: /* @__PURE__ */ new Map(),
50
+ // Map to store custom resource types
51
+ flows: /* @__PURE__ */ new Map(),
52
+ // Map to store flows
53
+ flowOptions: /* @__PURE__ */ new Map(),
54
+ // Map to store flow options
55
+ flowGroups: /* @__PURE__ */ new Map(),
56
+ // Map to store flow groups
57
+ currentProcessPerFlow: /* @__PURE__ */ new Map(),
58
+ // Map to store current process per flow (flowId -> processId)
59
+ pendingFlows: /* @__PURE__ */ new Set(),
60
+ // Set to store pending flows
61
+ pendingProcesses: /* @__PURE__ */ new Set(),
62
+ // Set to store pending processes
63
+ completedProcesses: /* @__PURE__ */ new Set(),
64
+ // Set to store completed processes
65
+ loadActions: /* @__PURE__ */ new Set(),
66
+ // Set to store before load triggers
67
+ initActions: /* @__PURE__ */ new Set(),
68
+ // Set to store init triggers
69
+ addProcessFilters: /* @__PURE__ */ new Set(),
70
+ // Set to store add triggers
71
+ completedFlowsActions: /* @__PURE__ */ new Set(),
72
+ // Set to store completed flows actions
73
+ flowIdFilters: /* @__PURE__ */ new Set(),
74
+ // Set to store flowId filters
75
+ conditionHandlers: /* @__PURE__ */ new Set(),
76
+ // Set to store condition handlers
77
+ triggerHandlers: /* @__PURE__ */ new Set(),
78
+ // Set to store trigger handlers
79
+ processCompleteActions: /* @__PURE__ */ new Set(),
80
+ // Set to store process completion actions
81
+ allCompleteActions: /* @__PURE__ */ new Set(),
82
+ // Set to store all flows completion actions
83
+ resetActions: /* @__PURE__ */ new Set(),
84
+ // Set to store reset actions
85
+ handlerCallbacksFilters: /* @__PURE__ */ new Set(),
86
+ // Set to store handler callbacks filters
87
+ onAllComplete: null,
88
+ // Callback for all flows completion
89
+ globalResolve: null,
90
+ // Global resolve function
91
+ logger: null,
92
+ // Logger instance
93
+ hasStarted: false,
94
+ // Flag to check if QSL has started,
95
+ eventsEnabled: false,
96
+ // Flag to check if events are enabled
97
+ initialized: false,
98
+ // Flag to check if QSL is initialized
99
+ completing: false,
100
+ // Flag to check if QSL is completing
101
+ autoReset: true,
102
+ // Whether reset() runs automatically once every flow completes
103
+ globalBetween: 0,
104
+ // Global delay between processes
105
+ /**
106
+ * Initialize the QSL library.
107
+ * @returns {Promise<this>}
108
+ */
109
+ async init() {
110
+ if (this.initialized) return this;
111
+ window.__QSL__ = window.__QSL__ || this;
112
+ if (document.readyState === "interactive" || document.readyState === "complete") {
113
+ this.LIFECYCLE.DOMREADY = true;
114
+ } else {
115
+ document.addEventListener("DOMContentLoaded", () => this.LIFECYCLE.DOMREADY = true, { once: true });
116
+ }
117
+ if (document.readyState === "complete") {
118
+ this.LIFECYCLE.LOADED = true;
119
+ } else {
120
+ window.addEventListener("load", () => this.LIFECYCLE.LOADED = true, { once: true });
121
+ }
122
+ this.registerType("console", (process) => {
123
+ return new Promise((resolve) => {
124
+ var _a;
125
+ (_a = process.onBeforeStart) == null ? void 0 : _a.call(process);
126
+ setTimeout(() => {
127
+ var _a2;
128
+ if (process.message) this.log(process.message, { timestamp: Date.now() });
129
+ (_a2 = process.onComplete) == null ? void 0 : _a2.call(process);
130
+ resolve();
131
+ }, process.delay || 0);
132
+ });
133
+ });
134
+ window.addEventListener("QSL:log", (e) => this.log(e.detail.type, e.detail.config.id));
135
+ window.addEventListener("QSL:error", (e) => this.error(e.detail.type, e.detail.error, e.detail.config.id));
136
+ if (this.initActions.size) {
137
+ for (const cb of this.initActions) {
138
+ if (typeof cb === "function") await cb.call(this);
139
+ }
140
+ }
141
+ this.initialized = true;
142
+ const url = document.currentScript ? new URL(document.currentScript.src, document.baseURI) : null;
143
+ if (!url || url.searchParams.get("async") !== "true") return this;
144
+ const callback = url.searchParams.get("callback") || this.CALLBACK;
145
+ if (typeof window[callback] === "function") window[callback]();
146
+ return this;
147
+ },
148
+ /**
149
+ * Register a plugin to QSL.
150
+ *
151
+ * @param {Function} plugin - The plugin function to register.
152
+ * @param {...any} args - Additional arguments passed to the plugin.
153
+ * @returns {this}
154
+ */
155
+ use(plugin, ...args) {
156
+ if (typeof plugin === "function") plugin(this, ...args);
157
+ return this;
158
+ },
159
+ /**
160
+ * Add a process config to a flow.
161
+ * Handles process-level dependencies separately from flow-level logic.
162
+ *
163
+ * @param {Object} config - The process configuration object.
164
+ * @param {string|boolean|null} [flowId=null] - The flow ID or true for ordered, or null for default.
165
+ * @returns {this}
166
+ */
167
+ add(config, flowId = null) {
168
+ if (!config || typeof config !== "object") return this;
169
+ config.id = config.id ? this.PREFIX + config.id : this.PREFIX + Math.random().toString(36).slice(2);
170
+ config.skipped = false;
171
+ if (!config.type) config.type = "console";
172
+ if (Array.isArray(config.depends)) config.depends = [...new Set(config.depends)];
173
+ if (this.addProcessFilters.size) {
174
+ for (const cb of this.addProcessFilters) {
175
+ if (typeof cb === "function") [flowId, config] = cb.call(this, flowId, config);
176
+ }
177
+ }
178
+ const normalizedFlowId = this.normalizeFlowId(flowId);
179
+ config.flowId = normalizedFlowId;
180
+ this.getOrCreateFlow(normalizedFlowId).push(config);
181
+ return this;
182
+ },
183
+ /**
184
+ * Start loading all flows.
185
+ *
186
+ * @param {Object} [options={}]
187
+ * @param {number|boolean} [options.between=false] - Global delay between processes.
188
+ * @returns {Promise<this>}
189
+ */
190
+ async load({ between = false } = {}) {
191
+ if (this.hasStarted) return;
192
+ this.hasStarted = true;
193
+ this.globalBetween = between;
194
+ for (const cb of this.loadActions) {
195
+ if (typeof cb === "function") cb.call(this);
196
+ }
197
+ return new Promise((resolve) => {
198
+ if (!this.flows.size) {
199
+ this.reset();
200
+ return resolve();
201
+ }
202
+ this.globalResolve = resolve;
203
+ this.processFlows();
204
+ });
205
+ },
206
+ /**
207
+ * Reset all internal state and clear all flows/options.
208
+ *
209
+ * @returns {void}
210
+ */
211
+ reset() {
212
+ if (this.resetActions.size) {
213
+ for (const action of this.resetActions) {
214
+ if (typeof action === "function") action.call(this);
215
+ }
216
+ }
217
+ this.flows.clear();
218
+ this.flowOptions.clear();
219
+ this.flowGroups.clear();
220
+ this.pendingFlows.clear();
221
+ this.pendingProcesses.clear();
222
+ this.completedProcesses.clear();
223
+ this.currentProcessPerFlow.clear();
224
+ this.onAllComplete = null;
225
+ this.globalResolve = null;
226
+ this.hasStarted = false;
227
+ this.globalBetween = 0;
228
+ this.log("RESET");
229
+ return this;
230
+ },
231
+ /**
232
+ * Tear the instance down completely: run state, plugin registrations and
233
+ * registered types. After this, init() has to run again.
234
+ *
235
+ * @returns {this}
236
+ */
237
+ destroy() {
238
+ this.reset();
239
+ this.types.clear();
240
+ this.initActions.clear();
241
+ this.loadActions.clear();
242
+ this.addProcessFilters.clear();
243
+ this.completedFlowsActions.clear();
244
+ this.flowIdFilters.clear();
245
+ this.conditionHandlers.clear();
246
+ this.triggerHandlers.clear();
247
+ this.processCompleteActions.clear();
248
+ this.allCompleteActions.clear();
249
+ this.resetActions.clear();
250
+ this.handlerCallbacksFilters.clear();
251
+ this.logger = null;
252
+ this.eventsEnabled = false;
253
+ this.initialized = false;
254
+ return this;
255
+ },
256
+ /**
257
+ * Set the logger instance.
258
+ *
259
+ * @param {Object|Function} logger - Logger instance or function.
260
+ * @returns {this}
261
+ */
262
+ setLogger(logger2) {
263
+ if (logger2 && (typeof logger2 === "function" || typeof logger2 === "object")) this.logger = logger2;
264
+ return this;
265
+ },
266
+ /**
267
+ * Set a callback to run when all flows/processes are complete.
268
+ *
269
+ * @param {Function} callback - The callback function.
270
+ * @returns {this}
271
+ */
272
+ setOnAllComplete(callback) {
273
+ this.onAllComplete = typeof callback === "function" ? callback : null;
274
+ return this;
275
+ },
276
+ /**
277
+ * Enable DOM events for process/flow lifecycle.
278
+ * @returns {this}
279
+ */
280
+ useEvents() {
281
+ this.eventsEnabled = true;
282
+ return this;
283
+ },
284
+ /**
285
+ * Log a message using the custom logger if set.
286
+ *
287
+ * @param {string} type - Log type.
288
+ * @param {...any} args - Additional log arguments.
289
+ */
290
+ log(type, ...args) {
291
+ if (this.logger && typeof this.logger.log === "function") this.logger.log(type, ...args);
292
+ },
293
+ /**
294
+ * Log an error using the custom logger if set.
295
+ *
296
+ * @param {string} type - Error type.
297
+ * @param {...any} args - Additional error arguments.
298
+ */
299
+ error(type, ...args) {
300
+ if (this.logger && typeof this.logger.error === "function") this.logger.error(type, ...args);
301
+ },
302
+ /**
303
+ * Fire a DOM event if events are enabled.
304
+ *
305
+ * @param {string} event - Event name.
306
+ * @param {Object} detail - Event detail object.
307
+ */
308
+ fire(event, detail) {
309
+ if (this.eventsEnabled && this.EVENTS[event]) {
310
+ window.dispatchEvent(new CustomEvent(this.EVENTS[event], { detail }));
311
+ }
312
+ },
313
+ /**
314
+ * Normalize the flow ID.
315
+ *
316
+ * @param {string|boolean|null} flowId - The flow ID or true for ordered, or null for default.
317
+ * @returns {string} Normalized flow ID.
318
+ */
319
+ normalizeFlowId(flowId) {
320
+ if (flowId === true) {
321
+ flowId = this.FLOW_TYPE.ORDERED;
322
+ } else if (typeof flowId !== "string") {
323
+ flowId = this.FLOW_TYPE.DEFAULT;
324
+ }
325
+ return flowId;
326
+ },
327
+ /**
328
+ * Register a custom resource type handler.
329
+ *
330
+ * @param {string} type - Resource type name.
331
+ * @param {Function} handler - Handler function for the type.
332
+ * @returns {this}
333
+ */
334
+ registerType(type, handler) {
335
+ if (typeof type !== "string" || typeof handler !== "function") return this;
336
+ this.types.set(type, handler);
337
+ return this;
338
+ },
339
+ /**
340
+ * Register multiple custom resource types.
341
+ *
342
+ * @param {Array<{type: string, handler: Function}>|Object} types - Array or object of type definitions.
343
+ * @returns {this}
344
+ */
345
+ registerTypes(types) {
346
+ if (!types || typeof types !== "object") return this;
347
+ const list = Array.isArray(types) ? types : Object.entries(types).map(([type, handler]) => typeof handler === "function" ? { type, handler } : handler);
348
+ for (const type of list) {
349
+ if (type) this.registerType(type.type, type.handler);
350
+ }
351
+ return this;
352
+ },
353
+ /**
354
+ * Pause all flows in a group.
355
+ *
356
+ * @param {string} group - Group name.
357
+ * @returns {this}
358
+ */
359
+ pauseGroup(group) {
360
+ const flowGroup = this.flowGroups.get(group);
361
+ if (!flowGroup) return this;
362
+ for (const flowId of flowGroup) {
363
+ this.setFlowOptions({ paused: true }, flowId);
364
+ }
365
+ return this;
366
+ },
367
+ /**
368
+ * Run all flows in a group.
369
+ *
370
+ * @param {string} group - Group name.
371
+ * @returns {this}
372
+ */
373
+ runGroup(group) {
374
+ const flowGroup = this.flowGroups.get(group);
375
+ if (!flowGroup) return this;
376
+ for (const flowId of flowGroup) {
377
+ this.setFlowOptions({ paused: false }, flowId);
378
+ this.runFlow(flowId);
379
+ }
380
+ return this;
381
+ },
382
+ /**
383
+ * Run a specific flow by id.
384
+ *
385
+ * @param {string} flowId - Flow ID.
386
+ * @param {boolean} [withTrigger=false] - Whether to run with trigger logic.
387
+ * @returns {this}
388
+ */
389
+ runFlow(flowId, withTrigger = false) {
390
+ const processes = this.flows.get(flowId);
391
+ const options = this.flowOptions.get(flowId);
392
+ if (!processes || !options || options.status !== this.FLOW_STATE.READY) return this;
393
+ this.processFlows(flowId, withTrigger);
394
+ return this;
395
+ },
396
+ /**
397
+ * Get or create a flow.
398
+ *
399
+ * @param {string} flowId - Flow ID.
400
+ * @returns {Array} The flow's process array.
401
+ */
402
+ getOrCreateFlow(flowId) {
403
+ if (!this.flows.has(flowId)) {
404
+ this.flows.set(flowId, []);
405
+ this.flowOptions.set(flowId, {
406
+ ...this.FLOW_OPTIONS,
407
+ ordered: flowId === this.FLOW_TYPE.ORDERED,
408
+ status: this.FLOW_STATE.READY
409
+ });
410
+ }
411
+ return this.flows.get(flowId);
412
+ },
413
+ /**
414
+ * Set or update options for a flow.
415
+ * If depends is set, pauses the flow until dependencies are resolved.
416
+ *
417
+ * @param {Object} options - Flow options.
418
+ * @param {string|boolean|null} [flowId=null] - Flow ID.
419
+ * @returns {this}
420
+ */
421
+ setFlowOptions(options = {}, flowId = null) {
422
+ flowId = this.normalizeFlowId(flowId);
423
+ this.getOrCreateFlow(flowId);
424
+ if (!options || typeof options !== "object") return this;
425
+ const prevOptions = this.flowOptions.get(flowId);
426
+ if (Array.isArray(options.depends) && options.depends.length) {
427
+ options.depends = [...new Set(options.depends)];
428
+ options.paused = true;
429
+ this.pendingFlows.add(flowId);
430
+ }
431
+ if (options.group) {
432
+ if (!this.flowGroups.has(options.group)) this.flowGroups.set(options.group, /* @__PURE__ */ new Set());
433
+ this.flowGroups.get(options.group).add(flowId);
434
+ }
435
+ this.flowOptions.set(flowId, { ...prevOptions, ...options });
436
+ return this;
437
+ },
438
+ /**
439
+ * Check all pending flows and run those whose dependencies are now resolved.
440
+ *
441
+ * @returns {void}
442
+ */
443
+ checkPendingFlows() {
444
+ if (!this.pendingFlows.size) return;
445
+ for (const pendingFlowId of this.pendingFlows) {
446
+ const pendingOptions = this.flowOptions.get(pendingFlowId);
447
+ if (pendingOptions && pendingOptions.depends && pendingOptions.depends.every((depId) => {
448
+ const depOpt = this.flowOptions.get(this.normalizeFlowId(depId));
449
+ return depOpt && depOpt.status === this.FLOW_STATE.COMPLETED;
450
+ })) {
451
+ this.setFlowOptions({ paused: false }, pendingFlowId);
452
+ this.pendingFlows.delete(pendingFlowId);
453
+ this.runFlow(pendingFlowId);
454
+ }
455
+ }
456
+ },
457
+ /**
458
+ * Check all pending processes and run those whose dependencies are now resolved.
459
+ *
460
+ * @returns {void}
461
+ */
462
+ checkPendingProcesses() {
463
+ if (!this.pendingProcesses.size) return;
464
+ for (const process of this.pendingProcesses) {
465
+ const missingDeps = process.depends.filter((depId) => {
466
+ const hasProcess = Array.from(this.flows.values()).some(
467
+ (flow) => flow.some((p) => p.id === this.PREFIX + depId)
468
+ );
469
+ return !this.completedProcesses.has(this.PREFIX + depId) && !hasProcess;
470
+ });
471
+ if (missingDeps.length) {
472
+ this.pendingProcesses.delete(process);
473
+ this.log("DEP_NOT_FOUND", process.id, `${missingDeps.join(", ")}`);
474
+ process._depsResolved = true;
475
+ process._triggered = true;
476
+ if (process._waitResolve) process._waitResolve();
477
+ continue;
478
+ }
479
+ const allDepsCompleted = process.depends.every((depId) => this.completedProcesses.has(this.PREFIX + depId));
480
+ if (allDepsCompleted) {
481
+ this.pendingProcesses.delete(process);
482
+ process._depsResolved = true;
483
+ if (process._triggered && process._waitResolve) process._waitResolve();
484
+ }
485
+ }
486
+ },
487
+ /**
488
+ * Check if all flows/processes are complete and resolve global promise if so.
489
+ *
490
+ * @returns {Promise<void>}
491
+ */
492
+ async maybeComplete() {
493
+ var _a;
494
+ if (!this.hasStarted) return;
495
+ if (this.pendingFlows.size) {
496
+ for (const pendingFlowId of this.pendingFlows) {
497
+ const pendingOptions = this.flowOptions.get(pendingFlowId);
498
+ if (pendingOptions && pendingOptions.depends && pendingOptions.depends.some((depId) => !this.flowOptions.has(this.normalizeFlowId(depId)))) {
499
+ this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, pendingFlowId);
500
+ this.pendingFlows.delete(pendingFlowId);
501
+ this.log("FLOW_DEP_SKIPPED", { flow: pendingFlowId, depends: `${pendingOptions.depends.filter((depId) => !this.flowOptions.has(this.normalizeFlowId(depId))).join(", ")}` });
502
+ }
503
+ }
504
+ }
505
+ let flowsDone = this.flowOptions.size ? Array.from(this.flowOptions.values()).every((opt) => opt.status === this.FLOW_STATE.COMPLETED) : false;
506
+ if (!flowsDone) return;
507
+ let maybeComplete = true;
508
+ if (this.flows.size && this.completedFlowsActions.size) {
509
+ for (const cb of this.completedFlowsActions) {
510
+ maybeComplete = cb.call(this, flowsDone, this.flows, this.flowOptions);
511
+ }
512
+ }
513
+ if (!maybeComplete) return;
514
+ if (this.completing) return;
515
+ this.completing = true;
516
+ this.log("ALL_COMPLETED");
517
+ this.fire("ALL_COMPLETED");
518
+ (_a = this.onAllComplete) == null ? void 0 : _a.call(this);
519
+ if (this.globalResolve !== null) this.globalResolve();
520
+ if (this.allCompleteActions.size) {
521
+ for (const action of this.allCompleteActions) {
522
+ if (typeof action === "function") action.call(this);
523
+ }
524
+ }
525
+ if (this.autoReset) this.reset();
526
+ this.completing = false;
527
+ },
528
+ /**
529
+ * Process all flows and their dependencies.
530
+ *
531
+ * @param {string|null} [flowId=null] - Specific flow ID or null for all.
532
+ * @param {boolean} [withTrigger=false] - Whether to run with trigger logic.
533
+ * @returns {this}
534
+ */
535
+ processFlows(flowId = null, withTrigger = false) {
536
+ if (!this.flows.size) return;
537
+ let flowIds = flowId ? [flowId] : Array.from(this.flows.keys());
538
+ if (flowIds.length && this.flowIdFilters.size) {
539
+ for (const cb of this.flowIdFilters) {
540
+ if (typeof cb === "function") flowIds = cb.call(this, flowIds);
541
+ }
542
+ }
543
+ flowIds.sort((a, b) => {
544
+ const aOpts = this.flowOptions.get(a);
545
+ const bOpts = this.flowOptions.get(b);
546
+ const aHasTrigger = (aOpts == null ? void 0 : aOpts.trigger) != null;
547
+ const bHasTrigger = (bOpts == null ? void 0 : bOpts.trigger) != null;
548
+ if (aHasTrigger && !bHasTrigger) return 1;
549
+ if (!aHasTrigger && bHasTrigger) return -1;
550
+ const aPriority = (aOpts == null ? void 0 : aOpts.priority) || 0;
551
+ const bPriority = (bOpts == null ? void 0 : bOpts.priority) || 0;
552
+ return bPriority - aPriority;
553
+ });
554
+ for (const fid of flowIds) {
555
+ const options = this.flowOptions.get(fid);
556
+ if (!options || options.status === this.FLOW_STATE.COMPLETED) continue;
557
+ if (this.getConditionStatus(options.condition)) {
558
+ this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);
559
+ continue;
560
+ }
561
+ if (options.paused) continue;
562
+ if (flowId === null || flowId && !withTrigger) {
563
+ if (options.trigger != null) {
564
+ const trigger = this.getTriggerFunction(options.trigger, options);
565
+ if (trigger) {
566
+ this.setFlowOptions({ paused: true }, fid);
567
+ let triggered = false;
568
+ trigger(() => {
569
+ if (triggered) return;
570
+ triggered = true;
571
+ this.setFlowOptions({ paused: false }, fid);
572
+ this.runFlow(fid, true);
573
+ });
574
+ continue;
575
+ }
576
+ }
577
+ }
578
+ this.setFlowOptions({ status: this.FLOW_STATE.RUNNING }, fid);
579
+ (async () => {
580
+ var _a, _b;
581
+ (_a = options.beforeStart) == null ? void 0 : _a.call(options);
582
+ if (options.delay && options.delay > 0) {
583
+ await new Promise((res) => setTimeout(res, options.delay));
584
+ }
585
+ const processes = (this.flows.get(fid) || []).slice();
586
+ processes.sort((a, b) => (b.priority || 0) - (a.priority || 0));
587
+ if ((options.preload || options.prefetch) && !options.trigger) {
588
+ for (const p of processes) {
589
+ if (p.trigger) continue;
590
+ if (p.type === "script" && p.src || p.type === "style" && p.href) {
591
+ try {
592
+ const link = document.createElement("link");
593
+ link.rel = options.preload ? "preload" : "prefetch";
594
+ link.href = p.src || p.href;
595
+ link.as = p.type === "script" ? "script" : "style";
596
+ if (p.crossOrigin) link.crossOrigin = p.crossOrigin;
597
+ document.head.appendChild(link);
598
+ } catch (e) {
599
+ this.error("PRELOAD_ERROR", e, p.id);
600
+ }
601
+ }
602
+ }
603
+ }
604
+ const between = options.between !== void 0 && options.between !== null ? options.between : this.globalBetween;
605
+ if (options.ordered) {
606
+ let prev = Promise.resolve();
607
+ processes.forEach((process, idx) => {
608
+ prev = prev.then(async () => {
609
+ if (idx > 0 && between) await new Promise((res) => setTimeout(res, between));
610
+ await this.run(process);
611
+ });
612
+ });
613
+ await prev;
614
+ } else {
615
+ const promises = processes.map(async (process, idx) => {
616
+ if (idx > 0 && between) await new Promise((res) => setTimeout(res, between));
617
+ return this.run(process);
618
+ });
619
+ await Promise.all(promises);
620
+ }
621
+ this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);
622
+ (_b = options.onComplete) == null ? void 0 : _b.call(options);
623
+ this.checkPendingFlows();
624
+ this.maybeComplete();
625
+ })();
626
+ }
627
+ this.checkPendingFlows();
628
+ this.maybeComplete();
629
+ },
630
+ /**
631
+ * Execute a process based on its type.
632
+ *
633
+ * @param {Object} process - The process object.
634
+ * @returns {Promise<any>}
635
+ */
636
+ async run(process) {
637
+ if (process._running || this.getConditionStatus(process.condition)) return;
638
+ process._running = true;
639
+ if (!process._waitPromise) {
640
+ process._triggered = false;
641
+ process._depsResolved = false;
642
+ process._waitPromise = new Promise((res) => process._waitResolve = res);
643
+ }
644
+ if (process.trigger != null) {
645
+ const trigger = this.getTriggerFunction(process.trigger, process);
646
+ if (trigger) {
647
+ trigger(() => {
648
+ process._triggered = true;
649
+ if (process._depsResolved) process._waitResolve();
650
+ });
651
+ } else {
652
+ process._triggered = true;
653
+ }
654
+ } else {
655
+ process._triggered = true;
656
+ }
657
+ if (Array.isArray(process.depends) && process.depends.length) {
658
+ const missingDeps = process.depends.filter((depId) => {
659
+ const hasProcess = Array.from(this.flows.values()).some(
660
+ (flow) => flow.some((p) => p.id === this.PREFIX + depId)
661
+ );
662
+ return !this.completedProcesses.has(this.PREFIX + depId) && !hasProcess;
663
+ });
664
+ if (missingDeps.length) {
665
+ this.log("DEP_NOT_FOUND", process.id, `${missingDeps.join(", ")}`);
666
+ process._depsResolved = true;
667
+ process._triggered = true;
668
+ if (process._waitResolve) process._waitResolve();
669
+ } else {
670
+ const allDepsCompleted = process.depends.every((depId) => this.completedProcesses.has(this.PREFIX + depId));
671
+ if (!allDepsCompleted) {
672
+ this.pendingProcesses.add(process);
673
+ } else {
674
+ process._depsResolved = true;
675
+ if (process._triggered) process._waitResolve();
676
+ }
677
+ }
678
+ } else {
679
+ process._depsResolved = true;
680
+ if (process._triggered) process._waitResolve();
681
+ }
682
+ await process._waitPromise;
683
+ return this.execute(process);
684
+ },
685
+ /**
686
+ * Check the condition option and return true if the condition fails.
687
+ *
688
+ * @param {string|Function|boolean} conditionOption - The condition option.
689
+ * @returns {boolean} True if the condition fails, false otherwise.
690
+ */
691
+ getConditionStatus(opt) {
692
+ if (opt == null) return false;
693
+ if (Array.isArray(opt)) {
694
+ return opt.some((c) => this.getConditionStatus(c));
695
+ }
696
+ if (typeof opt === "object" && opt.operator) {
697
+ const { operator, conditions: conditions2 } = opt;
698
+ if (!Array.isArray(conditions2)) return false;
699
+ if (operator === "or") {
700
+ return conditions2.every((c) => this.getConditionStatus(c));
701
+ } else if (operator === "and") {
702
+ return conditions2.some((c) => this.getConditionStatus(c));
703
+ }
704
+ return false;
705
+ }
706
+ if (typeof opt === "function" && !opt()) return true;
707
+ if (typeof opt === "boolean" && !opt) return true;
708
+ if (this.conditionHandlers.size) {
709
+ for (const h of this.conditionHandlers) {
710
+ if (typeof h === "function") {
711
+ const r = h.call(this, opt);
712
+ if (r === true || r === false) return r;
713
+ }
714
+ }
715
+ }
716
+ return false;
717
+ },
718
+ /**
719
+ * Parse and return a trigger function based on the trigger option.
720
+ *
721
+ * @param {string|Function|boolean} opt - The trigger option.
722
+ * @param {Object} o - The associated process or flow object.
723
+ * @returns {Function|null} The trigger function or null if no trigger function is found.
724
+ */
725
+ getTriggerFunction(opt, o) {
726
+ if (opt == null) return null;
727
+ if (typeof opt === "function") {
728
+ return (cb) => opt(cb);
729
+ }
730
+ if (Array.isArray(opt)) {
731
+ return (cb) => {
732
+ const vd = opt.map((t) => this.getTriggerFunction(t, o)).filter((tF) => tF);
733
+ if (vd.length === 0) {
734
+ cb();
735
+ return;
736
+ }
737
+ let f = 0;
738
+ const fCb = () => {
739
+ if (++f === vd.length) cb();
740
+ };
741
+ vd.forEach((tF) => tF(fCb));
742
+ };
743
+ }
744
+ if (typeof opt === "object" && opt.operator) {
745
+ const { operator, triggers: triggers2 } = opt;
746
+ if (!Array.isArray(triggers2)) return null;
747
+ if (operator === "or") {
748
+ return (cb) => {
749
+ const vd = triggers2.map((t) => this.getTriggerFunction(t, o)).filter((tF) => tF);
750
+ if (vd.length === 0) {
751
+ cb();
752
+ return;
753
+ }
754
+ let f = false;
755
+ const fCb = () => {
756
+ if (!f) {
757
+ f = true;
758
+ cb();
759
+ }
760
+ };
761
+ vd.forEach((tF) => tF(fCb));
762
+ };
763
+ } else if (operator === "and") {
764
+ return (cb) => {
765
+ const vd = triggers2.map((t) => this.getTriggerFunction(t, o)).filter((tF) => tF);
766
+ if (vd.length === 0) {
767
+ cb();
768
+ return;
769
+ }
770
+ let f = 0;
771
+ const fCb = () => {
772
+ if (++f === vd.length) cb();
773
+ };
774
+ vd.forEach((tF) => tF(fCb));
775
+ };
776
+ }
777
+ return null;
778
+ }
779
+ if (this.triggerHandlers.size) {
780
+ for (const h of this.triggerHandlers) {
781
+ if (typeof h === "function") {
782
+ const r = h.call(this, opt, o);
783
+ if (r && typeof r === "function") return r;
784
+ }
785
+ }
786
+ }
787
+ if (opt === true || opt === "interaction") {
788
+ return (cb) => this.waitForInteraction(cb);
789
+ }
790
+ return null;
791
+ },
792
+ /**
793
+ * Wait for user interaction before running a callback (for interaction phase).
794
+ * This is the default fallback trigger.
795
+ *
796
+ * @param {Function} cb - The callback to run after user interaction.
797
+ * @returns {void}
798
+ */
799
+ waitForInteraction(cb) {
800
+ ["click", "keydown", "wheel", "mousedown", "mousemove", "touchstart"].forEach((e) => window.addEventListener(e, () => cb(), { once: true, passive: true }));
801
+ },
802
+ /**
803
+ * Execute the process based on its type.
804
+ *
805
+ * @param {Object} process - The process object.
806
+ * @returns {Promise<any>}
807
+ */
808
+ async execute(process) {
809
+ const finishProcess = async () => {
810
+ if (this.processCompleteActions.size) {
811
+ for (const action of this.processCompleteActions) {
812
+ if (typeof action === "function") action.call(this, process);
813
+ }
814
+ }
815
+ this.completedProcesses.add(process.id);
816
+ process._running = false;
817
+ this.checkPendingProcesses();
818
+ };
819
+ if (process.skipped) {
820
+ this.fire("SKIPPED", { ...process, id: process.id });
821
+ finishProcess();
822
+ return;
823
+ }
824
+ const handler = this.types.get(process.type);
825
+ if (!handler) {
826
+ this.log("UNKNOWN_TYPE", process.type, process.id);
827
+ finishProcess();
828
+ return;
829
+ }
830
+ this.fire("STARTED", { ...process, id: process.id });
831
+ const callbacks = {};
832
+ if (this.handlerCallbacksFilters.size) {
833
+ for (const filter of this.handlerCallbacksFilters) {
834
+ if (typeof filter === "function") {
835
+ const pluginCallbacks = filter.call(this, process);
836
+ if (pluginCallbacks && typeof pluginCallbacks === "object") {
837
+ Object.assign(callbacks, pluginCallbacks);
838
+ }
839
+ }
840
+ }
841
+ }
842
+ return handler(process, callbacks).then(() => {
843
+ this.fire("COMPLETED", { ...process, id: process.id });
844
+ finishProcess();
845
+ }).catch(() => {
846
+ this.fire("ERROR", { ...process, id: process.id });
847
+ finishProcess();
848
+ });
849
+ }
850
+ };
851
+ const bypassSuffix = (source, bypassCache) => {
852
+ return bypassCache ? (source.includes("?") ? "&" : "?") + Date.now() : "";
853
+ };
854
+ const log = (detail) => {
855
+ window.dispatchEvent(new CustomEvent("QSL:log", { detail }));
856
+ };
857
+ const error = (detail) => {
858
+ window.dispatchEvent(new CustomEvent("QSL:error", { detail }));
859
+ };
860
+ const render = (config, callbacks = {}) => {
861
+ return new Promise(async (resolve) => {
862
+ var _a;
863
+ const { flowId, tag, id, delay, data, onBeforeStart, onComplete, onError, footer, dom, onElement, onCustomResolve } = config;
864
+ if (!flowId || !tag || !id) {
865
+ resolve();
866
+ return;
867
+ }
868
+ try {
869
+ if (onBeforeStart) await onBeforeStart(config);
870
+ log({ tag, type: "PROCESS_STARTED", config });
871
+ if (delay) await new Promise((res) => setTimeout(res, delay));
872
+ let el = document.createElement(tag);
873
+ onElement == null ? void 0 : onElement(el, config);
874
+ (_a = callbacks.registerProcessElement) == null ? void 0 : _a.call(callbacks, el, config);
875
+ if (data && typeof data === "object") {
876
+ for (const [key, value] of Object.entries(data)) {
877
+ el.setAttribute(`data-${key.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/[^a-z0-9_-]/g, "").replace(/^-/, "")}`, String(value));
878
+ }
879
+ }
880
+ if (!onCustomResolve) {
881
+ el.onload = () => {
882
+ log({ tag, type: "PROCESS_COMPLETED", config });
883
+ onComplete == null ? void 0 : onComplete();
884
+ resolve();
885
+ };
886
+ }
887
+ el.onerror = (e) => {
888
+ error({ tag, type: "PROCESS_FAILED", config });
889
+ onError == null ? void 0 : onError(e);
890
+ resolve(e);
891
+ };
892
+ if (dom) {
893
+ (footer ? document.body : document.head).appendChild(el);
894
+ }
895
+ onCustomResolve == null ? void 0 : onCustomResolve({ el, config, resolve });
896
+ } catch (e) {
897
+ error({ tag, type: "PROCESS_FAILED", config, error: e });
898
+ onError == null ? void 0 : onError(e);
899
+ resolve(e);
900
+ }
901
+ });
902
+ };
903
+ const InlineScript = {
904
+ type: "inline-script",
905
+ handler: (config, callbacks) => {
906
+ var _a;
907
+ let storedResolve = null;
908
+ let alreadyFired = false;
909
+ const eventName = `QSL:inline-script:completed:${config.id}`;
910
+ const resolveProcess = () => {
911
+ var _a2;
912
+ log({ tag: "inline-script", type: "INLINE_SCRIPT_SUCCESS", config });
913
+ log({ tag: "inline-script", type: "PROCESS_COMPLETED", config });
914
+ (_a2 = config == null ? void 0 : config.onComplete) == null ? void 0 : _a2.call(config);
915
+ storedResolve == null ? void 0 : storedResolve();
916
+ };
917
+ const normalizedConfig = {
918
+ ...config,
919
+ code: (_a = config.code) == null ? void 0 : _a.replace(/<script.*?>|<\/script>/gi, "")
920
+ };
921
+ return render({
922
+ ...normalizedConfig,
923
+ tag: "script",
924
+ dom: true,
925
+ onElement: (el, config2) => {
926
+ const { code, module, id, flowId } = config2;
927
+ if (code) el.textContent = code;
928
+ if (module) {
929
+ el.type = "module";
930
+ const originalCode = el.textContent;
931
+ const fid = JSON.stringify(String(flowId));
932
+ const pid = JSON.stringify(String(id));
933
+ const evt = JSON.stringify(String(eventName));
934
+ const wrappedCode = `(function(){window.__QSL__.currentProcessPerFlow.set(${fid},${pid});try{${originalCode}}finally{window.__QSL__.currentProcessPerFlow.delete(${fid});window.dispatchEvent(new Event(${evt}));}})();`;
935
+ el.textContent = wrappedCode;
936
+ const handler = () => {
937
+ window.removeEventListener(eventName, handler);
938
+ if (storedResolve) {
939
+ resolveProcess();
940
+ } else {
941
+ alreadyFired = true;
942
+ }
943
+ };
944
+ window.addEventListener(eventName, handler);
945
+ }
946
+ },
947
+ onCustomResolve: ({ el, config: config2, resolve }) => {
948
+ const { module } = config2;
949
+ storedResolve = resolve;
950
+ if (module && alreadyFired) {
951
+ resolveProcess();
952
+ } else if (!module) {
953
+ queueMicrotask(() => {
954
+ if (storedResolve === resolve) resolveProcess();
955
+ });
956
+ }
957
+ }
958
+ }, callbacks);
959
+ }
960
+ };
961
+ const Script = {
962
+ type: "script",
963
+ handler: (config, callbacks) => {
964
+ return render({
965
+ ...config,
966
+ tag: "script",
967
+ dom: true,
968
+ onElement: (el, { src, module, async, defer, crossOrigin, integrity, bypassCache }) => {
969
+ if (module) el.type = "module";
970
+ if (async) el.async = async;
971
+ if (defer) el.defer = defer;
972
+ if (crossOrigin) el.crossOrigin = crossOrigin;
973
+ if (integrity) el.integrity = integrity;
974
+ if (src) el.src = src + bypassSuffix(src, bypassCache);
975
+ }
976
+ }, callbacks);
977
+ }
978
+ };
979
+ const InlineStyle = {
980
+ type: "style",
981
+ handler: (config, callbacks) => {
982
+ var _a;
983
+ const normalizedConfig = {
984
+ ...config,
985
+ code: (_a = config.code) == null ? void 0 : _a.replace(/<style.*?>|<\/style>/gi, "")
986
+ };
987
+ return render({
988
+ ...normalizedConfig,
989
+ tag: "style",
990
+ dom: true,
991
+ onElement: (el, { code }) => {
992
+ if (code) el.textContent = code;
993
+ },
994
+ onCustomResolve: ({ el, config: config2, resolve }) => {
995
+ const { tag, onComplete } = config2;
996
+ log({ tag, type: "INLINE_STYLE_SUCCESS", config: config2 });
997
+ log({ tag, type: "PROCESS_COMPLETED", config: config2 });
998
+ onComplete == null ? void 0 : onComplete();
999
+ resolve();
1000
+ }
1001
+ }, callbacks);
1002
+ }
1003
+ };
1004
+ const Stylesheet = {
1005
+ type: "stylesheet",
1006
+ handler: (config, callbacks) => {
1007
+ return render({
1008
+ ...config,
1009
+ tag: "link",
1010
+ dom: true,
1011
+ onElement: (el, { href, crossOrigin, bypassCache }) => {
1012
+ el.rel = "stylesheet";
1013
+ if (crossOrigin) el.crossOrigin = crossOrigin;
1014
+ el.href = href + bypassSuffix(href, bypassCache);
1015
+ }
1016
+ }, callbacks);
1017
+ }
1018
+ };
1019
+ const Pixel = {
1020
+ type: "pixel",
1021
+ handler: (config, callbacks) => {
1022
+ return render({
1023
+ ...config,
1024
+ tag: "img",
1025
+ dom: true,
1026
+ onElement: (el, { style = { display: "none" }, dom, src, bypassCache }) => {
1027
+ if (!dom) el = new window.Image();
1028
+ el.src = src + bypassSuffix(src, bypassCache);
1029
+ el.width = 1;
1030
+ el.height = 1;
1031
+ if (style && typeof style === "object") {
1032
+ for (const [key, value] of Object.entries(style)) {
1033
+ el.style.setProperty(key, value);
1034
+ }
1035
+ }
1036
+ },
1037
+ onCustomResolve: ({ el, config: config2, resolve }) => {
1038
+ const { tag, dom, onComplete } = config2;
1039
+ const resolver = () => {
1040
+ log({ tag, type: "IMAGE_LOADED", config: config2 });
1041
+ log({ tag, type: "PROCESS_COMPLETED", config: config2 });
1042
+ onComplete == null ? void 0 : onComplete();
1043
+ resolve();
1044
+ };
1045
+ !dom ? resolver() : el.onload = () => resolver();
1046
+ }
1047
+ }, callbacks);
1048
+ }
1049
+ };
1050
+ const Shadow = {
1051
+ type: "shadow",
1052
+ handler: (config, callbacks) => {
1053
+ return render({
1054
+ ...config,
1055
+ onBeforeStart: async ({ tag }) => await window.customElements.whenDefined(tag),
1056
+ onElement: (el, { shadowData }) => {
1057
+ el.data = shadowData || {};
1058
+ if (shadowData == null ? void 0 : shadowData.hidden) el.setAttribute("hidden", "");
1059
+ },
1060
+ onCustomResolve: ({ el, config: config2, resolve }) => {
1061
+ const { tag, shadowData, onComplete, onError } = config2;
1062
+ const resolver = () => {
1063
+ const selector = shadowData == null ? void 0 : shadowData.container;
1064
+ let container = null;
1065
+ if (selector === "body") {
1066
+ container = document.body;
1067
+ } else if (typeof selector === "string" && selector) {
1068
+ try {
1069
+ container = document.querySelector(selector);
1070
+ } catch (e) {
1071
+ container = null;
1072
+ }
1073
+ }
1074
+ if (!container) {
1075
+ const err = new Error(`Container not found: ${selector}`);
1076
+ error({ tag, type: "SHADOW_FAILED", config: config2, error: err });
1077
+ onError == null ? void 0 : onError(err);
1078
+ resolve(err);
1079
+ return;
1080
+ }
1081
+ (shadowData == null ? void 0 : shadowData.position) === "top" ? container.insertBefore(el, container.firstChild) : container.appendChild(el);
1082
+ log({ tag, type: "SHADOW_SUCCESS", config: config2 });
1083
+ log({ tag, type: "PROCESS_COMPLETED", config: config2 });
1084
+ onComplete == null ? void 0 : onComplete();
1085
+ resolve();
1086
+ };
1087
+ if (document.readyState === "interactive" || document.readyState === "complete") {
1088
+ resolver();
1089
+ } else {
1090
+ document.addEventListener("DOMContentLoaded", resolver, { once: true });
1091
+ }
1092
+ }
1093
+ }, callbacks);
1094
+ }
1095
+ };
1096
+ const HTML = {
1097
+ type: "html",
1098
+ handler: (config, callbacks) => {
1099
+ return render({
1100
+ ...config,
1101
+ dom: true,
1102
+ onElement: (el, { html = "", id = "", className = "", style = {} }) => {
1103
+ if (html) el.innerHTML = html;
1104
+ if (id) el.id = id;
1105
+ if (className) el.className = Array.isArray(className) ? className.join(" ") : className;
1106
+ if (style && typeof style === "object") {
1107
+ for (const [key, value] of Object.entries(style)) {
1108
+ el.style.setProperty(key, value);
1109
+ }
1110
+ }
1111
+ },
1112
+ onCustomResolve: ({ el, config: config2, resolve }) => {
1113
+ const { tag, onComplete } = config2;
1114
+ log({ tag, type: "HTML_SUCCESS", config: config2 });
1115
+ log({ tag, type: "PROCESS_COMPLETED", config: config2 });
1116
+ onComplete == null ? void 0 : onComplete();
1117
+ resolve();
1118
+ }
1119
+ }, callbacks);
1120
+ }
1121
+ };
1122
+ function mediaQueryCondition(QSL) {
1123
+ QSL.conditionHandlers.add(function(opt) {
1124
+ if (typeof opt !== "string" || !opt.startsWith("media:")) {
1125
+ return null;
1126
+ }
1127
+ return !window.matchMedia(opt.slice("media:".length)).matches;
1128
+ });
1129
+ }
1130
+ function languageCondition(QSL) {
1131
+ QSL.conditionHandlers.add(function(opt) {
1132
+ var _a;
1133
+ if (typeof opt !== "string" || !opt.startsWith("lang:")) {
1134
+ return null;
1135
+ }
1136
+ const p = opt.split(":");
1137
+ const t = p[1] || "equals";
1138
+ const v = p.slice(2).join(":");
1139
+ const l = navigator.language || ((_a = navigator.languages) == null ? void 0 : _a[0]) || "";
1140
+ switch (t) {
1141
+ case "equals":
1142
+ case "is":
1143
+ return l !== v;
1144
+ case "contains":
1145
+ return !l.includes(v);
1146
+ case "startsWith":
1147
+ return !l.startsWith(v);
1148
+ case "in":
1149
+ const ls = v.split(",").map((ll) => ll.trim());
1150
+ return !ls.includes(l);
1151
+ default:
1152
+ return true;
1153
+ }
1154
+ });
1155
+ }
1156
+ function timezoneCondition(QSL) {
1157
+ QSL.conditionHandlers.add(function(opt) {
1158
+ if (typeof opt !== "string" || !opt.startsWith("tz:") && !opt.startsWith("timezone:")) {
1159
+ return null;
1160
+ }
1161
+ const p = opt.split(":");
1162
+ const t = p[1] || "equals";
1163
+ const v = p.slice(2).join(":");
1164
+ try {
1165
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
1166
+ const o = -(/* @__PURE__ */ new Date()).getTimezoneOffset() / 60;
1167
+ switch (t) {
1168
+ case "equals":
1169
+ case "is":
1170
+ return tz !== v;
1171
+ case "contains":
1172
+ return !tz.includes(v);
1173
+ case "offset":
1174
+ return o !== parseInt(v);
1175
+ default:
1176
+ return true;
1177
+ }
1178
+ } catch (e) {
1179
+ return true;
1180
+ }
1181
+ });
1182
+ }
1183
+ function urlCondition(QSL) {
1184
+ QSL.conditionHandlers.add(function(opt) {
1185
+ if (typeof opt !== "string" || !opt.startsWith("url:")) {
1186
+ return null;
1187
+ }
1188
+ const lc = window.location;
1189
+ const hf = lc.href;
1190
+ const pn = lc.pathname;
1191
+ const se = lc.search;
1192
+ const hn = lc.hostname;
1193
+ const p = opt.split(":");
1194
+ const t = p[1];
1195
+ const v = p.slice(2).join(":");
1196
+ if (!t) return true;
1197
+ switch (t) {
1198
+ case "contains":
1199
+ return !hf.includes(v);
1200
+ case "path":
1201
+ return !pn.includes(v);
1202
+ case "pathStartsWith":
1203
+ return !pn.startsWith(v);
1204
+ case "pathEndsWith":
1205
+ return !pn.endsWith(v);
1206
+ case "query":
1207
+ if (se) {
1208
+ const q = new URLSearchParams(se);
1209
+ if (v.includes("=")) {
1210
+ const [key, val] = v.split("=");
1211
+ return q.get(key) !== val;
1212
+ } else {
1213
+ return !q.has(v);
1214
+ }
1215
+ } else {
1216
+ return true;
1217
+ }
1218
+ case "hostname":
1219
+ return !hn.includes(v);
1220
+ case "matches":
1221
+ try {
1222
+ return !new RegExp(v).test(hf);
1223
+ } catch (e) {
1224
+ return true;
1225
+ }
1226
+ case "pathMatches":
1227
+ try {
1228
+ return !new RegExp(v).test(pn);
1229
+ } catch (e) {
1230
+ return true;
1231
+ }
1232
+ default:
1233
+ return true;
1234
+ }
1235
+ });
1236
+ }
1237
+ function userAgentCondition(QSL) {
1238
+ QSL.conditionHandlers.add(function(opt) {
1239
+ if (typeof opt !== "string" || !opt.startsWith("ua:") && !opt.startsWith("userAgent:")) {
1240
+ return null;
1241
+ }
1242
+ const p = opt.split(":");
1243
+ const t = p[1] || "contains";
1244
+ const v = p.slice(2).join(":");
1245
+ const ua = navigator.userAgent || "";
1246
+ const uaLower = ua.toLowerCase();
1247
+ const vLower = v.toLowerCase();
1248
+ switch (t) {
1249
+ case "contains":
1250
+ if (!uaLower.includes(vLower)) return true;
1251
+ break;
1252
+ case "equals":
1253
+ case "is":
1254
+ if (ua !== v) return true;
1255
+ break;
1256
+ case "matches":
1257
+ try {
1258
+ if (!new RegExp(v, "i").test(ua)) return true;
1259
+ } catch (e) {
1260
+ return true;
1261
+ }
1262
+ break;
1263
+ case "browser":
1264
+ const bMap = {
1265
+ "chrome": /chrome/i.test(ua) && !/edg|opr/i.test(ua),
1266
+ "firefox": /firefox/i.test(ua),
1267
+ "safari": /safari/i.test(ua) && !/chrome|chromium|edg|opr/i.test(ua),
1268
+ "edge": /edg/i.test(ua),
1269
+ "opera": /opr/i.test(ua),
1270
+ "ie": /msie|trident/i.test(ua),
1271
+ "chromium": /chromium/i.test(ua)
1272
+ };
1273
+ const bKey = vLower;
1274
+ if (!bMap[bKey]) return true;
1275
+ break;
1276
+ case "device":
1277
+ const isM = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/i.test(ua);
1278
+ const isT = /tablet|ipad|playbook|silk/i.test(ua) || isM && /android/i.test(ua) && !/mobile/i.test(ua);
1279
+ const isD = !isM && !isT;
1280
+ switch (vLower) {
1281
+ case "mobile":
1282
+ if (!isM) return true;
1283
+ break;
1284
+ case "tablet":
1285
+ if (!isT) return true;
1286
+ break;
1287
+ case "desktop":
1288
+ if (!isD) return true;
1289
+ break;
1290
+ default:
1291
+ return true;
1292
+ }
1293
+ break;
1294
+ case "os":
1295
+ case "platform":
1296
+ const oMap = {
1297
+ "windows": /win/i.test(ua),
1298
+ "mac": /mac/i.test(ua),
1299
+ "ios": /iphone|ipad|ipod/i.test(ua),
1300
+ "android": /android/i.test(ua),
1301
+ "linux": /linux/i.test(ua) && !/android/i.test(ua),
1302
+ "unix": /unix/i.test(ua),
1303
+ "chromeos": /cros/i.test(ua)
1304
+ };
1305
+ if (!oMap[vLower]) return true;
1306
+ break;
1307
+ default:
1308
+ return true;
1309
+ }
1310
+ return false;
1311
+ });
1312
+ }
1313
+ function conditions(QSL) {
1314
+ mediaQueryCondition(QSL);
1315
+ languageCondition(QSL);
1316
+ timezoneCondition(QSL);
1317
+ urlCondition(QSL);
1318
+ userAgentCondition(QSL);
1319
+ }
1320
+ const arg = (opt, prefix) => opt.slice(prefix.length);
1321
+ const isPrefixed = (opt, prefix) => typeof opt === "string" && opt.startsWith(prefix);
1322
+ const whenElement = (selector, cb) => {
1323
+ let el = null;
1324
+ try {
1325
+ el = document.querySelector(selector);
1326
+ } catch (e) {
1327
+ cb(null);
1328
+ return;
1329
+ }
1330
+ if (el) {
1331
+ cb(el);
1332
+ return;
1333
+ }
1334
+ if (typeof MutationObserver !== "function") {
1335
+ cb(null);
1336
+ return;
1337
+ }
1338
+ const root = document.body || document.documentElement;
1339
+ if (!root) {
1340
+ cb(null);
1341
+ return;
1342
+ }
1343
+ const observer = new MutationObserver(() => {
1344
+ const found = document.querySelector(selector);
1345
+ if (found) {
1346
+ observer.disconnect();
1347
+ cb(found);
1348
+ }
1349
+ });
1350
+ observer.observe(root, { childList: true, subtree: true });
1351
+ };
1352
+ function loadTrigger(QSL) {
1353
+ QSL.triggerHandlers.add(function(opt) {
1354
+ if (opt !== "load") return null;
1355
+ return (cb) => {
1356
+ if (document.readyState === "complete") {
1357
+ cb();
1358
+ } else {
1359
+ window.addEventListener("load", () => cb(), { once: true });
1360
+ }
1361
+ };
1362
+ });
1363
+ }
1364
+ function idleTrigger(QSL) {
1365
+ QSL.triggerHandlers.add(function(opt) {
1366
+ if (opt !== "idle") return null;
1367
+ return (cb) => {
1368
+ if (typeof window.requestIdleCallback === "function") {
1369
+ window.requestIdleCallback(() => cb());
1370
+ } else {
1371
+ setTimeout(() => cb(), 200);
1372
+ }
1373
+ };
1374
+ });
1375
+ }
1376
+ function domReadyTrigger(QSL) {
1377
+ QSL.triggerHandlers.add(function(opt) {
1378
+ if (opt !== "domready") return null;
1379
+ return (cb) => {
1380
+ if (document.readyState === "interactive" || document.readyState === "complete") {
1381
+ cb();
1382
+ } else {
1383
+ document.addEventListener("DOMContentLoaded", () => cb(), { once: true });
1384
+ }
1385
+ };
1386
+ });
1387
+ }
1388
+ function delayTrigger(QSL) {
1389
+ QSL.triggerHandlers.add(function(opt) {
1390
+ if (!isPrefixed(opt, "delay:")) return null;
1391
+ const ms = parseInt(arg(opt, "delay:"), 10);
1392
+ return (cb) => setTimeout(cb, Number.isFinite(ms) && ms > 0 ? ms : 0);
1393
+ });
1394
+ }
1395
+ function hoverTrigger(QSL) {
1396
+ QSL.triggerHandlers.add(function(opt) {
1397
+ if (!isPrefixed(opt, "hover:")) return null;
1398
+ const selector = arg(opt, "hover:");
1399
+ return (cb) => {
1400
+ whenElement(selector, (el) => {
1401
+ if (!el) {
1402
+ cb();
1403
+ return;
1404
+ }
1405
+ el.addEventListener("mouseenter", () => cb(), { once: true, passive: true });
1406
+ });
1407
+ };
1408
+ });
1409
+ }
1410
+ function visibleTrigger(QSL) {
1411
+ QSL.triggerHandlers.add(function(opt) {
1412
+ if (!isPrefixed(opt, "visible:")) return null;
1413
+ const selector = arg(opt, "visible:");
1414
+ return (cb) => {
1415
+ whenElement(selector, (el) => {
1416
+ if (!el || typeof IntersectionObserver !== "function") {
1417
+ cb();
1418
+ return;
1419
+ }
1420
+ const observer = new IntersectionObserver((entries) => {
1421
+ for (const entry of entries) {
1422
+ if (entry.isIntersecting) {
1423
+ observer.disconnect();
1424
+ cb();
1425
+ return;
1426
+ }
1427
+ }
1428
+ });
1429
+ observer.observe(el);
1430
+ });
1431
+ };
1432
+ });
1433
+ }
1434
+ function appearsTrigger(QSL) {
1435
+ QSL.triggerHandlers.add(function(opt) {
1436
+ if (!isPrefixed(opt, "appears:")) return null;
1437
+ const selector = arg(opt, "appears:");
1438
+ return (cb) => whenElement(selector, () => cb());
1439
+ });
1440
+ }
1441
+ function mediaQueryTrigger(QSL) {
1442
+ QSL.triggerHandlers.add(function(opt, o) {
1443
+ if (!isPrefixed(opt, "media:")) return null;
1444
+ const query = arg(opt, "media:");
1445
+ return (cb) => {
1446
+ if (!query.length || typeof window.matchMedia !== "function") {
1447
+ if (o) o.skipped = true;
1448
+ cb();
1449
+ return;
1450
+ }
1451
+ const mql = window.matchMedia(query);
1452
+ if (mql.matches) {
1453
+ cb();
1454
+ return;
1455
+ }
1456
+ const handler = (e) => {
1457
+ if (!e.matches) return;
1458
+ mql.removeEventListener("change", handler);
1459
+ cb();
1460
+ };
1461
+ mql.addEventListener("change", handler);
1462
+ };
1463
+ });
1464
+ }
1465
+ function triggers(QSL) {
1466
+ loadTrigger(QSL);
1467
+ idleTrigger(QSL);
1468
+ domReadyTrigger(QSL);
1469
+ delayTrigger(QSL);
1470
+ hoverTrigger(QSL);
1471
+ visibleTrigger(QSL);
1472
+ appearsTrigger(QSL);
1473
+ mediaQueryTrigger(QSL);
1474
+ }
1475
+ function logger(QSL) {
1476
+ QSL.initActions.add(function() {
1477
+ QSL.logger = {
1478
+ VERSION: "qsl-logger",
1479
+ LOG: {
1480
+ LOGGER_LOADED: "[QSL] Logger loaded",
1481
+ LOGGER_LOAD_ERROR: "[QSL] Logger load error:",
1482
+ UNKNOWN_TYPE: "[QSL] Unknown type:",
1483
+ PROCESS_STARTED: "[QSL] Process started:",
1484
+ PROCESS_COMPLETED: "[QSL] Process completed:",
1485
+ PROCESS_FAILED: "[QSL] Process failed:",
1486
+ STYLESHEET_STARTED: "[QSL] Stylesheet loading:",
1487
+ STYLESHEET_LOADED: "[QSL] Stylesheet loaded:",
1488
+ STYLESHEET_FAILED: "[QSL] Stylesheet failed to load:",
1489
+ INLINE_SCRIPT_STARTED: "[QSL] Inline script loading:",
1490
+ INLINE_SCRIPT_SUCCESS: "[QSL] Inline script loaded:",
1491
+ INLINE_SCRIPT_ERROR: "[QSL] Inline script load error:",
1492
+ INLINE_STYLE_STARTED: "[QSL] Inline style loading:",
1493
+ INLINE_STYLE_SUCCESS: "[QSL] Inline style loaded:",
1494
+ INLINE_STYLE_ERROR: "[QSL] Inline style load error:",
1495
+ IMAGE_STARTED: "[QSL] Image pixel loading:",
1496
+ IMAGE_LOADED: "[QSL] Image pixel loaded:",
1497
+ IMAGE_FAILED: "[QSL] Image pixel failed:",
1498
+ SHADOW_STARTED: "[QSL] Shadow element loading:",
1499
+ SHADOW_SUCCESS: "[QSL] Shadow element loaded:",
1500
+ SHADOW_FAILED: "[QSL] Shadow element failed:",
1501
+ HTML_STARTED: "[QSL] HTML element loading:",
1502
+ HTML_SUCCESS: "[QSL] HTML element loaded:",
1503
+ HTML_FAILED: "[QSL] HTML element failed:",
1504
+ PRELOAD_ERROR: "[QSL] Preload error:",
1505
+ FLOW_DEP_SKIPPED: "[QSL] Flow dependency missed:",
1506
+ DEP_NOT_FOUND: "[QSL] Dependency not found:",
1507
+ RESET: "[QSL] Global reset",
1508
+ ALL_COMPLETED: "[QSL] Loading is completed"
1509
+ },
1510
+ log(type, ...args) {
1511
+ if (this.LOG[type]) {
1512
+ console.log(this.LOG[type], ...args, { timestamp: Date.now() });
1513
+ } else {
1514
+ console.log("[QSL] " + type, ...args);
1515
+ }
1516
+ },
1517
+ error(type, ...args) {
1518
+ if (this.LOG[type]) {
1519
+ console.error(this.LOG[type], ...args);
1520
+ } else {
1521
+ console.error("[QSL] " + type, ...args);
1522
+ }
1523
+ }
1524
+ };
1525
+ });
1526
+ }
1527
+ function events(QSL) {
1528
+ const customEvents = /* @__PURE__ */ new Map();
1529
+ const processElementMap = /* @__PURE__ */ new WeakMap();
1530
+ let documentListener = null;
1531
+ let windowListener = null;
1532
+ let isIntercepting = false;
1533
+ const normalizeScriptPath = (u) => {
1534
+ if (!u) return "";
1535
+ try {
1536
+ return u.includes("://") ? new URL(u).pathname : u.split("?")[0].split("#")[0];
1537
+ } catch (e) {
1538
+ return u.split("?")[0].split("#")[0];
1539
+ }
1540
+ };
1541
+ QSL.loadActions.add(function() {
1542
+ if (isIntercepting) return;
1543
+ documentListener = document.addEventListener;
1544
+ windowListener = window.addEventListener;
1545
+ isIntercepting = true;
1546
+ const iterator = (type, eventType, changeEventName) => {
1547
+ var _a;
1548
+ let currentScriptId = null;
1549
+ let targetFlowId = null;
1550
+ if (document.currentScript) {
1551
+ const processElement = processElementMap.get(document.currentScript);
1552
+ if (processElement) {
1553
+ currentScriptId = processElement.processId;
1554
+ targetFlowId = processElement.flowId;
1555
+ }
1556
+ }
1557
+ if (!currentScriptId && this.currentProcessPerFlow.size) {
1558
+ for (const [flowId, processId] of this.currentProcessPerFlow) {
1559
+ if (processId) {
1560
+ currentScriptId = processId;
1561
+ targetFlowId = flowId;
1562
+ break;
1563
+ }
1564
+ }
1565
+ }
1566
+ if (!currentScriptId) {
1567
+ const stack = new Error().stack;
1568
+ if (stack) {
1569
+ const lines = stack.split("\n");
1570
+ for (let i = 2; i < lines.length; i++) {
1571
+ const match = lines[i].match(/([^()\s]+\.js(?:\?[^:)]*)?):\d+(?::\d+)?/);
1572
+ if (match) {
1573
+ const file = match[1];
1574
+ const qIndex = file.indexOf("?");
1575
+ const stackFile = qIndex === -1 ? file.trim() : file.slice(0, qIndex).trim();
1576
+ if (stackFile) {
1577
+ const qIdx = stackFile.indexOf("?");
1578
+ const hIdx = stackFile.indexOf("#");
1579
+ const endIdx = qIdx === -1 ? hIdx === -1 ? stackFile.length : hIdx : hIdx === -1 ? qIdx : Math.min(qIdx, hIdx);
1580
+ let normalizedFile = stackFile.slice(0, endIdx);
1581
+ try {
1582
+ if (normalizedFile.includes("://")) {
1583
+ normalizedFile = new URL(normalizedFile).pathname;
1584
+ }
1585
+ } catch (e) {
1586
+ }
1587
+ const lastSlash = normalizedFile.lastIndexOf("/");
1588
+ const fileName = lastSlash === -1 ? normalizedFile : normalizedFile.slice(lastSlash + 1);
1589
+ for (const [flowId, processes] of this.flows) {
1590
+ for (const process of processes) {
1591
+ if (process.src && process.type === "script") {
1592
+ const normalizedSrc = normalizeScriptPath(process.src);
1593
+ const srcLastSlash = normalizedSrc.lastIndexOf("/");
1594
+ const srcFileName = srcLastSlash === -1 ? normalizedSrc : normalizedSrc.slice(srcLastSlash + 1);
1595
+ if (normalizedFile === normalizedSrc || fileName && fileName === srcFileName) {
1596
+ currentScriptId = process.id;
1597
+ targetFlowId = flowId;
1598
+ break;
1599
+ }
1600
+ }
1601
+ }
1602
+ if (currentScriptId) break;
1603
+ }
1604
+ if (currentScriptId) break;
1605
+ }
1606
+ }
1607
+ }
1608
+ }
1609
+ }
1610
+ if (currentScriptId && targetFlowId) {
1611
+ const flow = this.flows.get(targetFlowId);
1612
+ const process = flow == null ? void 0 : flow.find((p) => p.id === currentScriptId || p.id === this.PREFIX + currentScriptId);
1613
+ if (process) {
1614
+ const shouldFireEvents = process.fireEvents !== false && ((_a = this.flowOptions.get(targetFlowId)) == null ? void 0 : _a.fireEvents) !== false;
1615
+ if (shouldFireEvents) {
1616
+ const eventName = `${type}:${process.id}`;
1617
+ if (!customEvents.has(process.id)) customEvents.set(process.id, []);
1618
+ const events2 = customEvents.get(process.id);
1619
+ if (!events2.some((e) => e.name === eventName)) events2.push({ type: eventType, name: eventName });
1620
+ if (changeEventName) type = eventName;
1621
+ }
1622
+ }
1623
+ }
1624
+ return type;
1625
+ };
1626
+ document.addEventListener = (type, listener, opts) => {
1627
+ if (type === "DOMContentLoaded" && this.LIFECYCLE.DOMREADY) {
1628
+ const trackedType = iterator.call(this, type, this.EVENTS.DOMREADY, true);
1629
+ if (trackedType !== type) {
1630
+ type = trackedType;
1631
+ queueMicrotask(() => document.dispatchEvent(new Event(trackedType)));
1632
+ }
1633
+ }
1634
+ return documentListener.call(document, type, listener, opts);
1635
+ };
1636
+ window.addEventListener = (type, listener, opts) => {
1637
+ if (type === "load" && this.LIFECYCLE.LOADED) {
1638
+ const trackedType = iterator.call(this, type, this.EVENTS.LOADED, true);
1639
+ if (trackedType !== type) {
1640
+ type = trackedType;
1641
+ queueMicrotask(() => window.dispatchEvent(new Event(trackedType)));
1642
+ }
1643
+ }
1644
+ return windowListener.call(window, type, listener, opts);
1645
+ };
1646
+ });
1647
+ QSL.handlerCallbacksFilters.add(function(process) {
1648
+ return {
1649
+ registerProcessElement: (el, config) => {
1650
+ processElementMap.set(el, { flowId: config.flowId, processId: config.id });
1651
+ }
1652
+ };
1653
+ });
1654
+ QSL.processCompleteActions.add(function(process) {
1655
+ const events2 = customEvents.get(process.id);
1656
+ if (events2 && Array.isArray(events2)) {
1657
+ for (const event of events2) {
1658
+ if (event.type === this.EVENTS.DOMREADY) {
1659
+ if (this.LIFECYCLE.DOMREADY) {
1660
+ document.dispatchEvent(new Event(event.name));
1661
+ } else {
1662
+ document.addEventListener("DOMContentLoaded", () => {
1663
+ document.dispatchEvent(new Event(event.name));
1664
+ }, { once: true });
1665
+ }
1666
+ } else if (event.type === this.EVENTS.LOADED) {
1667
+ if (this.LIFECYCLE.LOADED) {
1668
+ window.dispatchEvent(new Event(event.name));
1669
+ } else {
1670
+ window.addEventListener("load", () => {
1671
+ window.dispatchEvent(new Event(event.name));
1672
+ }, { once: true });
1673
+ }
1674
+ }
1675
+ }
1676
+ }
1677
+ });
1678
+ QSL.resetActions.add(function() {
1679
+ if (isIntercepting && documentListener && windowListener) {
1680
+ document.addEventListener = documentListener;
1681
+ window.addEventListener = windowListener;
1682
+ isIntercepting = false;
1683
+ }
1684
+ });
1685
+ QSL.customEvents = customEvents;
1686
+ }
1687
+ function circ(QSL) {
1688
+ QSL.loadActions.add(function() {
1689
+ const detectCircularDependency = (id, getDeps, visited = /* @__PURE__ */ new Set()) => {
1690
+ if (visited.has(id)) return true;
1691
+ visited.add(id);
1692
+ const deps = getDeps(id) || [];
1693
+ for (const depId of deps) {
1694
+ if (detectCircularDependency(depId, getDeps, new Set(visited))) return true;
1695
+ }
1696
+ return false;
1697
+ };
1698
+ const getFlowDeps = (id) => {
1699
+ var _a;
1700
+ return ((_a = this.flowOptions.get(this.normalizeFlowId(id))) == null ? void 0 : _a.depends) || [];
1701
+ };
1702
+ for (const [fid, options] of this.flowOptions.entries()) {
1703
+ if (Array.isArray(options.depends) && options.depends.length) {
1704
+ if (detectCircularDependency(fid, getFlowDeps)) {
1705
+ this.log("CIRC_FLOW_DEP_SKIPPED", fid, options.depends);
1706
+ this.setFlowOptions({ status: this.FLOW_STATE.COMPLETED }, fid);
1707
+ }
1708
+ }
1709
+ }
1710
+ const getProcDeps = (id) => {
1711
+ for (const flow of this.flows.values()) {
1712
+ const proc = flow.find((p) => p.id === id);
1713
+ if (proc && Array.isArray(proc.depends)) return proc.depends.map((dep) => this.PREFIX + dep);
1714
+ }
1715
+ return [];
1716
+ };
1717
+ for (const flow of this.flows.values()) {
1718
+ for (const process of flow) {
1719
+ if (Array.isArray(process.depends) && process.depends.length) {
1720
+ if (detectCircularDependency(process.id, getProcDeps)) {
1721
+ this.log("CIRC_PROCESS_DEP_SKIPPED", process.id, process.depends);
1722
+ process.condition = false;
1723
+ }
1724
+ }
1725
+ }
1726
+ }
1727
+ });
1728
+ if (QSL.logger && QSL.logger.VERSION === "qsl-logger") {
1729
+ QSL.logger.LOG.CIRC_FLOW_DEP_SKIPPED = "[QSL] Circular flow dependency skipped:";
1730
+ QSL.logger.LOG.CIRC_PROCESS_DEP_SKIPPED = "[QSL] Circular process dependency skipped:";
1731
+ }
1732
+ }
1733
+ function dynamic(QSL) {
1734
+ QSL.addProcessFilters.add(function(flowId, config) {
1735
+ if (this.hasStarted && !flowId) {
1736
+ flowId = "dynamic-" + Math.random().toString(36).slice(2);
1737
+ config.paused = true;
1738
+ }
1739
+ return [flowId, config];
1740
+ });
1741
+ QSL.flowIdFilters.add(function(flowIds) {
1742
+ return flowIds.filter((fid) => !fid.includes("dynamic"));
1743
+ });
1744
+ QSL.completedFlowsActions.add(function(flowsDone, flows, flowOptions) {
1745
+ if (!flowsDone || !flows || !flowOptions) return true;
1746
+ const nonDynamicFlowsDone = [...flowOptions.entries()].filter(([fid]) => !fid.includes("dynamic")).every(([, opt]) => opt.status === this.FLOW_STATE.COMPLETED);
1747
+ if (!nonDynamicFlowsDone) return false;
1748
+ const dynamicFlowIds = [...flows.keys()].filter((fid) => fid.includes("dynamic"));
1749
+ if (dynamicFlowIds.length === 0) return true;
1750
+ for (const dynamicFlowId of dynamicFlowIds) {
1751
+ const dynamicOptions = flowOptions.get(dynamicFlowId);
1752
+ if (dynamicOptions && dynamicOptions.status !== this.FLOW_STATE.COMPLETED) {
1753
+ if (dynamicOptions.status === this.FLOW_STATE.READY) {
1754
+ this.setFlowOptions({ status: this.FLOW_STATE.RUNNING }, dynamicFlowId);
1755
+ this.runFlow(dynamicFlowId);
1756
+ }
1757
+ return false;
1758
+ }
1759
+ }
1760
+ return true;
1761
+ });
1762
+ }
1763
+ function simpleEvents(QSL) {
1764
+ QSL.allCompleteActions.add(function() {
1765
+ document.dispatchEvent(new Event("DOMContentLoaded"));
1766
+ window.dispatchEvent(new Event("load"));
1767
+ });
1768
+ }
1769
+ export {
1770
+ HTML,
1771
+ InlineScript,
1772
+ InlineStyle,
1773
+ Pixel,
1774
+ Script,
1775
+ Shadow,
1776
+ Stylesheet,
1777
+ appearsTrigger,
1778
+ circ,
1779
+ conditions,
1780
+ core,
1781
+ core as default,
1782
+ delayTrigger,
1783
+ domReadyTrigger,
1784
+ dynamic,
1785
+ events,
1786
+ hoverTrigger,
1787
+ idleTrigger,
1788
+ languageCondition,
1789
+ loadTrigger,
1790
+ logger,
1791
+ mediaQueryCondition,
1792
+ mediaQueryTrigger,
1793
+ simpleEvents,
1794
+ timezoneCondition,
1795
+ triggers,
1796
+ urlCondition,
1797
+ userAgentCondition,
1798
+ visibleTrigger
1799
+ };
1800
+ //# sourceMappingURL=qsl.mjs.map