Skip to content

⬆️ chore: Upgrade Click UI, i18next, TypeScript, Vitest and the Dev Tooling to Their New Majors - #194

Open
danny-avila wants to merge 8 commits into
pr/deps-refreshfrom
pr/deps-majors
Open

danny-avila wants to merge 8 commits into
pr/deps-refreshfrom
pr/deps-majors

Conversation

@danny-avila

Copy link
Copy Markdown
Contributor

Pull Request Template

⚠️ Before Submitting a PR, Please Review:

  • Please ensure that you have thoroughly read and understood the Contributing Docs before submitting your Pull Request.

⚠️ Documentation Updates Notice:

  • Kindly note that documentation updates are managed in this repository: librechat.ai

Summary

Takes the major upgrades that the in-range refresh left out: Click UI 0.15, i18next 26 / react-i18next 17, TypeScript 6, Vitest 5, jsdom 30, jest-dom 7, @vitejs/plugin-react 6, lint-staged 17, @tanstack/devtools-vite 0.8, dotenv 18, lucide-react 1.x and @types/node 26. styled-components leaves the tree, because Click UI no longer uses it.

TypeScript 7, js-yaml 5 and mongoose 9 are not upgraded; Not upgraded says why.

Stacked on #189 (the in-range refresh, branch pr/deps-refresh). This PR targets that branch and is built on its head, 4e129c9, so it only adds the eight commits below. Merge #189 first. If #189 is squash-merged, rebase this branch onto main (git rebase --onto main 4e129c9) instead of only retargeting the PR, or #189's two commits come back with it.

There are eight commits, one for each upgrade or group of packages that have to move together. Every commit installs with bun install --frozen-lockfile and passes tsc on its own, so each can be reviewed or reverted separately:

  1. ⬆️ i18next 26 and react-i18next 17, plus a test that renders every translation key
  2. ⬆️ Click UI 0.15.0 and lucide-react 1.61.0 (drops styled-components)
  3. ⬆️ TypeScript 6.0.3, with the two changes TypeScript 7 will also need
  4. ⬆️ Vitest 5, jsdom 30 and jest-dom 7
  5. ⬆️ @vitejs/plugin-react 6
  6. ⬆️ lint-staged 17
  7. ⬆️ @tanstack/devtools-vite 0.8, with its console piping kept off
  8. ⬆️ dotenv 18 and @types/node 26

What moved

Package Before After
@clickhouse/click-ui 0.9.1 0.15.0
styled-components 6.6.0 removed
lucide-react 0.545.0 1.61.0
i18next 25.10.10 26.5.10
react-i18next 16.6.6 17.1.8
typescript 5.9.3 6.0.3
vitest 4.1.12 5.0.5
jsdom 27.4.0 30.1.3
@testing-library/jest-dom 6.10.0 7.0.1
@vitejs/plugin-react 5.2.0 6.1.2
lint-staged 16.4.0 17.6.0
@tanstack/devtools-vite (and its override pin) 0.3.12 0.8.5
dotenv 17.4.2 18.0.9
@types/node 22.20.5 26.6.5

Source and config changes are small:

  • src/start.ts: one type annotation.
  • tsconfig.json: baseUrl removed.
  • vite.config.ts: styled-components removed from optimizeDeps, the devtools option added, and the file Prettier-formatted for the first time.
  • src/styles.css: one Click UI workaround removed.
  • Two tests changed and one test file added.
  • .claude/skills/click-ui.md rewritten so it no longer recommends styled-components, and its examples only use Tailwind for properties Click UI leaves unset.
  • tools/eslint-plugin-click-ui/index.js: the comment on the disabled require-css-import rule now gives the CSS Modules reason instead of styled-components.

i18next 26 and react-i18next 17

react-i18next 17 requires i18next 26.2.0 or newer, so the two move together.

Breaking changes and how they were handled:

  • i18next 26 removes four options: initImmediate, the legacy interpolation.format function, showSupportNotice and simplifyPluralSuffix. src/locales/i18n.ts sets none of them, so no app code changes.
    • With showSupportNotice gone, the Locize notice that i18next 25 printed to the browser console on every page load is gone too. "locize" no longer appears in dist/client.
  • react-i18next 17 changes the key <Trans> generates for kept HTML nodes. The panel doesn't use <Trans>.
  • Dependencies: i18next no longer depends on @babel/runtime. html-parse-stringify moves to 4.0.1, which drops void-elements.

