happo 6.6.0 → 6.6.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 (40) hide show
  1. package/dist/cli/cancelJob-DETLA3XZ.js +10 -0
  2. package/dist/cli/{chunk-OXGH6FW4.js → chunk-2LNQIG6R.js} +2 -2
  3. package/dist/cli/{chunk-PRPDWPU3.js → chunk-JMN6VM22.js} +3 -3
  4. package/dist/cli/{chunk-QC2HOKDQ.js → chunk-MCYQSPED.js} +2 -2
  5. package/dist/cli/{chunk-LCNHMIOU.js → chunk-MGNFR3W2.js} +2 -2
  6. package/dist/cli/{chunk-DUWOS4XT.js → chunk-OJHKEE3W.js} +3 -2
  7. package/dist/cli/chunk-OJHKEE3W.js.map +7 -0
  8. package/dist/cli/{chunk-AFAI3HL3.js → chunk-SE7XKHF6.js} +2 -2
  9. package/dist/cli/createAsyncComparison-B3USWOAI.js +10 -0
  10. package/dist/cli/{createAsyncReport-IQO7YVCA.js → createAsyncReport-3FKLGSYD.js} +4 -4
  11. package/dist/cli/{getFlakes-HICLTPZC.js → getFlakes-5DA34KWE.js} +4 -4
  12. package/dist/cli/main.js +11 -11
  13. package/dist/cli/package-CY7G2FGG.js +7 -0
  14. package/dist/cli/{prepareSnapRequests-VFWDWE5X.js → prepareSnapRequests-RSZU5TQG.js} +16 -5
  15. package/dist/cli/{prepareSnapRequests-VFWDWE5X.js.map → prepareSnapRequests-RSZU5TQG.js.map} +3 -3
  16. package/dist/cli/startJob-OPTUE4PO.js +10 -0
  17. package/dist/cli/{wrapper-IQJTUXE4.js → wrapper-QAPBXQCV.js} +7 -7
  18. package/dist/cypress/task.js +14 -2
  19. package/dist/cypress/task.js.map +3 -3
  20. package/dist/network/uploadAssets.d.ts.map +1 -1
  21. package/dist/playwright/index.js +14 -2
  22. package/dist/playwright/index.js.map +3 -3
  23. package/package.json +2 -1
  24. package/dist/cli/cancelJob-HZDX6274.js +0 -10
  25. package/dist/cli/chunk-DUWOS4XT.js.map +0 -7
  26. package/dist/cli/createAsyncComparison-FQQHINTM.js +0 -10
  27. package/dist/cli/package-RZI6QOJX.js +0 -7
  28. package/dist/cli/startJob-QZA4POSE.js +0 -10
  29. /package/dist/cli/{cancelJob-HZDX6274.js.map → cancelJob-DETLA3XZ.js.map} +0 -0
  30. /package/dist/cli/{chunk-OXGH6FW4.js.map → chunk-2LNQIG6R.js.map} +0 -0
  31. /package/dist/cli/{chunk-PRPDWPU3.js.map → chunk-JMN6VM22.js.map} +0 -0
  32. /package/dist/cli/{chunk-QC2HOKDQ.js.map → chunk-MCYQSPED.js.map} +0 -0
  33. /package/dist/cli/{chunk-LCNHMIOU.js.map → chunk-MGNFR3W2.js.map} +0 -0
  34. /package/dist/cli/{chunk-AFAI3HL3.js.map → chunk-SE7XKHF6.js.map} +0 -0
  35. /package/dist/cli/{createAsyncComparison-FQQHINTM.js.map → createAsyncComparison-B3USWOAI.js.map} +0 -0
  36. /package/dist/cli/{createAsyncReport-IQO7YVCA.js.map → createAsyncReport-3FKLGSYD.js.map} +0 -0
  37. /package/dist/cli/{getFlakes-HICLTPZC.js.map → getFlakes-5DA34KWE.js.map} +0 -0
  38. /package/dist/cli/{package-RZI6QOJX.js.map → package-CY7G2FGG.js.map} +0 -0
  39. /package/dist/cli/{startJob-QZA4POSE.js.map → startJob-OPTUE4PO.js.map} +0 -0
  40. /package/dist/cli/{wrapper-IQJTUXE4.js.map → wrapper-QAPBXQCV.js.map} +0 -0
