capdebug 0.1.0 → 0.2.0

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/dist/plugin.js CHANGED
@@ -1,846 +1,776 @@
1
1
  var capacitorCapDebug = (function (exports, core) {
2
- 'use strict';
3
-
4
- const DEFAULT_SENSITIVE_KEYS = new Set([
5
- 'authorization',
6
- 'cookie',
7
- 'set-cookie',
8
- 'password',
9
- 'passwd',
10
- 'pass',
11
- 'token',
12
- 'access_token',
13
- 'accesstoken',
14
- 'refresh_token',
15
- 'refreshtoken',
16
- 'api_key',
17
- 'apikey',
18
- 'secret',
19
- 'client_secret',
20
- 'clientsecret',
21
- 'bearer',
22
- 'private_key',
23
- 'privatekey',
24
- 'session_id',
25
- 'sessionid',
26
- 'jwt',
27
- 'credit_card',
28
- 'creditcard',
29
- 'cvv',
30
- 'ssn',
31
- ]);
32
- const MASK_VALUE = '********';
33
- class DataSanitizer {
34
- maskKeys;
35
- maxDepth;
36
- maxArrayLength;
37
- constructor(options = {}) {
38
- this.maskKeys = new Set([
39
- ...DEFAULT_SENSITIVE_KEYS,
40
- ...(options.customMaskKeys || []).map(k => k.toLowerCase().trim()),
41
- ]);
42
- this.maxDepth = options.maxDepth ?? 10;
43
- this.maxArrayLength = options.maxArrayLength ?? 100;
44
- }
45
- isSensitiveKey(key) {
46
- const normalized = key.toLowerCase().replace(/[-_]/g, '');
47
- if (this.maskKeys.has(key.toLowerCase()) || this.maskKeys.has(normalized)) {
48
- return true;
49
- }
50
- for (const sensitive of this.maskKeys) {
51
- const cleanSensitive = sensitive.replace(/[-_]/g, '');
52
- if (normalized.includes(cleanSensitive) && cleanSensitive.length >= 4) {
53
- return true;
54
- }
55
- }
56
- return false;
57
- }
58
- sanitize(value) {
59
- const seen = new WeakSet();
60
- return this.sanitizeRecursive(value, 0, seen);
61
- }
62
- sanitizeRecursive(value, depth, seen) {
63
- if (value === null || value === undefined) {
64
- return value;
65
- }
66
- if (depth > this.maxDepth) {
67
- return '[Max Depth Reached]';
68
- }
69
- const type = typeof value;
70
- if (type === 'string' || type === 'number' || type === 'boolean') {
71
- return value;
72
- }
73
- if (type === 'bigint') {
74
- return value.toString() + 'n';
75
- }
76
- if (type === 'symbol') {
77
- return value.toString();
78
- }
79
- if (type === 'function') {
80
- return `[Function: ${value.name || 'anonymous'}]`;
81
- }
82
- if (typeof value === 'object') {
83
- // Check circular reference
84
- if (seen.has(value)) {
85
- return '[Circular Reference]';
86
- }
87
- seen.add(value);
88
- // Error handling
89
- if (value instanceof Error) {
90
- return {
91
- name: value.name,
92
- message: value.message,
93
- stack: value.stack,
94
- ...value,
95
- };
96
- }
97
- // Date handling
98
- if (value instanceof Date) {
99
- return value.toISOString();
100
- }
101
- // RegExp handling
102
- if (value instanceof RegExp) {
103
- return value.toString();
104
- }
105
- // DOM Node handling
106
- if (typeof Element !== 'undefined' && value instanceof Element) {
107
- const id = value.id ? `#${value.id}` : '';
108
- const className = value.className ? `.${String(value.className).trim().replace(/\s+/g, '.')}` : '';
109
- return `<${value.tagName.toLowerCase()}${id}${className}>`;
110
- }
111
- // Array handling
112
- if (Array.isArray(value)) {
113
- const arr = value.slice(0, this.maxArrayLength).map(item => this.sanitizeRecursive(item, depth + 1, seen));
114
- if (value.length > this.maxArrayLength) {
115
- arr.push(`[... ${value.length - this.maxArrayLength} more items]`);
116
- }
117
- return arr;
118
- }
119
- // Map handling
120
- if (value instanceof Map) {
121
- const entries = {};
122
- for (const [k, v] of value.entries()) {
123
- const keyStr = String(k);
124
- entries[keyStr] = this.isSensitiveKey(keyStr)
125
- ? MASK_VALUE
126
- : this.sanitizeRecursive(v, depth + 1, seen);
127
- }
128
- return entries;
129
- }
130
- // Set handling
131
- if (value instanceof Set) {
132
- return Array.from(value).map(item => this.sanitizeRecursive(item, depth + 1, seen));
133
- }
134
- // Plain Object handling
135
- const result = {};
136
- const obj = value;
137
- for (const [key, val] of Object.entries(obj)) {
138
- if (this.isSensitiveKey(key)) {
139
- result[key] = MASK_VALUE;
140
- }
141
- else {
142
- result[key] = this.sanitizeRecursive(val, depth + 1, seen);
143
- }
144
- }
145
- return result;
146
- }
147
- return String(value);
148
- }
2
+ 'use strict';
3
+
4
+ const DEFAULT_SENSITIVE_KEYS = /* @__PURE__ */ new Set([
5
+ "authorization",
6
+ "cookie",
7
+ "set-cookie",
8
+ "password",
9
+ "passwd",
10
+ "pass",
11
+ "token",
12
+ "access_token",
13
+ "accesstoken",
14
+ "refresh_token",
15
+ "refreshtoken",
16
+ "api_key",
17
+ "apikey",
18
+ "secret",
19
+ "client_secret",
20
+ "clientsecret",
21
+ "bearer",
22
+ "private_key",
23
+ "privatekey",
24
+ "session_id",
25
+ "sessionid",
26
+ "jwt",
27
+ "credit_card",
28
+ "creditcard",
29
+ "cvv",
30
+ "ssn"
31
+ ]);
32
+ const MASK_VALUE = "********";
33
+ class DataSanitizer {
34
+ maskKeys;
35
+ maxDepth;
36
+ maxArrayLength;
37
+ constructor(options = {}) {
38
+ this.maskKeys = /* @__PURE__ */ new Set([
39
+ ...DEFAULT_SENSITIVE_KEYS,
40
+ ...(options.customMaskKeys || []).map((k) => k.toLowerCase().trim())
41
+ ]);
42
+ this.maxDepth = options.maxDepth ?? 10;
43
+ this.maxArrayLength = options.maxArrayLength ?? 100;
149
44
  }
150
- const defaultSanitizer = new DataSanitizer();
151
- function sanitize(value, options) {
152
- if (!options) {
153
- return defaultSanitizer.sanitize(value);
154
- }
155
- return new DataSanitizer(options).sanitize(value);
156
- }
157
-
158
- class CapDebugStore {
159
- buffer = [];
160
- maxEvents;
161
- paused = false;
162
- listeners = new Set();
163
- rafId = null;
164
- customMaskKeys = [];
165
- filterState = {
166
- tab: 'all',
167
- search: '',
168
- level: 'all',
169
- source: 'all',
170
- };
171
- constructor(maxEvents = 500, customMaskKeys = []) {
172
- this.maxEvents = Math.max(1, maxEvents);
173
- this.customMaskKeys = customMaskKeys;
174
- }
175
- setMaxEvents(max) {
176
- this.maxEvents = Math.max(1, max);
177
- if (this.buffer.length > this.maxEvents) {
178
- this.buffer = this.buffer.slice(this.buffer.length - this.maxEvents);
179
- this.notify();
180
- }
181
- }
182
- setCustomMaskKeys(keys) {
183
- this.customMaskKeys = keys;
184
- }
185
- add(event) {
186
- if (this.paused) {
187
- return null;
188
- }
189
- const sanitizedData = event.data !== undefined
190
- ? sanitize(event.data, { customMaskKeys: this.customMaskKeys })
191
- : undefined;
192
- const fullEvent = {
193
- id: event.id || this.generateId(),
194
- timestamp: event.timestamp || Date.now(),
195
- source: event.source || 'web',
196
- type: event.type,
197
- level: event.level || 'info',
198
- message: event.message,
199
- data: sanitizedData,
200
- duration: event.duration,
201
- platform: event.platform,
202
- };
203
- if (this.buffer.length >= this.maxEvents) {
204
- this.buffer.shift(); // Evict oldest FIFO
205
- }
206
- this.buffer.push(fullEvent);
207
- this.notify();
208
- return fullEvent;
209
- }
210
- clear() {
211
- this.buffer = [];
212
- this.notify();
213
- }
214
- pause() {
215
- this.paused = true;
216
- this.notify();
217
- }
218
- resume() {
219
- this.paused = false;
220
- this.notify();
221
- }
222
- togglePause() {
223
- this.paused = !this.paused;
224
- this.notify();
225
- return this.paused;
226
- }
227
- isPaused() {
228
- return this.paused;
229
- }
230
- setFilter(partial) {
231
- this.filterState = { ...this.filterState, ...partial };
232
- this.notify();
233
- }
234
- getFilter() {
235
- return this.filterState;
236
- }
237
- getAll() {
238
- return [...this.buffer];
239
- }
240
- getCounts() {
241
- const counts = {
242
- all: this.buffer.length,
243
- console: 0,
244
- errors: 0,
245
- events: 0,
246
- native: 0,
247
- device: 0,
248
- network: 0,
249
- bridge: 0,
250
- };
251
- for (const ev of this.buffer) {
252
- if (ev.source === 'console')
253
- counts.console++;
254
- if (ev.level === 'error')
255
- counts.errors++;
256
- if (ev.source === 'web' || ev.source === 'system')
257
- counts.events++;
258
- if (ev.source === 'native')
259
- counts.native++;
260
- if (ev.source === 'network')
261
- counts.network++;
262
- if (ev.source === 'bridge')
263
- counts.bridge++;
264
- }
265
- return counts;
266
- }
267
- getFiltered() {
268
- const { tab, search, level, source } = this.filterState;
269
- const query = search.trim().toLowerCase();
270
- return this.buffer.filter(event => {
271
- // 1. Tab filtering
272
- if (tab === 'console' && event.source !== 'console')
273
- return false;
274
- if (tab === 'errors' && event.level !== 'error')
275
- return false;
276
- if (tab === 'events' && (event.source !== 'web' && event.source !== 'system'))
277
- return false;
278
- if (tab === 'native' && event.source !== 'native')
279
- return false;
280
- if (tab === 'network' && event.source !== 'network')
281
- return false;
282
- if (tab === 'bridge' && event.source !== 'bridge')
283
- return false;
284
- // 2. Level filter
285
- if (level !== 'all' && event.level !== level)
286
- return false;
287
- // 3. Source filter
288
- if (source !== 'all' && event.source !== source)
289
- return false;
290
- // 4. Search query
291
- if (query) {
292
- const typeMatch = event.type.toLowerCase().includes(query);
293
- const msgMatch = event.message ? event.message.toLowerCase().includes(query) : false;
294
- const sourceMatch = event.source.toLowerCase().includes(query);
295
- if (typeMatch || msgMatch || sourceMatch)
296
- return true;
297
- if (event.data) {
298
- try {
299
- const dataStr = typeof event.data === 'string'
300
- ? event.data.toLowerCase()
301
- : JSON.stringify(event.data).toLowerCase();
302
- return dataStr.includes(query);
303
- }
304
- catch {
305
- return false;
306
- }
307
- }
308
- return false;
309
- }
310
- return true;
311
- });
312
- }
313
- exportJson() {
314
- return JSON.stringify({
315
- exportedAt: new Date().toISOString(),
316
- totalEvents: this.buffer.length,
317
- events: this.buffer,
318
- }, null, 2);
319
- }
320
- subscribe(listener) {
321
- this.listeners.add(listener);
322
- listener(this.getFiltered(), this);
323
- return () => {
324
- this.listeners.delete(listener);
325
- };
326
- }
327
- notify() {
328
- if (typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function') {
329
- if (this.rafId !== null) {
330
- cancelAnimationFrame(this.rafId);
331
- }
332
- this.rafId = requestAnimationFrame(() => {
333
- this.rafId = null;
334
- this.dispatchToListeners();
335
- });
336
- }
337
- else {
338
- this.dispatchToListeners();
339
- }
340
- }
341
- dispatchToListeners() {
342
- const filtered = this.getFiltered();
343
- for (const listener of this.listeners) {
344
- try {
345
- listener(filtered, this);
346
- }
347
- catch (err) {
348
- // Prevent subscriber errors from halting store
349
- }
350
- }
351
- }
352
- generateId() {
353
- return 'ev_' + Math.random().toString(36).substring(2, 9) + '_' + Date.now().toString(36);
354
- }
45
+ isSensitiveKey(key) {
46
+ const normalized = key.toLowerCase().replace(/[-_]/g, "");
47
+ if (this.maskKeys.has(key.toLowerCase()) || this.maskKeys.has(normalized)) {
48
+ return true;
49
+ }
50
+ for (const sensitive of this.maskKeys) {
51
+ const cleanSensitive = sensitive.replace(/[-_]/g, "");
52
+ if (normalized.includes(cleanSensitive) && cleanSensitive.length >= 4) {
53
+ return true;
54
+ }
55
+ }
56
+ return false;
355
57
  }
58
+ sanitize(value) {
59
+ const seen = /* @__PURE__ */ new WeakSet();
60
+ return this.sanitizeRecursive(value, 0, seen);
61
+ }
62
+ sanitizeRecursive(value, depth, seen) {
63
+ if (value === null || value === void 0) {
64
+ return value;
65
+ }
66
+ if (depth > this.maxDepth) {
67
+ return "[Max Depth Reached]";
68
+ }
69
+ const type = typeof value;
70
+ if (type === "string" || type === "number" || type === "boolean") {
71
+ return value;
72
+ }
73
+ if (type === "bigint") {
74
+ return value.toString() + "n";
75
+ }
76
+ if (type === "symbol") {
77
+ return value.toString();
78
+ }
79
+ if (type === "function") {
80
+ return `[Function: ${value.name || "anonymous"}]`;
81
+ }
82
+ if (typeof value === "object") {
83
+ if (seen.has(value)) {
84
+ return "[Circular Reference]";
85
+ }
86
+ seen.add(value);
87
+ if (value instanceof Error) {
88
+ return {
89
+ name: value.name,
90
+ message: value.message,
91
+ stack: value.stack,
92
+ ...value
93
+ };
94
+ }
95
+ if (value instanceof Date) {
96
+ return value.toISOString();
97
+ }
98
+ if (value instanceof RegExp) {
99
+ return value.toString();
100
+ }
101
+ if (typeof Element !== "undefined" && value instanceof Element) {
102
+ const id = value.id ? `#${value.id}` : "";
103
+ const className = value.className ? `.${String(value.className).trim().replace(/\s+/g, ".")}` : "";
104
+ return `<${value.tagName.toLowerCase()}${id}${className}>`;
105
+ }
106
+ if (Array.isArray(value)) {
107
+ const arr = value.slice(0, this.maxArrayLength).map(
108
+ (item) => this.sanitizeRecursive(item, depth + 1, seen)
109
+ );
110
+ if (value.length > this.maxArrayLength) {
111
+ arr.push(`[... ${value.length - this.maxArrayLength} more items]`);
112
+ }
113
+ return arr;
114
+ }
115
+ if (value instanceof Map) {
116
+ const entries = {};
117
+ for (const [k, v] of value.entries()) {
118
+ const keyStr = String(k);
119
+ entries[keyStr] = this.isSensitiveKey(keyStr) ? MASK_VALUE : this.sanitizeRecursive(v, depth + 1, seen);
120
+ }
121
+ return entries;
122
+ }
123
+ if (value instanceof Set) {
124
+ return Array.from(value).map(
125
+ (item) => this.sanitizeRecursive(item, depth + 1, seen)
126
+ );
127
+ }
128
+ const result = {};
129
+ const obj = value;
130
+ for (const [key, val] of Object.entries(obj)) {
131
+ if (this.isSensitiveKey(key)) {
132
+ result[key] = MASK_VALUE;
133
+ } else {
134
+ result[key] = this.sanitizeRecursive(val, depth + 1, seen);
135
+ }
136
+ }
137
+ return result;
138
+ }
139
+ return String(value);
140
+ }
141
+ }
142
+ const defaultSanitizer = new DataSanitizer();
143
+ function sanitize(value, options) {
144
+ if (!options) {
145
+ return defaultSanitizer.sanitize(value);
146
+ }
147
+ return new DataSanitizer(options).sanitize(value);
148
+ }
356
149
 
357
- class ConsoleCollector {
358
- id = 'console';
359
- running = false;
360
- originalMethods = {};
361
- start() {
362
- if (this.running || typeof console === 'undefined')
363
- return;
364
- const methods = [
365
- { method: 'log', level: 'info' },
366
- { method: 'info', level: 'info' },
367
- { method: 'warn', level: 'warn' },
368
- { method: 'error', level: 'error' },
369
- { method: 'debug', level: 'debug' },
370
- ];
371
- for (const { method, level } of methods) {
372
- const original = console[method]?.bind(console);
373
- this.originalMethods[method] = original;
374
- console[method] = (...args) => {
375
- // 1. Call original console method
376
- if (original) {
377
- try {
378
- original(...args);
379
- }
380
- catch {
381
- // ignore
382
- }
383
- }
384
- // 2. Dispatch CapDebug event safely
385
- try {
386
- this.emitConsoleEvent(method, level, args);
387
- }
388
- catch {
389
- // ignore to prevent crashing host application
390
- }
391
- };
392
- }
393
- this.running = true;
394
- }
395
- stop() {
396
- if (!this.running || typeof console === 'undefined')
397
- return;
398
- for (const method of Object.keys(this.originalMethods)) {
399
- const original = this.originalMethods[method];
400
- if (original) {
401
- console[method] = original;
402
- }
403
- }
404
- this.originalMethods = {};
405
- this.running = false;
406
- }
407
- emitConsoleEvent(method, level, args) {
408
- if (typeof window === 'undefined')
409
- return;
410
- let message = '';
411
- let data = undefined;
412
- if (args.length === 1) {
413
- const arg = args[0];
414
- if (typeof arg === 'string' || typeof arg === 'number' || typeof arg === 'boolean') {
415
- message = String(arg);
416
- }
417
- else if (arg instanceof Error) {
418
- message = `${arg.name}: ${arg.message}`;
419
- data = { name: arg.name, message: arg.message, stack: arg.stack };
420
- }
421
- else {
422
- message = `[${typeof arg}]`;
423
- data = arg;
424
- }
425
- }
426
- else if (args.length > 1) {
427
- // Multiple arguments
428
- const first = args[0];
429
- if (typeof first === 'string') {
430
- message = first;
431
- data = args.slice(1);
432
- }
433
- else {
434
- message = args.map(a => (typeof a === 'object' && a !== null ? '[Object]' : String(a))).join(' ');
435
- data = args;
436
- }
150
+ class CapDebugStore {
151
+ buffer = [];
152
+ maxEvents;
153
+ paused = false;
154
+ listeners = /* @__PURE__ */ new Set();
155
+ rafId = null;
156
+ customMaskKeys = [];
157
+ filterState = {
158
+ tab: "all",
159
+ search: "",
160
+ level: "all",
161
+ source: "all"
162
+ };
163
+ constructor(maxEvents = 500, customMaskKeys = []) {
164
+ this.maxEvents = Math.max(1, maxEvents);
165
+ this.customMaskKeys = customMaskKeys;
166
+ }
167
+ setMaxEvents(max) {
168
+ this.maxEvents = Math.max(1, max);
169
+ if (this.buffer.length > this.maxEvents) {
170
+ this.buffer = this.buffer.slice(this.buffer.length - this.maxEvents);
171
+ this.notify();
172
+ }
173
+ }
174
+ setCustomMaskKeys(keys) {
175
+ this.customMaskKeys = keys;
176
+ }
177
+ add(event) {
178
+ if (this.paused) {
179
+ return null;
180
+ }
181
+ const sanitizedData = event.data !== void 0 ? sanitize(event.data, { customMaskKeys: this.customMaskKeys }) : void 0;
182
+ const fullEvent = {
183
+ id: event.id || this.generateId(),
184
+ timestamp: event.timestamp || Date.now(),
185
+ source: event.source || "web",
186
+ type: event.type,
187
+ level: event.level || "info",
188
+ message: event.message,
189
+ data: sanitizedData,
190
+ duration: event.duration,
191
+ platform: event.platform
192
+ };
193
+ if (this.buffer.length >= this.maxEvents) {
194
+ this.buffer.shift();
195
+ }
196
+ this.buffer.push(fullEvent);
197
+ this.notify();
198
+ return fullEvent;
199
+ }
200
+ clear() {
201
+ this.buffer = [];
202
+ this.notify();
203
+ }
204
+ pause() {
205
+ this.paused = true;
206
+ this.notify();
207
+ }
208
+ resume() {
209
+ this.paused = false;
210
+ this.notify();
211
+ }
212
+ togglePause() {
213
+ this.paused = !this.paused;
214
+ this.notify();
215
+ return this.paused;
216
+ }
217
+ isPaused() {
218
+ return this.paused;
219
+ }
220
+ setFilter(partial) {
221
+ this.filterState = { ...this.filterState, ...partial };
222
+ this.notify();
223
+ }
224
+ getFilter() {
225
+ return this.filterState;
226
+ }
227
+ getAll() {
228
+ return [...this.buffer];
229
+ }
230
+ getCounts() {
231
+ const counts = {
232
+ all: this.buffer.length,
233
+ console: 0,
234
+ errors: 0,
235
+ events: 0,
236
+ native: 0,
237
+ device: 0,
238
+ network: 0,
239
+ bridge: 0
240
+ };
241
+ for (const ev of this.buffer) {
242
+ if (ev.source === "console") counts.console++;
243
+ if (ev.level === "error") counts.errors++;
244
+ if (ev.source === "web" || ev.source === "system") counts.events++;
245
+ if (ev.source === "native") counts.native++;
246
+ if (ev.source === "network") counts.network++;
247
+ if (ev.source === "bridge") counts.bridge++;
248
+ }
249
+ return counts;
250
+ }
251
+ getFiltered() {
252
+ const { tab, search, level, source } = this.filterState;
253
+ const query = search.trim().toLowerCase();
254
+ return this.buffer.filter((event) => {
255
+ if (tab === "console" && event.source !== "console") return false;
256
+ if (tab === "errors" && event.level !== "error") return false;
257
+ if (tab === "events" && (event.source !== "web" && event.source !== "system")) return false;
258
+ if (tab === "native" && event.source !== "native") return false;
259
+ if (tab === "network" && event.source !== "network") return false;
260
+ if (tab === "bridge" && event.source !== "bridge") return false;
261
+ if (level !== "all" && event.level !== level) return false;
262
+ if (source !== "all" && event.source !== source) return false;
263
+ if (query) {
264
+ const typeMatch = event.type.toLowerCase().includes(query);
265
+ const msgMatch = event.message ? event.message.toLowerCase().includes(query) : false;
266
+ const sourceMatch = event.source.toLowerCase().includes(query);
267
+ if (typeMatch || msgMatch || sourceMatch) return true;
268
+ if (event.data) {
269
+ try {
270
+ const dataStr = typeof event.data === "string" ? event.data.toLowerCase() : JSON.stringify(event.data).toLowerCase();
271
+ return dataStr.includes(query);
272
+ } catch {
273
+ return false;
437
274
  }
438
- window.dispatchEvent(new CustomEvent('capdebug', {
439
- detail: {
440
- source: 'console',
441
- type: `console.${method}`,
442
- level,
443
- message,
444
- data,
445
- timestamp: Date.now(),
446
- },
447
- }));
275
+ }
276
+ return false;
448
277
  }
278
+ return true;
279
+ });
280
+ }
281
+ exportJson() {
282
+ return JSON.stringify(
283
+ {
284
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
285
+ totalEvents: this.buffer.length,
286
+ events: this.buffer
287
+ },
288
+ null,
289
+ 2
290
+ );
291
+ }
292
+ subscribe(listener) {
293
+ this.listeners.add(listener);
294
+ listener(this.getFiltered(), this);
295
+ return () => {
296
+ this.listeners.delete(listener);
297
+ };
298
+ }
299
+ notify() {
300
+ if (typeof window !== "undefined" && typeof window.requestAnimationFrame === "function") {
301
+ if (this.rafId !== null) {
302
+ cancelAnimationFrame(this.rafId);
303
+ }
304
+ this.rafId = requestAnimationFrame(() => {
305
+ this.rafId = null;
306
+ this.dispatchToListeners();
307
+ });
308
+ } else {
309
+ this.dispatchToListeners();
310
+ }
449
311
  }
312
+ dispatchToListeners() {
313
+ const filtered = this.getFiltered();
314
+ for (const listener of this.listeners) {
315
+ try {
316
+ listener(filtered, this);
317
+ } catch (err) {
318
+ }
319
+ }
320
+ }
321
+ generateId() {
322
+ return "ev_" + Math.random().toString(36).substring(2, 9) + "_" + Date.now().toString(36);
323
+ }
324
+ }
450
325
 
451
- class ErrorCollector {
452
- id = 'error';
453
- running = false;
454
- errorHandler = null;
455
- rejectionHandler = null;
456
- start() {
457
- if (this.running || typeof window === 'undefined')
458
- return;
459
- this.errorHandler = (event) => {
460
- try {
461
- const error = event.error;
462
- const message = event.message || (error && error.message) || 'Uncaught Error';
463
- const stack = error && error.stack ? error.stack : undefined;
464
- window.dispatchEvent(new CustomEvent('capdebug', {
465
- detail: {
466
- source: 'web',
467
- type: 'window.error',
468
- level: 'error',
469
- message,
470
- data: {
471
- filename: event.filename,
472
- lineno: event.lineno,
473
- colno: event.colno,
474
- stack,
475
- errorName: error?.name,
476
- },
477
- timestamp: Date.now(),
478
- },
479
- }));
480
- }
481
- catch {
482
- // ignore
483
- }
484
- };
485
- this.rejectionHandler = (event) => {
486
- try {
487
- const reason = event.reason;
488
- let message = 'Unhandled Promise Rejection';
489
- let stack = undefined;
490
- let data = reason;
491
- if (reason instanceof Error) {
492
- message = `Unhandled Rejection: ${reason.message}`;
493
- stack = reason.stack;
494
- data = {
495
- name: reason.name,
496
- message: reason.message,
497
- stack,
498
- };
499
- }
500
- else if (typeof reason === 'string') {
501
- message = `Unhandled Rejection: ${reason}`;
502
- }
503
- window.dispatchEvent(new CustomEvent('capdebug', {
504
- detail: {
505
- source: 'web',
506
- type: 'unhandledrejection',
507
- level: 'error',
508
- message,
509
- data: {
510
- reason: data,
511
- stack,
512
- },
513
- timestamp: Date.now(),
514
- },
515
- }));
516
- }
517
- catch {
518
- // ignore
519
- }
520
- };
521
- window.addEventListener('error', this.errorHandler);
522
- window.addEventListener('unhandledrejection', this.rejectionHandler);
523
- this.running = true;
524
- }
525
- stop() {
526
- if (!this.running || typeof window === 'undefined')
527
- return;
528
- if (this.errorHandler) {
529
- window.removeEventListener('error', this.errorHandler);
530
- this.errorHandler = null;
531
- }
532
- if (this.rejectionHandler) {
533
- window.removeEventListener('unhandledrejection', this.rejectionHandler);
534
- this.rejectionHandler = null;
535
- }
536
- this.running = false;
537
- }
326
+ class ConsoleCollector {
327
+ id = "console";
328
+ running = false;
329
+ originalMethods = {};
330
+ start() {
331
+ if (this.running || typeof console === "undefined") return;
332
+ const methods = [
333
+ { method: "log", level: "info" },
334
+ { method: "info", level: "info" },
335
+ { method: "warn", level: "warn" },
336
+ { method: "error", level: "error" },
337
+ { method: "debug", level: "debug" }
338
+ ];
339
+ for (const { method, level } of methods) {
340
+ const original = console[method]?.bind(console);
341
+ this.originalMethods[method] = original;
342
+ console[method] = (...args) => {
343
+ if (original) {
344
+ try {
345
+ original(...args);
346
+ } catch {
347
+ }
348
+ }
349
+ try {
350
+ this.emitConsoleEvent(method, level, args);
351
+ } catch {
352
+ }
353
+ };
354
+ }
355
+ this.running = true;
538
356
  }
357
+ stop() {
358
+ if (!this.running || typeof console === "undefined") return;
359
+ for (const method of Object.keys(this.originalMethods)) {
360
+ const original = this.originalMethods[method];
361
+ if (original) {
362
+ console[method] = original;
363
+ }
364
+ }
365
+ this.originalMethods = {};
366
+ this.running = false;
367
+ }
368
+ emitConsoleEvent(method, level, args) {
369
+ if (typeof window === "undefined") return;
370
+ let message = "";
371
+ let data = void 0;
372
+ if (args.length === 1) {
373
+ const arg = args[0];
374
+ if (typeof arg === "string" || typeof arg === "number" || typeof arg === "boolean") {
375
+ message = String(arg);
376
+ } else if (arg instanceof Error) {
377
+ message = `${arg.name}: ${arg.message}`;
378
+ data = { name: arg.name, message: arg.message, stack: arg.stack };
379
+ } else {
380
+ message = `[${typeof arg}]`;
381
+ data = arg;
382
+ }
383
+ } else if (args.length > 1) {
384
+ const first = args[0];
385
+ if (typeof first === "string") {
386
+ message = first;
387
+ data = args.slice(1);
388
+ } else {
389
+ message = args.map((a) => typeof a === "object" && a !== null ? "[Object]" : String(a)).join(" ");
390
+ data = args;
391
+ }
392
+ }
393
+ window.dispatchEvent(
394
+ new CustomEvent("capdebug", {
395
+ detail: {
396
+ source: "console",
397
+ type: `console.${method}`,
398
+ level,
399
+ message,
400
+ data,
401
+ timestamp: Date.now()
402
+ }
403
+ })
404
+ );
405
+ }
406
+ }
539
407
 
540
- class NetworkCollector {
541
- id = 'network';
542
- running = false;
543
- originalFetch = null;
544
- options;
545
- constructor(options = {}) {
546
- this.options = {
547
- body: false,
548
- ...options,
549
- };
550
- }
551
- setOptions(options) {
552
- this.options = { ...this.options, ...options };
553
- }
554
- start() {
555
- if (this.running || typeof window === 'undefined' || !window.fetch)
556
- return;
557
- this.originalFetch = window.fetch;
558
- const self = this;
559
- window.fetch = async function (input, init) {
560
- const startTime = performance.now();
561
- const timestamp = Date.now();
562
- let url = '';
563
- let method = 'GET';
564
- if (typeof input === 'string') {
565
- url = input;
566
- }
567
- else if (input instanceof URL) {
568
- url = input.toString();
569
- }
570
- else if (typeof Request !== 'undefined' && input instanceof Request) {
571
- url = input.url;
572
- method = input.method;
573
- }
574
- if (init && init.method) {
575
- method = init.method.toUpperCase();
576
- }
577
- let requestHeaders = {};
578
- if (init && init.headers) {
579
- if (typeof Headers !== 'undefined' && init.headers instanceof Headers) {
580
- init.headers.forEach((value, key) => {
581
- requestHeaders[key] = value;
582
- });
583
- }
584
- else if (Array.isArray(init.headers)) {
585
- for (const [k, v] of init.headers) {
586
- requestHeaders[k] = v;
587
- }
588
- }
589
- else if (typeof init.headers === 'object') {
590
- requestHeaders = { ...init.headers };
591
- }
592
- }
593
- let requestBody = undefined;
594
- if (self.options.body && init && init.body) {
595
- try {
596
- if (typeof init.body === 'string') {
597
- try {
598
- requestBody = JSON.parse(init.body);
599
- }
600
- catch {
601
- requestBody = init.body;
602
- }
603
- }
604
- else {
605
- requestBody = '[Binary/Stream Body]';
606
- }
607
- }
608
- catch {
609
- requestBody = '[Unreadable Body]';
610
- }
611
- }
612
- try {
613
- const response = await self.originalFetch.call(this, input, init);
614
- const duration = Math.round(performance.now() - startTime);
615
- let level = 'info';
616
- if (response.status >= 500) {
617
- level = 'error';
618
- }
619
- else if (response.status >= 400) {
620
- level = 'warn';
621
- }
622
- let responseBody = undefined;
623
- if (self.options.body) {
624
- try {
625
- const clone = response.clone();
626
- const contentType = clone.headers.get('content-type') || '';
627
- if (contentType.includes('application/json')) {
628
- responseBody = await clone.json();
629
- }
630
- else if (contentType.includes('text/')) {
631
- responseBody = await clone.text();
632
- }
633
- }
634
- catch {
635
- responseBody = '[Could not clone response body]';
636
- }
637
- }
638
- const responseHeaders = {};
639
- response.headers.forEach((v, k) => {
640
- responseHeaders[k] = v;
641
- });
642
- self.emitNetworkEvent({
643
- type: `fetch ${method}`,
644
- level,
645
- message: `${method} ${url} → ${response.status} ${response.statusText} (${duration}ms)`,
646
- duration,
647
- timestamp,
648
- data: {
649
- method,
650
- url,
651
- status: response.status,
652
- statusText: response.statusText,
653
- ok: response.ok,
654
- duration,
655
- requestHeaders,
656
- responseHeaders,
657
- requestBody,
658
- responseBody,
659
- },
660
- });
661
- return response;
662
- }
663
- catch (err) {
664
- const duration = Math.round(performance.now() - startTime);
665
- self.emitNetworkEvent({
666
- type: `fetch ${method}`,
667
- level: 'error',
668
- message: `${method} ${url} → Failed: ${err?.message || 'Network Error'} (${duration}ms)`,
669
- duration,
670
- timestamp,
671
- data: {
672
- method,
673
- url,
674
- error: err?.message || String(err),
675
- duration,
676
- requestHeaders,
677
- requestBody,
678
- },
679
- });
680
- throw err;
681
- }
408
+ class ErrorCollector {
409
+ id = "error";
410
+ running = false;
411
+ errorHandler = null;
412
+ rejectionHandler = null;
413
+ start() {
414
+ if (this.running || typeof window === "undefined") return;
415
+ this.errorHandler = (event) => {
416
+ try {
417
+ const error = event.error;
418
+ const message = event.message || error && error.message || "Uncaught Error";
419
+ const stack = error && error.stack ? error.stack : void 0;
420
+ window.dispatchEvent(
421
+ new CustomEvent("capdebug", {
422
+ detail: {
423
+ source: "web",
424
+ type: "window.error",
425
+ level: "error",
426
+ message,
427
+ data: {
428
+ filename: event.filename,
429
+ lineno: event.lineno,
430
+ colno: event.colno,
431
+ stack,
432
+ errorName: error?.name
433
+ },
434
+ timestamp: Date.now()
435
+ }
436
+ })
437
+ );
438
+ } catch {
439
+ }
440
+ };
441
+ this.rejectionHandler = (event) => {
442
+ try {
443
+ const reason = event.reason;
444
+ let message = "Unhandled Promise Rejection";
445
+ let stack = void 0;
446
+ let data = reason;
447
+ if (reason instanceof Error) {
448
+ message = `Unhandled Rejection: ${reason.message}`;
449
+ stack = reason.stack;
450
+ data = {
451
+ name: reason.name,
452
+ message: reason.message,
453
+ stack
682
454
  };
683
- this.running = true;
684
- }
685
- stop() {
686
- if (!this.running || typeof window === 'undefined')
687
- return;
688
- if (this.originalFetch) {
689
- window.fetch = this.originalFetch;
690
- this.originalFetch = null;
691
- }
692
- this.running = false;
693
- }
694
- emitNetworkEvent(detail) {
695
- if (typeof window === 'undefined')
696
- return;
455
+ } else if (typeof reason === "string") {
456
+ message = `Unhandled Rejection: ${reason}`;
457
+ }
458
+ window.dispatchEvent(
459
+ new CustomEvent("capdebug", {
460
+ detail: {
461
+ source: "web",
462
+ type: "unhandledrejection",
463
+ level: "error",
464
+ message,
465
+ data: {
466
+ reason: data,
467
+ stack
468
+ },
469
+ timestamp: Date.now()
470
+ }
471
+ })
472
+ );
473
+ } catch {
474
+ }
475
+ };
476
+ window.addEventListener("error", this.errorHandler);
477
+ window.addEventListener("unhandledrejection", this.rejectionHandler);
478
+ this.running = true;
479
+ }
480
+ stop() {
481
+ if (!this.running || typeof window === "undefined") return;
482
+ if (this.errorHandler) {
483
+ window.removeEventListener("error", this.errorHandler);
484
+ this.errorHandler = null;
485
+ }
486
+ if (this.rejectionHandler) {
487
+ window.removeEventListener("unhandledrejection", this.rejectionHandler);
488
+ this.rejectionHandler = null;
489
+ }
490
+ this.running = false;
491
+ }
492
+ }
493
+
494
+ class NetworkCollector {
495
+ id = "network";
496
+ running = false;
497
+ originalFetch = null;
498
+ options;
499
+ constructor(options = {}) {
500
+ this.options = {
501
+ body: false,
502
+ ...options
503
+ };
504
+ }
505
+ setOptions(options) {
506
+ this.options = { ...this.options, ...options };
507
+ }
508
+ start() {
509
+ if (this.running || typeof window === "undefined" || !window.fetch) return;
510
+ this.originalFetch = window.fetch;
511
+ const self = this;
512
+ window.fetch = async function(input, init) {
513
+ const startTime = performance.now();
514
+ const timestamp = Date.now();
515
+ let url = "";
516
+ let method = "GET";
517
+ if (typeof input === "string") {
518
+ url = input;
519
+ } else if (input instanceof URL) {
520
+ url = input.toString();
521
+ } else if (typeof Request !== "undefined" && input instanceof Request) {
522
+ url = input.url;
523
+ method = input.method;
524
+ }
525
+ if (init && init.method) {
526
+ method = init.method.toUpperCase();
527
+ }
528
+ let requestHeaders = {};
529
+ if (init && init.headers) {
530
+ if (typeof Headers !== "undefined" && init.headers instanceof Headers) {
531
+ init.headers.forEach((value, key) => {
532
+ requestHeaders[key] = value;
533
+ });
534
+ } else if (Array.isArray(init.headers)) {
535
+ for (const [k, v] of init.headers) {
536
+ requestHeaders[k] = v;
537
+ }
538
+ } else if (typeof init.headers === "object") {
539
+ requestHeaders = { ...init.headers };
540
+ }
541
+ }
542
+ let requestBody = void 0;
543
+ if (self.options.body && init && init.body) {
544
+ try {
545
+ if (typeof init.body === "string") {
546
+ try {
547
+ requestBody = JSON.parse(init.body);
548
+ } catch {
549
+ requestBody = init.body;
550
+ }
551
+ } else {
552
+ requestBody = "[Binary/Stream Body]";
553
+ }
554
+ } catch {
555
+ requestBody = "[Unreadable Body]";
556
+ }
557
+ }
558
+ try {
559
+ const response = await self.originalFetch.call(this, input, init);
560
+ const duration = Math.round(performance.now() - startTime);
561
+ let level = "info";
562
+ if (response.status >= 500) {
563
+ level = "error";
564
+ } else if (response.status >= 400) {
565
+ level = "warn";
566
+ }
567
+ let responseBody = void 0;
568
+ if (self.options.body) {
697
569
  try {
698
- window.dispatchEvent(new CustomEvent('capdebug', {
699
- detail: {
700
- source: 'network',
701
- ...detail,
702
- },
703
- }));
704
- }
705
- catch {
706
- // ignore
707
- }
708
- }
570
+ const clone = response.clone();
571
+ const contentType = clone.headers.get("content-type") || "";
572
+ if (contentType.includes("application/json")) {
573
+ responseBody = await clone.json();
574
+ } else if (contentType.includes("text/")) {
575
+ responseBody = await clone.text();
576
+ }
577
+ } catch {
578
+ responseBody = "[Could not clone response body]";
579
+ }
580
+ }
581
+ const responseHeaders = {};
582
+ response.headers.forEach((v, k) => {
583
+ responseHeaders[k] = v;
584
+ });
585
+ self.emitNetworkEvent({
586
+ type: `fetch ${method}`,
587
+ level,
588
+ message: `${method} ${url} \u2192 ${response.status} ${response.statusText} (${duration}ms)`,
589
+ duration,
590
+ timestamp,
591
+ data: {
592
+ method,
593
+ url,
594
+ status: response.status,
595
+ statusText: response.statusText,
596
+ ok: response.ok,
597
+ duration,
598
+ requestHeaders,
599
+ responseHeaders,
600
+ requestBody,
601
+ responseBody
602
+ }
603
+ });
604
+ return response;
605
+ } catch (err) {
606
+ const duration = Math.round(performance.now() - startTime);
607
+ self.emitNetworkEvent({
608
+ type: `fetch ${method}`,
609
+ level: "error",
610
+ message: `${method} ${url} \u2192 Failed: ${err?.message || "Network Error"} (${duration}ms)`,
611
+ duration,
612
+ timestamp,
613
+ data: {
614
+ method,
615
+ url,
616
+ error: err?.message || String(err),
617
+ duration,
618
+ requestHeaders,
619
+ requestBody
620
+ }
621
+ });
622
+ throw err;
623
+ }
624
+ };
625
+ this.running = true;
626
+ }
627
+ stop() {
628
+ if (!this.running || typeof window === "undefined") return;
629
+ if (this.originalFetch) {
630
+ window.fetch = this.originalFetch;
631
+ this.originalFetch = null;
632
+ }
633
+ this.running = false;
634
+ }
635
+ emitNetworkEvent(detail) {
636
+ if (typeof window === "undefined") return;
637
+ try {
638
+ window.dispatchEvent(
639
+ new CustomEvent("capdebug", {
640
+ detail: {
641
+ source: "network",
642
+ ...detail
643
+ }
644
+ })
645
+ );
646
+ } catch {
647
+ }
709
648
  }
649
+ }
710
650
 
711
- class CustomEventCollector {
712
- id = 'custom-event';
713
- store;
714
- running = false;
715
- handler = null;
716
- constructor(store) {
717
- this.store = store;
718
- }
719
- start() {
720
- if (this.running || typeof window === 'undefined')
721
- return;
722
- this.handler = (event) => {
723
- const customEvent = event;
724
- if (customEvent && customEvent.detail) {
725
- const detail = customEvent.detail;
726
- this.store.add({
727
- id: detail.id,
728
- timestamp: detail.timestamp || Date.now(),
729
- source: detail.source || 'web',
730
- type: detail.type || 'custom-event',
731
- level: detail.level || 'info',
732
- message: detail.message,
733
- data: detail.data,
734
- duration: detail.duration,
735
- platform: detail.platform,
736
- });
737
- }
738
- };
739
- window.addEventListener('capdebug', this.handler);
740
- this.running = true;
741
- }
742
- stop() {
743
- if (!this.running || typeof window === 'undefined')
744
- return;
745
- if (this.handler) {
746
- window.removeEventListener('capdebug', this.handler);
747
- this.handler = null;
748
- }
749
- this.running = false;
750
- }
651
+ class CustomEventCollector {
652
+ id = "custom-event";
653
+ store;
654
+ running = false;
655
+ handler = null;
656
+ constructor(store) {
657
+ this.store = store;
658
+ }
659
+ start() {
660
+ if (this.running || typeof window === "undefined") return;
661
+ this.handler = (event) => {
662
+ const customEvent = event;
663
+ if (customEvent && customEvent.detail) {
664
+ const detail = customEvent.detail;
665
+ this.store.add({
666
+ id: detail.id,
667
+ timestamp: detail.timestamp || Date.now(),
668
+ source: detail.source || "web",
669
+ type: detail.type || "custom-event",
670
+ level: detail.level || "info",
671
+ message: detail.message,
672
+ data: detail.data,
673
+ duration: detail.duration,
674
+ platform: detail.platform
675
+ });
676
+ }
677
+ };
678
+ window.addEventListener("capdebug", this.handler);
679
+ this.running = true;
680
+ }
681
+ stop() {
682
+ if (!this.running || typeof window === "undefined") return;
683
+ if (this.handler) {
684
+ window.removeEventListener("capdebug", this.handler);
685
+ this.handler = null;
686
+ }
687
+ this.running = false;
751
688
  }
689
+ }
752
690
 
753
- class BrowserEventCollector {
754
- id = 'browser-event';
755
- running = false;
756
- observedEvents = new Map();
757
- start() {
758
- this.running = true;
759
- }
760
- observe(eventName) {
761
- if (!this.running || typeof window === 'undefined' || this.observedEvents.has(eventName))
762
- return;
763
- const listener = (event) => {
764
- let data = {
765
- type: event.type,
766
- timeStamp: event.timeStamp,
767
- };
768
- if (event.type === 'visibilitychange' && typeof document !== 'undefined') {
769
- data.visibilityState = document.visibilityState;
770
- data.hidden = document.hidden;
771
- }
772
- else if (event.type === 'online' || event.type === 'offline') {
773
- data.onLine = typeof navigator !== 'undefined' ? navigator.onLine : undefined;
774
- }
775
- window.dispatchEvent(new CustomEvent('capdebug', {
776
- detail: {
777
- source: 'system',
778
- type: `event.${eventName}`,
779
- level: 'info',
780
- message: `Browser event fired: ${eventName}`,
781
- data,
782
- timestamp: Date.now(),
783
- },
784
- }));
785
- };
786
- const target = eventName === 'visibilitychange' && typeof document !== 'undefined'
787
- ? document
788
- : window;
789
- target.addEventListener(eventName, listener);
790
- this.observedEvents.set(eventName, listener);
791
- }
792
- unobserve(eventName) {
793
- const listener = this.observedEvents.get(eventName);
794
- if (!listener)
795
- return;
796
- const target = eventName === 'visibilitychange' && typeof document !== 'undefined'
797
- ? document
798
- : window;
799
- target.removeEventListener(eventName, listener);
800
- this.observedEvents.delete(eventName);
801
- }
802
- stop() {
803
- for (const [eventName, listener] of this.observedEvents.entries()) {
804
- const target = eventName === 'visibilitychange' && typeof document !== 'undefined'
805
- ? document
806
- : window;
807
- target.removeEventListener(eventName, listener);
808
- }
809
- this.observedEvents.clear();
810
- this.running = false;
811
- }
691
+ class BrowserEventCollector {
692
+ id = "browser-event";
693
+ running = false;
694
+ observedEvents = /* @__PURE__ */ new Map();
695
+ start() {
696
+ this.running = true;
697
+ }
698
+ observe(eventName) {
699
+ if (!this.running || typeof window === "undefined" || this.observedEvents.has(eventName)) return;
700
+ const listener = (event) => {
701
+ let data = {
702
+ type: event.type,
703
+ timeStamp: event.timeStamp
704
+ };
705
+ if (event.type === "visibilitychange" && typeof document !== "undefined") {
706
+ data.visibilityState = document.visibilityState;
707
+ data.hidden = document.hidden;
708
+ } else if (event.type === "online" || event.type === "offline") {
709
+ data.onLine = typeof navigator !== "undefined" ? navigator.onLine : void 0;
710
+ }
711
+ window.dispatchEvent(
712
+ new CustomEvent("capdebug", {
713
+ detail: {
714
+ source: "system",
715
+ type: `event.${eventName}`,
716
+ level: "info",
717
+ message: `Browser event fired: ${eventName}`,
718
+ data,
719
+ timestamp: Date.now()
720
+ }
721
+ })
722
+ );
723
+ };
724
+ const target = eventName === "visibilitychange" && typeof document !== "undefined" ? document : window;
725
+ target.addEventListener(eventName, listener);
726
+ this.observedEvents.set(eventName, listener);
727
+ }
728
+ unobserve(eventName) {
729
+ const listener = this.observedEvents.get(eventName);
730
+ if (!listener) return;
731
+ const target = eventName === "visibilitychange" && typeof document !== "undefined" ? document : window;
732
+ target.removeEventListener(eventName, listener);
733
+ this.observedEvents.delete(eventName);
734
+ }
735
+ stop() {
736
+ for (const [eventName, listener] of this.observedEvents.entries()) {
737
+ const target = eventName === "visibilitychange" && typeof document !== "undefined" ? document : window;
738
+ target.removeEventListener(eventName, listener);
739
+ }
740
+ this.observedEvents.clear();
741
+ this.running = false;
812
742
  }
743
+ }
813
744
 
814
- class BridgeCollector {
815
- id = 'bridge';
816
- running = false;
817
- start() {
818
- if (this.running)
819
- return;
820
- // Reserved for non-intrusive Capacitor bridge telemetry
821
- this.running = true;
822
- }
823
- stop() {
824
- this.running = false;
825
- }
826
- emitBridgeCall(pluginName, methodName, options, duration) {
827
- if (!this.running || typeof window === 'undefined')
828
- return;
829
- window.dispatchEvent(new CustomEvent('capdebug', {
830
- detail: {
831
- source: 'bridge',
832
- type: `${pluginName}.${methodName}`,
833
- level: 'debug',
834
- message: `Bridge call: ${pluginName}.${methodName}`,
835
- data: options,
836
- duration,
837
- timestamp: Date.now(),
838
- },
839
- }));
840
- }
745
+ class BridgeCollector {
746
+ id = "bridge";
747
+ running = false;
748
+ start() {
749
+ if (this.running) return;
750
+ this.running = true;
751
+ }
752
+ stop() {
753
+ this.running = false;
841
754
  }
755
+ emitBridgeCall(pluginName, methodName, options, duration) {
756
+ if (!this.running || typeof window === "undefined") return;
757
+ window.dispatchEvent(
758
+ new CustomEvent("capdebug", {
759
+ detail: {
760
+ source: "bridge",
761
+ type: `${pluginName}.${methodName}`,
762
+ level: "debug",
763
+ message: `Bridge call: ${pluginName}.${methodName}`,
764
+ data: options,
765
+ duration,
766
+ timestamp: Date.now()
767
+ }
768
+ })
769
+ );
770
+ }
771
+ }
842
772
 
843
- const VIEWER_STYLES = `
773
+ const VIEWER_STYLES = `
844
774
  :host {
845
775
  --cd-bg-base: #0d1117;
846
776
  --cd-bg-surface: #161b22;
@@ -1564,1226 +1494,1157 @@ var capacitorCapDebug = (function (exports, core) {
1564
1494
  }
1565
1495
  `;
1566
1496
 
1567
- const STORAGE_KEY = 'capdebug_btn_pos';
1568
- class FloatingButton {
1569
- element;
1570
- badgeElement;
1571
- options;
1572
- isDragging = false;
1573
- hasMoved = false;
1574
- startX = 0;
1575
- startY = 0;
1576
- initialLeft = 0;
1577
- initialTop = 0;
1578
- constructor(options = {}) {
1579
- this.options = {
1580
- position: 'right',
1581
- persistPosition: true,
1582
- ...options,
1583
- };
1584
- this.element = document.createElement('div');
1585
- this.element.className = 'cd-floating-btn';
1586
- this.element.setAttribute('role', 'button');
1587
- this.element.setAttribute('aria-label', 'Open CapDebug');
1588
- const logo = document.createElement('span');
1589
- logo.className = 'cd-btn-logo';
1590
- logo.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 4px"><path d="m8 2 1.88 1.88"/><path d="M14.12 3.88 16 2"/><path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1"/><path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6"/><path d="M12 20v-9"/><path d="M6.53 9C4.6 8.8 3 7.1 3 5"/><path d="M6 13H2"/><path d="M3 21c0-2.1 1.7-3.9 3.8-4"/><path d="M20.97 5c0 2.1-1.6 3.8-3.5 4"/><path d="M22 13h-4"/><path d="M17.2 17c2.1.1 3.8 1.9 3.8 4"/></svg>CAP`;
1591
- this.badgeElement = document.createElement('span');
1592
- this.badgeElement.className = 'cd-btn-badge';
1593
- this.badgeElement.textContent = '0';
1594
- this.element.appendChild(logo);
1595
- this.element.appendChild(this.badgeElement);
1596
- this.initPosition();
1597
- this.bindEvents();
1598
- }
1599
- getElement() {
1600
- return this.element;
1601
- }
1602
- setErrorCount(count) {
1603
- if (count > 0) {
1604
- this.badgeElement.textContent = count > 99 ? '99+' : String(count);
1605
- this.badgeElement.classList.add('visible');
1606
- }
1607
- else {
1608
- this.badgeElement.classList.remove('visible');
1609
- }
1610
- }
1611
- show() {
1612
- this.element.style.display = 'flex';
1613
- }
1614
- hide() {
1615
- this.element.style.display = 'none';
1616
- }
1617
- initPosition() {
1618
- let savedPos = null;
1619
- if (this.options.persistPosition && typeof localStorage !== 'undefined') {
1620
- try {
1621
- const stored = localStorage.getItem(STORAGE_KEY);
1622
- if (stored) {
1623
- savedPos = JSON.parse(stored);
1624
- }
1625
- }
1626
- catch {
1627
- // ignore
1628
- }
1629
- }
1630
- const windowWidth = typeof window !== 'undefined' ? window.innerWidth : 400;
1631
- const windowHeight = typeof window !== 'undefined' ? window.innerHeight : 800;
1632
- let x = windowWidth - 76;
1633
- let y = Math.max(80, windowHeight * 0.4);
1634
- if (savedPos && typeof savedPos.x === 'number' && typeof savedPos.y === 'number') {
1635
- x = Math.min(Math.max(10, savedPos.x), windowWidth - 76);
1636
- y = Math.min(Math.max(60, savedPos.y), windowHeight - 60);
1637
- }
1638
- else if (typeof this.options.position === 'object') {
1639
- x = this.options.position.x;
1640
- y = this.options.position.y;
1641
- }
1642
- else if (this.options.position === 'left') {
1643
- x = 12;
1644
- }
1645
- this.setPosition(x, y);
1646
- }
1647
- setPosition(x, y) {
1648
- this.element.style.left = `${x}px`;
1649
- this.element.style.top = `${y}px`;
1650
- this.element.style.right = 'auto';
1651
- this.element.style.bottom = 'auto';
1652
- }
1653
- bindEvents() {
1654
- const onPointerDown = (e) => {
1655
- this.isDragging = true;
1656
- this.hasMoved = false;
1657
- this.startX = e.clientX;
1658
- this.startY = e.clientY;
1659
- const rect = this.element.getBoundingClientRect();
1660
- this.initialLeft = rect.left;
1661
- this.initialTop = rect.top;
1662
- this.element.classList.add('dragging');
1663
- this.element.setPointerCapture(e.pointerId);
1664
- };
1665
- const onPointerMove = (e) => {
1666
- if (!this.isDragging)
1667
- return;
1668
- const deltaX = e.clientX - this.startX;
1669
- const deltaY = e.clientY - this.startY;
1670
- if (Math.abs(deltaX) > 4 || Math.abs(deltaY) > 4) {
1671
- this.hasMoved = true;
1672
- }
1673
- let newX = this.initialLeft + deltaX;
1674
- let newY = this.initialTop + deltaY;
1675
- const maxX = window.innerWidth - this.element.offsetWidth - 8;
1676
- const maxY = window.innerHeight - this.element.offsetHeight - 8;
1677
- newX = Math.max(8, Math.min(newX, maxX));
1678
- newY = Math.max(40, Math.min(newY, maxY));
1679
- this.setPosition(newX, newY);
1680
- };
1681
- const onPointerUp = (e) => {
1682
- if (!this.isDragging)
1683
- return;
1684
- this.isDragging = false;
1685
- this.element.classList.remove('dragging');
1686
- try {
1687
- this.element.releasePointerCapture(e.pointerId);
1688
- }
1689
- catch {
1690
- // ignore
1691
- }
1692
- if (!this.hasMoved) {
1693
- // Tap / Click action
1694
- if (this.options.onClick) {
1695
- this.options.onClick();
1696
- }
1697
- }
1698
- else {
1699
- // Snap to nearest edge (left or right)
1700
- this.snapToEdge();
1701
- }
1702
- };
1703
- this.element.addEventListener('pointerdown', onPointerDown);
1704
- this.element.addEventListener('pointermove', onPointerMove);
1705
- this.element.addEventListener('pointerup', onPointerUp);
1706
- this.element.addEventListener('pointercancel', onPointerUp);
1707
- }
1708
- snapToEdge() {
1709
- const rect = this.element.getBoundingClientRect();
1710
- const windowWidth = window.innerWidth;
1711
- const windowHeight = window.innerHeight;
1712
- const snapLeft = 12;
1713
- const snapRight = windowWidth - rect.width - 12;
1714
- const targetX = rect.left + rect.width / 2 < windowWidth / 2 ? snapLeft : snapRight;
1715
- const targetY = Math.max(50, Math.min(rect.top, windowHeight - rect.height - 50));
1716
- this.element.style.transition = 'left 0.2s cubic-bezier(0.16, 1, 0.3, 1), top 0.2s cubic-bezier(0.16, 1, 0.3, 1)';
1717
- this.setPosition(targetX, targetY);
1718
- setTimeout(() => {
1719
- this.element.style.transition = '';
1720
- }, 200);
1721
- if (this.options.persistPosition && typeof localStorage !== 'undefined') {
1722
- try {
1723
- localStorage.setItem(STORAGE_KEY, JSON.stringify({ x: targetX, y: targetY }));
1724
- }
1725
- catch {
1726
- // ignore
1727
- }
1728
- }
1729
- }
1497
+ const STORAGE_KEY = "capdebug_btn_pos";
1498
+ class FloatingButton {
1499
+ element;
1500
+ badgeElement;
1501
+ options;
1502
+ isDragging = false;
1503
+ hasMoved = false;
1504
+ startX = 0;
1505
+ startY = 0;
1506
+ initialLeft = 0;
1507
+ initialTop = 0;
1508
+ constructor(options = {}) {
1509
+ this.options = {
1510
+ position: "right",
1511
+ persistPosition: true,
1512
+ ...options
1513
+ };
1514
+ this.element = document.createElement("div");
1515
+ this.element.className = "cd-floating-btn";
1516
+ this.element.setAttribute("role", "button");
1517
+ this.element.setAttribute("aria-label", "Open CapDebug");
1518
+ const logo = document.createElement("span");
1519
+ logo.className = "cd-btn-logo";
1520
+ logo.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 4px"><path d="m8 2 1.88 1.88"/><path d="M14.12 3.88 16 2"/><path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1"/><path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6"/><path d="M12 20v-9"/><path d="M6.53 9C4.6 8.8 3 7.1 3 5"/><path d="M6 13H2"/><path d="M3 21c0-2.1 1.7-3.9 3.8-4"/><path d="M20.97 5c0 2.1-1.6 3.8-3.5 4"/><path d="M22 13h-4"/><path d="M17.2 17c2.1.1 3.8 1.9 3.8 4"/></svg>CAP`;
1521
+ this.badgeElement = document.createElement("span");
1522
+ this.badgeElement.className = "cd-btn-badge";
1523
+ this.badgeElement.textContent = "0";
1524
+ this.element.appendChild(logo);
1525
+ this.element.appendChild(this.badgeElement);
1526
+ this.initPosition();
1527
+ this.bindEvents();
1528
+ }
1529
+ getElement() {
1530
+ return this.element;
1531
+ }
1532
+ setErrorCount(count) {
1533
+ if (count > 0) {
1534
+ this.badgeElement.textContent = count > 99 ? "99+" : String(count);
1535
+ this.badgeElement.classList.add("visible");
1536
+ } else {
1537
+ this.badgeElement.classList.remove("visible");
1538
+ }
1730
1539
  }
1540
+ show() {
1541
+ this.element.style.display = "flex";
1542
+ }
1543
+ hide() {
1544
+ this.element.style.display = "none";
1545
+ }
1546
+ initPosition() {
1547
+ let savedPos = null;
1548
+ if (this.options.persistPosition && typeof localStorage !== "undefined") {
1549
+ try {
1550
+ const stored = localStorage.getItem(STORAGE_KEY);
1551
+ if (stored) {
1552
+ savedPos = JSON.parse(stored);
1553
+ }
1554
+ } catch {
1555
+ }
1556
+ }
1557
+ const windowWidth = typeof window !== "undefined" ? window.innerWidth : 400;
1558
+ const windowHeight = typeof window !== "undefined" ? window.innerHeight : 800;
1559
+ let x = windowWidth - 76;
1560
+ let y = Math.max(80, windowHeight * 0.4);
1561
+ if (savedPos && typeof savedPos.x === "number" && typeof savedPos.y === "number") {
1562
+ x = Math.min(Math.max(10, savedPos.x), windowWidth - 76);
1563
+ y = Math.min(Math.max(60, savedPos.y), windowHeight - 60);
1564
+ } else if (typeof this.options.position === "object") {
1565
+ x = this.options.position.x;
1566
+ y = this.options.position.y;
1567
+ } else if (this.options.position === "left") {
1568
+ x = 12;
1569
+ }
1570
+ this.setPosition(x, y);
1571
+ }
1572
+ setPosition(x, y) {
1573
+ this.element.style.left = `${x}px`;
1574
+ this.element.style.top = `${y}px`;
1575
+ this.element.style.right = "auto";
1576
+ this.element.style.bottom = "auto";
1577
+ }
1578
+ bindEvents() {
1579
+ const onPointerDown = (e) => {
1580
+ this.isDragging = true;
1581
+ this.hasMoved = false;
1582
+ this.startX = e.clientX;
1583
+ this.startY = e.clientY;
1584
+ const rect = this.element.getBoundingClientRect();
1585
+ this.initialLeft = rect.left;
1586
+ this.initialTop = rect.top;
1587
+ this.element.classList.add("dragging");
1588
+ this.element.setPointerCapture(e.pointerId);
1589
+ };
1590
+ const onPointerMove = (e) => {
1591
+ if (!this.isDragging) return;
1592
+ const deltaX = e.clientX - this.startX;
1593
+ const deltaY = e.clientY - this.startY;
1594
+ if (Math.abs(deltaX) > 4 || Math.abs(deltaY) > 4) {
1595
+ this.hasMoved = true;
1596
+ }
1597
+ let newX = this.initialLeft + deltaX;
1598
+ let newY = this.initialTop + deltaY;
1599
+ const maxX = window.innerWidth - this.element.offsetWidth - 8;
1600
+ const maxY = window.innerHeight - this.element.offsetHeight - 8;
1601
+ newX = Math.max(8, Math.min(newX, maxX));
1602
+ newY = Math.max(40, Math.min(newY, maxY));
1603
+ this.setPosition(newX, newY);
1604
+ };
1605
+ const onPointerUp = (e) => {
1606
+ if (!this.isDragging) return;
1607
+ this.isDragging = false;
1608
+ this.element.classList.remove("dragging");
1609
+ try {
1610
+ this.element.releasePointerCapture(e.pointerId);
1611
+ } catch {
1612
+ }
1613
+ if (!this.hasMoved) {
1614
+ if (this.options.onClick) {
1615
+ this.options.onClick();
1616
+ }
1617
+ } else {
1618
+ this.snapToEdge();
1619
+ }
1620
+ };
1621
+ this.element.addEventListener("pointerdown", onPointerDown);
1622
+ this.element.addEventListener("pointermove", onPointerMove);
1623
+ this.element.addEventListener("pointerup", onPointerUp);
1624
+ this.element.addEventListener("pointercancel", onPointerUp);
1625
+ }
1626
+ snapToEdge() {
1627
+ const rect = this.element.getBoundingClientRect();
1628
+ const windowWidth = window.innerWidth;
1629
+ const windowHeight = window.innerHeight;
1630
+ const snapLeft = 12;
1631
+ const snapRight = windowWidth - rect.width - 12;
1632
+ const targetX = rect.left + rect.width / 2 < windowWidth / 2 ? snapLeft : snapRight;
1633
+ const targetY = Math.max(50, Math.min(rect.top, windowHeight - rect.height - 50));
1634
+ this.element.style.transition = "left 0.2s cubic-bezier(0.16, 1, 0.3, 1), top 0.2s cubic-bezier(0.16, 1, 0.3, 1)";
1635
+ this.setPosition(targetX, targetY);
1636
+ setTimeout(() => {
1637
+ this.element.style.transition = "";
1638
+ }, 200);
1639
+ if (this.options.persistPosition && typeof localStorage !== "undefined") {
1640
+ try {
1641
+ localStorage.setItem(STORAGE_KEY, JSON.stringify({ x: targetX, y: targetY }));
1642
+ } catch {
1643
+ }
1644
+ }
1645
+ }
1646
+ }
1731
1647
 
1732
- class JsonViewer {
1733
- static render(data, initialExpandedDepth = 2) {
1734
- const container = document.createElement('div');
1735
- container.className = 'cd-json-tree';
1736
- if (data === undefined) {
1737
- const undefinedSpan = document.createElement('span');
1738
- undefinedSpan.className = 'cd-json-null';
1739
- undefinedSpan.textContent = 'undefined';
1740
- container.appendChild(undefinedSpan);
1741
- return container;
1742
- }
1743
- const rootNode = JsonViewer.renderNode('', data, 0, initialExpandedDepth);
1744
- container.appendChild(rootNode);
1745
- return container;
1746
- }
1747
- static renderNode(key, value, depth, maxExpandedDepth) {
1748
- const node = document.createElement('div');
1749
- node.className = 'cd-json-node';
1750
- const row = document.createElement('div');
1751
- row.className = 'cd-json-row';
1752
- const isObject = typeof value === 'object' && value !== null;
1753
- const isArray = Array.isArray(value);
1754
- // Toggle button for objects/arrays
1755
- if (isObject) {
1756
- const toggle = document.createElement('span');
1757
- toggle.className = 'cd-json-toggle';
1758
- toggle.innerHTML = '▼';
1759
- row.appendChild(toggle);
1760
- }
1761
- else {
1762
- const spacer = document.createElement('span');
1763
- spacer.style.width = '14px';
1764
- spacer.style.display = 'inline-block';
1765
- row.appendChild(spacer);
1766
- }
1767
- // Key (if present)
1768
- if (key !== '') {
1769
- const keySpan = document.createElement('span');
1770
- keySpan.className = 'cd-json-key';
1771
- keySpan.textContent = typeof key === 'number' ? `[${key}]` : `"${key}"`;
1772
- row.appendChild(keySpan);
1773
- const colonSpan = document.createElement('span');
1774
- colonSpan.className = 'cd-json-colon';
1775
- colonSpan.textContent = ': ';
1776
- row.appendChild(colonSpan);
1777
- }
1778
- // Value preview or primitive
1779
- if (isObject) {
1780
- const entries = isArray
1781
- ? value.map((v, i) => [i, v])
1782
- : Object.entries(value);
1783
- const bracketOpen = isArray ? '[' : '{';
1784
- const bracketClose = isArray ? ']' : '}';
1785
- const previewSpan = document.createElement('span');
1786
- previewSpan.className = 'cd-json-colon';
1787
- previewSpan.textContent = `${bracketOpen} ${entries.length} ${isArray ? 'items' : 'keys'} ${bracketClose}`;
1788
- row.appendChild(previewSpan);
1789
- // Copy object JSON button
1790
- const copyBtn = document.createElement('button');
1791
- copyBtn.className = 'cd-json-copy-btn';
1792
- copyBtn.textContent = 'copy';
1793
- copyBtn.title = 'Copy branch JSON';
1794
- copyBtn.addEventListener('click', e => {
1795
- e.stopPropagation();
1796
- JsonViewer.copyToClipboard(JSON.stringify(value, null, 2), copyBtn);
1797
- });
1798
- row.appendChild(copyBtn);
1799
- node.appendChild(row);
1800
- // Children container
1801
- const childrenContainer = document.createElement('div');
1802
- childrenContainer.className = 'cd-json-children';
1803
- const isInitiallyExpanded = depth < maxExpandedDepth;
1804
- if (!isInitiallyExpanded) {
1805
- childrenContainer.classList.add('hidden');
1806
- const toggle = row.querySelector('.cd-json-toggle');
1807
- if (toggle)
1808
- toggle.classList.add('collapsed');
1809
- }
1810
- for (const [childKey, childVal] of entries) {
1811
- childrenContainer.appendChild(JsonViewer.renderNode(childKey, childVal, depth + 1, maxExpandedDepth));
1812
- }
1813
- node.appendChild(childrenContainer);
1814
- // Toggle collapse on row or toggle click
1815
- row.addEventListener('click', e => {
1816
- if (e.target.tagName.toLowerCase() === 'button')
1817
- return;
1818
- const toggle = row.querySelector('.cd-json-toggle');
1819
- const isHidden = childrenContainer.classList.toggle('hidden');
1820
- if (toggle) {
1821
- toggle.classList.toggle('collapsed', isHidden);
1822
- }
1823
- });
1824
- }
1825
- else {
1826
- // Primitive value
1827
- const valSpan = document.createElement('span');
1828
- const valType = typeof value;
1829
- if (value === null) {
1830
- valSpan.className = 'cd-json-null';
1831
- valSpan.textContent = 'null';
1832
- }
1833
- else if (valType === 'string') {
1834
- valSpan.className = 'cd-json-string';
1835
- valSpan.textContent = `"${value}"`;
1836
- }
1837
- else if (valType === 'number') {
1838
- valSpan.className = 'cd-json-number';
1839
- valSpan.textContent = String(value);
1840
- }
1841
- else if (valType === 'boolean') {
1842
- valSpan.className = 'cd-json-boolean';
1843
- valSpan.textContent = String(value);
1844
- }
1845
- else {
1846
- valSpan.className = 'cd-json-null';
1847
- valSpan.textContent = String(value);
1848
- }
1849
- row.appendChild(valSpan);
1850
- // Copy primitive value button
1851
- const copyBtn = document.createElement('button');
1852
- copyBtn.className = 'cd-json-copy-btn';
1853
- copyBtn.textContent = 'copy';
1854
- copyBtn.title = 'Copy value';
1855
- copyBtn.addEventListener('click', e => {
1856
- e.stopPropagation();
1857
- JsonViewer.copyToClipboard(String(value), copyBtn);
1858
- });
1859
- row.appendChild(copyBtn);
1860
- node.appendChild(row);
1861
- }
1862
- return node;
1863
- }
1864
- static async copyToClipboard(text, triggerBtn) {
1865
- try {
1866
- if (navigator.clipboard && window.isSecureContext) {
1867
- await navigator.clipboard.writeText(text);
1868
- }
1869
- else {
1870
- const textarea = document.createElement('textarea');
1871
- textarea.value = text;
1872
- textarea.style.position = 'fixed';
1873
- textarea.style.left = '-9999px';
1874
- textarea.style.top = '-9999px';
1875
- document.body.appendChild(textarea);
1876
- textarea.focus();
1877
- textarea.select();
1878
- document.execCommand('copy');
1879
- document.body.removeChild(textarea);
1880
- }
1881
- if (triggerBtn) {
1882
- const originalText = triggerBtn.textContent;
1883
- triggerBtn.textContent = 'copied!';
1884
- triggerBtn.style.color = '#34d399';
1885
- setTimeout(() => {
1886
- triggerBtn.textContent = originalText;
1887
- triggerBtn.style.color = '';
1888
- }, 1500);
1889
- }
1890
- return true;
1891
- }
1892
- catch {
1893
- return false;
1894
- }
1895
- }
1648
+ class JsonViewer {
1649
+ static render(data, initialExpandedDepth = 2) {
1650
+ const container = document.createElement("div");
1651
+ container.className = "cd-json-tree";
1652
+ if (data === void 0) {
1653
+ const undefinedSpan = document.createElement("span");
1654
+ undefinedSpan.className = "cd-json-null";
1655
+ undefinedSpan.textContent = "undefined";
1656
+ container.appendChild(undefinedSpan);
1657
+ return container;
1658
+ }
1659
+ const rootNode = JsonViewer.renderNode("", data, 0, initialExpandedDepth);
1660
+ container.appendChild(rootNode);
1661
+ return container;
1662
+ }
1663
+ static renderNode(key, value, depth, maxExpandedDepth) {
1664
+ const node = document.createElement("div");
1665
+ node.className = "cd-json-node";
1666
+ const row = document.createElement("div");
1667
+ row.className = "cd-json-row";
1668
+ const isObject = typeof value === "object" && value !== null;
1669
+ const isArray = Array.isArray(value);
1670
+ if (isObject) {
1671
+ const toggle = document.createElement("span");
1672
+ toggle.className = "cd-json-toggle";
1673
+ toggle.innerHTML = "\u25BC";
1674
+ row.appendChild(toggle);
1675
+ } else {
1676
+ const spacer = document.createElement("span");
1677
+ spacer.style.width = "14px";
1678
+ spacer.style.display = "inline-block";
1679
+ row.appendChild(spacer);
1680
+ }
1681
+ if (key !== "") {
1682
+ const keySpan = document.createElement("span");
1683
+ keySpan.className = "cd-json-key";
1684
+ keySpan.textContent = typeof key === "number" ? `[${key}]` : `"${key}"`;
1685
+ row.appendChild(keySpan);
1686
+ const colonSpan = document.createElement("span");
1687
+ colonSpan.className = "cd-json-colon";
1688
+ colonSpan.textContent = ": ";
1689
+ row.appendChild(colonSpan);
1690
+ }
1691
+ if (isObject) {
1692
+ const entries = isArray ? value.map((v, i) => [i, v]) : Object.entries(value);
1693
+ const bracketOpen = isArray ? "[" : "{";
1694
+ const bracketClose = isArray ? "]" : "}";
1695
+ const previewSpan = document.createElement("span");
1696
+ previewSpan.className = "cd-json-colon";
1697
+ previewSpan.textContent = `${bracketOpen} ${entries.length} ${isArray ? "items" : "keys"} ${bracketClose}`;
1698
+ row.appendChild(previewSpan);
1699
+ const copyBtn = document.createElement("button");
1700
+ copyBtn.className = "cd-json-copy-btn";
1701
+ copyBtn.textContent = "copy";
1702
+ copyBtn.title = "Copy branch JSON";
1703
+ copyBtn.addEventListener("click", (e) => {
1704
+ e.stopPropagation();
1705
+ JsonViewer.copyToClipboard(JSON.stringify(value, null, 2), copyBtn);
1706
+ });
1707
+ row.appendChild(copyBtn);
1708
+ node.appendChild(row);
1709
+ const childrenContainer = document.createElement("div");
1710
+ childrenContainer.className = "cd-json-children";
1711
+ const isInitiallyExpanded = depth < maxExpandedDepth;
1712
+ if (!isInitiallyExpanded) {
1713
+ childrenContainer.classList.add("hidden");
1714
+ const toggle = row.querySelector(".cd-json-toggle");
1715
+ if (toggle) toggle.classList.add("collapsed");
1716
+ }
1717
+ for (const [childKey, childVal] of entries) {
1718
+ childrenContainer.appendChild(
1719
+ JsonViewer.renderNode(childKey, childVal, depth + 1, maxExpandedDepth)
1720
+ );
1721
+ }
1722
+ node.appendChild(childrenContainer);
1723
+ row.addEventListener("click", (e) => {
1724
+ if (e.target.tagName.toLowerCase() === "button") return;
1725
+ const toggle = row.querySelector(".cd-json-toggle");
1726
+ const isHidden = childrenContainer.classList.toggle("hidden");
1727
+ if (toggle) {
1728
+ toggle.classList.toggle("collapsed", isHidden);
1729
+ }
1730
+ });
1731
+ } else {
1732
+ const valSpan = document.createElement("span");
1733
+ const valType = typeof value;
1734
+ if (value === null) {
1735
+ valSpan.className = "cd-json-null";
1736
+ valSpan.textContent = "null";
1737
+ } else if (valType === "string") {
1738
+ valSpan.className = "cd-json-string";
1739
+ valSpan.textContent = `"${value}"`;
1740
+ } else if (valType === "number") {
1741
+ valSpan.className = "cd-json-number";
1742
+ valSpan.textContent = String(value);
1743
+ } else if (valType === "boolean") {
1744
+ valSpan.className = "cd-json-boolean";
1745
+ valSpan.textContent = String(value);
1746
+ } else {
1747
+ valSpan.className = "cd-json-null";
1748
+ valSpan.textContent = String(value);
1749
+ }
1750
+ row.appendChild(valSpan);
1751
+ const copyBtn = document.createElement("button");
1752
+ copyBtn.className = "cd-json-copy-btn";
1753
+ copyBtn.textContent = "copy";
1754
+ copyBtn.title = "Copy value";
1755
+ copyBtn.addEventListener("click", (e) => {
1756
+ e.stopPropagation();
1757
+ JsonViewer.copyToClipboard(String(value), copyBtn);
1758
+ });
1759
+ row.appendChild(copyBtn);
1760
+ node.appendChild(row);
1761
+ }
1762
+ return node;
1896
1763
  }
1764
+ static async copyToClipboard(text, triggerBtn) {
1765
+ try {
1766
+ if (navigator.clipboard && window.isSecureContext) {
1767
+ await navigator.clipboard.writeText(text);
1768
+ } else {
1769
+ const textarea = document.createElement("textarea");
1770
+ textarea.value = text;
1771
+ textarea.style.position = "fixed";
1772
+ textarea.style.left = "-9999px";
1773
+ textarea.style.top = "-9999px";
1774
+ document.body.appendChild(textarea);
1775
+ textarea.focus();
1776
+ textarea.select();
1777
+ document.execCommand("copy");
1778
+ document.body.removeChild(textarea);
1779
+ }
1780
+ if (triggerBtn) {
1781
+ const originalText = triggerBtn.textContent;
1782
+ triggerBtn.textContent = "copied!";
1783
+ triggerBtn.style.color = "#34d399";
1784
+ setTimeout(() => {
1785
+ triggerBtn.textContent = originalText;
1786
+ triggerBtn.style.color = "";
1787
+ }, 1500);
1788
+ }
1789
+ return true;
1790
+ } catch {
1791
+ return false;
1792
+ }
1793
+ }
1794
+ }
1897
1795
 
1898
- const CapDebugNative = core.registerPlugin('CapDebug', {
1899
- web: () => Promise.resolve().then(function () { return web; }).then(m => new m.CapDebugWeb()),
1900
- });
1901
-
1902
- class DebugPanel {
1903
- element;
1904
- backdrop;
1905
- store;
1906
- options;
1907
- isOpen = false;
1908
- // Header UI
1909
- statusIndicator;
1910
- titleCountSpan;
1911
- pauseBtn;
1912
- // Tab elements
1913
- tabElements = new Map();
1914
- tabBadgeElements = new Map();
1915
- // Search & Filter UI
1916
- searchInput;
1917
- levelPills = new Map();
1918
- // Content
1919
- contentContainer;
1920
- eventListContainer;
1921
- deviceViewContainer;
1922
- // Detail Overlay
1923
- detailOverlay;
1924
- selectedEvent = null;
1925
- // Device tab state
1926
- isDeviceLoading = false;
1927
- deviceData = null;
1928
- constructor(store, options = {}) {
1929
- this.store = store;
1930
- this.options = {
1931
- defaultTab: 'all',
1932
- ...options,
1933
- };
1934
- this.backdrop = document.createElement('div');
1935
- this.backdrop.className = 'cd-backdrop';
1936
- this.element = document.createElement('div');
1937
- this.element.className = 'cd-panel';
1938
- this.buildUI();
1939
- this.bindStore();
1940
- if (this.options.defaultTab) {
1941
- this.store.setFilter({ tab: this.options.defaultTab });
1942
- }
1943
- }
1944
- getElement() {
1945
- return this.element;
1946
- }
1947
- getBackdrop() {
1948
- return this.backdrop;
1949
- }
1950
- open() {
1951
- this.isOpen = true;
1952
- this.element.classList.add('open');
1953
- this.backdrop.classList.add('open');
1954
- // If device tab is active, trigger lazy load
1955
- if (this.store.getFilter().tab === 'device') {
1956
- this.loadDeviceDiagnostics();
1957
- }
1958
- }
1959
- close() {
1960
- this.isOpen = false;
1961
- this.element.classList.remove('open');
1962
- this.backdrop.classList.remove('open');
1963
- this.closeDetail();
1964
- if (this.options.onClose) {
1965
- this.options.onClose();
1966
- }
1967
- }
1968
- toggle() {
1969
- if (this.isOpen) {
1970
- this.close();
1971
- return false;
1972
- }
1973
- else {
1974
- this.open();
1975
- return true;
1976
- }
1977
- }
1978
- isPanelOpen() {
1979
- return this.isOpen;
1980
- }
1981
- buildUI() {
1982
- this.backdrop.addEventListener('click', () => this.close());
1983
- // 1. Header
1984
- const header = document.createElement('div');
1985
- header.className = 'cd-header';
1986
- const headerLeft = document.createElement('div');
1987
- headerLeft.className = 'cd-header-left';
1988
- this.statusIndicator = document.createElement('div');
1989
- this.statusIndicator.className = 'cd-status-indicator';
1990
- this.statusIndicator.title = 'CapDebug Active';
1991
- const headerTitle = document.createElement('div');
1992
- headerTitle.className = 'cd-header-title';
1993
- headerTitle.innerHTML = `<span>CapDebug</span>`;
1994
- this.titleCountSpan = document.createElement('span');
1995
- this.titleCountSpan.style.color = 'var(--cd-text-muted)';
1996
- this.titleCountSpan.style.fontSize = '11px';
1997
- this.titleCountSpan.textContent = '(0)';
1998
- headerTitle.appendChild(this.titleCountSpan);
1999
- headerLeft.appendChild(this.statusIndicator);
2000
- headerLeft.appendChild(headerTitle);
2001
- const headerActions = document.createElement('div');
2002
- headerActions.className = 'cd-header-actions';
2003
- // Pause/Resume Button
2004
- this.pauseBtn = document.createElement('button');
2005
- this.pauseBtn.className = 'cd-btn-icon';
2006
- this.pauseBtn.title = 'Pause/Resume capture';
2007
- this.pauseBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>`;
2008
- this.pauseBtn.addEventListener('click', () => {
2009
- const isPaused = this.store.togglePause();
2010
- this.updatePauseState(isPaused);
2011
- });
2012
- // Clear Button
2013
- const clearBtn = document.createElement('button');
2014
- clearBtn.className = 'cd-btn-icon';
2015
- clearBtn.title = 'Clear events';
2016
- clearBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/></svg>`;
2017
- clearBtn.addEventListener('click', () => {
2018
- this.store.clear();
2019
- this.closeDetail();
2020
- });
2021
- // Export Button
2022
- const exportBtn = document.createElement('button');
2023
- exportBtn.className = 'cd-btn-icon';
2024
- exportBtn.title = 'Export JSON to clipboard';
2025
- exportBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>`;
2026
- exportBtn.addEventListener('click', async () => {
2027
- const json = this.store.exportJson();
2028
- await JsonViewer.copyToClipboard(json, exportBtn);
2029
- });
2030
- // Close Button
2031
- const closeBtn = document.createElement('button');
2032
- closeBtn.className = 'cd-btn-icon';
2033
- closeBtn.title = 'Close viewer';
2034
- closeBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
2035
- closeBtn.addEventListener('click', () => this.close());
2036
- headerActions.appendChild(this.pauseBtn);
2037
- headerActions.appendChild(clearBtn);
2038
- headerActions.appendChild(exportBtn);
2039
- headerActions.appendChild(closeBtn);
2040
- header.appendChild(headerLeft);
2041
- header.appendChild(headerActions);
2042
- this.element.appendChild(header);
2043
- // 2. Tabs Bar
2044
- const tabsBar = document.createElement('div');
2045
- tabsBar.className = 'cd-tabs-bar';
2046
- const tabs = [
2047
- { id: 'all', label: 'All' },
2048
- { id: 'console', label: 'Console' },
2049
- { id: 'errors', label: 'Errors' },
2050
- { id: 'events', label: 'Events' },
2051
- { id: 'native', label: 'Native' },
2052
- { id: 'device', label: 'Device' },
2053
- { id: 'network', label: 'Network' },
2054
- { id: 'bridge', label: 'Bridge' },
2055
- ];
2056
- for (const { id, label } of tabs) {
2057
- const tabBtn = document.createElement('button');
2058
- tabBtn.className = 'cd-tab';
2059
- if (id === this.options.defaultTab) {
2060
- tabBtn.classList.add('active');
2061
- }
2062
- const labelSpan = document.createElement('span');
2063
- labelSpan.textContent = label;
2064
- const badgeSpan = document.createElement('span');
2065
- badgeSpan.className = 'cd-tab-badge';
2066
- badgeSpan.textContent = '0';
2067
- tabBtn.appendChild(labelSpan);
2068
- tabBtn.appendChild(badgeSpan);
2069
- tabBtn.addEventListener('click', () => {
2070
- this.selectTab(id);
2071
- });
2072
- this.tabElements.set(id, tabBtn);
2073
- this.tabBadgeElements.set(id, badgeSpan);
2074
- tabsBar.appendChild(tabBtn);
2075
- }
2076
- this.element.appendChild(tabsBar);
2077
- // 3. Toolbar (Search & Level Filters)
2078
- const toolbar = document.createElement('div');
2079
- toolbar.className = 'cd-toolbar';
2080
- this.searchInput = document.createElement('input');
2081
- this.searchInput.className = 'cd-search-input';
2082
- this.searchInput.type = 'text';
2083
- this.searchInput.placeholder = 'Filter logs, types, payloads...';
2084
- this.searchInput.addEventListener('input', () => {
2085
- this.store.setFilter({ search: this.searchInput.value });
2086
- });
2087
- const levelFilters = document.createElement('div');
2088
- levelFilters.className = 'cd-level-filters';
2089
- const levels = ['all', 'error', 'warn', 'info', 'debug'];
2090
- for (const lvl of levels) {
2091
- const pill = document.createElement('button');
2092
- pill.className = 'cd-level-pill';
2093
- pill.setAttribute('data-level', lvl);
2094
- pill.textContent = lvl === 'all' ? 'All' : lvl.toUpperCase();
2095
- if (lvl === 'all')
2096
- pill.classList.add('active');
2097
- pill.addEventListener('click', () => {
2098
- this.selectLevel(lvl);
2099
- });
2100
- this.levelPills.set(lvl, pill);
2101
- levelFilters.appendChild(pill);
2102
- }
2103
- toolbar.appendChild(this.searchInput);
2104
- toolbar.appendChild(levelFilters);
2105
- this.element.appendChild(toolbar);
2106
- // 4. Content Area
2107
- this.contentContainer = document.createElement('div');
2108
- this.contentContainer.className = 'cd-content';
2109
- this.eventListContainer = document.createElement('div');
2110
- this.eventListContainer.className = 'cd-event-list';
2111
- this.deviceViewContainer = document.createElement('div');
2112
- this.deviceViewContainer.className = 'cd-device-view';
2113
- this.deviceViewContainer.style.display = 'none';
2114
- this.contentContainer.appendChild(this.eventListContainer);
2115
- this.contentContainer.appendChild(this.deviceViewContainer);
2116
- this.element.appendChild(this.contentContainer);
2117
- // 5. Detail Overlay
2118
- this.buildDetailOverlay();
2119
- }
2120
- selectTab(tab) {
2121
- for (const [id, el] of this.tabElements.entries()) {
2122
- el.classList.toggle('active', id === tab);
2123
- }
2124
- this.store.setFilter({ tab });
2125
- this.closeDetail();
2126
- if (tab === 'device') {
2127
- this.eventListContainer.style.display = 'none';
2128
- this.deviceViewContainer.style.display = 'flex';
2129
- this.loadDeviceDiagnostics();
2130
- }
2131
- else {
2132
- this.eventListContainer.style.display = 'flex';
2133
- this.deviceViewContainer.style.display = 'none';
2134
- }
2135
- }
2136
- selectLevel(level) {
2137
- for (const [lvl, pill] of this.levelPills.entries()) {
2138
- pill.classList.toggle('active', lvl === level);
2139
- }
2140
- this.store.setFilter({ level });
2141
- }
2142
- updatePauseState(isPaused) {
2143
- this.statusIndicator.classList.toggle('paused', isPaused);
2144
- this.pauseBtn.classList.toggle('active', isPaused);
2145
- this.pauseBtn.title = isPaused ? 'Resume capture' : 'Pause capture';
2146
- }
2147
- bindStore() {
2148
- this.store.subscribe((events, store) => {
2149
- this.renderEventList(events);
2150
- this.renderCounts(store.getCounts());
2151
- this.updatePauseState(store.isPaused());
2152
- });
2153
- }
2154
- renderCounts(counts) {
2155
- this.titleCountSpan.textContent = `(${counts.all})`;
2156
- for (const [tab, badge] of this.tabBadgeElements.entries()) {
2157
- if (tab === 'device') {
2158
- badge.style.display = 'none';
2159
- }
2160
- else {
2161
- const count = counts[tab] || 0;
2162
- badge.textContent = count > 999 ? '999+' : String(count);
2163
- }
2164
- }
2165
- }
2166
- renderEventList(events) {
2167
- if (this.store.getFilter().tab === 'device') {
2168
- return;
2169
- }
2170
- this.eventListContainer.innerHTML = '';
2171
- if (events.length === 0) {
2172
- const empty = document.createElement('div');
2173
- empty.className = 'cd-empty-state';
2174
- empty.innerHTML = `
1796
+ const CapDebugNative = core.registerPlugin("CapDebug", {
1797
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.CapDebugWeb())
1798
+ });
1799
+
1800
+ class DebugPanel {
1801
+ element;
1802
+ backdrop;
1803
+ store;
1804
+ options;
1805
+ isOpen = false;
1806
+ // Header UI
1807
+ statusIndicator;
1808
+ titleCountSpan;
1809
+ pauseBtn;
1810
+ // Tab elements
1811
+ tabElements = /* @__PURE__ */ new Map();
1812
+ tabBadgeElements = /* @__PURE__ */ new Map();
1813
+ // Search & Filter UI
1814
+ searchInput;
1815
+ levelPills = /* @__PURE__ */ new Map();
1816
+ // Content
1817
+ contentContainer;
1818
+ eventListContainer;
1819
+ deviceViewContainer;
1820
+ // Detail Overlay
1821
+ detailOverlay;
1822
+ selectedEvent = null;
1823
+ // Device tab state
1824
+ isDeviceLoading = false;
1825
+ deviceData = null;
1826
+ constructor(store, options = {}) {
1827
+ this.store = store;
1828
+ this.options = {
1829
+ defaultTab: "all",
1830
+ ...options
1831
+ };
1832
+ this.backdrop = document.createElement("div");
1833
+ this.backdrop.className = "cd-backdrop";
1834
+ this.element = document.createElement("div");
1835
+ this.element.className = "cd-panel";
1836
+ this.buildUI();
1837
+ this.bindStore();
1838
+ if (this.options.defaultTab) {
1839
+ this.store.setFilter({ tab: this.options.defaultTab });
1840
+ }
1841
+ }
1842
+ getElement() {
1843
+ return this.element;
1844
+ }
1845
+ getBackdrop() {
1846
+ return this.backdrop;
1847
+ }
1848
+ open() {
1849
+ this.isOpen = true;
1850
+ this.element.classList.add("open");
1851
+ this.backdrop.classList.add("open");
1852
+ if (this.store.getFilter().tab === "device") {
1853
+ this.loadDeviceDiagnostics();
1854
+ }
1855
+ }
1856
+ close() {
1857
+ this.isOpen = false;
1858
+ this.element.classList.remove("open");
1859
+ this.backdrop.classList.remove("open");
1860
+ this.closeDetail();
1861
+ if (this.options.onClose) {
1862
+ this.options.onClose();
1863
+ }
1864
+ }
1865
+ toggle() {
1866
+ if (this.isOpen) {
1867
+ this.close();
1868
+ return false;
1869
+ } else {
1870
+ this.open();
1871
+ return true;
1872
+ }
1873
+ }
1874
+ isPanelOpen() {
1875
+ return this.isOpen;
1876
+ }
1877
+ buildUI() {
1878
+ this.backdrop.addEventListener("click", () => this.close());
1879
+ const header = document.createElement("div");
1880
+ header.className = "cd-header";
1881
+ const headerLeft = document.createElement("div");
1882
+ headerLeft.className = "cd-header-left";
1883
+ this.statusIndicator = document.createElement("div");
1884
+ this.statusIndicator.className = "cd-status-indicator";
1885
+ this.statusIndicator.title = "CapDebug Active";
1886
+ const headerTitle = document.createElement("div");
1887
+ headerTitle.className = "cd-header-title";
1888
+ headerTitle.innerHTML = `<span>CapDebug</span>`;
1889
+ this.titleCountSpan = document.createElement("span");
1890
+ this.titleCountSpan.style.color = "var(--cd-text-muted)";
1891
+ this.titleCountSpan.style.fontSize = "11px";
1892
+ this.titleCountSpan.textContent = "(0)";
1893
+ headerTitle.appendChild(this.titleCountSpan);
1894
+ headerLeft.appendChild(this.statusIndicator);
1895
+ headerLeft.appendChild(headerTitle);
1896
+ const headerActions = document.createElement("div");
1897
+ headerActions.className = "cd-header-actions";
1898
+ this.pauseBtn = document.createElement("button");
1899
+ this.pauseBtn.className = "cd-btn-icon";
1900
+ this.pauseBtn.title = "Pause/Resume capture";
1901
+ this.pauseBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>`;
1902
+ this.pauseBtn.addEventListener("click", () => {
1903
+ const isPaused = this.store.togglePause();
1904
+ this.updatePauseState(isPaused);
1905
+ });
1906
+ const clearBtn = document.createElement("button");
1907
+ clearBtn.className = "cd-btn-icon";
1908
+ clearBtn.title = "Clear events";
1909
+ clearBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/></svg>`;
1910
+ clearBtn.addEventListener("click", () => {
1911
+ this.store.clear();
1912
+ this.closeDetail();
1913
+ });
1914
+ const exportBtn = document.createElement("button");
1915
+ exportBtn.className = "cd-btn-icon";
1916
+ exportBtn.title = "Export JSON to clipboard";
1917
+ exportBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>`;
1918
+ exportBtn.addEventListener("click", async () => {
1919
+ const json = this.store.exportJson();
1920
+ await JsonViewer.copyToClipboard(json, exportBtn);
1921
+ });
1922
+ const closeBtn = document.createElement("button");
1923
+ closeBtn.className = "cd-btn-icon";
1924
+ closeBtn.title = "Close viewer";
1925
+ closeBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
1926
+ closeBtn.addEventListener("click", () => this.close());
1927
+ headerActions.appendChild(this.pauseBtn);
1928
+ headerActions.appendChild(clearBtn);
1929
+ headerActions.appendChild(exportBtn);
1930
+ headerActions.appendChild(closeBtn);
1931
+ header.appendChild(headerLeft);
1932
+ header.appendChild(headerActions);
1933
+ this.element.appendChild(header);
1934
+ const tabsBar = document.createElement("div");
1935
+ tabsBar.className = "cd-tabs-bar";
1936
+ const tabs = [
1937
+ { id: "all", label: "All" },
1938
+ { id: "console", label: "Console" },
1939
+ { id: "errors", label: "Errors" },
1940
+ { id: "events", label: "Events" },
1941
+ { id: "native", label: "Native" },
1942
+ { id: "device", label: "Device" },
1943
+ { id: "network", label: "Network" },
1944
+ { id: "bridge", label: "Bridge" }
1945
+ ];
1946
+ for (const { id, label } of tabs) {
1947
+ const tabBtn = document.createElement("button");
1948
+ tabBtn.className = "cd-tab";
1949
+ if (id === this.options.defaultTab) {
1950
+ tabBtn.classList.add("active");
1951
+ }
1952
+ const labelSpan = document.createElement("span");
1953
+ labelSpan.textContent = label;
1954
+ const badgeSpan = document.createElement("span");
1955
+ badgeSpan.className = "cd-tab-badge";
1956
+ badgeSpan.textContent = "0";
1957
+ tabBtn.appendChild(labelSpan);
1958
+ tabBtn.appendChild(badgeSpan);
1959
+ tabBtn.addEventListener("click", () => {
1960
+ this.selectTab(id);
1961
+ });
1962
+ this.tabElements.set(id, tabBtn);
1963
+ this.tabBadgeElements.set(id, badgeSpan);
1964
+ tabsBar.appendChild(tabBtn);
1965
+ }
1966
+ this.element.appendChild(tabsBar);
1967
+ const toolbar = document.createElement("div");
1968
+ toolbar.className = "cd-toolbar";
1969
+ this.searchInput = document.createElement("input");
1970
+ this.searchInput.className = "cd-search-input";
1971
+ this.searchInput.type = "text";
1972
+ this.searchInput.placeholder = "Filter logs, types, payloads...";
1973
+ this.searchInput.addEventListener("input", () => {
1974
+ this.store.setFilter({ search: this.searchInput.value });
1975
+ });
1976
+ const levelFilters = document.createElement("div");
1977
+ levelFilters.className = "cd-level-filters";
1978
+ const levels = ["all", "error", "warn", "info", "debug"];
1979
+ for (const lvl of levels) {
1980
+ const pill = document.createElement("button");
1981
+ pill.className = "cd-level-pill";
1982
+ pill.setAttribute("data-level", lvl);
1983
+ pill.textContent = lvl === "all" ? "All" : lvl.toUpperCase();
1984
+ if (lvl === "all") pill.classList.add("active");
1985
+ pill.addEventListener("click", () => {
1986
+ this.selectLevel(lvl);
1987
+ });
1988
+ this.levelPills.set(lvl, pill);
1989
+ levelFilters.appendChild(pill);
1990
+ }
1991
+ toolbar.appendChild(this.searchInput);
1992
+ toolbar.appendChild(levelFilters);
1993
+ this.element.appendChild(toolbar);
1994
+ this.contentContainer = document.createElement("div");
1995
+ this.contentContainer.className = "cd-content";
1996
+ this.eventListContainer = document.createElement("div");
1997
+ this.eventListContainer.className = "cd-event-list";
1998
+ this.deviceViewContainer = document.createElement("div");
1999
+ this.deviceViewContainer.className = "cd-device-view";
2000
+ this.deviceViewContainer.style.display = "none";
2001
+ this.contentContainer.appendChild(this.eventListContainer);
2002
+ this.contentContainer.appendChild(this.deviceViewContainer);
2003
+ this.element.appendChild(this.contentContainer);
2004
+ this.buildDetailOverlay();
2005
+ }
2006
+ selectTab(tab) {
2007
+ for (const [id, el] of this.tabElements.entries()) {
2008
+ el.classList.toggle("active", id === tab);
2009
+ }
2010
+ this.store.setFilter({ tab });
2011
+ this.closeDetail();
2012
+ if (tab === "device") {
2013
+ this.eventListContainer.style.display = "none";
2014
+ this.deviceViewContainer.style.display = "flex";
2015
+ this.loadDeviceDiagnostics();
2016
+ } else {
2017
+ this.eventListContainer.style.display = "flex";
2018
+ this.deviceViewContainer.style.display = "none";
2019
+ }
2020
+ }
2021
+ selectLevel(level) {
2022
+ for (const [lvl, pill] of this.levelPills.entries()) {
2023
+ pill.classList.toggle("active", lvl === level);
2024
+ }
2025
+ this.store.setFilter({ level });
2026
+ }
2027
+ updatePauseState(isPaused) {
2028
+ this.statusIndicator.classList.toggle("paused", isPaused);
2029
+ this.pauseBtn.classList.toggle("active", isPaused);
2030
+ this.pauseBtn.title = isPaused ? "Resume capture" : "Pause capture";
2031
+ }
2032
+ bindStore() {
2033
+ this.store.subscribe((events, store) => {
2034
+ this.renderEventList(events);
2035
+ this.renderCounts(store.getCounts());
2036
+ this.updatePauseState(store.isPaused());
2037
+ });
2038
+ }
2039
+ renderCounts(counts) {
2040
+ this.titleCountSpan.textContent = `(${counts.all})`;
2041
+ for (const [tab, badge] of this.tabBadgeElements.entries()) {
2042
+ if (tab === "device") {
2043
+ badge.style.display = "none";
2044
+ } else {
2045
+ const count = counts[tab] || 0;
2046
+ badge.textContent = count > 999 ? "999+" : String(count);
2047
+ }
2048
+ }
2049
+ }
2050
+ renderEventList(events) {
2051
+ if (this.store.getFilter().tab === "device") {
2052
+ return;
2053
+ }
2054
+ this.eventListContainer.innerHTML = "";
2055
+ if (events.length === 0) {
2056
+ const empty = document.createElement("div");
2057
+ empty.className = "cd-empty-state";
2058
+ empty.innerHTML = `
2175
2059
  <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
2176
2060
  <span>No events match current filter</span>
2177
2061
  `;
2178
- this.eventListContainer.appendChild(empty);
2179
- return;
2180
- }
2181
- // Render newest items at the top
2182
- for (let i = events.length - 1; i >= 0; i--) {
2183
- const event = events[i];
2184
- const row = this.createEventRow(event);
2185
- this.eventListContainer.appendChild(row);
2186
- }
2187
- }
2188
- createEventRow(event) {
2189
- const row = document.createElement('div');
2190
- row.className = 'cd-event-row';
2191
- row.setAttribute('data-level', event.level || 'info');
2192
- const dot = document.createElement('div');
2193
- dot.className = 'cd-event-level-dot';
2194
- const time = document.createElement('div');
2195
- time.className = 'cd-event-time';
2196
- time.textContent = this.formatTime(event.timestamp);
2197
- const source = document.createElement('div');
2198
- source.className = 'cd-event-source';
2199
- source.textContent = event.source;
2200
- const main = document.createElement('div');
2201
- main.className = 'cd-event-main';
2202
- const type = document.createElement('div');
2203
- type.className = 'cd-event-type';
2204
- type.textContent = event.type;
2205
- main.appendChild(type);
2206
- if (event.message) {
2207
- const msg = document.createElement('div');
2208
- msg.className = 'cd-event-msg';
2209
- msg.textContent = event.message;
2210
- main.appendChild(msg);
2211
- }
2212
- row.appendChild(dot);
2213
- row.appendChild(time);
2214
- row.appendChild(source);
2215
- row.appendChild(main);
2216
- if (event.duration !== undefined) {
2217
- const duration = document.createElement('div');
2218
- duration.className = 'cd-event-duration';
2219
- duration.textContent = `${event.duration}ms`;
2220
- row.appendChild(duration);
2221
- }
2222
- row.addEventListener('click', () => {
2223
- this.showDetail(event);
2224
- });
2225
- return row;
2226
- }
2227
- buildDetailOverlay() {
2228
- this.detailOverlay = document.createElement('div');
2229
- this.detailOverlay.className = 'cd-detail-overlay';
2230
- const header = document.createElement('div');
2231
- header.className = 'cd-detail-header';
2232
- const backBtn = document.createElement('button');
2233
- backBtn.className = 'cd-detail-back';
2234
- backBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg> Back`;
2235
- backBtn.addEventListener('click', () => this.closeDetail());
2236
- const copyAllBtn = document.createElement('button');
2237
- copyAllBtn.className = 'cd-copy-btn-sm';
2238
- copyAllBtn.textContent = 'Copy JSON';
2239
- copyAllBtn.addEventListener('click', async () => {
2240
- if (this.selectedEvent) {
2241
- await JsonViewer.copyToClipboard(JSON.stringify(this.selectedEvent, null, 2), copyAllBtn);
2242
- }
2243
- });
2244
- header.appendChild(backBtn);
2245
- header.appendChild(copyAllBtn);
2246
- this.detailOverlay.appendChild(header);
2247
- const body = document.createElement('div');
2248
- body.className = 'cd-detail-body';
2249
- this.detailOverlay.appendChild(body);
2250
- this.contentContainer.appendChild(this.detailOverlay);
2251
- }
2252
- showDetail(event) {
2253
- this.selectedEvent = event;
2254
- const body = this.detailOverlay.querySelector('.cd-detail-body');
2255
- body.innerHTML = '';
2256
- // 1. Meta Grid
2257
- const metaGrid = document.createElement('div');
2258
- metaGrid.className = 'cd-meta-grid';
2259
- const addMeta = (label, value) => {
2260
- if (value === undefined)
2261
- return;
2262
- const item = document.createElement('div');
2263
- item.className = 'cd-meta-item';
2264
- item.innerHTML = `
2062
+ this.eventListContainer.appendChild(empty);
2063
+ return;
2064
+ }
2065
+ for (let i = events.length - 1; i >= 0; i--) {
2066
+ const event = events[i];
2067
+ const row = this.createEventRow(event);
2068
+ this.eventListContainer.appendChild(row);
2069
+ }
2070
+ }
2071
+ createEventRow(event) {
2072
+ const row = document.createElement("div");
2073
+ row.className = "cd-event-row";
2074
+ row.setAttribute("data-level", event.level || "info");
2075
+ const dot = document.createElement("div");
2076
+ dot.className = "cd-event-level-dot";
2077
+ const time = document.createElement("div");
2078
+ time.className = "cd-event-time";
2079
+ time.textContent = this.formatTime(event.timestamp);
2080
+ const source = document.createElement("div");
2081
+ source.className = "cd-event-source";
2082
+ source.textContent = event.source;
2083
+ const main = document.createElement("div");
2084
+ main.className = "cd-event-main";
2085
+ const type = document.createElement("div");
2086
+ type.className = "cd-event-type";
2087
+ type.textContent = event.type;
2088
+ main.appendChild(type);
2089
+ if (event.message) {
2090
+ const msg = document.createElement("div");
2091
+ msg.className = "cd-event-msg";
2092
+ msg.textContent = event.message;
2093
+ main.appendChild(msg);
2094
+ }
2095
+ row.appendChild(dot);
2096
+ row.appendChild(time);
2097
+ row.appendChild(source);
2098
+ row.appendChild(main);
2099
+ if (event.duration !== void 0) {
2100
+ const duration = document.createElement("div");
2101
+ duration.className = "cd-event-duration";
2102
+ duration.textContent = `${event.duration}ms`;
2103
+ row.appendChild(duration);
2104
+ }
2105
+ row.addEventListener("click", () => {
2106
+ this.showDetail(event);
2107
+ });
2108
+ return row;
2109
+ }
2110
+ buildDetailOverlay() {
2111
+ this.detailOverlay = document.createElement("div");
2112
+ this.detailOverlay.className = "cd-detail-overlay";
2113
+ const header = document.createElement("div");
2114
+ header.className = "cd-detail-header";
2115
+ const backBtn = document.createElement("button");
2116
+ backBtn.className = "cd-detail-back";
2117
+ backBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg> Back`;
2118
+ backBtn.addEventListener("click", () => this.closeDetail());
2119
+ const copyAllBtn = document.createElement("button");
2120
+ copyAllBtn.className = "cd-copy-btn-sm";
2121
+ copyAllBtn.textContent = "Copy JSON";
2122
+ copyAllBtn.addEventListener("click", async () => {
2123
+ if (this.selectedEvent) {
2124
+ await JsonViewer.copyToClipboard(
2125
+ JSON.stringify(this.selectedEvent, null, 2),
2126
+ copyAllBtn
2127
+ );
2128
+ }
2129
+ });
2130
+ header.appendChild(backBtn);
2131
+ header.appendChild(copyAllBtn);
2132
+ this.detailOverlay.appendChild(header);
2133
+ const body = document.createElement("div");
2134
+ body.className = "cd-detail-body";
2135
+ this.detailOverlay.appendChild(body);
2136
+ this.contentContainer.appendChild(this.detailOverlay);
2137
+ }
2138
+ showDetail(event) {
2139
+ this.selectedEvent = event;
2140
+ const body = this.detailOverlay.querySelector(".cd-detail-body");
2141
+ body.innerHTML = "";
2142
+ const metaGrid = document.createElement("div");
2143
+ metaGrid.className = "cd-meta-grid";
2144
+ const addMeta = (label, value) => {
2145
+ if (value === void 0) return;
2146
+ const item = document.createElement("div");
2147
+ item.className = "cd-meta-item";
2148
+ item.innerHTML = `
2265
2149
  <span class="cd-meta-label">${label}</span>
2266
2150
  <span class="cd-meta-val">${value}</span>
2267
2151
  `;
2268
- metaGrid.appendChild(item);
2269
- };
2270
- addMeta('Type', event.type);
2271
- addMeta('Source', event.source);
2272
- addMeta('Level', event.level);
2273
- addMeta('Time', `${this.formatTime(event.timestamp)} (${new Date(event.timestamp).toLocaleTimeString()})`);
2274
- addMeta('ID', event.id);
2275
- if (event.duration !== undefined)
2276
- addMeta('Duration', `${event.duration}ms`);
2277
- if (event.platform)
2278
- addMeta('Platform', event.platform);
2279
- body.appendChild(metaGrid);
2280
- // 2. Message
2281
- if (event.message) {
2282
- const msgSection = document.createElement('div');
2283
- msgSection.innerHTML = `<div class="cd-section-title">Message</div>`;
2284
- const msgBlock = document.createElement('div');
2285
- msgBlock.className = 'cd-msg-block';
2286
- msgBlock.textContent = event.message;
2287
- msgSection.appendChild(msgBlock);
2288
- body.appendChild(msgSection);
2289
- }
2290
- // 3. Data Payload / JSON Viewer
2291
- if (event.data !== undefined) {
2292
- const dataSection = document.createElement('div');
2293
- dataSection.innerHTML = `<div class="cd-section-title">Data Payload</div>`;
2294
- const jsonTree = JsonViewer.render(event.data, 3);
2295
- dataSection.appendChild(jsonTree);
2296
- body.appendChild(dataSection);
2297
- }
2298
- this.detailOverlay.classList.add('open');
2299
- }
2300
- closeDetail() {
2301
- this.selectedEvent = null;
2302
- this.detailOverlay.classList.remove('open');
2303
- }
2304
- async loadDeviceDiagnostics() {
2305
- if (this.isDeviceLoading)
2306
- return;
2307
- this.isDeviceLoading = true;
2308
- this.deviceViewContainer.innerHTML = `
2152
+ metaGrid.appendChild(item);
2153
+ };
2154
+ addMeta("Type", event.type);
2155
+ addMeta("Source", event.source);
2156
+ addMeta("Level", event.level);
2157
+ addMeta("Time", `${this.formatTime(event.timestamp)} (${new Date(event.timestamp).toLocaleTimeString()})`);
2158
+ addMeta("ID", event.id);
2159
+ if (event.duration !== void 0) addMeta("Duration", `${event.duration}ms`);
2160
+ if (event.platform) addMeta("Platform", event.platform);
2161
+ body.appendChild(metaGrid);
2162
+ if (event.message) {
2163
+ const msgSection = document.createElement("div");
2164
+ msgSection.innerHTML = `<div class="cd-section-title">Message</div>`;
2165
+ const msgBlock = document.createElement("div");
2166
+ msgBlock.className = "cd-msg-block";
2167
+ msgBlock.textContent = event.message;
2168
+ msgSection.appendChild(msgBlock);
2169
+ body.appendChild(msgSection);
2170
+ }
2171
+ if (event.data !== void 0) {
2172
+ const dataSection = document.createElement("div");
2173
+ dataSection.innerHTML = `<div class="cd-section-title">Data Payload</div>`;
2174
+ const jsonTree = JsonViewer.render(event.data, 3);
2175
+ dataSection.appendChild(jsonTree);
2176
+ body.appendChild(dataSection);
2177
+ }
2178
+ this.detailOverlay.classList.add("open");
2179
+ }
2180
+ closeDetail() {
2181
+ this.selectedEvent = null;
2182
+ this.detailOverlay.classList.remove("open");
2183
+ }
2184
+ async loadDeviceDiagnostics() {
2185
+ if (this.isDeviceLoading) return;
2186
+ this.isDeviceLoading = true;
2187
+ this.deviceViewContainer.innerHTML = `
2309
2188
  <div class="cd-empty-state">
2310
2189
  <span>Querying native device diagnostics...</span>
2311
2190
  </div>
2312
2191
  `;
2313
- try {
2314
- const [device, memory, webView, app, network] = await Promise.allSettled([
2315
- CapDebugNative.getDeviceInfo(),
2316
- CapDebugNative.getMemoryInfo(),
2317
- CapDebugNative.getWebViewInfo(),
2318
- CapDebugNative.getAppInfo(),
2319
- CapDebugNative.getNetworkInfo(),
2320
- ]);
2321
- this.deviceData = {
2322
- device: device.status === 'fulfilled' ? device.value : { error: String(device.reason) },
2323
- memory: memory.status === 'fulfilled' ? memory.value : { error: String(memory.reason) },
2324
- webView: webView.status === 'fulfilled' ? webView.value : { error: String(webView.reason) },
2325
- app: app.status === 'fulfilled' ? app.value : { error: String(app.reason) },
2326
- network: network.status === 'fulfilled' ? network.value : { error: String(network.reason) },
2327
- };
2328
- // Emit native diagnostics event into the store as well
2329
- this.store.add({
2330
- source: 'native',
2331
- type: 'device.diagnostics',
2332
- level: 'info',
2333
- message: 'Device diagnostics loaded',
2334
- data: this.deviceData,
2335
- });
2336
- this.renderDeviceView();
2337
- }
2338
- catch (err) {
2339
- this.deviceViewContainer.innerHTML = `
2192
+ try {
2193
+ const [device, memory, webView, app, network] = await Promise.allSettled([
2194
+ CapDebugNative.getDeviceInfo(),
2195
+ CapDebugNative.getMemoryInfo(),
2196
+ CapDebugNative.getWebViewInfo(),
2197
+ CapDebugNative.getAppInfo(),
2198
+ CapDebugNative.getNetworkInfo()
2199
+ ]);
2200
+ this.deviceData = {
2201
+ device: device.status === "fulfilled" ? device.value : { error: String(device.reason) },
2202
+ memory: memory.status === "fulfilled" ? memory.value : { error: String(memory.reason) },
2203
+ webView: webView.status === "fulfilled" ? webView.value : { error: String(webView.reason) },
2204
+ app: app.status === "fulfilled" ? app.value : { error: String(app.reason) },
2205
+ network: network.status === "fulfilled" ? network.value : { error: String(network.reason) }
2206
+ };
2207
+ this.store.add({
2208
+ source: "native",
2209
+ type: "device.diagnostics",
2210
+ level: "info",
2211
+ message: "Device diagnostics loaded",
2212
+ data: this.deviceData
2213
+ });
2214
+ this.renderDeviceView();
2215
+ } catch (err) {
2216
+ this.deviceViewContainer.innerHTML = `
2340
2217
  <div class="cd-empty-state">
2341
2218
  <span style="color: var(--cd-color-error)">Failed to load diagnostics: ${err?.message || String(err)}</span>
2342
2219
  </div>
2343
2220
  `;
2344
- }
2345
- finally {
2346
- this.isDeviceLoading = false;
2347
- }
2348
- }
2349
- renderDeviceView() {
2350
- if (!this.deviceData)
2351
- return;
2352
- this.deviceViewContainer.innerHTML = '';
2353
- // Refresh action bar
2354
- const topBar = document.createElement('div');
2355
- topBar.style.display = 'flex';
2356
- topBar.style.justifyContent = 'space-between';
2357
- topBar.style.alignItems = 'center';
2358
- const infoLabel = document.createElement('span');
2359
- infoLabel.style.fontSize = '11px';
2360
- infoLabel.style.color = 'var(--cd-text-muted)';
2361
- infoLabel.textContent = `Diagnostic snapshot: ${new Date().toLocaleTimeString()}`;
2362
- const refreshBtn = document.createElement('button');
2363
- refreshBtn.className = 'cd-copy-btn-sm';
2364
- refreshBtn.textContent = '↻ Refresh Live Data';
2365
- refreshBtn.addEventListener('click', () => this.loadDeviceDiagnostics());
2366
- topBar.appendChild(infoLabel);
2367
- topBar.appendChild(refreshBtn);
2368
- this.deviceViewContainer.appendChild(topBar);
2369
- const sections = [
2370
- { title: 'Device Information', data: this.deviceData.device },
2371
- { title: 'Memory & Heap', data: this.deviceData.memory },
2372
- { title: 'Application Info', data: this.deviceData.app },
2373
- { title: 'WebView & User Agent', data: this.deviceData.webView },
2374
- { title: 'Network State', data: this.deviceData.network },
2375
- ];
2376
- for (const { title, data } of sections) {
2377
- const card = document.createElement('div');
2378
- card.className = 'cd-device-card';
2379
- const cardHeader = document.createElement('div');
2380
- cardHeader.className = 'cd-device-card-header';
2381
- cardHeader.textContent = title;
2382
- card.appendChild(cardHeader);
2383
- if (typeof data === 'object' && data !== null) {
2384
- const grid = document.createElement('div');
2385
- grid.className = 'cd-device-grid';
2386
- for (const [k, v] of Object.entries(data)) {
2387
- if (typeof v === 'object' && v !== null)
2388
- continue;
2389
- const item = document.createElement('div');
2390
- item.className = 'cd-meta-item';
2391
- item.innerHTML = `
2221
+ } finally {
2222
+ this.isDeviceLoading = false;
2223
+ }
2224
+ }
2225
+ renderDeviceView() {
2226
+ if (!this.deviceData) return;
2227
+ this.deviceViewContainer.innerHTML = "";
2228
+ const topBar = document.createElement("div");
2229
+ topBar.style.display = "flex";
2230
+ topBar.style.justifyContent = "space-between";
2231
+ topBar.style.alignItems = "center";
2232
+ const infoLabel = document.createElement("span");
2233
+ infoLabel.style.fontSize = "11px";
2234
+ infoLabel.style.color = "var(--cd-text-muted)";
2235
+ infoLabel.textContent = `Diagnostic snapshot: ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`;
2236
+ const refreshBtn = document.createElement("button");
2237
+ refreshBtn.className = "cd-copy-btn-sm";
2238
+ refreshBtn.textContent = "\u21BB Refresh Live Data";
2239
+ refreshBtn.addEventListener("click", () => this.loadDeviceDiagnostics());
2240
+ topBar.appendChild(infoLabel);
2241
+ topBar.appendChild(refreshBtn);
2242
+ this.deviceViewContainer.appendChild(topBar);
2243
+ const sections = [
2244
+ { title: "Device Information", data: this.deviceData.device },
2245
+ { title: "Memory & Heap", data: this.deviceData.memory },
2246
+ { title: "Application Info", data: this.deviceData.app },
2247
+ { title: "WebView & User Agent", data: this.deviceData.webView },
2248
+ { title: "Network State", data: this.deviceData.network }
2249
+ ];
2250
+ for (const { title, data } of sections) {
2251
+ const card = document.createElement("div");
2252
+ card.className = "cd-device-card";
2253
+ const cardHeader = document.createElement("div");
2254
+ cardHeader.className = "cd-device-card-header";
2255
+ cardHeader.textContent = title;
2256
+ card.appendChild(cardHeader);
2257
+ if (typeof data === "object" && data !== null) {
2258
+ const grid = document.createElement("div");
2259
+ grid.className = "cd-device-grid";
2260
+ for (const [k, v] of Object.entries(data)) {
2261
+ if (typeof v === "object" && v !== null) continue;
2262
+ const item = document.createElement("div");
2263
+ item.className = "cd-meta-item";
2264
+ item.innerHTML = `
2392
2265
  <span class="cd-meta-label">${k}</span>
2393
- <span class="cd-meta-val">${v !== undefined && v !== null ? String(v) : '—'}</span>
2266
+ <span class="cd-meta-val">${v !== void 0 && v !== null ? String(v) : "\u2014"}</span>
2394
2267
  `;
2395
- grid.appendChild(item);
2396
- }
2397
- card.appendChild(grid);
2398
- // Render nested objects if present
2399
- for (const [k, v] of Object.entries(data)) {
2400
- if (typeof v === 'object' && v !== null) {
2401
- const nestedSection = document.createElement('div');
2402
- nestedSection.innerHTML = `<div style="font-size: 10px; color: var(--cd-text-muted); font-weight: 600; margin-top: 6px;">${k.toUpperCase()}</div>`;
2403
- nestedSection.appendChild(JsonViewer.render(v, 2));
2404
- card.appendChild(nestedSection);
2405
- }
2406
- }
2407
- }
2408
- else {
2409
- card.textContent = String(data);
2410
- }
2411
- this.deviceViewContainer.appendChild(card);
2412
- }
2413
- }
2414
- formatTime(timestamp) {
2415
- const d = new Date(timestamp);
2416
- const h = String(d.getHours()).padStart(2, '0');
2417
- const m = String(d.getMinutes()).padStart(2, '0');
2418
- const s = String(d.getSeconds()).padStart(2, '0');
2419
- const ms = String(d.getMilliseconds()).padStart(3, '0');
2420
- return `${h}:${m}:${s}.${ms}`;
2421
- }
2268
+ grid.appendChild(item);
2269
+ }
2270
+ card.appendChild(grid);
2271
+ for (const [k, v] of Object.entries(data)) {
2272
+ if (typeof v === "object" && v !== null) {
2273
+ const nestedSection = document.createElement("div");
2274
+ nestedSection.innerHTML = `<div style="font-size: 10px; color: var(--cd-text-muted); font-weight: 600; margin-top: 6px;">${k.toUpperCase()}</div>`;
2275
+ nestedSection.appendChild(JsonViewer.render(v, 2));
2276
+ card.appendChild(nestedSection);
2277
+ }
2278
+ }
2279
+ } else {
2280
+ card.textContent = String(data);
2281
+ }
2282
+ this.deviceViewContainer.appendChild(card);
2283
+ }
2284
+ }
2285
+ formatTime(timestamp) {
2286
+ const d = new Date(timestamp);
2287
+ const h = String(d.getHours()).padStart(2, "0");
2288
+ const m = String(d.getMinutes()).padStart(2, "0");
2289
+ const s = String(d.getSeconds()).padStart(2, "0");
2290
+ const ms = String(d.getMilliseconds()).padStart(3, "0");
2291
+ return `${h}:${m}:${s}.${ms}`;
2422
2292
  }
2293
+ }
2423
2294
 
2424
- class CapDebugViewerElement extends HTMLElement {
2425
- static TAG = 'cap-debug-viewer';
2426
- shadowRootNode;
2427
- floatingButton = null;
2428
- debugPanel = null;
2429
- store = null;
2430
- unsubscribeStore = null;
2431
- constructor() {
2432
- super();
2433
- this.shadowRootNode = this.attachShadow({ mode: 'open' });
2434
- }
2435
- getStore() {
2436
- return this.store;
2437
- }
2438
- init(store, options = {}) {
2439
- this.store = store;
2440
- // Inject isolated styles
2441
- const styleEl = document.createElement('style');
2442
- styleEl.textContent = VIEWER_STYLES;
2443
- this.shadowRootNode.appendChild(styleEl);
2444
- // Create Panel
2445
- this.debugPanel = new DebugPanel(store, {
2446
- defaultTab: options.defaultTab || 'all',
2447
- onClose: () => {
2448
- // Can handle panel close events if needed
2449
- },
2450
- });
2451
- this.shadowRootNode.appendChild(this.debugPanel.getBackdrop());
2452
- this.shadowRootNode.appendChild(this.debugPanel.getElement());
2453
- // Create Floating Button (if enabled)
2454
- if (options.button !== false) {
2455
- this.floatingButton = new FloatingButton({
2456
- position: options.position,
2457
- persistPosition: options.persistPosition !== false,
2458
- onClick: () => {
2459
- this.toggle();
2460
- },
2461
- });
2462
- this.shadowRootNode.appendChild(this.floatingButton.getElement());
2463
- }
2464
- // Subscribe to error counts for the button badge
2465
- this.unsubscribeStore = store.subscribe((_events, s) => {
2466
- const counts = s.getCounts();
2467
- if (this.floatingButton) {
2468
- this.floatingButton.setErrorCount(counts.errors);
2469
- }
2470
- });
2471
- }
2472
- show() {
2473
- if (this.debugPanel) {
2474
- this.debugPanel.open();
2475
- }
2476
- }
2477
- hide() {
2478
- if (this.debugPanel) {
2479
- this.debugPanel.close();
2480
- }
2481
- }
2482
- toggle() {
2483
- if (this.debugPanel) {
2484
- return this.debugPanel.toggle();
2485
- }
2486
- return false;
2487
- }
2488
- showButton() {
2489
- if (this.floatingButton) {
2490
- this.floatingButton.show();
2491
- }
2492
- }
2493
- hideButton() {
2494
- if (this.floatingButton) {
2495
- this.floatingButton.hide();
2496
- }
2497
- }
2498
- disconnectedCallback() {
2499
- if (this.unsubscribeStore) {
2500
- this.unsubscribeStore();
2501
- this.unsubscribeStore = null;
2502
- }
2503
- }
2295
+ class CapDebugViewerElement extends HTMLElement {
2296
+ static TAG = "cap-debug-viewer";
2297
+ shadowRootNode;
2298
+ floatingButton = null;
2299
+ debugPanel = null;
2300
+ store = null;
2301
+ unsubscribeStore = null;
2302
+ constructor() {
2303
+ super();
2304
+ this.shadowRootNode = this.attachShadow({ mode: "open" });
2504
2305
  }
2505
- function registerCustomElement() {
2506
- if (typeof customElements !== 'undefined' && !customElements.get(CapDebugViewerElement.TAG)) {
2507
- customElements.define(CapDebugViewerElement.TAG, CapDebugViewerElement);
2508
- }
2306
+ getStore() {
2307
+ return this.store;
2308
+ }
2309
+ init(store, options = {}) {
2310
+ this.store = store;
2311
+ const styleEl = document.createElement("style");
2312
+ styleEl.textContent = VIEWER_STYLES;
2313
+ this.shadowRootNode.appendChild(styleEl);
2314
+ this.debugPanel = new DebugPanel(store, {
2315
+ defaultTab: options.defaultTab || "all",
2316
+ onClose: () => {
2317
+ }
2318
+ });
2319
+ this.shadowRootNode.appendChild(this.debugPanel.getBackdrop());
2320
+ this.shadowRootNode.appendChild(this.debugPanel.getElement());
2321
+ if (options.button !== false) {
2322
+ this.floatingButton = new FloatingButton({
2323
+ position: options.position,
2324
+ persistPosition: options.persistPosition !== false,
2325
+ onClick: () => {
2326
+ this.toggle();
2327
+ }
2328
+ });
2329
+ this.shadowRootNode.appendChild(this.floatingButton.getElement());
2330
+ }
2331
+ this.unsubscribeStore = store.subscribe((_events, s) => {
2332
+ const counts = s.getCounts();
2333
+ if (this.floatingButton) {
2334
+ this.floatingButton.setErrorCount(counts.errors);
2335
+ }
2336
+ });
2337
+ }
2338
+ show() {
2339
+ if (this.debugPanel) {
2340
+ this.debugPanel.open();
2341
+ }
2342
+ }
2343
+ hide() {
2344
+ if (this.debugPanel) {
2345
+ this.debugPanel.close();
2346
+ }
2347
+ }
2348
+ toggle() {
2349
+ if (this.debugPanel) {
2350
+ return this.debugPanel.toggle();
2351
+ }
2352
+ return false;
2353
+ }
2354
+ showButton() {
2355
+ if (this.floatingButton) {
2356
+ this.floatingButton.show();
2357
+ }
2509
2358
  }
2359
+ hideButton() {
2360
+ if (this.floatingButton) {
2361
+ this.floatingButton.hide();
2362
+ }
2363
+ }
2364
+ disconnectedCallback() {
2365
+ if (this.unsubscribeStore) {
2366
+ this.unsubscribeStore();
2367
+ this.unsubscribeStore = null;
2368
+ }
2369
+ }
2370
+ }
2371
+ function registerCustomElement() {
2372
+ if (typeof customElements !== "undefined" && !customElements.get(CapDebugViewerElement.TAG)) {
2373
+ customElements.define(CapDebugViewerElement.TAG, CapDebugViewerElement);
2374
+ }
2375
+ }
2510
2376
 
2511
- class CapDebugManager {
2512
- store;
2513
- viewerElement = null;
2514
- isMounted = false;
2515
- customEventCollector;
2516
- consoleCollector;
2517
- errorCollector;
2518
- networkCollector;
2519
- browserEventCollector;
2520
- bridgeCollector;
2521
- constructor() {
2522
- this.store = new CapDebugStore();
2523
- this.customEventCollector = new CustomEventCollector(this.store);
2524
- this.consoleCollector = new ConsoleCollector();
2525
- this.errorCollector = new ErrorCollector();
2526
- this.networkCollector = new NetworkCollector();
2527
- this.browserEventCollector = new BrowserEventCollector();
2528
- this.bridgeCollector = new BridgeCollector();
2529
- }
2530
- get native() {
2531
- return CapDebugNative;
2532
- }
2533
- get currentStore() {
2534
- return this.store;
2535
- }
2536
- /**
2537
- * Mounts the CapDebug UI into the DOM and activates collectors.
2538
- */
2539
- mount(options = {}) {
2540
- if (typeof window === 'undefined' || typeof document === 'undefined') {
2541
- return;
2542
- }
2543
- if (this.isMounted) {
2544
- this.unmount();
2545
- }
2546
- // Configure store
2547
- if (options.maxEvents) {
2548
- this.store.setMaxEvents(options.maxEvents);
2549
- }
2550
- if (options.customMaskKeys) {
2551
- this.store.setCustomMaskKeys(options.customMaskKeys);
2552
- }
2553
- // 1. Start core CustomEvent bus listener
2554
- this.customEventCollector.start();
2555
- // 2. Start optional collectors
2556
- if (options.console !== false) {
2557
- this.consoleCollector.start();
2558
- }
2559
- if (options.errors !== false) {
2560
- this.errorCollector.start();
2561
- }
2562
- if (options.network) {
2563
- const netOpts = typeof options.network === 'object' ? options.network : {};
2564
- this.networkCollector.setOptions(netOpts);
2565
- this.networkCollector.start();
2566
- }
2567
- if (options.bridge) {
2568
- this.bridgeCollector.start();
2569
- }
2570
- this.browserEventCollector.start();
2571
- // 3. Register and create Web Component
2572
- registerCustomElement();
2573
- this.viewerElement = document.createElement(CapDebugViewerElement.TAG);
2574
- this.viewerElement.init(this.store, options);
2575
- document.body.appendChild(this.viewerElement);
2576
- this.isMounted = true;
2577
- }
2578
- /**
2579
- * Unmounts CapDebug UI and stops all collectors.
2580
- */
2581
- unmount() {
2582
- if (!this.isMounted)
2583
- return;
2584
- if (this.viewerElement && this.viewerElement.parentNode) {
2585
- this.viewerElement.parentNode.removeChild(this.viewerElement);
2586
- this.viewerElement = null;
2587
- }
2588
- this.customEventCollector.stop();
2589
- this.consoleCollector.stop();
2590
- this.errorCollector.stop();
2591
- this.networkCollector.stop();
2592
- this.browserEventCollector.stop();
2593
- this.bridgeCollector.stop();
2594
- this.isMounted = false;
2595
- }
2596
- /**
2597
- * Opens the debug viewer drawer.
2598
- */
2599
- show() {
2600
- if (this.viewerElement) {
2601
- this.viewerElement.show();
2602
- }
2603
- }
2604
- /**
2605
- * Closes the debug viewer drawer.
2606
- */
2607
- hide() {
2608
- if (this.viewerElement) {
2609
- this.viewerElement.hide();
2610
- }
2611
- }
2612
- /**
2613
- * Toggles the debug viewer drawer open/closed.
2614
- */
2615
- toggle() {
2616
- if (this.viewerElement) {
2617
- return this.viewerElement.toggle();
2618
- }
2619
- return false;
2620
- }
2621
- /**
2622
- * Dispatches a debug event through the CustomEvent bus.
2623
- */
2624
- emit(event) {
2625
- if (typeof window === 'undefined')
2626
- return;
2627
- window.dispatchEvent(new CustomEvent('capdebug', {
2628
- detail: {
2629
- id: event.id,
2630
- timestamp: event.timestamp || Date.now(),
2631
- source: event.source || 'web',
2632
- type: event.type,
2633
- level: event.level || 'info',
2634
- message: event.message,
2635
- data: event.data,
2636
- duration: event.duration,
2637
- platform: event.platform,
2638
- },
2639
- }));
2640
- }
2641
- /**
2642
- * Clears all recorded events from the store.
2643
- */
2644
- clear() {
2645
- this.store.clear();
2646
- }
2647
- /**
2648
- * Pauses capturing new events.
2649
- */
2650
- pause() {
2651
- this.store.pause();
2652
- }
2653
- /**
2654
- * Resumes capturing events.
2655
- */
2656
- resume() {
2657
- this.store.resume();
2658
- }
2659
- captureConsole() {
2660
- this.consoleCollector.start();
2661
- }
2662
- releaseConsole() {
2663
- this.consoleCollector.stop();
2664
- }
2665
- captureErrors() {
2666
- this.errorCollector.start();
2667
- }
2668
- releaseErrors() {
2669
- this.errorCollector.stop();
2670
- }
2671
- captureFetch(options) {
2672
- if (options) {
2673
- this.networkCollector.setOptions(options);
2674
- }
2675
- this.networkCollector.start();
2676
- }
2677
- releaseFetch() {
2678
- this.networkCollector.stop();
2679
- }
2680
- observeEvent(eventName) {
2681
- this.browserEventCollector.observe(eventName);
2682
- }
2683
- unobserveEvent(eventName) {
2684
- this.browserEventCollector.unobserve(eventName);
2685
- }
2377
+ class CapDebugManager {
2378
+ store;
2379
+ viewerElement = null;
2380
+ isMounted = false;
2381
+ customEventCollector;
2382
+ consoleCollector;
2383
+ errorCollector;
2384
+ networkCollector;
2385
+ browserEventCollector;
2386
+ bridgeCollector;
2387
+ constructor() {
2388
+ this.store = new CapDebugStore();
2389
+ this.customEventCollector = new CustomEventCollector(this.store);
2390
+ this.consoleCollector = new ConsoleCollector();
2391
+ this.errorCollector = new ErrorCollector();
2392
+ this.networkCollector = new NetworkCollector();
2393
+ this.browserEventCollector = new BrowserEventCollector();
2394
+ this.bridgeCollector = new BridgeCollector();
2686
2395
  }
2687
- const CapDebug = new CapDebugManager();
2688
-
2689
- function formatBytes(bytes) {
2690
- if (bytes === 0)
2691
- return '0 B';
2692
- const k = 1024;
2693
- const sizes = ['B', 'KB', 'MB', 'GB'];
2694
- const i = Math.floor(Math.log(bytes) / Math.log(k));
2695
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
2696
- }
2697
- class CapDebugWeb extends core.WebPlugin {
2698
- async getDeviceInfo() {
2699
- const nav = typeof navigator !== 'undefined' ? navigator : {};
2700
- return {
2701
- manufacturer: 'Web Browser',
2702
- model: nav.userAgentData?.brands?.[0]?.brand || nav.appName || 'Browser',
2703
- device: nav.platform || 'Web',
2704
- systemVersion: nav.appVersion || 'Unknown',
2705
- architecture: nav.userAgentData?.architecture || 'Unknown',
2706
- availableProcessors: nav.hardwareConcurrency || 1,
2707
- isEmulator: false,
2708
- platform: 'web',
2709
- };
2710
- }
2711
- async getMemoryInfo() {
2712
- const perf = typeof window !== 'undefined' ? window.performance : null;
2713
- const memory = perf && perf.memory ? perf.memory : null;
2714
- if (memory) {
2715
- return {
2716
- appMemoryUsage: memory.usedJSHeapSize,
2717
- appMemoryUsageFormatted: formatBytes(memory.usedJSHeapSize),
2718
- totalHeap: memory.totalJSHeapSize,
2719
- totalHeapFormatted: formatBytes(memory.totalJSHeapSize),
2720
- maxHeap: memory.jsHeapSizeLimit,
2721
- maxHeapFormatted: formatBytes(memory.jsHeapSizeLimit),
2722
- freeHeap: memory.totalJSHeapSize - memory.usedJSHeapSize,
2723
- freeHeapFormatted: formatBytes(memory.totalJSHeapSize - memory.usedJSHeapSize),
2724
- lowMemory: false,
2725
- };
2726
- }
2727
- return {
2728
- appMemoryUsageFormatted: 'N/A (Browser non-Chrome)',
2729
- lowMemory: false,
2730
- };
2731
- }
2732
- async getWebViewInfo() {
2733
- const nav = typeof navigator !== 'undefined' ? navigator : {};
2734
- return {
2735
- userAgent: nav.userAgent || 'Unknown',
2736
- version: nav.appVersion || 'Unknown',
2737
- packageName: typeof window !== 'undefined' ? window.location.hostname : 'localhost',
2738
- debugEnabled: true,
2739
- };
2740
- }
2741
- async getAppInfo() {
2742
- return {
2743
- applicationId: typeof window !== 'undefined' ? window.location.host : 'localhost',
2744
- version: '1.0.0',
2745
- versionName: '1.0.0 (Web)',
2746
- versionCode: 1,
2747
- buildType: typeof process !== 'undefined' && process.env?.NODE_ENV ? process.env.NODE_ENV : 'development',
2748
- };
2749
- }
2750
- async getNetworkInfo() {
2751
- const nav = typeof navigator !== 'undefined' ? navigator : {};
2752
- const conn = nav.connection || nav.mozConnection || nav.webkitConnection;
2753
- return {
2754
- connected: nav.onLine ?? true,
2755
- connectionType: conn ? conn.effectiveType || conn.type || 'unknown' : (nav.onLine ? 'online' : 'offline'),
2756
- metered: conn ? conn.saveData ?? false : false,
2757
- };
2758
- }
2396
+ get native() {
2397
+ return CapDebugNative;
2398
+ }
2399
+ get currentStore() {
2400
+ return this.store;
2401
+ }
2402
+ /**
2403
+ * Mounts the CapDebug UI into the DOM and activates collectors.
2404
+ */
2405
+ mount(options = {}) {
2406
+ if (typeof window === "undefined" || typeof document === "undefined") {
2407
+ return;
2408
+ }
2409
+ if (this.isMounted) {
2410
+ this.unmount();
2411
+ }
2412
+ if (options.maxEvents) {
2413
+ this.store.setMaxEvents(options.maxEvents);
2414
+ }
2415
+ if (options.customMaskKeys) {
2416
+ this.store.setCustomMaskKeys(options.customMaskKeys);
2417
+ }
2418
+ this.customEventCollector.start();
2419
+ if (options.console !== false) {
2420
+ this.consoleCollector.start();
2421
+ }
2422
+ if (options.errors !== false) {
2423
+ this.errorCollector.start();
2424
+ }
2425
+ if (options.network) {
2426
+ const netOpts = typeof options.network === "object" ? options.network : {};
2427
+ this.networkCollector.setOptions(netOpts);
2428
+ this.networkCollector.start();
2429
+ }
2430
+ if (options.bridge) {
2431
+ this.bridgeCollector.start();
2432
+ }
2433
+ this.browserEventCollector.start();
2434
+ registerCustomElement();
2435
+ this.viewerElement = document.createElement(CapDebugViewerElement.TAG);
2436
+ this.viewerElement.init(this.store, options);
2437
+ document.body.appendChild(this.viewerElement);
2438
+ this.isMounted = true;
2439
+ }
2440
+ /**
2441
+ * Unmounts CapDebug UI and stops all collectors.
2442
+ */
2443
+ unmount() {
2444
+ if (!this.isMounted) return;
2445
+ if (this.viewerElement && this.viewerElement.parentNode) {
2446
+ this.viewerElement.parentNode.removeChild(this.viewerElement);
2447
+ this.viewerElement = null;
2448
+ }
2449
+ this.customEventCollector.stop();
2450
+ this.consoleCollector.stop();
2451
+ this.errorCollector.stop();
2452
+ this.networkCollector.stop();
2453
+ this.browserEventCollector.stop();
2454
+ this.bridgeCollector.stop();
2455
+ this.isMounted = false;
2456
+ }
2457
+ /**
2458
+ * Opens the debug viewer drawer.
2459
+ */
2460
+ show() {
2461
+ if (this.viewerElement) {
2462
+ this.viewerElement.show();
2463
+ }
2464
+ }
2465
+ /**
2466
+ * Closes the debug viewer drawer.
2467
+ */
2468
+ hide() {
2469
+ if (this.viewerElement) {
2470
+ this.viewerElement.hide();
2471
+ }
2759
2472
  }
2473
+ /**
2474
+ * Toggles the debug viewer drawer open/closed.
2475
+ */
2476
+ toggle() {
2477
+ if (this.viewerElement) {
2478
+ return this.viewerElement.toggle();
2479
+ }
2480
+ return false;
2481
+ }
2482
+ /**
2483
+ * Dispatches a debug event through the CustomEvent bus.
2484
+ */
2485
+ emit(event) {
2486
+ if (typeof window === "undefined") return;
2487
+ window.dispatchEvent(
2488
+ new CustomEvent("capdebug", {
2489
+ detail: {
2490
+ id: event.id,
2491
+ timestamp: event.timestamp || Date.now(),
2492
+ source: event.source || "web",
2493
+ type: event.type,
2494
+ level: event.level || "info",
2495
+ message: event.message,
2496
+ data: event.data,
2497
+ duration: event.duration,
2498
+ platform: event.platform
2499
+ }
2500
+ })
2501
+ );
2502
+ }
2503
+ /**
2504
+ * Clears all recorded events from the store.
2505
+ */
2506
+ clear() {
2507
+ this.store.clear();
2508
+ }
2509
+ /**
2510
+ * Pauses capturing new events.
2511
+ */
2512
+ pause() {
2513
+ this.store.pause();
2514
+ }
2515
+ /**
2516
+ * Resumes capturing events.
2517
+ */
2518
+ resume() {
2519
+ this.store.resume();
2520
+ }
2521
+ captureConsole() {
2522
+ this.consoleCollector.start();
2523
+ }
2524
+ releaseConsole() {
2525
+ this.consoleCollector.stop();
2526
+ }
2527
+ captureErrors() {
2528
+ this.errorCollector.start();
2529
+ }
2530
+ releaseErrors() {
2531
+ this.errorCollector.stop();
2532
+ }
2533
+ captureFetch(options) {
2534
+ if (options) {
2535
+ this.networkCollector.setOptions(options);
2536
+ }
2537
+ this.networkCollector.start();
2538
+ }
2539
+ releaseFetch() {
2540
+ this.networkCollector.stop();
2541
+ }
2542
+ observeEvent(eventName) {
2543
+ this.browserEventCollector.observe(eventName);
2544
+ }
2545
+ unobserveEvent(eventName) {
2546
+ this.browserEventCollector.unobserve(eventName);
2547
+ }
2548
+ }
2549
+ const CapDebug = new CapDebugManager();
2550
+
2551
+ function formatBytes(bytes) {
2552
+ if (bytes === 0) return "0 B";
2553
+ const k = 1024;
2554
+ const sizes = ["B", "KB", "MB", "GB"];
2555
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
2556
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
2557
+ }
2558
+ class CapDebugWeb extends core.WebPlugin {
2559
+ async getDeviceInfo() {
2560
+ const nav = typeof navigator !== "undefined" ? navigator : {};
2561
+ return {
2562
+ manufacturer: "Web Browser",
2563
+ model: nav.userAgentData?.brands?.[0]?.brand || nav.appName || "Browser",
2564
+ device: nav.platform || "Web",
2565
+ systemVersion: nav.appVersion || "Unknown",
2566
+ architecture: nav.userAgentData?.architecture || "Unknown",
2567
+ availableProcessors: nav.hardwareConcurrency || 1,
2568
+ isEmulator: false,
2569
+ platform: "web"
2570
+ };
2571
+ }
2572
+ async getMemoryInfo() {
2573
+ const perf = typeof window !== "undefined" ? window.performance : null;
2574
+ const memory = perf && perf.memory ? perf.memory : null;
2575
+ if (memory) {
2576
+ return {
2577
+ appMemoryUsage: memory.usedJSHeapSize,
2578
+ appMemoryUsageFormatted: formatBytes(memory.usedJSHeapSize),
2579
+ totalHeap: memory.totalJSHeapSize,
2580
+ totalHeapFormatted: formatBytes(memory.totalJSHeapSize),
2581
+ maxHeap: memory.jsHeapSizeLimit,
2582
+ maxHeapFormatted: formatBytes(memory.jsHeapSizeLimit),
2583
+ freeHeap: memory.totalJSHeapSize - memory.usedJSHeapSize,
2584
+ freeHeapFormatted: formatBytes(memory.totalJSHeapSize - memory.usedJSHeapSize),
2585
+ lowMemory: false
2586
+ };
2587
+ }
2588
+ return {
2589
+ appMemoryUsageFormatted: "N/A (Browser non-Chrome)",
2590
+ lowMemory: false
2591
+ };
2592
+ }
2593
+ async getWebViewInfo() {
2594
+ const nav = typeof navigator !== "undefined" ? navigator : {};
2595
+ return {
2596
+ userAgent: nav.userAgent || "Unknown",
2597
+ version: nav.appVersion || "Unknown",
2598
+ packageName: typeof window !== "undefined" ? window.location.hostname : "localhost",
2599
+ debugEnabled: true
2600
+ };
2601
+ }
2602
+ async getAppInfo() {
2603
+ return {
2604
+ applicationId: typeof window !== "undefined" ? window.location.host : "localhost",
2605
+ version: "1.0.0",
2606
+ versionName: "1.0.0 (Web)",
2607
+ versionCode: 1,
2608
+ buildType: typeof process !== "undefined" && process.env?.NODE_ENV ? process.env.NODE_ENV : "development"
2609
+ };
2610
+ }
2611
+ async getNetworkInfo() {
2612
+ const nav = typeof navigator !== "undefined" ? navigator : {};
2613
+ const conn = nav.connection || nav.mozConnection || nav.webkitConnection;
2614
+ return {
2615
+ connected: nav.onLine ?? true,
2616
+ connectionType: conn ? conn.effectiveType || conn.type || "unknown" : nav.onLine ? "online" : "offline",
2617
+ metered: conn ? conn.saveData ?? false : false
2618
+ };
2619
+ }
2620
+ }
2760
2621
 
2761
- var web = /*#__PURE__*/Object.freeze({
2762
- __proto__: null,
2763
- CapDebugWeb: CapDebugWeb
2764
- });
2765
-
2766
- exports.BridgeCollector = BridgeCollector;
2767
- exports.BrowserEventCollector = BrowserEventCollector;
2768
- exports.CapDebug = CapDebug;
2769
- exports.CapDebugManager = CapDebugManager;
2770
- exports.CapDebugNative = CapDebugNative;
2771
- exports.CapDebugStore = CapDebugStore;
2772
- exports.CapDebugViewerElement = CapDebugViewerElement;
2773
- exports.ConsoleCollector = ConsoleCollector;
2774
- exports.CustomEventCollector = CustomEventCollector;
2775
- exports.DataSanitizer = DataSanitizer;
2776
- exports.ErrorCollector = ErrorCollector;
2777
- exports.JsonViewer = JsonViewer;
2778
- exports.NetworkCollector = NetworkCollector;
2779
- exports.default = CapDebug;
2780
- exports.defaultSanitizer = defaultSanitizer;
2781
- exports.registerCustomElement = registerCustomElement;
2782
- exports.sanitize = sanitize;
2783
-
2784
- Object.defineProperty(exports, '__esModule', { value: true });
2785
-
2786
- return exports;
2622
+ var web = /*#__PURE__*/Object.freeze({
2623
+ __proto__: null,
2624
+ CapDebugWeb: CapDebugWeb
2625
+ });
2626
+
2627
+ exports.BridgeCollector = BridgeCollector;
2628
+ exports.BrowserEventCollector = BrowserEventCollector;
2629
+ exports.CapDebug = CapDebug;
2630
+ exports.CapDebugManager = CapDebugManager;
2631
+ exports.CapDebugNative = CapDebugNative;
2632
+ exports.CapDebugStore = CapDebugStore;
2633
+ exports.CapDebugViewerElement = CapDebugViewerElement;
2634
+ exports.ConsoleCollector = ConsoleCollector;
2635
+ exports.CustomEventCollector = CustomEventCollector;
2636
+ exports.DataSanitizer = DataSanitizer;
2637
+ exports.ErrorCollector = ErrorCollector;
2638
+ exports.JsonViewer = JsonViewer;
2639
+ exports.NetworkCollector = NetworkCollector;
2640
+ exports.default = CapDebug;
2641
+ exports.defaultSanitizer = defaultSanitizer;
2642
+ exports.registerCustomElement = registerCustomElement;
2643
+ exports.sanitize = sanitize;
2644
+
2645
+ Object.defineProperty(exports, '__esModule', { value: true });
2646
+
2647
+ return exports;
2787
2648
 
2788
2649
  })({}, capacitorExports);
2789
2650
  //# sourceMappingURL=plugin.js.map