github Fighter90/career-ops-ui v1.234.0

5 hours ago

[1.234.0] — 2026-09-15

Parent parity — career-ops main @ 56cce8f (VERSION still 1.32.0, 58 commits past 1.32.0). One mirrored fix across 15 sources, plus a guard so it cannot come back.

Fixed

A single malformed job id no longer empties the whole page. encodeURIComponent throws URIError on a lone UTF-16 surrogate, and a JSON payload can carry one — JSON.parse('"\\uD800"') keeps it. Fifteen sources built each posting's URL from a host-controlled id or slug inside the parse loop, so one bad posting aborted the loop and lost every job on that page; nothing was logged as a source failure because the exception unwound before the per-company catch had anything to report. The parent fixed it in providers/_safe-url.mjs (safeEncodeURIComponentnull on URIError, rethrow anything else) and routed each loop's id through it, dropping just the one posting on null. That helper is now server/lib/sources/_safe-url.mjs, and the same change is applied to the thirteen mirrored sources — alibaba, arbeitsagentur, bamboohr, feishu-jobs, garena, jibeapply, manfred, meituan, mokahr, phenom, thehub, tkms, vdab — and to two web-ui-only sources the new guard surfaced on its first run, jobstreet and trudvsem, which had the same loop shape and the same latent throw. Scope is deliberate: only API-sourced ids go through the helper. Config-derived values keep their strict encode and fail loud — garena's office (a portals.yml segment) stays on the throwing urlSegment, while its API id gets a null-returning idUrlSegment; csod's corpName and 4dayweek's SLUG_RE-validated slug are allowlisted by name with the reason.
rheinmetall's title fallback could throw on a malformed href. When a card has no headline the title is reconstructed from the URL slug via decodeURIComponent, which throws on a bad percent-sequence in the scraped href — the same one-bad-row-kills-the-page shape, on the decode side. It now decodes defensively and falls back to the raw slug.
The sources registry skips _-prefixed files. Auto-discovery imported every .mjs in server/lib/sources/ except itself and warned on anything without export const meta — so the helper produced a boot-time warning. The parent's convention is adopted: a leading underscore means not a source; such files are neither imported nor warned about. An undeclared file without meta still warns, and the discovery test now asserts both halves (confirmed red against the old filter). The site build's sync-assets.mjs counts adapter files on disk the same way, so the helper no longer trips its silent-drop guard.

Notes

tests/sources-url-encoding-surrogate.test.mjs mirrors the parent's suite in three parts: the helper's contract (a paired surrogate — an ordinary emoji — still encodes; a throw from the value's own toString is the caller's bug and propagates), per-source behaviour for all fifteen (one bad id + one clean id → no throw, clean kept, bad dropped, each driven through the source's exported pure parser or, for thehub, its fetcher with a fake transport), and a source-level guard: every converted file must import the helper and call it, no file may reference it without importing it, and no unreviewed file may build a job URL with a bare encodeURIComponent — a new source with the old shape fails CI with the offending line number. All fifteen per-source cases were confirmed failing before the port.
Everything else in the parent delta is not ported, with the reason: batch/batch-runner.sh --cli is a CLI-only flag (web-ui does not shell into the batch runner); invite-match.mjs now resolves set-status.mjs from the code root — web-ui does not relay it; company-funded.mjs gained the same safe-url change internally and its --json output shape, which /api/company-funded parses, is unchanged; test-all.mjs moved a timeout budget only (the fork's vpFixtureEnv divergence is intact); web/ is the parent's own frontend and is not mirrored; AGENTS.md/SIGNATURES.md are repository-only. Fork divergences re-verified after the pull: the Cyrillic \p{L} fix in providers/telegram-channel.mjs, the fork's own providers/telegram.mjs, hermes in web/src/lib/clis.ts. Source count unchanged at 92 (87 EN + 5 RU), so help is untouched. 3022 → 3042 tests.

Don't miss a new career-ops-ui release

NewReleases is sending notifications on new releases.