From c8fc291f634b1fe627a40797fac0d97081d9ab25 Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 14:45:27 +0200 Subject: [PATCH 1/9] Postponing refresh when interval is greater than 24.8 days, to comply with JS max number limit. --- src/runtime/utils/refreshHandler.ts | 49 ++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index fc2af2c8..17f726b0 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -18,6 +18,12 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Because passing `this.visibilityHandler` to `document.addEventHandler` loses `this` context */ private boundVisibilityHandler: typeof this.visibilityHandler + /** Maximum age of the refresh token, in milliseconds */ + private maxAgeMs?: number + + /** Maximum JS value for setTimeout & setInterval (~24.85 days) */ + private readonly MAX_JS_TIMEOUT = 2_147_483_647 + constructor( public config: DefaultRefreshHandlerConfig ) { @@ -43,13 +49,8 @@ export class DefaultRefreshHandler implements RefreshHandler { const provider = this.runtimeConfig.provider if (provider.type === 'local' && provider.refresh.isEnabled && provider.refresh.token?.maxAgeInSeconds) { - const intervalTime = provider.refresh.token.maxAgeInSeconds * 1000 - - this.refreshTokenIntervalTimer = setInterval(() => { - if (this.auth?.refreshToken.value) { - this.auth.refresh() - } - }, intervalTime) + this.maxAgeMs = provider.refresh.token.maxAgeInSeconds * 1000 + this.startRefreshTimer(this.maxAgeMs) } } @@ -78,4 +79,38 @@ export class DefaultRefreshHandler implements RefreshHandler { this.auth.refresh() } } + + /** + * Starts the refresh timer, breaking down large intervals + * into smaller chunks, to avoid overflow issues. + * + * @param durationMs - Duration, in milliseconds. + */ + private startRefreshTimer(durationMs: number): void { + // Validate duration. + if (durationMs <= 0) { + return + } + + if (durationMs > this.MAX_JS_TIMEOUT) { + // Postpone for max value, when the interval exceeds it. + // It will continue with the remaining time. + this.refreshTokenIntervalTimer = setTimeout(() => { + const remainingDurationMs = durationMs - this.MAX_JS_TIMEOUT + this.startRefreshTimer(remainingDurationMs) + }, this.MAX_JS_TIMEOUT) + } + else { + // Perform refresh for a safe duration + // and reset its timer to the original value. + this.refreshTokenIntervalTimer = setTimeout(() => { + if (this.auth?.refreshToken.value) { + this.auth.refresh() + } + + // Restart the timer to its original value. + this.startRefreshTimer(this.maxAgeMs) + }, durationMs) + } + } } From f3b0b1c80fa87964604b2905328d3ab83c3c0b96 Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 14:47:57 +0200 Subject: [PATCH 2/9] Increased default refresh interval - 5 mins is a reasonable minimum for most apps & avoids too many calls to backend. --- src/runtime/utils/refreshHandler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index 17f726b0..5dca95c5 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -37,9 +37,10 @@ export class DefaultRefreshHandler implements RefreshHandler { document.addEventListener('visibilitychange', this.boundVisibilityHandler, false) const { enablePeriodically } = this.config + const defaultRefreshInterval = 5 * 60 * 1000 // 5 minutes, in ms if (enablePeriodically !== false) { - const intervalTime = enablePeriodically === true ? 1000 : enablePeriodically + const intervalTime = enablePeriodically === true ? defaultRefreshInterval : enablePeriodically this.refetchIntervalTimer = setInterval(() => { if (this.auth?.data.value) { this.auth.refresh() From 40a66746da446108d953607fce37f2a45bfa497c Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 14:51:36 +0200 Subject: [PATCH 3/9] Fixed timer refresh warning - this.maxAgeMs should always be set when the method is called, but we default to zero just in case. --- src/runtime/utils/refreshHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index 5dca95c5..5da9e062 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -110,7 +110,7 @@ export class DefaultRefreshHandler implements RefreshHandler { } // Restart the timer to its original value. - this.startRefreshTimer(this.maxAgeMs) + this.startRefreshTimer(this.maxAgeMs ?? 0) }, durationMs) } } From 50fa982d8410b918be4237bd9d2e8cf01bd675c1 Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 16:26:02 +0200 Subject: [PATCH 4/9] Unified both timers under the same method. --- src/runtime/utils/refreshHandler.ts | 91 ++++++++++++++++++----------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index 5da9e062..96cba08c 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -8,11 +8,11 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Runtime config is mostly used for getting provider data */ runtimeConfig?: ModuleOptionsNormalized - /** Refetch interval */ + /** Timer for periodic refresh */ refetchIntervalTimer?: ReturnType + /** Timer for refresh token renewal */ // TODO: find more Generic method to start a Timer for the Refresh Token - /** Refetch interval for local/refresh schema */ refreshTokenIntervalTimer?: ReturnType /** Because passing `this.visibilityHandler` to `document.addEventHandler` loses `this` context */ @@ -21,8 +21,11 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Maximum age of the refresh token, in milliseconds */ private maxAgeMs?: number - /** Maximum JS value for setTimeout & setInterval (~24.85 days) */ - private readonly MAX_JS_TIMEOUT = 2_147_483_647 + /** Interval time for periodic refresh, in milliseconds */ + private intervalTime?: number + + /** Maximum value for setTimeout & setInterval in JavaScript (~24.85 days) */ + private readonly MAX_JS_TIMEOUT: number = 2_147_483_647 constructor( public config: DefaultRefreshHandlerConfig @@ -30,39 +33,46 @@ export class DefaultRefreshHandler implements RefreshHandler { this.boundVisibilityHandler = this.visibilityHandler.bind(this) } + /** + * Initializes the refresh handler, setting up timers and event listeners. + */ init(): void { this.runtimeConfig = useRuntimeConfig().public.auth this.auth = useAuth() + // Set up visibility change listener document.addEventListener('visibilitychange', this.boundVisibilityHandler, false) const { enablePeriodically } = this.config - const defaultRefreshInterval = 5 * 60 * 1000 // 5 minutes, in ms + const defaultRefreshInterval: number = 5 * 60 * 1000 // 5 minutes, in ms + // Set up periodic refresh, if enabled if (enablePeriodically !== false) { - const intervalTime = enablePeriodically === true ? defaultRefreshInterval : enablePeriodically - this.refetchIntervalTimer = setInterval(() => { - if (this.auth?.data.value) { - this.auth.refresh() - } - }, intervalTime) + this.intervalTime = enablePeriodically === true ? defaultRefreshInterval : (enablePeriodically ?? defaultRefreshInterval) + this.startRefreshTimer(this.intervalTime, 'refetchIntervalTimer') } + // Set up refresh token timer, if applicable const provider = this.runtimeConfig.provider if (provider.type === 'local' && provider.refresh.isEnabled && provider.refresh.token?.maxAgeInSeconds) { this.maxAgeMs = provider.refresh.token.maxAgeInSeconds * 1000 - this.startRefreshTimer(this.maxAgeMs) + this.startRefreshTimer(this.maxAgeMs, 'refreshTokenIntervalTimer') } } + /** + * Cleans up timers and event listeners. + */ destroy(): void { - // Clear visibility handler + // Clear visibility change listener document.removeEventListener('visibilitychange', this.boundVisibilityHandler, false) - // Clear refetch interval - clearInterval(this.refetchIntervalTimer) + // Clear periodic refresh timer + if (this.refetchIntervalTimer) { + clearInterval(this.refetchIntervalTimer) + } - // Clear refetch interval + // Clear refresh token timer if (this.refreshTokenIntervalTimer) { clearInterval(this.refreshTokenIntervalTimer) } @@ -72,45 +82,56 @@ export class DefaultRefreshHandler implements RefreshHandler { this.runtimeConfig = undefined } + /** + * Handles visibility changes, refreshing the session when the browser tab/page becomes visible. + */ visibilityHandler(): void { - // Listen for when the page is visible, if the user switches tabs - // and makes our tab visible again, re-fetch the session, but only if - // this feature is not disabled. if (this.config?.enableOnWindowFocus && document.visibilityState === 'visible' && this.auth?.data.value) { this.auth.refresh() } } /** - * Starts the refresh timer, breaking down large intervals - * into smaller chunks, to avoid overflow issues. + * Starts or restarts a refresh timer, handling large durations by breaking them into smaller intervals. + * This method is used to periodically trigger the refresh. * - * @param durationMs - Duration, in milliseconds. + * @param {number} durationMs - The duration in milliseconds before the next refresh should occur. + * @param {'refetchIntervalTimer' | 'refreshTokenIntervalTimer'} timerName - Identifies which timer to start. */ - private startRefreshTimer(durationMs: number): void { - // Validate duration. + private startRefreshTimer(durationMs: number, timerName: 'refetchIntervalTimer' | 'refreshTokenIntervalTimer'): void { + // Ensure the duration is positive; if not, exit early if (durationMs <= 0) { return } + // Validate that the timerName is one of the allowed values + if (!['refetchIntervalTimer', 'refreshTokenIntervalTimer'].includes(timerName)) { + throw new Error(`Invalid timer name: ${timerName}`) + } + if (durationMs > this.MAX_JS_TIMEOUT) { - // Postpone for max value, when the interval exceeds it. - // It will continue with the remaining time. - this.refreshTokenIntervalTimer = setTimeout(() => { - const remainingDurationMs = durationMs - this.MAX_JS_TIMEOUT - this.startRefreshTimer(remainingDurationMs) + // If the duration exceeds JavaScript's maximum timeout value: + // Set a timeout for the maximum allowed duration, then recursively call + // this method with the remaining time when that timeout completes. + (this as any)[timerName] = setTimeout(() => { + this.startRefreshTimer(durationMs - this.MAX_JS_TIMEOUT, timerName) }, this.MAX_JS_TIMEOUT) } else { - // Perform refresh for a safe duration - // and reset its timer to the original value. - this.refreshTokenIntervalTimer = setTimeout(() => { - if (this.auth?.refreshToken.value) { + // If the duration is within the allowed range: + // The refresh can be triggered and the timer can be reset. + (this as any)[timerName] = setTimeout(() => { + // Determine which auth property to check based on the timer type + const needsSessOrToken: 'data' | 'refreshToken' = timerName === 'refetchIntervalTimer' ? 'data' : 'refreshToken' + + // Only refresh if the relevant auth data exists + if (this.auth?.[needsSessOrToken].value) { this.auth.refresh() } - // Restart the timer to its original value. - this.startRefreshTimer(this.maxAgeMs ?? 0) + // Restart timer with its original duration + const originalDuration: number = timerName === 'refetchIntervalTimer' ? this.intervalTime ?? 0 : this.maxAgeMs ?? 0 + this.startRefreshTimer(originalDuration, timerName) }, durationMs) } } From 66d3eb069b9e1fe345d8f9315fbdbb84c9c94480 Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 16:38:57 +0200 Subject: [PATCH 5/9] Type fix --- src/runtime/utils/refreshHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index 96cba08c..e248c4fe 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -113,14 +113,14 @@ export class DefaultRefreshHandler implements RefreshHandler { // If the duration exceeds JavaScript's maximum timeout value: // Set a timeout for the maximum allowed duration, then recursively call // this method with the remaining time when that timeout completes. - (this as any)[timerName] = setTimeout(() => { + this[timerName] = setTimeout(() => { this.startRefreshTimer(durationMs - this.MAX_JS_TIMEOUT, timerName) }, this.MAX_JS_TIMEOUT) } else { // If the duration is within the allowed range: // The refresh can be triggered and the timer can be reset. - (this as any)[timerName] = setTimeout(() => { + this[timerName] = setTimeout(() => { // Determine which auth property to check based on the timer type const needsSessOrToken: 'data' | 'refreshToken' = timerName === 'refetchIntervalTimer' ? 'data' : 'refreshToken' From b03d0da51b7593bdb8970050cfe9ae14fd3480d8 Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 17:09:21 +0200 Subject: [PATCH 6/9] This addresses the pending 'TODO', proposing a more general approach for starting refresh timers. --- src/runtime/utils/refreshHandler.ts | 67 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index e248c4fe..df158670 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -8,25 +8,19 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Runtime config is mostly used for getting provider data */ runtimeConfig?: ModuleOptionsNormalized - /** Timer for periodic refresh */ - refetchIntervalTimer?: ReturnType - - /** Timer for refresh token renewal */ - // TODO: find more Generic method to start a Timer for the Refresh Token - refreshTokenIntervalTimer?: ReturnType - /** Because passing `this.visibilityHandler` to `document.addEventHandler` loses `this` context */ private boundVisibilityHandler: typeof this.visibilityHandler - /** Maximum age of the refresh token, in milliseconds */ - private maxAgeMs?: number - - /** Interval time for periodic refresh, in milliseconds */ - private intervalTime?: number - /** Maximum value for setTimeout & setInterval in JavaScript (~24.85 days) */ private readonly MAX_JS_TIMEOUT: number = 2_147_483_647 + /** Timers for different refresh types */ + private refreshTimers: { [key: string]: ReturnType } = {} + + /** Reset interval times for periodic refresh, in milliseconds */ + private refreshIntervals: { [key: string]: number } = {} + + constructor( public config: DefaultRefreshHandlerConfig ) { @@ -48,15 +42,15 @@ export class DefaultRefreshHandler implements RefreshHandler { // Set up periodic refresh, if enabled if (enablePeriodically !== false) { - this.intervalTime = enablePeriodically === true ? defaultRefreshInterval : (enablePeriodically ?? defaultRefreshInterval) - this.startRefreshTimer(this.intervalTime, 'refetchIntervalTimer') + this.refreshIntervals['periodic'] = enablePeriodically === true ? defaultRefreshInterval : (enablePeriodically ?? defaultRefreshInterval) + this.startRefreshTimer('periodic', this.refreshIntervals['periodic']) } // Set up refresh token timer, if applicable const provider = this.runtimeConfig.provider if (provider.type === 'local' && provider.refresh.isEnabled && provider.refresh.token?.maxAgeInSeconds) { - this.maxAgeMs = provider.refresh.token.maxAgeInSeconds * 1000 - this.startRefreshTimer(this.maxAgeMs, 'refreshTokenIntervalTimer') + this.refreshIntervals['maxAge'] = provider.refresh.token.maxAgeInSeconds * 1000 + this.startRefreshTimer('maxAge', this.refreshIntervals['maxAge']) } } @@ -67,15 +61,8 @@ export class DefaultRefreshHandler implements RefreshHandler { // Clear visibility change listener document.removeEventListener('visibilitychange', this.boundVisibilityHandler, false) - // Clear periodic refresh timer - if (this.refetchIntervalTimer) { - clearInterval(this.refetchIntervalTimer) - } - - // Clear refresh token timer - if (this.refreshTokenIntervalTimer) { - clearInterval(this.refreshTokenIntervalTimer) - } + // Clear refresh timers + this.clearAllTimers() // Release state this.auth = undefined @@ -95,17 +82,17 @@ export class DefaultRefreshHandler implements RefreshHandler { * Starts or restarts a refresh timer, handling large durations by breaking them into smaller intervals. * This method is used to periodically trigger the refresh. * + * @param {'periodic' | 'maxAge'} timerName - Identifies which timer to start. * @param {number} durationMs - The duration in milliseconds before the next refresh should occur. - * @param {'refetchIntervalTimer' | 'refreshTokenIntervalTimer'} timerName - Identifies which timer to start. */ - private startRefreshTimer(durationMs: number, timerName: 'refetchIntervalTimer' | 'refreshTokenIntervalTimer'): void { + private startRefreshTimer(timerName: 'periodic' | 'maxAge', durationMs: number): void { // Ensure the duration is positive; if not, exit early if (durationMs <= 0) { return } // Validate that the timerName is one of the allowed values - if (!['refetchIntervalTimer', 'refreshTokenIntervalTimer'].includes(timerName)) { + if (!['periodic', 'maxAge'].includes(timerName)) { throw new Error(`Invalid timer name: ${timerName}`) } @@ -113,16 +100,16 @@ export class DefaultRefreshHandler implements RefreshHandler { // If the duration exceeds JavaScript's maximum timeout value: // Set a timeout for the maximum allowed duration, then recursively call // this method with the remaining time when that timeout completes. - this[timerName] = setTimeout(() => { - this.startRefreshTimer(durationMs - this.MAX_JS_TIMEOUT, timerName) + this.refreshTimers[timerName] = setTimeout(() => { + this.startRefreshTimer(timerName, durationMs - this.MAX_JS_TIMEOUT) }, this.MAX_JS_TIMEOUT) } else { // If the duration is within the allowed range: // The refresh can be triggered and the timer can be reset. - this[timerName] = setTimeout(() => { + this.refreshTimers[timerName] = setTimeout(() => { // Determine which auth property to check based on the timer type - const needsSessOrToken: 'data' | 'refreshToken' = timerName === 'refetchIntervalTimer' ? 'data' : 'refreshToken' + const needsSessOrToken: 'data' | 'refreshToken' = timerName === 'periodic' ? 'data' : 'refreshToken' // Only refresh if the relevant auth data exists if (this.auth?.[needsSessOrToken].value) { @@ -130,9 +117,19 @@ export class DefaultRefreshHandler implements RefreshHandler { } // Restart timer with its original duration - const originalDuration: number = timerName === 'refetchIntervalTimer' ? this.intervalTime ?? 0 : this.maxAgeMs ?? 0 - this.startRefreshTimer(originalDuration, timerName) + this.startRefreshTimer(timerName, this.refreshIntervals[timerName] ?? 0) }, durationMs) } } + + /** + * Clears all active refresh timers. + */ + private clearAllTimers(): void { + Object.values(this.refreshTimers).forEach((timer) => { + if (timer) { + clearTimeout(timer) + } + }) + } } From b41f424317414e6fb27686d41a6062e2d964d04c Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 17:14:17 +0200 Subject: [PATCH 7/9] Linter / dot-notation fixes --- src/runtime/utils/refreshHandler.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index df158670..99ccb107 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -20,7 +20,6 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Reset interval times for periodic refresh, in milliseconds */ private refreshIntervals: { [key: string]: number } = {} - constructor( public config: DefaultRefreshHandlerConfig ) { @@ -42,15 +41,15 @@ export class DefaultRefreshHandler implements RefreshHandler { // Set up periodic refresh, if enabled if (enablePeriodically !== false) { - this.refreshIntervals['periodic'] = enablePeriodically === true ? defaultRefreshInterval : (enablePeriodically ?? defaultRefreshInterval) - this.startRefreshTimer('periodic', this.refreshIntervals['periodic']) + this.refreshIntervals.periodic = enablePeriodically === true ? defaultRefreshInterval : (enablePeriodically ?? defaultRefreshInterval) + this.startRefreshTimer('periodic', this.refreshIntervals.periodic) } // Set up refresh token timer, if applicable const provider = this.runtimeConfig.provider if (provider.type === 'local' && provider.refresh.isEnabled && provider.refresh.token?.maxAgeInSeconds) { - this.refreshIntervals['maxAge'] = provider.refresh.token.maxAgeInSeconds * 1000 - this.startRefreshTimer('maxAge', this.refreshIntervals['maxAge']) + this.refreshIntervals.maxAge = provider.refresh.token.maxAgeInSeconds * 1000 + this.startRefreshTimer('maxAge', this.refreshIntervals.maxAge) } } From 0bbd066a8a76d7c00ba3a2897e2b45349fb4f819 Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 17:35:33 +0200 Subject: [PATCH 8/9] Improving unclear comments. --- src/runtime/utils/refreshHandler.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index 99ccb107..87b6cae8 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -14,10 +14,16 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Maximum value for setTimeout & setInterval in JavaScript (~24.85 days) */ private readonly MAX_JS_TIMEOUT: number = 2_147_483_647 - /** Timers for different refresh types */ + /** + * Timers for different refresh types. + * Key represents name, value is timeout object. + */ private refreshTimers: { [key: string]: ReturnType } = {} - /** Reset interval times for periodic refresh, in milliseconds */ + /** + * Interval durations for executing refresh timers. + * Key represents timer name, value is interval duration (in milliseconds). + */ private refreshIntervals: { [key: string]: number } = {} constructor( @@ -39,13 +45,13 @@ export class DefaultRefreshHandler implements RefreshHandler { const { enablePeriodically } = this.config const defaultRefreshInterval: number = 5 * 60 * 1000 // 5 minutes, in ms - // Set up periodic refresh, if enabled + // Set up 'periodic' refresh timer if (enablePeriodically !== false) { this.refreshIntervals.periodic = enablePeriodically === true ? defaultRefreshInterval : (enablePeriodically ?? defaultRefreshInterval) this.startRefreshTimer('periodic', this.refreshIntervals.periodic) } - // Set up refresh token timer, if applicable + // Set up 'maxAge' refresh timer const provider = this.runtimeConfig.provider if (provider.type === 'local' && provider.refresh.isEnabled && provider.refresh.token?.maxAgeInSeconds) { this.refreshIntervals.maxAge = provider.refresh.token.maxAgeInSeconds * 1000 From 008bd5e44fb111296eb4f70909c30d90f4c201ac Mon Sep 17 00:00:00 2001 From: Ciprian Cimpan Date: Thu, 29 Aug 2024 17:38:02 +0200 Subject: [PATCH 9/9] Lint fix for trailing spaces --- src/runtime/utils/refreshHandler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/utils/refreshHandler.ts b/src/runtime/utils/refreshHandler.ts index 87b6cae8..4a7fd006 100644 --- a/src/runtime/utils/refreshHandler.ts +++ b/src/runtime/utils/refreshHandler.ts @@ -14,13 +14,13 @@ export class DefaultRefreshHandler implements RefreshHandler { /** Maximum value for setTimeout & setInterval in JavaScript (~24.85 days) */ private readonly MAX_JS_TIMEOUT: number = 2_147_483_647 - /** + /** * Timers for different refresh types. * Key represents name, value is timeout object. */ private refreshTimers: { [key: string]: ReturnType } = {} - /** + /** * Interval durations for executing refresh timers. * Key represents timer name, value is interval duration (in milliseconds). */