
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
shared-timer-manager
Advanced tools
Manage multiple timer tasks with a single SharedWebWorker. Perfect for handling recurring tasks like token refresh, inactivity detection, and sleep mode across your application.
Using a SharedWorker for scheduling time-sensitive tasks is often preferable to relying on setInterval/setTimeout on the main thread:
SharedWorker are not blocked by main-thread work (UI rendering, long-running scripts), which reduces jitter and missed ticks.SharedWorker can serve multiple tabs/windows, avoiding duplicated timers and reducing cumulative drift when the same task would otherwise run in many contexts.SharedWorker centralizes coordination so connectivity-dependent tasks (e.g., token refresh) remain consistent across open pages.npm install shared-timer-manager
cp node_modules/shared-timer-manager/dist/shared-timer-worker.js public/
import TimerManager from 'shared-timer-manager';
// Initialize
const timerManager = new TimerManager('/shared-timer-worker.js');
// Add a repeating task
timerManager.addTimerTask(
'token-refresh',
15 * 60 * 1000, // 15 minutes
() => {
console.log('Refreshing token...');
refreshToken();
},
true // repeats
);
// Add a one-time task
timerManager.addTimerTask(
'inactivity-logout',
5 * 60 * 1000, // 5 minutes
() => {
console.log('Logging out due to inactivity');
logout();
},
false // doesn't repeat
);
// Clear a specific task
timerManager.clearTimerTask('token-refresh');
// Remove all tasks
timerManager.removeAllTimerTasks();
new TimerManager(workerPath)Creates a new TimerManager instance.
Parameters:
workerPath (string, optional): Path to the shared worker file. Default: '/shared-timer-worker.js'Example:
const timerManager = new TimerManager('/workers/shared-timer-worker.js');
addTimerTask(taskName, intervalTime, callback, canRepeat)Adds a new timer task.
Parameters:
taskName (string): Unique identifier for the taskintervalTime (number): Interval in millisecondscallback (function): Function to execute on each interval. Receives (taskName, timestamp) as argumentscanRepeat (boolean, optional): Whether the task should repeat. Default: trueExample:
timerManager.addTimerTask('my-task', 5000, (name, timestamp) => {
console.log(`${name} executed at ${timestamp}`);
}, true);
clearTimerTask(taskName)Clears a specific timer task.
Parameters:
taskName (string): Name of the task to clearExample:
timerManager.clearTimerTask('my-task');
removeAllTimerTasks()Removes all timer tasks.
Example:
timerManager.removeAllTimerTasks();
hasTask(taskName)Check if a task exists.
Parameters:
taskName (string): Name of the taskReturns:
boolean: Whether the task existsExample:
if (timerManager.hasTask('token-refresh')) {
console.log('Token refresh task is active');
}
getActiveTasks()Get list of active task names.
Returns:
Array<string>: Array of active task namesExample:
const tasks = timerManager.getActiveTasks();
console.log('Active tasks:', tasks); // ['token-refresh', 'inactivity-logout']
ping(taskName)Check if the worker is connected (health check).
Parameters:
taskName (string, optional): Task name for ping. Default: 'health-check'Returns:
boolean: Connection statusExample:
const isConnected = timerManager.ping();
Automatically refresh authentication tokens at regular intervals:
timerManager.addTimerTask(
'token-refresh',
15 * 60 * 1000, // Every 15 minutes
async () => {
try {
await refreshAccessToken();
console.log('Token refreshed successfully');
} catch (error) {
console.error('Token refresh failed:', error);
}
},
true
);
Log out users after a period of inactivity:
function setupInactivityTimer() {
timerManager.addTimerTask(
'inactivity-logout',
5 * 60 * 1000, // 5 minutes
() => {
console.log('User inactive - logging out');
logout();
},
false
);
}
// Reset timer on user activity
const resetTimer = () => {
timerManager.clearTimerTask('inactivity-logout');
setupInactivityTimer();
};
document.addEventListener('mousemove', resetTimer);
document.addEventListener('keydown', resetTimer);
document.addEventListener('click', resetTimer);
// Initialize
setupInactivityTimer();
Reduce backend requests after inactivity:
function setupSleepMode() {
timerManager.addTimerTask(
'sleep-mode',
5 * 60 * 1000, // 5 minutes
() => {
console.log('Activating sleep mode');
activateSleepMode();
// Stop non-critical API polling
stopBackgroundSync();
},
false
);
}
// Reset on user activity
const resetSleepMode = () => {
if (timerManager.hasTask('sleep-mode')) {
timerManager.clearTimerTask('sleep-mode');
deactivateSleepMode();
setupSleepMode();
}
};
window.addEventListener('focus', resetSleepMode);
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
resetSleepMode();
}
});
setupSleepMode();
Create a custom hook for easy integration:
// hooks/useTimerManager.js
import { useEffect, useRef } from 'react';
import TimerManager from 'shared-timer-manager';
export function useTimerManager() {
const timerManagerRef = useRef(null);
useEffect(() => {
timerManagerRef.current = new TimerManager('/shared-timer-worker.js');
return () => {
timerManagerRef.current?.removeAllTimerTasks();
};
}, []);
return timerManagerRef.current;
}
// Usage in component
function App() {
const timerManager = useTimerManager();
useEffect(() => {
if (timerManager) {
timerManager.addTimerTask('token-refresh', 15 * 60 * 1000, () => {
refreshToken();
}, true);
}
}, [timerManager]);
return <div>My App</div>;
}
// composables/useTimerManager.js
import { onUnmounted } from 'vue';
import TimerManager from 'shared-timer-manager';
const timerManager = new TimerManager('/shared-timer-worker.js');
export function useTimerManager() {
onUnmounted(() => {
timerManager.removeAllTimerTasks();
});
return {
addTask: (name, interval, callback, repeat = true) =>
timerManager.addTimerTask(name, interval, callback, repeat),
clearTask: (name) => timerManager.clearTimerTask(name),
removeAll: () => timerManager.removeAllTimerTasks(),
hasTask: (name) => timerManager.hasTask(name),
getActiveTasks: () => timerManager.getActiveTasks()
};
}
// Usage in component
<script setup>
import { onMounted } from 'vue';
import { useTimerManager } from '@/composables/useTimerManager';
const { addTask, clearTask } = useTimerManager();
onMounted(() => {
addTask('token-refresh', 15 * 60 * 1000, () => {
console.log('Refreshing token...');
});
});
</script>
// services/timer-manager.service.ts
import { Injectable, OnDestroy } from '@angular/core';
import TimerManager from 'shared-timer-manager';
@Injectable({
providedIn: 'root'
})
export class TimerManagerService implements OnDestroy {
private timerManager: TimerManager;
constructor() {
this.timerManager = new TimerManager('/shared-timer-worker.js');
}
addTask(name: string, interval: number, callback: Function, repeat = true): void {
this.timerManager.addTimerTask(name, interval, callback as any, repeat);
}
clearTask(name: string): void {
this.timerManager.clearTimerTask(name);
}
removeAllTasks(): void {
this.timerManager.removeAllTimerTasks();
}
hasTask(name: string): boolean {
return this.timerManager.hasTask(name);
}
getActiveTasks(): string[] {
return this.timerManager.getActiveTasks();
}
ngOnDestroy(): void {
this.timerManager.removeAllTimerTasks();
}
}
// Usage in component
export class AppComponent {
constructor(private timerService: TimerManagerService) {
this.timerService.addTask('token-refresh', 15 * 60 * 1000, () => {
console.log('Refreshing token...');
}, true);
}
}
// stores/timerStore.js
import { onDestroy } from 'svelte';
import TimerManager from 'shared-timer-manager';
const timerManager = new TimerManager('/shared-timer-worker.js');
export function useTimer() {
onDestroy(() => {
timerManager.removeAllTimerTasks();
});
return timerManager;
}
// Usage in component
<script>
import { onMount } from 'svelte';
import { useTimer } from './stores/timerStore';
const timer = useTimer();
onMount(() => {
timer.addTimerTask('my-task', 5000, () => {
console.log('Timer tick!');
}, true);
});
</script>
import TimerManager from 'shared-timer-manager';
const timerManager = new TimerManager('/shared-timer-worker.js');
// Add tasks
timerManager.addTimerTask('periodic-sync', 30000, () => {
syncData();
}, true);
// Clear when needed
document.getElementById('stop-btn').addEventListener('click', () => {
timerManager.clearTimerTask('periodic-sync');
});
SharedWebWorker is supported in:
Note: For browsers that don't support SharedWebWorker, consider implementing a fallback using regular setInterval or Web Workers.
This package includes TypeScript definitions. No additional types package needed!
import TimerManager from 'shared-timer-manager';
const timerManager: TimerManager = new TimerManager('/shared-timer-worker.js');
timerManager.addTimerTask(
'my-task',
5000,
(taskName: string, timestamp: number) => {
console.log(`Task ${taskName} executed at ${timestamp}`);
},
true
);
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)MIT © [Dario Espina]
If you encounter any issues or have questions:
FAQs
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.