You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
CLI: Shorten CTA link messages - #34236, thanks @shilman!
React Native Web: Fix vite8 support by bumping vite-plugin-rnw - #34231, thanks @dannyhw!
Commit history:
78e439 Merge pull request #35017 from storybookjs/norbert/service-clients
Open Service: Add sync between server, manager and preview
ccccfc ci: retry CircleCI after flaky portable-react E2E
The save-from-controls Playwright test failed once in CI with stale preview
text, but passes consistently locally (including CI=true). Retrigger checks.
57ab83 refactor(open-service): schema-validate channel payloads and constrain state to objects
Replace hand-rolled channel-payload parsers with Valibot schemas in
service-channel.ts; derive payload types from the schemas and narrow with
v.safeParse in the transport (removes the duplicated parse/isRecord helpers).
Constrain service state to a plain object at the defineService boundary via
a ServiceState type (rejects primitives, null, and arrays), matching the
deep-signal / deep-reconcile requirements. Add type tests and document it.
Co-authored-by: Cursor <cursoragent@cursor.com>
743764 refactor(open-service): tidy channel transport, deps, and query hook types
Consolidate channel wiring behind a single connectServiceToChannel entry
point and capture one channel reference (removes a broadcast/listener
channel-divergence hazard).
Use nanoid for the identity-critical client/call id instead of Math.random.
Drop spurious as unknown as Channel casts in the addon stores.
Move @preact/signals-core and deepsignal to devDependencies so they are
bundled into core's dist (fixes resolution in symlinked sandboxes).
Fix useServiceQuery input typing by inferring TInput/TOutput as direct type
parameters so the void-vs-input arg branch reads the concrete query type.
Co-authored-by: Cursor <cursoragent@cursor.com>
191b31 Merge branch 'next' into norbert/service-clients
Resolve docgen service conflicts by adopting next's id-based API and
getDocgenForAllComponents while keeping load hooks on the service
definition per the restricted registration model on this branch.
ef9f32 Merge pull request #35068 from storybookjs/norbert/remote-command-execution
OpenService: Implement remote command execution
1bf407 Bump version from "10.5.0-alpha.4" to "10.5.0-alpha.5" [skip ci]
9e2e92 Merge pull request #35038 from storybookjs/version-non-patch-from-10.5.0-alpha.4
Release: Prerelease 10.5.0-alpha.5
2ddbc3 Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
Core: Add ref-based components manifest index backed by docgen open service
e28303 Write changelog for 10.5.0-alpha.5 [skip ci]
b4903c CI: Add missing status to dangerjs for prerelease PR
903f5d Merge branch 'next' into jeppe-cursor/39213f22
Resolve conflicts in docgen server tests and buildReactComponentDocgen
by keeping the ref-manifest branch behavior (no toReactComponentManifest).
Co-authored-by: Cursor <cursoragent@cursor.com>
88819e Merge pull request #34963 from storybookjs/claude/docgen-phase-3-rcm-provider
Docgen: Wire up react-component-meta with DocgenService
3fd0cb Merge branch 'next' into claude/docgen-phase-3-rcm-provider
2e90f3 Fix format and DocgenPayload type compatibility
Apply oxfmt fixes and align ReactComponentManifest with DocgenPayload via
index signatures. Narrow reactComponentMeta in buildDocgen tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
1c9857 Omit empty subcomponents from manifest output
toReactComponentManifest was always setting subcomponents: undefined when
there were none, which broke generator.test.ts inline snapshots and
diverged from buildReactComponentDocgenFromResolved (which omits the key).
Also clarify preset comments to use componentMetaManager naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
10386a Merge pull request #34496 from NYCU-Chung/fix/docs-blocks-custom-mdx
Addon Docs: Fix Primary and Controls blocks not rendering in custom MDX pages
333f57 Merge branch 'norbert/remote-command-execution' of github.com:storybookjs/storybook into norbert/remote-command-execution
434e66 Refactor: Improve documentation for remote command execution in README
Enhanced the README documentation for the remote command execution section, clarifying the roles of requester and responder, the command invocation process, and the event structure. This update aims to provide clearer guidance on how commands are executed across different runtimes, improving overall understanding for developers.
747b49 Merge branch 'norbert/service-clients' into norbert/remote-command-execution
d25d87 Merge pull request #35056 from DevLikhith5/fix/canvas-wrap-firefox-esr-33743
Preview: Use width/height instead of min-* in CanvasWrap
17fa0b Build components.html from docgen snapshots instead of re-extracting
Read docgen payloads once from the static service snapshots and reuse them for
both the ref-based components.json index and the HTML debugger. Dev still
renders from the live docgen service.
Remove the unused JSON-Ref resolver/dereferencer (no in-repo consumer), simplify the
snapshot loader to a direct typed read, and rename json-references.ts to
components-ref-manifest.ts. Dedup the per-operation story-index walk in manifests.ts by
threading manifest entries through, and inline the trivial fs wrappers.
Co-authored-by: Cursor <cursoragent@cursor.com>
3269f9 Fix docgen server test for last-wins component entry selection
extractDocgen now resolves a componentId via selectComponentEntriesByComponentId
(last-wins), matching the manifest. Update the server test to expect the later
story entry when multiple stories share the same componentId.
Co-authored-by: Cursor <cursoragent@cursor.com>
133606 Refactor: Standardize channel options handling in PostMessageTransport and WebsocketTransport
Updated both PostMessageTransport and WebsocketTransport classes to utilize a local CHANNEL_OPTIONS constant instead of directly referencing globalThis.CHANNEL_OPTIONS. This change improves code clarity and consistency in accessing channel options across the transport implementations.
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
CLI: Shorten CTA link messages - #34236, thanks @shilman!
React Native Web: Fix vite8 support by bumping vite-plugin-rnw - #34231, thanks @dannyhw!
Commit history:
78e439 Merge pull request #35017 from storybookjs/norbert/service-clients
Open Service: Add sync between server, manager and preview
ccccfc ci: retry CircleCI after flaky portable-react E2E
The save-from-controls Playwright test failed once in CI with stale preview
text, but passes consistently locally (including CI=true). Retrigger checks.
57ab83 refactor(open-service): schema-validate channel payloads and constrain state to objects
Replace hand-rolled channel-payload parsers with Valibot schemas in
service-channel.ts; derive payload types from the schemas and narrow with
v.safeParse in the transport (removes the duplicated parse/isRecord helpers).
Constrain service state to a plain object at the defineService boundary via
a ServiceState type (rejects primitives, null, and arrays), matching the
deep-signal / deep-reconcile requirements. Add type tests and document it.
Co-authored-by: Cursor <cursoragent@cursor.com>
743764 refactor(open-service): tidy channel transport, deps, and query hook types
Consolidate channel wiring behind a single connectServiceToChannel entry
point and capture one channel reference (removes a broadcast/listener
channel-divergence hazard).
Use nanoid for the identity-critical client/call id instead of Math.random.
Drop spurious as unknown as Channel casts in the addon stores.
Move @preact/signals-core and deepsignal to devDependencies so they are
bundled into core's dist (fixes resolution in symlinked sandboxes).
Fix useServiceQuery input typing by inferring TInput/TOutput as direct type
parameters so the void-vs-input arg branch reads the concrete query type.
Co-authored-by: Cursor <cursoragent@cursor.com>
191b31 Merge branch 'next' into norbert/service-clients
Resolve docgen service conflicts by adopting next's id-based API and
getDocgenForAllComponents while keeping load hooks on the service
definition per the restricted registration model on this branch.
ef9f32 Merge pull request #35068 from storybookjs/norbert/remote-command-execution
OpenService: Implement remote command execution
1bf407 Bump version from "10.5.0-alpha.4" to "10.5.0-alpha.5" [skip ci]
9e2e92 Merge pull request #35038 from storybookjs/version-non-patch-from-10.5.0-alpha.4
Release: Prerelease 10.5.0-alpha.5
2ddbc3 Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
Core: Add ref-based components manifest index backed by docgen open service
e28303 Write changelog for 10.5.0-alpha.5 [skip ci]
b4903c CI: Add missing status to dangerjs for prerelease PR
903f5d Merge branch 'next' into jeppe-cursor/39213f22
Resolve conflicts in docgen server tests and buildReactComponentDocgen
by keeping the ref-manifest branch behavior (no toReactComponentManifest).
Co-authored-by: Cursor <cursoragent@cursor.com>
88819e Merge pull request #34963 from storybookjs/claude/docgen-phase-3-rcm-provider
Docgen: Wire up react-component-meta with DocgenService
3fd0cb Merge branch 'next' into claude/docgen-phase-3-rcm-provider
2e90f3 Fix format and DocgenPayload type compatibility
Apply oxfmt fixes and align ReactComponentManifest with DocgenPayload via
index signatures. Narrow reactComponentMeta in buildDocgen tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
1c9857 Omit empty subcomponents from manifest output
toReactComponentManifest was always setting subcomponents: undefined when
there were none, which broke generator.test.ts inline snapshots and
diverged from buildReactComponentDocgenFromResolved (which omits the key).
Also clarify preset comments to use componentMetaManager naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
10386a Merge pull request #34496 from NYCU-Chung/fix/docs-blocks-custom-mdx
Addon Docs: Fix Primary and Controls blocks not rendering in custom MDX pages
333f57 Merge branch 'norbert/remote-command-execution' of github.com:storybookjs/storybook into norbert/remote-command-execution
434e66 Refactor: Improve documentation for remote command execution in README
Enhanced the README documentation for the remote command execution section, clarifying the roles of requester and responder, the command invocation process, and the event structure. This update aims to provide clearer guidance on how commands are executed across different runtimes, improving overall understanding for developers.
747b49 Merge branch 'norbert/service-clients' into norbert/remote-command-execution
d25d87 Merge pull request #35056 from DevLikhith5/fix/canvas-wrap-firefox-esr-33743
Preview: Use width/height instead of min-* in CanvasWrap
17fa0b Build components.html from docgen snapshots instead of re-extracting
Read docgen payloads once from the static service snapshots and reuse them for
both the ref-based components.json index and the HTML debugger. Dev still
renders from the live docgen service.
Remove the unused JSON-Ref resolver/dereferencer (no in-repo consumer), simplify the
snapshot loader to a direct typed read, and rename json-references.ts to
components-ref-manifest.ts. Dedup the per-operation story-index walk in manifests.ts by
threading manifest entries through, and inline the trivial fs wrappers.
Co-authored-by: Cursor <cursoragent@cursor.com>
3269f9 Fix docgen server test for last-wins component entry selection
extractDocgen now resolves a componentId via selectComponentEntriesByComponentId
(last-wins), matching the manifest. Update the server test to expect the later
story entry when multiple stories share the same componentId.
Co-authored-by: Cursor <cursoragent@cursor.com>
133606 Refactor: Standardize channel options handling in PostMessageTransport and WebsocketTransport
Updated both PostMessageTransport and WebsocketTransport classes to utilize a local CHANNEL_OPTIONS constant instead of directly referencing globalThis.CHANNEL_OPTIONS. This change improves code clarity and consistency in accessing channel options across the transport implementations.
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
CLI: Shorten CTA link messages - #34236, thanks @shilman!
React Native Web: Fix vite8 support by bumping vite-plugin-rnw - #34231, thanks @dannyhw!
Commit history:
78e439 Merge pull request #35017 from storybookjs/norbert/service-clients
Open Service: Add sync between server, manager and preview
ccccfc ci: retry CircleCI after flaky portable-react E2E
The save-from-controls Playwright test failed once in CI with stale preview
text, but passes consistently locally (including CI=true). Retrigger checks.
57ab83 refactor(open-service): schema-validate channel payloads and constrain state to objects
Replace hand-rolled channel-payload parsers with Valibot schemas in
service-channel.ts; derive payload types from the schemas and narrow with
v.safeParse in the transport (removes the duplicated parse/isRecord helpers).
Constrain service state to a plain object at the defineService boundary via
a ServiceState type (rejects primitives, null, and arrays), matching the
deep-signal / deep-reconcile requirements. Add type tests and document it.
Co-authored-by: Cursor <cursoragent@cursor.com>
743764 refactor(open-service): tidy channel transport, deps, and query hook types
Consolidate channel wiring behind a single connectServiceToChannel entry
point and capture one channel reference (removes a broadcast/listener
channel-divergence hazard).
Use nanoid for the identity-critical client/call id instead of Math.random.
Drop spurious as unknown as Channel casts in the addon stores.
Move @preact/signals-core and deepsignal to devDependencies so they are
bundled into core's dist (fixes resolution in symlinked sandboxes).
Fix useServiceQuery input typing by inferring TInput/TOutput as direct type
parameters so the void-vs-input arg branch reads the concrete query type.
Co-authored-by: Cursor <cursoragent@cursor.com>
191b31 Merge branch 'next' into norbert/service-clients
Resolve docgen service conflicts by adopting next's id-based API and
getDocgenForAllComponents while keeping load hooks on the service
definition per the restricted registration model on this branch.
ef9f32 Merge pull request #35068 from storybookjs/norbert/remote-command-execution
OpenService: Implement remote command execution
1bf407 Bump version from "10.5.0-alpha.4" to "10.5.0-alpha.5" [skip ci]
9e2e92 Merge pull request #35038 from storybookjs/version-non-patch-from-10.5.0-alpha.4
Release: Prerelease 10.5.0-alpha.5
2ddbc3 Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
Core: Add ref-based components manifest index backed by docgen open service
e28303 Write changelog for 10.5.0-alpha.5 [skip ci]
b4903c CI: Add missing status to dangerjs for prerelease PR
903f5d Merge branch 'next' into jeppe-cursor/39213f22
Resolve conflicts in docgen server tests and buildReactComponentDocgen
by keeping the ref-manifest branch behavior (no toReactComponentManifest).
Co-authored-by: Cursor <cursoragent@cursor.com>
88819e Merge pull request #34963 from storybookjs/claude/docgen-phase-3-rcm-provider
Docgen: Wire up react-component-meta with DocgenService
3fd0cb Merge branch 'next' into claude/docgen-phase-3-rcm-provider
2e90f3 Fix format and DocgenPayload type compatibility
Apply oxfmt fixes and align ReactComponentManifest with DocgenPayload via
index signatures. Narrow reactComponentMeta in buildDocgen tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
1c9857 Omit empty subcomponents from manifest output
toReactComponentManifest was always setting subcomponents: undefined when
there were none, which broke generator.test.ts inline snapshots and
diverged from buildReactComponentDocgenFromResolved (which omits the key).
Also clarify preset comments to use componentMetaManager naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
10386a Merge pull request #34496 from NYCU-Chung/fix/docs-blocks-custom-mdx
Addon Docs: Fix Primary and Controls blocks not rendering in custom MDX pages
333f57 Merge branch 'norbert/remote-command-execution' of github.com:storybookjs/storybook into norbert/remote-command-execution
434e66 Refactor: Improve documentation for remote command execution in README
Enhanced the README documentation for the remote command execution section, clarifying the roles of requester and responder, the command invocation process, and the event structure. This update aims to provide clearer guidance on how commands are executed across different runtimes, improving overall understanding for developers.
747b49 Merge branch 'norbert/service-clients' into norbert/remote-command-execution
d25d87 Merge pull request #35056 from DevLikhith5/fix/canvas-wrap-firefox-esr-33743
Preview: Use width/height instead of min-* in CanvasWrap
17fa0b Build components.html from docgen snapshots instead of re-extracting
Read docgen payloads once from the static service snapshots and reuse them for
both the ref-based components.json index and the HTML debugger. Dev still
renders from the live docgen service.
Remove the unused JSON-Ref resolver/dereferencer (no in-repo consumer), simplify the
snapshot loader to a direct typed read, and rename json-references.ts to
components-ref-manifest.ts. Dedup the per-operation story-index walk in manifests.ts by
threading manifest entries through, and inline the trivial fs wrappers.
Co-authored-by: Cursor <cursoragent@cursor.com>
3269f9 Fix docgen server test for last-wins component entry selection
extractDocgen now resolves a componentId via selectComponentEntriesByComponentId
(last-wins), matching the manifest. Update the server test to expect the later
story entry when multiple stories share the same componentId.
Co-authored-by: Cursor <cursoragent@cursor.com>
133606 Refactor: Standardize channel options handling in PostMessageTransport and WebsocketTransport
Updated both PostMessageTransport and WebsocketTransport classes to utilize a local CHANNEL_OPTIONS constant instead of directly referencing globalThis.CHANNEL_OPTIONS. This change improves code clarity and consistency in accessing channel options across the transport implementations.
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
CLI: Shorten CTA link messages - #34236, thanks @shilman!
React Native Web: Fix vite8 support by bumping vite-plugin-rnw - #34231, thanks @dannyhw!
Commit history:
78e439 Merge pull request #35017 from storybookjs/norbert/service-clients
Open Service: Add sync between server, manager and preview
ccccfc ci: retry CircleCI after flaky portable-react E2E
The save-from-controls Playwright test failed once in CI with stale preview
text, but passes consistently locally (including CI=true). Retrigger checks.
57ab83 refactor(open-service): schema-validate channel payloads and constrain state to objects
Replace hand-rolled channel-payload parsers with Valibot schemas in
service-channel.ts; derive payload types from the schemas and narrow with
v.safeParse in the transport (removes the duplicated parse/isRecord helpers).
Constrain service state to a plain object at the defineService boundary via
a ServiceState type (rejects primitives, null, and arrays), matching the
deep-signal / deep-reconcile requirements. Add type tests and document it.
Co-authored-by: Cursor <cursoragent@cursor.com>
743764 refactor(open-service): tidy channel transport, deps, and query hook types
Consolidate channel wiring behind a single connectServiceToChannel entry
point and capture one channel reference (removes a broadcast/listener
channel-divergence hazard).
Use nanoid for the identity-critical client/call id instead of Math.random.
Drop spurious as unknown as Channel casts in the addon stores.
Move @preact/signals-core and deepsignal to devDependencies so they are
bundled into core's dist (fixes resolution in symlinked sandboxes).
Fix useServiceQuery input typing by inferring TInput/TOutput as direct type
parameters so the void-vs-input arg branch reads the concrete query type.
Co-authored-by: Cursor <cursoragent@cursor.com>
191b31 Merge branch 'next' into norbert/service-clients
Resolve docgen service conflicts by adopting next's id-based API and
getDocgenForAllComponents while keeping load hooks on the service
definition per the restricted registration model on this branch.
ef9f32 Merge pull request #35068 from storybookjs/norbert/remote-command-execution
OpenService: Implement remote command execution
1bf407 Bump version from "10.5.0-alpha.4" to "10.5.0-alpha.5" [skip ci]
9e2e92 Merge pull request #35038 from storybookjs/version-non-patch-from-10.5.0-alpha.4
Release: Prerelease 10.5.0-alpha.5
2ddbc3 Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
Core: Add ref-based components manifest index backed by docgen open service
e28303 Write changelog for 10.5.0-alpha.5 [skip ci]
b4903c CI: Add missing status to dangerjs for prerelease PR
903f5d Merge branch 'next' into jeppe-cursor/39213f22
Resolve conflicts in docgen server tests and buildReactComponentDocgen
by keeping the ref-manifest branch behavior (no toReactComponentManifest).
Co-authored-by: Cursor <cursoragent@cursor.com>
88819e Merge pull request #34963 from storybookjs/claude/docgen-phase-3-rcm-provider
Docgen: Wire up react-component-meta with DocgenService
3fd0cb Merge branch 'next' into claude/docgen-phase-3-rcm-provider
2e90f3 Fix format and DocgenPayload type compatibility
Apply oxfmt fixes and align ReactComponentManifest with DocgenPayload via
index signatures. Narrow reactComponentMeta in buildDocgen tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
1c9857 Omit empty subcomponents from manifest output
toReactComponentManifest was always setting subcomponents: undefined when
there were none, which broke generator.test.ts inline snapshots and
diverged from buildReactComponentDocgenFromResolved (which omits the key).
Also clarify preset comments to use componentMetaManager naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
10386a Merge pull request #34496 from NYCU-Chung/fix/docs-blocks-custom-mdx
Addon Docs: Fix Primary and Controls blocks not rendering in custom MDX pages
333f57 Merge branch 'norbert/remote-command-execution' of github.com:storybookjs/storybook into norbert/remote-command-execution
434e66 Refactor: Improve documentation for remote command execution in README
Enhanced the README documentation for the remote command execution section, clarifying the roles of requester and responder, the command invocation process, and the event structure. This update aims to provide clearer guidance on how commands are executed across different runtimes, improving overall understanding for developers.
747b49 Merge branch 'norbert/service-clients' into norbert/remote-command-execution
d25d87 Merge pull request #35056 from DevLikhith5/fix/canvas-wrap-firefox-esr-33743
Preview: Use width/height instead of min-* in CanvasWrap
17fa0b Build components.html from docgen snapshots instead of re-extracting
Read docgen payloads once from the static service snapshots and reuse them for
both the ref-based components.json index and the HTML debugger. Dev still
renders from the live docgen service.
Remove the unused JSON-Ref resolver/dereferencer (no in-repo consumer), simplify the
snapshot loader to a direct typed read, and rename json-references.ts to
components-ref-manifest.ts. Dedup the per-operation story-index walk in manifests.ts by
threading manifest entries through, and inline the trivial fs wrappers.
Co-authored-by: Cursor <cursoragent@cursor.com>
3269f9 Fix docgen server test for last-wins component entry selection
extractDocgen now resolves a componentId via selectComponentEntriesByComponentId
(last-wins), matching the manifest. Update the server test to expect the later
story entry when multiple stories share the same componentId.
Co-authored-by: Cursor <cursoragent@cursor.com>
133606 Refactor: Standardize channel options handling in PostMessageTransport and WebsocketTransport
Updated both PostMessageTransport and WebsocketTransport classes to utilize a local CHANNEL_OPTIONS constant instead of directly referencing globalThis.CHANNEL_OPTIONS. This change improves code clarity and consistency in accessing channel options across the transport implementations.
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
CLI: Shorten CTA link messages - #34236, thanks @shilman!
React Native Web: Fix vite8 support by bumping vite-plugin-rnw - #34231, thanks @dannyhw!
Commit history:
78e439 Merge pull request #35017 from storybookjs/norbert/service-clients
Open Service: Add sync between server, manager and preview
ccccfc ci: retry CircleCI after flaky portable-react E2E
The save-from-controls Playwright test failed once in CI with stale preview
text, but passes consistently locally (including CI=true). Retrigger checks.
57ab83 refactor(open-service): schema-validate channel payloads and constrain state to objects
Replace hand-rolled channel-payload parsers with Valibot schemas in
service-channel.ts; derive payload types from the schemas and narrow with
v.safeParse in the transport (removes the duplicated parse/isRecord helpers).
Constrain service state to a plain object at the defineService boundary via
a ServiceState type (rejects primitives, null, and arrays), matching the
deep-signal / deep-reconcile requirements. Add type tests and document it.
Co-authored-by: Cursor <cursoragent@cursor.com>
743764 refactor(open-service): tidy channel transport, deps, and query hook types
Consolidate channel wiring behind a single connectServiceToChannel entry
point and capture one channel reference (removes a broadcast/listener
channel-divergence hazard).
Use nanoid for the identity-critical client/call id instead of Math.random.
Drop spurious as unknown as Channel casts in the addon stores.
Move @preact/signals-core and deepsignal to devDependencies so they are
bundled into core's dist (fixes resolution in symlinked sandboxes).
Fix useServiceQuery input typing by inferring TInput/TOutput as direct type
parameters so the void-vs-input arg branch reads the concrete query type.
Co-authored-by: Cursor <cursoragent@cursor.com>
191b31 Merge branch 'next' into norbert/service-clients
Resolve docgen service conflicts by adopting next's id-based API and
getDocgenForAllComponents while keeping load hooks on the service
definition per the restricted registration model on this branch.
ef9f32 Merge pull request #35068 from storybookjs/norbert/remote-command-execution
OpenService: Implement remote command execution
1bf407 Bump version from "10.5.0-alpha.4" to "10.5.0-alpha.5" [skip ci]
9e2e92 Merge pull request #35038 from storybookjs/version-non-patch-from-10.5.0-alpha.4
Release: Prerelease 10.5.0-alpha.5
2ddbc3 Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
Core: Add ref-based components manifest index backed by docgen open service
e28303 Write changelog for 10.5.0-alpha.5 [skip ci]
b4903c CI: Add missing status to dangerjs for prerelease PR
903f5d Merge branch 'next' into jeppe-cursor/39213f22
Resolve conflicts in docgen server tests and buildReactComponentDocgen
by keeping the ref-manifest branch behavior (no toReactComponentManifest).
Co-authored-by: Cursor <cursoragent@cursor.com>
88819e Merge pull request #34963 from storybookjs/claude/docgen-phase-3-rcm-provider
Docgen: Wire up react-component-meta with DocgenService
3fd0cb Merge branch 'next' into claude/docgen-phase-3-rcm-provider
2e90f3 Fix format and DocgenPayload type compatibility
Apply oxfmt fixes and align ReactComponentManifest with DocgenPayload via
index signatures. Narrow reactComponentMeta in buildDocgen tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
1c9857 Omit empty subcomponents from manifest output
toReactComponentManifest was always setting subcomponents: undefined when
there were none, which broke generator.test.ts inline snapshots and
diverged from buildReactComponentDocgenFromResolved (which omits the key).
Also clarify preset comments to use componentMetaManager naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
10386a Merge pull request #34496 from NYCU-Chung/fix/docs-blocks-custom-mdx
Addon Docs: Fix Primary and Controls blocks not rendering in custom MDX pages
333f57 Merge branch 'norbert/remote-command-execution' of github.com:storybookjs/storybook into norbert/remote-command-execution
434e66 Refactor: Improve documentation for remote command execution in README
Enhanced the README documentation for the remote command execution section, clarifying the roles of requester and responder, the command invocation process, and the event structure. This update aims to provide clearer guidance on how commands are executed across different runtimes, improving overall understanding for developers.
747b49 Merge branch 'norbert/service-clients' into norbert/remote-command-execution
d25d87 Merge pull request #35056 from DevLikhith5/fix/canvas-wrap-firefox-esr-33743
Preview: Use width/height instead of min-* in CanvasWrap
17fa0b Build components.html from docgen snapshots instead of re-extracting
Read docgen payloads once from the static service snapshots and reuse them for
both the ref-based components.json index and the HTML debugger. Dev still
renders from the live docgen service.
Remove the unused JSON-Ref resolver/dereferencer (no in-repo consumer), simplify the
snapshot loader to a direct typed read, and rename json-references.ts to
components-ref-manifest.ts. Dedup the per-operation story-index walk in manifests.ts by
threading manifest entries through, and inline the trivial fs wrappers.
Co-authored-by: Cursor <cursoragent@cursor.com>
3269f9 Fix docgen server test for last-wins component entry selection
extractDocgen now resolves a componentId via selectComponentEntriesByComponentId
(last-wins), matching the manifest. Update the server test to expect the later
story entry when multiple stories share the same componentId.
Co-authored-by: Cursor <cursoragent@cursor.com>
133606 Refactor: Standardize channel options handling in PostMessageTransport and WebsocketTransport
Updated both PostMessageTransport and WebsocketTransport classes to utilize a local CHANNEL_OPTIONS constant instead of directly referencing globalThis.CHANNEL_OPTIONS. This change improves code clarity and consistency in accessing channel options across the transport implementations.
Core: Disable component manifest by default - #34408, thanks @yannbf!
[!NOTE] Version >=0.5.0 of @​storybook/addon-mcp enables component manifests again. If you're upgrading Storybook from version >= 10.3.0 to >= 10.3.5 and are using the MCP addon, you should also upgrade @​storybook/addon-mcp to keep the docs toolset in the MCP server.
CLI: Shorten CTA link messages - #34236, thanks @shilman!
React Native Web: Fix vite8 support by bumping vite-plugin-rnw - #34231, thanks @dannyhw!
Commit history:
78e439 Merge pull request #35017 from storybookjs/norbert/service-clients
Open Service: Add sync between server, manager and preview
ccccfc ci: retry CircleCI after flaky portable-react E2E
The save-from-controls Playwright test failed once in CI with stale preview
text, but passes consistently locally (including CI=true). Retrigger checks.
57ab83 refactor(open-service): schema-validate channel payloads and constrain state to objects
Replace hand-rolled channel-payload parsers with Valibot schemas in
service-channel.ts; derive payload types from the schemas and narrow with
v.safeParse in the transport (removes the duplicated parse/isRecord helpers).
Constrain service state to a plain object at the defineService boundary via
a ServiceState type (rejects primitives, null, and arrays), matching the
deep-signal / deep-reconcile requirements. Add type tests and document it.
Co-authored-by: Cursor <cursoragent@cursor.com>
743764 refactor(open-service): tidy channel transport, deps, and query hook types
Consolidate channel wiring behind a single connectServiceToChannel entry
point and capture one channel reference (removes a broadcast/listener
channel-divergence hazard).
Use nanoid for the identity-critical client/call id instead of Math.random.
Drop spurious as unknown as Channel casts in the addon stores.
Move @preact/signals-core and deepsignal to devDependencies so they are
bundled into core's dist (fixes resolution in symlinked sandboxes).
Fix useServiceQuery input typing by inferring TInput/TOutput as direct type
parameters so the void-vs-input arg branch reads the concrete query type.
Co-authored-by: Cursor <cursoragent@cursor.com>
191b31 Merge branch 'next' into norbert/service-clients
Resolve docgen service conflicts by adopting next's id-based API and
getDocgenForAllComponents while keeping load hooks on the service
definition per the restricted registration model on this branch.
ef9f32 Merge pull request #35068 from storybookjs/norbert/remote-command-execution
OpenService: Implement remote command execution
1bf407 Bump version from "10.5.0-alpha.4" to "10.5.0-alpha.5" [skip ci]
9e2e92 Merge pull request #35038 from storybookjs/version-non-patch-from-10.5.0-alpha.4
Release: Prerelease 10.5.0-alpha.5
2ddbc3 Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
Core: Add ref-based components manifest index backed by docgen open service
e28303 Write changelog for 10.5.0-alpha.5 [skip ci]
b4903c CI: Add missing status to dangerjs for prerelease PR
903f5d Merge branch 'next' into jeppe-cursor/39213f22
Resolve conflicts in docgen server tests and buildReactComponentDocgen
by keeping the ref-manifest branch behavior (no toReactComponentManifest).
Co-authored-by: Cursor <cursoragent@cursor.com>
88819e Merge pull request #34963 from storybookjs/claude/docgen-phase-3-rcm-provider
Docgen: Wire up react-component-meta with DocgenService
3fd0cb Merge branch 'next' into claude/docgen-phase-3-rcm-provider
2e90f3 Fix format and DocgenPayload type compatibility
Apply oxfmt fixes and align ReactComponentManifest with DocgenPayload via
index signatures. Narrow reactComponentMeta in buildDocgen tests.
Co-authored-by: Cursor <cursoragent@cursor.com>
1c9857 Omit empty subcomponents from manifest output
toReactComponentManifest was always setting subcomponents: undefined when
there were none, which broke generator.test.ts inline snapshots and
diverged from buildReactComponentDocgenFromResolved (which omits the key).
Also clarify preset comments to use componentMetaManager naming.
Co-authored-by: Cursor <cursoragent@cursor.com>
10386a Merge pull request #34496 from NYCU-Chung/fix/docs-blocks-custom-mdx
Addon Docs: Fix Primary and Controls blocks not rendering in custom MDX pages
333f57 Merge branch 'norbert/remote-command-execution' of github.com:storybookjs/storybook into norbert/remote-command-execution
434e66 Refactor: Improve documentation for remote command execution in README
Enhanced the README documentation for the remote command execution section, clarifying the roles of requester and responder, the command invocation process, and the event structure. This update aims to provide clearer guidance on how commands are executed across different runtimes, improving overall understanding for developers.
747b49 Merge branch 'norbert/service-clients' into norbert/remote-command-execution
d25d87 Merge pull request #35056 from DevLikhith5/fix/canvas-wrap-firefox-esr-33743
Preview: Use width/height instead of min-* in CanvasWrap
17fa0b Build components.html from docgen snapshots instead of re-extracting
Read docgen payloads once from the static service snapshots and reuse them for
both the ref-based components.json index and the HTML debugger. Dev still
renders from the live docgen service.
Remove the unused JSON-Ref resolver/dereferencer (no in-repo consumer), simplify the
snapshot loader to a direct typed read, and rename json-references.ts to
components-ref-manifest.ts. Dedup the per-operation story-index walk in manifests.ts by
threading manifest entries through, and inline the trivial fs wrappers.
Co-authored-by: Cursor <cursoragent@cursor.com>
3269f9 Fix docgen server test for last-wins component entry selection
extractDocgen now resolves a componentId via selectComponentEntriesByComponentId
(last-wins), matching the manifest. Update the server test to expect the later
story entry when multiple stories share the same componentId.
Co-authored-by: Cursor <cursoragent@cursor.com>
133606 Refactor: Standardize channel options handling in PostMessageTransport and WebsocketTransport
Updated both PostMessageTransport and WebsocketTransport classes to utilize a local CHANNEL_OPTIONS constant instead of directly referencing globalThis.CHANNEL_OPTIONS. This change improves code clarity and consistency in accessing channel options across the transport implementations.
a98861 repl: keep multi-byte UTF-8 input in the interactive line editor (#31876)
Fixes #31871
Related to #27556 (same root cause: non-ASCII characters not accepted in bun repl). The interactive line editor only runs under a PTY, which is
POSIX-only today, so this does not change the Windows REPL path that
issue describes.
What
The interactive bun repl line editor silently drops every non-ASCII
byte typed or pasted into the input line, so Korean (and any multi-byte
UTF-8) characters vanish and the evaluated expression differs from what
the user typed.
Reproduction
The line editor only activates when both stdin and stdout are TTYs, so
it has to be driven under a PTY. With a debug build:
$ bun repl
> "a한b".length
Expected 3 (matches bun -e '"a한b".length'). Before this change the 한 never appears, the buffer becomes "ab".length, and the result is 2. The issue's second example, "안녕하세요 영재님".length, collapses to " ".length (only the ASCII space survives).
Root cause
In src/runtime/cli/repl.rs, Key::from_byte maps any byte >= 128 to Key::Unknown:
32..=126 => Key::Char(byte),
_ => Key::Unknown,
read_key reads a single byte and, for non-ESC input, calls from_byte. Every UTF-8 lead and continuation byte is >= 0x80, so it
becomes Key::Unknown, which the main input loop drops via its _ => {} arm. A 3-byte character like 한 therefore produces three dropped
events.
Fix
read_key now recognizes a UTF-8 lead byte, reads the rest of the
sequence, and returns it as a single new Key::Text([u8; 4], len)
event, inserted through the existing LineEditor::insert_slice. A
truncated or malformed sequence (stream ends mid-character, or a byte
that is not a continuation byte) is dropped rather than corrupting the
buffer.
move_left / move_right / backspace / delete_char stepped one
byte at a time, which would split a multi-byte character. They now step
whole codepoints via two small helpers (prev_boundary / next_boundary).
refresh_line positioned the cursor using the byte offset as a
terminal column. It now uses the visible display width of the text
before the cursor
(strings::visible::width::exclude_ansi_colors::utf8), so multi-byte
and wide (CJK) characters advance the column correctly.
ASCII input is unchanged: single bytes still flow through Key::Char.
Verification
Four PTY-driven tests added to test/js/bun/repl/repl.test.ts (under
the existing Bun REPL (Terminal) suite, which is already gated off on
Windows):
"a한b".length evaluates to 3 and the echoed line keeps the 한
"안녕하세요 영재님".length evaluates to 9 and the full string is preserved
backspace over a Korean character deletes the whole codepoint
(leftover "ok".length evaluates to 2)
left-arrow navigation steps over a whole multi-byte character before
inserting ("b한".length evaluates to 2)
All four fail on the unfixed build (the expected output never appears)
and pass with the fix. Reverting only the cursor-stepping helpers makes
the backspace and left-arrow tests fail while input still assembles,
confirming each part of the change is exercised. The full repl.test.ts
suite (114 tests) passes with bun bd test.
1293ef css: minify merged duplicate rules in linear time (#31920)
What does this PR do?
Fixes a family of fuzzer-found CSS minifier hangs: stylesheets
containing many adjacent rules with equivalent selectors took
superlinear time to minify. Hang signature sampled by the fuzzer: bun_css::selectors::selector::serialize::serialize_selector (the
process spinning inside the minify merge loop). Multiple minimized
inputs shared this root cause, covering the color-scheme, clamp/math, -webkit-gradient, and background handler families.
Repro (release build, before this change):
bun -e 'require("fs").writeFileSync("dup.css", ".a{color-scheme:dark}".repeat(2000))'# via bun:internal-for-testing cssInternals._test with {chrome: 80<<16} targets:# 500 rules -> 4.6 s, 1000 -> 35 s, 2000 -> 376 s
Root cause
Two independent superlinear shapes in CssRuleList::minify
(src/css/rules/mod.rs), both of the form "reprocess all accumulated
state once per merged duplicate":
Declaration merges.merge_style_rules appends the incoming
rule's declarations to the accumulated last rule and re-runs the
property handlers over the whole merged block, once per merged rule.
That is only linear if duplicates collapse during re-minification, but
several handlers emit one output declaration per input declaration
(custom properties, color-scheme, vendor-prefixed background images,
unparsed fallbacks), so the block stays O(n) long and the total work is
O(n^2) handler passes and property clones. Worse, the color-scheme
handler re-expands its own output on every pass (it pushes fresh --buncss-light/--buncss-dark polyfill vars each time it sees the
retained color-scheme declaration when targets lack light-dark()
support), so the block itself grows per pass: O(n^2) declarations
re-minified n times is O(n^3). That is the 376 s case above.
Selector merges. When declarations are equal, the incoming rule's
selectors are appended to the last rule, and each merge re-validates the
combined rule with StyleRule::is_compatible, which walks every
accumulated selector component. n same-declaration rules therefore walk
O(n^2) selector components (measured 3.3x per input doubling).
Upstream lightningcss 1.30.1 has the identical merge loop and is
quadratic on the same floods (color-scheme x1000/2000/4000: 59/239/946
ms via the npm CLI), so there is no upstream fix to port.
The fix
A declaration merge now only concatenates the declaration lists and
marks the last rule as pending (StyleRuleMergeState::pending_minify).
The single re-minify runs when the merge run ends: the next rule does
not merge, extra rules (logical/@supports/incompatible-selector/nested
splits) get appended, a non-style rule arrives, or the rule list
finishes. The merge-with-previous cascade that a declaration merge
enables runs at the same point. n merged duplicates now cost one handler
pass over the concatenated block instead of n passes.
is_compatible for the accumulated last rule is cached in StyleRuleMergeState::last_compat, invalidated when the last rule
changes, and updated incrementally on selector merges (the merged list
is compatible iff both inputs were).
No declarations are dropped, deduplicated, or reordered; the output is
whatever the existing handler pipeline produces for the merged block,
computed once per run instead of once per merge. The branch that
compares declaration contents settles any pending merge first, so merge
decisions see the same canonical form as before.
Measured after (debug build with ASAN, so absolute numbers are
conservative; ratios per input doubling are the point):
flood
before (release)
after (debug)
.a{color-scheme:dark} x2000, chrome 80 targets
375.7 s
0.25 s
.a{color-scheme:light dark} x4000
0.46 s, 4.1x per doubling
0.35
s, 2.0x
-webkit-gradient background x4000
2.37 s, 4.3x
1.06 s, 1.9x
4000 distinct custom properties, same selector
0.42 s, 4.2x
0.58
s, 1.8x
8000 distinct selectors, same declaration
84 ms, 3.3x
0.64 s, 2.0x
|
Output compatibility
The full CSS corpus is byte-identical: test/js/bun/css/ (1093
exact-output tests plus the 432-snapshot real-world corpus) and test/bundler/css/ + bundler_minify all pass unchanged. A targeted
A/B sweep of merge-heavy inputs against the previous build found exactly
two divergences, both confined to inputs the corpus does not contain:
Runs of 3+ duplicate color-scheme rules with old targets now emit
the polyfill vars re-expanded once instead of once per merge pass (the
old output grew O(n^2) with the duplicate count; the new output is
strictly smaller and still later-wins-correct).
A mid-run cascade collapse corner: .a{color:red}.b{color:blue}.b{color:red}.b{font-style:italic} used to
emit .a,.b{color:red}.b{font-style:italic} because the cascade fired
between the 3rd and 4th rule; it now emits .a{color:red}.b{color:red;font-style:italic}. Both outputs are
semantically identical CSS; the cascade now evaluates once per merge run
rather than between every pair of merges.
Verification
Review follow-up (45495b0): the deferred re-minify originally ran after
the handler context was drained, which leaked re-staged dark-mode
entries when the merged-in rule carried a color-scheme declaration
needing fallback vars, and a run ended by a non-merging style rule
skipped the merge-with-previous cascade. Pending merges are now settled
before extras are collected whenever the context has staged entries, and
the cascade runs on the inline-settle path too. Both shapes are pinned
by exact-output tests in the same file
(.a{color:red}.a{color-scheme:light dark} with chrome 80 targets, and .x{color:blue}.a{color:red}.a{color:blue}.b{font-style:italic}),
asserting byte equality with the previous per-merge implementation.
test/js/bun/css/duplicate-declaration-merge-hang.test.ts embeds the
minimized fuzzer input (gzip+base64, exercised through the same
minify/test/prefix endpoints as the fuzzer) plus synthetic 2000-rule
floods for each affected family, sized so the old complexity cannot
finish within the 60 s spawn timeout while the fixed build completes in
~2.5 s. On the unfixed build the test is killed at the timeout (fails);
with the fix it passes.
Related: #31279 addresses one instance of the same bug class
(exact-duplicate declarations) by deduplicating values during the merge,
which raised cascade-order questions in review. This PR fixes the
underlying complexity for all inputs, including legitimately distinct
declarations and the selector-side quadratic, without touching
declaration order or values.
0342ab Don't panic when auto-install can't read the top-level directory (#31938)
Crash
Sentry BUN-34PN: ~120 events, 100% Windows x64, bun <script> / bun -e, bun 1.3.8 through 1.3.14.
panic: access of union field 'entries' while field 'err' is active
in initWithRuntimeOnce (PackageManager runtime init), reached from import.meta.resolveSync via the resolver's auto-install path. On
current main the same path still crashes, with the message panic: Failed to initialize package manager.
Repro
The cwd must be unlistable from process start (if it is readable at
startup, the dir walk caches its entries and the cached listing
satisfies the later init), and the script must live in a readable
directory so the resolver reaches the auto-install path:
ENOENT: failed to read root directory: '/tmp/t/cwd'
panic: Failed to initialize package manager
(exit 132, crash report). This matches the field population: cwd on a
dead mapped drive or with revoked permissions.
Fix
The runtime auto-installer's one-time init read the top-level directory
and panicked on failure. That failure is user-reachable, so it is now a
recoverable error:
init_with_runtime / init_with_runtime_once
(src/install/PackageManager.rs) return Result. The directory read
happens before the singleton allocation, so a failure leaves holder::RAW_PTR null instead of pointing at an uninitialized manager.
The failure is sticky across calls (same Once semantics as before).
__bun_resolver_init_package_manager (src/install/auto_installer.rs)
and Resolver::get_package_manager (src/resolver/resolver.rs) propagate
the error.
load_node_modules turns it into MatchStatus::Failure with a Metadata::Resolve log message, so JS gets a catchable ResolveMessage.
VirtualMachine::package_manager keeps its infallible signature; its
production callers (AsyncModule pending-task machinery) only run after a
successful init, documented at the expect.
After:
caught: Cannot read directory "/tmp/t/cwd": ENOENT while resolving "left-pad"
exit 0, execution continues, repeated resolves rethrow the same error.
The bun install CLI init path already returned Err(e.canonical_error) for this case and is unchanged.
Verification
New test in test/js/bun/resolve/resolve.test.ts (auto-install init failure from an unreadable cwd is a catchable error), next to the
existing entries-cache EACCES test and reusing its root/runuser
scaffolding. Fails on the unfixed build (panic, exit 132), passes with
the fix.
bun bd test test/js/bun/resolve/resolve.test.ts: 39 pass, 0 fail.
bun bd test test/cli/run/run-autoinstall.test.ts test/cli/run/run-autoinstall-abs-path.test.ts test/cli/run/autoinstall-cached-manifest.test.ts: 13 pass, 0 fail.
Happy path intact: auto-install resolve with a readable cwd still
works; bun install CLI unaffected; await import() on the broken-cwd
path rejects with the same catchable error.
90589f bundler: fix dev server crash when a CSS rebuild fails import resolution (#31905)
Fixes #31903
Repro
Debug builds panic during a dev server hot reload when a CSS file parses
but fails import resolution (for example an unterminated url( that
tokenizes to a URL, or a url(./missing.png) pointing at a file that
does not exist):
Both of these existing tests crash on main with DevServer crashed while waiting for hot reload:
bun bd test test/bake/dev/css.test.ts -t "syntax error crash"
bun bd test test/bake/dev/css.test.ts -t "css import before create project relative"
Cause
graph.css_file_count is only incremented when a parse task completes
successfully with a CSS AST. When resolution fails after a successful
CSS parse, run_resolution_for_parse_task converts the result to an
error, and (since the leak fixes in #30875) moved the parsed stylesheet
onto the graph row so teardown could free it. That comment assumed the
linker never runs after such an error, but the dev server intentionally
proceeds with failed files, and finish_from_bake_dev_server treats a
populated css slot as "successfully parsed CSS" when discovering CSS
entry points. The failed file was therefore re-added as a CSS entry
point and got a CSS chunk while css_file_count stayed 0, tripping the debug_assert!(!chunk.content.is_css()) in generate_chunks_in_parallel. In release builds the assert compiles out
and the CSS dedup/prepare pass is silently skipped for that chunk. The
Zig implementation never stored the CSS AST on this path, so the dev
server's invariant held there.
The parked AST also diverged from the reference in find_imported_files_in_css_order (a failed file's stale rules could be
included in another chunk's import order) and scan_css_imports.
Fix
Drop the stylesheet at the failure site in run_resolution_for_parse_task instead of parking it on the graph row.
The graph row stays None for failed files, restoring the invariant
every dev server consumer of the css column relies on, and the
stylesheet's non-arena allocations are still freed (same drop_in_place
the teardown pass uses).
Verification
New test test/bake/dev/css.test.ts "css url resolve error on hot
reload is recoverable" fails on the unfixed build with DevServer crashed while waiting for hot reload and passes with the fix: a
connected client asserts the exact error overlay text and the route
returns 500, then recovery back to a 200 is checked after the error is
fixed. Exercising the recovery with the client still connected hits a
separate, pre-existing HMR patch bug (the HTML route module is shipped
without the route-reload flag), tracked in #31908.
Full test/bake/dev/css.test.ts (14 tests, including the two
previously-crashing ones), test/bake/dev/html.test.ts, test/bake/dev/bundle.test.ts, test/bake/dev/hot.test.ts, and test/bake/dev/plugins.test.ts pass on the debug/ASAN build.
Non-dev path (Bun.build with a CSS entry whose url() fails to
resolve) still reports Could not resolve and is clean under ASAN.
300b14 test runner: store Scanner.fs as a raw pointer instead of casting away shared refs (#31850)
The bun test file-discovery Scanner held its FileSystem as a shared
reference but derived &mut RealFS from it in two places
(read_dir_with_name and next) via #[allow(invalid_reference_casting)]&T -> &mut T casts, giving the
writes read-only provenance — undefined behavior under Rust's aliasing
rules. The fix changes Scanner.fs to *mut FileSystem (the same shape Transpiler.fs already uses), storing transpiler.fs directly in Scanner::init. The two mutation sites now derive &mut (*self.fs).fs
/ &raw mut (*self.fs).fs with genuine write provenance, and the lint
allow is gone. Reads outside the directory-iterator callback go through
a new fs() accessor returning &'static FileSystem (sound: the
singleton lives for the whole process); reads on the callback path
(next and callees, which run while the resolver holds &mut to the
singleton's fs field) use field-precise place projections
(top_level_dir/filename_store/abs_buf_projected) so no
whole-struct &FileSystem spans the mutably-borrowed field. The
remaining reentrant Entry::kind*mut reborrow is the resolver's
documented, entries_mutex-serialised contract and is called out in the
SAFETY comments. The two scanner.fs.top_level_dir reads in
test_command.rs were updated to use the accessor. New scanner-discovery
tests in test/cli/test/bun-test.test.ts (deep nested scanning,
dot-dir/node_modules pruning, subdirectory positional, single-file
NotDir path) are behavior guards over the rewritten paths — the refactor
has no intended behavior change, so they are not pre/post
discriminators; verification is the build/test phase.
Verification
Implemented and verified on a unified integration branch: full debug
build (linux-x64, ASAN), cargo check across the workspace, and the
affected test files run against the debug build (failures cross-checked
against main's build to exclude pre-existing issues). Each change was
reviewed twice (compile/API correctness and GC/concurrency/semantics
lenses) with findings repaired before landing.
27d518 markdown: fix quadratic rendering of nested link/image labels without a depth cap (#31909)
73ab3d css: fix exponential backtracking on nested color function values in token lists (#31919)
Fixes a fuzzer-reported OOM/DoS class in the CSS parser.
Fuzzer signature: oom:css with allocation stacks in <alloc::vec::Vec<bun_css::properties::custom::TokenOrValue> as core::ops::drop::Drop>::drop, diagnosed as error recovery re-buffering
raw TokenOrValue lists once per nesting level.
Same blowup with "rgb(1 1 1/ ".repeat(D) and a bad-string token or an
invalid var() at the bottom. Time and allocation churn multiply by ~2
per added nesting level (measured x16 per +4 levels). Under allocator
instrumentation the churn shows up as memory, matching the fuzzer's OOM;
in release builds it is a CPU DoS from a few KB of CSS.
Cause
TokenList::parse_into (src/css/properties/custom.rs) tries UnresolvedColor::parse for rgb()/hsl()/light-dark() and, when
that attempt fails, rewinds and re-parses the arguments as a plain
function. The attempt buffers token-list arguments (the rgb/hsl alpha,
the light-dark halves), so a late failure makes the fallback re-parse
the whole consumed range. When such functions nest, each level runs both
the attempt and the fallback over the same suffix, so the work is
O(2^depth) in total.
#31243 added the unclosed-block-at-EOF short-circuit, which kills this
only when the input is truncated mid-block. Balanced inputs (closed
parens) with a late failure, or a tokenizer error token mid-stream,
never hit it.
Fix
Two parts, in src/css/properties/custom.rs and src/css/css_parser.rs:
ParserInput gains a token_list_parse_failures counter (same
pattern as the existing math_fn_parse_failures used by the atan2 fix,
#31558), bumped whenever TokenList::parse_into fails. The UnresolvedColor call site samples it around the attempt; if it grew,
the failure came from inside a token-list argument, which fails
identically under every later alternative, so the error is propagated
instead of falling through to a re-parse. A token-list parse is
context-free, so re-parsing the same tokens cannot succeed.
light-dark() fails on a missing top-level comma only after buffering
its first half; that is a structural failure the counter cannot see. It
now checks for the comma with a raw scan (no allocation, nested blocks
skipped) before parsing, so the failed attempt costs no buffering and
the fallback's single pass is the only full parse.
Recovery is now a single descent: parse failures propagate immediately,
and the only repeated work is the light-dark comma scan, which is
allocation-free and bounded by the 500-level nesting cap.
Verification
The three shapes above: exponential before (D=16 ~15s, D=20 no
finish), linear after (D=256 in ~0.8s on an ASAN debug build, flat
memory).
The fuzzer's minimized input (embedded in the test, gzip+base64)
parses in bounded time/memory through minifyTest, _test, and prefixTest. Note it did not reproduce a standalone OOM on the reported
canary build (1.4.0-canary.1+5ac120ca3, built and tested from that
exact commit); the class it was diagnosed as is what the synthetic
shapes reproduce.
Output unchanged: valid/recovered color values minify byte-identically
to the unfixed build (pinned in the new test), and test/js/bun/css/css.test.ts (1093), test/js/bun/css/ (only
pre-existing css-fuzz.test.ts timeouts, identical on the unfixed build
in the same container), test/bundler/css/ (167), test/bundler/esbuild/css.test.ts (53) all pass.
New tests in test/js/bun/css/token-list-backtracking.test.ts fail on
the unfixed build (3 timeouts) and pass with the fix.
While testing this I found a separate success-path amplification: nested
relative colors with light-dark() origins produce O(2^depth) output.
Not touched here; tracked in #31918.
a7034f Evaluate private method call receivers once in decorator lowering (#31426)
What does this PR do?
Fixes unbounded memory growth in the transpiler (found by fuzzing) when
a decorated class contains chained private method calls, plus a receiver
double-evaluation bug in the same lowering.
Repro (fuzzer input, ~555 bytes — 5+ GB RSS and climbing before this
change, 5 KB output in ~10 ms after):
rewrite_private_accesses_in_expr in src/js_parser/lower/lower_decorators.rs lowers recv.#m(args) to __privateGet(recv, _m).call(recv, args), inserting the same receiver
expression twice (the two copies share AST nodes). Two consequences:
Exponential output: when the receiver itself contains another
lowered .#m() call, each chain link doubles what the printer has to
emit — ?.Foo.#m() ×44 is ~2^44 worth of text, so the printer allocates
until it OOMs. Measured with the old lowering: a 16-link chain prints
2.9 MB, 18 links 11.8 MB, 20 links 47 MB (×4 per 2 links).
Double evaluation: side effects in the receiver run twice, e.g. getCounter().#m(42) called getCounter() two times.
Fix
Evaluate the receiver exactly once:
this and identifier receivers are reused directly (output unchanged
for the common this.#m() / obj.#m() cases).
Any other receiver is captured in a temporary: __privateGet(_obj = recv, _m).call(_obj, args).
Temporaries created inside method/function/arrow bodies are declared at
the top of that body (run(id) { var _obj; return __privateGet(_obj = make(id), ...).call(_obj); }), so each invocation gets a fresh binding;
a binding shared across invocations could be clobbered when a
getter-backed private call reenters the same site, since __privateGet(obj, member, getter) runs the user getter between the
temp write and the .call(_obj) read. Temporaries created outside
function bodies (field initializers, static blocks, decorate
expressions, which run at most once per class evaluation) are declared
alongside the other lowering variables (_dec, WeakMaps, _init),
covering both class statements and class expressions. Both placements
match where esbuild declares the corresponding _a temps.
Output for the fuzz chain is now linear in chain length (n=44 → ~5 KB).
Note: optional-chain short-circuiting across a lowered private access
(o?.Foo.#m() when o is nullish) still throws like it did before this
change; that is a separate, pre-existing gap in the decorator lowering,
tracked in #31910, and is not affected by this PR.
Verification
New tests in test/bundler/transpiler/es-decorators.test.ts ("private
member calls in lowered classes"):
transpiled output for a 20-link ?.Foo.#m() chain stays under 50 KB
and reparses (old lowering: 47,186,639 bytes → fails)
double-call .#method()() chains in decorated static field
initializers stay linear (old lowering: ~64 MB for 20 links → fails)
private method call receiver is evaluated exactly once (old lowering
evaluates it twice → fails)
receiver temps are scoped per invocation: a private getter reentering
the same call site must not clobber the outer call's receiver (fails
with a class-scope hoisted temp, output matches untranspiled Node)
chained optional private method calls return the right value
this / identifier receivers keep working, decorated class
expressions evaluate receivers once
bun bd test test/bundler/transpiler/es-decorators.test.ts — 43 pass
with the fix; the size/evaluation tests above fail without it
(USE_SYSTEM_BUN=1). Also ran es-decorators-esbuild.test.ts, decorators.test.ts, decorator-metadata.test.ts, bundler_decorator_metadata.test.ts, and transpiler.test.js — no
regressions (400+ tests), plus a minified Bun.build bundle to confirm
the renamer keeps function-scoped temps collision-free.
a7839d ci: platform smoke check before running tests (#31904)
What
Test steps now declare what platform they were generated for
(EXPECTED_PLATFORM_OS/ARCH/ABI/DISTRO/RELEASE in getTestBunStep),
and runner.node.mjs asserts the agent actually matches before running
any test, using the same scripts/utils.mjs helpers the agent uses to
emit its tags, so expectation and reality come from one source of truth.
Why
A misrouted job (a macOS 26 step landing on a macOS 15 box, an
alpine/musl step on a glibc agent) currently runs the entire shard and
produces silently-wrong results that look green. With this change it
fails in the first second with a message naming the exact mismatch:
Platform smoke check FAILED, this job landed on the wrong agent:
release: step expects "26", agent is "15.7"
Notes
The check fails closed: a declared expectation with no detectable
actual value (for example the ABI probe failing) is a mismatch, rendered
as (undetected).
release is only asserted where the lane pins an exact version.
darwin aarch64 previous and darwin x64 float across macOS versions by
design; the windows "2019" label doesn't match the kernel-style version
agents report.
No-op for local runs (no EXPECTED_PLATFORM_OS in env).
08226e fs.watch: type FSWatcher's wrapper self-reference as JsRef instead of a bare JSValue (#31848)
FSWatcher stored its reference to its own JS wrapper as a bare
Cell, an untyped encoded value with no expression of its GC
contract. The wrapper's liveness is rooted by hasPendingActivity()
(pending_activity_count starts at 1 and stays positive until
close/detach), so the field is now a JsCell held weak on purpose
— a Strong here would be a self-reference cycle that pins the wrapper
forever. All readers (emit, emit_with_filename, emit_error, emit_abort,
close, the js_this() accessor) now go through JsRef::try_get() and copy
the value out before any re-entrant listener call, and detach()
idempotently resets the ref to JsRef::empty(). Behavior is unchanged;
the field is now typed for its GC role and every read is null-checked
through one audited path. Tested with a new subprocess GC-stress test in
fs.watch.test.ts that forces Bun.gc(true) between watcher creation,
event delivery, abort-signal abort, re-entrant close-from-listener,
double close, and close-event emission, asserting all events arrive and
the process exits cleanly.
Verification
Implemented and verified on a unified integration branch: full debug
build (linux-x64, ASAN), cargo check across the workspace, and the
affected test files run against the debug build (failures cross-checked
against main's build to exclude pre-existing issues). Each change was
reviewed twice (compile/API correctness and GC/concurrency/semantics
lenses) with findings repaired before landing.
d155a2 webcore: fix ReadableStream::isLocked never matching any stream (#31884)
What
Fixes #31882. Both WebCore::ReadableStream::isLocked overloads in src/jsc/bindings/webcore/ReadableStream.cpp returned false for every
stream, locked or not.
Root cause
The helper read the $reader private slot and checked .isTrue():
Nothing in the tree ever stores the literal boolean true in $reader.
The streams builtins store one of:
a reader object: readableStreamReaderGenericInitialize
($putByIdDirectPrivate(stream, "reader", reader))
an empty {} sentinel: $readDirectStream, lazyLoadStream, readableStreamToArrayBufferDirect
undefined (cleared)
A reader object and {} are both truthy objects, not the boolean true, so .isTrue() never matched. The builtin's own isReadableStreamLocked (ReadableStreamInternals.ts) defines
lockedness as !!$getByIdDirectPrivate(stream, "reader") || stream.$bunNativePtr === -1.
Because the C++ helper always said "not locked", the Rust ReadableStream::is_locked() guards that feed off ReadableStream__isLocked never fired, so locked streams slipped past
checks in Body.rs, ResumableSink.rs, and RequestContext.rs.
Fix
Make both overloads mirror the builtin (the fixing lines are in ReadableStream::isLocked(JSGlobalObject*, JSReadableStream*)): a
stream is locked when $reader holds a value, or when the native reader
has been detached ($bunNativePtr set to -1 by ReadableStream__detach). The empty-slot case (getDirect returns an
empty JSValue when the property is absent) is handled explicitly so a
fresh stream with no reader reads as unlocked. The instance overload now
delegates to the static one.
Consequences (validated)
Two observable behaviors that were previously silent:
Returning a Response whose body stream is already locked from Bun.serve now surfaces ERR_STREAM_CANNOT_PIPE through the server's error handler. Before the fix the server returned a 200 with an
empty body.
Piping an already-locked ReadableStream as a fetch request body
now rejects with ERR_STREAM_CANNOT_PIPE at the pipe boundary
(ResumableSink). Before the fix it proceeded as if the stream were
usable and reported a late TypeError: ReadableStream is locked from getReader().
Cancel-on-teardown (ReadableStream__cancel) also becomes live, but readableStreamCancel early-returns for already-closed/errored streams,
so the normal streaming-response completion path (RequestContext.rs)
that now routes finished streams through cancel() is a no-op for them.
The existing streaming > text from JS server tests confirm normal
streaming responses are unaffected.
Tests
Both tests fail on the current release and pass with this change:
test/js/web/fetch/fetch.stream.test.ts — "rejects with
ERR_STREAM_CANNOT_PIPE when the request body stream is already locked".
On an unfixed build it sees TypeError: ReadableStream is locked
instead.
test/js/bun/http/serve.test.ts — "returning a Response whose body
stream is already locked calls the error handler". On an unfixed build
the server returns 200 with an empty body and the error handler is
never called.
These are latent-bug tests (the C++ helper never worked), so they live
in the module test files rather than test/regression/issue.
a2eaf9 ci: bake Intel SDE into the Windows image for verify-baseline (#31893)
Fixes #31872. Supersedes #31873 (mirror-at-job-time approach; this
removes the job-time download entirely).
Problem
Every windows-x64-baseline - verify-baseline run since 2026-06-04
fails before the verifier starts:
Downloading Intel SDE...
Extracting Intel SDE...
1 file, 0 bytes
ERROR: sde.tar.xz
Cannot open the file as archive
downloadmirror.intel.com now fronts all downloads with a bot challenge
that returns HTTP 202 with an empty body to non-browser clients
(verified against multiple file IDs, including the current SDE 10.8
release — the URL we pin is still valid, the host just no longer serves
CLI clients). curl -fsSL treats 202 as success, so the step extracted
a 0-byte tarball.
Fix
Bake SDE into the Windows x64 CI image instead of downloading it on
every run:
bootstrap.ps1: new Install-IntelSde (x64 only) downloads sde-external-9.58.0-2025-06-16-win.tar.xz from our CI blob mirror,
verifies Intel's published SHA256 (EBB8…D9CA9), and extracts the kit
to C:\intel-sde (directory kept intact — sde.exe resolves its Pin DLLs
relative to itself). Image version 19 → 20. The tarball is mirrored
unmodified; the Intel Simplified Software License it ships under permits
redistribution without modification.
ci.mjs: verify-baseline uses the baked C:\intel-sde\sde.exe; the
download/extract lines are gone. The remaining batch lines get || exit /b 1 so a failure stops the step with the real error (cmd.exe otherwise
continues past failed lines — that's why this broke as a confusing 7z
error).
verify-baseline.ts: comment-only; it already resolves absolute
emulator paths and runs SDE from its own directory.
Mirror blob verified anonymously fetchable and byte-identical to
Intel's published SHA256.
The commit message carries [build windows images], so this build
bakes a throwaway image (exercising Install-IntelSde for real) and
runs the Windows jobs against it.
Rollout
After review and a green [build windows images] run: run [publish images] from this branch (~2-3 h) to publish windows-x64-2019-v20, then merge. Merging first would point main's jobs at a
not-yet-published image.
82808d test(sql): use container.host instead of hardcoded localhost in 'Connect using uri' (#31901)
What
One-line fix in test/js/sql/sql.test.ts: the "Connect using uri" test
built its connection string with a hardcoded @​localhost: instead of container.host.
Why
Every other test in the file uses container.host (which respects BUN_DOCKER_TEST_HOST, added in #31731), so they pass against any
Docker setup — local or remote daemon. This one test only worked when
the daemon is on the same machine. Against a remote daemon it fails
instantly with PostgresError: Connection closed, and that single
subtest marks the whole 845-test file as failed even though the other
844 pass.
How verified
With this change, the full sql.test.ts passes (843 pass / 2 todo / 0
fail) against a remote Docker daemon on macOS arm64, and behavior on a
local daemon is unchanged (container.host resolves to 127.0.0.1
there).
a1dd64 resolver: root dir-cache slot pointers at the singleton and drop browser-map borrow erasures (#31836)
The DirInfo dir-cache put() returned a slot pointer derived from a
transient &mut HashMap; because the map's backing buffer is stored
inline, any later fresh reborrow of the singleton invalidated previously
stashed slot pointers under Stacked Borrows, and the only protection was
an unenforced calling convention. put() now re-derives the returned
pointer (and dir_info_cached_miss's parent slot pointer, via a new slot_ptr_at helper) directly from the raw singleton with a raw place
projection, so slot pointers survive sibling map reborrows outright; the
inline-arm bounds check is unconditional (a corrupted index panics,
matching the old at_index failure mode, instead of yielding an
out-of-bounds slot pointer), and dir_info_for_resolution's cache-hit arm
was migrated to the same re-derivation. The browser-map checker
(BrowserMapPath::check_path) stored matched candidate strings back
into the checker through four lifetime-erasing casts into threadlocal
scratch buffers; those stores were dead (callers only read remapped
after a match), so they are removed along with all four erasures. dir_info_uncached no longer materializes &mut RealFS / &mut DirEntry per use: the raw fs pointer is passed straight through to the
lazy-stat helpers and the directory entry is read through a shared
BackRef, matching the existing pattern in load_as_file. New
regression-pin tests cover each probe stage of the browser-map checker
plus the './'-key package-path quirk, and a resolver stress test
resolves through 200 packages and a 30-deep directory chain (kept under
Windows MAX_PATH) to exercise dir-cache slot-pointer stability. These
tests pin behavior parity — all three orders are aliasing hardening /
dead-store removal with no intended behavior change, so they pass before
and after; the actual verification gate is the build plus the
resolver/bundler suites (and Miri-style reasoning recorded in the code
comments). NOT YET RUN: no build or test has been executed on this
branch — the post-cluster build+verify phase mu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Updated Packages