@seethruhead/cra-payroll 0.3.1 → 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.
Files changed (2) hide show
  1. package/dist/cra-payroll.js +87 -21
  2. package/package.json +2 -2
@@ -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 resolve6 } from "path";
69216
- import { existsSync as existsSync4, readFileSync as readFileSync4, fstatSync } from "fs";
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 craService = {
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 existsSync3, renameSync, unlinkSync, chmodSync } from "fs";
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.3.1",
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 && existsSync3(process.execPath) && !process.execPath.endsWith("/bun")) {
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 && existsSync3(which))
79778
+ if (which && existsSync4(which))
79716
79779
  binaryPath = which;
79717
79780
  } catch {}
79718
79781
  }
@@ -79885,6 +79948,7 @@ var { values } = parseArgs({
79885
79948
  table: { type: "boolean", short: "t", default: false },
79886
79949
  annual: { type: "boolean", short: "a", default: false },
79887
79950
  monthly: { type: "boolean", short: "m", default: false },
79951
+ "no-cache": { type: "boolean", default: false },
79888
79952
  update: { type: "boolean", default: false },
79889
79953
  version: { type: "boolean", default: false },
79890
79954
  headless: { type: "boolean", default: false },
@@ -79915,6 +79979,7 @@ if (values.help) {
79915
79979
  -t, --table Show per-paycheck table for the year (tracks CPP/EI max)
79916
79980
  -a, --annual Show annualized totals
79917
79981
  -m, --monthly Show monthly averages
79982
+ --no-cache Skip cache and force a fresh CRA lookup
79918
79983
  --headless Run browser headless (may be blocked by CRA)
79919
79984
  --update Self-update to the latest release
79920
79985
  --version Show current version
@@ -80009,14 +80074,14 @@ var readStdinConfig = async () => {
80009
80074
  };
80010
80075
  var readFileConfig = (configFlag) => {
80011
80076
  const configPaths = [
80012
- configFlag ? resolve6(configFlag) : "",
80013
- resolve6("config.json"),
80014
- resolve6(process.env.HOME || "~", ".config", "cra-payroll.json"),
80015
- resolve6(process.env.HOME || "~", ".cra-payroll.json")
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")
80016
80081
  ].filter(Boolean);
80017
80082
  for (const p of configPaths) {
80018
- if (p && existsSync4(p)) {
80019
- return JSON.parse(readFileSync4(p, "utf-8"));
80083
+ if (p && existsSync5(p)) {
80084
+ return JSON.parse(readFileSync5(p, "utf-8"));
80020
80085
  }
80021
80086
  }
80022
80087
  return {};
@@ -80032,7 +80097,7 @@ var loadFileConfig = async (configFlag, isPiped) => {
80032
80097
  try {
80033
80098
  const config2 = readFileConfig(configFlag);
80034
80099
  if (configFlag && Object.keys(config2).length === 0) {
80035
- return $err(`Config file not found: ${resolve6(configFlag)}`);
80100
+ return $err(`Config file not found: ${resolve7(configFlag)}`);
80036
80101
  }
80037
80102
  return $ok(config2);
80038
80103
  } catch (e2) {
@@ -80082,8 +80147,8 @@ var resolveConfig = async (vals, fileConfig, isPiped) => {
80082
80147
  eiMaxedOut
80083
80148
  });
80084
80149
  };
80085
- var runYearlyMode = async (config2, headless, flags) => {
80086
- const yearlyResult = await calculateYearly(craService, config2, headless);
80150
+ var runYearlyMode = async (config2, headless, svc, flags) => {
80151
+ const yearlyResult = await calculateYearly(svc, config2, headless);
80087
80152
  if (yearlyResult.isErr()) {
80088
80153
  console.error(`Error: ${yearlyResult.error}`);
80089
80154
  process.exit(1);
@@ -80097,8 +80162,8 @@ var runYearlyMode = async (config2, headless, flags) => {
80097
80162
  if (flags.monthly)
80098
80163
  console.log(renderMonthly(yearly.totals));
80099
80164
  };
80100
- var runSingleMode = async (config2, headless) => {
80101
- const calcResult = await calculatePayroll(config2, headless);
80165
+ var runSingleMode = async (config2, headless, svc) => {
80166
+ const calcResult = await svc.calculate(config2, headless);
80102
80167
  if (calcResult.isErr()) {
80103
80168
  console.error(`Error: ${calcResult.error}`);
80104
80169
  process.exit(1);
@@ -80129,6 +80194,7 @@ if (configResult.isErr()) {
80129
80194
  }
80130
80195
  var config2 = configResult.value;
80131
80196
  var headless = values.headless ?? false;
80197
+ var service = values["no-cache"] ? craServiceNoCache : craService;
80132
80198
  if (values.verbose)
80133
80199
  setVerbose(true);
80134
80200
  var wantTable = values.table ?? false;
@@ -80136,8 +80202,8 @@ var wantAnnual = values.annual ?? false;
80136
80202
  var wantMonthly = values.monthly ?? false;
80137
80203
  console.log(renderConfig(config2, !wantTable && !wantAnnual && !wantMonthly));
80138
80204
  if (wantTable || wantAnnual || wantMonthly) {
80139
- await runYearlyMode(config2, headless, { table: wantTable, annual: wantAnnual, monthly: wantMonthly });
80205
+ await runYearlyMode(config2, headless, service, { table: wantTable, annual: wantAnnual, monthly: wantMonthly });
80140
80206
  } else {
80141
- await runSingleMode(config2, headless);
80207
+ await runSingleMode(config2, headless, service);
80142
80208
  }
80143
80209
  await showUpdateNag();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seethruhead/cra-payroll",
3
- "version": "0.3.1",
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
  },