import CJS_COMPAT_NODE_URL_jj04cksboja from 'node:url';
import CJS_COMPAT_NODE_PATH_jj04cksboja from 'node:path';
import CJS_COMPAT_NODE_MODULE_jj04cksboja from "node:module";

var __filename = CJS_COMPAT_NODE_URL_jj04cksboja.fileURLToPath(import.meta.url);
var __dirname = CJS_COMPAT_NODE_PATH_jj04cksboja.dirname(__filename);
var require = CJS_COMPAT_NODE_MODULE_jj04cksboja.createRequire(import.meta.url);

// ------------------------------------------------------------
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
// ------------------------------------------------------------
import {
  require_build
} from "./chunk-RLDWXV7X.js";
import {
  resolvePackageDir
} from "./chunk-3ML5DUTC.js";
import {
  require_prompts
} from "./chunk-MPER7OLU.js";
import {
  require_dist
} from "./chunk-TUFGO7A6.js";
import {
  require_picocolors
} from "./chunk-NSCUD2JQ.js";
import {
  __name,
  __toESM
} from "./chunk-T7Y6VNG2.js";

// src/core-server/utils/server-statics.ts
var import_picocolors = __toESM(require_picocolors(), 1);
var import_sirv = __toESM(require_build(), 1);
var import_ts_dedent = __toESM(require_dist(), 1);
import { existsSync, statSync } from "node:fs";
import { readFile, stat } from "node:fs/promises";
import { basename, isAbsolute, join, posix, resolve, sep, win32 } from "node:path";
import { getDirectoryFromWorkingDir, resolvePathInStorybookCache } from "storybook/internal/common";
import { logger, once } from "storybook/internal/node-logger";
var cacheDir = resolvePathInStorybookCache("", "ignored-sub").split("ignored-sub")[0];
var files = /* @__PURE__ */ new Map();
var readFileOnce = /* @__PURE__ */ __name(async (path) => {
  if (files.has(path)) {
    return files.get(path);
  } else {
    const [data, stats] = await Promise.all([readFile(path, "utf-8"), stat(path)]);
    const result = { data, mtime: stats.mtimeMs };
    files.set(path, result);
    return result;
  }
}, "readFileOnce");
var faviconWrapperPath = join(
  resolvePackageDir("storybook"),
  "/assets/browser/favicon-wrapper.svg"
);
var prepareNestedSvg = /* @__PURE__ */ __name((svg) => {
  const [, openingTag, contents, closingTag] = svg?.match(/(<svg[^>]*>)(.*?)(<\/svg>)/s) ?? [];
  if (!openingTag || !contents || !closingTag) {
    return svg;
  }
  let width;
  let height;
  let modifiedTag = openingTag.replace(/width=["']([^"']*)["']/g, (_, value) => {
    width = parseFloat(value);
    return 'width="32px"';
  }).replace(/height=["']([^"']*)["']/g, (_, value) => {
    height = parseFloat(value);
    return 'height="32px"';
  });
  const hasViewBox = /viewBox=["'][^"']*["']/.test(modifiedTag);
  if (!hasViewBox && width && height) {
    modifiedTag = modifiedTag.replace(/>$/, ` viewBox="0 0 ${width} ${height}">`);
  }
  modifiedTag = modifiedTag.replace(/preserveAspectRatio=["'][^"']*["']/g, "").replace(/>$/, ' preserveAspectRatio="xMidYMid meet">');
  return modifiedTag + contents + closingTag;
}, "prepareNestedSvg");
async function useStatics(app, options) {
  const staticDirs = await options.presets.apply("staticDirs") ?? [];
  const faviconPath = await options.presets.apply("favicon");
  const faviconDir = resolve(faviconPath, "..");
  const faviconFile = basename(faviconPath);
  app.use(`/${faviconFile}`, async (req, res, next) => {
    const status = req.query.status;
    if (status && faviconFile.endsWith(".svg") && ["active", "critical", "negative", "positive", "warning"].includes(status)) {
      const [faviconInfo, faviconWrapperInfo] = await Promise.all([
        readFileOnce(join(faviconDir, faviconFile)),
        readFileOnce(faviconWrapperPath)
      ]).catch((e) => {
        if (e instanceof Error) {
          once.warn(`Failed to read favicon: ${e.message}`);
        }
        return [null, null];
      });
      if (faviconInfo && faviconWrapperInfo) {
        const svg = faviconWrapperInfo.data.replace('<g id="mask"', `<g mask="url(#${status}-mask)"`).replace('<use id="status"', `<use href="#${status}"`).replace('<use id="icon" />', prepareNestedSvg(faviconInfo.data));
        res.setHeader("Content-Type", "image/svg+xml");
        res.setHeader("ETag", `"${faviconWrapperInfo.mtime}-${faviconInfo.mtime}"`);
        res.end(svg);
        return;
      }
    }
    req.url = `/${faviconFile}`;
    return sirvWorkaround(faviconDir)(req, res, next);
  });
  staticDirs.map((dir) => {
    try {
      const { staticDir, staticPath, targetEndpoint } = mapStaticDir(dir, options.configDir);
      if (!targetEndpoint.startsWith("/sb-") && !staticDir.startsWith(cacheDir)) {
        logger.info(
          `=> Serving static files from ${import_picocolors.default.cyan(staticDir)} at ${import_picocolors.default.cyan(targetEndpoint)}`
        );
      }
      if (existsSync(staticPath) && statSync(staticPath).isFile()) {
        const staticPathDir = resolve(staticPath, "..");
        const staticPathFile = basename(staticPath);
        app.use(targetEndpoint, (req, res, next) => {
          req.url = `/${staticPathFile}`;
          sirvWorkaround(staticPathDir)(req, res, next);
        });
      } else {
        app.use(targetEndpoint, sirvWorkaround(staticPath));
      }
    } catch (e) {
      if (e instanceof Error) {
        logger.warn(e.message);
      }
    }
  });
}
__name(useStatics, "useStatics");
var sirvWorkaround = /* @__PURE__ */ __name((dir, opts = {}) => (req, res, next) => {
  const originalParsedUrl = req._parsedUrl;
  const maybeNext = next ? () => {
    req._parsedUrl = originalParsedUrl;
    next();
  } : void 0;
  (0, import_sirv.default)(dir, { dev: true, etag: true, extensions: [], ...opts })(req, res, maybeNext);
}, "sirvWorkaround");
var parseStaticDir = /* @__PURE__ */ __name((arg) => {
  const lastColonIndex = arg.lastIndexOf(":");
  const isWindowsAbsolute = win32.isAbsolute(arg);
  const isWindowsRawDirOnly = isWindowsAbsolute && lastColonIndex === 1;
  const splitIndex = lastColonIndex !== -1 && !isWindowsRawDirOnly ? lastColonIndex : arg.length;
  const [from, to] = [arg.slice(0, splitIndex), arg.slice(splitIndex + 1)];
  const staticDir = isAbsolute(from) ? from : `./${from}`;
  const staticPath = resolve(staticDir);
  if (!existsSync(staticPath)) {
    throw new Error(
      import_ts_dedent.dedent`
        Failed to load static files, no such directory: ${import_picocolors.default.cyan(staticPath)}
        Make sure this directory exists.
      `
    );
  }
  const targetRaw = to || (statSync(staticPath).isFile() ? basename(staticPath) : "/");
  const target = targetRaw.split(sep).join(posix.sep);
  const targetDir = target.replace(/^\/?/, "./");
  const targetEndpoint = targetDir.substring(1);
  return { staticDir, staticPath, targetDir, targetEndpoint };
}, "parseStaticDir");
var mapStaticDir = /* @__PURE__ */ __name((staticDir, configDir) => {
  const specifier = typeof staticDir === "string" ? staticDir : `${staticDir.from}:${staticDir.to}`;
  const normalizedDir = isAbsolute(specifier) ? specifier : getDirectoryFromWorkingDir({ configDir, workingDir: process.cwd(), directory: specifier });
  return parseStaticDir(normalizedDir);
}, "mapStaticDir");

