UNPKG

storybook

Version:

Storybook: Develop, document, and test UI components in isolation

1,109 lines (1,068 loc) • 44.8 kB
import CJS_COMPAT_NODE_URL_e6wt3b00afv from 'node:url'; import CJS_COMPAT_NODE_PATH_e6wt3b00afv from 'node:path'; import CJS_COMPAT_NODE_MODULE_e6wt3b00afv from "node:module"; var __filename = CJS_COMPAT_NODE_URL_e6wt3b00afv.fileURLToPath(import.meta.url); var __dirname = CJS_COMPAT_NODE_PATH_e6wt3b00afv.dirname(__filename); var require = CJS_COMPAT_NODE_MODULE_e6wt3b00afv.createRequire(import.meta.url); // ------------------------------------------------------------ // end of CJS compatibility banner, injected by Storybook's esbuild configuration // ------------------------------------------------------------ import { version } from "./chunk-BFUOXQW6.js"; import { createFileSystemCache, execa, execaCommand, getProjectRoot, resolvePathInStorybookCache, up } from "./chunk-3LP2BDDH.js"; import { DATA_FETCHING_PACKAGES, I18N_PACKAGES, ROUTER_PACKAGES, STATE_MANAGEMENT_PACKAGES, STYLING_PACKAGES, TEST_PACKAGES, UI_LIBRARY_PACKAGES, matchesPackagePattern } from "./chunk-L5XXUDIG.js"; import { globalSettings } from "./chunk-GHPI5GQW.js"; import { resolvePackageDir } from "./chunk-QAXH75FV.js"; import { slash } from "./chunk-SOP5BQAH.js"; import { __commonJS, __toESM } from "./chunk-LF7MVXPB.js"; // ../../node_modules/fetch-retry/index.js var require_fetch_retry = __commonJS({ "../../node_modules/fetch-retry/index.js"(exports, module) { "use strict"; module.exports = function(fetch2, defaults) { if (defaults = defaults || {}, typeof fetch2 != "function") throw new ArgumentError("fetch must be a function"); if (typeof defaults != "object") throw new ArgumentError("defaults must be an object"); if (defaults.retries !== void 0 && !isPositiveInteger(defaults.retries)) throw new ArgumentError("retries must be a positive integer"); if (defaults.retryDelay !== void 0 && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay != "function") throw new ArgumentError("retryDelay must be a positive integer or a function returning a positive integer"); if (defaults.retryOn !== void 0 && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn != "function") throw new ArgumentError("retryOn property expects an array or function"); var baseDefaults = { retries: 3, retryDelay: 1e3, retryOn: [] }; return defaults = Object.assign(baseDefaults, defaults), function(input, init) { var retries = defaults.retries, retryDelay = defaults.retryDelay, retryOn = defaults.retryOn; if (init && init.retries !== void 0) if (isPositiveInteger(init.retries)) retries = init.retries; else throw new ArgumentError("retries must be a positive integer"); if (init && init.retryDelay !== void 0) if (isPositiveInteger(init.retryDelay) || typeof init.retryDelay == "function") retryDelay = init.retryDelay; else throw new ArgumentError("retryDelay must be a positive integer or a function returning a positive integer"); if (init && init.retryOn) if (Array.isArray(init.retryOn) || typeof init.retryOn == "function") retryOn = init.retryOn; else throw new ArgumentError("retryOn property expects an array or function"); return new Promise(function(resolve2, reject) { var wrappedFetch = function(attempt) { var _input = typeof Request < "u" && input instanceof Request ? input.clone() : input; fetch2(_input, init).then(function(response) { if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) resolve2(response); else if (typeof retryOn == "function") try { return Promise.resolve(retryOn(attempt, null, response)).then(function(retryOnResponse) { retryOnResponse ? retry2(attempt, null, response) : resolve2(response); }).catch(reject); } catch (error) { reject(error); } else attempt < retries ? retry2(attempt, null, response) : resolve2(response); }).catch(function(error) { if (typeof retryOn == "function") try { Promise.resolve(retryOn(attempt, error, null)).then(function(retryOnResponse) { retryOnResponse ? retry2(attempt, error, null) : reject(error); }).catch(function(error2) { reject(error2); }); } catch (error2) { reject(error2); } else attempt < retries ? retry2(attempt, error, null) : reject(error); }); }; function retry2(attempt, error, response) { var delay = typeof retryDelay == "function" ? retryDelay(attempt, error, response) : retryDelay; setTimeout(function() { wrappedFetch(++attempt); }, delay); } wrappedFetch(0); }); }; }; function isPositiveInteger(value) { return Number.isInteger(value) && value >= 0; } function ArgumentError(message) { this.name = "ArgumentError", this.message = message; } } }); // src/telemetry/index.ts import { logger as logger2 } from "storybook/internal/node-logger"; // src/telemetry/notify.ts import { cache } from "storybook/internal/common"; import { logger } from "storybook/internal/node-logger"; var TELEMETRY_KEY_NOTIFY_DATE = "telemetry-notification-date", called = !1, notify = async () => { called || (called = !0, await cache.get(TELEMETRY_KEY_NOTIFY_DATE, null) || (cache.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now()), logger.info( "Storybook collects completely anonymous usage telemetry. We use it to shape Storybook's roadmap and prioritize features. You can learn more, including how to opt out, at https://storybook.js.org/telemetry" ))); }; // src/telemetry/sanitize.ts import os from "node:os"; import path from "node:path"; function regexpEscape(str) { return str.replace(/[-[/{}()*+?.\\^$|]/g, "\\$&"); } function removeAnsiEscapeCodes(input = "") { return input.replace(/\u001B\[[0-9;]*m/g, ""); } function cleanPaths(str, separator = path.sep) { if (!str) return str; let separators = Array.from(/* @__PURE__ */ new Set([separator, "/", "\\"])); return [process.cwd(), os.homedir()].filter(Boolean).flatMap( (basePath) => separators.map((sep2) => ({ separator: sep2, normalizedPath: basePath.split(/[\\/]/).join(sep2) })) ).forEach(({ separator: sep2, normalizedPath }) => { let stack = normalizedPath.split(sep2); for (; stack.length > 1; ) { let currentPath = stack.join(sep2), currentRegex = new RegExp(regexpEscape(currentPath), "gi"); str = str.replace(currentRegex, "$SNIP"); let doubledSeparatorPath = stack.join(sep2 + sep2), doubledSeparatorRegex = new RegExp(regexpEscape(doubledSeparatorPath), "gi"); str = str.replace(doubledSeparatorRegex, "$SNIP"), stack.pop(); } }), str; } function sanitizeError(error, pathSeparator = path.sep) { try { error = { ...JSON.parse(JSON.stringify(error)), message: removeAnsiEscapeCodes(error.message), stack: removeAnsiEscapeCodes(error.stack), cause: error.cause, name: error.name }; let errorString = cleanPaths(JSON.stringify(error), pathSeparator); return JSON.parse(errorString); } catch (err) { return `Sanitization error: ${err instanceof Error ? err.message : String(err)}`; } } // src/telemetry/storybook-metadata.ts import { createHash } from "node:crypto"; import { existsSync as existsSync2 } from "node:fs"; import { readFile } from "node:fs/promises"; import { dirname, resolve } from "node:path"; import { getStorybookConfiguration, getStorybookInfo as getStorybookInfo2, isCI, loadMainConfig, versions } from "storybook/internal/common"; import { getInterpretedFile } from "storybook/internal/common"; import { readConfig } from "storybook/internal/csf-tools"; // src/telemetry/get-application-file-count.ts import { sep } from "node:path"; // src/telemetry/exec-command-count-lines.ts import { createInterface } from "node:readline"; async function execCommandCountLines(command, args, options) { let process3 = execa(command, args, { buffer: !1, ...options }); if (!process3.stdout) throw new Error("Unexpected missing stdout"); let lineCount = 0, rl = createInterface(process3.stdout); return rl.on("line", () => { lineCount += 1; }), await process3, rl.close(), lineCount; } // src/telemetry/run-telemetry-operation.ts var cache2 = createFileSystemCache({ basePath: resolvePathInStorybookCache("telemetry"), ns: "storybook", ttl: 1440 * 60 * 1e3 // 24h }), runTelemetryOperation = async (cacheKey, operation) => { let cached = await cache2.get(cacheKey); return cached === void 0 && (cached = await operation(), cached !== void 0 && await cache2.set(cacheKey, cached)), cached; }; // src/telemetry/get-application-file-count.ts var nameMatches = ["page", "screen"], extensions = ["js", "jsx", "ts", "tsx"], getApplicationFilesCountUncached = async (basePath) => { let globs = nameMatches.flatMap((match) => [ match, [match[0].toUpperCase(), ...match.slice(1)].join("") ]).flatMap( (match) => extensions.map((extension) => `${basePath}${sep}*${match}*.${extension}`) ); try { return await execCommandCountLines("git", ["ls-files", "--", ...globs]); } catch { return; } }, getApplicationFileCount = async (path3) => runTelemetryOperation( "applicationFiles", async () => getApplicationFilesCountUncached(path3) ); // src/telemetry/get-chromatic-version.ts function getChromaticVersionSpecifier(packageJson) { let dependency = packageJson.dependencies?.chromatic || packageJson.devDependencies?.chromatic || packageJson.peerDependencies?.chromatic; return dependency || (packageJson.scripts && Object.values(packageJson.scripts).find((s2) => s2?.match(/chromatic/)) ? "latest" : void 0); } // src/telemetry/get-framework-info.ts import { getStorybookInfo } from "storybook/internal/common"; var cleanAndSanitizePath = (path3) => cleanPaths(path3).replace(/.*node_modules[\\/]/, ""); async function getFrameworkInfo(mainConfig, configDir) { let { frameworkPackage, rendererPackage, builderPackage } = await getStorybookInfo(configDir), frameworkOptions = typeof mainConfig.framework == "object" ? mainConfig.framework.options : {}; return { framework: { name: frameworkPackage ? cleanAndSanitizePath(frameworkPackage) : void 0, options: frameworkOptions }, builder: builderPackage ? cleanAndSanitizePath(builderPackage) : void 0, renderer: rendererPackage ? cleanAndSanitizePath(rendererPackage) : void 0 }; } // src/telemetry/get-has-router-package.ts var routerPackages = /* @__PURE__ */ new Set([ "react-router", "react-router-dom", "remix", "@tanstack/react-router", "expo-router", "@reach/router", "react-easy-router", "@remix-run/router", "wouter", "wouter-preact", "preact-router", "vue-router", "unplugin-vue-router", "@angular/router", "@solidjs/router", // metaframeworks that imply routing "next", "react-scripts", "gatsby", "nuxt", "@sveltejs/kit" ]); function getHasRouterPackage(packageJson) { return Object.keys(packageJson?.dependencies ?? {}).some( (depName) => routerPackages.has(depName) ); } // src/telemetry/get-known-packages.ts import semver from "semver"; // src/telemetry/package-json.ts import { fileURLToPath, pathToFileURL } from "node:url"; var getActualPackageVersions = async (packages) => { let packageNames = Object.keys(packages); return Promise.all(packageNames.map(getActualPackageVersion)); }, getActualPackageVersion = async (packageName) => { try { let packageJson = await getActualPackageJson(packageName); return { name: packageJson?.name || packageName, version: packageJson?.version || null }; } catch { return { name: packageName, version: null }; } }, getActualPackageJson = async (packageName) => { try { let resolvedPackageJsonPath = up({ cwd: fileURLToPath(import.meta.resolve(packageName, process.cwd())) }); resolvedPackageJsonPath || (resolvedPackageJsonPath = import.meta.resolve(`${packageName}/package.json`, process.cwd())); let { default: packageJson } = await import(pathToFileURL(resolvedPackageJsonPath).href, { with: { type: "json" } }); return packageJson; } catch { return; } }; // src/telemetry/get-known-packages.ts function getSafeVersionSpecifier(version2) { if (!version2) return null; if (version2 === "*") return "latest"; if (version2.includes(":")) return "custom-protocol"; if ([ "latest", "next", "canary", "beta", "alpha", "rc", "nightly", "dev", "stable", "experimental", "insiders", "preview" ].includes(version2)) return version2; try { let operator = version2.trim().match(/^[~^]/)?.[0] ?? "", coerced = semver.coerce(version2); return coerced ? `${operator}${coerced.version}` : null; } catch { return "could-not-be-parsed-by-semver"; } } async function analyzeEcosystemPackages(packageJson) { let allDependencies = { ...packageJson?.dependencies, ...packageJson?.devDependencies, ...packageJson?.peerDependencies }, depNames = Object.keys(allDependencies), pickMatches = (packages) => depNames.filter((dep) => matchesPackagePattern(dep, packages)), pickDepsObject = (packages) => { let result = Object.fromEntries( pickMatches(packages).map((dep) => { let rawVersion = allDependencies[dep], version2 = getSafeVersionSpecifier(rawVersion); return [dep, version2]; }) ); return Object.keys(result).length === 0 ? null : result; }, testPackagesResult = Object.fromEntries( await Promise.all( depNames.filter((dep) => matchesPackagePattern(dep, TEST_PACKAGES)).map(async (dep) => { let resolved = (await getActualPackageVersion(dep))?.version ?? allDependencies[dep], version2 = getSafeVersionSpecifier(resolved); return [dep, version2]; }) ) ), testPackages = Object.keys(testPackagesResult).length === 0 ? null : testPackagesResult, stylingPackages = pickDepsObject(STYLING_PACKAGES), stateManagementPackages = pickDepsObject(STATE_MANAGEMENT_PACKAGES), dataFetchingPackages = pickDepsObject(DATA_FETCHING_PACKAGES), uiLibraryPackages = pickDepsObject(UI_LIBRARY_PACKAGES), i18nPackages = pickDepsObject(I18N_PACKAGES), routerPackages2 = pickDepsObject(ROUTER_PACKAGES); return { ...testPackages && { testPackages }, ...stylingPackages && { stylingPackages }, ...stateManagementPackages && { stateManagementPackages }, ...dataFetchingPackages && { dataFetchingPackages }, ...uiLibraryPackages && { uiLibraryPackages }, ...i18nPackages && { i18nPackages }, ...routerPackages2 && { routerPackages: routerPackages2 } }; } // src/telemetry/get-monorepo-type.ts import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { getProjectRoot as getProjectRoot2 } from "storybook/internal/common"; var monorepoConfigs = { Nx: "nx.json", Turborepo: "turbo.json", Lerna: "lerna.json", Rush: "rush.json", Lage: "lage.config.json" }, getMonorepoType = () => { let monorepoType = Object.keys(monorepoConfigs).find((monorepo) => { let configFile = join(getProjectRoot2(), monorepoConfigs[monorepo]); return existsSync(configFile); }); if (monorepoType) return monorepoType; if (!existsSync(join(getProjectRoot2(), "package.json"))) return; if (JSON.parse( readFileSync(join(getProjectRoot2(), "package.json"), { encoding: "utf8" }) )?.workspaces) return "Workspaces"; }; // ../../node_modules/package-manager-detector/dist/commands.mjs function dashDashArg(agent, agentCommand) { return (args) => args.length > 1 ? [agent, agentCommand, args[0], "--", ...args.slice(1)] : [agent, agentCommand, args[0]]; } function denoExecute() { return (args) => ["deno", "run", `npm:${args[0]}`, ...args.slice(1)]; } var npm = { agent: ["npm", 0], run: dashDashArg("npm", "run"), install: ["npm", "i", 0], frozen: ["npm", "ci", 0], global: ["npm", "i", "-g", 0], add: ["npm", "i", 0], upgrade: ["npm", "update", 0], "upgrade-interactive": null, dedupe: ["npm", "dedupe", 0], execute: ["npx", 0], "execute-local": ["npx", 0], uninstall: ["npm", "uninstall", 0], global_uninstall: ["npm", "uninstall", "-g", 0] }, yarn = { agent: ["yarn", 0], run: ["yarn", "run", 0], install: ["yarn", "install", 0], frozen: ["yarn", "install", "--frozen-lockfile", 0], global: ["yarn", "global", "add", 0], add: ["yarn", "add", 0], upgrade: ["yarn", "upgrade", 0], "upgrade-interactive": ["yarn", "upgrade-interactive", 0], dedupe: null, execute: ["npx", 0], "execute-local": dashDashArg("yarn", "exec"), uninstall: ["yarn", "remove", 0], global_uninstall: ["yarn", "global", "remove", 0] }, yarnBerry = { ...yarn, frozen: ["yarn", "install", "--immutable", 0], upgrade: ["yarn", "up", 0], "upgrade-interactive": ["yarn", "up", "-i", 0], dedupe: ["yarn", "dedupe", 0], execute: ["yarn", "dlx", 0], "execute-local": ["yarn", "exec", 0], // Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821 global: ["npm", "i", "-g", 0], global_uninstall: ["npm", "uninstall", "-g", 0] }, pnpm = { agent: ["pnpm", 0], run: ["pnpm", "run", 0], install: ["pnpm", "i", 0], frozen: ["pnpm", "i", "--frozen-lockfile", 0], global: ["pnpm", "add", "-g", 0], add: ["pnpm", "add", 0], upgrade: ["pnpm", "update", 0], "upgrade-interactive": ["pnpm", "update", "-i", 0], dedupe: ["pnpm", "dedupe", 0], execute: ["pnpm", "dlx", 0], "execute-local": ["pnpm", "exec", 0], uninstall: ["pnpm", "remove", 0], global_uninstall: ["pnpm", "remove", "--global", 0] }, bun = { agent: ["bun", 0], run: ["bun", "run", 0], install: ["bun", "install", 0], frozen: ["bun", "install", "--frozen-lockfile", 0], global: ["bun", "add", "-g", 0], add: ["bun", "add", 0], upgrade: ["bun", "update", 0], "upgrade-interactive": ["bun", "update", "-i", 0], dedupe: null, execute: ["bun", "x", 0], "execute-local": ["bun", "x", 0], uninstall: ["bun", "remove", 0], global_uninstall: ["bun", "remove", "-g", 0] }, deno = { agent: ["deno", 0], run: ["deno", "task", 0], install: ["deno", "install", 0], frozen: ["deno", "install", "--frozen", 0], global: ["deno", "install", "-g", 0], add: ["deno", "add", 0], upgrade: ["deno", "outdated", "--update", 0], "upgrade-interactive": ["deno", "outdated", "--update", 0], dedupe: null, execute: denoExecute(), "execute-local": ["deno", "task", "--eval", 0], uninstall: ["deno", "remove", 0], global_uninstall: ["deno", "uninstall", "-g", 0] }, COMMANDS = { npm, yarn, "yarn@berry": yarnBerry, pnpm, // pnpm v6.x or below "pnpm@6": { ...pnpm, run: dashDashArg("pnpm", "run") }, bun, deno }; // ../../node_modules/package-manager-detector/dist/constants.mjs var AGENTS = [ "npm", "yarn", "yarn@berry", "pnpm", "pnpm@6", "bun", "deno" ], LOCKS = { "bun.lock": "bun", "bun.lockb": "bun", "deno.lock": "deno", "pnpm-lock.yaml": "pnpm", "pnpm-workspace.yaml": "pnpm", "yarn.lock": "yarn", "package-lock.json": "npm", "npm-shrinkwrap.json": "npm" }, INSTALL_METADATA = { "node_modules/.deno/": "deno", "node_modules/.pnpm/": "pnpm", "node_modules/.yarn-state.yml": "yarn", // yarn v2+ (node-modules) "node_modules/.yarn_integrity": "yarn", // yarn v1 "node_modules/.package-lock.json": "npm", ".pnp.cjs": "yarn", // yarn v3+ (pnp) ".pnp.js": "yarn", // yarn v2 (pnp) "bun.lock": "bun", "bun.lockb": "bun" }; // ../../node_modules/package-manager-detector/dist/detect.mjs import fs from "node:fs/promises"; import path2 from "node:path"; import process2 from "node:process"; async function pathExists(path22, type) { try { let stat = await fs.stat(path22); return type === "file" ? stat.isFile() : stat.isDirectory(); } catch { return !1; } } function* lookup(cwd = process2.cwd()) { let directory = path2.resolve(cwd), { root } = path2.parse(directory); for (; directory && directory !== root; ) yield directory, directory = path2.dirname(directory); } async function parsePackageJson(filepath, onUnknown) { return !filepath || !pathExists(filepath, "file") ? null : await handlePackageManager(filepath, onUnknown); } async function detect(options = {}) { let { cwd, strategies = ["lockfile", "packageManager-field", "devEngines-field"], onUnknown } = options, stopDir; if (typeof options.stopDir == "string") { let resolved = path2.resolve(options.stopDir); stopDir = (dir) => dir === resolved; } else stopDir = options.stopDir; for (let directory of lookup(cwd)) { for (let strategy of strategies) switch (strategy) { case "lockfile": { for (let lock of Object.keys(LOCKS)) if (await pathExists(path2.join(directory, lock), "file")) { let name = LOCKS[lock], result = await parsePackageJson(path2.join(directory, "package.json"), onUnknown); return result || { name, agent: name }; } break; } case "packageManager-field": case "devEngines-field": { let result = await parsePackageJson(path2.join(directory, "package.json"), onUnknown); if (result) return result; break; } case "install-metadata": { for (let metadata of Object.keys(INSTALL_METADATA)) { let fileOrDir = metadata.endsWith("/") ? "dir" : "file"; if (await pathExists(path2.join(directory, metadata), fileOrDir)) { let name = INSTALL_METADATA[metadata], agent = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name; return { name, agent }; } } break; } } if (stopDir?.(directory)) break; } return null; } function getNameAndVer(pkg) { let handelVer = (version2) => version2?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version2; if (typeof pkg.packageManager == "string") { let [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@"); return { name, ver: handelVer(ver) }; } if (typeof pkg.devEngines?.packageManager?.name == "string") return { name: pkg.devEngines.packageManager.name, ver: handelVer(pkg.devEngines.packageManager.version) }; } async function handlePackageManager(filepath, onUnknown) { try { let pkg = JSON.parse(await fs.readFile(filepath, "utf8")), agent, nameAndVer = getNameAndVer(pkg); if (nameAndVer) { let name = nameAndVer.name, ver = nameAndVer.ver, version2 = ver; return name === "yarn" && ver && Number.parseInt(ver) > 1 ? (agent = "yarn@berry", version2 = "berry", { name, agent, version: version2 }) : name === "pnpm" && ver && Number.parseInt(ver) < 7 ? (agent = "pnpm@6", { name, agent, version: version2 }) : AGENTS.includes(name) ? (agent = name, { name, agent, version: version2 }) : onUnknown?.(pkg.packageManager) ?? null; } } catch { } return null; } function isMetadataYarnClassic(metadataPath) { return metadataPath.endsWith(".yarn_integrity"); } // src/telemetry/get-package-manager-info.ts var getPackageManagerInfo = async () => { let packageManagerType = await detect({ cwd: getProjectRoot() }); if (!packageManagerType) return; let nodeLinker = "node_modules"; if (packageManagerType.name === "yarn") try { let { stdout } = await execaCommand("yarn config get nodeLinker", { cwd: getProjectRoot() }); nodeLinker = stdout.trim(); } catch { } if (packageManagerType.name === "pnpm") try { let { stdout } = await execaCommand("pnpm config get nodeLinker", { cwd: getProjectRoot() }); nodeLinker = stdout.trim() ?? "isolated"; } catch { } return { type: packageManagerType.name, version: packageManagerType.version, agent: packageManagerType.agent, nodeLinker }; }; // src/telemetry/get-portable-stories-usage.ts var getPortableStoriesFileCountUncached = async (path3) => { try { return await execCommandCountLines("git", [ "grep", "-l", "composeStor", ...path3 ? ["--", path3] : [] ]); } catch (err) { return err.exitCode === 1 ? 0 : void 0; } }, getPortableStoriesFileCount = async (path3) => runTelemetryOperation( "portableStories", async () => getPortableStoriesFileCountUncached(path3) ); // src/telemetry/storybook-metadata.ts var metaFrameworks = { next: "Next", "react-scripts": "CRA", gatsby: "Gatsby", "@nuxtjs/storybook": "nuxt", "@nrwl/storybook": "nx", "@vue/cli-service": "vue-cli", "@sveltejs/kit": "sveltekit", "@tanstack/react-router": "tanstack-react", "@react-router/dev": "react-router", "@remix-run/dev": "remix", expo: "expo", "vike-react": "vike-react", "vike-vue": "vike-vue", "vike-solid": "vike-solid" }, sanitizeAddonName = (name) => { let normalized = name.replace(/\\/g, "/"), candidate = normalized; normalized.includes("/node_modules/") && (candidate = normalized.split("/node_modules/").pop() ?? normalized); let cleaned = cleanPaths(candidate).replace(/^file:\/\//i, "").replace(/\/+$/, "").replace(/\/dist\/.*/, "").replace(/\.[mc]?[tj]?s[x]?$/, "").replace(/\/(register|manager|preset|index)$/, "").replace(/\$SNIP?/g, ""), prefix = ""; (cleaned.startsWith("file") || cleaned.startsWith(".") || cleaned.startsWith("/") || cleaned.includes(":")) && (prefix = "CUSTOM:"); let scopedMatches = cleaned.match(/@[^/]+\/[^/]+/g); if (scopedMatches?.length) return scopedMatches.at(-1); let parts = cleaned.split("/").filter(Boolean), addonLike = [...parts].reverse().find((part) => part.includes("addon-") || part.includes("-addon")); return addonLike ? `${prefix}${addonLike}` : parts.length >= 2 && parts[parts.length - 2].startsWith("@") ? `${prefix}${parts[parts.length - 2]}/${parts[parts.length - 1]}` : parts.length ? `${prefix}${parts[parts.length - 1]}` : `${prefix}${candidate}`; }, computeStorybookMetadata = async ({ packageJsonPath, packageJson, mainConfig, configDir }) => { let settings = isCI() ? void 0 : await globalSettings(), metadata = { generatedAt: (/* @__PURE__ */ new Date()).getTime(), userSince: settings?.value.userSince, hasCustomBabel: !1, hasCustomWebpack: !1, hasStaticDirs: !1, hasStorybookEslint: !1, refCount: 0 }, allDependencies = { ...packageJson?.dependencies, ...packageJson?.devDependencies, ...packageJson?.peerDependencies }, metaFramework = Object.keys(allDependencies).find((dep) => !!metaFrameworks[dep]); if (metaFramework) { let { version: version2 } = await getActualPackageVersion(metaFramework); metadata.metaFramework = { name: metaFrameworks[metaFramework], packageName: metaFramework, version: version2 || "unknown" }; } metadata.knownPackages = await analyzeEcosystemPackages(packageJson), metadata.hasRouterPackage = getHasRouterPackage(packageJson); let monorepoType = getMonorepoType(); monorepoType && (metadata.monorepo = monorepoType), metadata.packageManager = await getPackageManagerInfo(); let language = allDependencies.typescript ? "typescript" : "javascript"; if (!mainConfig) return { ...metadata, storybookVersionSpecifier: versions.storybook, language }; metadata.hasCustomBabel = !!mainConfig.babel, metadata.hasCustomWebpack = !!mainConfig.webpackFinal, metadata.hasStaticDirs = !!mainConfig.staticDirs, typeof mainConfig.typescript == "object" && (metadata.typescriptOptions = mainConfig.typescript); let frameworkInfo = await getFrameworkInfo(mainConfig, configDir); typeof mainConfig.refs == "object" && (metadata.refCount = Object.keys(mainConfig.refs).length), typeof mainConfig.features == "object" && (metadata.features = mainConfig.features); let addons = {}; mainConfig.addons && mainConfig.addons.forEach((addon) => { let addonName, options; typeof addon == "string" ? addonName = sanitizeAddonName(addon) : (addon.name.includes("addon-essentials") && (options = addon.options), addonName = sanitizeAddonName(addon.name)), addons[addonName] = { options, version: void 0 }; }); let chromaticVersionSpecifier = getChromaticVersionSpecifier(packageJson); chromaticVersionSpecifier && (addons.chromatic = { version: void 0, versionSpecifier: chromaticVersionSpecifier, options: void 0 }), (await getActualPackageVersions(addons)).forEach(({ name, version: version2 }) => { addons[name] = addons[name] || { name, version: version2 }, addons[name].version = version2 || void 0; }); let addonNames = Object.keys(addons), storybookPackages = Object.keys(allDependencies).filter((dep) => dep.includes("storybook") && !addonNames.includes(dep)).reduce((acc, dep) => ({ ...acc, [dep]: { version: void 0 } }), {}); (await getActualPackageVersions(storybookPackages)).forEach(({ name, version: version2 }) => { storybookPackages[name] = storybookPackages[name] || { name, version: version2 }, storybookPackages[name].version = version2 || void 0; }); let hasStorybookEslint = !!allDependencies["eslint-plugin-storybook"], storybookInfo = await getStorybookInfo2(configDir); try { let { previewConfigPath: previewConfig } = storybookInfo; if (previewConfig) { let config = await readConfig(previewConfig), usesGlobals = !!(config.getFieldNode(["globals"]) || config.getFieldNode(["globalTypes"])); metadata.preview = { ...metadata.preview, usesGlobals }; } } catch { } let portableStoriesFileCount = await getPortableStoriesFileCount(), applicationFileCount = await getApplicationFileCount(dirname(packageJsonPath)); return { ...metadata, ...frameworkInfo, portableStoriesFileCount, applicationFileCount, storybookVersion: version, storybookVersionSpecifier: storybookInfo.versionSpecifier ?? "", language, storybookPackages, addons, hasStorybookEslint, packageJsonType: packageJson.type ?? "unknown" }; }; async function getPackageJsonDetails() { let packageJsonPath = up(); return packageJsonPath ? { packageJsonPath, packageJson: JSON.parse(await readFile(packageJsonPath, "utf8")) } : { packageJsonPath: process.cwd(), packageJson: {} }; } var metadataCache = /* @__PURE__ */ new Map(); async function hashMainConfig(configDir) { try { let mainPath = getInterpretedFile(resolve(configDir, "main")); if (!mainPath || !existsSync2(mainPath)) return "missing"; let content = await readFile(mainPath); return createHash("sha256").update(new Uint8Array(content)).digest("hex"); } catch { return "unknown"; } } var getStorybookMetadata = async (_configDir) => { let { packageJson, packageJsonPath } = await getPackageJsonDetails(), configDir = (_configDir || getStorybookConfiguration( String(packageJson?.scripts?.storybook || ""), "-c", "--config-dir" )) ?? ".storybook", contentHash = await hashMainConfig(configDir), cacheKey = `${configDir}::${contentHash}`, cached = metadataCache.get(cacheKey); if (cached) return cached; let mainConfig = await loadMainConfig({ configDir }).catch(() => { }), computed = await computeStorybookMetadata({ mainConfig, packageJson, packageJsonPath, configDir }); return metadataCache.set(cacheKey, computed), computed; }; // src/telemetry/telemetry.ts var import_fetch_retry = __toESM(require_fetch_retry(), 1); import { readFileSync as readFileSync2 } from "node:fs"; import * as os2 from "node:os"; import { join as join2 } from "node:path"; import { isCI as isCI2 } from "storybook/internal/common"; // ../../node_modules/nanoid/index.js import { randomFillSync } from "crypto"; // ../../node_modules/nanoid/url-alphabet/index.js var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict"; // ../../node_modules/nanoid/index.js var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset, fillPool = (bytes) => { !pool || pool.length < bytes ? (pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER), randomFillSync(pool), poolOffset = 0) : poolOffset + bytes > pool.length && (randomFillSync(pool), poolOffset = 0), poolOffset += bytes; }; var nanoid = (size = 21) => { fillPool(size -= 0); let id = ""; for (let i2 = poolOffset - size; i2 < poolOffset; i2++) id += urlAlphabet[pool[i2] & 63]; return id; }; // src/telemetry/anonymous-id.ts import { relative } from "node:path"; import { executeCommandSync, getProjectRoot as getProjectRoot3 } from "storybook/internal/common"; // src/telemetry/one-way-hash.ts import { createHash as createHash2 } from "crypto"; var oneWayHash = (payload) => { let hash = createHash2("sha256"); return hash.update("storybook-telemetry-salt"), hash.update(payload), hash.digest("hex"); }; // src/telemetry/anonymous-id.ts function normalizeGitUrl(rawUrl) { let urlWithoutScheme = rawUrl.trim().replace(/#.*$/, "").replace(/^.*@/, "").replace(/^.*\/\//, ""); return (urlWithoutScheme.endsWith(".git") ? urlWithoutScheme : `${urlWithoutScheme}.git`).replace(":", "/"); } function unhashedProjectId(remoteUrl, projectRootPath) { return `${normalizeGitUrl(remoteUrl)}${slash(projectRootPath)}`; } var anonymousProjectId, getProjectSinceResult, getAnonymousProjectId = () => { if (anonymousProjectId) return anonymousProjectId; try { let projectRootPath = relative(getProjectRoot3(), process.cwd()), result = executeCommandSync({ command: "git", args: ["config", "--get", "remote.origin.url"], timeout: 1e3 }); anonymousProjectId = oneWayHash(unhashedProjectId(result, projectRootPath)); } catch { } return anonymousProjectId; }, getProjectSince = () => { try { if (getProjectSinceResult) return getProjectSinceResult; let dateBuffer = executeCommandSync({ command: "git", args: ["log", "--reverse", "--format=%cd", "--date=iso"], timeout: 1e3 }), firstLine = String(dateBuffer).trim().split(` `)[0], date = new Date(firstLine); return Number.isNaN(date.getTime()) ? void 0 : (getProjectSinceResult = date, date); } catch { } }; // ../../node_modules/std-env/dist/index.mjs var e = globalThis.process?.env || /* @__PURE__ */ Object.create(null), t = globalThis.process || { env: e }, n = t !== void 0 && t.env && t.env.NODE_ENV || void 0, r = [["claude", ["CLAUDECODE", "CLAUDE_CODE"]], ["replit", ["REPL_ID"]], ["gemini", ["GEMINI_CLI"]], ["codex", ["CODEX_SANDBOX", "CODEX_THREAD_ID"]], ["opencode", ["OPENCODE"]], ["pi", [i("PATH", /\.pi[\\/]agent/)]], ["auggie", ["AUGMENT_AGENT"]], ["goose", ["GOOSE_PROVIDER"]], ["devin", [i("EDITOR", /devin/)]], ["cursor", ["CURSOR_AGENT"]], ["kiro", [i("TERM_PROGRAM", /kiro/)]]]; function i(t2, n2) { return () => { let r2 = e[t2]; return r2 ? n2.test(r2) : !1; }; } function a() { let t2 = e.AI_AGENT; if (t2) return { name: t2.toLowerCase() }; for (let [t3, n2] of r) for (let r2 of n2) if (typeof r2 == "string" ? e[r2] : r2()) return { name: t3 }; return {}; } var o = a(), s = o.name, c = !!o.name, l = [["APPVEYOR"], ["AWS_AMPLIFY", "AWS_APP_ID", { ci: !0 }], ["AZURE_PIPELINES", "SYSTEM_TEAMFOUNDATIONCOLLECTIONURI"], ["AZURE_STATIC", "INPUT_AZURE_STATIC_WEB_APPS_API_TOKEN"], ["APPCIRCLE", "AC_APPCIRCLE"], ["BAMBOO", "bamboo_planKey"], ["BITBUCKET", "BITBUCKET_COMMIT"], ["BITRISE", "BITRISE_IO"], ["BUDDY", "BUDDY_WORKSPACE_ID"], ["BUILDKITE"], ["CIRCLE", "CIRCLECI"], ["CIRRUS", "CIRRUS_CI"], ["CLOUDFLARE_PAGES", "CF_PAGES", { ci: !0 }], ["CLOUDFLARE_WORKERS", "WORKERS_CI", { ci: !0 }], ["GOOGLE_CLOUDRUN", "K_SERVICE"], ["GOOGLE_CLOUDRUN_JOB", "CLOUD_RUN_JOB"], ["CODEBUILD", "CODEBUILD_BUILD_ARN"], ["CODEFRESH", "CF_BUILD_ID"], ["DRONE"], ["DRONE", "DRONE_BUILD_EVENT"], ["DSARI"], ["GITHUB_ACTIONS"], ["GITLAB", "GITLAB_CI"], ["GITLAB", "CI_MERGE_REQUEST_ID"], ["GOCD", "GO_PIPELINE_LABEL"], ["LAYERCI"], ["JENKINS", "JENKINS_URL"], ["HUDSON", "HUDSON_URL"], ["MAGNUM"], ["NETLIFY"], ["NETLIFY", "NETLIFY_LOCAL", { ci: !1 }], ["NEVERCODE"], ["RENDER"], ["SAIL", "SAILCI"], ["SEMAPHORE"], ["SCREWDRIVER"], ["SHIPPABLE"], ["SOLANO", "TDDIUM"], ["STRIDER"], ["TEAMCITY", "TEAMCITY_VERSION"], ["TRAVIS"], ["VERCEL", "NOW_BUILDER"], ["VERCEL", "VERCEL", { ci: !1 }], ["VERCEL", "VERCEL_ENV", { ci: !1 }], ["APPCENTER", "APPCENTER_BUILD_ID"], ["CODESANDBOX", "CODESANDBOX_SSE", { ci: !1 }], ["CODESANDBOX", "CODESANDBOX_HOST", { ci: !1 }], ["STACKBLITZ"], ["STORMKIT"], ["CLEAVR"], ["ZEABUR"], ["CODESPHERE", "CODESPHERE_APP_ID", { ci: !0 }], ["RAILWAY", "RAILWAY_PROJECT_ID"], ["RAILWAY", "RAILWAY_SERVICE_ID"], ["DENO-DEPLOY", "DENO_DEPLOY"], ["DENO-DEPLOY", "DENO_DEPLOYMENT_ID"], ["FIREBASE_APP_HOSTING", "FIREBASE_APP_HOSTING", { ci: !0 }]]; function u() { for (let t2 of l) if (e[t2[1] || t2[0]]) return { name: t2[0].toLowerCase(), ...t2[2] }; return e.SHELL === "/bin/jsh" && t.versions?.webcontainer ? { name: "stackblitz", ci: !1 } : { name: "", ci: !1 }; } var d = u(), f = d.name, p = t.platform || "", m = !!e.CI || d.ci !== !1, h = !!t.stdout?.isTTY; var _ = !!e.DEBUG, v = n === "test" || !!e.TEST, y = n === "production" || e.MODE === "production", b = n === "dev" || n === "development" || e.MODE === "development", x = !!e.MINIMAL || m || v || !h, S = /^win/i.test(p), C = /^linux/i.test(p), w = /^darwin/i.test(p), T = !e.NO_COLOR && (!!e.FORCE_COLOR || (h || S) && e.TERM !== "dumb" || m), E = (t.versions?.node || "").replace(/^v/, "") || null, D = Number(E?.split(".")[0]) || null, O = !!t?.versions?.node, k = "Bun" in globalThis, A = "Deno" in globalThis, j = "fastly" in globalThis, M = "Netlify" in globalThis, N = "EdgeRuntime" in globalThis, P = globalThis.navigator?.userAgent === "Cloudflare-Workers", F = [[M, "netlify"], [N, "edge-light"], [P, "workerd"], [j, "fastly"], [A, "deno"], [k, "bun"], [O, "node"]]; function I() { let e2 = F.find((e3) => e3[0]); if (e2) return { name: e2[1] }; } var L = I(), R = L?.name || ""; // src/telemetry/detect-agent.ts var detectAgent = () => { let { name } = a(); if (name) return { name }; }; // src/telemetry/event-cache.ts import { cache as cache3 } from "storybook/internal/common"; var processingPromise = Promise.resolve(), setHelper = async (eventType, body) => { let lastEvents = await cache3.get("lastEvents") || {}; lastEvents[eventType] = { body, timestamp: Date.now() }, await cache3.set("lastEvents", lastEvents); }, set = (eventType, body) => { let run = processingPromise.then(async () => { await setHelper(eventType, body); }); return processingPromise = run.catch(() => { }), run; }; var getLastEvents = async () => (await processingPromise, await cache3.get("lastEvents") || {}), upgradeFields = (event) => { let { body, timestamp } = event; return { timestamp, eventType: body?.eventType, eventId: body?.eventId, sessionId: body?.sessionId }; }, UPGRADE_EVENTS = ["init", "upgrade"], RUN_EVENTS = ["build", "dev", "error"], lastEvent = (lastEvents, eventTypes) => { let descendingEvents = eventTypes.map((eventType) => lastEvents?.[eventType]).filter((event) => !!event).sort((a2, b2) => b2.timestamp - a2.timestamp); return descendingEvents.length > 0 ? descendingEvents[0] : void 0; }, getPrecedingUpgrade = async (events = void 0) => { let lastEvents = events || await cache3.get("lastEvents") || {}, lastUpgradeEvent = lastEvent(lastEvents, UPGRADE_EVENTS), lastRunEvent = lastEvent(lastEvents, RUN_EVENTS); if (lastUpgradeEvent) return !lastRunEvent?.timestamp || lastUpgradeEvent.timestamp > lastRunEvent.timestamp ? upgradeFields(lastUpgradeEvent) : void 0; }; // src/telemetry/fetch.ts var fetch = global.fetch; // src/telemetry/session-id.ts import { cache as cache4 } from "storybook/internal/common"; var SESSION_TIMEOUT = 1e3 * 60 * 60 * 2, sessionId; var getSessionId = async () => { let now = Date.now(); if (!sessionId) { let session = await cache4.get("session"); session && session.lastUsed >= now - SESSION_TIMEOUT ? sessionId = session.id : sessionId = nanoid(); } return await cache4.set("session", { id: sessionId, lastUsed: now }), sessionId; }; // src/telemetry/telemetry.ts var retryingFetch = (0, import_fetch_retry.default)(fetch), URL = process.env.STORYBOOK_TELEMETRY_URL || "https://storybook.js.org/event-log", tasks = [], addToGlobalContext = (key, value) => { globalContext[key] = value; }, getOperatingSystem = () => { try { let platform2 = os2.platform(); return platform2 === "win32" ? "Windows" : platform2 === "darwin" ? "macOS" : platform2 === "linux" ? "Linux" : `Other: ${platform2}`; } catch { return "Unknown"; } }, inCI = isCI2(), agentDetection = detectAgent(), globalContext = { inCI, isTTY: process.stdout.isTTY, agent: agentDetection, platform: getOperatingSystem(), nodeVersion: process.versions.node, storybookVersion: getVersionNumber() }, prepareRequest = async (data, context, options) => { let { eventType, payload, metadata, ...rest } = data, sessionId2 = await getSessionId(), eventId = nanoid(), body = { ...rest, eventType, eventId, sessionId: sessionId2, metadata, payload, context }; return retryingFetch(URL, { method: "post", body: JSON.stringify(body), headers: { "Content-Type": "application/json" }, retries: 3, retryOn: [503, 504], retryDelay: (attempt) => 2 ** attempt * (typeof options?.retryDelay == "number" && !Number.isNaN(options?.retryDelay) ? options.retryDelay : 1e3) }); }; function getVersionNumber() { try { return JSON.parse(readFileSync2(join2(resolvePackageDir("storybook"), "package.json"), "utf8")).version; } catch { return version; } } async function sendTelemetry(data, options = { retryDelay: 1e3, immediate: !1 }) { let { eventType, payload, metadata, ...rest } = data, context = options.stripMetadata ? globalContext : { ...globalContext, anonymousId: getAnonymousProjectId(), projectSince: getProjectSince()?.getTime() }, request; try { request = prepareRequest(data, context, options), tasks.push(request); let sessionId2 = await getSessionId(), eventId = nanoid(), body = { ...rest, eventType, eventId, sessionId: sessionId2, metadata, payload, context }, waitFor = options.immediate ? tasks : [request]; await Promise.all([...waitFor, set(eventType, body)]); } catch { } finally { tasks = tasks.filter((task) => task !== request); } } // src/telemetry/error-collector.ts var ErrorCollector = class _ErrorCollector { constructor() { this.errors = []; } static getInstance() { return _ErrorCollector.instance || (_ErrorCollector.instance = new _ErrorCollector()), _ErrorCollector.instance; } static addError(error) { this.getInstance().errors.push(error); } static getErrors() { return this.getInstance().errors; } }; // src/telemetry/index.ts var isExampleStoryId = (storyId) => storyId.startsWith("example-button--") || storyId.startsWith("example-header--") || storyId.startsWith("example-page--"), telemetry = async (eventType, payload = {}, options = {}) => { eventType !== "boot" && options.notify !== !1 && await notify(); let telemetryData = { eventType, payload }; try { options?.stripMetadata || (telemetryData.metadata = await getStorybookMetadata(options?.configDir)); } catch (error) { payload.metadataErrorMessage = sanitizeError(error).message, options?.enableCrashReports && (payload.metadataError = sanitizeError(error)); } finally { let { error } = payload; error && (payload.error = sanitizeError(error)), (!payload.error || options?.enableCrashReports) && (process.env?.STORYBOOK_TELEMETRY_DEBUG && (logger2.info("[telemetry]"), logger2.info(JSON.stringify(telemetryData, null, 2))), await sendTelemetry(telemetryData, options)); } }; export { removeAnsiEscapeCodes, cleanPaths, sanitizeError, metaFrameworks, sanitizeAddonName, computeStorybookMetadata, getStorybookMetadata, oneWayHash, getLastEvents, getPrecedingUpgrade, getSessionId, addToGlobalContext, ErrorCollector, isExampleStoryId, telemetry };