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

shall-i-send

v1.0.0

Published

Shall I send?

Readme

shall-i-send

Shall I send this message now? Given a country and a moment, shall-i-send tells you if it is a good time to reach someone there, and when to send it otherwise.

  • Activity is modeled per country with a small Fourier series (no CSV, no network, no runtime dependency).
  • Weekdays and weekends have distinct profiles.
  • Countries spanning several time zones are handled with an uncertainty score, to avoid false positives (e.g. the United States).
  • Unknown countries fall back to a global profile.

Installation

npm install shall-i-send

Requires Node.js 18 or newer.

Usage

import ShallISend from "shall-i-send";

const shallISend = new ShallISend();

const assessment = shallISend.assess("FR", "2026-09-10T21:30:00Z");

assessment.recommendation; // "delay"
assessment.local.time; // "2026-09-10T23:30:00"
assessment.next?.at; // "2026-09-11T07:00:00.000Z"
assessment.next?.localTime; // "2026-09-11T09:00:00"

The instant can be a Date, a timestamp or an ISO string. It defaults to now.

API

new ShallISend(options?)

| Option | Default | Description | | ----------------- | ------- | --------------------------------------------------------------- | | quietStart | 21 | Local hour from which it is considered too late | | quietEnd | 8 | Local hour before which it is considered too early | | quietConsensus | 0.7 | Share of local times in quiet hours needed to delay (0 to 1) | | minimumActivity | 0.4 | Below this relative activity, the message is delayed (0 to 1) | | targetActivity | 0.7 | Relative activity wanted for the next candidate (0 to 1) | | stepMinutes | 15 | Search step of the next candidate, in minutes (1 to 60) | | horizonHours | 24 | How far the next candidate is searched, in hours (1 to 168) |

Invalid options throw a RangeError. Every method that takes options accepts the same keys to override them for a single call.

Methods

  • assess(country, at?, options?) returns a SendAssessment: the recommendation ("send" or "delay"), a delay score, the estimated activity, the local time assessment and the next candidate.
  • getNextCandidate(country, at?, options?) returns the next suitable instant, or the best one reachable in the horizon (meetsTarget: false), or null.
  • getActivity(country, at?) returns the activity index, the activity relative to the weekly peak (0 to 1) and the share of the daily activity.
  • getPeakHours(country, period?, count?) lists the most active UTC hours, for "weekday" or "weekend".
  • compareCountries(countries, at?) sorts countries by activity at a given instant.
  • getTimeZone(country) returns the representative time zone of a country.
  • getLocalTimes(country, at?) returns the distinct local times observed across a country.
  • getModelInfo(country) returns the sample size, the confidence and whether the global fallback is used.

Country codes are ISO 3166-1 alpha-2 and case insensitive.

How it works

  • Activity: a 24h Fourier series (4 harmonics) per country and per period, smoothed towards the global profile when a country has few samples. The activity is expressed relative to the weekly peak of the country.
  • Weekdays and weekends: selected from the UTC day of the instant.
  • Quiet hours: the local time is computed in every time zone of the country. The probability of quiet hours is the share of distinct local times that are too late or too early.
  • Decision: the message is delayed if the relative activity is under minimumActivity, or if the quiet probability reaches quietConsensus.

Limitations

  • The model describes when customers are active, not when they are likely to reply.
  • Public holidays are not modeled.
  • The profiles come from a sample of the activity, with hours assumed to be in UTC.

License

MIT, Baptiste Jamin