1// @effect-diagnostics globalFetch:off - This browser transport runs without an Effect runtime, like the live stream.
2import * as Schema from "effect/Schema";
3import { withDeviceHubQuery } from "./hubAccess.ts";
4import type { DeviceStreamTarget } from "./stream.ts";
5
6export class DeviceScreenshotError extends Schema.TaggedError<DeviceScreenshotError>()(
7 "DeviceScreenshotError",
8 { status: Schema.Number },
9) {
10 override get message(): string {
11 return `Screenshot capture failed (${this.status}). Try again.`;
12 }
13}
14
15export async function captureDeviceScreenshot(target: DeviceStreamTarget, signal: AbortSignal) {
16 const vendor = target.platform === "ios" ? "serve-sim" : "serve-emu";
17 const url = withDeviceHubQuery(
18 `${target.access.httpBase}/vendor/${vendor}/api/screenshot?device=${encodeURIComponent(target.deviceId)}`,
19 target.access,
20 );
21 const response = await fetch(url, {
22 method: "POST",
23 credentials: target.access.credentials ? "include" : "omit",
24 signal: AbortSignal.any([signal, AbortSignal.timeout(20_000)]),
25 });
26 if (!response.ok) throw new DeviceScreenshotError({ status: response.status });
27 const image = await response.blob();
28 if (!image.size) throw new Error("The device returned an empty screenshot. Try again.");
29 return image;
30}