happo 6.9.0 → 6.10.1

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.
Files changed (95) hide show
  1. package/dist/cli/cancelJob-4I7RBUQG.js +10 -0
  2. package/dist/cli/{chunk-P4EXA4AX.js → chunk-64XRFVHC.js} +8 -4
  3. package/dist/cli/chunk-64XRFVHC.js.map +7 -0
  4. package/dist/cli/{chunk-J2EA5OBW.js → chunk-GG7D7TQZ.js} +2 -2
  5. package/dist/cli/chunk-ML3Z5Z22.js +44 -0
  6. package/dist/cli/chunk-ML3Z5Z22.js.map +7 -0
  7. package/dist/cli/{chunk-BK32666K.js → chunk-OCKO64S4.js} +3 -3
  8. package/dist/cli/{chunk-R6YURZXU.js → chunk-RJXHIGT5.js} +2 -2
  9. package/dist/cli/{chunk-BESQLM5F.js → chunk-UTRRH3WF.js} +2 -2
  10. package/dist/cli/{chunk-CVX5DVCT.js → chunk-XZTQZZFK.js} +2 -2
  11. package/dist/cli/createAsyncComparison-WLPUS2NJ.js +10 -0
  12. package/dist/cli/{createAsyncReport-4ZD53TJC.js → createAsyncReport-2ZTQOHDA.js} +4 -4
  13. package/dist/cli/createExtendsReportSnapRequest-4ZSBNCPL.js +32 -0
  14. package/dist/cli/createExtendsReportSnapRequest-4ZSBNCPL.js.map +7 -0
  15. package/dist/cli/findBaselineReport-2SHS2OH7.js +36 -0
  16. package/dist/cli/findBaselineReport-2SHS2OH7.js.map +7 -0
  17. package/dist/cli/{getFlakes-6ZGTWZTM.js → getFlakes-DLKH2VLM.js} +4 -4
  18. package/dist/cli/index.d.ts.map +1 -1
  19. package/dist/cli/main.js +160 -19
  20. package/dist/cli/main.js.map +3 -3
  21. package/dist/cli/package-TU7REKQ6.js +7 -0
  22. package/dist/cli/parseOptions.d.ts +6 -0
  23. package/dist/cli/parseOptions.d.ts.map +1 -1
  24. package/dist/cli/{prepareSnapRequests-2LHSGFZV.js → prepareSnapRequests-WBXFGB4B.js} +170 -65
  25. package/dist/cli/prepareSnapRequests-WBXFGB4B.js.map +7 -0
  26. package/dist/cli/startJob-33HGTT4N.js +10 -0
  27. package/dist/cli/{wrapper-7RE2N7Y3.js → wrapper-CCHBHKT2.js} +45 -26
  28. package/dist/cli/wrapper-CCHBHKT2.js.map +7 -0
  29. package/dist/config/index.d.ts +0 -8
  30. package/dist/config/index.d.ts.map +1 -1
  31. package/dist/config/index.js.map +2 -2
  32. package/dist/custom/index.d.ts.map +1 -1
  33. package/dist/custom/index.js +70 -14
  34. package/dist/custom/index.js.map +3 -3
  35. package/dist/cypress/chunk-TYBGAHYH.js +69 -0
  36. package/dist/cypress/chunk-TYBGAHYH.js.map +7 -0
  37. package/dist/cypress/index.d.ts.map +1 -1
  38. package/dist/cypress/index.js +14 -4
  39. package/dist/cypress/index.js.map +2 -2
  40. package/dist/cypress/task.d.ts +4 -2
  41. package/dist/cypress/task.d.ts.map +1 -1
  42. package/dist/cypress/task.js +25 -6
  43. package/dist/cypress/task.js.map +4 -4
  44. package/dist/e2e/wrapper.d.ts +1 -1
  45. package/dist/e2e/wrapper.d.ts.map +1 -1
  46. package/dist/environment/index.d.ts +2 -1
  47. package/dist/environment/index.d.ts.map +1 -1
  48. package/dist/isomorphic/parseOnly.d.ts +15 -0
  49. package/dist/isomorphic/parseOnly.d.ts.map +1 -0
  50. package/dist/isomorphic/parseSkip.d.ts +28 -0
  51. package/dist/isomorphic/parseSkip.d.ts.map +1 -0
  52. package/dist/isomorphic/types.d.ts +11 -0
  53. package/dist/isomorphic/types.d.ts.map +1 -1
  54. package/dist/network/createExtendsReportSnapRequest.d.ts +4 -0
  55. package/dist/network/createExtendsReportSnapRequest.d.ts.map +1 -0
  56. package/dist/network/findBaselineReport.d.ts +5 -0
  57. package/dist/network/findBaselineReport.d.ts.map +1 -0
  58. package/dist/network/prepareSnapRequests.d.ts +9 -1
  59. package/dist/network/prepareSnapRequests.d.ts.map +1 -1
  60. package/dist/playwright/index.d.ts.map +1 -1
  61. package/dist/playwright/index.js +59 -3
  62. package/dist/playwright/index.js.map +3 -3
  63. package/dist/storybook/browser/register.d.ts +2 -1
  64. package/dist/storybook/browser/register.d.ts.map +1 -1
  65. package/dist/storybook/browser/register.js +5 -1
  66. package/dist/storybook/browser/register.js.map +2 -2
  67. package/dist/storybook/index.d.ts +9 -1
  68. package/dist/storybook/index.d.ts.map +1 -1
  69. package/dist/storybook/index.js +134 -42
  70. package/dist/storybook/index.js.map +4 -4
  71. package/dist/storybook/isomorphic/types.d.ts +4 -0
  72. package/dist/storybook/isomorphic/types.d.ts.map +1 -1
  73. package/dist/storybook/resolveStoryFileItems.d.ts +21 -0
  74. package/dist/storybook/resolveStoryFileItems.d.ts.map +1 -0
  75. package/package.json +7 -3
  76. package/dist/cli/cancelJob-Y4WJCCU6.js +0 -10
  77. package/dist/cli/chunk-P4EXA4AX.js.map +0 -7
  78. package/dist/cli/createAsyncComparison-CQLGQXY2.js +0 -10
  79. package/dist/cli/package-4NRNRUE3.js +0 -7
  80. package/dist/cli/prepareSnapRequests-2LHSGFZV.js.map +0 -7
  81. package/dist/cli/startJob-JAO5FUA2.js +0 -10
  82. package/dist/cli/wrapper-7RE2N7Y3.js.map +0 -7
  83. package/dist/cypress/chunk-RKK2MPML.js +0 -20
  84. package/dist/cypress/chunk-RKK2MPML.js.map +0 -7
  85. /package/dist/cli/{cancelJob-Y4WJCCU6.js.map → cancelJob-4I7RBUQG.js.map} +0 -0
  86. /package/dist/cli/{chunk-J2EA5OBW.js.map → chunk-GG7D7TQZ.js.map} +0 -0
  87. /package/dist/cli/{chunk-BK32666K.js.map → chunk-OCKO64S4.js.map} +0 -0
  88. /package/dist/cli/{chunk-R6YURZXU.js.map → chunk-RJXHIGT5.js.map} +0 -0
  89. /package/dist/cli/{chunk-BESQLM5F.js.map → chunk-UTRRH3WF.js.map} +0 -0
  90. /package/dist/cli/{chunk-CVX5DVCT.js.map → chunk-XZTQZZFK.js.map} +0 -0
  91. /package/dist/cli/{createAsyncComparison-CQLGQXY2.js.map → createAsyncComparison-WLPUS2NJ.js.map} +0 -0
  92. /package/dist/cli/{createAsyncReport-4ZD53TJC.js.map → createAsyncReport-2ZTQOHDA.js.map} +0 -0
  93. /package/dist/cli/{getFlakes-6ZGTWZTM.js.map → getFlakes-DLKH2VLM.js.map} +0 -0
  94. /package/dist/cli/{package-4NRNRUE3.js.map → package-TU7REKQ6.js.map} +0 -0
  95. /package/dist/cli/{startJob-JAO5FUA2.js.map → startJob-33HGTT4N.js.map} +0 -0
@@ -1,13 +1,17 @@
1
+ import {
2
+ isInSkipSet,
3
+ toSkipSet
4
+ } from "./chunk-ML3Z5Z22.js";
1
5
  import {
2
6
  makeHappoAPIRequest
3
- } from "./chunk-R6YURZXU.js";
7
+ } from "./chunk-RJXHIGT5.js";
4
8
  import {
5
9
  ErrorWithStatusCode
6
- } from "./chunk-BESQLM5F.js";
7
- import "./chunk-P4EXA4AX.js";
10
+ } from "./chunk-UTRRH3WF.js";
11
+ import "./chunk-64XRFVHC.js";
8
12
 
9
13
  // src/network/prepareSnapRequests.ts
10
- import fs6 from "node:fs";
14
+ import fs5 from "node:fs";
11
15
  import path6 from "node:path";
12
16
 
13
17
  // src/utils/createHash.ts
