cuoral-ionic 0.0.7 → 0.0.9

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.
Files changed (44) hide show
  1. package/CuoralIonic.podspec +17 -0
  2. package/README.md +22 -0
  3. package/android/build/.transforms/bb54161301273cf9b5b94a21c0fb3f23/transformed/classes/classes_dex/classes.dex +0 -0
  4. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$4.dex +0 -0
  5. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$5.dex +0 -0
  6. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$6.dex +0 -0
  7. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin.dex +0 -0
  8. package/android/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
  9. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$4.class +0 -0
  10. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$5.class +0 -0
  11. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$6.class +0 -0
  12. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin.class +0 -0
  13. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$4.class +0 -0
  14. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$5.class +0 -0
  15. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$6.class +0 -0
  16. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin.class +0 -0
  17. package/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
  18. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/{CuoralPlugin$1.class.uniqueId1 → CuoralPlugin$1.class.uniqueId2} +0 -0
  19. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/{CuoralPlugin$2.class.uniqueId2 → CuoralPlugin$2.class.uniqueId5} +0 -0
  20. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$3.class.uniqueId3 +0 -0
  21. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$4.class.uniqueId6 +0 -0
  22. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$5.class.uniqueId4 +0 -0
  23. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$6.class.uniqueId8 +0 -0
  24. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$InitiateCallback.class.uniqueId0 +0 -0
  25. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$UploadCallback.class.uniqueId7 +0 -0
  26. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin.class.uniqueId1 +0 -0
  27. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  28. package/android/src/main/java/com/cuoral/ionic/CuoralPlugin.java +38 -35
  29. package/dist/bridge.d.ts.map +1 -1
  30. package/dist/cuoral.d.ts.map +1 -1
  31. package/dist/cuoral.js +31 -6
  32. package/dist/index.esm.js +75 -43
  33. package/dist/index.esm.js.map +1 -1
  34. package/dist/index.js +75 -43
  35. package/dist/index.js.map +1 -1
  36. package/dist/plugin.d.ts +2 -2
  37. package/dist/plugin.d.ts.map +1 -1
  38. package/dist/plugin.js +43 -39
  39. package/ios/Plugin/CuoralPlugin.swift +3 -3
  40. package/package.json +3 -2
  41. package/src/bridge.ts +1 -0
  42. package/src/cuoral.ts +33 -6
  43. package/src/plugin.ts +43 -38
  44. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin.class.uniqueId0 +0 -0
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ class CuoralRecorder {
65
65
  /**
66
66
  * Start recording with automatic permission handling
67
67
  */
68
- async startRecording(options) {
68
+ async startRecording(options, sendMessages = true) {
69
69
  try {
70
70
  // Check if already recording
71
71
  if (this.isRecording) {
@@ -87,20 +87,24 @@ class CuoralRecorder {
87
87
  if (result.success) {
88
88
  this.isRecording = true;
89
89
  this.recordingStartTime = Date.now();
90
- // Post message to widget
91
- this.postMessage({
92
- type: exports.CuoralMessageType.RECORDING_STARTED,
93
- payload: { timestamp: this.recordingStartTime },
94
- });
90
+ // Post message to widget only if enabled (disabled when called from widget handler)
91
+ if (sendMessages) {
92
+ this.postMessage({
93
+ type: exports.CuoralMessageType.RECORDING_STARTED,
94
+ payload: { timestamp: this.recordingStartTime },
95
+ });
96
+ }
95
97
  }
96
98
  else {
97
99
  // Recording failed - reset state and notify widget
98
100
  this.isRecording = false;
99
101
  this.recordingStartTime = undefined;
100
- this.postMessage({
101
- type: exports.CuoralMessageType.RECORDING_ERROR,
102
- payload: { error: 'Failed to start recording' },
103
- });
102
+ if (sendMessages) {
103
+ this.postMessage({
104
+ type: exports.CuoralMessageType.RECORDING_ERROR,
105
+ payload: { error: 'Failed to start recording' },
106
+ });
107
+ }
104
108
  }
105
109
  return result.success;
106
110
  }
@@ -108,24 +112,28 @@ class CuoralRecorder {
108
112
  // Exception occurred - reset state and notify widget
109
113
  this.isRecording = false;
110
114
  this.recordingStartTime = undefined;
111
- this.postMessage({
112
- type: exports.CuoralMessageType.RECORDING_ERROR,
113
- payload: { error: error.message },
114
- });
115
+ if (sendMessages) {
116
+ this.postMessage({
117
+ type: exports.CuoralMessageType.RECORDING_ERROR,
118
+ payload: { error: error.message },
119
+ });
120
+ }
115
121
  return false;
116
122
  }
117
123
  }
118
124
  /**
119
125
  * Stop recording
120
126
  */
121
- async stopRecording(options) {
127
+ async stopRecording(options, sendMessages = true) {
122
128
  try {
123
129
  if (!this.isRecording) {
124
130
  // Send error message to widget so it can exit "stopping" state
125
- this.postMessage({
126
- type: exports.CuoralMessageType.RECORDING_ERROR,
127
- payload: { error: 'Not recording' },
128
- });
131
+ if (sendMessages) {
132
+ this.postMessage({
133
+ type: exports.CuoralMessageType.RECORDING_ERROR,
134
+ payload: { error: 'Not recording' },
135
+ });
136
+ }
129
137
  return null;
130
138
  }
131
139
  const result = await CuoralPlugin$1.stopRecording(options);
@@ -134,23 +142,15 @@ class CuoralRecorder {
134
142
  const duration = this.recordingStartTime
135
143
  ? Math.floor((Date.now() - this.recordingStartTime) / 1000)
136
144
  : 0;
137
- // If uploaded, notify widget differently
138
- if (result.uploaded) {
139
- this.postMessage({
140
- type: exports.CuoralMessageType.RECORDING_UPLOADED,
141
- payload: {
142
- duration: result.duration || duration,
143
- uploaded: true
144
- },
145
- });
146
- }
147
- else {
148
- // Post message to widget (old behavior)
145
+ // Send RECORDING_STOPPED message only if enabled
146
+ if (sendMessages) {
149
147
  this.postMessage({
150
148
  type: exports.CuoralMessageType.RECORDING_STOPPED,
151
149
  payload: {
152
150
  filePath: result.filePath,
153
151
  duration: result.duration || duration,
152
+ uploaded: result.uploaded,
153
+ uploadedToBackend: result.uploaded,
154
154
  },
155
155
  });
156
156
  }
@@ -161,18 +161,22 @@ class CuoralRecorder {
161
161
  };
162
162
  }
163
163
  // If result.success is false, send error to widget
164
- this.postMessage({
165
- type: exports.CuoralMessageType.RECORDING_ERROR,
166
- payload: { error: 'Failed to stop recording' },
167
- });
164
+ if (sendMessages) {
165
+ this.postMessage({
166
+ type: exports.CuoralMessageType.RECORDING_ERROR,
167
+ payload: { error: 'Failed to stop recording' },
168
+ });
169
+ }
168
170
  return null;
169
171
  }
170
172
  catch (error) {
171
173
  console.error('[Cuoral] Failed to stop recording:', error);
172
- this.postMessage({
173
- type: exports.CuoralMessageType.RECORDING_ERROR,
174
- payload: { error: error.message },
175
- });
174
+ if (sendMessages) {
175
+ this.postMessage({
176
+ type: exports.CuoralMessageType.RECORDING_ERROR,
177
+ payload: { error: error.message },
178
+ });
179
+ }
176
180
  return null;
177
181
  }
178
182
  }
@@ -1451,6 +1455,7 @@ class CuoralIntelligence {
1451
1455
  */
1452
1456
  class Cuoral {
1453
1457
  constructor(options) {
1458
+ console.log('[Cuoral] Constructor called with options:', options);
1454
1459
  // Check if running on a mobile platform
1455
1460
  if (!core.Capacitor.isNativePlatform()) {
1456
1461
  throw new Error('Cuoral Ionic library only works on native mobile platforms (iOS/Android). Web is not supported.');
@@ -1460,6 +1465,7 @@ class Cuoral {
1460
1465
  useModal: true,
1461
1466
  ...options
1462
1467
  };
1468
+ console.log('[Cuoral] Merged options:', this.options);
1463
1469
  // Determine widget base URL
1464
1470
  const baseUrl = options.widgetBaseUrl || Cuoral.PRODUCTION_WIDGET_URL;
1465
1471
  const params = new URLSearchParams({
@@ -1489,8 +1495,14 @@ class Cuoral {
1489
1495
  debug: options.debug || false
1490
1496
  });
1491
1497
  this.recorder = new CuoralRecorder();
1498
+ // Expose bridge on window for widget detection and debugging
1499
+ window.CuoralCapacitorBridge = true;
1500
+ window.__cuoralBridge = this.bridge; // For debugging
1501
+ window.__cuoralRecorder = this.recorder; // For debugging
1502
+ console.log('[Cuoral] Bridge and recorder created, exposed on window');
1492
1503
  // Setup automatic message handlers
1493
1504
  this.setupMessageHandlers();
1505
+ console.log('[Cuoral] Constructor complete');
1494
1506
  }
1495
1507
  /**
1496
1508
  * Initialize Cuoral
@@ -1885,25 +1897,45 @@ class Cuoral {
1885
1897
  setupMessageHandlers() {
1886
1898
  // Handle start recording requests from widget
1887
1899
  this.bridge.on(exports.CuoralMessageType.START_RECORDING, async () => {
1888
- await this.recorder.startRecording();
1900
+ // Pass sendMessages: false to prevent duplicate messages
1901
+ const success = await this.recorder.startRecording(undefined, false);
1902
+ if (success) {
1903
+ // Send RECORDING_STARTED back to widget
1904
+ this.bridge.sendToWidget({
1905
+ type: exports.CuoralMessageType.RECORDING_STARTED,
1906
+ payload: {
1907
+ timestamp: Date.now()
1908
+ }
1909
+ });
1910
+ }
1911
+ else {
1912
+ this.bridge.sendToWidget({
1913
+ type: exports.CuoralMessageType.RECORDING_ERROR,
1914
+ payload: {
1915
+ error: 'Failed to start recording'
1916
+ }
1917
+ });
1918
+ }
1889
1919
  });
1890
1920
  // Handle stop recording requests from widget
1891
1921
  this.bridge.on(exports.CuoralMessageType.STOP_RECORDING, async () => {
1892
1922
  const sessionId = localStorage.getItem('__x_loadID');
1893
1923
  const customerId = localStorage.getItem('cuoralCustomerId');
1924
+ // Pass sendMessages: false to prevent duplicate messages
1894
1925
  const result = await this.recorder.stopRecording({
1895
1926
  autoUpload: true,
1896
1927
  sessionId: sessionId || undefined,
1897
1928
  publicKey: this.options.publicKey,
1898
1929
  customerId: customerId || undefined,
1899
- });
1930
+ }, false);
1900
1931
  if (result && result.uploaded) {
1901
- // Video was automatically uploaded, just notify widget
1932
+ // Video was automatically uploaded, notify widget with RECORDING_STOPPED
1902
1933
  this.bridge.sendToWidget({
1903
- type: exports.CuoralMessageType.RECORDING_UPLOADED,
1934
+ type: exports.CuoralMessageType.RECORDING_STOPPED,
1904
1935
  payload: {
1905
1936
  duration: result.duration,
1906
1937
  uploaded: true,
1938
+ uploadedToBackend: true,
1907
1939
  timestamp: Date.now()
1908
1940
  }
1909
1941
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/plugin.d.ts CHANGED
@@ -59,7 +59,7 @@ export declare class CuoralRecorder {
59
59
  /**
60
60
  * Start recording with automatic permission handling
61
61
  */
62
- startRecording(options?: RecordingOptions): Promise<boolean>;
62
+ startRecording(options?: RecordingOptions, sendMessages?: boolean): Promise<boolean>;
63
63
  /**
64
64
  * Stop recording
65
65
  */
@@ -68,7 +68,7 @@ export declare class CuoralRecorder {
68
68
  sessionId?: string;
69
69
  publicKey?: string;
70
70
  customerId?: string;
71
- }): Promise<{
71
+ }, sendMessages?: boolean): Promise<{
72
72
  filePath?: string;
73
73
  duration?: number;
74
74
  uploaded?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAE1E;;OAEG;IACH,aAAa,CAAC,OAAO,CAAC,EAAE;QACtB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IAEH;;OAEG;IACH,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAE7C;;OAEG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAErE;;OAEG;IACH,oBAAoB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAExD;;OAEG;IACH,kBAAkB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,QAAA,MAAM,YAAY,uBAAwD,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAEpC;;OAEG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAyDlE;;OAEG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE;QAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IA6DhF;;OAEG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqBjF;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAIzC;;OAEG;IACH,OAAO,CAAC,WAAW;CAKpB"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAE1E;;OAEG;IACH,aAAa,CAAC,OAAO,CAAC,EAAE;QACtB,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IAEH;;OAEG;IACH,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC;IAE7C;;OAEG;IACH,cAAc,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAErE;;OAEG;IACH,oBAAoB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAExD;;OAEG;IACH,kBAAkB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,QAAA,MAAM,YAAY,uBAAwD,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAEpC;;OAEG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IA+DhG;;OAEG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE;QAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,EAAE,YAAY,GAAE,OAAc,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IA4D9G;;OAEG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqBjF;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;IAIzC;;OAEG;IACH,OAAO,CAAC,WAAW;CAKpB"}
package/dist/plugin.js CHANGED
@@ -15,7 +15,7 @@ export class CuoralRecorder {
15
15
  /**
16
16
  * Start recording with automatic permission handling
17
17
  */
18
- async startRecording(options) {
18
+ async startRecording(options, sendMessages = true) {
19
19
  try {
20
20
  // Check if already recording
21
21
  if (this.isRecording) {
@@ -37,20 +37,24 @@ export class CuoralRecorder {
37
37
  if (result.success) {
38
38
  this.isRecording = true;
39
39
  this.recordingStartTime = Date.now();
40
- // Post message to widget
41
- this.postMessage({
42
- type: CuoralMessageType.RECORDING_STARTED,
43
- payload: { timestamp: this.recordingStartTime },
44
- });
40
+ // Post message to widget only if enabled (disabled when called from widget handler)
41
+ if (sendMessages) {
42
+ this.postMessage({
43
+ type: CuoralMessageType.RECORDING_STARTED,
44
+ payload: { timestamp: this.recordingStartTime },
45
+ });
46
+ }
45
47
  }
46
48
  else {
47
49
  // Recording failed - reset state and notify widget
48
50
  this.isRecording = false;
49
51
  this.recordingStartTime = undefined;
50
- this.postMessage({
51
- type: CuoralMessageType.RECORDING_ERROR,
52
- payload: { error: 'Failed to start recording' },
53
- });
52
+ if (sendMessages) {
53
+ this.postMessage({
54
+ type: CuoralMessageType.RECORDING_ERROR,
55
+ payload: { error: 'Failed to start recording' },
56
+ });
57
+ }
54
58
  }
55
59
  return result.success;
56
60
  }
@@ -58,24 +62,28 @@ export class CuoralRecorder {
58
62
  // Exception occurred - reset state and notify widget
59
63
  this.isRecording = false;
60
64
  this.recordingStartTime = undefined;
61
- this.postMessage({
62
- type: CuoralMessageType.RECORDING_ERROR,
63
- payload: { error: error.message },
64
- });
65
+ if (sendMessages) {
66
+ this.postMessage({
67
+ type: CuoralMessageType.RECORDING_ERROR,
68
+ payload: { error: error.message },
69
+ });
70
+ }
65
71
  return false;
66
72
  }
67
73
  }
68
74
  /**
69
75
  * Stop recording
70
76
  */
71
- async stopRecording(options) {
77
+ async stopRecording(options, sendMessages = true) {
72
78
  try {
73
79
  if (!this.isRecording) {
74
80
  // Send error message to widget so it can exit "stopping" state
75
- this.postMessage({
76
- type: CuoralMessageType.RECORDING_ERROR,
77
- payload: { error: 'Not recording' },
78
- });
81
+ if (sendMessages) {
82
+ this.postMessage({
83
+ type: CuoralMessageType.RECORDING_ERROR,
84
+ payload: { error: 'Not recording' },
85
+ });
86
+ }
79
87
  return null;
80
88
  }
81
89
  const result = await CuoralPlugin.stopRecording(options);
@@ -84,23 +92,15 @@ export class CuoralRecorder {
84
92
  const duration = this.recordingStartTime
85
93
  ? Math.floor((Date.now() - this.recordingStartTime) / 1000)
86
94
  : 0;
87
- // If uploaded, notify widget differently
88
- if (result.uploaded) {
89
- this.postMessage({
90
- type: CuoralMessageType.RECORDING_UPLOADED,
91
- payload: {
92
- duration: result.duration || duration,
93
- uploaded: true
94
- },
95
- });
96
- }
97
- else {
98
- // Post message to widget (old behavior)
95
+ // Send RECORDING_STOPPED message only if enabled
96
+ if (sendMessages) {
99
97
  this.postMessage({
100
98
  type: CuoralMessageType.RECORDING_STOPPED,
101
99
  payload: {
102
100
  filePath: result.filePath,
103
101
  duration: result.duration || duration,
102
+ uploaded: result.uploaded,
103
+ uploadedToBackend: result.uploaded,
104
104
  },
105
105
  });
106
106
  }
@@ -111,18 +111,22 @@ export class CuoralRecorder {
111
111
  };
112
112
  }
113
113
  // If result.success is false, send error to widget
114
- this.postMessage({
115
- type: CuoralMessageType.RECORDING_ERROR,
116
- payload: { error: 'Failed to stop recording' },
117
- });
114
+ if (sendMessages) {
115
+ this.postMessage({
116
+ type: CuoralMessageType.RECORDING_ERROR,
117
+ payload: { error: 'Failed to stop recording' },
118
+ });
119
+ }
118
120
  return null;
119
121
  }
120
122
  catch (error) {
121
123
  console.error('[Cuoral] Failed to stop recording:', error);
122
- this.postMessage({
123
- type: CuoralMessageType.RECORDING_ERROR,
124
- payload: { error: error.message },
125
- });
124
+ if (sendMessages) {
125
+ this.postMessage({
126
+ type: CuoralMessageType.RECORDING_ERROR,
127
+ payload: { error: error.message },
128
+ });
129
+ }
126
130
  return null;
127
131
  }
128
132
  }
@@ -110,10 +110,10 @@ public class CuoralPlugin: CAPPlugin {
110
110
  do {
111
111
  assetWriter = try AVAssetWriter(url: outputURL, fileType: .mp4)
112
112
 
113
- // Reduced quality settings to prevent huge file sizes
114
- // 2.5 Mbps bitrate = ~18MB per minute (down from ~600MB per minute)
113
+ // Optimized quality settings for screen recordings
114
+ // 1.5 Mbps bitrate = ~11MB per minute (~54MB for 5 min)
115
115
  let compressionProperties: [String: Any] = [
116
- AVVideoAverageBitRateKey: 2_500_000, // 2.5 Mbps
116
+ AVVideoAverageBitRateKey: 1_500_000, // 1.5 Mbps
117
117
  AVVideoMaxKeyFrameIntervalKey: 30,
118
118
  AVVideoProfileLevelKey: AVVideoProfileLevelH264BaselineAutoLevel
119
119
  ]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cuoral-ionic",
3
- "version": "0.0.7",
4
- "description": "Cuoral Ionic Framework Library - Proactive customer success platform with support ticketing, customer intelligence, screen recording, and engagement tools",
3
+ "version": "0.0.9",
4
+ "description": "Cuoral Ionic Framework Library - silent churn prevention platform for Ionic apps. Provides screen recording, user interaction capture, and support widget integration for enhanced customer support experiences.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.esm.js",
@@ -12,6 +12,7 @@
12
12
  "assets",
13
13
  "ios",
14
14
  "android",
15
+ "CuoralIonic.podspec",
15
16
  "README.md"
16
17
  ],
17
18
  "scripts": {
package/src/bridge.ts CHANGED
@@ -129,6 +129,7 @@ export class CuoralBridge {
129
129
  window.addEventListener('message', (event: MessageEvent) => {
130
130
  // Only process messages FROM the iframe
131
131
  const widgetFrame = document.querySelector('iframe[src*="mobile.html"]') as HTMLIFrameElement;
132
+
132
133
  if (widgetFrame && event.source === widgetFrame.contentWindow) {
133
134
  this.widgetIframe = widgetFrame;
134
135
  } else if (widgetFrame) {
package/src/cuoral.ts CHANGED
@@ -42,6 +42,8 @@ export class Cuoral {
42
42
  private static readonly DEV_WIDGET_URL = 'assets/mobile.html';
43
43
 
44
44
  constructor(options: CuoralOptions) {
45
+ console.log('[Cuoral] Constructor called with options:', options);
46
+
45
47
  // Check if running on a mobile platform
46
48
  if (!Capacitor.isNativePlatform()) {
47
49
  throw new Error('Cuoral Ionic library only works on native mobile platforms (iOS/Android). Web is not supported.');
@@ -53,6 +55,8 @@ export class Cuoral {
53
55
  ...options
54
56
  };
55
57
 
58
+ console.log('[Cuoral] Merged options:', this.options);
59
+
56
60
  // Determine widget base URL
57
61
  const baseUrl = options.widgetBaseUrl || Cuoral.PRODUCTION_WIDGET_URL;
58
62
  const params = new URLSearchParams({
@@ -86,8 +90,15 @@ export class Cuoral {
86
90
 
87
91
  this.recorder = new CuoralRecorder();
88
92
 
93
+ // Expose bridge on window for widget detection and debugging
94
+ (window as any).CuoralCapacitorBridge = true;
95
+ (window as any).__cuoralBridge = this.bridge; // For debugging
96
+ (window as any).__cuoralRecorder = this.recorder; // For debugging
97
+ console.log('[Cuoral] Bridge and recorder created, exposed on window');
98
+
89
99
  // Setup automatic message handlers
90
100
  this.setupMessageHandlers();
101
+ console.log('[Cuoral] Constructor complete');
91
102
  }
92
103
 
93
104
  /**
@@ -530,9 +541,23 @@ export class Cuoral {
530
541
  private setupMessageHandlers(): void {
531
542
  // Handle start recording requests from widget
532
543
  this.bridge.on(CuoralMessageType.START_RECORDING, async () => {
533
- const success = await this.recorder.startRecording();
534
- if (!success) {
535
- // Error already handled by recorder
544
+ // Pass sendMessages: false to prevent duplicate messages
545
+ const success = await this.recorder.startRecording(undefined, false);
546
+ if (success) {
547
+ // Send RECORDING_STARTED back to widget
548
+ this.bridge.sendToWidget({
549
+ type: CuoralMessageType.RECORDING_STARTED,
550
+ payload: {
551
+ timestamp: Date.now()
552
+ }
553
+ });
554
+ } else {
555
+ this.bridge.sendToWidget({
556
+ type: CuoralMessageType.RECORDING_ERROR,
557
+ payload: {
558
+ error: 'Failed to start recording'
559
+ }
560
+ });
536
561
  }
537
562
  });
538
563
 
@@ -541,20 +566,22 @@ export class Cuoral {
541
566
  const sessionId = localStorage.getItem('__x_loadID');
542
567
  const customerId = localStorage.getItem('cuoralCustomerId');
543
568
 
569
+ // Pass sendMessages: false to prevent duplicate messages
544
570
  const result = await this.recorder.stopRecording({
545
571
  autoUpload: true,
546
572
  sessionId: sessionId || undefined,
547
573
  publicKey: this.options.publicKey,
548
574
  customerId: customerId || undefined,
549
- });
575
+ }, false);
550
576
 
551
577
  if (result && result.uploaded) {
552
- // Video was automatically uploaded, just notify widget
578
+ // Video was automatically uploaded, notify widget with RECORDING_STOPPED
553
579
  this.bridge.sendToWidget({
554
- type: CuoralMessageType.RECORDING_UPLOADED,
580
+ type: CuoralMessageType.RECORDING_STOPPED,
555
581
  payload: {
556
582
  duration: result.duration,
557
583
  uploaded: true,
584
+ uploadedToBackend: true,
558
585
  timestamp: Date.now()
559
586
  }
560
587
  });