Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
191 commits
Select commit Hold shift + click to select a range
3b109d0
fix(docs): guard normalizeOptions against array labels and prototype …
creazyfrog Apr 30, 2026
0b34853
fix(docs): export normalizeOptions and test real implementation
creazyfrog Apr 30, 2026
1f4ff36
test(docs/controls): add stories for partial labels and array-labels …
Trivenzaa-Admin May 15, 2026
8bebdaf
Fix resolveImport TSX fallback
cyphercodes May 16, 2026
0f46ca5
fix: align resolveImport fallback with oxc resolver
cyphercodes May 22, 2026
dd6b9cf
Merge remote-tracking branch 'upstream/next' into fix-resolve-import-…
cyphercodes May 22, 2026
5e002b8
Initial plan
Copilot May 27, 2026
e65847f
fix: remove webpack lazy compilation import pipeline workaround
Copilot May 27, 2026
e49a84e
Merge latest next into resolve import fallback PR
cyphercodes May 28, 2026
5d3d954
Merge branch 'next' into copilot/revert-workaround-webpack-bug
Sidnioulz May 29, 2026
c51090f
fix: keep import pipeline fallback for webpack < 5.101.3 with lazy co…
Copilot May 29, 2026
a549e3d
fix: handle prerelease version strings in webpack version comparison
Copilot May 29, 2026
0676344
test: add coverage for toImportFn generated code behavior
Copilot May 29, 2026
98565c0
fix: restore SupportedFramework in exports (accidentally removed)
Copilot May 29, 2026
3c1af0c
CI: Restrict trusted CircleCI PR authors to specific teams
Sidnioulz May 29, 2026
3bb369f
Restore trusted author param lost in rebase
Sidnioulz May 29, 2026
21a4ff6
fix(ci): pass trusted-author flag and grant members read permission
Copilot May 29, 2026
0309863
Implement open-service architecture runtime sync
ndelangen Jun 1, 2026
f853c5b
refactor: use semver for version comparison and restore importPipelin…
Copilot Jun 1, 2026
ecf9085
fix: improve version check safety and test type safety
Copilot Jun 1, 2026
736a29b
docs: clarify conservative fallback behavior for unparseable versions
Copilot Jun 1, 2026
13fd63c
fix: scope TSX import fallback to JS imports
cyphercodes Jun 1, 2026
d4dd5a6
Implement open-service architecture runtime sync
ndelangen Jun 1, 2026
0beda2b
Refactor open-service channel integration and enhance state synchroni…
ndelangen Jun 2, 2026
1dc1df2
Enhance open-service integration and background handling
ndelangen Jun 2, 2026
8ec8992
Refactor postMessage integration and clean up unused event exports
ndelangen Jun 2, 2026
abf5677
Enhance ManagerProvider initialization and refine open-service tests
ndelangen Jun 2, 2026
10d2dd5
Refine open-service documentation and enhance type safety in tests
ndelangen Jun 2, 2026
b58178b
Merge branch 'jeppe-cursor/docgen-subscription-referential-equality-5…
ndelangen Jun 2, 2026
5f3eb96
Merge branch 'norbert/service-clients' of github.com:storybookjs/stor…
ndelangen Jun 3, 2026
bd0719a
Refactor open-service registration and channel integration
ndelangen Jun 3, 2026
17d8157
Refactor open-service channel events and enhance synchronization logic
ndelangen Jun 3, 2026
ee68aa1
Refactor open-service imports and enhance build configuration
ndelangen Jun 3, 2026
d6268e2
Refactor global channel assignment in common preset
ndelangen Jun 3, 2026
68c5ca1
Refactor open-service documentation and enhance channel sync tests
ndelangen Jun 3, 2026
88125e7
Merge branch 'next' into norbert/service-clients
ndelangen Jun 3, 2026
034ba47
Remove deprecated `getServiceChannel` export from multiple modules
ndelangen Jun 3, 2026
b61ab95
Merge branch 'norbert/service-clients' of github.com:storybookjs/stor…
ndelangen Jun 3, 2026
1bd402d
Add OpenServiceMissingChannelError for improved error handling
ndelangen Jun 3, 2026
6dcbd33
Update Playwright configuration and add new E2E tests
ndelangen Jun 3, 2026
40d9619
Refactor Open Service API exports for improved clarity and structure
ndelangen Jun 3, 2026
b3f7da7
Refactor Open Service API imports and exports for improved clarity
ndelangen Jun 3, 2026
1e2b76a
Update Playwright configuration and enhance E2E testing setup
ndelangen Jun 3, 2026
4ea789c
Refactor global channel assignment in common preset
ndelangen Jun 3, 2026
a160e59
wip
ndelangen Jun 3, 2026
814168c
Refactor module graph into open service
JReinhold Jun 3, 2026
1978afd
Use kebab-case module graph files
JReinhold Jun 3, 2026
91902ea
Await module graph query loads
JReinhold Jun 4, 2026
417f36a
Remove legacy dependency graph registry
JReinhold Jun 4, 2026
8619d7b
Fix the OOM problem
ndelangen Jun 4, 2026
d3f90f9
Store module graph paths relatively
JReinhold Jun 4, 2026
a3ba897
Refactor channel management in Storybook
ndelangen Jun 4, 2026
26d1e08
Enhance channel management and testing in Storybook
ndelangen Jun 4, 2026
7897559
Drive module graph lifecycle through service status
JReinhold Jun 4, 2026
c6883a3
Refactor channel management and enhance service registration in Story…
ndelangen Jun 4, 2026
96bae6d
cleanup
ndelangen Jun 4, 2026
152ff5b
Simplify module graph status command
JReinhold Jun 4, 2026
01753c3
Remove adapter from change detection start
JReinhold Jun 4, 2026
952b7f0
Refactor Vitest plugin configuration and channel management
ndelangen Jun 4, 2026
654d283
Enhance channel management in Storybook stories
ndelangen Jun 4, 2026
6d8a916
Enhance test setup for service commands and queries
ndelangen Jun 4, 2026
d8181dd
Enhance Vitest configuration and channel management
ndelangen Jun 4, 2026
cb10681
Simplify module graph story changes
JReinhold Jun 4, 2026
7c1a334
Merge base branch into module graph PR
JReinhold Jun 4, 2026
25439eb
Refactor mock channel implementation and introduce test channel
ndelangen Jun 4, 2026
e6c885e
Merge branch 'next' into norbert/service-clients
ndelangen Jun 4, 2026
b3df163
Update channel type casting in AddonStore
ndelangen Jun 4, 2026
7386dd2
Merge branch 'norbert/service-clients' of github.com:storybookjs/stor…
ndelangen Jun 4, 2026
ae57be7
Add internal open-service visibility
JReinhold Jun 4, 2026
121eacb
Fix internal operation type inference
JReinhold Jun 4, 2026
715e480
Merge branch 'next' into norbert/service-clients
ndelangen Jun 5, 2026
e3a77cc
Refactor: Update background service registration import path
ndelangen Jun 5, 2026
88bd895
chore: Add TypeScript configuration for Storybook
ndelangen Jun 5, 2026
323725b
Refactor: Remove redundant global channel assignment in initTransport…
ndelangen Jun 5, 2026
9957d28
Refactor: Replace global object references with globalThis in channel…
ndelangen Jun 5, 2026
62a1bc7
Refactor: Remove channel assignment from common preset service initia…
ndelangen Jun 5, 2026
86afb92
Refactor: Consolidate mockChannel import paths and remove unused files
ndelangen Jun 5, 2026
b11f8d4
Refactor: Update import paths for getChannel in globals-runtime and r…
ndelangen Jun 5, 2026
5136549
Refactor: Update channel management in Storybook stories
ndelangen Jun 5, 2026
829b7e0
Refactor: Update import path for channel management in addons module
ndelangen Jun 5, 2026
e7323c5
Refactor: Simplify telemetry error handling in runtime
ndelangen Jun 5, 2026
bbb594d
Refactor: Remove open-service client module
ndelangen Jun 5, 2026
80c2529
Refactor: Remove state schema validation from open-service module
ndelangen Jun 5, 2026
ef87843
Merge branch 'next' into norbert/service-clients
ndelangen Jun 5, 2026
d506661
Refactor: Enhance error handling in channel-slot tests
ndelangen Jun 5, 2026
2b11a51
Refactor: Update channel type casting in addon store
ndelangen Jun 5, 2026
5551ec9
Refactor: Restrict query and command overrides in service registry
ndelangen Jun 5, 2026
ad42215
Refactor: Enhance validation in parseStampedSnapshot function
ndelangen Jun 5, 2026
8e8a1d3
Refactor: Remove unnecessary wait time in open-service background tests
ndelangen Jun 5, 2026
0922f88
Add ref-based components manifest index backed by the docgen open ser…
JReinhold Jun 5, 2026
60873aa
Refactor: Add undefined output query service fixture and update tests
ndelangen Jun 5, 2026
a6c1bb0
Refactor: Update global channel options handling in PostMessageTransp…
ndelangen Jun 5, 2026
22412f5
wip
ndelangen Jun 5, 2026
1336062
Refactor: Standardize channel options handling in PostMessageTranspor…
ndelangen Jun 5, 2026
1f19c67
Fix static build fixture state typing
JReinhold Jun 5, 2026
28c385f
Docs: Add test proving scroll is reset across nav
Sidnioulz May 29, 2026
8eda228
Slim down components manifest ref handling
JReinhold Jun 5, 2026
17fa0b9
Build components.html from docgen snapshots instead of re-extracting
JReinhold Jun 5, 2026
747b49c
Merge branch 'norbert/service-clients' into norbert/remote-command-ex…
ndelangen Jun 5, 2026
434e664
Refactor: Improve documentation for remote command execution in README
ndelangen Jun 5, 2026
333f57c
Merge branch 'norbert/remote-command-execution' of github.com:storybo…
ndelangen Jun 5, 2026
c787726
Add preventDefault to interaction debugger controls
BrenoSI03 Jun 5, 2026
641036a
Merge branch 'next' into jeppe-cursor/0e545a17
JReinhold Jun 5, 2026
2e90f3f
Fix format and DocgenPayload type compatibility
JReinhold Jun 5, 2026
e1cde36
Agentic Setup: Revert ai init flag default value
Sidnioulz Jun 5, 2026
0657cc9
Merge branch 'next' into sidnioulz/double-gate-ai-optin
Sidnioulz Jun 5, 2026
1195a1e
Docs: Deprecate ExternalDocs
Sidnioulz Jun 5, 2026
3930029
Merge base branch and resolve docgen server conflict
JReinhold Jun 5, 2026
d7684ee
Merge branch 'next' into copilot/revert-workaround-webpack-bug
Sidnioulz Jun 5, 2026
fc7b6f9
Merge branch 'next' into copilot/revert-workaround-webpack-bug
Sidnioulz Jun 5, 2026
903f5d8
Merge branch 'next' into jeppe-cursor/39213f22
JReinhold Jun 5, 2026
ffc37d0
Add missing lockfile changes
Sidnioulz Jun 5, 2026
d571fa0
Apply suggestion from @Sidnioulz
Sidnioulz Jun 5, 2026
331367e
Fix permissions
Sidnioulz Jun 5, 2026
a90a725
fix(controls): handle undefined label values in normalizeOptions
creazyfrog Jun 5, 2026
2ddbc3f
Merge pull request #35063 from storybookjs/jeppe-cursor/39213f22
JReinhold Jun 5, 2026
4970cdf
fix(viewport): highlight toolbar button when custom viewport is activ…
derinbarutcu17 Jun 5, 2026
5877d59
style(controls): fix oxfmt formatting in Options.test.ts
creazyfrog Jun 5, 2026
ef9f323
Merge pull request #35068 from storybookjs/norbert/remote-command-exe…
JReinhold Jun 5, 2026
f7a30cb
Merge branch 'next-release' into next
storybook-bot Jun 5, 2026
191b318
Merge branch 'next' into norbert/service-clients
JReinhold Jun 5, 2026
743764e
refactor(open-service): tidy channel transport, deps, and query hook …
JReinhold Jun 5, 2026
e5f7408
Manager: Keep local preview iframe on host URL when a ref story loads…
TheSeydiCharyyev Jun 6, 2026
57ab839
refactor(open-service): schema-validate channel payloads and constrai…
JReinhold Jun 6, 2026
5905767
Add open-service sync demos
JReinhold Jun 6, 2026
182c107
Format open-service sync demos
JReinhold Jun 6, 2026
17e1200
Fix open-service sync type errors
JReinhold Jun 6, 2026
e79ab39
Pass refId: undefined explicitly for the local preview iframe
TheSeydiCharyyev Jun 6, 2026
062e88b
Revert unrelated addon-vitest configureVitest change
JReinhold Jun 6, 2026
ccccfc0
ci: retry CircleCI after flaky portable-react E2E
JReinhold Jun 6, 2026
78e4393
Merge pull request #35017 from storybookjs/norbert/service-clients
JReinhold Jun 6, 2026
7ef5919
fix(telemetry): add timeout to event-log POST to prevent build hang
badams Jun 7, 2026
72f3722
Update tests
Sidnioulz Jun 8, 2026
07163ba
Merge pull request #34973 from storybookjs/sidnioulz/e2e-test-scroll-…
Sidnioulz Jun 8, 2026
1ea9136
Merge pull request #34975 from storybookjs/sidnioulz/restrict-trusted…
Sidnioulz Jun 8, 2026
5737967
Undo TS changes to test
Sidnioulz Jun 8, 2026
23bcfb9
Merge pull request #35053 from storybookjs/sidnioulz/double-gate-ai-o…
yannbf Jun 8, 2026
17e6248
Merge branch 'next' into fix/control-option-reverse-array-prototype-c…
Sidnioulz Jun 8, 2026
9b194a2
Merge pull request #35085 from badams/fix/telemetry-fetch-timeout
Sidnioulz Jun 8, 2026
e43e860
Merge pull request #34815 from cyphercodes/fix-resolve-import-tsx-fal…
Sidnioulz Jun 8, 2026
abc7af8
Merge branch 'next' into fix/control-option-reverse-array-prototype-c…
Sidnioulz Jun 8, 2026
ce685da
Merge pull request #35074 from storybookjs/sidnioulz/deprecate-extern…
Sidnioulz Jun 8, 2026
fb56c4e
Merge branch 'next' into jeppe-cursor/0e545a17
JReinhold Jun 8, 2026
2b3fa5f
Merge branch 'next' into fix/viewport-toolbar-active-state-35067
Sidnioulz Jun 8, 2026
c3e3205
Merge pull request #34931 from storybookjs/copilot/revert-workaround-…
Sidnioulz Jun 8, 2026
2949311
Merge pull request #35057 from storybookjs/jeppe-cursor/0e545a17
JReinhold Jun 8, 2026
986a227
Merge pull request #35073 from BrenoSI03/feature-add-prevent-default-…
Sidnioulz Jun 8, 2026
f3965b5
style: Reformat
Sidnioulz Jun 8, 2026
9307f24
fix: inject core annotations exactly once for non-CSF4 stories under …
JReinhold Jun 8, 2026
c9b1aea
fix: resolve CI format and type errors in core annotation tests
JReinhold Jun 8, 2026
311ce3a
Use the Icons composed ref in the FramesRenderer story
TheSeydiCharyyev Jun 9, 2026
3e6d6c6
Make getGraphRevision scope-aware and ignore out-of-graph changes.
JReinhold Jun 9, 2026
6ce2b2b
Build: Bump Node.js to 22.22.3
valentinpalkovic May 22, 2026
c05728a
Merge branch 'next' and fix open-service integration regressions.
JReinhold Jun 9, 2026
af8067b
Clear stale latestChangedStoryFiles on non-update revision bumps.
JReinhold Jun 9, 2026
ba992dd
Fix open-service query load wiring after registration API change.
JReinhold Jun 9, 2026
3759688
Fix bench-packages BigQuery error when baseBranch is boolean
circleci-app[bot] Jun 9, 2026
9c40f77
Update CHANGELOG.md for v10.4.2 [skip ci]
storybook-bot Jun 9, 2026
8e73765
Merge pull request #34664 from creazyfrog/fix/control-option-reverse-…
Sidnioulz Jun 9, 2026
d4535cf
Merge pull request #35075 from derinbarutcu17/fix/viewport-toolbar-ac…
Sidnioulz Jun 9, 2026
b0c55cf
Merge pull request #35100 from storybookjs/chunk/fix-bench-packages-b…
Sidnioulz Jun 9, 2026
d5f75ee
Merge pull request #35078 from TheSeydiCharyyev/fix/framesrenderer-re…
Sidnioulz Jun 9, 2026
4dcfdcf
Replace module-graph settlement bridge with waitForSettledEngine comm…
JReinhold Jun 9, 2026
9b3e49f
Open service: route load-body commands through channel for peer ops
JReinhold Jun 9, 2026
4df04f6
React: fix subcomponent prop extraction without JSX usage
JReinhold Jun 9, 2026
48ebf57
Merge branch 'next' into split/open-service-load-body-commands
JReinhold Jun 9, 2026
3bef442
Merge branch 'next' into split/rcm-subcomponent-prop-extraction
JReinhold Jun 9, 2026
6f7b4a7
Angular: Fix @angular/forms version to 21 in sandbox
Sidnioulz Jun 9, 2026
065be44
React: restore original RCM inline comments after refactor
JReinhold Jun 9, 2026
f37fa24
OpenService: restore getService overloads for definition and instance…
JReinhold Jun 9, 2026
1bd10bf
Revert "OpenService: restore getService overloads for definition and …
JReinhold Jun 9, 2026
753d1ca
OpenService: use DocgenService instance type in manifests getService …
JReinhold Jun 9, 2026
78ea919
Merge branch 'next' into sidnioulz/fix-angular-forms-version
Sidnioulz Jun 9, 2026
79b2e1f
Merge pull request #35112 from storybookjs/sidnioulz/fix-angular-form…
Sidnioulz Jun 9, 2026
b51cd54
React: fix member and namespace subcomponent prop resolution
JReinhold Jun 9, 2026
a899ec5
Merge branch 'next' into split/rcm-subcomponent-prop-extraction
JReinhold Jun 9, 2026
2fddfe3
React: use memfs mirror for story reads in RCM project tests
JReinhold Jun 9, 2026
80d5f38
Fix eslint and internal e2e CI failures.
JReinhold Jun 9, 2026
677e322
simplify engine assignment
JReinhold Jun 9, 2026
a1f5ea6
Add getLatestStoryChanges tests and precompute docgen component lookups.
JReinhold Jun 9, 2026
8522045
Merge pull request #35107 from storybookjs/split/rcm-subcomponent-pro…
JReinhold Jun 9, 2026
a2971d9
Merge pull request #35094 from storybookjs/jeppe-cursor/a236965c
JReinhold Jun 9, 2026
01b3bc0
Merge pull request #35048 from storybookjs/jeppe-cursor/4b72cdff
JReinhold Jun 9, 2026
6c2ca41
OpenService: address PR review on test cleanup and remoteCommandNames
JReinhold Jun 10, 2026
c379225
Merge branch 'next' into split/open-service-load-body-commands
JReinhold Jun 10, 2026
685a186
ci: fail build when compile leaves uncommitted changes
JReinhold Jun 10, 2026
1e41430
Merge branch 'next' into ci/check-git-clean-after-build
JReinhold Jun 10, 2026
acd0f7d
fix(open-service): migrate moduleGraph getService callsites to instan…
JReinhold Jun 10, 2026
dda0188
Merge pull request #35106 from storybookjs/split/open-service-load-bo…
JReinhold Jun 10, 2026
514a19b
Merge pull request #35123 from storybookjs/ci/check-git-clean-after-b…
JReinhold Jun 10, 2026
c47e6a8
Write changelog for 10.5.0-alpha.6 [skip ci]
storybook-bot Jun 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions .github/workflows/trigger-circle-ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,37 @@ jobs:
- id: trusted-author
env:
EVENT_NAME: ${{ github.event_name }}
ASSOCIATION: ${{ github.event.pull_request.author_association }}
USER_TYPE: ${{ github.event.pull_request.user.type }}
USER_LOGIN: ${{ github.event.pull_request.user.login }}
GITHUB_API_TOKEN: ${{ secrets.STORYBOOKJS_ORG_MEMBERSHIP_TOKEN }}
run: |
# You can only push to `main` and `next` as a core team member, so the content is trustworthy.
if [ "$EVENT_NAME" = "push" ]; then
echo "result=true" >> "$GITHUB_OUTPUT"
# These commits are made by the release actions, which are gated to core team members.
elif [ "$USER_LOGIN" = "github-actions[bot]" ] && [ "$USER_TYPE" = "Bot" ]; then
echo "result=true" >> "$GITHUB_OUTPUT"
# Trusted members of the organization can also write to cache (core team, DX, and a few maintainers)
elif { [ "$ASSOCIATION" = "OWNER" ] || [ "$ASSOCIATION" = "MEMBER" ]; } && [ "$USER_TYPE" != "Bot" ]; then
echo "result=true" >> "$GITHUB_OUTPUT"
else
echo "result=false" >> "$GITHUB_OUTPUT"
# Explicitly trust only members of specific Storybook teams.
# Team slugs for: Maintainers, Core, Developer Experience.
TRUSTED_TEAMS="maintainers core developer-experience"
IS_TRUSTED=false

