tiny-essentials 1.28.0 → 1.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/changelog/1/28/1.md +23 -0
  2. package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
  3. package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
  4. package/dist/v1/TinyAnalogClock.min.js +1 -1
  5. package/dist/v1/TinyBasicsEs.min.js +1 -1
  6. package/dist/v1/TinyDayNightCycle.min.js +1 -1
  7. package/dist/v1/TinyDragDropDetector.min.js +1 -1
  8. package/dist/v1/TinyDragger.min.js +1 -1
  9. package/dist/v1/TinyElementObserver.min.js +1 -1
  10. package/dist/v1/TinyEssentials.min.js +1 -1
  11. package/dist/v1/TinyGamepad.min.js +1 -1
  12. package/dist/v1/TinyHtml.min.js +1 -1
  13. package/dist/v1/TinyI18.min.js +1 -1
  14. package/dist/v1/TinyIframeEvents.min.js +1 -1
  15. package/dist/v1/TinyLocalStorage.min.js +1 -1
  16. package/dist/v1/TinyMediaPlayer.min.js +1 -1
  17. package/dist/v1/TinyNewWinEvents.min.js +1 -1
  18. package/dist/v1/TinyNotifyCenter.min.js +1 -1
  19. package/dist/v1/TinyRadioFm.min.js +1 -1
  20. package/dist/v1/TinyRateLimiter.min.js +1 -1
  21. package/dist/v1/TinySmartScroller.min.js +1 -1
  22. package/dist/v1/TinyTextDiffer.min.js +1 -1
  23. package/dist/v1/TinyTextarea.min.js +1 -1
  24. package/dist/v1/TinyTimeout.min.js +1 -1
  25. package/dist/v1/TinyToastNotify.min.js +1 -1
  26. package/dist/v1/TinyUploadClicker.min.js +1 -1
  27. package/dist/v1/UltraRandomMsgGen.min.js +1 -1
  28. package/dist/v1/basics/array.cjs +57 -9
  29. package/dist/v1/basics/array.d.mts +27 -11
  30. package/dist/v1/basics/array.mjs +51 -9
  31. package/dist/v1/basics/clock.cjs +94 -42
  32. package/dist/v1/basics/clock.d.mts +10 -10
  33. package/dist/v1/basics/clock.mjs +91 -54
  34. package/dist/v1/basics/deprecated/html.cjs +246 -0
  35. package/dist/v1/basics/deprecated/html.d.mts +63 -0
  36. package/dist/v1/basics/deprecated/html.mjs +190 -0
  37. package/dist/v1/basics/html.cjs +149 -130
  38. package/dist/v1/basics/html.d.mts +26 -61
  39. package/dist/v1/basics/html.mjs +113 -105
  40. package/dist/v1/basics/index.cjs +2 -0
  41. package/dist/v1/basics/index.d.mts +3 -1
  42. package/dist/v1/basics/index.mjs +3 -3
  43. package/dist/v1/basics/mediaContent.cjs +51 -9
  44. package/dist/v1/basics/mediaContent.d.mts +0 -87
  45. package/dist/v1/basics/mediaContent.mjs +40 -10
  46. package/dist/v1/basics/objChecker.cjs +7 -5
  47. package/dist/v1/basics/objChecker.d.mts +3 -2
  48. package/dist/v1/basics/objChecker.mjs +6 -6
  49. package/dist/v1/basics/objFilter.cjs +40 -7
  50. package/dist/v1/basics/objFilter.d.mts +6 -6
  51. package/dist/v1/basics/objFilter.mjs +32 -7
  52. package/dist/v1/basics/simpleMath.cjs +81 -25
  53. package/dist/v1/basics/simpleMath.d.mts +2 -2
  54. package/dist/v1/basics/simpleMath.mjs +70 -27
  55. package/dist/v1/basics/text.cjs +76 -31
  56. package/dist/v1/basics/text.d.mts +69 -7
  57. package/dist/v1/basics/text.mjs +62 -31
  58. package/dist/v1/index.cjs +4 -0
  59. package/dist/v1/index.d.mts +4 -1
  60. package/dist/v1/index.mjs +4 -3
  61. package/dist/v1/libs/TinyAdvancedRaffle.cjs +64 -50
  62. package/dist/v1/libs/TinyAdvancedRaffle.d.mts +4 -13
  63. package/dist/v1/libs/TinyAdvancedRaffle.mjs +62 -49
  64. package/dist/v1/libs/TinyAfterScrollWatcher.cjs +17 -1
  65. package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +4 -1
  66. package/dist/v1/libs/TinyAfterScrollWatcher.mjs +15 -1
  67. package/dist/v1/libs/TinyAnalogClock.cjs +60 -0
  68. package/dist/v1/libs/TinyAnalogClock.d.mts +6 -0
  69. package/dist/v1/libs/TinyAnalogClock.mjs +57 -0
  70. package/dist/v1/libs/TinyClipboard.cjs +2 -0
  71. package/dist/v1/libs/TinyClipboard.d.mts +4 -2
  72. package/dist/v1/libs/TinyClipboard.mjs +2 -0
  73. package/dist/v1/libs/TinyColorConverter.cjs +1 -0
  74. package/dist/v1/libs/TinyColorConverter.d.mts +2 -1
  75. package/dist/v1/libs/TinyColorConverter.mjs +1 -0
  76. package/dist/v1/libs/TinyDayNightCycle.cjs +67 -42
  77. package/dist/v1/libs/TinyDayNightCycle.d.mts +2 -7
  78. package/dist/v1/libs/TinyDayNightCycle.mjs +65 -41
  79. package/dist/v1/libs/TinyDragDropDetector.cjs +25 -0
  80. package/dist/v1/libs/TinyDragDropDetector.d.mts +6 -0
  81. package/dist/v1/libs/TinyDragDropDetector.mjs +22 -0
  82. package/dist/v1/libs/TinyDragger.cjs +46 -19
  83. package/dist/v1/libs/TinyDragger.mjs +45 -18
  84. package/dist/v1/libs/TinyElementObserver.cjs +39 -0
  85. package/dist/v1/libs/TinyElementObserver.d.mts +6 -0
  86. package/dist/v1/libs/TinyElementObserver.mjs +36 -0
  87. package/dist/v1/libs/TinyGamepad.cjs +131 -1
  88. package/dist/v1/libs/TinyGamepad.mjs +129 -1
  89. package/dist/v1/libs/TinyHtml.cjs +1 -1
  90. package/dist/v1/libs/TinyHtml.mjs +2 -2
  91. package/dist/v1/libs/TinyI18.cjs +61 -0
  92. package/dist/v1/libs/TinyI18.d.mts +14 -0
  93. package/dist/v1/libs/TinyI18.mjs +55 -0
  94. package/dist/v1/libs/TinyIframeEvents.cjs +18 -1
  95. package/dist/v1/libs/TinyIframeEvents.mjs +18 -1
  96. package/dist/v1/libs/TinyLocalStorage.cjs +48 -0
  97. package/dist/v1/libs/TinyLocalStorage.d.mts +6 -0
  98. package/dist/v1/libs/TinyLocalStorage.mjs +45 -0
  99. package/dist/v1/libs/TinyMediaPlayer.cjs +72 -0
  100. package/dist/v1/libs/TinyMediaPlayer.d.mts +10 -0
  101. package/dist/v1/libs/TinyMediaPlayer.mjs +66 -0
  102. package/dist/v1/libs/TinyNewWinEvents.cjs +29 -0
  103. package/dist/v1/libs/TinyNewWinEvents.d.mts +6 -0
  104. package/dist/v1/libs/TinyNewWinEvents.mjs +26 -0
  105. package/dist/v1/libs/TinyNotifyCenter.cjs +36 -0
  106. package/dist/v1/libs/TinyNotifyCenter.d.mts +6 -0
  107. package/dist/v1/libs/TinyNotifyCenter.mjs +32 -0
  108. package/dist/v1/libs/TinyRadioFm.cjs +38 -0
  109. package/dist/v1/libs/TinyRadioFm.d.mts +1 -0
  110. package/dist/v1/libs/TinyRadioFm.mjs +35 -0
  111. package/dist/v1/libs/TinyRateLimiter.cjs +52 -0
  112. package/dist/v1/libs/TinyRateLimiter.d.mts +6 -0
  113. package/dist/v1/libs/TinyRateLimiter.mjs +48 -0
  114. package/dist/v1/libs/TinySmartScroller.cjs +52 -3
  115. package/dist/v1/libs/TinySmartScroller.d.mts +17 -15
  116. package/dist/v1/libs/TinySmartScroller.mjs +51 -5
  117. package/dist/v1/libs/TinyTextDiffer.cjs +19 -18
  118. package/dist/v1/libs/TinyTextDiffer.d.mts +1 -0
  119. package/dist/v1/libs/TinyTextDiffer.mjs +16 -17
  120. package/dist/v1/libs/TinyTextarea.cjs +19 -0
  121. package/dist/v1/libs/TinyTextarea.d.mts +6 -0
  122. package/dist/v1/libs/TinyTextarea.mjs +17 -0
  123. package/dist/v1/libs/TinyTimeout.cjs +11 -1
  124. package/dist/v1/libs/TinyTimeout.mjs +9 -1
  125. package/dist/v1/libs/TinyToastNotify.cjs +35 -0
  126. package/dist/v1/libs/TinyToastNotify.d.mts +6 -0
  127. package/dist/v1/libs/TinyToastNotify.mjs +31 -0
  128. package/dist/v1/libs/TinyUploadClicker.cjs +19 -0
  129. package/dist/v1/libs/TinyUploadClicker.d.mts +6 -0
  130. package/dist/v1/libs/TinyUploadClicker.mjs +17 -0
  131. package/dist/v1/libs/UltraRandomMsgGen.cjs +148 -35
  132. package/dist/v1/libs/UltraRandomMsgGen.d.mts +17 -3
  133. package/dist/v1/libs/UltraRandomMsgGen.mjs +133 -34
  134. package/dist/v1/libs/utils.cjs +21 -0
  135. package/dist/v1/libs/utils.d.mts +2 -0
  136. package/dist/v1/libs/utils.mjs +16 -0
  137. package/docs/v1/README.md +1 -0
  138. package/docs/v1/basics/array.md +2 -2
  139. package/docs/v1/basics/deprecated/html.md +17 -0
  140. package/docs/v1/basics/fullScreen.md +1 -1
  141. package/docs/v1/basics/html.md +12 -26
  142. package/docs/v1/basics/mediaContent.md +1 -1
  143. package/docs/v1/basics/objChecker.md +1 -1
  144. package/docs/v1/basics/text.md +2 -2
  145. package/docs/v1/fileManager/main.md +1 -1
  146. package/docs/v1/libs/ColorSafeStringify.md +1 -1
  147. package/docs/v1/libs/TinyAfterScrollWatcher.md +1 -1
  148. package/docs/v1/libs/TinyAnalogClock.md +1 -1
  149. package/docs/v1/libs/TinyArrayComparator.md +1 -1
  150. package/docs/v1/libs/TinyArrayPaginator.md +1 -1
  151. package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +2 -2
  152. package/docs/v1/libs/TinyClassManager.md +1 -1
  153. package/docs/v1/libs/TinyClipboard.md +1 -1
  154. package/docs/v1/libs/TinyCookieConsent.md +1 -1
  155. package/docs/v1/libs/TinyDomReadyManager.md +1 -1
  156. package/docs/v1/libs/TinyDragDropDetector.md +1 -1
  157. package/docs/v1/libs/TinyDragger.md +1 -1
  158. package/docs/v1/libs/TinyElementObserver.md +1 -1
  159. package/docs/v1/libs/TinyHtml.md +1 -1
  160. package/docs/v1/libs/TinyIframeEvents.md +2 -2
  161. package/docs/v1/libs/TinyLevelUp.md +1 -1
  162. package/docs/v1/libs/TinyLoadingScreen.md +1 -1
  163. package/docs/v1/libs/TinyNewWinEvents.md +2 -2
  164. package/docs/v1/libs/TinyNotifications.md +1 -1
  165. package/docs/v1/libs/TinyPromiseQueue.md +2 -2
  166. package/docs/v1/libs/TinyTextDiffer.md +1 -1
  167. package/docs/v1/libs/TinyTextarea.md +1 -1
  168. package/package.json +10 -1
@@ -1,3 +1,5 @@
1
+ import { createCheckDestroyed } from './utils.mjs';
2
+ const checkDestroy = createCheckDestroyed('TinyRateLimiter');
1
3
  /**
2
4
  * Callback triggered when a group's stored hit history exceeds
3
5
  * the configured memory limit.
@@ -66,6 +68,19 @@
66
68
  * and safe to use in long-running Node.js processes.
67
69
  */
68
70
  class TinyRateLimiter {
71
+ /**
72
+ * Tracks whether the instance has been destroyed.
73
+ * @type {boolean}
74
+ */
75
+ #destroyed = false;
76
+ /**
77
+ * Gets the current destruction status of the instance.
78
+ *
79
+ * @returns {boolean} True if the instance is destroyed, false otherwise.
80
+ */
81
+ get destroyed() {
82
+ return this.#destroyed;
83
+ }
69
84
  /**
70
85
  * Maximum number of timestamps stored per group.
71
86
  * When exceeded, older entries are discarded.
@@ -170,6 +185,7 @@ class TinyRateLimiter {
170
185
  * @param {OnMemoryExceeded} callback
171
186
  */
172
187
  setOnMemoryExceeded(callback) {
188
+ checkDestroy(this.#destroyed);
173
189
  if (typeof callback !== 'function')
174
190
  throw new Error('onMemoryExceeded must be a function');
175
191
  this.#onMemoryExceeded = callback;
@@ -178,6 +194,7 @@ class TinyRateLimiter {
178
194
  * Removes the memory-exceeded callback.
179
195
  */
180
196
  clearOnMemoryExceeded() {
197
+ checkDestroy(this.#destroyed);
181
198
  this.#onMemoryExceeded = null;
182
199
  }
183
200
  /**
@@ -195,6 +212,7 @@ class TinyRateLimiter {
195
212
  * @param {OnGroupExpired} callback - A function that receives the expired groupId.
196
213
  */
197
214
  setOnGroupExpired(callback) {
215
+ checkDestroy(this.#destroyed);
198
216
  if (typeof callback !== 'function')
199
217
  throw new Error('onGroupExpired must be a function');
200
218
  this.#onGroupExpired = callback;
@@ -203,6 +221,7 @@ class TinyRateLimiter {
203
221
  * Removes the group-expiration callback.
204
222
  */
205
223
  clearOnGroupExpired() {
224
+ checkDestroy(this.#destroyed);
206
225
  this.#onGroupExpired = null;
207
226
  }
208
227
  /**
@@ -262,6 +281,7 @@ class TinyRateLimiter {
262
281
  * @returns {boolean}
263
282
  */
264
283
  isGroupId(id) {
284
+ checkDestroy(this.#destroyed);
265
285
  const result = this.groupFlags.get(id);
266
286
  return typeof result === 'boolean' ? result : false;
267
287
  }
@@ -271,6 +291,7 @@ class TinyRateLimiter {
271
291
  * @returns {string[]}
272
292
  */
273
293
  getUsersInGroup(groupId) {
294
+ checkDestroy(this.#destroyed);
274
295
  const users = [];
275
296
  for (const [userId, assignedGroup] of this.userToGroup.entries()) {
276
297
  if (assignedGroup === groupId) {
@@ -285,6 +306,7 @@ class TinyRateLimiter {
285
306
  * @param {number} ttl
286
307
  */
287
308
  setGroupTTL(groupId, ttl) {
309
+ checkDestroy(this.#destroyed);
288
310
  if (typeof ttl !== 'number' || !Number.isFinite(ttl) || ttl <= 0)
289
311
  throw new Error('TTL must be a positive number in milliseconds');
290
312
  this.groupTTL.set(groupId, ttl);
@@ -295,6 +317,7 @@ class TinyRateLimiter {
295
317
  * @returns {number|null}
296
318
  */
297
319
  getGroupTTL(groupId) {
320
+ checkDestroy(this.#destroyed);
298
321
  return this.groupTTL.get(groupId) ?? null;
299
322
  }
300
323
  /**
@@ -302,6 +325,7 @@ class TinyRateLimiter {
302
325
  * @param {string} groupId
303
326
  */
304
327
  deleteGroupTTL(groupId) {
328
+ checkDestroy(this.#destroyed);
305
329
  this.groupTTL.delete(groupId);
306
330
  }
307
331
  /**
@@ -315,6 +339,7 @@ class TinyRateLimiter {
315
339
  * @throws {Error} If the user belongs to another group
316
340
  */
317
341
  assignToGroup(userId, groupId) {
342
+ checkDestroy(this.#destroyed);
318
343
  const existingGroup = this.userToGroup.get(userId);
319
344
  if (existingGroup && existingGroup !== groupId)
320
345
  throw new Error(`User ${userId} is already assigned to group ${existingGroup}`);
@@ -363,6 +388,7 @@ class TinyRateLimiter {
363
388
  * @returns {string}
364
389
  */
365
390
  getGroupId(userId) {
391
+ checkDestroy(this.#destroyed);
366
392
  return this.userToGroup.get(userId) || userId; // fallback: use userId as own group
367
393
  }
368
394
  /**
@@ -388,6 +414,7 @@ class TinyRateLimiter {
388
414
  * @param {string} userId
389
415
  */
390
416
  hit(userId) {
417
+ checkDestroy(this.#destroyed);
391
418
  const groupId = this.getGroupId(userId);
392
419
  const now = Date.now();
393
420
  if (!this.groupData.has(groupId)) {
@@ -437,6 +464,7 @@ class TinyRateLimiter {
437
464
  * @returns {boolean}
438
465
  */
439
466
  isRateLimited(userId) {
467
+ checkDestroy(this.#destroyed);
440
468
  const groupId = this.getGroupId(userId);
441
469
  if (!this.groupData.has(groupId))
442
470
  return false;
@@ -468,6 +496,7 @@ class TinyRateLimiter {
468
496
  * @param {string} groupId
469
497
  */
470
498
  resetGroup(groupId) {
499
+ checkDestroy(this.#destroyed);
471
500
  this.groupFlags.delete(groupId);
472
501
  this.groupData.delete(groupId);
473
502
  this.lastSeen.delete(groupId);
@@ -478,6 +507,7 @@ class TinyRateLimiter {
478
507
  * @param {string} userId
479
508
  */
480
509
  resetUserGroup(userId) {
510
+ checkDestroy(this.#destroyed);
481
511
  this.userToGroup.delete(userId);
482
512
  }
483
513
  /**
@@ -486,6 +516,7 @@ class TinyRateLimiter {
486
516
  * @param {number[]} timestamps
487
517
  */
488
518
  setData(groupId, timestamps) {
519
+ checkDestroy(this.#destroyed);
489
520
  if (!Array.isArray(timestamps))
490
521
  throw new Error('timestamps must be an array of numbers.');
491
522
  for (const t of timestamps) {
@@ -504,6 +535,7 @@ class TinyRateLimiter {
504
535
  * @returns {boolean}
505
536
  */
506
537
  hasData(groupId) {
538
+ checkDestroy(this.#destroyed);
507
539
  return this.groupData.has(groupId);
508
540
  }
509
541
  /**
@@ -512,6 +544,7 @@ class TinyRateLimiter {
512
544
  * @returns {number[]}
513
545
  */
514
546
  getData(groupId) {
547
+ checkDestroy(this.#destroyed);
515
548
  return this.groupData.get(groupId) || [];
516
549
  }
517
550
  /**
@@ -519,6 +552,7 @@ class TinyRateLimiter {
519
552
  * @returns {number}
520
553
  */
521
554
  getMaxIdle() {
555
+ checkDestroy(this.#destroyed);
522
556
  if (typeof this.#maxIdle !== 'number' || !Number.isFinite(this.#maxIdle) || this.#maxIdle < 0) {
523
557
  throw new Error("'maxIdle' must be a non-negative finite number.");
524
558
  }
@@ -529,6 +563,7 @@ class TinyRateLimiter {
529
563
  * @param {number} ms
530
564
  */
531
565
  setMaxIdle(ms) {
566
+ checkDestroy(this.#destroyed);
532
567
  if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0) {
533
568
  throw new Error("'maxIdle' must be a non-negative finite number.");
534
569
  }
@@ -559,6 +594,7 @@ class TinyRateLimiter {
559
594
  * @returns {string[]}
560
595
  */
561
596
  getActiveGroups() {
597
+ checkDestroy(this.#destroyed);
562
598
  return Array.from(this.groupData.keys());
563
599
  }
564
600
  /**
@@ -566,6 +602,7 @@ class TinyRateLimiter {
566
602
  * @returns {Record<string, string>}
567
603
  */
568
604
  getAllUserMappings() {
605
+ checkDestroy(this.#destroyed);
569
606
  return Object.fromEntries(this.userToGroup);
570
607
  }
571
608
  /**
@@ -577,6 +614,7 @@ class TinyRateLimiter {
577
614
  * @returns {number}
578
615
  */
579
616
  getInterval() {
617
+ checkDestroy(this.#destroyed);
580
618
  if (typeof this.#interval !== 'number' || !Number.isFinite(this.#interval)) {
581
619
  throw new Error("'interval' is not a valid finite number.");
582
620
  }
@@ -587,6 +625,7 @@ class TinyRateLimiter {
587
625
  * @returns {number}
588
626
  */
589
627
  getMaxHits() {
628
+ checkDestroy(this.#destroyed);
590
629
  if (typeof this.#maxHits !== 'number' || !Number.isFinite(this.#maxHits)) {
591
630
  throw new Error("'maxHits' is not a valid finite number.");
592
631
  }
@@ -598,6 +637,7 @@ class TinyRateLimiter {
598
637
  * @returns {number}
599
638
  */
600
639
  getTotalHits(groupId) {
640
+ checkDestroy(this.#destroyed);
601
641
  const history = this.groupData.get(groupId);
602
642
  return Array.isArray(history) ? history.length : 0;
603
643
  }
@@ -607,6 +647,7 @@ class TinyRateLimiter {
607
647
  * @returns {number|null}
608
648
  */
609
649
  getLastHit(groupId) {
650
+ checkDestroy(this.#destroyed);
610
651
  const history = this.groupData.get(groupId);
611
652
  return history?.length ? history[history.length - 1] : null;
612
653
  }
@@ -616,6 +657,7 @@ class TinyRateLimiter {
616
657
  * @returns {number|null}
617
658
  */
618
659
  getTimeSinceLastHit(groupId) {
660
+ checkDestroy(this.#destroyed);
619
661
  const last = this.getLastHit(groupId);
620
662
  return last !== null ? Date.now() - last : null;
621
663
  }
@@ -640,6 +682,7 @@ class TinyRateLimiter {
640
682
  * @returns {number|null}
641
683
  */
642
684
  getAverageHitSpacing(groupId) {
685
+ checkDestroy(this.#destroyed);
643
686
  return this._calculateAverageSpacing(this.groupData.get(groupId));
644
687
  }
645
688
  /**
@@ -653,6 +696,7 @@ class TinyRateLimiter {
653
696
  * }}
654
697
  */
655
698
  getMetrics(groupId) {
699
+ checkDestroy(this.#destroyed);
656
700
  const history = this.groupData.get(groupId);
657
701
  if (!Array.isArray(history) || history.length === 0) {
658
702
  return {
@@ -677,6 +721,8 @@ class TinyRateLimiter {
677
721
  * Destroy the rate limiter, stopping cleanup and clearing data
678
722
  */
679
723
  destroy() {
724
+ if (this.destroyed)
725
+ return;
680
726
  if (this.#cleanupTimer)
681
727
  clearInterval(this.#cleanupTimer);
682
728
  this._cleanup();
@@ -685,6 +731,8 @@ class TinyRateLimiter {
685
731
  this.userToGroup.clear();
686
732
  this.groupTTL.clear();
687
733
  this.groupFlags.clear();
734
+ // Lock the instance
735
+ this.#destroyed = true;
688
736
  }
689
737
  }
690
738
  export default TinyRateLimiter;
@@ -3,6 +3,9 @@
3
3
  var events = require('events');
4
4
  var TinyHtml = require('./TinyHtml.cjs');
5
5
  var collision = require('../basics/collision.cjs');
6
+ var utils = require('./utils.cjs');
7
+
8
+ const checkDestroy = utils.createCheckDestroyed('TinySmartScroller');
6
9
 
7
10
  /**
8
11
  * Represents the dimensions of a DOM element.
@@ -227,6 +230,7 @@ class TinySmartScroller extends events.EventEmitter {
227
230
  * @returns {NodeSizesEvent} A function that compares previous and current height, returning height delta.
228
231
  */
229
232
  getSimpleOnHeight(filter = []) {
233
+ checkDestroy(this.#destroyed);
230
234
  if (!Array.isArray(filter))
231
235
  throw new TypeError('getSimpleOnHeight(filter): filter must be an array of tag names');
232
236
  return (elem, sizes, amounts) => {
@@ -246,6 +250,7 @@ class TinySmartScroller extends events.EventEmitter {
246
250
  * @returns {NodeSizesEvent} The added size difference callback.
247
251
  */
248
252
  addSimpleOnHeight(filter) {
253
+ checkDestroy(this.#destroyed);
249
254
  if (!Array.isArray(filter))
250
255
  throw new TypeError('addSimpleOnHeight(filter): filter must be an array of tag names');
251
256
  const result = this.getSimpleOnHeight(filter);
@@ -259,6 +264,7 @@ class TinySmartScroller extends events.EventEmitter {
259
264
  * @returns {string[]} Array of tag names.
260
265
  */
261
266
  getLoadTags() {
267
+ checkDestroy(this.#destroyed);
262
268
  return Array.from(this.#loadTags);
263
269
  }
264
270
 
@@ -268,6 +274,7 @@ class TinySmartScroller extends events.EventEmitter {
268
274
  * @param {string} tag - The tag name to add (e.g., 'IMG').
269
275
  */
270
276
  addLoadTag(tag) {
277
+ checkDestroy(this.#destroyed);
271
278
  if (typeof tag !== 'string') throw new TypeError('addLoadTag(tag): tag must be a string');
272
279
  this.#loadTags.add(tag.toUpperCase());
273
280
  }
@@ -278,6 +285,7 @@ class TinySmartScroller extends events.EventEmitter {
278
285
  * @param {string} tag - The tag name to remove.
279
286
  */
280
287
  removeLoadTag(tag) {
288
+ checkDestroy(this.#destroyed);
281
289
  if (typeof tag !== 'string') throw new TypeError('removeLoadTag(tag): tag must be a string');
282
290
  this.#loadTags.delete(tag.toUpperCase());
283
291
  }
@@ -289,6 +297,7 @@ class TinySmartScroller extends events.EventEmitter {
289
297
  * @returns {boolean} True if the tag is being tracked.
290
298
  */
291
299
  hasLoadTag(tag) {
300
+ checkDestroy(this.#destroyed);
292
301
  if (typeof tag !== 'string') throw new TypeError('hasLoadTag(tag): tag must be a string');
293
302
  return this.#loadTags.has(tag.toUpperCase());
294
303
  }
@@ -300,6 +309,7 @@ class TinySmartScroller extends events.EventEmitter {
300
309
  * @throws {TypeError} If `addDefault` is not a boolean.
301
310
  */
302
311
  resetLoadTags(addDefault = false) {
312
+ checkDestroy(this.#destroyed);
303
313
  if (typeof addDefault !== 'boolean')
304
314
  throw new TypeError('resetLoadTags(addDefault): addDefault must be a boolean');
305
315
  this.#loadTags.clear();
@@ -315,6 +325,7 @@ class TinySmartScroller extends events.EventEmitter {
315
325
  * @returns {string[]} Array of attribute names.
316
326
  */
317
327
  getAttributeFilters() {
328
+ checkDestroy(this.#destroyed);
318
329
  return Array.from(this.#attributeFilter);
319
330
  }
320
331
 
@@ -324,6 +335,7 @@ class TinySmartScroller extends events.EventEmitter {
324
335
  * @param {string} attr - The attribute name to add.
325
336
  */
326
337
  addAttributeFilter(attr) {
338
+ checkDestroy(this.#destroyed);
327
339
  if (typeof attr !== 'string')
328
340
  throw new TypeError('addAttributeFilter(attr): attr must be a string');
329
341
  this.#attributeFilter.add(attr);
@@ -335,6 +347,7 @@ class TinySmartScroller extends events.EventEmitter {
335
347
  * @param {string} attr - The attribute name to remove.
336
348
  */
337
349
  removeAttributeFilter(attr) {
350
+ checkDestroy(this.#destroyed);
338
351
  if (typeof attr !== 'string')
339
352
  throw new TypeError('removeAttributeFilter(attr): attr must be a string');
340
353
  this.#attributeFilter.delete(attr);
@@ -347,6 +360,7 @@ class TinySmartScroller extends events.EventEmitter {
347
360
  * @returns {boolean} True if the attribute is being filtered.
348
361
  */
349
362
  hasAttributeFilter(attr) {
363
+ checkDestroy(this.#destroyed);
350
364
  if (typeof attr !== 'string')
351
365
  throw new TypeError('hasAttributeFilter(attr): attr must be a string');
352
366
  return this.#attributeFilter.has(attr);
@@ -360,6 +374,7 @@ class TinySmartScroller extends events.EventEmitter {
360
374
  * @throws {TypeError} If `addDefault` is not a boolean.
361
375
  */
362
376
  resetAttributeFilters(addDefault = false) {
377
+ checkDestroy(this.#destroyed);
363
378
  if (typeof addDefault !== 'boolean')
364
379
  throw new TypeError('resetAttributeFilters(addDefault): addDefault must be a boolean');
365
380
  this.#attributeFilter.clear();
@@ -375,7 +390,7 @@ class TinySmartScroller extends events.EventEmitter {
375
390
  * @param {NodeSizesEvent} handler - Function that compares old and new sizes.
376
391
  */
377
392
  onSize(handler) {
378
- if (this.#destroyed) return;
393
+ checkDestroy(this.#destroyed);
379
394
  if (typeof handler !== 'function')
380
395
  throw new TypeError('onSize(handler): handler must be a function');
381
396
  this.#sizeFilter.add(handler);
@@ -387,7 +402,7 @@ class TinySmartScroller extends events.EventEmitter {
387
402
  * @param {NodeSizesEvent} handler - The handler function to remove.
388
403
  */
389
404
  offSize(handler) {
390
- if (this.#destroyed) return;
405
+ checkDestroy(this.#destroyed);
391
406
  if (typeof handler !== 'function')
392
407
  throw new TypeError('offSize(handler): handler must be a function');
393
408
  this.#sizeFilter.delete(handler);
@@ -397,6 +412,7 @@ class TinySmartScroller extends events.EventEmitter {
397
412
  * Checks which elements inside the target are currently visible and updates internal maps.
398
413
  *
399
414
  * @returns {Map<Element, { oldIsVisible: boolean; isVisible: boolean }>} Visibility comparison results.
415
+ * @private
400
416
  */
401
417
  _scrollDataUpdater() {
402
418
  const results = new Map();
@@ -414,6 +430,7 @@ class TinySmartScroller extends events.EventEmitter {
414
430
 
415
431
  /**
416
432
  * Handles scroll events, calculates position-related statuses, and emits appropriate events.
433
+ * @private
417
434
  */
418
435
  _onScroll() {
419
436
  if (this.#destroyed) return;
@@ -475,6 +492,7 @@ class TinySmartScroller extends events.EventEmitter {
475
492
  * Attempts to correct the scroll position when layout shifts happen, preserving the user position if needed.
476
493
  *
477
494
  * @param {Element[]} [targets=[]] - List of elements involved in the size change.
495
+ * @private
478
496
  */
479
497
  _fixScroll(targets = []) {
480
498
  if (this.#destroyed) return;
@@ -564,6 +582,7 @@ class TinySmartScroller extends events.EventEmitter {
564
582
  }
565
583
  /**
566
584
  * Sets up a MutationObserver to watch for DOM changes and react accordingly to maintain scroll consistency.
585
+ * @private
567
586
  */
568
587
  _observeMutations() {
569
588
  this.#mutationObserver = new MutationObserver((mutations) => {
@@ -604,6 +623,7 @@ class TinySmartScroller extends events.EventEmitter {
604
623
  * Adds a ResizeObserver to monitor elements' size changes and trigger layout adjustments.
605
624
  *
606
625
  * @param {NodeListOf<Element>|Element[]|HTMLCollection} elements - Elements to observe.
626
+ * @private
607
627
  */
608
628
  _observeResizes(elements) {
609
629
  // Add resize observer
@@ -644,6 +664,7 @@ class TinySmartScroller extends events.EventEmitter {
644
664
  * Listens for media/content load events (e.g., images, iframes, videos) to trigger scroll updates.
645
665
  *
646
666
  * @param {NodeListOf<Element>|Element} elements - Target element(s) to listen on.
667
+ * @private
647
668
  */
648
669
  _listenLoadEvents(elements) {
649
670
  if (this.#destroyed) return;
@@ -682,6 +703,7 @@ class TinySmartScroller extends events.EventEmitter {
682
703
  * @returns {NodeSizes|null} The old size, or undefined.
683
704
  */
684
705
  getOldSize(el) {
706
+ checkDestroy(this.#destroyed);
685
707
  return this.#oldSizes.get(el) ?? null;
686
708
  }
687
709
 
@@ -692,6 +714,7 @@ class TinySmartScroller extends events.EventEmitter {
692
714
  * @returns {NodeSizes|null} The new size, or undefined.
693
715
  */
694
716
  getNewSize(el) {
717
+ checkDestroy(this.#destroyed);
695
718
  return this.#newSizes.get(el) ?? null;
696
719
  }
697
720
 
@@ -702,6 +725,7 @@ class TinySmartScroller extends events.EventEmitter {
702
725
  * @returns {boolean} True if visible, false if not, or undefined if not tracked.
703
726
  */
704
727
  wasVisible(el) {
728
+ checkDestroy(this.#destroyed);
705
729
  return this.#oldVisibles.get(el) ?? false;
706
730
  }
707
731
 
@@ -712,6 +736,7 @@ class TinySmartScroller extends events.EventEmitter {
712
736
  * @returns {boolean} True if visible, false if not, or undefined if not tracked.
713
737
  */
714
738
  isVisible(el) {
739
+ checkDestroy(this.#destroyed);
715
740
  return this.#newVisibles.get(el) ?? false;
716
741
  }
717
742
 
@@ -722,6 +747,7 @@ class TinySmartScroller extends events.EventEmitter {
722
747
  * @returns {boolean} Visibility state from the previous timed check.
723
748
  */
724
749
  wasTimedVisible(el) {
750
+ checkDestroy(this.#destroyed);
725
751
  return this.#oldVisiblesByTime.get(el) ?? false;
726
752
  }
727
753
 
@@ -732,6 +758,7 @@ class TinySmartScroller extends events.EventEmitter {
732
758
  * @returns {boolean} Visibility state from the current timed check.
733
759
  */
734
760
  isTimedVisible(el) {
761
+ checkDestroy(this.#destroyed);
735
762
  return this.#newVisiblesByTime.get(el) ?? false;
736
763
  }
737
764
 
@@ -741,6 +768,7 @@ class TinySmartScroller extends events.EventEmitter {
741
768
  * @param {number} value - Pixels of additional margin to use.
742
769
  */
743
770
  setExtraScrollBoundary(value) {
771
+ checkDestroy(this.#destroyed);
744
772
  if (typeof value !== 'number' || Number.isNaN(value))
745
773
  throw new TypeError('setExtraScrollBoundary(value): value must be a valid number');
746
774
  this.#extraScrollBoundary = value;
@@ -752,6 +780,7 @@ class TinySmartScroller extends events.EventEmitter {
752
780
  * @returns {number}
753
781
  */
754
782
  getExtraScrollBoundary() {
783
+ checkDestroy(this.#destroyed);
755
784
  return this.#extraScrollBoundary;
756
785
  }
757
786
 
@@ -761,6 +790,7 @@ class TinySmartScroller extends events.EventEmitter {
761
790
  * @returns {number}
762
791
  */
763
792
  getLastKnownScrollBottomOffset() {
793
+ checkDestroy(this.#destroyed);
764
794
  return this.#lastKnownScrollBottomOffset;
765
795
  }
766
796
 
@@ -768,6 +798,7 @@ class TinySmartScroller extends events.EventEmitter {
768
798
  * Forces the scroll position to move to the very bottom of the target.
769
799
  */
770
800
  scrollToBottom() {
801
+ checkDestroy(this.#destroyed);
771
802
  this.#targetElement.scrollTop = this.#targetElement.scrollHeight;
772
803
  }
773
804
 
@@ -775,6 +806,7 @@ class TinySmartScroller extends events.EventEmitter {
775
806
  * Forces the scroll position to move to the very top of the target.
776
807
  */
777
808
  scrollToTop() {
809
+ checkDestroy(this.#destroyed);
778
810
  this.#targetElement.scrollTop = 0;
779
811
  }
780
812
 
@@ -784,6 +816,7 @@ class TinySmartScroller extends events.EventEmitter {
784
816
  * @returns {boolean}
785
817
  */
786
818
  isAtCustomBottom() {
819
+ checkDestroy(this.#destroyed);
787
820
  return this.#isAtCustomBottom;
788
821
  }
789
822
 
@@ -793,6 +826,7 @@ class TinySmartScroller extends events.EventEmitter {
793
826
  * @returns {boolean}
794
827
  */
795
828
  isAtCustomTop() {
829
+ checkDestroy(this.#destroyed);
796
830
  return this.#isAtCustomTop;
797
831
  }
798
832
 
@@ -802,6 +836,7 @@ class TinySmartScroller extends events.EventEmitter {
802
836
  * @returns {boolean}
803
837
  */
804
838
  isAtBottom() {
839
+ checkDestroy(this.#destroyed);
805
840
  return this.#isAtBottom;
806
841
  }
807
842
 
@@ -811,6 +846,7 @@ class TinySmartScroller extends events.EventEmitter {
811
846
  * @returns {boolean}
812
847
  */
813
848
  isAtTop() {
849
+ checkDestroy(this.#destroyed);
814
850
  return this.#isAtTop;
815
851
  }
816
852
 
@@ -820,6 +856,7 @@ class TinySmartScroller extends events.EventEmitter {
820
856
  * @returns {boolean}
821
857
  */
822
858
  isPastAtBottom() {
859
+ checkDestroy(this.#destroyed);
823
860
  return this.#isPastAtBottom;
824
861
  }
825
862
 
@@ -829,6 +866,7 @@ class TinySmartScroller extends events.EventEmitter {
829
866
  * @returns {boolean}
830
867
  */
831
868
  isPastAtTop() {
869
+ checkDestroy(this.#destroyed);
832
870
  return this.#isPastAtTop;
833
871
  }
834
872
 
@@ -838,6 +876,7 @@ class TinySmartScroller extends events.EventEmitter {
838
876
  * @returns {boolean}
839
877
  */
840
878
  isPastAtCustomTop() {
879
+ checkDestroy(this.#destroyed);
841
880
  return this.#isPastAtCustomTop;
842
881
  }
843
882
 
@@ -847,6 +886,7 @@ class TinySmartScroller extends events.EventEmitter {
847
886
  * @returns {boolean}
848
887
  */
849
888
  isPastAtCustomBottom() {
889
+ checkDestroy(this.#destroyed);
850
890
  return this.#isPastAtCustomBottom;
851
891
  }
852
892
 
@@ -856,6 +896,7 @@ class TinySmartScroller extends events.EventEmitter {
856
896
  * @returns {boolean}
857
897
  */
858
898
  isScrollPaused() {
899
+ checkDestroy(this.#destroyed);
859
900
  return this.#scrollPaused;
860
901
  }
861
902
 
@@ -865,6 +906,7 @@ class TinySmartScroller extends events.EventEmitter {
865
906
  * @returns {boolean} True if the scroll target is window, false otherwise.
866
907
  */
867
908
  isWindow() {
909
+ checkDestroy(this.#destroyed);
868
910
  return this.#useWindow;
869
911
  }
870
912
 
@@ -883,6 +925,7 @@ class TinySmartScroller extends events.EventEmitter {
883
925
  * @returns {boolean} True if auto-scroll is active, false otherwise.
884
926
  */
885
927
  getAutoScrollBottom() {
928
+ checkDestroy(this.#destroyed);
886
929
  return this.#autoScrollBottom;
887
930
  }
888
931
 
@@ -892,6 +935,7 @@ class TinySmartScroller extends events.EventEmitter {
892
935
  * @returns {boolean} True if mutation observation is active, false otherwise.
893
936
  */
894
937
  getObserveMutations() {
938
+ checkDestroy(this.#destroyed);
895
939
  return this.#observeMutations;
896
940
  }
897
941
 
@@ -901,6 +945,7 @@ class TinySmartScroller extends events.EventEmitter {
901
945
  * @returns {boolean} True if scroll preservation is active, false otherwise.
902
946
  */
903
947
  getPreserveScrollOnLayoutShift() {
948
+ checkDestroy(this.#destroyed);
904
949
  return this.#preserveScrollOnLayoutShift;
905
950
  }
906
951
 
@@ -910,6 +955,7 @@ class TinySmartScroller extends events.EventEmitter {
910
955
  * @returns {number} Debounce delay time.
911
956
  */
912
957
  getDebounceTime() {
958
+ checkDestroy(this.#destroyed);
913
959
  return this.#debounceTime;
914
960
  }
915
961
 
@@ -919,6 +965,7 @@ class TinySmartScroller extends events.EventEmitter {
919
965
  * @returns {number} Current count of matching elements.
920
966
  */
921
967
  getElemAmount() {
968
+ checkDestroy(this.#destroyed);
922
969
  return this.#elemAmount;
923
970
  }
924
971
 
@@ -928,6 +975,7 @@ class TinySmartScroller extends events.EventEmitter {
928
975
  * @returns {number} Previous count of matching elements.
929
976
  */
930
977
  getPrevElemAmount() {
978
+ checkDestroy(this.#destroyed);
931
979
  return this.#elemOldAmount;
932
980
  }
933
981
 
@@ -937,6 +985,7 @@ class TinySmartScroller extends events.EventEmitter {
937
985
  * @returns {string} The CSS selector string, or an empty string if none was provided.
938
986
  */
939
987
  getQuerySelector() {
988
+ checkDestroy(this.#destroyed);
940
989
  return this.#querySelector;
941
990
  }
942
991
 
@@ -946,7 +995,6 @@ class TinySmartScroller extends events.EventEmitter {
946
995
  */
947
996
  destroy() {
948
997
  if (this.#destroyed) return;
949
- this.#destroyed = true;
950
998
 
951
999
  // Disconnects MutationObserver
952
1000
  if (this.#mutationObserver) {
@@ -976,6 +1024,7 @@ class TinySmartScroller extends events.EventEmitter {
976
1024
  this.removeAllListeners();
977
1025
  this.#sizeFilter.clear();
978
1026
  this.#loadTags.clear();
1027
+ this.#destroyed = true;
979
1028
  }
980
1029
  }
981
1030