driftdetect-dashboard 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 (33) hide show
  1. package/dist/client/assets/main-DQAs4VF9.js +59 -0
  2. package/dist/client/assets/main-DQAs4VF9.js.map +1 -0
  3. package/dist/client/assets/main-Du5_09U3.css +2 -0
  4. package/dist/client/index.html +19 -0
  5. package/dist/server/api-routes.d.ts +50 -0
  6. package/dist/server/api-routes.d.ts.map +1 -0
  7. package/dist/server/api-routes.js +478 -0
  8. package/dist/server/api-routes.js.map +1 -0
  9. package/dist/server/dashboard-server.d.ts +64 -0
  10. package/dist/server/dashboard-server.d.ts.map +1 -0
  11. package/dist/server/dashboard-server.js +154 -0
  12. package/dist/server/dashboard-server.js.map +1 -0
  13. package/dist/server/drift-data-reader.d.ts +411 -0
  14. package/dist/server/drift-data-reader.d.ts.map +1 -0
  15. package/dist/server/drift-data-reader.js +1151 -0
  16. package/dist/server/drift-data-reader.js.map +1 -0
  17. package/dist/server/express-app.d.ts +24 -0
  18. package/dist/server/express-app.d.ts.map +1 -0
  19. package/dist/server/express-app.js +74 -0
  20. package/dist/server/express-app.js.map +1 -0
  21. package/dist/server/index.d.ts +20 -0
  22. package/dist/server/index.d.ts.map +1 -0
  23. package/dist/server/index.js +14 -0
  24. package/dist/server/index.js.map +1 -0
  25. package/dist/server/pattern-watcher.d.ts +55 -0
  26. package/dist/server/pattern-watcher.d.ts.map +1 -0
  27. package/dist/server/pattern-watcher.js +157 -0
  28. package/dist/server/pattern-watcher.js.map +1 -0
  29. package/dist/server/websocket-server.d.ts +83 -0
  30. package/dist/server/websocket-server.d.ts.map +1 -0
  31. package/dist/server/websocket-server.js +189 -0
  32. package/dist/server/websocket-server.js.map +1 -0
  33. package/package.json +86 -0