@@ -238,7 +242,7 @@ var RemoteBrowserTarget = class {
238
242
 
239
243
  // src/storybook/index.ts
240
244
  import { spawn } from "node:child_process";
241
- import fs4 from "node:fs";
245
+ import fs3 from "node:fs";
242
246
  import path4 from "node:path";
243
247
 
244
248
  // src/storybook/getStorybookBuildCommandParts.ts
@@ -276,27 +280,11 @@ function getStorybookBuildCommandParts(packageJsonPath = path.join(process.cwd()
276
280
  return ["storybook", "build"];
277
281
  }
278
282
 
279
- // src/storybook/getStorybookStoryCount.ts
283
+ // src/storybook/getStorybookVersionFromPackageJson.ts
280
284
  import fs2 from "node:fs";
281
285
  import path2 from "node:path";
282
- async function getStorybookStoryCount(packageDir) {
283
- const indexPath = path2.join(packageDir, "index.json");
284
- try {
285
- const content = await fs2.promises.readFile(indexPath, "utf8");
286
- const data = JSON.parse(content);
287
- const entries = data.entries ?? data.stories ?? {};
288
- return Object.values(entries).filter((e) => e.type === "story").length;
289
- } catch (error) {
290
- console.warn("Failed to get estimated snaps count from Storybook:", error);
291
- return void 0;
292
- }
293
- }
294
-
295
- // src/storybook/getStorybookVersionFromPackageJson.ts
296
- import fs3 from "node:fs";
297
- import path3 from "node:path";
298
- function getStorybookVersionFromPackageJson(packageJsonPath = path3.join(process.cwd(), "package.json")) {
299
- const data = fs3.readFileSync(packageJsonPath, "utf8");
286
+ function getStorybookVersionFromPackageJson(packageJsonPath = path2.join(process.cwd(), "package.json")) {
287
+ const data = fs2.readFileSync(packageJsonPath, "utf8");
300
288
  const packageJson = JSON.parse(data);
301
289
  const combinedDependencies = {
302
290
  ...packageJson.dependencies,
@@ -317,18 +305,55 @@ function getStorybookVersionFromPackageJson(packageJsonPath = path3.join(process
317
305
  }
318
306
  }
319
307
 
320
- // src/storybook/index.ts
321
- var { HAPPO_DEBUG: HAPPO_DEBUG2 } = process.env;
322
- function assertSkippedIsSkipItems(skipped) {
323
- if (!Array.isArray(skipped)) {
324
- throw new TypeError(`The \`skip\` option didn't provide an array`);
308
+ // src/storybook/resolveStoryFileItems.ts
309
+ import path3 from "node:path";
310
+ function resolveStoryFileItems(skip, entries) {
311
+ const fileToComponents = /* @__PURE__ */ new Map();
312
+ for (const entry of Object.values(entries)) {
313
+ if (!entry.importPath || !entry.title) continue;
314
+ const normalized = normalizeImportPath(entry.importPath);
315
+ let set = fileToComponents.get(normalized);
316
+ if (!set) {
317
+ set = /* @__PURE__ */ new Set();
318
+ fileToComponents.set(normalized, set);
319
+ }
320
+ set.add(entry.title);
325
321
  }
326
- if (skipped.some((item) => !item.component || !item.variant)) {
327
- throw new Error(
328
- `Each item provided by the \`skip\` option needs a \`component\` and a \`variant\` property`
329
- );
322
+ const resolved = [];
323
+ for (const item of skip) {
324
+ if ("component" in item) {
325
+ resolved.push(item);
326
+ continue;
327
+ }
328
+ const normalizedFile = normalizeImportPath(item.storyFile);
329
+ let components = fileToComponents.get(normalizedFile);
330
+ if (!components) {
331
+ const resolvedFile = path3.resolve(item.storyFile);
332
+ for (const [normalizedImport, titles] of fileToComponents) {
333
+ if (path3.resolve(normalizedImport) === resolvedFile) {
334
+ components = titles;
335
+ break;
336
+ }
337
+ }
338
+ }
339
+ if (components) {
340
+ for (const component of components) {
341
+ resolved.push({ component });
342
+ }
343
+ } else {
344
+ console.warn(
345
+ `[HAPPO] Could not find any stories for storyFile '${item.storyFile}' in the Storybook index`
346
+ );
347
+ }
330
348
  }
349
+ return resolved;
331
350
  }
351
+ function normalizeImportPath(p) {
352
+ return p.startsWith("./") ? p.slice(2) : p;
353
+ }
354
+
355
+ // src/storybook/index.ts
356
+ var { HAPPO_DEBUG: HAPPO_DEBUG2 } = process.env;
332
357
  function resolveBuildCommandParts() {
333
358
  const version = getStorybookVersionFromPackageJson();
334
359
  if (version < 9) {
@@ -343,7 +368,7 @@ async function buildStorybook({
343
368
  staticDir,
344
369
  outputDir
345
370
  }) {
346
- await fs4.promises.rm(outputDir, { recursive: true, force: true });
371
+ await fs3.promises.rm(outputDir, { recursive: true, force: true });
347
372
  const buildCommandParts = resolveBuildCommandParts();
348
373
  if (!buildCommandParts[0]) {
349
374
  throw new Error("Failed to resolve build command parts");
@@ -358,7 +383,7 @@ async function buildStorybook({
358
383
  if (staticDir) {
359
384
  params.push("--static-dir", staticDir);
360
385
  }
361
- let binary = fs4.existsSync("yarn.lock") ? "yarn" : "npx";
386
+ let binary = fs3.existsSync("yarn.lock") ? "yarn" : "npx";
362
387
  if (buildCommandParts[0].includes("node_modules")) {
363
388
  binary = buildCommandParts[0];
364
389
  params.shift();
@@ -374,7 +399,7 @@ async function buildStorybook({
374
399
  spawned.on("exit", (code) => {
375
400
  if (code === 0) {
376
401
  try {
377
- fs4.unlinkSync(path4.join(outputDir, "project.json"));
402
+ fs3.unlinkSync(path4.join(outputDir, "project.json"));
378
403
  } catch (error) {
379
404
  console.warn(
380
405
  `Ignoring error when attempting to remove project.json: ${error}`
@@ -392,39 +417,91 @@ async function buildStorybookPackage({
392
417
  staticDir,
393
418
  outputDir = ".out",
394
419
  usePrebuiltPackage = false,
395
- skip
420
+ skip,
421
+ only
396
422
  }) {
397
423
  if (!usePrebuiltPackage) {
398
424
  await buildStorybook({ configDir, staticDir, outputDir });
399
425
  }
400
426
  const iframePath = path4.join(outputDir, "iframe.html");
401
- if (!fs4.existsSync(iframePath)) {
427
+ if (!fs3.existsSync(iframePath)) {
402
428
  throw new Error(
403
429
  "Failed to build static storybook package (missing iframe.html)"
404
430
  );
405
431
  }
406
432
  try {
407
- const skipped = typeof skip === "function" ? await skip() : Array.isArray(skip) ? skip : [];
408
- assertSkippedIsSkipItems(skipped);
409
- const iframeContent = await fs4.promises.readFile(iframePath, "utf8");
410
- await fs4.promises.writeFile(
433
+ const iframeContent = await fs3.promises.readFile(iframePath, "utf8");
434
+ let estimatedSnapsCount;
435
+ let resolvedSkip;
436
+ let resolvedOnly;
437
+ const indexPath = path4.join(outputDir, "index.json");
438
+ try {
439
+ const indexContent = await fs3.promises.readFile(indexPath, "utf8");
440
+ const indexData = JSON.parse(indexContent);
441
+ const entries = indexData.entries ?? indexData.stories ?? {};
442
+ const storyEntries = Object.values(entries).filter((e) => e.type === "story");
443
+ estimatedSnapsCount = storyEntries.length;
444
+ if (skip !== void 0) {
445
+ resolvedSkip = resolveStoryFileItems(skip, entries);
446
+ const skipSet = toSkipSet(resolvedSkip);
447
+ estimatedSnapsCount = storyEntries.filter(
448
+ (e) => !isInSkipSet(skipSet, e.title ?? "", e.name ?? "")
449
+ ).length;
450
+ }
451
+ if (only !== void 0) {
452
+ resolvedOnly = resolveStoryFileItems(only, entries).map(
453
+ ({ component }) => ({ component })
454
+ );
455
+ if (resolvedOnly.length === 0) {
456
+ console.warn(
457
+ "[HAPPO] --only: no matching stories found in Storybook index. Generating a full report instead."
458
+ );
459
+ resolvedOnly = void 0;
460
+ } else {
461
+ const onlyComponents = new Set(resolvedOnly.map((item) => item.component));
462
+ estimatedSnapsCount = storyEntries.filter(
463
+ (e) => onlyComponents.has(e.title ?? "")
464
+ ).length;
465
+ const allComponents = /* @__PURE__ */ new Set();
466
+ for (const e of storyEntries) {
467
+ if (e.title) allComponents.add(e.title);
468
+ }
469
+ resolvedSkip = [...allComponents].filter((c) => !onlyComponents.has(c)).map((component) => ({ component }));
470
+ }
471
+ }
472
+ } catch (error) {
473
+ console.warn("[HAPPO] Failed to read Storybook index.json:", error);
474
+ if (skip !== void 0) {
475
+ resolvedSkip = skip.filter(
476
+ (item) => "component" in item
477
+ );
478
+ }
479
+ if (only !== void 0) {
480
+ const componentOnly = only.filter(
481
+ (item) => "component" in item
482
+ );
483
+ resolvedOnly = componentOnly.length > 0 ? componentOnly : void 0;
484
+ }
485
+ }
486
+ await fs3.promises.writeFile(
411
487
  iframePath,
412
488
  iframeContent.replace(
413
489
  "<head>",
414
490
  `<head>
415
491
  <meta name="viewport" content="width=device-width, initial-scale=1">
416
492
  <script type="text/javascript">window.__IS_HAPPO_RUN = true;</script>
417
- <script type="text/javascript">window.happoSkipped = ${JSON.stringify(
418
- skipped
419
- )};</script>
493
+ <script type="text/javascript">window.happoSkipped = ${JSON.stringify(resolvedSkip ?? []).replaceAll(/<\/script>/gi, String.raw`<\/script>`)};</script>
494
+ <script type="text/javascript">window.happoOnly = ${JSON.stringify(resolvedOnly ?? null).replaceAll(/<\/script>/gi, String.raw`<\/script>`)};</script>
420
495
  `
421
496
  )
422
497
  );
423
- const estimatedSnapsCount = await getStorybookStoryCount(outputDir);
424
498
  const result = { packageDir: outputDir };
425
499
  if (estimatedSnapsCount != null) {
426
500
  result.estimatedSnapsCount = estimatedSnapsCount;
427
501
  }
502
+ if (resolvedSkip !== void 0) {
503
+ result.resolvedSkip = resolvedSkip;
504
+ }
428
505
  return result;
429
506
  } catch (e) {
430
507
  console.error(e);
@@ -433,7 +510,7 @@ async function buildStorybookPackage({
433
510
  }
434
511
 
435
512
  // src/utils/deterministicArchive.ts
436
- import fs5 from "node:fs";
513
+ import fs4 from "node:fs";
437
514
  import path5 from "node:path";
438
515
  import { zip } from "fflate";
439
516
 
@@ -469,10 +546,10 @@ function normalizeEntryName(name) {
469
546
  var FILE_CREATION_DATE = new Date(2019, 1, 8, 13, 31, 55);
470
547
  async function resolveFilesRecursiveForDir(dirOrFile) {
471
548
  const resolvedDirOrFile = path5.resolve(dirOrFile);
472
- const isDir = (await fs5.promises.lstat(resolvedDirOrFile)).isDirectory();
549
+ const isDir = (await fs4.promises.lstat(resolvedDirOrFile)).isDirectory();
473
550
  if (isDir) {
474
551
  const fileEntries = [];
475
- for await (const fileType of fs5.promises.glob("**/*", {
552
+ for await (const fileType of fs4.promises.glob("**/*", {
476
553
  cwd: resolvedDirOrFile,
477
554
  withFileTypes: true
478
555
  })) {
@@ -480,7 +557,7 @@ async function resolveFilesRecursiveForDir(dirOrFile) {
480
557
  const fullPath = `${fileType.parentPath}/${fileType.name}`;
481
558
  fileEntries.push({
482
559
  name: normalizeEntryName(path5.relative(resolvedDirOrFile, fullPath)),
483
- stream: fs5.createReadStream(fullPath)
560
+ stream: fs4.createReadStream(fullPath)
484
561
  });
485
562
  }
486
563
  }
@@ -489,7 +566,7 @@ async function resolveFilesRecursiveForDir(dirOrFile) {
489
566
  return [
490
567
  {
491
568
  name: normalizeEntryName(path5.relative(process.cwd(), resolvedDirOrFile)),
492
- stream: fs5.createReadStream(resolvedDirOrFile)
569
+ stream: fs4.createReadStream(resolvedDirOrFile)
493
570
  }
494
571
  ];
495
572
  }
@@ -753,7 +830,7 @@ async function uploadAssets(buffer, options, config) {
753
830
  // src/network/prepareSnapRequests.ts
754
831
  async function fileExists(path7) {
755
832
  try {
756
- await fs6.promises.stat(path7);
833
+ await fs5.promises.stat(path7);
757
834
  return true;
758
835
  } catch (error) {
759
836
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -779,13 +856,29 @@ async function createIframeHTML(rootDir, entryPoint, logger) {
779
856
  <script src="${entryPoint}"></script>
780
857
  </body>
781
858
  </html>`;
782
- await fs6.promises.mkdir(rootDir, { recursive: true });
783
- await fs6.promises.writeFile(iframePath, iframeContent);
859
+ await fs5.promises.mkdir(rootDir, { recursive: true });
860
+ await fs5.promises.writeFile(iframePath, iframeContent);
861
+ }
862
+ async function injectSkippedIntoIframe(iframePath, skipped) {
863
+ const content = await fs5.promises.readFile(iframePath, "utf8");
864
+ const skippedJson = JSON.stringify(skipped).replaceAll(/<\/script>/gi, String.raw`<\/script>`);
865
+ const skippedScript = `<script type="application/json" id="happo-skipped">${skippedJson}</script>`;
866
+ const injected = content.replace(/<head\b[^>]*>/i, (match) => `${match}${skippedScript}`);
867
+ if (injected === content) {
868
+ throw new Error(
869
+ `Failed to inject skipped examples into iframe.html at '${iframePath}': could not find an opening <head> tag`
870
+ );
871
+ }
872
+ await fs5.promises.writeFile(iframePath, injected);
784
873
  }
785
- async function buildPackage({ integration }, logger) {
874
+ async function buildPackage({ integration }, logger, skip, only) {
786
875
  if (integration.type === "custom") {
787
876
  const { rootDir, entryPoint, estimatedSnapsCount } = await integration.build();
788
877
  await createIframeHTML(rootDir, entryPoint, logger);
878
+ if (skip && skip.length > 0) {
879
+ const iframePath = path6.join(rootDir, "iframe.html");
880
+ await injectSkippedIntoIframe(iframePath, skip);
881
+ }
789
882
  const result = { packageDir: rootDir };
790
883
  if (estimatedSnapsCount != null) {
791
884
  result.estimatedSnapsCount = estimatedSnapsCount;
@@ -793,7 +886,12 @@ async function buildPackage({ integration }, logger) {
793
886
  return result;
794
887
  }
795
888
  if (integration.type === "storybook") {
796
- return await buildStorybookPackage(integration);
889
+ const result = await buildStorybookPackage({
890
+ ...integration,
891
+ ...skip === void 0 ? {} : { skip },
892
+ ...only === void 0 ? {} : { only }
893
+ });
894
+ return result;
797
895
  }
798
896
  throw new Error(`Unsupported integration type: ${integration.type}`);
799
897
  }
@@ -805,8 +903,8 @@ async function validatePackage(packageDir) {
805
903
  );
806
904
  }
807
905
  }
808
- async function preparePackage(config, logger) {
809
- const { packageDir, estimatedSnapsCount } = await buildPackage(config, logger);
906
+ async function preparePackage(config, logger, skip, only) {
907
+ const { packageDir, estimatedSnapsCount, resolvedSkip } = await buildPackage(config, logger, skip, only);
810
908
  await validatePackage(packageDir);
811
909
  const { buffer, hash } = await deterministicArchive([packageDir]);
812
910
  const packagePath = await uploadAssets(
@@ -821,18 +919,21 @@ async function preparePackage(config, logger) {
821
919
  if (estimatedSnapsCount != null) {
822
920
  result.estimatedSnapsCount = estimatedSnapsCount;
823
921
  }
922
+ if (resolvedSkip !== void 0) {
923
+ result.resolvedSkip = resolvedSkip;
924
+ }
824
925
  return result;
825
926
  }
826
- async function prepareSnapRequests(config) {
927
+ async function prepareSnapRequests(config, skip, only) {
827
928
  const logger = new Logger();
828
- const prepareResult = config.integration.type === "pages" ? null : await preparePackage(config, logger);
929
+ const prepareResult = config.integration.type === "pages" ? null : await preparePackage(config, logger, skip, only);
829
930
  const targetNames = Object.keys(config.targets);
830
931
  const tl = targetNames.length;
831
932
  logger.info(
832
933
  `${logTag(config.project)}Generating screenshots in ${tl} target${tl > 1 ? "s" : ""}...`
833
934
  );
834
935
  const outerStartTime = Date.now();
835
- const results = [];
936
+ const snapRequestIds = [];
836
937
  await Promise.all(
837
938
  targetNames.map(async (name) => {
838
939
  const startTime = Date.now();
@@ -855,17 +956,21 @@ async function prepareSnapRequests(config) {
855
956
  if (config.integration.type === "pages") {
856
957
  targetParams.pages = config.integration.pages;
857
958
  }
858
- const snapRequestIds = await target.execute(targetParams, config);
959
+ const ids = await target.execute(targetParams, config);
859
960
  logger.start(` - ${logTag(config.project)}${name}`, { startTime });
860
961
  logger.success();
861
- results.push(...snapRequestIds);
962
+ snapRequestIds.push(...ids);
862
963
  })
863
964
  );
864
965
  logger.start(void 0, { startTime: outerStartTime });
865
966
  logger.success();
866
- return results;
967
+ const result = { snapRequestIds };
968
+ if (prepareResult?.resolvedSkip !== void 0) {
969
+ result.resolvedSkip = prepareResult.resolvedSkip;
970
+ }
971
+ return result;
867
972
  }
868
973
  export {
869
974
  prepareSnapRequests as default
870
975
  };
871
- //# sourceMappingURL=prepareSnapRequests-2LHSGFZV.js.map
976
+ //# sourceMappingURL=prepareSnapRequests-WBXFGB4B.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/network/prepareSnapRequests.ts", "../../src/utils/createHash.ts", "../../src/config/RemoteBrowserTarget.ts", "../../src/storybook/index.ts", "../../src/storybook/getStorybookBuildCommandParts.ts", "../../src/storybook/getStorybookVersionFromPackageJson.ts", "../../src/storybook/resolveStoryFileItems.ts", "../../src/utils/deterministicArchive.ts", "../../src/utils/validateArchive.ts", "../../src/utils/Logger.ts", "../../src/network/uploadAssets.ts"],
4
+ "sourcesContent": ["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport RemoteBrowserTarget, {\n type ExecuteParams,\n} from '../config/RemoteBrowserTarget.ts';\nimport type { OnlyItem, SkipItem } from '../isomorphic/types.ts';\nimport buildStorybookPackage from '../storybook/index.ts';\nimport deterministicArchive from '../utils/deterministicArchive.ts';\nimport Logger, { logTag } from '../utils/Logger.ts';\nimport uploadAssets from './uploadAssets.ts';\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await fs.promises.stat(path);\n return true;\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n return false;\n }\n\n throw error;\n }\n}\n\nasync function createIframeHTML(\n rootDir: string,\n entryPoint: string,\n logger: Logger,\n): Promise<void> {\n const iframePath = path.join(rootDir, 'iframe.html');\n\n if (await fileExists(iframePath)) {\n logger.info(`Using existing iframe.html at '${iframePath}'`);\n return;\n }\n\n const iframeContent = `<!DOCTYPE html>\n<html lang=\"en\" dir=\"ltr\">\n <head>\n <title>Happo</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n </head>\n <body>\n <script src=\"${entryPoint}\"></script>\n </body>\n</html>`;\n\n await fs.promises.mkdir(rootDir, { recursive: true });\n await fs.promises.writeFile(iframePath, iframeContent);\n}\n\ninterface BuildPackageResult {\n packageDir: string;\n estimatedSnapsCount?: number;\n resolvedSkip?: Array<{ component: string; variant?: string }>;\n}\n\nasync function injectSkippedIntoIframe(\n iframePath: string,\n skipped: Array<SkipItem>,\n): Promise<void> {\n const content = await fs.promises.readFile(iframePath, 'utf8');\n const skippedJson = JSON.stringify(skipped).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`);\n const skippedScript = `<script type=\"application/json\" id=\"happo-skipped\">${skippedJson}</script>`;\n const injected = content.replace(/<head\\b[^>]*>/i, (match) => `${match}${skippedScript}`);\n if (injected === content) {\n throw new Error(\n `Failed to inject skipped examples into iframe.html at '${iframePath}': could not find an opening <head> tag`,\n );\n }\n await fs.promises.writeFile(iframePath, injected);\n}\n\nasync function buildPackage(\n { integration }: ConfigWithDefaults,\n logger: Logger,\n skip?: Array<SkipItem>,\n only?: Array<OnlyItem>,\n): Promise<BuildPackageResult> {\n if (integration.type === 'custom') {\n const { rootDir, entryPoint, estimatedSnapsCount } = await integration.build();\n await createIframeHTML(rootDir, entryPoint, logger);\n\n if (skip && skip.length > 0) {\n const iframePath = path.join(rootDir, 'iframe.html');\n await injectSkippedIntoIframe(iframePath, skip);\n }\n\n const result: BuildPackageResult = { packageDir: rootDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n return result;\n }\n\n if (integration.type === 'storybook') {\n const result = await buildStorybookPackage({\n ...integration,\n ...(skip === undefined ? {} : { skip }),\n ...(only === undefined ? {} : { only }),\n });\n return result;\n }\n\n throw new Error(`Unsupported integration type: ${integration.type}`);\n}\n\nasync function validatePackage(packageDir: string): Promise<void> {\n const iframePath = path.join(packageDir, 'iframe.html');\n\n if (!(await fileExists(iframePath))) {\n throw new Error(\n `Could not find iframe.html in static package at '${iframePath}'`,\n );\n }\n}\n\ninterface PreparePackageResult {\n packagePath: string;\n estimatedSnapsCount?: number;\n resolvedSkip?: Array<{ component: string; variant?: string }>;\n}\n\nasync function preparePackage(\n config: ConfigWithDefaults,\n logger: Logger,\n skip?: Array<SkipItem>,\n only?: Array<OnlyItem>,\n): Promise<PreparePackageResult> {\n const { packageDir, estimatedSnapsCount, resolvedSkip } = await buildPackage(config, logger, skip, only);\n\n await validatePackage(packageDir);\n\n const { buffer, hash } = await deterministicArchive([packageDir]);\n const packagePath = await uploadAssets(\n buffer,\n {\n hash,\n logger,\n },\n config,\n );\n\n const result: PreparePackageResult = { packagePath };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n if (resolvedSkip !== undefined) {\n result.resolvedSkip = resolvedSkip;\n }\n return result;\n}\n\nexport interface PrepareSnapRequestsResult {\n snapRequestIds: Array<number>;\n resolvedSkip?: Array<{ component: string; variant?: string }>;\n}\n\nexport default async function prepareSnapRequests(\n config: ConfigWithDefaults,\n skip?: Array<SkipItem>,\n only?: Array<OnlyItem>,\n): Promise<PrepareSnapRequestsResult> {\n const logger = new Logger();\n const prepareResult =\n config.integration.type === 'pages'\n ? null\n : await preparePackage(config, logger, skip, only);\n\n const targetNames = Object.keys(config.targets);\n const tl = targetNames.length;\n logger.info(\n `${logTag(config.project)}Generating screenshots in ${tl} target${\n tl > 1 ? 's' : ''\n }...`,\n );\n const outerStartTime = Date.now();\n const snapRequestIds: Array<number> = [];\n await Promise.all(\n targetNames.map(async (name) => {\n const startTime = Date.now();\n\n if (!config.targets[name]) {\n throw new Error(`Target ${name} not found in config`);\n }\n\n const target = new RemoteBrowserTarget(\n config.targets[name].type,\n config.targets[name],\n );\n\n const targetParams: ExecuteParams = {\n targetName: name,\n };\n\n if (prepareResult) {\n targetParams.staticPackage = prepareResult.packagePath;\n\n if (prepareResult.estimatedSnapsCount != null) {\n targetParams.estimatedSnapsCount = prepareResult.estimatedSnapsCount;\n }\n }\n\n if (config.integration.type === 'pages') {\n targetParams.pages = config.integration.pages;\n }\n\n const ids = await target.execute(targetParams, config);\n logger.start(` - ${logTag(config.project)}${name}`, { startTime });\n logger.success();\n snapRequestIds.push(...ids);\n }),\n );\n logger.start(undefined, { startTime: outerStartTime });\n logger.success();\n const result: PrepareSnapRequestsResult = { snapRequestIds };\n if (prepareResult?.resolvedSkip !== undefined) {\n result.resolvedSkip = prepareResult.resolvedSkip;\n }\n return result;\n}\n", "import crypto from 'node:crypto';\n\n/**\n * Creates an MD5 hash of the input data\n * @param data - The data to hash (string, Buffer, or TypedArray)\n * @returns The MD5 hash as a hexadecimal string\n */\nexport default function createHash(\n data: string | Buffer | NodeJS.TypedArray,\n): string {\n return crypto.createHash('md5').update(data).digest('hex');\n}\n", "import { ErrorWithStatusCode } from '../network/fetchWithRetry.ts';\nimport makeHappoAPIRequest from '../network/makeHappoAPIRequest.ts';\nimport createHash from '../utils/createHash.ts';\nimport type {\n BrowserType,\n ConfigWithDefaults,\n Page,\n TargetWithDefaults,\n} from './index.ts';\n\nconst VIEWPORT_PATTERN = /^([0-9]+)x([0-9]+)$/;\n\n/**\n * Maximum number of chunk items sent in a single bulk request.\n * Keeps individual payloads bounded while still protecting against\n * arbitrarily large explicit `chunks` values exceeding server limits.\n */\nconst MAX_BULK_ITEMS_PER_REQUEST = 50;\n\n/**\n * Compute the number of chunks to use based on an estimated snapshot count.\n *\n * Aims for roughly 100 items per chunk, capped at 20. Returns 1 for\n * non-positive or non-finite inputs.\n */\nfunction computeDefaultChunks(estimatedSnapCount: number): number {\n if (!Number.isFinite(estimatedSnapCount) || estimatedSnapCount <= 0) {\n return 1;\n }\n\n return Math.min(20, Math.ceil(estimatedSnapCount / 100));\n}\n\n/**\n * PageSlice is an array of pages with the extra extendsSha property.\n */\ninterface PageSlice extends Array<Page> {\n extendsSha?: string;\n}\n\ninterface Chunk {\n index: number;\n total: number;\n}\n\ninterface ChunkItem {\n type: string;\n targetName: string | undefined;\n payloadString: string;\n payloadHash: string;\n extendsSha?: string;\n}\n\nexport interface CSSBlock {\n id: string;\n conditional: boolean;\n css: string;\n}\n\nexport interface ExecuteParams {\n globalCSS?: string | Array<CSSBlock>;\n\n /** Path to the assets package */\n assetsPackage?: string;\n\n /** Path to the static package */\n staticPackage?: string;\n\n snapPayloads?: Array<unknown>;\n pages?: Array<Page>;\n targetName?: string;\n\n /**\n * Total number of snapshots in the package. When provided for staticPackage\n * requests without explicit chunks, used to automatically determine the\n * optimal number of parallel chunks.\n */\n estimatedSnapsCount?: number;\n}\n\nfunction getPageSlices(pages: Array<Page>, chunks: number): Array<PageSlice> {\n const result: Array<PageSlice> = [];\n\n // First, split the raw pages into chunks\n const pagesPerChunk = Math.ceil(pages.length / chunks);\n for (let i = 0; i < chunks; i += 1) {\n const pageSlice = pages.slice(\n i * pagesPerChunk,\n i * pagesPerChunk + pagesPerChunk,\n );\n\n if (pageSlice.length > 0) {\n result.push(pageSlice);\n }\n }\n return result;\n}\n\nfunction buildChunkItem({\n slice,\n chunk,\n pageSlice,\n browserName,\n viewport,\n maxHeight,\n otherOptions,\n globalCSS,\n staticPackage,\n assetsPackage,\n targetName,\n}: {\n slice?: Array<unknown> | undefined;\n chunk?: Chunk | undefined;\n pageSlice?: PageSlice | undefined;\n browserName: BrowserType;\n viewport: string;\n maxHeight: number | undefined;\n otherOptions: Record<string, unknown>;\n globalCSS: string | Array<CSSBlock> | undefined;\n staticPackage: string | undefined;\n assetsPackage: string | undefined;\n targetName: string | undefined;\n}): ChunkItem {\n const payloadString = JSON.stringify({\n viewport,\n maxHeight,\n ...otherOptions,\n globalCSS,\n snapPayloads: slice,\n chunk,\n staticPackage,\n assetsPackage,\n pages: pageSlice,\n extendsSha: pageSlice ? pageSlice.extendsSha : undefined,\n });\n\n const payloadHash = createHash(payloadString + (pageSlice ? Math.random() : ''));\n\n const type =\n pageSlice && pageSlice.extendsSha ? 'extends-report' : `browser-${browserName}`;\n\n const item: ChunkItem = { type, targetName, payloadString, payloadHash };\n if (pageSlice?.extendsSha) {\n item.extendsSha = pageSlice.extendsSha;\n }\n return item;\n}\n\nasync function sendIndividualSnapRequest(\n item: ChunkItem,\n config: ConfigWithDefaults,\n): Promise<number> {\n const formData: Record<string, string | number | File | undefined> = {\n type: item.type,\n targetName: item.targetName,\n payloadHash: item.payloadHash,\n payload: new File([item.payloadString], 'payload.json', {\n type: 'application/json',\n }),\n };\n\n if (item.extendsSha) {\n formData.extendsSha = item.extendsSha;\n }\n\n // We `await` here inside the loop to avoid POSTing all payloads to the\n // server at the same time (thus reducing load a little).\n const requestResult = await makeHappoAPIRequest(\n {\n path: `/api/snap-requests?payloadHash=${item.payloadHash}`,\n method: 'POST',\n formData,\n },\n config,\n { retryCount: 5 },\n );\n\n if (!requestResult) {\n throw new Error('No requestResult');\n }\n\n if (!('requestId' in requestResult)) {\n throw new Error('No requestId in requestResult');\n }\n\n if (typeof requestResult.requestId !== 'number') {\n throw new TypeError('requestId is not a number');\n }\n\n return requestResult.requestId;\n}\n\nexport default class RemoteBrowserTarget {\n public readonly chunks: number | undefined;\n public readonly browserName: BrowserType;\n public readonly viewport: string;\n public readonly maxHeight: number | undefined;\n public readonly otherOptions: Record<string, unknown>;\n\n constructor(\n browserName: BrowserType,\n {\n viewport = '1024x768',\n chunks,\n maxHeight,\n ...otherOptions\n }: TargetWithDefaults,\n ) {\n if (!browserName) {\n throw new Error(\n `Invalid browser type: \"${browserName}\". Make sure the \"type\" field in your target configuration is set to a valid browser type.`,\n );\n }\n\n const viewportMatch = viewport.match(VIEWPORT_PATTERN);\n if (!viewportMatch) {\n throw new Error(\n `Invalid viewport \"${viewport}\". Here's an example of a valid one: \"1024x768\".`,\n );\n }\n\n this.chunks = chunks;\n this.browserName = browserName;\n this.viewport = viewport;\n this.maxHeight = maxHeight ?? undefined;\n this.otherOptions = otherOptions;\n }\n\n async execute(\n {\n globalCSS,\n assetsPackage,\n staticPackage,\n snapPayloads,\n pages,\n targetName,\n estimatedSnapsCount,\n }: ExecuteParams,\n config: ConfigWithDefaults,\n ): Promise<Array<number>> {\n const buildItemParams = {\n browserName: this.browserName,\n viewport: this.viewport,\n maxHeight: this.maxHeight,\n otherOptions: this.otherOptions,\n globalCSS,\n staticPackage,\n assetsPackage,\n targetName,\n };\n\n // Build all chunk items up front\n const items: Array<ChunkItem> = [];\n\n if (staticPackage) {\n const effectiveChunks =\n this.chunks ?? Math.max(1, computeDefaultChunks(estimatedSnapsCount ?? 0));\n for (let i = 0; i < effectiveChunks; i += 1) {\n items.push(\n buildChunkItem({\n ...buildItemParams,\n chunk:\n effectiveChunks > 1 ? { index: i, total: effectiveChunks } : undefined,\n }),\n );\n }\n } else if (pages) {\n for (const pageSlice of getPageSlices(pages, this.chunks ?? 1)) {\n items.push(buildChunkItem({ ...buildItemParams, pageSlice }));\n }\n } else {\n const effectiveChunks = this.chunks ?? 1;\n const snapsPerChunk = Math.ceil((snapPayloads?.length ?? 0) / effectiveChunks);\n for (let i = 0; i < effectiveChunks; i += 1) {\n const slice = snapPayloads?.slice(\n i * snapsPerChunk,\n i * snapsPerChunk + snapsPerChunk,\n );\n items.push(buildChunkItem({ ...buildItemParams, slice }));\n }\n }\n\n if (items.length === 0) {\n return [];\n }\n\n // Try the bulk endpoint first. If it is unavailable, fall back to individual\n // requests. If it responds with an unexpected payload shape, fail fast to\n // avoid creating duplicate snap-requests.\n //\n // Large item arrays are split into batches of MAX_BULK_ITEMS_PER_REQUEST\n // and sent as sequential bulk requests to keep individual payloads bounded.\n try {\n const requestIds: Array<number | undefined> = Array.from({\n length: items.length,\n });\n\n for (\n let batchStart = 0;\n batchStart < items.length;\n batchStart += MAX_BULK_ITEMS_PER_REQUEST\n ) {\n const batch = items.slice(\n batchStart,\n batchStart + MAX_BULK_ITEMS_PER_REQUEST,\n );\n\n const result = await makeHappoAPIRequest(\n {\n path: '/api/snap-requests/bulk',\n method: 'POST',\n body: { items: batch },\n },\n config,\n { retryCount: 5 },\n );\n\n if (\n result &&\n 'results' in result &&\n Array.isArray(result.results) &&\n result.results.length === batch.length\n ) {\n const bulkResults = result.results as Array<{\n requestId?: number;\n error?: string;\n }>;\n\n for (const [i, r] of bulkResults.entries()) {\n requestIds[batchStart + i] =\n typeof r.requestId === 'number' ? r.requestId : undefined;\n }\n } else {\n // The bulk endpoint responded with a 200 but an unexpected payload\n // shape. Fail fast instead of falling back to avoid potentially\n // creating duplicate snap-requests.\n throw new Error(\n 'Bulk snap-requests endpoint returned an unexpected payload shape; aborting to avoid duplicate snap-requests.',\n );\n }\n }\n\n // Retry any failed items individually (sequentially to reduce load)\n for (const [i, item] of items.entries()) {\n if (requestIds[i] === undefined) {\n requestIds[i] = await sendIndividualSnapRequest(item, config);\n }\n }\n\n return requestIds.map((id, index) => {\n if (id === undefined) {\n throw new Error(\n `Failed to obtain snap request ID for item at index ${index}`,\n );\n }\n\n return id;\n });\n } catch (error) {\n // Fall back to individual requests only when the server explicitly\n // reports that the bulk endpoint is missing or not implemented.\n if (\n !(\n error instanceof ErrorWithStatusCode &&\n (error.statusCode === 404 || error.statusCode === 501)\n )\n ) {\n throw error;\n }\n }\n\n // Fallback: sequential individual requests (for older happo deployments)\n const requestIds: Array<number> = [];\n\n for (const item of items) {\n requestIds.push(await sendIndividualSnapRequest(item, config));\n }\n\n return requestIds;\n }\n}\n", "import { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { StorybookIntegration } from '../config/index.ts';\nimport { isInSkipSet, toSkipSet } from '../isomorphic/parseSkip.ts';\nimport type { OnlyItem, SkipItem } from '../isomorphic/types.ts';\nimport getStorybookBuildCommandParts from './getStorybookBuildCommandParts.ts';\nimport getStorybookVersionFromPackageJson from './getStorybookVersionFromPackageJson.ts';\nimport resolveStoryFileItems, { type StorybookIndexEntry } from './resolveStoryFileItems.ts';\n\nconst { HAPPO_DEBUG } = process.env;\n\nfunction resolveBuildCommandParts() {\n const version = getStorybookVersionFromPackageJson();\n\n if (version < 9) {\n throw new Error(\n `Storybook v${version} is not supported. Please update storybook to v9 or later.`,\n );\n }\n\n return getStorybookBuildCommandParts();\n}\n\nasync function buildStorybook({\n configDir,\n staticDir,\n outputDir,\n}: {\n configDir: string;\n staticDir?: string | undefined;\n outputDir: string;\n}): Promise<void> {\n await fs.promises.rm(outputDir, { recursive: true, force: true });\n\n const buildCommandParts = resolveBuildCommandParts();\n\n if (!buildCommandParts[0]) {\n throw new Error('Failed to resolve build command parts');\n }\n\n const params = [\n ...buildCommandParts,\n '--output-dir',\n outputDir,\n '--config-dir',\n configDir,\n ];\n\n if (staticDir) {\n params.push('--static-dir', staticDir);\n }\n\n let binary = fs.existsSync('yarn.lock') ? 'yarn' : 'npx';\n\n if (buildCommandParts[0].includes('node_modules')) {\n binary = buildCommandParts[0];\n params.shift(); // remove binary from params\n }\n\n if (HAPPO_DEBUG) {\n console.log(`[happo] Using build command \\`${binary} ${params.join(' ')}\\``);\n }\n\n return new Promise((resolve, reject) => {\n const spawned = spawn(binary, params, {\n stdio: 'inherit',\n shell: process.platform == 'win32',\n });\n\n spawned.on('exit', (code) => {\n if (code === 0) {\n try {\n fs.unlinkSync(path.join(outputDir, 'project.json'));\n } catch (error) {\n console.warn(\n `Ignoring error when attempting to remove project.json: ${error}`,\n );\n }\n resolve();\n } else {\n reject(new Error('Failed to build static storybook package'));\n }\n });\n });\n}\n\nexport interface BuildStorybookPackageResult {\n packageDir: string;\n estimatedSnapsCount?: number;\n resolvedSkip?: Array<{ component: string; variant?: string }>;\n}\n\nexport default async function buildStorybookPackage({\n configDir = '.storybook',\n staticDir,\n outputDir = '.out',\n usePrebuiltPackage = false,\n skip,\n only,\n}: Omit<StorybookIntegration, 'type'> & {\n skip?: Array<SkipItem>;\n only?: Array<OnlyItem>;\n}): Promise<BuildStorybookPackageResult> {\n if (!usePrebuiltPackage) {\n await buildStorybook({ configDir, staticDir, outputDir });\n }\n\n const iframePath = path.join(outputDir, 'iframe.html');\n if (!fs.existsSync(iframePath)) {\n throw new Error(\n 'Failed to build static storybook package (missing iframe.html)',\n );\n }\n\n try {\n const iframeContent = await fs.promises.readFile(iframePath, 'utf8');\n\n // Read index.json once to compute story count and resolve storyFile items.\n let estimatedSnapsCount: number | undefined;\n let resolvedSkip: Array<{ component: string; variant?: string }> | undefined;\n let resolvedOnly: Array<{ component: string }> | undefined;\n\n const indexPath = path.join(outputDir, 'index.json');\n try {\n const indexContent = await fs.promises.readFile(indexPath, 'utf8');\n const indexData = JSON.parse(indexContent) as {\n entries?: Record<string, StorybookIndexEntry>;\n stories?: Record<string, StorybookIndexEntry>;\n };\n const entries = indexData.entries ?? indexData.stories ?? {};\n\n const storyEntries = Object.values(entries).filter((e) => e.type === 'story');\n estimatedSnapsCount = storyEntries.length;\n\n if (skip !== undefined) {\n resolvedSkip = resolveStoryFileItems(skip, entries);\n // Adjust the count so auto-chunking reflects only the stories that\n // will actually be rendered (skipped examples don't need a chunk slot).\n const skipSet = toSkipSet(resolvedSkip);\n estimatedSnapsCount = storyEntries.filter(\n (e) => !isInSkipSet(skipSet, e.title ?? '', e.name ?? ''),\n ).length;\n }\n\n if (only !== undefined) {\n resolvedOnly = resolveStoryFileItems(only as Array<SkipItem>, entries).map(\n ({ component }) => ({ component }),\n );\n if (resolvedOnly.length === 0) {\n console.warn(\n '[HAPPO] --only: no matching stories found in Storybook index. Generating a full report instead.',\n );\n resolvedOnly = undefined;\n } else {\n // Adjust the count so auto-chunking reflects only the stories that\n // will actually be rendered (only matching examples need a chunk slot).\n const onlyComponents = new Set(resolvedOnly.map((item) => item.component));\n estimatedSnapsCount = storyEntries.filter((e) =>\n onlyComponents.has(e.title ?? ''),\n ).length;\n\n // Compute the complement: all components NOT in the only list.\n // These will be borrowed from the baseline via an extends-report.\n const allComponents = new Set<string>();\n for (const e of storyEntries) {\n if (e.title) allComponents.add(e.title);\n }\n resolvedSkip = [...allComponents]\n .filter((c) => !onlyComponents.has(c))\n .map((component) => ({ component }));\n }\n }\n } catch (error) {\n console.warn('[HAPPO] Failed to read Storybook index.json:', error);\n if (skip !== undefined) {\n // Fall back to passing through only component-based items\n resolvedSkip = skip.filter(\n (item): item is { component: string; variant?: string } => 'component' in item,\n );\n }\n if (only !== undefined) {\n // Fall back to component-only items; if none remain, leave resolvedOnly\n // undefined so the browser-side filtering is disabled and a full report\n // is generated rather than an empty one.\n const componentOnly = only.filter(\n (item): item is { component: string } => 'component' in item,\n );\n resolvedOnly = componentOnly.length > 0 ? componentOnly : undefined;\n }\n }\n\n await fs.promises.writeFile(\n iframePath,\n iframeContent.replace(\n '<head>',\n `<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script type=\"text/javascript\">window.__IS_HAPPO_RUN = true;</script>\n <script type=\"text/javascript\">window.happoSkipped = ${JSON.stringify(resolvedSkip ?? []).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`)};</script>\n <script type=\"text/javascript\">window.happoOnly = ${JSON.stringify(resolvedOnly ?? null).replaceAll(/<\\/script>/gi, String.raw`<\\/script>`)};</script>\n `,\n ),\n );\n\n const result: BuildStorybookPackageResult = { packageDir: outputDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n if (resolvedSkip !== undefined) {\n result.resolvedSkip = resolvedSkip;\n }\n return result;\n } catch (e) {\n console.error(e);\n throw e;\n }\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\nconst { HAPPO_DEBUG } = process.env;\n\nexport default function getStorybookBuildCommandParts(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): [string, string] {\n try {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n if (packageJson.scripts.storybook) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Found `storybook` script in package.json. Will attempt to use binary found at `node_modules/.bin/storybook` instead',\n );\n }\n\n const pathToStorybookCommand = path.join(\n process.cwd(),\n 'node_modules',\n '.bin',\n 'storybook',\n );\n\n if (fs.existsSync(pathToStorybookCommand)) {\n return [pathToStorybookCommand, 'build'];\n }\n }\n } catch (e) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Caught error when resolving Storybook build command parts. Will use default.',\n e,\n );\n }\n }\n\n return ['storybook', 'build'];\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\nexport default function getStorybookVersionFromPackageJson(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): number {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n const combinedDependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const storybookPackage = [\n 'storybook',\n '@storybook/react',\n '@storybook/angular',\n '@storybook/vue',\n ].find((pkg) => combinedDependencies[pkg]);\n\n if (storybookPackage) {\n const storybookVersion = combinedDependencies[storybookPackage];\n const majorVersion = Number.parseInt(storybookVersion.match(/\\d+/)[0], 10);\n return majorVersion;\n } else {\n throw new Error('Storybook is not listed as a dependency in package.json');\n }\n}\n", "import path from 'node:path';\n\nimport type { SkipItem } from '../isomorphic/types.ts';\n\nexport interface StorybookIndexEntry {\n type: string;\n importPath?: string;\n title?: string;\n name?: string;\n}\n\n/**\n * Resolves `storyFile` skip items to component-based skip items using the\n * Storybook `index.json` entries. Items that already have a `component` are\n * passed through unchanged.\n *\n * Path matching is done by normalising both the `importPath` from the index\n * and the user-supplied `storyFile` (stripping a leading `./`), with an\n * absolute-path fallback via `path.resolve`.\n */\nexport default function resolveStoryFileItems(\n skip: Array<SkipItem>,\n entries: Record<string, StorybookIndexEntry>,\n): Array<{ component: string; variant?: string }> {\n const fileToComponents = new Map<string, Set<string>>();\n for (const entry of Object.values(entries)) {\n if (!entry.importPath || !entry.title) continue;\n const normalized = normalizeImportPath(entry.importPath);\n let set = fileToComponents.get(normalized);\n if (!set) {\n set = new Set();\n fileToComponents.set(normalized, set);\n }\n set.add(entry.title);\n }\n\n const resolved: Array<{ component: string; variant?: string }> = [];\n\n for (const item of skip) {\n if ('component' in item) {\n resolved.push(item);\n continue;\n }\n\n const normalizedFile = normalizeImportPath(item.storyFile);\n let components = fileToComponents.get(normalizedFile);\n\n if (!components) {\n // Fall back to absolute path comparison\n const resolvedFile = path.resolve(item.storyFile);\n for (const [normalizedImport, titles] of fileToComponents) {\n if (path.resolve(normalizedImport) === resolvedFile) {\n components = titles;\n break;\n }\n }\n }\n\n if (components) {\n for (const component of components) {\n resolved.push({ component });\n }\n } else {\n console.warn(\n `[HAPPO] Could not find any stories for storyFile '${item.storyFile}' in the Storybook index`,\n );\n }\n }\n\n return resolved;\n}\n\nfunction normalizeImportPath(p: string): string {\n return p.startsWith('./') ? p.slice(2) : p;\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\n\nimport type { Zippable } from 'fflate';\nimport { zip } from 'fflate';\n\nimport createHash from './createHash.ts';\nimport validateArchive from './validateArchive.ts';\n\n// Normalize path separators to forward slashes for cross-platform consistency.\n// path.relative() returns backslashes on Windows; callers may also pass names\n// built with path.join() on Windows.\nfunction normalizeEntryName(name: string): string {\n return name.replaceAll('\\\\', '/');\n}\n\n// We're setting the creation date to the same for all files so that the zip\n// packages created for the same content ends up having the same fingerprint.\n// https://github.com/101arrowz/fflate/issues/219#issuecomment-2333945868\nconst FILE_CREATION_DATE = new Date(2019, 1, 8, 13, 31, 55);\n\n// Type definitions\ninterface FileEntry {\n name: string;\n stream: fs.ReadStream;\n}\n\nexport interface ArchiveContentEntry {\n name: string;\n content: string | Buffer | fs.ReadStream | Readable;\n}\n\ninterface ArchiveResult {\n buffer: Buffer<ArrayBuffer>;\n hash: string;\n}\n\ninterface ArchiveEntry {\n name: string;\n size: number;\n}\n\n/**\n * Resolves all files in a directory and all of its subdirectories\n *\n * @param dirOrFile - The directory or file path to resolve\n * @returns Promise resolving to an array of file entries\n */\nasync function resolveFilesRecursiveForDir(\n dirOrFile: string,\n): Promise<Array<FileEntry>> {\n const resolvedDirOrFile = path.resolve(dirOrFile);\n const isDir = (await fs.promises.lstat(resolvedDirOrFile)).isDirectory();\n\n if (isDir) {\n const fileEntries: Array<FileEntry> = [];\n\n for await (const fileType of fs.promises.glob('**/*', {\n cwd: resolvedDirOrFile,\n withFileTypes: true,\n })) {\n // Check if it's a file (not a directory)\n if (fileType.isFile()) {\n const fullPath = `${fileType.parentPath}/${fileType.name}`;\n\n fileEntries.push({\n name: normalizeEntryName(path.relative(resolvedDirOrFile, fullPath)),\n stream: fs.createReadStream(fullPath),\n });\n }\n }\n\n return fileEntries;\n }\n\n return [\n {\n name: normalizeEntryName(path.relative(process.cwd(), resolvedDirOrFile)),\n stream: fs.createReadStream(resolvedDirOrFile),\n },\n ];\n}\n\n/**\n * Resolves all files in all directories recursively\n *\n * @param dirsAndFiles - Variable number of directory and file paths\n * @returns Promise resolving to a flattened array of file entries\n */\nasync function resolveFilesRecursive(\n ...dirsAndFiles: Array<string>\n): Promise<Array<FileEntry>> {\n const files = await Promise.all(\n dirsAndFiles.map((dirOrFile) => resolveFilesRecursiveForDir(dirOrFile)),\n );\n\n return files.flat();\n}\n\n/**\n * Converts a stream to a Uint8Array\n */\nasync function streamToUint8Array(\n stream: fs.ReadStream | Readable,\n): Promise<Uint8Array> {\n const chunks: Array<Uint8Array> = [];\n for await (const chunk of stream) {\n chunks.push(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk));\n }\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n}\n\n/**\n * Converts content to Uint8Array\n */\nasync function contentToUint8Array(\n content: string | Buffer | fs.ReadStream | Readable,\n): Promise<Uint8Array> {\n if (typeof content === 'string') {\n return new TextEncoder().encode(content);\n }\n if (Buffer.isBuffer(content)) {\n return new Uint8Array(content);\n }\n return streamToUint8Array(content);\n}\n\n/**\n * Creates a deterministic archive of the given files\n *\n * @param dirsAndFiles - Array of directory and file paths to include\n * @param contentToArchive - Array of content entries to include in the archive\n * @returns Promise resolving to archive result with buffer and hash\n */\nexport default async function deterministicArchive(\n dirsAndFiles: Array<string>,\n contentToArchive: Array<ArchiveContentEntry> = [],\n): Promise<ArchiveResult> {\n const uniqueDirsAndFiles = Array.from(new Set(dirsAndFiles));\n\n // Sort by name to make the output deterministic\n // Use simple string comparison instead of localeCompare for cross-platform determinism\n const filesToArchiveSorted = (\n await resolveFilesRecursive(...uniqueDirsAndFiles)\n ).toSorted((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n\n const contentToArchiveSorted = contentToArchive.toSorted((a, b) =>\n a.name < b.name ? -1 : a.name > b.name ? 1 : 0,\n );\n\n const seenFiles = new Set<string>();\n const entries: Array<ArchiveEntry> = [];\n\n // Collect all entries with their data first\n interface EntryData {\n name: string;\n data: Uint8Array;\n }\n\n const entryDataList: Array<EntryData> = [];\n\n // Process files from disk\n for (const file of filesToArchiveSorted) {\n if (!seenFiles.has(file.name)) {\n const data = await streamToUint8Array(file.stream);\n entryDataList.push({ name: file.name, data });\n entries.push({ name: file.name, size: data.length });\n seenFiles.add(file.name);\n }\n }\n\n // Process in-memory content\n // Extract basename to match archiver's behavior with prefix: '' for content entries\n for (const file of contentToArchiveSorted) {\n const normalizedName = normalizeEntryName(file.name);\n if (!seenFiles.has(normalizedName)) {\n const data = await contentToUint8Array(file.content);\n entryDataList.push({ name: normalizedName, data });\n entries.push({ name: normalizedName, size: data.length });\n seenFiles.add(normalizedName);\n }\n }\n\n // Sort all entries by name to ensure deterministic order\n // Use simple string comparison instead of localeCompare for cross-platform determinism\n entryDataList.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n\n // Build zipData object in sorted order to ensure deterministic zip creation\n const zipData: Zippable = {};\n for (const entry of entryDataList) {\n zipData[entry.name] = [\n entry.data,\n {\n mtime: FILE_CREATION_DATE,\n level: 6,\n },\n ];\n }\n\n const zipBuffer = await new Promise<Uint8Array>((resolve, reject) => {\n zip(zipData, { level: 6 }, (err, data) => {\n if (err) {\n reject(err);\n } else {\n resolve(data);\n }\n });\n });\n const buffer = Buffer.from(zipBuffer);\n validateArchive(buffer.length, entries);\n const hash = createHash(buffer);\n\n return { buffer, hash };\n}\n", "/**\n * Validates that the archive was created successfully\n * @param totalBytes - The total bytes in the archive\n * @param entries - Array of archive entries\n */\nexport default function validateArchive(\n totalBytes: number,\n entries: Array<{ name: string; size: number }>,\n): void {\n const totalMegaBytes = Math.round(totalBytes / 1024 / 1024);\n\n if (totalMegaBytes < 30) {\n return;\n }\n\n const messageBits = [\n `Package size is ${totalMegaBytes} MB (${totalBytes} bytes), maximum is 60 MB.`,\n \"Here are the largest 20 files in the archive. Consider removing ones that aren't necessary.\",\n ];\n\n const fileSizes = entries.map((entry) => ({\n name: entry.name,\n size: entry.size || 0,\n }));\n\n for (const file of fileSizes.toSorted((a, b) => b.size - a.size).slice(0, 20)) {\n messageBits.push(\n `${file.name}: ${Math.round(file.size / 1024 / 1024)} MB (${file.size} bytes)`,\n );\n }\n\n if (totalMegaBytes > 60) {\n throw new Error(messageBits.join('\\n'));\n }\n\n console.warn(messageBits.join('\\n'));\n}\n", "import { styleText } from 'node:util';\n\ntype PrintFunction = (str: string) => void;\n\nconst red = (str: string) => styleText('red', str);\nconst green = (str: string) => styleText('green', str);\nconst dim = (str: string) => styleText('dim', str);\nconst underline = (str: string) => styleText('underline', str);\n\nexport function logTag(project?: string): string {\n return project ? `[${project}] ` : '';\n}\n\nfunction printDuration(print: PrintFunction, startTime?: number): void {\n if (startTime) {\n print(dim(` (${Date.now() - startTime}ms)`));\n }\n}\n\ninterface LoggerOptions {\n stderrPrint?: PrintFunction;\n print?: PrintFunction;\n}\n\ninterface StartOptions {\n startTime?: number;\n}\n\nexport default class Logger {\n private print: PrintFunction;\n private stderrPrint: PrintFunction;\n private startTime?: number | undefined;\n private startMsg?: string | undefined;\n\n constructor({\n stderrPrint = (str: string) => process.stderr.write(str),\n print = (str: string) => process.stdout.write(str),\n }: LoggerOptions = {}) {\n this.print = print;\n this.stderrPrint = stderrPrint;\n this.startTime = undefined;\n this.startMsg = undefined;\n }\n\n mute(): void {\n this.print = () => null;\n this.stderrPrint = () => null;\n }\n\n divider(): void {\n this.info('-----------------------------------------');\n }\n\n info(msg: string): void {\n this.print(`${msg}`.replaceAll(/https?:\\/\\/[^ ]+/g, underline));\n this.print('\\n');\n }\n\n start(msg?: string, { startTime }: StartOptions = {}): void {\n this.startTime = startTime || Date.now();\n this.startMsg = msg;\n if (msg) {\n this.print(`Starting: ${msg} `);\n this.print('\\n');\n }\n }\n\n success(msg?: string): void {\n this.print(green('\u2713'));\n\n if (this.startMsg) {\n this.print(green(` ${this.startMsg}:`));\n }\n\n if (msg) {\n this.print(green(` ${msg}`));\n }\n printDuration(this.print, this.startTime);\n this.print('\\n');\n\n this.startMsg = undefined;\n }\n\n fail(msg?: string): void {\n this.print(red('\u2717'));\n\n if (this.startMsg) {\n this.print(red(` ${this.startMsg}:`));\n }\n\n if (msg) {\n this.print(red(` ${msg}`));\n }\n printDuration(this.print, this.startTime);\n this.print('\\n');\n\n this.startMsg = undefined;\n }\n\n error(e: Error | string): void {\n let stack: string | undefined;\n if (typeof e === 'object' && e.stack) {\n stack = e.stack;\n if (stack) {\n stack = stack.split(`file://${process.cwd()}/`).join('');\n }\n }\n this.stderrPrint(\n red(stack || (typeof e === 'object' ? e.message : e) || String(e)),\n );\n this.stderrPrint('\\n');\n }\n\n warn(message: string): void {\n this.stderrPrint(red(message));\n this.stderrPrint('\\n');\n }\n}\n", "import { createHash } from 'node:crypto';\n\nimport retry from 'async-retry';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport { logTag } from '../utils/Logger.ts';\nimport makeHappoAPIRequest from './makeHappoAPIRequest.ts';\n\n// Type definitions\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\ninterface UploadAssetsOptions {\n hash: string;\n logger: Logger;\n}\n\nexport default async function uploadAssets(\n buffer: Buffer<ArrayBuffer>,\n options: UploadAssetsOptions,\n config: ConfigWithDefaults,\n): Promise<string> {\n const { project } = config;\n const { hash, logger } = options;\n\n // First we need to get the signed URL from Happo.\n const signedUrlRes = await makeHappoAPIRequest(\n {\n path: `/api/snap-requests/assets/${hash}/signed-url`,\n method: 'GET',\n },\n config,\n { retryCount: 3 },\n );\n\n if (!signedUrlRes) {\n throw new Error('Failed to get signed URL');\n }\n\n if ('path' in signedUrlRes) {\n // If the asset has already been uploaded the response will have a path and\n // we can return it now.\n const { path: signedUrlPath } = signedUrlRes;\n\n logger.info(`${logTag(project)}Reusing existing assets at ${signedUrlPath}`);\n return typeof signedUrlPath === 'string' ? signedUrlPath : String(signedUrlPath);\n }\n\n if (!('signedUrl' in signedUrlRes)) {\n throw new Error(\n `Signed URL response does not have path or signedUrl. Response: ${JSON.stringify(signedUrlRes, null, 2)}`,\n );\n }\n\n const { signedUrl } = signedUrlRes;\n\n // Upload the assets to the signed URL using node's built-in fetch with\n // retries\n await retry(\n async (bail: (error: Error) => void) => {\n const res = await fetch(String(signedUrl), {\n method: 'PUT',\n body: buffer,\n headers: {\n 'Content-Type': 'application/zip',\n },\n signal: AbortSignal.timeout(60_000),\n });\n\n if (!res.ok) {\n const error = new Error(\n `Failed to upload assets to S3 signed URL: ${res.status} ${res.statusText}`,\n );\n\n if (res.status < 500 || res.status >= 600) {\n // If it's not a 5xx error, bail immediately instead of retrying\n bail(error);\n return;\n }\n\n throw error;\n }\n\n // Verify the upload succeeded by checking the ETag header. S3 always\n // returns an ETag matching the MD5 of the uploaded content. A firewall\n // or transparent proxy returning a fake 200 will typically not include\n // a correct ETag, catching the case where the payload never reached S3.\n const etag = res.headers.get('etag');\n const expectedEtag = createHash('md5').update(buffer).digest('hex');\n if (!etag || !etag.includes(expectedEtag)) {\n const error = new Error(\n `S3 upload verification failed: expected ETag to include ${expectedEtag}, got ${etag ?? '(none)'}. ` +\n `A firewall may be intercepting the upload.`,\n );\n bail(error);\n return;\n }\n\n return res;\n },\n {\n retries: 3,\n onRetry: (error: Error, attempt: number) => {\n logger.warn(\n `${logTag(project)}PUT request attempt ${attempt} failed: ${error.message}. Retrying...`,\n );\n },\n },\n );\n\n // Finally, we need to tell Happo that we've uploaded the assets.\n const finalizeRes = await makeHappoAPIRequest(\n {\n path: `/api/snap-requests/assets/${hash}/signed-url/finalize`,\n method: 'POST',\n },\n config,\n { retryCount: 3 },\n );\n\n if (!finalizeRes) {\n throw new Error('Failed to finalize assets');\n }\n\n if (!('path' in finalizeRes)) {\n throw new Error('Finalize response is missing path');\n }\n\n const { path: finalizedPath } = finalizeRes;\n\n return typeof finalizedPath === 'string' ? finalizedPath : String(finalizedPath);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["fs", "path", "requestIds", "fs", "path", "fs", "path", "path", "HAPPO_DEBUG", "fs", "path", "fs", "path", "path", "fs", "createHash", "createHash", "path", "fs"]
7
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ startJob
3
+ } from "./chunk-XZTQZZFK.js";
4
+ import "./chunk-RJXHIGT5.js";
5
+ import "./chunk-UTRRH3WF.js";
6
+ import "./chunk-64XRFVHC.js";
7
+ export {
8
+ startJob as default
9
+ };
10
+ //# sourceMappingURL=startJob-33HGTT4N.js.map