@onlook/storybook-plugin 0.3.1 → 0.3.2-beta.0

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.
@@ -93,20 +93,27 @@ async function captureScreenshotBuffer(storyId, theme, width = VIEWPORT_WIDTH, h
93
93
  await page.goto(url, { timeout: timeoutMs });
94
94
  await page.waitForLoadState("domcontentloaded", { timeout: timeoutMs });
95
95
  await page.waitForLoadState("load", { timeout: timeoutMs });
96
- await page.waitForLoadState("networkidle", { timeout: timeoutMs });
96
+ try {
97
+ await page.waitForLoadState("networkidle", { timeout: 5e3 });
98
+ } catch {
99
+ }
97
100
  await page.evaluate(() => document.fonts.ready);
98
- await page.evaluate(async () => {
99
- const images = document.querySelectorAll("img");
100
- await Promise.all(
101
- Array.from(images).map((img) => {
102
- if (img.complete) return Promise.resolve();
103
- return new Promise((resolve) => {
104
- img.addEventListener("load", resolve);
105
- img.addEventListener("error", resolve);
106
- });
107
- })
108
- );
109
- });
101
+ try {
102
+ await page.evaluate(async () => {
103
+ const images = document.querySelectorAll("img");
104
+ await Promise.all(
105
+ Array.from(images).map((img) => {
106
+ if (img.complete) return Promise.resolve();
107
+ return new Promise((resolve) => {
108
+ img.addEventListener("load", resolve);
109
+ img.addEventListener("error", resolve);
110
+ setTimeout(resolve, 3e3);
111
+ });
112
+ })
113
+ );
114
+ });
115
+ } catch {
116
+ }
110
117
  const contentBounds = await page.evaluate(() => {
111
118
  const root = document.querySelector("#storybook-root");
112
119
  if (!root) return null;
@@ -181,6 +188,33 @@ async function generateScreenshot(storyId, theme, storybookUrl = "http://localho
181
188
  }
182
189
 
183
190
  // src/screenshot-service/screenshot-service.ts
191
+ var StoryTimeoutError = class extends Error {
192
+ constructor(storyId, timeoutMs) {
193
+ super(`Story ${storyId} timed out after ${timeoutMs / 1e3}s`);
194
+ this.storyId = storyId;
195
+ this.timeoutMs = timeoutMs;
196
+ this.name = "StoryTimeoutError";
197
+ }
198
+ };
199
+ async function captureBothThemes(storyId, storybookUrl, timeoutMs, storyTimeoutMs) {
200
+ let timer;
201
+ try {
202
+ return await Promise.race([
203
+ Promise.all([
204
+ generateScreenshot(storyId, "light", storybookUrl, timeoutMs),
205
+ generateScreenshot(storyId, "dark", storybookUrl, timeoutMs)
206
+ ]),
207
+ new Promise((_, reject) => {
208
+ timer = setTimeout(
209
+ () => reject(new StoryTimeoutError(storyId, storyTimeoutMs)),
210
+ storyTimeoutMs
211
+ );
212
+ })
213
+ ]);
214
+ } finally {
215
+ if (timer) clearTimeout(timer);
216
+ }
217
+ }
184
218
  async function generateAllScreenshots(stories, storybookUrl = "http://localhost:6006", concurrency = 10, offset = 0, total, skipExisting = false, timeoutMs = 3e4) {
185
219
  const displayTotal = total ?? offset + stories.length;
186
220
  console.log(
@@ -191,6 +225,7 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
191
225
  for (let i = 0; i < stories.length; i += BATCH_SIZE) {
192
226
  batches.push(stories.slice(i, i + BATCH_SIZE));
193
227
  }
228
+ const storyTimeout = timeoutMs * 2 + 1e4;
194
229
  let completed = 0;
195
230
  for (const batch of batches) {
196
231
  await Promise.all(
@@ -201,19 +236,64 @@ async function generateAllScreenshots(stories, storybookUrl = "http://localhost:
201
236
  console.log(`[${absoluteIndex2}/${displayTotal}] Skipped (exists) ${story.id}`);
202
237
  return;
203
238
  }
204
- const [lightResult, darkResult] = await Promise.all([
205
- generateScreenshot(story.id, "light", storybookUrl, timeoutMs),
206
- generateScreenshot(story.id, "dark", storybookUrl, timeoutMs)
207
- ]);
239
+ let lightResult = null;
240
+ let darkResult = null;
241
+ let lastError;
242
+ const startedAt = Date.now();
243
+ let attempts = 0;
244
+ const maxAttempts = 2;
245
+ while (attempts < maxAttempts) {
246
+ attempts++;
247
+ try {
248
+ [lightResult, darkResult] = await captureBothThemes(
249
+ story.id,
250
+ storybookUrl,
251
+ timeoutMs,
252
+ storyTimeout
253
+ );
254
+ lastError = void 0;
255
+ break;
256
+ } catch (error) {
257
+ lastError = error;
258
+ if (!(error instanceof StoryTimeoutError) || attempts >= maxAttempts) {
259
+ break;
260
+ }
261
+ console.warn(
262
+ `[screenshot] Retrying ${story.id} after timeout (attempt ${attempts + 1}/${maxAttempts})`
263
+ );
264
+ }
265
+ }
266
+ completed++;
267
+ const absoluteIndex = offset + completed;
268
+ const durationMs = Date.now() - startedAt;
208
269
  if (lightResult && darkResult) {
209
270
  const fileHash = computeFileHash(story.importPath);
210
271
  updateManifest(story.id, story.importPath, fileHash, lightResult.boundingBox);
272
+ console.log(
273
+ `[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`,
274
+ { storyId: story.id, attempts, durationMs, outcome: "ok" }
275
+ );
276
+ } else if (lastError) {
277
+ console.error(
278
+ `[${absoluteIndex}/${displayTotal}] \u26A0\uFE0F Failed ${story.id}:`,
279
+ lastError instanceof Error ? lastError.message : lastError,
280
+ {
281
+ storyId: story.id,
282
+ attempts,
283
+ durationMs,
284
+ outcome: lastError instanceof StoryTimeoutError ? "timeout" : "error"
285
+ }
286
+ );
287
+ } else {
288
+ console.warn(`[${absoluteIndex}/${displayTotal}] Partial result ${story.id}`, {
289
+ storyId: story.id,
290
+ attempts,
291
+ durationMs,
292
+ outcome: "partial",
293
+ hasLight: !!lightResult,
294
+ hasDark: !!darkResult
295
+ });
211
296
  }
212
- completed++;
213
- const absoluteIndex = offset + completed;
214
- console.log(
215
- `[${absoluteIndex}/${displayTotal}] Generated screenshots for ${story.id}`
216
- );
217
297
  })
218
298
  );
219
299
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlook/storybook-plugin",
3
- "version": "0.3.1",
3
+ "version": "0.3.2-beta.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "onlook-storybook": "./dist/cli/index.js"
@@ -29,7 +29,8 @@
29
29
  "typecheck": "tsc --noEmit",
30
30
  "prepublishOnly": "bun run build && bun scripts/prepublish.ts",
31
31
  "postpublish": "bun scripts/postpublish.ts",
32
- "publish-pkg": "npm publish"
32
+ "publish-pkg": "bun publish",
33
+ "publish-beta": "bun publish --tag beta"
33
34
  },
34
35
  "dependencies": {
35
36
  "@babel/generator": "^7.26.9",
@@ -40,7 +41,7 @@
40
41
  "playwright": "^1.52.0"
41
42
  },
42
43
  "devDependencies": {
43
- "@onbook/tsconfig": "workspace:*",
44
+ "@onbook/tsconfig": "0.1.0",
44
45
  "@types/babel__generator": "^7.6.8",
45
46
  "@types/babel__traverse": "^7.20.6",
46
47
  "@types/node": "^22.15.32",