@seethruhead/cra-payroll 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,36 +1,15 @@
1
- # cra-payroll
1
+ # @seethruhead/cra-payroll
2
2
 
3
3
  Calculate Canadian payroll deductions using CRA's [Payroll Deductions Online Calculator (PDOC)](https://apps.cra-arc.gc.ca/ebci/rhpd/beta/entry).
4
4
 
5
- Automates the CRA wizard via Playwright and returns your net pay, taxes, CPP, EI, and RRSP breakdown — per paycheck, monthly, or annually.
6
-
7
- ## Download
8
-
9
- Grab the latest binary for your platform from [**Releases**](https://github.com/SeeThruHead/cra-payroll/releases):
10
-
11
- | Platform | File |
12
- |----------|------|
13
- | macOS (Apple Silicon) | `cra-payroll-darwin-arm64` |
14
- | macOS (Intel) | `cra-payroll-darwin-x64` |
15
- | Linux (x64) | `cra-payroll-linux-x64` |
16
-
17
- ```bash
18
- # Example: macOS Apple Silicon
19
- curl -L -o cra-payroll https://github.com/SeeThruHead/cra-payroll/releases/latest/download/cra-payroll-darwin-arm64
20
- chmod +x cra-payroll
21
-
22
- # Remove macOS quarantine flag (unsigned binary)
23
- xattr -d com.apple.quarantine cra-payroll
24
-
25
- sudo mv cra-payroll /usr/local/bin/
26
- ```
5
+ Automates the CRA wizard via Puppeteer and returns your net pay, taxes, CPP, EI, and RRSP breakdown — per paycheck, monthly, or annually.
27
6
 
28
7
  > **Requires Google Chrome** — uses your system Chrome, no extra browser install needed.
29
8
 
30
- Or use the one-liner:
9
+ ## Install
31
10
 
32
11
  ```bash
33
- curl -fsSL https://raw.githubusercontent.com/SeeThruHead/cra-payroll/main/install.sh | bash
12
+ npm install -g @seethruhead/cra-payroll
34
13
  ```
35
14
 
36
15
  ## Usage
@@ -53,21 +32,12 @@ cra-payroll --salary 100000 --monthly
53
32
 
54
33
  # Combine them
55
34
  cra-payroll --salary 150000 --table --annual --monthly
56
-
57
- # Verbose logging
58
- cra-payroll -v --salary 100000
59
-
60
- # Check version
61
- cra-payroll --version
62
-
63
- # Self-update to latest release
64
- cra-payroll --update
65
35
  ```
66
36
 
67
37
  ### Example output (`--table`)
68
38
 
69
39
  ```
70
- 📊 Per-Paycheck Table (2026)
40
+ Per-Paycheck Table (2026)
71
41
  ══════════════════════════════════════════════════════════════════════════════════════════════
72
42
  # │ Gross │ Fed Tax │ Prov Tax │ CPP │ EI │ Net Pay │ Cum CPP/EI
73
43
  ──────────────────────────────────────────────────────────────────────────────────────────────
@@ -81,30 +51,28 @@ cra-payroll --update
81
51
 
82
52
  ## Config
83
53
 
84
- Config is loaded from the first file found:
85
- 1. `--config <path>`
86
- 2. `./config.json`
87
- 3. `~/.config/cra-payroll.json`
88
- 4. `~/.cra-payroll.json`
89
-
90
- CLI args override config file values. Missing values are prompted interactively.
54
+ Create `~/.config/cra-payroll.json`:
91
55
 
92
56
  ```json
93
57
  {
94
58
  "province": "Ontario",
95
59
  "annualSalary": 100000,
96
60
  "payPeriod": "Semi-monthly (24 pay periods a year)",
61
+ "year": 2026,
97
62
  "rrspEmployeePercent": 4,
98
63
  "rrspEmployerPercent": 4
99
64
  }
100
65
  ```
101
66
 
67
+ CLI args override config file values. Missing values are prompted interactively.
68
+
102
69
  ### Options
103
70
 
104
71
  | Option | CLI flag | Config key | Default |
105
72
  |--------|----------|------------|---------|
106
73
  | Province | `-p`, `--province` | `province` | `Ontario` |
107
74
  | Annual salary | `-s`, `--salary` | `annualSalary` | _(prompted)_ |
75
+ | Tax year | `-y`, `--year` | `year` | current year |
108
76
  | Pay period | `--pay-period` | `payPeriod` | `Semi-monthly (24)` |
109
77
  | Employee RRSP % | `--rrsp-employee` | `rrspEmployeePercent` | `4` |
110
78
  | Employer RRSP % | `--rrsp-employer` | `rrspEmployerPercent` | `4` |
@@ -114,69 +82,20 @@ CLI args override config file values. Missing values are prompted interactively.
114
82
  | Annual totals | `-a`, `--annual` | — | `false` |
115
83
  | Monthly averages | `-m`, `--monthly` | — | `false` |
116
84
  | Verbose | `-v`, `--verbose` | — | `false` |
117
- | Self-update | `--update` | — | — |
118
- | Show version | `--version` | — | — |
119
85
  | Headless | `--headless` | — | `false` |
120
86
  | Config path | `-c`, `--config` | — | — |
121
87
 
122
- ### 2026 CPP/EI Maximums (used for `--table`)
123
-
124
- | | Amount |
125
- |---|---|
126
- | CPP max contribution | $4,230.45 |
127
- | CPP2 max (additional) | $416.00 |
128
- | EI max premium | $1,123.07 |
129
-
130
- ## Run from source
131
-
132
- If you'd rather not download a binary, you can clone and run directly. You'll need [Google Chrome](https://www.google.com/chrome/) installed.
133
-
134
- ### With Bun
135
-
136
- ```bash
137
- git clone https://github.com/SeeThruHead/cra-payroll.git
138
- cd cra-payroll
139
- bun install
140
- bun run dev -- --salary 100000
141
- bun run dev -- --salary 150000 --table
142
- ```
143
-
144
- ### With Node
145
-
146
- ```bash
147
- git clone https://github.com/SeeThruHead/cra-payroll.git
148
- cd cra-payroll
149
- npm install
150
- npx tsx src/cli.ts --salary 100000
151
- npx tsx src/cli.ts --salary 150000 --table
152
- ```
153
-
154
- ## Development
155
-
156
- ```bash
157
- # Run directly
158
- bun run dev -- --salary 100000
159
-
160
- # Build standalone binary
161
- bun run build
162
-
163
- # Unit tests (fast, no browser)
164
- bun test
165
-
166
- # Integration tests (hits CRA, needs Chrome, may be flaky)
167
- bun run test:integration
168
-
169
- # All tests
170
- bun run test:all
171
- ```
172
-
173
88
  ## How it works
174
89
 
175
90
  1. Launches your system Chrome via Puppeteer (headed by default — CRA blocks headless)
176
91
  2. Fills out the PDOC wizard: province, pay period, salary, RRSP contributions
177
92
  3. Sets CPP/EI status and hits Calculate
178
93
  4. Scrapes the results page for taxes, deductions, and net pay
179
- 5. For `--table` mode: runs twice (with/without CPP/EI) and simulates each paycheck using the 2026 maximums
94
+ 5. For `--table` mode: runs twice (with/without CPP/EI) and simulates each paycheck using the annual maximums
95
+
96
+ ## Standalone binary
97
+
98
+ If you prefer a standalone binary without Node.js, see the [GitHub releases](https://github.com/SeeThruHead/cra-payroll/releases).
180
99
 
181
100
  ## License
182
101
 
package/README.md.bak ADDED
@@ -0,0 +1,183 @@
1
+ # cra-payroll
2
+
3
+ Calculate Canadian payroll deductions using CRA's [Payroll Deductions Online Calculator (PDOC)](https://apps.cra-arc.gc.ca/ebci/rhpd/beta/entry).
4
+
5
+ Automates the CRA wizard via Playwright and returns your net pay, taxes, CPP, EI, and RRSP breakdown — per paycheck, monthly, or annually.
6
+
7
+ ## Download
8
+
9
+ Grab the latest binary for your platform from [**Releases**](https://github.com/SeeThruHead/cra-payroll/releases):
10
+
11
+ | Platform | File |
12
+ |----------|------|
13
+ | macOS (Apple Silicon) | `cra-payroll-darwin-arm64` |
14
+ | macOS (Intel) | `cra-payroll-darwin-x64` |
15
+ | Linux (x64) | `cra-payroll-linux-x64` |
16
+
17
+ ```bash
18
+ # Example: macOS Apple Silicon
19
+ curl -L -o cra-payroll https://github.com/SeeThruHead/cra-payroll/releases/latest/download/cra-payroll-darwin-arm64
20
+ chmod +x cra-payroll
21
+
22
+ # Remove macOS quarantine flag (unsigned binary)
23
+ xattr -d com.apple.quarantine cra-payroll
24
+
25
+ sudo mv cra-payroll /usr/local/bin/
26
+ ```
27
+
28
+ > **Requires Google Chrome** — uses your system Chrome, no extra browser install needed.
29
+
30
+ Or use the one-liner:
31
+
32
+ ```bash
33
+ curl -fsSL https://raw.githubusercontent.com/SeeThruHead/cra-payroll/main/install.sh | bash
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ```bash
39
+ # Interactive — prompts for missing values
40
+ cra-payroll
41
+
42
+ # CLI args
43
+ cra-payroll --salary 120000 --province "British Columbia"
44
+
45
+ # Per-paycheck table for the year (tracks CPP/EI maxout)
46
+ cra-payroll --salary 150000 --table
47
+
48
+ # Annual totals
49
+ cra-payroll --salary 100000 --annual
50
+
51
+ # Monthly averages
52
+ cra-payroll --salary 100000 --monthly
53
+
54
+ # Combine them
55
+ cra-payroll --salary 150000 --table --annual --monthly
56
+
57
+ # Verbose logging
58
+ cra-payroll -v --salary 100000
59
+
60
+ # Check version
61
+ cra-payroll --version
62
+
63
+ # Self-update to latest release
64
+ cra-payroll --update
65
+ ```
66
+
67
+ ### Example output (`--table`)
68
+
69
+ ```
70
+ 📊 Per-Paycheck Table (2026)
71
+ ══════════════════════════════════════════════════════════════════════════════════════════════
72
+ # │ Gross │ Fed Tax │ Prov Tax │ CPP │ EI │ Net Pay │ Cum CPP/EI
73
+ ──────────────────────────────────────────────────────────────────────────────────────────────
74
+ 1 │ 6,250.00 │ 1,028.37 │ 612.45 │ 382.51 │ 102.08 │ 4,124.59 │ 484.59
75
+ 2 │ 6,250.00 │ 1,028.37 │ 612.45 │ 382.51 │ 102.08 │ 4,124.59 │ 969.18
76
+ ... │ ... │ ... │ ... │ ... │ ... │ ... │ ...
77
+ 11 │ 6,250.00 │ 1,028.37 │ 612.45 │ 112.50 │ 19.37 │ 4,477.31 │ 5,353.52 ← partial
78
+ 12 │ 6,250.00 │ 1,028.37 │ 612.45 │ 0.00 │ 0.00 │ 4,609.18 │ 5,353.52 ✓ maxed
79
+ ... │ ... │ ... │ ... │ ... │ ... │ ... │ ...
80
+ ```
81
+
82
+ ## Config
83
+
84
+ Config is loaded from the first file found:
85
+ 1. `--config <path>`
86
+ 2. `./config.json`
87
+ 3. `~/.config/cra-payroll.json`
88
+ 4. `~/.cra-payroll.json`
89
+
90
+ CLI args override config file values. Missing values are prompted interactively.
91
+
92
+ ```json
93
+ {
94
+ "province": "Ontario",
95
+ "annualSalary": 100000,
96
+ "payPeriod": "Semi-monthly (24 pay periods a year)",
97
+ "rrspEmployeePercent": 4,
98
+ "rrspEmployerPercent": 4
99
+ }
100
+ ```
101
+
102
+ ### Options
103
+
104
+ | Option | CLI flag | Config key | Default |
105
+ |--------|----------|------------|---------|
106
+ | Province | `-p`, `--province` | `province` | `Ontario` |
107
+ | Annual salary | `-s`, `--salary` | `annualSalary` | _(prompted)_ |
108
+ | Pay period | `--pay-period` | `payPeriod` | `Semi-monthly (24)` |
109
+ | Employee RRSP % | `--rrsp-employee` | `rrspEmployeePercent` | `4` |
110
+ | Employer RRSP % | `--rrsp-employer` | `rrspEmployerPercent` | `4` |
111
+ | CPP maxed | `--cpp-maxed` | `cppMaxedOut` | `false` |
112
+ | EI maxed | `--ei-maxed` | `eiMaxedOut` | `false` |
113
+ | Yearly table | `-t`, `--table` | — | `false` |
114
+ | Annual totals | `-a`, `--annual` | — | `false` |
115
+ | Monthly averages | `-m`, `--monthly` | — | `false` |
116
+ | Verbose | `-v`, `--verbose` | — | `false` |
117
+ | Self-update | `--update` | — | — |
118
+ | Show version | `--version` | — | — |
119
+ | Headless | `--headless` | — | `false` |
120
+ | Config path | `-c`, `--config` | — | — |
121
+
122
+ ### 2026 CPP/EI Maximums (used for `--table`)
123
+
124
+ | | Amount |
125
+ |---|---|
126
+ | CPP max contribution | $4,230.45 |
127
+ | CPP2 max (additional) | $416.00 |
128
+ | EI max premium | $1,123.07 |
129
+
130
+ ## Run from source
131
+
132
+ If you'd rather not download a binary, you can clone and run directly. You'll need [Google Chrome](https://www.google.com/chrome/) installed.
133
+
134
+ ### With Bun
135
+
136
+ ```bash
137
+ git clone https://github.com/SeeThruHead/cra-payroll.git
138
+ cd cra-payroll
139
+ bun install
140
+ bun run dev -- --salary 100000
141
+ bun run dev -- --salary 150000 --table
142
+ ```
143
+
144
+ ### With Node
145
+
146
+ ```bash
147
+ git clone https://github.com/SeeThruHead/cra-payroll.git
148
+ cd cra-payroll
149
+ npm install
150
+ npx tsx src/cli.ts --salary 100000
151
+ npx tsx src/cli.ts --salary 150000 --table
152
+ ```
153
+
154
+ ## Development
155
+
156
+ ```bash
157
+ # Run directly
158
+ bun run dev -- --salary 100000
159
+
160
+ # Build standalone binary
161
+ bun run build
162
+
163
+ # Unit tests (fast, no browser)
164
+ bun test
165
+
166
+ # Integration tests (hits CRA, needs Chrome, may be flaky)
167
+ bun run test:integration
168
+
169
+ # All tests
170
+ bun run test:all
171
+ ```
172
+
173
+ ## How it works
174
+
175
+ 1. Launches your system Chrome via Puppeteer (headed by default — CRA blocks headless)
176
+ 2. Fills out the PDOC wizard: province, pay period, salary, RRSP contributions
177
+ 3. Sets CPP/EI status and hits Calculate
178
+ 4. Scrapes the results page for taxes, deductions, and net pay
179
+ 5. For `--table` mode: runs twice (with/without CPP/EI) and simulates each paycheck using the 2026 maximums
180
+
181
+ ## License
182
+
183
+ MIT
@@ -78951,9 +78951,9 @@ var puppeteer_core_default = puppeteer;
78951
78951
 
78952
78952
  // src/browser.ts
78953
78953
  import { statSync as statSync3 } from "fs";
78954
- var LAUNCH_TIMEOUT = 5000;
78955
- var PAGE_TIMEOUT = 5000;
78956
- var ACTION_TIMEOUT = 3000;
78954
+ var LAUNCH_TIMEOUT = 1e4;
78955
+ var PAGE_TIMEOUT = 15000;
78956
+ var ACTION_TIMEOUT = 1e4;
78957
78957
  var verbose = false;
78958
78958
  var setVerbose = (v) => {
78959
78959
  verbose = v;
@@ -79048,18 +79048,26 @@ var navigationMethods = (page) => ({
79048
79048
  waitForText: async (text) => safe(page.waitForFunction((t) => (document.querySelector("main")?.innerText ?? "").includes(t), { timeout: PAGE_TIMEOUT }, text), `wait for "${text}"`).map(() => {
79049
79049
  return;
79050
79050
  }),
79051
- waitForButton: async () => safe(page.waitForSelector("button", { visible: true, timeout: PAGE_TIMEOUT }), "wait for button").map(() => {
79052
- return;
79053
- })
79051
+ waitForButton: async (textMatch) => {
79052
+ if (!textMatch) {
79053
+ return safe(page.waitForSelector("button", { visible: true, timeout: PAGE_TIMEOUT }), "wait for button").map(() => {
79054
+ return;
79055
+ });
79056
+ }
79057
+ return safe(page.waitForFunction((text) => Array.from(document.querySelectorAll("button")).some((b) => b.textContent?.includes(text)), { timeout: PAGE_TIMEOUT }, textMatch), `wait for button "${textMatch}"`).map(() => {
79058
+ return;
79059
+ });
79060
+ }
79054
79061
  });
79055
79062
  var formMethods = (page) => ({
79056
- clickButton: async (textMatch) => safe(page.evaluate((text) => {
79063
+ clickButton: async (textMatch) => safe(page.waitForFunction((text) => {
79057
79064
  const btn = Array.from(document.querySelectorAll("button")).find((b) => b.textContent?.includes(text));
79058
79065
  if (!btn)
79059
- throw new Error(`Button "${text}" not found`);
79066
+ return false;
79060
79067
  btn.click();
79061
- }, textMatch), `click "${textMatch}"`),
79062
- selectByLabel: async (labelMatch, optionText) => safe(page.evaluate((match, text) => {
79068
+ return true;
79069
+ }, { timeout: ACTION_TIMEOUT }, textMatch).then(() => {}), `click "${textMatch}"`),
79070
+ selectByLabel: async (labelMatch, optionText) => safe(page.waitForFunction((match, text) => {
79063
79071
  const fireChangeEvents = (el) => {
79064
79072
  el.dispatchEvent(new Event("change", { bubbles: true }));
79065
79073
  el.dispatchEvent(new Event("input", { bubbles: true }));
@@ -79071,14 +79079,14 @@ var formMethods = (page) => ({
79071
79079
  if (label.includes(match) || title.includes(match)) {
79072
79080
  const opt = Array.from(s.options).find((o) => o.text.includes(text));
79073
79081
  if (!opt)
79074
- throw new Error(`Option "${text}" not found in "${match}"`);
79082
+ return false;
79075
79083
  s.value = opt.value;
79076
79084
  fireChangeEvents(s);
79077
- return;
79085
+ return true;
79078
79086
  }
79079
79087
  }
79080
- throw new Error(`Select "${match}" not found`);
79081
- }, labelMatch, optionText), `select ${labelMatch}="${optionText}"`),
79088
+ return false;
79089
+ }, { timeout: ACTION_TIMEOUT }, labelMatch, optionText).then(() => {}), `select ${labelMatch}="${optionText}"`),
79082
79090
  selectYear: async (year) => safe(page.evaluate((y) => {
79083
79091
  const fireChangeEvents = (el) => {
79084
79092
  el.dispatchEvent(new Event("change", { bubbles: true }));
@@ -79332,7 +79340,7 @@ var loadEntryPage = async (session) => retry2(async () => {
79332
79340
  const nav = await session.goto(CRA_URL);
79333
79341
  if (nav.isErr())
79334
79342
  return nav;
79335
- return session.waitForButton();
79343
+ return session.waitForButton("Next");
79336
79344
  }, 3, 1000, "entry page");
79337
79345
  var advancePastEntry = async (session) => {
79338
79346
  const click = await session.clickButton("Next");
@@ -79630,7 +79638,7 @@ import { existsSync as existsSync4, renameSync, unlinkSync, chmodSync } from "fs
79630
79638
  // package.json
79631
79639
  var package_default = {
79632
79640
  name: "@seethruhead/cra-payroll",
79633
- version: "0.8.0",
79641
+ version: "0.8.2",
79634
79642
  description: "Calculate Canadian payroll deductions using CRA's Payroll Deductions Online Calculator",
79635
79643
  type: "module",
79636
79644
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seethruhead/cra-payroll",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Calculate Canadian payroll deductions using CRA's Payroll Deductions Online Calculator",
5
5
  "type": "module",
6
6
  "bin": {