@elizaos/capacitor-screencapture 2.0.0-beta.1 → 2.0.3-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,313 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { ScreenCaptureWeb } from "./web";
3
+ class FakeTrack {
4
+ constructor(kind, settings = {}) {
5
+ this.kind = kind;
6
+ this.settings = settings;
7
+ this.stopped = false;
8
+ this.listeners = new Map();
9
+ }
10
+ getSettings() {
11
+ return this.settings;
12
+ }
13
+ stop() {
14
+ this.stopped = true;
15
+ }
16
+ addEventListener(eventName, callback) {
17
+ const listeners = this.listeners.get(eventName) ?? [];
18
+ listeners.push(callback);
19
+ this.listeners.set(eventName, listeners);
20
+ }
21
+ dispatchEnded() {
22
+ this.listeners.get("ended")?.forEach((callback) => {
23
+ callback(new Event("ended"));
24
+ });
25
+ }
26
+ }
27
+ class FakeStream {
28
+ constructor(tracks) {
29
+ this.tracks = tracks;
30
+ }
31
+ getTracks() {
32
+ return this.tracks;
33
+ }
34
+ getVideoTracks() {
35
+ return this.tracks.filter((track) => track.kind === "video");
36
+ }
37
+ getAudioTracks() {
38
+ return this.tracks.filter((track) => track.kind === "audio");
39
+ }
40
+ addTrack(track) {
41
+ this.tracks.push(track);
42
+ }
43
+ }
44
+ class FakeMediaRecorder {
45
+ static isTypeSupported(mimeType) {
46
+ return FakeMediaRecorder.supported && mimeType === "video/webm";
47
+ }
48
+ constructor(stream, options) {
49
+ this.stream = stream;
50
+ this.options = options;
51
+ this.ondataavailable = null;
52
+ this.onerror = null;
53
+ this.onstop = null;
54
+ this.start = vi.fn((_timeslice) => { });
55
+ this.pause = vi.fn();
56
+ this.resume = vi.fn();
57
+ this.stop = vi.fn(() => {
58
+ queueMicrotask(() => {
59
+ this.onstop?.(new Event("stop"));
60
+ });
61
+ });
62
+ this.mimeType = options.mimeType ?? "";
63
+ FakeMediaRecorder.instances.push(this);
64
+ }
65
+ }
66
+ FakeMediaRecorder.supported = true;
67
+ FakeMediaRecorder.instances = [];
68
+ function setNavigator(value) {
69
+ Object.defineProperty(globalThis, "navigator", {
70
+ configurable: true,
71
+ value,
72
+ });
73
+ }
74
+ function installDocument() {
75
+ const context = { drawImage: vi.fn() };
76
+ const canvas = {
77
+ width: 0,
78
+ height: 0,
79
+ getContext: vi.fn(() => context),
80
+ toDataURL: vi.fn(() => "data:image/webp;base64,c2NyZWVu"),
81
+ };
82
+ const createElement = vi.fn((tagName) => {
83
+ if (tagName === "canvas")
84
+ return canvas;
85
+ if (tagName === "video") {
86
+ return {
87
+ videoWidth: 1280,
88
+ videoHeight: 720,
89
+ set src(_value) { },
90
+ set onloadedmetadata(callback) {
91
+ queueMicrotask(callback);
92
+ },
93
+ set onerror(_callback) { },
94
+ };
95
+ }
96
+ throw new Error(`unexpected element: ${tagName}`);
97
+ });
98
+ vi.stubGlobal("document", { createElement });
99
+ vi.stubGlobal("URL", {
100
+ createObjectURL: vi.fn(() => "blob:screen-recording"),
101
+ });
102
+ return { canvas, context, createElement };
103
+ }
104
+ describe("ScreenCaptureWeb", () => {
105
+ afterEach(() => {
106
+ vi.useRealTimers();
107
+ vi.restoreAllMocks();
108
+ vi.unstubAllGlobals();
109
+ FakeMediaRecorder.supported = true;
110
+ FakeMediaRecorder.instances = [];
111
+ });
112
+ it("reports unsupported cleanly when optional browser capture APIs are absent", async () => {
113
+ setNavigator({});
114
+ vi.stubGlobal("MediaRecorder", undefined);
115
+ vi.stubGlobal("AudioContext", undefined);
116
+ const plugin = new ScreenCaptureWeb();
117
+ await expect(plugin.isSupported()).resolves.toEqual({
118
+ supported: false,
119
+ features: [],
120
+ });
121
+ await expect(plugin.checkPermissions()).resolves.toEqual({
122
+ screenCapture: "not_supported",
123
+ microphone: "prompt",
124
+ });
125
+ await expect(plugin.requestPermissions()).resolves.toEqual({
126
+ screenCapture: "not_supported",
127
+ microphone: "denied",
128
+ });
129
+ });
130
+ it("maps screenshot options into display capture and canvas encoding", async () => {
131
+ const track = new FakeTrack("video", { width: 320, height: 200 });
132
+ const stream = new FakeStream([track]);
133
+ const getDisplayMedia = vi.fn(async () => stream);
134
+ const close = vi.fn();
135
+ const grabFrame = vi.fn(async () => ({ close }));
136
+ const imageCapture = vi.fn(function ImageCapture() {
137
+ Object.assign(this, { grabFrame });
138
+ });
139
+ const { canvas, context } = installDocument();
140
+ setNavigator({
141
+ mediaDevices: { getDisplayMedia },
142
+ });
143
+ vi.stubGlobal("ImageCapture", imageCapture);
144
+ await expect(new ScreenCaptureWeb().captureScreenshot({
145
+ format: "webp",
146
+ quality: 25,
147
+ scale: 2,
148
+ })).resolves.toEqual({
149
+ base64: "c2NyZWVu",
150
+ format: "webp",
151
+ width: 640,
152
+ height: 400,
153
+ timestamp: expect.any(Number),
154
+ });
155
+ expect(getDisplayMedia).toHaveBeenCalledWith({
156
+ video: { displaySurface: "monitor" },
157
+ audio: false,
158
+ });
159
+ expect(canvas.width).toBe(640);
160
+ expect(canvas.height).toBe(400);
161
+ expect(context.drawImage).toHaveBeenCalledWith(expect.anything(), 0, 0, 640, 400);
162
+ expect(canvas.toDataURL).toHaveBeenCalledWith("image/webp", 0.25);
163
+ expect(track.stopped).toBe(true);
164
+ expect(close).toHaveBeenCalled();
165
+ });
166
+ it.each([
167
+ { quality: -1 },
168
+ { quality: 101 },
169
+ { quality: Number.POSITIVE_INFINITY },
170
+ { scale: 0 },
171
+ { scale: Number.NaN },
172
+ ])("rejects malformed screenshot options %# before requesting capture", async (options) => {
173
+ const getDisplayMedia = vi.fn();
174
+ setNavigator({
175
+ mediaDevices: { getDisplayMedia },
176
+ });
177
+ await expect(new ScreenCaptureWeb().captureScreenshot(options)).rejects.toThrow(/quality|scale/);
178
+ expect(getDisplayMedia).not.toHaveBeenCalled();
179
+ });
180
+ it("stops acquired display tracks when screenshot frame capture fails", async () => {
181
+ const track = new FakeTrack("video", { width: 320, height: 200 });
182
+ const stream = new FakeStream([track]);
183
+ const getDisplayMedia = vi.fn(async () => stream);
184
+ const grabFrame = vi.fn(async () => {
185
+ throw new Error("frame unavailable");
186
+ });
187
+ const imageCapture = vi.fn(function ImageCapture() {
188
+ Object.assign(this, { grabFrame });
189
+ });
190
+ installDocument();
191
+ setNavigator({
192
+ mediaDevices: { getDisplayMedia },
193
+ });
194
+ vi.stubGlobal("ImageCapture", imageCapture);
195
+ await expect(new ScreenCaptureWeb().captureScreenshot()).rejects.toThrow("frame unavailable");
196
+ expect(track.stopped).toBe(true);
197
+ });
198
+ it("stops acquired display tracks when recording cannot be encoded", async () => {
199
+ const videoTrack = new FakeTrack("video");
200
+ const audioTrack = new FakeTrack("audio");
201
+ const stream = new FakeStream([videoTrack, audioTrack]);
202
+ const getDisplayMedia = vi.fn(async () => stream);
203
+ setNavigator({
204
+ mediaDevices: { getDisplayMedia },
205
+ });
206
+ vi.stubGlobal("MediaRecorder", undefined);
207
+ const plugin = new ScreenCaptureWeb();
208
+ await expect(plugin.startRecording()).rejects.toThrow("No supported video mime type found");
209
+ expect(videoTrack.stopped).toBe(true);
210
+ expect(audioTrack.stopped).toBe(true);
211
+ await expect(plugin.getRecordingState()).resolves.toEqual({
212
+ isRecording: false,
213
+ duration: 0,
214
+ fileSize: 0,
215
+ });
216
+ });
217
+ it.each([
218
+ { fps: 0 },
219
+ { fps: Number.NaN },
220
+ { bitrate: -1 },
221
+ { maxDuration: Number.POSITIVE_INFINITY },
222
+ { maxFileSize: 0 },
223
+ ])("rejects malformed recording options %# before requesting capture", async (options) => {
224
+ const getDisplayMedia = vi.fn();
225
+ setNavigator({
226
+ mediaDevices: { getDisplayMedia },
227
+ });
228
+ vi.stubGlobal("MediaRecorder", FakeMediaRecorder);
229
+ await expect(new ScreenCaptureWeb().startRecording(options)).rejects.toThrow(/fps|bitrate|maxDuration|maxFileSize/);
230
+ expect(getDisplayMedia).not.toHaveBeenCalled();
231
+ });
232
+ it("runs recording pause, resume, stop, and listener removal without leaking tracks", async () => {
233
+ vi.useFakeTimers();
234
+ vi.setSystemTime(1000);
235
+ installDocument();
236
+ vi.stubGlobal("MediaRecorder", FakeMediaRecorder);
237
+ const videoTrack = new FakeTrack("video");
238
+ const micTrack = new FakeTrack("audio");
239
+ const displayStream = new FakeStream([videoTrack]);
240
+ const micStream = new FakeStream([micTrack]);
241
+ const getDisplayMedia = vi.fn(async () => displayStream);
242
+ const getUserMedia = vi.fn(async () => micStream);
243
+ setNavigator({
244
+ mediaDevices: {
245
+ getDisplayMedia,
246
+ getUserMedia,
247
+ },
248
+ });
249
+ const plugin = new ScreenCaptureWeb();
250
+ const states = [];
251
+ const removedListener = vi.fn();
252
+ plugin.addListener("recordingState", (event) => {
253
+ states.push(event);
254
+ });
255
+ const handle = await plugin.addListener("recordingState", removedListener);
256
+ await handle.remove();
257
+ await plugin.startRecording({
258
+ captureMicrophone: true,
259
+ fps: 30,
260
+ bitrate: 250000,
261
+ });
262
+ const recorder = FakeMediaRecorder.instances[0];
263
+ expect(getDisplayMedia).toHaveBeenCalledWith({
264
+ video: { displaySurface: "monitor", frameRate: { ideal: 30 } },
265
+ audio: true,
266
+ });
267
+ expect(getUserMedia).toHaveBeenCalledWith({ audio: true });
268
+ expect(recorder.options).toEqual({
269
+ mimeType: "video/webm",
270
+ videoBitsPerSecond: 250000,
271
+ });
272
+ expect(recorder.start).toHaveBeenCalledWith(1000);
273
+ expect(states[0]).toEqual({
274
+ isRecording: true,
275
+ duration: 0,
276
+ fileSize: 0,
277
+ });
278
+ expect(removedListener).not.toHaveBeenCalled();
279
+ recorder.ondataavailable?.({
280
+ data: new Blob(["chunk"]),
281
+ });
282
+ vi.setSystemTime(2500);
283
+ await plugin.pauseRecording();
284
+ await plugin.pauseRecording();
285
+ expect(recorder.pause).toHaveBeenCalledTimes(1);
286
+ vi.setSystemTime(3000);
287
+ await plugin.resumeRecording();
288
+ await plugin.resumeRecording();
289
+ expect(recorder.resume).toHaveBeenCalledTimes(1);
290
+ const stopPromise = plugin.stopRecording();
291
+ expect(recorder.stop).toHaveBeenCalledTimes(1);
292
+ await expect(stopPromise).resolves.toEqual({
293
+ path: "blob:screen-recording",
294
+ duration: 1.5,
295
+ width: 1280,
296
+ height: 720,
297
+ fileSize: 5,
298
+ mimeType: "video/webm",
299
+ });
300
+ expect(videoTrack.stopped).toBe(true);
301
+ expect(micTrack.stopped).toBe(true);
302
+ expect(states[states.length - 1]).toEqual({
303
+ isRecording: false,
304
+ duration: 1.5,
305
+ fileSize: 5,
306
+ });
307
+ await expect(plugin.getRecordingState()).resolves.toEqual({
308
+ isRecording: false,
309
+ duration: 0,
310
+ fileSize: 5,
311
+ });
312
+ });
313
+ });
@@ -13,8 +13,28 @@ const VIDEO_MIME_TYPES = [
13
13
  "video/webm",
14
14
  "video/mp4",
15
15
  ];