@@ -0,0 +1,10 @@
1
+ import {
2
+ cancelJob
3
+ } from "./chunk-JMN6VM22.js";
4
+ import "./chunk-2LNQIG6R.js";
5
+ import "./chunk-SE7XKHF6.js";
6
+ import "./chunk-OJHKEE3W.js";
7
+ export {
8
+ cancelJob as default
9
+ };
10
+ //# sourceMappingURL=cancelJob-DETLA3XZ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  fetchWithRetry
3
- } from "./chunk-AFAI3HL3.js";
3
+ } from "./chunk-SE7XKHF6.js";
4
4
 
5
5
  // src/network/getSignedToken.ts
6
6
  import { SignJWT } from "jose";
@@ -81,4 +81,4 @@ async function makeHappoAPIRequest({ url, path, method = "GET", formData, body }
81
81
  export {
82
82
  makeHappoAPIRequest
83
83
  };
84
- //# sourceMappingURL=chunk-OXGH6FW4.js.map
84
+ //# sourceMappingURL=chunk-2LNQIG6R.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-OXGH6FW4.js";
3
+ } from "./chunk-2LNQIG6R.js";
4
4
  import {
5
5
  ErrorWithStatusCode
6
- } from "./chunk-AFAI3HL3.js";
6
+ } from "./chunk-SE7XKHF6.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-PRPDWPU3.js.map
46
+ //# sourceMappingURL=chunk-JMN6VM22.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-OXGH6FW4.js";
3
+ } from "./chunk-2LNQIG6R.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-QC2HOKDQ.js.map
63
+ //# sourceMappingURL=chunk-MCYQSPED.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-OXGH6FW4.js";
3
+ } from "./chunk-2LNQIG6R.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-LCNHMIOU.js.map
39
+ //# sourceMappingURL=chunk-MGNFR3W2.js.map
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "happo",
4
- version: "6.6.0",
4
+ version: "6.6.1",
5
5
  description: "Catch unexpected visual and accessibility changes and UI bugs",
6
6
  license: "MIT",
