happo 6.3.6 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/cli/cancelJob-ORBIXVT5.js +10 -0
  2. package/dist/cli/{chunk-B4NWDBAN.js → chunk-6PWJAPHP.js} +2 -2
  3. package/dist/cli/chunk-6PWJAPHP.js.map +7 -0
  4. package/dist/cli/{chunk-2F4ONKOX.js → chunk-IGI756V3.js} +3 -3
  5. package/dist/cli/{chunk-GBORF5SP.js → chunk-JOPTBOXW.js} +2 -2
  6. package/dist/cli/{chunk-VOPCZYUD.js → chunk-QTTEOWAX.js} +2 -2
  7. package/dist/cli/{chunk-VOPCZYUD.js.map → chunk-QTTEOWAX.js.map} +1 -1
  8. package/dist/cli/{chunk-QIVIGY3K.js → chunk-ULGAHSS5.js} +2 -2
  9. package/dist/cli/{chunk-4FHG27V2.js → chunk-WJIEJMLG.js} +4 -4
  10. package/dist/cli/chunk-WJIEJMLG.js.map +7 -0
  11. package/dist/cli/createAsyncComparison-XISBMLXA.js +10 -0
  12. package/dist/cli/{createAsyncReport-MZGC4WYR.js → createAsyncReport-A27NY62E.js} +4 -4
  13. package/dist/cli/{getFlakes-OZICV3BM.js → getFlakes-CPW3FFIF.js} +4 -4
  14. package/dist/cli/main.js +11 -11
  15. package/dist/cli/package-ZLQ7KI7I.js +7 -0
  16. package/dist/cli/{prepareSnapRequests-6BOXFGHI.js → prepareSnapRequests-74QL6FGT.js} +77 -42
  17. package/dist/cli/prepareSnapRequests-74QL6FGT.js.map +7 -0
  18. package/dist/cli/startJob-NZDZNGVS.js +10 -0
  19. package/dist/cli/{wrapper-UNP6YKH6.js → wrapper-PXCRJ4BX.js} +7 -7
  20. package/dist/config/RemoteBrowserTarget.d.ts +7 -1
  21. package/dist/config/RemoteBrowserTarget.d.ts.map +1 -1
  22. package/dist/config/index.d.ts +5 -1
  23. package/dist/config/index.d.ts.map +1 -1
  24. package/dist/config/index.js.map +2 -2
  25. package/dist/cypress/task.js +6 -4
  26. package/dist/cypress/task.js.map +2 -2
  27. package/dist/network/fetchWithRetry.d.ts +1 -1
  28. package/dist/network/fetchWithRetry.d.ts.map +1 -1
  29. package/dist/network/makeHappoAPIRequest.d.ts +1 -1
  30. package/dist/network/makeHappoAPIRequest.d.ts.map +1 -1
  31. package/dist/network/prepareSnapRequests.d.ts.map +1 -1
  32. package/dist/playwright/index.js +6 -4
  33. package/dist/playwright/index.js.map +2 -2
  34. package/dist/storybook/getStorybookStoryCount.d.ts +7 -0
  35. package/dist/storybook/getStorybookStoryCount.d.ts.map +1 -0
  36. package/dist/storybook/index.d.ts +5 -1
  37. package/dist/storybook/index.d.ts.map +1 -1
  38. package/dist/storybook/index.js +34 -13
  39. package/dist/storybook/index.js.map +4 -4
  40. package/package.json +1 -1
  41. package/dist/cli/cancelJob-LQPQPD5I.js +0 -10
  42. package/dist/cli/chunk-4FHG27V2.js.map +0 -7
  43. package/dist/cli/chunk-B4NWDBAN.js.map +0 -7
  44. package/dist/cli/createAsyncComparison-5ZQY53AW.js +0 -10
  45. package/dist/cli/package-FRXI4E4G.js +0 -7
  46. package/dist/cli/prepareSnapRequests-6BOXFGHI.js.map +0 -7
  47. package/dist/cli/startJob-GASMCYIM.js +0 -10
  48. /package/dist/cli/{cancelJob-LQPQPD5I.js.map → cancelJob-ORBIXVT5.js.map} +0 -0
  49. /package/dist/cli/{chunk-2F4ONKOX.js.map → chunk-IGI756V3.js.map} +0 -0
  50. /package/dist/cli/{chunk-GBORF5SP.js.map → chunk-JOPTBOXW.js.map} +0 -0
  51. /package/dist/cli/{chunk-QIVIGY3K.js.map → chunk-ULGAHSS5.js.map} +0 -0
  52. /package/dist/cli/{createAsyncComparison-5ZQY53AW.js.map → createAsyncComparison-XISBMLXA.js.map} +0 -0
  53. /package/dist/cli/{createAsyncReport-MZGC4WYR.js.map → createAsyncReport-A27NY62E.js.map} +0 -0
  54. /package/dist/cli/{getFlakes-OZICV3BM.js.map → getFlakes-CPW3FFIF.js.map} +0 -0
  55. /package/dist/cli/{package-FRXI4E4G.js.map → package-ZLQ7KI7I.js.map} +0 -0
  56. /package/dist/cli/{startJob-GASMCYIM.js.map → startJob-NZDZNGVS.js.map} +0 -0
  57. /package/dist/cli/{wrapper-UNP6YKH6.js.map → wrapper-PXCRJ4BX.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/network/prepareSnapRequests.ts", "../../src/utils/createHash.ts", "../../src/config/RemoteBrowserTarget.ts", "../../src/storybook/index.ts", "../../src/storybook/getStorybookBuildCommandParts.ts", "../../src/storybook/getStorybookStoryCount.ts", "../../src/storybook/getStorybookVersionFromPackageJson.ts", "../../src/utils/deterministicArchive.ts", "../../src/utils/validateArchive.ts", "../../src/utils/Logger.ts", "../../src/network/uploadAssets.ts"],
4
+ "sourcesContent": ["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport RemoteBrowserTarget, {\n type ExecuteParams,\n} from '../config/RemoteBrowserTarget.ts';\nimport buildStorybookPackage from '../storybook/index.ts';\nimport deterministicArchive from '../utils/deterministicArchive.ts';\nimport Logger, { logTag } from '../utils/Logger.ts';\nimport uploadAssets from './uploadAssets.ts';\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await fs.promises.stat(path);\n return true;\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n return false;\n }\n\n throw error;\n }\n}\n\nasync function createIframeHTML(\n rootDir: string,\n entryPoint: string,\n logger: Logger,\n): Promise<void> {\n const iframePath = path.join(rootDir, 'iframe.html');\n\n if (await fileExists(iframePath)) {\n logger.info(`Using existing iframe.html at '${iframePath}'`);\n return;\n }\n\n const iframeContent = `<!DOCTYPE html>\n<html lang=\"en\" dir=\"ltr\">\n <head>\n <title>Happo</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n </head>\n <body>\n <script src=\"${entryPoint}\"></script>\n </body>\n</html>`;\n\n await fs.promises.mkdir(rootDir, { recursive: true });\n await fs.promises.writeFile(iframePath, iframeContent);\n}\n\ninterface BuildPackageResult {\n packageDir: string;\n estimatedSnapsCount?: number;\n}\n\nasync function buildPackage(\n { integration }: ConfigWithDefaults,\n logger: Logger,\n): Promise<BuildPackageResult> {\n if (integration.type === 'custom') {\n const { rootDir, entryPoint, estimatedSnapsCount } = await integration.build();\n await createIframeHTML(rootDir, entryPoint, logger);\n\n const result: BuildPackageResult = { packageDir: rootDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n return result;\n }\n\n if (integration.type === 'storybook') {\n return await buildStorybookPackage(integration);\n }\n\n throw new Error(`Unsupported integration type: ${integration.type}`);\n}\n\nasync function validatePackage(packageDir: string): Promise<void> {\n const iframePath = path.join(packageDir, 'iframe.html');\n\n if (!(await fileExists(iframePath))) {\n throw new Error(\n `Could not find iframe.html in static package at '${iframePath}'`,\n );\n }\n}\n\ninterface PreparePackageResult {\n packagePath: string;\n estimatedSnapsCount?: number;\n}\n\nasync function preparePackage(\n config: ConfigWithDefaults,\n logger: Logger,\n): Promise<PreparePackageResult> {\n const { packageDir, estimatedSnapsCount } = await buildPackage(config, logger);\n\n await validatePackage(packageDir);\n\n const { buffer, hash } = await deterministicArchive([packageDir]);\n const packagePath = await uploadAssets(\n buffer,\n {\n hash,\n logger,\n },\n config,\n );\n\n const result: PreparePackageResult = { packagePath };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n return result;\n}\n\nexport default async function prepareSnapRequests(\n config: ConfigWithDefaults,\n): Promise<Array<number>> {\n const logger = new Logger();\n const prepareResult =\n config.integration.type === 'pages'\n ? null\n : await preparePackage(config, logger);\n\n const targetNames = Object.keys(config.targets);\n const tl = targetNames.length;\n logger.info(\n `${logTag(config.project)}Generating screenshots in ${tl} target${\n tl > 1 ? 's' : ''\n }...`,\n );\n const outerStartTime = Date.now();\n const results: Array<number> = [];\n await Promise.all(\n targetNames.map(async (name) => {\n const startTime = Date.now();\n\n if (!config.targets[name]) {\n throw new Error(`Target ${name} not found in config`);\n }\n\n const target = new RemoteBrowserTarget(\n config.targets[name].type,\n config.targets[name],\n );\n\n const targetParams: ExecuteParams = {\n targetName: name,\n };\n\n if (prepareResult) {\n targetParams.staticPackage = prepareResult.packagePath;\n\n if (prepareResult.estimatedSnapsCount != null) {\n targetParams.estimatedSnapsCount = prepareResult.estimatedSnapsCount;\n }\n }\n\n if (config.integration.type === 'pages') {\n targetParams.pages = config.integration.pages;\n }\n\n const snapRequestIds = await target.execute(targetParams, config);\n logger.start(` - ${logTag(config.project)}${name}`, { startTime });\n logger.success();\n results.push(...snapRequestIds);\n }),\n );\n logger.start(undefined, { startTime: outerStartTime });\n logger.success();\n return results;\n}\n", "import crypto from 'node:crypto';\n\n/**\n * Creates an MD5 hash of the input data\n * @param data - The data to hash (string, Buffer, or TypedArray)\n * @returns The MD5 hash as a hexadecimal string\n */\nexport default function createHash(\n data: string | Buffer | NodeJS.TypedArray,\n): string {\n return crypto.createHash('md5').update(data).digest('hex');\n}\n", "import makeHappoAPIRequest from '../network/makeHappoAPIRequest.ts';\nimport createHash from '../utils/createHash.ts';\nimport type {\n BrowserType,\n ConfigWithDefaults,\n Page,\n TargetWithDefaults,\n} from './index.ts';\n\nconst VIEWPORT_PATTERN = /^([0-9]+)x([0-9]+)$/;\n\n/**\n * 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 /**\n * Total number of snapshots in the package. When provided for staticPackage\n * requests, the server can use this to automatically determine the optimal\n * number of parallel chunks.\n */\n estimatedSnapsCount?: number;\n}\n\nfunction getPageSlices(pages: Array<Page>, chunks: number): Array<PageSlice> {\n const result: Array<PageSlice> = [];\n\n // First, split the raw pages into chunks\n const pagesPerChunk = Math.ceil(pages.length / chunks);\n for (let i = 0; i < chunks; i += 1) {\n const pageSlice = pages.slice(\n i * pagesPerChunk,\n i * pagesPerChunk + pagesPerChunk,\n );\n\n if (pageSlice.length > 0) {\n result.push(pageSlice);\n }\n }\n return result;\n}\n\nexport default class RemoteBrowserTarget {\n public readonly chunks: number;\n public readonly browserName: BrowserType;\n public readonly viewport: string;\n public readonly maxHeight: number | undefined;\n public readonly otherOptions: Record<string, unknown>;\n\n constructor(\n browserName: BrowserType,\n {\n viewport = '1024x768',\n chunks = 1,\n maxHeight,\n ...otherOptions\n }: TargetWithDefaults,\n ) {\n if (!browserName) {\n throw new Error(\n `Invalid browser type: \"${browserName}\". Make sure the \"type\" field in your target configuration is set to a valid browser type.`,\n );\n }\n\n const viewportMatch = viewport.match(VIEWPORT_PATTERN);\n if (!viewportMatch) {\n throw new Error(\n `Invalid viewport \"${viewport}\". Here's an example of a valid one: \"1024x768\".`,\n );\n }\n\n this.chunks = chunks;\n this.browserName = browserName;\n this.viewport = viewport;\n this.maxHeight = maxHeight ?? undefined;\n this.otherOptions = otherOptions;\n }\n\n async execute(\n {\n globalCSS,\n assetsPackage,\n staticPackage,\n snapPayloads,\n pages,\n targetName,\n estimatedSnapsCount,\n }: ExecuteParams,\n config: ConfigWithDefaults,\n ): Promise<Array<number>> {\n const 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 | number | File | undefined> = {\n type:\n pageSlice && pageSlice.extendsSha\n ? 'extends-report'\n : `browser-${this.browserName}`,\n targetName,\n payloadHash,\n estimatedSnapsCount:\n staticPackage && estimatedSnapsCount != null ? estimatedSnapsCount : undefined,\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 { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { StorybookIntegration } from '../config/index.ts';\nimport getStorybookBuildCommandParts from './getStorybookBuildCommandParts.ts';\nimport getStorybookStoryCount from './getStorybookStoryCount.ts';\nimport getStorybookVersionFromPackageJson from './getStorybookVersionFromPackageJson.ts';\nimport type { SkipItems } from './isomorphic/types.ts';\n\nconst { HAPPO_DEBUG } = process.env;\n\nfunction assertSkippedIsSkipItems(skipped: unknown): asserts skipped is SkipItems {\n if (!Array.isArray(skipped)) {\n throw new TypeError(`The \\`skip\\` option didn't provide an array`);\n }\n\n if (skipped.some((item) => !item.component || !item.variant)) {\n throw new Error(\n `Each item provided by the \\`skip\\` option needs a \\`component\\` and a \\`variant\\` property`,\n );\n }\n}\n\nfunction resolveBuildCommandParts() {\n const version = getStorybookVersionFromPackageJson();\n\n if (version < 9) {\n throw new Error(\n `Storybook v${version} is not supported. Please update storybook to v9 or later.`,\n );\n }\n\n return getStorybookBuildCommandParts();\n}\n\nfunction buildStorybook({\n configDir,\n staticDir,\n outputDir,\n}: {\n configDir: string;\n staticDir?: string | undefined;\n outputDir: string;\n}): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.rmSync(outputDir, { recursive: true, force: true });\n\n const buildCommandParts = resolveBuildCommandParts();\n\n if (!buildCommandParts[0]) {\n throw new Error('Failed to resolve build command parts');\n }\n\n const params = [\n ...buildCommandParts,\n '--output-dir',\n outputDir,\n '--config-dir',\n configDir,\n ];\n\n if (staticDir) {\n params.push('--static-dir', staticDir);\n }\n\n let binary = fs.existsSync('yarn.lock') ? 'yarn' : 'npx';\n\n if (buildCommandParts[0].includes('node_modules')) {\n binary = buildCommandParts[0];\n params.shift(); // remove binary from params\n }\n\n if (HAPPO_DEBUG) {\n console.log(`[happo] Using build command \\`${binary} ${params.join(' ')}\\``);\n }\n\n const spawned = spawn(binary, params, {\n stdio: 'inherit',\n shell: process.platform == 'win32',\n });\n\n spawned.on('exit', (code) => {\n if (code === 0) {\n try {\n fs.unlinkSync(path.join(outputDir, 'project.json'));\n } catch (error) {\n console.warn(\n `Ignoring error when attempting to remove project.json: ${error}`,\n );\n }\n resolve();\n } else {\n reject(new Error('Failed to build static storybook package'));\n }\n });\n });\n}\n\nexport interface BuildStorybookPackageResult {\n packageDir: string;\n estimatedSnapsCount?: number;\n}\n\nexport default async function buildStorybookPackage({\n configDir = '.storybook',\n staticDir,\n outputDir = '.out',\n usePrebuiltPackage = false,\n skip,\n}: Omit<StorybookIntegration, 'type'>): Promise<BuildStorybookPackageResult> {\n if (!usePrebuiltPackage) {\n await buildStorybook({ configDir, staticDir, outputDir });\n }\n\n const iframePath = path.join(outputDir, 'iframe.html');\n if (!fs.existsSync(iframePath)) {\n throw new Error(\n 'Failed to build static storybook package (missing iframe.html)',\n );\n }\n\n try {\n const skipped =\n typeof skip === 'function' ? await skip() : Array.isArray(skip) ? skip : [];\n\n assertSkippedIsSkipItems(skipped);\n\n const iframeContent = fs.readFileSync(iframePath, 'utf8');\n\n fs.writeFileSync(\n iframePath,\n iframeContent.replace(\n '<head>',\n `<head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <script type=\"text/javascript\">window.__IS_HAPPO_RUN = true;</script>\n <script type=\"text/javascript\">window.happoSkipped = ${JSON.stringify(\n skipped,\n )};</script>\n `,\n ),\n );\n\n const estimatedSnapsCount = await getStorybookStoryCount(outputDir);\n\n const result: BuildStorybookPackageResult = { packageDir: outputDir };\n if (estimatedSnapsCount != null) {\n result.estimatedSnapsCount = estimatedSnapsCount;\n }\n return result;\n } catch (e) {\n console.error(e);\n throw e;\n }\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\nconst { HAPPO_DEBUG } = process.env;\n\nexport default function getStorybookBuildCommandParts(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): [string, string] {\n try {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n if (packageJson.scripts.storybook) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Found `storybook` script in package.json. Will attempt to use binary found at `node_modules/.bin/storybook` instead',\n );\n }\n\n const pathToStorybookCommand = path.join(\n process.cwd(),\n 'node_modules',\n '.bin',\n 'storybook',\n );\n\n if (fs.existsSync(pathToStorybookCommand)) {\n return [pathToStorybookCommand, 'build'];\n }\n }\n } catch (e) {\n if (HAPPO_DEBUG) {\n console.log(\n '[happo] Caught error when resolving Storybook build command parts. Will use default.',\n e,\n );\n }\n }\n\n return ['storybook', 'build'];\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\ninterface StorybookIndexEntry {\n type: string;\n}\n\ninterface StorybookIndex {\n entries?: Record<string, StorybookIndexEntry>;\n stories?: Record<string, StorybookIndexEntry>;\n}\n\n/**\n * Reads the storybook index.json from the given package directory and returns\n * the total number of story entries (excluding docs and other non-story types).\n * Returns undefined if the file cannot be read or parsed.\n */\nexport default async function getStorybookStoryCount(\n packageDir: string,\n): Promise<number | undefined> {\n const indexPath = path.join(packageDir, 'index.json');\n try {\n const content = await fs.promises.readFile(indexPath, 'utf8');\n const data = JSON.parse(content) as StorybookIndex;\n const entries = data.entries ?? data.stories ?? {};\n return Object.values(entries).filter((e) => e.type === 'story').length;\n } catch (error) {\n console.warn('Failed to get estimated snaps count from Storybook:', error);\n return undefined;\n }\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\n\nexport default function getStorybookVersionFromPackageJson(\n packageJsonPath: string = path.join(process.cwd(), 'package.json'),\n): number {\n const data = fs.readFileSync(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(data);\n\n const combinedDependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const storybookPackage = [\n 'storybook',\n '@storybook/react',\n '@storybook/angular',\n '@storybook/vue',\n ].find((pkg) => combinedDependencies[pkg]);\n\n if (storybookPackage) {\n const storybookVersion = combinedDependencies[storybookPackage];\n const majorVersion = Number.parseInt(storybookVersion.match(/\\d+/)[0], 10);\n return majorVersion;\n } else {\n throw new Error('Storybook is not listed as a dependency in package.json');\n }\n}\n", "import fs from 'node:fs';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\n\nimport type { Zippable } from 'fflate';\nimport { zip } from 'fflate';\n\nimport createHash from './createHash.ts';\nimport validateArchive from './validateArchive.ts';\n\n// 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 { styleText } from 'node:util';\n\ntype PrintFunction = (str: string) => void;\n\nconst red = (str: string) => styleText('red', str);\nconst green = (str: string) => styleText('green', str);\nconst dim = (str: string) => styleText('dim', str);\nconst underline = (str: string) => styleText('underline', str);\n\nexport function logTag(project?: string): string {\n return project ? `[${project}] ` : '';\n}\n\nfunction printDuration(print: PrintFunction, startTime?: number): void {\n if (startTime) {\n print(dim(` (${Date.now() - startTime}ms)`));\n }\n}\n\ninterface LoggerOptions {\n stderrPrint?: PrintFunction;\n print?: PrintFunction;\n}\n\ninterface StartOptions {\n startTime?: number;\n}\n\nexport default class Logger {\n private print: PrintFunction;\n private stderrPrint: PrintFunction;\n private startTime?: number | undefined;\n private startMsg?: string | undefined;\n\n constructor({\n stderrPrint = (str: string) => process.stderr.write(str),\n print = (str: string) => process.stdout.write(str),\n }: LoggerOptions = {}) {\n this.print = print;\n this.stderrPrint = stderrPrint;\n this.startTime = undefined;\n this.startMsg = undefined;\n }\n\n mute(): void {\n this.print = () => null;\n this.stderrPrint = () => null;\n }\n\n divider(): void {\n this.info('-----------------------------------------');\n }\n\n info(msg: string): void {\n this.print(`${msg}`.replaceAll(/https?:\\/\\/[^ ]+/g, underline));\n this.print('\\n');\n }\n\n start(msg?: string, { startTime }: StartOptions = {}): void {\n this.startTime = startTime || Date.now();\n this.startMsg = msg;\n if (msg) {\n this.print(`Starting: ${msg} `);\n this.print('\\n');\n }\n }\n\n success(msg?: string): void {\n this.print(green('\u2713'));\n\n if (this.startMsg) {\n this.print(green(` ${this.startMsg}:`));\n }\n\n if (msg) {\n this.print(green(` ${msg}`));\n }\n printDuration(this.print, this.startTime);\n this.print('\\n');\n\n this.startMsg = undefined;\n }\n\n fail(msg?: string): void {\n this.print(red('\u2717'));\n\n if (this.startMsg) {\n this.print(red(` ${this.startMsg}:`));\n }\n\n if (msg) {\n this.print(red(` ${msg}`));\n }\n printDuration(this.print, this.startTime);\n this.print('\\n');\n\n this.startMsg = undefined;\n }\n\n error(e: Error | string): void {\n let stack: string | undefined;\n if (typeof e === 'object' && e.stack) {\n stack = e.stack;\n if (stack) {\n stack = stack.split(`file://${process.cwd()}/`).join('');\n }\n }\n this.stderrPrint(\n red(stack || (typeof e === 'object' ? e.message : e) || String(e)),\n );\n this.stderrPrint('\\n');\n }\n\n warn(message: string): void {\n this.stderrPrint(red(message));\n this.stderrPrint('\\n');\n }\n}\n", "import retry from 'async-retry';\n\nimport type { ConfigWithDefaults } from '../config/index.ts';\nimport { logTag } from '../utils/Logger.ts';\nimport makeHappoAPIRequest from './makeHappoAPIRequest.ts';\n\n// Type definitions\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\ninterface UploadAssetsOptions {\n hash: string;\n logger: Logger;\n}\n\nexport default async function uploadAssets(\n buffer: Buffer<ArrayBuffer>,\n options: UploadAssetsOptions,\n config: ConfigWithDefaults,\n): Promise<string> {\n const { project } = config;\n const { hash, logger } = options;\n\n // First we need to get the signed URL from Happo.\n const signedUrlRes = await makeHappoAPIRequest(\n {\n path: `/api/snap-requests/assets/${hash}/signed-url`,\n method: 'GET',\n 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"],
5
+ "mappings": "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",
6
+ "names": ["fs", "path", "fs", "path", "fs", "path", "fs", "path", "HAPPO_DEBUG", "fs", "path", "fs", "path", "path", "fs", "path", "fs"]
7
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ startJob
3
+ } from "./chunk-ULGAHSS5.js";
4
+ import "./chunk-6PWJAPHP.js";
5
+ import "./chunk-WJIEJMLG.js";
6
+ import "./chunk-QTTEOWAX.js";
7
+ export {
8
+ startJob as default
9
+ };
10
+ //# sourceMappingURL=startJob-NZDZNGVS.js.map
@@ -3,21 +3,21 @@ import {
3
3
  } from "./chunk-JTRP4JVC.js";