@@ -0,0 +1,2 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
2
+ */*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,Fira Code,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}html{font-family:Inter,system-ui,sans-serif}code,pre{font-family:JetBrains Mono,Fira Code,monospace}.badge-error{border-width:1px;border-color:#ef44444d;background-color:#ef444433;--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.badge-warning{border-width:1px;border-color:#eab3084d;background-color:#eab30833;--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.badge-info{border-width:1px;border-color:#3b82f64d;background-color:#3b82f633;--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.badge-hint{border-width:1px;border-color:#6b72804d;background-color:#6b728033;--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.badge-discovered{border-width:1px;border-color:#8b5cf64d;background-color:#8b5cf633;--tw-text-opacity: 1;color:rgb(139 92 246 / var(--tw-text-opacity, 1))}.badge-approved{border-width:1px;border-color:#22c55e4d;background-color:#22c55e33;--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.badge-ignored{border-width:1px;border-color:#6b72804d;background-color:#6b728033;--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.card{border-radius:.5rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1));padding:1rem}.btn{border-radius:.375rem;padding:.5rem 1rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.btn-primary{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.btn-primary:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.btn-secondary{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(248 250 252 / var(--tw-text-opacity, 1))}.btn-secondary:hover{background-color:#94a3b833}.btn-danger{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.btn-danger:hover{--tw-bg-opacity: 1;background-color:rgb(185 28 28 / var(--tw-bg-opacity, 1))}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.-right-1{right:-.25rem}.-top-1{top:-.25rem}.left-3{left:.75rem}.top-1\/2{top:50%}.top-4{top:1rem}.z-10{z-index:10}.z-50{z-index:50}.mx-2{margin-left:.5rem;margin-right:.5rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-10{margin-left:2.5rem}.ml-14{margin-left:3.5rem}.ml-2{margin-left:.5rem}.ml-6{margin-left:1.5rem}.ml-7{margin-left:1.75rem}.ml-auto{margin-left:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1\.5{height:.375rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[60vh\]{height:60vh}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-\[600px\]{max-height:600px}.max-h-\[90vh\]{max-height:90vh}.max-h-\[calc\(100vh-400px\)\]{max-height:calc(100vh - 400px)}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-80{width:20rem}.w-96{width:24rem}.w-full{width:100%}.min-w-0{min-width:0px}.max-w-3xl{max-width:48rem}.max-w-5xl{max-width:64rem}.max-w-md{max-width:28rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0\.5{--tw-translate-x: .125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-6{--tw-translate-x: 1.5rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-blue-500\/20{border-color:#3b82f633}.border-blue-500\/30{border-color:#3b82f64d}.border-dark-border{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-dark-border\/30{border-color:#3341554d}.border-dark-border\/50{border-color:#33415580}.border-dark-muted\/20{border-color:#94a3b833}.border-dark-muted\/30{border-color:#94a3b84d}.border-severity-error\/20{border-color:#ef444433}.border-severity-error\/30{border-color:#ef44444d}.border-severity-info\/30{border-color:#3b82f64d}.border-severity-warning\/20{border-color:#eab30833}.border-severity-warning\/30{border-color:#eab3084d}.border-status-approved\/20{border-color:#22c55e33}.border-transparent{border-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-black\/60{background-color:#0009}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-400\/10{background-color:#60a5fa1a}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-500\/20{background-color:#3b82f633}.bg-cyan-500\/10{background-color:#06b6d41a}.bg-dark-bg{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-dark-bg\/50{background-color:#0f172a80}.bg-dark-border{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.bg-dark-muted{--tw-bg-opacity: 1;background-color:rgb(148 163 184 / var(--tw-bg-opacity, 1))}.bg-dark-muted\/10{background-color:#94a3b81a}.bg-dark-surface{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-gray-500\/10{background-color:#6b72801a}.bg-green-400\/10{background-color:#4ade801a}.bg-green-500\/10{background-color:#22c55e1a}.bg-orange-400\/10{background-color:#fb923c1a}.bg-orange-500\/10{background-color:#f973161a}.bg-pink-500\/10{background-color:#ec48991a}.bg-purple-500\/10{background-color:#a855f71a}.bg-red-400\/10{background-color:#f871711a}.bg-red-500\/10{background-color:#ef44441a}.bg-severity-error{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-severity-error\/10{background-color:#ef44441a}.bg-severity-error\/20{background-color:#ef444433}.bg-severity-info\/10{background-color:#3b82f61a}.bg-severity-info\/20{background-color:#3b82f633}.bg-severity-warning{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-severity-warning\/10{background-color:#eab3081a}.bg-severity-warning\/20{background-color:#eab30833}.bg-slate-500\/10{background-color:#64748b1a}.bg-status-approved{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-status-approved\/10{background-color:#22c55e1a}.bg-teal-500\/10{background-color:#14b8a61a}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-yellow-400\/10{background-color:#facc151a}.bg-yellow-500\/10{background-color:#eab3081a}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-3{padding-bottom:.75rem}.pl-10{padding-left:2.5rem}.pl-3{padding-left:.75rem}.pr-2{padding-right:.5rem}.pt-0{padding-top:0}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,Fira Code,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-cyan-400{--tw-text-opacity: 1;color:rgb(34 211 238 / var(--tw-text-opacity, 1))}.text-dark-border{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-dark-muted{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-dark-text{--tw-text-opacity: 1;color:rgb(248 250 252 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-fuchsia-400{--tw-text-opacity: 1;color:rgb(232 121 249 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-indigo-400{--tw-text-opacity: 1;color:rgb(129 140 248 / var(--tw-text-opacity, 1))}.text-lime-400{--tw-text-opacity: 1;color:rgb(163 230 53 / var(--tw-text-opacity, 1))}.text-neutral-400{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity, 1))}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-pink-400{--tw-text-opacity: 1;color:rgb(244 114 182 / var(--tw-text-opacity, 1))}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-rose-400{--tw-text-opacity: 1;color:rgb(251 113 133 / var(--tw-text-opacity, 1))}.text-severity-error{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-severity-hint{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-severity-info{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-severity-warning{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-status-approved{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-teal-400{--tw-text-opacity: 1;color:rgb(45 212 191 / var(--tw-text-opacity, 1))}.text-yellow-400{--tw-text-opacity: 1;color:rgb(250 204 21 / var(--tw-text-opacity, 1))}.line-through{text-decoration-line:line-through}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.scrollbar-dark{scrollbar-width:thin;scrollbar-color:#334155 transparent}.scrollbar-dark::-webkit-scrollbar{width:8px;height:8px}.scrollbar-dark::-webkit-scrollbar-track{background:transparent}.scrollbar-dark::-webkit-scrollbar-thumb{background-color:#334155;border-radius:4px}.scrollbar-dark::-webkit-scrollbar-thumb:hover{background-color:#94a3b8}.hover\:border-dark-border:hover{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.hover\:border-dark-muted:hover{--tw-border-opacity: 1;border-color:rgb(148 163 184 / var(--tw-border-opacity, 1))}.hover\:bg-dark-border\/10:hover{background-color:#3341551a}.hover\:bg-dark-border\/20:hover{background-color:#33415533}.hover\:bg-dark-border\/30:hover{background-color:#3341554d}.hover\:bg-dark-border\/50:hover{background-color:#33415580}.hover\:bg-dark-surface:hover{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.hover\:bg-severity-warning\/20:hover{background-color:#eab30833}.hover\:bg-status-approved\/20:hover{background-color:#22c55e33}.hover\:text-blue-300:hover{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.hover\:text-dark-text:hover{--tw-text-opacity: 1;color:rgb(248 250 252 / var(--tw-text-opacity, 1))}.hover\:text-severity-error:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.group:hover .group-hover\:scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Drift Dashboard</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
+ <link
10
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
11
+ rel="stylesheet"
12
+ />
13
+ <script type="module" crossorigin src="/assets/main-DQAs4VF9.js"></script>
14
+ <link rel="stylesheet" crossorigin href="/assets/main-Du5_09U3.css">
15
+ </head>
16
+ <body class="bg-dark-bg text-dark-text">
17
+ <div id="root"></div>
18
+ </body>
19
+ </html>
@@ -0,0 +1,50 @@
1
+ /**
2
+ * API Routes for the Drift Dashboard
3
+ *
4
+ * Provides REST API endpoints for patterns, violations, files, stats, and config.
5
+ *
6
+ * @requirements 8.1 - GET `/api/patterns` to list all patterns
7
+ * @requirements 8.2 - GET `/api/patterns/:id` to get pattern details with locations
8
+ * @requirements 8.3 - POST `/api/patterns/:id/approve` to approve a pattern
9
+ * @requirements 8.4 - POST `/api/patterns/:id/ignore` to ignore a pattern
10
+ * @requirements 8.5 - DELETE `/api/patterns/:id` to delete a pattern
11
+ * @requirements 8.6 - GET `/api/violations` to list all violations
12
+ * @requirements 8.7 - GET `/api/files` to get the file tree
13
+ * @requirements 8.8 - GET `/api/files/:path` to get patterns and violations for a specific file
14
+ * @requirements 8.9 - GET `/api/stats` to get overview statistics
15
+ * @requirements 8.10 - GET `/api/config` to get configuration
16
+ * @requirements 8.11 - PUT `/api/config` to update configuration
17
+ * @requirements 8.12 - Return appropriate HTTP status codes and error messages
18
+ */
19
+ import { Router, type Request, type Response, type NextFunction } from 'express';
20
+ import { DriftDataReader } from './drift-data-reader.js';
21
+ export interface ApiError extends Error {
22
+ statusCode: number;
23
+ }
24
+ export declare class NotFoundError extends Error implements ApiError {
25
+ statusCode: number;
26
+ constructor(message: string);
27
+ }
28
+ export declare class BadRequestError extends Error implements ApiError {
29
+ statusCode: number;
30
+ constructor(message: string);
31
+ }
32
+ export declare class InternalServerError extends Error implements ApiError {
33
+ statusCode: number;
34
+ constructor(message: string);
35
+ }
36
+ /**
37
+ * Create API routes for the dashboard
38
+ * @param reader - DriftDataReader instance for accessing drift data
39
+ */
40
+ export declare function createApiRoutes(reader: DriftDataReader): Router;
41
+ /**
42
+ * Error handling middleware for API routes
43
+ * @requirements 8.12 - Return appropriate HTTP status codes and error messages
44
+ */
45
+ export declare function errorHandler(err: Error | ApiError, _req: Request, res: Response, _next: NextFunction): void;
46
+ /**
47
+ * 404 handler for unknown routes
48
+ */
49
+ export declare function notFoundHandler(req: Request, res: Response): void;
50
+ //# sourceMappingURL=api-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-routes.d.ts","sourceRoot":"","sources":["../../src/server/api-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,eAAe,EAA4D,MAAM,wBAAwB,CAAC;AAMnH,MAAM,WAAW,QAAS,SAAQ,KAAK;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD,qBAAa,aAAc,SAAQ,KAAM,YAAW,QAAQ;IAC1D,UAAU,SAAO;gBACL,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,eAAgB,SAAQ,KAAM,YAAW,QAAQ;IAC5D,UAAU,SAAO;gBACL,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,mBAAoB,SAAQ,KAAM,YAAW,QAAQ;IAChE,UAAU,SAAO;gBACL,OAAO,EAAE,MAAM;CAI5B;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAib/D;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,KAAK,GAAG,QAAQ,EACrB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,YAAY,GAClB,IAAI,CAeN;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAMjE"}
@@ -0,0 +1,478 @@
1
+ /**
2
+ * API Routes for the Drift Dashboard
3
+ *
4
+ * Provides REST API endpoints for patterns, violations, files, stats, and config.
5
+ *
6
+ * @requirements 8.1 - GET `/api/patterns` to list all patterns
7
+ * @requirements 8.2 - GET `/api/patterns/:id` to get pattern details with locations
8
+ * @requirements 8.3 - POST `/api/patterns/:id/approve` to approve a pattern
9
+ * @requirements 8.4 - POST `/api/patterns/:id/ignore` to ignore a pattern
10
+ * @requirements 8.5 - DELETE `/api/patterns/:id` to delete a pattern
11
+ * @requirements 8.6 - GET `/api/violations` to list all violations
12
+ * @requirements 8.7 - GET `/api/files` to get the file tree
13
+ * @requirements 8.8 - GET `/api/files/:path` to get patterns and violations for a specific file
14
+ * @requirements 8.9 - GET `/api/stats` to get overview statistics
15
+ * @requirements 8.10 - GET `/api/config` to get configuration
16
+ * @requirements 8.11 - PUT `/api/config` to update configuration
17
+ * @requirements 8.12 - Return appropriate HTTP status codes and error messages
18
+ */
19
+ import { Router } from 'express';
20
+ import { DriftDataReader } from './drift-data-reader.js';
21
+ // ============================================================================
22
+ // Error Classes
23
+ // ============================================================================
24
+ export class NotFoundError extends Error {
25
+ statusCode = 404;
26
+ constructor(message) {
27
+ super(message);
28
+ this.name = 'NotFoundError';
29
+ }
30
+ }
31
+ export class BadRequestError extends Error {
32
+ statusCode = 400;
33
+ constructor(message) {
34
+ super(message);
35
+ this.name = 'BadRequestError';
36
+ }
37
+ }
38
+ export class InternalServerError extends Error {
39
+ statusCode = 500;
40
+ constructor(message) {
41
+ super(message);
42
+ this.name = 'InternalServerError';
43
+ }
44
+ }
45
+ // ============================================================================
46
+ // API Routes Factory
47
+ // ============================================================================
48
+ /**
49
+ * Create API routes for the dashboard
50
+ * @param reader - DriftDataReader instance for accessing drift data
51
+ */
52
+ export function createApiRoutes(reader) {
53
+ const router = Router();
54
+ // ==========================================================================
55
+ // Pattern Routes
56
+ // ==========================================================================
57
+ /**
58
+ * GET /api/patterns - List all patterns with optional filters
59
+ * @requirements 8.1
60
+ */
61
+ router.get('/patterns', async (req, res, next) => {
62
+ try {
63
+ const query = {};
64
+ if (req.query['category']) {
65
+ query.category = req.query['category'];
66
+ }
67
+ if (req.query['status']) {
68
+ query.status = req.query['status'];
69
+ }
70
+ if (req.query['minConfidence']) {
71
+ query.minConfidence = parseFloat(req.query['minConfidence']);
72
+ }
73
+ if (req.query['search']) {
74
+ query.search = req.query['search'];
75
+ }
76
+ const patterns = await reader.getPatterns(query);
77
+ res.json(patterns);
78
+ }
79
+ catch (error) {
80
+ next(error);
81
+ }
82
+ });
83
+ /**
84
+ * GET /api/patterns/:id - Get pattern with locations
85
+ * @requirements 8.2
86
+ */
87
+ router.get('/patterns/:id', async (req, res, next) => {
88
+ try {
89
+ const { id } = req.params;
90
+ if (!id) {
91
+ throw new BadRequestError('Pattern ID is required');
92
+ }
93
+ const pattern = await reader.getPattern(id);
94
+ if (!pattern) {
95
+ throw new NotFoundError(`Pattern not found: ${id}`);
96
+ }
97
+ res.json(pattern);
98
+ }
99
+ catch (error) {
100
+ next(error);
101
+ }
102
+ });
103
+ /**
104
+ * POST /api/patterns/:id/approve - Approve a pattern
105
+ * @requirements 8.3
106
+ */
107
+ router.post('/patterns/:id/approve', async (req, res, next) => {
108
+ try {
109
+ const { id } = req.params;
110
+ if (!id) {
111
+ throw new BadRequestError('Pattern ID is required');
112
+ }
113
+ await reader.approvePattern(id);
114
+ res.json({ success: true, message: `Pattern ${id} approved` });
115
+ }
116
+ catch (error) {
117
+ if (error instanceof Error && error.message.includes('not found')) {
118
+ next(new NotFoundError(error.message));
119
+ }
120
+ else {
121
+ next(error);
122
+ }
123
+ }
124
+ });
125
+ /**
126
+ * POST /api/patterns/:id/ignore - Ignore a pattern
127
+ * @requirements 8.4
128
+ */
129
+ router.post('/patterns/:id/ignore', async (req, res, next) => {
130
+ try {
131
+ const { id } = req.params;
132
+ if (!id) {
133
+ throw new BadRequestError('Pattern ID is required');
134
+ }
135
+ await reader.ignorePattern(id);
136
+ res.json({ success: true, message: `Pattern ${id} ignored` });
137
+ }
138
+ catch (error) {
139
+ if (error instanceof Error && error.message.includes('not found')) {
140
+ next(new NotFoundError(error.message));
141
+ }
142
+ else {
143
+ next(error);
144
+ }
145
+ }
146
+ });
147
+ /**
148
+ * POST /api/patterns/bulk-approve - Bulk approve multiple patterns
149
+ * Accepts an array of pattern IDs to approve at once
150
+ */
151
+ router.post('/patterns/bulk-approve', async (req, res, next) => {
152
+ try {
153
+ const { ids } = req.body;
154
+ if (!ids || !Array.isArray(ids) || ids.length === 0) {
155
+ throw new BadRequestError('Array of pattern IDs is required');
156
+ }
157
+ const results = [];
158
+ for (const id of ids) {
159
+ try {
160
+ await reader.approvePattern(id);
161
+ results.push({ id, success: true });
162
+ }
163
+ catch (error) {
164
+ results.push({
165
+ id,
166
+ success: false,
167
+ error: error instanceof Error ? error.message : 'Unknown error'
168
+ });
169
+ }
170
+ }
171
+ const successCount = results.filter(r => r.success).length;
172
+ res.json({
173
+ success: true,
174
+ message: `Approved ${successCount} of ${ids.length} patterns`,
175
+ results
176
+ });
177
+ }
178
+ catch (error) {
179
+ next(error);
180
+ }
181
+ });
182
+ /**
183
+ * DELETE /api/patterns/:id - Delete a pattern
184
+ * @requirements 8.5
185
+ */
186
+ router.delete('/patterns/:id', async (req, res, next) => {
187
+ try {
188
+ const { id } = req.params;
189
+ if (!id) {
190
+ throw new BadRequestError('Pattern ID is required');
191
+ }
192
+ await reader.deletePattern(id);
193
+ res.json({ success: true, message: `Pattern ${id} deleted` });
194
+ }
195
+ catch (error) {
196
+ if (error instanceof Error && error.message.includes('not found')) {
197
+ next(new NotFoundError(error.message));
198
+ }
199
+ else {
200
+ next(error);
201
+ }
202
+ }
203
+ });
204
+ // ==========================================================================
205
+ // Violation Routes
206
+ // ==========================================================================
207
+ /**
208
+ * GET /api/violations - List all violations with optional filters
209
+ * @requirements 8.6
210
+ */
211
+ router.get('/violations', async (req, res, next) => {
212
+ try {
213
+ const query = {};
214
+ if (req.query['severity']) {
215
+ query.severity = req.query['severity'];
216
+ }
217
+ if (req.query['file']) {
218
+ query.file = req.query['file'];
219
+ }
220
+ if (req.query['patternId']) {
221
+ query.patternId = req.query['patternId'];
222
+ }
223
+ if (req.query['search']) {
224
+ query.search = req.query['search'];
225
+ }
226
+ const violations = await reader.getViolations(query);
227
+ res.json(violations);
228
+ }
229
+ catch (error) {
230
+ next(error);
231
+ }
232
+ });
233
+ /**
234
+ * GET /api/snippet - Get code snippet for a file location
235
+ */
236
+ router.get('/snippet', async (req, res, next) => {
237
+ try {
238
+ const file = req.query['file'];
239
+ const line = parseInt(req.query['line'], 10);
240
+ const context = parseInt(req.query['context'], 10) || 3;
241
+ if (!file) {
242
+ throw new BadRequestError('File path is required');
243
+ }
244
+ if (isNaN(line)) {
245
+ throw new BadRequestError('Line number is required');
246
+ }
247
+ const snippet = await reader.getCodeSnippet(file, line, context);
248
+ if (!snippet) {
249
+ throw new NotFoundError(`Could not read file: ${file}`);
250
+ }
251
+ res.json(snippet);
252
+ }
253
+ catch (error) {
254
+ next(error);
255
+ }
256
+ });
257
+ // ==========================================================================
258
+ // File Routes
259
+ // ==========================================================================
260
+ /**
261
+ * GET /api/files - Get file tree
262
+ * @requirements 8.7
263
+ */
264
+ router.get('/files', async (_req, res, next) => {
265
+ try {
266
+ const fileTree = await reader.getFileTree();
267
+ res.json(fileTree);
268
+ }
269
+ catch (error) {
270
+ next(error);
271
+ }
272
+ });
273
+ /**
274
+ * GET /api/files/* - Get file details (wildcard path)
275
+ * @requirements 8.8
276
+ */
277
+ router.get('/files/*', async (req, res, next) => {
278
+ try {
279
+ // Extract the file path from the wildcard
280
+ const filePath = req.params[0];
281
+ if (!filePath) {
282
+ throw new BadRequestError('File path is required');
283
+ }
284
+ const fileDetails = await reader.getFileDetails(filePath);
285
+ if (!fileDetails) {
286
+ throw new NotFoundError(`File not found or has no patterns/violations: ${filePath}`);
287
+ }
288
+ res.json(fileDetails);
289
+ }
290
+ catch (error) {
291
+ next(error);
292
+ }
293
+ });
294
+ // ==========================================================================
295
+ // Stats Routes
296
+ // ==========================================================================
297
+ /**
298
+ * GET /api/stats - Get dashboard statistics
299
+ * @requirements 8.9
300
+ */
301
+ router.get('/stats', async (_req, res, next) => {
302
+ try {
303
+ const stats = await reader.getStats();
304
+ res.json(stats);
305
+ }
306
+ catch (error) {
307
+ next(error);
308
+ }
309
+ });
310
+ // ==========================================================================
311
+ // Config Routes
312
+ // ==========================================================================
313
+ /**
314
+ * GET /api/config - Get configuration
315
+ * @requirements 8.10
316
+ */
317
+ router.get('/config', async (_req, res, next) => {
318
+ try {
319
+ const config = await reader.getConfig();
320
+ res.json(config);
321
+ }
322
+ catch (error) {
323
+ next(error);
324
+ }
325
+ });
326
+ /**
327
+ * PUT /api/config - Update configuration
328
+ * @requirements 8.11
329
+ */
330
+ router.put('/config', async (req, res, next) => {
331
+ try {
332
+ const partialConfig = req.body;
333
+ if (!partialConfig || typeof partialConfig !== 'object') {
334
+ throw new BadRequestError('Invalid configuration format');
335
+ }
336
+ await reader.updateConfig(partialConfig);
337
+ const updatedConfig = await reader.getConfig();
338
+ res.json(updatedConfig);
339
+ }
340
+ catch (error) {
341
+ next(error);
342
+ }
343
+ });
344
+ // ==========================================================================
345
+ // Contract Routes (BE↔FE mismatch detection)
346
+ // ==========================================================================
347
+ /**
348
+ * GET /api/contracts - List all contracts with optional filters
349
+ */
350
+ router.get('/contracts', async (req, res, next) => {
351
+ try {
352
+ const query = {};
353
+ if (req.query['status']) {
354
+ query.status = req.query['status'];
355
+ }
356
+ if (req.query['method']) {
357
+ query.method = req.query['method'];
358
+ }
359
+ if (req.query['hasMismatches'] !== undefined) {
360
+ query.hasMismatches = req.query['hasMismatches'] === 'true';
361
+ }
362
+ if (req.query['search']) {
363
+ query.search = req.query['search'];
364
+ }
365
+ const contracts = await reader.getContracts(query);
366
+ res.json(contracts);
367
+ }
368
+ catch (error) {
369
+ next(error);
370
+ }
371
+ });
372
+ /**
373
+ * GET /api/contracts/stats - Get contract statistics
374
+ */
375
+ router.get('/contracts/stats', async (_req, res, next) => {
376
+ try {
377
+ const stats = await reader.getContractStats();
378
+ res.json(stats);
379
+ }
380
+ catch (error) {
381
+ next(error);
382
+ }
383
+ });
384
+ /**
385
+ * GET /api/contracts/:id - Get contract details
386
+ */
387
+ router.get('/contracts/:id', async (req, res, next) => {
388
+ try {
389
+ const { id } = req.params;
390
+ if (!id) {
391
+ throw new BadRequestError('Contract ID is required');
392
+ }
393
+ const contract = await reader.getContract(id);
394
+ if (!contract) {
395
+ throw new NotFoundError(`Contract not found: ${id}`);
396
+ }
397
+ res.json(contract);
398
+ }
399
+ catch (error) {
400
+ next(error);
401
+ }
402
+ });
403
+ /**
404
+ * POST /api/contracts/:id/verify - Verify a contract
405
+ */
406
+ router.post('/contracts/:id/verify', async (req, res, next) => {
407
+ try {
408
+ const { id } = req.params;
409
+ if (!id) {
410
+ throw new BadRequestError('Contract ID is required');
411
+ }
412
+ await reader.verifyContract(id);
413
+ res.json({ success: true, message: `Contract ${id} verified` });
414
+ }
415
+ catch (error) {
416
+ if (error instanceof Error && error.message.includes('not found')) {
417
+ next(new NotFoundError(error.message));
418
+ }
419
+ else {
420
+ next(error);
421
+ }
422
+ }
423
+ });
424
+ /**
425
+ * POST /api/contracts/:id/ignore - Ignore a contract
426
+ */
427
+ router.post('/contracts/:id/ignore', async (req, res, next) => {
428
+ try {
429
+ const { id } = req.params;
430
+ if (!id) {
431
+ throw new BadRequestError('Contract ID is required');
432
+ }
433
+ await reader.ignoreContract(id);
434
+ res.json({ success: true, message: `Contract ${id} ignored` });
435
+ }
436
+ catch (error) {
437
+ if (error instanceof Error && error.message.includes('not found')) {
438
+ next(new NotFoundError(error.message));
439
+ }
440
+ else {
441
+ next(error);
442
+ }
443
+ }
444
+ });
445
+ return router;
446
+ }
447
+ // ============================================================================
448
+ // Error Handling Middleware
449
+ // ============================================================================
450
+ /**
451
+ * Error handling middleware for API routes
452
+ * @requirements 8.12 - Return appropriate HTTP status codes and error messages
453
+ */
454
+ export function errorHandler(err, _req, res, _next) {
455
+ // Determine status code
456
+ const statusCode = 'statusCode' in err ? err.statusCode : 500;
457
+ // Log server errors
458
+ if (statusCode >= 500) {
459
+ console.error('Server error:', err);
460
+ }
461
+ // Send JSON error response
462
+ res.status(statusCode).json({
463
+ error: err.name || 'Error',
464
+ message: err.message || 'An unexpected error occurred',
465
+ statusCode,
466
+ });
467
+ }
468
+ /**
469
+ * 404 handler for unknown routes
470
+ */
471
+ export function notFoundHandler(req, res) {
472
+ res.status(404).json({
473
+ error: 'NotFound',
474
+ message: `Route not found: ${req.method} ${req.path}`,
475
+ statusCode: 404,
476
+ });
477
+ }
478
+ //# sourceMappingURL=api-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-routes.js","sourceRoot":"","sources":["../../src/server/api-routes.ts"],"names":[],"mappings":"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"}