@aussieljk/forkbook 0.0.0-stage → 0.0.1-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +77 -2
- package/assets/addon-vitest/templates/vitest.config.4.template.ts +36 -0
- package/assets/browser/favicon-wrapper.svg +46 -0
- package/assets/browser/favicon.svg +1 -0
- package/assets/browser/nunito-sans-bold-italic.woff2 +0 -0
- package/assets/browser/nunito-sans-bold.woff2 +0 -0
- package/assets/browser/nunito-sans-italic.woff2 +0 -0
- package/assets/browser/nunito-sans-regular.woff2 +0 -0
- package/assets/builder-vite/iframe.html +99 -0
- package/assets/create/rendererAssets/.eslintrc.json +16 -0
- package/assets/create/rendererAssets/common/Configure.mdx +388 -0
- package/assets/create/rendererAssets/common/assets/accessibility.png +0 -0
- package/assets/create/rendererAssets/common/assets/accessibility.svg +1 -0
- package/assets/create/rendererAssets/common/assets/addon-library.png +0 -0
- package/assets/create/rendererAssets/common/assets/assets.png +0 -0
- package/assets/create/rendererAssets/common/assets/avif-test-image.avif +0 -0
- package/assets/create/rendererAssets/common/assets/context.png +0 -0
- package/assets/create/rendererAssets/common/assets/discord.svg +1 -0
- package/assets/create/rendererAssets/common/assets/docs.png +0 -0
- package/assets/create/rendererAssets/common/assets/figma-plugin.png +0 -0
- package/assets/create/rendererAssets/common/assets/github.svg +1 -0
- package/assets/create/rendererAssets/common/assets/share.png +0 -0
- package/assets/create/rendererAssets/common/assets/styling.png +0 -0
- package/assets/create/rendererAssets/common/assets/testing.png +0 -0
- package/assets/create/rendererAssets/common/assets/theming.png +0 -0
- package/assets/create/rendererAssets/common/assets/tutorials.svg +1 -0
- package/assets/create/rendererAssets/common/assets/youtube.svg +1 -0
- package/assets/create/rendererAssets/common/button.css +30 -0
- package/assets/create/rendererAssets/common/header.css +32 -0
- package/assets/create/rendererAssets/common/page.css +68 -0
- package/assets/create/templates/react-native/index.expo.js +20 -0
- package/assets/create/templates/react-native/index.js +25 -0
- package/assets/docs/addon-backgrounds.gif +0 -0
- package/assets/docs/addon-controls-args-annotated.png +0 -0
- package/assets/docs/addon-controls-args-background-color.png +0 -0
- package/assets/docs/addon-controls-args-background-string.png +0 -0
- package/assets/docs/addon-controls-args-docs.png +0 -0
- package/assets/docs/addon-controls-args-logging.png +0 -0
- package/assets/docs/addon-controls-args-no-annotation.png +0 -0
- package/assets/docs/addon-controls-args-reflow-slider.png +0 -0
- package/assets/docs/addon-controls-args-reflow.png +0 -0
- package/assets/docs/addon-controls-args-template.png +0 -0
- package/assets/docs/addon-controls-expanded.png +0 -0
- package/assets/docs/addon-controls-hero.gif +0 -0
- package/assets/docs/addon-controls-install.png +0 -0
- package/assets/docs/hero.gif +0 -0
- package/assets/docs/highlight.png +0 -0
- package/assets/docs/message-reference.png +0 -0
- package/assets/docs/viewport.png +0 -0
- package/assets/react-native/metro-env.d.ts +69 -0
- package/assets/server/addon.tsconfig.json +6 -0
- package/assets/server/base-preview-body.html +116 -0
- package/assets/server/base-preview-head.html +494 -0
- package/assets/server/openBrowser.applescript +94 -0
- package/assets/server/template.ejs +87 -0
- package/dist/.build-stamp +0 -0
- package/dist/_browser-chunks/Color-PCLE2J36.js +1025 -0
- package/dist/_browser-chunks/DocsRenderer-JXND3PVQ.js +10 -0
- package/dist/_browser-chunks/WithTooltip-XSQFTBMB.js +1619 -0
- package/dist/_browser-chunks/chunk-2JDQ35OA.js +247 -0
- package/dist/_browser-chunks/chunk-2JT76G3E.js +104 -0
- package/dist/_browser-chunks/chunk-2MEPHP35.js +17 -0
- package/dist/_browser-chunks/chunk-2SCZVUKW.js +24 -0
- package/dist/_browser-chunks/chunk-46Z7NGAS.js +41 -0
- package/dist/_browser-chunks/chunk-4ATQOMJB.js +30 -0
- package/dist/_browser-chunks/chunk-52CW7FF7.js +49 -0
- package/dist/_browser-chunks/chunk-5I7E4GMO.js +62 -0
- package/dist/_browser-chunks/chunk-5P4QA6MY.js +20 -0
- package/dist/_browser-chunks/chunk-5WMXI5GW.js +816 -0
- package/dist/_browser-chunks/chunk-66OCZ54D.js +2604 -0
- package/dist/_browser-chunks/chunk-6SXYJQST.js +253 -0
- package/dist/_browser-chunks/chunk-AYRF6EJB.js +36 -0
- package/dist/_browser-chunks/chunk-B4AUNNU4.js +156 -0
- package/dist/_browser-chunks/chunk-BCP2FFXF.js +369 -0
- package/dist/_browser-chunks/chunk-C3D4HEFY.js +3396 -0
- package/dist/_browser-chunks/chunk-CFAOWGL7.js +43 -0
- package/dist/_browser-chunks/chunk-CFWWCCZV.js +223 -0
- package/dist/_browser-chunks/chunk-CNED6RYH.js +18 -0
- package/dist/_browser-chunks/chunk-DRQKCCAG.js +136 -0
- package/dist/_browser-chunks/chunk-ECQ75MKQ.js +0 -0
- package/dist/_browser-chunks/chunk-EIYAKDGP.js +302 -0
- package/dist/_browser-chunks/chunk-ENKK74N4.js +12 -0
- package/dist/_browser-chunks/chunk-FENFYI4X.js +698 -0
- package/dist/_browser-chunks/chunk-FJGWSWL5.js +155 -0
- package/dist/_browser-chunks/chunk-FVSEPWWX.js +2810 -0
- package/dist/_browser-chunks/chunk-GNZY6LOW.js +10116 -0
- package/dist/_browser-chunks/chunk-IE4ULIOQ.js +14 -0
- package/dist/_browser-chunks/chunk-IMSF75WX.js +42 -0
- package/dist/_browser-chunks/chunk-IWQGIXJS.js +14 -0
- package/dist/_browser-chunks/chunk-JMC7AIKT.js +108 -0
- package/dist/_browser-chunks/chunk-JPUOQJUI.js +8 -0
- package/dist/_browser-chunks/chunk-JSBKXXXF.js +218 -0
- package/dist/_browser-chunks/chunk-JWSKPMPC.js +73 -0
- package/dist/_browser-chunks/chunk-JYVGARBG.js +2943 -0
- package/dist/_browser-chunks/chunk-KBK7GKBN.js +35 -0
- package/dist/_browser-chunks/chunk-KQ7CRO2B.js +108 -0
- package/dist/_browser-chunks/chunk-LAWXTSXK.js +18 -0
- package/dist/_browser-chunks/chunk-LE2LTDW3.js +14 -0
- package/dist/_browser-chunks/chunk-LEVSOOLQ.js +48 -0
- package/dist/_browser-chunks/chunk-LV5PIKV4.js +93 -0
- package/dist/_browser-chunks/chunk-MDOL7KML.js +56 -0
- package/dist/_browser-chunks/chunk-MFMDGWP6.js +34 -0
- package/dist/_browser-chunks/chunk-MLBOOZL4.js +67 -0
- package/dist/_browser-chunks/chunk-NQUD4B7H.js +91 -0
- package/dist/_browser-chunks/chunk-NULBREPZ.js +43 -0
- package/dist/_browser-chunks/chunk-NZMVUW5T.js +7 -0
- package/dist/_browser-chunks/chunk-OD6IBQCC.js +117 -0
- package/dist/_browser-chunks/chunk-ODVJ3XZJ.js +157 -0
- package/dist/_browser-chunks/chunk-OQWFVDIN.js +386 -0
- package/dist/_browser-chunks/chunk-OVH3USFB.js +20 -0
- package/dist/_browser-chunks/chunk-OZZPSYQR.js +14 -0
- package/dist/_browser-chunks/chunk-P6PK47TQ.js +1970 -0
- package/dist/_browser-chunks/chunk-PFRNG3UC.js +22 -0
- package/dist/_browser-chunks/chunk-PJSMZ27A.js +13 -0
- package/dist/_browser-chunks/chunk-QC4HFS6K.js +41 -0
- package/dist/_browser-chunks/chunk-QDXFODK4.js +274 -0
- package/dist/_browser-chunks/chunk-RBCHTR7C.js +28 -0
- package/dist/_browser-chunks/chunk-RMYQ3QN3.js +294 -0
- package/dist/_browser-chunks/chunk-RNTIV5CE.js +411 -0
- package/dist/_browser-chunks/chunk-RSPAQWVJ.js +80 -0
- package/dist/_browser-chunks/chunk-S6TK43XQ.js +836 -0
- package/dist/_browser-chunks/chunk-SC67XZST.js +18 -0
- package/dist/_browser-chunks/chunk-SFVA4SBT.js +683 -0
- package/dist/_browser-chunks/chunk-SZYFOQMT.js +25 -0
- package/dist/_browser-chunks/chunk-TBJCJXK4.js +18 -0
- package/dist/_browser-chunks/chunk-UMDO3KB7.js +205 -0
- package/dist/_browser-chunks/chunk-V2G23FV7.js +11 -0
- package/dist/_browser-chunks/chunk-V5M7Q4HT.js +88 -0
- package/dist/_browser-chunks/chunk-W5M6NPS3.js +198 -0
- package/dist/_browser-chunks/chunk-W7NE2JXW.js +84 -0
- package/dist/_browser-chunks/chunk-WGVAAM43.js +1110 -0
- package/dist/_browser-chunks/chunk-WHQRNHXD.js +8 -0
- package/dist/_browser-chunks/chunk-WOSOWBCA.js +12 -0
- package/dist/_browser-chunks/chunk-WZ7KR7SH.js +85 -0
- package/dist/_browser-chunks/chunk-YEKO6BHJ.js +20 -0
- package/dist/_browser-chunks/chunk-YI2IBIQS.js +7 -0
- package/dist/_browser-chunks/chunk-YTIT5NA5.js +1966 -0
- package/dist/_browser-chunks/chunk-ZEHRUHTA.js +6 -0
- package/dist/_browser-chunks/chunk-ZTQ5MEJ5.js +203 -0
- package/dist/_browser-chunks/matchers-YLBYSYAF.js +1263 -0
- package/dist/_browser-chunks/react-dom-client-4OHE3QDV.js +9 -0
- package/dist/_node-chunks/attached-runtime-I2G4WLJI.js +282 -0
- package/dist/_node-chunks/builder-manager-VVHYQXCH.js +1661 -0
- package/dist/_node-chunks/chunk-2BUPBPFB.js +82 -0
- package/dist/_node-chunks/chunk-2DSIDINN.js +884 -0
- package/dist/_node-chunks/chunk-2RU7BKEW.js +23 -0
- package/dist/_node-chunks/chunk-34EO2PUT.js +26 -0
- package/dist/_node-chunks/chunk-3BKIBF5S.js +3008 -0
- package/dist/_node-chunks/chunk-3SDUYDXH.js +98 -0
- package/dist/_node-chunks/chunk-3T4ZSNPH.js +662 -0
- package/dist/_node-chunks/chunk-3W7F2B7P.js +79 -0
- package/dist/_node-chunks/chunk-3Y6AAY5H.js +80 -0
- package/dist/_node-chunks/chunk-42UWAGPW.js +1193 -0
- package/dist/_node-chunks/chunk-4FEANXWU.js +1986 -0
- package/dist/_node-chunks/chunk-5DQFEZEA.js +40 -0
- package/dist/_node-chunks/chunk-6KEHV53S.js +1218 -0
- package/dist/_node-chunks/chunk-6LMWA44H.js +3837 -0
- package/dist/_node-chunks/chunk-6YKBRP72.js +20 -0
- package/dist/_node-chunks/chunk-7GUDZVRQ.js +110 -0
- package/dist/_node-chunks/chunk-B5J7Q7J4.js +21 -0
- package/dist/_node-chunks/chunk-BS2WMZMR.js +90 -0
- package/dist/_node-chunks/chunk-BSKFCWQD.js +47 -0
- package/dist/_node-chunks/chunk-BXVYT7SB.js +36 -0
- package/dist/_node-chunks/chunk-CCOTJ4FC.js +688 -0
- package/dist/_node-chunks/chunk-CQKMLL5J.js +33 -0
- package/dist/_node-chunks/chunk-CXRU72ET.js +63 -0
- package/dist/_node-chunks/chunk-DC7DKR5K.js +20 -0
- package/dist/_node-chunks/chunk-DHJFTB4K.js +25 -0
- package/dist/_node-chunks/chunk-DUR55DJJ.js +1094 -0
- package/dist/_node-chunks/chunk-E6YESGLX.js +7032 -0
- package/dist/_node-chunks/chunk-EHUNOMDD.js +52345 -0
- package/dist/_node-chunks/chunk-ET7PWEO7.js +298 -0
- package/dist/_node-chunks/chunk-EWOX7HPJ.js +20 -0
- package/dist/_node-chunks/chunk-F3ZFKBHY.js +844 -0
- package/dist/_node-chunks/chunk-FK7KGTV7.js +26 -0
- package/dist/_node-chunks/chunk-FPZB5OI7.js +35 -0
- package/dist/_node-chunks/chunk-FW2HQUBQ.js +25 -0
- package/dist/_node-chunks/chunk-FY6UXW6G.js +11 -0
- package/dist/_node-chunks/chunk-GEFQN7K3.js +499 -0
- package/dist/_node-chunks/chunk-GRBLDJCR.js +989 -0
- package/dist/_node-chunks/chunk-H32DYT6P.js +87 -0
- package/dist/_node-chunks/chunk-H4PPVMP5.js +23 -0
- package/dist/_node-chunks/chunk-HMP2G23X.js +25 -0
- package/dist/_node-chunks/chunk-ICPBH3E7.js +59 -0
- package/dist/_node-chunks/chunk-IDEL2J23.js +23 -0
- package/dist/_node-chunks/chunk-IK4FGZLR.js +223 -0
- package/dist/_node-chunks/chunk-JDXXX6LB.js +68 -0
- package/dist/_node-chunks/chunk-JGGFYIG5.js +5468 -0
- package/dist/_node-chunks/chunk-JPAZLYJ3.js +29 -0
- package/dist/_node-chunks/chunk-JZOO7GGC.js +48 -0
- package/dist/_node-chunks/chunk-KISMCCP5.js +4744 -0
- package/dist/_node-chunks/chunk-LCK4ZQKG.js +115 -0
- package/dist/_node-chunks/chunk-LO56I6E2.js +132 -0
- package/dist/_node-chunks/chunk-LXBD4UL4.js +104 -0
- package/dist/_node-chunks/chunk-MA24JW6C.js +7162 -0
- package/dist/_node-chunks/chunk-MK2KYAI6.js +5414 -0
- package/dist/_node-chunks/chunk-NDWKJ4CL.js +2102 -0
- package/dist/_node-chunks/chunk-NIBT7XDZ.js +168 -0
- package/dist/_node-chunks/chunk-NPO45IMH.js +33 -0
- package/dist/_node-chunks/chunk-OISX4AGQ.js +414 -0
- package/dist/_node-chunks/chunk-OUW6R7C3.js +26 -0
- package/dist/_node-chunks/chunk-OWNFOGTA.js +194 -0
- package/dist/_node-chunks/chunk-Q7QNUM5H.js +49 -0
- package/dist/_node-chunks/chunk-QEQLR22M.js +1877 -0
- package/dist/_node-chunks/chunk-RRN2V55B.js +45 -0
- package/dist/_node-chunks/chunk-RWFIFGO5.js +144 -0
- package/dist/_node-chunks/chunk-RXNJDRGO.js +209 -0
- package/dist/_node-chunks/chunk-RZMQ7S3L.js +92 -0
- package/dist/_node-chunks/chunk-SIEXZVCR.js +51 -0
- package/dist/_node-chunks/chunk-SLWQNBGO.js +2034 -0
- package/dist/_node-chunks/chunk-SVTBJ7Q3.js +35 -0
- package/dist/_node-chunks/chunk-SWO5CDYU.js +32 -0
- package/dist/_node-chunks/chunk-TD5PLLQG.js +121 -0
- package/dist/_node-chunks/chunk-TEQGGSP7.js +33 -0
- package/dist/_node-chunks/chunk-TFCEV2XX.js +155 -0
- package/dist/_node-chunks/chunk-TFEWM4E3.js +1073 -0
- package/dist/_node-chunks/chunk-TINO74G5.js +21 -0
- package/dist/_node-chunks/chunk-TNJIXE37.js +40 -0
- package/dist/_node-chunks/chunk-TWI4GVH7.js +19 -0
- package/dist/_node-chunks/chunk-U5W53R2J.js +1011 -0
- package/dist/_node-chunks/chunk-UBOGWBEA.js +148 -0
- package/dist/_node-chunks/chunk-UMUBKI6E.js +3787 -0
- package/dist/_node-chunks/chunk-UVINFLGY.js +56 -0
- package/dist/_node-chunks/chunk-V2DY426G.js +1133 -0
- package/dist/_node-chunks/chunk-VLOXOXXE.js +45 -0
- package/dist/_node-chunks/chunk-W4OMYLSP.js +1297 -0
- package/dist/_node-chunks/chunk-WAXVSN3O.js +18 -0
- package/dist/_node-chunks/chunk-WCULS5TP.js +3767 -0
- package/dist/_node-chunks/chunk-WNZ2UMFM.js +153 -0
- package/dist/_node-chunks/chunk-WZJF2OUH.js +74 -0
- package/dist/_node-chunks/chunk-XGIUVY52.js +611 -0
- package/dist/_node-chunks/chunk-XHL2LVBM.js +415 -0
- package/dist/_node-chunks/chunk-XI6B6P47.js +59 -0
- package/dist/_node-chunks/chunk-XLP2ZKXV.js +60 -0
- package/dist/_node-chunks/chunk-YCMRA6RX.js +95 -0
- package/dist/_node-chunks/chunk-YZFWBA5L.js +2700 -0
- package/dist/_node-chunks/chunk-ZMAMXQKP.js +4731 -0
- package/dist/_node-chunks/chunk-ZWBCQ4MJ.js +110 -0
- package/dist/_node-chunks/dist-VTSTZKUB.js +16 -0
- package/dist/_node-chunks/globby-OEMHPBFY.js +2884 -0
- package/dist/_node-chunks/jiti-NFX6UU74.js +3848 -0
- package/dist/_node-chunks/lib-MDVARD7W.js +366 -0
- package/dist/_node-chunks/local-runtime-NTKIN2QT.js +78 -0
- package/dist/_node-chunks/mdx-plugin-MWISDWDQ.js +5680 -0
- package/dist/_node-chunks/monorepo-LIRFMQXE.js +121 -0
- package/dist/_node-chunks/monorepo-optimized-tests-relaxed-limits-no-story-deletion-CPDW4XTW.js +121 -0
- package/dist/_node-chunks/optimized-tests-HDOLR3EY.js +22 -0
- package/dist/_node-chunks/pattern-copy-play-EKHIUAU2.js +807 -0
- package/dist/_node-chunks/postinstallAddon-GYGMWDL6.js +20 -0
- package/dist/_node-chunks/rehype-external-links-BUN3HUCO.js +121 -0
- package/dist/_node-chunks/rehype-slug-PLADX223.js +52 -0
- package/dist/_node-chunks/relaxed-limits-GBHW6KIQ.js +117 -0
- package/dist/_node-chunks/run-KDTIZNSY.js +103 -0
- package/dist/_node-chunks/run-NL66VTNR.js +4532 -0
- package/dist/_node-chunks/session-id-KIIVOQLR.js +23 -0
- package/dist/_node-chunks/setup-MGC7BQO6.js +278 -0
- package/dist/_node-chunks/vitest.config.4.template-JH2THZFG.js +54 -0
- package/dist/actions/decorator.d.ts +7 -0
- package/dist/actions/decorator.js +43 -0
- package/dist/actions/index.d.ts +67 -0
- package/dist/actions/index.js +28 -0
- package/dist/addon-a11y/index.d.ts +52 -0
- package/dist/addon-a11y/index.js +16 -0
- package/dist/addon-a11y/manager.js +1429 -0
- package/dist/addon-a11y/preset.js +18 -0
- package/dist/addon-a11y/preview.d.ts +17 -0
- package/dist/addon-a11y/preview.js +15 -0
- package/dist/addon-docs/blocks.d.ts +1061 -0
- package/dist/addon-docs/blocks.js +2461 -0
- package/dist/addon-docs/index.d.ts +236 -0
- package/dist/addon-docs/index.js +16 -0
- package/dist/addon-docs/manager.js +90 -0
- package/dist/addon-docs/mdx-react-shim.d.ts +1 -0
- package/dist/addon-docs/mdx-react-shim.js +2 -0
- package/dist/addon-docs/preset.js +378 -0
- package/dist/addon-docs/preview.d.ts +4 -0
- package/dist/addon-docs/preview.js +7 -0
- package/dist/addon-links/index.d.ts +22 -0
- package/dist/addon-links/index.js +20 -0
- package/dist/addon-links/manager.js +14 -0
- package/dist/addon-links/preview.d.ts +6 -0
- package/dist/addon-links/preview.js +9 -0
- package/dist/addon-links/react/index.d.ts +25 -0
- package/dist/addon-links/react/index.js +52 -0
- package/dist/addon-mcp/preset.js +1345 -0
- package/dist/addon-mcp/preview.js +29 -0
- package/dist/addon-mcp/tools/preview-stories/preview-stories-app-script.js +1153 -0
- package/dist/addon-ondevice-actions/index.d.ts +4 -0
- package/dist/addon-ondevice-actions/index.js +7 -0
- package/dist/addon-ondevice-actions/register.js +7 -0
- package/dist/addon-ondevice-controls/index.d.ts +6 -0
- package/dist/addon-ondevice-controls/index.js +14 -0
- package/dist/addon-ondevice-controls/register.js +10 -0
- package/dist/addon-pseudo-states/index.d.ts +35 -0
- package/dist/addon-pseudo-states/index.js +15 -0
- package/dist/addon-pseudo-states/manager.js +53 -0
- package/dist/addon-pseudo-states/preview.d.ts +9 -0
- package/dist/addon-pseudo-states/preview.js +10 -0
- package/dist/addon-themes/index.d.ts +80 -0
- package/dist/addon-themes/index.js +104 -0
- package/dist/addon-themes/manager.js +97 -0
- package/dist/addon-themes/postinstall.js +33 -0
- package/dist/addon-themes/preview.d.ts +6 -0
- package/dist/addon-themes/preview.js +8 -0
- package/dist/addon-vitest/constants.d.ts +132 -0
- package/dist/addon-vitest/constants.js +66 -0
- package/dist/addon-vitest/index.d.ts +4 -0
- package/dist/addon-vitest/index.js +8 -0
- package/dist/addon-vitest/manager.js +665 -0
- package/dist/addon-vitest/node/coverage-reporter.js +1284 -0
- package/dist/addon-vitest/node/vitest.js +674 -0
- package/dist/addon-vitest/postinstall.js +24 -0
- package/dist/addon-vitest/preset.js +943 -0
- package/dist/addon-vitest/vitest-plugin/global-setup.js +162 -0
- package/dist/addon-vitest/vitest-plugin/index.d.ts +56 -0
- package/dist/addon-vitest/vitest-plugin/index.js +463 -0
- package/dist/addon-vitest/vitest-plugin/setup-file-with-project-annotations.js +9 -0
- package/dist/addon-vitest/vitest-plugin/setup-file.browser.4.js +20 -0
- package/dist/addon-vitest/vitest-plugin/setup-file.js +50 -0
- package/dist/addon-vitest/vitest-plugin/test-utils.js +128 -0
- package/dist/babel/index.d.ts +2301 -0
- package/dist/babel/index.js +61 -0
- package/dist/backgrounds/index.d.ts +6 -0
- package/dist/backgrounds/index.js +15 -0
- package/dist/bin/core.js +1705 -0
- package/dist/bin/dispatcher.js +43 -0
- package/dist/bin/loader.js +115 -0
- package/dist/builder-vite/index.d.ts +50 -0
- package/dist/builder-vite/index.js +245 -0
- package/dist/builder-vite/preset.js +27 -0
- package/dist/channels/index.d.ts +2 -0
- package/dist/channels/index.js +352 -0
- package/dist/chunk-B2t1tGRh.d.ts +284 -0
- package/dist/chunk-BCoJQE-f.d.ts +602 -0
- package/dist/chunk-BGkgZp-H.d.ts +214 -0
- package/dist/chunk-BTVrWliM.d.ts +115 -0
- package/dist/chunk-BXLImeLy.d.ts +197 -0
- package/dist/chunk-BfBzpgct.d.ts +916 -0
- package/dist/chunk-Bpi2tz-6.d.ts +511 -0
- package/dist/chunk-BxWufQms.d.ts +142 -0
- package/dist/chunk-C-bavsOH.d.ts +34 -0
- package/dist/chunk-C2p5r3Vt.d.ts +13001 -0
- package/dist/chunk-C6PAgHLT.d.ts +12 -0
- package/dist/chunk-CMeX4WRe.d.ts +179 -0
- package/dist/chunk-Ct9xd6IM.d.ts +65 -0
- package/dist/chunk-CwQKNaYL.d.ts +15 -0
- package/dist/chunk-D7DwV41f.d.ts +3622 -0
- package/dist/chunk-DEVFdzxR.d.ts +253 -0
- package/dist/chunk-DaVb55-_.d.ts +124 -0
- package/dist/chunk-DgRNfmj_.d.ts +40 -0
- package/dist/chunk-DoIGKY33.d.ts +666 -0
- package/dist/chunk-Dr3R0DXk.d.ts +40 -0
- package/dist/chunk-DtHByo32.d.ts +55 -0
- package/dist/chunk-Dw1z1Pki.d.ts +933 -0
- package/dist/chunk-DzuY9DXg.d.ts +79 -0
- package/dist/chunk-FjDVzZTj.d.ts +62 -0
- package/dist/chunk-Kt1tW-D1.d.ts +59 -0
- package/dist/chunk-XP8oHzpE.d.ts +6 -0
- package/dist/chunk-gCX81nOr.d.ts +61 -0
- package/dist/chunk-pcFXCimE.d.ts +741 -0
- package/dist/cli/index.d.ts +1174 -0
- package/dist/cli/index.js +5613 -0
- package/dist/cli/skills/content/index.d.ts +72 -0
- package/dist/cli/skills/content/index.js +335 -0
- package/dist/cli/tools/sdk/child-host.d.ts +61 -0
- package/dist/cli/tools/sdk/child-host.js +131 -0
- package/dist/cli/tools/sdk/index.d.ts +137 -0
- package/dist/cli/tools/sdk/index.js +44 -0
- package/dist/cli-commands/bin/index.js +25 -0
- package/dist/client-logger/index.d.ts +31 -0
- package/dist/client-logger/index.js +63 -0
- package/dist/common/index.d.ts +1103 -0
- package/dist/common/index.js +364 -0
- package/dist/components/index.d.ts +1924 -0
- package/dist/components/index.js +13759 -0
- package/dist/core-events/index.d.ts +155 -0
- package/dist/core-events/index.js +136 -0
- package/dist/core-server/index.d.ts +2200 -0
- package/dist/core-server/index.js +4165 -0
- package/dist/core-server/presets/common-manager.css +170 -0
- package/dist/core-server/presets/common-manager.js +4168 -0
- package/dist/core-server/presets/common-override-preset.js +81 -0
- package/dist/core-server/presets/common-preset.js +2187 -0
- package/dist/create/bin/index.js +23 -0
- package/dist/create/index.js +25 -0
- package/dist/csf/csf-utils.d.ts +2 -0
- package/dist/csf/csf-utils.js +19 -0
- package/dist/csf/index.d.ts +7 -0
- package/dist/csf/index.js +2142 -0
- package/dist/csf-tools/index.d.ts +1157 -0
- package/dist/csf-tools/index.js +736 -0
- package/dist/docs-tools/index.d.ts +197 -0
- package/dist/docs-tools/index.js +61 -0
- package/dist/highlight/index.d.ts +10 -0
- package/dist/highlight/index.js +15 -0
- package/dist/instrumenter/index.d.ts +113 -0
- package/dist/instrumenter/index.js +2595 -0
- package/dist/manager/_manager-chunks/globals-runtime-8HkdnU2F.js +6144 -0
- package/dist/manager/_manager-chunks/globals-runtime-BIKBO23x.js +3389 -0
- package/dist/manager/_manager-chunks/globals-runtime-BdGkqNEt.js +45 -0
- package/dist/manager/_manager-chunks/globals-runtime-BmphMP6z.js +1190 -0
- package/dist/manager/_manager-chunks/globals-runtime-BvM-NY2g.js +13307 -0
- package/dist/manager/_manager-chunks/globals-runtime-C02fvgcd.js +9243 -0
- package/dist/manager/_manager-chunks/globals-runtime-DkAPXCvc.js +9766 -0
- package/dist/manager/_manager-chunks/globals-runtime-DpNYC-qi.js +5564 -0
- package/dist/manager/_manager-chunks/globals-runtime-DtcOnYHR.js +5357 -0
- package/dist/manager/_manager-chunks/globals-runtime-DwFqpqya.js +722 -0
- package/dist/manager/_manager-chunks/globals-runtime-FC201B7s.js +6837 -0
- package/dist/manager/_manager-chunks/globals-runtime-Rp_zjGnh.js +121 -0
- package/dist/manager/_manager-chunks/globals-runtime-ZHrQFa3-.js +10463 -0
- package/dist/manager/_manager-chunks/globals-runtime-eLPTIfX-.js +7759 -0
- package/dist/manager/_manager-chunks/globals-runtime-qKvCZHFY.js +4468 -0
- package/dist/manager/_manager-chunks/globals-runtime-sGpNlIJ1.js +5102 -0
- package/dist/manager/_manager-chunks/runtime-B1L9TH89.js +452 -0
- package/dist/manager/_manager-chunks/runtime-BK0zF7FN.js +22 -0
- package/dist/manager/_manager-chunks/runtime-BhkT2CXl.js +1408 -0
- package/dist/manager/_manager-chunks/runtime-Bly6WJLN.js +998 -0
- package/dist/manager/_manager-chunks/runtime-D0UOWx0U.js +979 -0
- package/dist/manager/_manager-chunks/runtime-D94Vq3oR.js +4014 -0
- package/dist/manager/_manager-chunks/runtime-DMig8mT7.js +77 -0
- package/dist/manager/_manager-chunks/runtime-EITvVbkG.js +46 -0
- package/dist/manager/_manager-chunks/runtime-cp5pazY2.js +8936 -0
- package/dist/manager/_manager-chunks/runtime-eDVAYF7N.js +6860 -0
- package/dist/manager/_manager-chunks/runtime-i-PDAHLR.js +2493 -0
- package/dist/manager/globals-runtime.js +2 -0
- package/dist/manager/globals.d.ts +23 -0
- package/dist/manager/globals.js +26 -0
- package/dist/manager/manager-stores.d.ts +2 -0
- package/dist/manager/manager-stores.js +19 -0
- package/dist/manager/runtime.js +2 -0
- package/dist/manager-api/index.d.ts +2 -0
- package/dist/manager-api/index.js +3257 -0
- package/dist/manager-errors.d.ts +89 -0
- package/dist/manager-errors.js +20 -0
- package/dist/mcp/index.d.ts +270 -0
- package/dist/mcp/index.js +305 -0
- package/dist/mocking-utils/index.d.ts +689 -0
- package/dist/mocking-utils/index.js +521 -0
- package/dist/mocking-utils/mocker-runtime.js +1254 -0
- package/dist/nextjs-vite/config/preview.js +3 -0
- package/dist/nextjs-vite/export-mocks/cache/index.d.ts +25 -0
- package/dist/nextjs-vite/export-mocks/cache/index.js +29 -0
- package/dist/nextjs-vite/export-mocks/headers/index.d.ts +37 -0
- package/dist/nextjs-vite/export-mocks/headers/index.js +54 -0
- package/dist/nextjs-vite/export-mocks/link/index.d.ts +9 -0
- package/dist/nextjs-vite/export-mocks/link/index.js +59 -0
- package/dist/nextjs-vite/export-mocks/navigation/index.d.ts +28 -0
- package/dist/nextjs-vite/export-mocks/navigation/index.js +58 -0
- package/dist/nextjs-vite/export-mocks/router/index.d.ts +34 -0
- package/dist/nextjs-vite/export-mocks/router/index.js +63 -0
- package/dist/nextjs-vite/index.d.ts +92 -0
- package/dist/nextjs-vite/index.js +58 -0
- package/dist/nextjs-vite/node/index.d.ts +6 -0
- package/dist/nextjs-vite/node/index.js +20 -0
- package/dist/nextjs-vite/preset.js +648 -0
- package/dist/nextjs-vite/preview.d.ts +20 -0
- package/dist/nextjs-vite/preview.js +11 -0
- package/dist/nextjs-vite/vite-plugin/index.d.ts +6 -0
- package/dist/nextjs-vite/vite-plugin/index.js +19 -0
- package/dist/nextjs-vite-plugin/index.d.ts +28 -0
- package/dist/nextjs-vite-plugin/index.js +923 -0
- package/dist/nextjs-vite-plugin/mocks/storybook.global.js +29 -0
- package/dist/nextjs-vite-plugin/plugins/next-image/alias/image-context.js +8 -0
- package/dist/nextjs-vite-plugin/plugins/next-image/alias/image-default-loader.js +23 -0
- package/dist/nextjs-vite-plugin/plugins/next-image/alias/next-image.js +28 -0
- package/dist/nextjs-vite-plugin/plugins/next-image/alias/next-legacy-image.js +17 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/cache/index.js +29 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/dynamic/index.js +40 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/headers/index.js +55 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/link/index.js +63 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/navigation/index.js +71 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/router/index.js +74 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/rsc/server-only.js +7 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/alias/safe-stable-stringify/index.js +13 -0
- package/dist/nextjs-vite-plugin/plugins/next-mocks/compatibility/draft-mode.compat.js +7 -0
- package/dist/node-logger/index.d.ts +495 -0
- package/dist/node-logger/index.js +42 -0
- package/dist/oxc-parser/index.d.ts +99 -0
- package/dist/oxc-parser/index.js +275 -0
- package/dist/oxc-parser/worker.js +37 -0
- package/dist/preview/_chunks/runtime-BIzIdDbb.js +10263 -0
- package/dist/preview/_chunks/runtime-BTPtVY1p.js +1102 -0
- package/dist/preview/_chunks/runtime-BZSnICCg.js +8484 -0
- package/dist/preview/_chunks/runtime-BdGkqNEt.js +45 -0
- package/dist/preview/_chunks/runtime-BwSxqk3t.js +63 -0
- package/dist/preview/_chunks/runtime-CqHxptiK.js +6143 -0
- package/dist/preview/_chunks/runtime-CsV4HZPV.js +5064 -0
- package/dist/preview/_chunks/runtime-CxZK_Ln3.js +284 -0
- package/dist/preview/_chunks/runtime-DZToXfvO.js +9767 -0
- package/dist/preview/_chunks/runtime-DrTjJkPY.js +3872 -0
- package/dist/preview/_chunks/runtime-DuHdxMFA.js +387 -0
- package/dist/preview/_chunks/runtime-iXdo8CR8.js +3635 -0
- package/dist/preview/_chunks/runtime-q3wt0e_N.js +6838 -0
- package/dist/preview/globals.d.ts +16 -0
- package/dist/preview/globals.js +20 -0
- package/dist/preview/runtime.js +6 -0
- package/dist/preview-api/index.d.ts +4 -0
- package/dist/preview-api/index.js +147 -0
- package/dist/preview-errors.d.ts +186 -0
- package/dist/preview-errors.js +56 -0
- package/dist/react/docgen/docgen-worker.js +38 -0
- package/dist/react/entry-preview-argtypes.js +9 -0
- package/dist/react/entry-preview-docs.js +12 -0
- package/dist/react/entry-preview-rsc.js +11 -0
- package/dist/react/entry-preview.js +21 -0
- package/dist/react/index.d.ts +119 -0
- package/dist/react/index.js +26 -0
- package/dist/react/preset.js +301 -0
- package/dist/react/preview.d.ts +2 -0
- package/dist/react/preview.js +11 -0
- package/dist/react-native/bin/get-stories.js +34 -0
- package/dist/react-native/index.d.ts +160 -0
- package/dist/react-native/index.js +1547 -0
- package/dist/react-native/metro/node.d.ts +83 -0
- package/dist/react-native/metro/node.js +21 -0
- package/dist/react-native/metro/withStorybook.d.ts +2269 -0
- package/dist/react-native/metro/withStorybook.js +138 -0
- package/dist/react-native/preview.d.ts +6 -0
- package/dist/react-native/preview.js +20 -0
- package/dist/react-native/scripts/generate.d.ts +22 -0
- package/dist/react-native/scripts/generate.js +18 -0
- package/dist/react-native/stub.js +20 -0
- package/dist/react-native-theming/index.d.ts +175 -0
- package/dist/react-native-theming/index.js +2591 -0
- package/dist/react-native-ui/index.d.ts +130 -0
- package/dist/react-native-ui/index.js +1448 -0
- package/dist/react-native-ui-common/index.d.ts +230 -0
- package/dist/react-native-ui-common/index.js +514 -0
- package/dist/react-vite/index.d.ts +4 -0
- package/dist/react-vite/index.js +8 -0
- package/dist/react-vite/node/index.d.ts +6 -0
- package/dist/react-vite/node/index.js +20 -0
- package/dist/react-vite/preset.d.ts +6 -0
- package/dist/react-vite/preset.js +21 -0
- package/dist/router/index.d.ts +141 -0
- package/dist/router/index.js +1217 -0
- package/dist/server-errors.d.ts +2 -0
- package/dist/server-errors.js +149 -0
- package/dist/shared/open-service/index.d.ts +3 -0
- package/dist/shared/open-service/index.js +115 -0
- package/dist/shared/open-service/services/docgen/worker/docgen-worker.js +75 -0
- package/dist/shared/open-service/toolsets/docs/public.d.ts +1296 -0
- package/dist/shared/open-service/toolsets/docs/public.js +991 -0
- package/dist/telemetry/index.d.ts +314 -0
- package/dist/telemetry/index.js +103 -0
- package/dist/test/index.d.ts +158 -0
- package/dist/test/index.js +19421 -0
- package/dist/theming/create.d.ts +15 -0
- package/dist/theming/create.js +11 -0
- package/dist/theming/index.d.ts +54 -0
- package/dist/theming/index.js +511 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +48 -0
- package/dist/viewport/index.d.ts +275 -0
- package/dist/viewport/index.js +21 -0
- package/package.json +1054 -4
- package/template/nextjs-vite/cli/.eslintrc.json +6 -0
- package/template/nextjs-vite/cli/js/Button.jsx +42 -0
- package/template/nextjs-vite/cli/js/Button.stories.js +49 -0
- package/template/nextjs-vite/cli/js/Configure.mdx +470 -0
- package/template/nextjs-vite/cli/js/Header.jsx +58 -0
- package/template/nextjs-vite/cli/js/Header.stories.js +30 -0
- package/template/nextjs-vite/cli/js/Page.jsx +68 -0
- package/template/nextjs-vite/cli/js/Page.stories.js +28 -0
- package/template/nextjs-vite/cli/ts/Button.stories.ts +54 -0
- package/template/nextjs-vite/cli/ts/Button.tsx +39 -0
- package/template/nextjs-vite/cli/ts/Configure.mdx +446 -0
- package/template/nextjs-vite/cli/ts/Header.stories.ts +34 -0
- package/template/nextjs-vite/cli/ts/Header.tsx +54 -0
- package/template/nextjs-vite/cli/ts/Page.stories.ts +33 -0
- package/template/nextjs-vite/cli/ts/Page.tsx +73 -0
- package/template/react/cli/.eslintrc.json +5 -0
- package/template/react/cli/js/Button.jsx +39 -0
- package/template/react/cli/js/Button.stories.js +49 -0
- package/template/react/cli/js/Header.jsx +56 -0
- package/template/react/cli/js/Header.stories.js +29 -0
- package/template/react/cli/js/Page.jsx +69 -0
- package/template/react/cli/js/Page.stories.js +28 -0
- package/template/react/cli/ts/Button.stories.ts +54 -0
- package/template/react/cli/ts/Button.tsx +37 -0
- package/template/react/cli/ts/Header.stories.ts +34 -0
- package/template/react/cli/ts/Header.tsx +56 -0
- package/template/react/cli/ts/Page.stories.ts +33 -0
- package/template/react/cli/ts/Page.tsx +73 -0
- package/template/react-vite/cli/.eslintrc.json +5 -0
- package/template/react-vite/cli/js/Button.jsx +39 -0
- package/template/react-vite/cli/js/Button.stories.js +49 -0
- package/template/react-vite/cli/js/Header.jsx +56 -0
- package/template/react-vite/cli/js/Header.stories.js +29 -0
- package/template/react-vite/cli/js/Page.jsx +69 -0
- package/template/react-vite/cli/js/Page.stories.js +28 -0
- package/template/react-vite/cli/ts/Button.stories.ts +54 -0
- package/template/react-vite/cli/ts/Button.tsx +37 -0
- package/template/react-vite/cli/ts/Header.stories.ts +34 -0
- package/template/react-vite/cli/ts/Header.tsx +56 -0
- package/template/react-vite/cli/ts/Page.stories.ts +33 -0
- package/template/react-vite/cli/ts/Page.tsx +73 -0
|
@@ -0,0 +1,1345 @@
|
|
|
1
|
+
import CJS_COMPAT_NODE_URL_ro17f80mg6k from 'node:url';
|
|
2
|
+
import CJS_COMPAT_NODE_PATH_ro17f80mg6k from 'node:path';
|
|
3
|
+
import CJS_COMPAT_NODE_MODULE_ro17f80mg6k from "node:module";
|
|
4
|
+
|
|
5
|
+
var __filename = CJS_COMPAT_NODE_URL_ro17f80mg6k.fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = CJS_COMPAT_NODE_PATH_ro17f80mg6k.dirname(__filename);
|
|
7
|
+
var require = CJS_COMPAT_NODE_MODULE_ro17f80mg6k.createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
// ------------------------------------------------------------
|
|
10
|
+
// end of CJS compatibility banner, injected by Forkbook's esbuild configuration
|
|
11
|
+
// ------------------------------------------------------------
|
|
12
|
+
import {
|
|
13
|
+
package_default
|
|
14
|
+
} from "../_node-chunks/chunk-TFEWM4E3.js";
|
|
15
|
+
import "../_node-chunks/chunk-CXRU72ET.js";
|
|
16
|
+
|
|
17
|
+
// src/addon-mcp/mcp-handler.ts
|
|
18
|
+
import { McpServer } from "tmcp";
|
|
19
|
+
import { ValibotJsonSchemaAdapter } from "@tmcp/adapter-valibot";
|
|
20
|
+
import { HttpTransport } from "@tmcp/transport-http";
|
|
21
|
+
import { buffer } from "node:stream/consumers";
|
|
22
|
+
|
|
23
|
+
// src/addon-mcp/telemetry.ts
|
|
24
|
+
import { logger } from "@aussieljk/forkbook/internal/node-logger";
|
|
25
|
+
import { telemetry } from "@aussieljk/forkbook/internal/telemetry";
|
|
26
|
+
async function collectTelemetry({
|
|
27
|
+
event,
|
|
28
|
+
server,
|
|
29
|
+
...payload
|
|
30
|
+
}) {
|
|
31
|
+
try {
|
|
32
|
+
return await telemetry("addon-mcp", {
|
|
33
|
+
event,
|
|
34
|
+
mcpSessionId: server.ctx.sessionId,
|
|
35
|
+
clientInfo: server.ctx.sessionInfo?.clientInfo,
|
|
36
|
+
clientCapabilities: server.ctx.sessionInfo?.clientCapabilities,
|
|
37
|
+
transport: "mcp",
|
|
38
|
+
...payload
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
logger.debug(`Error collecting telemetry: ${String(error)}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/addon-mcp/mcp-handler.ts
|
|
46
|
+
import { logger as logger4 } from "@aussieljk/forkbook/internal/node-logger";
|
|
47
|
+
import {
|
|
48
|
+
getEffectiveToolAvailability,
|
|
49
|
+
getToolAvailability
|
|
50
|
+
} from "@aussieljk/forkbook/internal/core-server";
|
|
51
|
+
import { buildServerInstructions } from "@aussieljk/forkbook/internal/skills";
|
|
52
|
+
|
|
53
|
+
// src/addon-mcp/constants.ts
|
|
54
|
+
var DEFAULT_MCP_ENDPOINT = "/mcp";
|
|
55
|
+
|
|
56
|
+
// src/addon-mcp/tools/tool-registry.ts
|
|
57
|
+
import { logger as logger3 } from "@aussieljk/forkbook/internal/node-logger";
|
|
58
|
+
import {
|
|
59
|
+
createCompositionDocsSources,
|
|
60
|
+
createDocsToolset
|
|
61
|
+
} from "@aussieljk/forkbook/internal/toolsets-docs";
|
|
62
|
+
|
|
63
|
+
// src/addon-mcp/utils/format-validation-issues.ts
|
|
64
|
+
function formatPath(path2) {
|
|
65
|
+
if (!path2 || path2.length === 0) return "";
|
|
66
|
+
let out = "";
|
|
67
|
+
for (let segment of path2) {
|
|
68
|
+
let key = typeof segment == "object" && segment !== null && "key" in segment ? segment.key : segment;
|
|
69
|
+
typeof key == "number" ? out += `[${key}]` : key != null && (out += out === "" ? String(key) : `.${String(key)}`);
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
function summarizeIssue(issue) {
|
|
74
|
+
let path2 = formatPath(issue.path);
|
|
75
|
+
if (issue.kind === "schema" && (issue.type === "object" || issue.type === "strict_object" || issue.type === "loose_object") && typeof issue.expected == "string" && issue.expected.length >= 2 && issue.expected.startsWith('"') && issue.expected.endsWith('"') && issue.received === "undefined") {
|
|
76
|
+
let field = issue.expected.slice(1, -1), parentPathStr = formatPath((issue.path ?? []).slice(0, -1)), where = parentPathStr ? ` at \`${parentPathStr}\`` : "";
|
|
77
|
+
return { path: path2, message: `Missing required field \`${field}\`${where}.` };
|
|
78
|
+
}
|
|
79
|
+
return { path: path2, message: issue.message };
|
|
80
|
+
}
|
|
81
|
+
function withFriendlyErrors(schema) {
|
|
82
|
+
let original = schema["~standard"];
|
|
83
|
+
return {
|
|
84
|
+
...schema,
|
|
85
|
+
"~standard": {
|
|
86
|
+
...original,
|
|
87
|
+
validate(input) {
|
|
88
|
+
let result = original.validate(input), trim = (r) => (
|
|
89
|
+
// Cast: the spec issue type is the base shape; validators
|
|
90
|
+
// (notably valibot) augment with `kind`, `type`, `expected`,
|
|
91
|
+
// `received` — see {@link StandardSchemaIssue}.
|
|
92
|
+
r.issues ? { issues: r.issues.map(summarizeIssue) } : r
|
|
93
|
+
);
|
|
94
|
+
return result instanceof Promise ? result.then(trim) : trim(result);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/addon-mcp/tools/get-storybook-story-instructions.ts
|
|
101
|
+
import { resolveSkillInputs } from "@aussieljk/forkbook/internal/core-server";
|
|
102
|
+
import { buildStoryInstructions } from "@aussieljk/forkbook/internal/skills";
|
|
103
|
+
|
|
104
|
+
// src/addon-mcp/utils/errors.ts
|
|
105
|
+
var errorToMCPContent = (error) => ({
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
isError: !0
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// src/addon-mcp/tools/tool-names.ts
|
|
116
|
+
import { toMcpToolName } from "@aussieljk/forkbook/open-service";
|
|
117
|
+
var PREVIEW_STORIES_TOOL_NAME = toMcpToolName("stories.preview"), GET_CHANGED_STORIES_TOOL_NAME = toMcpToolName("stories.changed"), GET_STORIES_BY_COMPONENT_TOOL_NAME = toMcpToolName("stories.findByComponent"), RUN_STORY_TESTS_TOOL_NAME = toMcpToolName("test.run"), DISPLAY_REVIEW_TOOL_NAME = toMcpToolName("review.create"), GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME = "get-storybook-story-instructions";
|
|
118
|
+
|
|
119
|
+
// src/addon-mcp/tools/get-storybook-story-instructions.ts
|
|
120
|
+
async function addGetUIBuildingInstructionsTool(server, enabled = () => server.ctx.custom?.toolsets?.dev ?? !0, {
|
|
121
|
+
docsEnabled = !1,
|
|
122
|
+
addonVitestAvailable = !1
|
|
123
|
+
} = {}) {
|
|
124
|
+
server.tool(
|
|
125
|
+
{
|
|
126
|
+
name: GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME,
|
|
127
|
+
title: "Forkbook Story Development Instructions",
|
|
128
|
+
get description() {
|
|
129
|
+
let testSupported = (server.ctx.custom?.toolsets?.test ?? !0) && addonVitestAvailable, a11yAvailable = testSupported && (server.ctx.custom?.a11yEnabled ?? !1);
|
|
130
|
+
return getStorybookStoryInstructionsDescription({
|
|
131
|
+
testSupported,
|
|
132
|
+
a11yAvailable
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
enabled
|
|
136
|
+
},
|
|
137
|
+
async () => {
|
|
138
|
+
try {
|
|
139
|
+
let { options, disableTelemetry: disableTelemetry2 } = server.ctx.custom ?? {};
|
|
140
|
+
if (!options)
|
|
141
|
+
throw new Error("Options are required in addon context");
|
|
142
|
+
return disableTelemetry2 || await collectTelemetry({
|
|
143
|
+
event: "tool:getUIBuildingInstructions",
|
|
144
|
+
server,
|
|
145
|
+
toolset: "dev"
|
|
146
|
+
}), {
|
|
147
|
+
content: [{ type: "text", text: await buildStorybookStoryInstructions(options, {
|
|
148
|
+
toolsets: server.ctx.custom?.toolsets,
|
|
149
|
+
a11yEnabled: server.ctx.custom?.a11yEnabled,
|
|
150
|
+
addonVitestAvailable,
|
|
151
|
+
docsEnabled
|
|
152
|
+
}) }]
|
|
153
|
+
};
|
|
154
|
+
} catch (error) {
|
|
155
|
+
return errorToMCPContent(error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function getStorybookStoryInstructionsDescription({
|
|
161
|
+
testSupported,
|
|
162
|
+
a11yAvailable
|
|
163
|
+
}) {
|
|
164
|
+
return `Get comprehensive instructions for writing, testing, and fixing Forkbook stories (.stories.tsx, .stories.ts, .stories.jsx, .stories.js files).
|
|
165
|
+
|
|
166
|
+
CRITICAL: You MUST call this tool before:
|
|
167
|
+
- Creating new Forkbook stories or story files
|
|
168
|
+
- Updating or modifying existing Forkbook stories
|
|
169
|
+
- Adding new story variants or exports to story files
|
|
170
|
+
- Editing any file matching *.stories.* patterns
|
|
171
|
+
- Writing components that will need stories
|
|
172
|
+
- Editing anything that changes how the UI looks \u2014 components, styles, CSS, themes, colors, or design tokens; a shared file with no stories of its own still changes its consumers' stories${testSupported ? `
|
|
173
|
+
- Running story tests or fixing test failures` : ""}${a11yAvailable ? `
|
|
174
|
+
- Handling accessibility (a11y) violations in stories (fix semantic issues directly; ask before visual/design changes)` : ""}
|
|
175
|
+
|
|
176
|
+
This tool provides essential Forkbook-specific guidance including:
|
|
177
|
+
- How to structure stories correctly for Forkbook 9
|
|
178
|
+
- Required imports (Meta, StoryObj from framework package)
|
|
179
|
+
- Test utility imports (from '@aussieljk/forkbook/test')
|
|
180
|
+
- Story naming conventions and best practices
|
|
181
|
+
- Play function patterns for interactive testing
|
|
182
|
+
- Mocking strategies for external dependencies
|
|
183
|
+
- Story variants and coverage requirements${testSupported ? `
|
|
184
|
+
- How to handle test failures${a11yAvailable ? " and accessibility violations" : ""}` : ""}
|
|
185
|
+
|
|
186
|
+
Even if you're familiar with Forkbook, call this tool to ensure you're following the correct patterns, import paths, and conventions for this specific Forkbook setup.`;
|
|
187
|
+
}
|
|
188
|
+
function getStorybookStoryInstructionsToolMetadata(options) {
|
|
189
|
+
return {
|
|
190
|
+
name: GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME,
|
|
191
|
+
title: "Forkbook Story Development Instructions",
|
|
192
|
+
description: getStorybookStoryInstructionsDescription(options)
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
async function buildStorybookStoryInstructions(options, {
|
|
196
|
+
toolsets,
|
|
197
|
+
a11yEnabled: a11yEnabled2,
|
|
198
|
+
addonVitestAvailable,
|
|
199
|
+
docsEnabled
|
|
200
|
+
} = {}) {
|
|
201
|
+
let inputs = await resolveSkillInputs(options);
|
|
202
|
+
return buildStoryInstructions({
|
|
203
|
+
transport: "mcp",
|
|
204
|
+
framework: inputs.framework,
|
|
205
|
+
renderer: inputs.renderer,
|
|
206
|
+
testSupported: (toolsets?.test ?? !0) && (addonVitestAvailable ?? inputs.testSupported),
|
|
207
|
+
a11yEnabled: a11yEnabled2 ?? inputs.a11yEnabled,
|
|
208
|
+
docsEnabled: (toolsets?.docs ?? !0) && (docsEnabled ?? inputs.docsEnabled)
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/addon-mcp/tools/preview-stories.ts
|
|
213
|
+
import url from "node:url";
|
|
214
|
+
import fs from "node:fs/promises";
|
|
215
|
+
|
|
216
|
+
// src/addon-mcp/tools/preview-stories/preview-stories-app-template.html
|
|
217
|
+
var preview_stories_app_template_default = `<!doctype html>
|
|
218
|
+
<html>
|
|
219
|
+
<head>
|
|
220
|
+
<meta charset="utf-8" />
|
|
221
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
222
|
+
<style>
|
|
223
|
+
* {
|
|
224
|
+
margin: 0;
|
|
225
|
+
padding: 0;
|
|
226
|
+
box-sizing: border-box;
|
|
227
|
+
}
|
|
228
|
+
html[data-theme='light'] {
|
|
229
|
+
color-scheme: light;
|
|
230
|
+
}
|
|
231
|
+
html[data-theme='dark'] {
|
|
232
|
+
color-scheme: dark;
|
|
233
|
+
}
|
|
234
|
+
html,
|
|
235
|
+
body {
|
|
236
|
+
width: 100%;
|
|
237
|
+
margin: 0;
|
|
238
|
+
padding: 0;
|
|
239
|
+
background-color: var(--color-background-secondary);
|
|
240
|
+
}
|
|
241
|
+
body {
|
|
242
|
+
display: flex;
|
|
243
|
+
flex-direction: column;
|
|
244
|
+
gap: 1rem;
|
|
245
|
+
}
|
|
246
|
+
:root {
|
|
247
|
+
/*
|
|
248
|
+
These are fallback values, if the MCP client doesn't set them.
|
|
249
|
+
See https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#theming
|
|
250
|
+
*/
|
|
251
|
+
--color-text-primary: light-dark(black, white);
|
|
252
|
+
--color-border-primary: light-dark(#ccc, #444);
|
|
253
|
+
--color-background-secondary: light-dark(#f9f9f9, #1e1e1e);
|
|
254
|
+
--font-sans:
|
|
255
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Oxygen-Sans', Ubuntu, Cantarell,
|
|
256
|
+
'Helvetica Neue', sans-serif;
|
|
257
|
+
--font-heading-xs-size: 1rem;
|
|
258
|
+
--font-heading-xs-line-height: 1.25;
|
|
259
|
+
--border-width-regular: 1px;
|
|
260
|
+
}
|
|
261
|
+
.story-heading {
|
|
262
|
+
font-family: var(--font-sans);
|
|
263
|
+
font-size: var(--font-heading-xs-size);
|
|
264
|
+
line-height: var(--font-heading-xs-line-height);
|
|
265
|
+
color: var(--color-text-primary);
|
|
266
|
+
padding: 0.5rem 0;
|
|
267
|
+
}
|
|
268
|
+
.story-iframe {
|
|
269
|
+
background-color: white;
|
|
270
|
+
border: var(--border-width-regular) solid var(--color-border-primary);
|
|
271
|
+
}
|
|
272
|
+
body:has(> article:only-child) h1 {
|
|
273
|
+
/* if there is only one story rendered, hide its heading */
|
|
274
|
+
display: none;
|
|
275
|
+
}
|
|
276
|
+
</style>
|
|
277
|
+
<template id="preview-template">
|
|
278
|
+
<article>
|
|
279
|
+
<h1 class="story-heading"></h1>
|
|
280
|
+
<iframe class="story-iframe"></iframe>
|
|
281
|
+
</article>
|
|
282
|
+
</template>
|
|
283
|
+
<script type="module">
|
|
284
|
+
// APP_SCRIPT_PLACEHOLDER
|
|
285
|
+
</script>
|
|
286
|
+
</head>
|
|
287
|
+
<body></body>
|
|
288
|
+
</html>
|
|
289
|
+
`;
|
|
290
|
+
|
|
291
|
+
// src/addon-mcp/tools/preview-stories.ts
|
|
292
|
+
var PREVIEW_STORIES_RESOURCE_URI = `ui://${PREVIEW_STORIES_TOOL_NAME}/preview.html`;
|
|
293
|
+
async function addPreviewStoriesResource(server) {
|
|
294
|
+
let previewStoryAppScript = await fs.readFile(
|
|
295
|
+
url.fileURLToPath(
|
|
296
|
+
import.meta.resolve("@aussieljk/forkbook/addon-mcp/internal/preview-stories-app-script")
|
|
297
|
+
),
|
|
298
|
+
"utf-8"
|
|
299
|
+
), appHtml = preview_stories_app_template_default.replace("// APP_SCRIPT_PLACEHOLDER", previewStoryAppScript);
|
|
300
|
+
server.resource(
|
|
301
|
+
{
|
|
302
|
+
name: PREVIEW_STORIES_RESOURCE_URI,
|
|
303
|
+
description: "App resource for the Preview Stories tool",
|
|
304
|
+
uri: PREVIEW_STORIES_RESOURCE_URI,
|
|
305
|
+
mimeType: "text/html;profile=mcp-app"
|
|
306
|
+
},
|
|
307
|
+
() => {
|
|
308
|
+
let origin2 = server.ctx.custom.origin;
|
|
309
|
+
return {
|
|
310
|
+
contents: [
|
|
311
|
+
{
|
|
312
|
+
uri: PREVIEW_STORIES_RESOURCE_URI,
|
|
313
|
+
mimeType: "text/html;profile=mcp-app",
|
|
314
|
+
text: appHtml,
|
|
315
|
+
_meta: {
|
|
316
|
+
ui: {
|
|
317
|
+
prefersBorder: !1,
|
|
318
|
+
domain: origin2,
|
|
319
|
+
csp: {
|
|
320
|
+
connectDomains: [origin2],
|
|
321
|
+
resourceDomains: [origin2],
|
|
322
|
+
frameDomains: [origin2],
|
|
323
|
+
baseUriDomains: [origin2]
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
]
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/addon-mcp/tools/tool-registry.ts
|
|
335
|
+
import { OpenServiceMissingToolsetError, toMcpToolName as toMcpToolName3 } from "@aussieljk/forkbook/open-service";
|
|
336
|
+
|
|
337
|
+
// src/addon-mcp/tools/toolset-tools.ts
|
|
338
|
+
import { getService } from "@aussieljk/forkbook/internal/core-server";
|
|
339
|
+
import { logger as logger2 } from "@aussieljk/forkbook/internal/node-logger";
|
|
340
|
+
import { OpenServiceToolsetOutputMismatchError } from "@aussieljk/forkbook/internal/server-errors";
|
|
341
|
+
import {
|
|
342
|
+
getToolset,
|
|
343
|
+
invokeToolsetMethod,
|
|
344
|
+
parseToolsetMethodId,
|
|
345
|
+
resolveToolsetDescription,
|
|
346
|
+
toMcpToolName as toMcpToolName2
|
|
347
|
+
} from "@aussieljk/forkbook/open-service";
|
|
348
|
+
|
|
349
|
+
// src/addon-mcp/tools/toolset-origin.ts
|
|
350
|
+
function storybookRootFromRequest(request, trustedOrigin, endpoint) {
|
|
351
|
+
if (request?.url)
|
|
352
|
+
try {
|
|
353
|
+
let url2 = new URL(request.url), normalizedEndpoint = endpoint.replace(/\/$/, ""), normalizedPathname = url2.pathname.replace(/\/$/, ""), rootPath = normalizedPathname.endsWith(normalizedEndpoint) ? normalizedPathname.slice(0, -normalizedEndpoint.length) : normalizedPathname.replace(/\/[^/]+$/, "");
|
|
354
|
+
return `${trustedOrigin.replace(/\/$/, "")}${rootPath}`;
|
|
355
|
+
} catch {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function resolveToolsetOrigin(context) {
|
|
360
|
+
if (context.origin)
|
|
361
|
+
return context.request ? storybookRootFromRequest(
|
|
362
|
+
context.request,
|
|
363
|
+
context.origin,
|
|
364
|
+
context.endpoint ?? DEFAULT_MCP_ENDPOINT
|
|
365
|
+
) ?? context.origin : context.origin;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/addon-mcp/tools/toolset-tools.ts
|
|
369
|
+
function resolveToolset(options, server) {
|
|
370
|
+
return options.resolveToolset ? options.resolveToolset(server) : getToolset(parseToolsetMethodId(options.method).toolsetId);
|
|
371
|
+
}
|
|
372
|
+
function resolveMethod(toolset, options) {
|
|
373
|
+
return toolset.methods[parseToolsetMethodId(options.method).methodName];
|
|
374
|
+
}
|
|
375
|
+
function isAgentFacingError(error) {
|
|
376
|
+
return error instanceof Error && error.agentFacing === !0;
|
|
377
|
+
}
|
|
378
|
+
async function toStructuredContent(outputSchema, data) {
|
|
379
|
+
if (!outputSchema || data === void 0)
|
|
380
|
+
return;
|
|
381
|
+
let result = await outputSchema["~standard"].validate(data);
|
|
382
|
+
if (result.issues)
|
|
383
|
+
throw new OpenServiceToolsetOutputMismatchError({ issues: result.issues });
|
|
384
|
+
return result.value;
|
|
385
|
+
}
|
|
386
|
+
function buildContext(server) {
|
|
387
|
+
return {
|
|
388
|
+
transport: "mcp",
|
|
389
|
+
// The toolset origin is the complete UI base URL, including any deployment subpath.
|
|
390
|
+
origin: resolveToolsetOrigin(server.ctx.custom ?? {}),
|
|
391
|
+
getService: (serviceId, serviceOptions) => getService(serviceId, serviceOptions)
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
async function reportToolsetTelemetry(server, event, report) {
|
|
395
|
+
if (!report || server.ctx.custom?.disableTelemetry)
|
|
396
|
+
return;
|
|
397
|
+
let { payload, toolset, tool } = report;
|
|
398
|
+
await collectTelemetry({ event, server, ...payload, toolset, tool });
|
|
399
|
+
}
|
|
400
|
+
async function callToolsetMethod(server, options, input) {
|
|
401
|
+
let toolset = resolveToolset(options, server), { methodName } = parseToolsetMethodId(options.method), method = toolset.methods[methodName];
|
|
402
|
+
try {
|
|
403
|
+
let outcome = await invokeToolsetMethod(toolset, methodName, input, buildContext(server));
|
|
404
|
+
await reportToolsetTelemetry(server, options.mcpEventName, outcome.telemetry);
|
|
405
|
+
let structuredContent = await toStructuredContent(method.output, outcome.data);
|
|
406
|
+
return {
|
|
407
|
+
content: (Array.isArray(outcome.markdown) ? outcome.markdown : [outcome.markdown]).map((text) => ({ type: "text", text })),
|
|
408
|
+
...structuredContent !== void 0 ? { structuredContent } : {},
|
|
409
|
+
...outcome.ok ? {} : { isError: !0 }
|
|
410
|
+
};
|
|
411
|
+
} catch (error) {
|
|
412
|
+
return isAgentFacingError(error) ? { content: [{ type: "text", text: error.message }], isError: !0 } : (logger2.error(`MCP tool "${toMcpToolName2(options.method)}" failed: ${error}`), errorToMCPContent(error));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function getToolsetToolMetadata(options) {
|
|
416
|
+
let method = resolveMethod(resolveToolset(options), options), descriptionCtx = {
|
|
417
|
+
transport: "mcp",
|
|
418
|
+
getService: (serviceId, serviceOptions) => getService(serviceId, serviceOptions)
|
|
419
|
+
}, entries = method.input.entries, hasInput = !entries || Object.keys(entries).length > 0;
|
|
420
|
+
return {
|
|
421
|
+
name: toMcpToolName2(options.method),
|
|
422
|
+
title: method.title,
|
|
423
|
+
description: resolveToolsetDescription(method.description, descriptionCtx),
|
|
424
|
+
...hasInput ? { schema: options.wrapSchema ? options.wrapSchema(method.input) : method.input } : {},
|
|
425
|
+
...method.output ? { outputSchema: method.output } : {},
|
|
426
|
+
...options.extras
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
function registerToolsetTool(server, options, enabled) {
|
|
430
|
+
server.tool(
|
|
431
|
+
{ ...getToolsetToolMetadata(options), enabled },
|
|
432
|
+
((input) => callToolsetMethod(server, options, input))
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/addon-mcp/tools/tool-registry.ts
|
|
437
|
+
var isToolsetEnabled = (toolset, toolsets) => toolsets?.[toolset] ?? !0, isToolAvailable = (definition, context) => definition.available?.(context) ?? !0;
|
|
438
|
+
var createToolsetEnabled = (server, toolset) => () => server.ctx.custom?.toolsets?.[toolset] ?? !0;
|
|
439
|
+
function fromToolset(definition) {
|
|
440
|
+
let { options, available, ...rest } = definition;
|
|
441
|
+
return {
|
|
442
|
+
...rest,
|
|
443
|
+
// Read from the constant, not the registry: this array is built at import time, while toolsets
|
|
444
|
+
// register later from their preset hooks. Each availability gate is written to match the
|
|
445
|
+
// condition under which its toolset registers; if they still disagree, resolution fails loudly
|
|
446
|
+
// (getToolset throws) and the registry drops that one tool with an error log rather than taking
|
|
447
|
+
// down the whole server (see resolveDefinitionOrDrop).
|
|
448
|
+
name: toMcpToolName3(options.method),
|
|
449
|
+
available: (context) => available?.(context) ?? !0,
|
|
450
|
+
getMetadata: () => getToolsetToolMetadata(options),
|
|
451
|
+
register: async (server, _context, enabled) => {
|
|
452
|
+
registerToolsetTool(server, options, enabled);
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function compositionDocsToolset(server) {
|
|
457
|
+
let custom = server?.ctx.custom;
|
|
458
|
+
return createDocsToolset({
|
|
459
|
+
sources: createCompositionDocsSources({
|
|
460
|
+
sources: custom?.sources ?? [{ id: "local", title: "Local" }],
|
|
461
|
+
manifestProvider: custom?.manifestProvider,
|
|
462
|
+
getRequest: () => custom?.request,
|
|
463
|
+
localAccess: custom?.localAccess
|
|
464
|
+
})
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
var DOCS_EVENT_NAMES = {
|
|
468
|
+
"docs.list": "tool:listAllDocumentation",
|
|
469
|
+
"docs.show": "tool:getDocumentation",
|
|
470
|
+
"docs.showStory": "tool:getDocumentationForStory"
|
|
471
|
+
};
|
|
472
|
+
function docsToolDefinition(method) {
|
|
473
|
+
let forContext = (context) => ({
|
|
474
|
+
method,
|
|
475
|
+
mcpEventName: DOCS_EVENT_NAMES[method],
|
|
476
|
+
...context.multiSource ? { resolveToolset: (server) => compositionDocsToolset(server) } : {}
|
|
477
|
+
});
|
|
478
|
+
return {
|
|
479
|
+
name: toMcpToolName3(method),
|
|
480
|
+
toolset: "docs",
|
|
481
|
+
available: ({ availability }) => availability.docsEnabled,
|
|
482
|
+
getMetadata: (context) => getToolsetToolMetadata(forContext(context)),
|
|
483
|
+
register: async (server, context, enabled) => {
|
|
484
|
+
registerToolsetTool(server, forContext(context), enabled);
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
var docsToolDefinitions = [
|
|
489
|
+
docsToolDefinition("docs.list"),
|
|
490
|
+
docsToolDefinition("docs.show"),
|
|
491
|
+
docsToolDefinition("docs.showStory")
|
|
492
|
+
], addonToolDefinitions = [
|
|
493
|
+
fromToolset({
|
|
494
|
+
toolset: "dev",
|
|
495
|
+
options: {
|
|
496
|
+
method: "stories.preview",
|
|
497
|
+
mcpEventName: "tool:previewStories",
|
|
498
|
+
extras: { _meta: { ui: { resourceUri: PREVIEW_STORIES_RESOURCE_URI } } }
|
|
499
|
+
}
|
|
500
|
+
}),
|
|
501
|
+
{
|
|
502
|
+
name: GET_UI_BUILDING_INSTRUCTIONS_TOOL_NAME,
|
|
503
|
+
toolset: "dev",
|
|
504
|
+
getMetadata: ({ availability, toolsets }) => {
|
|
505
|
+
let testSupported = isToolsetEnabled("test", toolsets) && availability.testSupported;
|
|
506
|
+
return getStorybookStoryInstructionsToolMetadata({
|
|
507
|
+
testSupported,
|
|
508
|
+
a11yAvailable: testSupported && availability.a11yEnabled
|
|
509
|
+
});
|
|
510
|
+
},
|
|
511
|
+
register: (server, { availability, toolsets }, enabled) => addGetUIBuildingInstructionsTool(server, enabled, {
|
|
512
|
+
docsEnabled: isToolsetEnabled("docs", toolsets) && availability.docsEnabled,
|
|
513
|
+
addonVitestAvailable: availability.testSupported
|
|
514
|
+
})
|
|
515
|
+
},
|
|
516
|
+
fromToolset({
|
|
517
|
+
toolset: "dev",
|
|
518
|
+
options: { method: "stories.changed", mcpEventName: "tool:getChangedStories" }
|
|
519
|
+
}),
|
|
520
|
+
fromToolset({
|
|
521
|
+
toolset: "dev",
|
|
522
|
+
available: ({ availability }) => availability.moduleGraphSupported,
|
|
523
|
+
options: { method: "stories.findByComponent", mcpEventName: "tool:getStoriesByComponent" }
|
|
524
|
+
}),
|
|
525
|
+
fromToolset({
|
|
526
|
+
toolset: "dev",
|
|
527
|
+
options: {
|
|
528
|
+
method: "review.create",
|
|
529
|
+
mcpEventName: "tool:displayReview",
|
|
530
|
+
wrapSchema: withFriendlyErrors
|
|
531
|
+
}
|
|
532
|
+
}),
|
|
533
|
+
fromToolset({
|
|
534
|
+
toolset: "test",
|
|
535
|
+
available: ({ availability }) => availability.testSupported,
|
|
536
|
+
options: { method: "test.run", mcpEventName: "tool:runStoryTests" }
|
|
537
|
+
}),
|
|
538
|
+
// Docs run on the core docs toolset in both modes. A composition builds its toolset per request,
|
|
539
|
+
// because the sources it reads and the provider that fetches them belong to the request.
|
|
540
|
+
...docsToolDefinitions
|
|
541
|
+
];
|
|
542
|
+
function dropToolIfToolsetMissing(name, error) {
|
|
543
|
+
if (!(error instanceof OpenServiceMissingToolsetError))
|
|
544
|
+
throw error;
|
|
545
|
+
logger3.error(`Skipping MCP tool "${name}", its backing toolset is not registered: ${error}`);
|
|
546
|
+
}
|
|
547
|
+
async function registerAddonMcpTools(server, context) {
|
|
548
|
+
isToolsetEnabled("dev", context.toolsets) && await addPreviewStoriesResource(server);
|
|
549
|
+
for (let definition of addonToolDefinitions)
|
|
550
|
+
if (isToolsetEnabled(definition.toolset, context.toolsets) && isToolAvailable(definition, context))
|
|
551
|
+
try {
|
|
552
|
+
await definition.register(
|
|
553
|
+
server,
|
|
554
|
+
context,
|
|
555
|
+
createToolsetEnabled(server, definition.toolset)
|
|
556
|
+
);
|
|
557
|
+
} catch (error) {
|
|
558
|
+
dropToolIfToolsetMissing(definition.name, error);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/addon-mcp/mcp-handler.ts
|
|
563
|
+
var transport, origin, initialize, disableTelemetry, a11yEnabled, initializeMCPServer = async (options, multiSource) => {
|
|
564
|
+
disableTelemetry = (await options.presets.apply("core", {}))?.disableTelemetry ?? !1;
|
|
565
|
+
let rawAvailability = await getToolAvailability(options), availability = getEffectiveToolAvailability(rawAvailability, { multiSource });
|
|
566
|
+
a11yEnabled = availability.a11yEnabled;
|
|
567
|
+
let server, serverOptions = {
|
|
568
|
+
adapter: new ValibotJsonSchemaAdapter(),
|
|
569
|
+
get instructions() {
|
|
570
|
+
return buildServerInstructions({
|
|
571
|
+
transport: "mcp",
|
|
572
|
+
devEnabled: server?.ctx.custom?.toolsets?.dev ?? !0,
|
|
573
|
+
testSupported: (server?.ctx.custom?.toolsets?.test ?? !0) && availability.testSupported,
|
|
574
|
+
docsEnabled: (server?.ctx.custom?.toolsets?.docs ?? !0) && availability.docsEnabled,
|
|
575
|
+
moduleGraphSupported: availability.moduleGraphSupported
|
|
576
|
+
});
|
|
577
|
+
},
|
|
578
|
+
capabilities: {
|
|
579
|
+
tools: { listChanged: !0 },
|
|
580
|
+
resources: { listChanged: !0 }
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
return server = new McpServer(
|
|
584
|
+
{
|
|
585
|
+
name: `${package_default.name}/addon-mcp`,
|
|
586
|
+
version: package_default.version,
|
|
587
|
+
description: "Help agents automatically write and test stories for your UI components"
|
|
588
|
+
},
|
|
589
|
+
serverOptions
|
|
590
|
+
).withContext(), disableTelemetry || server.on("initialize", async () => {
|
|
591
|
+
await collectTelemetry({ event: "session:initialized", server });
|
|
592
|
+
}), await registerAddonMcpTools(server, { availability, multiSource }), transport = new HttpTransport(server, { path: null }), origin = `http://localhost:${options.port}`, logger4.debug(`MCP server origin: ${origin}`), server;
|
|
593
|
+
}, mcpServerHandler = async ({
|
|
594
|
+
req,
|
|
595
|
+
res,
|
|
596
|
+
options,
|
|
597
|
+
addonOptions,
|
|
598
|
+
endpoint = DEFAULT_MCP_ENDPOINT,
|
|
599
|
+
sources,
|
|
600
|
+
manifestProvider,
|
|
601
|
+
localAccess,
|
|
602
|
+
compositionAuth
|
|
603
|
+
}) => {
|
|
604
|
+
initialize || (initialize = initializeMCPServer(
|
|
605
|
+
options,
|
|
606
|
+
sources?.some((s) => s.url)
|
|
607
|
+
)), await initialize;
|
|
608
|
+
let webRequest = await incomingMessageToWebRequest(req), addonContext = {
|
|
609
|
+
options,
|
|
610
|
+
endpoint,
|
|
611
|
+
toolsets: getToolsets(webRequest, addonOptions),
|
|
612
|
+
origin,
|
|
613
|
+
disableTelemetry,
|
|
614
|
+
a11yEnabled,
|
|
615
|
+
request: webRequest,
|
|
616
|
+
sources,
|
|
617
|
+
manifestProvider,
|
|
618
|
+
localAccess
|
|
619
|
+
}, response = await transport.respond(webRequest, addonContext);
|
|
620
|
+
if (response) {
|
|
621
|
+
let body = await response.arrayBuffer(), finalResponse = compositionAuth.hadAuthError(webRequest) ? new Response("401 - Unauthorized", {
|
|
622
|
+
status: 401,
|
|
623
|
+
headers: {
|
|
624
|
+
"Content-Type": "text/plain",
|
|
625
|
+
"WWW-Authenticate": compositionAuth.buildWwwAuthenticate(origin)
|
|
626
|
+
}
|
|
627
|
+
}) : new Response(body, { status: response.status, headers: response.headers });
|
|
628
|
+
await webResponseToServerResponse(finalResponse, res);
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
async function incomingMessageToWebRequest(req) {
|
|
632
|
+
let host = req.headers.host || "localhost", protocol = "encrypted" in req.socket && req.socket.encrypted ? "https" : "http", url2 = new URL(req.url || "/", `${protocol}://${host}`), bodyBuffer = await buffer(req);
|
|
633
|
+
return new Request(url2, {
|
|
634
|
+
method: req.method,
|
|
635
|
+
headers: req.headers,
|
|
636
|
+
body: bodyBuffer.length > 0 ? new Uint8Array(bodyBuffer) : void 0
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
async function webResponseToServerResponse(webResponse, nodeResponse) {
|
|
640
|
+
if (nodeResponse.statusCode = webResponse.status, webResponse.headers.forEach((value, key) => {
|
|
641
|
+
nodeResponse.setHeader(key, value);
|
|
642
|
+
}), webResponse.body) {
|
|
643
|
+
let reader = webResponse.body.getReader();
|
|
644
|
+
try {
|
|
645
|
+
for (; ; ) {
|
|
646
|
+
let { done, value } = await reader.read();
|
|
647
|
+
if (done) break;
|
|
648
|
+
nodeResponse.write(value);
|
|
649
|
+
}
|
|
650
|
+
} finally {
|
|
651
|
+
reader.releaseLock();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
nodeResponse.end();
|
|
655
|
+
}
|
|
656
|
+
function getToolsets(request, addonOptions) {
|
|
657
|
+
let toolsetHeader = request.headers.get("X-MCP-Toolsets");
|
|
658
|
+
if (!toolsetHeader || toolsetHeader.trim() === "")
|
|
659
|
+
return addonOptions.toolsets;
|
|
660
|
+
let toolsets = {
|
|
661
|
+
dev: !1,
|
|
662
|
+
docs: !1,
|
|
663
|
+
test: !1
|
|
664
|
+
}, enabledToolsets = toolsetHeader.split(",");
|
|
665
|
+
for (let enabledToolset of enabledToolsets) {
|
|
666
|
+
let trimmedToolset = enabledToolset.trim();
|
|
667
|
+
trimmedToolset in toolsets && (toolsets[trimmedToolset] = !0);
|
|
668
|
+
}
|
|
669
|
+
return toolsets;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/addon-mcp/types.ts
|
|
673
|
+
import * as v from "valibot";
|
|
674
|
+
var isLiteralEndpointPathname = (endpoint) => {
|
|
675
|
+
try {
|
|
676
|
+
let { pathname } = new URL(endpoint, "http://storybook.local");
|
|
677
|
+
return pathname === endpoint && pathname !== "/";
|
|
678
|
+
} catch {
|
|
679
|
+
return !1;
|
|
680
|
+
}
|
|
681
|
+
}, AddonOptions = v.object({
|
|
682
|
+
endpoint: v.optional(
|
|
683
|
+
v.pipe(
|
|
684
|
+
v.string(),
|
|
685
|
+
v.check(isLiteralEndpointPathname, "Endpoint must be a literal URL pathname")
|
|
686
|
+
)
|
|
687
|
+
),
|
|
688
|
+
toolsets: v.optional(
|
|
689
|
+
v.object({
|
|
690
|
+
dev: v.exactOptional(v.boolean(), !0),
|
|
691
|
+
docs: v.exactOptional(v.boolean(), !0),
|
|
692
|
+
test: v.exactOptional(v.boolean(), !0)
|
|
693
|
+
}),
|
|
694
|
+
{
|
|
695
|
+
// Default values for toolsets
|
|
696
|
+
dev: !0,
|
|
697
|
+
docs: !0,
|
|
698
|
+
test: !0
|
|
699
|
+
}
|
|
700
|
+
)
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// src/addon-mcp/preset.ts
|
|
704
|
+
import * as v3 from "valibot";
|
|
705
|
+
import {
|
|
706
|
+
createLocalDocsAccess,
|
|
707
|
+
getEffectiveToolAvailability as getEffectiveToolAvailability2,
|
|
708
|
+
getToolAvailability as getToolAvailability2,
|
|
709
|
+
isValidHost,
|
|
710
|
+
loadManifests
|
|
711
|
+
} from "@aussieljk/forkbook/internal/core-server";
|
|
712
|
+
import { isWebContainer } from "@aussieljk/forkbook/internal/common";
|
|
713
|
+
|
|
714
|
+
// src/addon-mcp/template.html
|
|
715
|
+
var template_default = `<!doctype html>
|
|
716
|
+
<html>
|
|
717
|
+
<head>
|
|
718
|
+
<style>
|
|
719
|
+
@font-face {
|
|
720
|
+
font-family: 'Nunito Sans';
|
|
721
|
+
font-style: normal;
|
|
722
|
+
font-weight: 400;
|
|
723
|
+
font-display: swap;
|
|
724
|
+
src: url('./sb-common-assets/nunito-sans-regular.woff2') format('woff2');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
* {
|
|
728
|
+
margin: 0;
|
|
729
|
+
padding: 0;
|
|
730
|
+
box-sizing: border-box;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
html,
|
|
734
|
+
body {
|
|
735
|
+
height: 100%;
|
|
736
|
+
font-family:
|
|
737
|
+
'Nunito Sans',
|
|
738
|
+
-apple-system,
|
|
739
|
+
BlinkMacSystemFont,
|
|
740
|
+
'Segoe UI',
|
|
741
|
+
Roboto,
|
|
742
|
+
Oxygen,
|
|
743
|
+
Ubuntu,
|
|
744
|
+
Cantarell,
|
|
745
|
+
sans-serif;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
body {
|
|
749
|
+
display: flex;
|
|
750
|
+
flex-direction: column;
|
|
751
|
+
justify-content: center;
|
|
752
|
+
align-items: center;
|
|
753
|
+
text-align: center;
|
|
754
|
+
padding: 2rem;
|
|
755
|
+
background-color: #ffffff;
|
|
756
|
+
color: rgb(46, 52, 56);
|
|
757
|
+
line-height: 1.6;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
p {
|
|
761
|
+
margin-bottom: 1rem;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
code {
|
|
765
|
+
font-family: 'Monaco', 'Courier New', monospace;
|
|
766
|
+
background: #f5f5f5;
|
|
767
|
+
padding: 0.2em 0.4em;
|
|
768
|
+
border-radius: 3px;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
a {
|
|
772
|
+
color: #1ea7fd;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.container {
|
|
776
|
+
display: flex;
|
|
777
|
+
flex-direction: column;
|
|
778
|
+
align-items: center;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
.toolsets {
|
|
782
|
+
margin: 1.5rem 0;
|
|
783
|
+
text-align: left;
|
|
784
|
+
max-width: 500px;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
.toolsets h3 {
|
|
788
|
+
font-size: 1rem;
|
|
789
|
+
margin-bottom: 0.75rem;
|
|
790
|
+
text-align: center;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.toolset {
|
|
794
|
+
margin-bottom: 1rem;
|
|
795
|
+
padding: 0.75rem 1rem;
|
|
796
|
+
border-radius: 6px;
|
|
797
|
+
background: #f8f9fa;
|
|
798
|
+
border: 1px solid #e9ecef;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.toolset-header {
|
|
802
|
+
display: flex;
|
|
803
|
+
align-items: center;
|
|
804
|
+
gap: 0.5rem;
|
|
805
|
+
font-weight: 600;
|
|
806
|
+
margin-bottom: 0.5rem;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.toolset-status {
|
|
810
|
+
display: inline-block;
|
|
811
|
+
padding: 0.15em 0.5em;
|
|
812
|
+
border-radius: 3px;
|
|
813
|
+
font-size: 0.75rem;
|
|
814
|
+
font-weight: 500;
|
|
815
|
+
text-transform: uppercase;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.toolset-status.enabled {
|
|
819
|
+
background: #d4edda;
|
|
820
|
+
color: #155724;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.toolset-status.disabled {
|
|
824
|
+
background: #f8d7da;
|
|
825
|
+
color: #721c24;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
.toolset-tools {
|
|
829
|
+
font-size: 0.875rem;
|
|
830
|
+
color: #6c757d;
|
|
831
|
+
padding-left: 1.5rem;
|
|
832
|
+
margin: 0;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.toolset-tools li {
|
|
836
|
+
margin-bottom: 0.25rem;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.toolset-tools code {
|
|
840
|
+
font-size: 0.8rem;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.toolset-notice {
|
|
844
|
+
font-size: 0.8rem;
|
|
845
|
+
color: #856404;
|
|
846
|
+
background: #fff3cd;
|
|
847
|
+
padding: 0.5rem;
|
|
848
|
+
border-radius: 4px;
|
|
849
|
+
margin-top: 0.5rem;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.toolset-notice a {
|
|
853
|
+
color: #533f03;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
@media (prefers-color-scheme: dark) {
|
|
857
|
+
body {
|
|
858
|
+
background-color: rgb(34, 36, 37);
|
|
859
|
+
color: rgb(201, 205, 207);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
code {
|
|
863
|
+
background: rgba(255, 255, 255, 0.1);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.toolset {
|
|
867
|
+
background: rgba(255, 255, 255, 0.05);
|
|
868
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
.toolset-tools {
|
|
872
|
+
color: #adb5bd;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.toolset-status.enabled {
|
|
876
|
+
background: rgba(40, 167, 69, 0.2);
|
|
877
|
+
color: #75d67e;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.toolset-status.disabled {
|
|
881
|
+
background: rgba(220, 53, 69, 0.2);
|
|
882
|
+
color: #f5a6ad;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.toolset-notice {
|
|
886
|
+
background: rgba(255, 193, 7, 0.15);
|
|
887
|
+
color: #ffc107;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
.toolset-notice a {
|
|
891
|
+
color: #ffe066;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
</style>
|
|
895
|
+
</head>
|
|
896
|
+
<body>
|
|
897
|
+
<div class="container">
|
|
898
|
+
<p>
|
|
899
|
+
Forkbook MCP server successfully running via
|
|
900
|
+
<code>@aussieljk/forkbook/addon-mcp</code>.
|
|
901
|
+
</p>
|
|
902
|
+
<p>
|
|
903
|
+
See how to connect to it from your coding agent in the
|
|
904
|
+
<a
|
|
905
|
+
target="_blank"
|
|
906
|
+
href="https://storybook.js.org/docs/ai/mcp/overview#3-add-the-mcp-server-to-your-agent"
|
|
907
|
+
>agent connection setup guide</a
|
|
908
|
+
>.
|
|
909
|
+
</p>
|
|
910
|
+
|
|
911
|
+
<div class="toolsets">
|
|
912
|
+
<h3>Available Toolsets</h3>
|
|
913
|
+
|
|
914
|
+
<div class="toolset">
|
|
915
|
+
<div class="toolset-header">
|
|
916
|
+
<span>dev</span>
|
|
917
|
+
<span class="toolset-status {{DEV_STATUS}}">{{DEV_STATUS}}</span>
|
|
918
|
+
</div>
|
|
919
|
+
<ul class="toolset-tools">
|
|
920
|
+
<li><code>stories-preview</code></li>
|
|
921
|
+
<li><code>get-storybook-story-instructions</code></li>
|
|
922
|
+
<li><code>stories-changed</code></li>
|
|
923
|
+
<li>
|
|
924
|
+
<code>stories-find-by-component</code>
|
|
925
|
+
<span class="toolset-status {{STORIES_BY_COMPONENT_STATUS}}"
|
|
926
|
+
>{{STORIES_BY_COMPONENT_STATUS}}</span
|
|
927
|
+
>
|
|
928
|
+
</li>
|
|
929
|
+
<li><code>review-create</code></li>
|
|
930
|
+
</ul>
|
|
931
|
+
{{DEV_NOTICE}}
|
|
932
|
+
</div>
|
|
933
|
+
|
|
934
|
+
<div class="toolset">
|
|
935
|
+
<div class="toolset-header">
|
|
936
|
+
<span>docs</span>
|
|
937
|
+
<span class="toolset-status {{DOCS_STATUS}}">{{DOCS_STATUS}}</span>
|
|
938
|
+
</div>
|
|
939
|
+
<ul class="toolset-tools">
|
|
940
|
+
<li><code>docs-list</code></li>
|
|
941
|
+
<li><code>docs-show</code></li>
|
|
942
|
+
<li><code>docs-show-story</code></li>
|
|
943
|
+
</ul>
|
|
944
|
+
{{DOCS_NOTICE}}
|
|
945
|
+
</div>
|
|
946
|
+
|
|
947
|
+
<div class="toolset">
|
|
948
|
+
<div class="toolset-header">
|
|
949
|
+
<span>test</span>
|
|
950
|
+
<span class="toolset-status {{TEST_STATUS}}">{{TEST_STATUS}}</span>
|
|
951
|
+
</div>
|
|
952
|
+
<ul class="toolset-tools">
|
|
953
|
+
<li><code>test-run</code>{{A11Y_BADGE}}</li>
|
|
954
|
+
</ul>
|
|
955
|
+
{{TEST_NOTICE}}
|
|
956
|
+
</div>
|
|
957
|
+
</div>
|
|
958
|
+
|
|
959
|
+
{{MANIFEST_DEBUGGER_LINK}}
|
|
960
|
+
</div>
|
|
961
|
+
</body>
|
|
962
|
+
</html>
|
|
963
|
+
`;
|
|
964
|
+
|
|
965
|
+
// src/addon-mcp/preset.ts
|
|
966
|
+
import path from "node:path";
|
|
967
|
+
|
|
968
|
+
// src/addon-mcp/auth/composition-auth.ts
|
|
969
|
+
import {
|
|
970
|
+
ComponentManifestMap,
|
|
971
|
+
DocsManifestMap
|
|
972
|
+
} from "@aussieljk/forkbook/internal/toolsets-docs";
|
|
973
|
+
import { logger as logger5 } from "@aussieljk/forkbook/internal/node-logger";
|
|
974
|
+
import * as v2 from "valibot";
|
|
975
|
+
var OAuthResourceMetadata = v2.object({
|
|
976
|
+
resource: v2.optional(v2.string()),
|
|
977
|
+
authorization_servers: v2.pipe(v2.array(v2.string()), v2.minLength(1)),
|
|
978
|
+
scopes_supported: v2.optional(v2.array(v2.string()))
|
|
979
|
+
}), OAuthServerMetadata = v2.object({
|
|
980
|
+
issuer: v2.string(),
|
|
981
|
+
authorization_endpoint: v2.string(),
|
|
982
|
+
token_endpoint: v2.string(),
|
|
983
|
+
scopes_supported: v2.optional(v2.array(v2.string()))
|
|
984
|
+
}), MANIFEST_CACHE_TTL = 3600 * 1e3, REVALIDATION_TTL = 60 * 1e3, AuthenticationError = class extends Error {
|
|
985
|
+
constructor(url2) {
|
|
986
|
+
super(`Authentication failed for ${url2}. Your token may be invalid or expired.`), this.name = "AuthenticationError";
|
|
987
|
+
}
|
|
988
|
+
}, CompositionAuth = class {
|
|
989
|
+
#authRequirement = null;
|
|
990
|
+
#authRequiredUrls = [];
|
|
991
|
+
#refsWithManifests = [];
|
|
992
|
+
#manifestCache = /* @__PURE__ */ new Map();
|
|
993
|
+
#lastToken = null;
|
|
994
|
+
#authErrors = /* @__PURE__ */ new WeakMap();
|
|
995
|
+
/** Initialize by checking which refs require authentication and have manifests. */
|
|
996
|
+
async initialize(refs) {
|
|
997
|
+
for (let ref of refs)
|
|
998
|
+
try {
|
|
999
|
+
let result = await this.#checkRef(ref.url);
|
|
1000
|
+
if (result === "manifest-not-found") {
|
|
1001
|
+
logger5.warn(
|
|
1002
|
+
`[addon-mcp] Skipping composed ref "${ref.title}" (${ref.url}): components manifest not found at ${ref.url}/manifests/components.json. Enable the \`componentsManifest\` feature on that Forkbook to compose it into MCP.`
|
|
1003
|
+
);
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
if (result === "manifest-invalid") {
|
|
1007
|
+
logger5.warn(
|
|
1008
|
+
`[addon-mcp] Skipping composed ref "${ref.title}" (${ref.url}): its components manifest failed validation. This usually means a version mismatch between the composed Forkbook and this one \u2014 upgrade the older side.`
|
|
1009
|
+
);
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
if (this.#refsWithManifests.push(ref), result === "public") continue;
|
|
1013
|
+
if (this.#authRequiredUrls.push(ref.url), !this.#authRequirement)
|
|
1014
|
+
this.#authRequirement = result;
|
|
1015
|
+
else {
|
|
1016
|
+
let existingServer = this.#authRequirement.resourceMetadata.authorization_servers[0], newServer = result.resourceMetadata.authorization_servers[0];
|
|
1017
|
+
existingServer !== newServer && logger5.warn(
|
|
1018
|
+
`[addon-mcp] Composed ref "${ref.title}" uses a different OAuth server (${newServer}) than the first authenticated ref (${existingServer}). Only the first OAuth server will be used for authentication.`
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
logger5.warn(
|
|
1023
|
+
`[addon-mcp] Skipping composed ref "${ref.title}" (${ref.url}): the ref could not be reached (${error instanceof Error ? error.message : String(error)}). Refs are only checked at dev-server boot \u2014 restart Forkbook once the ref is reachable.`
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
get requiresAuth() {
|
|
1028
|
+
return this.#authRequiredUrls.length > 0;
|
|
1029
|
+
}
|
|
1030
|
+
get authUrls() {
|
|
1031
|
+
return this.#authRequiredUrls;
|
|
1032
|
+
}
|
|
1033
|
+
/** Check if a request encountered an auth error during manifest fetching. */
|
|
1034
|
+
hadAuthError(request) {
|
|
1035
|
+
return this.#authErrors.has(request);
|
|
1036
|
+
}
|
|
1037
|
+
/** Check if a URL requires authentication based on discovered auth requirements. */
|
|
1038
|
+
#isAuthRequiredUrl(url2) {
|
|
1039
|
+
return this.#authRequiredUrls.some((authUrl) => url2.startsWith(authUrl));
|
|
1040
|
+
}
|
|
1041
|
+
/** Build .well-known/oauth-protected-resource response. */
|
|
1042
|
+
buildWellKnown(origin2) {
|
|
1043
|
+
return this.#authRequirement ? {
|
|
1044
|
+
resource: `${origin2}/mcp`,
|
|
1045
|
+
authorization_servers: this.#authRequirement.resourceMetadata.authorization_servers,
|
|
1046
|
+
scopes_supported: this.#authRequirement.resourceMetadata.scopes_supported
|
|
1047
|
+
} : null;
|
|
1048
|
+
}
|
|
1049
|
+
/** Build WWW-Authenticate header for 401 responses */
|
|
1050
|
+
buildWwwAuthenticate(origin2) {
|
|
1051
|
+
return `Bearer error="unauthorized", error_description="Authorization needed for composed Storybooks", resource_metadata="${origin2}/.well-known/oauth-protected-resource"`;
|
|
1052
|
+
}
|
|
1053
|
+
/** Build sources configuration: local first, then refs that have manifests. */
|
|
1054
|
+
buildSources() {
|
|
1055
|
+
return [
|
|
1056
|
+
{ id: "local", title: "Local" },
|
|
1057
|
+
...this.#refsWithManifests.map((ref) => ({
|
|
1058
|
+
id: ref.id,
|
|
1059
|
+
title: ref.title,
|
|
1060
|
+
url: ref.url
|
|
1061
|
+
}))
|
|
1062
|
+
];
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Create a manifest provider for multi-source mode.
|
|
1066
|
+
*
|
|
1067
|
+
* Remote sources are fetched over HTTP with auth and caching; the local source fetches from
|
|
1068
|
+
* `localOrigin`. In `docgenServer` mode core 404s the local `/manifests/*.json`, and
|
|
1069
|
+
* the composition reads that source through its own access instead of this provider.
|
|
1070
|
+
*/
|
|
1071
|
+
createManifestProvider(localOrigin) {
|
|
1072
|
+
return async (request, path2, source) => {
|
|
1073
|
+
let token = extractBearerToken(request?.headers.get("Authorization")), remoteSource = source?.url ? { ...source, url: source.url } : void 0, baseUrl = remoteSource?.url ?? localOrigin, manifestUrl = `${baseUrl}${path2.replace(/^\.\//, "/")}`, isRemote = !!remoteSource, tokenForRequest = isRemote && this.#isAuthRequiredUrl(baseUrl) ? token : null;
|
|
1074
|
+
if (token && token !== this.#lastToken && (this.#manifestCache.clear(), this.#lastToken = token), isRemote) {
|
|
1075
|
+
let cached = this.#manifestCache.get(manifestUrl);
|
|
1076
|
+
if (cached)
|
|
1077
|
+
if (Date.now() - cached.timestamp > MANIFEST_CACHE_TTL)
|
|
1078
|
+
this.#manifestCache.delete(manifestUrl);
|
|
1079
|
+
else
|
|
1080
|
+
return (!cached.lastRevalidatedAt || Date.now() - cached.lastRevalidatedAt > REVALIDATION_TTL) && (cached.lastRevalidatedAt = Date.now(), this.#fetchManifest(manifestUrl, tokenForRequest).then(
|
|
1081
|
+
(text) => this.#manifestCache.set(manifestUrl, {
|
|
1082
|
+
text,
|
|
1083
|
+
timestamp: Date.now(),
|
|
1084
|
+
lastRevalidatedAt: Date.now()
|
|
1085
|
+
})
|
|
1086
|
+
).catch(() => {
|
|
1087
|
+
})), cached.text;
|
|
1088
|
+
}
|
|
1089
|
+
try {
|
|
1090
|
+
let text = await this.#fetchManifest(manifestUrl, tokenForRequest);
|
|
1091
|
+
return isRemote && this.#manifestCache.set(manifestUrl, { text, timestamp: Date.now() }), text;
|
|
1092
|
+
} catch (error) {
|
|
1093
|
+
throw error instanceof AuthenticationError && request && this.#authErrors.set(request, error), error;
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Fetch a manifest with optional auth token.
|
|
1099
|
+
* If the response is 200 but not a valid manifest, checks /mcp for auth issues.
|
|
1100
|
+
*/
|
|
1101
|
+
async #fetchManifest(url2, token) {
|
|
1102
|
+
let headers = { Accept: "application/json" };
|
|
1103
|
+
token && (headers.Authorization = `Bearer ${token}`);
|
|
1104
|
+
let response = await fetch(url2, { headers });
|
|
1105
|
+
if (response.status === 401)
|
|
1106
|
+
throw new AuthenticationError(url2);
|
|
1107
|
+
if (!response.ok)
|
|
1108
|
+
throw new Error(`Failed to fetch ${url2}: ${response.status}`);
|
|
1109
|
+
let text = await response.text(), { pathname } = new URL(url2), isComponentsManifest = pathname.endsWith("/manifests/components.json"), isDocsManifest = pathname.endsWith("/manifests/docs.json"), schema = isComponentsManifest ? ComponentManifestMap : isDocsManifest ? DocsManifestMap : v2.unknown();
|
|
1110
|
+
if (v2.safeParse(v2.pipe(v2.string(), v2.parseJson(), schema), text).success)
|
|
1111
|
+
return text;
|
|
1112
|
+
throw await this.#isMcpUnauthorized(new URL(url2).origin) ? new AuthenticationError(url2) : new Error(
|
|
1113
|
+
`Invalid manifest response from ${url2}: expected valid JSON manifest but got unexpected content.`
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Check a ref to determine if it has a manifest and whether it requires auth.
|
|
1118
|
+
* Returns 'public' if the ref has a valid manifest without auth,
|
|
1119
|
+
* an AuthRequirement if auth is needed, or the reason the ref has no usable manifest:
|
|
1120
|
+
* 'manifest-not-found' for a non-OK or non-JSON response (SPA fallback pages land here),
|
|
1121
|
+
* 'manifest-invalid' for real JSON that fails the manifest schema.
|
|
1122
|
+
*/
|
|
1123
|
+
async #checkRef(refUrl) {
|
|
1124
|
+
let response = await fetch(`${refUrl}/manifests/components.json`, {
|
|
1125
|
+
headers: { Accept: "application/json" }
|
|
1126
|
+
}), authReq = await this.#parseAuthFromResponse(response);
|
|
1127
|
+
if (authReq) return authReq;
|
|
1128
|
+
let noManifestReason = "manifest-not-found";
|
|
1129
|
+
if (response.ok) {
|
|
1130
|
+
let text = await response.text(), json = v2.safeParse(v2.pipe(v2.string(), v2.parseJson()), text);
|
|
1131
|
+
if (json.success) {
|
|
1132
|
+
if (v2.safeParse(ComponentManifestMap, json.output).success)
|
|
1133
|
+
return "public";
|
|
1134
|
+
noManifestReason = "manifest-invalid";
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
let mcpAuth = await this.#checkMcpAuth(refUrl);
|
|
1138
|
+
return mcpAuth || noManifestReason;
|
|
1139
|
+
}
|
|
1140
|
+
/** Check /mcp endpoint for 401 auth requirement. */
|
|
1141
|
+
async #checkMcpAuth(refUrl) {
|
|
1142
|
+
let response = await fetch(`${refUrl}/mcp`, {
|
|
1143
|
+
method: "POST",
|
|
1144
|
+
headers: { "Content-Type": "application/json" },
|
|
1145
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" })
|
|
1146
|
+
});
|
|
1147
|
+
return this.#parseAuthFromResponse(response);
|
|
1148
|
+
}
|
|
1149
|
+
/** Quick check: does the remote /mcp return 401? */
|
|
1150
|
+
async #isMcpUnauthorized(origin2) {
|
|
1151
|
+
try {
|
|
1152
|
+
return (await fetch(`${origin2}/mcp`, {
|
|
1153
|
+
method: "POST",
|
|
1154
|
+
headers: { "Content-Type": "application/json" },
|
|
1155
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" })
|
|
1156
|
+
})).status === 401;
|
|
1157
|
+
} catch {
|
|
1158
|
+
return !1;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
/** Extract auth requirement from a 401 response's WWW-Authenticate header. */
|
|
1162
|
+
async #parseAuthFromResponse(response) {
|
|
1163
|
+
if (response.status !== 401) return null;
|
|
1164
|
+
let wwwAuth = response.headers.get("WWW-Authenticate");
|
|
1165
|
+
if (!wwwAuth) return null;
|
|
1166
|
+
let match = wwwAuth.match(/resource_metadata="([^"]+)"/);
|
|
1167
|
+
if (!match?.[1]) return null;
|
|
1168
|
+
let resourceMetadataUrl = match[1], resourceResponse = await fetch(resourceMetadataUrl);
|
|
1169
|
+
if (!resourceResponse.ok)
|
|
1170
|
+
return logger5.warn(
|
|
1171
|
+
`[addon-mcp] Failed to fetch OAuth resource metadata from ${resourceMetadataUrl}: ${resourceResponse.status}`
|
|
1172
|
+
), null;
|
|
1173
|
+
let resourceResult = v2.safeParse(OAuthResourceMetadata, await resourceResponse.json());
|
|
1174
|
+
if (!resourceResult.success)
|
|
1175
|
+
return logger5.warn(
|
|
1176
|
+
`[addon-mcp] Invalid OAuth resource metadata from ${resourceMetadataUrl}: ${resourceResult.issues.map((i) => i.message).join(", ")}`
|
|
1177
|
+
), null;
|
|
1178
|
+
let serverMetadataUrl = `${resourceResult.output.authorization_servers[0]}/.well-known/oauth-authorization-server`, serverResponse = await fetch(serverMetadataUrl);
|
|
1179
|
+
if (!serverResponse.ok)
|
|
1180
|
+
return logger5.warn(
|
|
1181
|
+
`[addon-mcp] Failed to fetch OAuth server metadata from ${serverMetadataUrl}: ${serverResponse.status}`
|
|
1182
|
+
), null;
|
|
1183
|
+
let serverResult = v2.safeParse(OAuthServerMetadata, await serverResponse.json());
|
|
1184
|
+
return serverResult.success ? {
|
|
1185
|
+
resourceMetadataUrl,
|
|
1186
|
+
resourceMetadata: resourceResult.output,
|
|
1187
|
+
serverMetadata: serverResult.output
|
|
1188
|
+
} : (logger5.warn(
|
|
1189
|
+
`[addon-mcp] Invalid OAuth server metadata from ${serverMetadataUrl}: ${serverResult.issues.map((i) => i.message).join(", ")}`
|
|
1190
|
+
), null);
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
function extractBearerToken(authHeader) {
|
|
1194
|
+
let bearer = (Array.isArray(authHeader) ? authHeader : [authHeader]).find((value) => typeof value == "string" && value.startsWith("Bearer "));
|
|
1195
|
+
return bearer ? bearer.slice(7) : null;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// src/addon-mcp/auth/resolve-composition-sources.ts
|
|
1199
|
+
import { getRefsFromConfig } from "@aussieljk/forkbook/internal/core-server";
|
|
1200
|
+
async function resolveCompositionSources(options) {
|
|
1201
|
+
let refs = await getRefsFromConfig(options), compositionAuth = new CompositionAuth();
|
|
1202
|
+
if (refs.length === 0)
|
|
1203
|
+
return { refs, compositionAuth, sources: void 0, multiSource: !1 };
|
|
1204
|
+
await compositionAuth.initialize(refs);
|
|
1205
|
+
let sources = compositionAuth.buildSources();
|
|
1206
|
+
return {
|
|
1207
|
+
refs,
|
|
1208
|
+
compositionAuth,
|
|
1209
|
+
sources,
|
|
1210
|
+
multiSource: sources.some((source) => !!source.url)
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
// src/addon-mcp/preset.ts
|
|
1215
|
+
import { logger as logger7 } from "@aussieljk/forkbook/internal/node-logger";
|
|
1216
|
+
|
|
1217
|
+
// src/addon-mcp/utils/get-story-index.ts
|
|
1218
|
+
import { logger as logger6 } from "@aussieljk/forkbook/internal/node-logger";
|
|
1219
|
+
async function getStoryIndex(options) {
|
|
1220
|
+
let generator = await options.presets.apply(
|
|
1221
|
+
"storyIndexGenerator"
|
|
1222
|
+
);
|
|
1223
|
+
if (!generator)
|
|
1224
|
+
throw new Error(
|
|
1225
|
+
"Forkbook story index generator is unavailable. These MCP tools require a running Forkbook dev server with a builder that exposes the story index."
|
|
1226
|
+
);
|
|
1227
|
+
let index = await generator.getIndex();
|
|
1228
|
+
return logger6.debug(`Story index entries found: ${Object.keys(index.entries).length}`), index;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
// src/addon-mcp/preset.ts
|
|
1232
|
+
var previewAnnotations = async (existingAnnotations = []) => [...existingAnnotations, path.join(import.meta.dirname, "preview.js")], experimental_devServer = async (app, options) => {
|
|
1233
|
+
let addonOptions = v3.parse(AddonOptions, {
|
|
1234
|
+
endpoint: options.endpoint,
|
|
1235
|
+
toolsets: options.toolsets ?? {}
|
|
1236
|
+
}), origin2 = `http://localhost:${options.port}`, endpoint = addonOptions.endpoint ?? DEFAULT_MCP_ENDPOINT, core = await options.presets.apply("core", {}), hostValidation = {
|
|
1237
|
+
host: options.host,
|
|
1238
|
+
allowedHosts: core?.allowedHosts,
|
|
1239
|
+
localAddress: options.localAddress,
|
|
1240
|
+
networkAddress: options.networkAddress
|
|
1241
|
+
}, skipOriginValidation = isWebContainer(), rejectDisallowedOrigin = (req, res) => {
|
|
1242
|
+
if (skipOriginValidation)
|
|
1243
|
+
return !1;
|
|
1244
|
+
let { origin: requestOrigin } = req.headers;
|
|
1245
|
+
if (!requestOrigin)
|
|
1246
|
+
return !1;
|
|
1247
|
+
try {
|
|
1248
|
+
if (isValidHost(new URL(requestOrigin).host, hostValidation))
|
|
1249
|
+
return !1;
|
|
1250
|
+
} catch {
|
|
1251
|
+
}
|
|
1252
|
+
return res.writeHead(403, { "Content-Type": "text/plain" }), res.end("Invalid origin"), !0;
|
|
1253
|
+
}, rejectNonJsonBody = (req, res) => req.headers["content-type"]?.split(";")[0].trim().toLowerCase() === "application/json" ? !1 : (res.writeHead(415, { "Content-Type": "text/plain" }), res.end("Unsupported Media Type: Content-Type must be application/json"), !0), { refs, compositionAuth, sources, multiSource } = await resolveCompositionSources(options), rawAvailability = await getToolAvailability2(options), localAccess = rawAvailability.docgenServer && refs.length > 0 ? createLocalDocsAccess({
|
|
1254
|
+
storyIndex: { getIndex: () => getStoryIndex(options) },
|
|
1255
|
+
getManifests: () => loadManifests(options.presets)
|
|
1256
|
+
}) : void 0, createManifestProvider;
|
|
1257
|
+
refs.length > 0 && (logger7.info(`Initialized composition with ${refs.length} remote Forkbook(s)`), compositionAuth.requiresAuth && logger7.info(`Auth required for: ${compositionAuth.authUrls.join(", ")}`), logger7.info(`Sources: ${(sources ?? []).map((s) => s.id).join(", ")}`), createManifestProvider = () => compositionAuth.createManifestProvider(origin2));
|
|
1258
|
+
let manifestAccessFor = (req) => ({
|
|
1259
|
+
manifestProvider: createManifestProvider?.(req),
|
|
1260
|
+
localAccess
|
|
1261
|
+
});
|
|
1262
|
+
app.get("/.well-known/oauth-protected-resource", (_req, res) => {
|
|
1263
|
+
let wellKnown = compositionAuth.buildWellKnown(origin2);
|
|
1264
|
+
if (!wellKnown) {
|
|
1265
|
+
res.writeHead(404), res.end("Not found");
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
res.writeHead(200, { "Content-Type": "application/json" }), res.end(JSON.stringify(wellKnown));
|
|
1269
|
+
});
|
|
1270
|
+
let requireAuth = (req, res) => {
|
|
1271
|
+
let token = extractBearerToken(req.headers.authorization);
|
|
1272
|
+
return compositionAuth.requiresAuth && !token ? (res.writeHead(401, {
|
|
1273
|
+
"Content-Type": "text/plain",
|
|
1274
|
+
"WWW-Authenticate": compositionAuth.buildWwwAuthenticate(origin2)
|
|
1275
|
+
}), res.end("401 - Unauthorized"), !0) : !1;
|
|
1276
|
+
};
|
|
1277
|
+
app.post(endpoint, (req, res) => {
|
|
1278
|
+
if (!rejectDisallowedOrigin(req, res) && !requireAuth(req, res) && !rejectNonJsonBody(req, res))
|
|
1279
|
+
return mcpServerHandler({
|
|
1280
|
+
req,
|
|
1281
|
+
res,
|
|
1282
|
+
options,
|
|
1283
|
+
addonOptions,
|
|
1284
|
+
endpoint,
|
|
1285
|
+
sources,
|
|
1286
|
+
...manifestAccessFor(req),
|
|
1287
|
+
compositionAuth
|
|
1288
|
+
});
|
|
1289
|
+
});
|
|
1290
|
+
let {
|
|
1291
|
+
moduleGraphSupported,
|
|
1292
|
+
docsEnabled,
|
|
1293
|
+
docsHasManifests,
|
|
1294
|
+
docsFeatureEnabled,
|
|
1295
|
+
testSupported,
|
|
1296
|
+
a11yEnabled: a11yEnabled2
|
|
1297
|
+
} = getEffectiveToolAvailability2(rawAvailability, { multiSource }), isDevEnabled = addonOptions.toolsets?.dev ?? !0, isDocsEnabled = docsEnabled && (addonOptions.toolsets?.docs ?? !0), isTestEnabled = testSupported && (addonOptions.toolsets?.test ?? !0);
|
|
1298
|
+
return app.get(endpoint, (req, res) => {
|
|
1299
|
+
if (rejectDisallowedOrigin(req, res)) return;
|
|
1300
|
+
if (!req.headers.accept?.includes("text/html"))
|
|
1301
|
+
return requireAuth(req, res) ? void 0 : mcpServerHandler({
|
|
1302
|
+
req,
|
|
1303
|
+
res,
|
|
1304
|
+
options,
|
|
1305
|
+
addonOptions,
|
|
1306
|
+
endpoint,
|
|
1307
|
+
sources,
|
|
1308
|
+
...manifestAccessFor(req),
|
|
1309
|
+
compositionAuth
|
|
1310
|
+
});
|
|
1311
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1312
|
+
let docsNotice = "";
|
|
1313
|
+
docsHasManifests ? docsFeatureEnabled || (docsNotice = `<div class="toolset-notice">
|
|
1314
|
+
This toolset requires enabling the component manifest feature.
|
|
1315
|
+
<a target="_blank" href="https://github.com/storybookjs/storybook/tree/next/code/addons/mcp">Learn how to enable it</a>
|
|
1316
|
+
</div>`) : docsNotice = docsFeatureEnabled ? `<div class="toolset-notice">
|
|
1317
|
+
This toolset requires a components manifest, which your framework does not generate.
|
|
1318
|
+
<a target="_blank" href="https://storybook.js.org/docs/ai/mcp/overview#framework-support">See which frameworks are supported</a>
|
|
1319
|
+
</div>` : `<div class="toolset-notice">
|
|
1320
|
+
This toolset requires a components manifest, which is generated by the React frameworks. Enable the <code>componentsManifest</code> feature.
|
|
1321
|
+
<a target="_blank" href="https://storybook.js.org/docs/ai/mcp/overview#framework-support">Learn how to enable it</a>
|
|
1322
|
+
</div>`;
|
|
1323
|
+
let testNoticeLines = [
|
|
1324
|
+
!testSupported && 'This toolset requires Forkbook 10.3.0+ with <code>@aussieljk/forkbook/addon-vitest</code>. <a target="_blank" href="https://storybook.js.org/docs/writing-tests/integrations/vitest-addon#install-and-set-up">Learn how to set it up</a>',
|
|
1325
|
+
!a11yEnabled2 && 'Add <code>@aussieljk/forkbook/addon-a11y</code> for accessibility testing. <a target="_blank" href="https://storybook.js.org/docs/writing-tests/accessibility-testing">Learn more</a>'
|
|
1326
|
+
].filter(Boolean), testNotice = testNoticeLines.length ? `<div class="toolset-notice">${testNoticeLines.join("<br>")}</div>` : "", a11yBadge = a11yEnabled2 ? ' <span class="toolset-status enabled">+ accessibility</span>' : "", devNoticeLines = isDevEnabled ? [
|
|
1327
|
+
!moduleGraphSupported && "<code>stories-find-by-component</code> requires a dev server with a builder that supports the module graph (Vite)."
|
|
1328
|
+
].filter(Boolean) : ["The <code>dev</code> toolset is disabled via addon options."], devNotice = devNoticeLines.length ? `<div class="toolset-notice">${devNoticeLines.join("<br>")}</div>` : "", html = template_default.replaceAll("{{DEV_STATUS}}", isDevEnabled ? "enabled" : "disabled").replaceAll(
|
|
1329
|
+
"{{STORIES_BY_COMPONENT_STATUS}}",
|
|
1330
|
+
isDevEnabled && moduleGraphSupported ? "enabled" : "disabled"
|
|
1331
|
+
).replace("{{DEV_NOTICE}}", devNotice).replaceAll("{{DOCS_STATUS}}", isDocsEnabled ? "enabled" : "disabled").replace("{{DOCS_NOTICE}}", docsNotice).replaceAll("{{TEST_STATUS}}", isTestEnabled ? "enabled" : "disabled").replace("{{TEST_NOTICE}}", testNotice).replace(
|
|
1332
|
+
"{{MANIFEST_DEBUGGER_LINK}}",
|
|
1333
|
+
rawAvailability.docsEnabled ? '<p>View the <a href="/manifests/components.html">component manifest debugger</a>.</p>' : ""
|
|
1334
|
+
).replace("{{A11Y_BADGE}}", a11yBadge);
|
|
1335
|
+
res.end(html);
|
|
1336
|
+
}), app;
|
|
1337
|
+
}, features = async (existingFeatures) => ({
|
|
1338
|
+
...existingFeatures,
|
|
1339
|
+
componentsManifest: !0
|
|
1340
|
+
});
|
|
1341
|
+
export {
|
|
1342
|
+
experimental_devServer,
|
|
1343
|
+
features,
|
|
1344
|
+
previewAnnotations
|
|
1345
|
+
};
|