4
4
  import {
5
5
  startJob
6
- } from "./chunk-QIVIGY3K.js";
6
+ } from "./chunk-ULGAHSS5.js";
7
7
  import {
8
8
  createAsyncComparison
9
- } from "./chunk-GBORF5SP.js";
9
+ } from "./chunk-JOPTBOXW.js";
10
10
  import {
11
11
  postGitHubComment
12
12
  } from "./chunk-X4TE2VNY.js";
13
13
  import {
14
14
  cancelJob
15
- } from "./chunk-2F4ONKOX.js";
15
+ } from "./chunk-IGI756V3.js";
16
16
  import {
17
17
  makeHappoAPIRequest
18
- } from "./chunk-B4NWDBAN.js";
19
- import "./chunk-4FHG27V2.js";
20
- import "./chunk-VOPCZYUD.js";
18
+ } from "./chunk-6PWJAPHP.js";
19
+ import "./chunk-WJIEJMLG.js";
20
+ import "./chunk-QTTEOWAX.js";
21
21
 
22
22
  // src/e2e/wrapper.ts
23
23
  import { spawn } from "node:child_process";
@@ -219,4 +219,4 @@ export {
219
219
  runWithWrapper as default,
220
220
  finalizeAll
221
221
  };
222
- //# sourceMappingURL=wrapper-UNP6YKH6.js.map
222
+ //# sourceMappingURL=wrapper-PXCRJ4BX.js.map
@@ -13,6 +13,12 @@ export interface ExecuteParams {
13
13
  snapPayloads?: Array<unknown>;
14
14
  pages?: Array<Page>;
15
15
  targetName?: string;
16
+ /**
17
+ * Total number of snapshots in the package. When provided for staticPackage
18
+ * requests, the server can use this to automatically determine the optimal
19
+ * number of parallel chunks.
20
+ */
21
+ estimatedSnapsCount?: number;
16
22
  }
