@@ -20,7 +20,10 @@ import {
2020 detectCftPlatform ,
2121 downloadAndExtractCft ,
2222 fetchLatestCftRelease ,
23+ fetchPlaywrightBrowsersJson ,
2324 findCftExecutable ,
25+ isPlaywrightCdnPlatform ,
26+ playwrightCdnDownloadUrl ,
2427} from "./chrome-for-testing.ts" ;
2528
2629const kVersionFileName = "version" ;
@@ -32,6 +35,18 @@ export function chromeHeadlessShellInstallDir(): string {
3235 return quartoDataDir ( "chrome-headless-shell" ) ;
3336}
3437
38+ /**
39+ * The executable name for chrome-headless-shell on the current platform.
40+ * CfT builds use "chrome-headless-shell", Playwright arm64 builds use "headless_shell".
41+ */
42+ export function chromeHeadlessShellBinaryName ( ) : string {
43+ try {
44+ return isPlaywrightCdnPlatform ( ) ? "headless_shell" : "chrome-headless-shell" ;
45+ } catch {
46+ return "chrome-headless-shell" ;
47+ }
48+ }
49+
3550/**
3651 * Find the chrome-headless-shell executable in the install directory.
3752 * Returns the absolute path if installed, undefined otherwise.
@@ -41,7 +56,7 @@ export function chromeHeadlessShellExecutablePath(): string | undefined {
4156 if ( ! existsSync ( dir ) ) {
4257 return undefined ;
4358 }
44- return findCftExecutable ( dir , "chrome-headless-shell" ) ;
59+ return findCftExecutable ( dir , chromeHeadlessShellBinaryName ( ) ) ;
4560}
4661
4762/** Record the installed version as a plain text file. */
@@ -62,7 +77,7 @@ export function readInstalledVersion(dir: string): string | undefined {
6277/** Check if chrome-headless-shell is installed in the given directory. */
6378export function isInstalled ( dir : string ) : boolean {
6479 return existsSync ( join ( dir , kVersionFileName ) ) &&
65- findCftExecutable ( dir , "chrome-headless-shell" ) !== undefined ;
80+ findCftExecutable ( dir , chromeHeadlessShellBinaryName ( ) ) !== undefined ;
6681}
6782
6883// -- InstallableTool methods --
@@ -84,8 +99,22 @@ async function installedVersion(): Promise<string | undefined> {
8499}
85100
86101async function latestRelease ( ) : Promise < RemotePackageInfo > {
102+ const platformInfo = detectCftPlatform ( ) ;
103+
104+ if ( isPlaywrightCdnPlatform ( platformInfo ) ) {
105+ // arm64 Linux: use Playwright CDN
106+ const entry = await fetchPlaywrightBrowsersJson ( ) ;
107+ const url = playwrightCdnDownloadUrl ( entry . revision ) ;
108+ return {
109+ url,
110+ version : entry . browserVersion ,
111+ assets : [ { name : "chrome-headless-shell" , url } ] ,
112+ } ;
113+ }
114+
115+ // All other platforms: use CfT API
87116 const release = await fetchLatestCftRelease ( ) ;
88- const { platform } = detectCftPlatform ( ) ;
117+ const { platform } = platformInfo ;
89118
90119 const downloads = release . downloads [ "chrome-headless-shell" ] ;
91120 if ( ! downloads ) {
@@ -110,13 +139,15 @@ async function preparePackage(ctx: InstallContext): Promise<PackageInfo> {
110139 const release = await latestRelease ( ) ;
111140 const workingDir = Deno . makeTempDirSync ( { prefix : "quarto-chrome-hs-" } ) ;
112141
142+ const binaryName = chromeHeadlessShellBinaryName ( ) ;
143+
113144 try {
114145 await downloadAndExtractCft (
115146 "Chrome Headless Shell" ,
116147 release . url ,
117148 workingDir ,
118149 ctx ,
119- "chrome-headless-shell" ,
150+ binaryName ,
120151 ) ;
121152 } catch ( e ) {
122153 safeRemoveSync ( workingDir , { recursive : true } ) ;
0 commit comments