for TEAM in $TRUSTED_TEAMS; do
STATE=$(curl -fsSL \
-H "Authorization: Bearer $GITHUB_API_TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/orgs/storybookjs/teams/$TEAM/memberships/$USER_LOGIN" \
| jq -r '.state' 2>/dev/null || true)

if [ "$STATE" = "active" ]; then
IS_TRUSTED=true
break
fi
done

echo "result=$IS_TRUSTED" >> "$GITHUB_OUTPUT"
fi
outputs:
workflow: ${{ steps.normal.outputs.workflow || steps.docs.outputs.workflow || steps.merged.outputs.workflow || steps.daily.outputs.workflow }}
Expand All @@ -129,12 +145,14 @@ jobs:
WORKFLOW: ${{ needs.get-parameters.outputs.workflow }}
GH_BASE_BRANCH: ${{ needs.get-parameters.outputs.ghBaseBranch }}
GH_PR_NUMBER: ${{ needs.get-parameters.outputs.ghPrNumber }}
GH_TRUSTED_AUTHOR: ${{ needs.get-parameters.outputs.ghTrustedAuthor }}
run: |
PARAMETERS=$(jq -nc \
--arg workflow "$WORKFLOW" \
--arg ghBaseBranch "$GH_BASE_BRANCH" \
--arg ghPrNumber "$GH_PR_NUMBER" \
'{workflow: $workflow, ghBaseBranch: $ghBaseBranch, ghPrNumber: $ghPrNumber}')
--arg ghTrustedAuthor "$GH_TRUSTED_AUTHOR" \
'{workflow: $workflow, ghBaseBranch: $ghBaseBranch, ghPrNumber: $ghPrNumber, ghTrustedAuthor: $ghTrustedAuthor}')
PAYLOAD=$(jq -nc --arg branch "$BRANCH" --argjson parameters "$PARAMETERS" \
'{branch: $branch, parameters: $parameters}')
curl -sS --fail-with-body -X POST \
Expand Down
25 changes: 18 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This file is the canonical instruction source for coding agents. Files like `CLA
Storybook is a large TypeScript monorepo. The git root is the repo root, the main code lives in `code/`, and build tooling lives in `scripts/`. The default branch is `next`.

- **Base branch**: `next` (all PRs should target `next`, not `main`)
- **Node.js**: `22.12+` (see `.nvmrc`) — supports `.ts` natively via type stripping (no loader needed)
- **Node.js**: `22.22.3` (see `.nvmrc`) — supports `.ts` natively via type stripping (no loader needed)
- **Package Manager**: Yarn Berry
- **Task orchestration**: NX plus the custom `yarn task` runner
- **CI environment**: Linux and Windows
Expand Down Expand Up @@ -243,6 +243,17 @@ When writing unit tests (utilities, hooks, non-React modules):
- Use coverage when useful: `yarn vitest run --coverage <test-file>`
- Mock external dependencies like file system access and loggers

### Filesystem tests with `memfs`

For unit tests that touch `node:fs` / `node:fs/promises`, use [`memfs`](https://github.com/streamich/memfs) instead of real temp directories or wholesale `node:fs` mocks:

- Import `vol` from `memfs` and call `vol.reset()` in `beforeEach`
- Seed virtual files with `vol.fromNestedJSON({ '/absolute/path/file.json': '...' })` or memfs `writeFile` after redirecting spies
- Use `vi.mock('node:fs/promises', { spy: true })` and, in `beforeEach`, point `mkdir` / `writeFile` / `readFile` at `memfs.fs.promises` (see `code/core/src/shared/open-service/server.test.ts`)
- Assert disk state with `vol.toJSON()` when helpful

Do **not** use `/tmp` paths or replace `node:fs/promises` with a full async factory mock unless a test file already standardizes on the spy redirect pattern above.

## Quality and Logging

After changing files:
Expand Down Expand Up @@ -273,12 +284,12 @@ Avoid `console.log`, `console.warn`, and `console.error` unless the file is isol

## Environment Variables

| Variable | Purpose |
| ----------------------------- | --------------------------- |
| `IN_STORYBOOK_SANDBOX` | Set during sandbox creation |
| `STORYBOOK_DISABLE_TELEMETRY` | Disable telemetry |
| `STORYBOOK_TELEMETRY_DEBUG` | Log telemetry events |
| `DEBUG` | Enable debug logging |
| Variable | Purpose |
| ----------------------------- | ----------------------------------------------- |
| `IN_STORYBOOK_SANDBOX` | Set during sandbox creation |
| `STORYBOOK_DISABLE_TELEMETRY` | Disable telemetry |
| `STORYBOOK_TELEMETRY_DEBUG` | Log telemetry events |
| `DEBUG` | Enable debug logging |
| `FIX_ON_COMMIT` | Force autofix for fmt & lint in pre-commit hook |

## Commands To Avoid
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## 10.5.0-alpha.6

- Controls: Guard normalizeOptions against array labels and prototype chain lookups - [#34664](https://github.com/storybookjs/storybook/pull/34664), thanks @creazyfrog!
- Core: Add ref-based components manifest index backed by docgen open service - [#35063](https://github.com/storybookjs/storybook/pull/35063), thanks @JReinhold!
- Core: Fix resolveImport TSX fallback - [#34815](https://github.com/storybookjs/storybook/pull/34815), thanks @cyphercodes!
- Core: Rework AI checklist feature gate - [#35053](https://github.com/storybookjs/storybook/pull/35053), thanks @Sidnioulz!
- Docs: Deprecate ExternalDocs - [#35074](https://github.com/storybookjs/storybook/pull/35074), thanks @Sidnioulz!
- Interactions: Prevent debugger controls from stealing focus - [#35073](https://github.com/storybookjs/storybook/pull/35073), thanks @BrenoSI03!
- Manager: Keep local preview iframe on host URL when a ref story loads first - [#35078](https://github.com/storybookjs/storybook/pull/35078), thanks @TheSeydiCharyyev!
- Module Graph: Refactor from StoryDependencyService to open service-based ModuleGraphService - [#35048](https://github.com/storybookjs/storybook/pull/35048), thanks @JReinhold!
- Open Service: Add `internal` property to control visibility - [#35057](https://github.com/storybookjs/storybook/pull/35057), thanks @JReinhold!
- Open Service: Add sync between server, manager and preview - [#35017](https://github.com/storybookjs/storybook/pull/35017), thanks @ndelangen!
- Open Service: Call remote commands in load functions - [#35106](https://github.com/storybookjs/storybook/pull/35106), thanks @JReinhold!
- Preview: Stop mixed CSF3+4 stories getting core annotations injected twice - [#35094](https://github.com/storybookjs/storybook/pull/35094), thanks @JReinhold!
- React: Fix subcomponent prop extraction without JSX usage - [#35107](https://github.com/storybookjs/storybook/pull/35107), thanks @JReinhold!
- Telemetry: Add timeout to event-log POST to prevent build hang - [#35085](https://github.com/storybookjs/storybook/pull/35085), thanks @badams!
- Viewport: Highlight toolbar button when custom viewport is active - [#35075](https://github.com/storybookjs/storybook/pull/35075), thanks @derinbarutcu17!
- Webpack: Gate lazy-compilation import pipeline on webpack version - [#34931](https://github.com/storybookjs/storybook/pull/34931), thanks @copilot-swe-agent!

## 10.5.0-alpha.5

- Addon Docs: DocsContent not filling available width when TOC is enabled - [#35043](https://github.com/storybookjs/storybook/pull/35043), thanks @k-utsumi!
Expand Down
12 changes: 11 additions & 1 deletion MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<h1>Migration</h1>

- [From version 10.4.0 to 10.5.0](#from-version-1040-to-1050)
- [ExternalDocs and ExternalDocsContainer are deprecated](#externaldocs-and-externaldocscontainer-are-deprecated)
- [From version 10.3.0 to 10.4.0](#from-version-1030-to-1040)
- [React Native: on-device addons moved to `deviceAddons`](#react-native-on-device-addons-moved-to-deviceaddons)
- [TanStack React: migrate from `@storybook/react-vite` to `@storybook/tanstack-react`](#tanstack-router-projects-migrate-from-storybookreact-vite-to-storybooktanstack-react)
- [TanStack Router projects: migrate from `@storybook/react-vite` to `@storybook/tanstack-react`](#tanstack-router-projects-migrate-from-storybookreact-vite-to-storybooktanstack-react)
- [From version 10.0.0 to 10.1.0](#from-version-1000-to-1010)
- [API and Component Changes](#api-and-component-changes)
- [Button Component API Changes](#button-component-api-changes)
Expand Down Expand Up @@ -523,6 +525,14 @@
- [Packages renaming](#packages-renaming)
- [Deprecated embedded addons](#deprecated-embedded-addons)

## From version 10.4.0 to 10.5.0

### ExternalDocs and ExternalDocsContainer are deprecated

The `ExternalDocs` and `ExternalDocsContainer` components from `@storybook/addon-docs` are deprecated and will be removed in Storybook 11. These components allowed rendering Storybook docs pages outside of the Storybook UI, but the approach was never stabilized and is redundant with other embedding options.

If you are currently using `ExternalDocs` or `ExternalDocsContainer`, please open an issue describing your use case so the team can consider alternative solutions.

## From version 10.3.0 to 10.4.0

### React Native: on-device addons moved to `deviceAddons`
Expand Down
12 changes: 11 additions & 1 deletion code/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const config = defineMain({
directory: '../core/src/preview',
titlePrefix: 'preview',
},
{
directory: '../core/src/shared',
titlePrefix: 'core/shared',
},
{
directory: '../core/src/components/brand',
titlePrefix: 'brand',
Expand Down Expand Up @@ -184,7 +188,13 @@ const config = defineMain({
server: {
watch: {
// Something odd happens with tsconfig and nx which causes Storybook to keep reloading, so we ignore them
ignored: ['**/.nx/cache/**', '**/tsconfig.json'],
ignored: [
'**/.nx/cache/**',
'**/tsconfig.json',
// Internal e2e writes traces under code/playwright-results while the dev server is running.
'**/playwright-results/**',
'**/playwright-report/**',
],
},
},
} satisfies typeof viteConfig);
Expand Down
2 changes: 2 additions & 0 deletions code/.storybook/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ addons.setConfig({
renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)),
},
});

import '../core/src/shared/open-service/sync-test/manager.tsx';
2 changes: 1 addition & 1 deletion code/.storybook/open-service-debug-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as v from 'valibot';
import { logger } from 'storybook/internal/node-logger';
import type { StoryIndexGenerator } from '../core/src/core-server/utils/StoryIndexGenerator.ts';

import { defineService } from '../core/src/shared/open-service/index.ts';
import { defineService } from 'storybook/open-service';
import { describeService, registerService } from '../core/src/shared/open-service/server.ts';

const DEBUG_SERVICE_ID = 'storybook/internal/open-service-debug';
Expand Down
2 changes: 2 additions & 0 deletions code/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ sb.mock(import('lodash-es/sum'));
sb.mock(import('uuid'));
/* eslint-enable depend/ban-dependencies */

import '../core/src/shared/open-service/sync-test/preview.ts';

const { document } = global;
globalThis.CONFIG_TYPE = 'DEVELOPMENT';

Expand Down
9 changes: 5 additions & 4 deletions code/.storybook/services-preset.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { Options, StorybookConfigRaw } from 'storybook/internal/types';

import { registerOpenServiceSyncDemos } from '../core/src/shared/open-service/sync-test/server.ts';
import { registerOpenServiceDebugService } from './open-service-debug-service.ts';

/**
* Preset hook that registers the internal open-service debug service.
* Preset hook that registers internal open-service examples and the opt-in debug service.
*
* Lives in its own preset file so the `services` slot stays out of the public `StorybookConfig`
* surface while still letting the internal Storybook self-test the registration path. Set
* `STORYBOOK_OPEN_SERVICE_DEBUG=true` to opt in.
* Set `STORYBOOK_OPEN_SERVICE_DEBUG=true` to additionally register the debug service.
*/
export const services = async (_value: void, options: Options): Promise<void> => {
registerOpenServiceSyncDemos();

if (process.env.STORYBOOK_OPEN_SERVICE_DEBUG === 'true') {
await registerOpenServiceDebugService(
options.presets.apply<NonNullable<StorybookConfigRaw['storyIndexGenerator']>>(
Expand Down
1 change: 1 addition & 0 deletions code/.storybook/storybook.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { setProjectAnnotations } from '@storybook/react';
import { userEvent as storybookEvent, expect as storybookExpect } from 'storybook/test';

import '../core/src/shared/utils/toHaveLiveRegion.ts';

import preview from './preview.tsx';

vi.spyOn(console, 'warn').mockImplementation((...args) => console.log(...args));
Expand Down
4 changes: 4 additions & 0 deletions code/.storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.json",
"include": ["**/*"]
}
2 changes: 2 additions & 0 deletions code/addons/docs/src/blocks/blocks/external/ExternalDocs.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { PropsWithChildren } from 'react';
import React, { useRef } from 'react';

import { deprecate } from 'storybook/internal/client-logger';
import type { ProjectAnnotations, Renderer } from 'storybook/internal/types';

import { composeConfigs } from 'storybook/preview-api';
Expand All @@ -27,6 +28,7 @@ export function ExternalDocs<TRenderer extends Renderer = Renderer>({
projectAnnotationsList,
children,
}: PropsWithChildren<ExternalDocsProps<TRenderer>>) {
deprecate(`ExternalDocs is deprecated and will be removed in Storybook 11.`);
const projectAnnotations = composeConfigs<TRenderer>(projectAnnotationsList);
const preview = usePreview<TRenderer>(projectAnnotations);
const docsParameter = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';

import { deprecate } from 'storybook/internal/client-logger';
import type { Renderer } from 'storybook/internal/types';

import { ThemeProvider, ensure, themes } from 'storybook/theming';
Expand All @@ -12,6 +13,7 @@ let preview: ExternalPreview<Renderer>;
export const ExternalDocsContainer: React.FC<
React.PropsWithChildren<{ projectAnnotations: any }>
> = ({ projectAnnotations, children }) => {
deprecate(`ExternalDocsContainer is deprecated and will be removed in Storybook 11.`);
if (!preview) {
preview = new ExternalPreview(projectAnnotations);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const labels = {
Cat: 'Catwoman',
Rat: 'Ratwoman',
};
// Only `Bat` is labelled; `Cat` and `Rat` should fall back to String(item).
const partialLabels = {
Bat: 'Batwoman',
};
// Options that collide with Array.prototype method names — the regression case.
const prototypeCollisionOptions = ['reverse', 'map', 'filter'];
const objectOptions = {
A: { id: 'Aardvark' },
B: { id: 'Bat' },
Expand Down Expand Up @@ -70,6 +76,57 @@ export const ArrayInlineLabels: Story = {
},
};

// Partial labels: only 'Bat' is mapped; 'Cat' and 'Rat' fall back to String(item).
export const ArrayLabelsPartial: Story = {
args: {
value: [arrayOptions[0]],
labels: partialLabels,
},
};

export const ArrayInlineLabelsPartial: Story = {
args: {
type: 'inline-check',
value: [arrayOptions[1], arrayOptions[2]],
labels: partialLabels,
},
};

// Regression: when `labels` is emitted as an array by docgen (e.g. Svelte),
// options whose names match Array.prototype methods previously showed
// `function reverse() { [native code] }` instead of the option's string value.
// With the fix, each option must display as String(item) — 'reverse', 'map', 'filter'.
export const ArrayLabelsIsArray: Story = {
name: 'Array Labels (docgen array — prototype-collision fix)',
args: {
value: [prototypeCollisionOptions[0]],
argType: { options: prototypeCollisionOptions },
labels: ['Reverse', 'Map', 'Filter'] as any,
},
argTypes: {
value: {
control: { type: 'check' },
options: prototypeCollisionOptions,
},
},
};

export const ArrayInlineLabelsIsArray: Story = {
name: 'Array Inline Labels (docgen array — prototype-collision fix)',
args: {
type: 'inline-check',
value: [prototypeCollisionOptions[0], prototypeCollisionOptions[1]],
argType: { options: prototypeCollisionOptions },
labels: ['Reverse', 'Map', 'Filter'] as any,
},
argTypes: {
value: {
control: { type: 'inline-check' },
options: prototypeCollisionOptions,
},
},
};

export const ArrayUndefined: Story = {
args: {
value: undefined,
Expand Down
51 changes: 51 additions & 0 deletions code/addons/docs/src/blocks/controls/options/Options.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, expect, it } from 'vitest';

import { normalizeOptions } from './Options';

describe('normalizeOptions', () => {
it('uses String(item) as label when no labels map is provided', () => {
expect(normalizeOptions(['a', 'b', 'c'])).toEqual({ a: 'a', b: 'b', c: 'c' });
});

it('uses labels map when provided with matching keys', () => {
const labels = { a: 'Option A', b: 'Option B' };
expect(normalizeOptions(['a', 'b'], labels)).toEqual({
'Option A': 'a',
'Option B': 'b',
});
});

it('falls back to String(item) for items missing from labels map', () => {
const labels = { a: 'Option A' };
expect(normalizeOptions(['a', 'b'], labels)).toEqual({
'Option A': 'a',
b: 'b',
});
});

it('falls back to String(item) when a label key exists but its value is undefined', () => {
// Regression guard: { reverse: undefined } previously printed "undefined" as the label
// because Object.hasOwn found the key before we checked the value type.
const labels = { Bat: undefined as any, Cat: 'Catwoman' };
expect(normalizeOptions(['Bat', 'Cat'], labels)).toEqual({
Bat: 'Bat',
Catwoman: 'Cat',
});
});

it('does not resolve Array.prototype methods when labels is an array (issue #30142)', () => {
// When Svelte docgen incorrectly passes an array as `labels`, items whose name
// matches an Array prototype method (e.g. 'reverse') must NOT resolve to the
// native function — they should fall back to String(item).
const labelsAsArray: any = ['first', 'second', 'third'];
const options = ['reverse', 'map', 'filter'];
const result = normalizeOptions(options, labelsAsArray);
expect(result).toEqual({ reverse: 'reverse', map: 'map', filter: 'filter' });
expect(Object.keys(result as object)).not.toContain('function reverse() { [native code] }');
});

it('returns the options object unchanged when options is not an array', () => {
const obj = { 'Option A': 'a', 'Option B': 'b' };
expect(normalizeOptions(obj as any)).toBe(obj);
});
});
Loading
Loading