7
7
  repository: {
@@ -74,6 +74,7 @@ var package_default = {
74
74
  "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",
75
75
  "test:cypress:open": "cypress open -C src/cypress/__cypress__/cypress.config.ts",
76
76
  "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",
77
+ "test:playwright:nonce": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright-nonce.config.ts --nonce $HAPPO_NONCE e2e -- playwright test && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright-nonce.config.ts --nonce $HAPPO_NONCE finalize",
77
78
  "test:storybook": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts",
78
79
  "test:pages": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts",
79
80
  tsc: "tsc --build tsconfig.json"
@@ -183,4 +184,4 @@ var package_default = {
183
184
  export {
184
185
  package_default
185
186
  };
186
- //# sourceMappingURL=chunk-DUWOS4XT.js.map
187
+ //# sourceMappingURL=chunk-OJHKEE3W.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../package.json"],
4
+ "sourcesContent": ["{\n \"name\": \"happo\",\n \"version\": \"6.6.1\",\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\": \"node ./scripts/build.ts\",\n \"build:types\": \"pnpm tsc --pretty\",\n \"build:watch\": \"tsc --build --watch\",\n \"clean\": \"node ./scripts/clean.ts\",\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:playwright:nonce\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright-nonce.config.ts --nonce $HAPPO_NONCE e2e -- playwright test && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright-nonce.config.ts --nonce $HAPPO_NONCE finalize\",\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\": \"^29.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
+ "mappings": ";AAAA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,SAAW;AAAA,EACX,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,EACR,UAAY;AAAA,EACZ,KAAO;AAAA,IACL,OAAS;AAAA,EACX;AAAA,EACA,MAAQ;AAAA,EACR,MAAQ;AAAA,EACR,OAAS;AAAA,EACT,SAAW;AAAA,IACT,KAAK;AAAA,MACH,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,aAAa;AAAA,MACX,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,kBAAkB;AAAA,MAChB,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,gBAAgB;AAAA,MACd,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,YAAY;AAAA,MACV,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,qBAAqB;AAAA,MACnB,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,yBAAyB;AAAA,MACvB,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,sBAAsB;AAAA,MACpB,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,IACA,wBAAwB;AAAA,MACtB,OAAS;AAAA,MACT,SAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,gBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,MAAQ;AAAA,IACR,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,KAAO;AAAA,EACT;AAAA,EACA,cAAgB;AAAA,IACd,MAAQ;AAAA,MACN;AAAA,IACF;AAAA,IACA,SAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,YAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,UAAY;AAAA,IACV,YAAc;AAAA,IACd,aAAe;AAAA,IACf,eAAiB;AAAA,IACjB,aAAe;AAAA,EACjB;AAAA,EACA,iBAAmB;AAAA,IACjB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,qBAAqB;AAAA,IACrB,2BAA2B;AAAA,IAC3B,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,SAAW;AAAA,IACX,SAAW;AAAA,IACX,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,oCAAoC;AAAA,IACpC,yBAAyB;AAAA,IACzB,MAAQ;AAAA,IACR,OAAS;AAAA,IACT,YAAc;AAAA,IACd,UAAY;AAAA,IACZ,OAAS;AAAA,IACT,aAAa;AAAA,IACb,wBAAwB;AAAA,IACxB,WAAa;AAAA,IACb,YAAc;AAAA,IACd,qBAAqB;AAAA,EACvB;AAAA,EACA,cAAgB;AAAA,IACd,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,UAAY;AAAA,IACZ,QAAU;AAAA,IACV,MAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,QAAU;AAAA,EACZ;AAAA,EACA,WAAa;AAAA,IACX,aAAe;AAAA,IACf,MAAQ;AAAA,IACR,qBAAuB;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,uBAAyB,CAAC;AAAA,EAC5B;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AACF;",
6
+ "names": []
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./chunk-DUWOS4XT.js";
3
+ } from "./chunk-OJHKEE3W.js";
4
4
 
5
5
  // src/network/fetchWithRetry.ts
6
6
  import asyncRetry from "async-retry";
@@ -95,4 +95,4 @@ export {
95
95
  ErrorWithStatusCode,
96
96
  fetchWithRetry
97
97
  };
98
- //# sourceMappingURL=chunk-AFAI3HL3.js.map
98
+ //# sourceMappingURL=chunk-SE7XKHF6.js.map
@@ -0,0 +1,10 @@
1
+ import {
2
+ createAsyncComparison
3
+ } from "./chunk-MCYQSPED.js";
4
+ import "./chunk-2LNQIG6R.js";
5
+ import "./chunk-SE7XKHF6.js";
6
+ import "./chunk-OJHKEE3W.js";
7
+ export {
8
+ createAsyncComparison as default
9
+ };
10
+ //# sourceMappingURL=createAsyncComparison-B3USWOAI.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-OXGH6FW4.js";
4
- import "./chunk-AFAI3HL3.js";
5
- import "./chunk-DUWOS4XT.js";
3
+ } from "./chunk-2LNQIG6R.js";
4
+ import "./chunk-SE7XKHF6.js";
5
+ import "./chunk-OJHKEE3W.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-IQO7YVCA.js.map
41
+ //# sourceMappingURL=createAsyncReport-3FKLGSYD.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-OXGH6FW4.js";
4
- import "./chunk-AFAI3HL3.js";
5
- import "./chunk-DUWOS4XT.js";
3
+ } from "./chunk-2LNQIG6R.js";
4
+ import "./chunk-SE7XKHF6.js";
5
+ import "./chunk-OJHKEE3W.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-HICLTPZC.js.map
73
+ //# sourceMappingURL=getFlakes-5DA34KWE.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-AFAI3HL3.js";
7
+ } from "./chunk-SE7XKHF6.js";
8
8
  import {
9
9
  package_default
10
- } from "./chunk-DUWOS4XT.js";
10
+ } from "./chunk-OJHKEE3W.js";
11
11
 
12
12
  // src/cli/index.ts
13
13
  import path3 from "node:path";
