happo 6.3.5 → 6.4.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.
Files changed (61) hide show
  1. package/dist/cli/cancelJob-ORBIXVT5.js +10 -0
  2. package/dist/cli/{chunk-KBSCVKHT.js → chunk-6PWJAPHP.js} +2 -2
  3. package/dist/cli/chunk-6PWJAPHP.js.map +7 -0
  4. package/dist/cli/{chunk-JQRP37NK.js → chunk-IGI756V3.js} +3 -3
  5. package/dist/cli/{chunk-EIXHFGQL.js → chunk-JOPTBOXW.js} +2 -2
  6. package/dist/cli/{chunk-D6LAGJC3.js → chunk-QTTEOWAX.js} +3 -3
  7. package/dist/cli/{chunk-D6LAGJC3.js.map → chunk-QTTEOWAX.js.map} +1 -1
  8. package/dist/cli/{chunk-H6OKM3G2.js → chunk-ULGAHSS5.js} +2 -2
  9. package/dist/cli/{chunk-WYDYZN3N.js → chunk-WJIEJMLG.js} +4 -4
  10. package/dist/cli/chunk-WJIEJMLG.js.map +7 -0
  11. package/dist/cli/createAsyncComparison-XISBMLXA.js +10 -0
  12. package/dist/cli/{createAsyncReport-PWLSEU4U.js → createAsyncReport-A27NY62E.js} +4 -4
  13. package/dist/cli/{getFlakes-ISMCYQYN.js → getFlakes-CPW3FFIF.js} +4 -4
  14. package/dist/cli/main.js +11 -11
  15. package/dist/cli/package-ZLQ7KI7I.js +7 -0
  16. package/dist/cli/{prepareSnapRequests-LKEGFH3U.js → prepareSnapRequests-74QL6FGT.js} +77 -42
  17. package/dist/cli/prepareSnapRequests-74QL6FGT.js.map +7 -0
  18. package/dist/cli/startJob-NZDZNGVS.js +10 -0
  19. package/dist/cli/{wrapper-AA77AANX.js → wrapper-PXCRJ4BX.js} +7 -7
  20. package/dist/config/RemoteBrowserTarget.d.ts +7 -1
  21. package/dist/config/RemoteBrowserTarget.d.ts.map +1 -1
  22. package/dist/config/index.d.ts +5 -1
  23. package/dist/config/index.d.ts.map +1 -1
  24. package/dist/config/index.js.map +2 -2
  25. package/dist/cypress/task.d.ts.map +1 -1
  26. package/dist/cypress/task.js +21 -18
  27. package/dist/cypress/task.js.map +2 -2
  28. package/dist/e2e/controller.d.ts +1 -1
  29. package/dist/e2e/controller.d.ts.map +1 -1
  30. package/dist/network/fetchWithRetry.d.ts +1 -1
  31. package/dist/network/fetchWithRetry.d.ts.map +1 -1
  32. package/dist/network/makeHappoAPIRequest.d.ts +1 -1
  33. package/dist/network/makeHappoAPIRequest.d.ts.map +1 -1
  34. package/dist/network/prepareSnapRequests.d.ts.map +1 -1
  35. package/dist/playwright/index.d.ts.map +1 -1
  36. package/dist/playwright/index.js +17 -17
  37. package/dist/playwright/index.js.map +2 -2
  38. package/dist/storybook/getStorybookStoryCount.d.ts +7 -0
  39. package/dist/storybook/getStorybookStoryCount.d.ts.map +1 -0
  40. package/dist/storybook/index.d.ts +5 -1
  41. package/dist/storybook/index.d.ts.map +1 -1
  42. package/dist/storybook/index.js +34 -13
  43. package/dist/storybook/index.js.map +4 -4
  44. package/package.json +2 -2
  45. package/dist/cli/cancelJob-QSJ4H5RQ.js +0 -10
  46. package/dist/cli/chunk-KBSCVKHT.js.map +0 -7
  47. package/dist/cli/chunk-WYDYZN3N.js.map +0 -7
  48. package/dist/cli/createAsyncComparison-2X5JW753.js +0 -10
  49. package/dist/cli/package-QA5NMKSG.js +0 -7
  50. package/dist/cli/prepareSnapRequests-LKEGFH3U.js.map +0 -7
  51. package/dist/cli/startJob-3G7ZMTJL.js +0 -10
  52. /package/dist/cli/{cancelJob-QSJ4H5RQ.js.map → cancelJob-ORBIXVT5.js.map} +0 -0
  53. /package/dist/cli/{chunk-JQRP37NK.js.map → chunk-IGI756V3.js.map} +0 -0
  54. /package/dist/cli/{chunk-EIXHFGQL.js.map → chunk-JOPTBOXW.js.map} +0 -0
  55. /package/dist/cli/{chunk-H6OKM3G2.js.map → chunk-ULGAHSS5.js.map} +0 -0
  56. /package/dist/cli/{createAsyncComparison-2X5JW753.js.map → createAsyncComparison-XISBMLXA.js.map} +0 -0
  57. /package/dist/cli/{createAsyncReport-PWLSEU4U.js.map → createAsyncReport-A27NY62E.js.map} +0 -0
  58. /package/dist/cli/{getFlakes-ISMCYQYN.js.map → getFlakes-CPW3FFIF.js.map} +0 -0
  59. /package/dist/cli/{package-QA5NMKSG.js.map → package-ZLQ7KI7I.js.map} +0 -0
  60. /package/dist/cli/{startJob-3G7ZMTJL.js.map → startJob-NZDZNGVS.js.map} +0 -0
  61. /package/dist/cli/{wrapper-AA77AANX.js.map → wrapper-PXCRJ4BX.js.map} +0 -0
@@ -0,0 +1,10 @@
1
+ import {
2
+ cancelJob
3
+ } from "./chunk-IGI756V3.js";
4
+ import "./chunk-6PWJAPHP.js";
5
+ import "./chunk-WJIEJMLG.js";
6
+ import "./chunk-QTTEOWAX.js";
7
+ export {
8
+ cancelJob as default
9
+ };
10
+ //# sourceMappingURL=cancelJob-ORBIXVT5.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  fetchWithRetry
3
- } from "./chunk-WYDYZN3N.js";
3
+ } from "./chunk-WJIEJMLG.js";
4
4
 
5
5
  // src/network/makeHappoAPIRequest.ts
6
6
  import { SignJWT } from "jose";
