npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hexium-softworks/cooldown-manager

v0.2.0

Published

Game-agnostic Nevermore cooldown manager with server-authoritative trackers and ReplicationService-backed client timing data.

Readme

Cooldown Manager

A game-agnostic Nevermore package for server-authoritative runtime cooldowns.

Cooldown Manager tracks cooldowns by owner and string key, supports atomic check-and-start operations, shared cooldown groups, cancellation and adjustment, and ReplicationService-backed read-only client timing data for UI.

It does not execute abilities, process inputs, prevent network abuse, persist daily rewards, or decide game-specific cooldown definitions.

Installation

pnpm add @hexium-softworks/cooldown-manager @hexium-softworks/replicationservice

Nevermore Usage

Use the conflict-free manager service names through ServiceBag.

Server:

local require = require(script.Parent.loader).load(script)

local CooldownManagerService = require("CooldownManagerService")
local ReplicationService = require("ReplicationService")

function AbilityService:Init(serviceBag)
	serviceBag:GetService(ReplicationService)
	self._cooldowns = serviceBag:GetService(CooldownManagerService)
end

function AbilityService:TryDash(player)
	local success, cooldown = self._cooldowns:TryStart(player, "Abilities.Dash", 3, {
		Replicate = true,
	})

	if not success then
		return false, cooldown:GetRemaining()
	end

	return true
end

Client:

local require = require(script.Parent.loader).load(script)

local CooldownManagerServiceClient = require("CooldownManagerServiceClient")
local ReplicationServiceClient = require("ReplicationServiceClient")

function AbilityHud:Init(serviceBag)
	serviceBag:GetService(ReplicationServiceClient)
	self._cooldowns = serviceBag:GetService(CooldownManagerServiceClient)
end

function AbilityHud:Start()
	self._maid:GiveTask(self._cooldowns:ObserveReady("Abilities.Dash", function(isReady)
		self._dashButton.Active = isReady
	end))
end

Server API

CooldownManagerService is the authoritative registry.

| Method | Description | | --- | --- | | GetTracker(owner) | Returns or creates the tracker for an owner. | | FindTracker(owner) | Returns an existing tracker, if one exists. | | DestroyTracker(owner) | Destroys and removes one tracker. | | Clear(owner) | Cancels all cooldowns for an owner. | | IsReady(owner, key) | Returns whether the key is not cooling down. | | GetRemaining(owner, key) | Returns remaining seconds, or 0. | | GetCooldown(owner, key) | Returns the cooldown object, if active. | | TryStart(owner, key, duration, options?) | Atomically starts only if ready. | | Start(owner, key, duration, options?) | Starts or raises if rejected. | | Cancel(owner, key) | Cancels an active cooldown. | | Extend(owner, key, duration) | Adds time to an active cooldown. | | Reduce(owner, key, duration) | Removes time from an active cooldown. | | TryAcquire(owner, request) | Atomically checks and starts multiple keys. |

Tracker objects mirror these methods without the owner argument.

Policies

local Constants = require("CooldownManagerConstants")
local CooldownPolicy = Constants.CooldownPolicy

cooldowns:Start(player, "Abilities.Fireball", 8, {
	Policy = CooldownPolicy.Restart,
	Replicate = true,
})

Policies:

  • Reject: default; active cooldowns block the new start.
  • Restart: replace the current start/end timestamps.
  • KeepLonger: keep an active cooldown when it already has at least as much remaining time.
  • Extend: add the supplied duration to an active cooldown.

Replication

Cooldown Manager depends on @hexium-softworks/replicationservice.

When a player-owned cooldown starts with { Replicate = true }, the server creates or reuses a private state:

{
	Id = `Cooldowns:{player.UserId}`,
	InitialState = {
		Cooldowns = {},
	},
	Audience = player,
}

Each active cooldown is stored under Cooldowns using an encoded key segment, so namespaced keys such as Abilities.Dash are safe with ReplicationService path validation. The replicated value includes:

{
	Key = "Abilities.Dash",
	StartTime = 1000,
	EndTime = 1003,
	Duration = 3,
	Revision = 1,
	Metadata = nil,
}

When a cooldown completes or is cancelled, the server deletes that entry. When a tracker is destroyed, its replicated state is destroyed too. Replication is currently owner-only for Player owners; non-player owners can still use server-only cooldowns.

Shared Cooldowns

Use ordinary namespaced keys for group behavior.

local result = tracker:TryAcquire({
	Require = {
		"Abilities.Fireball",
		"Groups.GlobalAbility",
	},

	Start = {
		["Abilities.Fireball"] = 8,
		["Groups.GlobalAbility"] = 0.75,
	},
})

if not result.Success then
	return false, result.BlockedBy, result.Remaining
end

Client API

CooldownManagerServiceClient subscribes to Cooldowns:{LocalPlayer.UserId} via ReplicationServiceClient and exposes read-only timing helpers.

| Method | Description | | --- | --- | | IsReady(key) | Returns whether the key has no active client snapshot. | | GetCooldown(key) | Returns a defensive snapshot copy, if active. | | GetRemaining(key) | Calculates remaining time from timestamps. | | GetProgress(key) | Calculates progress from 0 to 1. | | ObserveCooldown(key, callback) | Fires immediately and when the snapshot changes. | | ObserveRemaining(key, options?, callback) | Samples remaining time while active. | | ObserveProgress(key, options?, callback) | Samples progress while active. | | ObserveReady(key, callback) | Fires ready state changes, including local expiry. | | ObserveAll(callback) | Observes all snapshot changes. |

The client intentionally has no Start, Cancel, Extend, Reduce, or Clear methods.

Key Rules

Cooldown keys must be strings from 1 to 128 characters. They cannot start or end with ., contain .., or start with the reserved __ prefix.

Recommended names:

  • Abilities.Dash
  • Abilities.Fireball
  • Tools.Sword.Primary
  • Interactions.Door
  • Groups.GlobalAbility

Persistence Boundary

Cooldown Manager is for ephemeral runtime cooldowns such as abilities, weapons, interactions, and UI affordances. Long-term timestamps like daily rewards, multi-day crafting, timed bans, and event claim dates should be stored by their own systems.