@onlook/storybook-plugin 0.4.0-beta.17 → 0.4.0-beta.19

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
@@ -514,52 +514,6 @@ async function getBrowser() {
514
514
  }
515
515
  return browserPromise;
516
516
  }
517
-
518
- // src/screenshot-service/utils/capture-semaphore/capture-semaphore.ts
519
- function createSemaphore(limit) {
520
- const max = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 1;
521
- let active = 0;
522
- const waiters = [];
523
- const acquire = () => {
524
- if (active < max) {
525
- active += 1;
526
- return Promise.resolve();
527
- }
528
- return new Promise((resolve) => {
529
- waiters.push(() => {
530
- active += 1;
531
- resolve();
532
- });
533
- });
534
- };
535
- const release = () => {
536
- active -= 1;
537
- const next = waiters.shift();
538
- if (next) next();
539
- };
540
- return {
541
- async run(fn) {
542
- await acquire();
543
- try {
544
- return await fn();
545
- } finally {
546
- release();
547
- }
548
- }
549
- };
550
- }
551
- var DEFAULT_CAPTURE_CONCURRENCY = 3;
552
- function resolveConcurrency(raw) {
553
- if (!raw) return DEFAULT_CAPTURE_CONCURRENCY;
554
- const parsed = Number.parseInt(raw, 10);
555
- if (!Number.isInteger(parsed) || parsed < 1) return DEFAULT_CAPTURE_CONCURRENCY;
556
- return parsed;
557
- }
558
- var captureSemaphore = createSemaphore(
559
- resolveConcurrency(process.env.ONLOOK_CAPTURE_CONCURRENCY)
560
- );
561
-
562
- // src/screenshot-service/utils/screenshot/screenshot.ts
563
517
  function classifyPreviewSnapshot(s) {
564
518
  if (s.text.includes("Sorry, something went wrong")) return "errored";
565
519
  if (s.text.includes("Couldn't find story")) return "errored";
@@ -630,89 +584,87 @@ function getScreenshotPath(storyId, theme) {
630
584
  return path8.join(storyDir, `${theme}.png`);
631
585
  }
632
586
  async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, height = VIEWPORT_HEIGHT, storybookUrl = "http://localhost:6006", loadTimeoutMs = 9e4, renderTimeoutMs = 2e4) {
633
- return captureSemaphore.run(async () => {
634
- const browser = await getBrowser();
635
- const context = await browser.newContext({
636
- viewport: { width, height },
637
- deviceScaleFactor: 2
638
- });
639
- const page = await context.newPage();
587
+ const browser = await getBrowser();
588
+ const context = await browser.newContext({
589
+ viewport: { width, height },
590
+ deviceScaleFactor: 2
591
+ });
592
+ const page = await context.newPage();
593
+ try {
594
+ const url = `${storybookUrl}/iframe.html?id=${storyId}&viewMode=story&globals=theme:${theme}`;
595
+ await page.goto(url, { timeout: loadTimeoutMs });
596
+ await page.waitForLoadState("domcontentloaded", { timeout: loadTimeoutMs });
597
+ await page.waitForLoadState("load", { timeout: loadTimeoutMs });
640
598
  try {
641
- const url = `${storybookUrl}/iframe.html?id=${storyId}&viewMode=story&globals=theme:${theme}`;
642
- await page.goto(url, { timeout: loadTimeoutMs });
643
- await page.waitForLoadState("domcontentloaded", { timeout: loadTimeoutMs });
644
- await page.waitForLoadState("load", { timeout: loadTimeoutMs });
645
- try {
646
- await page.waitForLoadState("networkidle", { timeout: 5e3 });
647
- } catch {
648
- }
649
- const renderState = await detectRenderState(page, { hardCapMs: renderTimeoutMs });
650
- await page.evaluate(() => document.fonts.ready);
651
- try {
652
- await page.evaluate(async () => {
653
- const images = document.querySelectorAll("img");
654
- await Promise.all(
655
- Array.from(images).map((img) => {
656
- if (img.complete) return Promise.resolve();
657
- return new Promise((resolve) => {
658
- img.addEventListener("load", resolve);
659
- img.addEventListener("error", resolve);
660
- setTimeout(resolve, 3e3);
661
- });
662
- })
663
- );
664
- });
665
- } catch {
666
- }
667
- const contentBounds = await page.evaluate(() => {
668
- const root = document.querySelector("#storybook-root");
669
- if (!root) return null;
670
- const children = root.querySelectorAll("*");
671
- if (children.length === 0) return null;
672
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
673
- children.forEach((child) => {
674
- const rect = child.getBoundingClientRect();
675
- if (rect.width === 0 || rect.height === 0) return;
676
- minX = Math.min(minX, rect.left);
677
- minY = Math.min(minY, rect.top);
678
- maxX = Math.max(maxX, rect.right);
679
- maxY = Math.max(maxY, rect.bottom);
680
- });
681
- if (minX === Infinity) return null;
682
- return {
683
- x: minX,
684
- y: minY,
685
- width: maxX - minX,
686
- height: maxY - minY
687
- };
599
+ await page.waitForLoadState("networkidle", { timeout: 5e3 });
600
+ } catch {
601
+ }
602
+ const renderState = await detectRenderState(page, { hardCapMs: renderTimeoutMs });
603
+ await page.evaluate(() => document.fonts.ready);
604
+ try {
605
+ await page.evaluate(async () => {
606
+ const images = document.querySelectorAll("img");
607
+ await Promise.all(
608
+ Array.from(images).map((img) => {
609
+ if (img.complete) return Promise.resolve();
610
+ return new Promise((resolve) => {
611
+ img.addEventListener("load", resolve);
612
+ img.addEventListener("error", resolve);
613
+ setTimeout(resolve, 3e3);
614
+ });
615
+ })
616
+ );
688
617
  });
689
- let screenshotBuffer;
690
- let resultBoundingBox = null;
691
- if (contentBounds && contentBounds.width > 0 && contentBounds.height > 0) {
692
- const PADDING = 20;
693
- const clippedWidth = Math.min(width, contentBounds.width + PADDING);
694
- const clippedHeight = Math.min(height, contentBounds.height + PADDING);
695
- resultBoundingBox = {
696
- width: Math.max(MIN_COMPONENT_WIDTH, Math.round(clippedWidth)),
697
- height: Math.max(MIN_COMPONENT_HEIGHT, Math.round(clippedHeight))
698
- };
699
- screenshotBuffer = await page.screenshot({
700
- type: "png",
701
- clip: {
702
- x: Math.max(0, contentBounds.x - 10),
703
- y: Math.max(0, contentBounds.y - 10),
704
- width: clippedWidth,
705
- height: clippedHeight
706
- }
707
- });
708
- } else {
709
- screenshotBuffer = await page.screenshot({ type: "png" });
710
- }
711
- return { buffer: screenshotBuffer, boundingBox: resultBoundingBox, renderState };
712
- } finally {
713
- await context.close();
618
+ } catch {
714
619
  }
715
- });
620
+ const contentBounds = await page.evaluate(() => {
621
+ const root = document.querySelector("#storybook-root");
622
+ if (!root) return null;
623
+ const children = root.querySelectorAll("*");
624
+ if (children.length === 0) return null;
625
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
626
+ children.forEach((child) => {
627
+ const rect = child.getBoundingClientRect();
628
+ if (rect.width === 0 || rect.height === 0) return;
629
+ minX = Math.min(minX, rect.left);
630
+ minY = Math.min(minY, rect.top);
631
+ maxX = Math.max(maxX, rect.right);
632
+ maxY = Math.max(maxY, rect.bottom);
633
+ });
634
+ if (minX === Infinity) return null;
635
+ return {
636
+ x: minX,
637
+ y: minY,
638
+ width: maxX - minX,
639
+ height: maxY - minY
640
+ };
641
+ });
642
+ let screenshotBuffer;
643
+ let resultBoundingBox = null;
644
+ if (contentBounds && contentBounds.width > 0 && contentBounds.height > 0) {
645
+ const PADDING = 20;
646
+ const clippedWidth = Math.min(width, contentBounds.width + PADDING);
647
+ const clippedHeight = Math.min(height, contentBounds.height + PADDING);
648
+ resultBoundingBox = {
649
+ width: Math.max(MIN_COMPONENT_WIDTH, Math.round(clippedWidth)),
650
+ height: Math.max(MIN_COMPONENT_HEIGHT, Math.round(clippedHeight))
651
+ };
652
+ screenshotBuffer = await page.screenshot({
653
+ type: "png",
654
+ clip: {
655
+ x: Math.max(0, contentBounds.x - 10),
656
+ y: Math.max(0, contentBounds.y - 10),
657
+ width: clippedWidth,
658
+ height: clippedHeight
659
+ }
660
+ });
661
+ } else {
662
+ screenshotBuffer = await page.screenshot({ type: "png" });
663
+ }
664
+ return { buffer: screenshotBuffer, boundingBox: resultBoundingBox, renderState };
665
+ } finally {
666
+ await context.close();
667
+ }
716
668
  }
717
669
  async function generateScreenshot(storyId, theme, storybookUrl = "http://localhost:6006", timeoutMs = 3e4) {
718
670
  try {
@@ -819,39 +771,7 @@ async function waitForIndexAndBroadcast(port = 6006) {
819
771
  });
820
772
  }
821
773
 
822
- // src/handlers/handleStoryFileChange/captureCoalescer/captureCoalescer.ts
823
- function createCaptureCoalescer(runCapture) {
824
- const inFlight2 = /* @__PURE__ */ new Map();
825
- const trailing = /* @__PURE__ */ new Set();
826
- const start = (storyId) => {
827
- const done = (async () => {
828
- try {
829
- await runCapture(storyId);
830
- } finally {
831
- inFlight2.delete(storyId);
832
- if (trailing.has(storyId)) {
833
- trailing.delete(storyId);
834
- await start(storyId);
835
- }
836
- }
837
- })();
838
- inFlight2.set(storyId, done);
839
- return done;
840
- };
841
- return {
842
- capture(storyId) {
843
- const existing = inFlight2.get(storyId);
844
- if (existing) {
845
- trailing.add(storyId);
846
- return existing;
847
- }
848
- return start(storyId);
849
- }
850
- };
851
- }
852
-
853
774
  // src/handlers/handleStoryFileChange/handleStoryFileChange.ts
854
- var STORYBOOK_URL = "http://localhost:6006";
855
775
  var cachedIndex = null;
856
776
  var indexFetchPromise = null;
857
777
  var pendingFiles = /* @__PURE__ */ new Set();
@@ -873,43 +793,44 @@ function getStoriesForFile(filePath) {
873
793
  const fileName = path8.basename(filePath);
874
794
  return Object.values(cachedIndex.entries).filter((entry) => entry.type === "story" && entry.importPath.endsWith(fileName)).map((entry) => entry.id);
875
795
  }
876
- var latestStoryFiles = /* @__PURE__ */ new Map();
877
- async function captureStoryAndUpdateManifest(storyId) {
878
- const [lightResult] = await Promise.all([
879
- generateScreenshot(storyId, "light", STORYBOOK_URL),
880
- generateScreenshot(storyId, "dark", STORYBOOK_URL)
881
- ]);
882
- const boundingBox = lightResult?.boundingBox ?? void 0;
883
- for (const file of latestStoryFiles.get(storyId) ?? []) {
884
- const fileHash = computeFileHash(file);
885
- updateManifest(storyId, file, fileHash, boundingBox);
886
- }
887
- }
888
- var captureCoalescer = createCaptureCoalescer(captureStoryAndUpdateManifest);
889
796
  async function regenerateScreenshotsForFiles(files) {
890
797
  await fetchStorybookIndex();
891
- const storyToFiles = /* @__PURE__ */ new Map();
798
+ const allStoryIds = /* @__PURE__ */ new Set();
799
+ const fileToStories = /* @__PURE__ */ new Map();
892
800
  for (const file of files) {
893
- for (const storyId of getStoriesForFile(file)) {
894
- const arr = storyToFiles.get(storyId) ?? [];
895
- arr.push(file);
896
- storyToFiles.set(storyId, arr);
801
+ const storyIds = getStoriesForFile(file);
802
+ fileToStories.set(file, storyIds);
803
+ for (const id of storyIds) {
804
+ allStoryIds.add(id);
897
805
  }
898
806
  }
899
- if (storyToFiles.size === 0) {
807
+ if (allStoryIds.size === 0) {
900
808
  console.log("[Screenshots] No stories found for changed files");
901
809
  return;
902
810
  }
903
811
  console.log(
904
- `[Screenshots] Regenerating ${storyToFiles.size} stories from ${files.length} files`
812
+ `[Screenshots] Regenerating ${allStoryIds.size} stories from ${files.length} files`
905
813
  );
906
- for (const [storyId, storyFiles] of storyToFiles) {
907
- latestStoryFiles.set(storyId, storyFiles);
908
- }
814
+ const storybookUrl = "http://localhost:6006";
815
+ const storyBoundingBoxes = /* @__PURE__ */ new Map();
909
816
  await Promise.all(
910
- Array.from(storyToFiles.keys()).map((storyId) => captureCoalescer.capture(storyId))
817
+ Array.from(allStoryIds).map(async (storyId) => {
818
+ const [lightResult, _darkResult] = await Promise.all([
819
+ generateScreenshot(storyId, "light", storybookUrl),
820
+ generateScreenshot(storyId, "dark", storybookUrl)
821
+ ]);
822
+ if (lightResult) {
823
+ storyBoundingBoxes.set(storyId, lightResult.boundingBox);
824
+ }
825
+ })
911
826
  );
912
- console.log(`[Screenshots] \u2713 Regenerated ${storyToFiles.size} stories`);
827
+ for (const [file, storyIds] of fileToStories) {
828
+ const fileHash = computeFileHash(file);
829
+ storyIds.forEach((storyId) => {
830
+ updateManifest(storyId, file, fileHash, storyBoundingBoxes.get(storyId));
831
+ });
832
+ }
833
+ console.log(`[Screenshots] \u2713 Regenerated ${allStoryIds.size} stories`);
913
834
  }
914
835
  function handleStoryFileChange({ file, modules }) {
915
836
  if (file.endsWith(".stories.tsx") || file.endsWith(".stories.ts")) {
@@ -936,9 +857,139 @@ function handleStoryFileChange({ file, modules }) {
936
857
  }
937
858
  }
938
859
 
939
- // src/package-mock/clerk-mock.ts
860
+ // src/package-mock/convex-mock.ts
940
861
  var VALID_IDENT_RE2 = /^[A-Za-z_$][\w$]*$/;
941
862
  var RESERVED_HELPER_NAMES = /* @__PURE__ */ new Set([
863
+ "__pass",
864
+ "__null",
865
+ "__asyncNoop",
866
+ "__noop",
867
+ "__convexClient",
868
+ "createElement",
869
+ "Fragment"
870
+ ]);
871
+ var SHARED_PREAMBLE = [
872
+ "import { createElement, Fragment } from 'react';",
873
+ "const __asyncNoop = async () => {};",
874
+ "const __noop = () => {};",
875
+ // No `: any` param annotation — the virtual module is parsed as PLAIN JS.
876
+ "const __pass = (props) => createElement(Fragment, null, props ? props.children : undefined);",
877
+ "const __null = () => null;"
878
+ ];
879
+ var CONVEX_CLIENT_PREAMBLE = [
880
+ "const __convexClient = {",
881
+ " setAuth: __noop,",
882
+ " clearAuth: __noop,",
883
+ " close: __asyncNoop,",
884
+ " connectionState: () => ({ hasInflightRequests: false, isWebSocketConnected: false }),",
885
+ " watchQuery: () => ({",
886
+ " onUpdate: () => __noop,",
887
+ " localQueryResult: () => undefined,",
888
+ " journal: () => undefined,",
889
+ " }),",
890
+ " mutation: __asyncNoop,",
891
+ " action: __asyncNoop,",
892
+ " query: __asyncNoop,",
893
+ "};"
894
+ ];
895
+ var CONVEX_KNOWN_HOOKS = {
896
+ useQuery: "undefined",
897
+ useQueries: "({})",
898
+ useMutation: "__asyncNoop",
899
+ useAction: "__asyncNoop",
900
+ usePaginatedQuery: "({ results: [], status: 'LoadingFirstPage', isLoading: true, loadMore: __noop })",
901
+ useConvex: "__convexClient",
902
+ useConvexAuth: "({ isLoading: false, isAuthenticated: true })"
903
+ };
904
+ var CONVEX_CHILDREN_COMPONENTS = /* @__PURE__ */ new Set([
905
+ "ConvexProvider",
906
+ "ConvexProviderWithAuth",
907
+ "ConvexProviderWithClerk",
908
+ "Authenticated"
909
+ ]);
910
+ var CONVEX_NULL_COMPONENTS = /* @__PURE__ */ new Set(["Unauthenticated", "AuthLoading"]);
911
+ function convexExportLine(name) {
912
+ if (name in CONVEX_KNOWN_HOOKS) {
913
+ return `export const ${name} = () => ${CONVEX_KNOWN_HOOKS[name]};`;
914
+ }
915
+ if (name === "ConvexReactClient") {
916
+ return "export function ConvexReactClient() { return __convexClient; }";
917
+ }
918
+ if (CONVEX_CHILDREN_COMPONENTS.has(name)) return `export const ${name} = __pass;`;
919
+ if (CONVEX_NULL_COMPONENTS.has(name)) return `export const ${name} = __null;`;
920
+ if (/^use[A-Z]/.test(name)) return `export const ${name} = () => undefined;`;
921
+ if (/^[A-Z]/.test(name)) return `export const ${name} = __pass;`;
922
+ return `export const ${name} = undefined;`;
923
+ }
924
+ function buildConvexReactMockSource(usedExports) {
925
+ const names = dedupeNames([
926
+ ...usedExports,
927
+ ...Object.keys(CONVEX_KNOWN_HOOKS),
928
+ ...CONVEX_CHILDREN_COMPONENTS,
929
+ ...CONVEX_NULL_COMPONENTS,
930
+ "ConvexReactClient"
931
+ ]);
932
+ return [
933
+ "// Auto-generated by @onlook/storybook-plugin (package mock). Zero-backend",
934
+ "// Convex stand-in: queries stay in the loading state (`useQuery` returns",
935
+ "// `undefined`), mutations/actions no-op, auth reads signed-in. Swap back to",
936
+ "// the real convex package (with a deployment URL) for live data.",
937
+ ...SHARED_PREAMBLE,
938
+ ...CONVEX_CLIENT_PREAMBLE,
939
+ "",
940
+ ...names.map(convexExportLine),
941
+ "",
942
+ "export default {};",
943
+ ""
944
+ ].join("\n");
945
+ }
946
+ var CONVEX_AUTH_KNOWN_HOOKS = {
947
+ useAuthActions: "({ signIn: __asyncNoop, signOut: __asyncNoop })",
948
+ useAuthToken: "null"
949
+ };
950
+ var CONVEX_AUTH_CHILDREN_COMPONENTS = /* @__PURE__ */ new Set(["ConvexAuthProvider"]);
951
+ function convexAuthExportLine(name) {
952
+ if (name in CONVEX_AUTH_KNOWN_HOOKS) {
953
+ return `export const ${name} = () => ${CONVEX_AUTH_KNOWN_HOOKS[name]};`;
954
+ }
955
+ if (CONVEX_AUTH_CHILDREN_COMPONENTS.has(name)) {
956
+ return `export const ${name} = __pass;`;
957
+ }
958
+ if (/^use[A-Z]/.test(name)) return `export const ${name} = () => undefined;`;
959
+ if (/^[A-Z]/.test(name)) return `export const ${name} = __pass;`;
960
+ return `export const ${name} = undefined;`;
961
+ }
962
+ function buildConvexAuthMockSource(usedExports) {
963
+ const names = dedupeNames([
964
+ ...usedExports,
965
+ ...Object.keys(CONVEX_AUTH_KNOWN_HOOKS),
966
+ ...CONVEX_AUTH_CHILDREN_COMPONENTS
967
+ ]);
968
+ return [
969
+ "// Auto-generated by @onlook/storybook-plugin (package mock). Zero-backend",
970
+ "// @convex-dev/auth stand-in: auth actions no-op, no token. Swap back to the",
971
+ "// real package for live auth flows.",
972
+ ...SHARED_PREAMBLE,
973
+ "",
974
+ ...names.map(convexAuthExportLine),
975
+ "",
976
+ "export default {};",
977
+ ""
978
+ ].join("\n");
979
+ }
980
+ function dedupeNames(usedExports) {
981
+ return Array.from(
982
+ new Set(
983
+ usedExports.filter(
984
+ (n) => VALID_IDENT_RE2.test(n) && n !== "default" && !RESERVED_HELPER_NAMES.has(n)
985
+ )
986
+ )
987
+ ).sort();
988
+ }
989
+
990
+ // src/package-mock/clerk-mock.ts
991
+ var VALID_IDENT_RE3 = /^[A-Za-z_$][\w$]*$/;
992
+ var RESERVED_HELPER_NAMES2 = /* @__PURE__ */ new Set([
942
993
  "__user",
943
994
  "__pass",
944
995
  "__null",
@@ -951,7 +1002,9 @@ var RESERVED_HELPER_NAMES = /* @__PURE__ */ new Set([
951
1002
  ]);
952
1003
  var BUILDERS = {
953
1004
  "@clerk/nextjs": buildClerkMockSource,
954
- "@clerk/clerk-react": buildClerkMockSource
1005
+ "@clerk/clerk-react": buildClerkMockSource,
1006
+ "convex/react": buildConvexReactMockSource,
1007
+ "@convex-dev/auth/react": buildConvexAuthMockSource
955
1008
  };
956
1009
  function isKnownMockPackage(pkg) {
957
1010
  return pkg in BUILDERS;
@@ -1075,7 +1128,7 @@ function buildClerkMockSource(usedExports) {
1075
1128
  const names = Array.from(
1076
1129
  new Set(
1077
1130
  usedExports.filter(
1078
- (n) => VALID_IDENT_RE2.test(n) && n !== "default" && !RESERVED_HELPER_NAMES.has(n)
1131
+ (n) => VALID_IDENT_RE3.test(n) && n !== "default" && !RESERVED_HELPER_NAMES2.has(n)
1079
1132
  )
1080
1133
  )
1081
1134
  ).sort();
@@ -1131,63 +1184,61 @@ function packageMockPlugin(options) {
1131
1184
 
1132
1185
  // src/screenshot-service/utils/console-logs/console-logs.ts
1133
1186
  async function captureConsoleLogs(storyId, theme = "light", storybookUrl = "http://localhost:6006", timeoutMs = 3e4) {
1134
- return captureSemaphore.run(async () => {
1135
- const browser = await getBrowser();
1136
- const context = await browser.newContext({
1137
- viewport: { width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT }
1138
- });
1139
- const page = await context.newPage();
1140
- const logs = [];
1141
- const pageErrors = [];
1142
- const failedRequests = [];
1143
- page.on("console", (msg) => {
1144
- const level = msg.type();
1145
- logs.push({
1146
- level: level === "warning" ? "warn" : level,
1147
- text: msg.text(),
1148
- timestamp: Date.now()
1149
- });
1150
- });
1151
- page.on("pageerror", (err) => {
1152
- pageErrors.push(err.message);
1153
- });
1154
- page.on("response", (res) => {
1155
- const status = res.status();
1156
- if (status >= 400) {
1157
- const req = res.request();
1158
- failedRequests.push({
1159
- url: res.url(),
1160
- status,
1161
- method: req.method(),
1162
- resourceType: req.resourceType(),
1163
- failure: null
1164
- });
1165
- }
1187
+ const browser = await getBrowser();
1188
+ const context = await browser.newContext({
1189
+ viewport: { width: VIEWPORT_WIDTH, height: VIEWPORT_HEIGHT }
1190
+ });
1191
+ const page = await context.newPage();
1192
+ const logs = [];
1193
+ const pageErrors = [];
1194
+ const failedRequests = [];
1195
+ page.on("console", (msg) => {
1196
+ const level = msg.type();
1197
+ logs.push({
1198
+ level: level === "warning" ? "warn" : level,
1199
+ text: msg.text(),
1200
+ timestamp: Date.now()
1166
1201
  });
1167
- page.on("requestfailed", (req) => {
1202
+ });
1203
+ page.on("pageerror", (err) => {
1204
+ pageErrors.push(err.message);
1205
+ });
1206
+ page.on("response", (res) => {
1207
+ const status = res.status();
1208
+ if (status >= 400) {
1209
+ const req = res.request();
1168
1210
  failedRequests.push({
1169
- url: req.url(),
1170
- status: null,
1211
+ url: res.url(),
1212
+ status,
1171
1213
  method: req.method(),
1172
1214
  resourceType: req.resourceType(),
1173
- failure: req.failure()?.errorText ?? "request failed"
1215
+ failure: null
1174
1216
  });
1217
+ }
1218
+ });
1219
+ page.on("requestfailed", (req) => {
1220
+ failedRequests.push({
1221
+ url: req.url(),
1222
+ status: null,
1223
+ method: req.method(),
1224
+ resourceType: req.resourceType(),
1225
+ failure: req.failure()?.errorText ?? "request failed"
1175
1226
  });
1176
- const url = `${storybookUrl}/iframe.html?id=${storyId}&viewMode=story&globals=theme:${theme}`;
1227
+ });
1228
+ const url = `${storybookUrl}/iframe.html?id=${storyId}&viewMode=story&globals=theme:${theme}`;
1229
+ try {
1230
+ await page.goto(url, { timeout: timeoutMs });
1231
+ await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
1232
+ await page.waitForLoadState("load", { timeout: timeoutMs });
1177
1233
  try {
1178
- await page.goto(url, { timeout: timeoutMs });
1179
- await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
1180
- await page.waitForLoadState("load", { timeout: timeoutMs });
1181
- try {
1182
- await page.waitForLoadState("networkidle", { timeout: 5e3 });
1183
- } catch {
1184
- }
1185
- await new Promise((r) => setTimeout(r, 1e3));
1186
- return { logs, pageErrors, failedRequests, url };
1187
- } finally {
1188
- await context.close();
1234
+ await page.waitForLoadState("networkidle", { timeout: 5e3 });
1235
+ } catch {
1189
1236
  }
1190
- });
1237
+ await new Promise((r) => setTimeout(r, 1e3));
1238
+ return { logs, pageErrors, failedRequests, url };
1239
+ } finally {
1240
+ await context.close();
1241
+ }
1191
1242
  }
1192
1243
 
1193
1244
  // src/soft-story-rerender/soft-story-rerender.ts
@@ -1378,17 +1429,6 @@ function findGitRoot(startPath) {
1378
1429
  }
1379
1430
  return null;
1380
1431
  }
1381
- function ifNoneMatchHits(header, etag) {
1382
- if (!header) return false;
1383
- return header.split(",").some((raw) => {
1384
- const token = raw.trim();
1385
- return token === etag || token === `W/${etag}`;
1386
- });
1387
- }
1388
- function decideIndexResponse(body, ifNoneMatch) {
1389
- const etag = `"${createHash("sha1").update(body).digest("hex")}"`;
1390
- return { etag, notModified: ifNoneMatchHits(ifNoneMatch, etag) };
1391
- }
1392
1432
  var STORY_FILE_PATTERN = /\.stories\.(js|jsx|mjs|ts|tsx|mdx)$/;
1393
1433
  function isStoryFile(file) {
1394
1434
  return STORY_FILE_PATTERN.test(file);
@@ -1421,7 +1461,8 @@ function portFromArgv(argv) {
1421
1461
  }
1422
1462
  async function defaultFetchIndex(port) {
1423
1463
  try {
1424
- const res = await fetch(`http://localhost:${port}/index.json`, {
1464
+ const res = await fetch(`http://localhost:${port}/index.json?_t=${Date.now()}`, {
1465
+ cache: "no-store",
1425
1466
  signal: AbortSignal.timeout(2e3)
1426
1467
  });
1427
1468
  if (!res.ok) return null;
@@ -1581,8 +1622,15 @@ function detectTailwindEntryCss(cwd) {
1581
1622
  var serveMetadataAndScreenshots = (req, res, next) => {
1582
1623
  if (req.url === "/onbook-index.json") {
1583
1624
  console.log("[STORYBOOK_PLUGIN] Serving /onbook-index.json endpoint");
1625
+ const cacheBuster = Date.now();
1584
1626
  console.log("[STORYBOOK_PLUGIN] Fetching http://localhost:6006/index.json");
1585
- fetch("http://localhost:6006/index.json").then((response) => {
1627
+ fetch(`http://localhost:6006/index.json?_t=${cacheBuster}`, {
1628
+ cache: "no-store",
1629
+ headers: {
1630
+ "Cache-Control": "no-cache",
1631
+ Pragma: "no-cache"
1632
+ }
1633
+ }).then((response) => {
1586
1634
  console.log("[STORYBOOK_PLUGIN] Storybook index fetch response", {
1587
1635
  status: response.status,
1588
1636
  ok: response.ok,
@@ -1601,21 +1649,12 @@ var serveMetadataAndScreenshots = (req, res, next) => {
1601
1649
  entryCount: Object.keys(indexData.entries || {}).length,
1602
1650
  hasMetadata: !!indexData.meta
1603
1651
  });
1604
- const body = JSON.stringify(indexData);
1605
- const { etag, notModified } = decideIndexResponse(
1606
- body,
1607
- req.headers["if-none-match"]
1608
- );
1609
- res.setHeader("Access-Control-Allow-Origin", "*");
1610
- res.setHeader("ETag", etag);
1611
- res.setHeader("Cache-Control", "no-cache");
1612
- if (notModified) {
1613
- res.statusCode = 304;
1614
- res.end();
1615
- return;
1616
- }
1617
1652
  res.setHeader("Content-Type", "application/json");
1618
- res.end(body);
1653
+ res.setHeader("Access-Control-Allow-Origin", "*");
1654
+ res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
1655
+ res.setHeader("Pragma", "no-cache");
1656
+ res.setHeader("Expires", "0");
1657
+ res.end(JSON.stringify(indexData));
1619
1658
  }).catch((error) => {
1620
1659
  console.error("[STORYBOOK_PLUGIN] Failed to fetch/extend index.json", {
1621
1660
  error: error instanceof Error ? error.message : String(error),
@@ -1,4 +1,4 @@
1
- import { O as OnlookPluginOptions } from '../storybook-onlook-plugin-BvrvMhRF.js';
1
+ import { O as OnlookPluginOptions } from '../storybook-onlook-plugin-J4qj72mN.js';
2
2
  import 'vite';
3
3
 
4
4
  declare function pluginOptionsFromPresetOptions(options: Record<string, unknown> | undefined): OnlookPluginOptions;