@@ -51,4 +51,4 @@ async function makeHappoAPIRequest({ url, path, method = "GET", formData, body }
51
51
  export {
52
52
  makeHappoAPIRequest
53
53
  };
54
- //# sourceMappingURL=chunk-KBSCVKHT.js.map
54
+ //# sourceMappingURL=chunk-6PWJAPHP.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/network/makeHappoAPIRequest.ts"],
4
+ "sourcesContent": ["import { SignJWT } from 'jose';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport fetchWithRetry from './fetchWithRetry.ts';\n\ntype FormDataValue = string | number | File | undefined;\n\nexport interface RequestAttributes {\n /**\n * The path to the API endpoint\n *\n * @example\n * '/api/snap-requests/with-results'\n */\n path?: `/api/${string}`;\n\n /**\n * The URL to fetch\n *\n * Prefer using the `path` property instead. If both are provided, the `path`\n * property will be used.\n */\n url?: string;\n\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n formData?: Record<string, FormDataValue>;\n body?: unknown;\n json?: boolean;\n}\n\nexport interface MakeHappoAPIRequestOptions {\n /**\n * The timeout in milliseconds\n * @default 60_000\n */\n timeout?: number;\n\n /**\n * The number of times to retry the request\n * @default 0\n */\n retryCount?: number;\n\n /**\n * The minimum timeout in milliseconds\n * @default 1000\n */\n retryMinTimeout?: number;\n\n /**\n * The maximum timeout in milliseconds\n * @default Infinity\n */\n retryMaxTimeout?: number;\n}\n\nasync function signRequest(apiKey: string, apiSecret: string): Promise<string> {\n const encodedSecret = new TextEncoder().encode(apiSecret);\n return await new SignJWT({ key: apiKey })\n .setProtectedHeader({ alg: 'HS256', kid: apiKey })\n .sign(encodedSecret);\n}\n\nexport default async function makeHappoAPIRequest(\n { url, path, method = 'GET', formData, body }: RequestAttributes,\n { apiKey, apiSecret, endpoint }: ConfigWithDefaults,\n {\n retryCount = 0,\n timeout = 60_000,\n retryMinTimeout = 1000,\n retryMaxTimeout = Infinity,\n }: MakeHappoAPIRequestOptions,\n logger: Logger = console,\n): Promise<object | null> {\n const fetchURL = path ? new URL(path, endpoint) : url;\n\n if (!fetchURL) {\n throw new Error(\n 'No fetch URL provided. Either `path` (preferred) or `url` must be provided.',\n );\n }\n\n const signed = await signRequest(apiKey, apiSecret);\n\n const headers = {\n Authorization: `Bearer ${signed}`,\n };\n\n const response = await fetchWithRetry(\n fetchURL,\n {\n method,\n headers,\n formData,\n body,\n timeout,\n retryCount,\n retryMinTimeout,\n retryMaxTimeout,\n },\n logger,\n );\n\n if (response.status === 204) {\n return null;\n }\n\n // We expect API responses to be JSON, so let's parse it as JSON here for\n // convenience.\n const result = await response.json();\n\n if (typeof result !== 'object') {\n throw new TypeError(`Response is not an object: ${JSON.stringify(result)}`);\n }\n\n return result;\n}\n"],
5
+ "mappings": ";;;;;AAAA,SAAS,eAAe;AAyDxB,eAAe,YAAY,QAAgB,WAAoC;AAC7E,QAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,SAAS;AACxD,SAAO,MAAM,IAAI,QAAQ,EAAE,KAAK,OAAO,CAAC,EACrC,mBAAmB,EAAE,KAAK,SAAS,KAAK,OAAO,CAAC,EAChD,KAAK,aAAa;AACvB;AAEA,eAAO,oBACL,EAAE,KAAK,MAAM,SAAS,OAAO,UAAU,KAAK,GAC5C,EAAE,QAAQ,WAAW,SAAS,GAC9B;AAAA,EACE,aAAa;AAAA,EACb,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,kBAAkB;AACpB,GACA,SAAiB,SACO;AACxB,QAAM,WAAW,OAAO,IAAI,IAAI,MAAM,QAAQ,IAAI;AAElD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,YAAY,QAAQ,SAAS;AAElD,QAAM,UAAU;AAAA,IACd,eAAe,UAAU,MAAM;AAAA,EACjC;AAEA,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,KAAK;AAC3B,WAAO;AAAA,EACT;AAIA,QAAM,SAAS,MAAM,SAAS,KAAK;AAEnC,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAM,IAAI,UAAU,8BAA8B,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC5E;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-KBSCVKHT.js";
3
+ } from "./chunk-6PWJAPHP.js";
4
4
  import {
5
5
  ErrorWithStatusCode
6
- } from "./chunk-WYDYZN3N.js";
6
+ } from "./chunk-WJIEJMLG.js";
7
7
 
8
8
  // src/network/cancelJob.ts
