GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — trigger.dev/patches at main · triggerdotdev/trigger.dev

Expand file tree

/

patches

/
Copy path

Directory actions

More options

More options

Directory actions

More options

More options

Latest commit

 

History

History
History
/

patches

/
Copy path

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
@[email protected]
@[email protected]
 
 
@[email protected]
@[email protected]
 
 
@[email protected]
@[email protected]
 
 
@[email protected]
@[email protected]
 
 
@[email protected]
@[email protected]
 
 
@[email protected]
@[email protected]
 
 
@upstash__ratelimit.patch
@upstash__ratelimit.patch
 
 
@[email protected]
@[email protected]
 
 
README.md
README.md
 
 
[email protected]
[email protected]
 
 
[email protected]
[email protected]
 
 
[email protected]
[email protected]
 
 
[email protected]
[email protected]
 
 

README.md

Outline

Patches

This directory holds pnpm patches applied on install via pnpm.patchedDependencies in the root package.json. Each .patch is a diff against the published package. Most are small and self-explanatory from the diff; the non-obvious ones are documented below.


@remix-run/[email protected] — route-matching memoization

File: patches/@[email protected] (patches dist/router.cjs.js)

What it does

Four changes to matchRoutesImpl / compilePath, all derived from work that depends only on the static route manifest:

  1. Cache flattened + ranked branches per route-tree (WeakMap keyed by the routes ref). flattenRoutes() + rankRouteBranches() were recomputed on every matchRoutes call across all ~436 webapp routes.

  2. Hoist decodePath(pathname) out of the branch-match loop — it's loop-invariant but was recomputed once per branch.

  3. Memoize compilePath compiled regexes by path|caseSensitive|end (bounded Map, cap 2000). The matcher RegExp was rebuilt on every matchPath call.

  4. Bucket ranked branches by first static path segment (WeakMap keyed by the branch array). Even with (1)–(3), matching was still a linear scan calling matchPath on every branch until one matched — O(route table) per request, now across 521 route files. Branches are indexed by their lowercased leading segment, with one always-considered list for branches whose leading segment is dynamic, splat or optional (and for root/pathless paths). A request walks only its own bucket merged with that list.

    Ordering is preserved exactly: both lists hold indexes into the already rank-sorted branch array and are walked in ascending-index order, so the first match found is the same branch the full scan would have found. Bucketing lowercases on both sides, so case-insensitive matching still resolves and caseSensitive: true routes are still rejected by matchPath itself. A pathname whose own leading segment can't be bucketed falls back to the full scan.

    Verified equivalent to the unpatched matcher over 20,050 pathnames (literal, dynamic, splat, optional, case variants, basenames, percent-encoded). The semantics it depends on are pinned by apps/webapp/test/routeMatchingPatch.test.ts, which asserts matching behaviour rather than the optimisation, so it still passes without the patch.

Why

Profiling the realtime runs feed under load (100 concurrent tag feeds, ~425 req/s) found ~68% of webapp CPU was spent in react-router's matchRoutes — re-flattening, re-ranking, and re-compiling the entire route table on every request. It is not a dev artifact: there is no NODE_ENV gate, and a NODE_ENV=production profile was identical (67.9% vs 68.3%). The realtime feed's high request rate (each long-poll returns fast and immediately re-polls) just amplifies a latent per-request cost that large route tables pay everywhere.

Measured on a single instance, same load, before vs after this patch:

before after
active CPU (self-time / window) 28.3s 18.5s (−34%)
route-matching self-time 19.2s 7.5s (−61%)
event-loop lag p99 322ms 113ms (−65%)
idle headroom 26% 52%

The realtime machinery itself (router/hydrate/serialize/diff) was ~0% — the bottleneck was entirely generic Remix request overhead.

Change (4) was added later, from a CPU audit of the engine-facing worker-action routes (apps/webapp/test/bench). With (1)–(3) already in place, route matching was still 10.4% of on-CPU time on that path — the residual linear scan rather than any recompilation. Bucketing took route-matching self-time from 3.6s to 1.3s (−64%) over a 90s window at ~300 req/s.

Upstream status (why we patch instead of upgrade)

This is a known, acknowledged inefficiency, and it is only partially fixed in React Router v7 — which we can't adopt without a full Remix 2 → RR7 framework migration.

  • Issue #8653 "Performance issues" reported it (a user with 12k routes, ~67ms per match) and was closed as a dup of the route-ranking discussion remix#4786.
  • PR #14866 "Optimize route matching performance with caching" implemented exactly this patch (hoist decodePath, cache compilePath, cache flatten/rank), claiming ~80% route-matching CPU reduction on a 400+ route app. It was closed, not merged.
  • PR #14967 "perf: cache flattened/ranked route branches" is the partial fix that did ship (in v7): it caches only the branches, threaded via a precomputedBranches param through the framework's server-runtime (~15% SSR gain). It does not cache compilePath — that regex rebuild remains even on main. (PR #14971 added client-side wins.)

The maintainer's reasoning for closing the fuller PR (#14866), verbatim:

"This is great as a patch-package optimization for those who want it, but we are actively working on integrating the more performant route-pattern library from Remix 3 so we'd rather just do the right 'fix' and ship the new algorithm instead of trying to band-aide perf improvements to the existing algorithm which was written with a very different set of constraints. Those constraints come from early v6 when it was only declarative mode so route trees were defined at render time and thus had to be re-flattened/re-ranked/re-compiled every time."

So: the re-compute-everything design is a holdover from early React Router v6 declarative mode (route trees defined at render time, so recomputing was correct then). The maintainer explicitly endorsed patch-package as the interim approach and is betting on the Remix 3 route-pattern rewrite for the real fix. This patch is that sanctioned stopgap — and it also includes the compilePath cache the merged PR left on the table.

Safety

Pure memoization of deterministic, internal-only values:

  • flattenRoutes/rankRouteBranches and the compiled regexes depend solely on the static route manifest; the cached values are never returned to or mutated by the framework.
  • The compiled RegExp has no /g flag, so .exec() carries no cross-call state — safe to share under concurrency.
  • The branch cache is a WeakMap (collected with its route tree); the compile cache is bounded at 2000 entries (route patterns are a static set; the cap only guards any dynamic matchPath() use).
  • Targets the CJS build (dist/router.cjs.js), which the webapp server loads at runtime (@remix-run/router is not bundled into the server build).

When to remove

Drop this patch if/when the webapp moves to React Router v7+ (which threads precomputedBranches itself) or the Remix 3 route-pattern matcher lands. Re-profile at that point — the compilePath cache may still be worth keeping since upstream never added it.


@ai-sdk/[email protected]: send tool_choice: none with the tools

File: patches/@[email protected] (patches dist/index.* and dist/internal/index.*)

The provider maps toolChoice: "none" to sending no tools at all. The Messages API accepts tool_choice: {"type": "none"} with the tools declared, and models with preserved thinking (Claude Sonnet 5.5, Opus 5.5, Fable 5.1) need that: their thinking blocks are bound to the tool list they were produced with, so a request that drops the tools invalidates the conversation's earlier reasoning. The dashboard agent's wake turns rely on it. The patch returns the prepared tools with { type: "none" } instead. @ai-sdk/amazon-bedrock/anthropic reuses this model, so Bedrock gets the same behavior. internal-packages/dashboard-agent/src/provider-wire.test.ts fails if the patch is lost; drop the patch once the provider sends none upstream.

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.