@onlook/storybook-plugin 0.4.0-beta.10 → 0.4.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module';
2
- import path6, { dirname, join, relative } from 'path';
2
+ import path7, { dirname, join, relative } from 'path';
3
3
  import crypto, { createHash } from 'crypto';
4
- import fs4, { existsSync } from 'fs';
4
+ import fs5, { existsSync } from 'fs';
5
5
  import { fileURLToPath } from 'url';
6
6
  import generateModule from '@babel/generator';
7
7
  import { parse } from '@babel/parser';
@@ -61,7 +61,7 @@ function envContainmentPlugin(options) {
61
61
  const resolveOutcomes = /* @__PURE__ */ new Map();
62
62
  const roots = /* @__PURE__ */ new Set([normalizeSlashes(process.cwd())]);
63
63
  const matchTarget = (absPath) => {
64
- const norm = normalizeSlashes(path6.normalize(absPath));
64
+ const norm = normalizeSlashes(path7.normalize(absPath));
65
65
  for (const rel of byModule.keys()) {
66
66
  for (const root of roots) {
67
67
  const target = `${root}/${rel}`;
@@ -96,10 +96,10 @@ function envContainmentPlugin(options) {
96
96
  if (source.startsWith("\0")) return null;
97
97
  const cleaned = stripQuery(source);
98
98
  let direct = null;
99
- if (path6.isAbsolute(cleaned)) {
99
+ if (path7.isAbsolute(cleaned)) {
100
100
  direct = cleaned;
101
101
  } else if (importer && (cleaned.startsWith("./") || cleaned.startsWith("../"))) {
102
- direct = path6.resolve(path6.dirname(stripQuery(importer)), cleaned);
102
+ direct = path7.resolve(path7.dirname(stripQuery(importer)), cleaned);
103
103
  }
104
104
  if (direct) {
105
105
  const rel = matchTarget(direct);
@@ -108,7 +108,7 @@ function envContainmentPlugin(options) {
108
108
  }
109
109
  if (!specifierMightMatch(cleaned)) return null;
110
110
  if (typeof this.resolve !== "function") return null;
111
- const importerDir = importer ? path6.dirname(stripQuery(importer)) : "";
111
+ const importerDir = importer ? path7.dirname(stripQuery(importer)) : "";
112
112
  const outcomeKey = `${importerDir}|${source}`;
113
113
  const memoized = resolveOutcomes.get(outcomeKey);
114
114
  if (memoized !== void 0) return memoized;
@@ -328,7 +328,7 @@ function componentLocPlugin(options = {}) {
328
328
  sourceFilename: filepath
329
329
  });
330
330
  let mutated = false;
331
- const relativePath = path6.relative(root, filepath);
331
+ const relativePath = path7.relative(root, filepath);
332
332
  traverse(ast, {
333
333
  JSXElement(nodePath) {
334
334
  const opening = nodePath.node.openingElement;
@@ -387,9 +387,9 @@ function fastRefreshTolerantExportsPlugin() {
387
387
  }
388
388
  };
389
389
  }
390
- var CACHE_DIR = path6.join(process.cwd(), ".storybook-cache");
391
- var SCREENSHOTS_DIR = path6.join(CACHE_DIR, "screenshots");
392
- var MANIFEST_PATH = path6.join(CACHE_DIR, "manifest.json");
390
+ var CACHE_DIR = path7.join(process.cwd(), ".storybook-cache");
391
+ var SCREENSHOTS_DIR = path7.join(CACHE_DIR, "screenshots");
392
+ var MANIFEST_PATH = path7.join(CACHE_DIR, "manifest.json");
393
393
  var VIEWPORT_WIDTH = 1920;
394
394
  var VIEWPORT_HEIGHT = 1080;
395
395
  var MIN_COMPONENT_WIDTH = 420;
@@ -397,30 +397,30 @@ var MIN_COMPONENT_HEIGHT = 280;
397
397
 
398
398
  // src/utils/fileSystem/fileSystem.ts
399
399
  function ensureCacheDirectories() {
400
- if (!fs4.existsSync(CACHE_DIR)) {
401
- fs4.mkdirSync(CACHE_DIR, { recursive: true });
400
+ if (!fs5.existsSync(CACHE_DIR)) {
401
+ fs5.mkdirSync(CACHE_DIR, { recursive: true });
402
402
  }
403
- if (!fs4.existsSync(SCREENSHOTS_DIR)) {
404
- fs4.mkdirSync(SCREENSHOTS_DIR, { recursive: true });
403
+ if (!fs5.existsSync(SCREENSHOTS_DIR)) {
404
+ fs5.mkdirSync(SCREENSHOTS_DIR, { recursive: true });
405
405
  }
406
406
  }
407
407
  function computeFileHash(filePath) {
408
- if (!fs4.existsSync(filePath)) {
408
+ if (!fs5.existsSync(filePath)) {
409
409
  return "";
410
410
  }
411
- const content = fs4.readFileSync(filePath, "utf-8");
411
+ const content = fs5.readFileSync(filePath, "utf-8");
412
412
  return crypto.createHash("sha256").update(content).digest("hex");
413
413
  }
414
414
  function loadManifest() {
415
- if (fs4.existsSync(MANIFEST_PATH)) {
416
- const content = fs4.readFileSync(MANIFEST_PATH, "utf-8");
415
+ if (fs5.existsSync(MANIFEST_PATH)) {
416
+ const content = fs5.readFileSync(MANIFEST_PATH, "utf-8");
417
417
  return JSON.parse(content);
418
418
  }
419
419
  return { stories: {} };
420
420
  }
421
421
  function saveManifest(manifest) {
422
422
  ensureCacheDirectories();
423
- fs4.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
423
+ fs5.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2));
424
424
  }
425
425
  function updateManifest(storyId, sourcePath, fileHash, boundingBox) {
426
426
  const manifest = loadManifest();
@@ -509,11 +509,76 @@ async function getBrowser() {
509
509
  }
510
510
  return browserPromise;
511
511
  }
512
+ function classifyPreviewSnapshot(s) {
513
+ if (s.text.includes("Sorry, something went wrong")) return "errored";
514
+ if (s.text.includes("Couldn't find story")) return "errored";
515
+ if (s.hasContainedCard) return "contained";
516
+ if (s.renderStateAttr === "contained") return "contained";
517
+ if (s.renderStateAttr === "rendered") return "rendered";
518
+ if (s.text.length > 0) return "rendered";
519
+ if (s.hasSizedElement) return "rendered";
520
+ return "pending";
521
+ }
522
+ async function detectRenderState(page, opts = {}) {
523
+ const pollMs = opts.pollMs ?? 250;
524
+ const settleMs = opts.settleMs ?? 4e3;
525
+ const blankStablePolls = opts.blankStablePolls ?? 6;
526
+ const hardCapMs = opts.hardCapMs ?? 2e4;
527
+ const now = opts.now ?? Date.now;
528
+ const start = now();
529
+ let emptyStreak = 0;
530
+ const snapshot = () => page.evaluate(
531
+ ({ stateAttr, cardAttr }) => {
532
+ const root = document.getElementById("storybook-root") ?? document.body;
533
+ const text = (root?.textContent ?? "").trim();
534
+ let hasSizedElement = false;
535
+ if (root) {
536
+ const all = root.querySelectorAll("*");
537
+ for (let i = 0; i < all.length; i++) {
538
+ const rect = all[i]?.getBoundingClientRect();
539
+ if (rect && rect.width > 0 && rect.height > 0) {
540
+ hasSizedElement = true;
541
+ break;
542
+ }
543
+ }
544
+ }
545
+ return {
546
+ text,
547
+ hasContainedCard: Boolean(root?.querySelector(`[${cardAttr}]`)),
548
+ renderStateAttr: root?.getAttribute(stateAttr) ?? null,
549
+ hasSizedElement
550
+ };
551
+ },
552
+ { stateAttr: ONLOOK_RENDER_STATE_ATTR, cardAttr: ONLOOK_CONTAINED_CARD_ATTR }
553
+ );
554
+ while (true) {
555
+ let state;
556
+ let threw = false;
557
+ try {
558
+ state = classifyPreviewSnapshot(await snapshot());
559
+ } catch {
560
+ state = "pending";
561
+ threw = true;
562
+ }
563
+ if (state === "rendered" || state === "contained" || state === "errored") {
564
+ return state;
565
+ }
566
+ const elapsed = now() - start;
567
+ if (threw) {
568
+ emptyStreak = 0;
569
+ } else if (elapsed >= settleMs) {
570
+ emptyStreak += 1;
571
+ if (emptyStreak >= blankStablePolls) return "blank";
572
+ }
573
+ if (elapsed >= hardCapMs) return "timedOut";
574
+ await page.waitForTimeout(pollMs);
575
+ }
576
+ }
512
577
  function getScreenshotPath(storyId, theme) {
513
- const storyDir = path6.join(SCREENSHOTS_DIR, storyId);
514
- return path6.join(storyDir, `${theme}.png`);
578
+ const storyDir = path7.join(SCREENSHOTS_DIR, storyId);
579
+ return path7.join(storyDir, `${theme}.png`);
515
580
  }
516
- async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, height = VIEWPORT_HEIGHT, storybookUrl = "http://localhost:6006", timeoutMs = 3e4) {
581
+ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, height = VIEWPORT_HEIGHT, storybookUrl = "http://localhost:6006", loadTimeoutMs = 9e4, renderTimeoutMs = 2e4) {
517
582
  const browser = await getBrowser();
518
583
  const context = await browser.newContext({
519
584
  viewport: { width, height },
@@ -522,13 +587,14 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
522
587
  const page = await context.newPage();
523
588
  try {
524
589
  const url = `${storybookUrl}/iframe.html?id=${storyId}&viewMode=story&globals=theme:${theme}`;
525
- await page.goto(url, { timeout: timeoutMs });
526
- await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
527
- await page.waitForLoadState("load", { timeout: timeoutMs });
590
+ await page.goto(url, { timeout: loadTimeoutMs });
591
+ await page.waitForLoadState("domcontentloaded", { timeout: loadTimeoutMs });
592
+ await page.waitForLoadState("load", { timeout: loadTimeoutMs });
528
593
  try {
529
594
  await page.waitForLoadState("networkidle", { timeout: 5e3 });
530
595
  } catch {
531
596
  }
597
+ const renderState = await detectRenderState(page, { hardCapMs: renderTimeoutMs });
532
598
  await page.evaluate(() => document.fonts.ready);
533
599
  try {
534
600
  await page.evaluate(async () => {
@@ -590,7 +656,7 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
590
656
  } else {
591
657
  screenshotBuffer = await page.screenshot({ type: "png" });
592
658
  }
593
- return { buffer: screenshotBuffer, boundingBox: resultBoundingBox };
659
+ return { buffer: screenshotBuffer, boundingBox: resultBoundingBox, renderState };
594
660
  } finally {
595
661
  await context.close();
596
662
  }
@@ -598,9 +664,9 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
598
664
  async function generateScreenshot(storyId, theme, storybookUrl = "http://localhost:6006", timeoutMs = 3e4) {
599
665
  try {
600
666
  ensureCacheDirectories();
601
- const storyDir = path6.join(SCREENSHOTS_DIR, storyId);
602
- if (!fs4.existsSync(storyDir)) {
603
- fs4.mkdirSync(storyDir, { recursive: true });
667
+ const storyDir = path7.join(SCREENSHOTS_DIR, storyId);
668
+ if (!fs5.existsSync(storyDir)) {
669
+ fs5.mkdirSync(storyDir, { recursive: true });
604
670
  }
605
671
  const screenshotPath = getScreenshotPath(storyId, theme);
606
672
  const { buffer, boundingBox } = await captureScreenshotBuffer(
@@ -611,7 +677,7 @@ async function generateScreenshot(storyId, theme, storybookUrl = "http://localho
611
677
  storybookUrl,
612
678
  timeoutMs
613
679
  );
614
- fs4.writeFileSync(screenshotPath, buffer);
680
+ fs5.writeFileSync(screenshotPath, buffer);
615
681
  return { path: screenshotPath, boundingBox };
616
682
  } catch (error) {
617
683
  console.error(`Error generating screenshot for ${storyId} (${theme}):`, error);
@@ -719,7 +785,7 @@ async function fetchStorybookIndex() {
719
785
  }
720
786
  function getStoriesForFile(filePath) {
721
787
  if (!cachedIndex) return [];
722
- const fileName = path6.basename(filePath);
788
+ const fileName = path7.basename(filePath);
723
789
  return Object.values(cachedIndex.entries).filter((entry) => entry.type === "story" && entry.importPath.endsWith(fileName)).map((entry) => entry.id);
724
790
  }
725
791
  async function regenerateScreenshotsForFiles(files) {
@@ -795,6 +861,7 @@ async function captureConsoleLogs(storyId, theme = "light", storybookUrl = "http
795
861
  const page = await context.newPage();
796
862
  const logs = [];
797
863
  const pageErrors = [];
864
+ const failedRequests = [];
798
865
  page.on("console", (msg) => {
799
866
  const level = msg.type();
800
867
  logs.push({
@@ -806,6 +873,28 @@ async function captureConsoleLogs(storyId, theme = "light", storybookUrl = "http
806
873
  page.on("pageerror", (err) => {
807
874
  pageErrors.push(err.message);
808
875
  });
876
+ page.on("response", (res) => {
877
+ const status = res.status();
878
+ if (status >= 400) {
879
+ const req = res.request();
880
+ failedRequests.push({
881
+ url: res.url(),
882
+ status,
883
+ method: req.method(),
884
+ resourceType: req.resourceType(),
885
+ failure: null
886
+ });
887
+ }
888
+ });
889
+ page.on("requestfailed", (req) => {
890
+ failedRequests.push({
891
+ url: req.url(),
892
+ status: null,
893
+ method: req.method(),
894
+ resourceType: req.resourceType(),
895
+ failure: req.failure()?.errorText ?? "request failed"
896
+ });
897
+ });
809
898
  const url = `${storybookUrl}/iframe.html?id=${storyId}&viewMode=story&globals=theme:${theme}`;
810
899
  try {
811
900
  await page.goto(url, { timeout: timeoutMs });
@@ -816,7 +905,7 @@ async function captureConsoleLogs(storyId, theme = "light", storybookUrl = "http
816
905
  } catch {
817
906
  }
818
907
  await new Promise((r) => setTimeout(r, 1e3));
819
- return { logs, pageErrors, url };
908
+ return { logs, pageErrors, failedRequests, url };
820
909
  } finally {
821
910
  await context.close();
822
911
  }
@@ -891,13 +980,115 @@ function softStoryRerenderPlugin() {
891
980
  preview.onStoriesChanged({ importFn: newModule.importFn });
892
981
  }
893
982
  });`;
894
- const out = code.replace(pattern, (_match, quote, path7) => {
895
- return replacement.replace("$QUOTE$$PATH$$QUOTE$", `${quote}${path7}${quote}`);
983
+ const out = code.replace(pattern, (_match, quote, path8) => {
984
+ return replacement.replace("$QUOTE$$PATH$$QUOTE$", `${quote}${path8}${quote}`);
896
985
  });
897
986
  return out === code ? null : { code: out, map: null };
898
987
  }
899
988
  };
900
989
  }
990
+ var TSCONFIG_CANDIDATES = ["tsconfig.json", "tsconfig.app.json", "tsconfig.base.json"];
991
+ function resolveTsconfigAliases(root) {
992
+ try {
993
+ const config = readTsconfigAliasConfig(root);
994
+ if (!config) return [];
995
+ const base = path7.resolve(root, config.baseUrl ?? ".");
996
+ const aliases = [];
997
+ for (const [key, targets] of Object.entries(config.paths)) {
998
+ const target = targets[0];
999
+ if (!target) continue;
1000
+ if (key.endsWith("/*") && target.endsWith("/*")) {
1001
+ const findPrefix = key.slice(0, -1);
1002
+ const targetDir = path7.resolve(base, target.slice(0, -2));
1003
+ aliases.push({
1004
+ find: new RegExp(`^${escapeRegExp(findPrefix)}`),
1005
+ replacement: `${targetDir}/`
1006
+ });
1007
+ } else if (!key.includes("*") && !target.includes("*")) {
1008
+ aliases.push({
1009
+ find: new RegExp(`^${escapeRegExp(key)}$`),
1010
+ replacement: path7.resolve(base, target)
1011
+ });
1012
+ }
1013
+ }
1014
+ return aliases.sort((a, b) => b.find.source.length - a.find.source.length);
1015
+ } catch {
1016
+ return [];
1017
+ }
1018
+ }
1019
+ function readTsconfigAliasConfig(root) {
1020
+ for (const candidate of TSCONFIG_CANDIDATES) {
1021
+ const abs = path7.join(root, candidate);
1022
+ let text;
1023
+ try {
1024
+ text = fs5.readFileSync(abs, "utf-8");
1025
+ } catch {
1026
+ continue;
1027
+ }
1028
+ let parsed;
1029
+ try {
1030
+ parsed = JSON.parse(stripJsonComments(text));
1031
+ } catch {
1032
+ continue;
1033
+ }
1034
+ const paths = parsed.compilerOptions?.paths;
1035
+ if (paths && typeof paths === "object" && Object.keys(paths).length > 0) {
1036
+ const baseUrl = parsed.compilerOptions?.baseUrl;
1037
+ return typeof baseUrl === "string" ? { baseUrl, paths } : { paths };
1038
+ }
1039
+ }
1040
+ return null;
1041
+ }
1042
+ function escapeRegExp(value) {
1043
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1044
+ }
1045
+ function stripJsonComments(text) {
1046
+ let out = "";
1047
+ let inString = false;
1048
+ let inLine = false;
1049
+ let inBlock = false;
1050
+ for (let i = 0; i < text.length; i++) {
1051
+ const c = text.charAt(i);
1052
+ const next = text.charAt(i + 1);
1053
+ if (inLine) {
1054
+ if (c === "\n") {
1055
+ inLine = false;
1056
+ out += c;
1057
+ }
1058
+ continue;
1059
+ }
1060
+ if (inBlock) {
1061
+ if (c === "*" && next === "/") {
1062
+ inBlock = false;
1063
+ i++;
1064
+ }
1065
+ continue;
1066
+ }
1067
+ if (inString) {
1068
+ out += c;
1069
+ if (c === "\\") {
1070
+ out += next;
1071
+ i++;
1072
+ } else if (c === '"') {
1073
+ inString = false;
1074
+ }
1075
+ continue;
1076
+ }
1077
+ if (c === '"') {
1078
+ inString = true;
1079
+ out += c;
1080
+ } else if (c === "/" && next === "/") {
1081
+ inLine = true;
1082
+ i++;
1083
+ } else if (c === "/" && next === "*") {
1084
+ inBlock = true;
1085
+ i++;
1086
+ } else {
1087
+ out += c;
1088
+ }
1089
+ }
1090
+ return out;
1091
+ }
901
1092
  function findGitRoot(startPath) {
902
1093
  let currentPath = startPath;
903
1094
  while (currentPath !== dirname(currentPath)) {
@@ -924,8 +1115,8 @@ var manifestCache = null;
924
1115
  var manifestHash = null;
925
1116
  function readManifestFromDisk(filePath) {
926
1117
  try {
927
- if (!fs4.existsSync(filePath)) return null;
928
- const raw = fs4.readFileSync(filePath, "utf-8");
1118
+ if (!fs5.existsSync(filePath)) return null;
1119
+ const raw = fs5.readFileSync(filePath, "utf-8");
929
1120
  const hash = createHash("sha1").update(raw).digest("hex");
930
1121
  const manifest = JSON.parse(raw);
931
1122
  return { manifest, hash };
@@ -968,10 +1159,10 @@ var TAILWIND_ENTRY_CANDIDATES = [
968
1159
  var TAILWIND_DIRECTIVE_PATTERN = /@import\s+['"](?:tailwindcss|tailwindcss\/.+)['"]|@tailwind\s+(?:base|components|utilities)/;
969
1160
  function detectTailwindEntryCss(cwd) {
970
1161
  for (const rel of TAILWIND_ENTRY_CANDIDATES) {
971
- const abs = path6.join(cwd, rel);
1162
+ const abs = path7.join(cwd, rel);
972
1163
  try {
973
- if (!fs4.existsSync(abs)) continue;
974
- const head = fs4.readFileSync(abs, "utf-8").slice(0, 2048);
1164
+ if (!fs5.existsSync(abs)) continue;
1165
+ const head = fs5.readFileSync(abs, "utf-8").slice(0, 2048);
975
1166
  if (TAILWIND_DIRECTIVE_PATTERN.test(head)) return abs;
976
1167
  } catch {
977
1168
  }
@@ -1046,9 +1237,11 @@ var serveMetadataAndScreenshots = (req, res, next) => {
1046
1237
  res.end(JSON.stringify({ error: 'theme must be "light" or "dark"' }));
1047
1238
  return;
1048
1239
  }
1049
- captureScreenshotBuffer(storyId, theme, width, height).then(({ buffer }) => {
1240
+ captureScreenshotBuffer(storyId, theme, width, height).then(({ buffer, renderState }) => {
1050
1241
  res.setHeader("Content-Type", "image/png");
1051
1242
  res.setHeader("Access-Control-Allow-Origin", "*");
1243
+ res.setHeader("Access-Control-Expose-Headers", "x-onlook-render-state");
1244
+ res.setHeader("x-onlook-render-state", renderState);
1052
1245
  res.setHeader("Cache-Control", "no-cache");
1053
1246
  res.end(buffer);
1054
1247
  }).catch((error) => {
@@ -1099,7 +1292,7 @@ var serveMetadataAndScreenshots = (req, res, next) => {
1099
1292
  return;
1100
1293
  }
1101
1294
  if (req.url?.startsWith("/screenshots/")) {
1102
- const screenshotPath = path6.join(
1295
+ const screenshotPath = path7.join(
1103
1296
  process.cwd(),
1104
1297
  ".storybook-cache",
1105
1298
  req.url.replace("/screenshots/", "screenshots/")
@@ -1108,11 +1301,11 @@ var serveMetadataAndScreenshots = (req, res, next) => {
1108
1301
  const storyId = urlParts[0];
1109
1302
  const themeFile = urlParts[1];
1110
1303
  const theme = themeFile?.replace(".png", "");
1111
- if (fs4.existsSync(screenshotPath)) {
1304
+ if (fs5.existsSync(screenshotPath)) {
1112
1305
  res.setHeader("Content-Type", "image/png");
1113
1306
  res.setHeader("Access-Control-Allow-Origin", "*");
1114
1307
  res.setHeader("Cache-Control", "public, max-age=3600");
1115
- fs4.createReadStream(screenshotPath).pipe(res);
1308
+ fs5.createReadStream(screenshotPath).pipe(res);
1116
1309
  return;
1117
1310
  }
1118
1311
  if (storyId && theme && (theme === "light" || theme === "dark")) {
@@ -1120,16 +1313,16 @@ var serveMetadataAndScreenshots = (req, res, next) => {
1120
1313
  `[STORYBOOK_PLUGIN] Generating screenshot on-demand: ${storyId}/${theme}`
1121
1314
  );
1122
1315
  captureScreenshotBuffer(storyId, theme).then(({ buffer }) => {
1123
- const storyDir = path6.join(
1316
+ const storyDir = path7.join(
1124
1317
  process.cwd(),
1125
1318
  ".storybook-cache",
1126
1319
  "screenshots",
1127
1320
  storyId
1128
1321
  );
1129
- if (!fs4.existsSync(storyDir)) {
1130
- fs4.mkdirSync(storyDir, { recursive: true });
1322
+ if (!fs5.existsSync(storyDir)) {
1323
+ fs5.mkdirSync(storyDir, { recursive: true });
1131
1324
  }
1132
- fs4.writeFileSync(screenshotPath, buffer);
1325
+ fs5.writeFileSync(screenshotPath, buffer);
1133
1326
  res.setHeader("Content-Type", "image/png");
1134
1327
  res.setHeader("Access-Control-Allow-Origin", "*");
1135
1328
  res.setHeader("Cache-Control", "public, max-age=3600");
@@ -1203,10 +1396,20 @@ function storybookOnlookPlugin(options = {}) {
1203
1396
  repoRoot,
1204
1397
  hmr: hmrOverride ?? null
1205
1398
  });
1399
+ const aliasEntries = options.resolveAliases === false ? [] : resolveTsconfigAliases(process.cwd());
1400
+ if (aliasEntries.length > 0) {
1401
+ console.log("[STORYBOOK_PLUGIN] Resolved tsconfig path aliases", {
1402
+ count: aliasEntries.length,
1403
+ aliases: aliasEntries.map((a) => a.find.source)
1404
+ });
1405
+ }
1206
1406
  const mainPlugin = {
1207
1407
  name: "storybook-onlook-plugin",
1208
1408
  config() {
1209
1409
  return {
1410
+ ...aliasEntries.length > 0 && {
1411
+ resolve: { alias: aliasEntries }
1412
+ },
1210
1413
  server: {
1211
1414
  // HMR override applies only when the caller explicitly opts in
1212
1415
  // (typically: Storybook fronted over HTTPS by a reverse proxy).
@@ -1227,7 +1430,7 @@ function storybookOnlookPlugin(options = {}) {
1227
1430
  configureServer(server) {
1228
1431
  console.log("[STORYBOOK_PLUGIN] Configuring server middleware");
1229
1432
  server.middlewares.use(serveMetadataAndScreenshots);
1230
- const cachedManifestPath = path6.join(
1433
+ const cachedManifestPath = path7.join(
1231
1434
  process.cwd(),
1232
1435
  ".storybook-cache",
1233
1436
  "manifest.json"
@@ -1246,7 +1449,7 @@ function storybookOnlookPlugin(options = {}) {
1246
1449
  server.watcher.on("change", scheduleRefresh);
1247
1450
  const storyGlobs = options.storyGlobs ?? ["**/*.stories.@(js|jsx|mjs|ts|tsx|mdx)"];
1248
1451
  const resolvedStoryGlobs = storyGlobs.map(
1249
- (glob) => path6.isAbsolute(glob) ? glob : path6.join(process.cwd(), glob)
1452
+ (glob) => path7.isAbsolute(glob) ? glob : path7.join(process.cwd(), glob)
1250
1453
  );
1251
1454
  if (resolvedStoryGlobs.length > 0) {
1252
1455
  server.watcher.add(resolvedStoryGlobs);
@@ -1257,7 +1460,7 @@ function storybookOnlookPlugin(options = {}) {
1257
1460
  const tailwindEntryPath = (() => {
1258
1461
  if (options.tailwindEntryCss === false) return null;
1259
1462
  if (typeof options.tailwindEntryCss === "string") {
1260
- return path6.isAbsolute(options.tailwindEntryCss) ? options.tailwindEntryCss : path6.join(process.cwd(), options.tailwindEntryCss);
1463
+ return path7.isAbsolute(options.tailwindEntryCss) ? options.tailwindEntryCss : path7.join(process.cwd(), options.tailwindEntryCss);
1261
1464
  }
1262
1465
  return detectTailwindEntryCss(process.cwd());
1263
1466
  })();
@@ -1273,13 +1476,13 @@ function storybookOnlookPlugin(options = {}) {
1273
1476
  });
1274
1477
  server.watcher.on("add", (file) => {
1275
1478
  if (!/\.tsx?$/.test(file)) return;
1276
- const dir = path6.dirname(file);
1479
+ const dir = path7.dirname(file);
1277
1480
  const isNewDir = !seenDirs.has(dir);
1278
1481
  seenDirs.add(dir);
1279
1482
  if (!watcherReady || !isNewDir) return;
1280
1483
  try {
1281
1484
  const now = /* @__PURE__ */ new Date();
1282
- fs4.utimesSync(tailwindEntryPath, now, now);
1485
+ fs5.utimesSync(tailwindEntryPath, now, now);
1283
1486
  console.log("[STORYBOOK_PLUGIN] Tailwind rescan for new dir", {
1284
1487
  dir,
1285
1488
  entry: tailwindEntryPath
@@ -1304,7 +1507,7 @@ function storybookOnlookPlugin(options = {}) {
1304
1507
  configurePreviewServer(server) {
1305
1508
  console.log("[STORYBOOK_PLUGIN] Configuring preview server middleware");
1306
1509
  server.middlewares.use(serveMetadataAndScreenshots);
1307
- refreshManifest(path6.join(process.cwd(), ".storybook-cache", "manifest.json"));
1510
+ refreshManifest(path7.join(process.cwd(), ".storybook-cache", "manifest.json"));
1308
1511
  },
1309
1512
  handleHotUpdate: handleStoryFileChange
1310
1513
  };
@@ -1,4 +1,4 @@
1
- import { O as OnlookPluginOptions } from '../storybook-onlook-plugin-CigILdDb.js';
1
+ import { O as OnlookPluginOptions } from '../storybook-onlook-plugin-B9Eo_OIq.js';
2
2
  import 'vite';
3
3
 
4
4
  declare function pluginOptionsFromPresetOptions(options: Record<string, unknown> | undefined): OnlookPluginOptions;