9
9
  async function cancelJob(status, message, config, { beforeSha, afterSha, link }, logger) {
@@ -43,4 +43,4 @@ async function cancelJob(status, message, config, { beforeSha, afterSha, link },
43
43
  export {
44
44
  cancelJob
45
45
  };
46
- //# sourceMappingURL=chunk-JQRP37NK.js.map
46
+ //# sourceMappingURL=chunk-IGI756V3.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-KBSCVKHT.js";
3
+ } from "./chunk-6PWJAPHP.js";
4
4
 
5
5
  // src/network/createAsyncComparison.ts
6
6
  function assertResultIsCreateAsyncComparisonResult(result) {
@@ -60,4 +60,4 @@ async function createAsyncComparison(config, {
60
60
  export {
61
61
  createAsyncComparison
62
62
  };
63
- //# sourceMappingURL=chunk-EIXHFGQL.js.map
63
+ //# sourceMappingURL=chunk-JOPTBOXW.js.map
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "happo",
4
- version: "6.3.5",
4
+ version: "6.4.0",
5
5
  description: "Catch unexpected visual and accessibility changes and UI bugs",
6
6
  license: "MIT",
7
7
  repository: {
@@ -120,7 +120,7 @@ var package_default = {
120
120
  esbuild: "^0.27.0",
121
121
  eslint: "^10.0.2",
122
122
  "eslint-config-prettier": "^10.1.8",
123
- "eslint-plugin-compat": "^6.2.0",
123
+ "eslint-plugin-compat": "^7.0.1",
124
124
  "eslint-plugin-depend": "^1.4.0",
125
125
  "eslint-plugin-simple-import-sort": "^12.1.1",
126
126
  "eslint-plugin-unicorn": "^63.0.0",
@@ -183,4 +183,4 @@ var package_default = {
183
183
  export {
184
184
  package_default
185
185
  };
186
- //# sourceMappingURL=chunk-D6LAGJC3.js.map
186
+ //# sourceMappingURL=chunk-QTTEOWAX.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../package.json"],
4
- "sourcesContent": ["{\n \"name\": \"happo\",\n \"version\": \"6.3.5\",\n \"description\": \"Catch unexpected visual and accessibility changes and UI bugs\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/happo/happo.git\"\n },\n \"bugs\": \"https://github.com/happo/happo/issues\",\n \"homepage\": \"https://happo.io\",\n \"bin\": {\n \"happo\": \"dist/cli/main.js\"\n },\n \"type\": \"module\",\n \"main\": \"./dist/config/index.js\",\n \"types\": \"./dist/config/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/config/index.d.ts\",\n \"default\": \"./dist/config/index.js\"\n },\n \"./cypress\": {\n \"types\": \"./dist/cypress/index.d.ts\",\n \"default\": \"./dist/cypress/index.js\"\n },\n \"./cypress/task\": {\n \"types\": \"./dist/cypress/task.d.ts\",\n \"default\": \"./dist/cypress/task.js\"\n },\n \"./playwright\": {\n \"types\": \"./dist/playwright/index.d.ts\",\n \"default\": \"./dist/playwright/index.js\"\n },\n \"./custom\": {\n \"types\": \"./dist/custom/index.d.ts\",\n \"default\": \"./dist/custom/index.js\"\n },\n \"./storybook/addon\": {\n \"types\": \"./dist/storybook/browser/addon.d.ts\",\n \"default\": \"./dist/storybook/browser/addon.js\"\n },\n \"./storybook/decorator\": {\n \"types\": \"./dist/storybook/browser/decorator.d.ts\",\n \"default\": \"./dist/storybook/browser/decorator.js\"\n },\n \"./storybook/preset\": {\n \"types\": \"./dist/storybook/preset.d.ts\",\n \"default\": \"./dist/storybook/preset.js\"\n },\n \"./storybook/register\": {\n \"types\": \"./dist/storybook/browser/register.d.ts\",\n \"default\": \"./dist/storybook/browser/register.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"preset.js\"\n ],\n \"scripts\": {\n \"all\": \"node ./scripts/allchecks.ts\",\n \"build\": \"pnpm build:types && pnpm build:dist\",\n \"build:custom\": \"esbuild src/custom/__happo__/index.ts --bundle --format=iife --global-name=happoCustom --outfile=tmp/happo-custom/bundle.js --platform=browser --target=esnext\",\n \"build:dist\": \"./scripts/build.ts\",\n \"build:types\": \"pnpm tsc --pretty\",\n \"build:watch\": \"tsc --build --watch\",\n \"clean\": \"rm -rf dist tmp/tsc tmp/happo-custom\",\n \"lint\": \"eslint .\",\n \"prepublishOnly\": \"pnpm clean && pnpm build\",\n \"storybook:dev\": \"storybook dev --config-dir src/storybook/__tests__/storybook-app -p ${PORT:-6007}\",\n \"test\": \"node --env-file-if-exists=.env.local ./scripts/test.ts\",\n \"test:custom\": \"pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.custom.config.ts\",\n \"test:cypress\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.cypress.config.ts e2e -- cypress run -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:cypress:open\": \"cypress open -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:playwright\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright.config.ts e2e -- playwright test\",\n \"test:storybook\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts\",\n \"test:pages\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts\",\n \"tsc\": \"tsc --build tsconfig.json\"\n },\n \"browserslist\": {\n \"node\": [\n \"node 22\"\n ],\n \"browser\": [\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ],\n \"isomorphic\": [\n \"node 22\",\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ]\n },\n \"prettier\": {\n \"printWidth\": 85,\n \"singleQuote\": true,\n \"trailingComma\": \"all\",\n \"arrowParens\": \"always\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@playwright/test\": \"^1.55.1\",\n \"@reporters/github\": \"^1.11.0\",\n \"@storybook/builder-vite\": \"^10.0.1\",\n \"@storybook/react-vite\": \"^10.0.1\",\n \"@types/async-retry\": \"^1.4.9\",\n \"@types/base64-stream\": \"^1.0.5\",\n \"@types/jsdom\": \"^28.0.0\",\n \"@types/mime-types\": \"^3.0.1\",\n \"@types/multiparty\": \"^4.2.1\",\n \"@types/node\": \"^24.9.1\",\n \"@types/react\": \"^19.2.0\",\n \"@types/react-dom\": \"^19.2.0\",\n \"cypress\": \"^15.5.0\",\n \"esbuild\": \"^0.27.0\",\n \"eslint\": \"^10.0.2\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-compat\": \"^6.2.0\",\n \"eslint-plugin-depend\": \"^1.4.0\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unicorn\": \"^63.0.0\",\n \"jiti\": \"^2.6.1\",\n \"jsdom\": \"^28.0.0\",\n \"multiparty\": \"^4.2.3\",\n \"prettier\": \"^3.6.2\",\n \"react\": \"^19.2.0\",\n \"react-dom\": \"^19.2.0\",\n \"react-error-boundary\": \"^6.0.0\",\n \"storybook\": \"^10.0.1\",\n \"typescript\": \"^5.9.2\",\n \"typescript-eslint\": \"^8.56.1\"\n },\n \"dependencies\": {\n \"async-retry\": \"^1.3.3\",\n \"base64-stream\": \"^1.0.0\",\n \"empathic\": \"^2.0.0\",\n \"fflate\": \"^0.8.2\",\n \"jose\": \"^6.1.0\",\n \"limit-concur\": \"^4.0.0\",\n \"mime-types\": \"^3.0.1\",\n \"srcset\": \"^5.0.2\"\n },\n \"storybook\": {\n \"displayName\": \"Happo\",\n \"icon\": \"https://happo.io/static/happo-hippo.png\",\n \"supportedFrameworks\": [\n \"angular\",\n \"ember\",\n \"html\",\n \"preact\",\n \"react\",\n \"react-native\",\n \"svelte\",\n \"vue\",\n \"web-components\"\n ],\n \"unsupportedFrameworks\": []\n },\n \"keywords\": [\n \"storybook-addon\",\n \"accessibility\",\n \"cypress\",\n \"playwright\",\n \"regression\",\n \"storybook\",\n \"test\",\n \"testing\",\n \"ui\",\n \"visual-regression\",\n \"visual\",\n \"vrt\"\n ],\n \"engines\": {\n \"node\": \"^22.18.0 || ^23.6.0 || >=24.0.0\"\n }\n}\n"],
4
+ "sourcesContent": ["{\n \"name\": \"happo\",\n \"version\": \"6.4.0\",\n \"description\": \"Catch unexpected visual and accessibility changes and UI bugs\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/happo/happo.git\"\n },\n \"bugs\": \"https://github.com/happo/happo/issues\",\n \"homepage\": \"https://happo.io\",\n \"bin\": {\n \"happo\": \"dist/cli/main.js\"\n },\n \"type\": \"module\",\n \"main\": \"./dist/config/index.js\",\n \"types\": \"./dist/config/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/config/index.d.ts\",\n \"default\": \"./dist/config/index.js\"\n },\n \"./cypress\": {\n \"types\": \"./dist/cypress/index.d.ts\",\n \"default\": \"./dist/cypress/index.js\"\n },\n \"./cypress/task\": {\n \"types\": \"./dist/cypress/task.d.ts\",\n \"default\": \"./dist/cypress/task.js\"\n },\n \"./playwright\": {\n \"types\": \"./dist/playwright/index.d.ts\",\n \"default\": \"./dist/playwright/index.js\"\n },\n \"./custom\": {\n \"types\": \"./dist/custom/index.d.ts\",\n \"default\": \"./dist/custom/index.js\"\n },\n \"./storybook/addon\": {\n \"types\": \"./dist/storybook/browser/addon.d.ts\",\n \"default\": \"./dist/storybook/browser/addon.js\"\n },\n \"./storybook/decorator\": {\n \"types\": \"./dist/storybook/browser/decorator.d.ts\",\n \"default\": \"./dist/storybook/browser/decorator.js\"\n },\n \"./storybook/preset\": {\n \"types\": \"./dist/storybook/preset.d.ts\",\n \"default\": \"./dist/storybook/preset.js\"\n },\n \"./storybook/register\": {\n \"types\": \"./dist/storybook/browser/register.d.ts\",\n \"default\": \"./dist/storybook/browser/register.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"preset.js\"\n ],\n \"scripts\": {\n \"all\": \"node ./scripts/allchecks.ts\",\n \"build\": \"pnpm build:types && pnpm build:dist\",\n \"build:custom\": \"esbuild src/custom/__happo__/index.ts --bundle --format=iife --global-name=happoCustom --outfile=tmp/happo-custom/bundle.js --platform=browser --target=esnext\",\n \"build:dist\": \"./scripts/build.ts\",\n \"build:types\": \"pnpm tsc --pretty\",\n \"build:watch\": \"tsc --build --watch\",\n \"clean\": \"rm -rf dist tmp/tsc tmp/happo-custom\",\n \"lint\": \"eslint .\",\n \"prepublishOnly\": \"pnpm clean && pnpm build\",\n \"storybook:dev\": \"storybook dev --config-dir src/storybook/__tests__/storybook-app -p ${PORT:-6007}\",\n \"test\": \"node --env-file-if-exists=.env.local ./scripts/test.ts\",\n \"test:custom\": \"pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.custom.config.ts\",\n \"test:cypress\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.cypress.config.ts e2e -- cypress run -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:cypress:open\": \"cypress open -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:playwright\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright.config.ts e2e -- playwright test\",\n \"test:storybook\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts\",\n \"test:pages\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts\",\n \"tsc\": \"tsc --build tsconfig.json\"\n },\n \"browserslist\": {\n \"node\": [\n \"node 22\"\n ],\n \"browser\": [\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ],\n \"isomorphic\": [\n \"node 22\",\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ]\n },\n \"prettier\": {\n \"printWidth\": 85,\n \"singleQuote\": true,\n \"trailingComma\": \"all\",\n \"arrowParens\": \"always\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@playwright/test\": \"^1.55.1\",\n \"@reporters/github\": \"^1.11.0\",\n \"@storybook/builder-vite\": \"^10.0.1\",\n \"@storybook/react-vite\": \"^10.0.1\",\n \"@types/async-retry\": \"^1.4.9\",\n \"@types/base64-stream\": \"^1.0.5\",\n \"@types/jsdom\": \"^28.0.0\",\n \"@types/mime-types\": \"^3.0.1\",\n \"@types/multiparty\": \"^4.2.1\",\n \"@types/node\": \"^24.9.1\",\n \"@types/react\": \"^19.2.0\",\n \"@types/react-dom\": \"^19.2.0\",\n \"cypress\": \"^15.5.0\",\n \"esbuild\": \"^0.27.0\",\n \"eslint\": \"^10.0.2\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-compat\": \"^7.0.1\",\n \"eslint-plugin-depend\": \"^1.4.0\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unicorn\": \"^63.0.0\",\n \"jiti\": \"^2.6.1\",\n \"jsdom\": \"^28.0.0\",\n \"multiparty\": \"^4.2.3\",\n \"prettier\": \"^3.6.2\",\n \"react\": \"^19.2.0\",\n \"react-dom\": \"^19.2.0\",\n \"react-error-boundary\": \"^6.0.0\",\n \"storybook\": \"^10.0.1\",\n \"typescript\": \"^5.9.2\",\n \"typescript-eslint\": \"^8.56.1\"\n },\n \"dependencies\": {\n \"async-retry\": \"^1.3.3\",\n \"base64-stream\": \"^1.0.0\",\n \"empathic\": \"^2.0.0\",\n \"fflate\": \"^0.8.2\",\n \"jose\": \"^6.1.0\",\n \"limit-concur\": \"^4.0.0\",\n \"mime-types\": \"^3.0.1\",\n \"srcset\": \"^5.0.2\"\n },\n \"storybook\": {\n \"displayName\": \"Happo\",\n \"icon\": \"https://happo.io/static/happo-hippo.png\",\n \"supportedFrameworks\": [\n \"angular\",\n \"ember\",\n \"html\",\n \"preact\",\n \"react\",\n \"react-native\",\n \"svelte\",\n \"vue\",\n \"web-components\"\n ],\n \"unsupportedFrameworks\": []\n },\n \"keywords\": [\n \"storybook-addon\",\n \"accessibility\",\n \"cypress\",\n \"playwright\",\n \"regression\",\n \"storybook\",\n \"test\",\n \"testing\",\n \"ui\",\n \"visual-regression\",\n \"visual\",\n \"vrt\"\n ],\n \"engines\": {\n \"node\": \"^22.18.0 || ^23.6.0 || >=24.0.0\"\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-KBSCVKHT.js";
3
+ } from "./chunk-6PWJAPHP.js";
4
4
 
5
5
  // src/network/startJob.ts
6
6
  function assertResultIsStartJobResult(result) {
@@ -36,4 +36,4 @@ async function startJob(config, { beforeSha, afterSha, link, message }, logger)
36
36
  export {
37
37
  startJob
38
38
  };
39
- //# sourceMappingURL=chunk-H6OKM3G2.js.map
39
+ //# sourceMappingURL=chunk-ULGAHSS5.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./chunk-D6LAGJC3.js";
3
+ } from "./chunk-QTTEOWAX.js";
4
4
 
5
5
  // src/network/fetchWithRetry.ts
6
6
  import asyncRetry from "async-retry";
@@ -13,12 +13,12 @@ var ErrorWithStatusCode = class extends Error {
13
13
  }
14
14
  };
15
15
  function prepareFormData(data) {
16
- if (!data) {
16
+ if (data == null) {
17
17
  return null;
18
18
  }
19
19
  const form = new FormData();
20
20
  for (const [key, value] of Object.entries(data)) {
21
- if (value) {
21
+ if (value != null) {
22
22
  form.append(key, value);
23
23
  }
24
24
  }
@@ -95,4 +95,4 @@ export {
95
95
  ErrorWithStatusCode,
96
96
  fetchWithRetry
97
97
  };
98
- //# sourceMappingURL=chunk-WYDYZN3N.js.map
98
+ //# sourceMappingURL=chunk-WJIEJMLG.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/network/fetchWithRetry.ts"],
4
+ "sourcesContent": ["import asyncRetry from 'async-retry';\n\nimport packageJson from '../../package.json' with { type: 'json' };\nimport type { Logger } from '../isomorphic/types.ts';\n\nconst { version } = packageJson;\n\nexport class ErrorWithStatusCode extends Error {\n statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.statusCode = statusCode;\n }\n}\n\ntype FormDataValue = string | number | File | undefined;\n\nfunction prepareFormData(data: Record<string, FormDataValue>): FormData | null {\n if (data == null) {\n return null;\n }\n\n const form = new FormData();\n\n for (const [key, value] of Object.entries(data)) {\n if (value != null) {\n form.append(key, value);\n }\n }\n\n return form;\n}\n\ninterface FetchParams {\n method?: string;\n headers?: Record<string, string>;\n formData?: Record<string, FormDataValue> | undefined;\n body?: unknown;\n\n /**\n * The timeout in milliseconds\n * @default 60_000\n */\n timeout?: number;\n\n /**\n * The number of times to retry the request\n * @default 0\n */\n retryCount?: number;\n\n /**\n * The minimum timeout in milliseconds\n * @default 1000\n */\n retryMinTimeout?: number;\n\n /**\n * The maximum timeout in milliseconds\n * @default Infinity\n */\n retryMaxTimeout?: number;\n}\n\nconst defaultHeaders = {\n 'User-Agent': `happo@${version}`,\n};\n\nexport default async function fetchWithRetry(\n url: string | URL,\n {\n method = 'GET',\n headers = {},\n formData,\n body: jsonBody,\n timeout = 60_000,\n retryCount = 0,\n retryMinTimeout = 1000,\n retryMaxTimeout = Infinity,\n }: FetchParams,\n logger: Logger = console,\n): Promise<Response> {\n return asyncRetry(\n async (bail: (error: Error) => void) => {\n const start = Date.now();\n\n // We must avoid reusing FormData instances when retrying requests\n // because they are consumed and cannot be reused.\n // More info: https://github.com/node-fetch/node-fetch/issues/1743\n const body = formData\n ? prepareFormData(formData)\n : jsonBody\n ? JSON.stringify(jsonBody)\n : null;\n\n if (jsonBody) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: { ...defaultHeaders, ...headers },\n signal: AbortSignal.timeout(timeout),\n body,\n });\n } catch (maybeError) {\n const originalError =\n maybeError instanceof Error ? maybeError : new Error(String(maybeError));\n\n const message =\n originalError.name === 'TimeoutError'\n ? `Timeout when fetching ${url} using method ${method}`\n : originalError.message;\n\n // This WILL be retried\n throw new Error(`${message} (took ${Date.now() - start} ms)`, {\n // eslint-disable-next-line preserve-caught-error -- We actually are preserving the original error, the rule is wrong in this case\n cause: originalError,\n });\n }\n\n if (response.status >= 400 && response.status < 500) {\n // This WILL NOT be retried\n bail(\n new ErrorWithStatusCode(\n `[HAPPO] Request to ${url} failed: ${response.status} - ${await response.text()}`,\n response.status,\n ),\n );\n\n return response;\n }\n\n if (!response.ok) {\n // This WILL be retried\n throw new ErrorWithStatusCode(\n `[HAPPO] Request to ${url} failed: ${response.status} - ${await response.text()}`,\n response.status,\n );\n }\n\n return response;\n },\n\n {\n retries: retryCount,\n minTimeout: retryMinTimeout,\n maxTimeout: retryMaxTimeout,\n onRetry: (error: Error) => {\n logger.error(\n `[HAPPO] Failed fetching ${url} using method ${method}. Retrying (at ${new Date().toISOString()}) ...`,\n );\n logger.error(error);\n },\n },\n );\n}\n"],
5
+ "mappings": ";;;;;AAAA,OAAO,gBAAgB;AAKvB,IAAM,EAAE,QAAQ,IAAI;AAEb,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAC7C;AAAA,EAEA,YAAY,SAAiB,YAAoB;AAC/C,UAAM,OAAO;AACb,SAAK,aAAa;AAAA,EACpB;AACF;AAIA,SAAS,gBAAgB,MAAsD;AAC7E,MAAI,QAAQ,MAAM;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,SAAS;AAE1B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,QAAI,SAAS,MAAM;AACjB,WAAK,OAAO,KAAK,KAAK;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAiCA,IAAM,iBAAiB;AAAA,EACrB,cAAc,SAAS,OAAO;AAChC;AAEA,eAAO,eACL,KACA;AAAA,EACE,SAAS;AAAA,EACT,UAAU,CAAC;AAAA,EACX;AAAA,EACA,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,kBAAkB;AACpB,GACA,SAAiB,SACE;AACnB,SAAO;AAAA,IACL,OAAO,SAAiC;AACtC,YAAM,QAAQ,KAAK,IAAI;AAKvB,YAAM,OAAO,WACT,gBAAgB,QAAQ,IACxB,WACE,KAAK,UAAU,QAAQ,IACvB;AAEN,UAAI,UAAU;AACZ,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAEA,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,MAAM,KAAK;AAAA,UAC1B;AAAA,UACA,SAAS,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAAA,UACzC,QAAQ,YAAY,QAAQ,OAAO;AAAA,UACnC;AAAA,QACF,CAAC;AAAA,MACH,SAAS,YAAY;AACnB,cAAM,gBACJ,sBAAsB,QAAQ,aAAa,IAAI,MAAM,OAAO,UAAU,CAAC;AAEzE,cAAM,UACJ,cAAc,SAAS,iBACnB,yBAAyB,GAAG,iBAAiB,MAAM,KACnD,cAAc;AAGpB,cAAM,IAAI,MAAM,GAAG,OAAO,UAAU,KAAK,IAAI,IAAI,KAAK,QAAQ;AAAA;AAAA,UAE5D,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AAEnD;AAAA,UACE,IAAI;AAAA,YACF,sBAAsB,GAAG,YAAY,SAAS,MAAM,MAAM,MAAM,SAAS,KAAK,CAAC;AAAA,YAC/E,SAAS;AAAA,UACX;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,SAAS,IAAI;AAEhB,cAAM,IAAI;AAAA,UACR,sBAAsB,GAAG,YAAY,SAAS,MAAM,MAAM,MAAM,SAAS,KAAK,CAAC;AAAA,UAC/E,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IAEA;AAAA,MACE,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,SAAS,CAAC,UAAiB;AACzB,eAAO;AAAA,UACL,2BAA2B,GAAG,iBAAiB,MAAM,mBAAkB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,QACjG;AACA,eAAO,MAAM,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ createAsyncComparison
3
+ } from "./chunk-JOPTBOXW.js";
4
+ import "./chunk-6PWJAPHP.js";
5
+ import "./chunk-WJIEJMLG.js";
6
+ import "./chunk-QTTEOWAX.js";
7
+ export {
8
+ createAsyncComparison as default
9
+ };
10
+ //# sourceMappingURL=createAsyncComparison-XISBMLXA.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-KBSCVKHT.js";
4
- import "./chunk-WYDYZN3N.js";
5
- import "./chunk-D6LAGJC3.js";
3
+ } from "./chunk-6PWJAPHP.js";
4
+ import "./chunk-WJIEJMLG.js";
5
+ import "./chunk-QTTEOWAX.js";
6
6
 
7
7
  // src/network/createAsyncReport.ts
8
8
  function assertResultIsCreateAsyncReportResult(result) {
@@ -38,4 +38,4 @@ async function createAsyncReport(snapRequestIds, config, { afterSha, link, messa
38
38
  export {
39
39
  createAsyncReport as default
40
40
  };
41
- //# sourceMappingURL=createAsyncReport-PWLSEU4U.js.map
41
+ //# sourceMappingURL=createAsyncReport-A27NY62E.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-KBSCVKHT.js";
4
- import "./chunk-WYDYZN3N.js";
5
- import "./chunk-D6LAGJC3.js";
3
+ } from "./chunk-6PWJAPHP.js";
4
+ import "./chunk-WJIEJMLG.js";
5
+ import "./chunk-QTTEOWAX.js";
6
6
 
7
7
  // src/network/getFlakes.ts
8
8
  function formatFlakeOutput(flakes) {
@@ -70,4 +70,4 @@ export {
70
70
  getFlakes as default,
71
71
  formatFlakeOutput
72
72
  };
73
- //# sourceMappingURL=getFlakes-ISMCYQYN.js.map
73
+ //# sourceMappingURL=getFlakes-CPW3FFIF.js.map
package/dist/cli/main.js CHANGED
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-JTRP4JVC.js";
5
5
  import {
6
6
  fetchWithRetry
7
- } from "./chunk-WYDYZN3N.js";
7
+ } from "./chunk-WJIEJMLG.js";
8
8
  import {
9
9
  package_default
10
- } from "./chunk-D6LAGJC3.js";
10
+ } from "./chunk-QTTEOWAX.js";
11
11
 
12
12
  // src/cli/index.ts
13
13
  import path3 from "node:path";
@@ -1108,7 +1108,7 @@ function createReporter(opts = {}) {
1108
1108
 
1109
1109
  // src/cli/index.ts
1110
1110
  async function getVersion() {
1111
- const packageJson = await import("./package-QA5NMKSG.js");
1111
+ const packageJson = await import("./package-ZLQ7KI7I.js");
1112
1112
  return packageJson.default.version;
1113
1113
  }
1114
1114
  function parseDashdashCommandParts(rawArgs) {
@@ -1379,10 +1379,10 @@ async function main(rawArgs = process.argv, logger = console) {
1379
1379
  async function handleDefaultCommand(config, environment, logger) {
1380
1380
  logger.log("Running happo tests...");
1381
1381
  const [startJob, createAsyncComparison, createAsyncReport, prepareSnapRequests] = await Promise.all([
1382
- (await import("./startJob-3G7ZMTJL.js")).default,
1383
- (await import("./createAsyncComparison-2X5JW753.js")).default,
1384
- (await import("./createAsyncReport-PWLSEU4U.js")).default,
1385
- (await import("./prepareSnapRequests-LKEGFH3U.js")).default
1382
+ (await import("./startJob-NZDZNGVS.js")).default,
1383
+ (await import("./createAsyncComparison-XISBMLXA.js")).default,
1384
+ (await import("./createAsyncReport-A27NY62E.js")).default,
1385
+ (await import("./prepareSnapRequests-74QL6FGT.js")).default
1386
1386
  ]);
1387
1387
  await startJob(config, environment, logger);
1388
1388
  try {
@@ -1415,7 +1415,7 @@ async function handleDefaultCommand(config, environment, logger) {
1415
1415
  } catch (e) {
1416
1416
  const message = e instanceof Error ? e.message : String(e);
1417
1417
  logger.error(`${config.integration.type} run failed: ${message}`, e);
1418
- const cancelJob = (await import("./cancelJob-QSJ4H5RQ.js")).default;
1418
+ const cancelJob = (await import("./cancelJob-ORBIXVT5.js")).default;
1419
1419
  await cancelJob("failure", message, config, environment, logger);
1420
1420
  process.exitCode = 1;
1421
1421
  return;
@@ -1426,7 +1426,7 @@ async function handleFinalizeCommand(config, environment, logger) {
1426
1426
  logger.log("Config:", config);
1427
1427
  logger.log("Environment:", environment);
1428
1428
  try {
1429
- const finalizeAll = (await import("./wrapper-AA77AANX.js")).finalizeAll;
1429
+ const finalizeAll = (await import("./wrapper-PXCRJ4BX.js")).finalizeAll;
1430
1430
  await finalizeAll({ happoConfig: config, environment, logger });
1431
1431
  } catch (e) {
1432
1432
  logger.error(e instanceof Error ? e.message : String(e), e);
@@ -1454,7 +1454,7 @@ async function handleFlakeCommand(config, {
1454
1454
  process.exitCode = 1;
1455
1455
  return;
1456
1456
  }
1457
- const { default: getFlakes, formatFlakeOutput } = await import("./getFlakes-ISMCYQYN.js");
1457
+ const { default: getFlakes, formatFlakeOutput } = await import("./getFlakes-CPW3FFIF.js");
1458
1458
  const project = allProjects ? void 0 : projectOverride ?? config.project;
1459
1459
  const flakes = await getFlakes(
1460
1460
  {
@@ -1496,7 +1496,7 @@ async function handleE2ECommand(config, environment, dashdashCommandParts, confi
1496
1496
  logger.log("Config:", config);
1497
1497
  logger.log("Environment:", environment);
1498
1498
  logger.log("Dashdash command parts:", dashdashCommandParts);
1499
- const runWithWrapper = (await import("./wrapper-AA77AANX.js")).default;
1499
+ const runWithWrapper = (await import("./wrapper-PXCRJ4BX.js")).default;
1500
1500
  const exitCode = await runWithWrapper(
1501
1501
  dashdashCommandParts,
1502
1502
  config,
@@ -0,0 +1,7 @@
1
+ import {
2
+ package_default
3
+ } from "./chunk-QTTEOWAX.js";
4
+ export {
5
+ package_default as default
6
+ };
7
+ //# sourceMappingURL=package-ZLQ7KI7I.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-KBSCVKHT.js";
4
- import "./chunk-WYDYZN3N.js";
5
- import "./chunk-D6LAGJC3.js";
3
+ } from "./chunk-6PWJAPHP.js";
4
+ import "./chunk-WJIEJMLG.js";
5
+ import "./chunk-QTTEOWAX.js";
6
6
 
7
7
  // src/network/prepareSnapRequests.ts
8
- import fs5 from "node:fs";
9
- import path5 from "node:path";
8
+ import fs6 from "node:fs";
9
+ import path6 from "node:path";
10
10
 
11
11
  // src/utils/createHash.ts
12
12
  import crypto from "node:crypto";
@@ -65,7 +65,8 @@ var RemoteBrowserTarget = class {
65
65
  staticPackage,
66
66
  snapPayloads,
67
67
  pages,
68
- targetName
68
+ targetName,
69
+ estimatedSnapsCount
69
70
  }, config) {
70
71
  const boundMakeRequest = async ({
71
72
  slice,
@@ -91,6 +92,7 @@ var RemoteBrowserTarget = class {
91
92
  type: pageSlice && pageSlice.extendsSha ? "extends-report" : `browser-${this.browserName}`,
92
93
  targetName,
93
94
  payloadHash,
95
+ estimatedSnapsCount: staticPackage && estimatedSnapsCount != null ? estimatedSnapsCount : void 0,
94
96
  payload: new File([payloadString], "payload.json", {
95
97
  type: "application/json"
96
98
  })
@@ -153,8 +155,8 @@ var RemoteBrowserTarget = class {
153
155
 
154
156
  // src/storybook/index.ts
155
157
  import { spawn } from "node:child_process";
156
- import fs3 from "node:fs";
157
- import path3 from "node:path";
158
+ import fs4 from "node:fs";
159
+ import path4 from "node:path";
158
160
 
159
161
  // src/storybook/getStorybookBuildCommandParts.ts
160
162
  import fs from "node:fs";
@@ -191,11 +193,27 @@ function getStorybookBuildCommandParts(packageJsonPath = path.join(process.cwd()
191
193
  return ["storybook", "build"];
192
194
  }
193
195
 
194
- // src/storybook/getStorybookVersionFromPackageJson.ts
196
+ // src/storybook/getStorybookStoryCount.ts
195
197
  import fs2 from "node:fs";
196
198
  import path2 from "node:path";
197
- function getStorybookVersionFromPackageJson(packageJsonPath = path2.join(process.cwd(), "package.json")) {
198
- const data = fs2.readFileSync(packageJsonPath, "utf8");
199
+ async function getStorybookStoryCount(packageDir) {
200
+ const indexPath = path2.join(packageDir, "index.json");
201
+ try {
202
+ const content = await fs2.promises.readFile(indexPath, "utf8");
203
+ const data = JSON.parse(content);
204
+ const entries = data.entries ?? data.stories ?? {};
205
+ return Object.values(entries).filter((e) => e.type === "story").length;
206
+ } catch (error) {
207
+ console.warn("Failed to get estimated snaps count from Storybook:", error);
208
+ return void 0;
209
+ }
210
+ }
211
+
212
+ // src/storybook/getStorybookVersionFromPackageJson.ts
213
+ import fs3 from "node:fs";
214
+ import path3 from "node:path";
215
+ function getStorybookVersionFromPackageJson(packageJsonPath = path3.join(process.cwd(), "package.json")) {
216
+ const data = fs3.readFileSync(packageJsonPath, "utf8");
199
217
  const packageJson = JSON.parse(data);
200
218
  const combinedDependencies = {
201
219
  ...packageJson.dependencies,
@@ -243,7 +261,7 @@ function buildStorybook({
243
261
  outputDir
244
262
  }) {
245
263
  return new Promise((resolve, reject) => {
246
- fs3.rmSync(outputDir, { recursive: true, force: true });
264
+ fs4.rmSync(outputDir, { recursive: true, force: true });
247
265
  const buildCommandParts = resolveBuildCommandParts();
248
266
  if (!buildCommandParts[0]) {
249
267
  throw new Error("Failed to resolve build command parts");
@@ -258,7 +276,7 @@ function buildStorybook({
258
276
  if (staticDir) {
259
277
  params.push("--static-dir", staticDir);
260
278
  }
261
- let binary = fs3.existsSync("yarn.lock") ? "yarn" : "npx";
279
+ let binary = fs4.existsSync("yarn.lock") ? "yarn" : "npx";
262
280
  if (buildCommandParts[0].includes("node_modules")) {
263
281
  binary = buildCommandParts[0];
264
282
  params.shift();
@@ -273,7 +291,7 @@ function buildStorybook({
273
291
  spawned.on("exit", (code) => {
274
292
  if (code === 0) {
275
293
  try {
276
- fs3.unlinkSync(path3.join(outputDir, "project.json"));
294
+ fs4.unlinkSync(path4.join(outputDir, "project.json"));
277
295
  } catch (error) {
278
296
  console.warn(
279
297
  `Ignoring error when attempting to remove project.json: ${error}`
@@ -296,8 +314,8 @@ async function buildStorybookPackage({
296
314
  if (!usePrebuiltPackage) {
297
315
  await buildStorybook({ configDir, staticDir, outputDir });
298
316
  }
299
- const iframePath = path3.join(outputDir, "iframe.html");
300
- if (!fs3.existsSync(iframePath)) {
317
+ const iframePath = path4.join(outputDir, "iframe.html");
318
+ if (!fs4.existsSync(iframePath)) {
301
319
  throw new Error(
302
320
  "Failed to build static storybook package (missing iframe.html)"
303
321
  );
@@ -305,8 +323,8 @@ async function buildStorybookPackage({
305
323
  try {
306
324
  const skipped = typeof skip === "function" ? await skip() : Array.isArray(skip) ? skip : [];
307
325
  assertSkippedIsSkipItems(skipped);
308
- const iframeContent = fs3.readFileSync(iframePath, "utf8");
309
- fs3.writeFileSync(
326
+ const iframeContent = fs4.readFileSync(iframePath, "utf8");
327
+ fs4.writeFileSync(
310
328
  iframePath,
311
329
  iframeContent.replace(
312
330
  "<head>",
@@ -319,7 +337,12 @@ async function buildStorybookPackage({
319
337
  `
320
338
  )
321
339
  );
322
- return outputDir;
340
+ const estimatedSnapsCount = await getStorybookStoryCount(outputDir);
341
+ const result = { packageDir: outputDir };
342
+ if (estimatedSnapsCount != null) {
343
+ result.estimatedSnapsCount = estimatedSnapsCount;
344
+ }
345
+ return result;
323
346
  } catch (e) {
324
347
  console.error(e);
325
348
  throw e;
@@ -327,8 +350,8 @@ async function buildStorybookPackage({
327
350
  }
328
351
 
329
352
  // src/utils/deterministicArchive.ts
330
- import fs4 from "node:fs";
331
- import path4 from "node:path";
353
+ import fs5 from "node:fs";
354
+ import path5 from "node:path";
332
355
  import { zip } from "fflate";
333
356
 
334
357
  // src/utils/validateArchive.ts
@@ -359,19 +382,19 @@ function validateArchive(totalBytes, entries) {
359
382
  // src/utils/deterministicArchive.ts
360
383
  var FILE_CREATION_DATE = new Date(2019, 1, 8, 13, 31, 55);
361
384
  async function resolveFilesRecursiveForDir(dirOrFile) {
362
- const resolvedDirOrFile = path4.resolve(dirOrFile);
363
- const isDir = (await fs4.promises.lstat(resolvedDirOrFile)).isDirectory();
385
+ const resolvedDirOrFile = path5.resolve(dirOrFile);
386
+ const isDir = (await fs5.promises.lstat(resolvedDirOrFile)).isDirectory();
364
387
  if (isDir) {
365
388
  const fileEntries = [];
366
- for await (const fileType of fs4.promises.glob("**/*", {
389
+ for await (const fileType of fs5.promises.glob("**/*", {
367
390
  cwd: resolvedDirOrFile,
368
391
  withFileTypes: true
369
392
  })) {
370
393
  if (fileType.isFile()) {
371
394
  const fullPath = `${fileType.parentPath}/${fileType.name}`;
372
395
  fileEntries.push({
373
- name: path4.relative(resolvedDirOrFile, fullPath),
374
- stream: fs4.createReadStream(fullPath)
396
+ name: path5.relative(resolvedDirOrFile, fullPath),
397
+ stream: fs5.createReadStream(fullPath)
375
398
  });
376
399
  }
377
400
  }
@@ -379,8 +402,8 @@ async function resolveFilesRecursiveForDir(dirOrFile) {
379
402
  }
380
403
  return [
381
404
  {
382
- name: path4.relative(process.cwd(), resolvedDirOrFile),
383
- stream: fs4.createReadStream(resolvedDirOrFile)
405
+ name: path5.relative(process.cwd(), resolvedDirOrFile),
406
+ stream: fs5.createReadStream(resolvedDirOrFile)
384
407
  }
385
408
  ];
386
409
  }
@@ -632,9 +655,9 @@ async function uploadAssets(buffer, options, config) {
632
655
  }
633
656
 
634
657
  // src/network/prepareSnapRequests.ts
635
- async function fileExists(path6) {
658
+ async function fileExists(path7) {
636
659
  try {
637
- await fs5.promises.stat(path6);
660
+ await fs6.promises.stat(path7);
638
661
  return true;
639
662
  } catch (error) {
640
663
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -644,7 +667,7 @@ async function fileExists(path6) {
644
667
  }
645
668
  }
646
669
  async function createIframeHTML(rootDir, entryPoint, logger) {
647
- const iframePath = path5.join(rootDir, "iframe.html");
670
+ const iframePath = path6.join(rootDir, "iframe.html");
648
671
  if (await fileExists(iframePath)) {
649
672
  logger.info(`Using existing iframe.html at '${iframePath}'`);
650
673
  return;
@@ -660,14 +683,18 @@ async function createIframeHTML(rootDir, entryPoint, logger) {
660
683
  <script src="${entryPoint}"></script>
661
684
  </body>
662
685
  </html>`;
663
- await fs5.promises.mkdir(rootDir, { recursive: true });
664
- await fs5.promises.writeFile(iframePath, iframeContent);
686
+ await fs6.promises.mkdir(rootDir, { recursive: true });
687
+ await fs6.promises.writeFile(iframePath, iframeContent);
665
688
  }
666
689
  async function buildPackage({ integration }, logger) {
667
690
  if (integration.type === "custom") {
668
- const { rootDir, entryPoint } = await integration.build();
691
+ const { rootDir, entryPoint, estimatedSnapsCount } = await integration.build();
669
692
  await createIframeHTML(rootDir, entryPoint, logger);
670
- return rootDir;
693
+ const result = { packageDir: rootDir };
694
+ if (estimatedSnapsCount != null) {
695
+ result.estimatedSnapsCount = estimatedSnapsCount;
696
+ }
697
+ return result;
671
698
  }
672
699
  if (integration.type === "storybook") {
673
700
  return await buildStorybookPackage(integration);
@@ -675,7 +702,7 @@ async function buildPackage({ integration }, logger) {
675
702
  throw new Error(`Unsupported integration type: ${integration.type}`);
676
703
  }
677
704
  async function validatePackage(packageDir) {
678
- const iframePath = path5.join(packageDir, "iframe.html");
705
+ const iframePath = path6.join(packageDir, "iframe.html");
679
706
  if (!await fileExists(iframePath)) {
680
707
  throw new Error(
681
708
  `Could not find iframe.html in static package at '${iframePath}'`
@@ -683,10 +710,10 @@ async function validatePackage(packageDir) {
683
710
  }
684
711
  }
685
712
  async function preparePackage(config, logger) {
686
- const packageDir = await buildPackage(config, logger);
713
+ const { packageDir, estimatedSnapsCount } = await buildPackage(config, logger);
687
714
  await validatePackage(packageDir);
688
715
  const { buffer, hash } = await deterministicArchive([packageDir]);
689
- return await uploadAssets(
716
+ const packagePath = await uploadAssets(
690
717
  buffer,
691
718
  {
692
719
  hash,
@@ -694,10 +721,15 @@ async function preparePackage(config, logger) {
694
721
  },
695
722
  config
696
723
  );
724
+ const result = { packagePath };
725
+ if (estimatedSnapsCount != null) {
726
+ result.estimatedSnapsCount = estimatedSnapsCount;
727
+ }
728
+ return result;
697
729
  }
698
730
  async function prepareSnapRequests(config) {
699
731
  const logger = new Logger();
700
- const packagePath = config.integration.type === "pages" ? null : await preparePackage(config, logger);
732
+ const prepareResult = config.integration.type === "pages" ? null : await preparePackage(config, logger);
701
733
  const targetNames = Object.keys(config.targets);
702
734
  const tl = targetNames.length;
703
735
  logger.info(
@@ -718,8 +750,11 @@ async function prepareSnapRequests(config) {
718
750
  const targetParams = {
719
751
  targetName: name
720
752
  };
721
- if (packagePath) {
722
- targetParams.staticPackage = packagePath;
753
+ if (prepareResult) {
754
+ targetParams.staticPackage = prepareResult.packagePath;
755
+ if (prepareResult.estimatedSnapsCount != null) {
756
+ targetParams.estimatedSnapsCount = prepareResult.estimatedSnapsCount;
757
+ }
723
758
  }
724
759
  if (config.integration.type === "pages") {
725
760
  targetParams.pages = config.integration.pages;
@@ -737,4 +772,4 @@ async function prepareSnapRequests(config) {
737
772
  export {
738
773
  prepareSnapRequests as default
739
774
  };
740
- //# sourceMappingURL=prepareSnapRequests-LKEGFH3U.js.map
775
+ //# sourceMappingURL=prepareSnapRequests-74QL6FGT.js.map