Skip to content

Commit 99cc0ff

Browse files
authored
chore: bump dependencies and update bun (#945)
中文:升级依赖并更新 Bun,同时完成 KaTeX 迁移和安全依赖修复。
1 parent 4bad6a9 commit 99cc0ff

14 files changed

Lines changed: 581 additions & 484 deletions

‎bun.lock‎

Lines changed: 417 additions & 418 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,31 +50,27 @@
5050
},
5151
"devDependencies": {
5252
"@babel/core": "^8.0.1",
53-
"@types/node": "^26.2.0",
53+
"@types/node": "^26.4.0",
5454
"is-ci": "^4.1.0",
5555
"lefthook": "^2.1.10",
56-
"oxfmt": "^0.63.0",
57-
"oxlint": "^1.78.0",
56+
"oxfmt": "^0.65.0",
57+
"oxlint": "^1.80.0",
5858
"rimraf": "^6.1.3",
5959
"typescript": "^6.0.3",
60-
"vite": "^8.2.1"
60+
"vite": "^8.2.2"
6161
},
6262
"overrides": {
63-
"brace-expansion": "5.0.9",
64-
"dompurify": "3.4.13",
65-
"fast-uri": "4.1.2",
66-
"hono": "4.13.2",
67-
"ip-address": "10.5.0",
68-
"js-yaml": "3.15.1",
69-
"jsdom": "30.0.1",
70-
"nanoid": "3.3.18",
71-
"undici": "8.10.0"
63+
"brace-expansion@>=4.0.0 <5.0.9": "5.0.9",
64+
"fast-uri@>=4.0.0 <4.1.2": "4.1.2",
65+
"js-yaml@>=3.0.0 <3.15.1": "3.15.1",
66+
"nanoid@>=3.0.0 <3.3.18": "3.3.18",
67+
"undici@>=6.0.0 <6.28.0": "6.28.0"
7268
},
7369
"engines": {
74-
"bun": ">=1.3.14",
70+
"bun": ">=1.4.0",
7571
"node": ">=24.11.0"
7672
},
77-
"packageManager": "bun@1.3.14",
73+
"packageManager": "bun@1.4.0",
7874
"trustedDependencies": [
7975
"@posthog/cli",
8076
"core-js",

‎packages/app/package.json‎

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
"dependencies": {
3636
"@chenglou/pretext": "^0.0.8",
3737
"@jpinsonneau/html-to-image": "^1.11.13",
38-
"@noble/ciphers": "^2.3.0",
39-
"@posthog/nextjs-config": "^1.9.69",
38+
"@noble/ciphers": "^2.4.0",
39+
"@posthog/nextjs-config": "^1.10.0",
4040
"@radix-ui/react-dialog": "^1.1.23",
4141
"@radix-ui/react-label": "^2.1.15",
4242
"@radix-ui/react-popover": "^1.1.23",
@@ -50,46 +50,48 @@
5050
"@semianalysisai/inferencex-db": "workspace:*",
5151
"@shikijs/rehype": "^4.4.3",
5252
"@tailwindcss/typography": "^0.5.20",
53-
"@tanstack/react-query": "^5.101.4",
53+
"@tanstack/react-query": "^5.102.8",
5454
"@vercel/analytics": "^2.0.1",
5555
"@vercel/blob": "^2.8.0",
5656
"@vercel/speed-insights": "^2.0.0",
5757
"adm-zip": "^0.6.0",
5858
"class-variance-authority": "^0.7.1",
5959
"clsx": "^2.1.1",
6060
"d3": "^7.9.0",
61-
"dompurify": "^3.4.13",
61+
"dompurify": "^3.4.14",
6262
"gray-matter": "^4.0.3",
63+
"hast-util-from-html-isomorphic": "^2.0.0",
64+
"hast-util-to-text": "^4.0.2",
6365
"iwanthue": "^2.1.0",
64-
"katex": "^0.16.47",
65-
"lucide-react": "^1.31.0",
66+
"katex": "^0.18.4",
67+
"lucide-react": "^1.34.0",
6668
"mp4-muxer": "^5.2.2",
67-
"next": "^16.3.1",
69+
"next": "^16.3.3",
6870
"next-mdx-remote": "^6.0.0",
6971
"next-themes": "^0.4.6",
70-
"posthog-js": "^1.407.2",
72+
"posthog-js": "^1.422.0",
7173
"react": "^19.2.8",
7274
"react-dom": "^19.2.8",
73-
"rehype-katex": "^7.0.1",
7475
"remark-gfm": "^4.0.1",
7576
"remark-math": "^6.0.0",
7677
"shiki": "^4.4.3",
7778
"tailwind-merge": "^3.6.0",
78-
"three": "^0.185.1"
79+
"three": "^0.185.1",
80+
"unist-util-visit-parents": "^6.0.2"
7981
},
8082
"devDependencies": {
8183
"@bahmutov/cypress-esbuild-preprocessor": "^2.2.8",
8284
"@tailwindcss/postcss": "^4.3.3",
8385
"@types/adm-zip": "^0.5.8",
8486
"@types/d3": "^7.4.3",
8587
"@types/mdast": "^4.0.4",
86-
"@types/node": "^26.2.0",
87-
"@types/react": "19.2.17",
88-
"@types/react-dom": "19.2.3",
88+
"@types/node": "^26.4.0",
89+
"@types/react": "19.2.18",
90+
"@types/react-dom": "19.2.5",
8991
"@types/three": "^0.185.4",
90-
"@vitest/coverage-v8": "^4.1.10",
92+
"@vitest/coverage-v8": "^4.1.11",
9193
"axe-core": "^4.13.0",
92-
"cypress": "15.19.0",
94+
"cypress": "15.21.1",
9395
"cypress-axe": "^1.7.0",
9496
"cypress-split": "^1.25.0",
9597
"esbuild": "^0.28.2",
@@ -98,10 +100,11 @@
98100
"tailwindcss": "^4.3.3",
99101
"tw-animate-css": "^1.4.0",
100102
"typescript": "^6.0.3",
101-
"vitest": "^4.1.10"
103+
"vfile": "^6.0.3",
104+
"vitest": "^4.1.11"
102105
},
103106
"engines": {
104-
"bun": ">=1.3.14",
107+
"bun": ">=1.4.0",
105108
"node": ">=24.11.0"
106109
}
107110
}

