tiny-essentials 1.28.0 → 1.28.2
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/changelog/1/28/1.md +23 -0
- package/changelog/1/28/2.md +43 -0
- package/dist/_/numbers.d.mts +91 -16
- package/dist/v1/TinyAdvancedRaffle.min.js +1 -1
- package/dist/v1/TinyAfterScrollWatcher.min.js +1 -1
- package/dist/v1/TinyAnalogClock.min.js +1 -1
- package/dist/v1/TinyBasicsEs.min.js +1 -1
- package/dist/v1/TinyDayNightCycle.min.js +1 -1
- package/dist/v1/TinyDragDropDetector.min.js +1 -1
- package/dist/v1/TinyDragger.min.js +1 -1
- package/dist/v1/TinyElementObserver.min.js +1 -1
- package/dist/v1/TinyEssentials.min.js +1 -1
- package/dist/v1/TinyGamepad.min.js +1 -1
- package/dist/v1/TinyHtml.min.js +1 -1
- package/dist/v1/TinyI18.min.js +1 -1
- package/dist/v1/TinyIframeEvents.min.js +1 -1
- package/dist/v1/TinyLocalStorage.min.js +1 -1
- package/dist/v1/TinyMediaPlayer.min.js +1 -1
- package/dist/v1/TinyNewWinEvents.min.js +1 -1
- package/dist/v1/TinyNotifyCenter.min.js +1 -1
- package/dist/v1/TinyRadioFm.min.js +1 -1
- package/dist/v1/TinyRateLimiter.min.js +1 -1
- package/dist/v1/TinySmartScroller.min.js +1 -1
- package/dist/v1/TinyTextDiffer.min.js +1 -1
- package/dist/v1/TinyTextarea.min.js +1 -1
- package/dist/v1/TinyTimeout.min.js +1 -1
- package/dist/v1/TinyToastNotify.min.js +1 -1
- package/dist/v1/TinyUploadClicker.min.js +1 -1
- package/dist/v1/UltraRandomMsgGen.min.js +1 -1
- package/dist/v1/basics/array.cjs +57 -9
- package/dist/v1/basics/array.d.mts +28 -12
- package/dist/v1/basics/array.mjs +51 -9
- package/dist/v1/basics/clock.cjs +94 -42
- package/dist/v1/basics/clock.d.mts +22 -22
- package/dist/v1/basics/clock.mjs +91 -54
- package/dist/v1/basics/collision.d.mts +245 -104
- package/dist/v1/basics/deprecated/html.cjs +246 -0
- package/dist/v1/basics/deprecated/html.d.mts +63 -0
- package/dist/v1/basics/deprecated/html.mjs +190 -0
- package/dist/v1/basics/extendObjType/Buffer.d.mts +1 -1
- package/dist/v1/basics/fullScreen.d.mts +47 -7
- package/dist/v1/basics/html.cjs +149 -130
- package/dist/v1/basics/html.d.mts +69 -113
- package/dist/v1/basics/html.mjs +113 -105
- package/dist/v1/basics/index.cjs +2 -0
- package/dist/v1/basics/index.d.mts +11 -65
- package/dist/v1/basics/index.mjs +3 -3
- package/dist/v1/basics/mediaContent.cjs +116 -32
- package/dist/v1/basics/mediaContent.d.mts +143 -159
- package/dist/v1/basics/mediaContent.mjs +105 -33
- package/dist/v1/basics/objChecker.cjs +7 -5
- package/dist/v1/basics/objChecker.d.mts +5 -4
- package/dist/v1/basics/objChecker.mjs +6 -6
- package/dist/v1/basics/objFilter.cjs +71 -14
- package/dist/v1/basics/objFilter.d.mts +16 -19
- package/dist/v1/basics/objFilter.mjs +63 -14
- package/dist/v1/basics/simpleMath.cjs +81 -25
- package/dist/v1/basics/simpleMath.d.mts +22 -22
- package/dist/v1/basics/simpleMath.mjs +70 -27
- package/dist/v1/basics/text.cjs +76 -31
- package/dist/v1/basics/text.d.mts +64 -14
- package/dist/v1/basics/text.mjs +62 -31
- package/dist/v1/build/ColorSafeStringify.d.mts +1 -1
- package/dist/v1/build/TinyAdvancedRaffle.d.mts +1 -1
- package/dist/v1/build/TinyAfterScrollWatcher.d.mts +1 -1
- package/dist/v1/build/TinyAnalogClock.d.mts +1 -1
- package/dist/v1/build/TinyArrayComparator.d.mts +1 -1
- package/dist/v1/build/TinyArrayPaginator.d.mts +1 -1
- package/dist/v1/build/TinyClassManager.d.mts +1 -1
- package/dist/v1/build/TinyClipboard.d.mts +1 -1
- package/dist/v1/build/TinyColorConverter.d.mts +1 -1
- package/dist/v1/build/TinyColorValidator.d.mts +1 -1
- package/dist/v1/build/TinyCookieConsent.d.mts +1 -1
- package/dist/v1/build/TinyDayNightCycle.d.mts +1 -1
- package/dist/v1/build/TinyDomReadyManager.d.mts +1 -1
- package/dist/v1/build/TinyDragDropDetector.d.mts +1 -1
- package/dist/v1/build/TinyDragger.d.mts +1 -1
- package/dist/v1/build/TinyElementObserver.d.mts +1 -1
- package/dist/v1/build/TinyGamepad.d.mts +1 -1
- package/dist/v1/build/TinyHtml.d.mts +1 -1
- package/dist/v1/build/TinyI18.d.mts +1 -1
- package/dist/v1/build/TinyIframeEvents.d.mts +1 -1
- package/dist/v1/build/TinyInventory.d.mts +1 -1
- package/dist/v1/build/TinyInventoryTrader.d.mts +1 -1
- package/dist/v1/build/TinyLevelUp.d.mts +1 -1
- package/dist/v1/build/TinyLoadingScreen.d.mts +1 -1
- package/dist/v1/build/TinyLocalStorage.d.mts +1 -1
- package/dist/v1/build/TinyMediaPlayer.d.mts +1 -1
- package/dist/v1/build/TinyNeedBar.d.mts +1 -1
- package/dist/v1/build/TinyNewWinEvents.d.mts +1 -1
- package/dist/v1/build/TinyNotifications.d.mts +1 -1
- package/dist/v1/build/TinyNotifyCenter.d.mts +1 -1
- package/dist/v1/build/TinyPromiseQueue.d.mts +1 -1
- package/dist/v1/build/TinyRadioFm.d.mts +1 -1
- package/dist/v1/build/TinyRateLimiter.d.mts +1 -1
- package/dist/v1/build/TinySimpleDice.d.mts +1 -1
- package/dist/v1/build/TinySmartScroller.d.mts +1 -1
- package/dist/v1/build/TinyTextDiffer.d.mts +1 -1
- package/dist/v1/build/TinyTextRangeEditor.d.mts +1 -1
- package/dist/v1/build/TinyTextarea.d.mts +1 -1
- package/dist/v1/build/TinyTimeout.d.mts +1 -1
- package/dist/v1/build/TinyToastNotify.d.mts +1 -1
- package/dist/v1/build/TinyUploadClicker.d.mts +1 -1
- package/dist/v1/build/UltraRandomMsgGen.d.mts +1 -1
- package/dist/v1/fileManager/asyncFuncs.d.mts +13 -13
- package/dist/v1/fileManager/index.d.mts +3 -29
- package/dist/v1/fileManager/normalFuncs.d.mts +22 -22
- package/dist/v1/index.cjs +4 -0
- package/dist/v1/index.d.mts +54 -137
- package/dist/v1/index.mjs +4 -3
- package/dist/v1/libs/ColorSafeStringify.d.mts +3 -12
- package/dist/v1/libs/TinyAdvancedRaffle.cjs +64 -50
- package/dist/v1/libs/TinyAdvancedRaffle.d.mts +64 -116
- package/dist/v1/libs/TinyAdvancedRaffle.mjs +62 -49
- package/dist/v1/libs/TinyAfterScrollWatcher.cjs +17 -1
- package/dist/v1/libs/TinyAfterScrollWatcher.d.mts +15 -19
- package/dist/v1/libs/TinyAfterScrollWatcher.mjs +15 -1
- package/dist/v1/libs/TinyAnalogClock.cjs +60 -0
- package/dist/v1/libs/TinyAnalogClock.d.mts +12 -9
- package/dist/v1/libs/TinyAnalogClock.mjs +57 -0
- package/dist/v1/libs/TinyArrayComparator.d.mts +14 -20
- package/dist/v1/libs/TinyArrayPaginator.d.mts +22 -26
- package/dist/v1/libs/TinyClassManager/TinyPluginInliner.d.mts +8 -8
- package/dist/v1/libs/TinyClassManager.cjs +5 -7
- package/dist/v1/libs/TinyClassManager.d.mts +16 -16
- package/dist/v1/libs/TinyClassManager.mjs +5 -6
- package/dist/v1/libs/TinyClipboard.cjs +2 -0
- package/dist/v1/libs/TinyClipboard.d.mts +12 -5
- package/dist/v1/libs/TinyClipboard.mjs +2 -0
- package/dist/v1/libs/TinyColorConverter.cjs +1 -0
- package/dist/v1/libs/TinyColorConverter.d.mts +10 -32
- package/dist/v1/libs/TinyColorConverter.mjs +1 -0
- package/dist/v1/libs/TinyColorValidator.d.mts +145 -184
- package/dist/v1/libs/TinyCookieConsent.d.mts +17 -17
- package/dist/v1/libs/TinyDayNightCycle.cjs +67 -42
- package/dist/v1/libs/TinyDayNightCycle.d.mts +87 -117
- package/dist/v1/libs/TinyDayNightCycle.mjs +65 -41
- package/dist/v1/libs/TinyDomReadyManager.d.mts +8 -16
- package/dist/v1/libs/TinyDragDropDetector.cjs +25 -0
- package/dist/v1/libs/TinyDragDropDetector.d.mts +32 -26
- package/dist/v1/libs/TinyDragDropDetector.mjs +22 -0
- package/dist/v1/libs/TinyDragger.cjs +46 -19
- package/dist/v1/libs/TinyDragger.d.mts +82 -81
- package/dist/v1/libs/TinyDragger.mjs +45 -18
- package/dist/v1/libs/TinyElementObserver.cjs +39 -0
- package/dist/v1/libs/TinyElementObserver.d.mts +28 -25
- package/dist/v1/libs/TinyElementObserver.mjs +36 -0
- package/dist/v1/libs/TinyGamepad.cjs +131 -2
- package/dist/v1/libs/TinyGamepad.d.mts +50 -122
- package/dist/v1/libs/TinyGamepad.mjs +129 -2
- package/dist/v1/libs/TinyHtml/TinyHtmlAnchor.cjs +2 -25
- package/dist/v1/libs/TinyHtml/TinyHtmlAnchor.d.mts +19 -25
- package/dist/v1/libs/TinyHtml/TinyHtmlAnchor.mjs +3 -27
- package/dist/v1/libs/TinyHtml/TinyHtmlButton.cjs +2 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlButton.d.mts +55 -55
- package/dist/v1/libs/TinyHtml/TinyHtmlButton.mjs +2 -1
- package/dist/v1/libs/TinyHtml/TinyHtmlCanvas.d.mts +6 -6
- package/dist/v1/libs/TinyHtml/TinyHtmlDatalist.cjs +8 -4
- package/dist/v1/libs/TinyHtml/TinyHtmlDatalist.d.mts +19 -21
- package/dist/v1/libs/TinyHtml/TinyHtmlDatalist.mjs +7 -4
- package/dist/v1/libs/TinyHtml/TinyHtmlEmbed.d.mts +8 -8
- package/dist/v1/libs/TinyHtml/TinyHtmlForm.d.mts +18 -18
- package/dist/v1/libs/TinyHtml/TinyHtmlIcon.d.mts +5 -6
- package/dist/v1/libs/TinyHtml/TinyHtmlIframe.d.mts +19 -19
- package/dist/v1/libs/TinyHtml/TinyHtmlImage.cjs +0 -28
- package/dist/v1/libs/TinyHtml/TinyHtmlImage.d.mts +22 -28
- package/dist/v1/libs/TinyHtml/TinyHtmlImage.mjs +1 -27
- package/dist/v1/libs/TinyHtml/TinyHtmlInput.d.mts +11 -11
- package/dist/v1/libs/TinyHtml/TinyHtmlLink.d.mts +23 -23
- package/dist/v1/libs/TinyHtml/TinyHtmlMedia.d.mts +26 -26
- package/dist/v1/libs/TinyHtml/TinyHtmlScript.cjs +4 -30
- package/dist/v1/libs/TinyHtml/TinyHtmlScript.d.mts +20 -26
- package/dist/v1/libs/TinyHtml/TinyHtmlScript.mjs +5 -32
- package/dist/v1/libs/TinyHtml/TinyHtmlSelect.d.mts +19 -19
- package/dist/v1/libs/TinyHtml/TinyHtmlStyle.d.mts +8 -8
- package/dist/v1/libs/TinyHtml/TinyHtmlTemplate.d.mts +26 -28
- package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.cjs +14 -15
- package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.d.mts +32 -32
- package/dist/v1/libs/TinyHtml/TinyHtmlTextarea.mjs +15 -15
- package/dist/v1/libs/TinyHtml/index.d.mts +102 -45
- package/dist/v1/libs/TinyHtml/input/TinyHtmlColorInput.cjs +11 -9
- package/dist/v1/libs/TinyHtml/input/TinyHtmlColorInput.d.mts +21 -21
- package/dist/v1/libs/TinyHtml/input/TinyHtmlColorInput.mjs +11 -9
- package/dist/v1/libs/TinyHtml/input/TinyHtmlFileInput.d.mts +11 -11
- package/dist/v1/libs/TinyHtml/input/TinyHtmlHiddenInput.cjs +4 -4
- package/dist/v1/libs/TinyHtml/input/TinyHtmlHiddenInput.d.mts +17 -13
- package/dist/v1/libs/TinyHtml/input/TinyHtmlHiddenInput.mjs +4 -4
- package/dist/v1/libs/TinyHtml/input/TinyHtmlImageInput.d.mts +21 -21
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlButtonInput.cjs +5 -4
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlButtonInput.d.mts +14 -14
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlButtonInput.mjs +5 -4
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlResetInput.cjs +4 -3
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlResetInput.d.mts +10 -10
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlResetInput.mjs +4 -3
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlSubmitInput.cjs +4 -3
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlSubmitInput.d.mts +19 -19
- package/dist/v1/libs/TinyHtml/input/button/TinyHtmlSubmitInput.mjs +4 -3
- package/dist/v1/libs/TinyHtml/input/check/TinyHtmlCheckboxInput.cjs +5 -4
- package/dist/v1/libs/TinyHtml/input/check/TinyHtmlCheckboxInput.d.mts +11 -11
- package/dist/v1/libs/TinyHtml/input/check/TinyHtmlCheckboxInput.mjs +5 -4
- package/dist/v1/libs/TinyHtml/input/check/TinyHtmlRadioInput.cjs +4 -3
- package/dist/v1/libs/TinyHtml/input/check/TinyHtmlRadioInput.d.mts +15 -11
- package/dist/v1/libs/TinyHtml/input/check/TinyHtmlRadioInput.mjs +4 -3
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlDateInput.cjs +49 -21
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlDateInput.d.mts +34 -20
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlDateInput.mjs +45 -20
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlDateTimeInput.cjs +1 -1
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlDateTimeInput.d.mts +14 -14
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlDateTimeInput.mjs +1 -1
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlMonthInput.cjs +1 -1
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlMonthInput.d.mts +14 -14
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlMonthInput.mjs +1 -1
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlTimeInput.cjs +48 -25
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlTimeInput.d.mts +27 -21
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlTimeInput.mjs +40 -27
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlWeekInput.cjs +1 -1
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlWeekInput.d.mts +14 -14
- package/dist/v1/libs/TinyHtml/input/date/TinyHtmlWeekInput.mjs +1 -1
- package/dist/v1/libs/TinyHtml/input/number/TinyHtmlNumberInput.d.mts +14 -14
- package/dist/v1/libs/TinyHtml/input/number/TinyHtmlRangeInput.d.mts +14 -14
- package/dist/v1/libs/TinyHtml/input/text/TinyHtmlEmailInput.d.mts +25 -21
- package/dist/v1/libs/TinyHtml/input/text/TinyHtmlPasswordInput.d.mts +18 -18
- package/dist/v1/libs/TinyHtml/input/text/TinyHtmlSearchInput.d.mts +33 -29
- package/dist/v1/libs/TinyHtml/input/text/TinyHtmlTelInput.d.mts +22 -22
- package/dist/v1/libs/TinyHtml/input/text/TinyHtmlTextInput.d.mts +18 -18
- package/dist/v1/libs/TinyHtml/input/text/TinyHtmlUrlInput.d.mts +31 -27
- package/dist/v1/libs/TinyHtml/media/TinyHtmlAudio.d.mts +35 -11
- package/dist/v1/libs/TinyHtml/media/TinyHtmlObject.d.mts +10 -10
- package/dist/v1/libs/TinyHtml/media/TinyHtmlSource.d.mts +12 -12
- package/dist/v1/libs/TinyHtml/media/TinyHtmlVideo.d.mts +35 -27
- package/dist/v1/libs/TinyHtml.cjs +4 -5
- package/dist/v1/libs/TinyHtml.d.mts +1503 -1731
- package/dist/v1/libs/TinyHtml.mjs +5 -6
- package/dist/v1/libs/TinyI18.cjs +61 -0
- package/dist/v1/libs/TinyI18.d.mts +34 -58
- package/dist/v1/libs/TinyI18.mjs +55 -0
- package/dist/v1/libs/TinyIframeEvents.cjs +19 -2
- package/dist/v1/libs/TinyIframeEvents.d.mts +29 -38
- package/dist/v1/libs/TinyIframeEvents.mjs +19 -2
- package/dist/v1/libs/TinyInventory.d.mts +78 -141
- package/dist/v1/libs/TinyInventoryTrader.d.mts +19 -22
- package/dist/v1/libs/TinyLevelUp.d.mts +10 -13
- package/dist/v1/libs/TinyLoadingScreen.d.mts +21 -31
- package/dist/v1/libs/TinyLocalStorage.cjs +48 -0
- package/dist/v1/libs/TinyLocalStorage.d.mts +11 -30
- package/dist/v1/libs/TinyLocalStorage.mjs +45 -0
- package/dist/v1/libs/TinyMamdaniInferenceSystem.d.mts +37 -23
- package/dist/v1/libs/TinyMediaPlayer.cjs +77 -3
- package/dist/v1/libs/TinyMediaPlayer.d.mts +109 -106
- package/dist/v1/libs/TinyMediaPlayer.mjs +71 -3
- package/dist/v1/libs/TinyNeedBar.d.mts +25 -37
- package/dist/v1/libs/TinyNewWinEvents.cjs +29 -0
- package/dist/v1/libs/TinyNewWinEvents.d.mts +32 -29
- package/dist/v1/libs/TinyNewWinEvents.mjs +26 -0
- package/dist/v1/libs/TinyNotifications.d.mts +6 -6
- package/dist/v1/libs/TinyNotifyCenter.cjs +36 -0
- package/dist/v1/libs/TinyNotifyCenter.d.mts +15 -15
- package/dist/v1/libs/TinyNotifyCenter.mjs +32 -0
- package/dist/v1/libs/TinyPromiseQueue.d.mts +11 -11
- package/dist/v1/libs/TinyRadioFm.cjs +70 -12
- package/dist/v1/libs/TinyRadioFm.d.mts +45 -80
- package/dist/v1/libs/TinyRadioFm.mjs +64 -12
- package/dist/v1/libs/TinyRateLimiter.cjs +52 -0
- package/dist/v1/libs/TinyRateLimiter.d.mts +29 -36
- package/dist/v1/libs/TinyRateLimiter.mjs +48 -0
- package/dist/v1/libs/TinySimpleDice.d.mts +17 -36
- package/dist/v1/libs/TinySmartScroller.cjs +52 -3
- package/dist/v1/libs/TinySmartScroller.d.mts +62 -70
- package/dist/v1/libs/TinySmartScroller.mjs +51 -5
- package/dist/v1/libs/TinyTextDiffer.cjs +19 -18
- package/dist/v1/libs/TinyTextDiffer.d.mts +11 -13
- package/dist/v1/libs/TinyTextDiffer.mjs +16 -17
- package/dist/v1/libs/TinyTextRangeEditor.d.mts +8 -8
- package/dist/v1/libs/TinyTextarea.cjs +19 -0
- package/dist/v1/libs/TinyTextarea.d.mts +34 -28
- package/dist/v1/libs/TinyTextarea.mjs +17 -0
- package/dist/v1/libs/TinyTimeout.cjs +11 -1
- package/dist/v1/libs/TinyTimeout.d.mts +14 -14
- package/dist/v1/libs/TinyTimeout.mjs +9 -1
- package/dist/v1/libs/TinyToastNotify.cjs +36 -1
- package/dist/v1/libs/TinyToastNotify.d.mts +15 -17
- package/dist/v1/libs/TinyToastNotify.mjs +32 -1
- package/dist/v1/libs/TinyUploadClicker.cjs +19 -0
- package/dist/v1/libs/TinyUploadClicker.d.mts +38 -8
- package/dist/v1/libs/TinyUploadClicker.mjs +17 -0
- package/dist/v1/libs/UltraRandomMsgGen.cjs +148 -35
- package/dist/v1/libs/UltraRandomMsgGen.d.mts +52 -78
- package/dist/v1/libs/UltraRandomMsgGen.mjs +133 -34
- package/dist/v1/libs/utils.cjs +21 -0
- package/dist/v1/libs/utils.d.mts +6 -0
- package/dist/v1/libs/utils.mjs +16 -0
- package/docs/v1/README.md +1 -0
- package/docs/v1/basics/array.md +2 -2
- package/docs/v1/basics/deprecated/html.md +17 -0
- package/docs/v1/basics/fullScreen.md +1 -1
- package/docs/v1/basics/html.md +12 -26
- package/docs/v1/basics/mediaContent.md +1 -1
- package/docs/v1/basics/objChecker.md +1 -1
- package/docs/v1/basics/text.md +2 -2
- package/docs/v1/fileManager/main.md +1 -1
- package/docs/v1/libs/ColorSafeStringify.md +1 -1
- package/docs/v1/libs/TinyAfterScrollWatcher.md +1 -1
- package/docs/v1/libs/TinyAnalogClock.md +1 -1
- package/docs/v1/libs/TinyArrayComparator.md +1 -1
- package/docs/v1/libs/TinyArrayPaginator.md +1 -1
- package/docs/v1/libs/TinyClassManager/TinyPluginInliner.md +2 -2
- package/docs/v1/libs/TinyClassManager.md +1 -1
- package/docs/v1/libs/TinyClipboard.md +1 -1
- package/docs/v1/libs/TinyCookieConsent.md +1 -1
- package/docs/v1/libs/TinyDomReadyManager.md +1 -1
- package/docs/v1/libs/TinyDragDropDetector.md +1 -1
- package/docs/v1/libs/TinyDragger.md +1 -1
- package/docs/v1/libs/TinyElementObserver.md +1 -1
- package/docs/v1/libs/TinyHtml.md +1 -1
- package/docs/v1/libs/TinyIframeEvents.md +2 -2
- package/docs/v1/libs/TinyLevelUp.md +1 -1
- package/docs/v1/libs/TinyLoadingScreen.md +1 -1
- package/docs/v1/libs/TinyNewWinEvents.md +2 -2
- package/docs/v1/libs/TinyNotifications.md +1 -1
- package/docs/v1/libs/TinyPromiseQueue.md +2 -2
- package/docs/v1/libs/TinyTextDiffer.md +1 -1
- package/docs/v1/libs/TinyTextarea.md +1 -1
- package/package.json +11 -2
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
import { blobUrlToBase64, convertToBlobUrl, parseMediaMetadata, revokeContentUrls, } from '../basics/mediaContent.mjs';
|
|
3
|
+
import { createCheckDestroyed } from './utils.mjs';
|
|
4
|
+
const checkDestroy = createCheckDestroyed('TinyRadioFm');
|
|
3
5
|
/**
|
|
6
|
+
* @typedef {import('../basics/mediaContent.mjs').PictureDataType} PictureDataType
|
|
4
7
|
* @typedef {import('../basics/mediaContent.mjs').MediaContentBase} MediaContentBase
|
|
5
|
-
* @typedef {import('../basics/mediaContent.mjs').MediaContentMetadata} MediaContentMetadata
|
|
6
|
-
* @typedef {import('../basics/mediaContent.mjs').MediaContent} MediaContent
|
|
8
|
+
* @typedef {import('../basics/mediaContent.mjs').MediaContentMetadata<PictureDataType>} MediaContentMetadata
|
|
9
|
+
* @typedef {import('../basics/mediaContent.mjs').MediaContent<PictureDataType>} MediaContent
|
|
7
10
|
* @typedef {import('../basics/mediaContent.mjs').IPicture} IPicture
|
|
8
11
|
* @typedef {import('../basics/mediaContent.mjs').MediaNumber} MediaNumber
|
|
9
12
|
* @typedef {import('../basics/mediaContent.mjs').MediaLoadingError} MediaLoadingError
|
|
@@ -147,11 +150,17 @@ class TinyRadioFm extends EventEmitter {
|
|
|
147
150
|
throw new TypeError('unknownArtist must have an string or function.');
|
|
148
151
|
TinyRadioFm.#unknownArtist = value;
|
|
149
152
|
}
|
|
153
|
+
/** @type {boolean} */
|
|
154
|
+
#destroyed = false;
|
|
155
|
+
get destroyed() {
|
|
156
|
+
return this.#destroyed;
|
|
157
|
+
}
|
|
150
158
|
/**
|
|
151
159
|
* Gets the total count of all content items (music and voice) in the system.
|
|
152
160
|
* @returns {number}
|
|
153
161
|
*/
|
|
154
162
|
get size() {
|
|
163
|
+
checkDestroy(this.#destroyed);
|
|
155
164
|
return this.#musicList.length + this.#voiceList.length;
|
|
156
165
|
}
|
|
157
166
|
/**
|
|
@@ -159,6 +168,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
159
168
|
* @returns {number}
|
|
160
169
|
*/
|
|
161
170
|
get musicSize() {
|
|
171
|
+
checkDestroy(this.#destroyed);
|
|
162
172
|
return this.#musicList.length;
|
|
163
173
|
}
|
|
164
174
|
/**
|
|
@@ -166,6 +176,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
166
176
|
* @returns {number}
|
|
167
177
|
*/
|
|
168
178
|
get voiceSize() {
|
|
179
|
+
checkDestroy(this.#destroyed);
|
|
169
180
|
return this.#voiceList.length;
|
|
170
181
|
}
|
|
171
182
|
/**
|
|
@@ -173,6 +184,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
173
184
|
* @returns {number}
|
|
174
185
|
*/
|
|
175
186
|
get customPosSize() {
|
|
187
|
+
checkDestroy(this.#destroyed);
|
|
176
188
|
return this.#customPositions.length;
|
|
177
189
|
}
|
|
178
190
|
/**
|
|
@@ -180,6 +192,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
180
192
|
* @returns {number}
|
|
181
193
|
*/
|
|
182
194
|
get tasksSize() {
|
|
195
|
+
checkDestroy(this.#destroyed);
|
|
183
196
|
return this.#scheduledTasks.length;
|
|
184
197
|
}
|
|
185
198
|
/**
|
|
@@ -187,6 +200,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
187
200
|
* @returns {number}
|
|
188
201
|
*/
|
|
189
202
|
get cycleCacheSize() {
|
|
203
|
+
checkDestroy(this.#destroyed);
|
|
190
204
|
return this.#cycleCache.size;
|
|
191
205
|
}
|
|
192
206
|
/** @type {MediaContent[]} */
|
|
@@ -196,6 +210,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
196
210
|
* @returns {MediaContent[]}
|
|
197
211
|
*/
|
|
198
212
|
get musicList() {
|
|
213
|
+
checkDestroy(this.#destroyed);
|
|
199
214
|
return structuredClone(this.#musicList);
|
|
200
215
|
}
|
|
201
216
|
/** @type {MediaContent[]} */
|
|
@@ -205,6 +220,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
205
220
|
* @returns {MediaContent[]}
|
|
206
221
|
*/
|
|
207
222
|
get voiceList() {
|
|
223
|
+
checkDestroy(this.#destroyed);
|
|
208
224
|
return structuredClone(this.#voiceList);
|
|
209
225
|
}
|
|
210
226
|
/** @type {CustomPosition[]} */
|
|
@@ -214,6 +230,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
214
230
|
* @returns {CustomPosition[]}
|
|
215
231
|
*/
|
|
216
232
|
get customPositions() {
|
|
233
|
+
checkDestroy(this.#destroyed);
|
|
217
234
|
return structuredClone(this.#customPositions);
|
|
218
235
|
}
|
|
219
236
|
/** @type {ScheduledTask[]} */
|
|
@@ -223,6 +240,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
223
240
|
* @returns {ScheduledTask[]}
|
|
224
241
|
*/
|
|
225
242
|
get scheduledTasks() {
|
|
243
|
+
checkDestroy(this.#destroyed);
|
|
226
244
|
return structuredClone(this.#scheduledTasks);
|
|
227
245
|
}
|
|
228
246
|
/**
|
|
@@ -230,6 +248,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
230
248
|
* @returns {MediaContent[]} A cloned object of the cache.
|
|
231
249
|
*/
|
|
232
250
|
get allList() {
|
|
251
|
+
checkDestroy(this.#destroyed);
|
|
233
252
|
return [...this.musicList, ...this.voiceList];
|
|
234
253
|
}
|
|
235
254
|
/** @type {number} */
|
|
@@ -239,6 +258,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
239
258
|
* @returns {number}
|
|
240
259
|
*/
|
|
241
260
|
get seed() {
|
|
261
|
+
checkDestroy(this.#destroyed);
|
|
242
262
|
return this.#seed;
|
|
243
263
|
}
|
|
244
264
|
/**
|
|
@@ -246,6 +266,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
246
266
|
* @param {number} seed - The new seed.
|
|
247
267
|
*/
|
|
248
268
|
set seed(seed) {
|
|
269
|
+
checkDestroy(this.#destroyed);
|
|
249
270
|
if (typeof seed !== 'number')
|
|
250
271
|
throw new TypeError('Seed must be a number.');
|
|
251
272
|
this.#seed = seed;
|
|
@@ -259,6 +280,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
259
280
|
* @returns {number}
|
|
260
281
|
*/
|
|
261
282
|
get anchorDate() {
|
|
283
|
+
checkDestroy(this.#destroyed);
|
|
262
284
|
return this.#anchorDate;
|
|
263
285
|
}
|
|
264
286
|
/** @type {Map<number, CycleBlock>} */
|
|
@@ -280,6 +302,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
280
302
|
* @returns {RadioConfig}
|
|
281
303
|
*/
|
|
282
304
|
get config() {
|
|
305
|
+
checkDestroy(this.#destroyed);
|
|
283
306
|
return structuredClone(this.#config);
|
|
284
307
|
}
|
|
285
308
|
/**
|
|
@@ -288,6 +311,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
288
311
|
* @throws {TypeError|RangeError} If the new configuration is invalid.
|
|
289
312
|
*/
|
|
290
313
|
set config(config) {
|
|
314
|
+
checkDestroy(this.#destroyed);
|
|
291
315
|
// Validate the entire object before applying it
|
|
292
316
|
this.#validateConfig(config);
|
|
293
317
|
this.#config = structuredClone(config);
|
|
@@ -377,6 +401,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
377
401
|
* @throws {TypeError} If the type is invalid or the data lacks a valid ID and numerical duration.
|
|
378
402
|
*/
|
|
379
403
|
add(type, data, smartQueue = true) {
|
|
404
|
+
checkDestroy(this.#destroyed);
|
|
380
405
|
if (!['music', 'voice', 'custom'].includes(type)) {
|
|
381
406
|
throw new TypeError('Type must be "music", "voice", or "custom".');
|
|
382
407
|
}
|
|
@@ -410,6 +435,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
410
435
|
* @throws {TypeError} If arguments do not match the required types or action/type constraints.
|
|
411
436
|
*/
|
|
412
437
|
scheduleTask(timestamp, action, type, payload, smartQueue = true) {
|
|
438
|
+
checkDestroy(this.#destroyed);
|
|
413
439
|
if (typeof timestamp !== 'number' || isNaN(timestamp))
|
|
414
440
|
throw new TypeError('timestamp must be a valid number.');
|
|
415
441
|
if (!['add', 'remove', 'move'].includes(action))
|
|
@@ -467,6 +493,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
467
493
|
* @throws {TypeError} If the id is not a string.
|
|
468
494
|
*/
|
|
469
495
|
remove(id) {
|
|
496
|
+
checkDestroy(this.#destroyed);
|
|
470
497
|
if (typeof id !== 'string')
|
|
471
498
|
throw new TypeError('id must be a string.');
|
|
472
499
|
// Revoke Blob URLs of items being removed to free memory
|
|
@@ -477,7 +504,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
477
504
|
.forEach((cp) => revokeContentUrls(cp.content));
|
|
478
505
|
/**
|
|
479
506
|
* Filter function to match items against the provided ID.
|
|
480
|
-
* @type {
|
|
507
|
+
* @type {(item: any) => boolean}
|
|
481
508
|
*/
|
|
482
509
|
const filterFn = (item) => item.id !== id && item.content?.id !== id;
|
|
483
510
|
this.#musicList = this.#musicList.filter(filterFn);
|
|
@@ -505,6 +532,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
505
532
|
* @throws {TypeError|RangeError} If the provided values or the resulting state is invalid.
|
|
506
533
|
*/
|
|
507
534
|
setConfig(config) {
|
|
535
|
+
checkDestroy(this.#destroyed);
|
|
508
536
|
// First, validate the incoming partial object for basic type correctness
|
|
509
537
|
this.#validateConfig(config);
|
|
510
538
|
// Create the potential new state
|
|
@@ -520,6 +548,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
520
548
|
* @returns {RadioEvent|null} The current active event, or null if empty.
|
|
521
549
|
*/
|
|
522
550
|
getCurrentEvent() {
|
|
551
|
+
checkDestroy(this.#destroyed);
|
|
523
552
|
const now = Date.now();
|
|
524
553
|
this.#syncRealTimeState(now);
|
|
525
554
|
return this.#getEventAtTime(now, now);
|
|
@@ -534,6 +563,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
534
563
|
* @throws {RangeError} If the limit exceeds the configured queryLimit or is <= 0.
|
|
535
564
|
*/
|
|
536
565
|
queryTimeline(targetDate, limit = 10) {
|
|
566
|
+
checkDestroy(this.#destroyed);
|
|
537
567
|
if (typeof limit !== 'number' || isNaN(limit)) {
|
|
538
568
|
throw new TypeError(`Invalid query limit value. Ensure it is a number.`);
|
|
539
569
|
}
|
|
@@ -565,6 +595,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
565
595
|
* @returns {CustomPosition[]} Shallow copy of custom positions array.
|
|
566
596
|
*/
|
|
567
597
|
searchCustomPositions() {
|
|
598
|
+
checkDestroy(this.#destroyed);
|
|
568
599
|
this.#syncRealTimeState(Date.now());
|
|
569
600
|
return [...this.#customPositions];
|
|
570
601
|
}
|
|
@@ -578,10 +609,17 @@ class TinyRadioFm extends EventEmitter {
|
|
|
578
609
|
return Promise.all(list.map(async (item) => {
|
|
579
610
|
const newItem = structuredClone(item);
|
|
580
611
|
if (newItem.picture && Array.isArray(newItem.picture)) {
|
|
581
|
-
newItem.picture = await Promise.all(newItem.picture.map(async (pic) =>
|
|
582
|
-
|
|
583
|
-
data
|
|
584
|
-
|
|
612
|
+
newItem.picture = await Promise.all(newItem.picture.map(async (pic) => {
|
|
613
|
+
// Only performs the asynchronous conversion if it really is a Blob URL
|
|
614
|
+
if (typeof pic.data === 'string' && pic.data.startsWith('blob:')) {
|
|
615
|
+
return {
|
|
616
|
+
...pic,
|
|
617
|
+
data: await blobUrlToBase64(pic.data),
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
// If it is a normal URL, skip the process and keep it as it is
|
|
621
|
+
return pic;
|
|
622
|
+
}));
|
|
585
623
|
}
|
|
586
624
|
return newItem;
|
|
587
625
|
}));
|
|
@@ -607,6 +645,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
607
645
|
* @returns {Promise<string>} Stringified JSON state.
|
|
608
646
|
*/
|
|
609
647
|
async exportState() {
|
|
648
|
+
checkDestroy(this.#destroyed);
|
|
610
649
|
const processedMusic = await this._processListForExport(this.#musicList);
|
|
611
650
|
const processedVoice = await this._processListForExport(this.#voiceList);
|
|
612
651
|
const processedCustom = await Promise.all(this.#customPositions.map(async (cp) => {
|
|
@@ -641,6 +680,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
641
680
|
* @throws {TypeError} If json is not a valid string or object.
|
|
642
681
|
*/
|
|
643
682
|
importState(json) {
|
|
683
|
+
checkDestroy(this.#destroyed);
|
|
644
684
|
/** @type {TinyRadioFmImport} */
|
|
645
685
|
let data;
|
|
646
686
|
if (typeof json === 'string') {
|
|
@@ -663,7 +703,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
663
703
|
/**
|
|
664
704
|
* Mulberry32 Pseudo-Random Number Generator.
|
|
665
705
|
* @param {number} seed - The initialization seed.
|
|
666
|
-
* @returns {
|
|
706
|
+
* @returns {() => number} PRNG function returning a float between 0 and 1.
|
|
667
707
|
* @private
|
|
668
708
|
*/
|
|
669
709
|
_prng(seed) {
|
|
@@ -1075,10 +1115,19 @@ class TinyRadioFm extends EventEmitter {
|
|
|
1075
1115
|
return list.map((item) => {
|
|
1076
1116
|
const newItem = { ...item };
|
|
1077
1117
|
if (newItem.picture && Array.isArray(newItem.picture)) {
|
|
1078
|
-
newItem.picture = newItem.picture.map((pic) =>
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1118
|
+
newItem.picture = newItem.picture.map((pic) => {
|
|
1119
|
+
// Check whether the data is compatible with the Blob structure (Base64 or Binary)
|
|
1120
|
+
const isBase64 = typeof pic.data === 'string' && pic.data.startsWith('data:');
|
|
1121
|
+
const isUint8Array = pic.data instanceof Uint8Array;
|
|
1122
|
+
if (isBase64 || isUint8Array) {
|
|
1123
|
+
return {
|
|
1124
|
+
...pic,
|
|
1125
|
+
data: convertToBlobUrl(pic.data, pic.format),
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
// If it is a default web URL or local file, use the URL directly
|
|
1129
|
+
return pic;
|
|
1130
|
+
});
|
|
1082
1131
|
}
|
|
1083
1132
|
return newItem;
|
|
1084
1133
|
});
|
|
@@ -1111,6 +1160,8 @@ class TinyRadioFm extends EventEmitter {
|
|
|
1111
1160
|
* @param {boolean} [destroyThumbs=true]
|
|
1112
1161
|
*/
|
|
1113
1162
|
destroy(destroyThumbs = true) {
|
|
1163
|
+
if (this.#destroyed)
|
|
1164
|
+
return;
|
|
1114
1165
|
if (destroyThumbs) {
|
|
1115
1166
|
this.#musicList.forEach((item) => revokeContentUrls(item));
|
|
1116
1167
|
this.#voiceList.forEach((item) => revokeContentUrls(item));
|
|
@@ -1131,6 +1182,7 @@ class TinyRadioFm extends EventEmitter {
|
|
|
1131
1182
|
this.#cycleCache.clear();
|
|
1132
1183
|
this.emit('destroyed', { timestamp: Date.now() });
|
|
1133
1184
|
this.removeAllListeners();
|
|
1185
|
+
this.#destroyed = true;
|
|
1134
1186
|
}
|
|
1135
1187
|
}
|
|
1136
1188
|
export default TinyRadioFm;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var utils = require('./utils.cjs');
|
|
4
|
+
|
|
5
|
+
const checkDestroy = utils.createCheckDestroyed('TinyRateLimiter');
|
|
6
|
+
|
|
3
7
|
/**
|
|
4
8
|
* Callback triggered when a group's stored hit history exceeds
|
|
5
9
|
* the configured memory limit.
|
|
@@ -70,6 +74,21 @@
|
|
|
70
74
|
* and safe to use in long-running Node.js processes.
|
|
71
75
|
*/
|
|
72
76
|
class TinyRateLimiter {
|
|
77
|
+
/**
|
|
78
|
+
* Tracks whether the instance has been destroyed.
|
|
79
|
+
* @type {boolean}
|
|
80
|
+
*/
|
|
81
|
+
#destroyed = false;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Gets the current destruction status of the instance.
|
|
85
|
+
*
|
|
86
|
+
* @returns {boolean} True if the instance is destroyed, false otherwise.
|
|
87
|
+
*/
|
|
88
|
+
get destroyed() {
|
|
89
|
+
return this.#destroyed;
|
|
90
|
+
}
|
|
91
|
+
|
|
73
92
|
/**
|
|
74
93
|
* Maximum number of timestamps stored per group.
|
|
75
94
|
* When exceeded, older entries are discarded.
|
|
@@ -186,6 +205,7 @@ class TinyRateLimiter {
|
|
|
186
205
|
* @param {OnMemoryExceeded} callback
|
|
187
206
|
*/
|
|
188
207
|
setOnMemoryExceeded(callback) {
|
|
208
|
+
checkDestroy(this.#destroyed);
|
|
189
209
|
if (typeof callback !== 'function') throw new Error('onMemoryExceeded must be a function');
|
|
190
210
|
this.#onMemoryExceeded = callback;
|
|
191
211
|
}
|
|
@@ -194,6 +214,7 @@ class TinyRateLimiter {
|
|
|
194
214
|
* Removes the memory-exceeded callback.
|
|
195
215
|
*/
|
|
196
216
|
clearOnMemoryExceeded() {
|
|
217
|
+
checkDestroy(this.#destroyed);
|
|
197
218
|
this.#onMemoryExceeded = null;
|
|
198
219
|
}
|
|
199
220
|
|
|
@@ -213,6 +234,7 @@ class TinyRateLimiter {
|
|
|
213
234
|
* @param {OnGroupExpired} callback - A function that receives the expired groupId.
|
|
214
235
|
*/
|
|
215
236
|
setOnGroupExpired(callback) {
|
|
237
|
+
checkDestroy(this.#destroyed);
|
|
216
238
|
if (typeof callback !== 'function') throw new Error('onGroupExpired must be a function');
|
|
217
239
|
this.#onGroupExpired = callback;
|
|
218
240
|
}
|
|
@@ -221,6 +243,7 @@ class TinyRateLimiter {
|
|
|
221
243
|
* Removes the group-expiration callback.
|
|
222
244
|
*/
|
|
223
245
|
clearOnGroupExpired() {
|
|
246
|
+
checkDestroy(this.#destroyed);
|
|
224
247
|
this.#onGroupExpired = null;
|
|
225
248
|
}
|
|
226
249
|
|
|
@@ -285,6 +308,7 @@ class TinyRateLimiter {
|
|
|
285
308
|
* @returns {boolean}
|
|
286
309
|
*/
|
|
287
310
|
isGroupId(id) {
|
|
311
|
+
checkDestroy(this.#destroyed);
|
|
288
312
|
const result = this.groupFlags.get(id);
|
|
289
313
|
return typeof result === 'boolean' ? result : false;
|
|
290
314
|
}
|
|
@@ -295,6 +319,7 @@ class TinyRateLimiter {
|
|
|
295
319
|
* @returns {string[]}
|
|
296
320
|
*/
|
|
297
321
|
getUsersInGroup(groupId) {
|
|
322
|
+
checkDestroy(this.#destroyed);
|
|
298
323
|
const users = [];
|
|
299
324
|
for (const [userId, assignedGroup] of this.userToGroup.entries()) {
|
|
300
325
|
if (assignedGroup === groupId) {
|
|
@@ -311,6 +336,7 @@ class TinyRateLimiter {
|
|
|
311
336
|
* @param {number} ttl
|
|
312
337
|
*/
|
|
313
338
|
setGroupTTL(groupId, ttl) {
|
|
339
|
+
checkDestroy(this.#destroyed);
|
|
314
340
|
if (typeof ttl !== 'number' || !Number.isFinite(ttl) || ttl <= 0)
|
|
315
341
|
throw new Error('TTL must be a positive number in milliseconds');
|
|
316
342
|
this.groupTTL.set(groupId, ttl);
|
|
@@ -322,6 +348,7 @@ class TinyRateLimiter {
|
|
|
322
348
|
* @returns {number|null}
|
|
323
349
|
*/
|
|
324
350
|
getGroupTTL(groupId) {
|
|
351
|
+
checkDestroy(this.#destroyed);
|
|
325
352
|
return this.groupTTL.get(groupId) ?? null;
|
|
326
353
|
}
|
|
327
354
|
|
|
@@ -330,6 +357,7 @@ class TinyRateLimiter {
|
|
|
330
357
|
* @param {string} groupId
|
|
331
358
|
*/
|
|
332
359
|
deleteGroupTTL(groupId) {
|
|
360
|
+
checkDestroy(this.#destroyed);
|
|
333
361
|
this.groupTTL.delete(groupId);
|
|
334
362
|
}
|
|
335
363
|
|
|
@@ -344,6 +372,7 @@ class TinyRateLimiter {
|
|
|
344
372
|
* @throws {Error} If the user belongs to another group
|
|
345
373
|
*/
|
|
346
374
|
assignToGroup(userId, groupId) {
|
|
375
|
+
checkDestroy(this.#destroyed);
|
|
347
376
|
const existingGroup = this.userToGroup.get(userId);
|
|
348
377
|
if (existingGroup && existingGroup !== groupId)
|
|
349
378
|
throw new Error(`User ${userId} is already assigned to group ${existingGroup}`);
|
|
@@ -391,6 +420,7 @@ class TinyRateLimiter {
|
|
|
391
420
|
* @returns {string}
|
|
392
421
|
*/
|
|
393
422
|
getGroupId(userId) {
|
|
423
|
+
checkDestroy(this.#destroyed);
|
|
394
424
|
return this.userToGroup.get(userId) || userId; // fallback: use userId as own group
|
|
395
425
|
}
|
|
396
426
|
|
|
@@ -417,6 +447,7 @@ class TinyRateLimiter {
|
|
|
417
447
|
* @param {string} userId
|
|
418
448
|
*/
|
|
419
449
|
hit(userId) {
|
|
450
|
+
checkDestroy(this.#destroyed);
|
|
420
451
|
const groupId = this.getGroupId(userId);
|
|
421
452
|
const now = Date.now();
|
|
422
453
|
|
|
@@ -470,6 +501,7 @@ class TinyRateLimiter {
|
|
|
470
501
|
* @returns {boolean}
|
|
471
502
|
*/
|
|
472
503
|
isRateLimited(userId) {
|
|
504
|
+
checkDestroy(this.#destroyed);
|
|
473
505
|
const groupId = this.getGroupId(userId);
|
|
474
506
|
if (!this.groupData.has(groupId)) return false;
|
|
475
507
|
|
|
@@ -501,6 +533,7 @@ class TinyRateLimiter {
|
|
|
501
533
|
* @param {string} groupId
|
|
502
534
|
*/
|
|
503
535
|
resetGroup(groupId) {
|
|
536
|
+
checkDestroy(this.#destroyed);
|
|
504
537
|
this.groupFlags.delete(groupId);
|
|
505
538
|
this.groupData.delete(groupId);
|
|
506
539
|
this.lastSeen.delete(groupId);
|
|
@@ -512,6 +545,7 @@ class TinyRateLimiter {
|
|
|
512
545
|
* @param {string} userId
|
|
513
546
|
*/
|
|
514
547
|
resetUserGroup(userId) {
|
|
548
|
+
checkDestroy(this.#destroyed);
|
|
515
549
|
this.userToGroup.delete(userId);
|
|
516
550
|
}
|
|
517
551
|
|
|
@@ -521,6 +555,7 @@ class TinyRateLimiter {
|
|
|
521
555
|
* @param {number[]} timestamps
|
|
522
556
|
*/
|
|
523
557
|
setData(groupId, timestamps) {
|
|
558
|
+
checkDestroy(this.#destroyed);
|
|
524
559
|
if (!Array.isArray(timestamps)) throw new Error('timestamps must be an array of numbers.');
|
|
525
560
|
for (const t of timestamps) {
|
|
526
561
|
if (typeof t !== 'number' || !Number.isFinite(t)) {
|
|
@@ -538,6 +573,7 @@ class TinyRateLimiter {
|
|
|
538
573
|
* @returns {boolean}
|
|
539
574
|
*/
|
|
540
575
|
hasData(groupId) {
|
|
576
|
+
checkDestroy(this.#destroyed);
|
|
541
577
|
return this.groupData.has(groupId);
|
|
542
578
|
}
|
|
543
579
|
|
|
@@ -547,6 +583,7 @@ class TinyRateLimiter {
|
|
|
547
583
|
* @returns {number[]}
|
|
548
584
|
*/
|
|
549
585
|
getData(groupId) {
|
|
586
|
+
checkDestroy(this.#destroyed);
|
|
550
587
|
return this.groupData.get(groupId) || [];
|
|
551
588
|
}
|
|
552
589
|
|
|
@@ -555,6 +592,7 @@ class TinyRateLimiter {
|
|
|
555
592
|
* @returns {number}
|
|
556
593
|
*/
|
|
557
594
|
getMaxIdle() {
|
|
595
|
+
checkDestroy(this.#destroyed);
|
|
558
596
|
if (typeof this.#maxIdle !== 'number' || !Number.isFinite(this.#maxIdle) || this.#maxIdle < 0) {
|
|
559
597
|
throw new Error("'maxIdle' must be a non-negative finite number.");
|
|
560
598
|
}
|
|
@@ -566,6 +604,7 @@ class TinyRateLimiter {
|
|
|
566
604
|
* @param {number} ms
|
|
567
605
|
*/
|
|
568
606
|
setMaxIdle(ms) {
|
|
607
|
+
checkDestroy(this.#destroyed);
|
|
569
608
|
if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0) {
|
|
570
609
|
throw new Error("'maxIdle' must be a non-negative finite number.");
|
|
571
610
|
}
|
|
@@ -599,6 +638,7 @@ class TinyRateLimiter {
|
|
|
599
638
|
* @returns {string[]}
|
|
600
639
|
*/
|
|
601
640
|
getActiveGroups() {
|
|
641
|
+
checkDestroy(this.#destroyed);
|
|
602
642
|
return Array.from(this.groupData.keys());
|
|
603
643
|
}
|
|
604
644
|
|
|
@@ -607,6 +647,7 @@ class TinyRateLimiter {
|
|
|
607
647
|
* @returns {Record<string, string>}
|
|
608
648
|
*/
|
|
609
649
|
getAllUserMappings() {
|
|
650
|
+
checkDestroy(this.#destroyed);
|
|
610
651
|
return Object.fromEntries(this.userToGroup);
|
|
611
652
|
}
|
|
612
653
|
|
|
@@ -619,6 +660,7 @@ class TinyRateLimiter {
|
|
|
619
660
|
* @returns {number}
|
|
620
661
|
*/
|
|
621
662
|
getInterval() {
|
|
663
|
+
checkDestroy(this.#destroyed);
|
|
622
664
|
if (typeof this.#interval !== 'number' || !Number.isFinite(this.#interval)) {
|
|
623
665
|
throw new Error("'interval' is not a valid finite number.");
|
|
624
666
|
}
|
|
@@ -630,6 +672,7 @@ class TinyRateLimiter {
|
|
|
630
672
|
* @returns {number}
|
|
631
673
|
*/
|
|
632
674
|
getMaxHits() {
|
|
675
|
+
checkDestroy(this.#destroyed);
|
|
633
676
|
if (typeof this.#maxHits !== 'number' || !Number.isFinite(this.#maxHits)) {
|
|
634
677
|
throw new Error("'maxHits' is not a valid finite number.");
|
|
635
678
|
}
|
|
@@ -642,6 +685,7 @@ class TinyRateLimiter {
|
|
|
642
685
|
* @returns {number}
|
|
643
686
|
*/
|
|
644
687
|
getTotalHits(groupId) {
|
|
688
|
+
checkDestroy(this.#destroyed);
|
|
645
689
|
const history = this.groupData.get(groupId);
|
|
646
690
|
return Array.isArray(history) ? history.length : 0;
|
|
647
691
|
}
|
|
@@ -652,6 +696,7 @@ class TinyRateLimiter {
|
|
|
652
696
|
* @returns {number|null}
|
|
653
697
|
*/
|
|
654
698
|
getLastHit(groupId) {
|
|
699
|
+
checkDestroy(this.#destroyed);
|
|
655
700
|
const history = this.groupData.get(groupId);
|
|
656
701
|
return history?.length ? history[history.length - 1] : null;
|
|
657
702
|
}
|
|
@@ -662,6 +707,7 @@ class TinyRateLimiter {
|
|
|
662
707
|
* @returns {number|null}
|
|
663
708
|
*/
|
|
664
709
|
getTimeSinceLastHit(groupId) {
|
|
710
|
+
checkDestroy(this.#destroyed);
|
|
665
711
|
const last = this.getLastHit(groupId);
|
|
666
712
|
return last !== null ? Date.now() - last : null;
|
|
667
713
|
}
|
|
@@ -687,6 +733,7 @@ class TinyRateLimiter {
|
|
|
687
733
|
* @returns {number|null}
|
|
688
734
|
*/
|
|
689
735
|
getAverageHitSpacing(groupId) {
|
|
736
|
+
checkDestroy(this.#destroyed);
|
|
690
737
|
return this._calculateAverageSpacing(this.groupData.get(groupId));
|
|
691
738
|
}
|
|
692
739
|
|
|
@@ -701,6 +748,7 @@ class TinyRateLimiter {
|
|
|
701
748
|
* }}
|
|
702
749
|
*/
|
|
703
750
|
getMetrics(groupId) {
|
|
751
|
+
checkDestroy(this.#destroyed);
|
|
704
752
|
const history = this.groupData.get(groupId);
|
|
705
753
|
|
|
706
754
|
if (!Array.isArray(history) || history.length === 0) {
|
|
@@ -729,6 +777,7 @@ class TinyRateLimiter {
|
|
|
729
777
|
* Destroy the rate limiter, stopping cleanup and clearing data
|
|
730
778
|
*/
|
|
731
779
|
destroy() {
|
|
780
|
+
if (this.destroyed) return;
|
|
732
781
|
if (this.#cleanupTimer) clearInterval(this.#cleanupTimer);
|
|
733
782
|
this._cleanup();
|
|
734
783
|
this.groupData.clear();
|
|
@@ -736,6 +785,9 @@ class TinyRateLimiter {
|
|
|
736
785
|
this.userToGroup.clear();
|
|
737
786
|
this.groupTTL.clear();
|
|
738
787
|
this.groupFlags.clear();
|
|
788
|
+
|
|
789
|
+
// Lock the instance
|
|
790
|
+
this.#destroyed = true;
|
|
739
791
|
}
|
|
740
792
|
}
|
|
741
793
|
|
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
export default TinyRateLimiter;
|
|
2
|
-
/**
|
|
3
|
-
* Callback triggered when a group's stored hit history exceeds
|
|
4
|
-
* the configured memory limit.
|
|
5
|
-
*
|
|
6
|
-
* This callback is purely informational and does not block execution.
|
|
7
|
-
*/
|
|
8
1
|
export type OnMemoryExceeded = (groupId: string) => void;
|
|
9
|
-
/**
|
|
10
|
-
* Callback triggered when a group is considered expired and removed
|
|
11
|
-
* during the cleanup process.
|
|
12
|
-
*
|
|
13
|
-
* This usually happens when the group remains inactive longer than
|
|
14
|
-
* its configured TTL or the global maxIdle value.
|
|
15
|
-
*/
|
|
16
2
|
export type OnGroupExpired = (groupId: string) => void;
|
|
17
3
|
/**
|
|
18
4
|
* Callback triggered when a group's stored hit history exceeds
|
|
@@ -82,30 +68,13 @@ export type OnGroupExpired = (groupId: string) => void;
|
|
|
82
68
|
* and safe to use in long-running Node.js processes.
|
|
83
69
|
*/
|
|
84
70
|
declare class TinyRateLimiter {
|
|
71
|
+
#private;
|
|
85
72
|
/**
|
|
86
|
-
*
|
|
73
|
+
* Gets the current destruction status of the instance.
|
|
87
74
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* @param {Object} options
|
|
91
|
-
* @param {number|null} [options.maxMemory=100000]
|
|
92
|
-
* Maximum timestamps stored per group (memory cap).
|
|
93
|
-
* @param {number} [options.maxHits]
|
|
94
|
-
* Maximum number of allowed hits.
|
|
95
|
-
* @param {number} [options.interval]
|
|
96
|
-
* Sliding time window in milliseconds.
|
|
97
|
-
* @param {number} [options.cleanupInterval]
|
|
98
|
-
* Interval (ms) for automatic cleanup execution.
|
|
99
|
-
* @param {number} [options.maxIdle=300000]
|
|
100
|
-
* Maximum inactivity time (ms) before a group expires.
|
|
75
|
+
* @returns {boolean} True if the instance is destroyed, false otherwise.
|
|
101
76
|
*/
|
|
102
|
-
|
|
103
|
-
maxMemory?: number | null | undefined;
|
|
104
|
-
maxHits?: number | undefined;
|
|
105
|
-
interval?: number | undefined;
|
|
106
|
-
cleanupInterval?: number | undefined;
|
|
107
|
-
maxIdle?: number | undefined;
|
|
108
|
-
});
|
|
77
|
+
get destroyed(): boolean;
|
|
109
78
|
/**
|
|
110
79
|
* Stores hit timestamps per group.
|
|
111
80
|
*
|
|
@@ -170,6 +139,30 @@ declare class TinyRateLimiter {
|
|
|
170
139
|
* Removes the group-expiration callback.
|
|
171
140
|
*/
|
|
172
141
|
clearOnGroupExpired(): void;
|
|
142
|
+
/**
|
|
143
|
+
* Creates a new TinyRateLimiter instance.
|
|
144
|
+
*
|
|
145
|
+
* At least one of `maxHits` or `interval` must be provided.
|
|
146
|
+
*
|
|
147
|
+
* @param {Object} options
|
|
148
|
+
* @param {number|null} [options.maxMemory=100000]
|
|
149
|
+
* Maximum timestamps stored per group (memory cap).
|
|
150
|
+
* @param {number} [options.maxHits]
|
|
151
|
+
* Maximum number of allowed hits.
|
|
152
|
+
* @param {number} [options.interval]
|
|
153
|
+
* Sliding time window in milliseconds.
|
|
154
|
+
* @param {number} [options.cleanupInterval]
|
|
155
|
+
* Interval (ms) for automatic cleanup execution.
|
|
156
|
+
* @param {number} [options.maxIdle=300000]
|
|
157
|
+
* Maximum inactivity time (ms) before a group expires.
|
|
158
|
+
*/
|
|
159
|
+
constructor({ maxHits, interval, cleanupInterval, maxIdle, maxMemory }: {
|
|
160
|
+
maxMemory?: number | null;
|
|
161
|
+
maxHits?: number;
|
|
162
|
+
interval?: number;
|
|
163
|
+
cleanupInterval?: number;
|
|
164
|
+
maxIdle?: number;
|
|
165
|
+
});
|
|
173
166
|
/**
|
|
174
167
|
* Check if a given ID is a groupId (not a userId)
|
|
175
168
|
* @param {string} id
|
|
@@ -382,6 +375,6 @@ declare class TinyRateLimiter {
|
|
|
382
375
|
* Destroy the rate limiter, stopping cleanup and clearing data
|
|
383
376
|
*/
|
|
384
377
|
destroy(): void;
|
|
385
|
-
#private;
|
|
386
378
|
}
|
|
379
|
+
export default TinyRateLimiter;
|
|
387
380
|
//# sourceMappingURL=TinyRateLimiter.d.mts.map
|