@qodalis/cli-server-plugin-admin 1.0.0-beta.1 → 1.0.0-beta.13

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 (60) hide show
  1. package/README.md +226 -0
  2. package/dashboard/assets/index-BVWEEAZ_.js +248 -0
  3. package/dashboard/assets/index-DDYjltKc.css +32 -0
  4. package/dashboard/assets/wasm/qodalis_cli_wasm_bg.wasm +0 -0
  5. package/dashboard/index.html +14 -0
  6. package/dist/auth/auth-controller.d.ts +11 -2
  7. package/dist/auth/auth-controller.d.ts.map +1 -1
  8. package/dist/auth/auth-controller.js +59 -6
  9. package/dist/auth/auth-controller.js.map +1 -1
  10. package/dist/auth/auth-middleware.d.ts +2 -1
  11. package/dist/auth/auth-middleware.d.ts.map +1 -1
  12. package/dist/auth/auth-middleware.js +64 -1
  13. package/dist/auth/auth-middleware.js.map +1 -1
  14. package/dist/auth/auth-provider.d.ts +42 -0
  15. package/dist/auth/auth-provider.d.ts.map +1 -0
  16. package/dist/auth/auth-provider.js +16 -0
  17. package/dist/auth/auth-provider.js.map +1 -0
  18. package/dist/auth/jwt-service.d.ts +12 -2
  19. package/dist/auth/jwt-service.d.ts.map +1 -1
  20. package/dist/auth/jwt-service.js +11 -2
  21. package/dist/auth/jwt-service.js.map +1 -1
  22. package/dist/cli-admin-builder.d.ts +49 -9
  23. package/dist/cli-admin-builder.d.ts.map +1 -1
  24. package/dist/cli-admin-builder.js +87 -51
  25. package/dist/cli-admin-builder.js.map +1 -1
  26. package/dist/controllers/plugins-controller.d.ts.map +1 -1
  27. package/dist/controllers/plugins-controller.js +1 -2
  28. package/dist/controllers/plugins-controller.js.map +1 -1
  29. package/dist/controllers/status-controller.d.ts +1 -0
  30. package/dist/controllers/status-controller.d.ts.map +1 -1
  31. package/dist/controllers/status-controller.js.map +1 -1
  32. package/dist/controllers/ws-clients-controller.d.ts +1 -0
  33. package/dist/controllers/ws-clients-controller.d.ts.map +1 -1
  34. package/dist/controllers/ws-clients-controller.js.map +1 -1
  35. package/dist/index.d.ts +4 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +10 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/services/admin-config.d.ts +32 -3
  40. package/dist/services/admin-config.d.ts.map +1 -1
  41. package/dist/services/admin-config.js +56 -3
  42. package/dist/services/admin-config.js.map +1 -1
  43. package/dist/services/admin-theme.d.ts +31 -0
  44. package/dist/services/admin-theme.d.ts.map +1 -0
  45. package/dist/services/admin-theme.js +94 -0
  46. package/dist/services/admin-theme.js.map +1 -0
  47. package/dist/services/dashboard-dir.d.ts +10 -0
  48. package/dist/services/dashboard-dir.d.ts.map +1 -0
  49. package/dist/services/dashboard-dir.js +51 -0
  50. package/dist/services/dashboard-dir.js.map +1 -0
  51. package/dist/services/log-ring-buffer.d.ts +6 -0
  52. package/dist/services/log-ring-buffer.d.ts.map +1 -1
  53. package/dist/services/log-ring-buffer.js +13 -0
  54. package/dist/services/log-ring-buffer.js.map +1 -1
  55. package/dist/services/module-registry.d.ts +20 -7
  56. package/dist/services/module-registry.d.ts.map +1 -1
  57. package/dist/services/module-registry.js +22 -10
  58. package/dist/services/module-registry.js.map +1 -1
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +6 -2
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */.xterm{cursor:text;position:relative;-moz-user-select:none;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::-moz-selection{color:transparent}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;-moz-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:-moz-fit-content;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:double underline;text-decoration:double underline}.xterm-underline-3{-webkit-text-decoration:wavy underline;text-decoration:wavy underline}.xterm-underline-4{-webkit-text-decoration:dotted underline;text-decoration:dotted underline}.xterm-underline-5{-webkit-text-decoration:dashed underline;text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.cli-panel-wrapper{position:fixed;bottom:0;left:0;right:0;width:100vw;transform:translateY(0);transition:transform .3s cubic-bezier(.4,0,.2,1);background-color:var(--cli-panel-bg, #111827);color:var(--cli-panel-text, rgba(255, 255, 255, .87));border-top:1px solid var(--cli-panel-border, #374151);display:flex;flex-direction:column;z-index:1000;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;box-shadow:0 -4px 20px #00000040}.cli-panel-wrapper.collapsed{transform:translateY(calc(100% - 60px))}.cli-panel-wrapper.resizing{transition:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.cli-panel-header{background-color:var(--cli-panel-header-bg, #1f2937);display:flex;flex-direction:column;position:relative;flex-shrink:0}.cli-panel-resize-bar{position:absolute;top:-6px;left:0;right:0;height:12px;cursor:ns-resize;display:flex;align-items:center;justify-content:center;z-index:2}.cli-panel-resize-grip{width:32px;height:4px;border-radius:2px;background:var(--cli-panel-text-secondary, rgba(255, 255, 255, .3));opacity:0;transition:opacity .2s ease}.cli-panel-resize-bar:hover .cli-panel-resize-grip{opacity:1}.cli-panel-header-content{height:60px;display:flex;flex-direction:row;gap:1rem;align-items:center;border-bottom:1px solid var(--cli-panel-border, #374151);padding:0 1rem}.cli-panel-title{font-size:.95rem;display:flex;gap:.5rem;justify-content:center;align-items:center;margin:0;font-weight:600;color:var(--cli-panel-text, rgba(255, 255, 255, .87))}.cli-panel-title-icon{color:var(--cli-panel-accent, #818cf8);display:flex;align-items:center}.cli-panel-action-buttons{display:flex;flex-direction:row;gap:.35rem;margin-left:auto}.cli-panel-btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6));cursor:pointer;width:40px;height:40px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;padding:0;transition:background-color .2s ease,color .2s ease}.cli-panel-btn svg{flex-shrink:0}.cli-panel-btn:hover:not(:disabled){color:var(--cli-panel-text, rgba(255, 255, 255, .87));background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12))}.cli-panel-btn:active:not(:disabled){background-color:var(--cli-btn-active-bg, rgba(129, 140, 248, .2))}.cli-panel-btn:disabled{opacity:.3;cursor:not-allowed}.cli-panel-content{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}.cli-panel-tabs{background-color:var(--cli-panel-header-bg, #1f2937);display:flex;align-items:center;height:38px;padding:0 8px;gap:4px;border-bottom:1px solid var(--cli-panel-border, #374151);overflow-x:auto;overflow-y:hidden;flex-shrink:0;scrollbar-width:thin;scrollbar-color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .3)) transparent}.cli-panel-tabs::-webkit-scrollbar{height:2px}.cli-panel-tabs::-webkit-scrollbar-thumb{background:var(--cli-panel-text-secondary, rgba(255, 255, 255, .3));border-radius:1px}.cli-panel-tab-list{list-style:none;margin:0;padding:0;display:flex;gap:2px;align-items:stretch;height:100%}.cli-panel-tab{display:flex;align-items:center;gap:6px;padding:0 12px;cursor:pointer;background:transparent;border:none;border-top:2px solid transparent;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6));font-size:.8rem;font-family:inherit;white-space:nowrap;transition:background-color .15s ease,color .15s ease,border-color .15s ease;height:100%}.cli-panel-tab:hover:not(.active){background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12));color:var(--cli-panel-text, rgba(255, 255, 255, .87))}.cli-panel-tab.active{background-color:var(--cli-panel-bg, #111827);color:var(--cli-panel-text, rgba(255, 255, 255, .87));border-top-color:var(--cli-panel-accent, #818cf8)}.cli-panel-tab-title{pointer-events:none}.cli-panel-tab-rename-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--cli-panel-bg, #111827);border:1px solid var(--cli-panel-accent, #818cf8);color:var(--cli-panel-text, rgba(255, 255, 255, .87));font-size:.8rem;font-family:inherit;padding:2px 6px;border-radius:3px;outline:none;width:120px;height:22px}.cli-panel-tab-close-btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:none;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .4));cursor:pointer;font-size:1rem;line-height:1;padding:0 2px;border-radius:3px;transition:background-color .15s ease,color .15s ease}.cli-panel-tab-close-btn:hover{color:var(--cli-panel-text, rgba(255, 255, 255, .87));background-color:#ffffff1a}.cli-panel-add-tab{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:1px dashed var(--cli-panel-text-secondary, rgba(255, 255, 255, .3));color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .5));cursor:pointer;font-size:1rem;line-height:1;width:28px;height:24px;border-radius:4px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background-color .15s ease,color .15s ease,border-color .15s ease}.cli-panel-add-tab:hover{background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12));color:var(--cli-panel-text, rgba(255, 255, 255, .87));border-color:var(--cli-panel-text, rgba(255, 255, 255, .5))}.cli-panel-context-menu{position:fixed;z-index:1100;background-color:var(--cli-panel-header-bg, #1f2937);border:1px solid var(--cli-panel-border, #374151);border-radius:6px;padding:4px 0;min-width:180px;box-shadow:0 4px 16px #0006;font-family:inherit}.cli-panel-context-menu-item{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;color:var(--cli-panel-text, rgba(255, 255, 255, .87));cursor:pointer;display:block;width:100%;text-align:left;padding:6px 14px;font-size:.82rem;font-family:inherit;transition:background-color .1s ease}.cli-panel-context-menu-item:hover:not(:disabled){background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12))}.cli-panel-context-menu-item:disabled{color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .3));cursor:not-allowed}.cli-panel-context-menu-item.destructive{color:#f87171}.cli-panel-context-menu-item.destructive:hover:not(:disabled){background-color:#f871711f}.cli-panel-context-menu-separator{height:1px;background-color:var(--cli-panel-border, #374151);margin:4px 0}.cli-panel-instances{flex:1;min-height:0;overflow:hidden}.cli-panel-instance{height:100%}.cli-panel-panes-container{display:flex;height:100%}.cli-panel-panes-container.resizing{-webkit-user-select:none;-moz-user-select:none;user-select:none;cursor:ew-resize}.cli-panel-pane{position:relative;height:100%;min-width:0;overflow:hidden}.cli-panel-pane.active-pane{outline:1px solid var(--cli-panel-accent, #818cf8);outline-offset:-1px}.cli-panel-pane:hover .cli-panel-pane-close-btn{opacity:1}.cli-panel-pane-close-btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;position:absolute;top:4px;right:4px;z-index:10;background:var(--cli-panel-header-bg, #1f2937);border:1px solid var(--cli-panel-border, #374151);color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6));cursor:pointer;font-size:.9rem;line-height:1;width:22px;height:22px;border-radius:3px;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s ease,background-color .15s ease,color .15s ease}.cli-panel-pane-close-btn:hover{color:var(--cli-panel-text, rgba(255, 255, 255, .87));background-color:#ffffff1a}.cli-panel-pane-divider{width:6px;cursor:ew-resize;display:flex;align-items:center;justify-content:center;flex-shrink:0;background:transparent;transition:background-color .15s ease}.cli-panel-pane-divider:hover{background-color:var(--cli-panel-accent, #818cf8)}.cli-panel-pane-divider-grip{width:2px;height:24px;border-radius:1px;background-color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .3));transition:background-color .15s ease}.cli-panel-pane-divider:hover .cli-panel-pane-divider-grip{background-color:var(--cli-panel-text, rgba(255, 255, 255, .87))}.cli-panel-wrapper[data-position=top]{bottom:auto;top:0;border-top:none;border-bottom:1px solid var(--cli-panel-border, #374151);box-shadow:0 4px 20px #00000040;flex-direction:column-reverse}.cli-panel-wrapper[data-position=top].collapsed{transform:translateY(calc(-100% + 60px))}.cli-panel-wrapper[data-position=top] .cli-panel-header-content{border-bottom:none;border-top:1px solid var(--cli-panel-border, #374151)}.cli-panel-wrapper[data-position=top] .cli-panel-resize-bar{top:auto;bottom:-6px;cursor:ns-resize}.cli-panel-wrapper[data-position=left]{bottom:0;top:0;left:0;right:auto;width:auto;height:100vh!important;border-top:none;border-right:1px solid var(--cli-panel-border, #374151);box-shadow:4px 0 20px #00000040;flex-direction:row-reverse}.cli-panel-wrapper[data-position=left].collapsed{transform:translate(calc(-100% + 60px))}.cli-panel-wrapper[data-position=left] .cli-panel-header{width:60px;flex-shrink:0;flex-direction:column}.cli-panel-wrapper[data-position=left] .cli-panel-header-content{height:auto;flex:1;flex-direction:column;padding:1rem 0;border-bottom:none;border-left:1px solid var(--cli-panel-border, #374151)}.cli-panel-wrapper[data-position=left] .cli-panel-title{writing-mode:vertical-rl;text-orientation:mixed}.cli-panel-wrapper[data-position=left] .cli-panel-action-buttons{flex-direction:column;margin-left:0;margin-top:auto}.cli-panel-wrapper[data-position=left] .cli-panel-resize-bar{position:absolute;top:0;bottom:0;left:auto;right:-6px;width:12px;height:auto;cursor:ew-resize}.cli-panel-wrapper[data-position=left] .cli-panel-resize-grip{width:4px;height:32px}.cli-panel-wrapper[data-position=left] .cli-panel-content{flex:1;min-width:0}.cli-panel-wrapper[data-position=right]{bottom:0;top:0;left:auto;right:0;width:auto;height:100vh!important;border-top:none;border-left:1px solid var(--cli-panel-border, #374151);box-shadow:-4px 0 20px #00000040;flex-direction:row}.cli-panel-wrapper[data-position=right].collapsed{transform:translate(calc(100% - 60px))}.cli-panel-wrapper[data-position=right] .cli-panel-header{width:60px;flex-shrink:0;flex-direction:column}.cli-panel-wrapper[data-position=right] .cli-panel-header-content{height:auto;flex:1;flex-direction:column;padding:1rem 0;border-bottom:none;border-right:1px solid var(--cli-panel-border, #374151)}.cli-panel-wrapper[data-position=right] .cli-panel-title{writing-mode:vertical-rl;text-orientation:mixed}.cli-panel-wrapper[data-position=right] .cli-panel-action-buttons{flex-direction:column;margin-left:0;margin-top:auto}.cli-panel-wrapper[data-position=right] .cli-panel-resize-bar{position:absolute;top:0;bottom:0;right:auto;left:-6px;width:12px;height:auto;cursor:ew-resize}.cli-panel-wrapper[data-position=right] .cli-panel-resize-grip{width:4px;height:32px}.cli-panel-wrapper[data-position=right] .cli-panel-content{flex:1;min-width:0}.cli-panel-wrapper[data-resizable=false] .cli-panel-resize-bar,.cli-panel-wrapper[data-closable=false] .cli-panel-btn-close{display:none}.cli-panel-hide-tab{position:fixed;z-index:1000;display:flex;align-items:center;gap:6px;background-color:var(--cli-panel-header-bg, #1f2937);border:1px solid var(--cli-panel-border, #374151);color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6));cursor:pointer;padding:6px 12px;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:.8rem;font-weight:600;transition:transform .2s ease,opacity .2s ease,color .2s ease,background-color .2s ease,box-shadow .2s ease;box-shadow:0 2px 8px #0000004d;opacity:.85}.cli-panel-hide-tab:hover{transform:scale(1.05);opacity:1;color:var(--cli-panel-text, rgba(255, 255, 255, .87));background-color:var(--cli-panel-bg, #111827);box-shadow:0 4px 16px #0006}.cli-panel-hide-tab:active{transform:scale(.97)}.cli-panel-hide-tab svg{flex-shrink:0}.cli-panel-hide-tab .cli-panel-hide-tab-icon,.cli-panel-hide-tab:hover .cli-panel-hide-tab-icon{color:var(--cli-panel-accent, #818cf8)}.cli-panel-hide-tab .cli-panel-hide-tab-label{letter-spacing:.03em}@media(max-width:600px){.cli-panel-hide-tab{padding:6px 8px}.cli-panel-hide-tab .cli-panel-hide-tab-label,.cli-panel-hide-tab .cli-panel-hide-tab-arrow{display:none}}@keyframes cli-hide-tab-pulse{0%,to{transform:translate(0)}50%{transform:translate(3px)}}@keyframes cli-hide-tab-pulse-vertical{0%,to{transform:translateY(0)}50%{transform:translateY(3px)}}.cli-panel-hide-tab:hover .cli-panel-hide-tab-arrow{animation:cli-hide-tab-pulse .6s ease infinite}.cli-panel-hide-tab[data-position=left]:hover .cli-panel-hide-tab-arrow,.cli-panel-hide-tab[data-position=right]:hover .cli-panel-hide-tab-arrow{animation:cli-hide-tab-pulse-vertical .6s ease infinite}.cli-panel-hide-tab[data-position=bottom]{bottom:0;border-bottom:none;border-radius:8px 8px 0 0}.cli-panel-hide-tab[data-position=bottom][data-hide-align=start]{left:16px}.cli-panel-hide-tab[data-position=bottom][data-hide-align=center]{left:50%;transform:translate(-50%)}.cli-panel-hide-tab[data-position=bottom][data-hide-align=center]:hover{transform:translate(-50%) scale(1.05)}.cli-panel-hide-tab[data-position=bottom][data-hide-align=end]{right:16px}.cli-panel-hide-tab[data-position=top]{top:0;border-top:none;border-radius:0 0 8px 8px}.cli-panel-hide-tab[data-position=top][data-hide-align=start]{left:16px}.cli-panel-hide-tab[data-position=top][data-hide-align=center]{left:50%;transform:translate(-50%)}.cli-panel-hide-tab[data-position=top][data-hide-align=center]:hover{transform:translate(-50%) scale(1.05)}.cli-panel-hide-tab[data-position=top][data-hide-align=end]{right:16px}.cli-panel-hide-tab[data-position=left]{left:0;border-left:none;border-radius:0 8px 8px 0}.cli-panel-hide-tab[data-position=left][data-hide-align=start]{top:16px}.cli-panel-hide-tab[data-position=left][data-hide-align=center]{top:50%;transform:translateY(-50%)}.cli-panel-hide-tab[data-position=left][data-hide-align=center]:hover{transform:translateY(-50%) scale(1.05)}.cli-panel-hide-tab[data-position=left][data-hide-align=end]{bottom:16px}.cli-panel-hide-tab[data-position=right]{right:0;border-right:none;border-radius:8px 0 0 8px}.cli-panel-hide-tab[data-position=right][data-hide-align=start]{top:16px}.cli-panel-hide-tab[data-position=right][data-hide-align=center]{top:50%;transform:translateY(-50%)}.cli-panel-hide-tab[data-position=right][data-hide-align=center]:hover{transform:translateY(-50%) scale(1.05)}.cli-panel-hide-tab[data-position=right][data-hide-align=end]{bottom:16px}.cli-panel-wrapper[data-hideable=false] .cli-panel-btn-hide{display:none}.cli-panel-btn-position-wrapper{position:relative}.cli-panel-position-dropdown{position:absolute;bottom:calc(100% + 4px);top:auto;right:0;left:auto;background-color:var(--cli-panel-header-bg, #1f2937);border:1px solid var(--cli-panel-border, #374151);border-radius:6px;box-shadow:0 8px 24px #0006;z-index:1100;min-width:120px;overflow:hidden;display:flex;flex-direction:column}.cli-panel-position-dropdown-item{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6));cursor:pointer;display:flex;align-items:center;gap:8px;padding:8px 12px;font-size:.85rem;font-family:inherit;width:100%;text-align:left;transition:background-color .15s ease,color .15s ease}.cli-panel-position-dropdown-item:hover{background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12));color:var(--cli-panel-text, rgba(255, 255, 255, .87))}.cli-panel-position-dropdown-item.active{color:var(--cli-panel-accent, #818cf8)}.cli-panel-position-dropdown-item svg{flex-shrink:0}.cli-panel-wrapper[data-position=top] .cli-panel-position-dropdown{top:calc(100% + 4px);bottom:auto}.cli-panel-wrapper[data-position=left] .cli-panel-position-dropdown{top:0;bottom:auto;left:calc(100% + 4px);right:auto}.cli-panel-wrapper[data-position=right] .cli-panel-position-dropdown{top:0;bottom:auto;right:calc(100% + 4px);left:auto}.cli-panel-status-indicators{display:flex;align-items:center;gap:14px;margin-left:24px;font-size:12px;overflow:hidden;white-space:nowrap}.cli-panel-status-item{display:flex;align-items:center;gap:5px;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6))}.cli-panel-status-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--cli-status-neutral, #6b7280)}.cli-panel-status-dot.dot-idle{background:var(--cli-status-idle, #3fb950)}.cli-panel-status-dot.dot-running{background:var(--cli-status-running, #f0883e);animation:cliStatusPulse 1.5s ease-in-out infinite}.cli-panel-status-dot.dot-error{background:var(--cli-status-error, #f85149)}.cli-panel-status-icon{flex-shrink:0}.cli-panel-status-icon.status-success{color:var(--cli-status-idle, #3fb950)}.cli-panel-status-icon.status-error{color:var(--cli-status-error, #f85149)}.cli-panel-status-label{overflow:hidden;text-overflow:ellipsis}.cli-panel-status-item.status-muted{color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .4))}.cli-panel-status-item.status-text{max-width:200px}.cli-panel-status-item.status-text.level-info{color:var(--cli-panel-accent, #818cf8)}.cli-panel-status-item.status-text.level-success{color:var(--cli-status-idle, #3fb950)}.cli-panel-status-item.status-text.level-warn{color:var(--cli-status-running, #f0883e)}.cli-panel-status-item.status-text.level-error{color:var(--cli-status-error, #f85149)}.cli-panel-status-item.status-running{color:var(--cli-status-running, #f0883e)}.cli-panel-status-item.status-clickable{cursor:pointer;border-radius:4px;padding:2px 6px;margin:-2px -6px;transition:background-color .15s ease}.cli-panel-status-item.status-clickable:hover{background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12))}.cli-panel-status-indicators-compact{display:none}.cli-panel-wrapper[data-position=left] .cli-panel-status-indicators-compact,.cli-panel-wrapper[data-position=right] .cli-panel-status-indicators-compact{display:flex;flex-direction:column;align-items:center;gap:10px;padding:12px 0}.cli-panel-status-compact-item{display:flex;align-items:center;justify-content:center;width:20px;height:20px;cursor:default;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .6));font-size:12px}.cli-panel-status-compact-item.status-clickable{cursor:pointer;border-radius:4px}.cli-panel-status-compact-item.status-clickable:hover{background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .12))}.cli-panel-status-compact-item.status-muted{color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .4))}.cli-panel-status-compact-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}.cli-panel-status-compact-dot.level-info{background:var(--cli-panel-accent, #818cf8)}.cli-panel-status-compact-dot.level-success{background:var(--cli-status-idle, #3fb950)}.cli-panel-status-compact-dot.level-warn{background:var(--cli-status-running, #f0883e)}.cli-panel-status-compact-dot.level-error{background:var(--cli-status-error, #f85149)}.cli-panel-tab-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--cli-status-idle, #3fb950)}.cli-panel-tab-dot.dot-running{background:var(--cli-status-running, #f0883e);animation:cliStatusPulse 1.5s ease-in-out infinite}.cli-panel-tab-dot.dot-error{background:var(--cli-status-error, #f85149)}.cli-panel-services-dropdown{position:fixed;background-color:var(--cli-panel-header-bg, #1f2937);border:1px solid var(--cli-panel-border, #374151);border-radius:8px;box-shadow:0 8px 24px #0006;z-index:1100;min-width:260px;max-width:380px;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}.cli-panel-services-dropdown-header{padding:10px 14px 8px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .5));border-bottom:1px solid var(--cli-panel-border, #374151)}.cli-panel-services-dropdown-list{max-height:240px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .2)) transparent}.cli-panel-services-dropdown-list::-webkit-scrollbar{width:6px}.cli-panel-services-dropdown-list::-webkit-scrollbar-track{background:transparent}.cli-panel-services-dropdown-list::-webkit-scrollbar-thumb{background:var(--cli-panel-text-secondary, rgba(255, 255, 255, .2));border-radius:3px}.cli-panel-services-dropdown-list::-webkit-scrollbar-thumb:hover{background:var(--cli-panel-text-secondary, rgba(255, 255, 255, .35))}.cli-panel-services-dropdown-item{display:flex;align-items:flex-start;gap:10px;padding:10px 14px;border-bottom:1px solid rgba(255,255,255,.04);transition:background-color .15s ease}.cli-panel-services-dropdown-item:last-child{border-bottom:none}.cli-panel-services-dropdown-item:hover{background-color:var(--cli-btn-hover-bg, rgba(129, 140, 248, .08))}.cli-panel-svc-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;margin-top:5px}.cli-panel-svc-dot.svc-running{background:var(--cli-status-idle, #3fb950)}.cli-panel-svc-dot.svc-stopped{background:var(--cli-panel-text-secondary, rgba(255, 255, 255, .3))}.cli-panel-svc-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.cli-panel-svc-name{font-size:13px;font-weight:500;color:var(--cli-panel-text, rgba(255, 255, 255, .87));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cli-panel-svc-desc{font-size:11px;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .5));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cli-panel-svc-status{font-size:11px;flex-shrink:0;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .5));margin-top:1px}.cli-panel-srv-meta{display:flex;flex-direction:column;align-items:flex-end;gap:2px;flex-shrink:0}.cli-panel-services-dropdown-empty{padding:16px 14px;font-size:12px;color:var(--cli-panel-text-secondary, rgba(255, 255, 255, .4));text-align:center}.cli-panel-glow-line{position:absolute;bottom:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--cli-status-glow, var(--cli-panel-accent, #818cf8)),#a78bfa,var(--cli-status-glow, var(--cli-panel-accent, #818cf8)),transparent);background-size:200% 100%;opacity:.4;animation:cliGlowShift 8s ease-in-out infinite;transition:opacity .6s ease;pointer-events:none}.cli-panel-glow-line.glow-active{opacity:.8;animation-duration:3s}.cli-panel-wrapper[data-position=left] .cli-panel-glow-line{bottom:auto;top:0;left:auto;right:0;width:2px;height:100%;background:linear-gradient(180deg,transparent,var(--cli-status-glow, var(--cli-panel-accent, #818cf8)),#a78bfa,var(--cli-status-glow, var(--cli-panel-accent, #818cf8)),transparent);background-size:100% 200%}.cli-panel-wrapper[data-position=right] .cli-panel-glow-line{bottom:auto;top:0;left:0;right:auto;width:2px;height:100%;background:linear-gradient(180deg,transparent,var(--cli-status-glow, var(--cli-panel-accent, #818cf8)),#a78bfa,var(--cli-status-glow, var(--cli-panel-accent, #818cf8)),transparent);background-size:100% 200%}@keyframes cliStatusPulse{0%,to{opacity:1}50%{opacity:.3}}@keyframes cliGlowShift{0%{background-position:200% center}to{background-position:-200% center}}@media(prefers-reduced-motion:reduce){.cli-panel-glow-line,.cli-panel-status-dot,.cli-panel-tab-dot{animation:none!important}}.cli-panel-wrapper .xterm .xterm-viewport{overscroll-behavior:contain}.cli-panel-wrapper .xterm .xterm-viewport::-webkit-scrollbar{width:8px}.cli-panel-wrapper .xterm .xterm-viewport::-webkit-scrollbar-thumb{background:#444;border-radius:4px}.cli-panel-wrapper .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover{background:#666}body.cli-pane-resizing{-webkit-user-select:none;-moz-user-select:none;user-select:none;cursor:ew-resize}*,: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: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:currentColor}: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:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";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:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,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}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.collapse{visibility:collapse}.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}.top-0{top:0}.z-50{z-index:50}.col-span-full{grid-column:1 / -1}.m-6{margin:1.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-0\.5{margin-left:.125rem}.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}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-3\.5{height:.875rem}.h-5{height:1.25rem}.h-7{height:1.75rem}.h-\[calc\(100vh-12rem\)\]{height:calc(100vh - 12rem)}.h-full{height:100%}.h-screen{height:100vh}.max-h-80{max-height:20rem}.max-h-\[60vh\]{max-height:60vh}.min-h-0{min-height:0px}.min-h-\[38px\]{min-height:38px}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-3\.5{width:.875rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-\[220px\]{width:220px}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[80px\]{min-width:80px}.max-w-\[120px\]{max-width:120px}.max-w-\[200px\]{max-width:200px}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-\[2\]{flex:2}.flex-shrink-0,.shrink-0{flex-shrink:0}.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-4{--tw-translate-x: 1rem;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))}.rotate-90{--tw-rotate: 90deg;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))}.transform{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))}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,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-end{justify-content:flex-end}.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-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.gap-y-2{row-gap:.5rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * 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-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))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border\/50>:not([hidden])~:not([hidden]){border-color:color-mix(in srgb,var(--qcli-border) 50%,transparent)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.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-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-none{border-style:none}.border-border{--tw-border-opacity: 1;border-color:color-mix(in srgb,var(--qcli-border) calc(var(--tw-border-opacity, 1) * 100%),transparent)}.border-border\/50{border-color:color-mix(in srgb,var(--qcli-border) 50%,transparent)}.border-border\/75{border-color:color-mix(in srgb,var(--qcli-border) 75%,transparent)}.border-error\/20{border-color:color-mix(in srgb,var(--qcli-error) 20%,transparent)}.border-error\/30{border-color:color-mix(in srgb,var(--qcli-error) 30%,transparent)}.border-info\/30{border-color:color-mix(in srgb,var(--qcli-info) 30%,transparent)}.border-primary\/20{border-color:color-mix(in srgb,var(--qcli-primary) 20%,transparent)}.border-subtle\/30{border-color:color-mix(in srgb,var(--qcli-subtle) 30%,transparent)}.border-success\/30{border-color:color-mix(in srgb,var(--qcli-success) 30%,transparent)}.border-warning\/30{border-color:color-mix(in srgb,var(--qcli-warning) 30%,transparent)}.bg-control{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-control) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-current{background-color:currentColor}.bg-error{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-error) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-error\/10{background-color:color-mix(in srgb,var(--qcli-error) 10%,transparent)}.bg-error\/15{background-color:color-mix(in srgb,var(--qcli-error) 15%,transparent)}.bg-error\/20{background-color:color-mix(in srgb,var(--qcli-error) 20%,transparent)}.bg-error\/\[0\.06\]{background-color:color-mix(in srgb,var(--qcli-error) 6%,transparent)}.bg-info\/15{background-color:color-mix(in srgb,var(--qcli-info) 15%,transparent)}.bg-info\/20{background-color:color-mix(in srgb,var(--qcli-info) 20%,transparent)}.bg-on-primary{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-on-primary) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-overlay{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-overlay) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-popover{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-popover) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-primary{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-primary) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-primary\/10{background-color:color-mix(in srgb,var(--qcli-primary) 10%,transparent)}.bg-primary\/15{background-color:color-mix(in srgb,var(--qcli-primary) 15%,transparent)}.bg-primary\/20{background-color:color-mix(in srgb,var(--qcli-primary) 20%,transparent)}.bg-sidebar{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-sidebar) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-subtle{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-subtle) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-subtle\/15{background-color:color-mix(in srgb,var(--qcli-subtle) 15%,transparent)}.bg-subtle\/20{background-color:color-mix(in srgb,var(--qcli-subtle) 20%,transparent)}.bg-success{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-success) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-success\/15{background-color:color-mix(in srgb,var(--qcli-success) 15%,transparent)}.bg-success\/20{background-color:color-mix(in srgb,var(--qcli-success) 20%,transparent)}.bg-surface{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-surface) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-surface\/50{background-color:color-mix(in srgb,var(--qcli-surface) 50%,transparent)}.bg-surface\/75{background-color:color-mix(in srgb,var(--qcli-surface) 75%,transparent)}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-warning) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.bg-warning\/10{background-color:color-mix(in srgb,var(--qcli-warning) 10%,transparent)}.bg-warning\/15{background-color:color-mix(in srgb,var(--qcli-warning) 15%,transparent)}.bg-warning\/20{background-color:color-mix(in srgb,var(--qcli-warning) 20%,transparent)}.bg-warning\/30{background-color:color-mix(in srgb,var(--qcli-warning) 30%,transparent)}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.from-accent{--tw-gradient-from: color-mix(in srgb, var(--qcli-accent) 100% , transparent) var(--tw-gradient-from-position);--tw-gradient-to: color-mix(in srgb, var(--qcli-accent) 0% , transparent) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary{--tw-gradient-from: color-mix(in srgb, var(--qcli-primary) 100% , transparent) var(--tw-gradient-from-position);--tw-gradient-to: color-mix(in srgb, var(--qcli-primary) 0% , transparent) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-accent{--tw-gradient-to: color-mix(in srgb, var(--qcli-accent) 100% , transparent) var(--tw-gradient-to-position)}.to-primary{--tw-gradient-to: color-mix(in srgb, var(--qcli-primary) 100% , transparent) var(--tw-gradient-to-position)}.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{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.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-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-3{padding-bottom:.75rem}.pl-9{padding-left:2.25rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.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-5{line-height:1.25rem}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-accent{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-accent) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-error{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-error) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-error\/70{color:color-mix(in srgb,var(--qcli-error) 70%,transparent)}.text-heading{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-heading) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-info{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-info) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-muted{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-muted) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-on-primary{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-on-primary) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-subtle{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-subtle) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-success{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-success) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-text{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-text) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.text-warning{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-warning) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.placeholder-subtle::-moz-placeholder{--tw-placeholder-opacity: 1;color:color-mix(in srgb,var(--qcli-subtle) calc(var(--tw-placeholder-opacity, 1) * 100%),transparent)}.placeholder-subtle::placeholder{--tw-placeholder-opacity: 1;color:color-mix(in srgb,var(--qcli-subtle) calc(var(--tw-placeholder-opacity, 1) * 100%),transparent)}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.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)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.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)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.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}body{margin:0;min-height:100vh;background-color:var(--qcli-background);background-image:linear-gradient(135deg,var(--qcli-background-accent),var(--qcli-background));color:var(--qcli-text)}.xterm-char-measure-element{display:inline-block!important;visibility:hidden!important;position:absolute!important;top:0!important;left:-9999em!important}.xterm .xterm-helper-textarea{position:absolute!important;opacity:0!important;left:-9999em!important}.xterm .xterm-helpers{position:absolute!important;top:0!important;z-index:5!important}.last\:border-0:last-child{border-width:0px}.hover\:border-border:hover{--tw-border-opacity: 1;border-color:color-mix(in srgb,var(--qcli-border) calc(var(--tw-border-opacity, 1) * 100%),transparent)}.hover\:bg-control:hover{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-control) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.hover\:bg-control-hover:hover{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-control-hover) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.hover\:bg-error\/30:hover{background-color:color-mix(in srgb,var(--qcli-error) 30%,transparent)}.hover\:bg-primary-hover:hover{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-primary-hover) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.hover\:bg-primary\/30:hover{background-color:color-mix(in srgb,var(--qcli-primary) 30%,transparent)}.hover\:bg-success\/30:hover{background-color:color-mix(in srgb,var(--qcli-success) 30%,transparent)}.hover\:bg-surface:hover{--tw-bg-opacity: 1;background-color:color-mix(in srgb,var(--qcli-surface) calc(var(--tw-bg-opacity, 1) * 100%),transparent)}.hover\:bg-surface\/50:hover{background-color:color-mix(in srgb,var(--qcli-surface) 50%,transparent)}.hover\:bg-surface\/75:hover{background-color:color-mix(in srgb,var(--qcli-surface) 75%,transparent)}.hover\:bg-warning\/30:hover{background-color:color-mix(in srgb,var(--qcli-warning) 30%,transparent)}.hover\:text-accent:hover{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-accent) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.hover\:text-heading:hover{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-heading) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.hover\:text-text:hover{--tw-text-opacity: 1;color:color-mix(in srgb,var(--qcli-text) calc(var(--tw-text-opacity, 1) * 100%),transparent)}.hover\:opacity-80:hover{opacity:.8}.focus\:border-primary:focus{--tw-border-opacity: 1;border-color:color-mix(in srgb,var(--qcli-primary) calc(var(--tw-border-opacity, 1) * 100%),transparent)}.focus\:border-primary\/50:focus{border-color:color-mix(in srgb,var(--qcli-primary) 50%,transparent)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(min-width:1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%234f46e5'/%3E%3Ctext x='16' y='22' font-size='18' text-anchor='middle' fill='white' font-family='sans-serif'%3EQ%3C/text%3E%3C/svg%3E" />
7
+ <title>Qodalis Cli Admin</title>
8
+ <script type="module" crossorigin src="/qcli/admin/assets/index-BVWEEAZ_.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/qcli/admin/assets/index-DDYjltKc.css">
10
+ </head>
11
+ <body class="antialiased">
12
+ <div id="root"></div>
13
+ </body>
14
+ </html>
@@ -1,15 +1,24 @@
1
1
  import { Router } from 'express';
2
2
  import { AdminConfig } from '../services/admin-config';
3
+ import { AdminAuthProvider } from './auth-provider';
4
+ /** Mode name for the dashboard's own username/password form. */
5
+ export declare const ADMIN_AUTH_MODE_PASSWORD = "password";
6
+ /** Mode name for sign-in through the host application. */
7
+ export declare const ADMIN_AUTH_MODE_EXTERNAL = "external";
8
+ /** Return value of {@link createAuthController}. */
3
9
  export interface AuthControllerResult {
10
+ /** Express router with login and user-info routes. */
4
11
  router: Router;
12
+ /** Interval handle for cleaning up expired rate-limit entries; clear on shutdown. */
5
13
  cleanupInterval: ReturnType<typeof setInterval>;
6
14
  }
7
15
  /**
8
16
  * Creates the auth controller router.
9
17
  *
10
18
  * Routes (relative to mount point):
11
- * - POST /login — authenticate and receive JWT
19
+ * - GET /mode — public: `{ mode: 'password' | 'external', signInUrl }`
20
+ * - POST /login — authenticate and receive JWT (501 in external mode)
12
21
  * - GET /me — get current user info from token
13
22
  */
14
- export declare function createAuthController(config: AdminConfig, jwtSecret: string): AuthControllerResult;
23
+ export declare function createAuthController(config: AdminConfig, jwtSecret: string, provider?: AdminAuthProvider, isExternal?: () => boolean): AuthControllerResult;
15
24
  //# sourceMappingURL=auth-controller.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-controller.d.ts","sourceRoot":"","sources":["../../auth/auth-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAUvD,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACnD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAyFjG"}
1
+ {"version":3,"file":"auth-controller.d.ts","sourceRoot":"","sources":["../../auth/auth-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAGpD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAsD,MAAM,iBAAiB,CAAC;AAQxG,gEAAgE;AAChE,eAAO,MAAM,wBAAwB,aAAa,CAAC;AACnD,0DAA0D;AAC1D,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAKnD,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACjC,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,eAAe,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,UAAU,GAAE,MAAM,OAAqB,GACxC,oBAAoB,CAyItB"}
@@ -1,21 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ADMIN_AUTH_MODE_EXTERNAL = exports.ADMIN_AUTH_MODE_PASSWORD = void 0;
3
4
  exports.createAuthController = createAuthController;
4
5
  const express_1 = require("express");
5
6
  const jwt_service_1 = require("./jwt-service");
6
7
  const auth_middleware_1 = require("./auth-middleware");
8
+ const auth_provider_1 = require("./auth-provider");
9
+ /** Mode name for the dashboard's own username/password form. */
10
+ exports.ADMIN_AUTH_MODE_PASSWORD = 'password';
11
+ /** Mode name for sign-in through the host application. */
12
+ exports.ADMIN_AUTH_MODE_EXTERNAL = 'external';
7
13
  const MAX_ATTEMPTS = 5;
8
14
  const WINDOW_MS = 60_000; // 1 minute
9
15
  /**
10
16
  * Creates the auth controller router.
11
17
  *
12
18
  * Routes (relative to mount point):
13
- * - POST /login — authenticate and receive JWT
19
+ * - GET /mode — public: `{ mode: 'password' | 'external', signInUrl }`
20
+ * - POST /login — authenticate and receive JWT (501 in external mode)
14
21
  * - GET /me — get current user info from token
15
22
  */
16
- function createAuthController(config, jwtSecret) {
23
+ function createAuthController(config, jwtSecret, provider, isExternal = () => false) {
17
24
  const router = (0, express_1.Router)();
18
- const authMiddleware = (0, auth_middleware_1.createAuthMiddleware)(jwtSecret);
25
+ const authMiddleware = (0, auth_middleware_1.createAuthMiddleware)(jwtSecret, provider, isExternal);
19
26
  const failedAttempts = new Map();
20
27
  // Periodically clean up expired entries (every 5 minutes)
21
28
  const cleanupInterval = setInterval(() => {
@@ -30,7 +37,24 @@ function createAuthController(config, jwtSecret) {
30
37
  if (cleanupInterval.unref) {
31
38
  cleanupInterval.unref();
32
39
  }
40
+ // GET /mode — public: which sign-in the dashboard shows. `external` when the users
41
+ // plugin uses an external auth adapter (the host app signs users in and hands its
42
+ // token to the dashboard through /qcli/admin/#token=…), otherwise `password`.
43
+ router.get('/mode', (_req, res) => {
44
+ res.set('Cache-Control', 'no-store');
45
+ res.json({ mode: isExternal() ? exports.ADMIN_AUTH_MODE_EXTERNAL : exports.ADMIN_AUTH_MODE_PASSWORD, signInUrl: config.signInUrl ?? null });
46
+ });
33
47
  router.post('/login', (req, res) => {
48
+ // External sign-in mode: the static admin credentials sign no one in.
49
+ if (isExternal()) {
50
+ const where = config.signInUrl !== undefined ? ` at ${config.signInUrl}` : ' through the host application';
51
+ res.status(501).json({
52
+ error: `Sign-in is managed by the host application. Sign in${where}.`,
53
+ code: 'EXTERNAL_AUTH',
54
+ signInUrl: config.signInUrl ?? null,
55
+ });
56
+ return;
57
+ }
34
58
  const ip = req.ip ?? req.socket.remoteAddress ?? 'unknown';
35
59
  // Rate limiting
36
60
  const now = Date.now();
@@ -48,12 +72,11 @@ function createAuthController(config, jwtSecret) {
48
72
  }
49
73
  }
50
74
  const { username, password } = req.body ?? {};
51
- if (!username || !password) {
75
+ if (!username || !password || typeof username !== 'string' || typeof password !== 'string') {
52
76
  res.status(400).json({ error: 'Username and password are required' });
53
77
  return;
54
78
  }
55
- if (!config.validateCredentials(username, password)) {
56
- // Track failed attempt
79
+ const recordFailure = () => {
57
80
  const existing = failedAttempts.get(ip);
58
81
  if (existing && now - existing.firstAttemptAt <= WINDOW_MS) {
59
82
  existing.count++;
@@ -61,6 +84,36 @@ function createAuthController(config, jwtSecret) {
61
84
  else {
62
85
  failedAttempts.set(ip, { count: 1, firstAttemptAt: now });
63
86
  }
87
+ };
88
+ if (provider) {
89
+ // Users plugin installed: authenticate through it and require admin:access
90
+ provider
91
+ .login(username, password, { remoteAddress: ip, userAgent: req.headers['user-agent'] })
92
+ .then(async (result) => {
93
+ if (!provider.hasPermission(result, auth_provider_1.ADMIN_ACCESS_PERMISSION)) {
94
+ await provider.logout?.(result.token).catch(() => undefined);
95
+ res.status(403).json({ error: `forbidden: missing permission ${auth_provider_1.ADMIN_ACCESS_PERMISSION}` });
96
+ return;
97
+ }
98
+ failedAttempts.delete(ip);
99
+ res.json({
100
+ token: result.token,
101
+ expiresIn: Math.max(0, Math.floor((result.expiresAt - Date.now()) / 1000)),
102
+ username: result.userName,
103
+ mustChangePassword: !!result.mustChangePassword,
104
+ });
105
+ })
106
+ .catch((err) => {
107
+ const status = (0, auth_provider_1.errorStatus)(err);
108
+ if (status === 401)
109
+ recordFailure();
110
+ res.status(status).json({ error: (0, auth_provider_1.errorMessage)(err, 'Invalid credentials') });
111
+ });
112
+ return;
113
+ }
114
+ if (!config.validateCredentials(username, password)) {
115
+ // Track failed attempt
116
+ recordFailure();
64
117
  res.status(401).json({ error: 'Invalid credentials' });
65
118
  return;
66
119
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth-controller.js","sourceRoot":"","sources":["../../auth/auth-controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-controller.js","sourceRoot":"","sources":["../../auth/auth-controller.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { Request, RequestHandler } from 'express';
2
2
  import { JwtPayload } from './jwt-service';
3
+ import { AdminAuthProvider } from './auth-provider';
3
4
  /**
4
5
  * Extended request interface with authenticated user info.
5
6
  */
@@ -13,5 +14,5 @@ export interface AuthenticatedRequest extends Request {
13
14
  *
14
15
  * @param secret JWT secret used to verify tokens.
15
16
  */
16
- export declare function createAuthMiddleware(secret: string): RequestHandler;
17
+ export declare function createAuthMiddleware(secret: string, provider?: AdminAuthProvider, isExternal?: () => boolean): RequestHandler;
17
18
  //# sourceMappingURL=auth-middleware.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../auth/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA0B,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAe,UAAU,EAAE,MAAM,eAAe,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACjD,IAAI,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAwBnE"}
1
+ {"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../auth/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA0B,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAe,UAAU,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAsD,MAAM,iBAAiB,CAAC;AAExG;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACjD,IAAI,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,UAAU,CAAC,EAAE,MAAM,OAAO,GAAG,cAAc,CA8B7H"}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAuthMiddleware = createAuthMiddleware;
4
4
  const jwt_service_1 = require("./jwt-service");
5
+ const auth_provider_1 = require("./auth-provider");
5
6
  /**
6
7
  * Creates an Express middleware that validates JWT Bearer tokens.
7
8
  *
@@ -9,7 +10,13 @@ const jwt_service_1 = require("./jwt-service");
9
10
  *
10
11
  * @param secret JWT secret used to verify tokens.
11
12
  */
12
- function createAuthMiddleware(secret) {
13
+ function createAuthMiddleware(secret, provider, isExternal) {
14
+ if (provider) {
15
+ const sessions = createProviderAuthMiddleware(provider);
16
+ const host = provider.authenticateRequest ? createHostSessionMiddleware(provider) : undefined;
17
+ // External sign-in mode: the dashboard sends the host application's own bearer token.
18
+ return (req, res, next) => (host && isExternal?.() ? host : sessions)(req, res, next);
19
+ }
13
20
  return (req, res, next) => {
14
21
  // Skip auth for login endpoint
15
22
  if (req.path === '/auth/login') {
@@ -32,4 +39,60 @@ function createAuthMiddleware(secret) {
32
39
  }
33
40
  };
34
41
  }
42
+ /**
43
+ * Auth middleware for external sign-in mode: the provider authenticates the request
44
+ * as any other request from the host app (its external auth adapter), and the user
45
+ * needs `admin:access`.
46
+ */
47
+ function createHostSessionMiddleware(provider) {
48
+ return (req, res, next) => {
49
+ provider.authenticateRequest(req).then((ctx) => {
50
+ if (!provider.hasPermission(ctx, auth_provider_1.ADMIN_ACCESS_PERMISSION)) {
51
+ res.status(403).json({ error: `forbidden: missing permission ${auth_provider_1.ADMIN_ACCESS_PERMISSION}` });
52
+ return;
53
+ }
54
+ req.user = { username: ctx.userName, authenticatedAt: new Date().toISOString() };
55
+ next();
56
+ }, (err) => {
57
+ const status = err?.status;
58
+ if (typeof status !== 'number') {
59
+ // not an auth error (e.g. a failing adapter): log it, never expose its message
60
+ console.error('[qcli-admin] authentication failed unexpectedly:', err);
61
+ res.status(500).json({ error: 'internal server error' });
62
+ return;
63
+ }
64
+ res.status(status).json({ error: (0, auth_provider_1.errorMessage)(err, 'Not authenticated') });
65
+ });
66
+ };
67
+ }
68
+ /**
69
+ * Auth middleware backed by the users plugin: a users session token with the
70
+ * `admin:access` permission (and no pending password change).
71
+ */
72
+ function createProviderAuthMiddleware(provider) {
73
+ return (req, res, next) => {
74
+ const authHeader = req.headers.authorization;
75
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
76
+ res.status(401).json({ error: 'Missing or invalid Authorization header' });
77
+ return;
78
+ }
79
+ provider.authenticateToken(authHeader.slice(7)).then((ctx) => {
80
+ if (ctx.mustChangePassword) {
81
+ res.status(403).json({ error: 'password change required' });
82
+ return;
83
+ }
84
+ if (!provider.hasPermission(ctx, auth_provider_1.ADMIN_ACCESS_PERMISSION)) {
85
+ res.status(403).json({ error: `forbidden: missing permission ${auth_provider_1.ADMIN_ACCESS_PERMISSION}` });
86
+ return;
87
+ }
88
+ req.user = {
89
+ username: ctx.userName,
90
+ authenticatedAt: new Date(ctx.loginTime ?? Date.now()).toISOString(),
91
+ };
92
+ next();
93
+ }, (err) => {
94
+ res.status((0, auth_provider_1.errorStatus)(err)).json({ error: (0, auth_provider_1.errorMessage)(err, 'Invalid or expired token') });
95
+ });
96
+ };
97
+ }
35
98
  //# sourceMappingURL=auth-middleware.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../auth/auth-middleware.ts"],"names":[],"mappings":";;AAiBA,oDAwBC;AAxCD,+CAAwD;AASxD;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,MAAc;IAC/C,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC7D,+BAA+B;QAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC7B,IAAI,EAAE,CAAC;YACP,OAAO;QACX,CAAC;QAED,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAC7C,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC,CAAC;YAC3E,OAAO;QACX,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAElC,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,IAAA,yBAAW,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC1C,GAA4B,CAAC,IAAI,GAAG,OAAO,CAAC;YAC7C,IAAI,EAAE,CAAC;QACX,CAAC;QAAC,MAAM,CAAC;YACL,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;QAChE,CAAC;IACL,CAAC,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../auth/auth-middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * External authentication for the admin dashboard — implemented by the users
3
+ * plugin (`usersPlugin.serverAuth`). When set, the dashboard logs in through
4
+ * it and requires the `admin:access` permission; the static admin
5
+ * credentials are not used.
6
+ */
7
+ export interface AdminAuthProvider {
8
+ login(username: string, password: string, metadata?: {
9
+ remoteAddress?: string;
10
+ userAgent?: string;
11
+ }): Promise<{
12
+ token: string;
13
+ userName: string;
14
+ permissions: string[];
15
+ expiresAt: number;
16
+ mustChangePassword?: boolean;
17
+ }>;
18
+ authenticateToken(token: string): Promise<{
19
+ userName: string;
20
+ permissions: string[];
21
+ mustChangePassword?: boolean;
22
+ loginTime?: number;
23
+ }>;
24
+ logout?(token: string): Promise<void>;
25
+ /**
26
+ * Authenticates a whole request (session token or, with an external auth adapter,
27
+ * the host application's own session). Used in external sign-in mode, where the
28
+ * dashboard sends the host's bearer token.
29
+ */
30
+ authenticateRequest?(req: import('express').Request): Promise<{
31
+ userName: string;
32
+ permissions: string[];
33
+ }>;
34
+ hasPermission(ctx: {
35
+ permissions: string[];
36
+ }, permission: string): boolean;
37
+ }
38
+ export declare const ADMIN_ACCESS_PERMISSION = "admin:access";
39
+ /** Status of an error thrown by the provider (defaults to 401). */
40
+ export declare function errorStatus(err: unknown): number;
41
+ export declare function errorMessage(err: unknown, fallback: string): string;
42
+ //# sourceMappingURL=auth-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.d.ts","sourceRoot":"","sources":["../../auth/auth-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAC9B,KAAK,CACD,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC1D,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzI,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC;;;;OAIG;IACH,mBAAmB,CAAC,CAAC,GAAG,EAAE,OAAO,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC3G,aAAa,CAAC,GAAG,EAAE;QAAE,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9E;AAED,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAEtD,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGhD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGnE"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ADMIN_ACCESS_PERMISSION = void 0;
4
+ exports.errorStatus = errorStatus;
5
+ exports.errorMessage = errorMessage;
6
+ exports.ADMIN_ACCESS_PERMISSION = 'admin:access';
7
+ /** Status of an error thrown by the provider (defaults to 401). */
8
+ function errorStatus(err) {
9
+ const status = err?.status;
10
+ return typeof status === 'number' ? status : 401;
11
+ }
12
+ function errorMessage(err, fallback) {
13
+ const message = err?.message;
14
+ return typeof message === 'string' && message ? message : fallback;
15
+ }
16
+ //# sourceMappingURL=auth-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.js","sourceRoot":"","sources":["../../auth/auth-provider.ts"],"names":[],"mappings":";;;AA0BA,kCAGC;AAED,oCAGC;AAXY,QAAA,uBAAuB,GAAG,cAAc,CAAC;AAEtD,mEAAmE;AACnE,SAAgB,WAAW,CAAC,GAAY;IACpC,MAAM,MAAM,GAAI,GAA4B,EAAE,MAAM,CAAC;IACrD,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACrD,CAAC;AAED,SAAgB,YAAY,CAAC,GAAY,EAAE,QAAgB;IACvD,MAAM,OAAO,GAAI,GAA6B,EAAE,OAAO,CAAC;IACxD,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvE,CAAC"}
@@ -1,15 +1,25 @@
1
+ /** JWT token payload containing user identity and authentication timestamp. */
1
2
  export interface JwtPayload {
2
3
  username: string;
3
4
  authenticatedAt: string;
4
5
  [key: string]: unknown;
5
6
  }
6
7
  /**
7
- * Sign a JWT token.
8
+ * Sign a JWT token with the given payload and secret.
9
+ *
10
+ * @param payload - Claims to include in the token.
11
+ * @param secret - HMAC secret used for signing.
12
+ * @param expiresIn - Token lifetime (e.g. '24h' or seconds).
13
+ * @returns The signed JWT string.
8
14
  */
9
15
  export declare function signToken(payload: JwtPayload, secret: string, expiresIn?: string | number): string;
10
16
  /**
11
17
  * Verify and decode a JWT token.
12
- * Returns the decoded payload, or throws on invalid/expired tokens.
18
+ *
19
+ * @param token - The JWT string to verify.
20
+ * @param secret - HMAC secret used during signing.
21
+ * @returns The decoded payload.
22
+ * @throws If the token is invalid or expired.
13
23
  */
14
24
  export declare function verifyToken(token: string, secret: string): JwtPayload;
15
25
  //# sourceMappingURL=jwt-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-service.d.ts","sourceRoot":"","sources":["../../auth/jwt-service.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,SAAS,CACrB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAM,GAAG,MAAc,GACnC,MAAM,CAKR;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf,UAAU,CAEZ"}
1
+ {"version":3,"file":"jwt-service.d.ts","sourceRoot":"","sources":["../../auth/jwt-service.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACrB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAM,GAAG,MAAc,GACnC,MAAM,CAKR;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACf,UAAU,CAEZ"}
@@ -37,7 +37,12 @@ exports.signToken = signToken;
37
37
  exports.verifyToken = verifyToken;
38
38
  const jwt = __importStar(require("jsonwebtoken"));
39
39
  /**
40
- * Sign a JWT token.
40
+ * Sign a JWT token with the given payload and secret.
41
+ *
42
+ * @param payload - Claims to include in the token.
43
+ * @param secret - HMAC secret used for signing.
44
+ * @param expiresIn - Token lifetime (e.g. '24h' or seconds).
45
+ * @returns The signed JWT string.
41
46
  */
42
47
  function signToken(payload, secret, expiresIn = '24h') {
43
48
  const options = {
@@ -47,7 +52,11 @@ function signToken(payload, secret, expiresIn = '24h') {
47
52
  }
48
53
  /**
49
54
  * Verify and decode a JWT token.
50
- * Returns the decoded payload, or throws on invalid/expired tokens.
55
+ *
56
+ * @param token - The JWT string to verify.
57
+ * @param secret - HMAC secret used during signing.
58
+ * @returns The decoded payload.
59
+ * @throws If the token is invalid or expired.
51
60
  */
52
61
  function verifyToken(token, secret) {
53
62
  return jwt.verify(token, secret);
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-service.js","sourceRoot":"","sources":["../../auth/jwt-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,8BASC;AAMD,kCAKC;AA/BD,kDAAoC;AAQpC;;GAEG;AACH,SAAgB,SAAS,CACrB,OAAmB,EACnB,MAAc,EACd,YAA6B,KAAK;IAElC,MAAM,OAAO,GAAoB;QAC7B,SAAS,EAAE,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,SAA0C;KACrG,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CACvB,KAAa,EACb,MAAc;IAEd,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAe,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"jwt-service.js","sourceRoot":"","sources":["../../auth/jwt-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,8BASC;AAUD,kCAKC;AAzCD,kDAAoC;AASpC;;;;;;;GAOG;AACH,SAAgB,SAAS,CACrB,OAAmB,EACnB,MAAc,EACd,YAA6B,KAAK;IAElC,MAAM,OAAO,GAAoB;QAC7B,SAAS,EAAE,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,SAA0C;KACrG,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,WAAW,CACvB,KAAa,EACb,MAAc;IAEd,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAe,CAAC;AACnD,CAAC"}