job-pro 1.0.26 → 1.0.28

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/apply.js +25 -2
  2. package/package.json +1 -1
package/dist/apply.js CHANGED
@@ -715,10 +715,13 @@ async function fetchWithRetry(url, init, label, log) {
715
715
  }
716
716
  return { ok: false, message: lastErr };
717
717
  }
718
- // 4xx → user error, don't retry.
718
+ // 4xx → user error, don't retry. Enrich with a hint pointing at the most
719
+ // likely cause — bare "HTTP 401: " gives the user nothing to act on.
719
720
  if (response.status >= 400 && response.status < 500) {
721
+ const hint = hintForStatus(response.status);
722
+ const message = `HTTP ${response.status}: ${response.statusText}${hint ? ` — ${hint}` : ""}`;
720
723
  log?.push({ attempt: attempt + 1, ok: false, status: response.status, message: `${label}: HTTP ${response.status} (no retry — 4xx)` });
721
- return { ok: false, status: response.status, message: `HTTP ${response.status}: ${response.statusText}` };
724
+ return { ok: false, status: response.status, message };
722
725
  }
723
726
  // 5xx → server error, retry.
724
727
  if (response.status >= 500 && attempt < maxRetries) {
@@ -732,6 +735,26 @@ async function fetchWithRetry(url, init, label, log) {
732
735
  }
733
736
  return { ok: false, message: lastErr || "exhausted retries" };
734
737
  }
738
+ function hintForStatus(status) {
739
+ // Stale-session hints are by far the most common cause of 401/403 here —
740
+ // the session.json cookies have expired since capture. The
741
+ // really-submit-blocked / session-age gate catches >30d staleness, but
742
+ // sessions sometimes expire earlier (logout from another tab, password
743
+ // change, server-side revoke).
744
+ if (status === 401 || status === 403) {
745
+ return "session likely stale — recapture via `job-pro extension`, log into the careers site, click Export";
746
+ }
747
+ if (status === 404) {
748
+ return "endpoint not found — submit_endpoint may have drifted upstream; verify via `apply --schema` + `--debug-submit-to`";
749
+ }
750
+ if (status === 422 || status === 400) {
751
+ return "request rejected — likely a missing/malformed answer; rerun `apply --interactive` to refill required fields";
752
+ }
753
+ if (status === 429) {
754
+ return "rate limited — retry after a few minutes";
755
+ }
756
+ return "";
757
+ }
735
758
  function retryDelayMs(attempt) {
736
759
  // Exponential backoff with jitter: 250ms / 500ms / 1s / 2s / 4s, ±25%.
737
760
  const base = 250 * Math.pow(2, attempt);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "job-pro",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "Query Chinese big-tech campus recruiting from your terminal. 50 companies, all 50 live. 46 via each company's own API; the 4 with no public canonical feed (Hikvision, CICC, Cainiao, WeBank) surfaced via Liepin as a clearly-labeled third-party fallback. No signup, no token, no server.",
5
5
  "homepage": "https://job.ha7ch.com",
6
6
  "repository": "https://github.com/HA7CH/job-pro",