@concavejs/devtools 0.0.1-alpha.10

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.
@@ -0,0 +1,668 @@
1
+ function c(o = {}) {
2
+ const { enabled: s = !0, position: a = "bottom-right" } = o;
3
+ let t = !1;
4
+ return {
5
+ name: "concave-devtools",
6
+ configResolved(e) {
7
+ t = e.mode === "development";
8
+ },
9
+ transformIndexHtml: {
10
+ order: "pre",
11
+ handler(e) {
12
+ if (!t || !s)
13
+ return e;
14
+ const i = `
15
+ <script>
16
+ // Initialize event store immediately
17
+ (function() {
18
+ if (window.__concaveDevTools) return;
19
+
20
+ console.log('[DevTools] Installing WebSocket interceptor...');
21
+
22
+ // Minimal event store for capturing events
23
+ window.__concaveDevToolsEvents = [];
24
+ window.__concaveDevToolsPendingQueries = new Map();
25
+ window.__concaveDevToolsPendingMutations = new Map();
26
+ window.__concaveDevToolsPendingActions = new Map();
27
+ window.__concaveDevToolsPendingAuthTokenType = null;
28
+
29
+ // Latency simulation config (mutated by devtools settings panel)
30
+ if (!window.__concaveDevToolsLatencyConfig) {
31
+ window.__concaveDevToolsLatencyConfig = { latencyMs: 0, jitterMs: 0 };
32
+ }
33
+
34
+ var __concaveSanitizeLatency = function(value) {
35
+ var parsed = Number(value);
36
+ if (!Number.isFinite(parsed) || parsed <= 0) return 0;
37
+ return Math.min(parsed, 5000);
38
+ };
39
+
40
+ var __concaveGetLatencyDelay = function() {
41
+ var cfg = window.__concaveDevToolsLatencyConfig;
42
+ if (!cfg) return 0;
43
+ var base = __concaveSanitizeLatency(cfg.latencyMs);
44
+ var jitter = __concaveSanitizeLatency(cfg.jitterMs);
45
+ if (base <= 0 && jitter <= 0) return 0;
46
+ if (base > 0 && jitter > base) jitter = base;
47
+ return Math.max(0, base + (jitter > 0 ? (Math.random() * 2 - 1) * jitter : 0));
48
+ };
49
+
50
+ var __concaveInternalMessageListener = Symbol.for('__concaveDevToolsInternalWsListener');
51
+ var __concaveLatencyDelaySymbol = Symbol.for('__concaveDevToolsWsDelayMs');
52
+ var __concaveGetDelayForEvent = function(event) {
53
+ if (!event || typeof event !== 'object') return __concaveGetLatencyDelay();
54
+ var existing = event[__concaveLatencyDelaySymbol];
55
+ if (typeof existing === 'number' && isFinite(existing) && existing >= 0) {
56
+ return existing;
57
+ }
58
+ var sampled = __concaveGetLatencyDelay();
59
+ try {
60
+ Object.defineProperty(event, __concaveLatencyDelaySymbol, {
61
+ value: sampled,
62
+ configurable: true
63
+ });
64
+ } catch (e) {
65
+ event[__concaveLatencyDelaySymbol] = sampled;
66
+ }
67
+ return sampled;
68
+ };
69
+ var __concaveInvokeWithLatency = function(listener, target, event) {
70
+ if (typeof listener !== 'function') return;
71
+ if (listener[__concaveInternalMessageListener]) {
72
+ listener.call(target, event);
73
+ return;
74
+ }
75
+ var delay = 0;
76
+ try {
77
+ delay = __concaveGetDelayForEvent(event);
78
+ } catch (e) {
79
+ delay = 0;
80
+ }
81
+ if (delay > 0) {
82
+ setTimeout(function() {
83
+ listener.call(target, event);
84
+ }, delay);
85
+ return;
86
+ }
87
+ listener.call(target, event);
88
+ };
89
+
90
+ const OriginalWebSocket = window.WebSocket;
91
+
92
+ const emitAuthEvent = (direction, messageType, status, details, error, tokenType) => {
93
+ const now = Date.now();
94
+ window.__concaveDevToolsEvents.push({
95
+ id: 'auth-' + direction + '-' + messageType + '-' + now + '-' + Math.random().toString(36).slice(2, 8),
96
+ timestamp: now,
97
+ type: 'auth',
98
+ direction,
99
+ messageType,
100
+ status,
101
+ tokenType,
102
+ error,
103
+ details,
104
+ });
105
+ };
106
+
107
+ const decodeJwtClaims = (token) => {
108
+ const parts = token.split('.');
109
+ if (parts.length < 2) return null;
110
+ try {
111
+ const normalized = parts[1].replace(/-/g, '+').replace(/_/g, '/');
112
+ const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);
113
+ const payload = JSON.parse(atob(padded));
114
+ const keys = ['iss', 'sub', 'aud', 'exp', 'iat', 'nbf'];
115
+ const claims = {};
116
+ keys.forEach((key) => {
117
+ if (payload[key] !== undefined) claims[key] = payload[key];
118
+ });
119
+ if (typeof claims.exp === 'number') claims.expIso = new Date(claims.exp * 1000).toISOString();
120
+ if (typeof claims.iat === 'number') claims.iatIso = new Date(claims.iat * 1000).toISOString();
121
+ return Object.keys(claims).length > 0 ? claims : null;
122
+ } catch (e) {
123
+ return null;
124
+ }
125
+ };
126
+
127
+ // Create intercepted WebSocket constructor
128
+ window.WebSocket = function(url, protocols) {
129
+ const ws = new OriginalWebSocket(url, protocols);
130
+
131
+ // Intercept send
132
+ const originalSend = ws.send.bind(ws);
133
+ ws.send = function(data) {
134
+ if (typeof data === 'string') {
135
+ try {
136
+ const msg = JSON.parse(data);
137
+ const now = Date.now();
138
+
139
+ if (msg.type === 'Connect') {
140
+ const connectDetails = {};
141
+ if (typeof msg.connectionCount === 'number') connectDetails.connectionCount = msg.connectionCount;
142
+ if (typeof msg.lastCloseReason === 'string') connectDetails.lastCloseReason = msg.lastCloseReason;
143
+ if (typeof msg.clientTs === 'number') connectDetails.clientTs = msg.clientTs;
144
+ if (typeof msg.sessionId === 'string') connectDetails.sessionId = msg.sessionId;
145
+ emitAuthEvent('client', 'Connect', 'success', connectDetails, undefined, undefined);
146
+ }
147
+
148
+ if (msg.type === 'Authenticate') {
149
+ const authDetails = {};
150
+ if (typeof msg.baseVersion === 'number') authDetails.baseVersion = msg.baseVersion;
151
+ if (typeof msg.tokenType === 'string') authDetails.tokenType = msg.tokenType;
152
+ if (typeof msg.value === 'string' && msg.value.length > 0) {
153
+ authDetails.tokenLength = msg.value.length;
154
+ authDetails.tokenPreview = msg.value.length > 24
155
+ ? msg.value.slice(0, 12) + '…' + msg.value.slice(-10)
156
+ : msg.value;
157
+ const claims = decodeJwtClaims(msg.value);
158
+ if (claims) authDetails.jwtClaims = claims;
159
+ }
160
+ window.__concaveDevToolsPendingAuthTokenType = msg.tokenType || 'Unknown';
161
+ emitAuthEvent('client', 'Authenticate', 'success', authDetails, undefined, msg.tokenType);
162
+ }
163
+
164
+ // Track queries
165
+ if (msg.type === 'ModifyQuerySet' && msg.modifications) {
166
+ msg.modifications.forEach(mod => {
167
+ if (mod.type === 'Add') {
168
+ window.__concaveDevToolsPendingQueries.set(mod.queryId, {
169
+ queryId: mod.queryId,
170
+ udfPath: mod.udfPath,
171
+ args: mod.args,
172
+ componentPath: mod.componentPath,
173
+ startTime: now
174
+ });
175
+
176
+ window.__concaveDevToolsEvents.push({
177
+ id: 'sub-' + mod.queryId + '-' + now,
178
+ timestamp: now,
179
+ type: 'subscription',
180
+ queryId: mod.queryId,
181
+ udfPath: mod.udfPath,
182
+ args: mod.args,
183
+ componentPath: mod.componentPath,
184
+ status: 'added'
185
+ });
186
+
187
+ window.__concaveDevToolsEvents.push({
188
+ id: 'query-pending-' + mod.queryId + '-' + now,
189
+ timestamp: now,
190
+ type: 'query',
191
+ queryId: mod.queryId,
192
+ udfPath: mod.udfPath,
193
+ args: mod.args,
194
+ componentPath: mod.componentPath,
195
+ status: 'pending'
196
+ });
197
+ } else if (mod.type === 'Remove') {
198
+ const pending = window.__concaveDevToolsPendingQueries.get(mod.queryId);
199
+ window.__concaveDevToolsPendingQueries.delete(mod.queryId);
200
+ // Emit removed subscription if we have context
201
+ window.__concaveDevToolsEvents.push({
202
+ id: 'sub-' + mod.queryId + '-' + now,
203
+ timestamp: now,
204
+ type: 'subscription',
205
+ queryId: mod.queryId,
206
+ udfPath: pending ? pending.udfPath : 'unknown',
207
+ args: pending ? pending.args : [],
208
+ componentPath: pending ? pending.componentPath : undefined,
209
+ status: 'removed'
210
+ });
211
+ }
212
+ });
213
+ }
214
+
215
+ // Track mutations
216
+ if (msg.type === 'Mutation') {
217
+ window.__concaveDevToolsPendingMutations.set(msg.requestId, {
218
+ requestId: msg.requestId,
219
+ udfPath: msg.udfPath,
220
+ args: msg.args,
221
+ componentPath: msg.componentPath,
222
+ startTime: now
223
+ });
224
+
225
+ window.__concaveDevToolsEvents.push({
226
+ id: 'mutation-pending-' + msg.requestId + '-' + now,
227
+ timestamp: now,
228
+ type: 'mutation',
229
+ requestId: msg.requestId,
230
+ udfPath: msg.udfPath,
231
+ args: msg.args,
232
+ componentPath: msg.componentPath,
233
+ status: 'pending'
234
+ });
235
+ }
236
+
237
+ // Track actions
238
+ if (msg.type === 'Action') {
239
+ window.__concaveDevToolsPendingActions.set(msg.requestId, {
240
+ requestId: msg.requestId,
241
+ udfPath: msg.udfPath,
242
+ args: msg.args,
243
+ componentPath: msg.componentPath,
244
+ startTime: now
245
+ });
246
+
247
+ window.__concaveDevToolsEvents.push({
248
+ id: 'action-pending-' + msg.requestId + '-' + now,
249
+ timestamp: now,
250
+ type: 'action',
251
+ requestId: msg.requestId,
252
+ udfPath: msg.udfPath,
253
+ args: msg.args,
254
+ componentPath: msg.componentPath,
255
+ status: 'pending'
256
+ });
257
+ }
258
+ } catch (e) {
259
+ console.warn('[DevTools] Error parsing client message:', e);
260
+ }
261
+ }
262
+ return originalSend(data);
263
+ };
264
+
265
+ // Intercept message handlers and keep listener identity stable so removeEventListener works.
266
+ const originalAddEventListener = ws.addEventListener.bind(ws);
267
+ const originalRemoveEventListener = ws.removeEventListener.bind(ws);
268
+ const messageListenerWrappers = new WeakMap();
269
+ ws.addEventListener = function(type, listener, options) {
270
+ if (type === 'message' && typeof listener === 'function') {
271
+ let wrappedListener = messageListenerWrappers.get(listener);
272
+ if (!wrappedListener) {
273
+ wrappedListener = function(event) {
274
+ try {
275
+ const msg = JSON.parse(event.data);
276
+ const now = Date.now();
277
+ const delayMs = __concaveGetDelayForEvent(event);
278
+
279
+ if (msg.type === 'AuthError') {
280
+ const errorDetails = {};
281
+ if (typeof msg.baseVersion === 'number') errorDetails.baseVersion = msg.baseVersion;
282
+ if (typeof msg.authUpdateAttempted === 'boolean') errorDetails.authUpdateAttempted = msg.authUpdateAttempted;
283
+ emitAuthEvent('server', 'AuthError', 'error', errorDetails, msg.error || 'Authentication failed', window.__concaveDevToolsPendingAuthTokenType || undefined);
284
+ window.__concaveDevToolsPendingAuthTokenType = null;
285
+ }
286
+
287
+ // Handle transitions (query updates)
288
+ if (msg.type === 'Transition' && msg.modifications) {
289
+ if (window.__concaveDevToolsPendingAuthTokenType) {
290
+ emitAuthEvent(
291
+ 'server',
292
+ 'Authenticated',
293
+ 'success',
294
+ { modificationCount: msg.modifications.length },
295
+ undefined,
296
+ window.__concaveDevToolsPendingAuthTokenType
297
+ );
298
+ window.__concaveDevToolsPendingAuthTokenType = null;
299
+ }
300
+ msg.modifications.forEach(mod => {
301
+ if (mod.type === 'QueryUpdated' || mod.type === 'QueryFailed') {
302
+ const pending = window.__concaveDevToolsPendingQueries.get(mod.queryId);
303
+ if (pending) {
304
+ const duration = now - pending.startTime;
305
+ window.__concaveDevToolsEvents.push({
306
+ id: 'query-' + mod.queryId + '-' + now,
307
+ timestamp: now,
308
+ type: 'query',
309
+ queryId: mod.queryId,
310
+ udfPath: pending.udfPath,
311
+ args: pending.args,
312
+ componentPath: pending.componentPath,
313
+ status: mod.type === 'QueryUpdated' ? 'success' : 'error',
314
+ result: mod.type === 'QueryUpdated' ? mod.value : undefined,
315
+ error: mod.type === 'QueryFailed' ? mod.errorMessage : undefined,
316
+ trace: mod.type === 'QueryUpdated' ? mod.trace : undefined,
317
+ logLines: mod.logLines,
318
+ duration: duration,
319
+ simulatedDelayMs: delayMs,
320
+ endToEndDurationMs: duration + delayMs
321
+ });
322
+
323
+ // Extract log events
324
+ if (mod.logLines && mod.logLines.length > 0) {
325
+ mod.logLines.forEach(logLine => {
326
+ const match = logLine.match(/^\\[(log|info|warn|error)\\]\\s+(.+)$/i);
327
+ const level = match ? match[1].toLowerCase() : 'log';
328
+ const message = match ? match[2] : logLine;
329
+ window.__concaveDevToolsEvents.push({
330
+ id: 'log-' + now + '-' + Math.random(),
331
+ timestamp: now,
332
+ type: 'log',
333
+ level: level,
334
+ message: message,
335
+ relatedEventId: 'query-' + mod.queryId + '-' + now
336
+ });
337
+ });
338
+ }
339
+ }
340
+ }
341
+ });
342
+ }
343
+
344
+ // Handle mutation responses
345
+ if (msg.type === 'MutationResponse') {
346
+ const pending = window.__concaveDevToolsPendingMutations.get(msg.requestId);
347
+ if (pending) {
348
+ const duration = now - pending.startTime;
349
+ window.__concaveDevToolsEvents.push({
350
+ id: 'mutation-' + msg.requestId + '-' + now,
351
+ timestamp: now,
352
+ type: 'mutation',
353
+ requestId: msg.requestId,
354
+ udfPath: pending.udfPath,
355
+ args: pending.args,
356
+ componentPath: pending.componentPath,
357
+ status: msg.success ? 'success' : 'error',
358
+ result: msg.success ? msg.result : undefined,
359
+ error: !msg.success ? msg.result : undefined,
360
+ trace: msg.trace,
361
+ logLines: msg.logLines,
362
+ duration: duration,
363
+ simulatedDelayMs: delayMs,
364
+ endToEndDurationMs: duration + delayMs
365
+ });
366
+
367
+ // Extract log events
368
+ if (msg.logLines && msg.logLines.length > 0) {
369
+ msg.logLines.forEach(logLine => {
370
+ const match = logLine.match(/^\\[(log|info|warn|error)\\]\\s+(.+)$/i);
371
+ const level = match ? match[1].toLowerCase() : 'log';
372
+ const message = match ? match[2] : logLine;
373
+ window.__concaveDevToolsEvents.push({
374
+ id: 'log-' + now + '-' + Math.random(),
375
+ timestamp: now,
376
+ type: 'log',
377
+ level: level,
378
+ message: message,
379
+ relatedEventId: 'mutation-' + msg.requestId + '-' + now
380
+ });
381
+ });
382
+ }
383
+
384
+ window.__concaveDevToolsPendingMutations.delete(msg.requestId);
385
+ }
386
+ }
387
+
388
+ // Handle action responses
389
+ if (msg.type === 'ActionResponse') {
390
+ const pending = window.__concaveDevToolsPendingActions.get(msg.requestId);
391
+ if (pending) {
392
+ const duration = now - pending.startTime;
393
+ window.__concaveDevToolsEvents.push({
394
+ id: 'action-' + msg.requestId + '-' + now,
395
+ timestamp: now,
396
+ type: 'action',
397
+ requestId: msg.requestId,
398
+ udfPath: pending.udfPath,
399
+ args: pending.args,
400
+ componentPath: pending.componentPath,
401
+ status: msg.success ? 'success' : 'error',
402
+ result: msg.success ? msg.result : undefined,
403
+ error: !msg.success ? msg.result : undefined,
404
+ trace: msg.trace,
405
+ logLines: msg.logLines,
406
+ duration: duration,
407
+ simulatedDelayMs: delayMs,
408
+ endToEndDurationMs: duration + delayMs
409
+ });
410
+
411
+ // Extract log events
412
+ if (msg.logLines && msg.logLines.length > 0) {
413
+ msg.logLines.forEach(logLine => {
414
+ const match = logLine.match(/^\\[(log|info|warn|error)\\]\\s+(.+)$/i);
415
+ const level = match ? match[1].toLowerCase() : 'log';
416
+ const message = match ? match[2] : logLine;
417
+ window.__concaveDevToolsEvents.push({
418
+ id: 'log-' + now + '-' + Math.random(),
419
+ timestamp: now,
420
+ type: 'log',
421
+ level: level,
422
+ message: message,
423
+ relatedEventId: 'action-' + msg.requestId + '-' + now
424
+ });
425
+ });
426
+ }
427
+
428
+ window.__concaveDevToolsPendingActions.delete(msg.requestId);
429
+ }
430
+ }
431
+ } catch (e) {
432
+ console.warn('[DevTools] Error parsing server message:', e);
433
+ }
434
+ __concaveInvokeWithLatency(listener, ws, event);
435
+ };
436
+ wrappedListener[__concaveInternalMessageListener] = true;
437
+ messageListenerWrappers.set(listener, wrappedListener);
438
+ }
439
+ return originalAddEventListener('message', wrappedListener, options);
440
+ }
441
+ return originalAddEventListener(type, listener, options);
442
+ };
443
+
444
+ ws.removeEventListener = function(type, listener, options) {
445
+ if (type === 'message' && typeof listener === 'function') {
446
+ const wrappedListener = messageListenerWrappers.get(listener);
447
+ return originalRemoveEventListener('message', wrappedListener || listener, options);
448
+ }
449
+ return originalRemoveEventListener(type, listener, options);
450
+ };
451
+
452
+ // Intercept onmessage assignment as well
453
+ (function(){
454
+ let currentHandler = null;
455
+ let currentOnMessageWrapper = null;
456
+ Object.defineProperty(ws, 'onmessage', {
457
+ configurable: true,
458
+ enumerable: true,
459
+ get() {
460
+ return currentHandler;
461
+ },
462
+ set(handler) {
463
+ // Remove previous wrapper if present
464
+ if (currentOnMessageWrapper) {
465
+ originalRemoveEventListener('message', currentOnMessageWrapper);
466
+ currentOnMessageWrapper = null;
467
+ }
468
+ currentHandler = handler;
469
+ if (typeof handler === 'function') {
470
+ const wrapper = function(event) {
471
+ try {
472
+ const msg = JSON.parse(event.data);
473
+ const now = Date.now();
474
+ const delayMs = __concaveGetDelayForEvent(event);
475
+
476
+ if (msg.type === 'AuthError') {
477
+ const errorDetails = {};
478
+ if (typeof msg.baseVersion === 'number') errorDetails.baseVersion = msg.baseVersion;
479
+ if (typeof msg.authUpdateAttempted === 'boolean') errorDetails.authUpdateAttempted = msg.authUpdateAttempted;
480
+ emitAuthEvent('server', 'AuthError', 'error', errorDetails, msg.error || 'Authentication failed', window.__concaveDevToolsPendingAuthTokenType || undefined);
481
+ window.__concaveDevToolsPendingAuthTokenType = null;
482
+ }
483
+
484
+ // Mirror the same processing as in addEventListener wrapper
485
+ if (msg.type === 'Transition' && msg.modifications) {
486
+ if (window.__concaveDevToolsPendingAuthTokenType) {
487
+ emitAuthEvent(
488
+ 'server',
489
+ 'Authenticated',
490
+ 'success',
491
+ { modificationCount: msg.modifications.length },
492
+ undefined,
493
+ window.__concaveDevToolsPendingAuthTokenType
494
+ );
495
+ window.__concaveDevToolsPendingAuthTokenType = null;
496
+ }
497
+ msg.modifications.forEach(mod => {
498
+ if (mod.type === 'QueryUpdated' || mod.type === 'QueryFailed') {
499
+ const pending = window.__concaveDevToolsPendingQueries.get(mod.queryId);
500
+ if (pending) {
501
+ const duration = now - pending.startTime;
502
+ window.__concaveDevToolsEvents.push({
503
+ id: 'query-' + mod.queryId + '-' + now,
504
+ timestamp: now,
505
+ type: 'query',
506
+ queryId: mod.queryId,
507
+ udfPath: pending.udfPath,
508
+ args: pending.args,
509
+ componentPath: pending.componentPath,
510
+ status: mod.type === 'QueryUpdated' ? 'success' : 'error',
511
+ result: mod.type === 'QueryUpdated' ? mod.value : undefined,
512
+ error: mod.type === 'QueryFailed' ? mod.errorMessage : undefined,
513
+ trace: mod.type === 'QueryUpdated' ? mod.trace : undefined,
514
+ logLines: mod.logLines,
515
+ duration: duration,
516
+ simulatedDelayMs: delayMs,
517
+ endToEndDurationMs: duration + delayMs
518
+ });
519
+ if (mod.logLines && mod.logLines.length > 0) {
520
+ mod.logLines.forEach(logLine => {
521
+ const match = logLine.match(/^\\[(log|info|warn|error)\\]\\s+(.+)$/i);
522
+ const level = match ? match[1].toLowerCase() : 'log';
523
+ const message = match ? match[2] : logLine;
524
+ window.__concaveDevToolsEvents.push({
525
+ id: 'log-' + now + '-' + Math.random(),
526
+ timestamp: now,
527
+ type: 'log',
528
+ level: level,
529
+ message: message,
530
+ relatedEventId: 'query-' + mod.queryId + '-' + now
531
+ });
532
+ });
533
+ }
534
+ }
535
+ }
536
+ });
537
+ }
538
+ if (msg.type === 'MutationResponse') {
539
+ const pending = window.__concaveDevToolsPendingMutations.get(msg.requestId);
540
+ if (pending) {
541
+ const duration = now - pending.startTime;
542
+ window.__concaveDevToolsEvents.push({
543
+ id: 'mutation-' + msg.requestId + '-' + now,
544
+ timestamp: now,
545
+ type: 'mutation',
546
+ requestId: msg.requestId,
547
+ udfPath: pending.udfPath,
548
+ args: pending.args,
549
+ componentPath: pending.componentPath,
550
+ status: msg.success ? 'success' : 'error',
551
+ result: msg.success ? msg.result : undefined,
552
+ error: !msg.success ? msg.result : undefined,
553
+ trace: msg.trace,
554
+ logLines: msg.logLines,
555
+ duration: duration,
556
+ simulatedDelayMs: delayMs,
557
+ endToEndDurationMs: duration + delayMs
558
+ });
559
+ if (msg.logLines && msg.logLines.length > 0) {
560
+ msg.logLines.forEach(logLine => {
561
+ const match = logLine.match(/^\\[(log|info|warn|error)\\]\\s+(.+)$/i);
562
+ const level = match ? match[1].toLowerCase() : 'log';
563
+ const message = match ? match[2] : logLine;
564
+ window.__concaveDevToolsEvents.push({
565
+ id: 'log-' + now + '-' + Math.random(),
566
+ timestamp: now,
567
+ type: 'log',
568
+ level: level,
569
+ message: message,
570
+ relatedEventId: 'mutation-' + msg.requestId + '-' + now
571
+ });
572
+ });
573
+ }
574
+ window.__concaveDevToolsPendingMutations.delete(msg.requestId);
575
+ }
576
+ }
577
+ if (msg.type === 'ActionResponse') {
578
+ const pending = window.__concaveDevToolsPendingActions.get(msg.requestId);
579
+ if (pending) {
580
+ const duration = now - pending.startTime;
581
+ window.__concaveDevToolsEvents.push({
582
+ id: 'action-' + msg.requestId + '-' + now,
583
+ timestamp: now,
584
+ type: 'action',
585
+ requestId: msg.requestId,
586
+ udfPath: pending.udfPath,
587
+ args: pending.args,
588
+ componentPath: pending.componentPath,
589
+ status: msg.success ? 'success' : 'error',
590
+ result: msg.success ? msg.result : undefined,
591
+ error: !msg.success ? msg.result : undefined,
592
+ trace: msg.trace,
593
+ logLines: msg.logLines,
594
+ duration: duration,
595
+ simulatedDelayMs: delayMs,
596
+ endToEndDurationMs: duration + delayMs
597
+ });
598
+ if (msg.logLines && msg.logLines.length > 0) {
599
+ msg.logLines.forEach(logLine => {
600
+ const match = logLine.match(/^\\[(log|info|warn|error)\\]\\s+(.+)$/i);
601
+ const level = match ? match[1].toLowerCase() : 'log';
602
+ const message = match ? match[2] : logLine;
603
+ window.__concaveDevToolsEvents.push({
604
+ id: 'log-' + now + '-' + Math.random(),
605
+ timestamp: now,
606
+ type: 'log',
607
+ level: level,
608
+ message: message,
609
+ relatedEventId: 'action-' + msg.requestId + '-' + now
610
+ });
611
+ });
612
+ }
613
+ window.__concaveDevToolsPendingActions.delete(msg.requestId);
614
+ }
615
+ }
616
+ } catch (e) {
617
+ console.warn('[DevTools] Error parsing server message (onmessage):', e);
618
+ }
619
+ __concaveInvokeWithLatency(handler, ws, event);
620
+ };
621
+ wrapper[__concaveInternalMessageListener] = true;
622
+ currentOnMessageWrapper = wrapper;
623
+ originalAddEventListener('message', wrapper);
624
+ }
625
+ }
626
+ });
627
+ })();
628
+
629
+ return ws;
630
+ };
631
+
632
+ // Preserve prototype chain
633
+ Object.setPrototypeOf(window.WebSocket, OriginalWebSocket);
634
+ Object.defineProperty(window.WebSocket, 'prototype', {
635
+ value: OriginalWebSocket.prototype,
636
+ writable: false,
637
+ configurable: false
638
+ });
639
+
640
+ console.log('[DevTools] WebSocket interceptor installed');
641
+ })();
642
+ <\/script>
643
+ `, r = `
644
+ <script>
645
+ window.__concaveDevToolsConfig = ${JSON.stringify({ position: a, autoInit: !0 })};
646
+ <\/script>
647
+ `, n = i + r + `
648
+ <script type="module">
649
+ import { initDevTools } from '@concavejs/devtools/client';
650
+ <\/script>
651
+ `;
652
+ return e.includes("</head>") ? e.replace("</head>", `${n}</head>`) : e.includes("</body>") ? e.replace("</body>", `${n}</body>`) : e + n;
653
+ }
654
+ },
655
+ // Ensure devtools dependencies are optimized
656
+ config(e) {
657
+ return {
658
+ optimizeDeps: {
659
+ include: [...e.optimizeDeps?.include || [], "react", "react-dom"]
660
+ }
661
+ };
662
+ }
663
+ };
664
+ }
665
+ export {
666
+ c as concaveDevTools,
667
+ c as default
668
+ };