17
23
  export default class RemoteBrowserTarget {
18
24
  readonly chunks: number;
@@ -21,6 +27,6 @@ export default class RemoteBrowserTarget {
21
27
  readonly maxHeight: number | undefined;
22
28
  readonly otherOptions: Record<string, unknown>;
23
29
  constructor(browserName: BrowserType, { viewport, chunks, maxHeight, ...otherOptions }: TargetWithDefaults);
24
- execute({ globalCSS, assetsPackage, staticPackage, snapPayloads, pages, targetName, }: ExecuteParams, config: ConfigWithDefaults): Promise<Array<number>>;
30
+ execute({ globalCSS, assetsPackage, staticPackage, snapPayloads, pages, targetName, estimatedSnapsCount, }: ExecuteParams, config: ConfigWithDefaults): Promise<Array<number>>;
25
31
  }
26
32
  //# sourceMappingURL=RemoteBrowserTarget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RemoteBrowserTarget.d.ts","sourceRoot":"","sources":["../../src/config/RemoteBrowserTarget.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAsB5F,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAErC,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,YAAY,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAoBD,MAAM,CAAC,OAAO,OAAO,mBAAmB;IACtC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,WAAW,EAAE,WAAW,CAAC;IACzC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,SAAgB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAGpD,WAAW,EAAE,WAAW,EACxB,EACE,QAAqB,EACrB,MAAU,EACV,SAAS,EACT,GAAG,YAAY,EAChB,EAAE,kBAAkB;IAsBjB,OAAO,CACX,EACE,SAAS,EACT,aAAa,EACb,aAAa,EACb,YAAY,EACZ,KAAK,EACL,UAAU,GACX,EAAE,aAAa,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;CAwG1B"}
1
+ {"version":3,"file":"RemoteBrowserTarget.d.ts","sourceRoot":"","sources":["../../src/config/RemoteBrowserTarget.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,IAAI,EACJ,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAsBpB,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAErC,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,iCAAiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,YAAY,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAoBD,MAAM,CAAC,OAAO,OAAO,mBAAmB;IACtC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,WAAW,EAAE,WAAW,CAAC;IACzC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,SAAgB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAGpD,WAAW,EAAE,WAAW,EACxB,EACE,QAAqB,EACrB,MAAU,EACV,SAAS,EACT,GAAG,YAAY,EAChB,EAAE,kBAAkB;IAsBjB,OAAO,CACX,EACE,SAAS,EACT,aAAa,EACb,aAAa,EACb,YAAY,EACZ,KAAK,EACL,UAAU,EACV,mBAAmB,GACpB,EAAE,aAAa,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;CA0G1B"}
@@ -52,12 +52,16 @@ interface CustomIntegration {
52
52
  * the path to the folder containing the custom files and the path to the
53
53
  * entry point file relative to the root directory.
54
54
  *
55
+ * Optionally return `estimatedSnapsCount` to enable server-side auto-chunking,
56
+ * which parallelizes rendering across multiple workers.
57
+ *
55
58
  * @example
56
- * { rootDir: 'dist/custom', entryPoint: 'index.js' }
59
+ * { rootDir: 'dist/custom', entryPoint: 'index.js', estimatedSnapsCount: 42 }
57
60
  */
58
61
  build: () => Promise<{
59
62
  rootDir: string;
60
63
  entryPoint: string;
64
+ estimatedSnapsCount?: number;
61
65
  }>;
62
66
  }
63
67
  export interface Page {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/config/index.ts"],
4
- "sourcesContent": ["import type { SkipItems } from '../storybook/isomorphic/types.ts';\n\nexport interface StorybookIntegration {\n type: 'storybook';\n\n /**\n * The directory containing the Storybook configuration\n */\n configDir?: string;\n\n /**\n * The directory containing the static files to serve\n */\n staticDir?: string;\n\n /**\n * The directory to output the static Storybook package to\n */\n outputDir?: string;\n\n /**\n * Whether to use a prebuilt Storybook package. If you use this option, make\n * sure that files are built to the outputDir.\n */\n usePrebuiltPackage?: boolean;\n\n /**\n * Items to skip when generating snapshots.\n *\n * Can be an async function that resolves to an array of `{component,\n * variant}`, or an array of `{component, variant}`.\n */\n skip?: SkipItems | (() => Promise<SkipItems>) | undefined;\n}\n\ninterface BaseE2EIntegration {\n /**\n * Whether to allow failures.\n */\n allowFailures?: boolean;\n\n /**\n * Whether to download and include all assets in the asset package. If false\n * (default), only local assets will be included. When true, even external\n * assets will be included.\n */\n downloadAllAssets?: boolean;\n}\n\ninterface CypressIntegration extends BaseE2EIntegration {\n type: 'cypress';\n}\n\ninterface PlaywrightIntegration extends BaseE2EIntegration {\n type: 'playwright';\n}\n\nexport type E2EIntegration = CypressIntegration | PlaywrightIntegration;\n\ninterface CustomIntegration {\n type: 'custom';\n\n /**\n * An async function that generates a custom package. Returns an object with\n * the path to the folder containing the custom files and the path to the\n * entry point file relative to the root directory.\n *\n * @example\n * { rootDir: 'dist/custom', entryPoint: 'index.js' }\n */\n build: () => Promise<{ rootDir: string; entryPoint: string }>;\n}\n\nexport interface Page {\n /**\n * URL of the page to screenshot\n *\n * Note: The URLs to the website need to be publicly available, otherwise\n * Happo workers won't be able to access the pages.\n */\n url: string;\n\n /**\n * Title of the page to screenshot\n *\n * This is used as the \"component\" identifier in Happo reports, so ensure\n * it is unique for each page.\n */\n title: string;\n\n /**\n * Wait for the content to appear on the page before taking the screenshot.\n */\n waitForContent?: string;\n\n /**\n * Wait for a condition to be true before taking the screenshot.\n */\n waitForSelector?: string;\n}\n\ninterface PagesIntegration {\n type: 'pages';\n\n /**\n * A list of pages to screenshot.\n */\n pages: Array<Page>;\n}\n\n/**\n * Settings for deep compare functionality\n */\nexport interface DeepCompareSettings {\n /**\n * Threshold for comparing images with the given diff algorithm (float between\n * 0 and 1). 1 means all differences are allowed. 0 means no differences are\n * allowed. A good starting value is 0.03 for color-delta and 0.01 for ssim.\n */\n compareThreshold: number;\n\n /**\n * Algorithm to use for diff comparison. Must be \"color-delta\" or \"ssim\".\n * Defaults to \"color-delta\" if not provided. Note that \"ssim\" is experimental\n * and may be removed in the future.\n */\n diffAlgorithm?: 'color-delta' | 'ssim';\n\n /**\n * Threshold for ignoring individual pixel differences, side-stepping the\n * compare threshold. Used relatively to the image size. E.g. a value of 0.01\n * means 1% of the pixels can be above the compare threshold. Use this option\n * if your screenshots contain images or graphics with sharp noise. It is not\n * recommended to use this option for other types of diffs. (float\n * between 0 and 1).\n */\n ignoreThreshold?: number;\n\n /**\n * Whether to ignore whitespace in the diff. If true, whitespace differences\n * will not be considered when comparing images. Whitespace is defined as a\n * vertical section in a screenshot containing a single solid color.\n */\n ignoreWhitespace?: boolean;\n\n /**\n * Whether to apply blur to the diff. This can be used to smooth out subtle\n * differences that would otherwise be above the compare threshold. This\n * should mainly be used when your screenshots have a high contrast and you\n * want to smooth out some of the sharpness that can otherwise cause flakiness.\n */\n applyBlur?: boolean;\n}\n\nexport interface Config {\n /**\n * Key used to authenticate with the Happo API. Never store this in plain\n * text.\n */\n apiKey?: string;\n\n /**\n * Secret used to authenticate with the Happo API. Never store this in plain\n * text.\n */\n apiSecret?: string;\n\n /**\n * The endpoint to use for the happo run. Defaults to `https://happo.io`\n */\n endpoint?: string;\n\n /**\n * The name of the project to associate the Happo run with. If not provided,\n * the default project will be used.\n */\n project?: string;\n\n /**\n * Use this to post Happo statuses as comments to your PR. This can be useful\n * if the Happo server doesn't have access to your GitHub repository.\n *\n * The default is `'https://api.github.com'`. If you are using GitHub\n * Enterprise, enter the URL to your local GitHub API here, such as\n * `'https://ghe.mycompany.zone/api/v3'` (the default for GHE installation is\n * for the API to be located at `/api/v3`).\n */\n githubApiUrl?: string;\n\n /**\n * Browsers to use when generating snapshots\n */\n targets: Record<string, Target>;\n\n /**\n * Type of integration to use\n *\n * - 'storybook': Use Storybook to generate snapshots\n * - 'e2e': Use Playwright or Cypress to generate snapshots\n * - 'custom': Use a custom JS bundle to generate snapshots\n *\n * - 'pages': Use a list of pages to generate snapshots\n */\n integration?:\n | StorybookIntegration\n | CypressIntegration\n | PlaywrightIntegration\n | CustomIntegration\n | PagesIntegration;\n\n /**\n * An object with settings for deep compare.\n */\n deepCompare?: DeepCompareSettings;\n}\n\ntype MobileSafariBrowserType = 'ios-safari' | 'ipad-safari';\ntype DesktopBrowserType = 'chrome' | 'firefox' | 'edge' | 'safari' | 'accessibility';\nexport type BrowserType = MobileSafariBrowserType | DesktopBrowserType;\n\ninterface BaseTarget {\n type: BrowserType;\n\n /**\n * Split the target into chunks to be run on multiple workers in parallel\n *\n * This adds some overhead, so if your test suite isn't large, using more than\n * one chunk might actually slow things down.\n */\n chunks?: number;\n\n /**\n * Override the default maximum height (5000px) used by Happo workers\n *\n * This is useful when taking screenshots of tall components or pages.\n *\n * Note: The maximum width defaults to the maximum height, so if you set\n * `maxHeight`, you may also want to set `maxWidth` at the same time.\n */\n maxHeight?: number;\n\n /**\n * Override the default maximum width used by Happo workers (defaults to\n * `maxHeight`, which defaults to 5000 pixels)\n *\n * This is useful when taking screenshots of wide components or pages.\n */\n maxWidth?: number;\n\n /**\n * Controls how Happo handles elements with the `data-happo-hide` attribute.\n * By default, elements with this attribute are made invisible. Use the value\n * `'ignore'` to make the content appear in screenshots but exclude it from\n * comparison.\n */\n hideBehavior?: 'ignore';\n\n /**\n * When set to `true`, this option allows you to add `data-happo-hover`,\n * `data-happo-focus`, and `data-happo-active` attributes to your DOM elements\n * and have Happo apply the corresponding `:hover`, `:focus`, or `:active`\n * styles.\n *\n * For example, if you have this markup:\n *\n * ```html\n * <button>Hover me</button>\n * <style>\n * button:hover {\n * background-color: blue;\n * }\n * </style>\n * ```\n *\n * To apply the hover style before taking the screenshot (making the button\n * blue), change the markup to:\n *\n * ```html\n * <button data-happo-hover>Hover me</button>\n * <style>\n * button:hover {\n * background-color: blue;\n * }\n * </style>\n * ```\n *\n * Similarly, you can add focus to elements using `data-happo-focus`:\n *\n * ```html\n * <input type=\"text\" data-happo-focus />\n * ```\n *\n * And add `data-happo-active` to elements to simulate the `:active` state:\n *\n * ```html\n * <button data-happo-active>Click me</button>\n * <style>\n * button:active {\n * background-color: red;\n * }\n * </style>\n * ```\n */\n applyPseudoClasses?: boolean;\n\n /**\n * Set `prefersColorScheme: 'dark'` or `prefersColorScheme: 'light'` to set\n * the color scheme preference in the browser.\n */\n prefersColorScheme?: 'light' | 'dark';\n\n /**\n * Set `allowPointerEvents: true` to allow pointer events in the browser\n *\n * By default Happo injects some CSS to prevent spurious hover effects caused\n * by the system mouse pointer. If you rely on mouse interaction in your tests\n * (e.g., when using Storybook interactive stories), you might see an error\n * like this in your logs:\n *\n * > Error: Unable to perform pointer interaction as the element has\n * > `pointer-events: none`\n *\n * In some cases, this error prevents the variant from being included in the\n * report.\n *\n * To resolve this, set `allowPointerEvents: true` to tell Happo to skip\n * injecting the CSS that disables pointer events.\n *\n * If you're interested in testing `:hover`, `:focus`, and `:active` states\n * with Happo, you may also want to use the `applyPseudoClasses` option.\n */\n allowPointerEvents?: boolean;\n\n /**\n * Set `freezeAnimations: 'last-frame'` to freeze the animations at the last\n * frame. This is the default behavior.\n *\n * Set `freezeAnimations: 'first-frame'` to freeze the animations at the first\n * frame.\n */\n freezeAnimations?: 'last-frame' | 'first-frame';\n}\n\ninterface MobileSafariTarget extends BaseTarget {\n type: MobileSafariBrowserType;\n}\n\ninterface DesktopTarget extends BaseTarget {\n type: DesktopBrowserType;\n\n /**\n * Set the viewport size for the browser\n */\n viewport: `${number}x${number}`;\n\n /**\n * By default, Happo makes the browser prefer reduced motion when rendering\n * the UI. Set `prefersReducedMotion: false` to disable this behavior.\n */\n prefersReducedMotion?: boolean;\n\n /**\n * Add additional headers to the outgoing requests from the browser. This is\n * useful if you for instance need to tell a CDN that the request originates\n * from a Happo run.\n */\n outgoingRequestHeaders?: Array<{ name: string; value: string }>;\n}\n\nexport type Target = MobileSafariTarget | DesktopTarget;\n\nexport interface TargetWithDefaults extends BaseTarget {\n viewport: `${number}x${number}`;\n __dynamic: boolean;\n prefersReducedMotion?: boolean;\n}\n\nexport interface ConfigWithDefaults extends Config {\n apiKey: NonNullable<Config['apiKey']>;\n apiSecret: NonNullable<Config['apiSecret']>;\n integration: NonNullable<Config['integration']>;\n endpoint: NonNullable<Config['endpoint']>;\n githubApiUrl: NonNullable<Config['githubApiUrl']>;\n targets: Record<string, TargetWithDefaults>;\n}\n\nexport function defineConfig(config: Config): Config {\n return config;\n}\n"],
5
- "mappings": ";AAkYO,SAAS,aAAa,QAAwB;AACnD,SAAO;AACT;",
4
+ "sourcesContent": ["import type { SkipItems } from '../storybook/isomorphic/types.ts';\n\nexport interface StorybookIntegration {\n type: 'storybook';\n\n /**\n * The directory containing the Storybook configuration\n */\n configDir?: string;\n\n /**\n * The directory containing the static files to serve\n */\n staticDir?: string;\n\n /**\n * The directory to output the static Storybook package to\n */\n outputDir?: string;\n\n /**\n * Whether to use a prebuilt Storybook package. If you use this option, make\n * sure that files are built to the outputDir.\n */\n usePrebuiltPackage?: boolean;\n\n /**\n * Items to skip when generating snapshots.\n *\n * Can be an async function that resolves to an array of `{component,\n * variant}`, or an array of `{component, variant}`.\n */\n skip?: SkipItems | (() => Promise<SkipItems>) | undefined;\n}\n\ninterface BaseE2EIntegration {\n /**\n * Whether to allow failures.\n */\n allowFailures?: boolean;\n\n /**\n * Whether to download and include all assets in the asset package. If false\n * (default), only local assets will be included. When true, even external\n * assets will be included.\n */\n downloadAllAssets?: boolean;\n}\n\ninterface CypressIntegration extends BaseE2EIntegration {\n type: 'cypress';\n}\n\ninterface PlaywrightIntegration extends BaseE2EIntegration {\n type: 'playwright';\n}\n\nexport type E2EIntegration = CypressIntegration | PlaywrightIntegration;\n\ninterface CustomIntegration {\n type: 'custom';\n\n /**\n * An async function that generates a custom package. Returns an object with\n * the path to the folder containing the custom files and the path to the\n * entry point file relative to the root directory.\n *\n * Optionally return `estimatedSnapsCount` to enable server-side auto-chunking,\n * which parallelizes rendering across multiple workers.\n *\n * @example\n * { rootDir: 'dist/custom', entryPoint: 'index.js', estimatedSnapsCount: 42 }\n */\n build: () => Promise<{\n rootDir: string;\n entryPoint: string;\n estimatedSnapsCount?: number;\n }>;\n}\n\nexport interface Page {\n /**\n * URL of the page to screenshot\n *\n * Note: The URLs to the website need to be publicly available, otherwise\n * Happo workers won't be able to access the pages.\n */\n url: string;\n\n /**\n * Title of the page to screenshot\n *\n * This is used as the \"component\" identifier in Happo reports, so ensure\n * it is unique for each page.\n */\n title: string;\n\n /**\n * Wait for the content to appear on the page before taking the screenshot.\n */\n waitForContent?: string;\n\n /**\n * Wait for a condition to be true before taking the screenshot.\n */\n waitForSelector?: string;\n}\n\ninterface PagesIntegration {\n type: 'pages';\n\n /**\n * A list of pages to screenshot.\n */\n pages: Array<Page>;\n}\n\n/**\n * Settings for deep compare functionality\n */\nexport interface DeepCompareSettings {\n /**\n * Threshold for comparing images with the given diff algorithm (float between\n * 0 and 1). 1 means all differences are allowed. 0 means no differences are\n * allowed. A good starting value is 0.03 for color-delta and 0.01 for ssim.\n */\n compareThreshold: number;\n\n /**\n * Algorithm to use for diff comparison. Must be \"color-delta\" or \"ssim\".\n * Defaults to \"color-delta\" if not provided. Note that \"ssim\" is experimental\n * and may be removed in the future.\n */\n diffAlgorithm?: 'color-delta' | 'ssim';\n\n /**\n * Threshold for ignoring individual pixel differences, side-stepping the\n * compare threshold. Used relatively to the image size. E.g. a value of 0.01\n * means 1% of the pixels can be above the compare threshold. Use this option\n * if your screenshots contain images or graphics with sharp noise. It is not\n * recommended to use this option for other types of diffs. (float\n * between 0 and 1).\n */\n ignoreThreshold?: number;\n\n /**\n * Whether to ignore whitespace in the diff. If true, whitespace differences\n * will not be considered when comparing images. Whitespace is defined as a\n * vertical section in a screenshot containing a single solid color.\n */\n ignoreWhitespace?: boolean;\n\n /**\n * Whether to apply blur to the diff. This can be used to smooth out subtle\n * differences that would otherwise be above the compare threshold. This\n * should mainly be used when your screenshots have a high contrast and you\n * want to smooth out some of the sharpness that can otherwise cause flakiness.\n */\n applyBlur?: boolean;\n}\n\nexport interface Config {\n /**\n * Key used to authenticate with the Happo API. Never store this in plain\n * text.\n */\n apiKey?: string;\n\n /**\n * Secret used to authenticate with the Happo API. Never store this in plain\n * text.\n */\n apiSecret?: string;\n\n /**\n * The endpoint to use for the happo run. Defaults to `https://happo.io`\n */\n endpoint?: string;\n\n /**\n * The name of the project to associate the Happo run with. If not provided,\n * the default project will be used.\n */\n project?: string;\n\n /**\n * Use this to post Happo statuses as comments to your PR. This can be useful\n * if the Happo server doesn't have access to your GitHub repository.\n *\n * The default is `'https://api.github.com'`. If you are using GitHub\n * Enterprise, enter the URL to your local GitHub API here, such as\n * `'https://ghe.mycompany.zone/api/v3'` (the default for GHE installation is\n * for the API to be located at `/api/v3`).\n */\n githubApiUrl?: string;\n\n /**\n * Browsers to use when generating snapshots\n */\n targets: Record<string, Target>;\n\n /**\n * Type of integration to use\n *\n * - 'storybook': Use Storybook to generate snapshots\n * - 'e2e': Use Playwright or Cypress to generate snapshots\n * - 'custom': Use a custom JS bundle to generate snapshots\n *\n * - 'pages': Use a list of pages to generate snapshots\n */\n integration?:\n | StorybookIntegration\n | CypressIntegration\n | PlaywrightIntegration\n | CustomIntegration\n | PagesIntegration;\n\n /**\n * An object with settings for deep compare.\n */\n deepCompare?: DeepCompareSettings;\n}\n\ntype MobileSafariBrowserType = 'ios-safari' | 'ipad-safari';\ntype DesktopBrowserType = 'chrome' | 'firefox' | 'edge' | 'safari' | 'accessibility';\nexport type BrowserType = MobileSafariBrowserType | DesktopBrowserType;\n\ninterface BaseTarget {\n type: BrowserType;\n\n /**\n * Split the target into chunks to be run on multiple workers in parallel\n *\n * This adds some overhead, so if your test suite isn't large, using more than\n * one chunk might actually slow things down.\n */\n chunks?: number;\n\n /**\n * Override the default maximum height (5000px) used by Happo workers\n *\n * This is useful when taking screenshots of tall components or pages.\n *\n * Note: The maximum width defaults to the maximum height, so if you set\n * `maxHeight`, you may also want to set `maxWidth` at the same time.\n */\n maxHeight?: number;\n\n /**\n * Override the default maximum width used by Happo workers (defaults to\n * `maxHeight`, which defaults to 5000 pixels)\n *\n * This is useful when taking screenshots of wide components or pages.\n */\n maxWidth?: number;\n\n /**\n * Controls how Happo handles elements with the `data-happo-hide` attribute.\n * By default, elements with this attribute are made invisible. Use the value\n * `'ignore'` to make the content appear in screenshots but exclude it from\n * comparison.\n */\n hideBehavior?: 'ignore';\n\n /**\n * When set to `true`, this option allows you to add `data-happo-hover`,\n * `data-happo-focus`, and `data-happo-active` attributes to your DOM elements\n * and have Happo apply the corresponding `:hover`, `:focus`, or `:active`\n * styles.\n *\n * For example, if you have this markup:\n *\n * ```html\n * <button>Hover me</button>\n * <style>\n * button:hover {\n * background-color: blue;\n * }\n * </style>\n * ```\n *\n * To apply the hover style before taking the screenshot (making the button\n * blue), change the markup to:\n *\n * ```html\n * <button data-happo-hover>Hover me</button>\n * <style>\n * button:hover {\n * background-color: blue;\n * }\n * </style>\n * ```\n *\n * Similarly, you can add focus to elements using `data-happo-focus`:\n *\n * ```html\n * <input type=\"text\" data-happo-focus />\n * ```\n *\n * And add `data-happo-active` to elements to simulate the `:active` state:\n *\n * ```html\n * <button data-happo-active>Click me</button>\n * <style>\n * button:active {\n * background-color: red;\n * }\n * </style>\n * ```\n */\n applyPseudoClasses?: boolean;\n\n /**\n * Set `prefersColorScheme: 'dark'` or `prefersColorScheme: 'light'` to set\n * the color scheme preference in the browser.\n */\n prefersColorScheme?: 'light' | 'dark';\n\n /**\n * Set `allowPointerEvents: true` to allow pointer events in the browser\n *\n * By default Happo injects some CSS to prevent spurious hover effects caused\n * by the system mouse pointer. If you rely on mouse interaction in your tests\n * (e.g., when using Storybook interactive stories), you might see an error\n * like this in your logs:\n *\n * > Error: Unable to perform pointer interaction as the element has\n * > `pointer-events: none`\n *\n * In some cases, this error prevents the variant from being included in the\n * report.\n *\n * To resolve this, set `allowPointerEvents: true` to tell Happo to skip\n * injecting the CSS that disables pointer events.\n *\n * If you're interested in testing `:hover`, `:focus`, and `:active` states\n * with Happo, you may also want to use the `applyPseudoClasses` option.\n */\n allowPointerEvents?: boolean;\n\n /**\n * Set `freezeAnimations: 'last-frame'` to freeze the animations at the last\n * frame. This is the default behavior.\n *\n * Set `freezeAnimations: 'first-frame'` to freeze the animations at the first\n * frame.\n */\n freezeAnimations?: 'last-frame' | 'first-frame';\n}\n\ninterface MobileSafariTarget extends BaseTarget {\n type: MobileSafariBrowserType;\n}\n\ninterface DesktopTarget extends BaseTarget {\n type: DesktopBrowserType;\n\n /**\n * Set the viewport size for the browser\n */\n viewport: `${number}x${number}`;\n\n /**\n * By default, Happo makes the browser prefer reduced motion when rendering\n * the UI. Set `prefersReducedMotion: false` to disable this behavior.\n */\n prefersReducedMotion?: boolean;\n\n /**\n * Add additional headers to the outgoing requests from the browser. This is\n * useful if you for instance need to tell a CDN that the request originates\n * from a Happo run.\n */\n outgoingRequestHeaders?: Array<{ name: string; value: string }>;\n}\n\nexport type Target = MobileSafariTarget | DesktopTarget;\n\nexport interface TargetWithDefaults extends BaseTarget {\n viewport: `${number}x${number}`;\n __dynamic: boolean;\n prefersReducedMotion?: boolean;\n}\n\nexport interface ConfigWithDefaults extends Config {\n apiKey: NonNullable<Config['apiKey']>;\n apiSecret: NonNullable<Config['apiSecret']>;\n integration: NonNullable<Config['integration']>;\n endpoint: NonNullable<Config['endpoint']>;\n githubApiUrl: NonNullable<Config['githubApiUrl']>;\n targets: Record<string, TargetWithDefaults>;\n}\n\nexport function defineConfig(config: Config): Config {\n return config;\n}\n"],
5
+ "mappings": ";AAyYO,SAAS,aAAa,QAAwB;AACnD,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -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.3.6",
21
+ version: "6.4.0",
22
22
  description: "Catch unexpected visual and accessibility changes and UI bugs",
23
23
  license: "MIT",
24
24
  repository: {
@@ -207,12 +207,12 @@ var ErrorWithStatusCode = class extends Error {
207
207
  }
208
208
  };
209
209
  function prepareFormData(data) {
210
- if (!data) {
210
+ if (data == null) {
211
211
  return null;
212
212
  }
213
213
  const form = new FormData();
214
214
  for (const [key, value] of Object.entries(data)) {
215
- if (value) {
215
+ if (value != null) {
216
216
  form.append(key, value);
217
217
  }
218
218
  }
@@ -757,7 +757,8 @@ var RemoteBrowserTarget = class {
757
757
  staticPackage,
758
758
  snapPayloads,
759
759
  pages,
760
- targetName
760
+ targetName,
761
+ estimatedSnapsCount
761
762
  }, config) {
762
763
  const boundMakeRequest = async ({
763
764
  slice,
@@ -783,6 +784,7 @@ var RemoteBrowserTarget = class {
783
784
  type: pageSlice && pageSlice.extendsSha ? "extends-report" : `browser-${this.browserName}`,
784
785
  targetName,
785
786
  payloadHash,
787
+ estimatedSnapsCount: staticPackage && estimatedSnapsCount != null ? estimatedSnapsCount : void 0,
786
788
  payload: new File([payloadString], "payload.json", {
787
789
  type: "application/json"
788
790
  })