@@ -1189,7 +1189,7 @@ function createReporter(opts = {}) {
1189
1189
 
1190
1190
  // src/cli/index.ts
1191
1191
  async function getVersion() {
1192
- const packageJson = await import("./package-RZI6QOJX.js");
1192
+ const packageJson = await import("./package-CY7G2FGG.js");
1193
1193
  return packageJson.default.version;
1194
1194
  }
1195
1195
  function parseDashdashCommandParts(rawArgs) {
@@ -1431,10 +1431,10 @@ async function main(rawArgs = process.argv, logger = console) {
1431
1431
  async function handleDefaultCommand(config, environment, logger) {
1432
1432
  logger.log("Running happo tests...");
1433
1433
  const [startJob, createAsyncComparison, createAsyncReport, prepareSnapRequests] = await Promise.all([
1434
- (await import("./startJob-QZA4POSE.js")).default,
1435
- (await import("./createAsyncComparison-FQQHINTM.js")).default,
1436
- (await import("./createAsyncReport-IQO7YVCA.js")).default,
1437
- (await import("./prepareSnapRequests-VFWDWE5X.js")).default
1434
+ (await import("./startJob-OPTUE4PO.js")).default,
1435
+ (await import("./createAsyncComparison-B3USWOAI.js")).default,
1436
+ (await import("./createAsyncReport-3FKLGSYD.js")).default,
1437
+ (await import("./prepareSnapRequests-RSZU5TQG.js")).default
1438
1438
  ]);
1439
1439
  await startJob(config, environment, logger);
1440
1440
  try {
@@ -1467,7 +1467,7 @@ async function handleDefaultCommand(config, environment, logger) {
1467
1467
  } catch (e) {
1468
1468
  const message = e instanceof Error ? e.message : String(e);
1469
1469
  logger.error(`${config.integration.type} run failed: ${message}`, e);
1470
- const cancelJob = (await import("./cancelJob-HZDX6274.js")).default;
1470
+ const cancelJob = (await import("./cancelJob-DETLA3XZ.js")).default;
1471
1471
  await cancelJob("failure", message, config, environment, logger);
1472
1472
  process.exitCode = 1;
1473
1473
  return;
@@ -1478,7 +1478,7 @@ async function handleFinalizeCommand(config, environment, logger) {
1478
1478
  logger.log("Config:", config);
1479
1479
  logger.log("Environment:", environment);
1480
1480
  try {
1481
- const finalizeAll = (await import("./wrapper-IQJTUXE4.js")).finalizeAll;
1481
+ const finalizeAll = (await import("./wrapper-QAPBXQCV.js")).finalizeAll;
1482
1482
  await finalizeAll({ happoConfig: config, environment, logger });
1483
1483
  } catch (e) {
1484
1484
  logger.error(e instanceof Error ? e.message : String(e), e);
@@ -1506,7 +1506,7 @@ async function handleFlakeCommand(config, {
1506
1506
  process.exitCode = 1;
1507
1507
  return;
1508
1508
  }
1509
- const { default: getFlakes, formatFlakeOutput } = await import("./getFlakes-HICLTPZC.js");
1509
+ const { default: getFlakes, formatFlakeOutput } = await import("./getFlakes-5DA34KWE.js");
1510
1510
  const project = allProjects ? void 0 : projectOverride ?? config.project;
1511
1511
  const flakes = await getFlakes(
1512
1512
  {
@@ -1548,7 +1548,7 @@ async function handleE2ECommand(config, environment, dashdashCommandParts, confi
1548
1548
  logger.log("Config:", config);
1549
1549
  logger.log("Environment:", environment);
1550
1550
  logger.log("Dashdash command parts:", dashdashCommandParts);
1551
- const runWithWrapper = (await import("./wrapper-IQJTUXE4.js")).default;
1551
+ const runWithWrapper = (await import("./wrapper-QAPBXQCV.js")).default;
1552
1552
  const exitCode = await runWithWrapper(
1553
1553
  dashdashCommandParts,
1554
1554
  config,
@@ -0,0 +1,7 @@
1
+ import {
2
+ package_default
3
+ } from "./chunk-OJHKEE3W.js";
4
+ export {
5
+ package_default as default
6
+ };
7
+ //# sourceMappingURL=package-CY7G2FGG.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-OXGH6FW4.js";
3
+ } from "./chunk-2LNQIG6R.js";
4
4
  import {
5
5
  ErrorWithStatusCode
6
- } from "./chunk-AFAI3HL3.js";
7
- import "./chunk-DUWOS4XT.js";
6
+ } from "./chunk-SE7XKHF6.js";
7
+ import "./chunk-OJHKEE3W.js";
8
8
 
9
9
  // src/network/prepareSnapRequests.ts
10
10
  import fs6 from "node:fs";
@@ -665,6 +665,7 @@ var Logger = class {
665
665
  };
666
666
 
667
667
  // src/network/uploadAssets.ts
668
+ import { createHash as createHash2 } from "node:crypto";
668
669
  import retry from "async-retry";
669
670
  async function uploadAssets(buffer, options, config) {
670
671
  const { project } = config;
@@ -698,7 +699,8 @@ async function uploadAssets(buffer, options, config) {
698
699
  body: buffer,
699
700
  headers: {
700
701
  "Content-Type": "application/zip"
701
- }
702
+ },
703
+ signal: AbortSignal.timeout(6e4)
702
704
  });
703
705
  if (!res.ok) {
704
706
  const error = new Error(
@@ -710,6 +712,15 @@ async function uploadAssets(buffer, options, config) {
710
712
  }
711
713
  throw error;
712
714
  }
715
+ const etag = res.headers.get("etag");
716
+ const expectedEtag = createHash2("md5").update(buffer).digest("hex");
717
+ if (!etag || !etag.includes(expectedEtag)) {
718
+ const error = new Error(
719
+ `S3 upload verification failed: expected ETag to include ${expectedEtag}, got ${etag ?? "(none)"}. A firewall may be intercepting the upload.`
720
+ );
721
+ bail(error);
722
+ return;
723
+ }
713
724
  return res;
714
725
  },
715
726
  {
@@ -857,4 +868,4 @@ async function prepareSnapRequests(config) {
857
868
  export {
858
869
  prepareSnapRequests as default
859
870
  };
860
- //# sourceMappingURL=prepareSnapRequests-VFWDWE5X.js.map
871
+ //# sourceMappingURL=prepareSnapRequests-RSZU5TQG.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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/getStorybookStoryCount.ts", "../../src/storybook/getStorybookVersionFromPackageJson.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 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}\n\nasync function buildPackage(\n { integration }: ConfigWithDefaults,\n logger: Logger,\n): Promise<BuildPackageResult> {\n if (integration.type === 'custom') {\n const { rootDir, entryPoint, estimatedSnapsCount } = await integration.build();\n await createIframeHTML(rootDir, entryPoint, logger);\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 return await buildStorybookPackage(integration);\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}\n\nasync function preparePackage(\n config: ConfigWithDefaults,\n logger: Logger,\n): Promise<PreparePackageResult> {\n const { packageDir, estimatedSnapsCount } = await buildPackage(config, logger);\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 return result;\n}\n\nexport default async function prepareSnapRequests(\n config: ConfigWithDefaults,\n): Promise<Array<number>> {\n const logger = new Logger();\n const prepareResult =\n config.integration.type === 'pages'\n ? null\n : await preparePackage(config, logger);\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 results: 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 snapRequestIds = await target.execute(targetParams, config);\n logger.start(` - ${logTag(config.project)}${name}`, { startTime });\n logger.success();\n results.push(...snapRequestIds);\n }),\n );\n logger.start(undefined, { startTime: outerStartTime });\n logger.success();\n return results;\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 getStorybookBuildCommandParts from './getStorybookBuildCommandParts.ts';\nimport getStorybookStoryCount from './getStorybookStoryCount.ts';\nimport getStorybookVersionFromPackageJson from './getStorybookVersionFromPackageJson.ts';\nimport type { SkipItems } from './isomorphic/types.ts';\n\nconst { HAPPO_DEBUG } = process.env;\n\nfunction assertSkippedIsSkipItems(skipped: unknown): asserts skipped is SkipItems {\n if (!Array.isArray(skipped)) {\n throw new TypeError(`The \\`skip\\` option didn't provide an array`);\n }\n\n if (skipped.some((item) => !item.component || !item.variant)) {\n throw new Error(\n `Each item provided by the \\`skip\\` option needs a \\`component\\` and a \\`variant\\` property`,\n );\n }\n}\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}\n\nexport default async function buildStorybookPackage({\n configDir = '.storybook',\n staticDir,\n outputDir = '.out',\n usePrebuiltPackage = false,\n skip,\n}: Omit<StorybookIntegration, 'type'>): 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 skipped =\n typeof skip === 'function' ? await skip() : Array.isArray(skip) ? skip : [];\n\n assertSkippedIsSkipItems(skipped);\n\n const iframeContent = await fs.promises.readFile(iframePath, 'utf8');\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(\n skipped,\n )};</script>\n `,\n ),\n );\n\n const estimatedSnapsCount = await getStorybookStoryCount(outputDir);\n\n const result: BuildStorybookPackageResult = { packageDir: outputDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\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\ninterface StorybookIndexEntry {\n type: string;\n}\n\ninterface StorybookIndex {\n entries?: Record<string, StorybookIndexEntry>;\n stories?: Record<string, StorybookIndexEntry>;\n}\n\n/**\n * Reads the storybook index.json from the given package directory and returns\n * the total number of story entries (excluding docs and other non-story types).\n * Returns undefined if the file cannot be read or parsed.\n */\nexport default async function getStorybookStoryCount(\n packageDir: string,\n): Promise<number | undefined> {\n const indexPath = path.join(packageDir, 'index.json');\n try {\n const content = await fs.promises.readFile(indexPath, 'utf8');\n const data = JSON.parse(content) as StorybookIndex;\n const entries = data.entries ?? data.stories ?? {};\n return Object.values(entries).filter((e) => e.type === 'story').length;\n } catch (error) {\n console.warn('Failed to get estimated snaps count from Storybook:', error);\n return undefined;\n }\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 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 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 });\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 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", "fs", "path", "HAPPO_DEBUG", "fs", "path", "fs", "path", "path", "fs", "path", "fs"]
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 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}\n\nasync function buildPackage(\n { integration }: ConfigWithDefaults,\n logger: Logger,\n): Promise<BuildPackageResult> {\n if (integration.type === 'custom') {\n const { rootDir, entryPoint, estimatedSnapsCount } = await integration.build();\n await createIframeHTML(rootDir, entryPoint, logger);\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 return await buildStorybookPackage(integration);\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}\n\nasync function preparePackage(\n config: ConfigWithDefaults,\n logger: Logger,\n): Promise<PreparePackageResult> {\n const { packageDir, estimatedSnapsCount } = await buildPackage(config, logger);\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 return result;\n}\n\nexport default async function prepareSnapRequests(\n config: ConfigWithDefaults,\n): Promise<Array<number>> {\n const logger = new Logger();\n const prepareResult =\n config.integration.type === 'pages'\n ? null\n : await preparePackage(config, logger);\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 results: 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 snapRequestIds = await target.execute(targetParams, config);\n logger.start(` - ${logTag(config.project)}${name}`, { startTime });\n logger.success();\n results.push(...snapRequestIds);\n }),\n );\n logger.start(undefined, { startTime: outerStartTime });\n logger.success();\n return results;\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 getStorybookBuildCommandParts from './getStorybookBuildCommandParts.ts';\nimport getStorybookStoryCount from './getStorybookStoryCount.ts';\nimport getStorybookVersionFromPackageJson from './getStorybookVersionFromPackageJson.ts';\nimport type { SkipItems } from './isomorphic/types.ts';\n\nconst { HAPPO_DEBUG } = process.env;\n\nfunction assertSkippedIsSkipItems(skipped: unknown): asserts skipped is SkipItems {\n if (!Array.isArray(skipped)) {\n throw new TypeError(`The \\`skip\\` option didn't provide an array`);\n }\n\n if (skipped.some((item) => !item.component || !item.variant)) {\n throw new Error(\n `Each item provided by the \\`skip\\` option needs a \\`component\\` and a \\`variant\\` property`,\n );\n }\n}\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}\n\nexport default async function buildStorybookPackage({\n configDir = '.storybook',\n staticDir,\n outputDir = '.out',\n usePrebuiltPackage = false,\n skip,\n}: Omit<StorybookIntegration, 'type'>): 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 skipped =\n typeof skip === 'function' ? await skip() : Array.isArray(skip) ? skip : [];\n\n assertSkippedIsSkipItems(skipped);\n\n const iframeContent = await fs.promises.readFile(iframePath, 'utf8');\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(\n skipped,\n )};</script>\n `,\n ),\n );\n\n const estimatedSnapsCount = await getStorybookStoryCount(outputDir);\n\n const result: BuildStorybookPackageResult = { packageDir: outputDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\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\ninterface StorybookIndexEntry {\n type: string;\n}\n\ninterface StorybookIndex {\n entries?: Record<string, StorybookIndexEntry>;\n stories?: Record<string, StorybookIndexEntry>;\n}\n\n/**\n * Reads the storybook index.json from the given package directory and returns\n * the total number of story entries (excluding docs and other non-story types).\n * Returns undefined if the file cannot be read or parsed.\n */\nexport default async function getStorybookStoryCount(\n packageDir: string,\n): Promise<number | undefined> {\n const indexPath = path.join(packageDir, 'index.json');\n try {\n const content = await fs.promises.readFile(indexPath, 'utf8');\n const data = JSON.parse(content) as StorybookIndex;\n const entries = data.entries ?? data.stories ?? {};\n return Object.values(entries).filter((e) => e.type === 'story').length;\n } catch (error) {\n console.warn('Failed to get estimated snaps count from Storybook:', error);\n return undefined;\n }\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 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", "fs", "path", "HAPPO_DEBUG", "fs", "path", "fs", "path", "path", "fs", "createHash", "createHash", "path", "fs"]
7
7
  }