happo 6.2.2 → 6.2.3
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.
- package/dist/browser/main.js +3 -3
- package/dist/browser/main.js.map +1 -1
- package/dist/cli/{cancelJob-GSKS46TB.js → cancelJob-SCH4KW2U.js} +4 -4
- package/dist/cli/{chunk-NGLSIV6L.js → chunk-45CRUCYS.js} +4 -3
- package/dist/cli/chunk-45CRUCYS.js.map +7 -0
- package/dist/cli/{chunk-JP3VGTB2.js → chunk-4JARS643.js} +2 -2
- package/dist/cli/{chunk-55SEC3JJ.js → chunk-F24YIN3G.js} +2 -2
- package/dist/cli/{chunk-ASKP4L7R.js → chunk-MGD7RXBX.js} +2 -2
- package/dist/cli/createAsyncComparison-2FVFP4R2.js +10 -0
- package/dist/cli/{createAsyncReport-NQDKCCIK.js → createAsyncReport-3MQXEVMB.js} +4 -4
- package/dist/cli/main.js +10 -10
- package/dist/cli/package-46PKZYUO.js +7 -0
- package/dist/cli/{prepareSnapRequests-APMV2VBI.js → prepareSnapRequests-NUFQ2CFV.js} +4 -4
- package/dist/cli/{startJob-2U53W3V6.js → startJob-WHA3HOB4.js} +4 -4
- package/dist/cli/{wrapper-C5BC2R2A.js → wrapper-W3LDE6K7.js} +5 -5
- package/dist/cypress/index.js +3 -3
- package/dist/cypress/index.js.map +1 -1
- package/dist/cypress/task.js +3 -2
- package/dist/cypress/task.js.map +2 -2
- package/dist/playwright/index.js +3 -2
- package/dist/playwright/index.js.map +2 -2
- package/package.json +3 -2
- package/preset.js +5 -0
- package/dist/cli/chunk-NGLSIV6L.js.map +0 -7
- package/dist/cli/createAsyncComparison-U2A5HP3C.js +0 -10
- package/dist/cli/package-4VJLMKE2.js +0 -7
- /package/dist/cli/{cancelJob-GSKS46TB.js.map → cancelJob-SCH4KW2U.js.map} +0 -0
- /package/dist/cli/{chunk-JP3VGTB2.js.map → chunk-4JARS643.js.map} +0 -0
- /package/dist/cli/{chunk-55SEC3JJ.js.map → chunk-F24YIN3G.js.map} +0 -0
- /package/dist/cli/{chunk-ASKP4L7R.js.map → chunk-MGD7RXBX.js.map} +0 -0
- /package/dist/cli/{createAsyncComparison-U2A5HP3C.js.map → createAsyncComparison-2FVFP4R2.js.map} +0 -0
- /package/dist/cli/{createAsyncReport-NQDKCCIK.js.map → createAsyncReport-3MQXEVMB.js.map} +0 -0
- /package/dist/cli/{package-4VJLMKE2.js.map → package-46PKZYUO.js.map} +0 -0
- /package/dist/cli/{prepareSnapRequests-APMV2VBI.js.map → prepareSnapRequests-NUFQ2CFV.js.map} +0 -0
- /package/dist/cli/{startJob-2U53W3V6.js.map → startJob-WHA3HOB4.js.map} +0 -0
- /package/dist/cli/{wrapper-C5BC2R2A.js.map → wrapper-W3LDE6K7.js.map} +0 -0
package/dist/cypress/task.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/e2e/controller.ts", "../../src/config/loadConfig.ts", "../../src/network/fetchWithRetry.ts", "../../package.json", "../../src/network/startServer.ts", "../../src/config/openBrowser.ts", "../../src/config/promptUser.ts", "../../src/config/getShortLivedAPIToken.ts", "../../src/network/makeHappoAPIRequest.ts", "../../src/utils/createHash.ts", "../../src/config/RemoteBrowserTarget.ts", "../../src/network/uploadAssets.ts", "../../src/utils/Logger.ts", "../../src/e2e/convertBase64FileToReal.ts", "../../src/e2e/createAssetPackage.ts", "../../src/utils/deterministicArchive.ts", "../../src/utils/validateArchive.ts", "../../src/e2e/makeAbsolute.ts", "../../src/e2e/makeExternalUrlsAbsolute.ts", "../../src/cypress/task.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'node:fs';\n\nimport limitConcur from 'limit-concur';\n\nimport type {\n BrowserType,\n ConfigWithDefaults,\n E2EIntegration,\n TargetWithDefaults,\n} from '../config/index.ts';\nimport { findConfigFile, loadConfigFile } from '../config/loadConfig.ts';\nimport RemoteBrowserTarget from '../config/RemoteBrowserTarget.ts';\nimport findCSSAssetUrls from '../isomorphic/findCSSAssetUrls.ts';\nimport fetchWithRetry from '../network/fetchWithRetry.ts';\nimport makeHappoAPIRequest from '../network/makeHappoAPIRequest.ts';\nimport uploadAssets from '../network/uploadAssets.ts';\nimport createHash from '../utils/createHash.ts';\nimport convertBase64FileToReal from './convertBase64FileToReal.ts';\nimport type { AssetUrl } from './createAssetPackage.ts';\nimport createAssetPackage from './createAssetPackage.ts';\nimport makeAbsolute from './makeAbsolute.ts';\nimport makeExternalUrlsAbsolute from './makeExternalUrlsAbsolute.ts';\n\n// Type definitions\ninterface Snapshot {\n timestamp?: number | undefined;\n html: string;\n component: string;\n variant: string;\n targets?: Array<string> | undefined;\n stylesheets?: Array<string> | undefined;\n htmlElementAttrs?: Record<string, string> | undefined;\n bodyElementAttrs?: Record<string, string> | undefined;\n}\n\ninterface DynamicTarget {\n name: string;\n viewport: `${number}x${number}`;\n type: BrowserType;\n}\n\ninterface CSSBlock {\n key: string;\n content?: string;\n href?: string | undefined;\n baseUrl?: string | undefined;\n assetsBaseUrl?: string;\n}\n\nexport interface SnapshotRegistrationParams {\n timestamp?: number | undefined;\n html: string;\n assetUrls: Array<AssetUrl>;\n cssBlocks: Array<CSSBlock>;\n component: string;\n variant: string;\n targets?: Array<string | DynamicTarget> | undefined;\n htmlElementAttrs?: Record<string, string> | undefined;\n bodyElementAttrs?: Record<string, string> | undefined;\n}\n\ninterface TimeframeParams {\n start: number;\n end: number;\n}\n\ninterface Base64ChunkParams {\n base64Chunk: string;\n src: string;\n isFirst: boolean;\n isLast: boolean;\n}\n\nfunction assertIntegrationIsE2E(\n integration: NonNullable<ConfigWithDefaults['integration']>,\n): asserts integration is E2EIntegration {\n if (integration.type !== 'cypress' && integration.type !== 'playwright') {\n throw new Error(`Unsupported integration type: ${integration.type}`);\n }\n}\n\nfunction dedupeSnapshots(snapshots: Array<Snapshot>): Array<Snapshot> {\n const allIndexed: Record<string, Snapshot> = {};\n for (const snapshot of snapshots) {\n const key = [snapshot.component, snapshot.variant].join('-_|_-');\n allIndexed[key] = snapshot;\n }\n return Object.values(allIndexed);\n}\n\nfunction getUniqueUrls(urls: Array<AssetUrl>): Array<AssetUrl> {\n const seenKeys = new Set<string>();\n\n const result = [];\n\n for (const url of urls) {\n const key = [url.url, url.baseUrl].join('||');\n\n if (!seenKeys.has(key)) {\n result.push(url);\n seenKeys.add(key);\n }\n }\n\n return result;\n}\n\nfunction ampersands(string: string): string {\n return string.replaceAll('&', '&');\n}\n\nasync function downloadCSSContent(blocks: Array<CSSBlock>): Promise<void> {\n const { HAPPO_DEBUG } = process.env;\n\n const actions = blocks.map((block) => async () => {\n if (block.href) {\n const absUrl = makeAbsolute(block.href, block.baseUrl || '');\n\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Downloading CSS file from ${absUrl}`);\n }\n\n let res;\n try {\n res = await fetchWithRetry(absUrl, { retryCount: 5 });\n } catch {\n console.warn(\n `[HAPPO] Failed to fetch CSS file from ${absUrl} (using ${block.href} with base URL ${block.baseUrl}). This might mean styles are missing in your Happo screenshots.`,\n );\n return;\n }\n\n let text = await res.text();\n\n if (HAPPO_DEBUG) {\n console.log(\n `[HAPPO] Done downloading CSS file from ${absUrl}. Got ${text.length} chars back.`,\n );\n }\n\n // Strip UTF-8 BOM character if present\n if (text.codePointAt(0) === 0xfe_ff) {\n text = text.slice(1);\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Stripped UTF-8 BOM from CSS file ${absUrl}`);\n }\n }\n\n if (!absUrl.startsWith(block.baseUrl || '')) {\n text = makeExternalUrlsAbsolute(text, absUrl);\n }\n\n block.content = text;\n block.assetsBaseUrl = absUrl.replace(/\\/[^/]*$/, '/');\n delete block.href;\n }\n });\n\n await Promise.all(\n actions.map(limitConcur(5, (action: () => Promise<void>) => action())),\n );\n}\n\nclass Controller {\n private snapshots: Array<Snapshot> = [];\n private allCssBlocks: Array<CSSBlock> = [];\n private snapshotAssetUrls: Array<AssetUrl> = [];\n private happoDebug: boolean = false;\n protected happoConfig: ConfigWithDefaults | null = null;\n\n // Public getters for testing\n get config(): ConfigWithDefaults | null {\n return this.happoConfig;\n }\n\n get snapshotsList(): Array<Snapshot> {\n return this.snapshots;\n }\n\n get assetUrls(): Array<AssetUrl> {\n return this.snapshotAssetUrls;\n }\n\n get cssBlocks(): Array<CSSBlock> {\n return this.allCssBlocks;\n }\n\n private assertHappoConfig(): asserts this is this & {\n happoConfig: ConfigWithDefaults;\n } {\n if (!this.happoConfig) {\n throw new Error('Happo config not initialized');\n }\n }\n\n async init(): Promise<void> {\n this.snapshots = [];\n this.allCssBlocks = [];\n this.snapshotAssetUrls = [];\n this.happoDebug = false;\n\n const { HAPPO_E2E_PORT, HAPPO_DEBUG } = process.env;\n\n if (HAPPO_DEBUG) {\n this.happoDebug = true;\n }\n\n if (!HAPPO_E2E_PORT) {\n console.log(\n `\n[HAPPO] Happo is disabled. Enable it by using the \\`happo\\` command.\n\nDocumentation:\n Playwright: https://docs.happo.io/docs/playwright#usage\n Cypress (run): https://docs.happo.io/docs/cypress#usage-with-cypress-run\n Cypress (open): https://docs.happo.io/docs/cypress#usage-with-cypress-open\n `.trim(),\n );\n return;\n }\n\n if (this.happoDebug) {\n console.log('[HAPPO] Running Controller.init');\n }\n\n const configFilePath = findConfigFile();\n this.happoConfig = await loadConfigFile(configFilePath);\n }\n\n isActive(): boolean {\n const result = !!this.happoConfig;\n if (this.happoDebug) {\n console.log('[HAPPO] Controller.isActive()?', result);\n }\n return result;\n }\n\n async uploadAssetsIfNeeded({\n buffer,\n hash,\n }: {\n buffer: Buffer<ArrayBuffer>;\n hash: string;\n }): Promise<string> {\n this.assertHappoConfig();\n\n if (!this.happoConfig.endpoint) {\n throw new Error('Missing `endpoint` in Happo config');\n }\n\n const assetsPath = await uploadAssets(\n buffer,\n {\n hash,\n logger: console,\n },\n this.happoConfig,\n );\n\n return assetsPath;\n }\n\n async finish(): Promise<void> {\n if (this.happoDebug) {\n console.log('[HAPPO] Running Controller.finish');\n }\n\n this.assertHappoConfig();\n\n if (!this.snapshots.length) {\n if (this.happoDebug) {\n console.log('[HAPPO] No snapshots recorded');\n }\n return;\n }\n\n this.snapshots = dedupeSnapshots(this.snapshots);\n await downloadCSSContent(this.allCssBlocks);\n const allUrls = [...this.snapshotAssetUrls];\n\n for (const block of this.allCssBlocks) {\n for (const url of findCSSAssetUrls(block.content || ''))\n allUrls.push({\n url,\n baseUrl: block.assetsBaseUrl || block.baseUrl || undefined,\n });\n }\n\n const uniqueUrls = getUniqueUrls(allUrls);\n assertIntegrationIsE2E(this.happoConfig.integration);\n const downloadAllAssets = this.happoConfig.integration.downloadAllAssets;\n const { buffer, hash } = await createAssetPackage(uniqueUrls, {\n downloadAllAssets: downloadAllAssets ?? false,\n });\n\n const assetsPath = await this.uploadAssetsIfNeeded({ buffer, hash });\n\n const globalCSS = this.allCssBlocks.map((block) => ({\n id: block.key,\n conditional: true,\n css: block.content || '',\n }));\n\n for (const url of uniqueUrls) {\n if (url.name && /^\\/_external\\//.test(url.name) && url.name !== url.url) {\n for (const block of globalCSS) {\n block.css = block.css ? block.css.split(url.url).join(url.name!) : '';\n }\n\n for (const snapshot of this.snapshots) {\n snapshot.html = snapshot.html.split(url.url).join(url.name!);\n if (/&/.test(url.url)) {\n // When URL has an ampersand, we need to make sure the html wasn't\n // escaped so we replace again, this time with \"&\" replaced by\n // \"&\"\n snapshot.html = snapshot.html.split(ampersands(url.url)).join(url.name!);\n }\n }\n }\n }\n\n const allRequestIds = [];\n\n for (const name of Object.keys(this.happoConfig.targets)) {\n if (this.happoDebug) {\n console.log(`[HAPPO] Sending snap-request(s) for target=${name}`);\n }\n\n const snapshotsForTarget = this.snapshots.filter(\n ({ targets }) => !targets || targets.includes(name),\n );\n\n if (!snapshotsForTarget.length) {\n if (this.happoDebug) {\n console.log(`[HAPPO] No snapshots recorded for target=${name}. Skipping.`);\n }\n continue;\n }\n\n if (!this.happoConfig.targets[name]) {\n throw new Error(`Target ${name} not found in Happo config`);\n }\n\n if (!this.happoConfig.endpoint) {\n throw new Error('Missing `endpoint` in Happo config');\n }\n\n const target = this.happoConfig.targets[name];\n const remoteTarget = new RemoteBrowserTarget(target.type, target);\n const requestIds = await remoteTarget.execute(\n {\n targetName: name,\n globalCSS,\n assetsPackage: assetsPath,\n snapPayloads: snapshotsForTarget,\n },\n this.happoConfig,\n );\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Snap-request(s) for target=${name} created with ID(s)=${requestIds.join(\n ',',\n )}`,\n );\n }\n allRequestIds.push(...requestIds);\n }\n\n await this.processSnapRequestIds(allRequestIds);\n }\n\n async registerSnapshot({\n timestamp,\n html,\n assetUrls,\n cssBlocks,\n component,\n variant,\n targets: rawTargets,\n htmlElementAttrs,\n bodyElementAttrs,\n }: SnapshotRegistrationParams): Promise<void> {\n if (!component) {\n throw new Error('Missing `component`');\n }\n\n if (!variant) {\n throw new Error('Missing `variant`');\n }\n\n if (this.happoDebug) {\n console.log(`[HAPPO] Registering snapshot for ${component} > ${variant}`);\n }\n\n this.snapshotAssetUrls.push(...assetUrls);\n const targets = this.handleDynamicTargets(rawTargets);\n this.snapshots.push({\n timestamp,\n html,\n component,\n variant,\n targets,\n stylesheets: cssBlocks.map((b) => b.key),\n htmlElementAttrs,\n bodyElementAttrs,\n });\n\n for (const block of cssBlocks) {\n if (this.allCssBlocks.some((b) => b.key === block.key)) {\n continue;\n }\n\n this.allCssBlocks.push(block);\n }\n }\n\n removeSnapshotsMadeBetween({ start, end }: TimeframeParams): void {\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Removing snapshots made between ${new Date(\n start,\n )} and ${new Date(end)}`,\n );\n }\n\n this.snapshots = this.snapshots.filter(({ timestamp }) => {\n if (!timestamp) {\n return true;\n }\n return timestamp < start || timestamp > end;\n });\n }\n\n removeDuplicatesInTimeframe({ start, end }: TimeframeParams): void {\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Removing duplicate snapshots made between ${new Date(\n start,\n )} and ${new Date(end)}`,\n );\n }\n\n const seenSnapshots: Record<string, boolean> = {};\n this.snapshots = this.snapshots.filter((snapshot) => {\n const { timestamp, component, variant } = snapshot;\n\n if (!timestamp) {\n return true;\n }\n\n const id = [component, variant].join('-_|_-');\n const inTimeframe = timestamp >= start && timestamp <= end;\n\n if (inTimeframe) {\n if (seenSnapshots[id]) {\n // Found a duplicate made in the timeframe specified\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Found duplicate snapshot to remove: \"${component}\", \"${variant}\" at timestamp ${new Date(\n timestamp,\n )}`,\n );\n }\n\n return false;\n }\n\n seenSnapshots[id] = true;\n }\n\n return true;\n });\n }\n\n async processSnapRequestIds(allRequestIds: Array<number>): Promise<void> {\n const { HAPPO_E2E_PORT } = process.env;\n if (!HAPPO_E2E_PORT) {\n // We are not running with `happo --` so there's no work to do here.\n return;\n }\n\n this.assertHappoConfig();\n\n // We're running with `happo --`\n const fetchRes = await fetch(`http://localhost:${HAPPO_E2E_PORT}/`, {\n method: 'POST',\n body: allRequestIds.join('\\n'),\n });\n\n if (!fetchRes.ok) {\n throw new Error('Failed to communicate with happo-e2e server');\n }\n }\n\n handleDynamicTargets(targets?: Array<string | DynamicTarget>): Array<string> {\n this.assertHappoConfig();\n const result: Array<string> = [];\n if (targets === undefined) {\n // return non-dynamic targets from .happo.js\n if (!this.happoConfig) {\n return [];\n }\n\n return Object.keys(this.happoConfig.targets).filter(\n (targetName) => !this.happoConfig.targets[targetName]?.__dynamic,\n );\n }\n\n for (const target of targets) {\n if (typeof target === 'string') {\n result.push(target);\n }\n\n if (\n typeof target === 'object' &&\n target.name &&\n target.viewport &&\n target.type\n ) {\n if (!this.happoConfig) {\n throw new Error('Happo config not initialized');\n }\n\n if (this.happoConfig.targets[target.name]) {\n // already added\n } else {\n const targetName = target.name;\n const constructedTarget: TargetWithDefaults = {\n viewport: target.viewport,\n type: target.type,\n __dynamic: true,\n };\n // add dynamic target\n this.happoConfig.targets[targetName] = constructedTarget;\n }\n\n result.push(target.name);\n }\n }\n\n return result;\n }\n\n async uploadImage(pathOrBuffer: string | Buffer<ArrayBuffer>): Promise<string> {\n if (!this.happoConfig) {\n throw new Error('Happo config not initialized');\n }\n\n const pathToFile = Buffer.isBuffer(pathOrBuffer) ? undefined : pathOrBuffer;\n if (this.happoDebug) {\n console.log(`[HAPPO] Uploading image ${pathToFile || ''}`);\n }\n\n const buffer = pathToFile\n ? await fs.promises.readFile(pathToFile, { encoding: 'binary' })\n : pathOrBuffer;\n\n const hash = await createHash(buffer);\n\n const uploadUrlResult = await makeHappoAPIRequest(\n {\n path: `/api/images/${hash}/upload-url`,\n method: 'GET',\n json: true,\n },\n this.happoConfig,\n { retryCount: 2 },\n );\n\n if (!uploadUrlResult) {\n throw new Error('No uploadUrlResult');\n }\n\n if (!('uploadUrl' in uploadUrlResult) || !uploadUrlResult.uploadUrl) {\n if (!('url' in uploadUrlResult)) {\n throw new Error('Missing url in uploadUrlResult when uploadUrl is missing');\n }\n\n const { url } = uploadUrlResult;\n\n // image has already been uploaded\n if (this.happoDebug) {\n console.log(`[HAPPO] Image has already been uploaded: ${url}`);\n }\n\n return typeof url === 'string' ? url : String(url);\n }\n\n const { uploadUrl } = uploadUrlResult;\n\n if (typeof uploadUrl !== 'string') {\n throw new TypeError('uploadUrlResult.uploadUrl is not a string');\n }\n\n const uploadResult = await makeHappoAPIRequest(\n {\n url: uploadUrl,\n method: 'POST',\n json: true,\n formData: {\n file: new File([buffer], 'image.png', { type: 'image/png' }),\n },\n },\n this.happoConfig,\n { retryCount: 2 },\n );\n\n if (!uploadResult) {\n throw new Error('No uploadResult');\n }\n\n if (this.happoDebug) {\n console.log(`[HAPPO] Uploaded image: ${uploadUrl}`);\n }\n\n if (!('url' in uploadResult)) {\n throw new Error('No url in uploadResult');\n }\n\n return typeof uploadResult.url === 'string'\n ? uploadResult.url\n : String(uploadResult.url);\n }\n\n async registerBase64ImageChunk({\n base64Chunk,\n src,\n isFirst,\n isLast,\n }: Base64ChunkParams): Promise<void> {\n const filename = src.slice(1);\n const filenameB64 = `${filename}.b64`;\n if (isFirst) {\n await fs.promises.mkdir('.happo-tmp/_inlined', { recursive: true });\n await fs.promises.writeFile(filenameB64, base64Chunk);\n } else {\n await fs.promises.appendFile(filenameB64, base64Chunk);\n }\n\n if (isLast) {\n await convertBase64FileToReal(filenameB64, filename);\n }\n }\n}\n\nexport default Controller;\n", "import fs from 'node:fs';\nimport path from 'node:path';\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 getShortLivedAPIToken from './getShortLivedAPIToken.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\nasync function getFallbackApiToken(\n endpoint: string,\n environment: Pick<EnvironmentResult, 'link' | 'ci'> | undefined,\n logger: Logger,\n): Promise<{ key: string; secret: string } | undefined> {\n if (environment?.link) {\n try {\n // Fetch pull request auth\n const pullRequestSecret = await getPullRequestSecret(\n endpoint,\n environment.link,\n logger,\n );\n return {\n key: environment.link,\n secret: pullRequestSecret,\n };\n } catch {\n logger.log(\n `Failed to obtain temporary pull-request token for URL: ${environment.link}`,\n );\n }\n }\n\n if (!environment?.ci) {\n const shortLivedApiToken = await getShortLivedAPIToken(endpoint, logger);\n return shortLivedApiToken ?? undefined;\n }\n return undefined;\n}\n\nexport async function loadConfigFile(\n configFilePath: string,\n environment?: Pick<EnvironmentResult, 'link' | 'ci'>,\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 // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: change this to unknown and add type assertions\n let config: any;\n try {\n config = (await import(configFilePath)).default;\n } catch (error) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ERR_UNKNOWN_FILE_EXTENSION'\n ) {\n // Older versions of Node don't support .ts files natively, so let's throw\n // a more helpful error message.\n const extension = path.extname(configFilePath);\n throw new TypeError(\n `Your Happo config file ${configFilePath} is using an extension that is not supported by this version of Node.js (${extension}). Please use a newer version of Node.js (22.18.0+, 23.6.0+, or 24+).`,\n { cause: error },\n );\n }\n\n throw error;\n }\n\n if (config === null) {\n throw new TypeError(\n `Your Happo config file ${configFilePath} must have a default export that is an object, got: null.`,\n );\n }\n\n if (typeof config !== 'object') {\n throw new TypeError(\n `Your Happo config file ${configFilePath} must have a default export that is an object, got: ${typeof config}.`,\n );\n }\n\n if (Array.isArray(config)) {\n throw new TypeError(\n `Your Happo config file ${configFilePath} must have a default export that is an object, got: array.`,\n );\n }\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 logger.log(\n `Missing ${missing} in Happo config. Attempting alternative authentication.`,\n );\n const fallbackApiToken = await getFallbackApiToken(\n config.endpoint || DEFAULT_ENDPOINT,\n environment,\n logger,\n );\n if (!fallbackApiToken) {\n throw new Error(\n `Missing ${missing} in your Happo config. Reference yours at https://happo.io/settings`,\n );\n }\n config.apiKey = fallbackApiToken.key;\n config.apiSecret = fallbackApiToken.secret;\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 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", "{\n \"name\": \"happo\",\n \"version\": \"6.2.2\",\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.18.0 || ^23.6.0 || >=24.0.0\"\n }\n}\n", "import http from 'node:http';\n\nexport interface ServerInfo {\n close: () => Promise<void>;\n port: number;\n}\n\nexport default function startServer(\n requestHandler: (req: http.IncomingMessage, res: http.ServerResponse) => void,\n { port }: { port?: number | undefined } = {},\n): Promise<ServerInfo> {\n return new Promise((resolve) => {\n const server = http.createServer(requestHandler);\n server.listen(port, () => {\n const address = server.address();\n if (!address || typeof address === 'string') {\n throw new Error('Expected server address to be AddressInfo');\n }\n resolve({\n close: () =>\n new Promise((resolve, reject) =>\n server.close((err) => (err ? reject(err) : resolve())),\n ),\n port: address.port,\n });\n });\n });\n}\n", "import { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\nexport default function openBrowser(url: string): Promise<void> {\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"\" \"${url}\"`;\n } else {\n // Linux and others\n command = `xdg-open \"${url}\"`;\n }\n\n return execAsync(command).then(() => {\n // Ignore errors - browser might not open, but that's okay\n });\n}\n\n", "import { createInterface } from 'node:readline';\n\nexport default function promptUser(message: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n rl.question(message, (answer) => {\n rl.close();\n // Only proceed if Enter was pressed (empty string or newline)\n if (answer.trim() === '') {\n resolve();\n } else {\n reject(new Error('User cancelled authentication'));\n }\n });\n });\n}\n\n", "import type { Logger } from '../isomorphic/types.ts';\nimport startServer from '../network/startServer.ts';\nimport openBrowser from './openBrowser.ts';\nimport promptUser from './promptUser.ts';\n\nconst VALID_HEX_REGEX = /^[0-9a-fA-F]+$/;\n\nfunction createHTML(endpoint: string, phase: string): string {\n return `<!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <title>Happo CLI Authentication</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script type=\"text/javascript\">\n const message = { type: 'happo-cli-auth', payload: { phase: '${phase}' } };\n // Use the exact origin of the parent page\n window.parent.postMessage(message, '${endpoint}'); \n </script>\n </head>\n <body>\n <main>\n <h1>Happo CLI Authentication</h1> \n <p>Authentication successful!</p>\n </main>\n </body>\n </html>`;\n}\n\nfunction validateKeyAndSecret(args: {\n key: string | null;\n secret: string | null;\n}): args is { key: string; secret: string } {\n const { key, secret } = args;\n if (!key) {\n return false;\n }\n if (!secret) {\n return false;\n }\n if (key.length < 10 || key.length > 64) {\n return false;\n }\n if (secret.length < 20 || secret.length > 256) {\n return false;\n }\n // validate that key and secret are valid hex strings\n if (!VALID_HEX_REGEX.test(key)) {\n return false;\n }\n if (!VALID_HEX_REGEX.test(secret)) {\n return false;\n }\n return true;\n}\n\nexport default async function getShortLivedAPIToken(\n endpoint: string,\n logger: Logger,\n): Promise<{ key: string; secret: string } | null> {\n if (!process.stdin.isTTY) {\n return null;\n }\n // Prompt user to press Enter only if in an interactive terminal\n await promptUser('Press <Enter> to authenticate in the browser');\n\n // Set up promise to wait for callback\n let resolveCallback: (value: { key: string; secret: string }) => void;\n let rejectCallback: (error: Error) => void;\n const callbackPromise = new Promise<{ key: string; secret: string }>(\n (resolve, reject) => {\n resolveCallback = resolve;\n rejectCallback = reject;\n },\n );\n\n // Start local server on auto port\n const serverInfo = await startServer((req, res) => {\n // Get port from the request socket\n const url = new URL(req.url ?? '', `http://localhost:${serverInfo.port}`);\n\n if (url.pathname === '/callback') {\n const token = {\n key: url.searchParams.get('key'),\n secret: url.searchParams.get('secret'),\n };\n const ping = url.searchParams.get('ping');\n\n if (ping) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(createHTML(endpoint, 'auth'));\n return;\n }\n if (validateKeyAndSecret(token)) {\n // Send success response\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(createHTML(endpoint, 'done'));\n\n // Resolve the promise with token and secret\n return resolveCallback(token);\n }\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('Bad request');\n return rejectCallback(new Error('Missing key or secret in callback'));\n }\n\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n });\n\n const callbackUrl = `http://localhost:${serverInfo.port}/callback`;\n const authUrl = `${endpoint}/cli/auth?callbackUrl=${encodeURIComponent(callbackUrl)}`;\n\n try {\n // Open browser\n console.log(`Opening URL: ${authUrl}`);\n await openBrowser(authUrl);\n const result = await callbackPromise;\n return result;\n } catch (error) {\n logger.error(\n `Failed to authenticate: ${error instanceof Error ? error.message : String(error)}`,\n );\n return null;\n } finally {\n // Clean up server\n await serverInfo.close();\n }\n}\n", "import { SignJWT } from 'jose';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport fetchWithRetry from './fetchWithRetry.ts';\n\ntype FormDataValue = string | File | undefined;\n\nexport interface RequestAttributes {\n /**\n * The path to the API endpoint\n *\n * @example\n * '/api/snap-requests/with-results'\n */\n path?: `/api/${string}`;\n\n /**\n * The URL to fetch\n *\n * Prefer using the `path` property instead. If both are provided, the `path`\n * property will be used.\n */\n url?: string;\n\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n formData?: Record<string, FormDataValue>;\n body?: unknown;\n json?: boolean;\n}\n\nexport interface MakeHappoAPIRequestOptions {\n /**\n * The timeout in milliseconds\n * @default 60_000\n */\n timeout?: number;\n\n /**\n * The number of times to retry the request\n * @default 0\n */\n retryCount?: number;\n\n /**\n * The minimum timeout in milliseconds\n * @default 1000\n */\n retryMinTimeout?: number;\n\n /**\n * The maximum timeout in milliseconds\n * @default Infinity\n */\n retryMaxTimeout?: number;\n}\n\nasync function signRequest(apiKey: string, apiSecret: string): Promise<string> {\n const encodedSecret = new TextEncoder().encode(apiSecret);\n return await new SignJWT({ key: apiKey })\n .setProtectedHeader({ alg: 'HS256', kid: apiKey })\n .sign(encodedSecret);\n}\n\nexport default async function makeHappoAPIRequest(\n { url, path, method = 'GET', formData, body }: RequestAttributes,\n { apiKey, apiSecret, endpoint }: ConfigWithDefaults,\n {\n retryCount = 0,\n timeout = 60_000,\n retryMinTimeout = 1000,\n retryMaxTimeout = Infinity,\n }: MakeHappoAPIRequestOptions,\n logger: Logger = console,\n): Promise<object | null> {\n const fetchURL = path ? new URL(path, endpoint) : url;\n\n if (!fetchURL) {\n throw new Error(\n 'No fetch URL provided. Either `path` (preferred) or `url` must be provided.',\n );\n }\n\n const signed = await signRequest(apiKey, apiSecret);\n\n const headers = {\n Authorization: `Bearer ${signed}`,\n };\n\n const response = await fetchWithRetry(\n fetchURL,\n {\n method,\n headers,\n formData,\n body,\n timeout,\n retryCount,\n retryMinTimeout,\n retryMaxTimeout,\n },\n logger,\n );\n\n if (response.status === 204) {\n return null;\n }\n\n // We expect API responses to be JSON, so let's parse it as JSON here for\n // convenience.\n const result = await response.json();\n\n if (typeof result !== 'object') {\n throw new TypeError(`Response is not an object: ${JSON.stringify(result)}`);\n }\n\n return result;\n}\n", "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 makeHappoAPIRequest from '../network/makeHappoAPIRequest.ts';\nimport createHash from '../utils/createHash.ts';\nimport type { ConfigWithDefaults, Page, TargetWithDefaults } from './index.ts';\n\nconst VIEWPORT_PATTERN = /^([0-9]+)x([0-9]+)$/;\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 BoundMakeRequestParams {\n slice?: Array<unknown> | undefined;\n chunk?: Chunk | undefined;\n pageSlice?: PageSlice | undefined;\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\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\nexport default class RemoteBrowserTarget {\n public readonly chunks: number;\n public readonly browserName: string;\n public readonly viewport: string;\n public readonly maxHeight: number | undefined;\n public readonly otherOptions: Record<string, unknown>;\n\n constructor(\n browserName: string,\n {\n viewport = '1024x768',\n chunks = 1,\n maxHeight,\n ...otherOptions\n }: TargetWithDefaults,\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 }: ExecuteParams,\n config: ConfigWithDefaults,\n ): Promise<Array<number>> {\n const boundMakeRequest = async ({\n slice,\n chunk,\n pageSlice,\n }: BoundMakeRequestParams): Promise<number> => {\n const payloadString = JSON.stringify({\n viewport: this.viewport,\n maxHeight: this.maxHeight,\n ...this.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(\n payloadString + (pageSlice ? Math.random() : ''),\n );\n\n const formData: Record<string, string | File | undefined> = {\n type:\n pageSlice && pageSlice.extendsSha\n ? 'extends-report'\n : `browser-${this.browserName}`,\n targetName,\n payloadHash,\n payload: new File([payloadString], 'payload.json', {\n type: 'application/json',\n }),\n };\n\n if (pageSlice && pageSlice.extendsSha) {\n formData.extendsSha = pageSlice.extendsSha;\n }\n\n const requestResult = await makeHappoAPIRequest(\n {\n path: `/api/snap-requests?payloadHash=${payloadHash}`,\n method: 'POST',\n json: true,\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\n const requestIds: Array<number> = [];\n\n if (staticPackage) {\n for (let i = 0; i < this.chunks; i += 1) {\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 requestId = await boundMakeRequest({\n chunk: { index: i, total: this.chunks },\n });\n requestIds.push(requestId);\n }\n } else if (pages) {\n for (const pageSlice of getPageSlices(pages, this.chunks)) {\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 requestId = await boundMakeRequest({\n pageSlice,\n });\n requestIds.push(requestId);\n }\n } else {\n const snapsPerChunk = Math.ceil((snapPayloads?.length ?? 0) / this.chunks);\n for (let i = 0; i < this.chunks; i += 1) {\n const slice = snapPayloads?.slice(\n i * snapsPerChunk,\n i * snapsPerChunk + snapsPerChunk,\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 requestId = await boundMakeRequest({\n slice,\n });\n requestIds.push(requestId);\n }\n }\n\n return requestIds;\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 json: true,\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 json: true,\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", "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 fs from 'node:fs';\n\nimport { Base64Decode } from 'base64-stream';\n\nexport default async function convertBase64FileToReal(\n filenameB64: string,\n filename: string,\n): Promise<void> {\n const readStream = fs.createReadStream(filenameB64);\n const outStream = fs.createWriteStream(filename, { encoding: undefined });\n const readyPromise = new Promise<void>((resolve, reject) => {\n outStream.on('finish', resolve);\n outStream.on('error', reject);\n });\n readStream.pipe(new Base64Decode()).pipe(outStream);\n\n await readyPromise;\n\n // Clean up the base64 file after we're done\n await fs.promises.unlink(filenameB64);\n}\n", "import crypto from 'node:crypto';\nimport { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\n\nimport mime from 'mime-types';\n\nimport fetchWithRetry from '../network/fetchWithRetry.ts';\nimport type { ArchiveContentEntry } from '../utils/deterministicArchive.ts';\nimport deterministicArchive from '../utils/deterministicArchive.ts';\nimport makeAbsolute from './makeAbsolute.ts';\n\n// Type definitions\nexport interface AssetUrl {\n url: string;\n baseUrl?: string | undefined;\n name?: string;\n}\n\nfunction stripQueryParams(url: string): string {\n const i = url.indexOf('?');\n if (i !== -1) {\n return url.slice(0, i);\n }\n return url;\n}\n\nfunction normalize(url: string, baseUrl: string): string {\n if (url.startsWith(baseUrl)) {\n return url.slice(baseUrl.length);\n }\n if (url.startsWith('/')) {\n return url.slice(1);\n }\n if (url.startsWith('../')) {\n return url.slice(3);\n }\n return url;\n}\n\nfunction getFileSuffixFromMimeType(mimeType = ''): string {\n const ext = mime.extension(mimeType);\n if (!ext) {\n return '';\n }\n return `.${ext}`;\n}\n\nexport default async function createAssetPackage(\n urls: Array<AssetUrl>,\n { downloadAllAssets }: { downloadAllAssets?: boolean },\n): Promise<{ buffer: Buffer<ArrayBuffer>; hash: string }> {\n const { HAPPO_DEBUG } = process.env;\n\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Creating asset package from urls`, urls);\n }\n\n const seenUrls = new Set<string>();\n\n const archiveFiles: Array<string> = [];\n const archiveContent: Array<ArchiveContentEntry> = [];\n\n // Get all of the archive items in parallel first. Then add them to the\n // archive serially afterwards to ensure that packages are created\n // deterministically.\n await Promise.all(\n urls.map(async (item: AssetUrl) => {\n const { url, baseUrl } = item;\n const isExternalUrl = /^https?:/.test(url);\n const isLocalhost = /\\/\\/(localhost|127\\.0\\.0\\.1)(:|\\/)/.test(url);\n\n if (!downloadAllAssets && isExternalUrl && !isLocalhost) {\n return;\n }\n\n const isDynamic = url.includes('?');\n let name =\n isExternalUrl || isDynamic\n ? `_external/${crypto.createHash('md5').update(url).digest('hex')}`\n : normalize(stripQueryParams(url), baseUrl || '');\n\n if (name.startsWith('#') || name === '' || seenUrls.has(name)) {\n return;\n }\n\n seenUrls.add(name);\n\n if (/\\.happo-tmp\\/_inlined/.test(name)) {\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Adding inlined asset ${name}`);\n }\n\n archiveFiles.push(name);\n } else {\n const fetchUrl = makeAbsolute(url, baseUrl || '');\n\n if (HAPPO_DEBUG) {\n console.log(\n `[HAPPO] Fetching asset from ${fetchUrl} \u2014 storing as ${name}`,\n );\n }\n\n try {\n const fetchRes = await fetchWithRetry(fetchUrl, { retryCount: 5 });\n\n const { body } = fetchRes;\n\n if (!body) {\n throw new Error(`No body for ${fetchUrl}`);\n }\n\n if (isDynamic || isExternalUrl) {\n // Add a file suffix so that svg images work\n name = `${name}${getFileSuffixFromMimeType(\n fetchRes.headers.get('content-type') || 'image/png',\n )}`;\n }\n\n // decode URI to make sure \"%20\" and such are converted to the right\n // chars\n name = decodeURI(name);\n item.name = `/${name}`;\n\n const content = Readable.fromWeb(\n // Unfortunately, it seems that we need to use a type cast here for\n // now. More info:\n // https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65542#discussioncomment-6071004\n body as ReadableStream<Uint8Array>,\n );\n\n archiveContent.push({\n name,\n content,\n });\n } catch (error) {\n console.log(`[HAPPO] Failed to fetch url ${fetchUrl}`);\n console.error(error);\n }\n }\n }),\n );\n\n return deterministicArchive(archiveFiles, archiveContent);\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// 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: path.relative(resolvedDirOrFile, fullPath),\n stream: fs.createReadStream(fullPath),\n });\n }\n }\n\n return fileEntries;\n }\n\n return [\n {\n name: 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 if (!seenFiles.has(file.name)) {\n const data = await contentToUint8Array(file.content);\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 // 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 { URL } from 'node:url';\n\nexport default function makeAbsolute(url: string, baseUrl: string): string {\n if (url.startsWith('//')) {\n return `${baseUrl.split(':')[0]}:${url}`;\n }\n if (/^https?:/.test(url)) {\n return url;\n }\n return new URL(url, baseUrl).href;\n}\n", "import { URL } from 'node:url';\n\nimport { URL_PATTERN } from '../isomorphic/findCSSAssetUrls.ts';\n\nexport default function makeExternalUrlsAbsolute(\n text: string,\n absUrl: string,\n): string {\n return text.replaceAll(URL_PATTERN, (full, pre, url, post) => {\n if (url.startsWith('data:')) {\n return full;\n }\n const fullUrl = new URL(url, absUrl);\n return `${pre}${fullUrl.href}${post}`;\n });\n}\n", "import Controller, { type SnapshotRegistrationParams } from '../e2e/controller.ts';\n\nconst controller = new Controller();\n\nconst { HAPPO_DEBUG } = process.env;\n\ninterface Attempt {\n wallClockStartedAt?: string;\n wallClockDuration?: number;\n state: string;\n}\n\nfunction getCleanupTimeframe({\n attempt,\n results,\n}: {\n attempt: Attempt;\n results: CypressCommandLine.RunResult;\n}): { start: number; end: number } {\n if (attempt.wallClockStartedAt && attempt.wallClockDuration) {\n // Cypress <= v12 (custom timing data)\n const start = new Date(attempt.wallClockStartedAt).getTime();\n return { start, end: start + attempt.wallClockDuration };\n }\n\n // Cypress >= 13 (use official stats)\n if (!results.stats) {\n if (HAPPO_DEBUG) {\n console.log(\n `[HAPPO] Couldn't find start and end time for failed attempt. This could lead to duplicate screenshots in your Happo reports.`,\n );\n }\n return { start: 0, end: 0 };\n }\n\n const start = new Date(results.stats.startedAt).getTime();\n const end = new Date(results.stats.endedAt).getTime();\n return { start, end };\n}\n\ninterface HappoTask {\n isRegisteredCorrectly: boolean;\n register(on: Cypress.PluginEvents): void;\n handleAfterSpec(\n spec: Cypress.Spec,\n results: CypressCommandLine.RunResult,\n ): Promise<void>;\n happoRegisterSnapshot(snapshot: SnapshotRegistrationParams): Promise<null>;\n happoRegisterBase64Image(params: {\n base64Chunk: string;\n src: string;\n isFirst: boolean;\n isLast: boolean;\n }): Promise<null>;\n handleBeforeSpec(): Promise<void>;\n}\n\nconst task: HappoTask = {\n isRegisteredCorrectly: false,\n\n register(on: Cypress.PluginEvents) {\n on('task', {\n happoRegisterSnapshot: task.happoRegisterSnapshot,\n happoRegisterBase64Image: task.happoRegisterBase64Image,\n });\n on('before:spec', task.handleBeforeSpec);\n on('after:spec', task.handleAfterSpec);\n task.isRegisteredCorrectly = true;\n },\n\n async handleAfterSpec(\n _spec: Cypress.Spec,\n results: CypressCommandLine.RunResult,\n ): Promise<void> {\n if (!controller.isActive()) {\n return;\n }\n if (results) {\n for (const test of results.tests) {\n const wasRetried =\n test.attempts.some((t) => t.state === 'failed') &&\n test.attempts.at(-1)?.state === 'passed';\n if (!wasRetried) {\n continue;\n }\n for (const attempt of test.attempts) {\n if (attempt.state === 'failed') {\n const { start, end } = getCleanupTimeframe({\n attempt,\n results,\n });\n controller.removeDuplicatesInTimeframe({\n start,\n end,\n });\n }\n }\n }\n }\n\n await controller.finish();\n },\n\n async happoRegisterSnapshot(snapshot: SnapshotRegistrationParams): Promise<null> {\n if (!controller.isActive()) {\n return null;\n }\n await controller.registerSnapshot(snapshot);\n return null;\n },\n\n async happoRegisterBase64Image({\n base64Chunk,\n src,\n isFirst,\n isLast,\n }: {\n base64Chunk: string;\n src: string;\n isFirst: boolean;\n isLast: boolean;\n }): Promise<null> {\n if (!controller.isActive()) {\n return null;\n }\n await controller.registerBase64ImageChunk({\n base64Chunk,\n src,\n isFirst,\n isLast,\n });\n return null;\n },\n\n async handleBeforeSpec(): Promise<void> {\n await controller.init();\n\n if (controller.isActive() && !task.isRegisteredCorrectly) {\n throw new Error(`Happo hasn't been registered correctly. Make sure you call \\`happoTask.register\\` when you register the plugin:\n\n const happoTask = require('happo/cypress/task');\n\n module.exports = (on) => {\n happoTask.register(on);\n };\n `);\n }\n },\n};\n\nexport default task;\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs';\n\nimport limitConcur from 'limit-concur';\n\nimport type {\n BrowserType,\n ConfigWithDefaults,\n E2EIntegration,\n TargetWithDefaults,\n} from '../config/index.ts';\nimport { findConfigFile, loadConfigFile } from '../config/loadConfig.ts';\nimport RemoteBrowserTarget from '../config/RemoteBrowserTarget.ts';\nimport findCSSAssetUrls from '../isomorphic/findCSSAssetUrls.ts';\nimport fetchWithRetry from '../network/fetchWithRetry.ts';\nimport makeHappoAPIRequest from '../network/makeHappoAPIRequest.ts';\nimport uploadAssets from '../network/uploadAssets.ts';\nimport createHash from '../utils/createHash.ts';\nimport convertBase64FileToReal from './convertBase64FileToReal.ts';\nimport type { AssetUrl } from './createAssetPackage.ts';\nimport createAssetPackage from './createAssetPackage.ts';\nimport makeAbsolute from './makeAbsolute.ts';\nimport makeExternalUrlsAbsolute from './makeExternalUrlsAbsolute.ts';\n\n// Type definitions\ninterface Snapshot {\n timestamp?: number | undefined;\n html: string;\n component: string;\n variant: string;\n targets?: Array<string> | undefined;\n stylesheets?: Array<string> | undefined;\n htmlElementAttrs?: Record<string, string> | undefined;\n bodyElementAttrs?: Record<string, string> | undefined;\n}\n\ninterface DynamicTarget {\n name: string;\n viewport: `${number}x${number}`;\n type: BrowserType;\n}\n\ninterface CSSBlock {\n key: string;\n content?: string;\n href?: string | undefined;\n baseUrl?: string | undefined;\n assetsBaseUrl?: string;\n}\n\nexport interface SnapshotRegistrationParams {\n timestamp?: number | undefined;\n html: string;\n assetUrls: Array<AssetUrl>;\n cssBlocks: Array<CSSBlock>;\n component: string;\n variant: string;\n targets?: Array<string | DynamicTarget> | undefined;\n htmlElementAttrs?: Record<string, string> | undefined;\n bodyElementAttrs?: Record<string, string> | undefined;\n}\n\ninterface TimeframeParams {\n start: number;\n end: number;\n}\n\ninterface Base64ChunkParams {\n base64Chunk: string;\n src: string;\n isFirst: boolean;\n isLast: boolean;\n}\n\nfunction assertIntegrationIsE2E(\n integration: NonNullable<ConfigWithDefaults['integration']>,\n): asserts integration is E2EIntegration {\n if (integration.type !== 'cypress' && integration.type !== 'playwright') {\n throw new Error(`Unsupported integration type: ${integration.type}`);\n }\n}\n\nfunction dedupeSnapshots(snapshots: Array<Snapshot>): Array<Snapshot> {\n const allIndexed: Record<string, Snapshot> = {};\n for (const snapshot of snapshots) {\n const key = [snapshot.component, snapshot.variant].join('-_|_-');\n allIndexed[key] = snapshot;\n }\n return Object.values(allIndexed);\n}\n\nfunction getUniqueUrls(urls: Array<AssetUrl>): Array<AssetUrl> {\n const seenKeys = new Set<string>();\n\n const result = [];\n\n for (const url of urls) {\n const key = [url.url, url.baseUrl].join('||');\n\n if (!seenKeys.has(key)) {\n result.push(url);\n seenKeys.add(key);\n }\n }\n\n return result;\n}\n\nfunction ampersands(string: string): string {\n return string.replaceAll('&', '&');\n}\n\nasync function downloadCSSContent(blocks: Array<CSSBlock>): Promise<void> {\n const { HAPPO_DEBUG } = process.env;\n\n const actions = blocks.map((block) => async () => {\n if (block.href) {\n const absUrl = makeAbsolute(block.href, block.baseUrl || '');\n\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Downloading CSS file from ${absUrl}`);\n }\n\n let res;\n try {\n res = await fetchWithRetry(absUrl, { retryCount: 5 });\n } catch {\n console.warn(\n `[HAPPO] Failed to fetch CSS file from ${absUrl} (using ${block.href} with base URL ${block.baseUrl}). This might mean styles are missing in your Happo screenshots.`,\n );\n return;\n }\n\n let text = await res.text();\n\n if (HAPPO_DEBUG) {\n console.log(\n `[HAPPO] Done downloading CSS file from ${absUrl}. Got ${text.length} chars back.`,\n );\n }\n\n // Strip UTF-8 BOM character if present\n if (text.codePointAt(0) === 0xfe_ff) {\n text = text.slice(1);\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Stripped UTF-8 BOM from CSS file ${absUrl}`);\n }\n }\n\n if (!absUrl.startsWith(block.baseUrl || '')) {\n text = makeExternalUrlsAbsolute(text, absUrl);\n }\n\n block.content = text;\n block.assetsBaseUrl = absUrl.replace(/\\/[^/]*$/, '/');\n delete block.href;\n }\n });\n\n await Promise.all(\n actions.map(limitConcur(5, (action: () => Promise<void>) => action())),\n );\n}\n\nclass Controller {\n private snapshots: Array<Snapshot> = [];\n private allCssBlocks: Array<CSSBlock> = [];\n private snapshotAssetUrls: Array<AssetUrl> = [];\n private happoDebug: boolean = false;\n protected happoConfig: ConfigWithDefaults | null = null;\n\n // Public getters for testing\n get config(): ConfigWithDefaults | null {\n return this.happoConfig;\n }\n\n get snapshotsList(): Array<Snapshot> {\n return this.snapshots;\n }\n\n get assetUrls(): Array<AssetUrl> {\n return this.snapshotAssetUrls;\n }\n\n get cssBlocks(): Array<CSSBlock> {\n return this.allCssBlocks;\n }\n\n private assertHappoConfig(): asserts this is this & {\n happoConfig: ConfigWithDefaults;\n } {\n if (!this.happoConfig) {\n throw new Error('Happo config not initialized');\n }\n }\n\n async init(): Promise<void> {\n this.snapshots = [];\n this.allCssBlocks = [];\n this.snapshotAssetUrls = [];\n this.happoDebug = false;\n\n const { HAPPO_E2E_PORT, HAPPO_DEBUG } = process.env;\n\n if (HAPPO_DEBUG) {\n this.happoDebug = true;\n }\n\n if (!HAPPO_E2E_PORT) {\n console.log(\n `\n[HAPPO] Happo is disabled. Enable it by using the \\`happo\\` command.\n\nDocumentation:\n Playwright: https://docs.happo.io/docs/playwright#usage\n Cypress (run): https://docs.happo.io/docs/cypress#usage-with-cypress-run\n Cypress (open): https://docs.happo.io/docs/cypress#usage-with-cypress-open\n `.trim(),\n );\n return;\n }\n\n if (this.happoDebug) {\n console.log('[HAPPO] Running Controller.init');\n }\n\n const configFilePath = findConfigFile();\n this.happoConfig = await loadConfigFile(configFilePath);\n }\n\n isActive(): boolean {\n const result = !!this.happoConfig;\n if (this.happoDebug) {\n console.log('[HAPPO] Controller.isActive()?', result);\n }\n return result;\n }\n\n async uploadAssetsIfNeeded({\n buffer,\n hash,\n }: {\n buffer: Buffer<ArrayBuffer>;\n hash: string;\n }): Promise<string> {\n this.assertHappoConfig();\n\n if (!this.happoConfig.endpoint) {\n throw new Error('Missing `endpoint` in Happo config');\n }\n\n const assetsPath = await uploadAssets(\n buffer,\n {\n hash,\n logger: console,\n },\n this.happoConfig,\n );\n\n return assetsPath;\n }\n\n async finish(): Promise<void> {\n if (this.happoDebug) {\n console.log('[HAPPO] Running Controller.finish');\n }\n\n this.assertHappoConfig();\n\n if (!this.snapshots.length) {\n if (this.happoDebug) {\n console.log('[HAPPO] No snapshots recorded');\n }\n return;\n }\n\n this.snapshots = dedupeSnapshots(this.snapshots);\n await downloadCSSContent(this.allCssBlocks);\n const allUrls = [...this.snapshotAssetUrls];\n\n for (const block of this.allCssBlocks) {\n for (const url of findCSSAssetUrls(block.content || ''))\n allUrls.push({\n url,\n baseUrl: block.assetsBaseUrl || block.baseUrl || undefined,\n });\n }\n\n const uniqueUrls = getUniqueUrls(allUrls);\n assertIntegrationIsE2E(this.happoConfig.integration);\n const downloadAllAssets = this.happoConfig.integration.downloadAllAssets;\n const { buffer, hash } = await createAssetPackage(uniqueUrls, {\n downloadAllAssets: downloadAllAssets ?? false,\n });\n\n const assetsPath = await this.uploadAssetsIfNeeded({ buffer, hash });\n\n const globalCSS = this.allCssBlocks.map((block) => ({\n id: block.key,\n conditional: true,\n css: block.content || '',\n }));\n\n for (const url of uniqueUrls) {\n if (url.name && /^\\/_external\\//.test(url.name) && url.name !== url.url) {\n for (const block of globalCSS) {\n block.css = block.css ? block.css.split(url.url).join(url.name!) : '';\n }\n\n for (const snapshot of this.snapshots) {\n snapshot.html = snapshot.html.split(url.url).join(url.name!);\n if (/&/.test(url.url)) {\n // When URL has an ampersand, we need to make sure the html wasn't\n // escaped so we replace again, this time with \"&\" replaced by\n // \"&\"\n snapshot.html = snapshot.html.split(ampersands(url.url)).join(url.name!);\n }\n }\n }\n }\n\n const allRequestIds = [];\n\n for (const name of Object.keys(this.happoConfig.targets)) {\n if (this.happoDebug) {\n console.log(`[HAPPO] Sending snap-request(s) for target=${name}`);\n }\n\n const snapshotsForTarget = this.snapshots.filter(\n ({ targets }) => !targets || targets.includes(name),\n );\n\n if (!snapshotsForTarget.length) {\n if (this.happoDebug) {\n console.log(`[HAPPO] No snapshots recorded for target=${name}. Skipping.`);\n }\n continue;\n }\n\n if (!this.happoConfig.targets[name]) {\n throw new Error(`Target ${name} not found in Happo config`);\n }\n\n if (!this.happoConfig.endpoint) {\n throw new Error('Missing `endpoint` in Happo config');\n }\n\n const target = this.happoConfig.targets[name];\n const remoteTarget = new RemoteBrowserTarget(target.type, target);\n const requestIds = await remoteTarget.execute(\n {\n targetName: name,\n globalCSS,\n assetsPackage: assetsPath,\n snapPayloads: snapshotsForTarget,\n },\n this.happoConfig,\n );\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Snap-request(s) for target=${name} created with ID(s)=${requestIds.join(\n ',',\n )}`,\n );\n }\n allRequestIds.push(...requestIds);\n }\n\n await this.processSnapRequestIds(allRequestIds);\n }\n\n async registerSnapshot({\n timestamp,\n html,\n assetUrls,\n cssBlocks,\n component,\n variant,\n targets: rawTargets,\n htmlElementAttrs,\n bodyElementAttrs,\n }: SnapshotRegistrationParams): Promise<void> {\n if (!component) {\n throw new Error('Missing `component`');\n }\n\n if (!variant) {\n throw new Error('Missing `variant`');\n }\n\n if (this.happoDebug) {\n console.log(`[HAPPO] Registering snapshot for ${component} > ${variant}`);\n }\n\n this.snapshotAssetUrls.push(...assetUrls);\n const targets = this.handleDynamicTargets(rawTargets);\n this.snapshots.push({\n timestamp,\n html,\n component,\n variant,\n targets,\n stylesheets: cssBlocks.map((b) => b.key),\n htmlElementAttrs,\n bodyElementAttrs,\n });\n\n for (const block of cssBlocks) {\n if (this.allCssBlocks.some((b) => b.key === block.key)) {\n continue;\n }\n\n this.allCssBlocks.push(block);\n }\n }\n\n removeSnapshotsMadeBetween({ start, end }: TimeframeParams): void {\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Removing snapshots made between ${new Date(\n start,\n )} and ${new Date(end)}`,\n );\n }\n\n this.snapshots = this.snapshots.filter(({ timestamp }) => {\n if (!timestamp) {\n return true;\n }\n return timestamp < start || timestamp > end;\n });\n }\n\n removeDuplicatesInTimeframe({ start, end }: TimeframeParams): void {\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Removing duplicate snapshots made between ${new Date(\n start,\n )} and ${new Date(end)}`,\n );\n }\n\n const seenSnapshots: Record<string, boolean> = {};\n this.snapshots = this.snapshots.filter((snapshot) => {\n const { timestamp, component, variant } = snapshot;\n\n if (!timestamp) {\n return true;\n }\n\n const id = [component, variant].join('-_|_-');\n const inTimeframe = timestamp >= start && timestamp <= end;\n\n if (inTimeframe) {\n if (seenSnapshots[id]) {\n // Found a duplicate made in the timeframe specified\n if (this.happoDebug) {\n console.log(\n `[HAPPO] Found duplicate snapshot to remove: \"${component}\", \"${variant}\" at timestamp ${new Date(\n timestamp,\n )}`,\n );\n }\n\n return false;\n }\n\n seenSnapshots[id] = true;\n }\n\n return true;\n });\n }\n\n async processSnapRequestIds(allRequestIds: Array<number>): Promise<void> {\n const { HAPPO_E2E_PORT } = process.env;\n if (!HAPPO_E2E_PORT) {\n // We are not running with `happo --` so there's no work to do here.\n return;\n }\n\n this.assertHappoConfig();\n\n // We're running with `happo --`\n const fetchRes = await fetch(`http://localhost:${HAPPO_E2E_PORT}/`, {\n method: 'POST',\n body: allRequestIds.join('\\n'),\n });\n\n if (!fetchRes.ok) {\n throw new Error('Failed to communicate with happo-e2e server');\n }\n }\n\n handleDynamicTargets(targets?: Array<string | DynamicTarget>): Array<string> {\n this.assertHappoConfig();\n const result: Array<string> = [];\n if (targets === undefined) {\n // return non-dynamic targets from .happo.js\n if (!this.happoConfig) {\n return [];\n }\n\n return Object.keys(this.happoConfig.targets).filter(\n (targetName) => !this.happoConfig.targets[targetName]?.__dynamic,\n );\n }\n\n for (const target of targets) {\n if (typeof target === 'string') {\n result.push(target);\n }\n\n if (\n typeof target === 'object' &&\n target.name &&\n target.viewport &&\n target.type\n ) {\n if (!this.happoConfig) {\n throw new Error('Happo config not initialized');\n }\n\n if (this.happoConfig.targets[target.name]) {\n // already added\n } else {\n const targetName = target.name;\n const constructedTarget: TargetWithDefaults = {\n viewport: target.viewport,\n type: target.type,\n __dynamic: true,\n };\n // add dynamic target\n this.happoConfig.targets[targetName] = constructedTarget;\n }\n\n result.push(target.name);\n }\n }\n\n return result;\n }\n\n async uploadImage(pathOrBuffer: string | Buffer<ArrayBuffer>): Promise<string> {\n if (!this.happoConfig) {\n throw new Error('Happo config not initialized');\n }\n\n const pathToFile = Buffer.isBuffer(pathOrBuffer) ? undefined : pathOrBuffer;\n if (this.happoDebug) {\n console.log(`[HAPPO] Uploading image ${pathToFile || ''}`);\n }\n\n const buffer = pathToFile\n ? await fs.promises.readFile(pathToFile, { encoding: 'binary' })\n : pathOrBuffer;\n\n const hash = await createHash(buffer);\n\n const uploadUrlResult = await makeHappoAPIRequest(\n {\n path: `/api/images/${hash}/upload-url`,\n method: 'GET',\n json: true,\n },\n this.happoConfig,\n { retryCount: 2 },\n );\n\n if (!uploadUrlResult) {\n throw new Error('No uploadUrlResult');\n }\n\n if (!('uploadUrl' in uploadUrlResult) || !uploadUrlResult.uploadUrl) {\n if (!('url' in uploadUrlResult)) {\n throw new Error('Missing url in uploadUrlResult when uploadUrl is missing');\n }\n\n const { url } = uploadUrlResult;\n\n // image has already been uploaded\n if (this.happoDebug) {\n console.log(`[HAPPO] Image has already been uploaded: ${url}`);\n }\n\n return typeof url === 'string' ? url : String(url);\n }\n\n const { uploadUrl } = uploadUrlResult;\n\n if (typeof uploadUrl !== 'string') {\n throw new TypeError('uploadUrlResult.uploadUrl is not a string');\n }\n\n const uploadResult = await makeHappoAPIRequest(\n {\n url: uploadUrl,\n method: 'POST',\n json: true,\n formData: {\n file: new File([buffer], 'image.png', { type: 'image/png' }),\n },\n },\n this.happoConfig,\n { retryCount: 2 },\n );\n\n if (!uploadResult) {\n throw new Error('No uploadResult');\n }\n\n if (this.happoDebug) {\n console.log(`[HAPPO] Uploaded image: ${uploadUrl}`);\n }\n\n if (!('url' in uploadResult)) {\n throw new Error('No url in uploadResult');\n }\n\n return typeof uploadResult.url === 'string'\n ? uploadResult.url\n : String(uploadResult.url);\n }\n\n async registerBase64ImageChunk({\n base64Chunk,\n src,\n isFirst,\n isLast,\n }: Base64ChunkParams): Promise<void> {\n const filename = src.slice(1);\n const filenameB64 = `${filename}.b64`;\n if (isFirst) {\n await fs.promises.mkdir('.happo-tmp/_inlined', { recursive: true });\n await fs.promises.writeFile(filenameB64, base64Chunk);\n } else {\n await fs.promises.appendFile(filenameB64, base64Chunk);\n }\n\n if (isLast) {\n await convertBase64FileToReal(filenameB64, filename);\n }\n }\n}\n\nexport default Controller;\n", "import fs from 'node:fs';\nimport path from 'node:path';\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 getShortLivedAPIToken from './getShortLivedAPIToken.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\nasync function getFallbackApiToken(\n endpoint: string,\n environment: Pick<EnvironmentResult, 'link' | 'ci'> | undefined,\n logger: Logger,\n): Promise<{ key: string; secret: string } | undefined> {\n if (environment?.link) {\n try {\n // Fetch pull request auth\n const pullRequestSecret = await getPullRequestSecret(\n endpoint,\n environment.link,\n logger,\n );\n return {\n key: environment.link,\n secret: pullRequestSecret,\n };\n } catch {\n logger.log(\n `Failed to obtain temporary pull-request token for URL: ${environment.link}`,\n );\n }\n }\n\n if (!environment?.ci) {\n const shortLivedApiToken = await getShortLivedAPIToken(endpoint, logger);\n return shortLivedApiToken ?? undefined;\n }\n return undefined;\n}\n\nexport async function loadConfigFile(\n configFilePath: string,\n environment?: Pick<EnvironmentResult, 'link' | 'ci'>,\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 // eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: change this to unknown and add type assertions\n let config: any;\n try {\n config = (await import(configFilePath)).default;\n } catch (error) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ERR_UNKNOWN_FILE_EXTENSION'\n ) {\n // Older versions of Node don't support .ts files natively, so let's throw\n // a more helpful error message.\n const extension = path.extname(configFilePath);\n throw new TypeError(\n `Your Happo config file ${configFilePath} is using an extension that is not supported by this version of Node.js (${extension}). Please use a newer version of Node.js (22.18.0+, 23.6.0+, or 24+).`,\n { cause: error },\n );\n }\n\n throw error;\n }\n\n if (config === null) {\n throw new TypeError(\n `Your Happo config file ${configFilePath} must have a default export that is an object, got: null.`,\n );\n }\n\n if (typeof config !== 'object') {\n throw new TypeError(\n `Your Happo config file ${configFilePath} must have a default export that is an object, got: ${typeof config}.`,\n );\n }\n\n if (Array.isArray(config)) {\n throw new TypeError(\n `Your Happo config file ${configFilePath} must have a default export that is an object, got: array.`,\n );\n }\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 logger.log(\n `Missing ${missing} in Happo config. Attempting alternative authentication.`,\n );\n const fallbackApiToken = await getFallbackApiToken(\n config.endpoint || DEFAULT_ENDPOINT,\n environment,\n logger,\n );\n if (!fallbackApiToken) {\n throw new Error(\n `Missing ${missing} in your Happo config. Reference yours at https://happo.io/settings`,\n );\n }\n config.apiKey = fallbackApiToken.key;\n config.apiSecret = fallbackApiToken.secret;\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 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", "{\n \"name\": \"happo\",\n \"version\": \"6.2.3\",\n \"description\": \"Catch unexpected visual and accessibility changes and UI bugs\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/happo/happo.git\"\n },\n \"bugs\": \"https://github.com/happo/happo/issues\",\n \"homepage\": \"https://happo.io\",\n \"bin\": {\n \"happo\": \"dist/cli/main.js\"\n },\n \"type\": \"module\",\n \"main\": \"./dist/config/index.js\",\n \"types\": \"./dist/config/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/config/index.d.ts\",\n \"default\": \"./dist/config/index.js\"\n },\n \"./cypress\": {\n \"types\": \"./dist/cypress/index.d.ts\",\n \"default\": \"./dist/cypress/index.js\"\n },\n \"./cypress/task\": {\n \"types\": \"./dist/cypress/task.d.ts\",\n \"default\": \"./dist/cypress/task.js\"\n },\n \"./playwright\": {\n \"types\": \"./dist/playwright/index.d.ts\",\n \"default\": \"./dist/playwright/index.js\"\n },\n \"./custom\": {\n \"types\": \"./dist/custom/index.d.ts\",\n \"default\": \"./dist/custom/index.js\"\n },\n \"./storybook/addon\": {\n \"types\": \"./dist/storybook/browser/addon.d.ts\",\n \"default\": \"./dist/storybook/browser/addon.js\"\n },\n \"./storybook/decorator\": {\n \"types\": \"./dist/storybook/browser/decorator.d.ts\",\n \"default\": \"./dist/storybook/browser/decorator.js\"\n },\n \"./storybook/preset\": {\n \"types\": \"./dist/storybook/preset.d.ts\",\n \"default\": \"./dist/storybook/preset.js\"\n },\n \"./storybook/register\": {\n \"types\": \"./dist/storybook/browser/register.d.ts\",\n \"default\": \"./dist/storybook/browser/register.js\"\n }\n },\n \"files\": [\n \"dist\",\n \"preset.js\"\n ],\n \"scripts\": {\n \"all\": \"node ./scripts/allchecks.ts\",\n \"build\": \"pnpm build:types && pnpm build:dist\",\n \"build:custom\": \"esbuild src/custom/__happo__/index.ts --bundle --format=iife --global-name=happoCustom --outfile=tmp/happo-custom/bundle.js --platform=browser --target=esnext\",\n \"build:dist\": \"./scripts/build.ts\",\n \"build:types\": \"pnpm tsc --pretty\",\n \"build:watch\": \"tsc --build --watch\",\n \"clean\": \"rm -rf dist tmp/tsc tmp/happo-custom\",\n \"lint\": \"eslint .\",\n \"prepublishOnly\": \"pnpm clean && pnpm build\",\n \"storybook:dev\": \"storybook dev --config-dir src/storybook/__tests__/storybook-app -p ${PORT:-6007}\",\n \"test\": \"node --env-file-if-exists=.env.local ./scripts/test.ts\",\n \"test:custom\": \"pnpm build:dist && pnpm build:custom && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.custom.config.ts\",\n \"test:cypress\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.cypress.config.ts e2e -- cypress run -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:cypress:open\": \"cypress open -C src/cypress/__cypress__/cypress.config.ts\",\n \"test:playwright\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.playwright.config.ts e2e -- playwright test\",\n \"test:storybook\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.storybook.config.ts\",\n \"test:pages\": \"pnpm build:dist && node --env-file-if-exists=.env.local dist/cli/main.js -c ./happoconfigs/happo.pages.config.ts\",\n \"tsc\": \"tsc --build tsconfig.json\"\n },\n \"browserslist\": {\n \"node\": [\n \"node 22\"\n ],\n \"browser\": [\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ],\n \"isomorphic\": [\n \"node 22\",\n \"last 2 Chrome major versions\",\n \"last 2 Firefox major versions\",\n \"last 2 Safari major versions\",\n \"last 2 Edge major versions\"\n ]\n },\n \"prettier\": {\n \"printWidth\": 85,\n \"singleQuote\": true,\n \"trailingComma\": \"all\",\n \"arrowParens\": \"always\"\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^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.18.0 || ^23.6.0 || >=24.0.0\"\n }\n}\n", "import http from 'node:http';\n\nexport interface ServerInfo {\n close: () => Promise<void>;\n port: number;\n}\n\nexport default function startServer(\n requestHandler: (req: http.IncomingMessage, res: http.ServerResponse) => void,\n { port }: { port?: number | undefined } = {},\n): Promise<ServerInfo> {\n return new Promise((resolve) => {\n const server = http.createServer(requestHandler);\n server.listen(port, () => {\n const address = server.address();\n if (!address || typeof address === 'string') {\n throw new Error('Expected server address to be AddressInfo');\n }\n resolve({\n close: () =>\n new Promise((resolve, reject) =>\n server.close((err) => (err ? reject(err) : resolve())),\n ),\n port: address.port,\n });\n });\n });\n}\n", "import { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\nexport default function openBrowser(url: string): Promise<void> {\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n command = `open \"${url}\"`;\n } else if (platform === 'win32') {\n command = `start \"\" \"${url}\"`;\n } else {\n // Linux and others\n command = `xdg-open \"${url}\"`;\n }\n\n return execAsync(command).then(() => {\n // Ignore errors - browser might not open, but that's okay\n });\n}\n\n", "import { createInterface } from 'node:readline';\n\nexport default function promptUser(message: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n rl.question(message, (answer) => {\n rl.close();\n // Only proceed if Enter was pressed (empty string or newline)\n if (answer.trim() === '') {\n resolve();\n } else {\n reject(new Error('User cancelled authentication'));\n }\n });\n });\n}\n\n", "import type { Logger } from '../isomorphic/types.ts';\nimport startServer from '../network/startServer.ts';\nimport openBrowser from './openBrowser.ts';\nimport promptUser from './promptUser.ts';\n\nconst VALID_HEX_REGEX = /^[0-9a-fA-F]+$/;\n\nfunction createHTML(endpoint: string, phase: string): string {\n return `<!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <title>Happo CLI Authentication</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script type=\"text/javascript\">\n const message = { type: 'happo-cli-auth', payload: { phase: '${phase}' } };\n // Use the exact origin of the parent page\n window.parent.postMessage(message, '${endpoint}'); \n </script>\n </head>\n <body>\n <main>\n <h1>Happo CLI Authentication</h1> \n <p>Authentication successful!</p>\n </main>\n </body>\n </html>`;\n}\n\nfunction validateKeyAndSecret(args: {\n key: string | null;\n secret: string | null;\n}): args is { key: string; secret: string } {\n const { key, secret } = args;\n if (!key) {\n return false;\n }\n if (!secret) {\n return false;\n }\n if (key.length < 10 || key.length > 64) {\n return false;\n }\n if (secret.length < 20 || secret.length > 256) {\n return false;\n }\n // validate that key and secret are valid hex strings\n if (!VALID_HEX_REGEX.test(key)) {\n return false;\n }\n if (!VALID_HEX_REGEX.test(secret)) {\n return false;\n }\n return true;\n}\n\nexport default async function getShortLivedAPIToken(\n endpoint: string,\n logger: Logger,\n): Promise<{ key: string; secret: string } | null> {\n if (!process.stdin.isTTY) {\n return null;\n }\n // Prompt user to press Enter only if in an interactive terminal\n await promptUser('Press <Enter> to authenticate in the browser');\n\n // Set up promise to wait for callback\n let resolveCallback: (value: { key: string; secret: string }) => void;\n let rejectCallback: (error: Error) => void;\n const callbackPromise = new Promise<{ key: string; secret: string }>(\n (resolve, reject) => {\n resolveCallback = resolve;\n rejectCallback = reject;\n },\n );\n\n // Start local server on auto port\n const serverInfo = await startServer((req, res) => {\n // Get port from the request socket\n const url = new URL(req.url ?? '', `http://localhost:${serverInfo.port}`);\n\n if (url.pathname === '/callback') {\n const token = {\n key: url.searchParams.get('key'),\n secret: url.searchParams.get('secret'),\n };\n const ping = url.searchParams.get('ping');\n\n if (ping) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(createHTML(endpoint, 'auth'));\n return;\n }\n if (validateKeyAndSecret(token)) {\n // Send success response\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(createHTML(endpoint, 'done'));\n\n // Resolve the promise with token and secret\n return resolveCallback(token);\n }\n res.writeHead(400, { 'Content-Type': 'text/html' });\n res.end('Bad request');\n return rejectCallback(new Error('Missing key or secret in callback'));\n }\n\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n });\n\n const callbackUrl = `http://localhost:${serverInfo.port}/callback`;\n const authUrl = `${endpoint}/cli/auth?callbackUrl=${encodeURIComponent(callbackUrl)}`;\n\n try {\n // Open browser\n console.log(`Opening URL: ${authUrl}`);\n await openBrowser(authUrl);\n const result = await callbackPromise;\n return result;\n } catch (error) {\n logger.error(\n `Failed to authenticate: ${error instanceof Error ? error.message : String(error)}`,\n );\n return null;\n } finally {\n // Clean up server\n await serverInfo.close();\n }\n}\n", "import { SignJWT } from 'jose';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport type { Logger } from '../isomorphic/types.ts';\nimport fetchWithRetry from './fetchWithRetry.ts';\n\ntype FormDataValue = string | File | undefined;\n\nexport interface RequestAttributes {\n /**\n * The path to the API endpoint\n *\n * @example\n * '/api/snap-requests/with-results'\n */\n path?: `/api/${string}`;\n\n /**\n * The URL to fetch\n *\n * Prefer using the `path` property instead. If both are provided, the `path`\n * property will be used.\n */\n url?: string;\n\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n formData?: Record<string, FormDataValue>;\n body?: unknown;\n json?: boolean;\n}\n\nexport interface MakeHappoAPIRequestOptions {\n /**\n * The timeout in milliseconds\n * @default 60_000\n */\n timeout?: number;\n\n /**\n * The number of times to retry the request\n * @default 0\n */\n retryCount?: number;\n\n /**\n * The minimum timeout in milliseconds\n * @default 1000\n */\n retryMinTimeout?: number;\n\n /**\n * The maximum timeout in milliseconds\n * @default Infinity\n */\n retryMaxTimeout?: number;\n}\n\nasync function signRequest(apiKey: string, apiSecret: string): Promise<string> {\n const encodedSecret = new TextEncoder().encode(apiSecret);\n return await new SignJWT({ key: apiKey })\n .setProtectedHeader({ alg: 'HS256', kid: apiKey })\n .sign(encodedSecret);\n}\n\nexport default async function makeHappoAPIRequest(\n { url, path, method = 'GET', formData, body }: RequestAttributes,\n { apiKey, apiSecret, endpoint }: ConfigWithDefaults,\n {\n retryCount = 0,\n timeout = 60_000,\n retryMinTimeout = 1000,\n retryMaxTimeout = Infinity,\n }: MakeHappoAPIRequestOptions,\n logger: Logger = console,\n): Promise<object | null> {\n const fetchURL = path ? new URL(path, endpoint) : url;\n\n if (!fetchURL) {\n throw new Error(\n 'No fetch URL provided. Either `path` (preferred) or `url` must be provided.',\n );\n }\n\n const signed = await signRequest(apiKey, apiSecret);\n\n const headers = {\n Authorization: `Bearer ${signed}`,\n };\n\n const response = await fetchWithRetry(\n fetchURL,\n {\n method,\n headers,\n formData,\n body,\n timeout,\n retryCount,\n retryMinTimeout,\n retryMaxTimeout,\n },\n logger,\n );\n\n if (response.status === 204) {\n return null;\n }\n\n // We expect API responses to be JSON, so let's parse it as JSON here for\n // convenience.\n const result = await response.json();\n\n if (typeof result !== 'object') {\n throw new TypeError(`Response is not an object: ${JSON.stringify(result)}`);\n }\n\n return result;\n}\n", "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 makeHappoAPIRequest from '../network/makeHappoAPIRequest.ts';\nimport createHash from '../utils/createHash.ts';\nimport type { ConfigWithDefaults, Page, TargetWithDefaults } from './index.ts';\n\nconst VIEWPORT_PATTERN = /^([0-9]+)x([0-9]+)$/;\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 BoundMakeRequestParams {\n slice?: Array<unknown> | undefined;\n chunk?: Chunk | undefined;\n pageSlice?: PageSlice | undefined;\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\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\nexport default class RemoteBrowserTarget {\n public readonly chunks: number;\n public readonly browserName: string;\n public readonly viewport: string;\n public readonly maxHeight: number | undefined;\n public readonly otherOptions: Record<string, unknown>;\n\n constructor(\n browserName: string,\n {\n viewport = '1024x768',\n chunks = 1,\n maxHeight,\n ...otherOptions\n }: TargetWithDefaults,\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 }: ExecuteParams,\n config: ConfigWithDefaults,\n ): Promise<Array<number>> {\n const boundMakeRequest = async ({\n slice,\n chunk,\n pageSlice,\n }: BoundMakeRequestParams): Promise<number> => {\n const payloadString = JSON.stringify({\n viewport: this.viewport,\n maxHeight: this.maxHeight,\n ...this.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(\n payloadString + (pageSlice ? Math.random() : ''),\n );\n\n const formData: Record<string, string | File | undefined> = {\n type:\n pageSlice && pageSlice.extendsSha\n ? 'extends-report'\n : `browser-${this.browserName}`,\n targetName,\n payloadHash,\n payload: new File([payloadString], 'payload.json', {\n type: 'application/json',\n }),\n };\n\n if (pageSlice && pageSlice.extendsSha) {\n formData.extendsSha = pageSlice.extendsSha;\n }\n\n const requestResult = await makeHappoAPIRequest(\n {\n path: `/api/snap-requests?payloadHash=${payloadHash}`,\n method: 'POST',\n json: true,\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\n const requestIds: Array<number> = [];\n\n if (staticPackage) {\n for (let i = 0; i < this.chunks; i += 1) {\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 requestId = await boundMakeRequest({\n chunk: { index: i, total: this.chunks },\n });\n requestIds.push(requestId);\n }\n } else if (pages) {\n for (const pageSlice of getPageSlices(pages, this.chunks)) {\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 requestId = await boundMakeRequest({\n pageSlice,\n });\n requestIds.push(requestId);\n }\n } else {\n const snapsPerChunk = Math.ceil((snapPayloads?.length ?? 0) / this.chunks);\n for (let i = 0; i < this.chunks; i += 1) {\n const slice = snapPayloads?.slice(\n i * snapsPerChunk,\n i * snapsPerChunk + snapsPerChunk,\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 requestId = await boundMakeRequest({\n slice,\n });\n requestIds.push(requestId);\n }\n }\n\n return requestIds;\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 json: true,\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 json: true,\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", "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 fs from 'node:fs';\n\nimport { Base64Decode } from 'base64-stream';\n\nexport default async function convertBase64FileToReal(\n filenameB64: string,\n filename: string,\n): Promise<void> {\n const readStream = fs.createReadStream(filenameB64);\n const outStream = fs.createWriteStream(filename, { encoding: undefined });\n const readyPromise = new Promise<void>((resolve, reject) => {\n outStream.on('finish', resolve);\n outStream.on('error', reject);\n });\n readStream.pipe(new Base64Decode()).pipe(outStream);\n\n await readyPromise;\n\n // Clean up the base64 file after we're done\n await fs.promises.unlink(filenameB64);\n}\n", "import crypto from 'node:crypto';\nimport { Readable } from 'node:stream';\nimport type { ReadableStream } from 'node:stream/web';\n\nimport mime from 'mime-types';\n\nimport fetchWithRetry from '../network/fetchWithRetry.ts';\nimport type { ArchiveContentEntry } from '../utils/deterministicArchive.ts';\nimport deterministicArchive from '../utils/deterministicArchive.ts';\nimport makeAbsolute from './makeAbsolute.ts';\n\n// Type definitions\nexport interface AssetUrl {\n url: string;\n baseUrl?: string | undefined;\n name?: string;\n}\n\nfunction stripQueryParams(url: string): string {\n const i = url.indexOf('?');\n if (i !== -1) {\n return url.slice(0, i);\n }\n return url;\n}\n\nfunction normalize(url: string, baseUrl: string): string {\n if (url.startsWith(baseUrl)) {\n return url.slice(baseUrl.length);\n }\n if (url.startsWith('/')) {\n return url.slice(1);\n }\n if (url.startsWith('../')) {\n return url.slice(3);\n }\n return url;\n}\n\nfunction getFileSuffixFromMimeType(mimeType = ''): string {\n const ext = mime.extension(mimeType);\n if (!ext) {\n return '';\n }\n return `.${ext}`;\n}\n\nexport default async function createAssetPackage(\n urls: Array<AssetUrl>,\n { downloadAllAssets }: { downloadAllAssets?: boolean },\n): Promise<{ buffer: Buffer<ArrayBuffer>; hash: string }> {\n const { HAPPO_DEBUG } = process.env;\n\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Creating asset package from urls`, urls);\n }\n\n const seenUrls = new Set<string>();\n\n const archiveFiles: Array<string> = [];\n const archiveContent: Array<ArchiveContentEntry> = [];\n\n // Get all of the archive items in parallel first. Then add them to the\n // archive serially afterwards to ensure that packages are created\n // deterministically.\n await Promise.all(\n urls.map(async (item: AssetUrl) => {\n const { url, baseUrl } = item;\n const isExternalUrl = /^https?:/.test(url);\n const isLocalhost = /\\/\\/(localhost|127\\.0\\.0\\.1)(:|\\/)/.test(url);\n\n if (!downloadAllAssets && isExternalUrl && !isLocalhost) {\n return;\n }\n\n const isDynamic = url.includes('?');\n let name =\n isExternalUrl || isDynamic\n ? `_external/${crypto.createHash('md5').update(url).digest('hex')}`\n : normalize(stripQueryParams(url), baseUrl || '');\n\n if (name.startsWith('#') || name === '' || seenUrls.has(name)) {\n return;\n }\n\n seenUrls.add(name);\n\n if (/\\.happo-tmp\\/_inlined/.test(name)) {\n if (HAPPO_DEBUG) {\n console.log(`[HAPPO] Adding inlined asset ${name}`);\n }\n\n archiveFiles.push(name);\n } else {\n const fetchUrl = makeAbsolute(url, baseUrl || '');\n\n if (HAPPO_DEBUG) {\n console.log(\n `[HAPPO] Fetching asset from ${fetchUrl} \u2014 storing as ${name}`,\n );\n }\n\n try {\n const fetchRes = await fetchWithRetry(fetchUrl, { retryCount: 5 });\n\n const { body } = fetchRes;\n\n if (!body) {\n throw new Error(`No body for ${fetchUrl}`);\n }\n\n if (isDynamic || isExternalUrl) {\n // Add a file suffix so that svg images work\n name = `${name}${getFileSuffixFromMimeType(\n fetchRes.headers.get('content-type') || 'image/png',\n )}`;\n }\n\n // decode URI to make sure \"%20\" and such are converted to the right\n // chars\n name = decodeURI(name);\n item.name = `/${name}`;\n\n const content = Readable.fromWeb(\n // Unfortunately, it seems that we need to use a type cast here for\n // now. More info:\n // https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65542#discussioncomment-6071004\n body as ReadableStream<Uint8Array>,\n );\n\n archiveContent.push({\n name,\n content,\n });\n } catch (error) {\n console.log(`[HAPPO] Failed to fetch url ${fetchUrl}`);\n console.error(error);\n }\n }\n }),\n );\n\n return deterministicArchive(archiveFiles, archiveContent);\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// 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: path.relative(resolvedDirOrFile, fullPath),\n stream: fs.createReadStream(fullPath),\n });\n }\n }\n\n return fileEntries;\n }\n\n return [\n {\n name: 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 if (!seenFiles.has(file.name)) {\n const data = await contentToUint8Array(file.content);\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 // 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 { URL } from 'node:url';\n\nexport default function makeAbsolute(url: string, baseUrl: string): string {\n if (url.startsWith('//')) {\n return `${baseUrl.split(':')[0]}:${url}`;\n }\n if (/^https?:/.test(url)) {\n return url;\n }\n return new URL(url, baseUrl).href;\n}\n", "import { URL } from 'node:url';\n\nimport { URL_PATTERN } from '../isomorphic/findCSSAssetUrls.ts';\n\nexport default function makeExternalUrlsAbsolute(\n text: string,\n absUrl: string,\n): string {\n return text.replaceAll(URL_PATTERN, (full, pre, url, post) => {\n if (url.startsWith('data:')) {\n return full;\n }\n const fullUrl = new URL(url, absUrl);\n return `${pre}${fullUrl.href}${post}`;\n });\n}\n", "import Controller, { type SnapshotRegistrationParams } from '../e2e/controller.ts';\n\nconst controller = new Controller();\n\nconst { HAPPO_DEBUG } = process.env;\n\ninterface Attempt {\n wallClockStartedAt?: string;\n wallClockDuration?: number;\n state: string;\n}\n\nfunction getCleanupTimeframe({\n attempt,\n results,\n}: {\n attempt: Attempt;\n results: CypressCommandLine.RunResult;\n}): { start: number; end: number } {\n if (attempt.wallClockStartedAt && attempt.wallClockDuration) {\n // Cypress <= v12 (custom timing data)\n const start = new Date(attempt.wallClockStartedAt).getTime();\n return { start, end: start + attempt.wallClockDuration };\n }\n\n // Cypress >= 13 (use official stats)\n if (!results.stats) {\n if (HAPPO_DEBUG) {\n console.log(\n `[HAPPO] Couldn't find start and end time for failed attempt. This could lead to duplicate screenshots in your Happo reports.`,\n );\n }\n return { start: 0, end: 0 };\n }\n\n const start = new Date(results.stats.startedAt).getTime();\n const end = new Date(results.stats.endedAt).getTime();\n return { start, end };\n}\n\ninterface HappoTask {\n isRegisteredCorrectly: boolean;\n register(on: Cypress.PluginEvents): void;\n handleAfterSpec(\n spec: Cypress.Spec,\n results: CypressCommandLine.RunResult,\n ): Promise<void>;\n happoRegisterSnapshot(snapshot: SnapshotRegistrationParams): Promise<null>;\n happoRegisterBase64Image(params: {\n base64Chunk: string;\n src: string;\n isFirst: boolean;\n isLast: boolean;\n }): Promise<null>;\n handleBeforeSpec(): Promise<void>;\n}\n\nconst task: HappoTask = {\n isRegisteredCorrectly: false,\n\n register(on: Cypress.PluginEvents) {\n on('task', {\n happoRegisterSnapshot: task.happoRegisterSnapshot,\n happoRegisterBase64Image: task.happoRegisterBase64Image,\n });\n on('before:spec', task.handleBeforeSpec);\n on('after:spec', task.handleAfterSpec);\n task.isRegisteredCorrectly = true;\n },\n\n async handleAfterSpec(\n _spec: Cypress.Spec,\n results: CypressCommandLine.RunResult,\n ): Promise<void> {\n if (!controller.isActive()) {\n return;\n }\n if (results) {\n for (const test of results.tests) {\n const wasRetried =\n test.attempts.some((t) => t.state === 'failed') &&\n test.attempts.at(-1)?.state === 'passed';\n if (!wasRetried) {\n continue;\n }\n for (const attempt of test.attempts) {\n if (attempt.state === 'failed') {\n const { start, end } = getCleanupTimeframe({\n attempt,\n results,\n });\n controller.removeDuplicatesInTimeframe({\n start,\n end,\n });\n }\n }\n }\n }\n\n await controller.finish();\n },\n\n async happoRegisterSnapshot(snapshot: SnapshotRegistrationParams): Promise<null> {\n if (!controller.isActive()) {\n return null;\n }\n await controller.registerSnapshot(snapshot);\n return null;\n },\n\n async happoRegisterBase64Image({\n base64Chunk,\n src,\n isFirst,\n isLast,\n }: {\n base64Chunk: string;\n src: string;\n isFirst: boolean;\n isLast: boolean;\n }): Promise<null> {\n if (!controller.isActive()) {\n return null;\n }\n await controller.registerBase64ImageChunk({\n base64Chunk,\n src,\n isFirst,\n isLast,\n });\n return null;\n },\n\n async handleBeforeSpec(): Promise<void> {\n await controller.init();\n\n if (controller.isActive() && !task.isRegisteredCorrectly) {\n throw new Error(`Happo hasn't been registered correctly. Make sure you call \\`happoTask.register\\` when you register the plugin:\n\n const happoTask = require('happo/cypress/task');\n\n module.exports = (on) => {\n happoTask.register(on);\n };\n `);\n }\n },\n};\n\nexport default task;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["fs", "resolve", "path", "fs", "crypto", "fs", "path", "path", "fs", "URL", "HAPPO_DEBUG", "crypto", "URL", "URL", "HAPPO_DEBUG", "fs", "start"]
|
|
7
7
|
}
|
package/dist/playwright/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import asyncRetry from "async-retry";
|
|
|
18
18
|
// package.json
|
|
19
19
|
var package_default = {
|
|
20
20
|
name: "happo",
|
|
21
|
-
version: "6.2.
|
|
21
|
+
version: "6.2.3",
|
|
22
22
|
description: "Catch unexpected visual and accessibility changes and UI bugs",
|
|
23
23
|
license: "MIT",
|
|
24
24
|
repository: {
|
|
@@ -72,7 +72,8 @@ var package_default = {
|
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
files: [
|
|
75
|
-
"dist"
|
|
75
|
+
"dist",
|
|
76
|
+
"preset.js"
|
|
76
77
|
],
|
|
77
78
|
scripts: {
|
|
78
79
|
all: "node ./scripts/allchecks.ts",
|