@seethruhead/cra-payroll 0.3.0 → 0.4.0
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/dist/cra-payroll.js +101 -28
- package/package.json +2 -2
package/dist/cra-payroll.js
CHANGED
|
@@ -69212,8 +69212,8 @@ var init_LaunchOptions = __esm(() => {
|
|
|
69212
69212
|
|
|
69213
69213
|
// src/cli.ts
|
|
69214
69214
|
import { parseArgs } from "util";
|
|
69215
|
-
import { resolve as
|
|
69216
|
-
import { existsSync as
|
|
69215
|
+
import { resolve as resolve7 } from "path";
|
|
69216
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, fstatSync } from "fs";
|
|
69217
69217
|
import { createInterface as createInterface2 } from "readline";
|
|
69218
69218
|
|
|
69219
69219
|
// node_modules/neverthrow/dist/index.cjs.js
|
|
@@ -79486,10 +79486,73 @@ ${text.value}
|
|
|
79486
79486
|
await session.close();
|
|
79487
79487
|
return parsed;
|
|
79488
79488
|
};
|
|
79489
|
+
// src/cache.ts
|
|
79490
|
+
import { resolve as resolve6 } from "path";
|
|
79491
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
|
|
79492
|
+
import { createHash } from "crypto";
|
|
79493
|
+
var DEFAULT_CACHE_DIR = resolve6(process.env.HOME || "~", ".config", "cra-payroll", "cache");
|
|
79494
|
+
var ensureDir = (dir) => {
|
|
79495
|
+
if (!existsSync3(dir))
|
|
79496
|
+
mkdirSync(dir, { recursive: true });
|
|
79497
|
+
};
|
|
79498
|
+
var cacheKey = (config2) => {
|
|
79499
|
+
const data = JSON.stringify({
|
|
79500
|
+
province: config2.province,
|
|
79501
|
+
annualSalary: config2.annualSalary,
|
|
79502
|
+
payPeriod: config2.payPeriod,
|
|
79503
|
+
year: config2.year,
|
|
79504
|
+
rrspMatchPercent: config2.rrspMatchPercent,
|
|
79505
|
+
rrspUnmatchedPercent: config2.rrspUnmatchedPercent,
|
|
79506
|
+
cppMaxedOut: config2.cppMaxedOut,
|
|
79507
|
+
eiMaxedOut: config2.eiMaxedOut
|
|
79508
|
+
});
|
|
79509
|
+
return createHash("sha256").update(data).digest("hex").slice(0, 16);
|
|
79510
|
+
};
|
|
79511
|
+
var cachePath = (config2, dir) => resolve6(dir, `${cacheKey(config2)}.json`);
|
|
79512
|
+
var readCache = (config2, dir) => {
|
|
79513
|
+
const path12 = cachePath(config2, dir);
|
|
79514
|
+
if (!existsSync3(path12))
|
|
79515
|
+
return null;
|
|
79516
|
+
try {
|
|
79517
|
+
const data = JSON.parse(readFileSync4(path12, "utf-8"));
|
|
79518
|
+
if (typeof data.grossIncome === "number" && typeof data.net === "number") {
|
|
79519
|
+
return data;
|
|
79520
|
+
}
|
|
79521
|
+
return null;
|
|
79522
|
+
} catch {
|
|
79523
|
+
return null;
|
|
79524
|
+
}
|
|
79525
|
+
};
|
|
79526
|
+
var writeCache = (config2, result, dir) => {
|
|
79527
|
+
try {
|
|
79528
|
+
ensureDir(dir);
|
|
79529
|
+
writeFileSync(cachePath(config2, dir), JSON.stringify(result, null, 2));
|
|
79530
|
+
} catch (e2) {
|
|
79531
|
+
log(`cache write failed: ${e2.message}`);
|
|
79532
|
+
}
|
|
79533
|
+
};
|
|
79534
|
+
var withCache = (inner, cacheDir = DEFAULT_CACHE_DIR) => ({
|
|
79535
|
+
calculate: async (config2, headless) => {
|
|
79536
|
+
const cached = readCache(config2, cacheDir);
|
|
79537
|
+
if (cached) {
|
|
79538
|
+
log(`cache hit: ${cachePath(config2, cacheDir)}`);
|
|
79539
|
+
return $ok(cached);
|
|
79540
|
+
}
|
|
79541
|
+
log(`cache miss, hitting CRA...`);
|
|
79542
|
+
const result = await inner.calculate(config2, headless);
|
|
79543
|
+
if (result.isOk()) {
|
|
79544
|
+
writeCache(config2, result.value, cacheDir);
|
|
79545
|
+
}
|
|
79546
|
+
return result;
|
|
79547
|
+
}
|
|
79548
|
+
});
|
|
79549
|
+
|
|
79489
79550
|
// src/calculator.ts
|
|
79490
|
-
var
|
|
79551
|
+
var rawService = {
|
|
79491
79552
|
calculate: calculatePayroll
|
|
79492
79553
|
};
|
|
79554
|
+
var craService = withCache(rawService);
|
|
79555
|
+
var craServiceNoCache = rawService;
|
|
79493
79556
|
|
|
79494
79557
|
// src/yearly.ts
|
|
79495
79558
|
var CPP_MAX_BASE = 4230.45;
|
|
@@ -79563,11 +79626,11 @@ var calculateYearly = async (service, config2, headless = false) => {
|
|
|
79563
79626
|
|
|
79564
79627
|
// src/updater.ts
|
|
79565
79628
|
import { execSync as execSync2 } from "child_process";
|
|
79566
|
-
import { existsSync as
|
|
79629
|
+
import { existsSync as existsSync4, renameSync, unlinkSync, chmodSync } from "fs";
|
|
79567
79630
|
// package.json
|
|
79568
79631
|
var package_default = {
|
|
79569
79632
|
name: "@seethruhead/cra-payroll",
|
|
79570
|
-
version: "0.
|
|
79633
|
+
version: "0.4.0",
|
|
79571
79634
|
description: "Calculate Canadian payroll deductions using CRA's Payroll Deductions Online Calculator",
|
|
79572
79635
|
type: "module",
|
|
79573
79636
|
bin: {
|
|
@@ -79581,7 +79644,7 @@ var package_default = {
|
|
|
79581
79644
|
build: "bun build --compile src/cli.ts --outfile cra-payroll --external electron",
|
|
79582
79645
|
"build:npm": "bun build src/cli.ts --outfile dist/cra-payroll.js --target=node",
|
|
79583
79646
|
release: "bash release.sh",
|
|
79584
|
-
test: "bun test src/unit.test.ts",
|
|
79647
|
+
test: "bun test src/unit.test.ts src/cache.test.ts",
|
|
79585
79648
|
"test:integration": "bun test src/integration.test.ts --timeout 120000 --max-concurrency 1",
|
|
79586
79649
|
"test:all": "bun test --timeout 120000 --max-concurrency 1"
|
|
79587
79650
|
},
|
|
@@ -79706,13 +79769,13 @@ var selfUpdate = async () => {
|
|
|
79706
79769
|
console.log(`Downloading ${update.downloadUrl}...
|
|
79707
79770
|
`);
|
|
79708
79771
|
let binaryPath = "";
|
|
79709
|
-
if (process.execPath &&
|
|
79772
|
+
if (process.execPath && existsSync4(process.execPath) && !process.execPath.endsWith("/bun")) {
|
|
79710
79773
|
binaryPath = process.execPath;
|
|
79711
79774
|
}
|
|
79712
79775
|
if (!binaryPath) {
|
|
79713
79776
|
try {
|
|
79714
79777
|
const which = execSync2("which cra-payroll", { encoding: "utf-8" }).trim();
|
|
79715
|
-
if (which &&
|
|
79778
|
+
if (which && existsSync4(which))
|
|
79716
79779
|
binaryPath = which;
|
|
79717
79780
|
} catch {}
|
|
79718
79781
|
}
|
|
@@ -79764,7 +79827,7 @@ ${line("═", W)}
|
|
|
79764
79827
|
|
|
79765
79828
|
// src/views/table.ts
|
|
79766
79829
|
var col = (v, w) => typeof v === "number" ? money(v).padStart(w) : v.padStart(w);
|
|
79767
|
-
var renderRow = (r2) => `${r2.label} │ ${col(r2.gross, 10)} │ ${col(r2.fedTax, 10)} │ ${col(r2.provTax, 10)} │ ${col(r2.cpp, 10)} │ ${col(r2.cpp2, 6)} │ ${col(r2.ei, 10)} │ ${col(r2.netPay, 10)}${r2.
|
|
79830
|
+
var renderRow = (r2) => `${r2.label} │ ${col(r2.gross, 10)} │ ${col(r2.fedTax, 10)} │ ${col(r2.provTax, 10)} │ ${col(r2.cpp, 10)} │ ${col(r2.cpp2, 6)} │ ${col(r2.ei, 10)} │ ${col(r2.netPay, 10)}${r2.rrspYou !== undefined ? ` │ ${col(r2.rrspYou, 10)} │ ${col(r2.rrspEr, 10)} │ ${col(r2.takeHome, 10)}` : ""} │ ${col(r2.cumCppEi, 10)}${r2.suffix ?? ""}`;
|
|
79768
79831
|
var totalEmployeeRrsp = (r2) => r2.rrspMatched + r2.rrspUnmatched;
|
|
79769
79832
|
var totalEmployeeRrspTotals = (t8) => t8.rrspMatched + t8.rrspUnmatched;
|
|
79770
79833
|
var showRrsp = (totals) => totals.rrspMatched > 0 || totals.rrspUnmatched > 0 || totals.rrspEmployer > 0;
|
|
@@ -79779,7 +79842,7 @@ var toRow = (r2, first2, rrsp) => ({
|
|
|
79779
79842
|
cpp2: r2.cpp2,
|
|
79780
79843
|
ei: r2.ei,
|
|
79781
79844
|
netPay: r2.netPay,
|
|
79782
|
-
...rrspFields(rrsp, {
|
|
79845
|
+
...rrspFields(rrsp, { rrspYou: totalEmployeeRrsp(r2), rrspEr: r2.rrspEmployer, takeHome: r2.netPay - totalEmployeeRrsp(r2) }),
|
|
79783
79846
|
cumCppEi: r2.cumulativeCpp + r2.cumulativeCpp2 + r2.cumulativeEi,
|
|
79784
79847
|
suffix: annotate(r2, first2)
|
|
79785
79848
|
});
|
|
@@ -79792,7 +79855,7 @@ var headerRow = (rrsp) => ({
|
|
|
79792
79855
|
cpp2: "CPP2",
|
|
79793
79856
|
ei: "EI",
|
|
79794
79857
|
netPay: "Net Pay",
|
|
79795
|
-
...rrspFields(rrsp, {
|
|
79858
|
+
...rrspFields(rrsp, { rrspYou: "RRSP You", rrspEr: "RRSP Er", takeHome: "Take Home" }),
|
|
79796
79859
|
cumCppEi: "Cum CPP/EI"
|
|
79797
79860
|
});
|
|
79798
79861
|
var totalsRow = (totals, rrsp) => ({
|
|
@@ -79804,10 +79867,17 @@ var totalsRow = (totals, rrsp) => ({
|
|
|
79804
79867
|
cpp2: totals.cpp2,
|
|
79805
79868
|
ei: totals.ei,
|
|
79806
79869
|
netPay: totals.netPay,
|
|
79807
|
-
...rrspFields(rrsp, {
|
|
79870
|
+
...rrspFields(rrsp, { rrspYou: totalEmployeeRrspTotals(totals), rrspEr: totals.rrspEmployer, takeHome: totals.netPay - totalEmployeeRrspTotals(totals) }),
|
|
79808
79871
|
cumCppEi: ""
|
|
79809
79872
|
});
|
|
79810
|
-
var renderTable = (yearly, periodsPerYear, year = 2026) => t3(yearly, (ctx) => ({ ...ctx, rrsp: showRrsp(ctx.totals) }), (ctx) => ({ ...ctx, header: renderRow(headerRow(ctx.rrsp)) }), (ctx) => ({ ...ctx, bodyRows: ctx.rows.map((r2) => renderRow(toRow(r2, ctx.rows[0], ctx.rrsp))) }), (ctx) => ({ ...ctx, totalsStr: renderRow(totalsRow(ctx.totals, ctx.rrsp)), W: ctx.header.length }), (ctx) =>
|
|
79873
|
+
var renderTable = (yearly, periodsPerYear, year = 2026) => t3(yearly, (ctx) => ({ ...ctx, rrsp: showRrsp(ctx.totals) }), (ctx) => ({ ...ctx, header: renderRow(headerRow(ctx.rrsp)) }), (ctx) => ({ ...ctx, bodyRows: ctx.rows.map((r2) => renderRow(toRow(r2, ctx.rows[0], ctx.rrsp))) }), (ctx) => ({ ...ctx, totalsStr: renderRow(totalsRow(ctx.totals, ctx.rrsp)), W: ctx.header.length }), (ctx) => {
|
|
79874
|
+
const t8 = ctx.totals;
|
|
79875
|
+
const empTotal = totalEmployeeRrspTotals(t8);
|
|
79876
|
+
const rrspSummary = !ctx.rrsp ? "" : `
|
|
79877
|
+
RRSP You: $${money(empTotal)}/yr ($${money(empTotal / periodsPerYear)}/period)${t8.rrspMatched > 0 ? ` — matched: $${money(t8.rrspMatched)}/yr` : ""}${t8.rrspUnmatched > 0 ? ` — unmatched: $${money(t8.rrspUnmatched)}/yr` : ""}
|
|
79878
|
+
RRSP Er: $${money(t8.rrspEmployer)}/yr ($${money(t8.rrspEmployer / periodsPerYear)}/period)
|
|
79879
|
+
RRSP Total (You + Er): $${money(empTotal + t8.rrspEmployer)}/yr`;
|
|
79880
|
+
return `Per-Paycheck Table (${year})
|
|
79811
79881
|
${line("═", ctx.W)}
|
|
79812
79882
|
${ctx.header}
|
|
79813
79883
|
${line("─", ctx.W)}
|
|
@@ -79815,8 +79885,8 @@ ${ctx.bodyRows.join(`
|
|
|
79815
79885
|
`)}
|
|
79816
79886
|
${line("─", ctx.W)}
|
|
79817
79887
|
${ctx.totalsStr}
|
|
79818
|
-
${line("═", ctx.W)}${
|
|
79819
|
-
|
|
79888
|
+
${line("═", ctx.W)}${rrspSummary}`;
|
|
79889
|
+
});
|
|
79820
79890
|
|
|
79821
79891
|
// src/views/summary.ts
|
|
79822
79892
|
var W2 = 42;
|
|
@@ -79878,6 +79948,7 @@ var { values } = parseArgs({
|
|
|
79878
79948
|
table: { type: "boolean", short: "t", default: false },
|
|
79879
79949
|
annual: { type: "boolean", short: "a", default: false },
|
|
79880
79950
|
monthly: { type: "boolean", short: "m", default: false },
|
|
79951
|
+
"no-cache": { type: "boolean", default: false },
|
|
79881
79952
|
update: { type: "boolean", default: false },
|
|
79882
79953
|
version: { type: "boolean", default: false },
|
|
79883
79954
|
headless: { type: "boolean", default: false },
|
|
@@ -79908,6 +79979,7 @@ if (values.help) {
|
|
|
79908
79979
|
-t, --table Show per-paycheck table for the year (tracks CPP/EI max)
|
|
79909
79980
|
-a, --annual Show annualized totals
|
|
79910
79981
|
-m, --monthly Show monthly averages
|
|
79982
|
+
--no-cache Skip cache and force a fresh CRA lookup
|
|
79911
79983
|
--headless Run browser headless (may be blocked by CRA)
|
|
79912
79984
|
--update Self-update to the latest release
|
|
79913
79985
|
--version Show current version
|
|
@@ -80002,14 +80074,14 @@ var readStdinConfig = async () => {
|
|
|
80002
80074
|
};
|
|
80003
80075
|
var readFileConfig = (configFlag) => {
|
|
80004
80076
|
const configPaths = [
|
|
80005
|
-
configFlag ?
|
|
80006
|
-
|
|
80007
|
-
|
|
80008
|
-
|
|
80077
|
+
configFlag ? resolve7(configFlag) : "",
|
|
80078
|
+
resolve7("config.json"),
|
|
80079
|
+
resolve7(process.env.HOME || "~", ".config", "cra-payroll.json"),
|
|
80080
|
+
resolve7(process.env.HOME || "~", ".cra-payroll.json")
|
|
80009
80081
|
].filter(Boolean);
|
|
80010
80082
|
for (const p of configPaths) {
|
|
80011
|
-
if (p &&
|
|
80012
|
-
return JSON.parse(
|
|
80083
|
+
if (p && existsSync5(p)) {
|
|
80084
|
+
return JSON.parse(readFileSync5(p, "utf-8"));
|
|
80013
80085
|
}
|
|
80014
80086
|
}
|
|
80015
80087
|
return {};
|
|
@@ -80025,7 +80097,7 @@ var loadFileConfig = async (configFlag, isPiped) => {
|
|
|
80025
80097
|
try {
|
|
80026
80098
|
const config2 = readFileConfig(configFlag);
|
|
80027
80099
|
if (configFlag && Object.keys(config2).length === 0) {
|
|
80028
|
-
return $err(`Config file not found: ${
|
|
80100
|
+
return $err(`Config file not found: ${resolve7(configFlag)}`);
|
|
80029
80101
|
}
|
|
80030
80102
|
return $ok(config2);
|
|
80031
80103
|
} catch (e2) {
|
|
@@ -80075,8 +80147,8 @@ var resolveConfig = async (vals, fileConfig, isPiped) => {
|
|
|
80075
80147
|
eiMaxedOut
|
|
80076
80148
|
});
|
|
80077
80149
|
};
|
|
80078
|
-
var runYearlyMode = async (config2, headless, flags) => {
|
|
80079
|
-
const yearlyResult = await calculateYearly(
|
|
80150
|
+
var runYearlyMode = async (config2, headless, svc, flags) => {
|
|
80151
|
+
const yearlyResult = await calculateYearly(svc, config2, headless);
|
|
80080
80152
|
if (yearlyResult.isErr()) {
|
|
80081
80153
|
console.error(`Error: ${yearlyResult.error}`);
|
|
80082
80154
|
process.exit(1);
|
|
@@ -80090,8 +80162,8 @@ var runYearlyMode = async (config2, headless, flags) => {
|
|
|
80090
80162
|
if (flags.monthly)
|
|
80091
80163
|
console.log(renderMonthly(yearly.totals));
|
|
80092
80164
|
};
|
|
80093
|
-
var runSingleMode = async (config2, headless) => {
|
|
80094
|
-
const calcResult = await
|
|
80165
|
+
var runSingleMode = async (config2, headless, svc) => {
|
|
80166
|
+
const calcResult = await svc.calculate(config2, headless);
|
|
80095
80167
|
if (calcResult.isErr()) {
|
|
80096
80168
|
console.error(`Error: ${calcResult.error}`);
|
|
80097
80169
|
process.exit(1);
|
|
@@ -80122,6 +80194,7 @@ if (configResult.isErr()) {
|
|
|
80122
80194
|
}
|
|
80123
80195
|
var config2 = configResult.value;
|
|
80124
80196
|
var headless = values.headless ?? false;
|
|
80197
|
+
var service = values["no-cache"] ? craServiceNoCache : craService;
|
|
80125
80198
|
if (values.verbose)
|
|
80126
80199
|
setVerbose(true);
|
|
80127
80200
|
var wantTable = values.table ?? false;
|
|
@@ -80129,8 +80202,8 @@ var wantAnnual = values.annual ?? false;
|
|
|
80129
80202
|
var wantMonthly = values.monthly ?? false;
|
|
80130
80203
|
console.log(renderConfig(config2, !wantTable && !wantAnnual && !wantMonthly));
|
|
80131
80204
|
if (wantTable || wantAnnual || wantMonthly) {
|
|
80132
|
-
await runYearlyMode(config2, headless, { table: wantTable, annual: wantAnnual, monthly: wantMonthly });
|
|
80205
|
+
await runYearlyMode(config2, headless, service, { table: wantTable, annual: wantAnnual, monthly: wantMonthly });
|
|
80133
80206
|
} else {
|
|
80134
|
-
await runSingleMode(config2, headless);
|
|
80207
|
+
await runSingleMode(config2, headless, service);
|
|
80135
80208
|
}
|
|
80136
80209
|
await showUpdateNag();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seethruhead/cra-payroll",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Calculate Canadian payroll deductions using CRA's Payroll Deductions Online Calculator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build": "bun build --compile src/cli.ts --outfile cra-payroll --external electron",
|
|
15
15
|
"build:npm": "bun build src/cli.ts --outfile dist/cra-payroll.js --target=node",
|
|
16
16
|
"release": "bash release.sh",
|
|
17
|
-
"test": "bun test src/unit.test.ts",
|
|
17
|
+
"test": "bun test src/unit.test.ts src/cache.test.ts",
|
|
18
18
|
"test:integration": "bun test src/integration.test.ts --timeout 120000 --max-concurrency 1",
|
|
19
19
|
"test:all": "bun test --timeout 120000 --max-concurrency 1"
|
|
20
20
|
},
|