opencons 0.1.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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +382 -0
  3. package/opencons.d.ts +55 -0
  4. package/package.json +73 -0
  5. package/scripts/vendor-d3.js +22 -0
  6. package/src/core/context.js +44 -0
  7. package/src/core/index.js +198 -0
  8. package/src/core/tracer.js +252 -0
  9. package/src/drivers/db-language.js +207 -0
  10. package/src/drivers/detect.js +62 -0
  11. package/src/drivers/drizzle.js +87 -0
  12. package/src/drivers/index.js +43 -0
  13. package/src/drivers/mongoose.js +89 -0
  14. package/src/drivers/mysql2.js +116 -0
  15. package/src/drivers/pg.js +130 -0
  16. package/src/drivers/prisma.js +109 -0
  17. package/src/drivers/record.js +158 -0
  18. package/src/index.js +28 -0
  19. package/src/integrations/nest-lifecycle.js +357 -0
  20. package/src/integrations/nest.js +89 -0
  21. package/src/interceptors/express.js +270 -0
  22. package/src/interceptors/require-hook.js +109 -0
  23. package/src/lib/config.js +139 -0
  24. package/src/lib/errors.js +54 -0
  25. package/src/lib/http-response.js +37 -0
  26. package/src/lib/logger.js +69 -0
  27. package/src/lib/serialize.js +22 -0
  28. package/src/server/static.js +165 -0
  29. package/src/server/ws.js +62 -0
  30. package/src/store/source-cache.js +120 -0
  31. package/src/store/trace-store.js +117 -0
  32. package/src/transform/ast.js +255 -0
  33. package/src/transform/natural-language.js +146 -0
  34. package/src/transform/probe.js +161 -0
  35. package/src/transform/register.js +44 -0
  36. package/src/utils/label.js +26 -0
  37. package/src/utils/observable.js +103 -0
  38. package/widget/app.js +356 -0
  39. package/widget/db-language.js +90 -0
  40. package/widget/graph.js +1167 -0
  41. package/widget/index.html +132 -0
  42. package/widget/styles.css +773 -0
  43. package/widget/timeline.js +57 -0
  44. package/widget/vendor/d3.min.js +2 -0
