cuoral-ionic 0.0.1 → 0.0.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.
Files changed (85) hide show
  1. package/README.md +40 -4
  2. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  3. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  4. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  5. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  6. package/android/.gradle/8.9/gc.properties +0 -0
  7. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  8. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  9. package/android/.gradle/vcs-1/gc.properties +0 -0
  10. package/android/build/.transforms/2c48e1f34ca03014b78fcb3e0ab7197b/results.bin +1 -0
  11. package/android/build/.transforms/2c48e1f34ca03014b78fcb3e0ab7197b/transformed/classes/classes_dex/classes.dex +0 -0
  12. package/android/build/.transforms/980c51bd075f726f311ad662d5d20ba0/results.bin +1 -0
  13. package/android/build/.transforms/980c51bd075f726f311ad662d5d20ba0/transformed/classes/classes_dex/classes.dex +0 -0
  14. package/android/build/.transforms/bb54161301273cf9b5b94a21c0fb3f23/results.bin +1 -0
  15. package/android/build/.transforms/bb54161301273cf9b5b94a21c0fb3f23/transformed/classes/classes_dex/classes.dex +0 -0
  16. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/results.bin +1 -0
  17. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$1.dex +0 -0
  18. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin$2.dex +0 -0
  19. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/CuoralPlugin.dex +0 -0
  20. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/debug_dex/com/cuoral/ionic/ScreenRecordService.dex +0 -0
  21. package/android/build/.transforms/f1aabffcd8b03aa664e77a79b3e1de5d/transformed/debug/desugar_graph.bin +0 -0
  22. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml +22 -0
  23. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json +18 -0
  24. package/android/build/intermediates/aar_main_jar/debug/classes.jar +0 -0
  25. package/android/build/intermediates/aar_metadata/debug/aar-metadata.properties +6 -0
  26. package/android/build/intermediates/annotation_processor_list/debug/annotationProcessors.json +1 -0
  27. package/android/build/intermediates/annotations_typedef_file/debug/typedefs.txt +0 -0
  28. package/android/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
  29. package/android/build/intermediates/compile_r_class_jar/debug/R.jar +0 -0
  30. package/android/build/intermediates/compile_symbol_list/debug/R.txt +0 -0
  31. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  32. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  33. package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
  34. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  35. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  36. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
  37. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$1.class +0 -0
  38. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin$2.class +0 -0
  39. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/CuoralPlugin.class +0 -0
  40. package/android/build/intermediates/javac/debug/classes/com/cuoral/ionic/ScreenRecordService.class +0 -0
  41. package/android/build/intermediates/local_only_symbol_list/debug/R-def.txt +2 -0
  42. package/android/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt +38 -0
  43. package/android/build/intermediates/merged_java_res/debug/feature-cuoral-ionic.jar +0 -0
  44. package/android/build/intermediates/merged_manifest/debug/AndroidManifest.xml +22 -0
  45. package/android/build/intermediates/navigation_json/debug/navigation.json +1 -0
  46. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$1.class +0 -0
  47. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin$2.class +0 -0
  48. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/CuoralPlugin.class +0 -0
  49. package/android/build/intermediates/runtime_library_classes_dir/debug/com/cuoral/ionic/ScreenRecordService.class +0 -0
  50. package/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
  51. package/android/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt +1 -0
  52. package/android/build/outputs/aar/cuoral-ionic-debug.aar +0 -0
  53. package/android/build/outputs/logs/manifest-merger-debug-report.txt +49 -0
  54. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$1.class.uniqueId1 +0 -0
  55. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin$2.class.uniqueId2 +0 -0
  56. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/CuoralPlugin.class.uniqueId0 +0 -0
  57. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  58. package/android/build.gradle +61 -0
  59. package/android/src/main/AndroidManifest.xml +9 -0
  60. package/android/src/main/java/com/cuoral/ionic/CuoralPlugin.java +290 -33
  61. package/android/src/main/java/com/cuoral/ionic/ScreenRecordService.java +59 -0
  62. package/dist/cuoral.d.ts +30 -1
  63. package/dist/cuoral.d.ts.map +1 -1
  64. package/dist/cuoral.js +168 -1
  65. package/dist/index.d.ts +1 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.esm.js +706 -127
  68. package/dist/index.esm.js.map +1 -1
  69. package/dist/index.js +706 -126
  70. package/dist/index.js.map +1 -1
  71. package/dist/intelligence.d.ts +66 -0
  72. package/dist/intelligence.d.ts.map +1 -0
  73. package/dist/intelligence.js +508 -0
  74. package/dist/plugin.d.ts +1 -1
  75. package/dist/plugin.d.ts.map +1 -1
  76. package/dist/plugin.js +24 -6
  77. package/dist/web.d.ts.map +1 -1
  78. package/dist/web.js +0 -3
  79. package/ios/Plugin/CuoralPlugin.swift +78 -1
  80. package/package.json +1 -1
  81. package/src/cuoral.ts +205 -1
  82. package/src/index.ts +1 -0
  83. package/src/intelligence.ts +609 -0
  84. package/src/plugin.ts +26 -6
  85. package/src/web.ts +0 -6
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,66 @@
1
+ export declare class CuoralIntelligence {
2
+ private config;
3
+ private queues;
4
+ private batchTimers;
5
+ private sessionId;
6
+ private isInitialized;
7
+ private lastPageViewTimestamp;
8
+ private lastPageViewScreen;
9
+ private pendingEvents;
10
+ private originalFetch;
11
+ private originalXMLHttpRequest;
12
+ constructor(sessionId: string);
13
+ /**
14
+ * Initialize intelligence tracking
15
+ */
16
+ init(): void;
17
+ /**
18
+ * Track a page/screen view
19
+ */
20
+ trackPageView(screen: string, metadata?: any): void;
21
+ /**
22
+ * Track a console error manually
23
+ */
24
+ trackError(message: string, stackTrace?: string, metadata?: any): void;
25
+ /**
26
+ * Flush all queued events immediately
27
+ */
28
+ flush(): void;
29
+ /**
30
+ * Destroy and cleanup
31
+ */
32
+ destroy(): void;
33
+ /**
34
+ * Setup console error listener
35
+ */
36
+ private setupConsoleErrorListener;
37
+ /**
38
+ * Setup network monitoring
39
+ */
40
+ private setupNetworkMonitoring;
41
+ /**
42
+ * Setup app state listener
43
+ */
44
+ private setupAppStateListener;
45
+ /**
46
+ * Enqueue an event
47
+ */
48
+ private enqueueEvent;
49
+ /**
50
+ * Flush a specific queue
51
+ */
52
+ private flushQueue;
53
+ /**
54
+ * Send data to backend
55
+ */
56
+ private sendToBackend;
57
+ /**
58
+ * Flush pending events
59
+ */
60
+ private flushPendingEvents;
61
+ /**
62
+ * Setup native error capture for Android/iOS crashes
63
+ */
64
+ private setupNativeErrorCapture;
65
+ }
66
+ //# sourceMappingURL=intelligence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intelligence.d.ts","sourceRoot":"","sources":["../src/intelligence.ts"],"names":[],"mappings":"AAsDA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CASZ;IAEF,OAAO,CAAC,MAAM,CAKZ;IAEF,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,qBAAqB,CAAc;IAC3C,OAAO,CAAC,kBAAkB,CAAM;IAChC,OAAO,CAAC,aAAa,CAAa;IAGlC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,sBAAsB,CAAa;gBAE/B,SAAS,EAAE,MAAM;IAI7B;;OAEG;IACI,IAAI,IAAI,IAAI;IAenB;;OAEG;IACI,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,IAAI;IAc1D;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,IAAI;IAS7E;;OAEG;IACI,KAAK,IAAI,IAAI;IAMpB;;OAEG;IACI,OAAO,IAAI,IAAI;IA4BtB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAoFjC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA8H9B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,OAAO,CAAC,YAAY;IAwCpB;;OAEG;IACH,OAAO,CAAC,UAAU;IAoFlB;;OAEG;YACW,aAAa;IAiC3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAgBhC"}
@@ -0,0 +1,508 @@
1
+ import { Capacitor } from '@capacitor/core';
2
+ import { registerPlugin } from '@capacitor/core';
3
+ // Register the Cuoral plugin for native error capture
4
+ const CuoralPlugin = registerPlugin('CuoralPlugin');
5
+ export class CuoralIntelligence {
6
+ constructor(sessionId) {
7
+ this.config = {
8
+ consoleErrorBackendUrl: 'https://api.cuoral.com/customer-intelligence/console-error',
9
+ pageViewBackendUrl: 'https://api.cuoral.com/customer-intelligence/page-view',
10
+ apiResponseBackendUrl: 'https://api.cuoral.com/customer-intelligence/api-response',
11
+ batchSize: 10,
12
+ batchInterval: 2000,
13
+ maxQueueSize: 30,
14
+ retryAttempts: 1,
15
+ retryDelay: 2000,
16
+ };
17
+ this.queues = {
18
+ console_error: [],
19
+ unhandled_error: [],
20
+ page_view: [],
21
+ api_call: [],
22
+ };
23
+ this.batchTimers = {};
24
+ this.sessionId = null;
25
+ this.isInitialized = false;
26
+ this.lastPageViewTimestamp = Date.now();
27
+ this.lastPageViewScreen = '';
28
+ this.pendingEvents = [];
29
+ // Network monitoring state
30
+ this.originalFetch = null;
31
+ this.originalXMLHttpRequest = null;
32
+ this.sessionId = sessionId;
33
+ }
34
+ /**
35
+ * Initialize intelligence tracking
36
+ */
37
+ init() {
38
+ if (this.isInitialized) {
39
+ console.warn('[Cuoral Intelligence] Already initialized');
40
+ return;
41
+ }
42
+ this.setupConsoleErrorListener();
43
+ this.setupNetworkMonitoring();
44
+ this.setupAppStateListener();
45
+ this.setupNativeErrorCapture();
46
+ this.isInitialized = true;
47
+ this.flushPendingEvents();
48
+ }
49
+ /**
50
+ * Track a page/screen view
51
+ */
52
+ trackPageView(screen, metadata) {
53
+ const duration = Date.now() - this.lastPageViewTimestamp;
54
+ this.enqueueEvent('page_view', {
55
+ screen,
56
+ referrer: this.lastPageViewScreen,
57
+ duration,
58
+ metadata: metadata || {},
59
+ });
60
+ this.lastPageViewTimestamp = Date.now();
61
+ this.lastPageViewScreen = screen;
62
+ }
63
+ /**
64
+ * Track a console error manually
65
+ */
66
+ trackError(message, stackTrace, metadata) {
67
+ this.enqueueEvent('console_error', {
68
+ message,
69
+ stack_trace: stackTrace || 'No stack trace available',
70
+ log_level: 'error',
71
+ metadata: metadata || {},
72
+ });
73
+ }
74
+ /**
75
+ * Flush all queued events immediately
76
+ */
77
+ flush() {
78
+ Object.keys(this.queues).forEach((type) => {
79
+ this.flushQueue(type);
80
+ });
81
+ }
82
+ /**
83
+ * Destroy and cleanup
84
+ */
85
+ destroy() {
86
+ // Clear all timers
87
+ Object.keys(this.batchTimers).forEach((type) => {
88
+ if (this.batchTimers[type]) {
89
+ clearTimeout(this.batchTimers[type]);
90
+ delete this.batchTimers[type];
91
+ }
92
+ });
93
+ // Restore original functions
94
+ if (this.originalFetch) {
95
+ window.fetch = this.originalFetch;
96
+ this.originalFetch = null;
97
+ }
98
+ if (this.originalXMLHttpRequest) {
99
+ window.XMLHttpRequest = this.originalXMLHttpRequest;
100
+ this.originalXMLHttpRequest = null;
101
+ }
102
+ // Clear queues
103
+ Object.keys(this.queues).forEach((type) => {
104
+ this.queues[type] = [];
105
+ });
106
+ this.isInitialized = false;
107
+ }
108
+ /**
109
+ * Setup console error listener
110
+ */
111
+ setupConsoleErrorListener() {
112
+ // Override console.error
113
+ const originalConsoleError = console.error;
114
+ console.error = (...args) => {
115
+ originalConsoleError.apply(console, args);
116
+ try {
117
+ // Try to find an Error object in arguments to get real stack trace
118
+ let stack = '';
119
+ let message = '';
120
+ // Check each argument for error information
121
+ for (const arg of args) {
122
+ if (arg instanceof Error) {
123
+ stack = arg.stack || '';
124
+ message = arg.message;
125
+ break;
126
+ }
127
+ else if (arg && typeof arg === 'object') {
128
+ if (arg.stack && typeof arg.stack === 'string') {
129
+ stack = arg.stack;
130
+ message = arg.message || arg.toString();
131
+ break;
132
+ }
133
+ if (arg.rejection && arg.rejection instanceof Error) {
134
+ stack = arg.rejection.stack || '';
135
+ message = arg.rejection.message;
136
+ break;
137
+ }
138
+ if (arg.error instanceof Error) {
139
+ stack = arg.error.stack || '';
140
+ message = arg.error.message;
141
+ break;
142
+ }
143
+ }
144
+ }
145
+ // If no stack found, generate one from current context
146
+ // Note: Angular's ErrorHandler doesn't pass Error objects, so this will
147
+ // capture the console.error call stack, not the original error stack.
148
+ // For better error tracking, use source maps or test with unminified builds.
149
+ if (!stack) {
150
+ const error = new Error();
151
+ stack = error.stack || 'No stack trace available';
152
+ message = args.map((a) => (typeof a === 'object' ? JSON.stringify(a) : String(a))).join(' ');
153
+ }
154
+ this.enqueueEvent('console_error', {
155
+ message: message || 'Console error',
156
+ stack_trace: stack,
157
+ log_level: 'error',
158
+ metadata: {},
159
+ });
160
+ }
161
+ catch (err) {
162
+ // Silently fail
163
+ }
164
+ };
165
+ // Global error handler
166
+ window.onerror = (message, source, lineno, colno, error) => {
167
+ try {
168
+ this.enqueueEvent('unhandled_error', {
169
+ message: String(message),
170
+ source: source || 'unknown',
171
+ lineno: lineno || 0,
172
+ colno: colno || 0,
173
+ stack_trace: error?.stack || 'No stack trace available',
174
+ log_level: 'error',
175
+ });
176
+ }
177
+ catch (err) {
178
+ // Silently fail
179
+ }
180
+ return false;
181
+ };
182
+ // Unhandled promise rejection
183
+ window.addEventListener('unhandledrejection', (event) => {
184
+ this.enqueueEvent('unhandled_error', {
185
+ message: event.reason instanceof Error ? event.reason.message : String(event.reason),
186
+ stack_trace: event.reason?.stack || 'No stack trace available',
187
+ log_level: 'error',
188
+ });
189
+ });
190
+ }
191
+ /**
192
+ * Setup network monitoring
193
+ */
194
+ setupNetworkMonitoring() {
195
+ // Store original fetch
196
+ if (!this.originalFetch) {
197
+ this.originalFetch = window.fetch;
198
+ }
199
+ // Override fetch
200
+ window.fetch = async (...args) => {
201
+ const url = args[0] instanceof Request ? args[0].url : args[0];
202
+ const method = args[0] instanceof Request && args[0].method
203
+ ? args[0].method
204
+ : args[1]?.method || 'GET';
205
+ const startTime = Date.now();
206
+ try {
207
+ const response = await this.originalFetch.apply(window, args);
208
+ const duration = Date.now() - startTime;
209
+ const status = response.status;
210
+ // Only track errors (4xx, 5xx)
211
+ if (status >= 400) {
212
+ const responseClone = response.clone();
213
+ try {
214
+ const text = await responseClone.text();
215
+ let responseData = null;
216
+ try {
217
+ const truncated = text.length > 5000 ? text.substring(0, 5000) + '...' : text;
218
+ responseData = JSON.parse(truncated);
219
+ }
220
+ catch (e) {
221
+ responseData = text.length > 5000 ? text.substring(0, 5000) + '...' : text;
222
+ }
223
+ this.enqueueEvent('api_call', {
224
+ method,
225
+ url,
226
+ status_code: status,
227
+ response_data: responseData,
228
+ duration,
229
+ });
230
+ }
231
+ catch (err) {
232
+ this.enqueueEvent('api_call', {
233
+ method,
234
+ url,
235
+ status_code: status,
236
+ duration,
237
+ error: 'Failed to read response body',
238
+ });
239
+ }
240
+ }
241
+ return response;
242
+ }
243
+ catch (error) {
244
+ const duration = Date.now() - startTime;
245
+ this.enqueueEvent('api_call', {
246
+ method,
247
+ url,
248
+ status_code: 0,
249
+ response_data: error.message || 'Network Error',
250
+ duration,
251
+ error: error.message || 'Network Error',
252
+ });
253
+ throw error;
254
+ }
255
+ };
256
+ // Store original XMLHttpRequest
257
+ if (!this.originalXMLHttpRequest && window.XMLHttpRequest) {
258
+ this.originalXMLHttpRequest = window.XMLHttpRequest;
259
+ }
260
+ // Override XMLHttpRequest
261
+ const originalOpen = XMLHttpRequest.prototype.open;
262
+ const originalSend = XMLHttpRequest.prototype.send;
263
+ XMLHttpRequest.prototype.open = function (method, url) {
264
+ this._cuoralMethod = method;
265
+ this._cuoralUrl = url;
266
+ return originalOpen.apply(this, arguments);
267
+ };
268
+ XMLHttpRequest.prototype.send = function () {
269
+ const startTime = Date.now();
270
+ const xhr = this;
271
+ const loadendHandler = () => {
272
+ try {
273
+ const status = xhr.status;
274
+ const duration = Date.now() - startTime;
275
+ // Only track errors (4xx, 5xx)
276
+ if (status >= 400) {
277
+ let responseData = null;
278
+ try {
279
+ const responseText = xhr.responseText || '';
280
+ const truncated = responseText.length > 5000
281
+ ? responseText.substring(0, 5000) + '...'
282
+ : responseText;
283
+ responseData = truncated ? JSON.parse(truncated) : truncated;
284
+ }
285
+ catch (e) {
286
+ const responseText = xhr.responseText || '';
287
+ responseData = responseText.length > 5000
288
+ ? responseText.substring(0, 5000) + '...'
289
+ : responseText;
290
+ }
291
+ window._cuoralIntelligence?.enqueueEvent('api_call', {
292
+ method: xhr._cuoralMethod,
293
+ url: xhr._cuoralUrl,
294
+ status_code: status,
295
+ response_data: responseData,
296
+ duration,
297
+ });
298
+ }
299
+ }
300
+ catch (err) {
301
+ // Silently fail
302
+ }
303
+ };
304
+ this.addEventListener('loadend', loadendHandler, { once: true });
305
+ return originalSend.apply(this, arguments);
306
+ };
307
+ // Store reference for XMLHttpRequest monitoring
308
+ window._cuoralIntelligence = this;
309
+ }
310
+ /**
311
+ * Setup app state listener
312
+ */
313
+ setupAppStateListener() {
314
+ // Listen for app going to background
315
+ window.addEventListener('visibilitychange', () => {
316
+ if (document.visibilityState === 'hidden') {
317
+ this.flush();
318
+ }
319
+ });
320
+ // Listen for app pause (Capacitor)
321
+ if (Capacitor.isNativePlatform()) {
322
+ window.addEventListener('pause', () => {
323
+ this.flush();
324
+ });
325
+ }
326
+ }
327
+ /**
328
+ * Enqueue an event
329
+ */
330
+ enqueueEvent(type, data) {
331
+ const queue = this.queues[type];
332
+ if (!queue) {
333
+ return;
334
+ }
335
+ // Don't track successful API calls (2xx, 3xx)
336
+ if (type === 'api_call' && data.status_code >= 200 && data.status_code < 400) {
337
+ return;
338
+ }
339
+ // Limit queue size
340
+ if (queue.length >= this.config.maxQueueSize) {
341
+ queue.shift();
342
+ }
343
+ const event = {
344
+ event_type: type,
345
+ timestamp: Date.now(),
346
+ session_id: this.sessionId || '',
347
+ user_agent: navigator.userAgent,
348
+ url: window.location.href,
349
+ data,
350
+ };
351
+ queue.push(event);
352
+ // Flush immediately for critical errors
353
+ const shouldFlushImmediately = type === 'api_call' && (data.status_code === 0 || data.status_code >= 400);
354
+ if (shouldFlushImmediately || queue.length >= this.config.batchSize) {
355
+ this.flushQueue(type);
356
+ }
357
+ else if (!this.batchTimers[type]) {
358
+ this.batchTimers[type] = setTimeout(() => this.flushQueue(type), this.config.batchInterval);
359
+ }
360
+ }
361
+ /**
362
+ * Flush a specific queue
363
+ */
364
+ flushQueue(eventType, useBeacon = false) {
365
+ const queue = this.queues[eventType];
366
+ if (!queue || queue.length === 0) {
367
+ return;
368
+ }
369
+ // Clear timer
370
+ if (this.batchTimers[eventType]) {
371
+ clearTimeout(this.batchTimers[eventType]);
372
+ delete this.batchTimers[eventType];
373
+ }
374
+ const eventsToProcess = [...queue];
375
+ this.queues[eventType] = [];
376
+ let backendUrl;
377
+ let transformedPayload;
378
+ if (eventType === 'console_error' || eventType === 'unhandled_error') {
379
+ backendUrl = this.config.consoleErrorBackendUrl;
380
+ transformedPayload = eventsToProcess.map((event) => ({
381
+ message: event.data.message,
382
+ stack_trace: event.data.stack_trace,
383
+ log_level: 'error',
384
+ url: event.url,
385
+ session_id: event.session_id,
386
+ source: 'mobile',
387
+ console_metadata: event.data.metadata || {},
388
+ }));
389
+ }
390
+ else if (eventType === 'page_view') {
391
+ backendUrl = this.config.pageViewBackendUrl;
392
+ transformedPayload = eventsToProcess.map((event) => ({
393
+ session_id: event.session_id,
394
+ url: event.data.screen,
395
+ referrer: event.data.referrer,
396
+ user_agent: event.user_agent,
397
+ source: 'mobile',
398
+ page_metadata: {
399
+ duration: event.data.duration,
400
+ screen: event.data.screen,
401
+ ...event.data.metadata,
402
+ },
403
+ timestamp: new Date(event.timestamp).toISOString(),
404
+ }));
405
+ }
406
+ else if (eventType === 'api_call') {
407
+ backendUrl = this.config.apiResponseBackendUrl;
408
+ transformedPayload = eventsToProcess
409
+ .map((event) => {
410
+ let responseBody = event.data.response_data;
411
+ if (typeof responseBody === 'string') {
412
+ try {
413
+ responseBody = JSON.parse(responseBody);
414
+ }
415
+ catch (e) {
416
+ responseBody = { raw_text: responseBody };
417
+ }
418
+ }
419
+ else if (responseBody === null || typeof responseBody === 'undefined') {
420
+ responseBody = {};
421
+ }
422
+ return {
423
+ url: event.data.url,
424
+ method: event.data.method,
425
+ status_code: event.data.status_code,
426
+ response_body: responseBody,
427
+ session_id: event.session_id,
428
+ source: 'mobile',
429
+ api_metadata: {
430
+ duration: event.data.duration,
431
+ error: event.data.error || null,
432
+ },
433
+ };
434
+ })
435
+ .filter((item) => item !== null && item !== undefined);
436
+ }
437
+ else {
438
+ return;
439
+ }
440
+ const filteredPayload = transformedPayload.filter((item) => item !== null && item !== undefined);
441
+ if (backendUrl && filteredPayload.length > 0) {
442
+ this.sendToBackend(backendUrl, filteredPayload, useBeacon);
443
+ }
444
+ }
445
+ /**
446
+ * Send data to backend
447
+ */
448
+ async sendToBackend(url, payload, useBeacon = false, retryCount = 0) {
449
+ if (!this.sessionId) {
450
+ this.pendingEvents.push({ url, payload, useBeacon });
451
+ return;
452
+ }
453
+ if (!navigator.onLine) {
454
+ return;
455
+ }
456
+ const data = JSON.stringify(payload);
457
+ const headers = {
458
+ 'Content-Type': 'application/json',
459
+ };
460
+ try {
461
+ const response = await fetch(url, {
462
+ method: 'POST',
463
+ headers,
464
+ body: data,
465
+ keepalive: useBeacon,
466
+ });
467
+ if (!response.ok && retryCount < this.config.retryAttempts) {
468
+ setTimeout(() => {
469
+ this.sendToBackend(url, payload, false, retryCount + 1);
470
+ }, this.config.retryDelay);
471
+ }
472
+ }
473
+ catch (error) {
474
+ // Silently fail
475
+ }
476
+ }
477
+ /**
478
+ * Flush pending events
479
+ */
480
+ flushPendingEvents() {
481
+ if (this.pendingEvents.length > 0) {
482
+ const pending = [...this.pendingEvents];
483
+ this.pendingEvents = [];
484
+ pending.forEach(({ url, payload, useBeacon }) => {
485
+ this.sendToBackend(url, payload, useBeacon);
486
+ });
487
+ }
488
+ }
489
+ /**
490
+ * Setup native error capture for Android/iOS crashes
491
+ */
492
+ setupNativeErrorCapture() {
493
+ try {
494
+ // Only run on native platforms and if we have a session ID
495
+ if (Capacitor.isNativePlatform() && this.sessionId) {
496
+ CuoralPlugin.setupNativeErrorCapture({
497
+ backendUrl: this.config.consoleErrorBackendUrl,
498
+ sessionId: this.sessionId,
499
+ }).catch(() => {
500
+ // Silently fail - native error capture optional
501
+ });
502
+ }
503
+ }
504
+ catch (error) {
505
+ // Silently fail if plugin is not available
506
+ }
507
+ }
508
+ }
package/dist/plugin.d.ts CHANGED
@@ -39,7 +39,7 @@ export interface CuoralPluginInterface {
39
39
  }>;
