mirror of
https://github.com/jakejarvis/hoot.git
synced 2025-10-18 14:24:26 -04:00
Integrate @sparticuz/chromium and puppeteer-core for screenshot service, updating configuration and removing puppeteer dependency
This commit is contained in:
2
.npmrc
Normal file
2
.npmrc
Normal file
@@ -0,0 +1,2 @@
|
||||
public-hoist-pattern[]=@sparticuz/chromium
|
||||
public-hoist-pattern[]=puppeteer-core
|
17
lib/puppeteer.ts
Normal file
17
lib/puppeteer.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import "server-only";
|
||||
|
||||
export async function launchChromium(
|
||||
overrides: Record<string, unknown> = {},
|
||||
): Promise<import("puppeteer-core").Browser> {
|
||||
const chromium = (await import("@sparticuz/chromium")).default;
|
||||
const { launch } = await import("puppeteer-core");
|
||||
|
||||
const executablePath = await chromium.executablePath();
|
||||
return launch({
|
||||
headless: true,
|
||||
args: chromium.args,
|
||||
executablePath,
|
||||
defaultViewport: null,
|
||||
...overrides,
|
||||
});
|
||||
}
|
@@ -9,6 +9,10 @@ const nextConfig: NextConfig = {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
serverExternalPackages: ["@sparticuz/chromium", "puppeteer-core"],
|
||||
outputFileTracingRoot: process.cwd(),
|
||||
outputFileTracingIncludes: {
|
||||
"app/api/**": ["node_modules/@sparticuz/chromium/bin/**"],
|
||||
},
|
||||
reactCompiler: true,
|
||||
images: {
|
||||
unoptimized: true,
|
||||
|
@@ -81,7 +81,6 @@
|
||||
"@vitest/ui": "^3.2.4",
|
||||
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
||||
"jsdom": "^27.0.0",
|
||||
"puppeteer": "24.22.3",
|
||||
"tailwindcss": "^4.1.14",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "5.9.3",
|
||||
|
123
pnpm-lock.yaml
generated
123
pnpm-lock.yaml
generated
@@ -174,9 +174,6 @@ importers:
|
||||
jsdom:
|
||||
specifier: ^27.0.0
|
||||
version: 27.0.0(postcss@8.5.6)
|
||||
puppeteer:
|
||||
specifier: 24.22.3
|
||||
version: 24.22.3(typescript@5.9.3)
|
||||
tailwindcss:
|
||||
specifier: ^4.1.14
|
||||
version: 4.1.14
|
||||
@@ -2033,9 +2030,6 @@ packages:
|
||||
any-base@1.1.0:
|
||||
resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
aria-hidden@1.2.6:
|
||||
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2173,10 +2167,6 @@ packages:
|
||||
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
callsites@3.1.0:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
caniuse-lite@1.0.30001748:
|
||||
resolution: {integrity: sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==}
|
||||
|
||||
@@ -2249,15 +2239,6 @@ packages:
|
||||
core-js@3.45.1:
|
||||
resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
|
||||
|
||||
cosmiconfig@9.0.0:
|
||||
resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
typescript: '>=4.9.5'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -2378,13 +2359,6 @@ packages:
|
||||
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
env-paths@2.2.1:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
error-ex@1.3.4:
|
||||
resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
|
||||
|
||||
es-define-property@1.0.1:
|
||||
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -2647,10 +2621,6 @@ packages:
|
||||
ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
indent-string@4.0.0:
|
||||
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2663,9 +2633,6 @@ packages:
|
||||
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
is-arrayish@0.2.1:
|
||||
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||
|
||||
is-buffer@2.0.5:
|
||||
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -2746,10 +2713,6 @@ packages:
|
||||
js-tokens@9.0.1:
|
||||
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
||||
hasBin: true
|
||||
|
||||
jsdom@27.0.0:
|
||||
resolution: {integrity: sha512-lIHeR1qlIRrIN5VMccd8tI2Sgw6ieYXSVktcSHaNe3Z5nE/tcPQYQWOq00wxMvYOsz+73eAkNenVvmPC6bba9A==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -2764,9 +2727,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
hasBin: true
|
||||
|
||||
json-parse-even-better-errors@2.3.1:
|
||||
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||
|
||||
json-stringify-pretty-compact@3.0.0:
|
||||
resolution: {integrity: sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==}
|
||||
|
||||
@@ -2842,9 +2802,6 @@ packages:
|
||||
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
loupe@3.2.1:
|
||||
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
|
||||
|
||||
@@ -3020,14 +2977,6 @@ packages:
|
||||
package-json-from-dist@1.0.1:
|
||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||
|
||||
parent-module@1.0.1:
|
||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
parse-json@5.2.0:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
parse5@7.3.0:
|
||||
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
||||
|
||||
@@ -3149,11 +3098,6 @@ packages:
|
||||
resolution: {integrity: sha512-M/Jhg4PWRANSbL/C9im//Yb55wsWBS5wdp+h59iwM+EPicVQQCNs56iC5aEAO7avfDPRfxs4MM16wHjOYHNJEw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
puppeteer@24.22.3:
|
||||
resolution: {integrity: sha512-mnhXzIqSYSJ1SMv1RYH07YMzWP81xCmmQj91Q8iQMZqnf97eVzeHgsGL6kpywiGCi+nQafta/+NkwM4URMy/XQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
quickselect@3.0.0:
|
||||
resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==}
|
||||
|
||||
@@ -3256,10 +3200,6 @@ packages:
|
||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
resolve-protobuf-schema@2.1.0:
|
||||
resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==}
|
||||
|
||||
@@ -5572,8 +5512,6 @@ snapshots:
|
||||
|
||||
any-base@1.1.0: {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
aria-hidden@1.2.6:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -5713,8 +5651,6 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
function-bind: 1.1.2
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
caniuse-lite@1.0.30001748: {}
|
||||
|
||||
chai@5.3.3:
|
||||
@@ -5788,15 +5724,6 @@ snapshots:
|
||||
|
||||
core-js@3.45.1: {}
|
||||
|
||||
cosmiconfig@9.0.0(typescript@5.9.3):
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
import-fresh: 3.3.1
|
||||
js-yaml: 4.1.0
|
||||
parse-json: 5.2.0
|
||||
optionalDependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
@@ -5906,12 +5833,6 @@ snapshots:
|
||||
|
||||
entities@6.0.1: {}
|
||||
|
||||
env-paths@2.2.1: {}
|
||||
|
||||
error-ex@1.3.4:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
|
||||
es-define-property@1.0.1: {}
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
@@ -6193,19 +6114,12 @@ snapshots:
|
||||
|
||||
ieee754@1.2.1: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
resolve-from: 4.0.0
|
||||
|
||||
indent-string@4.0.0: {}
|
||||
|
||||
ip-address@10.0.1: {}
|
||||
|
||||
ipaddr.js@2.2.0: {}
|
||||
|
||||
is-arrayish@0.2.1: {}
|
||||
|
||||
is-buffer@2.0.5: {}
|
||||
|
||||
is-extendable@0.1.1: {}
|
||||
@@ -6278,10 +6192,6 @@ snapshots:
|
||||
|
||||
js-tokens@9.0.1: {}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
jsdom@27.0.0(postcss@8.5.6):
|
||||
dependencies:
|
||||
'@asamuzakjp/dom-selector': 6.6.1
|
||||
@@ -6312,8 +6222,6 @@ snapshots:
|
||||
|
||||
jsesc@3.1.0: {}
|
||||
|
||||
json-parse-even-better-errors@2.3.1: {}
|
||||
|
||||
json-stringify-pretty-compact@3.0.0: {}
|
||||
|
||||
json5@2.2.3: {}
|
||||
@@ -6365,8 +6273,6 @@ snapshots:
|
||||
lightningcss-win32-arm64-msvc: 1.30.1
|
||||
lightningcss-win32-x64-msvc: 1.30.1
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
loupe@3.2.1: {}
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
@@ -6548,17 +6454,6 @@ snapshots:
|
||||
|
||||
package-json-from-dist@1.0.1: {}
|
||||
|
||||
parent-module@1.0.1:
|
||||
dependencies:
|
||||
callsites: 3.1.0
|
||||
|
||||
parse-json@5.2.0:
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
error-ex: 1.3.4
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
lines-and-columns: 1.2.4
|
||||
|
||||
parse5@7.3.0:
|
||||
dependencies:
|
||||
entities: 6.0.1
|
||||
@@ -6683,22 +6578,6 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
puppeteer@24.22.3(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@puppeteer/browsers': 2.10.10
|
||||
chromium-bidi: 9.1.0(devtools-protocol@0.0.1495869)
|
||||
cosmiconfig: 9.0.0(typescript@5.9.3)
|
||||
devtools-protocol: 0.0.1495869
|
||||
puppeteer-core: 24.22.3
|
||||
typed-query-selector: 2.12.0
|
||||
transitivePeerDependencies:
|
||||
- bare-buffer
|
||||
- bufferutil
|
||||
- react-native-b4a
|
||||
- supports-color
|
||||
- typescript
|
||||
- utf-8-validate
|
||||
|
||||
quickselect@3.0.0: {}
|
||||
|
||||
radix-ui@1.4.3(@types/react-dom@19.1.9(@types/react@19.1.16))(@types/react@19.1.16)(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
|
||||
@@ -6838,8 +6717,6 @@ snapshots:
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
resolve-protobuf-schema@2.1.0:
|
||||
dependencies:
|
||||
protocol-buffers-schema: 3.6.0
|
||||
|
@@ -20,8 +20,11 @@ const browserMock = {
|
||||
close: vi.fn(async () => undefined),
|
||||
};
|
||||
|
||||
vi.mock("puppeteer", () => ({
|
||||
launch: vi.fn(async () => browserMock),
|
||||
vi.mock("@sparticuz/chromium", () => ({
|
||||
default: {
|
||||
args: ["--no-sandbox", "--disable-setuid-sandbox"],
|
||||
executablePath: vi.fn(async () => "/usr/bin/chromium"),
|
||||
},
|
||||
}));
|
||||
vi.mock("puppeteer-core", () => ({
|
||||
launch: vi.fn(async () => browserMock),
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import type { Browser } from "puppeteer-core";
|
||||
import { captureServer } from "@/lib/analytics/server";
|
||||
import { getScreenshotTtlSeconds, putScreenshotBlob } from "@/lib/blob";
|
||||
import { USER_AGENT } from "@/lib/constants";
|
||||
import { addWatermarkToScreenshot, optimizePngCover } from "@/lib/image";
|
||||
import { launchChromium } from "@/lib/puppeteer";
|
||||
import { ns, redis } from "@/lib/redis";
|
||||
|
||||
const VIEWPORT_WIDTH = 1200;
|
||||
@@ -72,91 +74,10 @@ export async function getOrCreateScreenshotBlobUrl(
|
||||
}
|
||||
|
||||
// 2) Attempt to capture
|
||||
let browser: import("puppeteer-core").Browser | null = null;
|
||||
let browser: Browser | null = null;
|
||||
try {
|
||||
const isVercel = process.env.VERCEL === "1";
|
||||
const isLinux = process.platform === "linux";
|
||||
const preferChromium = isLinux || isVercel;
|
||||
|
||||
type LaunchFn = (
|
||||
options?: Record<string, unknown>,
|
||||
) => Promise<import("puppeteer-core").Browser>;
|
||||
let puppeteerLaunch: LaunchFn = async () => {
|
||||
throw new Error("puppeteer launcher not configured");
|
||||
};
|
||||
let launchOptions: Record<string, unknown> = { headless: true };
|
||||
let launcherMode: "chromium" | "puppeteer" = preferChromium
|
||||
? "chromium"
|
||||
: "puppeteer";
|
||||
|
||||
async function setupChromium() {
|
||||
const chromium = (await import("@sparticuz/chromium")).default;
|
||||
const core = await import("puppeteer-core");
|
||||
puppeteerLaunch = core.launch as unknown as LaunchFn;
|
||||
launchOptions = {
|
||||
...launchOptions,
|
||||
args: chromium.args,
|
||||
executablePath: await chromium.executablePath(),
|
||||
};
|
||||
|
||||
console.debug("[screenshot] using chromium", {
|
||||
executablePath: (launchOptions as { executablePath?: unknown })
|
||||
.executablePath,
|
||||
});
|
||||
}
|
||||
|
||||
async function setupPuppeteer() {
|
||||
const full = await import("puppeteer");
|
||||
puppeteerLaunch = (full as unknown as { launch: LaunchFn }).launch;
|
||||
const path = process.env.PUPPETEER_EXECUTABLE_PATH;
|
||||
launchOptions = {
|
||||
...launchOptions,
|
||||
...(path ? { executablePath: path } : {}),
|
||||
args: [
|
||||
"--no-sandbox",
|
||||
"--disable-setuid-sandbox",
|
||||
"--disable-dev-shm-usage",
|
||||
],
|
||||
};
|
||||
|
||||
console.debug("[screenshot] using puppeteer", {
|
||||
executablePath: path || null,
|
||||
});
|
||||
}
|
||||
|
||||
// First attempt based on platform preference
|
||||
try {
|
||||
if (launcherMode === "chromium") await setupChromium();
|
||||
else await setupPuppeteer();
|
||||
// Try launch
|
||||
|
||||
console.debug("[screenshot] launching browser", { mode: launcherMode });
|
||||
browser = await puppeteerLaunch(launchOptions);
|
||||
} catch (firstErr) {
|
||||
console.warn("[screenshot] first launch attempt failed", {
|
||||
mode: launcherMode,
|
||||
error: (firstErr as Error)?.message,
|
||||
});
|
||||
// Flip mode and retry once
|
||||
launcherMode = launcherMode === "chromium" ? "puppeteer" : "chromium";
|
||||
try {
|
||||
if (launcherMode === "chromium") await setupChromium();
|
||||
else await setupPuppeteer();
|
||||
|
||||
console.debug("[screenshot] retry launching browser", {
|
||||
mode: launcherMode,
|
||||
});
|
||||
browser = await puppeteerLaunch(launchOptions);
|
||||
} catch (secondErr) {
|
||||
console.error("[screenshot] both launch attempts failed", {
|
||||
first_error: (firstErr as Error)?.message,
|
||||
second_error: (secondErr as Error)?.message,
|
||||
});
|
||||
throw secondErr;
|
||||
}
|
||||
}
|
||||
|
||||
console.debug("[screenshot] browser launched", { mode: launcherMode });
|
||||
browser = await launchChromium();
|
||||
console.debug("[screenshot] browser launched", { mode: "chromium" });
|
||||
|
||||
const tryUrls = buildHomepageUrls(domain);
|
||||
for (const url of tryUrls) {
|
||||
|
Reference in New Issue
Block a user