‎packages/app/src/components/reliability/ReliabilityContext.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ export function aggregateByDateRange(rows: ReliabilityRow[]): DateRangeSuccessRa
4949
const rowTime = new Date(row.date).getTime();
5050
for (const [range, cutoff] of ranges) {
5151
if (cutoff !== null && rowTime < cutoff) continue;
52-
const stats = (aggregates[range][row.hardware] ??= { n_success: 0, total: 0 });
52+
aggregates[range][row.hardware] ??= { n_success: 0, total: 0 };
53+
const stats = aggregates[range][row.hardware];
5354
stats.n_success += row.n_success;
5455
stats.total += row.total;
5556
}

‎packages/app/src/components/ui/badge.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function Badge({
3030
asChild = false,
3131
...props
3232
}: React.ComponentProps<'span'> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
33-
const Comp = asChild ? Slot : 'span';
33+
const Comp: React.ElementType = asChild ? Slot : 'span';
3434

3535
return (
3636
<Comp data-slot="badge" className={cn(badgeVariants({ variant }), className)} {...props} />

‎packages/app/src/components/ui/button.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ function Button({
4242
VariantProps<typeof buttonVariants> & {
4343
asChild?: boolean;
4444
}) {
45-
const Comp = asChild ? Slot : 'button';
45+
const Comp: React.ElementType = asChild ? Slot : 'button';
4646

4747
return (
4848
<Comp

‎packages/app/src/lib/blog-mdx.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { compileMDX } from 'next-mdx-remote/rsc';
22
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';
3-
import rehypeKatex from 'rehype-katex';
43
import remarkGfm from 'remark-gfm';
54
import remarkMath from 'remark-math';
65
import { createHighlighterCore } from 'shiki/core';
@@ -9,6 +8,7 @@ import type { HighlighterCore } from 'shiki/types';
98

109
import { createMdxComponents } from '@/components/blog/mdx-components';
1110
import type { BlogLocale } from '@/lib/blog';
11+
import { rehypeKatex } from '@/lib/rehype-katex';
1212

1313
let highlighterPromise: Promise<HighlighterCore> | null = null;
1414

‎packages/app/src/lib/katex-css-version.test.ts‎

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,14 @@ import path from 'node:path';
44
import { describe, expect, it } from 'vitest';
55

66
/**
7-
* The blog post pages import `katex/dist/katex.min.css` from the top-level `katex`
8-
* dependency, but the HTML those styles have to match is generated by whatever `katex`
9-
* copy `rehype-katex` resolves. If the two drift apart the math still renders — it just
10-
* renders unstyled, because KaTeX renames layout classes across majors (0.16 emits
11-
* `.base` / `.strut`; 0.18 renamed them to `.katex-base` / `.katex-strut`).
12-
*
13-
* Bumping `katex` past what `rehype-katex` supports must fail here, not in review.
7+
* Blog post pages import `katex/dist/katex.min.css`, and the local rehype
8+
* renderer imports the same top-level KaTeX package. Keep the generated layout
9+
* classes aligned with that stylesheet across future KaTeX majors.
1410
*/
1511

1612
const appRequire = createRequire(import.meta.url);
17-
const rendererRequire = createRequire(appRequire.resolve('rehype-katex'));
18-
19-
const katexVersion = (require_: NodeJS.Require) =>
20-
(require_('katex/package.json') as { version: string }).version;
2113

2214
describe('KaTeX CSS matches the KaTeX that renders the HTML', () => {
23-
it('resolves the same katex version for the stylesheet and the renderer', () => {
24-
expect(katexVersion(rendererRequire)).toBe(katexVersion(appRequire));
25-
});
26-
2715
it('styles the layout classes the renderer actually emits', async () => {
2816
const katexModule = await import('katex');
2917
const katex = katexModule.default;
@@ -41,10 +29,9 @@ describe('KaTeX CSS matches the KaTeX that renders the HTML', () => {
4129
);
4230
expect(emitted).toContain('katex');
4331

44-
// `base` and `strut` are the classes that silently changed name in 0.18. Asserting
45-
// the renderer still emits them is the other half of the guard: if a future version
46-
// renames them, the CSS check below would pass vacuously.
47-
for (const cls of ['base', 'strut']) {
32+
// These layout classes were prefixed in KaTeX 0.18. Assert both sides so
33+
// a future rename cannot make the stylesheet check pass vacuously.
34+
for (const cls of ['katex-base', 'katex-strut']) {
4835
expect([...emitted], `expected the renderer to emit .${cls}`).toContain(cls);
4936
expect(css, `renderer emits .${cls} but the CSS never styles it`).toContain(`.${cls}`);
5037
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { fromHtmlIsomorphic } from 'hast-util-from-html-isomorphic';
2+
import { toText } from 'hast-util-to-text';
3+
import katex, { type KatexOptions } from 'katex';
4+
import { SKIP, visitParents } from 'unist-util-visit-parents';
5+
import type { VFile } from 'vfile';
6+
7+
type Options = Omit<KatexOptions, 'displayMode' | 'throwOnError'>;
8+
type HastNode = Parameters<typeof toText>[0];
9+
type Root = Extract<HastNode, { type: 'root' }>;
10+
type ElementContent = Extract<HastNode, { type: 'element' }>['children'][number];
11+
12+
function parseKaTeXHtml(html: string): ElementContent[] {
13+
return fromHtmlIsomorphic(html, { fragment: true }).children.filter(
14+
(child: HastNode): child is ElementContent => child.type !== 'doctype',
15+
);
16+
}
17+
18+
const EMPTY_OPTIONS: Readonly<Options> = {};
19+
const EMPTY_CLASSES: readonly unknown[] = [];
20+
21+
/**
22+
* Render the math nodes produced by remark-math with the app's direct KaTeX version.
23+
* rehype-katex 7 is intentionally not used because it pins KaTeX 0.16 and emits
24+
* layout classes that do not match the KaTeX 0.18 stylesheet.
25+
*/
26+
export function rehypeKatex(options?: Readonly<Options> | null) {
27+
const settings = options ?? EMPTY_OPTIONS;
28+
29+
return (tree: Root, file: VFile) => {
30+
visitParents(tree, 'element', (element, parents) => {
31+
const classes = Array.isArray(element.properties.className)
32+
? element.properties.className
33+
: EMPTY_CLASSES;
34+
const languageMath = classes.includes('language-math');
35+
const mathDisplay = classes.includes('math-display');
36+
const mathInline = classes.includes('math-inline');
37+
let displayMode = mathDisplay;
38+
39+
if (!languageMath && !mathDisplay && !mathInline) return;
40+
41+
let parent = parents.at(-1);
42+
let scope = element;
43+
44+
if (
45+
element.tagName === 'code' &&
46+
languageMath &&
47+
parent?.type === 'element' &&
48+
parent.tagName === 'pre'
49+
) {
50+
scope = parent;
51+
parent = parents.at(-2);
52+
displayMode = true;
53+
}
54+
55+
if (!parent) return;
56+
57+
const value = toText(scope, { whitespace: 'pre' });
58+
let result: ElementContent[];
59+
60+
try {
61+
result = parseKaTeXHtml(
62+
katex.renderToString(value, {
63+
...settings,
64+
displayMode,
65+
throwOnError: true,
66+
}),
67+
);
68+
} catch (error) {
69+
const cause = error as Error;
70+
file.message('Could not render math with KaTeX', {
71+
ancestors: [...parents, element],
72+
cause,
73+
place: element.position,
74+
ruleId: cause.name.toLowerCase(),
75+
source: 'rehype-katex',
76+
});
77+
78+
try {
79+
result = parseKaTeXHtml(
80+
katex.renderToString(value, {
81+
...settings,
82+
displayMode,
83+
strict: 'ignore',
84+
throwOnError: false,
85+
}),
86+
);
87+
} catch {
88+
result = [
89+
{
90+
type: 'element',
91+
tagName: 'span',
92+
properties: {
93+
className: ['katex-error'],
94+
style: `color:${settings.errorColor ?? '#cc0000'}`,
95+
title: String(error),
96+
},
97+
children: [{ type: 'text', value }],
98+
},
99+
];
100+
}
101+
}
102+
103+
const index = parent.children.indexOf(scope);
104+
parent.children.splice(index, 1, ...result);
105+
return SKIP;
106+
});
107+
};
108+
}

‎packages/constants/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"test:unit:coverage": "vitest run --coverage"
1414
},
1515
"devDependencies": {
16-
"@vitest/coverage-v8": "^4.1.10",
17-
"vitest": "^4.1.10"
16+
"@vitest/coverage-v8": "^4.1.11",
17+
"vitest": "^4.1.11"
1818
}
1919
}

0 commit comments

Comments
 (0)