// src/core-server/withTelemetry.ts
var import_prompts = __toESM(require_prompts(), 1);
import { HandledError, cache, isCI, loadAllPresets } from "storybook/internal/common";
import { logger as logger2 } from "storybook/internal/node-logger";
import { getPrecedingUpgrade, oneWayHash, telemetry } from "storybook/internal/telemetry";
var promptCrashReports = /* @__PURE__ */ __name(async () => {
  if (isCI() || !process.stdout.isTTY) {
    return void 0;
  }
  const { enableCrashReports } = await (0, import_prompts.default)({
    type: "confirm",
    name: "enableCrashReports",
    message: `Would you like to help improve Storybook by sending anonymous crash reports?`,
    initial: true
  });
  await cache.set("enableCrashReports", enableCrashReports);
  return enableCrashReports;
}, "promptCrashReports");
async function getErrorLevel({
  cliOptions,
  presetOptions,
  skipPrompt
}) {
  if (cliOptions.disableTelemetry) {
    return "none";
  }
  if (!presetOptions) {
    return "full";
  }
  const presets = await loadAllPresets(presetOptions);
  const core = await presets.apply("core");
  if (core?.enableCrashReports !== void 0) {
    return core.enableCrashReports ? "full" : "error";
  }
  if (core?.disableTelemetry) {
    return "none";
  }
  const valueFromCache = await cache.get("enableCrashReports") ?? await cache.get("enableCrashreports");
  if (valueFromCache !== void 0) {
    return valueFromCache ? "full" : "error";
  }
  if (skipPrompt) {
    return "error";
  }
  const valueFromPrompt = await promptCrashReports();
  if (valueFromPrompt !== void 0) {
    return valueFromPrompt ? "full" : "error";
  }
  return "full";
}
__name(getErrorLevel, "getErrorLevel");
async function sendTelemetryError(_error, eventType, options) {
  try {
    let errorLevel = "error";
    try {
      errorLevel = await getErrorLevel(options);
    } catch (err) {
    }
    if (errorLevel !== "none") {
      const precedingUpgrade = await getPrecedingUpgrade();
      const error = _error;
      let errorHash;
      if ("message" in error) {
        errorHash = error.message ? oneWayHash(error.message) : "EMPTY_MESSAGE";
      } else {
        errorHash = "NO_MESSAGE";
      }
      const { code, name, category } = error;
      await telemetry(
        "error",
        {
          code,
          name,
          category,
          eventType,
          precedingUpgrade,
          error: errorLevel === "full" ? error : void 0,
          errorHash,
          // if we ever end up sending a non-error instance, we'd like to know
          isErrorInstance: error instanceof Error
        },
        {
          immediate: true,
          configDir: options.cliOptions.configDir || options.presetOptions?.configDir,
          enableCrashReports: errorLevel === "full"
        }
      );
    }
  } catch (err) {
  }
}
__name(sendTelemetryError, "sendTelemetryError");
async function withTelemetry(eventType, options, run) {
  const enableTelemetry = !(options.cliOptions.disableTelemetry || options.cliOptions.test === true);
  let canceled = false;
  async function cancelTelemetry() {
    canceled = true;
    if (enableTelemetry) {
      await telemetry("canceled", { eventType }, { stripMetadata: true, immediate: true });
    }
    process.exit(0);
  }
  __name(cancelTelemetry, "cancelTelemetry");
  if (eventType === "init") {
    process.on("SIGINT", cancelTelemetry);
  }
  if (enableTelemetry) {
    telemetry("boot", { eventType }, { stripMetadata: true });
  }
  try {
    return await run();
  } catch (error) {
    if (canceled) {
      return void 0;
    }
    if (!(error instanceof HandledError)) {
      const { printError = logger2.error } = options;
      printError(error);
    }
    if (enableTelemetry) {
      await sendTelemetryError(error, eventType, options);
    }
    throw error;
  } finally {
    process.off("SIGINT", cancelTelemetry);
  }
}
__name(withTelemetry, "withTelemetry");

export {
  useStatics,
  parseStaticDir,
  mapStaticDir,
  getErrorLevel,
  sendTelemetryError,
  withTelemetry
};