@@ -0,0 +1,773 @@
1
+ :root {
2
+ --sidebar-bg: #121212;
3
+ --main-bg: #1a1a1a;
4
+ --card-bg: #222222;
5
+ --card-hover: #2a2a2a;
6
+ --border: rgba(255, 255, 255, 0.08);
7
+ --border-strong: rgba(255, 255, 255, 0.14);
8
+ --text: #ffffff;
9
+ --text-muted: #9ca3af;
10
+ --text-subtle: #6b7280;
11
+ --accent: #154f7f;
12
+ --accent-soft: rgba(255, 77, 0, 0.14);
13
+ --accent-glow: rgba(255, 77, 0, 0.35);
14
+ --middleware: #154f7f;
15
+ --branch: #154f7f;
16
+ --db: #3b82f6;
17
+ --request: #6b7280;
18
+ --error: #e43636;
19
+ --success: #22c55e;
20
+ --warning: #154f7f;
21
+ --radius: 8px;
22
+ --radius-lg: 12px;
23
+ --sidebar-width: 280px;
24
+ --font: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
25
+ --mono: 'Cascadia Code', 'Fira Code', 'SF Mono', monospace;
26
+ }
27
+
28
+ * {
29
+ box-sizing: border-box;
30
+ margin: 0;
31
+ padding: 0;
32
+ }
33
+
34
+ body {
35
+ font-family: var(--font);
36
+ background: var(--main-bg);
37
+ color: var(--text);
38
+ height: 100vh;
39
+ overflow: hidden;
40
+ -webkit-font-smoothing: antialiased;
41
+ }
42
+
43
+ .app-shell {
44
+ display: grid;
45
+ grid-template-columns: var(--sidebar-width) 1fr;
46
+ height: 100vh;
47
+ background: var(--sidebar-bg)
48
+ }
49
+
50
+ /* ── Sidebar ─────────────────────────────────────────────── */
51
+
52
+ .sidebar {
53
+ background: var(--sidebar-bg);
54
+ /* border-right: 1px solid var(--border); */
55
+ display: flex;
56
+ flex-direction: column;
57
+ min-height: 0;
58
+ }
59
+
60
+ .sidebar-top {
61
+ padding: 20px 16px 12px;
62
+ }
63
+
64
+ .workspace-brand {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 12px;
68
+ }
69
+
70
+ .brand-mark {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ width: 36px;
75
+ height: 36px;
76
+ border-radius: var(--radius);
77
+ background: var(--accent);
78
+ color: #fff;
79
+ font-weight: 700;
80
+ font-size: 1rem;
81
+ flex-shrink: 0;
82
+ }
83
+
84
+ .brand-text {
85
+ display: flex;
86
+ flex-direction: column;
87
+ gap: 2px;
88
+ min-width: 0;
89
+ }
90
+
91
+ .workspace-name {
92
+ font-size: 0.95rem;
93
+ font-weight: 600;
94
+ color: var(--text);
95
+ letter-spacing: -0.01em;
96
+ }
97
+
98
+ .workspace-sub {
99
+ font-size: 0.72rem;
100
+ color: var(--text-subtle);
101
+ }
102
+
103
+ .sidebar-nav {
104
+ display: flex;
105
+ flex-direction: column;
106
+ gap: 2px;
107
+ padding: 8px 10px;
108
+ }
109
+
110
+ .nav-item {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 10px;
114
+ width: 100%;
115
+ padding: 10px 12px;
116
+ border: none;
117
+ border-radius: var(--radius);
118
+ background: transparent;
119
+ color: var(--text-muted);
120
+ font-family: inherit;
121
+ font-size: 0.84rem;
122
+ font-weight: 500;
123
+ text-align: left;
124
+ cursor: pointer;
125
+ transition: background 0.15s, color 0.15s;
126
+ }
127
+
128
+ .nav-item:hover:not(:disabled) {
129
+ background: rgba(255, 255, 255, 0.05);
130
+ color: var(--text);
131
+ }
132
+
133
+ .nav-item.active {
134
+ background: rgba(255, 255, 255, 0.08);
135
+ color: var(--text);
136
+ }
137
+
138
+ .nav-item:disabled {
139
+ opacity: 0.45;
140
+ cursor: not-allowed;
141
+ }
142
+
143
+ .nav-icon {
144
+ width: 18px;
145
+ height: 18px;
146
+ flex-shrink: 0;
147
+ opacity: 0.85;
148
+ }
149
+
150
+ .nav-badge {
151
+ margin-left: auto;
152
+ background: var(--card-bg);
153
+ border: 1px solid var(--border);
154
+ padding: 2px 8px;
155
+ border-radius: 999px;
156
+ font-size: 0.72rem;
157
+ font-weight: 600;
158
+ color: var(--text-muted);
159
+ }
160
+
161
+ .nav-item.active .nav-badge {
162
+ border-color: var(--accent-glow);
163
+ color: var(--accent);
164
+ }
165
+
166
+ .sidebar-section {
167
+ flex: 1;
168
+ display: flex;
169
+ flex-direction: column;
170
+ min-height: 0;
171
+ padding: 12px 10px 8px;
172
+ border-top: 1px solid var(--border);
173
+ margin-top: 8px;
174
+ }
175
+
176
+ .section-label {
177
+ font-size: 0.68rem;
178
+ font-weight: 600;
179
+ text-transform: uppercase;
180
+ letter-spacing: 0.08em;
181
+ color: var(--text-subtle);
182
+ padding: 0 6px 10px;
183
+ }
184
+
185
+ .request-list {
186
+ list-style: none;
187
+ overflow-y: auto;
188
+ flex: 1;
189
+ }
190
+
191
+ .request-item {
192
+ padding: 10px 12px;
193
+ margin-bottom: 4px;
194
+ border-radius: var(--radius);
195
+ border: 1px solid transparent;
196
+ cursor: pointer;
197
+ transition: background 0.15s, border-color 0.15s;
198
+ }
199
+
200
+ .request-item:hover {
201
+ background: rgba(255, 255, 255, 0.04);
202
+ }
203
+
204
+ .request-item.active {
205
+ background: var(--accent-soft);
206
+ border-color: var(--accent-glow);
207
+ }
208
+
209
+ .request-item.in-flight {
210
+ border-left: 3px solid var(--accent);
211
+ padding-left: 9px;
212
+ }
213
+
214
+ .request-item.highlight {
215
+ animation: request-highlight 2s ease-out;
216
+ }
217
+
218
+ @keyframes request-highlight {
219
+ 0% {
220
+ background: var(--accent-soft);
221
+ box-shadow: 0 0 0 1px var(--accent-glow);
222
+ }
223
+
224
+ 100% {
225
+ background: transparent;
226
+ box-shadow: none;
227
+ }
228
+ }
229
+
230
+ .live-dot {
231
+ display: inline-block;
232
+ width: 7px;
233
+ height: 7px;
234
+ margin-left: 6px;
235
+ border-radius: 50%;
236
+ background: var(--accent);
237
+ animation: live-pulse 1.2s ease-in-out infinite;
238
+ vertical-align: middle;
239
+ }
240
+
241
+ @keyframes live-pulse {
242
+
243
+ 0%,
244
+ 100% {
245
+ opacity: 1;
246
+ transform: scale(1);
247
+ }
248
+
249
+ 50% {
250
+ opacity: 0.4;
251
+ transform: scale(0.85);
252
+ }
253
+ }
254
+
255
+ .request-item .method {
256
+ font-size: 0.68rem;
257
+ font-weight: 700;
258
+ padding: 2px 6px;
259
+ border-radius: 4px;
260
+ margin-right: 8px;
261
+ }
262
+
263
+ .method-GET {
264
+ background: rgba(59, 130, 246, 0.18);
265
+ color: #60a5fa;
266
+ }
267
+
268
+ .method-POST {
269
+ background: rgba(34, 197, 94, 0.18);
270
+ color: #4ade80;
271
+ }
272
+
273
+ .method-PUT,
274
+ .method-PATCH {
275
+ background: rgba(245, 158, 11, 0.18);
276
+ color: #fbbf24;
277
+ }
278
+
279
+ .method-DELETE {
280
+ background: rgba(239, 68, 68, 0.18);
281
+ color: #f87171;
282
+ }
283
+
284
+ .request-item .url {
285
+ font-size: 0.8rem;
286
+ word-break: break-all;
287
+ color: var(--text);
288
+ }
289
+
290
+ .request-meta {
291
+ display: flex;
292
+ gap: 10px;
293
+ margin-top: 6px;
294
+ font-size: 0.7rem;
295
+ color: var(--text-subtle);
296
+ }
297
+
298
+ .status-badge {
299
+ padding: 1px 6px;
300
+ border-radius: 4px;
301
+ font-weight: 600;
302
+ }
303
+
304
+ .status-pending {
305
+ background: var(--accent-soft);
306
+ color: var(--accent);
307
+ }
308
+
309
+ .status-2xx {
310
+ background: rgba(34, 197, 94, 0.18);
311
+ color: #4ade80;
312
+ }
313
+
314
+ .status-3xx {
315
+ background: rgba(59, 130, 246, 0.18);
316
+ color: #60a5fa;
317
+ }
318
+
319
+ .status-4xx {
320
+ background: rgba(245, 158, 11, 0.18);
321
+ color: #fbbf24;
322
+ }
323
+
324
+ .status-5xx {
325
+ background: rgba(239, 68, 68, 0.18);
326
+ color: #f87171;
327
+ }
328
+
329
+ .empty-state {
330
+ padding: 20px 12px;
331
+ text-align: center;
332
+ color: var(--text-subtle);
333
+ font-size: 0.82rem;
334
+ line-height: 1.5;
335
+ }
336
+
337
+ .sidebar-footer {
338
+ padding: 14px 16px;
339
+ border-top: 1px solid var(--border);
340
+ }
341
+
342
+ .status {
343
+ display: flex;
344
+ align-items: center;
345
+ gap: 8px;
346
+ font-size: 0.78rem;
347
+ color: var(--text-muted);
348
+ }
349
+
350
+ .status-dot {
351
+ width: 8px;
352
+ height: 8px;
353
+ border-radius: 50%;
354
+ background: var(--error);
355
+ flex-shrink: 0;
356
+ }
357
+
358
+ .status-dot.connected {
359
+ background: var(--success);
360
+ box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);
361
+ }
362
+
363
+ /* ── Main content ────────────────────────────────────────── */
364
+
365
+ .main-content {
366
+ display: flex;
367
+ flex-direction: column;
368
+ min-width: 0;
369
+ min-height: 0;
370
+ background: var(--main-bg);
371
+ padding: 10px;
372
+ background-color: var(--card-bg);
373
+ margin: 10px 10px 10px 0px;
374
+ border-radius: 20px;
375
+ }
376
+
377
+ .main-header {
378
+ display: flex;
379
+ align-items: flex-end;
380
+ justify-content: space-between;
381
+ gap: 20px;
382
+ padding: 20px 20px 20px 20px;
383
+ }
384
+
385
+ .eyebrow {
386
+ font-size: 0.72rem;
387
+ font-weight: 600;
388
+ text-transform: uppercase;
389
+ letter-spacing: 0.08em;
390
+ color: var(--accent);
391
+ margin-bottom: 6px;
392
+ }
393
+
394
+ .main-header h1 {
395
+ font-size: 1.5rem;
396
+ font-weight: 700;
397
+ letter-spacing: -0.02em;
398
+ line-height: 1.2;
399
+ color: var(--text);
400
+ }
401
+
402
+ .view-tabs {
403
+ display: flex;
404
+ gap: 6px;
405
+ background: var(--card-bg);
406
+ padding: 4px;
407
+ border-radius: var(--radius);
408
+ border: 1px solid var(--border);
409
+ }
410
+
411
+ .tab {
412
+ background: transparent;
413
+ border: none;
414
+ color: var(--text-muted);
415
+ padding: 8px 16px;
416
+ border-radius: 6px;
417
+ font-family: inherit;
418
+ font-size: 0.8rem;
419
+ font-weight: 500;
420
+ cursor: pointer;
421
+ transition: background 0.15s, color 0.15s;
422
+ }
423
+
424
+ .tab:hover {
425
+ color: var(--text);
426
+ }
427
+
428
+ .tab.active {
429
+ background: var(--accent);
430
+ color: #fff;
431
+ }
432
+
433
+ .main-body {
434
+ flex: 1;
435
+ display: flex;
436
+ flex-direction: column;
437
+ min-height: 0;
438
+ padding: 10px 0px 0px 0px;
439
+ gap: 16px;
440
+ border-radius: 30px;
441
+ }
442
+
443
+ .trace-views {
444
+ flex: 1 1 auto;
445
+ min-height: 280px;
446
+ position: relative;
447
+ overflow: hidden;
448
+ }
449
+
450
+ .view {
451
+ display: none;
452
+ height: 100%;
453
+ }
454
+
455
+ .view.active {
456
+ display: block;
457
+ }
458
+
459
+ .view-card {
460
+ height: 100%;
461
+ background: var(--card-bg);
462
+ border: 1px solid var(--border);
463
+ border-radius: var(--radius-lg);
464
+ overflow: hidden;
465
+ position: relative;
466
+ }
467
+
468
+ #graph-view {
469
+ position: relative;
470
+ }
471
+
472
+ #graph-svg {
473
+ width: 100%;
474
+ height: 100%;
475
+ background: #181818;
476
+ cursor: grab;
477
+ }
478
+
479
+ #graph-svg:active {
480
+ cursor: grabbing;
481
+ }
482
+
483
+ .graph-controls {
484
+ position: absolute;
485
+ top: 14px;
486
+ right: 14px;
487
+ display: flex;
488
+ align-items: center;
489
+ gap: 8px;
490
+ z-index: 5;
491
+ }
492
+
493
+ .graph-hint {
494
+ font-size: 0.72rem;
495
+ color: var(--text-subtle);
496
+ margin-right: 4px;
497
+ user-select: none;
498
+ }
499
+
500
+ .graph-controls button {
501
+ background: var(--sidebar-bg);
502
+ border: 1px solid var(--border-strong);
503
+ color: var(--text);
504
+ border-radius: var(--radius);
505
+ min-width: 32px;
506
+ height: 30px;
507
+ font-size: 0.82rem;
508
+ cursor: pointer;
509
+ transition: border-color 0.15s, color 0.15s;
510
+ }
511
+
512
+ .graph-controls button:hover {
513
+ border-color: var(--accent);
514
+ color: var(--accent);
515
+ }
516
+
517
+ #graph-zoom-reset {
518
+ min-width: 40px;
519
+ font-weight: 600;
520
+ }
521
+
522
+ .graph-node {
523
+ cursor: grab;
524
+ }
525
+
526
+ .graph-node.is-dragging {
527
+ cursor: grabbing;
528
+ }
529
+
530
+ .graph-node text {
531
+ pointer-events: none;
532
+ }
533
+
534
+ .graph-link {
535
+ fill: none;
536
+ stroke-width: 2.5px;
537
+ stroke-linecap: round;
538
+ }
539
+
540
+ .graph-link.active {
541
+ stroke-width: 3px;
542
+ opacity: 0.95;
543
+ }
544
+
545
+ .graph-link.inactive {
546
+ stroke-width: 2px;
547
+ stroke-dasharray: 7 6;
548
+ opacity: 0.45;
549
+ }
550
+
551
+ .graph-link.db-out,
552
+ .graph-link.db-to-hub {
553
+ stroke: var(--db);
554
+ stroke-width: 2.5px;
555
+ opacity: 0.9;
556
+ }
557
+
558
+ .graph-link.db-from-hub,
559
+ .graph-link.db-return {
560
+ stroke: #60a5fa;
561
+ stroke-width: 2px;
562
+ stroke-dasharray: 7 6;
563
+ opacity: 0.72;
564
+ }
565
+
566
+ .graph-node.is-decision .decision-diamond {
567
+ filter: drop-shadow(0 0 8px rgba(255, 77, 0, 0.2));
568
+ }
569
+
570
+ .tooltip {
571
+ position: absolute;
572
+ background: var(--sidebar-bg);
573
+ border: 1px solid var(--border-strong);
574
+ border-radius: var(--radius);
575
+ padding: 12px 14px;
576
+ font-size: 0.8rem;
577
+ pointer-events: none;
578
+ z-index: 10;
579
+ max-width: 300px;
580
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
581
+ }
582
+
583
+ .tooltip.hidden {
584
+ display: none;
585
+ }
586
+
587
+ .tooltip dt {
588
+ color: var(--text-subtle);
589
+ font-size: 0.7rem;
590
+ margin-top: 6px;
591
+ }
592
+
593
+ .tooltip dt:first-child {
594
+ margin-top: 0;
595
+ }
596
+
597
+ .tooltip dd {
598
+ margin-left: 0;
599
+ font-family: var(--mono);
600
+ font-size: 0.78rem;
601
+ }
602
+
603
+ /* ── Detail panels ───────────────────────────────────────── */
604
+
605
+ .detail-panels {
606
+ display: grid;
607
+ grid-template-columns: 1fr 1fr;
608
+ gap: 16px;
609
+ flex-shrink: 0;
610
+ }
611
+
612
+ .detail-card {
613
+ background: var(--card-bg);
614
+ border: 1px solid var(--border);
615
+ border-radius: var(--radius-lg);
616
+ padding: 16px 20px;
617
+ max-height: 200px;
618
+ overflow-y: auto;
619
+ }
620
+
621
+ .detail-card.hidden {
622
+ display: none;
623
+ }
624
+
625
+ .card-title {
626
+ font-size: 0.72rem;
627
+ font-weight: 600;
628
+ text-transform: uppercase;
629
+ letter-spacing: 0.08em;
630
+ color: var(--text-subtle);
631
+ margin-bottom: 12px;
632
+ }
633
+
634
+ .detail-grid {
635
+ display: grid;
636
+ grid-template-columns: 120px 1fr;
637
+ gap: 6px 12px;
638
+ font-size: 0.82rem;
639
+ }
640
+
641
+ .detail-grid dt {
642
+ color: var(--text-muted);
643
+ }
644
+
645
+ .detail-grid dd {
646
+ font-family: var(--mono);
647
+ word-break: break-all;
648
+ color: var(--text);
649
+ }
650
+
651
+ .source-peek-header {
652
+ display: flex;
653
+ align-items: baseline;
654
+ gap: 12px;
655
+ margin-bottom: 10px;
656
+ }
657
+
658
+ .source-peek-path {
659
+ font-family: var(--mono);
660
+ font-size: 0.75rem;
661
+ color: var(--text-subtle);
662
+ }
663
+
664
+ .source-peek-content {
665
+ margin: 0;
666
+ font-family: var(--mono);
667
+ font-size: 0.78rem;
668
+ line-height: 1.55;
669
+ white-space: pre;
670
+ }
671
+
672
+ .source-line {
673
+ display: block;
674
+ }
675
+
676
+ .source-line .line-num {
677
+ display: inline-block;
678
+ width: 3.5em;
679
+ color: var(--text-subtle);
680
+ user-select: none;
681
+ }
682
+
683
+ .source-line.highlight {
684
+ background: var(--accent-soft);
685
+ border-left: 3px solid var(--accent);
686
+ padding-left: 6px;
687
+ margin-left: -9px;
688
+ }
689
+
690
+ /* ── Timeline ────────────────────────────────────────────── */
691
+
692
+ .view-card {
693
+ overflow-y: auto;
694
+ }
695
+
696
+ .timeline-row {
697
+ display: grid;
698
+ grid-template-columns: 180px 1fr 80px;
699
+ align-items: center;
700
+ gap: 12px;
701
+ padding: 10px 20px;
702
+ border-bottom: 1px solid var(--border);
703
+ font-size: 0.8rem;
704
+ }
705
+
706
+ .timeline-row:last-child {
707
+ border-bottom: none;
708
+ }
709
+
710
+ .timeline-label {
711
+ overflow: hidden;
712
+ text-overflow: ellipsis;
713
+ white-space: nowrap;
714
+ color: var(--text);
715
+ }
716
+
717
+ .timeline-bar-track {
718
+ height: 20px;
719
+ background: rgba(255, 255, 255, 0.05);
720
+ border-radius: 4px;
721
+ position: relative;
722
+ }
723
+
724
+ .timeline-bar {
725
+ position: absolute;
726
+ height: 100%;
727
+ border-radius: 4px;
728
+ min-width: 2px;
729
+ }
730
+
731
+ .timeline-duration {
732
+ text-align: right;
733
+ color: var(--text-subtle);
734
+ font-family: var(--mono);
735
+ font-size: 0.75rem;
736
+ }
737
+
738
+ .type-request .timeline-bar,
739
+ .type-response .timeline-bar {
740
+ background: var(--request);
741
+ }
742
+
743
+ .type-middleware .timeline-bar {
744
+ background: var(--middleware);
745
+ }
746
+
747
+ .type-branch .timeline-bar {
748
+ background: var(--branch);
749
+ }
750
+
751
+ .type-db .timeline-bar {
752
+ background: var(--db);
753
+ }
754
+
755
+ .type-error .timeline-bar {
756
+ background: var(--error);
757
+ }
758
+
759
+ @media (max-width: 1100px) {
760
+ .detail-panels {
761
+ grid-template-columns: 1fr;
762
+ }
763
+ }
764
+
765
+ @media (max-width: 900px) {
766
+ .app-shell {
767
+ grid-template-columns: 1fr;
768
+ }
769
+
770
+ .sidebar {
771
+ display: none;
772
+ }
773
+ }