Merge pull request #2082 from heygen-com/fix/drawelement-chrome-version-pin

fix(engine,cli): resolve drawElement to a Chrome build that actually has it
This commit is contained in:
Vance Ingalls
2026-07-08 15:50:17 -07:00
committed by GitHub
13 changed files with 222 additions and 93 deletions
+81 -27
View File
@@ -22,7 +22,7 @@
},
"packages/aws-lambda": {
"name": "@hyperframes/aws-lambda",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@aws-sdk/client-s3": "^3.700.0",
"@aws-sdk/client-sfn": "^3.700.0",
@@ -30,7 +30,7 @@
"@sparticuz/chromium": "148.0.0",
"ffmpeg-static": "^5.2.0",
"ffprobe-static": "^3.1.0",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"tar": "^7.4.3",
},
"devDependencies": {
@@ -54,7 +54,7 @@
},
"packages/cli": {
"name": "@hyperframes/cli",
"version": "0.7.22",
"version": "0.7.42",
"bin": {
"hyperframes": "./dist/cli.js",
},
@@ -73,7 +73,7 @@
"open": "^10.0.0",
"postcss": "^8.5.8",
"prettier": "^3.8.1",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"sharp": "^0.34.5",
},
"devDependencies": {
@@ -103,7 +103,7 @@
},
"packages/core": {
"name": "@hyperframes/core",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@chenglou/pretext": "^0.0.5",
"@hyperframes/lint": "workspace:*",
@@ -128,14 +128,14 @@
},
"packages/engine": {
"name": "@hyperframes/engine",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@hono/node-server": "^1.13.0",
"@hyperframes/core": "workspace:^",
"hono": "^4.6.0",
"linkedom": "^0.18.12",
"puppeteer": "^24.0.0",
"puppeteer-core": "^24.39.1",
"puppeteer": "^25.2.1",
"puppeteer-core": "^25.2.1",
},
"devDependencies": {
"@types/node": "^25.0.10",
@@ -146,14 +146,14 @@
},
"packages/gcp-cloud-run": {
"name": "@hyperframes/gcp-cloud-run",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@google-cloud/storage": "^7.14.0",
"@google-cloud/workflows": "^4.2.0",
"@hono/node-server": "^1.13.0",
"@hyperframes/producer": "workspace:^",
"hono": "^4.6.0",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"tar": "^7.4.3",
},
"devDependencies": {
@@ -166,7 +166,7 @@
},
"packages/lint": {
"name": "@hyperframes/lint",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@hyperframes/parsers": "workspace:*",
"linkedom": "^0.18.12",
@@ -182,7 +182,7 @@
},
"packages/parsers": {
"name": "@hyperframes/parsers",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@babel/parser": "^7.27.0",
"acorn": "^8.17.0",
@@ -202,14 +202,14 @@
},
"packages/player": {
"name": "@hyperframes/player",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@hyperframes/core": "workspace:*",
},
"devDependencies": {
"@types/bun": "^1.1.0",
"gsap": "^3.12.5",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"tsup": "^8.0.0",
"typescript": "^5.0.0",
"vitest": "^3.2.4",
@@ -217,7 +217,7 @@
},
"packages/producer": {
"name": "@hyperframes/producer",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@fontsource/archivo-black": "^5.2.8",
"@fontsource/eb-garamond": "^5.2.7",
@@ -239,8 +239,8 @@
"hono": "^4.6.0",
"linkedom": "^0.18.12",
"postcss": "^8.4.0",
"puppeteer": "^24.0.0",
"puppeteer-core": "^24.39.1",
"puppeteer": "^25.2.1",
"puppeteer-core": "^25.2.1",
"wawoff2": "^2.0.1",
},
"devDependencies": {
@@ -261,7 +261,7 @@
},
"packages/sdk": {
"name": "@hyperframes/sdk",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@hyperframes/core": "workspace:*",
"@hyperframes/parsers": "workspace:*",
@@ -288,7 +288,7 @@
},
"packages/shader-transitions": {
"name": "@hyperframes/shader-transitions",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"html2canvas": "^1.4.1",
},
@@ -300,7 +300,7 @@
},
"packages/studio": {
"name": "@hyperframes/studio",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@codemirror/autocomplete": "^6.20.1",
"@codemirror/commands": "^6.10.3",
@@ -332,7 +332,7 @@
"@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"puppeteer-core": "^24.40.0",
"puppeteer-core": "^25.2.1",
"tailwindcss": "^3.4.0",
"tsup": "^8.0.0",
"typescript": "^5.0.0",
@@ -348,7 +348,7 @@
},
"packages/studio-server": {
"name": "@hyperframes/studio-server",
"version": "0.7.22",
"version": "0.7.42",
"dependencies": {
"@hyperframes/core": "workspace:*",
"@hyperframes/parsers": "workspace:*",
@@ -1301,7 +1301,7 @@
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
"chromium-bidi": ["chromium-bidi@14.0.0", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw=="],
"chromium-bidi": ["chromium-bidi@16.0.1", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-J63PGu/9PpeCwLIcKYyzWP6yaVL5pxuBc0shlYCYM8BaAkmlwiQboXO1iNbOgSDbVklEyYFfNEcHD8oOAWacUA=="],
"citty": ["citty@0.2.2", "", {}, "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w=="],
@@ -1389,7 +1389,7 @@
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"devtools-protocol": ["devtools-protocol@0.0.1608973", "", {}, "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ=="],
"devtools-protocol": ["devtools-protocol@0.0.1638949", "", {}, "sha512-mXwg4Fqnv0WR4iuAT/gYUmctNkjILwXFHyZ+m7Ty1dfr0ezZt2U3gnrrJTfRobJTHoXf+IbuFvFITzLrLFjwJA=="],
"dfa": ["dfa@1.2.0", "", {}, "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="],
@@ -1531,6 +1531,8 @@
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
"get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
@@ -1763,6 +1765,8 @@
"mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="],
"modern-tar": ["modern-tar@0.7.6", "", {}, "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
@@ -1877,9 +1881,9 @@
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"puppeteer": ["puppeteer@24.43.1", "", { "dependencies": { "@puppeteer/browsers": "2.13.2", "chromium-bidi": "14.0.0", "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1608973", "puppeteer-core": "24.43.1", "typed-query-selector": "^2.12.2" }, "bin": { "puppeteer": "lib/cjs/puppeteer/node/cli.js" } }, "sha512-/FSOViCrqRdb1HDocpsM9Z1giA71gTQPUt3SpHGVRALKAy/rJr1fLFYZW9F23qPxqVxTHQnbh/5B5opJST3kAw=="],
"puppeteer": ["puppeteer@25.3.0", "", { "dependencies": { "@puppeteer/browsers": "3.0.6", "chromium-bidi": "16.0.1", "devtools-protocol": "0.0.1638949", "lilconfig": "^3.1.3", "puppeteer-core": "25.3.0", "typed-query-selector": "^2.12.2" }, "bin": { "puppeteer": "lib/puppeteer/node/cli.js" } }, "sha512-O1tx8S315aw8eI99HZ5ZNcVEzJ9+jKF//eO5UvfZ3cXJ6okZ5sX3Y50u7DJaM+ewEK4LqXP068tBhfRaWikj+g=="],
"puppeteer-core": ["puppeteer-core@24.43.1", "", { "dependencies": { "@puppeteer/browsers": "2.13.2", "chromium-bidi": "14.0.0", "debug": "^4.4.3", "devtools-protocol": "0.0.1608973", "typed-query-selector": "^2.12.2", "webdriver-bidi-protocol": "0.4.1", "ws": "^8.20.0" } }, "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw=="],
"puppeteer-core": ["puppeteer-core@25.3.0", "", { "dependencies": { "@puppeteer/browsers": "3.0.6", "chromium-bidi": "16.0.1", "devtools-protocol": "0.0.1638949", "typed-query-selector": "^2.12.2", "webdriver-bidi-protocol": "0.4.2", "ws": "^8.21.0" } }, "sha512-fm+wpUr2oigH1PXZvwgATrM2tYWHMDG8ASzTEe9uukCye4X5Ldx1K5BTHPFKITrIWvQQAQ256d1NpbEveBcKjA=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
@@ -2111,7 +2115,7 @@
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
"webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.1", "", {}, "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw=="],
"webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.2", "", {}, "sha512-VSV+fzfChirL3e7jay2yUC7B4HQCGtEWEg/MSSQbK+qWbqeGlRLlXTzPpYr3XGUvbpDHumWZBJxgesg4N7dbtA=="],
"webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="],
@@ -2263,6 +2267,12 @@
"proxy-agent/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
"puppeteer/@puppeteer/browsers": ["@puppeteer/browsers@3.0.6", "", { "dependencies": { "modern-tar": "^0.7.6", "yargs": "^18.0.0" }, "peerDependencies": { "proxy-agent": ">=8.0.1", "yauzl": "^2.10.0 || ^3.4.0" }, "optionalPeers": ["proxy-agent", "yauzl"], "bin": { "browsers": "lib/main-cli.js" } }, "sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA=="],
"puppeteer-core/@puppeteer/browsers": ["@puppeteer/browsers@3.0.6", "", { "dependencies": { "modern-tar": "^0.7.6", "yargs": "^18.0.0" }, "peerDependencies": { "proxy-agent": ">=8.0.1", "yauzl": "^2.10.0 || ^3.4.0" }, "optionalPeers": ["proxy-agent", "yauzl"], "bin": { "browsers": "lib/main-cli.js" } }, "sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA=="],
"puppeteer-core/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="],
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"socks-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
@@ -2323,6 +2333,10 @@
"node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
"puppeteer-core/@puppeteer/browsers/yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="],
"puppeteer/@puppeteer/browsers/yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="],
"tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
@@ -2443,10 +2457,50 @@
"google-gax/retry-request/teeny-request/https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
"puppeteer-core/@puppeteer/browsers/yargs/cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="],
"puppeteer-core/@puppeteer/browsers/yargs/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"puppeteer-core/@puppeteer/browsers/yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="],
"puppeteer/@puppeteer/browsers/yargs/cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="],
"puppeteer/@puppeteer/browsers/yargs/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
"puppeteer/@puppeteer/browsers/yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="],
"tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
"google-gax/google-auth-library/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"google-gax/retry-request/teeny-request/https-proxy-agent/agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"puppeteer-core/@puppeteer/browsers/yargs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"puppeteer-core/@puppeteer/browsers/yargs/cliui/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
"puppeteer-core/@puppeteer/browsers/yargs/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"puppeteer-core/@puppeteer/browsers/yargs/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"puppeteer/@puppeteer/browsers/yargs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"puppeteer/@puppeteer/browsers/yargs/cliui/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
"puppeteer/@puppeteer/browsers/yargs/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
"puppeteer/@puppeteer/browsers/yargs/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
"puppeteer-core/@puppeteer/browsers/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
"puppeteer-core/@puppeteer/browsers/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"puppeteer-core/@puppeteer/browsers/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
"puppeteer/@puppeteer/browsers/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
"puppeteer/@puppeteer/browsers/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
"puppeteer/@puppeteer/browsers/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
}
}
+1 -1
View File
@@ -53,7 +53,7 @@
"@sparticuz/chromium": "148.0.0",
"ffmpeg-static": "^5.2.0",
"ffprobe-static": "^3.1.0",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"tar": "^7.4.3"
},
"devDependencies": {
+1 -1
View File
@@ -41,7 +41,7 @@
"open": "^10.0.0",
"postcss": "^8.5.8",
"prettier": "^3.8.1",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"sharp": "^0.34.5"
},
"devDependencies": {
+67 -41
View File
@@ -20,7 +20,7 @@ async function loadPuppeteerBrowsers(): Promise<PuppeteerBrowsers> {
}
}
const CHROME_VERSION = "131.0.6778.85";
const CHROME_VERSION = "152.0.7928.2";
const CACHE_ROOT_DIR = join(homedir(), ".cache", "hyperframes");
const CACHE_DIR = join(homedir(), ".cache", "hyperframes", "chrome");
// Puppeteer's managed cache — where `@puppeteer/browsers install
@@ -133,6 +133,17 @@ export interface EnsureBrowserOptions {
// Purge any cached HF-managed download before resolving, so a stale or
// partially-extracted install can't make the retry look like a no-op.
force?: boolean;
// Always resolve to OUR pinned `CHROME_VERSION` build (cached, or freshly
// downloaded) — skip both the shared puppeteer-cache preference (some other
// tool's install, arbitrary version) and system Chrome (tracks Stable,
// arbitrary version, doesn't get updated in lockstep with this codebase).
// Rendering behavior should not vary with whatever Chrome happens to be
// sitting on the machine: it's the version we've actually tested against,
// and the one that implements `canvas.drawElementImage` (Dev/Canary-only —
// Stable doesn't have it, so system Chrome used to crash drawElement-
// eligible renders outright; HF#2060). `HYPERFRAMES_BROWSER_PATH` still
// wins over this — an explicit override is still an explicit override.
preferManagedChrome?: boolean;
}
interface CacheLookupResult {
@@ -195,6 +206,38 @@ function findFromEnv(): BrowserResult | undefined {
return undefined;
}
/**
* Hyperframes-managed cache only (populated by `ensureBrowser` as a
* download-of-last-resort, pinned to `CHROME_VERSION`).
*/
async function findFromHyperframesCache(): Promise<CacheLookupResult> {
if (!existsSync(CACHE_DIR)) return {};
const { Browser, getInstalledBrowsers } = await loadPuppeteerBrowsers();
// A corrupt cache (stub file where a browser dir is expected, malformed
// metadata) makes getInstalledBrowsers throw. Treat that as "no cached
// browser" so resolution falls through to system/download instead of
// crashing every caller.
let installed: Awaited<ReturnType<typeof getInstalledBrowsers>>;
try {
installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR });
} catch (err) {
const code = (err as NodeJS.ErrnoException | undefined)?.code;
const suffix = code ? ` (${code})` : "";
console.warn(
`[hyperframes] Browser cache read failed${suffix}: ${normalizeErrorMessage(err)}. Falling back to system Chrome or a fresh download.`,
);
installed = [];
}
const match = installed.find((b) => b.browser === Browser.CHROMEHEADLESSSHELL);
if (match && existsSync(match.executablePath)) {
return { result: { executablePath: match.executablePath, source: "cache" } };
}
if (match) {
return { staleHyperframesCachePath: match.executablePath, staleInstallPath: match.path };
}
return {};
}
async function findFromCache(): Promise<CacheLookupResult> {
// 1) Puppeteer's managed cache — where `npx @puppeteer/browsers install
// chrome-headless-shell` lands, and where `puppeteer install` from a project
@@ -204,45 +247,20 @@ async function findFromCache(): Promise<CacheLookupResult> {
// engine an older binary than the engine itself would pick.
//
// We intentionally check puppeteer BEFORE the hyperframes-managed cache:
// the HF cache is pinned to `CHROME_VERSION` (above) which lags behind
// upstream Chrome by many releases. If a user installed chrome-headless-shell
// separately (via `@puppeteer/browsers install`) we want to use that
// newer binary, not the pinned-stale fallback.
// this is the non-`preferManagedChrome` path, which exists so a user who
// installed chrome-headless-shell separately (via `@puppeteer/browsers
// install`) keeps using that binary instead of being silently switched to
// the HF-pinned one. Note `CHROME_VERSION` (above) is a Dev-channel pin
// that may be NEWER than a user's puppeteer-cache Stable build — this is
// about respecting an explicit prior choice, not "newest wins".
const fromPuppeteer = findFromPuppeteerCache();
if (fromPuppeteer) {
return { result: fromPuppeteer };
}
// 2) Hyperframes-managed cache (populated by `ensureBrowser` below as a
// download-of-last-resort). This is the fallback path: only reached when
// no puppeteer-cache binary exists.
if (existsSync(CACHE_DIR)) {
const { Browser, getInstalledBrowsers } = await loadPuppeteerBrowsers();
// A corrupt cache (stub file where a browser dir is expected, malformed
// metadata) makes getInstalledBrowsers throw. Treat that as "no cached
// browser" so resolution falls through to system/download instead of
// crashing every caller.
let installed: Awaited<ReturnType<typeof getInstalledBrowsers>>;
try {
installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR });
} catch (err) {
const code = (err as NodeJS.ErrnoException | undefined)?.code;
const suffix = code ? ` (${code})` : "";
console.warn(
`[hyperframes] Browser cache read failed${suffix}: ${normalizeErrorMessage(err)}. Falling back to system Chrome or a fresh download.`,
);
installed = [];
}
const match = installed.find((b) => b.browser === Browser.CHROMEHEADLESSSHELL);
if (match && existsSync(match.executablePath)) {
return { result: { executablePath: match.executablePath, source: "cache" } };
}
if (match) {
return { staleHyperframesCachePath: match.executablePath, staleInstallPath: match.path };
}
}
return {};
// 2) Hyperframes-managed cache. This is the fallback path: only reached
// when no puppeteer-cache binary exists.
return findFromHyperframesCache();
}
/**
@@ -466,13 +484,17 @@ async function ensureLinuxArmBrowser(options?: EnsureBrowserOptions): Promise<Br
/**
* Find or download a browser.
* Resolution: env var -> cached download -> system Chrome -> auto-download.
* With `preferManagedChrome`: env var -> OUR pinned cache -> auto-download
* (puppeteer-cache preference and system Chrome are both skipped).
*/
export async function ensureBrowser(options?: EnsureBrowserOptions): Promise<BrowserResult> {
const fromEnv = findFromEnv();
if (fromEnv) return fromEnv;
if (!options?.force) {
const fromCache = await findFromCache();
const fromCache = await (options?.preferManagedChrome
? findFromHyperframesCache()
: findFromCache());
if (fromCache.result) return fromCache.result;
if (fromCache.staleHyperframesCachePath) {
console.warn(
@@ -484,10 +506,12 @@ export async function ensureBrowser(options?: EnsureBrowserOptions): Promise<Bro
});
}
const fromSystem = findFromSystem();
if (fromSystem) {
warnSystemFallbackOnce(fromSystem.executablePath);
return fromSystem;
if (!options?.preferManagedChrome) {
const fromSystem = findFromSystem();
if (fromSystem) {
warnSystemFallbackOnce(fromSystem.executablePath);
return fromSystem;
}
}
}
@@ -505,7 +529,9 @@ export async function ensureBrowser(options?: EnsureBrowserOptions): Promise<Bro
// result instead of downloading and extracting a second time. Skipped
// under --force, which already purged and always wants a fresh download.
if (!options?.force) {
const afterLock = await findFromCache();
const afterLock = await (options?.preferManagedChrome
? findFromHyperframesCache()
: findFromCache());
if (afterLock.result) return afterLock.result;
if (afterLock.staleInstallPath) purgeStaleInstall(afterLock.staleInstallPath);
}
+27 -13
View File
@@ -63,24 +63,38 @@ async function runEnsure(options?: { force?: boolean }): Promise<void> {
const s = clack.spinner();
if (!options?.force) {
// Resolve with `preferManagedChrome` so this reports what `render`
// actually uses — a system Chrome without our pinned HF cache still
// downloads on the next render, so it shouldn't be reported as "found".
s.start("Looking for an existing browser...");
const existing = await findBrowser();
if (existing) {
s.stop(c.success("Browser found"));
console.log();
console.log(` ${c.dim("Source:")} ${c.bold(existing.source)}`);
console.log(` ${c.dim("Path:")} ${c.bold(existing.executablePath)}`);
console.log();
clack.outro(c.success("Ready to render."));
return;
}
let lastPct = -1;
const existing = await ensureBrowser({
preferManagedChrome: true,
onProgress: (downloaded, total) => {
if (total <= 0) return;
const pct = Math.floor((downloaded / total) * 100);
if (pct > lastPct) {
lastPct = pct;
s.message(
`Downloading Chrome Headless Shell ${c.dim("v" + CHROME_VERSION)}${c.progress(pct + "%")} ${c.dim("(" + formatBytes(downloaded) + " / " + formatBytes(total) + ")")}`,
);
}
},
});
s.stop("No browser found — downloading");
} else {
s.start("Purging cached download and re-downloading...");
if (existing.source === "download") trackBrowserInstall();
s.stop(c.success(existing.source === "download" ? "Download complete" : "Browser found"));
console.log();
console.log(` ${c.dim("Source:")} ${c.bold(existing.source)}`);
console.log(` ${c.dim("Path:")} ${c.bold(existing.executablePath)}`);
console.log();
clack.outro(c.success("Ready to render."));
return;
}
s.start("Purging cached download and re-downloading...");
const downloadSpinner = clack.spinner();
downloadSpinner.start(`Downloading Chrome Headless Shell ${c.dim("v" + CHROME_VERSION)}...`);
+6 -1
View File
@@ -757,6 +757,10 @@ export default defineCommand({
}
// ── Ensure browser for local renders ────────────────────────────────
// Always resolve to our own pinned/managed Chrome, never a
// separately-installed puppeteer-cache binary or system Chrome — render
// behavior (drawElement support included, HF#2060) shouldn't depend on
// whatever arbitrary Chrome version happens to be on the machine.
let browserPath: string | undefined;
if (!useDocker) {
const { ensureBrowser } = await import("../browser/manager.js");
@@ -769,13 +773,14 @@ export default defineCommand({
| undefined;
try {
if (effectiveQuiet) {
const info = await ensureBrowser();
const info = await ensureBrowser({ preferManagedChrome: true });
browserPath = info.executablePath;
} else {
const clack = await import("@clack/prompts");
browserSpinner = clack.spinner();
browserSpinner.start("Checking browser...");
const info = await ensureBrowser({
preferManagedChrome: true,
onProgress: (downloaded, total) => {
if (total <= 0) return;
const pct = Math.floor((downloaded / total) * 100);
+2 -2
View File
@@ -179,7 +179,7 @@ async function getThumbnailBrowser(): Promise<import("puppeteer-core").Browser |
const { acquireBrowser, buildChromeArgs } = await import("@hyperframes/engine");
try {
const b = await ensureBrowser();
const b = await ensureBrowser({ preferManagedChrome: true });
if (b.executablePath && !process.env.PRODUCER_HEADLESS_SHELL_PATH) {
process.env.PRODUCER_HEADLESS_SHELL_PATH = b.executablePath;
}
@@ -394,7 +394,7 @@ export function createStudioServer(options: StudioServerOptions): StudioServer {
const { ensureBrowser } = await import("../browser/manager.js");
try {
const browser = await ensureBrowser();
const browser = await ensureBrowser({ preferManagedChrome: true });
if (browser.executablePath && !process.env.PRODUCER_HEADLESS_SHELL_PATH) {
process.env.PRODUCER_HEADLESS_SHELL_PATH = browser.executablePath;
}
+2 -2
View File
@@ -49,8 +49,8 @@
"@hyperframes/core": "workspace:^",
"hono": "^4.6.0",
"linkedom": "^0.18.12",
"puppeteer": "^24.0.0",
"puppeteer-core": "^24.39.1"
"puppeteer": "^25.2.1",
"puppeteer-core": "^25.2.1"
},
"devDependencies": {
"@types/node": "^25.0.10",
@@ -525,6 +525,36 @@ async function initDrawElementOrTransparentBackground(
await armStaticDedup(session, page, logInitPhase);
}
}
// Capability gate: `canvas.drawElementImage` is an unlaunched Blink feature
// that only exists on recent Dev/Canary Chrome builds (~151+); it is absent
// from Stable and from most pinned/system Chrome installs. The
// `--enable-features=CanvasDrawElement` flag no-ops silently on a build that
// doesn't implement it, so without this probe the first drawElementImage()
// call throws `TypeError: ... is not a function` deep inside the capture
// loop and takes the whole render down instead of falling back (HF#2060).
// Cheap (no paint-wait) and must run before any other drawElement work.
// Not gated by forceDE (HF_FORCE_DRAWELEMENT, an R&D knob that bypasses the
// quality gates below to measure raw damage) — there's no "forced but
// degraded" mode for a method that doesn't exist, only a crash, so this
// always routes to the fallback instead.
const supportsDrawElement = await page.evaluate(() => {
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
return (
typeof (ctx as unknown as { drawElementImage?: unknown })?.drawElementImage === "function"
);
});
if (!supportsDrawElement) {
session.deGateReason = "unsupported_chrome";
console.log(
`[engine] fast capture: falling back to ${session.launchCaptureMode} capture — ` +
"this Chrome build does not implement canvas.drawElementImage (Dev/Canary-only " +
"feature, ~151+); run `hyperframes browser ensure --force` to fetch a supported " +
"build, or set HYPERFRAMES_BROWSER_PATH to one.",
);
await routeToFallback();
return;
}
// SwiftShader gate: drawElement's only advantage is skipping the GPU→CPU
// screenshot-readback IPC. On a software rasterizer (Docker/CI, no GPU) both
// paths block on identical software raster, so drawElement is parity-or-slower
+1 -1
View File
@@ -46,7 +46,7 @@
"@hono/node-server": "^1.13.0",
"@hyperframes/producer": "workspace:^",
"hono": "^4.6.0",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"tar": "^7.4.3"
},
"devDependencies": {
+1 -1
View File
@@ -39,7 +39,7 @@
"devDependencies": {
"@types/bun": "^1.1.0",
"gsap": "^3.12.5",
"puppeteer-core": "^24.39.1",
"puppeteer-core": "^25.2.1",
"tsup": "^8.0.0",
"typescript": "^5.0.0",
"vitest": "^3.2.4"
+2 -2
View File
@@ -76,8 +76,8 @@
"hono": "^4.6.0",
"linkedom": "^0.18.12",
"postcss": "^8.4.0",
"puppeteer": "^24.0.0",
"puppeteer-core": "^24.39.1",
"puppeteer": "^25.2.1",
"puppeteer-core": "^25.2.1",
"wawoff2": "^2.0.1"
},
"devDependencies": {
+1 -1
View File
@@ -73,7 +73,7 @@
"@vitejs/plugin-react": "^4.0.0",
"autoprefixer": "^10.4.0",
"postcss": "^8.4.0",
"puppeteer-core": "^24.40.0",
"puppeteer-core": "^25.2.1",
"tailwindcss": "^3.4.0",
"tsup": "^8.0.0",
"typescript": "^5.0.0",