jev-devtools 0.2.0 → 0.3.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/README.md +47 -3
- package/lib/flow/index.d.ts +82 -0
- package/lib/flow/index.js +588 -0
- package/lib/server/flows.d.ts +25 -0
- package/lib/server/flows.js +115 -0
- package/lib/server/index.d.ts +8 -0
- package/lib/server/index.js +85 -1
- package/lib/server/recorder.d.ts +4 -1
- package/lib/server/recorder.js +12 -1
- package/lib/src/ChoiceProbabilities.js +1 -1
- package/lib/src/ConnectedInspector.js +13 -4
- package/lib/src/DiagramContent.d.ts +6 -0
- package/lib/src/DiagramContent.js +32 -0
- package/lib/src/FlowOverview.d.ts +7 -0
- package/lib/src/FlowOverview.js +228 -0
- package/lib/src/JevDevtools.d.ts +6 -1
- package/lib/src/JevDevtools.js +18 -4
- package/lib/src/TraceDiagram.d.ts +4 -1
- package/lib/src/TraceDiagram.js +30 -12
- package/lib/src/condition-inputs.d.ts +9 -0
- package/lib/src/condition-inputs.js +100 -0
- package/lib/src/flow-condition.d.ts +4 -0
- package/lib/src/flow-condition.js +47 -0
- package/lib/src/flow-model.d.ts +7 -2
- package/lib/src/flow-model.js +2 -11
- package/lib/src/flow-protocol.d.ts +68 -0
- package/lib/src/flow-protocol.js +1 -0
- package/lib/src/flow-stream.d.ts +8 -0
- package/lib/src/flow-stream.js +80 -0
- package/lib/src/inspector-styles.js +1 -1
- package/lib/src/inspector.css +501 -8
- package/lib/src/protocol.d.ts +5 -0
- package/lib/src/useDiagramViewport.d.ts +4 -0
- package/lib/src/useDiagramViewport.js +20 -3
- package/package.json +6 -2
- package/skills/setup-jev-devtools/SKILL.md +6 -2
- package/skills/setup-jev-devtools/references/flows.md +150 -0
- package/skills/setup-jev-devtools/references/nextjs.md +1 -1
- package/skills/setup-jev-devtools/references/verify.md +1 -1
package/lib/src/inspector.css
CHANGED
|
@@ -831,7 +831,11 @@
|
|
|
831
831
|
min-height: 100px;
|
|
832
832
|
overflow: hidden;
|
|
833
833
|
background-color: #0d0a0f;
|
|
834
|
-
background-image: radial-gradient(
|
|
834
|
+
background-image: radial-gradient(
|
|
835
|
+
rgb(70 52 73 / var(--diagram-grid-opacity, 1))
|
|
836
|
+
calc(0.8px * var(--diagram-grid-weight, 1)),
|
|
837
|
+
transparent calc(0.8px * var(--diagram-grid-weight, 1))
|
|
838
|
+
);
|
|
835
839
|
background-size: 20px 20px;
|
|
836
840
|
border-block: 1px solid #302634;
|
|
837
841
|
cursor: grab;
|
|
@@ -889,7 +893,7 @@
|
|
|
889
893
|
position: absolute;
|
|
890
894
|
border: 1.3px solid #f5f3f6;
|
|
891
895
|
border-radius: 14px;
|
|
892
|
-
padding:
|
|
896
|
+
padding: 16px;
|
|
893
897
|
background: #0d0a0f;
|
|
894
898
|
overflow: hidden;
|
|
895
899
|
}
|
|
@@ -900,19 +904,20 @@
|
|
|
900
904
|
500 10px ui-monospace,
|
|
901
905
|
monospace;
|
|
902
906
|
letter-spacing: 1px;
|
|
903
|
-
margin: 0 0
|
|
907
|
+
margin: 0 0 7px;
|
|
904
908
|
}
|
|
905
909
|
.jev-devtools .lab-card h3 {
|
|
906
|
-
font-size:
|
|
907
|
-
font-weight:
|
|
908
|
-
line-height: 1.
|
|
909
|
-
|
|
910
|
+
font-size: 16px;
|
|
911
|
+
font-weight: 600;
|
|
912
|
+
line-height: 1.3;
|
|
913
|
+
letter-spacing: -0.2px;
|
|
914
|
+
margin: 0 0 10px;
|
|
910
915
|
overflow: hidden;
|
|
911
916
|
white-space: nowrap;
|
|
912
917
|
text-overflow: ellipsis;
|
|
913
918
|
}
|
|
914
919
|
.jev-devtools .lab-card p {
|
|
915
|
-
font-size:
|
|
920
|
+
font-size: 13px;
|
|
916
921
|
line-height: 1.4;
|
|
917
922
|
margin: 10px 0;
|
|
918
923
|
}
|
|
@@ -1143,6 +1148,7 @@
|
|
|
1143
1148
|
}
|
|
1144
1149
|
.jev-devtools .lab-choice-table-scroll {
|
|
1145
1150
|
overflow: auto;
|
|
1151
|
+
overscroll-behavior: contain;
|
|
1146
1152
|
min-height: 0;
|
|
1147
1153
|
flex: 1;
|
|
1148
1154
|
}
|
|
@@ -1264,3 +1270,490 @@
|
|
|
1264
1270
|
animation: none;
|
|
1265
1271
|
}
|
|
1266
1272
|
}
|
|
1273
|
+
|
|
1274
|
+
/* Connected requests share one camera and one opt-in full request detail. */
|
|
1275
|
+
.whole-flow {
|
|
1276
|
+
min-width: 0;
|
|
1277
|
+
overflow: auto;
|
|
1278
|
+
}
|
|
1279
|
+
.flow-overview-viewport {
|
|
1280
|
+
position: relative;
|
|
1281
|
+
min-height: 240px;
|
|
1282
|
+
flex: 1 0 260px;
|
|
1283
|
+
overflow: hidden;
|
|
1284
|
+
touch-action: none;
|
|
1285
|
+
cursor: grab;
|
|
1286
|
+
background-image: radial-gradient(
|
|
1287
|
+
rgb(83 67 87 / var(--diagram-grid-opacity, 1))
|
|
1288
|
+
calc(1px * var(--diagram-grid-weight, 1)),
|
|
1289
|
+
transparent calc(1px * var(--diagram-grid-weight, 1))
|
|
1290
|
+
);
|
|
1291
|
+
background-size: 20px 20px;
|
|
1292
|
+
}
|
|
1293
|
+
.flow-overview-viewport[data-panning] {
|
|
1294
|
+
cursor: grabbing;
|
|
1295
|
+
}
|
|
1296
|
+
.flow-overview-canvas {
|
|
1297
|
+
position: absolute;
|
|
1298
|
+
transform-origin: 0 0;
|
|
1299
|
+
}
|
|
1300
|
+
.flow-connections {
|
|
1301
|
+
position: absolute;
|
|
1302
|
+
inset: 0;
|
|
1303
|
+
color: #c0b8c4;
|
|
1304
|
+
pointer-events: none;
|
|
1305
|
+
}
|
|
1306
|
+
.flow-step {
|
|
1307
|
+
position: absolute;
|
|
1308
|
+
width: 220px;
|
|
1309
|
+
min-height: 98px;
|
|
1310
|
+
display: flex;
|
|
1311
|
+
flex-direction: column;
|
|
1312
|
+
gap: 8px;
|
|
1313
|
+
text-align: left;
|
|
1314
|
+
padding: 14px;
|
|
1315
|
+
border: 1px solid #736476;
|
|
1316
|
+
border-radius: 12px;
|
|
1317
|
+
background: #151017;
|
|
1318
|
+
color: inherit;
|
|
1319
|
+
}
|
|
1320
|
+
.flow-step strong {
|
|
1321
|
+
overflow: hidden;
|
|
1322
|
+
text-overflow: ellipsis;
|
|
1323
|
+
white-space: nowrap;
|
|
1324
|
+
width: 100%;
|
|
1325
|
+
}
|
|
1326
|
+
.flow-step-description {
|
|
1327
|
+
overflow-wrap: anywhere;
|
|
1328
|
+
font-size: 12px;
|
|
1329
|
+
}
|
|
1330
|
+
.flow-step.flow-request {
|
|
1331
|
+
display: block;
|
|
1332
|
+
padding: 0;
|
|
1333
|
+
background: #0d0a0f;
|
|
1334
|
+
/* Skip offscreen paint/layout while preserving each question/expansion state. */
|
|
1335
|
+
content-visibility: auto;
|
|
1336
|
+
contain-intrinsic-size: auto 640px;
|
|
1337
|
+
}
|
|
1338
|
+
.flow-request-heading {
|
|
1339
|
+
width: 100%;
|
|
1340
|
+
height: 64px;
|
|
1341
|
+
display: flex;
|
|
1342
|
+
align-items: center;
|
|
1343
|
+
justify-content: space-between;
|
|
1344
|
+
text-align: left;
|
|
1345
|
+
padding: 12px 20px;
|
|
1346
|
+
border: 0;
|
|
1347
|
+
border-bottom: 1px solid #342a38;
|
|
1348
|
+
border-radius: 12px 12px 0 0;
|
|
1349
|
+
background: transparent;
|
|
1350
|
+
color: inherit;
|
|
1351
|
+
}
|
|
1352
|
+
.flow-request-heading .eyebrow {
|
|
1353
|
+
display: block;
|
|
1354
|
+
margin-bottom: 4px;
|
|
1355
|
+
}
|
|
1356
|
+
.jev-devtools .lab-flow-embedded {
|
|
1357
|
+
width: 1120px;
|
|
1358
|
+
display: block;
|
|
1359
|
+
}
|
|
1360
|
+
.jev-devtools .lab-flow-surface {
|
|
1361
|
+
position: relative;
|
|
1362
|
+
width: 1120px;
|
|
1363
|
+
}
|
|
1364
|
+
.jev-devtools .lab-flow-surface[hidden] {
|
|
1365
|
+
display: none;
|
|
1366
|
+
}
|
|
1367
|
+
.jev-devtools .lab-flow-embedded .lab-flow-canvas {
|
|
1368
|
+
will-change: auto;
|
|
1369
|
+
}
|
|
1370
|
+
.jev-devtools .lab-flow-embedded .lab-choice-browser {
|
|
1371
|
+
height: 520px;
|
|
1372
|
+
}
|
|
1373
|
+
.flow-step.selected {
|
|
1374
|
+
outline: 2px solid #e551ba;
|
|
1375
|
+
outline-offset: 3px;
|
|
1376
|
+
}
|
|
1377
|
+
.flow-step[data-status="completed"] {
|
|
1378
|
+
border-color: #e551ba;
|
|
1379
|
+
}
|
|
1380
|
+
.flow-step[data-status="running"] {
|
|
1381
|
+
border-color: #e551ba;
|
|
1382
|
+
background: #2b1728;
|
|
1383
|
+
}
|
|
1384
|
+
.flow-step[data-status="untaken"],
|
|
1385
|
+
.flow-step[data-status="blocked"] {
|
|
1386
|
+
color: #948797;
|
|
1387
|
+
border-color: #403746;
|
|
1388
|
+
background: #151017;
|
|
1389
|
+
}
|
|
1390
|
+
.flow-step[data-status="error"] {
|
|
1391
|
+
border-color: #f17c78;
|
|
1392
|
+
}
|
|
1393
|
+
.flow-step[data-status="cancelled"] {
|
|
1394
|
+
border-style: dashed;
|
|
1395
|
+
}
|
|
1396
|
+
.flow-selection {
|
|
1397
|
+
padding: 12px 20px;
|
|
1398
|
+
border-top: 1px solid #342a38;
|
|
1399
|
+
}
|
|
1400
|
+
.flow-selection p {
|
|
1401
|
+
margin: 6px 0;
|
|
1402
|
+
overflow-wrap: anywhere;
|
|
1403
|
+
}
|
|
1404
|
+
.flow-request-detail {
|
|
1405
|
+
min-height: 450px;
|
|
1406
|
+
border-top: 1px solid #534357;
|
|
1407
|
+
}
|
|
1408
|
+
.flow-request-detail > .request-detail {
|
|
1409
|
+
min-height: 450px;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
.flow-card-heading,
|
|
1413
|
+
.flow-card-footer,
|
|
1414
|
+
.flow-join-summary,
|
|
1415
|
+
.flow-lane {
|
|
1416
|
+
display: flex;
|
|
1417
|
+
align-items: center;
|
|
1418
|
+
justify-content: space-between;
|
|
1419
|
+
gap: 8px;
|
|
1420
|
+
width: 100%;
|
|
1421
|
+
}
|
|
1422
|
+
.flow-card-heading {
|
|
1423
|
+
justify-content: flex-start;
|
|
1424
|
+
}
|
|
1425
|
+
.flow-kind-icon {
|
|
1426
|
+
width: 26px;
|
|
1427
|
+
height: 26px;
|
|
1428
|
+
color: #e551ba;
|
|
1429
|
+
flex-shrink: 0;
|
|
1430
|
+
}
|
|
1431
|
+
.flow-kind-icon svg {
|
|
1432
|
+
width: 100%;
|
|
1433
|
+
height: 100%;
|
|
1434
|
+
}
|
|
1435
|
+
.flow-card-heading .eyebrow {
|
|
1436
|
+
font-size: 10px;
|
|
1437
|
+
}
|
|
1438
|
+
.flow-status {
|
|
1439
|
+
margin-left: auto;
|
|
1440
|
+
font-size: 10px;
|
|
1441
|
+
border-radius: 20px;
|
|
1442
|
+
padding: 4px 8px;
|
|
1443
|
+
background: #342031;
|
|
1444
|
+
color: #f0b7e0;
|
|
1445
|
+
}
|
|
1446
|
+
.flow-step[data-status="untaken"] .flow-status {
|
|
1447
|
+
background: #241e28;
|
|
1448
|
+
color: #948797;
|
|
1449
|
+
}
|
|
1450
|
+
.flow-step[data-status="untaken"] .flow-kind-icon {
|
|
1451
|
+
color: #948797;
|
|
1452
|
+
}
|
|
1453
|
+
.flow-step > strong {
|
|
1454
|
+
white-space: normal;
|
|
1455
|
+
font-size: 18px;
|
|
1456
|
+
line-height: 1.25;
|
|
1457
|
+
display: -webkit-box;
|
|
1458
|
+
-webkit-line-clamp: 2;
|
|
1459
|
+
-webkit-box-orient: vertical;
|
|
1460
|
+
overflow-wrap: anywhere;
|
|
1461
|
+
}
|
|
1462
|
+
.flow-step-description {
|
|
1463
|
+
line-height: 1.5;
|
|
1464
|
+
color: #b9aebf;
|
|
1465
|
+
display: -webkit-box;
|
|
1466
|
+
-webkit-line-clamp: 3;
|
|
1467
|
+
-webkit-box-orient: vertical;
|
|
1468
|
+
overflow: hidden;
|
|
1469
|
+
}
|
|
1470
|
+
.flow-card-footer {
|
|
1471
|
+
margin-top: auto;
|
|
1472
|
+
padding-top: 10px;
|
|
1473
|
+
border-top: 1px solid #342a38;
|
|
1474
|
+
font-size: 10px;
|
|
1475
|
+
color: #a092a7;
|
|
1476
|
+
}
|
|
1477
|
+
.flow-card-footer code {
|
|
1478
|
+
max-width: 45%;
|
|
1479
|
+
overflow: hidden;
|
|
1480
|
+
text-overflow: ellipsis;
|
|
1481
|
+
white-space: nowrap;
|
|
1482
|
+
}
|
|
1483
|
+
.flow-card-footer small {
|
|
1484
|
+
text-align: right;
|
|
1485
|
+
}
|
|
1486
|
+
.flow-join-summary {
|
|
1487
|
+
margin-top: 4px;
|
|
1488
|
+
font-size: 11px;
|
|
1489
|
+
color: #c9b9cd;
|
|
1490
|
+
}
|
|
1491
|
+
.flow-join-summary > span {
|
|
1492
|
+
color: #ef9ed9;
|
|
1493
|
+
font-variant-numeric: tabular-nums;
|
|
1494
|
+
}
|
|
1495
|
+
.flow-lanes {
|
|
1496
|
+
display: flex;
|
|
1497
|
+
flex-direction: column;
|
|
1498
|
+
gap: 4px;
|
|
1499
|
+
width: 100%;
|
|
1500
|
+
}
|
|
1501
|
+
.flow-lane {
|
|
1502
|
+
border-radius: 5px;
|
|
1503
|
+
background: #211923;
|
|
1504
|
+
padding: 6px 8px;
|
|
1505
|
+
font-size: 11px;
|
|
1506
|
+
min-height: 28px;
|
|
1507
|
+
}
|
|
1508
|
+
.flow-lane > span {
|
|
1509
|
+
overflow: hidden;
|
|
1510
|
+
text-overflow: ellipsis;
|
|
1511
|
+
white-space: nowrap;
|
|
1512
|
+
}
|
|
1513
|
+
.flow-lane > span > span {
|
|
1514
|
+
color: #ef9ed9;
|
|
1515
|
+
margin-right: 4px;
|
|
1516
|
+
}
|
|
1517
|
+
.flow-lane small {
|
|
1518
|
+
color: #b9aebf;
|
|
1519
|
+
}
|
|
1520
|
+
.flow-lane-details {
|
|
1521
|
+
padding-left: 18px;
|
|
1522
|
+
font-size: 12px;
|
|
1523
|
+
}
|
|
1524
|
+
.flow-request-heading > span:first-child {
|
|
1525
|
+
min-width: 0;
|
|
1526
|
+
max-width: 80%;
|
|
1527
|
+
}
|
|
1528
|
+
.flow-request-description {
|
|
1529
|
+
display: -webkit-box;
|
|
1530
|
+
-webkit-line-clamp: 2;
|
|
1531
|
+
-webkit-box-orient: vertical;
|
|
1532
|
+
overflow: hidden;
|
|
1533
|
+
font-size: 12px;
|
|
1534
|
+
line-height: 1.5;
|
|
1535
|
+
color: #b9aebf;
|
|
1536
|
+
margin-top: 5px;
|
|
1537
|
+
overflow-wrap: anywhere;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
/* Structured context stays within the card; its gestures never move the camera. */
|
|
1541
|
+
.jev-devtools .lab-content-card {
|
|
1542
|
+
display: flex;
|
|
1543
|
+
flex-direction: column;
|
|
1544
|
+
padding: 14px;
|
|
1545
|
+
}
|
|
1546
|
+
.jev-devtools .lab-content-card h3 {
|
|
1547
|
+
font-size: 14px;
|
|
1548
|
+
margin-bottom: 8px;
|
|
1549
|
+
flex-shrink: 0;
|
|
1550
|
+
}
|
|
1551
|
+
.jev-devtools .lab-content-card .lab-eyebrow {
|
|
1552
|
+
font-size: 9px;
|
|
1553
|
+
margin-bottom: 5px;
|
|
1554
|
+
flex-shrink: 0;
|
|
1555
|
+
}
|
|
1556
|
+
.jev-devtools .diagram-content {
|
|
1557
|
+
min-height: 0;
|
|
1558
|
+
flex: 1;
|
|
1559
|
+
overflow: auto;
|
|
1560
|
+
overscroll-behavior: contain;
|
|
1561
|
+
touch-action: pan-y;
|
|
1562
|
+
scrollbar-width: thin;
|
|
1563
|
+
scrollbar-color: #514256 transparent;
|
|
1564
|
+
padding-right: 4px;
|
|
1565
|
+
font-size: 12px;
|
|
1566
|
+
line-height: 1.5;
|
|
1567
|
+
color: #d5cdd9;
|
|
1568
|
+
cursor: auto;
|
|
1569
|
+
user-select: text;
|
|
1570
|
+
}
|
|
1571
|
+
.jev-devtools .diagram-content:focus-visible {
|
|
1572
|
+
outline: 1px solid #e551ba;
|
|
1573
|
+
outline-offset: -1px;
|
|
1574
|
+
border-radius: 3px;
|
|
1575
|
+
}
|
|
1576
|
+
.jev-devtools .diagram-property {
|
|
1577
|
+
display: flex;
|
|
1578
|
+
justify-content: space-between;
|
|
1579
|
+
align-items: baseline;
|
|
1580
|
+
gap: 8px;
|
|
1581
|
+
padding: 5px 0;
|
|
1582
|
+
border-bottom: 1px solid #261e2a;
|
|
1583
|
+
}
|
|
1584
|
+
.jev-devtools .diagram-property-text {
|
|
1585
|
+
display: block;
|
|
1586
|
+
}
|
|
1587
|
+
.jev-devtools .diagram-property-key {
|
|
1588
|
+
font:
|
|
1589
|
+
10px/1.5 ui-monospace,
|
|
1590
|
+
monospace;
|
|
1591
|
+
color: #c8a8c8;
|
|
1592
|
+
overflow-wrap: anywhere;
|
|
1593
|
+
min-width: 0;
|
|
1594
|
+
}
|
|
1595
|
+
.jev-devtools .diagram-property-text > .diagram-property-key {
|
|
1596
|
+
display: block;
|
|
1597
|
+
margin-bottom: 2px;
|
|
1598
|
+
}
|
|
1599
|
+
.jev-devtools .diagram-text-value {
|
|
1600
|
+
display: block;
|
|
1601
|
+
white-space: pre-wrap;
|
|
1602
|
+
overflow-wrap: anywhere;
|
|
1603
|
+
}
|
|
1604
|
+
.jev-devtools .diagram-text-preview {
|
|
1605
|
+
display: -webkit-box;
|
|
1606
|
+
-webkit-line-clamp: 3;
|
|
1607
|
+
-webkit-box-orient: vertical;
|
|
1608
|
+
overflow: hidden;
|
|
1609
|
+
}
|
|
1610
|
+
.jev-devtools .diagram-value-number {
|
|
1611
|
+
color: #a6d6ca;
|
|
1612
|
+
font:
|
|
1613
|
+
11px/1.5 ui-monospace,
|
|
1614
|
+
monospace;
|
|
1615
|
+
font-variant-numeric: tabular-nums;
|
|
1616
|
+
overflow-wrap: anywhere;
|
|
1617
|
+
}
|
|
1618
|
+
.jev-devtools .diagram-value-boolean {
|
|
1619
|
+
color: #c4b1ed;
|
|
1620
|
+
font:
|
|
1621
|
+
11px/1.5 ui-monospace,
|
|
1622
|
+
monospace;
|
|
1623
|
+
}
|
|
1624
|
+
.jev-devtools .diagram-value-empty {
|
|
1625
|
+
color: #9c8ca4;
|
|
1626
|
+
font:
|
|
1627
|
+
10px/1.5 ui-monospace,
|
|
1628
|
+
monospace;
|
|
1629
|
+
}
|
|
1630
|
+
.jev-devtools .diagram-property-disclosure {
|
|
1631
|
+
width: 100%;
|
|
1632
|
+
display: flex;
|
|
1633
|
+
align-items: baseline;
|
|
1634
|
+
gap: 5px;
|
|
1635
|
+
padding: 6px 0;
|
|
1636
|
+
border: 0;
|
|
1637
|
+
border-bottom: 1px solid #261e2a;
|
|
1638
|
+
border-radius: 0;
|
|
1639
|
+
background: transparent;
|
|
1640
|
+
text-align: left;
|
|
1641
|
+
color: inherit;
|
|
1642
|
+
}
|
|
1643
|
+
.jev-devtools .diagram-property-disclosure:hover {
|
|
1644
|
+
background: #211723;
|
|
1645
|
+
}
|
|
1646
|
+
.jev-devtools .diagram-property-caret {
|
|
1647
|
+
color: #ab8aab;
|
|
1648
|
+
flex-shrink: 0;
|
|
1649
|
+
}
|
|
1650
|
+
.jev-devtools .diagram-property-type {
|
|
1651
|
+
color: #9c8ca4;
|
|
1652
|
+
font:
|
|
1653
|
+
10px/1.5 ui-monospace,
|
|
1654
|
+
monospace;
|
|
1655
|
+
margin-left: auto;
|
|
1656
|
+
flex-shrink: 0;
|
|
1657
|
+
}
|
|
1658
|
+
.jev-devtools .diagram-property-children {
|
|
1659
|
+
margin-left: 4px;
|
|
1660
|
+
padding-left: 9px;
|
|
1661
|
+
border-left: 1px solid #49324b;
|
|
1662
|
+
}
|
|
1663
|
+
.jev-devtools .diagram-content-toggle {
|
|
1664
|
+
display: block;
|
|
1665
|
+
padding: 3px 0;
|
|
1666
|
+
border: 0;
|
|
1667
|
+
border-radius: 0;
|
|
1668
|
+
background: transparent;
|
|
1669
|
+
color: #e9a4d7;
|
|
1670
|
+
font-size: 10px;
|
|
1671
|
+
text-align: left;
|
|
1672
|
+
}
|
|
1673
|
+
.jev-devtools .diagram-content-toggle:hover {
|
|
1674
|
+
color: #ffd9f3;
|
|
1675
|
+
text-decoration: underline;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
/* Noul is a probability of true; its two outputs carry p and 1-p.
|
|
1679
|
+
Keep the fill opaque, with readable text even at zero probability. */
|
|
1680
|
+
.jev-devtools .lab-noul-output {
|
|
1681
|
+
border-color: rgb(
|
|
1682
|
+
245 243 246 / calc(0.35 + 0.65 * var(--lab-noul-probability, 1))
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
.jev-devtools .lab-noul-output > h3,
|
|
1686
|
+
.jev-devtools .lab-noul-output > p {
|
|
1687
|
+
opacity: calc(0.65 + 0.35 * var(--lab-noul-probability, 1));
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.flow-condition-rule {
|
|
1691
|
+
display: block;
|
|
1692
|
+
padding: 10px 12px;
|
|
1693
|
+
border: 1px solid #49324b;
|
|
1694
|
+
border-radius: 6px;
|
|
1695
|
+
background: #211723;
|
|
1696
|
+
width: 100%;
|
|
1697
|
+
}
|
|
1698
|
+
.flow-condition-label {
|
|
1699
|
+
display: block;
|
|
1700
|
+
font-size: 10px;
|
|
1701
|
+
color: #ba9dbe;
|
|
1702
|
+
margin-bottom: 5px;
|
|
1703
|
+
}
|
|
1704
|
+
.flow-condition-rule code {
|
|
1705
|
+
display: -webkit-box;
|
|
1706
|
+
-webkit-line-clamp: 3;
|
|
1707
|
+
-webkit-box-orient: vertical;
|
|
1708
|
+
overflow: hidden;
|
|
1709
|
+
overflow-wrap: anywhere;
|
|
1710
|
+
font:
|
|
1711
|
+
12px/1.6 ui-monospace,
|
|
1712
|
+
monospace;
|
|
1713
|
+
color: #f2d7eb;
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
.flow-condition-incoming {
|
|
1717
|
+
display: block;
|
|
1718
|
+
padding-bottom: 10px;
|
|
1719
|
+
margin-bottom: 10px;
|
|
1720
|
+
border-bottom: 1px solid #49324b;
|
|
1721
|
+
}
|
|
1722
|
+
.flow-condition-input {
|
|
1723
|
+
display: flex;
|
|
1724
|
+
justify-content: space-between;
|
|
1725
|
+
align-items: baseline;
|
|
1726
|
+
gap: 12px;
|
|
1727
|
+
font-size: 12px;
|
|
1728
|
+
padding: 3px 0;
|
|
1729
|
+
}
|
|
1730
|
+
.flow-condition-input > span {
|
|
1731
|
+
overflow: hidden;
|
|
1732
|
+
text-overflow: ellipsis;
|
|
1733
|
+
white-space: nowrap;
|
|
1734
|
+
}
|
|
1735
|
+
.flow-condition-input > b {
|
|
1736
|
+
font-size: 17px;
|
|
1737
|
+
font-weight: 600;
|
|
1738
|
+
color: #f2d7eb;
|
|
1739
|
+
overflow: hidden;
|
|
1740
|
+
text-overflow: ellipsis;
|
|
1741
|
+
white-space: nowrap;
|
|
1742
|
+
max-width: 65%;
|
|
1743
|
+
}
|
|
1744
|
+
.flow-input-details {
|
|
1745
|
+
font-size: 12px;
|
|
1746
|
+
}
|
|
1747
|
+
.flow-input-details > div {
|
|
1748
|
+
display: flex;
|
|
1749
|
+
gap: 16px;
|
|
1750
|
+
margin: 6px 0;
|
|
1751
|
+
}
|
|
1752
|
+
.flow-input-details code {
|
|
1753
|
+
color: #a092a7;
|
|
1754
|
+
margin-left: 8px;
|
|
1755
|
+
}
|
|
1756
|
+
.flow-input-details dd {
|
|
1757
|
+
margin: 0;
|
|
1758
|
+
overflow-wrap: anywhere;
|
|
1759
|
+
}
|
package/lib/src/protocol.d.ts
CHANGED
|
@@ -7,4 +7,8 @@ export declare function useDiagramViewport(width: number, height: number, scene:
|
|
|
7
7
|
zoomBy: (factor: number, point?: Point) => void;
|
|
8
8
|
fit: () => void;
|
|
9
9
|
preserveCamera: () => void;
|
|
10
|
+
focusArea: (area: Point & {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}) => void;
|
|
10
14
|
};
|
|
@@ -23,7 +23,12 @@ export function useDiagramViewport(width, height, scene) {
|
|
|
23
23
|
canvas.current.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
|
|
24
24
|
if (viewport.current) {
|
|
25
25
|
viewport.current.style.backgroundPosition = `${x}px ${y}px`;
|
|
26
|
-
|
|
26
|
+
// Thin out the decorative grid at overview zooms instead of packing
|
|
27
|
+
// more dots behind an increasingly small diagram.
|
|
28
|
+
const grid = 24 * Math.max(scale, 1 / Math.sqrt(scale));
|
|
29
|
+
viewport.current.style.backgroundSize = `${grid}px ${grid}px`;
|
|
30
|
+
viewport.current.style.setProperty("--diagram-grid-opacity", String(0.45 * Math.min(1, Math.sqrt(scale))));
|
|
31
|
+
viewport.current.style.setProperty("--diagram-grid-weight", String(Math.max(0.5, Math.min(0.75, Math.sqrt(scale)))));
|
|
27
32
|
}
|
|
28
33
|
setZoom(Math.round(scale * 100));
|
|
29
34
|
});
|
|
@@ -38,6 +43,16 @@ export function useDiagramViewport(width, height, scene) {
|
|
|
38
43
|
const preserveCamera = useCallback(() => {
|
|
39
44
|
fitted.current = false;
|
|
40
45
|
}, []);
|
|
46
|
+
const focusArea = useCallback((area) => {
|
|
47
|
+
fitted.current = false;
|
|
48
|
+
const focused = fitCamera(size.current, area);
|
|
49
|
+
camera.current = {
|
|
50
|
+
...focused,
|
|
51
|
+
x: focused.x - area.x * focused.scale,
|
|
52
|
+
y: focused.y - area.y * focused.scale,
|
|
53
|
+
};
|
|
54
|
+
paint();
|
|
55
|
+
}, [paint]);
|
|
41
56
|
useEffect(() => {
|
|
42
57
|
if (fitted.current)
|
|
43
58
|
fit();
|
|
@@ -76,7 +91,7 @@ export function useDiagramViewport(width, height, scene) {
|
|
|
76
91
|
const down = (event) => {
|
|
77
92
|
if (event.button !== 0 ||
|
|
78
93
|
pointers.size >= 2 ||
|
|
79
|
-
event.target.closest("button, input, select, textarea, a, summary"))
|
|
94
|
+
event.target.closest("button, input, select, textarea, a, summary, [data-diagram-scroll]"))
|
|
80
95
|
return;
|
|
81
96
|
event.preventDefault();
|
|
82
97
|
el.focus({ preventScroll: true });
|
|
@@ -113,6 +128,8 @@ export function useDiagramViewport(width, height, scene) {
|
|
|
113
128
|
delete el.dataset.panning;
|
|
114
129
|
};
|
|
115
130
|
const wheel = (event) => {
|
|
131
|
+
if (event.target.closest("[data-diagram-scroll]"))
|
|
132
|
+
return;
|
|
116
133
|
event.preventDefault();
|
|
117
134
|
const units = event.deltaMode === 1
|
|
118
135
|
? 16
|
|
@@ -179,5 +196,5 @@ export function useDiagramViewport(width, height, scene) {
|
|
|
179
196
|
frame.current = null;
|
|
180
197
|
};
|
|
181
198
|
}, [fit, zoomBy, paint, scene]);
|
|
182
|
-
return { viewport, canvas, zoom, zoomBy, fit, preserveCamera };
|
|
199
|
+
return { viewport, canvas, zoom, zoomBy, fit, preserveCamera, focusArea };
|
|
183
200
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jev-devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.12"
|
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
"types": "./lib/server/index.d.ts",
|
|
20
20
|
"import": "./lib/server/index.js"
|
|
21
21
|
},
|
|
22
|
-
"./styles.css": "./lib/src/inspector.css"
|
|
22
|
+
"./styles.css": "./lib/src/inspector.css",
|
|
23
|
+
"./flow": {
|
|
24
|
+
"types": "./lib/flow/index.d.ts",
|
|
25
|
+
"import": "./lib/flow/index.js"
|
|
26
|
+
}
|
|
23
27
|
},
|
|
24
28
|
"files": [
|
|
25
29
|
"lib",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-jev-devtools
|
|
3
|
-
description: Install and verify Jev DevTools in an existing React application with a Node backend or Next.js App Router. Use when asked to add the Jev request inspector, wire capture, or troubleshoot its setup.
|
|
3
|
+
description: Install and verify Jev DevTools in an existing React application with a Node backend or Next.js App Router. Use when asked to add the Jev request inspector, wire capture, build connected Jev flows with branches and parallel checks, or troubleshoot its setup.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Set up Jev DevTools
|
|
@@ -17,9 +17,13 @@ Inspect the app's package manager/lockfile, React and Node versions, root compon
|
|
|
17
17
|
|
|
18
18
|
Install `jev-devtools` using the app's existing package manager (npm: `npm install jev-devtools`; pnpm: `pnpm add jev-devtools`; Yarn: `yarn add jev-devtools`). Install in the workspace(s) that actually import it. It is a regular dependency when application modules import it, even though capture/display are development-only. React 18/19 and Node 22.12+ are required. Do not replace the app's framework or upgrade unrelated dependencies to force compatibility.
|
|
19
19
|
|
|
20
|
+
## Optional connected flow API (0.3.0+)
|
|
21
|
+
|
|
22
|
+
When asked to build or inspect connected calls, read [references/flows.md](references/flows.md) after the framework recipe. It includes an executable parallel-checks/branch example, step titles/descriptions, scope and execution rules, sample verification, and privacy limits. Preserve existing application policies; do not convert unrelated calls just to install the drawer. Flow execution is server-only and continues even with the inspector disabled.
|
|
23
|
+
|
|
20
24
|
## Integration invariants
|
|
21
25
|
|
|
22
|
-
- Use only public imports: `jev-devtools`, `jev-devtools/styles.css`, and server-only `jev-devtools/server`. No provider, TanStack, Tailwind, or shadcn
|
|
26
|
+
- Use only public imports: `jev-devtools`, `jev-devtools/styles.css`, and server-only `jev-devtools/server` and `jev-devtools/flow`. No provider, TanStack DevTools shell, Tailwind, or shadcn setup is needed; TanStack Virtual is an internal dependency.
|
|
23
27
|
- Mount `<JevDevtools />` once with an explicit development flag and import the CSS. Server capture must also be explicitly enabled for development; both default to off.
|
|
24
28
|
- Create a shared adapter; the inspector routes and application client must use it in the same Node realm/process. Replace existing `new TypeSafeClient(options)` construction with `inspector.createClient(options)` while preserving keys, transport options, retries, and call semantics. Keep existing `systemOne(...)` inputs and application behavior.
|
|
25
29
|
- Browser and server `endpoint` paths must agree (default `/api/jev-devtools`). Route the base path and its subpaths. The server `origin` must exactly match the browser scheme, hostname, and port. A browser endpoint is a same-origin path, not an absolute backend URL.
|