storybook
Version:
Storybook: Develop, document, and test UI components in isolation
1,109 lines (1,068 loc) • 44.8 kB
JavaScript
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
};