swagger-parser-mcp-server 2.0.4 → 2.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.
Files changed (131) hide show
  1. package/README.md +131 -100
  2. package/dist/application/snapshot/createSnapshotRuntime.d.ts +2 -0
  3. package/dist/application/snapshot/createSnapshotRuntime.d.ts.map +1 -0
  4. package/dist/application/snapshot/createSnapshotRuntime.js +2 -0
  5. package/dist/application/snapshot/createSnapshotRuntime.js.map +1 -0
  6. package/dist/application/snapshot/snapshotCaptureService.d.ts +90 -0
  7. package/dist/application/snapshot/snapshotCaptureService.d.ts.map +1 -0
  8. package/dist/application/snapshot/snapshotCaptureService.js +394 -0
  9. package/dist/application/snapshot/snapshotCaptureService.js.map +1 -0
  10. package/dist/application/snapshot/snapshotRepository.d.ts +77 -0
  11. package/dist/application/snapshot/snapshotRepository.d.ts.map +1 -0
  12. package/dist/application/snapshot/snapshotRepository.js +2 -0
  13. package/dist/application/snapshot/snapshotRepository.js.map +1 -0
  14. package/dist/domain/canonical/canonicalSnapshot.d.ts +61 -0
  15. package/dist/domain/canonical/canonicalSnapshot.d.ts.map +1 -0
  16. package/dist/domain/canonical/canonicalSnapshot.js +300 -0
  17. package/dist/domain/canonical/canonicalSnapshot.js.map +1 -0
  18. package/dist/domain/contracts/runtimeEnvironmentContract.d.ts +21 -0
  19. package/dist/domain/contracts/runtimeEnvironmentContract.d.ts.map +1 -0
  20. package/dist/domain/contracts/runtimeEnvironmentContract.js +50 -0
  21. package/dist/domain/contracts/runtimeEnvironmentContract.js.map +1 -0
  22. package/dist/domain/contracts/snapshotDiffContract.d.ts +270 -0
  23. package/dist/domain/contracts/snapshotDiffContract.d.ts.map +1 -0
  24. package/dist/domain/contracts/snapshotDiffContract.js +99 -0
  25. package/dist/domain/contracts/snapshotDiffContract.js.map +1 -0
  26. package/dist/domain/diff/endpointDiffClassifier.d.ts +78 -0
  27. package/dist/domain/diff/endpointDiffClassifier.d.ts.map +1 -0
  28. package/dist/domain/diff/endpointDiffClassifier.js +317 -0
  29. package/dist/domain/diff/endpointDiffClassifier.js.map +1 -0
  30. package/dist/http.d.ts +3 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/http.js +52 -0
  33. package/dist/http.js.map +1 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +88 -266
  37. package/dist/index.js.map +1 -1
  38. package/dist/infrastructure/postgres/migrationRunner.d.ts +14 -0
  39. package/dist/infrastructure/postgres/migrationRunner.d.ts.map +1 -0
  40. package/dist/infrastructure/postgres/migrationRunner.js +161 -0
  41. package/dist/infrastructure/postgres/migrationRunner.js.map +1 -0
  42. package/dist/infrastructure/postgres/migrations/001_snapshot_schema.sql +29 -0
  43. package/dist/infrastructure/postgres/migrations/002_snapshot_change_history.sql +32 -0
  44. package/dist/infrastructure/postgres/postgresSnapshotRepository.d.ts +25 -0
  45. package/dist/infrastructure/postgres/postgresSnapshotRepository.d.ts.map +1 -0
  46. package/dist/infrastructure/postgres/postgresSnapshotRepository.js +323 -0
  47. package/dist/infrastructure/postgres/postgresSnapshotRepository.js.map +1 -0
  48. package/dist/infrastructure/postgres/runMigrations.d.ts +3 -0
  49. package/dist/infrastructure/postgres/runMigrations.d.ts.map +1 -0
  50. package/dist/infrastructure/postgres/runMigrations.js +33 -0
  51. package/dist/infrastructure/postgres/runMigrations.js.map +1 -0
  52. package/dist/infrastructure/runtime/createSnapshotRuntime.d.ts +17 -0
  53. package/dist/infrastructure/runtime/createSnapshotRuntime.d.ts.map +1 -0
  54. package/dist/infrastructure/runtime/createSnapshotRuntime.js +38 -0
  55. package/dist/infrastructure/runtime/createSnapshotRuntime.js.map +1 -0
  56. package/dist/schemas.d.ts +284 -3
  57. package/dist/schemas.d.ts.map +1 -1
  58. package/dist/schemas.js +110 -1
  59. package/dist/schemas.js.map +1 -1
  60. package/dist/tests/canonicalSnapshot.test.d.ts +2 -0
  61. package/dist/tests/canonicalSnapshot.test.d.ts.map +1 -0
  62. package/dist/tests/canonicalSnapshot.test.js +425 -0
  63. package/dist/tests/canonicalSnapshot.test.js.map +1 -0
  64. package/dist/tests/endpointDiffClassifier.test.d.ts +2 -0
  65. package/dist/tests/endpointDiffClassifier.test.d.ts.map +1 -0
  66. package/dist/tests/endpointDiffClassifier.test.js +633 -0
  67. package/dist/tests/endpointDiffClassifier.test.js.map +1 -0
  68. package/dist/tests/httpSnapshotTransport.test.d.ts +2 -0
  69. package/dist/tests/httpSnapshotTransport.test.d.ts.map +1 -0
  70. package/dist/tests/httpSnapshotTransport.test.js +356 -0
  71. package/dist/tests/httpSnapshotTransport.test.js.map +1 -0
  72. package/dist/tests/indexLifecycle.test.d.ts +2 -0
  73. package/dist/tests/indexLifecycle.test.d.ts.map +1 -0
  74. package/dist/tests/indexLifecycle.test.js +23 -0
  75. package/dist/tests/indexLifecycle.test.js.map +1 -0
  76. package/dist/tests/mcpSnapshotTools.test.d.ts +2 -0
  77. package/dist/tests/mcpSnapshotTools.test.d.ts.map +1 -0
  78. package/dist/tests/mcpSnapshotTools.test.js +316 -0
  79. package/dist/tests/mcpSnapshotTools.test.js.map +1 -0
  80. package/dist/tests/postgresMigrationSmoke.test.d.ts +2 -0
  81. package/dist/tests/postgresMigrationSmoke.test.d.ts.map +1 -0
  82. package/dist/tests/postgresMigrationSmoke.test.js +187 -0
  83. package/dist/tests/postgresMigrationSmoke.test.js.map +1 -0
  84. package/dist/tests/realPostgresTestSchema.d.ts +10 -0
  85. package/dist/tests/realPostgresTestSchema.d.ts.map +1 -0
  86. package/dist/tests/realPostgresTestSchema.js +73 -0
  87. package/dist/tests/realPostgresTestSchema.js.map +1 -0
  88. package/dist/tests/snapshotCapturePipeline.test.d.ts +2 -0
  89. package/dist/tests/snapshotCapturePipeline.test.d.ts.map +1 -0
  90. package/dist/tests/snapshotCapturePipeline.test.js +475 -0
  91. package/dist/tests/snapshotCapturePipeline.test.js.map +1 -0
  92. package/dist/tests/snapshotDiffContract.test.d.ts +2 -0
  93. package/dist/tests/snapshotDiffContract.test.d.ts.map +1 -0
  94. package/dist/tests/snapshotDiffContract.test.js +156 -0
  95. package/dist/tests/snapshotDiffContract.test.js.map +1 -0
  96. package/dist/tests/snapshotPersistence.real.test.d.ts +2 -0
  97. package/dist/tests/snapshotPersistence.real.test.d.ts.map +1 -0
  98. package/dist/tests/snapshotPersistence.real.test.js +310 -0
  99. package/dist/tests/snapshotPersistence.real.test.js.map +1 -0
  100. package/dist/tests/webServerRuntime.test.d.ts +2 -0
  101. package/dist/tests/webServerRuntime.test.d.ts.map +1 -0
  102. package/dist/tests/webServerRuntime.test.js +123 -0
  103. package/dist/tests/webServerRuntime.test.js.map +1 -0
  104. package/dist/transport/createSnapshotToolRuntime.d.ts +7 -0
  105. package/dist/transport/createSnapshotToolRuntime.d.ts.map +1 -0
  106. package/dist/transport/createSnapshotToolRuntime.js +40 -0
  107. package/dist/transport/createSnapshotToolRuntime.js.map +1 -0
  108. package/dist/transport/httpSnapshotServer.d.ts +11 -0
  109. package/dist/transport/httpSnapshotServer.d.ts.map +1 -0
  110. package/dist/transport/httpSnapshotServer.js +216 -0
  111. package/dist/transport/httpSnapshotServer.js.map +1 -0
  112. package/dist/transport/mcpToolRouter.d.ts +81 -0
  113. package/dist/transport/mcpToolRouter.d.ts.map +1 -0
  114. package/dist/transport/mcpToolRouter.js +416 -0
  115. package/dist/transport/mcpToolRouter.js.map +1 -0
  116. package/dist/transport/webServerRuntime.d.ts +17 -0
  117. package/dist/transport/webServerRuntime.d.ts.map +1 -0
  118. package/dist/transport/webServerRuntime.js +73 -0
  119. package/dist/transport/webServerRuntime.js.map +1 -0
  120. package/dist/utils/swaggerCache.d.ts +4 -0
  121. package/dist/utils/swaggerCache.d.ts.map +1 -1
  122. package/dist/utils/swaggerCache.js +8 -0
  123. package/dist/utils/swaggerCache.js.map +1 -1
  124. package/dist/utils/types.d.ts +2 -1
  125. package/dist/utils/types.d.ts.map +1 -1
  126. package/dist/utils/types.js +2 -0
  127. package/dist/utils/types.js.map +1 -1
  128. package/dist/web/dashboard.css +411 -0
  129. package/dist/web/dashboard.html +141 -0
  130. package/dist/web/dashboard.js +540 -0
  131. package/package.json +27 -17
