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

@itayost/il

v1.1.0

Published

Israeli domain primitives. Zero dependencies.

Readme

@itayost/il

Israeli domain primitives. Zero runtime dependencies, ESM only.

Phone numbers

An Israeli phone number is written five different ways in the wild, and a normalized one is indistinguishable from a raw one if both are just string. This package gives the canonical form its own type, so passing an unparsed value where a canonical one is required is a compile error rather than a lookup that silently misses.

import { parseIlPhone, toChatId, toLocal, toStorage } from "@itayost/il";

const phone = parseIlPhone("050-123-4567"); // IlPhone | null
if (phone) {
  toChatId(phone); // "[email protected]"
  toLocal(phone); // "050-123-4567"
  toStorage(phone, "bare"); // "972501234567"
}

parseIlPhone accepts local, international with or without a plus, and any of those with spaces, dashes or parentheses. It returns null rather than throwing, and never returns a half-normalized value. Landlines, non-geographic 07x numbers and mobiles written without a trunk zero all parse.

It deliberately rejects WhatsApp Chat IDs, LIDs, star short codes and non-Israeli numbers instead of coercing them into a number that looks plausible but reaches someone else.

The canonical form is an in-memory contract, not a storage format — toStorage renders back into whatever format your database already holds, so adopting this package needs no migration.

Chat IDs

import { fromChatId } from "@itayost/il";

fromChatId("[email protected]"); // IlPhone
fromChatId("[email protected]"); // null, a group
fromChatId("123456789012345@lid"); // null, an opaque identifier

Money

Nine formatters for the same shekel amount existed across the portfolio and disagreed on the glyph ( or ש״ח), whether it leads or trails, which locale groups the thousands, how many agorot to show, and what an unusable input renders as. Two grouped digits with no locale at all, so their output followed the server rather than the reader.

import { formatIls, formatAgorot } from "@itayost/il";

formatIls(150); // "150 ₪"
formatIls(1234.5); // "1,234.5 ₪"
formatIls(1234.5, { decimals: 2 }); // "1,234.50 ₪"
formatIls(585000, { compact: true }); // "₪585K"
formatIls(150, { locale: "en-US" }); // "₪150"
formatAgorot(15000); // "150 ₪"

The package states no opinion about the glyph or where it sits. Intl decides both from the locale, which is why Hebrew trails the symbol and English leads it. Any locale works, so a multilingual Consumer passes its own and gets the right form rather than a Hebrew string it has to undo.

Unusable input returns null rather than a dash, because the dash is copy — Consumers variously want -, and חינם — and that choice belongs to the screen. Nothing throws. A number that failed to parse upstream, a blank string from an empty column, a division by zero: all of them are an absence, never a price of NaN ₪ or a free one.

Numbers may arrive as strings, since Postgres numeric and Prisma Decimal columns serialize that way.

The output separates the amount from the symbol with a non-breaking space, so a narrow column cannot wrap the two apart. The invisible bidi marks Intl adds around Hebrew currency are stripped, since they corrupt character-count maths and leak into WhatsApp messages and CSV exports; pass bidiMarks: true to keep them when embedding into mixed-direction text.

Israel time

Twelve repos reason about Asia/Jerusalem and five wrote their own helper. They diverged in ways that surface twice a year or once a day: one derives the calendar date from en-US parts and another from an en-CA formatter, and one carries a % 24 because hour12: false reports midnight as hour 24 on some ICU builds.

import { israelParts, israelDate, startOfIsraelDay, formatIlDate, formatIlTime } from "@itayost/il";

israelParts("2026-01-14T22:30:00Z");
// { year: 2026, month: 1, day: 15, hour: 0, minute: 30, weekday: "Thu", minutesOfDay: 30 }

israelDate("2026-01-14T22:30:00Z"); // "2026-01-15" — already tomorrow in Israel
startOfIsraelDay(); // UTC midnight of today's Israel date, for a date-only column
formatIlDate(new Date()); // "יום רביעי, 4 במרץ 2026"
formatIlDate(new Date(), { style: "short" }); // "04.03.2026"
formatIlTime(new Date()); // "16:30"

Everything is Intl, so there is no tz database to ship and no date-fns-tz to install. Midnight is hour 0, never 24. An unusable date returns null rather than throwing or resolving to the first of January.

The formatters take a locale rather than naming a language, so a multilingual Consumer asks for what it wants instead of undoing a Hebrew string. The Hebrew output is byte-identical to what date-fns with its Hebrew locale produced.

israelParts accepts a second argument if you need a different zone; Quiet Hours uses it, which is how the two stay consistent.

Quiet Hours

When a bot must not message a person: a nightly window plus the Shabbat blackout, always evaluated in Israel local time.

import { isQuiet } from "@itayost/il";

isQuiet(new Date()); // { quiet: true, reason: "shabbat" } | { quiet: false }

Defaults to 09:00–21:00 and Friday 16:00 → Saturday 20:30 in Asia/Jerusalem. Pass a config to change the window or the boundaries.

Licence

MIT