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

@classytic/tax-core

v0.2.0

Published

Shared contracts for jurisdiction tax engines — TaxResolver (invoice-time rating), TaxEngine/TaxObligation (filing-time compute), LedgerPostingAdapter + wireTaxToLedger, effective-dated rule windows, layered rule registries, and the ledger-facing TaxCode/

Readme

@classytic/tax-core

Shared contracts for jurisdiction tax engines. Zero jurisdiction logic, zero rate tables, zero runtime dependencies — this package is the seams, nothing else. Bangladesh lives in @classytic/bd-tax (the reference implementation), Canada in @classytic/ca-tax, and the accounting engine (@classytic/ledger) stays deliberately tax-free.

The design in one paragraph

Tax computation does not compose across countries — BD VAT, CA GST/HST, and US sales tax share no math. What composes is everything AROUND the math: how a line item asks "what rate applies right now" (resolver), how a closed period becomes an amount owed (obligation), how an obligation becomes journal entries (posting adapter), how rules are versioned in time (effective windows), how hosts hot-patch when an authority publishes mid-period (registries), and the posting-shaped data ledgers consume (tax codes + report templates — the Odoo account.tax insight, kept as pure data). tax-core owns exactly those six seams.

Subpaths

| Subpath | Ships | |---|---| | ./resolver | TaxResolver — invoice-time rating contract: resolveClass (country-neutral tax classes → TaxClassRate), fiscal positions with audit trail, accountFor role mapping, TaxPackDescriptor introspection | | ./obligation | TaxEngine<TInput, TBreakdown>TaxObligation (integer minor units, typed breakdown) → LedgerPostingAdapterwireTaxToLedger() (sequential, fail-fast, session-threaded) | | ./effective | EffectiveDated windows (inclusive, open-ended current law) + isEffectiveAt / firstEffectiveAt / effectiveEntries / latestEntry + RuleProvenance | | ./registry | createLayeredRules (row tables — extensions matched first) + createKeyedOverrides (keyed tables — newest wins): the boot-time hot-patch seam | | ./ledger | TaxCode, TaxRepartitionLine, TaxExigibility, TaxReportLine, TaxReportTemplate, TaxCodesByRegion |

Two temporal surfaces, never conflated

// 1. INVOICE TIME — a line is being priced now
const resolver = createBdTaxResolver();                    // from @classytic/bd-tax
const rate = resolver.resolveClass('STANDARD', invoiceDate); // { rateCode, rate, inputCreditAllowed, … }
const account = resolver.accountFor(rate.rateCode, 'output', 'standard');

// 2. FILING TIME — a period is being closed
import { wireTaxToLedger } from '@classytic/tax-core';
const postReturn = wireTaxToLedger(gst34Engine, gstLedgerAdapter, engine.repositories.journalEntries);
await postReturn(quarterData, { resolveAccount: (role) => accountIds.get(role), session });

Consumers that only want computation (a filing tool, not an ERP) use engine.validate + compute + render and never touch the ledger seam.

Rules for jurisdiction packs

  • Money is integer minor units (paisa/cents) at every contract boundary. Packs computing in major units convert at their edge.
  • Everything effective-dated. Old documents recompute under the law of their date forever: never mutate a closed window — close it with effectiveTo and push a new entry. All lookups go through ./effective; there is one implementation of "active on this date".
  • Provenance is data. Rate entries carry sourceRef (the legal instrument), verifiedOn, notes — auditors ask, the table answers.
  • Unknown returns null, invalid throws. resolveClass('NOPE') is a business decision for the caller; validate(garbage) is a bug at the boundary.
  • Hot-patches are dated, not blanket. Compose ./registry into an extend<Country>TaxRules() facade; extensions carry the same windows as built-ins so a mid-year SRO patch is period-accurate.
  • Packs peer on tax-core only. They never import @classytic/ledger — hosts wire the two at the application layer.

Reference implementation

@classytic/bd-tax — study it before writing a new pack: dated rate schedules with a gazette-verification research trail (research/FY2026-27/), the extension facade (extendBdTaxRules), per-fiscal-year currency tests, and the update recipe (docs/updating-rules.md). Architecture rationale: the fajr repo's packages/tax/PLAN.md.

Primitives alignment

tax-core peers on @classytic/primitives >= 0.9 for TYPE-ONLY imports (runtime stays zero-dependency): TaxPeriod extends DateRange (/period), currency fields accept the branded CurrencyCode (/currency), and minor-unit amounts pair with primitives' Money / minorUnitFactor. Effective-dated windows and layered registries do NOT exist in primitives — they are tax-core's own contribution (candidates to upstream if a non-tax package ever needs them).

ESM only · Node ≥ 20 · exactOptionalPropertyTypes · zero runtime deps · MIT