New test src/locales/i18n.test.ts has three cases:

  • Every key in translation.json goes through the app's own i18n instance, with a value for each {{placeholder}}, and must come out as its own text: never its id, never escaped.
  • Every _zero / _one / _other base picks the right form for 0, 1, 2 and 21.
  • useLocalize interpolates and pluralizes.

The test also passes on i18next 25. It fails if escapeValue is set to true or the resources are emptied.

Both packages now accept TypeScript ^5 || ^6 || ^7 as an optional peer.

Click UI 0.9.1 → 0.15.0

I went through every release in between (0.10 to 0.15). None of the API breaks reach this app, so no component code changes:

  • 0.10 drops styled-components and puts all Click UI CSS in one @layer clickui.
    • Nothing here imported styled-components itself: no ThemeProvider bridge, linkStyles or useTheme. It leaves package.json and the Vite optimizeDeps list, and @emotion/*, stylis, camelize and css-to-react-native leave the tree.
    • The layer order in the build and in vite dev is properties, theme, base, components, utilities, clickui. So Click UI still overrides Tailwind's preflight and utilities, as its unlayered CSS did before, and the unlayered rules in styles.css (focus rings, switch and dark-accent tokens) still override Click UI. Every --click-* token the panel overrides still exists in 0.15.
    • Because clickui comes after utilities, a Tailwind class can't override a property Click UI sets. On this branch's build, grid grid-cols-2 on a Tabs.TriggersList still computes to display: flex. The skill doc's Tabs example relied on that override; it now splits the row with flex-1 on each trigger (two 200px triggers in a 400px list) and says to use an unlayered rule in styles.css for anything Click UI already sets.
  • 0.11 moves Radix to its 1.6.7 set. The react-dialog 1.3.1 and dismissable-layer 1.2.1 override pins still leave a single dismissable-layer, and react-popper drops from two copies to one.
  • Type-level breaks in 0.13 and 0.15 touch nothing used here: the DropdownItemProps union, FileTab and Dropdown.Sub props, and Tooltip.Trigger asChild forwarding.
  • 0.13 stops stacking a menu item's icon above its label at 768px and below. The styles.css rule that forced those rows back onto one line is removed. At 390 and 1440 px wide, removing it changed no pixel.
  • Kept: useDialogCloseLabels and useStripAriaExpanded. 0.15 still renders the dialog close button without a name and still puts aria-expanded on the trigger's wrapper.
  • Visible change: 0.15 keeps Dropdown menus 8px from the viewport edge instead of 100px.
    • The user menu now opens about 34px further left, over the icon rail.
    • On a phone, row-action menus are wider and wrap less.
    • Nothing else changed. When this upgrade was compared on its own against the 0.9.1 build (light and dark, 1440 and 390 px wide), 156 of 174 screenshot pairs were pixel-identical. The other 18 were these menus and audit-log loading timing.
  • Cascade layers in vite dev on this branch: properties, theme, base, components, utilities, clickui, the same order as the build.
  • Bundle: across this whole PR, the production client JS and CSS grow from 1,026 kB to 1,088 kB gzipped (+6%). Most of that is new logos and flags in Click UI's icons chunk.

lucide-react 0.545 → 1.61

Nothing in src or e2e imports it. v1 removes the brand icons and sets aria-hidden by default, neither of which matters here. It could be removed outright in a follow-up.

TypeScript 5.9 → 6.0.3

  • baseUrl is deprecated. TypeScript 6 fails on it with TS5101, and 7 removes it (TS5102). It is removed from tsconfig.json.
    • paths already resolve @/* from the tsconfig folder.
    • Vite's own tsconfig paths resolution and vite-tsconfig-paths in Vitest still resolve @/.
  • src/start.ts annotates the CSRF middleware as ReturnType<typeof createCsrfMiddleware>.
    • Without the annotation, the inferred type forms a cycle through the generated Register config in routeTree.gen.ts. TypeScript 7's stable type ordering, and 6.0 with --stableTypeOrdering, report it as TS7022/TS7024.
    • The annotation is type-only, because the return type doesn't depend on the type arguments. tsc --noEmit --stableTypeOrdering passes on this branch.
  • typescript-eslint 8.72 accepts TypeScript >=4.8.4 <6.1.0, so 6.0.3 is inside its range.
  • Built on its own, this commit produced client and server bundles byte-identical to the 5.9 build, apart from absolute paths in the Start manifest.

Vitest 4 → 5

Vitest 5 needs Node 22.12+ and Vite 6.4+. These breaking changes could have affected this suite, and none needed a code change:

  • Mocks are cleared before each test by default.
  • An expect that is never awaited now fails its test.
  • The sequential option is removed.
  • The config file is no longer looked up in ancestor directories.
  • Reporter and attachment output defaults to .vitest/.

155 files and 3,341 tests pass with no unhandled errors.

Vite still warns that vite-tsconfig-paths in vitest.config.ts is no longer needed. #189's branch already shows the same warning.

jsdom 27 → 30

  • 28 rebuilds resource loading on undici. undici 8.12.3 comes back into the tree, as a dev-only dependency of jsdom. ⬆️ chore: Refresh Dependencies Within Their Majors and Clear the Fixable Audit Findings #189 dropped the old 7.29.1 override because nothing used it then.
  • 29 replaces cssstyle with jsdom's own CSSOM. getComputedStyle now reports a textarea's box-sizing as content-box, where 27 returned "".
    • Because of that, react-textarea-autosize now leaves its hidden measuring <textarea> in document.body between tests.
    • One ListField test in collections.test.tsx, "keeps whitespace-only stop sequences", read the first textarea in the document, got that hidden one and failed (expected '\n', got 'x'). It and the test beside it, which read its first value the same way but still passed, now find the item's textarea by its accessible name.
  • 30 requires Node ^22.22.2 || ^24.15.0 || >=26. CI's ubuntu-latest image ships Node 22.23.3.

jest-dom 6 → 7

7.0 makes @testing-library/dom a required peer, and it is already a direct devDependency (10.4.2). It also requires Node 22 or newer. 7.0.1 makes Vitest an optional peer. Nothing else changes.

@vitejs/plugin-react 5 → 6

Version 6 drops Babel. React Refresh is now done by Vite 8's Oxc, and the plugin's babel option is gone. vite.config.ts passes no Babel options, so nothing changes.

Built on its own, this commit produced a production client bundle byte-identical to the one 5.2 builds.

On this branch's vite dev, I edited ToolbarFilter.tsx and then reverted it. Both changes hot-reloaded without a page reload, and the filter text and a window marker survived.

lint-staged 16 → 17

Version 17 needs Node 22.22.1+ and Git 2.32+. It makes yaml optional, which doesn't matter because the config is .lintstagedrc.json. After running its tasks it re-stages the files with git update-index --again instead of git add.

Tried directly when the upgrade was made:

  • A badly formatted staged file was fixed by Prettier and eslint --fix and re-staged.
  • A staged @tanstack/start-server-core import failed the commit, and the original state was restored.

@tanstack/devtools-vite 0.3.12 → 0.8.5

This bumps the devDependency and its override pin together.

Console piping is kept off. 0.8 pipes the server console into the browser and the browser console back to the dev server, both by default. Vite 8 forwards browser warnings and errors to the terminal whenever it runs under a coding agent, so the two feed each other:

  • A single [checkOpenIdFn] warning on /login re-logged itself with a growing [Server] prefix.
  • That produced 150 messages in 10 seconds.

vite.config.ts now calls devtools({ consolePiping: { enabled: false } }). 0.3.12 had no console piping, so this keeps the dev server as it was.

0.8 also moves its event bus to an OS-assigned port when port 42069 is taken. 0.3.12 crashed vite dev with EADDRINUSE whenever another dev server held that port.

Production builds still strip the devtools from __root.tsx, and no devtools code is left in dist/client.

Checked on this branch's vite dev while running under a coding agent:

  • The devtools trigger opens the panel, with its Router and Query plugins.
  • 312 elements carry data-tsd-source.
  • There were no console errors, and the dev log stayed at 3 kB with no [Server] loop.

dotenv 17 → 18

18 removes .env.vault support and preloading with -r dotenv/config, writes its injection message to stderr, and adds a CLI. Nothing in the repo imports or preloads dotenv: Bun and Vite read .env themselves. Like lucide-react, it could be removed in a follow-up.

@types/node 22 → 26

The Docker image runs oven/bun:1.4.3, and its process.version is v26.3.0, so the types now describe the Node API the production runtime reports.

  • undici-types moves from 6.21.0 to 8.9.0, and bun-types (which takes @types/node and undici-types at *) uses the same single copy.
  • server.ts, which tsconfig.json excludes, type-checks against bun types and @types/node 26.
  • Vite 8 and Vitest 5 both accept Node 26 types.

Lockfile

bun.lock stays at "lockfileVersion": 1, the same as main and #189.

  • Wherever two upgrades touched the same part of the lockfile, it was regenerated with bun install from the previous commit's lockfile, never edited by hand. The resolved versions are the ones each upgrade was tested with.
  • bun install kept a stale nested bun-types/undici-types@6.21.0 beside the new 8.9.0. Removing and re-adding @types/bun with Bun let it resolve again to the single 8.9.0 copy.
  • Where git merged a commit's lockfile cleanly, a plain bun install leaves it unchanged. Regenerating it from the previous commit's lockfile gives the same file, except for the Click UI commit, where Bun would pick lucide-react 1.62.0 over the tested 1.61.0.
  • All 53 override pins still resolve to their pinned versions.

Not upgraded

  • TypeScript 7 (7.0.2).

    • typescript-eslint 8.72, the latest release, accepts TypeScript >=4.8.4 <6.1.0. Its parser deliberately throws "typescript-eslint does not support TS 7.0" at load, because 7.0 ships no JavaScript compiler API. There is no 9.x yet, and support is tracked in typescript-eslint#10940.
    • Tested on the TypeScript commit: with its baseUrl and start.ts changes, tsc 7.0.2 passes, and so do vitest and vite build, which don't load typescript at all. Only ESLint fails.
    • i18next 26 and react-i18next 17 already accept TypeScript 7 as a peer.
    • Two ways forward:
      1. Bump the package once typescript-eslint supports 7.
      2. Use Microsoft's side-by-side setup now: "typescript": "npm:@typescript/typescript6@^6.0.2" plus "@typescript/native": "npm:typescript@^7.0.2". With that, tsc, tsc6 and ESLint all passed.
  • js-yaml 5. A migration was built and tested with a small compatibility layer: every input js-yaml 4 accepts reads the same, and output is byte-identical for the existing tests and six real configs. It is not adopted for three reasons:

    1. librechat-data-provider 0.8.524 keeps js-yaml 4 in the client bundle, so the browser would ship both parsers (+17 kB gzipped).
    2. The js-yaml 4.3.2 security override would have to go, because Bun overrides apply to direct dependencies too.
    3. LibreChat itself reads librechat.yaml with js-yaml 4, so staying on 4 is the simplest way to read and write YAML exactly as it does.

    Revisit once librechat-data-provider and LibreChat move to js-yaml 5.

  • mongoose 9. @librechat/data-schemas, both 0.0.74 and the latest 0.0.77, declares a peer dependency on mongoose ^8.24.1, and so does LibreChat. The panel lists mongoose only to pin the patched 8.24.x and never loads it at runtime: neither built bundle imports it. It stays at 8.24.7 until data-schemas widens its range to 9.

  • Unchanged from ⬆️ chore: Refresh Dependencies Within Their Majors and Clear the Fixable Audit Findings #189: zod 3.25.76 under librechat-data-provider, and @librechat/data-schemas 0.0.74. bun audit reports the same single finding as ⬆️ chore: Refresh Dependencies Within Their Majors and Clear the Fixable Audit Findings #189, GHSA-mrhx-c7xc-m3w5 on that zod 3 copy.

  • Newer patches inside the new ranges aren't taken: i18next 26.5.11, react-i18next 17.1.9 and lucide-react 1.62.0. Each upgrade keeps the version it was tested with, and the next in-range refresh will pick these up.

  • Follow-ups, not done here:

    • Remove the unused dotenv and lucide-react.
    • Replace vite-tsconfig-paths with Vite's native resolve.tsconfigPaths.
    • Decide whether the user menu should keep Click UI's new 8px edge padding (collisionPadding on its Dropdown.Content brings back the old position).
    • Turning devtools console piping on would also need server.forwardConsole: false.

Change Type

  • Bug fix (non-breaking change which fixes an issue)

Testing

Each check below exited 0, except bun audit. After this branch moved onto #189's head and the Click UI commit's skill doc and ESLint comment were corrected, I ran them again on the final head. Four I did not repeat: the clean rm -rf node_modules install, the server.ts check, the bun --bun build and the Docker install path. Those ran on the previous head, which differs from this one only in .claude/skills/click-ui.md and that comment.

  • rm -rf node_modules && bun install --frozen-lockfile. The react-movable patch still applies, and a plain bun install leaves bun.lock unchanged.
  • npx tsc --noEmit, and npx tsc --noEmit --stableTypeOrdering.
  • server.ts type-checked separately with "types": ["bun"].
  • npx eslint src/ e2e/ --max-warnings 0
  • bun run format:check, plus prettier --check on every changed file outside src (package.json, tsconfig.json, vite.config.ts, .claude/skills/click-ui.md, tools/eslint-plugin-click-ui/index.js).
  • bun run test:lint-rules: 19 of 19 pass.
  • npx vitest run --maxWorkers=3: 155 files and 3,341 tests pass, with no unhandled errors. That is ⬆️ chore: Refresh Dependencies Within Their Majors and Clear the Fixable Audit Findings #189's 154 files and 3,338 tests plus the new i18n test.
  • bun run build, under Node and under bun --bun (the Docker image builds with Bun). The Docker install path also works: bun install --frozen-lockfile, then --production.
  • Every commit separately, in a scratch worktree: bun install --frozen-lockfile, a bun install --lockfile-only that leaves bun.lock byte-identical, and tsc --noEmit.
  • bun audit exits 1 on the same single zod 3 finding as ⬆️ chore: Refresh Dependencies Within Their Majors and Clear the Fixable Audit Findings #189.

Live click-through

This is the production build (bun server.ts) against a LibreChat backend with existing admin overrides, at 1440px, and I looked at the screenshots.

  • The save and the import ran in light mode.
  • The dark-mode run opened the same review dialog and import preview, then discarded or cancelled them.
  • Every other step ran in both modes.
  • Sign-in: works and lands on /.
  • Configuration:
    • All seven tabs render.
    • I changed OpenAI's stream rate. The review dialog showed 25 (librechat.yaml) → 33. I saved, and the value was still 33 after a reload.
    • A second edit, which I discarded with Discard, left the saved value in place.
  • YAML export (Preview drawer): it renders the merged configuration as YAML, including openAI: streamRate: 33. The page's pointer events come back after it closes.
  • YAML import:
    • I uploaded a .yaml file with startBalance: 0x2710 and prompts: False. The preview showed Starting credits 110,474 → 10,000 and listed prompts as not importable ("managed with role permissions").
    • Importing it showed "Imported 1 value into the base configuration", and the field showed 10,000 with an Admin override badge.
    • Pasted invalid YAML showed "Invalid YAML syntax (line 3, column 1)" with the code frame.
  • Access: the roles list, the Groups tab, and the ADMIN role dialog's Details, Permissions and Members tabs.
  • Users: /users redirects to /, as intended.
  • Grants: the roles list, USER's capability dialog and the audit log.
  • Command menu: opens with Ctrl+K.

Every server-function call answered 200: 114 GETs and 4 POSTs in the run that saved, and 108 GETs and 2 POSTs in each of the others.

The only console error was an avatar URL pointing at a LibreChat on :3080 that wasn't running. Besides that, one run had a single server-function GET aborted by a page navigation.

The Bun-built bundle was served and clicked through the same way.

Playwright e2e (not run by CI)

The whole suite ran against e2e/mock-backend.mjs with --workers=2: 30 passed, 46 failed, 137 skipped. All 46 failures are the access.spec.ts and grants.spec.ts tests that also fail on main: since #185, the mock doesn't serve GET /api/admin/grants/effective, so those pages show "Could not verify permissions". login.spec.ts passes in full, including the 2FA separator test.

I also ran those two specs with #190's mock fix applied locally (not committed): 41 failures, the same count #190 reports for main with that fix.

Test Configuration:

  • Bun 1.4.0 and Node 24.16.0 locally.
  • Production build (bun run build + bun server.ts) with SESSION_COOKIE_SECURE=false over plain HTTP.
  • LibreChat backend from dev (f7a56e8), before the Zod v4 merge.

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

i18next 25.10.10 -> 26.5.10 and react-i18next 16.6.6 -> 17.1.8, resolved with
`--minimum-release-age=86400` like the rest of the refresh, so i18next 26.5.11 and react-i18next
17.1.9 (both from the last day) stay out. react-i18next 17 needs i18next >= 26.2.0, so the two
move together. i18next no longer depends on @babel/runtime, and react-i18next's html-parse-stringify
moves to 4.0.1, which drops void-elements from the tree. i18next-browser-languagedetector 8.2.2
has no i18next peer and works unchanged.

Nothing in the app needed to change. i18next 26 removes initImmediate, the legacy
interpolation.format function, showSupportNotice and simplifyPluralSuffix, none of which
src/locales/i18n.ts sets. The console support notice goes with it: every page load printed the
Locize notice in the browser console before. react-i18next 17's one breaking change is the key
<Trans> generates for kept HTML nodes, and the panel does not use <Trans>.

src/locales/i18n.test.ts renders every key of translation.json through the app's i18n instance
with a value for each {{placeholder}} and expects its own text, so no key can fall back to its id
or come out escaped. It also checks that each _zero/_one/_other base picks the right form for
0, 1, 2 and 21, and that useLocalize interpolates and pluralizes. The test passes on i18next 25 /
react-i18next 16 as well, and fails with escapeValue: true or with empty resources.
Click UI 0.9.1 -> 0.15.0, read through every release in between (0.10.0, 0.11.0, 0.12.0,
0.13.0, 0.14.0, 0.15.0). None of the API breaks reach this app, so no component code changes:

- 0.10 drops styled-components and wraps all Click UI CSS in one `clickui` cascade layer. The
  app never imported styled-components itself (no ThemeProvider bridge, linkStyles or
  useTheme), so it leaves package.json and the Vite optimizeDeps list, and @emotion/*,
  stylis, camelize and css-to-react-native leave the tree. styles.css loads first, so the
  layer order is properties, theme, base, components, utilities, clickui in the build and in
  `vite dev`: Click UI still beats Tailwind utilities and preflight as its unlayered styles
  did, and the unlayered rules in styles.css (focus rings, switch and dark-accent tokens)
  still beat Click UI. Every --click-* token the app overrides still exists in 0.15.
- 0.11 bumps Radix to the 1.6.7 set. The react-dialog 1.3.1 and dismissable-layer 1.2.1
  override pins still leave one dismissable-layer; react-popper now has one copy instead of
  two, and the focus-scope/focus-guards copies nested under menu and popover are the same
  split the tree had before. IconButton, Toast role and Table header changes touch nothing
  the app renders or tests.
- 0.13's DropdownItemProps union, FileTab/Dropdown.Sub prop types and token semicolons, and
  0.15's Tooltip.Trigger asChild forwarding, are unused here.
- 0.13 stops IconWrapper stacking a menu item's icon above its label at 768px and below, so
  the styles.css rule that forced those rows back to one line goes.

The dialog close-button naming and the Dropdown.Trigger aria-expanded workarounds stay: 0.15
still renders the close button unnamed and still puts aria-expanded on the trigger's wrapper.

Visible change: 0.15 keeps Dropdown menus 8px from the viewport edge instead of 100px, so the
user menu opens flush with the left edge (over the icon rail) and, on a phone, row action
menus are wider and wrap less. Checked against the 0.9.1 build on a live stack, light and
dark at 1440 and 390 wide (login and its error, configuration tabs, scope selector, endpoint
drawer and its select, row action menu, preview drawer, provenance hover card, review dialog,
discard toast, Import YAML, access roles/groups, role dialog tabs, delete confirmation, create
role, grants and capability dialog, audit log, date picker, command menu, user menu): 156 of
174 screenshot pairs are pixel-identical; the rest are those menus and audit-log loading
timing. Dropping the menu-row rule changed no pixel at either width. The production client
bundle grows by 62 kB gzipped, mostly new logos and flags in the icons chunk.

lucide-react ^0.545.0 -> ^1.61.0. Nothing in src imports it; v1 drops brand icons and sets
aria-hidden by default, neither of which applies.

Resolved with `bun install --minimum-release-age=86400`; bun.lock keeps lockfileVersion 1.
The .claude click-ui skill no longer tells agents to extend components with styled-components,
and its examples only use Tailwind for properties the clickui layer leaves unset, since a
utility can't override one Click UI sets. The ESLint plugin's comment on the disabled
require-css-import rule now gives the CSS Modules reason.
…ypeScript 7 Compiler

TypeScript 7.0.2 is not adopted: typescript-eslint 8.72 peers on
typescript >=4.8.4 <6.1.0 and its parser throws "typescript-eslint does
not support TS 7.0" at load, because 7.0 ships no JS compiler API.

6.0.3 is inside that range and is the step toward 7:
- Drop baseUrl from tsconfig. 6.0 rejects it as deprecated (TS5101) and
  7.0 removes it (TS5102); paths already resolve from the tsconfig folder.
- Annotate the CSRF middleware in start.ts. Under 7.0's stable type
  ordering (and 6.0 with --stableTypeOrdering) its inferred type cycles
  through the generated Register config (TS7022/TS7024).

The built client and server bundles are byte-identical to the 5.9 build
apart from the start manifest's absolute paths.
jsdom 30 computes box-sizing ("content-box"; 27 returned an empty
string), so react-textarea-autosize now mounts its hidden measuring
textarea in document.body and keeps it there between tests. A
ListField test that read the first textarea in the document got that
one (value "x") instead of the stop sequence; it and the test beside
it now find the item's textarea by its accessible name.

Vitest 5 needs Node 22.12+, jsdom 30 Node 22.22.2+ and jest-dom 7
Node 22+; the ubuntu-latest CI image ships Node 22.23.3.
Version 6 drops its Babel pipeline and leaves the React Refresh
transform to Vite 8's Oxc. The panel passes the plugin no Babel
options, and the production client bundle is byte-identical to the
one 5.2 builds.
Version 17 needs Node 22.22.1+ and Git 2.32+, and makes yaml an
optional dependency. .lintstagedrc.json stays JSON, so nothing else
changes.
… Piping Off

devtools-vite 0.8 pipes server console output into the browser and browser
console output back to the dev server by default. Vite 8 forwards browser
warnings and errors to the terminal whenever it runs under a coding agent, so
the two features feed each other: a single server warning on the login page
re-logs itself with a growing [Server] prefix until the tab closes. 0.3.12 had
no console piping, so turning it off keeps the dev server as it was.

0.8 also moves its event bus to an OS-assigned port when the default one is
taken, where 0.3.12 crashed `vite dev` with EADDRINUSE on port 42069 whenever
a second dev server was already running. Production builds still strip the
devtools from __root.tsx, and the client bundle is byte-identical to 0.3.12's.
…4 Reports

- dotenv ^17.4.2 -> ^18.0.9. Nothing imports it (Bun and Vite load .env
  themselves), so the bump changes no runtime path.
- @types/node ^22.20.5 -> ^26.6.5. The image runs on oven/bun:1.4.3, whose
  process.version is v26.3.0, and bun-types takes @types/node "*"; the
  types now describe the Node API the production runtime reports. Its
  undici-types moves to 8.9.0 and stays a single copy.

Left on their current majors:
- js-yaml 4: librechat-data-provider keeps js-yaml 4 in the client chunk,
  so 5 would ship both parsers (+17 KB gzip), would need the global
  js-yaml 4.3.2 security override dropped, and needs a compat layer to
  read and write YAML as LibreChat's own js-yaml 4 does.
- mongoose 8: @librechat/data-schemas (0.0.74 and the latest 0.0.77) peers
  on mongoose ^8.24.1, as LibreChat itself does; the panel only lists it
  to pin the patched 8.24.x and never loads it at runtime.
@danny-avila

Copy link
Copy Markdown
Contributor Author

@codex review

Pass 1. Head: 6d4c290

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T08:19:38.814571Z 6d4c290 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 6d4c2906f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant