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

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaw Walters and elizaOS Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # @elizaos/capacitor-screencapture
2
+
3
+ Cross-platform screen capture Capacitor plugin for elizaOS. Captures screenshots and records the screen on browser (Web API), iOS (ReplayKit + AVFoundation), and Android (MediaProjection).
4
+
5
+ ## What it does
6
+
7
+ - **Screenshot:** Captures a single frame of the screen as a base64-encoded PNG, JPEG, or WebP image.
8
+ - **Screen recording:** Records the screen to a video file (WebM on browser, MP4 on native), with optional audio from the system, microphone, or both.
9
+ - **Pause / resume:** Pause and resume an active recording without creating a new file (Android requires API 24+).
10
+ - **Permission checks:** Query and request screen-capture and microphone permissions in a unified cross-platform API.
11
+ - **Live events:** Subscribe to `recordingState` and `error` events emitted during recording.
12
+
13
+ ## Platform support
14
+
15
+ | Feature | Browser | iOS | Android |
16
+ |---------|---------|-----|---------|
17
+ | Screenshot | Yes (getDisplayMedia) | Yes (UIKit) | Yes (MediaProjection) |
18
+ | Screen recording | Yes (MediaRecorder) | Yes (ReplayKit) | Yes (MediaRecorder) |
19
+ | Pause/resume | Yes | Yes | API 24+ only |
20
+ | System audio | Browser-dependent | Yes (RPSampleBufferType.audioApp) | No (microphone only) |
21
+ | Microphone audio | Yes | Yes | Yes |
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @elizaos/capacitor-screencapture
27
+ npx cap sync
28
+ ```
29
+
30
+ For iOS, add to your app's `Info.plist`:
31
+ ```xml
32
+ <key>NSMicrophoneUsageDescription</key>
33
+ <string>Microphone is used to capture audio during screen recording.</string>
34
+ ```
35
+
36
+ For Android 14+ (API 34), declare in `AndroidManifest.xml`:
37
+ ```xml
38
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
39
+ ```
40
+ This is in addition to the `FOREGROUND_SERVICE` permission that this plugin's own `AndroidManifest.xml` already declares.
41
+
42
+ ## Usage
43
+
44
+ ```typescript
45
+ import { ScreenCapture } from '@elizaos/capacitor-screencapture';
46
+
47
+ // Check support
48
+ const { supported, features } = await ScreenCapture.isSupported();
49
+
50
+ // Take a screenshot
51
+ const shot = await ScreenCapture.captureScreenshot({ format: 'png', quality: 100 });
52
+ // shot.base64 contains the image data
53
+
54
+ // Record the screen
55
+ await ScreenCapture.startRecording({
56
+ quality: 'high', // 'low' | 'medium' | 'high' | 'highest'
57
+ fps: 30,
58
+ captureSystemAudio: true,
59
+ captureMicrophone: false,
60
+ maxDuration: 300, // seconds; undefined = unlimited
61
+ });
62
+
63
+ // Listen for state updates
64
+ const handle = await ScreenCapture.addListener('recordingState', (state) => {
65
+ console.log(`Recording: ${state.isRecording}, duration: ${state.duration}s`);
66
+ });
67
+
68
+ // Stop and get the result
69
+ const result = await ScreenCapture.stopRecording();
70
+ // result.path — blob: URL (browser) or filesystem path (native)
71
+ // result.mimeType — video/webm (browser) or video/mp4 (native)
72
+
73
+ await handle.remove();
74
+ ```
75
+
76
+ ## Permissions
77
+
78
+ Screen capture permission works differently per platform:
79
+
80
+ - **Browser:** `getDisplayMedia` always shows an OS-level picker dialog. There is no way to pre-grant or query this permission. `checkPermissions()` returns `"prompt"` when the API is available.
81
+ - **iOS:** Screenshots use UIKit only — no permission required. `startRecording` uses ReplayKit, which shows a system broadcast picker on first use.
82
+ - **Android:** `captureScreenshot` and `startRecording` both trigger a `MediaProjection` consent dialog. Microphone permission (`RECORD_AUDIO`) is requested at runtime when `captureMicrophone: true`.
83
+
84
+ ```typescript
85
+ // Check permissions
86
+ const status = await ScreenCapture.checkPermissions();
87
+ // status.screenCapture: 'granted' | 'denied' | 'prompt' | 'not_supported'
88
+ // status.microphone: 'granted' | 'denied' | 'prompt'
89
+
90
+ // Request microphone permission before recording with audio
91
+ await ScreenCapture.requestPermissions();
92
+ ```
93
+
94
+ ## Output formats
95
+
96
+ | Platform | Screenshot | Recording |
97
+ |----------|-----------|-----------|
98
+ | Browser | PNG / JPEG / WebP | video/webm (VP9 preferred), blob: URL |
99
+ | iOS | PNG / JPEG / WebP (WebP requires iOS 14+) | video/mp4 (H.264 + AAC), file:// path |
100
+ | Android | PNG / JPEG / WebP (WebP lossy requires API 30+) | video/mp4 (H.264), file path |
101
+
102
+ ## Recording options
103
+
104
+ | Option | Type | Default | Description |
105
+ |--------|------|---------|-------------|
106
+ | `quality` | `'low' \| 'medium' \| 'high' \| 'highest'` | `'high'` | Quality preset (sets bitrate on iOS; sets fps + bitrate on Android) |
107
+ | `fps` | `number` | 30 | Frames per second (1–60; overrides quality preset) |
108
+ | `bitrate` | `number` | Estimated | Video bitrate in bits/s (overrides quality preset) |
109
+ | `maxDuration` | `number` | unlimited | Stop automatically after N seconds |
110
+ | `maxFileSize` | `number` | unlimited | Stop automatically after N bytes |
111
+ | `captureSystemAudio` | `boolean` | `true` | Include app/system audio (browser + iOS; Android records microphone only) |
112
+ | `captureMicrophone` | `boolean` | `false` | Include microphone audio in recording |
113
+
114
+ ## Building from source
115
+
116
+ ```bash
117
+ bun run --cwd plugins/plugin-native-screencapture build
118
+ ```
119
+
120
+ This runs `tsc` then `rollup` and outputs `dist/esm/`, `dist/plugin.js` (IIFE), and `dist/plugin.cjs.js`.
@@ -7,6 +7,16 @@ ext {
7
7
  }
8
8
 
9
9
  apply plugin: 'com.android.library'
10
+ // Explicitly apply the Kotlin Android plugin. The kotlin-gradle-plugin is on
11
+ // the root buildscript classpath, but without applying it here AGP 8.13 falls
12
+ // back to its "built-in Kotlin" compile path (build/intermediates/
13
+ // built_in_kotlinc), which compiles the .kt sources but does NOT bundle the
14
+ // resulting .class files into the *release* library jar. The app's
15
+ // :app:assembleRelease then links a library AAR with zero plugin classes, so
16
+ // the Capacitor plugin (and any manifest-declared component) is absent from
17
+ // the release dex. Applying the standard Kotlin plugin wires Kotlin
18
+ // compilation into both the debug and release jar-bundling tasks.
19
+ apply plugin: 'org.jetbrains.kotlin.android'
10
20
  android {
11
21
  namespace = "ai.eliza.plugins.screencapture"
12
22
  compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
@@ -25,8 +35,12 @@ android {
25
35
  }
26
36
 
27
37
  compileOptions {
28
- sourceCompatibility JavaVersion.VERSION_17
29
- targetCompatibility JavaVersion.VERSION_17
38
+ sourceCompatibility JavaVersion.VERSION_21
39
+ targetCompatibility JavaVersion.VERSION_21
40
+ }
41
+
42
+ kotlinOptions {
43
+ jvmTarget = "21"
30
44
  }
31
45
 
32
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB,KAAK,sBAAsB,GAAG,oBAAoB,GAAG,uBAAuB,CAAC;AA4B7E,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,sBAAsB,CAA+C;IAC7E,OAAO,CAAC,eAAe,CAGf;IAEF,WAAW,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IASlE,iBAAiB,CACrB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IA0DtB,cAAc,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmG/D,aAAa,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAuE/C,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B/B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAchC,iBAAiB,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAgBxD;;;;;;;;;;OAUG;IACG,gBAAgB,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAiBhE;;;;;;;;;;OAUG;IACG,kBAAkB,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAkB5D,WAAW,CACf,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,GACpD,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAWrC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC,SAAS,CAAC,eAAe,CACvB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,sBAAsB,GAC3B,IAAI;CAOR"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,uBAAuB,EACvB,6BAA6B,EAC7B,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,eAAe,CAAC;AAEvB,KAAK,sBAAsB,GAAG,oBAAoB,GAAG,uBAAuB,CAAC;AAiD7E,qBAAa,gBAAiB,SAAQ,SAAS;IAC7C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,sBAAsB,CAA+C;IAC7E,OAAO,CAAC,eAAe,CAGf;IAEF,WAAW,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IASlE,iBAAiB,CACrB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,gBAAgB,CAAC;IAgEtB,cAAc,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+G/D,aAAa,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAuE/C,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B/B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAchC,iBAAiB,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAgBxD;;;;;;;;;;OAUG;IACG,gBAAgB,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAiBhE;;;;;;;;;;OAUG;IACG,kBAAkB,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAkB5D,WAAW,CACf,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,GACpD,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAWrC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC,SAAS,CAAC,eAAe,CACvB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,sBAAsB,GAC3B,IAAI;CAOR"}
package/dist/esm/web.js CHANGED
@@ -5,8 +5,28 @@ const VIDEO_MIME_TYPES = [
5
5
  "video/webm",
6
6
  "video/mp4",
7
7
  ];
8
- const getSupportedMimeType = () => VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null;
9
- const hasDisplayMedia = () => !!navigator.mediaDevices.getDisplayMedia;
8
+ const getSupportedMimeType = () => typeof MediaRecorder === "undefined"
9
+ ? null
10
+ : (VIDEO_MIME_TYPES.find((m) => MediaRecorder.isTypeSupported(m)) ?? null);
11
+ const hasDisplayMedia = () => !!navigator.mediaDevices
12
+ ?.getDisplayMedia;
13
+ function assertPositiveFiniteNumber(value, label) {
14
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
15
+ throw new Error(`${label} must be a positive finite number`);
16
+ }
17
+ return value;
18
+ }
19
+ function assertQuality(value) {
20
+ if (value === undefined)
21
+ return 1;
22
+ if (typeof value !== "number" || !Number.isFinite(value)) {
23
+ throw new Error("quality must be a finite number between 0 and 100");
24
+ }
25
+ if (value < 0 || value > 100) {
26
+ throw new Error("quality must be between 0 and 100");
27
+ }
28
+ return value / 100;
29
+ }
10
30
  const getDisplayMedia = (opts) => navigator.mediaDevices.getDisplayMedia(opts);
11
31
  export class ScreenCaptureWeb extends WebPlugin {
12
32
  constructor() {
@@ -35,8 +55,10 @@ export class ScreenCaptureWeb extends WebPlugin {
35
55
  }
36
56
  async captureScreenshot(options) {
37
57
  const format = options?.format || "png";
38
- const quality = (options?.quality || 100) / 100;
39
- const scale = options?.scale || 1;
58
+ const quality = assertQuality(options?.quality);
59
+ const scale = options?.scale === undefined
60
+ ? 1
61
+ : assertPositiveFiniteNumber(options.scale, "scale");
40
62
  // PERMISSIONS_MIGRATION: getDisplayMedia() triggers the OS screen
41
63
  // recording / picker dialog implicitly. New flow probes via
42
64
  // `screenRecordingProber` in
@@ -51,11 +73,16 @@ export class ScreenCaptureWeb extends WebPlugin {
51
73
  const settings = track.getSettings();
52
74
  const width = (settings.width || 1920) * scale;
53
75
  const height = (settings.height || 1080) * scale;
54
- const imageCapture = new ImageCapture(track);
55
- const bitmap = await imageCapture.grabFrame();
56
- stream.getTracks().forEach((t) => {
57
- t.stop();
58
- });
76
+ let bitmap = null;
77
+ try {
78
+ const imageCapture = new ImageCapture(track);
79
+ bitmap = await imageCapture.grabFrame();
80
+ }
81
+ finally {
82
+ stream.getTracks().forEach((t) => {
83
+ t.stop();
84
+ });
85
+ }
59
86
  const canvas = document.createElement("canvas");
60
87
  canvas.width = width;
61
88
  canvas.height = height;
@@ -83,6 +110,18 @@ export class ScreenCaptureWeb extends WebPlugin {
83
110
  async startRecording(options) {
84
111
  if (this.isRecording)
85
112
  throw new Error("Recording already in progress");
113
+ if (options?.fps !== undefined) {
114
+ assertPositiveFiniteNumber(options.fps, "fps");
115
+ }
116
+ if (options?.bitrate !== undefined) {
117
+ assertPositiveFiniteNumber(options.bitrate, "bitrate");
118
+ }
119
+ if (options?.maxDuration !== undefined) {
120
+ assertPositiveFiniteNumber(options.maxDuration, "maxDuration");
121
+ }
122
+ if (options?.maxFileSize !== undefined) {
123
+ assertPositiveFiniteNumber(options.maxFileSize, "maxFileSize");
124
+ }
86
125
  const videoConstraints = {
87
126
  displaySurface: "monitor",
88
127
  };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=web.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.test.d.ts","sourceRoot":"","sources":["../../src/web.test.ts"],"names":[],"mappings":""}
@@ -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":"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"}
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
  };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.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.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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/capacitor-screencapture",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.3-beta.2",
4
4
  "description": "Captures screenshots and records the screen across web, mobile, and desktop.",
5
5
  "keywords": [
6
6
  "screen-capture",
@@ -14,6 +14,8 @@
14
14
  "exports": {
15
15
  ".": {
16
16
  "types": "./dist/esm/index.d.ts",
17
+ "bun": "./src/index.ts",
18
+ "development": "./src/index.ts",
17
19
  "import": "./dist/esm/index.js",
18
20
  "require": "./dist/plugin.cjs.js"
19
21
  },
@@ -31,27 +33,25 @@
31
33
  ],
32
34
  "author": "elizaOS",
33
35
  "license": "MIT",
34
- "dependencies": {
35
- "@elizaos/app-core": "2.0.0-beta.1"
36
- },
36
+ "dependencies": {},
37
37
  "repository": {
38
38
  "type": "git",
39
39
  "url": "https://github.com/elizaOS/eliza"
40
40
  },
41
41
  "scripts": {
42
- "build": "bun run clean && tsc && bun --bun rollup -c rollup.config.mjs",
43
- "clean": "node ../../../scripts/rm-path-recursive.mjs dist",
42
+ "build": "node ../../packages/scripts/with-package-build-lock.mjs plugins/plugin-native-screencapture -- bun run build:unlocked",
43
+ "clean": "node ../../packages/scripts/rm-path-recursive.mjs dist",
44
+ "test": "vitest run",
44
45
  "prepublishOnly": "bun run build",
45
- "watch": "tsc --watch"
46
+ "watch": "tsc --watch",
47
+ "build:unlocked": "bun run clean && tsc && bunx rollup -c rollup.config.mjs"
46
48
  },
47
49
  "devDependencies": {
48
- "@capacitor/android": "^8.0.0",
49
50
  "@capacitor/core": "^8.3.1",
50
- "@capacitor/ios": "^8.0.0",
51
51
  "@rollup/plugin-node-resolve": "^16.0.0",
52
- "rimraf": "^6.0.0",
53
52
  "rollup": "^4.60.2",
54
- "typescript": "^6.0.3"
53
+ "typescript": "^6.0.3",
54
+ "vitest": "^4.0.0"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@capacitor/core": "^8.3.1"
@@ -80,5 +80,6 @@
80
80
  "ios": true,
81
81
  "android": true
82
82
  }
83
- }
83
+ },
84
+ "gitHead": "82fe0f44215954c2417328203f5bd6510985c1fc"
84
85
  }