happo 6.0.4 → 6.0.6

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 (37) hide show
  1. package/dist/cli/{cancelJob-GCTVJGYB.js → cancelJob-NIUI7GBR.js} +4 -3
  2. package/dist/cli/{cancelJob-GCTVJGYB.js.map → cancelJob-NIUI7GBR.js.map} +1 -1
  3. package/dist/cli/{chunk-TPF2272Y.js → chunk-6SJAK2WZ.js} +2 -2
  4. package/dist/cli/chunk-BLNR2H52.js +51 -0
  5. package/dist/cli/chunk-BLNR2H52.js.map +7 -0
  6. package/dist/cli/{chunk-DYCU4INF.js → chunk-FCZLLRXU.js} +8 -8
  7. package/dist/cli/chunk-FCZLLRXU.js.map +7 -0
  8. package/dist/cli/{chunk-TCHC2O3E.js → chunk-NNZOCTDI.js} +3 -48
  9. package/dist/cli/chunk-NNZOCTDI.js.map +7 -0
  10. package/dist/cli/createAsyncComparison-DTUUZUEX.js +10 -0
  11. package/dist/cli/{createAsyncReport-ZIO2Q6SS.js → createAsyncReport-7QIIMSNX.js} +4 -3
  12. package/dist/cli/{createAsyncReport-ZIO2Q6SS.js.map → createAsyncReport-7QIIMSNX.js.map} +1 -1
  13. package/dist/cli/main.d.ts +2 -0
  14. package/dist/cli/main.d.ts.map +1 -0
  15. package/dist/cli/{index.js → main.js} +29 -24
  16. package/dist/cli/main.js.map +7 -0
  17. package/dist/cli/package-BYHQMCNB.js +7 -0
  18. package/dist/cli/{prepareSnapRequests-NPYZG2AI.js → prepareSnapRequests-T6RBWTYD.js} +4 -3
  19. package/dist/cli/{prepareSnapRequests-NPYZG2AI.js.map → prepareSnapRequests-T6RBWTYD.js.map} +1 -1
  20. package/dist/cli/{startJob-T3PWEYOP.js → startJob-74BLUAGF.js} +4 -3
  21. package/dist/cli/{startJob-T3PWEYOP.js.map → startJob-74BLUAGF.js.map} +1 -1
  22. package/dist/cli/{wrapper-WKKUKM7T.js → wrapper-IM3TNBSL.js} +5 -4
  23. package/dist/cli/{wrapper-WKKUKM7T.js.map → wrapper-IM3TNBSL.js.map} +1 -1
  24. package/dist/config/loadConfig.d.ts.map +1 -1
  25. package/dist/cypress/task.js +126 -120
  26. package/dist/cypress/task.js.map +3 -3
  27. package/dist/playwright/index.js +126 -120
  28. package/dist/playwright/index.js.map +3 -3
  29. package/package.json +7 -7
  30. package/dist/cli/chunk-DYCU4INF.js.map +0 -7
  31. package/dist/cli/chunk-TCHC2O3E.js.map +0 -7
  32. package/dist/cli/createAsyncComparison-5X5OBHF2.js +0 -9
  33. package/dist/cli/index.js.map +0 -7
  34. package/dist/cli/package-CB7WD7JO.js +0 -7
  35. /package/dist/cli/{chunk-TPF2272Y.js.map → chunk-6SJAK2WZ.js.map} +0 -0
  36. /package/dist/cli/{createAsyncComparison-5X5OBHF2.js.map → createAsyncComparison-DTUUZUEX.js.map} +0 -0
  37. /package/dist/cli/{package-CB7WD7JO.js.map → package-BYHQMCNB.js.map} +0 -0
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-TCHC2O3E.js";
4
- import "./chunk-DYCU4INF.js";
3
+ } from "./chunk-BLNR2H52.js";
4
+ import "./chunk-NNZOCTDI.js";
5
+ import "./chunk-FCZLLRXU.js";
5
6
 
6
7
  // src/network/cancelJob.ts
