-
Notifications
You must be signed in to change notification settings - Fork 3
Release History
viaduct is versioned with npm semver and shipped from git tags. Every published GitHub Release triggers a GitHub Action that publishes the package to npm as @magicelk235/viaduct over Trusted Publishing (OIDC): no long-lived NPM_TOKEN. The current released version is 1.8.0. The project spans roughly 185 commits from 2026-05-29 (scaffold) to 2026-07-22 (working branch), and this page maps each tag to what actually shipped in it, grounded in the commit record.
Every bullet cites the (shorthash) it came from. Newest release is on top.
Cross-references: Runtime Shim · Manifest Transform · Analyzer · Build and Install · OAuth Bridge · Safari Quirks
Theme: an adversarially-verified sweep over the whole pipeline — eight correctness/robustness fixes, none behavior-visible on the happy path. All land in 92fa2ee.
- Recover the CRX-embedded
keywith the lenientparseJsonc, not strictJSON.parse. A Chrome manifest carrying a BOM,//comment, or trailing comma madeJSON.parsethrow, so the key was silently dropped and the derived Chrome id (OAuth bridge,chrome-extension://origin spoof) was lost for exactly the bundles most likely to be hand-edited (92fa2ee), see Input Handling and OAuth Bridge. -
defaultBundleIdnow hashes whenever the slug isn't a lossless rendering of the name, not only when it's empty. Two distinct names reducing to the same non-empty slug (Foo/1Foo,Cafe/Café,MyExt/My-Ext) previously collapsed to one bundle id and shadowed each other in LaunchServices (92fa2ee), see Build and Install. -
--uninstallreads the installed app's realCFBundleIdentifierto key the native-messaging broker LaunchAgent, instead of recomputing the default id. An extension installed with a custom--bundle-idused to leave an orphanedKeepAliveagent runningopenon the deleted app forever (92fa2ee), see Build and Install and OAuth Bridge. - The whole-download 5-minute wall-clock deadline is threaded through the redirect recursion as one shared deadline, instead of re-armed per hop — a 5-hop redirect chain could otherwise stay open ~30 min (
92fa2ee), see Input Handling. - The
ancestorOriginsguard regex no longer allows)/]in the receiver walk-back, so it can't start a match mid-expression (foo().ancestorOrigins…) and emit unbalanced parentheses. Latent (real bundles never call through toancestorOrigins), but a token rewrite must never be able to produce invalid JS (92fa2ee), see Safari Quirks E3. - The action hotkey maps a named command key to its DOM
KeyboardEvent.keyform (Up→ArrowUp,Space→" ", …) instead of the bare WebExtensions token, and falls back to theCtrl+Shift+Ydefault when a token is unmappable. A command likeCtrl+Shift+Upused to wire a shortcut that could never fire (92fa2ee), see Runtime Shim and Safari Quirks A5. - Drop the dead
try/catcharoundBuffer.from(key, "base64")inderiveChromeId— Node's base64 decoder never throws; theder.length === 0check is the real malformed-key guard (92fa2ee), see OAuth Bridge. - Strip comments before the
importScriptsdynamic-argument residue test, soimportScripts("a.js" /*x*/, "b.js")is recognized as fully static instead of being flipped to dynamic — which needlessly triggered webpack-chunk collection and module-mode background loading (92fa2ee), see Runtime Shim and Conversion Pipeline.
Regression tests added for the bundle-id collision, the hotkey key mapping, and the ancestorOrigins call-receiver balance.
- Stop overwriting an extension's own
browser-polyfill.min.js. uBlock Origin ships its own polyfill in its content-script list;writePolyfillcopied viaduct's webextension-polyfill build over that exact file, so uBlock'svapi.js(compiled against its own copy) threw at load and every content script after it, includingcontentscript.js(the cosmetic/element-hiding engine), never ran. The extension installed, enabled, and badged from the background but did nothing on the page. viaduct now writes its copy underviaduct-browser-polyfill.min.jswhen the extension already ships one, leaving the original intact and loading both (the polyfill is idempotent) (622001c), see Runtime Shim and Safari Quirks E5. Closes #10. - Strip a
chrome://-scheme URL (and any other unparseable-scheme host pattern, e.g.ws://) frompermissions/optional_permissionsduring transform. Tampermonkey shipschrome://favicon/inpermissions; left in place, Safari treats the whole manifest as invalid and never loads the extension, even though it installs and registers with pluginkit. The analyzer already warned but the converter left it alone (warn-don't-move), which is right for a merely-ignoredhttps://pattern but fatal for a Chrome-only scheme Safari can't grant anywhere. The transform now drops these the same wayhost_permissionsalready filters unparseable schemes, and the analyzer reports the case as auto-fixed (31d13b9), see Manifest Transform and Safari Quirks A6. Closes #11.
Theme: Safari runtime-compat fixes, driven by the TWP – Translate Web Pages conversion (#4) and a review-surfaced XHR bug (#6). Squash-merged as #5 (7247e8b) and #8 (47d2454); per-fix shorthashes below are the working-branch commits.
- Route content-script messages and XHR through the correct Safari paths (
26605b7), see Runtime Shim. - Stop hijacking
onClickedactions and preserveversion_namein the transformed manifest (5b1bd03), see Manifest Transform. - Guard
ancestorOriginsreads and rewrite self-pagechrome-extension://URLs during staging (02c4007), see Safari Quirks E3 / B1. - Prepend the compat shim to MV2 background scripts so the background survives load (
0240e1d), see Safari Quirks A1. - Strip
ftp://fromcontextMenusURL patterns (4a5cae9), see Safari Quirks F4. - Cap
commandsat Safari's 4-shortcut limit (d3fcb9a), see Manifest Transform / Safari Quirks A4. - Make top-level content-script globals re-injection-safe (
const/let→var) so Safari's double-evaluation of adocument_end/all_framesgroup into a shared world can't throw "Can't create duplicate variable" (1f22a10), then normalize./and backslash content-scriptjspaths so every referenced file is reached (2dc30ca), see Safari Quirks E4. Closes #4. - Proxied XHR fires
timeout(+loadend), noterror, on a timeout (2501a8b), see Safari Quirks D6. Closes #6.
Theme: debugger/CDP emulation, native-messaging broker, real Chrome-id derivation, plus licensing.
- Emulate
chrome.debugger/ the Chrome DevTools Protocol for converted extensions (a2a0f55), see Runtime Shim. - Native-messaging broker so
runtime.connectNativeworks on Safari (05cc244), see OAuth Bridge. - Derive the Chrome extension id from the CRX public key instead of guessing (
34d4724), see Build and Install. - Source-comment tidy (
f7e3c75).
Licensing / meta milestones folded into this release window:
- Added an MIT license and privacy policy (
8579c84), then a security policy (3c94a79). - Relicensed under PolyForm Shield 1.0.0 (
a8bd84d), the current license.
Theme: main-world content scripts.
- Re-declare content-script page-world injections as
world: MAINso scripts that expect the page's own JS context behave on Safari (d35e3ad), see Manifest Transform and Safari Quirks.
Theme: popup-less action buttons.
- Popover-free toggle for popup-less
onClickedactions, so a toolbar button with no popup fires its click handler on Safari instead of opening an empty popover (e9ba1e3), see Safari Quirks. - Analyzer now flags blocking-
webRequestcontent blockers that can't block in Safari (dbe3442), with README guidance that full uBO can't block and users should reach for uBO Lite (644e97e), see Analyzer. -
deriveAppNamewhitelists characters to stop XML/scheme injection into generated project files (ba89cc7).
Theme: URL-rewrite correctness fix.
- Keep concrete-host
chrome-extension://URLs intact rather than rewriting them (1b7b6f5), see Safari Quirks.
Theme: docs.
- Spell out the Safari website-access grant step users must perform after install (
2ea6657), see Build and Install.
Theme: Safari blob downloads, dark mode, webpack SWs, popup tightening.
- Safari blob downloads, dark-mode pages, webpack service workers, and WebSocket hosts (
7acf2ca), with follow-ups to preserve the filename via the share sheet (bfa7903) and to make direct one-click blob downloads keep the correct extension (6c2396d). - Route offscreen-document replies and rewrite the
chrome-extension:scheme (5a12186); strip the?tabIdquery from popupsender.url(49c41cb), see Runtime Shim. - Keep a
declarativeContent-gated action button clickable and further tighten popup sizing (db06848), see Safari Quirks.
Theme: docs / release chore.
- Smaller viaduct ASCII icon in the README (
39820ba); release bump (886284c). No code changes.
Theme: docs / release chore.
- New viaduct ASCII icon and README banner update (
357a49e); release bump (a62f069). No code changes.
Theme: bug-hunt hardening at scale, plus config/batch/--verify.
This is a large release built mostly from multi-agent audit passes, hundreds of small correctness fixes across the shim, manifest transform, OAuth templates, and analyzer accuracy:
- Config file, batch convert, and
--verifymode (33e9bce), the batch/verify feature landed here, see Build and Install. - Wire 4 previously-inert shim stubs to real Safari/web implementations (
94ad310); strip two Safari-unrecognized permission tokens (774d0a8), see Runtime Shim and Manifest Transform. - Shim runtime hardening, frozen-root throw guards,
storage.sessioncorrectness, missing runtime APIs (f344d7a); external-messaging events and proxy-config substitution guard (54172b4). - Resolve
__MSG_*__i18n placeholders in the generatedbackground.htmltitle (f02a0cc), see Manifest Transform. - Rolled-up audit fixes: 6 bugs (
e9150d8), 9 bugs (4f42d8f), 5 issues (23aef5e), 13 issues (b016620), 8 more shim gaps from corpus cross-reference (8f8aef6), 22 issues across runtime/CLI/analyze (9a221ce), 13 bugs incl. iOS build/crashes/OAuth/codegen (eb71af6), and 28 bugs incl. shim semantics/manifest/OAuth/analyze (6e0d73b). - Single source of truth for the default Safari min-version (
45f4d29); removed the scratchscripts/anddocs/dirs (7f971ad); new README ASCII icon (dd17de2).
Theme: sidePanel + action badge fixes.
- Safari
sidePaneltoggle and action-badge init-abort fixes, with 5 extension test reports (4d1109a), see Safari Quirks. - 14 correctness bugs from a deep multi-agent codebase audit (
e5d343b).
Theme: many audit fixes, the Grammarly port-routing rewrite, and the src/ reorg.
The headline work is getting real extensions (Grammarly, uBlock) to actually run on Safari, driven by the port-routing rewrite:
- Rewrite
chrome.runtime.idto the UUID host and strip theruntime.idprefix from port-routing matchers so Safari routes popup↔background ports correctly (362feb9,cc611a3), then remove the now-dead port-clone machinery the matcher rewrite superseded (43047af), see Runtime Shim. Root-cause chain documented inb05abd8. - Supporting shim fixes for the same goal: route popup port by lowercasing
sender.urlhost (e90a45f); forward cloned-port methods bound to the real port for Safari's brand check (7c39c87);defineProperty-wrap nativeonConnect/onMessage/cookiesevents (16eccc6); backfillstorage.session.setAccessLeveland clearruntime.lastErrorso background init can't hang or reject (e0a70ea,f3eb880); carry the httpOnly session cookie through the native-host auth proxy (6071347); guardcookies.onChangedagainst Safari null events (8952cd5); restore resource loading +connect-src 'self'for Grammarly's background init (7debbf8). - Make converted extensions survive Safari's frozen/exotic namespaces and no-
chromeglobals; backfill MV3 enums/storage/userScriptsevents on the resolved namespace (73c1926,ca523e8,b81dda0,1880790); blockingwebRequestdegrades instead of aborting conversion (aa89a20), see Runtime Shim and Analyzer. - Input: descend into the lone manifest-bearing subdir of a repo-style layout (
e64f335); balanced-parenimportScriptsneutralization + DNR path-escape guard (e8830e0). - Large refactor splitting
src/into concern foldersinput/manifest/analyze/runtime/build(a07abde), extracting the shim runtime JS tosrc/runtime/safari-compat-shim.js(2927cdf) and the Safari compat-data tables out ofmanifest.ts(3f919d0); addedCLAUDE.mdarchitecture docs (41779ff). - Final rollup of audit correctness bugs across shim/analyze/manifest/build (
d885422); the release also carries per-extension Safari test reports and a live-testing debug protocol (7bd822d).
Theme: UA-sniffing detection + a bug hunt.
- Detect
navigator.userAgentChrome-version sniffing so the analyzer can warn about it (a534d69), see Analyzer. - Surface shim-emulated APIs in analysis output and fix
pluginkitparsing (30509f8), see Analyzer. - Bug-hunt fixes: 3 conversion bugs (
cef6aee); bundle-id collisions + a symlink leak in staging (b0c81a1); native-proxyResponsecrashes on out-of-range/null-body status (3a16e42); shimfill()no longer clobbers legitimately-falsy native members (273272b); sanitize hosts/origin in generated native-proxy Swift literals (dab04f1); fix report handling of the MV2page_actionfold (72158b8).
Theme: emulate complex Chrome APIs behind a catch-all shim safety net; keyboard-shortcut management.
- Emulate complex Chrome APIs and add a catch-all shim safety net so unknown
chrome.*access degrades gracefully (75d6cd2), see Runtime Shim. - Make keyboard-shortcut management work in Safari, which has no
chrome://extensions/shortcutspage (503e14f), and warn at build time on hardcodedchrome://extensions/shortcuts(orsettings) links (f74597a); documented in the shim feature list (e7d1653), see Safari Quirks. - First real test suite lands and hardens the release:
applyDnr(7e8477d),analyzeManifestCSP/host-misplacement (1156251),scanExtensiondetections (2cc6c34),extract.tsCRX3/zip-slip (748a9eb), plus a DNR keyless-ruleset fix and sidepanel-open test (cd9b73c). - GitHub issue templates for conversion failures, broken extensions, and feature requests (
ed8be98, later trimmed in2d7b4ac).
(This tag range also sweeps up the tail of the README ASCII-banner iteration 700c321→85e408c and the final publishing-pipeline commits 1d728d2→47b3dea, see the v1.2.x note below.)
Theme: the rename to viaduct, @magicelk235 scoping, and the Trusted-Publishing burst.
This is where chrome2safari became viaduct and npm publishing was rebuilt:
- Rename
chrome2safari→viaductacross README, package, CLI, and source (6624163,c497683); scope the package as@magicelk235/viaductand add a release publish workflow (aaa1437); switch to npm Trusted Publishing (OIDC) instead ofNPM_TOKEN(df4346f), see Build and Install. -
Publishing-pipeline hardening (one note for the whole burst). Standing up OIDC Trusted Publishing took an iterative sequence of CI/npmrc fixes,
1197fd9(bump past the burned 1.2.6 publish),a983d3a,2a8ce3f(run onmacos-latest, the package isos:darwin),cca58cd(shell-expanded test glob),1d728d2(pin node, verify npm version),01cc7a7/8073d4e/0dadd91(registry-url and.npmrctoken-auth juggling so OIDC isn't shadowed),6038846/47b3dea(diagnostics added then removed once proven). The 1.2.6/1.2.7 versions were consumed pre-tag; v1.2.8 is the first tag published via Trusted Publishing. - Shim/analyzer work carried in this window: shim
chrome.windows/devtools/appplus a CORS proxy and build-config hardening (8255ebc); first test suite + CI gate with corpus-run bug fixes (0dd9519);oauth-bridgeidempotency, CSP sandbox scoping, optional-perm host warning, CDP MAIN-world eval (0fe0447), see OAuth Bridge; derive extension id generically instead of hardcoding Claude's (208eaa6); two converter-hardening sweeps (0ed107a,7395bec); flag native-messaging usage for Safari (a9c2e80). - Manifest/CLI/analyzer additions earlier in the window: manifest compat transforms + validation + input hardening (
b20954b); CLI lifecycle flags and new compat checks (a40114e,24424b4); completechrome.i18nand harden the runtime shim (1f3af6f); harden staging/extraction/reporting (781b01c). - Popup sizing on Safari iterated toward "floor only, never overrides the app's own size" (
0601904,b33698a,fb05734,bf77318), see Safari Quirks. Service-workerimportScriptshoisted into the background page for a CSP-safe fix (fc49074).
Theme: DNR sanitize, broaden the shim, unified scanner + i18n, packaging robustness.
- Sanitize static DNR rulesets for Safari (
55d8b0e), see Manifest Transform. - Broaden
chrome.*polyfill coverage and fix runtime gaps (a69e926), see Runtime Shim. - Unified scanner with i18n name resolution and richer checks (
744822b), see Analyzer. - Packaging robustness and lockfile sync (
f415d0c); publish-workflow token fix (7dc63b0), and a post-tag URL fix for provenance validation after the repo rename (e1d9317).
Theme: expanded compat analysis, stub no-equivalent namespaces, bundle the polyfill.
- Expand Safari compatibility-analysis coverage (
0d9e8e4), see Analyzer. - Stub no-equivalent
chrome.*namespaces in the compat shim (1232fff), see Runtime Shim. - Bundle
webextension-polyfillforbrowser.*parity (67e2039). - CI to auto-publish to npm with provenance on version tags (
45e6366), the first publishing automation, later replaced by OIDC in the v1.2.x burst.
Theme: the initial converter, made npm-publishable.
The 1.0 line predates tags, it runs from the scaffold at 2fd033c through the v1.0.1 tag. This is the whole first-cut pipeline:
- TypeScript CLI scaffold and workspace hygiene (
2fd033c); shared types and process/IO utilities (ac8f154). - zip/crx/dir extraction with xattr cleanup (
3846882); Safari manifest analysis/transform and a JS API scanner (5103497), see Manifest Transform and Analyzer. - The runtime compatibility shim,
storage.sync,identity,sidePanel,notifications(530a7ed), see Runtime Shim. - Clean asset staging into a persistent output dir (
7f0e825); packager wrapper with built-.appexbundle-id verification (e3e3007); pipeline orchestrator, CLI, reporting, and Safari 18 temp-load (c212d81), see Build and Install. - Safari OAuth bridge, identity polyfill + page bridges (
53b8e3c), see OAuth Bridge; DNR ruleset to pinOriginforapi.anthropic.com(5d1d542); a second runtime shim pass with achrome.debuggerpolyfill and SW→background-page conversion (2b09dd6). - Safari fixes that made the output actually load: extension discovery + popup compatibility (
a3a7ef5), persistent install via team signing + crash fixes (1a6ecef), MV3 non-persistent background + move-not-copy of the built app (bd3bbc7), and the analyze exit code / empty-action injection /debugger.onDetachfixes (146b6ca). - Made the package npm/npx-publishable (
3013af2) and cut the release (c996214).
Viaduct CLI · @magicelk235/viaduct · PolyForm Shield 1.0.0 · Verified against src/ and grounded in git history.