40
40
  }
41
41
  /**
42
- * Register the Capacitor plugin
42
+ * Register the Capacitor plugin (mobile only - iOS and Android)
43
43
  */
44
44
  declare const CuoralPlugin: CuoralPluginInterface;
45
45
  export { CuoralPlugin };
@@ -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,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAErF;;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,uBAEhB,CAAC;AAEH,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;IA4ClE;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAwC/E;;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,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAErF;;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,IAAI,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAiD/E;;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
@@ -1,11 +1,9 @@
1
1
  import { registerPlugin } from '@capacitor/core';
2
2
  import { CuoralMessageType, } from './types';
3
3
  /**
4
- * Register the Capacitor plugin
4
+ * Register the Capacitor plugin (mobile only - iOS and Android)
5
5
  */
6
- const CuoralPlugin = registerPlugin('CuoralPlugin', {
7
- web: () => import('./web').then(m => new m.CuoralPluginWeb()),
8
- });
6
+ const CuoralPlugin = registerPlugin('CuoralPlugin');
9
7
  export { CuoralPlugin };
10
8
  /**
11
9
  * High-level API for easier integration
@@ -45,10 +43,21 @@ export class CuoralRecorder {
45
43
  payload: { timestamp: this.recordingStartTime },
46
44
  });
47
45
  }
46
+ else {
47
+ // Recording failed - reset state and notify widget
48
+ this.isRecording = false;
49
+ this.recordingStartTime = undefined;
50
+ this.postMessage({
51
+ type: CuoralMessageType.RECORDING_ERROR,
52
+ payload: { error: 'Failed to start recording' },
53
+ });
54
+ }
48
55
  return result.success;
49
56
  }
50
57
  catch (error) {
51
- console.error('[Cuoral] Failed to start recording:', error);
58
+ // Exception occurred - reset state and notify widget
59
+ this.isRecording = false;
60
+ this.recordingStartTime = undefined;
52
61
  this.postMessage({
53
62
  type: CuoralMessageType.RECORDING_ERROR,
54
63
  payload: { error: error.message },
@@ -62,7 +71,11 @@ export class CuoralRecorder {
62
71
  async stopRecording() {
63
72
  try {
64
73
  if (!this.isRecording) {
65
- console.warn('[Cuoral] Not recording');
74
+ // 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
+ });
66
79
  return null;
67
80
  }
68
81
  const result = await CuoralPlugin.stopRecording();
@@ -84,6 +97,11 @@ export class CuoralRecorder {
84
97
  duration: result.duration || duration,
85
98
  };
86
99
  }
100
+ // If result.success is false, send error to widget
101
+ this.postMessage({
102
+ type: CuoralMessageType.RECORDING_ERROR,
103
+ payload: { error: 'Failed to stop recording' },
104
+ });
87
105
  return null;
88
106
  }
89
107
  catch (error) {
package/dist/web.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAU,YAAW,qBAAqB;IAC7E,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAE9B,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IA4BzE,aAAa,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA2BpF,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC;IAS5C,cAAc,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IA6CpE,oBAAoB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAKvD,kBAAkB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAI1D"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,EACf,MAAM,SAAS,CAAC;AAEjB;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAU,YAAW,qBAAqB;IAC7E,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAC,CAAS;IAE9B,cAAc,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IA0BzE,aAAa,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAyBpF,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC;IAS5C,cAAc,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IA2CpE,oBAAoB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAKvD,kBAAkB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAI1D"}