7
8
  async function cancelJob(status, config, { beforeSha, afterSha, link, message }, logger) {
@@ -24,4 +25,4 @@ async function cancelJob(status, config, { beforeSha, afterSha, link, message },
24
25
  export {
25
26
  cancelJob as default
26
27
  };
27
- //# sourceMappingURL=cancelJob-GCTVJGYB.js.map
28
+ //# sourceMappingURL=cancelJob-NIUI7GBR.js.map
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/network/cancelJob.ts"],
4
4
  "sourcesContent": ["import type { ConfigWithDefaults } from '../config/index.ts';\nimport type { EnvironmentResult } from '../environment/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport makeHappoAPIRequest from './makeHappoAPIRequest.ts';\n\ntype Status = 'failure' | 'success';\n\n/**\n * Tell Happo that a job comparing two SHAs had to be cancelled for some reason.\n *\n * @see https://happo.io/docs/api#cancelJob\n */\nexport default async function cancelJob(\n status: Status,\n config: ConfigWithDefaults,\n { beforeSha, afterSha, link, message }: EnvironmentResult,\n logger: Logger,\n): Promise<void> {\n await makeHappoAPIRequest(\n {\n path: `/api/jobs/${beforeSha}/${afterSha}/cancel`,\n method: 'POST',\n body: {\n link,\n message,\n project: config.project,\n status,\n },\n },\n config,\n { retryCount: 5 },\n logger,\n );\n}\n"],
5
- "mappings": ";;;;;;AAYA,eAAO,UACL,QACA,QACA,EAAE,WAAW,UAAU,MAAM,QAAQ,GACrC,QACe;AACf,QAAM;AAAA,IACJ;AAAA,MACE,MAAM,aAAa,SAAS,IAAI,QAAQ;AAAA,MACxC,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA,EAAE,YAAY,EAAE;AAAA,IAChB;AAAA,EACF;AACF;",
5
+ "mappings": ";;;;;;;AAYA,eAAO,UACL,QACA,QACA,EAAE,WAAW,UAAU,MAAM,QAAQ,GACrC,QACe;AACf,QAAM;AAAA,IACJ;AAAA,MACE,MAAM,aAAa,SAAS,IAAI,QAAQ;AAAA,MACxC,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,IACA,EAAE,YAAY,EAAE;AAAA,IAChB;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-TCHC2O3E.js";
3
+ } from "./chunk-BLNR2H52.js";
4
4
 
5
5
  // src/network/createAsyncComparison.ts
6
6
  function assertResultIsCreateAsyncComparisonResult(result) {
@@ -56,4 +56,4 @@ async function createAsyncComparison(config, {
56
56
  export {
57
57
  createAsyncComparison
58
58
  };
59
- //# sourceMappingURL=chunk-TPF2272Y.js.map
59
+ //# sourceMappingURL=chunk-6SJAK2WZ.js.map
@@ -0,0 +1,51 @@
1
+ import {
2
+ fetchWithRetry
3
+ } from "./chunk-NNZOCTDI.js";
4
+
5
+ // src/network/makeHappoAPIRequest.ts
6
+ import { SignJWT } from "jose";
7
+ async function signRequest(apiKey, apiSecret) {
8
+ const encodedSecret = new TextEncoder().encode(apiSecret);
9
+ return await new SignJWT({ key: apiKey }).setProtectedHeader({ alg: "HS256", kid: apiKey }).sign(encodedSecret);
10
+ }
11
+ async function makeHappoAPIRequest({ url, path, method = "GET", formData, body }, { apiKey, apiSecret, endpoint }, {
12
+ retryCount = 0,
13
+ timeout = 6e4,
14
+ retryMinTimeout = 1e3,
15
+ retryMaxTimeout = Infinity
16
+ }, logger = console) {
17
+ const fetchURL = path ? new URL(path, endpoint) : url;
18
+ if (!fetchURL) {
19
+ throw new Error(
20
+ "No fetch URL provided. Either `path` (preferred) or `url` must be provided."
21
+ );
22
+ }
23
+ const signed = await signRequest(apiKey, apiSecret);
24
+ const headers = {
25
+ Authorization: `Bearer ${signed}`
26
+ };
27
+ const response = await fetchWithRetry(
28
+ fetchURL,
29
+ {
30
+ method,
31
+ headers,
32
+ formData,
33
+ body,
34
+ timeout,
35
+ retryCount,
36
+ retryMinTimeout,
37
+ retryMaxTimeout
38
+ },
39
+ logger
40
+ );
41
+ const result = await response.json();
42
+ if (typeof result !== "object") {
43
+ throw new TypeError(`Response is not an object: ${JSON.stringify(result)}`);
44
+ }
45
+ return result;
46
+ }
47
+
48
+ export {
49
+ makeHappoAPIRequest
50
+ };
51
+ //# sourceMappingURL=chunk-BLNR2H52.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/network/makeHappoAPIRequest.ts"],
4
+ "sourcesContent": ["import { SignJWT } from 'jose';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport fetchWithRetry from './fetchWithRetry.ts';\n\nexport { ErrorWithStatusCode } from './fetchWithRetry.ts';\n\ntype FormDataValue = string | File | undefined;\n\nexport interface RequestAttributes {\n /**\n * The path to the API endpoint\n *\n * @example\n * '/api/snap-requests/with-results'\n */\n path?: `/api/${string}`;\n\n /**\n * The URL to fetch\n *\n * Prefer using the `path` property instead. If both are provided, the `path`\n * property will be used.\n */\n url?: string;\n\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n formData?: Record<string, FormDataValue>;\n body?: unknown;\n json?: boolean;\n}\n\nexport interface MakeHappoAPIRequestOptions {\n /**\n * The timeout in milliseconds\n * @default 60_000\n */\n timeout?: number;\n\n /**\n * The number of times to retry the request\n * @default 0\n */\n retryCount?: number;\n\n /**\n * The minimum timeout in milliseconds\n * @default 1000\n */\n retryMinTimeout?: number;\n\n /**\n * The maximum timeout in milliseconds\n * @default Infinity\n */\n retryMaxTimeout?: number;\n}\n\nasync function signRequest(apiKey: string, apiSecret: string): Promise<string> {\n const encodedSecret = new TextEncoder().encode(apiSecret);\n return await new SignJWT({ key: apiKey })\n .setProtectedHeader({ alg: 'HS256', kid: apiKey })\n .sign(encodedSecret);\n}\n\nexport default async function makeHappoAPIRequest(\n { url, path, method = 'GET', formData, body }: RequestAttributes,\n { apiKey, apiSecret, endpoint }: ConfigWithDefaults,\n {\n retryCount = 0,\n timeout = 60_000,\n retryMinTimeout = 1000,\n retryMaxTimeout = Infinity,\n }: MakeHappoAPIRequestOptions,\n logger: Logger = console,\n): Promise<object | null> {\n const fetchURL = path ? new URL(path, endpoint) : url;\n\n if (!fetchURL) {\n throw new Error(\n 'No fetch URL provided. Either `path` (preferred) or `url` must be provided.',\n );\n }\n\n const signed = await signRequest(apiKey, apiSecret);\n\n const headers = {\n Authorization: `Bearer ${signed}`,\n };\n\n const response = await fetchWithRetry(\n fetchURL,\n {\n method,\n headers,\n formData,\n body,\n timeout,\n retryCount,\n retryMinTimeout,\n retryMaxTimeout,\n },\n logger,\n );\n\n // We expect API responses to be JSON, so let's parse it as JSON here for\n // convenience.\n const result = await response.json();\n\n if (typeof result !== 'object') {\n throw new TypeError(`Response is not an object: ${JSON.stringify(result)}`);\n }\n\n return result;\n}\n"],
5
+ "mappings": ";;;;;AAAA,SAAS,eAAe;AA2DxB,eAAe,YAAY,QAAgB,WAAoC;AAC7E,QAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,SAAS;AACxD,SAAO,MAAM,IAAI,QAAQ,EAAE,KAAK,OAAO,CAAC,EACrC,mBAAmB,EAAE,KAAK,SAAS,KAAK,OAAO,CAAC,EAChD,KAAK,aAAa;AACvB;AAEA,eAAO,oBACL,EAAE,KAAK,MAAM,SAAS,OAAO,UAAU,KAAK,GAC5C,EAAE,QAAQ,WAAW,SAAS,GAC9B;AAAA,EACE,aAAa;AAAA,EACb,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,kBAAkB;AACpB,GACA,SAAiB,SACO;AACxB,QAAM,WAAW,OAAO,IAAI,IAAI,MAAM,QAAQ,IAAI;AAElD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,YAAY,QAAQ,SAAS;AAElD,QAAM,UAAU;AAAA,IACd,eAAe,UAAU,MAAM;AAAA,EACjC;AAEA,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAIA,QAAM,SAAS,MAAM,SAAS,KAAK;AAEnC,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAM,IAAI,UAAU,8BAA8B,KAAK,UAAU,MAAM,CAAC,EAAE;AAAA,EAC5E;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "happo",
4
- version: "6.0.4",
4
+ version: "6.0.6",
5
5
  description: "Catch unexpected visual and accessibility changes and UI bugs",
6
6
  license: "MIT",
7
7
  repository: {
@@ -11,7 +11,7 @@ var package_default = {
11
11
  bugs: "https://github.com/happo/happo/issues",
12
12
  homepage: "https://happo.io",
13
13
  bin: {
14
- happo: "dist/cli/index.js"
14
+ happo: "dist/cli/main.js"
15
15
  },
16
16
  type: "module",
17
17
  main: "./dist/config/index.js",
@@ -69,12 +69,12 @@ var package_default = {
69
69
  prepublishOnly: "pnpm clean && pnpm build",
70
70
  "storybook:dev": "storybook dev --config-dir src/storybook/__tests__/storybook-app -p ${PORT:-6007}",
71
71
  test: "node --env-file-if-exists=.env.local ./scripts/test.ts",
72
- "test:custom": "pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/index.js -c ./happoconfigs/happo.custom.config.ts",
73
- "test:cypress": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/index.js -c ./happoconfigs/happo.cypress.config.ts e2e -- cypress run -C src/cypress/__cypress__/cypress.config.ts",
72
+ "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",
73
+ "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",
74
74
  "test:cypress:open": "cypress open -C src/cypress/__cypress__/cypress.config.ts",
75
- "test:playwright": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/index.js -c ./happoconfigs/happo.playwright.config.ts e2e -- playwright test",
76
- "test:storybook": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/index.js -c ./happoconfigs/happo.storybook.config.ts",
77
- "test:pages": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/index.js -c ./happoconfigs/happo.pages.config.ts",
75
+ "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",
76
+ "test:storybook": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts",
77
+ "test:pages": "pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts",
78
78
  tsc: "tsc --build tsconfig.json"
79
79
  },
80
80
  browserslist: {
@@ -184,4 +184,4 @@ var package_default = {
184
184
  export {
185
185
  package_default
186
186
  };
187
- //# sourceMappingURL=chunk-DYCU4INF.js.map
187
+ //# sourceMappingURL=chunk-FCZLLRXU.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../package.json"],
4
+ "sourcesContent": ["{\n \"name\": \"happo\",\n \"version\": \"6.0.6\",\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 ],\n \"scripts\": {\n \"all\": \"node ./scripts/allchecks.ts\",\n \"build\": \"pnpm build:types && pnpm build:dist\",\n \"build:custom\": \"esbuild src/custom/__happo__/index.ts --bundle --format=iife --global-name=happoCustom --outfile=tmp/happo-custom/bundle.js --platform=browser --target=esnext\",\n \"build:dist\": \"./scripts/build.ts\",\n \"build:types\": \"pnpm tsc --pretty\",\n \"build:watch\": \"tsc --build --watch\",\n \"clean\": \"rm -rf dist tmp/tsc tmp/happo-custom\",\n \"lint\": \"eslint .\",\n \"prepublishOnly\": \"pnpm clean && pnpm build\",\n \"storybook:dev\": \"storybook dev --config-dir src/storybook/__tests__/storybook-app -p ${PORT:-6007}\",\n \"test\": \"node --env-file-if-exists=.env.local ./scripts/test.ts\",\n \"test:custom\": \"pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.custom.config.ts\",\n \"test:cypress\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.cypress.config.ts e2e -- cypress run -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:cypress:open\": \"cypress open -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:playwright\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright.config.ts e2e -- playwright test\",\n \"test:storybook\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts\",\n \"test:pages\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts\",\n \"tsc\": \"tsc --build tsconfig.json\"\n },\n \"browserslist\": {\n \"node\": [\n \"node 22\"\n ],\n \"browser\": [\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ],\n \"isomorphic\": [\n \"node 22\",\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ]\n },\n \"prettier\": {\n \"printWidth\": 85,\n \"singleQuote\": true,\n \"trailingComma\": \"all\",\n \"arrowParens\": \"always\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^9.36.0\",\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\": \"^27.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 \"@types/serve-handler\": \"^6.1.4\",\n \"cypress\": \"^15.5.0\",\n \"esbuild\": \"^0.27.0\",\n \"eslint\": \"^9.36.0\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"eslint-plugin-compat\": \"^6.0.2\",\n \"eslint-plugin-depend\": \"^1.3.1\",\n \"eslint-plugin-simple-import-sort\": \"^12.1.1\",\n \"eslint-plugin-unicorn\": \"^62.0.0\",\n \"jiti\": \"^2.6.0\",\n \"jsdom\": \"^27.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 \"serve-handler\": \"^6.1.6\",\n \"storybook\": \"^10.0.1\",\n \"typescript\": \"^5.9.2\",\n \"typescript-eslint\": \"^8.44.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\"\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./chunk-DYCU4INF.js";
4
-
5
- // src/network/makeHappoAPIRequest.ts
6
- import { SignJWT } from "jose";
3
+ } from "./chunk-FCZLLRXU.js";
7
4
 
8
5
  // src/network/fetchWithRetry.ts
9
6
  import asyncRetry from "async-retry";
@@ -93,49 +90,7 @@ async function fetchWithRetry(url, {
93
90
  );
94
91
  }
95
92
 
96
- // src/network/makeHappoAPIRequest.ts
97
- async function signRequest(apiKey, apiSecret) {
98
- const encodedSecret = new TextEncoder().encode(apiSecret);
99
- return await new SignJWT({ key: apiKey }).setProtectedHeader({ alg: "HS256", kid: apiKey }).sign(encodedSecret);
100
- }
101
- async function makeHappoAPIRequest({ url, path, method = "GET", formData, body }, { apiKey, apiSecret, endpoint }, {
102
- retryCount = 0,
103
- timeout = 6e4,
104
- retryMinTimeout = 1e3,
105
- retryMaxTimeout = Infinity
106
- }, logger = console) {
107
- const fetchURL = path ? new URL(path, endpoint) : url;
108
- if (!fetchURL) {
109
- throw new Error(
110
- "No fetch URL provided. Either `path` (preferred) or `url` must be provided."
111
- );
112
- }
113
- const signed = await signRequest(apiKey, apiSecret);
114
- const headers = {
115
- Authorization: `Bearer ${signed}`
116
- };
117
- const response = await fetchWithRetry(
118
- fetchURL,
119
- {
120
- method,
121
- headers,
122
- formData,
123
- body,
124
- timeout,
125
- retryCount,
126
- retryMinTimeout,
127
- retryMaxTimeout
128
- },
129
- logger
130
- );
131
- const result = await response.json();
132
- if (typeof result !== "object") {
133
- throw new TypeError(`Response is not an object: ${JSON.stringify(result)}`);
134
- }
135
- return result;
136
- }
137
-
138
93
  export {
139
- makeHappoAPIRequest
94
+ fetchWithRetry
140
95
  };
141
- //# sourceMappingURL=chunk-TCHC2O3E.js.map
96
+ //# sourceMappingURL=chunk-NNZOCTDI.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/network/fetchWithRetry.ts"],
4
+ "sourcesContent": ["import asyncRetry from 'async-retry';\n\nimport packageJson from '../../package.json' with { type: 'json' };\nimport type { Logger } from '../isomorphic/types.ts';\n\nconst { version } = packageJson;\n\nexport class ErrorWithStatusCode extends Error {\n statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.statusCode = statusCode;\n }\n}\n\ntype FormDataValue = string | File | undefined;\n\nfunction prepareFormData(data: Record<string, FormDataValue>): FormData | null {\n if (!data) {\n return null;\n }\n\n const form = new FormData();\n\n for (const [key, value] of Object.entries(data)) {\n if (value) {\n form.append(key, value);\n }\n }\n\n return form;\n}\n\ninterface FetchParams {\n method?: string;\n headers?: Record<string, string>;\n formData?: Record<string, FormDataValue> | undefined;\n body?: unknown;\n\n /**\n * The timeout in milliseconds\n * @default 60_000\n */\n timeout?: number;\n\n /**\n * The number of times to retry the request\n * @default 0\n */\n retryCount?: number;\n\n /**\n * The minimum timeout in milliseconds\n * @default 1000\n */\n retryMinTimeout?: number;\n\n /**\n * The maximum timeout in milliseconds\n * @default Infinity\n */\n retryMaxTimeout?: number;\n}\n\nconst defaultHeaders = {\n 'User-Agent': `happo@${version}`,\n};\n\nexport default async function fetchWithRetry(\n url: string | URL,\n {\n method = 'GET',\n headers = {},\n formData,\n body: jsonBody,\n timeout = 60_000,\n retryCount = 0,\n retryMinTimeout = 1000,\n retryMaxTimeout = Infinity,\n }: FetchParams,\n logger: Logger = console,\n): Promise<Response> {\n return asyncRetry(\n async (bail: (error: Error) => void) => {\n const start = Date.now();\n\n // We must avoid reusing FormData instances when retrying requests\n // because they are consumed and cannot be reused.\n // More info: https://github.com/node-fetch/node-fetch/issues/1743\n const body = formData\n ? prepareFormData(formData)\n : jsonBody\n ? JSON.stringify(jsonBody)\n : null;\n\n if (jsonBody) {\n headers['Content-Type'] = 'application/json';\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: { ...defaultHeaders, ...headers },\n signal: AbortSignal.timeout(timeout),\n body,\n });\n } catch (maybeError) {\n const originalError =\n maybeError instanceof Error ? maybeError : new Error(String(maybeError));\n\n const message =\n originalError.name === 'TimeoutError'\n ? `Timeout when fetching ${url} using method ${method}`\n : originalError.message;\n\n // This WILL be retried\n throw new Error(`${message} (took ${Date.now() - start} ms)`, {\n cause: originalError,\n });\n }\n\n if (response.status >= 400 && response.status < 500) {\n // This WILL NOT be retried\n bail(\n new ErrorWithStatusCode(\n `[HAPPO] Request to ${url} failed: ${response.status} - ${await response.text()}`,\n response.status,\n ),\n );\n\n return response;\n }\n\n if (!response.ok) {\n // This WILL be retried\n throw new ErrorWithStatusCode(\n `[HAPPO] Request to ${url} failed: ${response.status} - ${await response.text()}`,\n response.status,\n );\n }\n\n return response;\n },\n\n {\n retries: retryCount,\n minTimeout: retryMinTimeout,\n maxTimeout: retryMaxTimeout,\n onRetry: (error: Error) => {\n logger.error(\n `[HAPPO] Failed fetching ${url} using method ${method}. Retrying (at ${new Date().toISOString()}) ...`,\n );\n logger.error(error);\n },\n },\n );\n}\n"],
5
+ "mappings": ";;;;;AAAA,OAAO,gBAAgB;AAKvB,IAAM,EAAE,QAAQ,IAAI;AAEb,IAAM,sBAAN,cAAkC,MAAM;AAAA,EAC7C;AAAA,EAEA,YAAY,SAAiB,YAAoB;AAC/C,UAAM,OAAO;AACb,SAAK,aAAa;AAAA,EACpB;AACF;AAIA,SAAS,gBAAgB,MAAsD;AAC7E,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,IAAI,SAAS;AAE1B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,QAAI,OAAO;AACT,WAAK,OAAO,KAAK,KAAK;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAiCA,IAAM,iBAAiB;AAAA,EACrB,cAAc,SAAS,OAAO;AAChC;AAEA,eAAO,eACL,KACA;AAAA,EACE,SAAS;AAAA,EACT,UAAU,CAAC;AAAA,EACX;AAAA,EACA,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,kBAAkB;AACpB,GACA,SAAiB,SACE;AACnB,SAAO;AAAA,IACL,OAAO,SAAiC;AACtC,YAAM,QAAQ,KAAK,IAAI;AAKvB,YAAM,OAAO,WACT,gBAAgB,QAAQ,IACxB,WACE,KAAK,UAAU,QAAQ,IACvB;AAEN,UAAI,UAAU;AACZ,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAEA,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,MAAM,KAAK;AAAA,UAC1B;AAAA,UACA,SAAS,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAAA,UACzC,QAAQ,YAAY,QAAQ,OAAO;AAAA,UACnC;AAAA,QACF,CAAC;AAAA,MACH,SAAS,YAAY;AACnB,cAAM,gBACJ,sBAAsB,QAAQ,aAAa,IAAI,MAAM,OAAO,UAAU,CAAC;AAEzE,cAAM,UACJ,cAAc,SAAS,iBACnB,yBAAyB,GAAG,iBAAiB,MAAM,KACnD,cAAc;AAGpB,cAAM,IAAI,MAAM,GAAG,OAAO,UAAU,KAAK,IAAI,IAAI,KAAK,QAAQ;AAAA,UAC5D,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,SAAS,UAAU,OAAO,SAAS,SAAS,KAAK;AAEnD;AAAA,UACE,IAAI;AAAA,YACF,sBAAsB,GAAG,YAAY,SAAS,MAAM,MAAM,MAAM,SAAS,KAAK,CAAC;AAAA,YAC/E,SAAS;AAAA,UACX;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,SAAS,IAAI;AAEhB,cAAM,IAAI;AAAA,UACR,sBAAsB,GAAG,YAAY,SAAS,MAAM,MAAM,MAAM,SAAS,KAAK,CAAC;AAAA,UAC/E,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA,IAEA;AAAA,MACE,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,SAAS,CAAC,UAAiB;AACzB,eAAO;AAAA,UACL,2BAA2B,GAAG,iBAAiB,MAAM,mBAAkB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,QACjG;AACA,eAAO,MAAM,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ createAsyncComparison
3
+ } from "./chunk-6SJAK2WZ.js";
4
+ import "./chunk-BLNR2H52.js";
5
+ import "./chunk-NNZOCTDI.js";
6
+ import "./chunk-FCZLLRXU.js";
7
+ export {
8
+ createAsyncComparison as default
9
+ };
10
+ //# sourceMappingURL=createAsyncComparison-DTUUZUEX.js.map
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-TCHC2O3E.js";
4
- import "./chunk-DYCU4INF.js";
3
+ } from "./chunk-BLNR2H52.js";
4
+ import "./chunk-NNZOCTDI.js";
5
+ import "./chunk-FCZLLRXU.js";
5
6
 
6
7
  // src/network/createAsyncReport.ts
7
8
  function assertResultIsCreateAsyncReportResult(result) {
@@ -37,4 +38,4 @@ async function createAsyncReport(snapRequestIds, config, { afterSha, link, messa
37
38
  export {
38
39
  createAsyncReport as default
39
40
  };
40
- //# sourceMappingURL=createAsyncReport-ZIO2Q6SS.js.map
41
+ //# sourceMappingURL=createAsyncReport-7QIIMSNX.js.map
@@ -2,6 +2,6 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/network/createAsyncReport.ts"],
4
4
  "sourcesContent": ["import type { ConfigWithDefaults } from '../config/index.ts';\nimport type { EnvironmentResult } from '../environment/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport makeHappoAPIRequest from './makeHappoAPIRequest.ts';\n\ninterface CreateAsyncReportResult {\n id: number;\n url: string;\n}\n\nfunction assertResultIsCreateAsyncReportResult(\n result: unknown,\n): asserts result is CreateAsyncReportResult {\n if (typeof result !== 'object' || result === null) {\n throw new TypeError('Result is not an object');\n }\n\n if (!('id' in result) || typeof result.id !== 'number') {\n throw new TypeError('Result is missing id');\n }\n\n if (!('url' in result) || typeof result.url !== 'string') {\n throw new TypeError('Result is missing url');\n }\n}\n\nexport default async function createAsyncReport(\n snapRequestIds: Array<number>,\n config: ConfigWithDefaults,\n { afterSha, link, message }: EnvironmentResult,\n logger: Logger,\n): Promise<CreateAsyncReportResult> {\n const result = await makeHappoAPIRequest(\n {\n path: `/api/async-reports/${afterSha}`,\n method: 'POST',\n body: {\n requestIds: snapRequestIds,\n link,\n message,\n project: config.project,\n },\n },\n config,\n { retryCount: 3 },\n logger,\n );\n\n assertResultIsCreateAsyncReportResult(result);\n\n return result;\n}\n"],
5
- "mappings": ";;;;;;AAUA,SAAS,sCACP,QAC2C;AAC3C,MAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,UAAM,IAAI,UAAU,yBAAyB;AAAA,EAC/C;AAEA,MAAI,EAAE,QAAQ,WAAW,OAAO,OAAO,OAAO,UAAU;AACtD,UAAM,IAAI,UAAU,sBAAsB;AAAA,EAC5C;AAEA,MAAI,EAAE,SAAS,WAAW,OAAO,OAAO,QAAQ,UAAU;AACxD,UAAM,IAAI,UAAU,uBAAuB;AAAA,EAC7C;AACF;AAEA,eAAO,kBACL,gBACA,QACA,EAAE,UAAU,MAAM,QAAQ,GAC1B,QACkC;AAClC,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,MACE,MAAM,sBAAsB,QAAQ;AAAA,MACpC,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IACA;AAAA,IACA,EAAE,YAAY,EAAE;AAAA,IAChB;AAAA,EACF;AAEA,wCAAsC,MAAM;AAE5C,SAAO;AACT;",
5
+ "mappings": ";;;;;;;AAUA,SAAS,sCACP,QAC2C;AAC3C,MAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,UAAM,IAAI,UAAU,yBAAyB;AAAA,EAC/C;AAEA,MAAI,EAAE,QAAQ,WAAW,OAAO,OAAO,OAAO,UAAU;AACtD,UAAM,IAAI,UAAU,sBAAsB;AAAA,EAC5C;AAEA,MAAI,EAAE,SAAS,WAAW,OAAO,OAAO,QAAQ,UAAU;AACxD,UAAM,IAAI,UAAU,uBAAuB;AAAA,EAC7C;AACF;AAEA,eAAO,kBACL,gBACA,QACA,EAAE,UAAU,MAAM,QAAQ,GAC1B,QACkC;AAClC,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,MACE,MAAM,sBAAsB,QAAQ;AAAA,MACpC,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA,SAAS,OAAO;AAAA,MAClB;AAAA,IACF;AAAA,IACA;AAAA,IACA,EAAE,YAAY,EAAE;AAAA,IAChB;AAAA,EACF;AAEA,wCAAsC,MAAM;AAE5C,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":""}
@@ -1,7 +1,9 @@
1
- #!/usr/bin/env node
1
+ import {
2
+ fetchWithRetry
3
+ } from "./chunk-NNZOCTDI.js";
2
4
  import {
3
5
  package_default
4
- } from "./chunk-DYCU4INF.js";
6
+ } from "./chunk-FCZLLRXU.js";
5
7
 
6
8
  // src/cli/index.ts
7
9
  import path2 from "node:path";
@@ -36,12 +38,17 @@ function assertIsPullRequestTokenResponse(response) {
36
38
  throw new TypeError("Unexpected pull request token response");
37
39
  }
38
40
  }
39
- async function getPullRequestSecret(endpoint, prUrl) {
40
- const res = await fetch(`${endpoint}/api/pull-request-token`, {
41
- method: "POST",
42
- headers: { "Content-Type": "application/json" },
43
- body: JSON.stringify({ prUrl })
44
- });
41
+ async function getPullRequestSecret(endpoint, prUrl, logger) {
42
+ const url = new URL("/api/pull-request-token", endpoint);
43
+ const res = await fetchWithRetry(
44
+ url,
45
+ {
46
+ method: "POST",
47
+ body: { prUrl },
48
+ retryCount: 3
49
+ },
50
+ logger
51
+ );
45
52
  if (!res || !res.ok) {
46
53
  throw new Error(
47
54
  `Failed to get pull request secret: ${res.status} - ${await res.text()}`
@@ -87,7 +94,8 @@ async function loadConfigFile(configFilePath, environment, logger = console) {
87
94
  config.apiKey = environment.link;
88
95
  config.apiSecret = await getPullRequestSecret(
89
96
  config.endpoint || DEFAULT_ENDPOINT,
90
- environment.link
97
+ environment.link,
98
+ logger
91
99
  );
92
100
  } catch (e) {
93
101
  throw new Error("Failed to obtain temporary pull-request token", { cause: e });
@@ -799,7 +807,7 @@ function createReporter(opts = {}) {
799
807
 
800
808
  // src/cli/index.ts
801
809
  async function getVersion() {
802
- const packageJson = await import("./package-CB7WD7JO.js");
810
+ const packageJson = await import("./package-BYHQMCNB.js");
803
811
  return packageJson.default.version;
804
812
  }
805
813
  function parseDashdashCommandParts(rawArgs) {
@@ -989,10 +997,10 @@ async function main(rawArgs = process.argv, logger = console) {
989
997
  async function handleDefaultCommand(config, environment, logger) {
990
998
  logger.log("Running happo tests...");
991
999
  const [startJob, createAsyncComparison, createAsyncReport, prepareSnapRequests] = await Promise.all([
992
- (await import("./startJob-T3PWEYOP.js")).default,
993
- (await import("./createAsyncComparison-5X5OBHF2.js")).default,
994
- (await import("./createAsyncReport-ZIO2Q6SS.js")).default,
995
- (await import("./prepareSnapRequests-NPYZG2AI.js")).default
1000
+ (await import("./startJob-74BLUAGF.js")).default,
1001
+ (await import("./createAsyncComparison-DTUUZUEX.js")).default,
1002
+ (await import("./createAsyncReport-7QIIMSNX.js")).default,
1003
+ (await import("./prepareSnapRequests-T6RBWTYD.js")).default
996
1004
  ]);
997
1005
  await startJob(config, environment, logger);
998
1006
  try {
@@ -1014,7 +1022,7 @@ async function handleDefaultCommand(config, environment, logger) {
1014
1022
  }
1015
1023
  } catch (e) {
1016
1024
  logger.error(e instanceof Error ? e.message : String(e), e);
1017
- const cancelJob = (await import("./cancelJob-GCTVJGYB.js")).default;
1025
+ const cancelJob = (await import("./cancelJob-NIUI7GBR.js")).default;
1018
1026
  await cancelJob("failure", config, environment, logger);
1019
1027
  process.exitCode = 1;
1020
1028
  return;
@@ -1025,7 +1033,7 @@ async function handleFinalizeCommand(config, environment, logger) {
1025
1033
  logger.log("Config:", config);
1026
1034
  logger.log("Environment:", environment);
1027
1035
  try {
1028
- const finalizeAll = (await import("./wrapper-WKKUKM7T.js")).finalizeAll;
1036
+ const finalizeAll = (await import("./wrapper-IM3TNBSL.js")).finalizeAll;
1029
1037
  await finalizeAll({ happoConfig: config, environment, logger });
1030
1038
  } catch (e) {
1031
1039
  logger.error(e instanceof Error ? e.message : String(e), e);
@@ -1054,7 +1062,7 @@ async function handleE2ECommand(config, environment, dashdashCommandParts, confi
1054
1062
  logger.log("Config:", config);
1055
1063
  logger.log("Environment:", environment);
1056
1064
  logger.log("Dashdash command parts:", dashdashCommandParts);
1057
- const runWithWrapper = (await import("./wrapper-WKKUKM7T.js")).default;
1065
+ const runWithWrapper = (await import("./wrapper-IM3TNBSL.js")).default;
1058
1066
  const exitCode = await runWithWrapper(
1059
1067
  dashdashCommandParts,
1060
1068
  config,
@@ -1064,10 +1072,7 @@ async function handleE2ECommand(config, environment, dashdashCommandParts, confi
1064
1072
  );
1065
1073
  process.exitCode = exitCode;
1066
1074
  }
1067
- if (import.meta.main) {
1068
- await main();
1069
- }
1070
- export {
1071
- main
1072
- };
1073
- //# sourceMappingURL=index.js.map
1075
+
1076
+ // src/cli/main.ts
1077
+ await main();
1078
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cli/index.ts", "../../src/config/loadConfig.ts", "../../src/environment/index.ts", "../../src/cli/telemetry.ts", "../../src/cli/main.ts"],
4
+ "sourcesContent": ["#!/usr/bin/env node\n\nimport path from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport { findConfigFile, loadConfigFile } from '../config/loadConfig.ts';\nimport type { EnvironmentResult } from '../environment/index.ts';\nimport resolveEnvironment from '../environment/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport type { Reporter } from './telemetry.ts';\nimport { createReporter } from './telemetry.ts';\n\nasync function getVersion() {\n const packageJson = await import('../../package.json', {\n with: { type: 'json' },\n });\n return packageJson.default.version;\n}\n\nfunction parseDashdashCommandParts(\n rawArgs: Array<string>,\n): Array<string> | undefined {\n const dashdashIndex = rawArgs.indexOf('--');\n if (dashdashIndex === -1) {\n return undefined;\n }\n return rawArgs.slice(dashdashIndex + 1);\n}\n\nfunction parseRawArgs(rawArgs: Array<string>) {\n const parsedArgs = parseArgs({\n args: rawArgs,\n\n options: {\n version: {\n type: 'boolean',\n short: 'v',\n },\n\n help: {\n type: 'boolean',\n short: 'h',\n },\n\n config: {\n type: 'string',\n short: 'c',\n },\n\n baseBranch: {\n type: 'string',\n },\n\n link: {\n type: 'string',\n },\n\n message: {\n type: 'string',\n },\n\n authorEmail: {\n type: 'string',\n },\n\n afterSha: {\n type: 'string',\n },\n\n beforeSha: {\n type: 'string',\n },\n\n fallbackShas: {\n type: 'string',\n },\n\n fallbackShasCount: {\n type: 'string',\n },\n\n notify: {\n type: 'string',\n },\n\n nonce: {\n type: 'string',\n },\n\n githubToken: {\n type: 'string',\n },\n },\n\n allowPositionals: true,\n });\n\n return {\n ...parsedArgs,\n dashdashCommandParts: parseDashdashCommandParts(rawArgs),\n };\n}\n\nconst helpText = `Happo ${await getVersion()}\nUsage: happo [options]\n\nCommands:\n <default> Run happo tests\n finalize Finalize happo report for Cypress/Playwright tests running in parallel\n\nOptions:\n --config Path to happo config file\n --version Show version number\n --help Show help text\n --baseBranch <branch> Base branch to use for comparison (default: 'origin/main')\n --link <url> URL to contextualize the comparison (default: auto-detected from CI environment)\n --message <message> Message to associate with the comparison (default: auto-detected from CI environment)\n --authorEmail <email> Email address of the author of the comparison (default: auto-detected from CI environment)\n --afterSha <sha> \"After\" SHA to use for comparison (default: auto-detected from CI environment, or HEAD SHA if not set)\n --beforeSha <sha> \"Before\" SHA to use for comparison (default: auto-detected from CI environment)\n --beforeShaTagMatcher <matcher> git tag matcher to use for \"before\" SHA resolution\n --fallbackShas <shas> Space-, newline- or comma-separated list of fallback shas for compare calls (default: auto-detected from CI environment)\n --fallbackShasCount <count> Number of fallback shas to use for compare calls (default: 50)\n --notify <emails> One or more (comma-separated) email addresses to notify with results\n --nonce <nonce> Nonce to use for Cypress/Playwright comparison\n --githubToken <token> GitHub token to use for posting Happo statuses as comments. Use in combination with the \\`githubApiUrl\\` configuration option. (default: auto-detected from environment)\n\nExamples:\n happo\n\n happo --config path/to/happo.config.ts\n happo --baseBranch origin/long-lived-branch\n happo --link https://github.com/happo/happo/pull/123\n happo --message \"Add new feature\"\n happo --notify me@example.com,you@example.com\n happo --nonce my-unique-nonce\n happo --githubToken {{ secrets.GITHUB_TOKEN }}\n\n happo --version\n happo --help\n\n happo -- playwright test\n\n happo finalize\n happo finalize --nonce my-unique-nonce\n `;\n\nfunction makeAbsolute(configFilePath: string): string {\n if (configFilePath.startsWith('.')) {\n return path.resolve(process.cwd(), configFilePath);\n }\n return configFilePath;\n}\n\nfunction installErrorHandlers(reporter: Reporter, logger: Logger) {\n const unhandledRejectionHandler: NodeJS.UnhandledRejectionListener = (reason) => {\n if (reason instanceof Error) {\n reporter.captureException(reason);\n logger.error(reason.stack || reason.message || String(reason));\n } else {\n reporter.captureException(reason);\n logger.error(`Unhandled rejection (non-Error value): ${String(reason)}`);\n }\n\n process.exitCode = 1;\n return;\n };\n\n const uncaughtExceptionHandler: NodeJS.UncaughtExceptionListener = (error) => {\n reporter.captureException(error);\n logger.error(error.stack || error.message || String(error));\n process.exitCode = 1;\n };\n\n process.on('unhandledRejection', unhandledRejectionHandler);\n process.on('uncaughtException', uncaughtExceptionHandler);\n\n return () => {\n process.removeListener('unhandledRejection', unhandledRejectionHandler);\n process.removeListener('uncaughtException', uncaughtExceptionHandler);\n };\n}\n\nexport async function main(\n rawArgs: Array<string> = process.argv,\n logger: Logger = console,\n): Promise<void> {\n const reporter = createReporter();\n const uninstallErrorHandlers = installErrorHandlers(reporter, logger);\n\n try {\n const args = parseRawArgs(rawArgs.slice(2));\n\n if (args.values.version) {\n // --version\n logger.log(await getVersion());\n return;\n }\n\n if (args.values.help) {\n // --help\n logger.log(helpText);\n return;\n }\n\n const environment = await resolveEnvironment(args.values);\n\n // Get config file path (use --config if provided, otherwise find default)\n const configFilePath = makeAbsolute(args.values.config || findConfigFile());\n const config = await loadConfigFile(configFilePath, environment, logger);\n\n // Handle positional arguments (commands)\n const command = args.positionals[0];\n\n if (args.dashdashCommandParts) {\n await handleE2ECommand(\n config,\n environment,\n args.dashdashCommandParts,\n configFilePath,\n logger,\n );\n return;\n }\n\n if (command === 'finalize') {\n await handleFinalizeCommand(config, environment, logger);\n return;\n }\n\n if (command === undefined) {\n await handleDefaultCommand(config, environment, logger);\n return;\n }\n\n logger.error(`Unknown command: ${command}\\n`);\n logger.error(helpText);\n process.exitCode = 1;\n } catch (error) {\n await reporter.captureException(error);\n logger.error(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n } finally {\n uninstallErrorHandlers();\n }\n}\n\nasync function handleDefaultCommand(\n config: ConfigWithDefaults,\n environment: EnvironmentResult,\n logger: Logger,\n): Promise<void> {\n logger.log('Running happo tests...');\n\n const [startJob, createAsyncComparison, createAsyncReport, prepareSnapRequests] =\n await Promise.all([\n (await import('../network/startJob.ts')).default,\n (await import('../network/createAsyncComparison.ts')).default,\n (await import('../network/createAsyncReport.ts')).default,\n (await import('../network/prepareSnapRequests.ts')).default,\n ]);\n\n // Tell Happo that we are about to run a job\n await startJob(config, environment, logger);\n\n try {\n // Prepare the snap requests for the job. This includes bundling static\n // assets and uploading them.\n const snapRequestIds = await prepareSnapRequests(config);\n\n // Put together a report from the snap requests.\n const asyncReport = await createAsyncReport(\n snapRequestIds,\n config,\n environment,\n logger,\n );\n\n // Create an async comparison.\n logger.log(`[HAPPO] Async report URL: ${asyncReport.url}`);\n if (environment.beforeSha !== environment.afterSha) {\n const asyncComparison = await createAsyncComparison(\n config,\n environment,\n logger,\n );\n logger.log(`[HAPPO] Async comparison URL: ${asyncComparison.compareUrl}`);\n }\n } catch (e) {\n logger.error(e instanceof Error ? e.message : String(e), e);\n const cancelJob = (await import('../network/cancelJob.ts')).default;\n await cancelJob('failure', config, environment, logger);\n process.exitCode = 1;\n return;\n }\n}\n\nasync function handleFinalizeCommand(\n config: ConfigWithDefaults,\n environment: EnvironmentResult,\n logger: Logger,\n): Promise<void> {\n logger.log('Finalizing happo report...');\n logger.log('Config:', config);\n logger.log('Environment:', environment);\n\n try {\n const finalizeAll = (await import('../e2e/wrapper.ts')).finalizeAll;\n await finalizeAll({ happoConfig: config, environment, logger });\n } catch (e) {\n logger.error(e instanceof Error ? e.message : String(e), e);\n process.exitCode = 1;\n return;\n }\n process.exitCode = 0;\n return;\n}\n\nconst E2E_INTEGRATION_TYPES = ['cypress', 'playwright'];\n\nasync function handleE2ECommand(\n config: ConfigWithDefaults,\n environment: EnvironmentResult,\n dashdashCommandParts: Array<string>,\n configFilePath: string,\n logger: Logger,\n): Promise<void> {\n if (!E2E_INTEGRATION_TYPES.includes(config.integration.type)) {\n logger.error(\n `Unsupported integration type used for e2e command: ${config.integration.type}. Supported integration types for e2e are: ${E2E_INTEGRATION_TYPES.join(', ')}`,\n );\n process.exitCode = 1;\n return;\n }\n\n if (!dashdashCommandParts || dashdashCommandParts.length === 0) {\n logger.error('Missing command for e2e action');\n logger.error(helpText);\n process.exitCode = 1;\n return;\n }\n\n logger.log('Setting up happo wrapper for Cypress and Playwright...');\n logger.log('Config:', config);\n logger.log('Environment:', environment);\n logger.log('Dashdash command parts:', dashdashCommandParts);\n\n const runWithWrapper = (await import('../e2e/wrapper.ts')).default;\n const exitCode = await runWithWrapper(\n dashdashCommandParts,\n config,\n environment,\n logger,\n configFilePath,\n );\n process.exitCode = exitCode;\n}\n", "import fs from 'node:fs';\n\nimport { any as findAny } from 'empathic/find';\n\nimport type { EnvironmentResult } from '../environment/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport fetchWithRetry from '../network/fetchWithRetry.ts';\nimport type { ConfigWithDefaults, TargetWithDefaults } from './index.ts';\n\nconst CONFIG_FILENAMES = [\n 'happo.config.js',\n 'happo.config.mjs',\n 'happo.config.cjs',\n 'happo.config.ts',\n 'happo.config.mts',\n 'happo.config.cts',\n];\n\nconst DEFAULT_ENDPOINT = 'https://happo.io';\n\nexport function findConfigFile(): string {\n if (process.env.HAPPO_CONFIG_FILE) {\n return process.env.HAPPO_CONFIG_FILE;\n }\n\n const configFilePath = findAny(CONFIG_FILENAMES, { cwd: process.cwd() });\n\n if (!configFilePath) {\n throw new Error(\n 'Happo config file could not be found. Please create a config file in the root of your project.',\n );\n }\n\n return configFilePath;\n}\n\nfunction assertIsPullRequestTokenResponse(\n response: unknown,\n): asserts response is { secret: string } {\n if (typeof response !== 'object' || response === null || !('secret' in response)) {\n throw new TypeError('Unexpected pull request token response');\n }\n}\n\nasync function getPullRequestSecret(\n endpoint: string,\n prUrl: string,\n logger: Logger,\n): Promise<string> {\n const url = new URL('/api/pull-request-token', endpoint);\n const res = await fetchWithRetry(\n url,\n {\n method: 'POST',\n body: { prUrl },\n retryCount: 3,\n },\n logger,\n );\n\n if (!res || !res.ok) {\n throw new Error(\n `Failed to get pull request secret: ${res.status} - ${await res.text()}`,\n );\n }\n\n const json = await res.json();\n assertIsPullRequestTokenResponse(json);\n\n return json.secret;\n}\n\nexport async function loadConfigFile(\n configFilePath: string,\n environment?: Pick<EnvironmentResult, 'link'>,\n logger: Logger = console,\n): Promise<ConfigWithDefaults> {\n try {\n const stats = await fs.promises.stat(configFilePath);\n if (!stats.isFile()) {\n throw new Error(`Happo config file path is not a file: ${configFilePath}`);\n }\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n throw new Error(`Happo config file could not be found: ${configFilePath}`);\n }\n\n throw error;\n }\n\n const config = (await import(configFilePath)).default;\n\n // We read these in here so that they can be passed along to the child process\n // in e2e/wrapper.ts. This allows us to use pull-request authentication\n // without having to make an additional HTTP request.\n if (!config.apiKey && process.env.HAPPO_API_KEY) {\n config.apiKey = process.env.HAPPO_API_KEY;\n }\n if (!config.apiSecret && process.env.HAPPO_API_SECRET) {\n config.apiSecret = process.env.HAPPO_API_SECRET;\n }\n\n if (!config.apiKey || !config.apiSecret) {\n const missing = [\n config.apiKey ? null : 'apiKey',\n config.apiSecret ? null : 'apiSecret',\n ]\n .filter(Boolean)\n .map((key) => `\\`${key}\\``)\n .join(' and ');\n\n if (!environment?.link) {\n throw new Error(\n `Missing ${missing} in your Happo config. Reference yours at https://happo.io/settings`,\n );\n }\n\n try {\n // Reassign API tokens to temporary ones provided for the PR\n logger.log(\n `Missing ${missing} in Happo config. Falling back to pull-request authentication.`,\n );\n config.apiKey = environment.link;\n config.apiSecret = await getPullRequestSecret(\n config.endpoint || DEFAULT_ENDPOINT,\n environment.link,\n logger,\n );\n } catch (e) {\n throw new Error('Failed to obtain temporary pull-request token', { cause: e });\n }\n }\n\n if (!config.targets) {\n config.targets = {\n chrome: {\n type: 'chrome',\n viewport: '1024x768',\n },\n };\n }\n\n if (!config.integration) {\n config.integration = {\n type: 'storybook',\n };\n }\n\n const allTargets = Object.values(config.targets);\n for (const target of allTargets as Array<TargetWithDefaults>) {\n target.viewport = target.viewport || '1024x768';\n target.freezeAnimations = target.freezeAnimations || 'last-frame';\n target.prefersReducedMotion = target.prefersReducedMotion ?? true;\n }\n\n const configWithDefaults = {\n endpoint: DEFAULT_ENDPOINT,\n githubApiUrl: 'https://api.github.com',\n targets: allTargets,\n ...config,\n };\n\n return configWithDefaults;\n}\n", "import { spawnSync } from 'node:child_process';\nimport crypto, { randomBytes } from 'node:crypto';\nimport { readFileSync } from 'node:fs';\n\ninterface GitHubEvent {\n pull_request?: {\n html_url: string;\n title: string;\n base: {\n sha: string;\n };\n head: {\n sha: string;\n };\n };\n head_commit?: {\n url: string;\n };\n merge_group?: {\n head_sha: string;\n base_sha: string;\n };\n repository?: {\n html_url: string;\n };\n before?: string;\n after?: string;\n}\n\ninterface CLIArgs {\n baseBranch?: string;\n afterSha?: string;\n beforeSha?: string;\n message?: string;\n link?: string;\n authorEmail?: string;\n beforeShaTagMatcher?: string;\n notify?: string;\n fallbackShas?: string;\n fallbackShasCount?: string;\n nonce?: string;\n githubToken?: string;\n}\n\nexport interface EnvironmentResult {\n link: string | undefined;\n message: string | undefined;\n authorEmail: string | undefined;\n beforeSha: string;\n afterSha: string;\n nonce: string | undefined;\n debugMode: boolean;\n notify: string | undefined;\n fallbackShas: Array<string> | undefined;\n githubToken: string | undefined;\n}\n\nconst envKeys: ReadonlyArray<string> = [\n 'BUILD_REPOSITORY_URI',\n 'BUILD_SOURCEVERSION',\n 'CIRCLE_PROJECT_REPONAME',\n 'CIRCLE_PROJECT_USERNAME',\n 'CIRCLE_SHA1',\n 'CI_PULL_REQUEST',\n 'GITHUB_EVENT_PATH',\n 'GITHUB_SERVER_URL',\n 'GITHUB_SHA',\n 'HAPPO_DEBUG',\n 'SYSTEM_PULLREQUEST_PULLREQUESTID',\n 'SYSTEM_PULLREQUEST_SOURCEBRANCH',\n 'SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI',\n 'SYSTEM_PULLREQUEST_TARGETBRANCH',\n 'TRAVIS_COMMIT',\n 'TRAVIS_COMMIT_RANGE',\n 'TRAVIS_PULL_REQUEST',\n 'TRAVIS_PULL_REQUEST_SHA',\n 'TRAVIS_REPO_SLUG',\n];\n\nasync function resolveGithubEvent(GITHUB_EVENT_PATH: string): Promise<GitHubEvent> {\n try {\n const fs = await import('node:fs/promises');\n const content = await fs.readFile(GITHUB_EVENT_PATH, 'utf8');\n return JSON.parse(content);\n } catch (e) {\n throw new Error(\n `Failed to load GitHub event from the GITHUB_EVENT_PATH environment variable: ${JSON.stringify(GITHUB_EVENT_PATH)}`,\n { cause: e },\n );\n }\n}\n\nasync function resolveLink(\n cliArgs: CLIArgs,\n env: Record<string, string | undefined>,\n): Promise<string | undefined> {\n if (cliArgs.link) {\n // Validate the link\n let parsed: URL;\n try {\n parsed = new URL(cliArgs.link);\n } catch (e) {\n throw new TypeError(\n `link must be a valid http/https URL. Invalid URL: '${cliArgs.link}'`,\n { cause: e },\n );\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new TypeError(\n `link must be a valid http/https URL. Invalid protocol: '${parsed.protocol}' (from '${cliArgs.link}')`,\n );\n }\n\n return cliArgs.link;\n }\n\n const {\n BUILD_REPOSITORY_URI,\n BUILD_SOURCEVERSION,\n\n // https://circleci.com/docs/reference/variables/\n CIRCLE_PROJECT_REPONAME,\n CIRCLE_PROJECT_USERNAME,\n CIRCLE_PULL_REQUEST,\n CIRCLE_SHA1,\n\n CI_PULL_REQUEST,\n\n // https://docs.github.com/en/actions/reference/workflows-and-actions/variables#default-environment-variables\n GITHUB_EVENT_PATH,\n GITHUB_SHA,\n\n SYSTEM_PULLREQUEST_PULLREQUESTID,\n SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI,\n\n // https://docs.travis-ci.com/user/environment-variables/#default-environment-variables\n TRAVIS_COMMIT,\n TRAVIS_PULL_REQUEST,\n TRAVIS_REPO_SLUG,\n } = env;\n\n if (CI_PULL_REQUEST) {\n // Circle CI\n return CI_PULL_REQUEST;\n }\n\n if (GITHUB_EVENT_PATH) {\n const ghEvent = await resolveGithubEvent(GITHUB_EVENT_PATH);\n\n if (ghEvent.pull_request) {\n return ghEvent.pull_request.html_url;\n }\n if (ghEvent.head_commit) {\n return ghEvent.head_commit.url;\n }\n if (ghEvent.merge_group && ghEvent.repository) {\n return `${ghEvent.repository.html_url}/commit/${ghEvent.merge_group.head_sha}`;\n }\n if (GITHUB_SHA && ghEvent.repository) {\n return `${ghEvent.repository.html_url}/commit/${GITHUB_SHA}`;\n }\n }\n\n if (SYSTEM_PULLREQUEST_PULLREQUESTID && SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI) {\n return `${SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI}/pullrequest/${SYSTEM_PULLREQUEST_PULLREQUESTID}`.replace(\n /[^/]+@/,\n '',\n );\n }\n\n if (BUILD_REPOSITORY_URI && BUILD_SOURCEVERSION) {\n return `${BUILD_REPOSITORY_URI}/commit/${BUILD_SOURCEVERSION}`.replace(\n /[^/]+@/,\n '',\n );\n }\n\n const githubBase = 'https://github.com';\n\n if (TRAVIS_REPO_SLUG && TRAVIS_PULL_REQUEST) {\n return `${githubBase}/${TRAVIS_REPO_SLUG}/pull/${TRAVIS_PULL_REQUEST}`;\n }\n\n if (TRAVIS_REPO_SLUG && TRAVIS_COMMIT) {\n return `${githubBase}/${TRAVIS_REPO_SLUG}/commit/${TRAVIS_COMMIT}`;\n }\n\n if (CIRCLE_PULL_REQUEST) {\n return CIRCLE_PULL_REQUEST;\n }\n\n if (CIRCLE_PROJECT_USERNAME && CIRCLE_PROJECT_REPONAME && CIRCLE_SHA1) {\n return `${githubBase}/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/commit/${CIRCLE_SHA1}`;\n }\n\n return undefined;\n}\n\nasync function resolveAuthorEmail(\n cliArgs: CLIArgs,\n env: Record<string, string | undefined>,\n): Promise<string | undefined> {\n if (cliArgs.authorEmail) {\n return cliArgs.authorEmail;\n }\n\n const { GITHUB_EVENT_PATH } = env;\n\n if (GITHUB_EVENT_PATH) {\n // const ghEvent = await resolveGithubEvent(GITHUB_EVENT_PATH);\n // TODO: do something with the github event\n }\n\n const res = spawnSync('git', ['show', '-s', '--format=%ae'], {\n encoding: 'utf8',\n });\n\n if (res.status !== 0) {\n return undefined;\n }\n\n return res.stdout.trim();\n}\n\nasync function resolveMessage(\n cliArgs: CLIArgs,\n env: Record<string, string | undefined>,\n afterSha: string,\n): Promise<string | undefined> {\n if (cliArgs.message) {\n return cliArgs.message;\n }\n\n const { GITHUB_EVENT_PATH } = env;\n\n if (GITHUB_EVENT_PATH) {\n const ghEvent = await resolveGithubEvent(GITHUB_EVENT_PATH);\n if (ghEvent.pull_request) {\n return ghEvent.pull_request.title;\n }\n }\n\n const res = spawnSync('git', ['log', '-1', '--pretty=%s', afterSha], {\n encoding: 'utf8',\n });\n\n if (res.status !== 0) {\n return undefined;\n }\n\n const message = res.stdout.split('\\n')[0];\n\n if (!message) {\n return undefined;\n }\n\n return message;\n}\n\nfunction resolveShaFromTagMatcher(tagMatcher: string): string | undefined {\n const res = spawnSync(\n 'git',\n ['tag', '--list', tagMatcher, '--sort', 'refname', '--no-contains'],\n {\n encoding: 'utf8',\n },\n );\n\n if (res.status !== 0) {\n throw new Error(\n `Failed to list git tags when matching against --beforeShaTagMatcher '${tagMatcher}'. Error: ${res.stderr}`,\n );\n }\n\n const rawAllTags = res.stdout.trim();\n if (!rawAllTags.length) {\n return undefined;\n }\n\n const allTags = rawAllTags.split('\\n');\n const tag = allTags.at(-1);\n\n if (!tag) {\n throw new Error('No tag found matching the pattern');\n }\n\n const commitRes = spawnSync('git', ['rev-list', '-n', '1', tag], {\n encoding: 'utf8',\n });\n\n if (commitRes.status !== 0) {\n throw new Error(\n `Failed to resolve commit sha from tag \"${tag}\". Error: ${res.stderr}`,\n );\n }\n\n return commitRes.stdout.trim();\n}\n\nasync function resolveBeforeSha(\n cliArgs: CLIArgs,\n env: Record<string, string | undefined>,\n afterSha: string,\n): Promise<string | undefined> {\n if (cliArgs.beforeSha) {\n return cliArgs.beforeSha;\n }\n\n if (cliArgs.beforeShaTagMatcher) {\n const resolvedSha = resolveShaFromTagMatcher(cliArgs.beforeShaTagMatcher);\n if (resolvedSha) {\n return resolvedSha;\n }\n }\n\n const { TRAVIS_COMMIT_RANGE, GITHUB_EVENT_PATH, SYSTEM_PULLREQUEST_TARGETBRANCH } =\n env;\n\n if (GITHUB_EVENT_PATH) {\n const ghEvent = await resolveGithubEvent(GITHUB_EVENT_PATH);\n if (ghEvent.pull_request) {\n return ghEvent.pull_request.base.sha;\n }\n if (ghEvent.merge_group) {\n return ghEvent.merge_group.base_sha;\n }\n return ghEvent.before;\n }\n\n if (TRAVIS_COMMIT_RANGE) {\n const [first] = TRAVIS_COMMIT_RANGE.split('...');\n return first;\n }\n\n let baseAzureBranch;\n if (SYSTEM_PULLREQUEST_TARGETBRANCH) {\n baseAzureBranch = [\n 'origin',\n SYSTEM_PULLREQUEST_TARGETBRANCH.split('/').toReversed()[0],\n ].join('/');\n }\n\n const baseBranch = cliArgs.baseBranch || baseAzureBranch || 'origin/main';\n const res = spawnSync('git', ['merge-base', baseBranch, afterSha], {\n encoding: 'utf8',\n });\n if (res.status !== 0) {\n console.error(`[HAPPO] Ignored error when resolving base commit: ${res.stderr}`);\n return undefined;\n }\n return res.stdout.split('\\n')[0];\n}\n\nfunction getHeadShaWithLocalChanges(): {\n headSha: string;\n headShaWithLocalChanges: string;\n} {\n const randomSha = randomBytes(20).toString('hex');\n // Get the HEAD sha from the git repo, or if we have local changes, add them to the sha\n const res = spawnSync('git', ['rev-parse', 'HEAD'], {\n encoding: 'utf8',\n });\n if (res.status !== 0) {\n return { headSha: randomSha, headShaWithLocalChanges: randomSha };\n }\n const headSha = res.stdout.split('\\n')[0];\n if (!headSha) {\n return { headSha: randomSha, headShaWithLocalChanges: randomSha };\n }\n\n // Check for local changes\n const diffRes = spawnSync('git', ['diff', 'HEAD'], {\n encoding: 'utf8',\n });\n\n // If git diff fails, return HEAD sha\n if (diffRes.status !== 0) {\n return { headSha, headShaWithLocalChanges: headSha };\n }\n\n const lsRes = spawnSync('git', ['ls-files', '--other', '--exclude-standard'], {\n encoding: 'utf8',\n });\n\n if (lsRes.status !== 0) {\n return { headSha, headShaWithLocalChanges: headSha };\n }\n\n const localChanges = [diffRes.stdout.trim(), lsRes.stdout.trim()];\n\n // Get contents of untracked files\n const untrackedFiles = lsRes.stdout\n .trim()\n .split('\\n')\n .filter((file) => file.trim());\n\n for (const file of untrackedFiles) {\n try {\n const content = readFileSync(file, 'utf8');\n localChanges.push(content);\n } catch {\n // If we can't read the file, include just the filename\n localChanges.push(`${file}:<unreadable>`);\n }\n }\n\n const allChanges = localChanges.join('');\n\n if (!allChanges.trim()) {\n return { headSha, headShaWithLocalChanges: headSha };\n }\n\n // If there are local changes, create a hash that includes both HEAD and the changes\n const headShaWithLocalChanges = crypto\n .createHash('sha256')\n .update(headSha)\n .update(allChanges)\n .digest('hex')\n .slice(0, 40);\n\n return { headSha, headShaWithLocalChanges };\n}\n\nasync function resolveAfterSha(\n cliArgs: CLIArgs,\n env: Record<string, string | undefined>,\n): Promise<string | { headSha: string; headShaWithLocalChanges: string }> {\n if (cliArgs.afterSha) {\n return cliArgs.afterSha;\n }\n\n const {\n CIRCLE_SHA1,\n TRAVIS_PULL_REQUEST_SHA,\n TRAVIS_COMMIT,\n GITHUB_EVENT_PATH,\n GITHUB_SHA,\n BUILD_SOURCEVERSION,\n SYSTEM_PULLREQUEST_SOURCEBRANCH,\n CI,\n } = env;\n\n const sha = CIRCLE_SHA1 || TRAVIS_PULL_REQUEST_SHA || TRAVIS_COMMIT;\n\n if (sha) {\n return sha;\n }\n\n if (SYSTEM_PULLREQUEST_SOURCEBRANCH) {\n // azure pull request\n const rawBranchName = SYSTEM_PULLREQUEST_SOURCEBRANCH.split('/').toReversed()[0];\n const res = spawnSync('git', ['rev-parse', `origin/${rawBranchName}`], {\n encoding: 'utf8',\n });\n if (res.status === 0 && res.stdout) {\n const sha = res.stdout.split('\\n')[0];\n if (sha) {\n return sha;\n }\n }\n }\n if (BUILD_SOURCEVERSION) {\n // azure master job\n return BUILD_SOURCEVERSION;\n }\n if (GITHUB_EVENT_PATH) {\n const ghEvent = await resolveGithubEvent(GITHUB_EVENT_PATH);\n if (ghEvent.pull_request) {\n return ghEvent.pull_request.head.sha;\n }\n if (ghEvent.merge_group) {\n return ghEvent.merge_group.head_sha;\n }\n if (ghEvent.after) {\n return ghEvent.after;\n }\n if (GITHUB_SHA) {\n return GITHUB_SHA;\n }\n }\n const headShaWithLocalChanges = getHeadShaWithLocalChanges();\n if (CI) {\n return headShaWithLocalChanges.headSha;\n }\n return headShaWithLocalChanges;\n}\n\nfunction resolveFallbackShas(\n cliArgs: CLIArgs,\n beforeSha: string | undefined,\n): Array<string> | undefined {\n if (cliArgs.fallbackShas) {\n return cliArgs.fallbackShas.split(/[,\\s]+/).filter(Boolean);\n }\n\n const fallbackShasCount = cliArgs.fallbackShasCount\n ? Number.parseInt(cliArgs.fallbackShasCount, 10)\n : 50;\n\n if (Number.isNaN(fallbackShasCount)) {\n throw new TypeError(\n `fallbackShasCount must be a number. Invalid value: '${cliArgs.fallbackShasCount}'`,\n );\n }\n\n const res = spawnSync(\n 'git',\n [\n 'log',\n '--format=%H',\n '--first-parent',\n `--max-count=${fallbackShasCount}`,\n `${beforeSha}^`,\n ],\n {\n encoding: 'utf8',\n },\n );\n\n if (res.status !== 0) {\n return undefined;\n }\n\n return res.stdout.split('\\n').filter(Boolean);\n}\n\nfunction getRawEnv(\n env: Record<string, string | undefined>,\n): Record<string, string | undefined> {\n const res: Record<string, string | undefined> = {};\n for (const key of envKeys) {\n res[key] = env[key];\n }\n return res;\n}\n\nexport default async function resolveEnvironment(\n cliArgs: CLIArgs,\n env: Record<string, string | undefined> = process.env,\n): Promise<EnvironmentResult> {\n const debugMode = !!env.HAPPO_DEBUG;\n const afterSha = await resolveAfterSha(cliArgs, env);\n\n const realAfterSha = typeof afterSha === 'string' ? afterSha : afterSha.headSha;\n const afterShaWithLocalChanges =\n typeof afterSha === 'string' ? afterSha : afterSha.headShaWithLocalChanges;\n\n // Resolve the before SHA with the true HEAD SHA\n const [beforeSha, link, authorEmail, message] = await Promise.all([\n resolveBeforeSha(cliArgs, env, realAfterSha),\n resolveLink(cliArgs, env),\n resolveAuthorEmail(cliArgs, env),\n\n // Resolve message with the SHA that includes local changes\n resolveMessage(cliArgs, env, afterShaWithLocalChanges),\n ]);\n\n const nonNullBeforeSha = beforeSha || afterShaWithLocalChanges;\n\n const result = {\n link,\n authorEmail,\n message,\n beforeSha: nonNullBeforeSha,\n afterSha: afterShaWithLocalChanges,\n nonce: cliArgs.nonce,\n debugMode,\n notify: cliArgs.notify,\n fallbackShas: resolveFallbackShas(cliArgs, nonNullBeforeSha),\n githubToken: cliArgs.githubToken,\n };\n\n if (debugMode) {\n console.log('[HAPPO] Raw environment', getRawEnv(env));\n console.log('[HAPPO] Resolved environment', result);\n }\n\n return result;\n}\n", "import crypto from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { createInterface } from 'node:readline';\n\nimport { up as findPackage } from 'empathic/package';\n\nimport pkg from '../../package.json' with { type: 'json' };\n\n/**\n * Happo's PUBLIC DSN. Safe to ship.\n */\nconst SENTRY_DSN =\n 'https://3a495ff2101313edb024de73b005398f@o108341.ingest.us.sentry.io/4510341337645056';\n\nconst MAX_STACK_FRAMES = 50;\nconst MAX_FUNCTION_NAME_LENGTH = 120;\n\ntype CI =\n | 'github'\n | 'circleci'\n | 'travis'\n | 'azure'\n | 'buildkite'\n | 'jenkins'\n | 'gitlab'\n | 'bitbucket'\n | 'appveyor'\n | 'drone'\n | 'ci'\n | 'unknown';\n\ntype ErrorPayload = {\n pkg: {\n name: string;\n version: string;\n };\n\n error: {\n name: string;\n message: string;\n stack?: string;\n };\n\n env: string;\n\n /** Detected CI vendor if any */\n ci: CI;\n\n nodeVersion: string;\n platform: string;\n};\n\nexport type ReporterOptions = {\n maxPerMinute?: number; // default 10\n env?: string;\n};\n\nexport interface Reporter {\n captureException(e: unknown): Promise<void>;\n}\n\nexport function detectCI(env: Record<string, string | undefined> = process.env): CI {\n if (env.GITHUB_ACTIONS) {\n return 'github';\n }\n\n if (env.CIRCLECI) {\n return 'circleci';\n }\n\n if (env.TRAVIS) {\n return 'travis';\n }\n\n if (env.TF_BUILD) {\n return 'azure';\n }\n\n if (env.BUILDKITE) {\n return 'buildkite';\n }\n\n if (env.JENKINS_URL) {\n return 'jenkins';\n }\n\n if (env.GITLAB_CI) {\n return 'gitlab';\n }\n\n if (env.BITBUCKET_BUILD_NUMBER) {\n return 'bitbucket';\n }\n\n if (env.APPVEYOR) {\n return 'appveyor';\n }\n\n if (env.DRONE) {\n return 'drone';\n }\n\n if (env.CI) {\n return 'ci';\n }\n\n return 'unknown';\n}\n\nexport function parseDsn(dsn: string): {\n host: string;\n projectId: string;\n key: string;\n protocol: string;\n} | null {\n try {\n // https://{PUBLIC_KEY}@{host}/{project_id}\n const u = new URL(dsn);\n const projectId = u.pathname.replace(/^\\//, '');\n const key = u.username; // public key\n const host = u.host; // includes subdomain + port\n return {\n host,\n projectId,\n key,\n protocol: u.protocol.replace(':', ''),\n };\n } catch {\n return null;\n }\n}\n\nasync function sendToSentry(payload: ErrorPayload) {\n const dsn = parseDsn(SENTRY_DSN);\n\n if (!dsn) {\n return;\n }\n\n // Sentry envelope: https://develop.sentry.dev/sdk/envelopes/\n const now = Date.now();\n\n // Hexadecimal string representing a uuid4 value. The length is exactly 32\n // characters. Dashes are not allowed. Has to be lowercase.\n const eventId = crypto.randomUUID().replaceAll('-', '');\n\n const url = `https://${dsn.host}/api/${dsn.projectId}/envelope/`;\n\n const httpHeaders = {\n 'content-type': 'application/x-sentry-envelope',\n 'x-sentry-auth': [\n 'Sentry sentry_version=7',\n `sentry_key=${dsn.key}`,\n `sentry_client=${pkg.name}@${pkg.version}`,\n ].join(', '),\n };\n\n const memoryInfo = process.memoryUsage();\n\n // Minimal event; we keep fields lean & sanitized\n // https://develop.sentry.dev/sdk/data-model/event-payloads/#required-attributes\n const event = {\n event_id: eventId,\n\n // RFC 3339 format\n timestamp: new Date(now).toISOString(),\n\n // A string representing the platform the SDK is submitting from. This will\n // be used by the Sentry interface to customize various components in the\n // interface.\n platform: 'node',\n\n // Possible values: fatal, error, warning, info, debug\n level: 'error',\n\n logger: 'happo.telemetry.cli',\n\n environment: payload.env ?? 'unknown',\n\n // Release versions must be unique across all projects in the organization.\n release: `${payload.pkg.name}@${payload.pkg.version}`,\n\n tags: {\n ci: payload.ci ?? '',\n },\n\n contexts: {\n runtime: {\n type: 'runtime',\n name: 'node',\n version: payload.nodeVersion ?? '',\n },\n os: {\n type: 'os',\n name: payload.platform ?? '',\n },\n memory_info: {\n type: 'memory_info',\n ...memoryInfo,\n },\n },\n\n exception: {\n values: [\n {\n type: payload.error.name || 'Error',\n value: payload.error.message,\n\n // https://develop.sentry.dev/sdk/data-model/event-payloads/stacktrace/\n stacktrace: payload.error.stack\n ? {\n frames: await parseFrames(payload.error.stack),\n }\n : undefined,\n },\n ],\n },\n };\n\n /**\n * Envelope is ndjson-like chunks\n *\n * Envelope = Headers { \"\\n\" Item } [ \"\\n\" ] ;\n * Item = Headers \"\\n\" Payload ;\n * Payload = { * } ;\n *\n * @see https://develop.sentry.dev/sdk/data-model/envelopes/#headers\n */\n const envelopeHeader = JSON.stringify({\n event_id: eventId,\n dsn: SENTRY_DSN,\n sent_at: new Date(now).toISOString(),\n });\n\n // https://develop.sentry.dev/sdk/data-model/envelopes/#items\n const item = JSON.stringify(event);\n const itemHeader = JSON.stringify({ type: 'event', length: item.length });\n\n const body = [envelopeHeader, itemHeader, item].join('\\n');\n\n try {\n await fetch(url, { method: 'POST', headers: httpHeaders, body });\n } catch {\n // swallow; never throw in library code\n }\n}\n\ninterface SentryFrame {\n function: string;\n raw_function: string;\n abs_path: string | undefined;\n filename: string | undefined;\n lineno: number | undefined;\n colno: number | undefined;\n context_line?: string;\n pre_context?: Array<string>;\n post_context?: Array<string>;\n}\n\n/**\n * Get the package root directory\n */\nfunction getPackageRoot(): string {\n const packageJsonPath = findPackage({ cwd: import.meta.dirname });\n\n if (!packageJsonPath) {\n // Fallback to relative path if empathic can't find it\n return path.resolve(import.meta.dirname, '../..');\n }\n\n return path.dirname(packageJsonPath);\n}\n\n/**\n * Check if a file path is part of this package\n */\nfunction isFileInThisPackage(filePath: string): boolean {\n // Skip node: internal modules\n if (filePath.startsWith('node:')) {\n return false;\n }\n\n try {\n const packageRoot = getPackageRoot();\n // Remove file:// prefix if present\n const cleanPath = filePath.replace(/^file:\\/\\//, '');\n const resolvedPath = path.resolve(cleanPath);\n return resolvedPath.startsWith(packageRoot + path.sep);\n } catch {\n return false;\n }\n}\n\n/**\n * Read context lines from a source file around a given line number\n * Only reads files that are part of this package\n */\nasync function readContextLines(\n filePath: string,\n lineNumber: number,\n contextLines: number = 5,\n): Promise<{\n context_line?: string;\n pre_context?: Array<string>;\n post_context?: Array<string>;\n}> {\n // Only read context for files in this package. This is to avoid reading\n // context from external files that may contain sensitive information.\n if (!isFileInThisPackage(filePath)) {\n return {};\n }\n\n try {\n // Remove file:// prefix if present\n const cleanPath = filePath.replace(/^file:\\/\\//, '');\n\n // Line numbers are 1-indexed in stack traces, but arrays are 0-indexed\n const lineIndex = lineNumber - 1;\n\n if (lineIndex < 0) {\n return {};\n }\n\n const startLine = Math.max(0, lineIndex - contextLines);\n const endLine = lineIndex + contextLines + 1;\n\n const pre_context: Array<string> = [];\n let context_line: string | undefined;\n const post_context: Array<string> = [];\n\n const fileStream = fs.createReadStream(cleanPath, { encoding: 'utf8' });\n const rl = createInterface({\n input: fileStream,\n crlfDelay: Infinity,\n });\n\n let currentLine = 0;\n\n for await (const line of rl) {\n if (currentLine < startLine) {\n // Skip lines before our context window\n currentLine++;\n continue;\n }\n\n if (currentLine === lineIndex) {\n context_line = line;\n } else if (currentLine < lineIndex) {\n pre_context.push(line);\n } else if (currentLine < endLine) {\n post_context.push(line);\n } else {\n // We've read all the lines we need\n break;\n }\n\n currentLine++;\n }\n\n // Check if we found the target line\n if (context_line === undefined) {\n return {};\n }\n\n const result: {\n context_line: string;\n pre_context?: Array<string>;\n post_context?: Array<string>;\n } = {\n context_line,\n };\n\n if (pre_context.length > 0) {\n result.pre_context = pre_context;\n }\n\n if (post_context.length > 0) {\n result.post_context = post_context;\n }\n\n return result;\n } catch {\n // File might not exist, might not be readable, etc. Best-effort only.\n return {};\n }\n}\n\n/**\n * Convert an error stack to Sentry frames (best-effort)\n */\nexport async function parseFrames(\n stack: string,\n cwd: string = process.cwd(),\n): Promise<Array<SentryFrame>> {\n // Node stack lines like: \" at func (file:///absolute/path/to/file.js:10:5)\"\n const stackLines = stack.split('\\n').slice(0, MAX_STACK_FRAMES);\n\n const frames = [];\n\n for (const stackLine of stackLines) {\n const match = stackLine.match(\n /\\s+at\\s+(?<functionName>.*?)\\s+\\((?:file:\\/\\/)?(?<absPath>.+?):(?<lineno>\\d+):(?<colno>\\d+)\\)/,\n );\n\n if (!match || !match.groups) {\n // We didn't match a stack line, so skip it. This could cause some stack\n // lines to be dropped.\n continue;\n }\n\n const rawAbsPath = match.groups.absPath ?? '';\n\n const absPath = rawAbsPath.startsWith('node:')\n ? rawAbsPath\n : path.relative(cwd, rawAbsPath);\n const filename = rawAbsPath.startsWith('node:')\n ? rawAbsPath\n : path.basename(rawAbsPath);\n\n const functionName = match.groups.functionName ?? '';\n\n const lineno = match.groups.lineno\n ? Number.parseInt(match.groups.lineno, 10)\n : undefined;\n\n // Read context lines from the source file (only for package files)\n const context =\n rawAbsPath && lineno ? await readContextLines(rawAbsPath, lineno) : {};\n\n // https://develop.sentry.dev/sdk/data-model/event-payloads/stacktrace/#frame-attributes\n const frame: SentryFrame = {\n function: functionName.slice(0, MAX_FUNCTION_NAME_LENGTH),\n raw_function: functionName,\n\n abs_path: absPath,\n filename,\n\n lineno,\n\n colno: match.groups.colno\n ? Number.parseInt(match.groups.colno, 10)\n : undefined,\n\n ...context,\n };\n\n frames.push(frame);\n }\n\n // Sentry expects most recent frame last\n return frames.toReversed();\n}\n\n/**\n * Create a reporter with rate limiting\n */\nexport function createReporter(opts: ReporterOptions = {}): Reporter {\n const maxPerMinute = Math.max(1, opts.maxPerMinute ?? 10);\n let sentThisMinute = 0;\n let minuteTick = Date.now();\n\n function isRateLimitExceeded(): boolean {\n const now = Date.now();\n\n if (now - minuteTick >= 60_000) {\n minuteTick = now;\n sentThisMinute = 0;\n }\n\n if (sentThisMinute >= maxPerMinute) {\n return true;\n }\n\n sentThisMinute++;\n\n return false;\n }\n\n const ci = detectCI(process.env);\n const nodeVersion = process.version;\n const platform = process.platform;\n\n return {\n async captureException(e: unknown) {\n if (isRateLimitExceeded()) {\n return;\n }\n\n const err = e instanceof Error ? e : new Error(String(e));\n const message = err.message ?? 'Error';\n const stack = err.stack;\n\n const payload: ErrorPayload = {\n pkg,\n env: opts.env ?? process.env.NODE_ENV ?? 'unknown',\n ci,\n nodeVersion,\n platform,\n\n error: {\n name: err.name || 'Error',\n message,\n stack: stack ?? '',\n },\n };\n\n await sendToSentry(payload);\n },\n };\n}\n", "import { main } from './index.ts';\n\nawait main();\n"],
5
+ "mappings": "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",
6
+ "names": ["path", "fs", "sha", "crypto", "fs", "crypto", "fs", "path"]
7
+ }
@@ -0,0 +1,7 @@
1
+ import {
2
+ package_default
3
+ } from "./chunk-FCZLLRXU.js";
4
+ export {
5
+ package_default as default
6
+ };
7
+ //# sourceMappingURL=package-BYHQMCNB.js.map
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  makeHappoAPIRequest
3
- } from "./chunk-TCHC2O3E.js";
4
- import "./chunk-DYCU4INF.js";
3
+ } from "./chunk-BLNR2H52.js";
4
+ import "./chunk-NNZOCTDI.js";
5
+ import "./chunk-FCZLLRXU.js";
5
6
 
6
7
  // src/network/prepareSnapRequests.ts
7
8
  import fs5 from "node:fs";
@@ -731,4 +732,4 @@ async function prepareSnapRequests(config) {
731
732
  export {
732
733
  prepareSnapRequests as default
733
734
  };
734
- //# sourceMappingURL=prepareSnapRequests-NPYZG2AI.js.map
735
+ //# sourceMappingURL=prepareSnapRequests-T6RBWTYD.js.map