import { Workspace } from './package-files/workspace.js'; export interface PackageJsonInput { /** * Path used to identify this package.json in the hash. Should be a * forward-slash relative path matching the file's location in the * eventual archive (e.g. "package.json" or "packages/cli/package.json"). */ path: string; raw: Buffer; } export interface LockfileInput { /** * Basename of the lockfile (e.g. "package-lock.json"). */ name: string; /** * Raw 32-byte SHA-256 digest of the lockfile contents. */ hash: Buffer; } export interface NpmrcInput { /** * Forward-slash relative path matching the .npmrc's location in the eventual * archive (e.g. ".npmrc" or "packages/app/.npmrc"). */ path: string; /** * Raw 32-byte SHA-256 digest of the .npmrc contents. */ hash: Buffer; } export interface PnpmfileInput { /** * Forward-slash relative path matching the pnpmfile's location in the * eventual archive (e.g. ".pnpmfile.cjs" or ".pnpmfile.mjs"). */ path: string; /** * Raw 32-byte SHA-256 digest of the pnpmfile contents. */ hash: Buffer; } export interface EmbeddedPackageInput { /** Package name as recorded in the lockfile, e.g. `@acme/foo`. */ name: string; /** Exact version, e.g. `1.2.3`. */ version: string; /** * The lockfile's recorded content pin for the artifact: an SRI integrity * string, or for Yarn Berry lockfiles (which record no npm tarball * integrity) yarn's own checksum value — equally stable per content. */ integrity: string; } export interface FauxPackageJsonInput { /** * Forward-slash relative path matching the faux manifest's location in the * eventual archive (e.g. "packages/member/package.json"). */ path: string; /** * The faux manifest's raw content bytes. */ raw: Buffer; } export interface ComposeCacheHashInput { lockfile?: LockfileInput; packageJsons: PackageJsonInput[]; npmrcs?: NpmrcInput[]; /** * The workspace root's bundleable pnpmfiles (pnpm workspaces only). pnpm's * install hooks change resolution results without necessarily touching the * lockfile (the recorded `pnpmfileChecksum` only updates when the user * reinstalls), so the bundled files must contribute to the hash. An empty * or absent list writes no records, leaving the digest identical to one * computed before this input existed. */ pnpmfiles?: PnpmfileInput[]; /** * The resolved set of embedded package tarballs shipped in the bundle * (`bundle.packages.embed` after lockfile resolution, filtered to what * the shipped — possibly pruned — bundled lockfile still references). * Embedded tarballs change the runner's install-step inputs without * necessarily touching the lockfile, so they must contribute to the hash. * An empty or absent list writes no records, leaving the digest identical * to one computed before this input existed. */ embeddedPackages?: EmbeddedPackageInput[]; excludedFields: string[]; /** * Optional user-provided cache version, already normalized to a string. * An empty string is treated the same as undefined: no record is written, * so the digest stays identical to one computed without this input. */ dependencyCacheVersion?: string; /** * Every synthesized (non-physical) `package.json` actually shipped in the * bundle: the faux workspace member manifests, and any workspace manifest * rewritten at finalize time — pruned by `bundle.packages.prune`, or the * root manifest with patch declarations the bundle no longer needs * dropped. Unlike on-disk manifests — whose `version` is excluded because * the pinned lockfile absorbs it — a synthesized manifest's full content * including its version is load-bearing for the remote install (it * decides whether a specifier resolves to the workspace link, the * registry, or fails), so faux manifests are hashed verbatim, exactly as * the bytes ship. Rewritten manifests have an on-disk original whose * `version` the lockfile absorbs the same way, so the bundler passes * their shipped bytes pre-canonicalized (`version` stripped, keys * sorted) instead. An empty or absent list writes no records, leaving * the digest unchanged. */ fauxPackageJsons?: FauxPackageJsonInput[]; /** * The pruned lockfile actually shipped in the bundle, when lockfile * pruning replaced the original. The pruned bytes are the runner's real * install input, so they must contribute to the hash. Absent when the * original lockfile ships unchanged, writing no record. */ prunedLockfile?: LockfileInput; /** * The raw 32-byte SHA-256 digest of the serialized `runner.registries` * configuration shipped in the bundle (`.checkly/config/registries.json`). * Registry routing changes where the runner installs packages from * without necessarily touching the lockfile, so the shipped file must * contribute to the hash — the same reasoning as the `.npmrc` records. * Absent when the config is not set, writing no record. Unlike the * other bundle-content records this one is also present for a bundle * that ends up empty and ships nothing: the digest is fixed at bundler * construction, before any files are registered, and an empty bundle's * hash is never consumed. */ runnerRegistries?: Buffer; } /** * Fields stripped from a package.json before hashing. `version` is excluded * because the pinned lockfile already absorbs it, so a release bump must not * invalidate a dependency cache whose install inputs are unchanged. */ export declare const PACKAGE_JSON_EXCLUDED_FIELDS: string[]; /** * Encodes a value as JSON in a way that's stable across runs and machines. * * Differences from {@link JSON.stringify}: * - Object keys are sorted (byte-wise / code-point order) before * serialization. This is the load-bearing difference — without it, two * equivalent package.json files written in different key orders would * produce different hashes. * - HTML-significant characters (`<`, `>`, `&`) are escaped as * `\u003c`/`\u003e`/`\u0026`. * - U+2028 and U+2029 are escaped as `\u2028`/`\u2029`. * - No whitespace between tokens. * - Numbers use {@link String}; floating-point edge cases may differ from * other encoders. Package.json content is effectively never numeric * outside config blobs, so this is negligible in practice. */ export declare function stableJsonEncode(value: unknown): string; /** * Parses a package.json, removes the named top-level fields, and re-encodes * the result via {@link stableJsonEncode}. */ export declare function canonicalizePackageJson(raw: Buffer, excludedFields: string[]): Buffer; /** * Combines a lockfile digest and a set of canonicalized package.json * entries into a single SHA-256 hex digest. * * Each record contributes: * uint64-be(label length) || label bytes || * uint64-be(content length) || content bytes * * Records are written in the following order: * 1. The lockfile record (if present), labeled `lockfile:`, * whose content is the raw 32-byte SHA-256 digest of the lockfile. * 2. One record per package.json sorted by path, labeled * `package.json:`, whose content is the canonicalized * package.json bytes. * 3. One record per .npmrc sorted by path, labeled * `npmrc:`, whose content is the raw 32-byte SHA-256 * digest of the .npmrc contents. * 4. One record per bundleable pnpmfile sorted by path, labeled * `pnpmfile:`, whose content is the raw 32-byte SHA-256 * digest of the pnpmfile contents. * 5. One record per embedded package sorted by `name@version`, labeled * `embedded-package:`, whose content is the raw UTF-8 * bytes of the lockfile's content pin for the artifact — its SRI * integrity string, or for Yarn Berry lockfiles (which record no npm * tarball integrity) yarn's own checksum value. Callers must pass at * most one entry per `name@version` (the materializer already * de-duplicates); the record order among duplicate keys is undefined. * 6. The dependency cache version record (if set to a non-empty string), * labeled `dependency-cache-version`, whose content is the raw UTF-8 * bytes of the user-provided value. An empty string is treated as * absent so that e.g. an unset environment variable interpolated into * the config leaves the digest unchanged. * 7. One record per synthesized (non-physical) manifest shipped in the * bundle sorted by path, labeled `faux-package.json:`, * whose content is the manifest's UTF-8 bytes: raw for faux member * manifests, pre-canonicalized by the caller for manifests rewritten * from an on-disk original (see `fauxPackageJsons`). * 8. The pruned lockfile record (if present), labeled * `pruned-lockfile:`, whose content is the raw 32-byte * SHA-256 digest of the pruned lockfile contents. * 9. The runner registries record (if present), labeled * `runner-registries`, whose content is the raw 32-byte SHA-256 * digest of the serialized `.checkly/config/registries.json` shipped in * the bundle. * * All sorts compare strings by UTF-16 code unit (JavaScript's `<`/`>`), * which coincides with byte-wise UTF-8 order for ASCII inputs — the only * kind that occurs in practice. Mirror implementations in other languages * must reproduce this order exactly. */ export declare function composeCacheHash(input: ComposeCacheHashInput): string; /** * Reads the workspace lockfile, every workspace package.json, and every * workspace `.npmrc` (root + member packages) and returns the inputs needed * by {@link composeCacheHash}. * * Paths are normalized to forward slashes and made relative to the * workspace root so that they match what ends up in the bundle archive. * * `.npmrc` is hashed so that repointing a registry (which need not touch the * lockfile) invalidates the bundle cache. Packages without an `.npmrc` * contribute nothing, so a workspace with no `.npmrc` produces a hash * identical to before this input existed. * * The workspace's bundleable pnpmfiles (see {@link Workspace.pnpmfiles}) are * hashed for the same reason: their install hooks change resolution results, * and the lockfile's recorded `pnpmfileChecksum` only updates when the user * reinstalls, so the lockfile bytes alone do not cover them. A workspace * without bundleable pnpmfiles contributes nothing. */ export declare function loadWorkspaceCacheHashInputs(workspace: Workspace): Promise; export interface ComputeWorkspaceCacheHashOptions { /** * Optional user-provided cache version (`runner.cache.install.version` in * the checkly config, or its deprecated alias * `caching.dependencyCache.version` — see resolveDependencyCacheVersion in * services/checkly-config-loader.ts) mixed into the hash as an extra * record. Numbers * are converted with {@link String} and must be safe integers — larger or * fractional values do not stringify exactly (or use exponent notation), * which would break parity with non-JavaScript implementations of this * hash. Undefined and the empty string leave the digest unchanged. */ dependencyCacheVersion?: string | number; /** * The resolved set of embedded package tarballs shipped in the bundle. * See {@link ComposeCacheHashInput.embeddedPackages}. */ embeddedPackages?: EmbeddedPackageInput[]; } /** * Normalizes a user-provided dependency cache version to the exact string * that gets hashed, or undefined when the value is unset (or an empty * string, which is treated as unset). */ export declare function normalizeDependencyCacheVersion(version: string | number | undefined): string | undefined; export interface WorkspaceCacheHashInputs { lockfile?: LockfileInput; packageJsons: PackageJsonInput[]; npmrcs: NpmrcInput[]; pnpmfiles: PnpmfileInput[]; } export interface ComposeWorkspaceCacheHashOptions extends ComputeWorkspaceCacheHashOptions { /** * See {@link ComposeCacheHashInput.fauxPackageJsons}. */ fauxPackageJsons?: FauxPackageJsonInput[]; /** * See {@link ComposeCacheHashInput.prunedLockfile}. */ prunedLockfile?: LockfileInput; /** * See {@link ComposeCacheHashInput.runnerRegistries}. */ runnerRegistries?: Buffer; } /** * Composes the workspace cache hash from pre-loaded inputs, with the * standard set of excluded package.json fields. Lets callers that need to * recompute the hash later (with bundle-time inputs like faux manifests or * a pruned lockfile) reuse inputs loaded once. */ export declare function composeWorkspaceCacheHash(inputs: WorkspaceCacheHashInputs, options?: ComposeWorkspaceCacheHashOptions): string; /** * Convenience wrapper that loads workspace inputs and composes the cache * hash with the standard set of excluded package.json fields. */ export declare function computeWorkspaceCacheHash(workspace: Workspace, options?: ComputeWorkspaceCacheHashOptions): Promise;