@@ -0,0 +1,411 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
2
+
3
+ :root {
4
+ --color-bg: #f8fafc;
5
+ --color-surface: #ffffff;
6
+ --color-text: #1e293b;
7
+ --color-muted: #475569;
8
+ --color-border: #e2e8f0;
9
+ --color-primary: #2563eb;
10
+ --color-primary-ink: #ffffff;
11
+ --color-accent: #f97316;
12
+ --color-danger: #b91c1c;
13
+ --shadow-card: 0 24px 60px -48px rgba(30, 41, 59, 0.5);
14
+ --radius-lg: 18px;
15
+ --radius-md: 12px;
16
+ }
17
+
18
+ * {
19
+ box-sizing: border-box;
20
+ }
21
+
22
+ body {
23
+ margin: 0;
24
+ min-height: 100vh;
25
+ font-family: 'IBM Plex Sans', system-ui, sans-serif;
26
+ color: var(--color-text);
27
+ background:
28
+ radial-gradient(circle at 10% 0%, rgba(37, 99, 235, 0.09), transparent 30%),
29
+ radial-gradient(circle at 100% 0%, rgba(249, 115, 22, 0.1), transparent 35%), var(--color-bg);
30
+ }
31
+
32
+ .page-shell {
33
+ margin: 0 auto;
34
+ max-width: 1480px;
35
+ padding: 2rem 1rem 2.5rem;
36
+ }
37
+
38
+ .hero {
39
+ display: flex;
40
+ flex-wrap: wrap;
41
+ gap: 1rem;
42
+ justify-content: space-between;
43
+ align-items: flex-end;
44
+ margin-bottom: 1rem;
45
+ }
46
+
47
+ .eyebrow {
48
+ margin: 0;
49
+ font-family: 'JetBrains Mono', monospace;
50
+ font-size: 0.8rem;
51
+ letter-spacing: 0.14em;
52
+ text-transform: uppercase;
53
+ color: var(--color-primary);
54
+ }
55
+
56
+ h1 {
57
+ margin: 0.35rem 0 0;
58
+ font-size: clamp(2.1rem, 4.2vw, 4.2rem);
59
+ line-height: 0.95;
60
+ letter-spacing: -0.03em;
61
+ }
62
+
63
+ .subtitle {
64
+ margin: 0.55rem 0 0;
65
+ max-width: 72ch;
66
+ color: var(--color-muted);
67
+ }
68
+
69
+ .hero-actions {
70
+ display: flex;
71
+ gap: 0.5rem;
72
+ flex-wrap: wrap;
73
+ }
74
+
75
+ .status-alert {
76
+ margin: 0 0 1rem;
77
+ padding: 0.8rem 1rem;
78
+ border-radius: var(--radius-md);
79
+ border: 1px solid var(--color-border);
80
+ background: rgba(37, 99, 235, 0.08);
81
+ color: var(--color-primary);
82
+ font-weight: 500;
83
+ }
84
+
85
+ .status-alert.error {
86
+ border-color: rgba(185, 28, 28, 0.4);
87
+ background: rgba(185, 28, 28, 0.08);
88
+ color: var(--color-danger);
89
+ }
90
+
91
+ .dashboard-layout {
92
+ display: grid;
93
+ gap: 1rem;
94
+ grid-template-columns: 1fr;
95
+ }
96
+
97
+ .panel {
98
+ background: color-mix(in srgb, var(--color-surface) 92%, #dbeafe 8%);
99
+ border: 1px solid var(--color-border);
100
+ border-radius: var(--radius-lg);
101
+ box-shadow: var(--shadow-card);
102
+ padding: 1rem;
103
+ }
104
+
105
+ .panel-header {
106
+ display: flex;
107
+ justify-content: space-between;
108
+ gap: 0.75rem;
109
+ align-items: baseline;
110
+ margin-bottom: 0.8rem;
111
+ }
112
+
113
+ h2 {
114
+ margin: 0;
115
+ font-size: 1.25rem;
116
+ letter-spacing: -0.02em;
117
+ }
118
+
119
+ h3 {
120
+ margin: 0 0 0.6rem;
121
+ font-size: 1rem;
122
+ }
123
+
124
+ .caption {
125
+ margin: 0;
126
+ color: var(--color-muted);
127
+ font-size: 0.88rem;
128
+ }
129
+
130
+ .button {
131
+ border: 1px solid transparent;
132
+ border-radius: 999px;
133
+ padding: 0.55rem 1rem;
134
+ font: inherit;
135
+ font-weight: 600;
136
+ cursor: pointer;
137
+ transition:
138
+ background-color 200ms ease-out,
139
+ border-color 200ms ease-out,
140
+ transform 180ms ease-out;
141
+ }
142
+
143
+ .button:focus-visible {
144
+ outline: 2px solid rgba(37, 99, 235, 0.35);
145
+ outline-offset: 2px;
146
+ }
147
+
148
+ .button.primary {
149
+ background: var(--color-primary);
150
+ color: var(--color-primary-ink);
151
+ }
152
+
153
+ .button.primary:hover {
154
+ background: #1d4ed8;
155
+ transform: translateY(-1px);
156
+ }
157
+
158
+ .button.secondary {
159
+ background: var(--color-surface);
160
+ border-color: var(--color-border);
161
+ color: var(--color-text);
162
+ }
163
+
164
+ .button.secondary:hover {
165
+ border-color: var(--color-primary);
166
+ color: var(--color-primary);
167
+ }
168
+
169
+ .snapshot-list {
170
+ display: grid;
171
+ gap: 0.5rem;
172
+ }
173
+
174
+ .snapshot-item {
175
+ width: 100%;
176
+ text-align: left;
177
+ border: 1px solid var(--color-border);
178
+ border-radius: var(--radius-md);
179
+ padding: 0.7rem;
180
+ background: var(--color-surface);
181
+ cursor: pointer;
182
+ transition:
183
+ border-color 180ms ease-out,
184
+ box-shadow 180ms ease-out;
185
+ }
186
+
187
+ .snapshot-item:hover {
188
+ border-color: rgba(37, 99, 235, 0.6);
189
+ box-shadow: 0 10px 24px -22px rgba(37, 99, 235, 0.9);
190
+ }
191
+
192
+ .snapshot-item time {
193
+ display: block;
194
+ font-family: 'JetBrains Mono', monospace;
195
+ font-size: 0.8rem;
196
+ color: var(--color-muted);
197
+ }
198
+
199
+ .snapshot-item strong {
200
+ font-family: 'JetBrains Mono', monospace;
201
+ font-size: 0.85rem;
202
+ }
203
+
204
+ .compare-form {
205
+ display: grid;
206
+ gap: 0.8rem;
207
+ margin-bottom: 1rem;
208
+ }
209
+
210
+ .compare-form label {
211
+ display: grid;
212
+ gap: 0.35rem;
213
+ font-size: 0.9rem;
214
+ color: var(--color-muted);
215
+ }
216
+
217
+ select {
218
+ border: 1px solid var(--color-border);
219
+ border-radius: var(--radius-md);
220
+ padding: 0.55rem 0.7rem;
221
+ font: inherit;
222
+ color: var(--color-text);
223
+ background: var(--color-surface);
224
+ }
225
+
226
+ input[type='text'] {
227
+ border: 1px solid var(--color-border);
228
+ border-radius: var(--radius-md);
229
+ padding: 0.55rem 0.7rem;
230
+ font: inherit;
231
+ color: var(--color-text);
232
+ background: var(--color-surface);
233
+ }
234
+
235
+ .metric-grid {
236
+ display: grid;
237
+ margin: 0;
238
+ gap: 0.7rem;
239
+ grid-template-columns: repeat(2, minmax(0, 1fr));
240
+ }
241
+
242
+ .metric-grid dt {
243
+ color: var(--color-muted);
244
+ font-size: 0.82rem;
245
+ }
246
+
247
+ .metric-grid dd {
248
+ margin: 0.2rem 0 0;
249
+ font-family: 'JetBrains Mono', monospace;
250
+ font-size: 1.15rem;
251
+ font-weight: 600;
252
+ }
253
+
254
+ .changes-table-wrap {
255
+ overflow: auto;
256
+ max-height: 360px;
257
+ }
258
+
259
+ .changes-table {
260
+ width: 100%;
261
+ border-collapse: collapse;
262
+ font-size: 0.9rem;
263
+ }
264
+
265
+ .changes-table th,
266
+ .changes-table td {
267
+ text-align: left;
268
+ border-bottom: 1px solid var(--color-border);
269
+ padding: 0.55rem 0.4rem;
270
+ vertical-align: top;
271
+ }
272
+
273
+ .classification {
274
+ font-family: 'JetBrains Mono', monospace;
275
+ font-size: 0.78rem;
276
+ text-transform: uppercase;
277
+ letter-spacing: 0.05em;
278
+ }
279
+
280
+ .classification.breaking {
281
+ color: var(--color-danger);
282
+ }
283
+
284
+ .classification.non-breaking {
285
+ color: var(--color-primary);
286
+ }
287
+
288
+ .classification.info {
289
+ color: var(--color-accent);
290
+ }
291
+
292
+ .history-filter-form {
293
+ display: grid;
294
+ gap: 0.8rem;
295
+ margin-bottom: 1rem;
296
+ }
297
+
298
+ .history-filter-form label {
299
+ display: grid;
300
+ gap: 0.35rem;
301
+ font-size: 0.9rem;
302
+ color: var(--color-muted);
303
+ }
304
+
305
+ .history-filter-actions {
306
+ display: flex;
307
+ gap: 0.5rem;
308
+ flex-wrap: wrap;
309
+ }
310
+
311
+ .history-list {
312
+ display: grid;
313
+ gap: 0.6rem;
314
+ max-height: 420px;
315
+ overflow: auto;
316
+ }
317
+
318
+ .history-item {
319
+ width: 100%;
320
+ text-align: left;
321
+ border: 1px solid var(--color-border);
322
+ border-radius: var(--radius-md);
323
+ background: var(--color-surface);
324
+ padding: 0.75rem;
325
+ font: inherit;
326
+ color: inherit;
327
+ cursor: pointer;
328
+ transition:
329
+ border-color 180ms ease-out,
330
+ box-shadow 180ms ease-out;
331
+ }
332
+
333
+ .history-item:hover {
334
+ border-color: rgba(37, 99, 235, 0.6);
335
+ box-shadow: 0 10px 24px -22px rgba(37, 99, 235, 0.9);
336
+ }
337
+
338
+ .history-item-top,
339
+ .history-item-meta {
340
+ display: flex;
341
+ justify-content: space-between;
342
+ gap: 0.75rem;
343
+ align-items: baseline;
344
+ }
345
+
346
+ .history-item-top {
347
+ margin-bottom: 0.35rem;
348
+ }
349
+
350
+ .history-item-top strong,
351
+ .history-item-meta time {
352
+ font-family: 'JetBrains Mono', monospace;
353
+ }
354
+
355
+ .history-item-meta {
356
+ margin-bottom: 0.35rem;
357
+ font-size: 0.82rem;
358
+ color: var(--color-muted);
359
+ }
360
+
361
+ .detail-events {
362
+ display: grid;
363
+ gap: 0.45rem;
364
+ margin-bottom: 1rem;
365
+ }
366
+
367
+ .event-row {
368
+ border: 1px solid var(--color-border);
369
+ border-left: 4px solid var(--color-accent);
370
+ border-radius: var(--radius-md);
371
+ padding: 0.6rem 0.65rem;
372
+ font-size: 0.88rem;
373
+ }
374
+
375
+ .detail-grid {
376
+ display: grid;
377
+ gap: 0.75rem;
378
+ grid-template-columns: 1fr;
379
+ }
380
+
381
+ pre {
382
+ margin: 0;
383
+ border: 1px solid var(--color-border);
384
+ border-radius: var(--radius-md);
385
+ background: rgba(248, 250, 252, 0.92);
386
+ padding: 0.75rem;
387
+ font-family: 'JetBrains Mono', monospace;
388
+ font-size: 0.78rem;
389
+ line-height: 1.4;
390
+ max-height: 380px;
391
+ overflow: auto;
392
+ }
393
+
394
+ @media (min-width: 980px) {
395
+ .dashboard-layout {
396
+ grid-template-columns: minmax(260px, 1fr) minmax(390px, 1.3fr) minmax(360px, 1.2fr);
397
+ }
398
+
399
+ .detail-grid {
400
+ grid-template-columns: 1fr 1fr;
401
+ }
402
+ }
403
+
404
+ @media (prefers-reduced-motion: reduce) {
405
+ *,
406
+ *::before,
407
+ *::after {
408
+ animation: none !important;
409
+ transition-duration: 0ms !important;
410
+ }
411
+ }
@@ -0,0 +1,141 @@
1
+ <!doctype html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Swagger Snapshot Diff Dashboard</title>
7
+ <link rel="stylesheet" href="/dashboard.css" />
8
+ </head>
9
+ <body>
10
+ <div class="page-shell">
11
+ <header class="hero">
12
+ <div>
13
+ <p class="eyebrow">Swagger Snapshot Review</p>
14
+ <h1>Read-only Diff Dashboard</h1>
15
+ <p class="subtitle">
16
+ Snapshot 이력 조회, diff 비교, endpoint before/after drill-down을 한 화면에서 확인합니다.
17
+ </p>
18
+ </div>
19
+ <div class="hero-actions">
20
+ <button id="refresh-snapshots-button" class="button secondary" type="button">Refresh</button>
21
+ <button id="capture-button" class="button primary" type="button">Capture Snapshot</button>
22
+ </div>
23
+ </header>
24
+
25
+ <p id="status-alert" class="status-alert" role="alert" aria-live="polite" hidden></p>
26
+
27
+ <main class="dashboard-layout">
28
+ <section class="panel">
29
+ <div class="panel-header">
30
+ <h2>Snapshots</h2>
31
+ <p id="source-caption" class="caption">Loading source...</p>
32
+ </div>
33
+ <div id="snapshot-list" class="snapshot-list" aria-live="polite"></div>
34
+ </section>
35
+
36
+ <section class="panel">
37
+ <div class="panel-header">
38
+ <h2>Diff Summary</h2>
39
+ <p class="caption">Select two snapshots to compare.</p>
40
+ </div>
41
+ <form id="compare-form" class="compare-form">
42
+ <label>
43
+ Baseline Snapshot
44
+ <select id="baseline-select" required></select>
45
+ </label>
46
+ <label>
47
+ Target Snapshot
48
+ <select id="target-select" required></select>
49
+ </label>
50
+ <button class="button primary" type="submit">Compare</button>
51
+ </form>
52
+
53
+ <dl class="metric-grid">
54
+ <div>
55
+ <dt>Total</dt>
56
+ <dd id="metric-total">-</dd>
57
+ </div>
58
+ <div>
59
+ <dt>Breaking</dt>
60
+ <dd id="metric-breaking">-</dd>
61
+ </div>
62
+ <div>
63
+ <dt>Non-breaking</dt>
64
+ <dd id="metric-non-breaking">-</dd>
65
+ </div>
66
+ <div>
67
+ <dt>Info</dt>
68
+ <dd id="metric-info">-</dd>
69
+ </div>
70
+ </dl>
71
+
72
+ <p id="diff-summary-line" class="caption">No diff selected.</p>
73
+
74
+ <div class="changes-table-wrap">
75
+ <table class="changes-table">
76
+ <thead>
77
+ <tr>
78
+ <th>Endpoint</th>
79
+ <th>Classification</th>
80
+ <th>Reason</th>
81
+ </tr>
82
+ </thead>
83
+ <tbody id="change-table-body"></tbody>
84
+ </table>
85
+ </div>
86
+ </section>
87
+
88
+ <section class="panel">
89
+ <div class="panel-header">
90
+ <h2>Change History</h2>
91
+ <p id="history-caption" class="caption">Latest endpoint changes.</p>
92
+ </div>
93
+ <form id="history-filter-form" class="history-filter-form">
94
+ <label>
95
+ Path
96
+ <input id="history-path-input" type="text" placeholder="/users" />
97
+ </label>
98
+ <label>
99
+ Method
100
+ <select id="history-method-select">
101
+ <option value="">All</option>
102
+ <option value="get">GET</option>
103
+ <option value="post">POST</option>
104
+ <option value="put">PUT</option>
105
+ <option value="patch">PATCH</option>
106
+ <option value="delete">DELETE</option>
107
+ <option value="head">HEAD</option>
108
+ <option value="options">OPTIONS</option>
109
+ <option value="trace">TRACE</option>
110
+ </select>
111
+ </label>
112
+ <div class="history-filter-actions">
113
+ <button class="button primary" type="submit">Apply</button>
114
+ <button id="history-clear-button" class="button secondary" type="button">Clear</button>
115
+ </div>
116
+ </form>
117
+ <div id="history-list" class="history-list" aria-live="polite"></div>
118
+ </section>
119
+
120
+ <section class="panel">
121
+ <div class="panel-header">
122
+ <h2>Endpoint Detail</h2>
123
+ <p id="detail-heading" class="caption">Pick one endpoint from the diff table.</p>
124
+ </div>
125
+ <div id="detail-events" class="detail-events"></div>
126
+ <div class="detail-grid">
127
+ <article>
128
+ <h3>Before</h3>
129
+ <pre id="detail-before">No selection</pre>
130
+ </article>
131
+ <article>
132
+ <h3>After</h3>
133
+ <pre id="detail-after">No selection</pre>
134
+ </article>
135
+ </div>
136
+ </section>
137
+ </main>
138
+ </div>
139
+ <script type="module" src="/dashboard.js"></script>
140
+ </body>
141
+ </html>