cuoral-ionic 0.0.1

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/src/types.ts ADDED
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Message types for communication between WebView and Native code
3
+ */
4
+ export enum CuoralMessageType {
5
+ // Screen Recording
6
+ START_RECORDING = 'CUORAL_START_RECORDING',
7
+ STOP_RECORDING = 'CUORAL_STOP_RECORDING',
8
+ RECORDING_STARTED = 'CUORAL_RECORDING_STARTED',
9
+ RECORDING_STOPPED = 'CUORAL_RECORDING_STOPPED',
10
+ RECORDING_ERROR = 'CUORAL_RECORDING_ERROR',
11
+
12
+ // Screenshot
13
+ TAKE_SCREENSHOT = 'CUORAL_TAKE_SCREENSHOT',
14
+ SCREENSHOT_TAKEN = 'CUORAL_SCREENSHOT_TAKEN',
15
+ SCREENSHOT_ERROR = 'CUORAL_SCREENSHOT_ERROR',
16
+
17
+ // Widget Communication
18
+ WIDGET_READY = 'CUORAL_WIDGET_READY',
19
+ WIDGET_CLOSED = 'CUORAL_WIDGET_CLOSED',
20
+
21
+ // File Upload
22
+ UPLOAD_FILE = 'CUORAL_UPLOAD_FILE',
23
+ UPLOAD_PROGRESS = 'CUORAL_UPLOAD_PROGRESS',
24
+ UPLOAD_COMPLETE = 'CUORAL_UPLOAD_COMPLETE',
25
+ UPLOAD_ERROR = 'CUORAL_UPLOAD_ERROR',
26
+ }
27
+
28
+ /**
29
+ * Base message structure
30
+ */
31
+ export interface CuoralMessage {
32
+ type: CuoralMessageType;
33
+ payload?: any;
34
+ timestamp?: number;
35
+ }
36
+
37
+ /**
38
+ * Recording state
39
+ */
40
+ export interface RecordingState {
41
+ isRecording: boolean;
42
+ duration?: number;
43
+ filePath?: string;
44
+ error?: string;
45
+ }
46
+
47
+ /**
48
+ * Screenshot data
49
+ */
50
+ export interface ScreenshotData {
51
+ base64: string;
52
+ mimeType: string;
53
+ width: number;
54
+ height: number;
55
+ }
56
+
57
+ /**
58
+ * Upload progress data
59
+ */
60
+ export interface UploadProgress {
61
+ loaded: number;
62
+ total: number;
63
+ percentage: number;
64
+ }
65
+
66
+ /**
67
+ * Plugin configuration
68
+ */
69
+ export interface CuoralConfig {
70
+ /**
71
+ * Widget URL to load
72
+ */
73
+ widgetUrl: string;
74
+
75
+ /**
76
+ * Enable debug logging
77
+ */
78
+ debug?: boolean;
79
+
80
+ /**
81
+ * Custom message handler
82
+ */
83
+ onMessage?: (message: CuoralMessage) => void;
84
+
85
+ /**
86
+ * Recording quality (0.0 - 1.0)
87
+ */
88
+ recordingQuality?: number;
89
+
90
+ /**
91
+ * Screenshot quality (0.0 - 1.0)
92
+ */
93
+ screenshotQuality?: number;
94
+ }
95
+
96
+ /**
97
+ * Recording options
98
+ */
99
+ export interface RecordingOptions {
100
+ /**
101
+ * Video quality (0.0 - 1.0)
102
+ */
103
+ quality?: number;
104
+
105
+ /**
106
+ * Include audio
107
+ */
108
+ includeAudio?: boolean;
109
+
110
+ /**
111
+ * Maximum duration in seconds
112
+ */
113
+ maxDuration?: number;
114
+ }
115
+
116
+ /**
117
+ * Screenshot options
118
+ */
119
+ export interface ScreenshotOptions {
120
+ /**
121
+ * Image quality (0.0 - 1.0)
122
+ */
123
+ quality?: number;
124
+
125
+ /**
126
+ * Image format
127
+ */
128
+ format?: 'png' | 'jpeg';
129
+ }
package/src/web.ts ADDED
@@ -0,0 +1,135 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import { CuoralPluginInterface } from './plugin';
3
+ import {
4
+ RecordingOptions,
5
+ RecordingState,
6
+ ScreenshotOptions,
7
+ ScreenshotData,
8
+ } from './types';
9
+
10
+ /**
11
+ * Web implementation (for testing in browser)
12
+ */
13
+ export class CuoralPluginWeb extends WebPlugin implements CuoralPluginInterface {
14
+ private isRecording = false;
15
+ private recordingStartTime?: number;
16
+
17
+ async startRecording(options?: RecordingOptions): Promise<{ success: boolean }> {
18
+ console.log('[Cuoral Web] Start recording', options);
19
+
20
+ // Check if Screen Capture API is available
21
+ if (!navigator.mediaDevices || !navigator.mediaDevices.getDisplayMedia) {
22
+ throw new Error('Screen recording is not supported in this browser');
23
+ }
24
+
25
+ try {
26
+ // Request screen capture
27
+ const stream = await navigator.mediaDevices.getDisplayMedia({
28
+ video: true,
29
+ audio: options?.includeAudio || false,
30
+ });
31
+
32
+ this.isRecording = true;
33
+ this.recordingStartTime = Date.now();
34
+
35
+ // Store stream for later stopping
36
+ (window as any).__cuoralRecordingStream = stream;
37
+
38
+ return { success: true };
39
+ } catch (error) {
40
+ console.error('[Cuoral Web] Failed to start recording:', error);
41
+ return { success: false };
42
+ }
43
+ }
44
+
45
+ async stopRecording(): Promise<{ success: boolean; filePath?: string; duration?: number }> {
46
+ console.log('[Cuoral Web] Stop recording');
47
+
48
+ if (!this.isRecording) {
49
+ return { success: false };
50
+ }
51
+
52
+ const stream = (window as any).__cuoralRecordingStream as MediaStream;
53
+ if (stream) {
54
+ stream.getTracks().forEach(track => track.stop());
55
+ delete (window as any).__cuoralRecordingStream;
56
+ }
57
+
58
+ const duration = this.recordingStartTime
59
+ ? Math.floor((Date.now() - this.recordingStartTime) / 1000)
60
+ : 0;
61
+
62
+ this.isRecording = false;
63
+ this.recordingStartTime = undefined;
64
+
65
+ return {
66
+ success: true,
67
+ duration,
68
+ filePath: 'web-recording-not-saved',
69
+ };
70
+ }
71
+
72
+ async getRecordingState(): Promise<RecordingState> {
73
+ return {
74
+ isRecording: this.isRecording,
75
+ duration: this.recordingStartTime
76
+ ? Math.floor((Date.now() - this.recordingStartTime) / 1000)
77
+ : undefined,
78
+ };
79
+ }
80
+
81
+ async takeScreenshot(options?: ScreenshotOptions): Promise<ScreenshotData> {
82
+ console.log('[Cuoral Web] Take screenshot', options);
83
+
84
+ try {
85
+ // Use Screen Capture API
86
+ const stream = await navigator.mediaDevices.getDisplayMedia({
87
+ video: { width: 1920, height: 1080 },
88
+ });
89
+
90
+ // Capture frame from video stream
91
+ const video = document.createElement('video');
92
+ video.srcObject = stream;
93
+ video.play();
94
+
95
+ await new Promise(resolve => {
96
+ video.onloadedmetadata = resolve;
97
+ });
98
+
99
+ const canvas = document.createElement('canvas');
100
+ canvas.width = video.videoWidth;
101
+ canvas.height = video.videoHeight;
102
+
103
+ const ctx = canvas.getContext('2d');
104
+ ctx?.drawImage(video, 0, 0);
105
+
106
+ // Stop stream
107
+ stream.getTracks().forEach(track => track.stop());
108
+
109
+ // Convert to base64
110
+ const format = options?.format || 'png';
111
+ const quality = options?.quality || 0.92;
112
+ const base64 = canvas.toDataURL(`image/${format}`, quality);
113
+
114
+ return {
115
+ base64: base64.split(',')[1],
116
+ mimeType: `image/${format}`,
117
+ width: canvas.width,
118
+ height: canvas.height,
119
+ };
120
+ } catch (error) {
121
+ console.error('[Cuoral Web] Failed to take screenshot:', error);
122
+ throw error;
123
+ }
124
+ }
125
+
126
+ async isRecordingSupported(): Promise<{ supported: boolean }> {
127
+ const supported = !!(navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia);
128
+ return { supported };
129
+ }
130
+
131
+ async requestPermissions(): Promise<{ granted: boolean }> {
132
+ // Web doesn't require explicit permissions - they're requested on demand
133
+ return { granted: true };
134
+ }
135
+ }