16
- const getSupportedMimeType = () => VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null;
17
- const hasDisplayMedia = () => !!navigator.mediaDevices.getDisplayMedia;
16
+ const getSupportedMimeType = () => typeof MediaRecorder === "undefined"
17
+ ? null
18
+ : (VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null);
19
+ const hasDisplayMedia = () => !!navigator.mediaDevices
20
+ ?.getDisplayMedia;
21
+ function assertPositiveFiniteNumber(value, label) {
22
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
23
+ throw new Error(`${label} must be a positive finite number`);
24
+ }
25
+ return value;
26
+ }
27
+ function assertQuality(value) {
28
+ if (value === undefined)
29
+ return 1;
30
+ if (typeof value !== "number" || !Number.isFinite(value)) {
31
+ throw new Error("quality must be a finite number between 0 and 100");
32
+ }
33
+ if (value < 0 || value > 100) {
34
+ throw new Error("quality must be between 0 and 100");
35
+ }
36
+ return value / 100;
37
+ }
18
38
  const getDisplayMedia = (opts) => navigator.mediaDevices.getDisplayMedia(opts);
19
39
  class ScreenCaptureWeb extends core.WebPlugin {
20
40
  constructor() {
@@ -43,8 +63,10 @@ class ScreenCaptureWeb extends core.WebPlugin {
43
63
  }
44
64
  async captureScreenshot(options) {
45
65
  const format = options?.format || "png";
46
- const quality = (options?.quality || 100) / 100;
47
- const scale = options?.scale || 1;
66
+ const quality = assertQuality(options?.quality);
67
+ const scale = options?.scale === undefined
68
+ ? 1
69
+ : assertPositiveFiniteNumber(options.scale, "scale");
48
70
  // PERMISSIONS_MIGRATION: getDisplayMedia() triggers the OS screen
49
71
  // recording / picker dialog implicitly. New flow probes via
50
72
  // `screenRecordingProber` in
@@ -59,11 +81,16 @@ class ScreenCaptureWeb extends core.WebPlugin {
59
81
  const settings = track.getSettings();
60
82
  const width = (settings.width || 1920) * scale;
61
83
  const height = (settings.height || 1080) * scale;
62
- const imageCapture = new ImageCapture(track);
63
- const bitmap = await imageCapture.grabFrame();
64
- stream.getTracks().forEach((t) => {
65
- t.stop();
66
- });
84
+ let bitmap = null;
85
+ try {
86
+ const imageCapture = new ImageCapture(track);
87
+ bitmap = await imageCapture.grabFrame();
88
+ }
89
+ finally {
90
+ stream.getTracks().forEach((t) => {
91
+ t.stop();
92
+ });
93
+ }
67
94
  const canvas = document.createElement("canvas");
68
95
  canvas.width = width;
69
96
  canvas.height = height;
@@ -91,6 +118,18 @@ class ScreenCaptureWeb extends core.WebPlugin {
91
118
  async startRecording(options) {
92
119
  if (this.isRecording)
93
120
  throw new Error("Recording already in progress");
121
+ if (options?.fps !== undefined) {
122
+ assertPositiveFiniteNumber(options.fps, "fps");
123
+ }
124
+ if (options?.bitrate !== undefined) {
125
+ assertPositiveFiniteNumber(options.bitrate, "bitrate");
126
+ }
127
+ if (options?.maxDuration !== undefined) {
128
+ assertPositiveFiniteNumber(options.maxDuration, "maxDuration");
129
+ }
130
+ if (options?.maxFileSize !== undefined) {
131
+ assertPositiveFiniteNumber(options.maxFileSize, "maxFileSize");
132
+ }
94
133
  const videoConstraints = {
95
134
  displaySurface: "monitor",
96
135
  };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.ScreenCaptureWeb());\nexport const ScreenCapture = registerPlugin(\"ScreenCapture\", {\n web: loadWeb,\n});\n","import { WebPlugin } from \"@capacitor/core\";\nconst VIDEO_MIME_TYPES = [\n \"video/webm;codecs=vp9,opus\",\n \"video/webm;codecs=vp8,opus\",\n \"video/webm\",\n \"video/mp4\",\n];\nconst getSupportedMimeType = () => VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null;\nconst hasDisplayMedia = () => !!navigator.mediaDevices.getDisplayMedia;\nconst getDisplayMedia = (opts) => navigator.mediaDevices.getDisplayMedia(opts);\nexport class ScreenCaptureWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.mediaStream = null;\n this.mediaRecorder = null;\n this.recordedChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedDuration = 0;\n this.pauseStartTime = 0;\n this.recordingStateInterval = null;\n this.pluginListeners = [];\n }\n async isSupported() {\n const supported = hasDisplayMedia();\n const features = [];\n if (supported)\n features.push(\"screenshot\", \"recording\");\n if (typeof MediaRecorder !== \"undefined\")\n features.push(\"video_encoding\");\n if (typeof AudioContext !== \"undefined\")\n features.push(\"system_audio\");\n return { supported, features };\n }\n async captureScreenshot(options) {\n const format = options?.format || \"png\";\n const quality = (options?.quality || 100) / 100;\n const scale = options?.scale || 1;\n // PERMISSIONS_MIGRATION: getDisplayMedia() triggers the OS screen\n // recording / picker dialog implicitly. New flow probes via\n // `screenRecordingProber` in\n // `packages/agent/src/services/permissions/probers/screen-recording.ts`\n // before opening the stream. Will be retired by the chat-surface\n // migration agent.\n const stream = await getDisplayMedia({\n video: { displaySurface: \"monitor\" },\n audio: false,\n });\n const track = stream.getVideoTracks()[0];\n const settings = track.getSettings();\n const width = (settings.width || 1920) * scale;\n const height = (settings.height || 1080) * scale;\n const imageCapture = new ImageCapture(track);\n const bitmap = await imageCapture.grabFrame();\n stream.getTracks().forEach((t) => {\n t.stop();\n });\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Failed to get canvas context\");\n }\n ctx.drawImage(bitmap, 0, 0, width, height);\n bitmap.close();\n const mimeType = format === \"png\"\n ? \"image/png\"\n : format === \"webp\"\n ? \"image/webp\"\n : \"image/jpeg\";\n const dataUrl = canvas.toDataURL(mimeType, quality);\n const base64 = dataUrl.split(\",\")[1];\n return {\n base64,\n format,\n width,\n height,\n timestamp: Date.now(),\n };\n }\n async startRecording(options) {\n if (this.isRecording)\n throw new Error(\"Recording already in progress\");\n const videoConstraints = {\n displaySurface: \"monitor\",\n };\n if (options?.fps)\n videoConstraints.frameRate = { ideal: options.fps };\n this.mediaStream = await getDisplayMedia({\n video: videoConstraints,\n audio: options?.captureSystemAudio !== false,\n });\n if (options?.captureMicrophone) {\n const micStream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n });\n micStream.getAudioTracks().forEach((t) => {\n this.mediaStream?.addTrack(t);\n });\n }\n const mimeType = getSupportedMimeType();\n if (!mimeType) {\n this.mediaStream.getTracks().forEach((t) => {\n t.stop();\n });\n throw new Error(\"No supported video mime type found\");\n }\n const recorderOptions = { mimeType };\n if (options?.bitrate)\n recorderOptions.videoBitsPerSecond = options.bitrate;\n this.recordedChunks = [];\n this.mediaRecorder = new MediaRecorder(this.mediaStream, recorderOptions);\n this.mediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n this.recordedChunks.push(event.data);\n }\n };\n this.mediaRecorder.onerror = (event) => {\n this.notifyListeners(\"error\", {\n code: \"RECORDING_ERROR\",\n message: `Recording error: ${event.message || \"Unknown error\"}`,\n });\n };\n this.mediaStream.getVideoTracks()[0].addEventListener(\"ended\", () => {\n if (this.isRecording) {\n this.stopRecording().catch((err) => {\n console.error(\"[ScreenCapture] Auto-stop on track end failed:\", err);\n });\n }\n });\n this.recordingStartTime = Date.now();\n this.pausedDuration = 0;\n this.isRecording = true;\n this.isPaused = false;\n this.mediaRecorder.start(1000);\n this.notifyListeners(\"recordingState\", {\n isRecording: true,\n duration: 0,\n fileSize: 0,\n });\n let autoStopping = false;\n this.recordingStateInterval = setInterval(() => {\n if (!this.isRecording || this.isPaused || autoStopping)\n return;\n const duration = (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000;\n const fileSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);\n this.notifyListeners(\"recordingState\", {\n isRecording: true,\n duration,\n fileSize,\n });\n const overLimit = (options?.maxDuration && duration >= options.maxDuration) ||\n (options?.maxFileSize && fileSize >= options.maxFileSize);\n if (overLimit) {\n autoStopping = true;\n this.stopRecording().catch((err) => {\n console.error(\"[ScreenCapture] Auto-stop recording failed:\", err);\n });\n }\n }, 500);\n }\n async stopRecording() {\n if (!this.isRecording || !this.mediaRecorder) {\n throw new Error(\"Not recording\");\n }\n return new Promise((resolve, reject) => {\n if (!this.mediaRecorder) {\n reject(new Error(\"MediaRecorder not initialized\"));\n return;\n }\n const duration = (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000;\n this.mediaRecorder.onstop = () => {\n if (this.recordingStateInterval) {\n clearInterval(this.recordingStateInterval);\n this.recordingStateInterval = null;\n }\n this.isRecording = false;\n this.isPaused = false;\n if (this.mediaStream) {\n this.mediaStream.getTracks().forEach((track) => {\n track.stop();\n });\n this.mediaStream = null;\n }\n const blob = new Blob(this.recordedChunks, {\n type: this.mediaRecorder?.mimeType || \"video/webm\",\n });\n const url = URL.createObjectURL(blob);\n const video = document.createElement(\"video\");\n video.src = url;\n video.onloadedmetadata = () => {\n resolve({\n path: url,\n duration,\n width: video.videoWidth,\n height: video.videoHeight,\n fileSize: blob.size,\n mimeType: this.mediaRecorder?.mimeType || \"video/webm\",\n });\n };\n video.onerror = () => {\n resolve({\n path: url,\n duration,\n width: 0,\n height: 0,\n fileSize: blob.size,\n mimeType: this.mediaRecorder?.mimeType || \"video/webm\",\n });\n };\n this.notifyListeners(\"recordingState\", {\n isRecording: false,\n duration,\n fileSize: blob.size,\n });\n };\n this.mediaRecorder.stop();\n });\n }\n async pauseRecording() {\n if (!this.isRecording || !this.mediaRecorder) {\n throw new Error(\"Not recording\");\n }\n if (this.isPaused) {\n return;\n }\n this.mediaRecorder.pause();\n this.isPaused = true;\n this.pauseStartTime = Date.now();\n const duration = (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000;\n const fileSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);\n this.notifyListeners(\"recordingState\", {\n isRecording: true,\n duration,\n fileSize,\n });\n }\n async resumeRecording() {\n if (!this.isRecording || !this.mediaRecorder) {\n throw new Error(\"Not recording\");\n }\n if (!this.isPaused) {\n return;\n }\n this.pausedDuration += Date.now() - this.pauseStartTime;\n this.mediaRecorder.resume();\n this.isPaused = false;\n }\n async getRecordingState() {\n const duration = this.isRecording\n ? (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000\n : 0;\n const fileSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);\n return {\n isRecording: this.isRecording,\n duration,\n fileSize,\n };\n }\n /**\n * Check screen capture permissions.\n *\n * LIMITATION: The Screen Capture API (getDisplayMedia) does not support permission queries.\n * Unlike camera/microphone, there's no way to check if permission was previously granted.\n * Each call to getDisplayMedia always prompts the user.\n *\n * `screenCapture` will be:\n * - \"not_supported\": getDisplayMedia API not available\n * - \"prompt\": API available, but actual permission state is unknown (always requires prompt)\n */\n async checkPermissions() {\n let microphone = \"prompt\";\n try {\n const result = await navigator.permissions.query({\n name: \"microphone\",\n });\n microphone = result.state;\n }\n catch {\n // Permissions API may not support microphone query in this browser\n }\n // Screen capture permission cannot be queried - getDisplayMedia always prompts\n const screenCaptureStatus = hasDisplayMedia() ? \"prompt\" : \"not_supported\";\n return { screenCapture: screenCaptureStatus, microphone };\n }\n /**\n * Request screen capture permissions.\n *\n * LIMITATION: Screen capture (getDisplayMedia) cannot be pre-requested.\n * The user is prompted only when an actual capture is initiated.\n * This method only requests microphone permission for audio capture during recording.\n *\n * `screenCapture` will be:\n * - \"not_supported\": getDisplayMedia API not available\n * - \"prompt\": API available (permission prompt happens during actual capture)\n */\n async requestPermissions() {\n let microphone = \"denied\";\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((t) => {\n t.stop();\n });\n microphone = \"granted\";\n }\n catch {\n microphone = \"denied\";\n }\n // Cannot pre-request screen capture permission - it requires user gesture + actual capture\n const screenCaptureStatus = hasDisplayMedia() ? \"prompt\" : \"not_supported\";\n return { screenCapture: screenCaptureStatus, microphone };\n }\n async addListener(eventName, listenerFunc) {\n const entry = { eventName, callback: listenerFunc };\n this.pluginListeners.push(entry);\n return {\n remove: async () => {\n const i = this.pluginListeners.indexOf(entry);\n if (i >= 0)\n this.pluginListeners.splice(i, 1);\n },\n };\n }\n async removeAllListeners() {\n this.pluginListeners = [];\n }\n notifyListeners(eventName, data) {\n this.pluginListeners\n .filter((l) => l.eventName === eventName)\n .forEach((l) => {\n l.callback(data);\n });\n }\n}\n"],"names":["registerPlugin","WebPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\nexport * from \"./definitions\";\nconst loadWeb = () => import(\"./web\").then((m) => new m.ScreenCaptureWeb());\nexport const ScreenCapture = registerPlugin(\"ScreenCapture\", {\n web: loadWeb,\n});\n","import { WebPlugin } from \"@capacitor/core\";\nconst VIDEO_MIME_TYPES = [\n \"video/webm;codecs=vp9,opus\",\n \"video/webm;codecs=vp8,opus\",\n \"video/webm\",\n \"video/mp4\",\n];\nconst getSupportedMimeType = () => typeof MediaRecorder === \"undefined\"\n ? null\n : (VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null);\nconst hasDisplayMedia = () => !!navigator.mediaDevices\n ?.getDisplayMedia;\nfunction assertPositiveFiniteNumber(value, label) {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new Error(`${label} must be a positive finite number`);\n }\n return value;\n}\nfunction assertQuality(value) {\n if (value === undefined)\n return 1;\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new Error(\"quality must be a finite number between 0 and 100\");\n }\n if (value < 0 || value > 100) {\n throw new Error(\"quality must be between 0 and 100\");\n }\n return value / 100;\n}\nconst getDisplayMedia = (opts) => navigator.mediaDevices.getDisplayMedia(opts);\nexport class ScreenCaptureWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.mediaStream = null;\n this.mediaRecorder = null;\n this.recordedChunks = [];\n this.isRecording = false;\n this.isPaused = false;\n this.recordingStartTime = 0;\n this.pausedDuration = 0;\n this.pauseStartTime = 0;\n this.recordingStateInterval = null;\n this.pluginListeners = [];\n }\n async isSupported() {\n const supported = hasDisplayMedia();\n const features = [];\n if (supported)\n features.push(\"screenshot\", \"recording\");\n if (typeof MediaRecorder !== \"undefined\")\n features.push(\"video_encoding\");\n if (typeof AudioContext !== \"undefined\")\n features.push(\"system_audio\");\n return { supported, features };\n }\n async captureScreenshot(options) {\n const format = options?.format || \"png\";\n const quality = assertQuality(options?.quality);\n const scale = options?.scale === undefined\n ? 1\n : assertPositiveFiniteNumber(options.scale, \"scale\");\n // PERMISSIONS_MIGRATION: getDisplayMedia() triggers the OS screen\n // recording / picker dialog implicitly. New flow probes via\n // `screenRecordingProber` in\n // `packages/agent/src/services/permissions/probers/screen-recording.ts`\n // before opening the stream. Will be retired by the chat-surface\n // migration agent.\n const stream = await getDisplayMedia({\n video: { displaySurface: \"monitor\" },\n audio: false,\n });\n const track = stream.getVideoTracks()[0];\n const settings = track.getSettings();\n const width = (settings.width || 1920) * scale;\n const height = (settings.height || 1080) * scale;\n let bitmap = null;\n try {\n const imageCapture = new ImageCapture(track);\n bitmap = await imageCapture.grabFrame();\n }\n finally {\n stream.getTracks().forEach((t) => {\n t.stop();\n });\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Failed to get canvas context\");\n }\n ctx.drawImage(bitmap, 0, 0, width, height);\n bitmap.close();\n const mimeType = format === \"png\"\n ? \"image/png\"\n : format === \"webp\"\n ? \"image/webp\"\n : \"image/jpeg\";\n const dataUrl = canvas.toDataURL(mimeType, quality);\n const base64 = dataUrl.split(\",\")[1];\n return {\n base64,\n format,\n width,\n height,\n timestamp: Date.now(),\n };\n }\n async startRecording(options) {\n if (this.isRecording)\n throw new Error(\"Recording already in progress\");\n if (options?.fps !== undefined) {\n assertPositiveFiniteNumber(options.fps, \"fps\");\n }\n if (options?.bitrate !== undefined) {\n assertPositiveFiniteNumber(options.bitrate, \"bitrate\");\n }\n if (options?.maxDuration !== undefined) {\n assertPositiveFiniteNumber(options.maxDuration, \"maxDuration\");\n }\n if (options?.maxFileSize !== undefined) {\n assertPositiveFiniteNumber(options.maxFileSize, \"maxFileSize\");\n }\n const videoConstraints = {\n displaySurface: \"monitor\",\n };\n if (options?.fps)\n videoConstraints.frameRate = { ideal: options.fps };\n this.mediaStream = await getDisplayMedia({\n video: videoConstraints,\n audio: options?.captureSystemAudio !== false,\n });\n if (options?.captureMicrophone) {\n const micStream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n });\n micStream.getAudioTracks().forEach((t) => {\n this.mediaStream?.addTrack(t);\n });\n }\n const mimeType = getSupportedMimeType();\n if (!mimeType) {\n this.mediaStream.getTracks().forEach((t) => {\n t.stop();\n });\n throw new Error(\"No supported video mime type found\");\n }\n const recorderOptions = { mimeType };\n if (options?.bitrate)\n recorderOptions.videoBitsPerSecond = options.bitrate;\n this.recordedChunks = [];\n this.mediaRecorder = new MediaRecorder(this.mediaStream, recorderOptions);\n this.mediaRecorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n this.recordedChunks.push(event.data);\n }\n };\n this.mediaRecorder.onerror = (event) => {\n this.notifyListeners(\"error\", {\n code: \"RECORDING_ERROR\",\n message: `Recording error: ${event.message || \"Unknown error\"}`,\n });\n };\n this.mediaStream.getVideoTracks()[0].addEventListener(\"ended\", () => {\n if (this.isRecording) {\n this.stopRecording().catch((err) => {\n console.error(\"[ScreenCapture] Auto-stop on track end failed:\", err);\n });\n }\n });\n this.recordingStartTime = Date.now();\n this.pausedDuration = 0;\n this.isRecording = true;\n this.isPaused = false;\n this.mediaRecorder.start(1000);\n this.notifyListeners(\"recordingState\", {\n isRecording: true,\n duration: 0,\n fileSize: 0,\n });\n let autoStopping = false;\n this.recordingStateInterval = setInterval(() => {\n if (!this.isRecording || this.isPaused || autoStopping)\n return;\n const duration = (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000;\n const fileSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);\n this.notifyListeners(\"recordingState\", {\n isRecording: true,\n duration,\n fileSize,\n });\n const overLimit = (options?.maxDuration && duration >= options.maxDuration) ||\n (options?.maxFileSize && fileSize >= options.maxFileSize);\n if (overLimit) {\n autoStopping = true;\n this.stopRecording().catch((err) => {\n console.error(\"[ScreenCapture] Auto-stop recording failed:\", err);\n });\n }\n }, 500);\n }\n async stopRecording() {\n if (!this.isRecording || !this.mediaRecorder) {\n throw new Error(\"Not recording\");\n }\n return new Promise((resolve, reject) => {\n if (!this.mediaRecorder) {\n reject(new Error(\"MediaRecorder not initialized\"));\n return;\n }\n const duration = (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000;\n this.mediaRecorder.onstop = () => {\n if (this.recordingStateInterval) {\n clearInterval(this.recordingStateInterval);\n this.recordingStateInterval = null;\n }\n this.isRecording = false;\n this.isPaused = false;\n if (this.mediaStream) {\n this.mediaStream.getTracks().forEach((track) => {\n track.stop();\n });\n this.mediaStream = null;\n }\n const blob = new Blob(this.recordedChunks, {\n type: this.mediaRecorder?.mimeType || \"video/webm\",\n });\n const url = URL.createObjectURL(blob);\n const video = document.createElement(\"video\");\n video.src = url;\n video.onloadedmetadata = () => {\n resolve({\n path: url,\n duration,\n width: video.videoWidth,\n height: video.videoHeight,\n fileSize: blob.size,\n mimeType: this.mediaRecorder?.mimeType || \"video/webm\",\n });\n };\n video.onerror = () => {\n resolve({\n path: url,\n duration,\n width: 0,\n height: 0,\n fileSize: blob.size,\n mimeType: this.mediaRecorder?.mimeType || \"video/webm\",\n });\n };\n this.notifyListeners(\"recordingState\", {\n isRecording: false,\n duration,\n fileSize: blob.size,\n });\n };\n this.mediaRecorder.stop();\n });\n }\n async pauseRecording() {\n if (!this.isRecording || !this.mediaRecorder) {\n throw new Error(\"Not recording\");\n }\n if (this.isPaused) {\n return;\n }\n this.mediaRecorder.pause();\n this.isPaused = true;\n this.pauseStartTime = Date.now();\n const duration = (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000;\n const fileSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);\n this.notifyListeners(\"recordingState\", {\n isRecording: true,\n duration,\n fileSize,\n });\n }\n async resumeRecording() {\n if (!this.isRecording || !this.mediaRecorder) {\n throw new Error(\"Not recording\");\n }\n if (!this.isPaused) {\n return;\n }\n this.pausedDuration += Date.now() - this.pauseStartTime;\n this.mediaRecorder.resume();\n this.isPaused = false;\n }\n async getRecordingState() {\n const duration = this.isRecording\n ? (Date.now() - this.recordingStartTime - this.pausedDuration) / 1000\n : 0;\n const fileSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);\n return {\n isRecording: this.isRecording,\n duration,\n fileSize,\n };\n }\n /**\n * Check screen capture permissions.\n *\n * LIMITATION: The Screen Capture API (getDisplayMedia) does not support permission queries.\n * Unlike camera/microphone, there's no way to check if permission was previously granted.\n * Each call to getDisplayMedia always prompts the user.\n *\n * `screenCapture` will be:\n * - \"not_supported\": getDisplayMedia API not available\n * - \"prompt\": API available, but actual permission state is unknown (always requires prompt)\n */\n async checkPermissions() {\n let microphone = \"prompt\";\n try {\n const result = await navigator.permissions.query({\n name: \"microphone\",\n });\n microphone = result.state;\n }\n catch {\n // Permissions API may not support microphone query in this browser\n }\n // Screen capture permission cannot be queried - getDisplayMedia always prompts\n const screenCaptureStatus = hasDisplayMedia() ? \"prompt\" : \"not_supported\";\n return { screenCapture: screenCaptureStatus, microphone };\n }\n /**\n * Request screen capture permissions.\n *\n * LIMITATION: Screen capture (getDisplayMedia) cannot be pre-requested.\n * The user is prompted only when an actual capture is initiated.\n * This method only requests microphone permission for audio capture during recording.\n *\n * `screenCapture` will be:\n * - \"not_supported\": getDisplayMedia API not available\n * - \"prompt\": API available (permission prompt happens during actual capture)\n */\n async requestPermissions() {\n let microphone = \"denied\";\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach((t) => {\n t.stop();\n });\n microphone = \"granted\";\n }\n catch {\n microphone = \"denied\";\n }\n // Cannot pre-request screen capture permission - it requires user gesture + actual capture\n const screenCaptureStatus = hasDisplayMedia() ? \"prompt\" : \"not_supported\";\n return { screenCapture: screenCaptureStatus, microphone };\n }\n async addListener(eventName, listenerFunc) {\n const entry = { eventName, callback: listenerFunc };\n this.pluginListeners.push(entry);\n return {\n remove: async () => {\n const i = this.pluginListeners.indexOf(entry);\n if (i >= 0)\n this.pluginListeners.splice(i, 1);\n },\n };\n }\n async removeAllListeners() {\n this.pluginListeners = [];\n }\n notifyListeners(eventName, data) {\n this.pluginListeners\n .filter((l) => l.eventName === eventName)\n .forEach((l) => {\n l.callback(data);\n });\n }\n}\n"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AAEA,MAAM,OAAO,GAAG,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;AAC/D,MAAC,aAAa,GAAGA,mBAAc,CAAC,eAAe,EAAE;AAC7D,IAAI,GAAG,EAAE,OAAO;AAChB,CAAC;;ACJD,MAAM,gBAAgB,GAAG;AACzB,IAAI,4BAA4B;AAChC,IAAI,4BAA4B;AAChC,IAAI,YAAY;AAChB,IAAI,WAAW;AACf,CAAC;AACD,MAAM,oBAAoB,GAAG,MAAM,OAAO,aAAa,KAAK;AAC5D,MAAM;AACN,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC9E,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,SAAS,CAAC;AAC1C,MAAM,eAAe;AACrB,SAAS,0BAA0B,CAAC,KAAK,EAAE,KAAK,EAAE;AAClD,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE;AAC5E,QAAQ,MAAM,IAAI,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,iCAAiC,CAAC,CAAC;AACpE,IAAI;AACJ,IAAI,OAAO,KAAK;AAChB;AACA,SAAS,aAAa,CAAC,KAAK,EAAE;AAC9B,IAAI,IAAI,KAAK,KAAK,SAAS;AAC3B,QAAQ,OAAO,CAAC;AAChB,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AAC9D,QAAQ,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC;AAC5E,IAAI;AACJ,IAAI,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,EAAE;AAClC,QAAQ,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC;AAC5D,IAAI;AACJ,IAAI,OAAO,KAAK,GAAG,GAAG;AACtB;AACA,MAAM,eAAe,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC;AACvE,MAAM,gBAAgB,SAASC,cAAS,CAAC;AAChD,IAAI,WAAW,GAAG;AAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;AAC3B,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI;AAC/B,QAAQ,IAAI,CAAC,aAAa,GAAG,IAAI;AACjC,QAAQ,IAAI,CAAC,cAAc,GAAG,EAAE;AAChC,QAAQ,IAAI,CAAC,WAAW,GAAG,KAAK;AAChC,QAAQ,IAAI,CAAC,QAAQ,GAAG,KAAK;AAC7B,QAAQ,IAAI,CAAC,kBAAkB,GAAG,CAAC;AACnC,QAAQ,IAAI,CAAC,cAAc,GAAG,CAAC;AAC/B,QAAQ,IAAI,CAAC,cAAc,GAAG,CAAC;AAC/B,QAAQ,IAAI,CAAC,sBAAsB,GAAG,IAAI;AAC1C,QAAQ,IAAI,CAAC,eAAe,GAAG,EAAE;AACjC,IAAI;AACJ,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,MAAM,SAAS,GAAG,eAAe,EAAE;AAC3C,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B,QAAQ,IAAI,SAAS;AACrB,YAAY,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;AACpD,QAAQ,IAAI,OAAO,aAAa,KAAK,WAAW;AAChD,YAAY,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC;AAC3C,QAAQ,IAAI,OAAO,YAAY,KAAK,WAAW;AAC/C,YAAY,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC;AACzC,QAAQ,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE;AACtC,IAAI;AACJ,IAAI,MAAM,iBAAiB,CAAC,OAAO,EAAE;AACrC,QAAQ,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,KAAK;AAC/C,QAAQ,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC;AACvD,QAAQ,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,KAAK;AACzC,cAAc;AACd,cAAc,0BAA0B,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;AAChE;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;AAC7C,YAAY,KAAK,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE;AAChD,YAAY,KAAK,EAAE,KAAK;AACxB,SAAS,CAAC;AACV,QAAQ,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;AAChD,QAAQ,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE;AAC5C,QAAQ,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK;AACtD,QAAQ,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI,IAAI,KAAK;AACxD,QAAQ,IAAI,MAAM,GAAG,IAAI;AACzB,QAAQ,IAAI;AACZ,YAAY,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC;AACxD,YAAY,MAAM,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE;AACnD,QAAQ;AACR,gBAAgB;AAChB,YAAY,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AAC9C,gBAAgB,CAAC,CAAC,IAAI,EAAE;AACxB,YAAY,CAAC,CAAC;AACd,QAAQ;AACR,QAAQ,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AACvD,QAAQ,MAAM,CAAC,KAAK,GAAG,KAAK;AAC5B,QAAQ,MAAM,CAAC,MAAM,GAAG,MAAM;AAC9B,QAAQ,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;AAC3C,QAAQ,IAAI,CAAC,GAAG,EAAE;AAClB,YAAY,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;AAC3D,QAAQ;AACR,QAAQ,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AAClD,QAAQ,MAAM,CAAC,KAAK,EAAE;AACtB,QAAQ,MAAM,QAAQ,GAAG,MAAM,KAAK;AACpC,cAAc;AACd,cAAc,MAAM,KAAK;AACzB,kBAAkB;AAClB,kBAAkB,YAAY;AAC9B,QAAQ,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC;AAC3D,QAAQ,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5C,QAAQ,OAAO;AACf,YAAY,MAAM;AAClB,YAAY,MAAM;AAClB,YAAY,KAAK;AACjB,YAAY,MAAM;AAClB,YAAY,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;AACjC,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,cAAc,CAAC,OAAO,EAAE;AAClC,QAAQ,IAAI,IAAI,CAAC,WAAW;AAC5B,YAAY,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;AAC5D,QAAQ,IAAI,OAAO,EAAE,GAAG,KAAK,SAAS,EAAE;AACxC,YAAY,0BAA0B,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC;AAC1D,QAAQ;AACR,QAAQ,IAAI,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE;AAC5C,YAAY,0BAA0B,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC;AAClE,QAAQ;AACR,QAAQ,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,EAAE;AAChD,YAAY,0BAA0B,CAAC,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC;AAC1E,QAAQ;AACR,QAAQ,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,EAAE;AAChD,YAAY,0BAA0B,CAAC,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC;AAC1E,QAAQ;AACR,QAAQ,MAAM,gBAAgB,GAAG;AACjC,YAAY,cAAc,EAAE,SAAS;AACrC,SAAS;AACT,QAAQ,IAAI,OAAO,EAAE,GAAG;AACxB,YAAY,gBAAgB,CAAC,SAAS,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE;AAC/D,QAAQ,IAAI,CAAC,WAAW,GAAG,MAAM,eAAe,CAAC;AACjD,YAAY,KAAK,EAAE,gBAAgB;AACnC,YAAY,KAAK,EAAE,OAAO,EAAE,kBAAkB,KAAK,KAAK;AACxD,SAAS,CAAC;AACV,QAAQ,IAAI,OAAO,EAAE,iBAAiB,EAAE;AACxC,YAAY,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC;AACxE,gBAAgB,KAAK,EAAE,IAAI;AAC3B,aAAa,CAAC;AACd,YAAY,SAAS,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AACtD,gBAAgB,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC7C,YAAY,CAAC,CAAC;AACd,QAAQ;AACR,QAAQ,MAAM,QAAQ,GAAG,oBAAoB,EAAE;AAC/C,QAAQ,IAAI,CAAC,QAAQ,EAAE;AACvB,YAAY,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AACxD,gBAAgB,CAAC,CAAC,IAAI,EAAE;AACxB,YAAY,CAAC,CAAC;AACd,YAAY,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC;AACjE,QAAQ;AACR,QAAQ,MAAM,eAAe,GAAG,EAAE,QAAQ,EAAE;AAC5C,QAAQ,IAAI,OAAO,EAAE,OAAO;AAC5B,YAAY,eAAe,CAAC,kBAAkB,GAAG,OAAO,CAAC,OAAO;AAChE,QAAQ,IAAI,CAAC,cAAc,GAAG,EAAE;AAChC,QAAQ,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC;AACjF,QAAQ,IAAI,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,KAAK,KAAK;AACxD,YAAY,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE;AACrC,gBAAgB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AACpD,YAAY;AACZ,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,aAAa,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK;AAChD,YAAY,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE;AAC1C,gBAAgB,IAAI,EAAE,iBAAiB;AACvC,gBAAgB,OAAO,EAAE,CAAC,iBAAiB,EAAE,KAAK,CAAC,OAAO,IAAI,eAAe,CAAC,CAAC;AAC/E,aAAa,CAAC;AACd,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM;AAC7E,YAAY,IAAI,IAAI,CAAC,WAAW,EAAE;AAClC,gBAAgB,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK;AACpD,oBAAoB,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,GAAG,CAAC;AACxF,gBAAgB,CAAC,CAAC;AAClB,YAAY;AACZ,QAAQ,CAAC,CAAC;AACV,QAAQ,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE;AAC5C,QAAQ,IAAI,CAAC,cAAc,GAAG,CAAC;AAC/B,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI;AAC/B,QAAQ,IAAI,CAAC,QAAQ,GAAG,KAAK;AAC7B,QAAQ,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC;AACtC,QAAQ,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE;AAC/C,YAAY,WAAW,EAAE,IAAI;AAC7B,YAAY,QAAQ,EAAE,CAAC;AACvB,YAAY,QAAQ,EAAE,CAAC;AACvB,SAAS,CAAC;AACV,QAAQ,IAAI,YAAY,GAAG,KAAK;AAChC,QAAQ,IAAI,CAAC,sBAAsB,GAAG,WAAW,CAAC,MAAM;AACxD,YAAY,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,IAAI,YAAY;AAClE,gBAAgB;AAChB,YAAY,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI;AAChG,YAAY,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAC5F,YAAY,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE;AACnD,gBAAgB,WAAW,EAAE,IAAI;AACjC,gBAAgB,QAAQ;AACxB,gBAAgB,QAAQ;AACxB,aAAa,CAAC;AACd,YAAY,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,QAAQ,IAAI,OAAO,CAAC,WAAW;AACtF,iBAAiB,OAAO,EAAE,WAAW,IAAI,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;AACzE,YAAY,IAAI,SAAS,EAAE;AAC3B,gBAAgB,YAAY,GAAG,IAAI;AACnC,gBAAgB,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK;AACpD,oBAAoB,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,GAAG,CAAC;AACrF,gBAAgB,CAAC,CAAC;AAClB,YAAY;AACZ,QAAQ,CAAC,EAAE,GAAG,CAAC;AACf,IAAI;AACJ,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACtD,YAAY,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC;AAC5C,QAAQ;AACR,QAAQ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK;AAChD,YAAY,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACrC,gBAAgB,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;AAClE,gBAAgB;AAChB,YAAY;AACZ,YAAY,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI;AAChG,YAAY,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,MAAM;AAC9C,gBAAgB,IAAI,IAAI,CAAC,sBAAsB,EAAE;AACjD,oBAAoB,aAAa,CAAC,IAAI,CAAC,sBAAsB,CAAC;AAC9D,oBAAoB,IAAI,CAAC,sBAAsB,GAAG,IAAI;AACtD,gBAAgB;AAChB,gBAAgB,IAAI,CAAC,WAAW,GAAG,KAAK;AACxC,gBAAgB,IAAI,CAAC,QAAQ,GAAG,KAAK;AACrC,gBAAgB,IAAI,IAAI,CAAC,WAAW,EAAE;AACtC,oBAAoB,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK;AACpE,wBAAwB,KAAK,CAAC,IAAI,EAAE;AACpC,oBAAoB,CAAC,CAAC;AACtB,oBAAoB,IAAI,CAAC,WAAW,GAAG,IAAI;AAC3C,gBAAgB;AAChB,gBAAgB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;AAC3D,oBAAoB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,YAAY;AACtE,iBAAiB,CAAC;AAClB,gBAAgB,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;AACrD,gBAAgB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;AAC7D,gBAAgB,KAAK,CAAC,GAAG,GAAG,GAAG;AAC/B,gBAAgB,KAAK,CAAC,gBAAgB,GAAG,MAAM;AAC/C,oBAAoB,OAAO,CAAC;AAC5B,wBAAwB,IAAI,EAAE,GAAG;AACjC,wBAAwB,QAAQ;AAChC,wBAAwB,KAAK,EAAE,KAAK,CAAC,UAAU;AAC/C,wBAAwB,MAAM,EAAE,KAAK,CAAC,WAAW;AACjD,wBAAwB,QAAQ,EAAE,IAAI,CAAC,IAAI;AAC3C,wBAAwB,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,YAAY;AAC9E,qBAAqB,CAAC;AACtB,gBAAgB,CAAC;AACjB,gBAAgB,KAAK,CAAC,OAAO,GAAG,MAAM;AACtC,oBAAoB,OAAO,CAAC;AAC5B,wBAAwB,IAAI,EAAE,GAAG;AACjC,wBAAwB,QAAQ;AAChC,wBAAwB,KAAK,EAAE,CAAC;AAChC,wBAAwB,MAAM,EAAE,CAAC;AACjC,wBAAwB,QAAQ,EAAE,IAAI,CAAC,IAAI;AAC3C,wBAAwB,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,IAAI,YAAY;AAC9E,qBAAqB,CAAC;AACtB,gBAAgB,CAAC;AACjB,gBAAgB,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE;AACvD,oBAAoB,WAAW,EAAE,KAAK;AACtC,oBAAoB,QAAQ;AAC5B,oBAAoB,QAAQ,EAAE,IAAI,CAAC,IAAI;AACvC,iBAAiB,CAAC;AAClB,YAAY,CAAC;AACb,YAAY,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;AACrC,QAAQ,CAAC,CAAC;AACV,IAAI;AACJ,IAAI,MAAM,cAAc,GAAG;AAC3B,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACtD,YAAY,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC;AAC5C,QAAQ;AACR,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE;AAC3B,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AAClC,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI;AAC5B,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE;AACxC,QAAQ,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI;AAC5F,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACxF,QAAQ,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE;AAC/C,YAAY,WAAW,EAAE,IAAI;AAC7B,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,SAAS,CAAC;AACV,IAAI;AACJ,IAAI,MAAM,eAAe,GAAG;AAC5B,QAAQ,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACtD,YAAY,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC;AAC5C,QAAQ;AACR,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAC5B,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc;AAC/D,QAAQ,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;AACnC,QAAQ,IAAI,CAAC,QAAQ,GAAG,KAAK;AAC7B,IAAI;AACJ,IAAI,MAAM,iBAAiB,GAAG;AAC9B,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC;AAC9B,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,cAAc,IAAI;AAC7E,cAAc,CAAC;AACf,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACxF,QAAQ,OAAO;AACf,YAAY,WAAW,EAAE,IAAI,CAAC,WAAW;AACzC,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,SAAS;AACT,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,IAAI,UAAU,GAAG,QAAQ;AACjC,QAAQ,IAAI;AACZ,YAAY,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;AAC7D,gBAAgB,IAAI,EAAE,YAAY;AAClC,aAAa,CAAC;AACd,YAAY,UAAU,GAAG,MAAM,CAAC,KAAK;AACrC,QAAQ;AACR,QAAQ,MAAM;AACd;AACA,QAAQ;AACR;AACA,QAAQ,MAAM,mBAAmB,GAAG,eAAe,EAAE,GAAG,QAAQ,GAAG,eAAe;AAClF,QAAQ,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,UAAU,EAAE;AACjE,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,IAAI,UAAU,GAAG,QAAQ;AACjC,QAAQ,IAAI;AACZ,YAAY,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACrF,YAAY,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK;AAC9C,gBAAgB,CAAC,CAAC,IAAI,EAAE;AACxB,YAAY,CAAC,CAAC;AACd,YAAY,UAAU,GAAG,SAAS;AAClC,QAAQ;AACR,QAAQ,MAAM;AACd,YAAY,UAAU,GAAG,QAAQ;AACjC,QAAQ;AACR;AACA,QAAQ,MAAM,mBAAmB,GAAG,eAAe,EAAE,GAAG,QAAQ,GAAG,eAAe;AAClF,QAAQ,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,UAAU,EAAE;AACjE,IAAI;AACJ,IAAI,MAAM,WAAW,CAAC,SAAS,EAAE,YAAY,EAAE;AAC/C,QAAQ,MAAM,KAAK,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE;AAC3D,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;AACxC,QAAQ,OAAO;AACf,YAAY,MAAM,EAAE,YAAY;AAChC,gBAAgB,MAAM,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC;AAC7D,gBAAgB,IAAI,CAAC,IAAI,CAAC;AAC1B,oBAAoB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AACrD,YAAY,CAAC;AACb,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,IAAI,CAAC,eAAe,GAAG,EAAE;AACjC,IAAI;AACJ,IAAI,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE;AACrC,QAAQ,IAAI,CAAC;AACb,aAAa,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,KAAK,SAAS;AACpD,aAAa,OAAO,CAAC,CAAC,CAAC,KAAK;AAC5B,YAAY,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAC5B,QAAQ,CAAC,CAAC;AACV,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js CHANGED
@@ -12,8 +12,28 @@ var capacitorScreenCapture = (function (exports, core) {
12
12
  "video/webm",
13
13
  "video/mp4",
14
14
  ];
15
- const getSupportedMimeType = () => VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null;
16
- const hasDisplayMedia = () => !!navigator.mediaDevices.getDisplayMedia;
15
+ const getSupportedMimeType = () => typeof MediaRecorder === "undefined"
16
+ ? null
17
+ : (VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null);
18
+ const hasDisplayMedia = () => !!navigator.mediaDevices
19
+ ?.getDisplayMedia;
20
+ function assertPositiveFiniteNumber(value, label) {
21
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
22
+ throw new Error(`${label} must be a positive finite number`);
23
+ }
24
+ return value;
25
+ }
26
+ function assertQuality(value) {
27
+ if (value === undefined)
28
+ return 1;
29
+ if (typeof value !== "number" || !Number.isFinite(value)) {
30
+ throw new Error("quality must be a finite number between 0 and 100");
31
+ }
32
+ if (value < 0 || value > 100) {
33
+ throw new Error("quality must be between 0 and 100");
34
+ }
35
+ return value / 100;
36
+ }
17
37
  const getDisplayMedia = (opts) => navigator.mediaDevices.getDisplayMedia(opts);
18
38
  class ScreenCaptureWeb extends core.WebPlugin {
19
39
  constructor() {
@@ -42,8 +62,10 @@ var capacitorScreenCapture = (function (exports, core) {
42
62
  }
43
63
  async captureScreenshot(options) {
44
64
  const format = options?.format || "png";
45
- const quality = (options?.quality || 100) / 100;
46
- const scale = options?.scale || 1;
65
+ const quality = assertQuality(options?.quality);
66
+ const scale = options?.scale === undefined
67
+ ? 1
68
+ : assertPositiveFiniteNumber(options.scale, "scale");
47
69
  // PERMISSIONS_MIGRATION: getDisplayMedia() triggers the OS screen
48
70
  // recording / picker dialog implicitly. New flow probes via
49
71
  // `screenRecordingProber` in
@@ -58,11 +80,16 @@ var capacitorScreenCapture = (function (exports, core) {
58
80
  const settings = track.getSettings();
59
81
  const width = (settings.width || 1920) * scale;
60
82
  const height = (settings.height || 1080) * scale;
61
- const imageCapture = new ImageCapture(track);
62
- const bitmap = await imageCapture.grabFrame();
63
- stream.getTracks().forEach((t) => {
64
- t.stop();
65
- });
83
+ let bitmap = null;
84
+ try {
85
+ const imageCapture = new ImageCapture(track);
86
+ bitmap = await imageCapture.grabFrame();
87
+ }
88
+ finally {
89
+ stream.getTracks().forEach((t) => {
90
+ t.stop();
91
+ });
92
+ }
66
93
  const canvas = document.createElement("canvas");
67
94
  canvas.width = width;
68
95
  canvas.height = height;
@@ -90,6 +117,18 @@ var capacitorScreenCapture = (function (exports, core) {
90
117
  async startRecording(options) {
91
118
  if (this.isRecording)
92
119
  throw new Error("Recording already in progress");
120
+ if (options?.fps !== undefined) {
121
+ assertPositiveFiniteNumber(options.fps, "fps");
122
+ }
123
+ if (options?.bitrate !== undefined) {
124
+ assertPositiveFiniteNumber(options.bitrate, "bitrate");
125
+ }
126
+ if (options?.maxDuration !== undefined) {
127
+ assertPositiveFiniteNumber(options.maxDuration, "maxDuration");
128
+ }
129
+ if (options?.maxFileSize !== undefined) {
130
+ assertPositiveFiniteNumber(options.maxFileSize, "maxFileSize");
131
+ }
93
132
  const videoConstraints = {
94
133
  displaySurface: "monitor",
95
134
  };