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/ca-tax

v0.0.36

Published

Canadian corporate tax engine for @classytic/tax-core — federal T2, Alberta AT1 and Québec CO-17 with form definitions traced to the published forms, plus GST/HST/PST/QST with dated provincial regimes.

Readme

@classytic/ca-tax

Canadian corporate tax engine for @classytic/tax-core — federal T2, Alberta AT1, and Québec CO-17, with the sales-tax pack (GST/HST/PST/QST) it grew out of.

What distinguishes it: every line number is traced to the published form. The form definitions are extracted from the CRA PDFs, the Alberta TRA specification, and the Revenu Québec forms — never typed from memory — and a test refuses any line number that does not appear in one of them. A wrong line number is worse than a missing one: it files a real figure against the wrong box and nothing looks broken.

Verified rules + provenance: docs/research-2026-07.md.

Corporate tax

| Area | Coverage | |---|---| | Federal T2 | Schedule 1 book-to-tax reconciliation, CCA (S8), capital gains (S6), losses (S4), SBD with both grinds (S7/S23/S33), Part IV/IV.1/VI.1 (S3/S43), GRIP & LRIP (S53/S54), Part III.1 on excessive designations (S55), SR&ED ITC (S31), foreign credits (S21), EIFEL (S130) | | Alberta AT1 | Alberta tax, Reg 402 allocation (S2), the reconciliation to federal income (S12), Alberta CCA (S13), reserves (S17), dispositions (S18), donations (S20), loss continuity (S21/S10), the Innovation Employment Grant (S29), and the Net File payload | | Québec CO-17 | Québec tax over the allocation factor, and the form definition | | Form definitions | 30 forms as typed data — T2 jacket + 16 schedules, AT1 jacket + 8, CO-17 — each carrying its own provenance (document, revision, retrieval date). Exposed on the ./forms subpath, 29 kB rather than pulling the 249 kB engine | | Three numbering schemes | CRA three-digit lines, Alberta SSSFFFOOO line-item ids, and Québec boxes that carry letters (420c) — modelled distinctly, because assuming three digits truncates the third | | Fail-closed | An unclassified line throws rather than defaulting; a return missing a mandatory field refuses rather than filing a zero; an unanswered yes/no stays unanswered rather than becoming "No" |

Sales tax

| Area | Coverage | |---|---| | Rates | All 13 provinces/territories, effective-dated — Nova Scotia's 15%→14% (1 Apr 2025) ships as two windows, so early-2025 reprints stay period-accurate | | Place of supply | Goods → delivery province; services/intangibles → recipient address with performed-province fallback (ETA Sch. IX simplified) | | Multi-authority legs | calculateCaSalesTax returns per-authority legs: QC = GST(CRA) + QST(RQ) both on the GST-exclusive base; BC/SK/MB = GST + non-recoverable PST/RST — including Manitoba's RST-on-SaaS expansion from 1 Jan 2026 as a dated rule | | Zero-rated vs exempt | The VAT truth table: zero-rated (groceries, prescription, exports…) = 0% with ITCs; exempt (rent, health, financial…) = no tax, no ITCs | | ITC restrictions | Meals 50%, club dues denied, passenger-vehicle ceiling dated ($38k 2025 / $39k 2026), exempt-output denial | | Registration | Small supplier $30k (four-quarter + single-quarter tests), PSB $50k, simplified digital regime threshold | | GST34 | The CRA return as a tax-core TaxEngine (negative totalOwing = refund/line 114) over a tax-core TaxReportTemplate line grid — completing the /ledger seam validation — plus gst34LedgerAdapter posting balanced settlements via wireTaxToLedger | | Resolver | createCaTaxResolver({ province }) — per-province instances; accountFor('input') returns the ITC-receivable role (the recoverable side the US pack proves absent) | | Hot-patch | extendCaTaxRules — dated provincial-rate and PST-base overrides |

Quick start

import { calculateCaSalesTax, createCaTaxResolver } from '@classytic/ca-tax';

// A Québec sale: two legs, two authorities, GST-exclusive QST base
const r = calculateCaSalesTax({
  supplyType: 'goods', deliveryProvince: 'QC',
  category: 'STANDARD', amountMinor: 1_000_00,
});
// r.legs → [{ tax:'GST', authority:'CRA', … }, { tax:'QST', authority:'RQ', … }]

// Period close — post the GST34 through your ledger
import { wireTaxToLedger } from '@classytic/tax-core';
import { gst34Engine, gst34LedgerAdapter } from '@classytic/ca-tax';
const postReturn = wireTaxToLedger(gst34Engine, gst34LedgerAdapter, engine.repositories.journalEntries);

Deliberately out of scope

Transmission. The engine renders the filing payload; sending it is a host concern, and in two of three jurisdictions the wire format is not public. Alberta publishes its WSDL and response codes, so AT1 transmission is implementable. CRA's certified CIF schema and Revenu Québec's ImpôtNet element names are released only through their software-certification programmes — so both renderers produce a clearly-labelled draft rather than pretending otherwise.

Québec's small business deduction is computed on form CO-771, which applies a paid-hours test with no federal equivalent. Not inferable from the T2.

Also out: Quick Method (NS post-cut cells await RC4058 verification), T1 and payroll, the Bill C-4 first-time-homebuyer GST rebate, provincial PST returns.

Where the numbers come from

Every shipped tax figure carries an @statutory-data block naming its source and the date it was last checked, enforced by tests/statutory-data-provenance.test.ts — a rate table cannot be added without provenance, a cited document that stops existing fails the build, and a book's declared years are checked against the book.

The shipped rate books stop at 2024, deliberately. They are reference values behind a seam: a host supplies authoritative figures per year through CORP_TAX_RATE_BOOK and its siblings. If you are filing 2025 or later, wire your own book — t2/rates/province-rates.ts in particular is unsourced for all 22 of its figures.

See docs/STATUTORY-DATA.md for the convention, the current provenance table, and the yearly revision workflow.

ESM only · Node ≥ 20 · integer cents · effective-dated with provenance · MIT

Trademark

MIT-licensed code. "Classytic"/"arc" names + logos are trademarks of Classytic LLC — see TRADEMARK.md.