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

@xcwds/plugin-timers

v0.5.0

Published

Timers for @xcwds apps that count against wall-clock end times, so they survive a backgrounded tab and a reload, ring on every page and hold off app updates while running.

Readme

@xcwds/plugin-timers

Timers for an @xcwds app, extracted from xcwds.github.io's cooking and coffee timers. They count against wall-clock end times, so they stay right when a phone suspends the tab, and they're saved, so a reload resumes them. The app owns them, not a page: on every page a finished timer rings, a running one keeps the screen awake, and an app update waits until they stop.

// xcwds.config.ts
import timers from '@xcwds/plugin-timers';

export default defineConfig({
	brand,
	plugins: [shell({ sections }), timers({ page: '/utils/timer' })]
});
/* src/app.css, after Tailwind and the shell's styles */
@import '@xcwds/plugin-timers/styles.css';
<!-- src/routes/+layout.svelte: finished timers show as alerts in the notification stack -->
<Shell>
	{@render children()}
	{#snippet notices()}<TimerAlert />{/snippet}
</Shell>

<!-- src/routes/utils/timer/+page.svelte -->
<main class="page-narrow"><TimerList /></main>

Options

  • page: the timers page (an app path), for the alert's Open link.
  • storageKey: where timers are saved (default app:timers:timers). Set it to keep a key your app already uses, e.g. app:cooking-timer:timers for an app moving from xcwds.github.io's own code, which saves the same shape.

What it adds

  • app.timers:
    • create(label, ms) starts a timer of up to 7 days. Call it from a tap, so the alarm can play sound later on iOS.
    • toggle(id) pauses or resumes, add(id, ms) adds time (or snoozes a finished timer), reset(id) and remove(id).
    • list(), get(id), remaining(item), ringing(item), anyRunning() and now().
    • subscribe(listener) calls back on every change and on each tick while a timer runs.
    • show() says a page lists every timer, so <TimerAlert> stays out of the way. Recipe step timers and other plugins use the same timers.
  • The alarm: a finished timer beeps (Web Audio) and vibrates every 3 seconds until it's stopped or snoozed.
  • The alarm setting: { sound, vibration, keepAwake }, all on by default, in the timers settings section. keepAwake holds a screen wake lock while a timer runs.
  • An onBeforeReload reason, running timers, so @xcwds/plugin-update's banner asks to finish first.
  • Components:
    • TimerList.svelte: every timer, plus a form to start one.
    • Countdown.svelte: one timer's remaining time, <Countdown id={item.id} />.
    • TimerAlert.svelte: finished timers with +1 min, Stop and Open (openLabel names the Open link for screen readers; defaults to "Open timers").
    • Each timer records the page it was started on (path). While @xcwds/plugin-lock has the app locked, a timer started on a page it keeps out shows privateText instead of its label ("Timer finished" in TimerAlert, "Private timer" in TimerList), and still rings, snoozes and stops.
  • Pure functions from the main entry (start, pause, add, remaining, formatDuration and others) for tests and custom timers.