@preventive/triage 1.0.0-alpha.44 → 1.0.0-alpha.46

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 (207) hide show
  1. package/client/linked-findings.js +3 -0
  2. package/common/bundle-metadata.d.ts +1 -0
  3. package/common/bundle-metadata.js +1 -1
  4. package/common/bundle-sources.js +25 -2
  5. package/common/default-scan-models.ts +1 -1
  6. package/common/dependency-reviews.d.ts +0 -5
  7. package/common/dependency-reviews.js +0 -17
  8. package/common/line-diff.js +5 -4
  9. package/common/managed/agent-tasks.ts +292 -0
  10. package/common/managed/github-agents.ts +92 -0
  11. package/common/managed/github-logins.ts +49 -0
  12. package/common/managed/roles.ts +7 -0
  13. package/common/managed/routes.js +88 -7
  14. package/common/managed/team-app.d.ts +5 -2
  15. package/common/managed/team-app.js +2 -2
  16. package/common/server-info.ts +3 -0
  17. package/common/workspace-app.js +6 -3
  18. package/out/brotli-fallback.js +3 -3
  19. package/out/chunk-2XUEZHIP.js +18 -18
  20. package/out/chunk-2ZDZWLFY.js +1 -0
  21. package/out/chunk-3PS4KWD2.js +10 -0
  22. package/out/chunk-4HI2MSAV.js +17 -0
  23. package/out/chunk-4UFAMJAX.js +1 -0
  24. package/out/chunk-7C7DWL7I.js +1 -0
  25. package/out/chunk-7XRR4OFU.js +1 -0
  26. package/out/chunk-BC2UCLFJ.js +1 -0
  27. package/out/chunk-BOIXMUU5.js +3 -0
  28. package/out/chunk-C4Z6ZBXV.js +6 -6
  29. package/out/chunk-CC4OM6TZ.js +3 -0
  30. package/out/chunk-G24A42V6.js +2 -0
  31. package/out/chunk-GDPCLSOS.js +2 -0
  32. package/out/chunk-GO7FT4OD.js +1 -0
  33. package/out/chunk-I2MDGSQX.js +3 -0
  34. package/out/chunk-IYPY47MC.js +1 -0
  35. package/out/chunk-IZ7POWI3.js +18 -0
  36. package/out/chunk-JCIIBLKR.js +1 -1
  37. package/out/chunk-JKGQ3O7O.js +6 -0
  38. package/out/chunk-LE5ZWLG4.js +235 -0
  39. package/out/chunk-MSION3G4.js +36 -0
  40. package/out/chunk-NRPC74AM.js +1 -1
  41. package/out/chunk-OKRLLE5I.js +17 -0
  42. package/out/chunk-OOJM4CTU.js +1 -1
  43. package/out/chunk-PNHBZGDD.js +1 -1
  44. package/out/chunk-PXK7EU4V.js +1 -0
  45. package/out/chunk-QB4CBOX2.js +1 -0
  46. package/out/chunk-R3NZFXVR.js +1 -0
  47. package/out/chunk-R5O6FAW4.js +1 -1
  48. package/out/chunk-S6GIXWQW.js +52 -0
  49. package/out/chunk-SXV2T5C4.js +80 -0
  50. package/out/chunk-TUII34K2.js +1 -1
  51. package/out/chunk-V3KWNNMY.js +1 -0
  52. package/out/chunk-VFWMQ3LG.js +2 -0
  53. package/out/chunk-VH4XMZIW.js +2 -0
  54. package/out/chunk-WFYLMF6Z.js +10 -0
  55. package/out/chunk-WQ74ZBZF.js +7 -0
  56. package/out/client-managed-import.js +3 -3
  57. package/out/client-managed.js +31 -35
  58. package/out/client-sync.js +11 -11
  59. package/out/compare.js +35 -0
  60. package/out/dialogs.js +51 -0
  61. package/out/github-issue-authorized.html +1 -1
  62. package/out/github-issue-authorized.js +1 -1
  63. package/out/graph.js +17 -17
  64. package/out/index.html +30 -34
  65. package/out/prism.js +14 -14
  66. package/out/scan.js +2 -0
  67. package/out/terminal.js +294 -293
  68. package/out/view.css +1 -1
  69. package/out/view.js +16 -107
  70. package/package.json +53 -6
  71. package/risk/actions/findings.js +161 -0
  72. package/risk/actions/resolve.js +219 -0
  73. package/risk/actions/scripts/commands.js +182 -0
  74. package/risk/actions/scripts/grade.js +113 -0
  75. package/risk/actions/scripts/packages.js +123 -0
  76. package/risk/actions/scripts/shell.js +169 -0
  77. package/risk/actions/uses.js +76 -0
  78. package/risk/actions/workflow.js +110 -0
  79. package/risk/files/hosts.js +6 -6
  80. package/risk/files/readability.js +23 -17
  81. package/risk/files/runs-code.js +18 -6
  82. package/risk/files/script.js +7 -3
  83. package/risk/files/stamps.js +8 -7
  84. package/risk/index.d.ts +71 -1
  85. package/risk/index.js +6 -2
  86. package/risk/npm/assess.js +1 -1
  87. package/risk/npm/compare.js +34 -10
  88. package/risk/npm/files.js +413 -2
  89. package/risk/npm/tarball.js +56 -73
  90. package/server-e2e/app.ts +5 -4
  91. package/server-e2e/http.ts +5 -2
  92. package/server-managed/agent-merges.ts +198 -0
  93. package/server-managed/app-agents.ts +30 -0
  94. package/server-managed/avatar-store.ts +1 -0
  95. package/server-managed/bundle-cache.ts +7 -1
  96. package/server-managed/combined.ts +3 -2
  97. package/server-managed/commit-coauthors.ts +83 -0
  98. package/server-managed/commit-lockfiles.ts +72 -0
  99. package/server-managed/config.ts +6 -0
  100. package/server-managed/db-methods.ts +66 -19
  101. package/server-managed/db-neon.ts +89 -21
  102. package/server-managed/db-schema.ts +13 -2
  103. package/server-managed/db.ts +9 -1
  104. package/server-managed/dependabot-access.ts +60 -0
  105. package/server-managed/dependabot-alerts.ts +185 -0
  106. package/server-managed/dependency-review-comments.ts +97 -0
  107. package/server-managed/dependency-reviews.ts +78 -18
  108. package/server-managed/github-accounts.ts +33 -0
  109. package/server-managed/github-actions.ts +71 -0
  110. package/server-managed/github-app.ts +33 -13
  111. package/server-managed/github-errors.ts +2 -0
  112. package/server-managed/github-issue-links.ts +11 -5
  113. package/server-managed/github-link-oauth.ts +69 -0
  114. package/server-managed/github-links.ts +204 -0
  115. package/server-managed/github-oauth.ts +5 -2
  116. package/server-managed/github-pulls.ts +2 -2
  117. package/server-managed/github-requests.ts +39 -0
  118. package/server-managed/github-users.ts +30 -0
  119. package/server-managed/http-response.ts +10 -2
  120. package/server-managed/http.ts +1251 -97
  121. package/server-managed/index.ts +13 -8
  122. package/server-managed/kept-briefly.ts +37 -0
  123. package/server-managed/locked-packages.ts +37 -16
  124. package/server-managed/lockfile-scope.ts +49 -0
  125. package/server-managed/npm-delta-worker.js +23 -0
  126. package/server-managed/npm-delta.ts +178 -0
  127. package/server-managed/npm-insights.ts +20 -11
  128. package/server-managed/npm-kept.ts +83 -6
  129. package/server-managed/npm-loads.ts +114 -37
  130. package/server-managed/npm-packages.ts +110 -64
  131. package/server-managed/npm-risk.ts +4 -1
  132. package/server-managed/pretty-print.ts +67 -23
  133. package/server-managed/pull-comment-reviews.ts +161 -0
  134. package/server-managed/pull-dependencies.ts +300 -0
  135. package/server-managed/pull-dependency-reviews.ts +318 -0
  136. package/server-managed/pull-reviews.ts +205 -0
  137. package/server-managed/queue.ts +16 -0
  138. package/server-managed/release-commits.ts +84 -0
  139. package/server-managed/rename-diff.ts +22 -13
  140. package/server-managed/report-sources.ts +1 -1
  141. package/server-managed/report-store.ts +42 -9
  142. package/server-managed/repository-actions.ts +218 -0
  143. package/server-managed/repository-agents.ts +220 -0
  144. package/server-managed/repository-browser.ts +166 -37
  145. package/server-managed/repository-changes.ts +284 -0
  146. package/server-managed/repository-code.ts +52 -0
  147. package/server-managed/repository-dependency-reviews.ts +157 -0
  148. package/server-managed/repository-history.ts +461 -0
  149. package/server-managed/repository-issues.ts +181 -0
  150. package/server-managed/repository-pulse.ts +439 -0
  151. package/server-managed/repository-risk-audit.ts +13 -0
  152. package/server-managed/repository-risk-read.ts +170 -0
  153. package/server-managed/repository-risk.ts +133 -118
  154. package/server-managed/reviewed-dependencies.ts +149 -0
  155. package/server-managed/session.ts +27 -9
  156. package/server-managed/sql.ts +6 -3
  157. package/server-managed/storage-stores.ts +5 -0
  158. package/server-managed/storage.ts +4 -2
  159. package/server-managed/team-app.ts +19 -3
  160. package/server-managed/team-reports.ts +24 -12
  161. package/server-managed/upstream-cache.ts +12 -0
  162. package/server-managed/workspace-shares.ts +4 -1
  163. package/server.ts +25 -5
  164. package/out/chunk-2ABLKCOY.js +0 -46
  165. package/out/chunk-2KBF5TZ7.js +0 -2
  166. package/out/chunk-35VE6CDH.js +0 -2
  167. package/out/chunk-3BZ7JERB.js +0 -1
  168. package/out/chunk-4XCDFGDP.js +0 -10
  169. package/out/chunk-5LSXOLUS.js +0 -1
  170. package/out/chunk-5RCM2J63.js +0 -1
  171. package/out/chunk-7B6HB4D7.js +0 -1
  172. package/out/chunk-AJ4GTATZ.js +0 -3
  173. package/out/chunk-CH4UN6WK.js +0 -225
  174. package/out/chunk-CMQA4DM6.js +0 -1
  175. package/out/chunk-CVVJAXVY.js +0 -2
  176. package/out/chunk-DIJJNTRH.js +0 -10
  177. package/out/chunk-EDKLBQQN.js +0 -17
  178. package/out/chunk-F47DXCEV.js +0 -33
  179. package/out/chunk-FK3DZEKL.js +0 -1
  180. package/out/chunk-G6AJWENO.js +0 -1
  181. package/out/chunk-GJ4IUCNS.js +0 -1
  182. package/out/chunk-GNXOKIGP.js +0 -80
  183. package/out/chunk-GZ4MS3TE.js +0 -13
  184. package/out/chunk-GZWM7UQM.js +0 -2
  185. package/out/chunk-IU3CCINR.js +0 -3
  186. package/out/chunk-K3X5EJBQ.js +0 -2
  187. package/out/chunk-KEX2ATEW.js +0 -2
  188. package/out/chunk-KYCNJVB7.js +0 -1
  189. package/out/chunk-LPCTJYNA.js +0 -7
  190. package/out/chunk-O4RJY5TP.js +0 -2
  191. package/out/chunk-OD4LPN3H.js +0 -1
  192. package/out/chunk-QWDWTBM7.js +0 -1
  193. package/out/chunk-QYWKC557.js +0 -1
  194. package/out/chunk-R75XOKUP.js +0 -1
  195. package/out/chunk-SWTLADW5.js +0 -1
  196. package/out/chunk-T7OKH4VW.js +0 -1
  197. package/out/chunk-TZ5KB2Y5.js +0 -10
  198. package/out/chunk-UNTRGE26.js +0 -2
  199. package/out/chunk-UTR2LVME.js +0 -2
  200. package/out/chunk-UYAXVRVL.js +0 -1
  201. package/out/chunk-V3ME6FI5.js +0 -2
  202. package/out/chunk-V5O7M2YT.js +0 -1
  203. package/out/chunk-VIHGO77Y.js +0 -1
  204. package/out/chunk-W4J3MGLB.js +0 -1
  205. package/out/chunk-WGG7KQUH.js +0 -1
  206. package/out/chunk-XYFXXB2G.js +0 -10
  207. package/out/chunk-ZESLQCTF.js +0 -6
@@ -1,37 +1,33 @@
1
- import{a as ys,b as ws,c as oe,d as ht,e as mt,f as gt,g as $s,h as ks,i as xs,j as Rs,k as Ss,l as Cs,m as Es,n as As,o as Ts,p as ft,q as Is,r as Ns,s as Ls,t as Os}from"./chunk-5LSXOLUS.js";import{a as g,b as Ui,c as Fi,d as ji}from"./chunk-KYCNJVB7.js";import{a as be,b as P,c as qi,d as m}from"./chunk-IU3CCINR.js";import{A as $t,S as ne,b as ve,c as q,e as G,f as ut,g as bt,j as vt,m as _e,n as _t,y as wt}from"./chunk-2ABLKCOY.js";import{v as yt}from"./chunk-ZESLQCTF.js";import{a as pt,c as ae}from"./chunk-UYAXVRVL.js";import{a as w,b as y,c as f}from"./chunk-35VE6CDH.js";import{b as ct}from"./chunk-NRPC74AM.js";import"./chunk-PNHBZGDD.js";import"./chunk-V3ME6FI5.js";import{a as U}from"./chunk-R75XOKUP.js";import"./chunk-OD4LPN3H.js";import{a as kt}from"./chunk-4XCDFGDP.js";import"./chunk-3BZ7JERB.js";import"./chunk-TZ5KB2Y5.js";import"./chunk-XYFXXB2G.js";import{a as re}from"./chunk-DIJJNTRH.js";import{f as dt,j as H}from"./chunk-QYWKC557.js";import{B as nt,D as se,J as lt}from"./chunk-GNXOKIGP.js";import"./chunk-C4Z6ZBXV.js";import{a as h,b as rt,c as a,d as ie,g as d,j as M}from"./chunk-2XUEZHIP.js";import"./chunk-TUII34K2.js";import{b as st,s as at,t as ot}from"./chunk-V5O7M2YT.js";import"./chunk-OOJM4CTU.js";var b=class extends M{static properties={session:{attribute:!1},allowShare:{attribute:!1},_loading:{state:!0}};constructor(){super(),this.session=null,this.allowShare=!1,this.appState=g,this._loading=!1,this._loadRequest=null}get _role(){return this.session?.role??null}get _csrf(){return this.session?.csrfToken??null}get _me(){return this.session?.id??null}disconnectedCallback(){this._loadRequest?.abort(),super.disconnectedCallback()}async _loadCollection(e,t,i,r){this._loadRequest?.abort();let o=new AbortController;this._loadRequest=o,this._loading=!0;try{await this.appState.load(e,t,i,{signal:o.signal,apply:r})}catch(n){!o.signal.aborted&&n?.name!=="AbortError"&&this.appState.read(e)===void 0&&(this._error=String(n?.message??n))}finally{this._loadRequest===o&&(this._loading=!1)}}};function k(s){return a`<div class="loading-rows" role="status"><span class="sr-only">${s}</span><div aria-hidden="true">${[0,1,2,3].map(()=>a`<div class="loading-row"><span></span><span></span></div>`)}</div></div>`}var ye=class extends G{get changeEvent(){return"local-item-change"}get searchLabel(){return"Search local files"}get optionsLabel(){return"Local files"}get noMatchesLabel(){return"No matching files."}get emptyLabel(){return"No local files available."}choices(){let e=this._query.trim().toLocaleLowerCase(),t=this.options.filter(i=>`${i.label} ${i.secondary??""}`.toLocaleLowerCase().includes(e));return{pinned:[],sections:[{options:t}],count:t.length,total:this.options.length,showFacets:!1}}};customElements.define("managed-local-item-selector",ye);var K=class{constructor(e,t,i){this.host=e,this.kind=t,this.upload=i,this.source=null,this.hasData=!1,this.open=!1,this.options=[],this.value=null,this.busy=!1,this.loading=!1,this.error="",this.success="",this.generation=0,this.readAbort=null,this.onChange=r=>{if(r?.kind){if(r.kind!==this.kind)return;if(r.value!==this.value){this.refresh();return}}this.readAbort&&!this.readAbort.signal.aborted&&(this.readAbort.abort(),this.error=`The local ${this.kind} changed or the list was refreshed. Select it again before importing.`),this.options=[],this.value=null,this.success="",this.refresh()},this.onBlur=()=>{this.readAbort&&!this.readAbort.signal.aborted&&this.onChange()},this.onVisibilityChange=()=>{globalThis.document?.visibilityState==="hidden"&&this.onBlur()},e.addController(this)}hostConnected(){globalThis.addEventListener("focus",this.onChange),globalThis.addEventListener("blur",this.onBlur),globalThis.addEventListener("storage",this.onChange),globalThis.document?.addEventListener("visibilitychange",this.onVisibilityChange),this.connectSource()}hostUpdated(){this.connectSource()}connectSource(){this.source!==this.host.localImportSource&&(this.unsubscribe?.(),this.abort?.abort(),this.source=this.host.localImportSource,this.unsubscribe=this.source?.subscribe(this.onChange),this.onChange())}hostDisconnected(){++this.generation,this.abort?.abort(),this.unsubscribe?.(),this.source=null,globalThis.removeEventListener("focus",this.onChange),globalThis.removeEventListener("blur",this.onBlur),globalThis.removeEventListener("storage",this.onChange),globalThis.document?.removeEventListener("visibilitychange",this.onVisibilityChange)}async refresh(){let e=++this.generation,t=this.source;this.loading=!0,this.host.requestUpdate();try{let i=t?await t.hasData(this.kind):!1;if(e!==this.generation)return;this.hasData=i;let r=this.open&&!t?.locked?await t?.list(this.kind)??[]:[];if(e!==this.generation)return;this.options=r,r.some(o=>o.value===this.value)||(this.value=null)}catch(i){e===this.generation&&(this.error=String(i?.message??i))}finally{e===this.generation&&(this.loading=!1,this.host.requestUpdate())}}toggle(){this.busy||(this.open=!this.open,this.error="",this.success="",this.options=[],this.value=null,this.refresh())}async unlock(){if(this.busy)return;this.busy=!0,this.error="";let e=this.abort=new AbortController;this.host.requestUpdate();try{await this.source.unlock({signal:e.signal})&&!e.signal.aborted&&await this.refresh()}catch(t){e.signal.aborted||(this.error=String(t?.message??t))}finally{this.busy=!1,this.host.requestUpdate()}}async importSelected(){if(this.busy||this.loading||!this.value||this.source?.locked)return;this.busy=!0,this.error="",this.success="";let e=this.options.find(i=>i.value===this.value)?.label,t=this.abort=new AbortController;this.readAbort=t,this.host.requestUpdate();try{await this.source.importItem(this.kind,this.value,i=>(this.readAbort=null,this.upload(i)),{signal:t.signal}),!t.signal.aborted&&!this.source?.locked&&(this.success=`Imported ${e}.`,this.value=null)}catch(i){t.signal.aborted||(this.error=String(i?.message??i))}finally{this.readAbort===t&&(this.readAbort=null),this.busy=!1,this.host.requestUpdate()}}renderAction(){return this.hasData||this.open?a`<button type="button" class="local-import-toggle" aria-expanded="${this.open}" aria-controls="local-import-panel" ?disabled="${this.busy}" @click="${()=>this.toggle()}">Import</button>`:d}renderPanel(e){if(!this.open)return d;let t=this.source?.locked;return a`<section class="local-import-panel" id="local-import-panel" aria-label="${`Import local ${this.kind}`}"><div class="local-import-copy"><strong>Import local ${this.kind}</strong><p>${t?"Unlock local data with your passkey to choose a file.":"Copy a file from this browser to the managed workspace. The local copy stays on this device."}</p></div><div class="local-import-controls">${t?a`<button type="button" class="local-import-submit" ?disabled="${this.busy}" @click="${()=>this.unlock()}">${this.busy?"Waiting for passkey\u2026":"Unlock with passkey"}</button>`:a`<managed-local-item-selector label="${`Choose local ${this.kind}`}" placeholder="${this.loading?"Loading local files\u2026":`Choose local ${this.kind}\u2026`}" .options="${this.options}" .value="${this.value}" ?disabled="${this.busy||this.loading}" @local-item-change="${i=>{this.value=i.detail.value,this.success="",this.host.requestUpdate()}}"></managed-local-item-selector><button type="button" class="local-import-submit" ?disabled="${e||this.busy||this.loading||!this.value}" @click="${()=>this.importSelected()}">${this.busy?"Importing\u2026":`Import ${this.kind}`}</button>`} <button type="button" class="local-import-close" ?disabled="${this.busy}" @click="${()=>this.toggle()}">Close</button></div>${!t&&!this.loading&&this.options.length===0?a`<p class="local-import-message">No local ${this.kind}s available.</p>`:d} ${this.error?a`<p class="local-import-message error" role="alert">${this.error} <button type="button" ?disabled="${this.busy}" @click="${()=>{this.error="",this.refresh()}}">Retry</button></p>`:d} ${this.success?a`<p class="local-import-message" role="status">${this.success}</p>`:d}</section>`}};async function Hi({signal:s}={}){s=s?AbortSignal.any([s,g.sessionController.signal]):g.sessionController.signal,s.throwIfAborted();let e=await m("/api/admin/bundles",{credentials:"same-origin",signal:s});if(s.throwIfAborted(),!e.ok)throw Object.assign(new Error(`Bundle catalogue request failed (${e.status})`),{status:e.status});let t=await e.json();return s.throwIfAborted(),t.bundles??[]}async function le(s,e,t){let i=g.generation,r=await m(`/api/bundles/${encodeURIComponent(s)}/${e}`,{credentials:"same-origin",signal:t});if(t?.throwIfAborted(),!r.ok)throw Object.assign(new Error(`Bundle ${e} request failed (${r.status})`),{status:r.status});let o=e==="contents"?await r.text():await r.json();if(t?.throwIfAborted(),i!==g.generation)throw new DOMException("Managed session changed","AbortError");return o}function we(s,{signal:e}={}){return g.load(`bundle-metadata:${s}`,"bundle metadata",t=>le(s,"metadata",t),{signal:e,retryInvalidated:!0})}async function xt(s,{signal:e}={}){e=e?AbortSignal.any([e,g.sessionController.signal]):g.sessionController.signal;let t=await le(s,"metadata",e),i=t?.bundle?.repo??null,r=se({repo:i});if(!r)return i;let o=new URLSearchParams({repo:r,directory:i.directory??""}),n=new Set(t.unsized??[]),l=ct((t.files??[]).filter(([u,v])=>v!=null||n.has(u)).map(([u])=>u));l&&o.set("filePrefix",l);let c=await m(`/api/admin/repositories/resolve?${o}`,{credentials:"same-origin",cache:"no-store",signal:e});if(e.throwIfAborted(),!c.ok)throw new Error(`Repository suggestion request failed (${c.status})`);let{location:p}=await c.json();return e.throwIfAborted(),p?{...i,github:p.github,...p.mapped?{directory:p.directory}:{},repoId:p.repoId}:i}async function Gi(s,{signal:e}={}){e=e?AbortSignal.any([e,g.sessionController.signal]):g.sessionController.signal;try{return await le(s,"contents",e)}catch(t){throw t.name!=="AbortError"&&g.notify(`Couldn't load bundle contents: ${t.message}`),t}}function Ki(s,e,t="",i=!1,r=!1){let o=[e?`team=${encodeURIComponent(e)}`:"",t?`reason=${encodeURIComponent(t)}`:"",i?"repoAdvisories=true":"",r?"details=true":""].filter(Boolean).join("&"),n=`advisories${o?`?${o}`:""}`;return le(s,n,g.sessionController.signal)}var D={400:"Not an npm package name and version.",404:"No such package version, or it is not available to you.",413:"This package is too large to open here.",429:"Too many packages are loading. Try again shortly.",502:"The npm registry couldn't be reached."};async function C(s,e,t,i){i=i?AbortSignal.any([i,g.sessionController.signal]):g.sessionController.signal;let r=g.generation,o=await m(s,{credentials:"same-origin",signal:i});if(i.throwIfAborted(),!o.ok){let l=(await o.json().catch(()=>null))?.error??null;throw Object.assign(new Error(e[l]??e[o.status]??`Request failed (${o.status})`),{status:o.status,code:l})}let n=await t(o);if(i.throwIfAborted(),r!==g.generation)throw new DOMException("Managed session changed","AbortError");return n}var T=(s,e,t)=>C(`/api/npm/${s}?${new URLSearchParams(e)}`,D,i=>i.json(),t);function Vi(s,e,{signal:t}={}){return T("package",{name:s,version:e},t)}function Wi(s,{signal:e}={}){return T("versions",{name:s},e)}function Ji(s,{signal:e}={}){return T("stats",{name:s},e)}function Yi(s,{signal:e}={}){return T("advisories",{name:s},e)}function Xi(s,e,{signal:t}={}){return T("tags",{name:s,version:e},t)}function Zi(s,e,{signal:t}={}){return T("socket",{name:s,version:e},t)}function Qi(s,e,t=null,{signal:i}={}){return T("risk",{name:s,version:e,...t===null?{}:{otherVersion:t}},i)}function er(s,e,{signal:t}={}){return T("provenance",{name:s,version:e},t)}var z={404:"This file is no longer available.",409:"This file has changed since it was opened.",413:"This file is too large to pretty-print.",422:"This file couldn't be read as code.","pretty-mismatch":"Pretty-printing would change more than its layout, so it is shown as published.",unsupported:"This kind of file can't be checked once pretty-printed, so it is shown as published.",429:"Too many files are being pretty-printed. Try again shortly.",502:"The npm registry couldn't be reached."};function tr(s,e,t,{signal:i}={}){return C(`/api/bundles/${encodeURIComponent(s)}/pretty?${new URLSearchParams({path:e,hash:t})}`,z,Rt,i)}function ir(s,e,t,i,{signal:r}={}){return C(`/api/npm/pretty?${new URLSearchParams({name:s,version:e,path:t,hash:i})}`,{...D,...z},Rt,r)}var Rt=async s=>({text:await s.text(),source:s.headers.get("x-source-hash")});async function*$e(s){let e=s.body.pipeThrough(new TextDecoderStream).getReader(),t=[];for(;;){let{done:i,value:r}=await e.read();if(i)return;let o=0;for(let n=r.indexOf(`
2
- `);n!==-1;o=n+1,n=r.indexOf(`
3
- `,o))t.push(r.slice(o,n)),yield JSON.parse(t.join("")),t=[];t.push(r.slice(o))}}function rr(s,e,t,{signal:i}={}){return B(`/api/npm/pretty?${new URLSearchParams({name:s,version:e})}`,D,t,i)}function sr(s,e,t,{signal:i}={}){return B(`/api/bundles/${encodeURIComponent(s)}/pretty?${new URLSearchParams({other:e})}`,z,t,i)}function ar(s,e,t,i,{signal:r}={}){return B(`/api/npm/pretty?${new URLSearchParams({name:s,version:e,otherVersion:t})}`,D,i,r)}function B(s,e,t,i,r=z){return C(s,e,async o=>{let n=g.generation;for await(let{error:l,status:c,...p}of $e(o)){if(n!==g.generation)throw new DOMException("Managed session changed","AbortError");await t(l?{...p,status:c,message:r[l]??r[c]??`Request failed (${c})`}:p)}},i)}var ke={...z,413:"This file is too large to compare with renamed names hidden.",422:"This file couldn't be compared as code.","diff-busy":"Too many files are being compared. Try again shortly.",504:"Comparing this file took too long."},St=(s,e)=>C(s,ke,t=>t.json(),e);function or(s,e,{path:t,hash:i,otherPath:r,otherHash:o},{signal:n}={}){return St(`/api/bundles/${encodeURIComponent(s)}/rename-diff?${new URLSearchParams({path:t,hash:i,other:e,otherPath:r,otherHash:o})}`,n)}function nr(s,e,t,{path:i,hash:r,otherPath:o,otherHash:n},{signal:l}={}){return St(`/api/npm/rename-diff?${new URLSearchParams({name:s,version:e,path:i,hash:r,otherVersion:t,otherPath:o,otherHash:n})}`,l)}var xe=(s,e)=>new URLSearchParams({other:s,...e?{scope:e}:{}});function lr(s,e,t,{signal:i,scope:r=""}={}){return B(`/api/bundles/${encodeURIComponent(s)}/rename-diff?${xe(e,r)}`,z,t,i,ke)}function dr(s,e,t,i,{signal:r}={}){return B(`/api/npm/rename-diff?${new URLSearchParams({name:s,version:e,otherVersion:t})}`,D,i,r,ke)}function cr(s,e,t,{signal:i,scope:r=""}={}){return B(`/api/bundles/${encodeURIComponent(s)}/type-only?${xe(e,r)}`,z,t,i)}function pr(s,e,t,i,{signal:r}={}){return B(`/api/npm/type-only?${new URLSearchParams({name:s,version:e,otherVersion:t})}`,D,i,r)}var ur={404:"This bundle is no longer available.",422:"This bundle couldn't be read.",429:"Too many bundles are being compared. Try again shortly."},Ct=async s=>{let e=await s.json();return e.files.basePaths=new Map(e.files.basePaths),e};function hr(s,e,{signal:t,scope:i=""}={}){return C(`/api/bundles/${encodeURIComponent(s)}/comparison?${xe(e,i)}`,ur,Ct,t)}function mr(s,e,t,{signal:i,otherName:r=s}={}){let o=new URLSearchParams({name:s,version:e,otherVersion:t,...r===s?{}:{otherName:r}});return C(`/api/npm/comparison?${o}`,D,Ct,i)}async function I(s,e){let t=await m(s,{signal:e,credentials:"same-origin",headers:{accept:"application/json"}});if(!t.ok)throw new Error(`HTTP ${t.status}`);return t.json()}function N(s,e,t){let i={"content-type":"application/json"};return e&&(i["x-csrf-token"]=e),m(s,{method:"POST",credentials:"same-origin",headers:i,body:JSON.stringify(t)})}async function de(s){let e=await s.json().then(t=>typeof t?.error=="string"?t.error:"",()=>"");return["repo-forbidden","forbidden"].includes(e)?"choose a repository and directory within your team access":`HTTP 403${e?`: ${e}`:""}`}async function Et(s,e,t){let i=t?{"x-csrf-token":t}:{},r=await m(`/api/admin/${s}/${encodeURIComponent(e)}`,{method:"DELETE",credentials:"same-origin",headers:i});if(!r.ok)throw new Error(`HTTP ${r.status}`)}async function At(s,e,t,i,r,o){let n=new URLSearchParams({page:String(e),limit:"100",kind:t,q:i.trim()});r&&n.set("repo",r),o&&n.set("actor",o);let l=await I(`/api/admin/history?${n}`,s);if(!Array.isArray(l?.history)||!Number.isSafeInteger(l.total)||l.total<0||!Number.isSafeInteger(l.page)||l.page<1)throw new Error("No history returned");return l}async function Tt(s){let e=await I("/api/admin/users",s);return Array.isArray(e?.users)?e.users:[]}async function It(s,e,t){let i=await N("/api/admin/set-role",t,{userId:s,role:e});if(!i.ok)throw new Error(`HTTP ${i.status}`)}async function Nt(s,e,t,i){let r=new URLSearchParams({scope:s});return s==="installed"&&r.set("showAll",String(e)),t&&r.set("refresh","true"),await I(`/api/admin/repositories?${r}`,i)}async function Lt(s,e,t){let i=await N("/api/admin/repositories/select",t,{repoId:s,selected:e});if(!i.ok)throw new Error(`HTTP ${i.status}`)}async function Ot(s,e){let t=await m("/api/admin/repositories/add-public",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json","x-csrf-token":e},body:JSON.stringify({repository:s})});if(!t.ok){let i={400:"Enter a repository as owner/repo or a GitHub repository URL.",403:"You do not have permission to add arbitrary public repositories.",404:"No public repository was found at that address.",409:"Choose a public, non-archived repository."};throw new Error(i[t.status]??`GitHub lookup failed (HTTP ${t.status}). Try again.`)}}async function Pt(s,e){let t=await I(`/api/admin/repositories/impact?repoId=${encodeURIComponent(s)}`,e);if(t?.repoId!==s||!Array.isArray(t.reports)||!Array.isArray(t.bundles)||!Number.isSafeInteger(t.triageCount)||t.triageCount<0)throw new Error("Invalid repository data");return t}async function Dt(s,e){let t=await m("/api/admin/repositories/connect-app",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json","x-csrf-token":e},body:JSON.stringify({repoId:s})}),i=await t.json();if(!t.ok){let r={"github-app-not-configured":"The GitHub App is not configured on this server.","repo-identity-changed":"The repository has changed on GitHub. Refresh and check its connection.","repo-connection-changed":"The connection or your permissions changed. Refresh and try again.","repo-not-connected":"This repository is no longer connected.",forbidden:"Administrator access is required to connect the GitHub App."};throw new Error(r[i.error]??`Could not connect the GitHub App (HTTP ${t.status}). Try again.`)}if(i.connected===!0)return i;if(i.connected!==!1||typeof i.installUrl!="string"||!/^https:\/\/github\.com\/apps\/[^/?#]+\/installations\/new$/u.test(i.installUrl))throw new Error("Invalid GitHub installation response.");return i}async function zt(s,e,t,i){let r=await N("/api/admin/repositories/remove",i,{repoId:s,fullName:e,acknowledge:!0,deleteTriage:t});if(!r.ok)throw new Error(`HTTP ${r.status}`);return r.json()}async function Bt(s){return await I("/api/admin/reports",s)}async function Mt(s,e,t){let i=await m("/api/admin/bundles/create",{method:"POST",credentials:"same-origin",signal:t,headers:{"content-type":"application/json","x-csrf-token":e},body:JSON.stringify(s)}),r=await i.json();if(!i.ok){let o={"unsupported-entries":"Select JavaScript/TypeScript files (including JSX/TSX) or Solidity files. Stasis cannot mix languages or use JSON or Rust as remote entry points.","bad-conditions":"Check the export conditions and selected platforms.","metro-conditions":"Stasis\u2019s Metro preset requires the react-native condition without manual changes.","build-lockfile":"Stasis needs a supported lockfile: pnpm-lock.yaml, yarn.lock (Yarn 1), package-lock.json, or soldeer.lock.","build-scope":"Your team needs access to the bundle\u2019s project root, including its lockfile and dependencies.","build-busy":"A bundle is already being built, or the server is busy. Try again shortly.","build-timeout":"The bundle build timed out. Try a smaller selection or retry.","too-large":"This bundle exceeds the server\u2019s size limit.","github-rate-limited":"GitHub\u2019s API rate limit has been reached. Retry after the limit resets.","github-build-failed":"Could not fetch the repository from GitHub. Check access and retry.","repository-changed":"The repository connection changed during the build. Reload and try again.","bundle-conflict":"This bundle already exists but is outside your current access.","build-failed":"Stasis could not build this selection. Check that its lockfile is supported and all entry points and imports exist at this commit."};throw new Error(o[r.error]??(i.status===401?"Sign in again to create a bundle.":i.status===403||i.status===404?"Repository access is required to create this bundle.":"Could not create the bundle. Try again."))}return r}async function Se(s,e,t=null,i=""){let r=(await I("/api/config")).managed?.uploadMaxBytes?.reports;if(Number.isSafeInteger(r)&&r>0){if(s.size>r)throw new Error("too large")}else if(s.size>3*1024*1024)return Re(s,e,t,i);let o=ut(await s.text(),s.name);if(!o)return Re(s,e,t,i);let n=[],l=[];for(let{name:c,content:p}of o)try{l.push(await Re(new File([p],c,{type:"application/json"}),e,t,i))}catch(u){n.push(`${c}: ${String(u?.message??u)}`)}if(n.length>0)throw new Error(`${n.length} of ${o.length} products failed (${n.join("; ")})`);return l.at(-1)}async function Re(s,e,t,i){let r={"content-type":s.type||"application/json","x-report-filename":encodeURIComponent(s.name)};e&&(r["x-csrf-token"]=e),t!=null&&(r["x-repo-id"]=String(t)),i!==""&&(r["x-repo-directory"]=encodeURIComponent(i));let o=await m("/api/admin/reports",{method:"POST",credentials:"same-origin",headers:r,body:s});if(!o.ok){if(o.status===413)throw new Error("too large");if(o.status===403)throw new Error(await de(o));let n=await o.json().catch(()=>null);if(n?.error==="storage-encryption-required")throw new Error("Link reports require managed storage encryption. Configure MANAGED_STORAGE_ENCRYPTION_KEY.");if(n?.error==="invalid-report")throw new Error(typeof n.reason=="string"&&n.reason?`This file is not a report: ${n.reason}`:"This file is not a recognized report.");let l=n?.error==="repo-not-connected"&&typeof n.repo=="string"?`: ${n.repo} is not connected`:"";throw new Error(`HTTP ${o.status}${l}`)}return o.json()}async function qt(s,e,t){let i=await N("/api/admin/reports/set-visible",t,{reportId:s,visible:e});if(!i.ok)throw new Error(`HTTP ${i.status}`)}async function Ut(s,e,t,i){let r=await N("/api/admin/reports/set-repo",i,{reportId:s,repoId:e,directory:t});if(!r.ok)throw r.status===409?new Error("this report already defines its repository"):r.status===403?new Error(await de(r)):new Error(r.status===400?"invalid repository or directory":`HTTP ${r.status}`);return r.json()}async function Ft(s,e){let t=await m(`/api/admin/reports/${encodeURIComponent(s)}/location`,{signal:e,credentials:"same-origin"});if(!t.ok)throw new Error(`Report location suggestion request failed (${t.status})`);return(await t.json())?.location??null}async function jt(s,e){await Et("reports",s,e)}async function Ce(s){return await I("/api/admin/bundles",s)}async function Ee(s,e,t,i=""){let r={"content-type":"application/octet-stream","x-bundle-filename":encodeURIComponent(s.name)};e&&(r["x-csrf-token"]=e),t!=null&&(r["x-repo-id"]=String(t)),i&&(r["x-repo-directory"]=encodeURIComponent(i));let o=await m("/api/admin/bundles",{method:"POST",credentials:"same-origin",headers:r,body:s});if(!o.ok)throw new Error(o.status===413?"too large":o.status===403?await de(o):`HTTP ${o.status}`);return o.json()}async function Ht(s,e){await Et("bundles",s,e)}async function Gt(s,e,t){let i=await N("/api/admin/bundles/set-visible",t,{bundleId:s,visible:e});if(!i.ok)throw new Error(`HTTP ${i.status}`)}async function Kt(s,e,t,i){let r=await N("/api/admin/bundles/set-repo",i,{bundleId:s,repoId:e,directory:t});if(!r.ok)throw new Error(r.status===403?await de(r):r.status===400?"invalid repository or directory":`HTTP ${r.status}`)}async function V(s){return await I("/api/admin/teams",s)}async function x(s,e,t){let i=await N(s,e,t);if(!i.ok)throw new Error(i.status===409?"name already taken":`HTTP ${i.status}`)}function W(s,e=!0){let t=document.createElement("input");t.type="file",t.multiple=e,t.addEventListener("change",()=>{s([...t.files])},{once:!0}),t.click()}function J(s,e,t){let i=0,r=p=>Array.from(p.dataTransfer?.types??[]).includes("Files"),o=p=>{r(p)&&(p.preventDefault(),i+=1,t(!0))},n=p=>{r(p)&&p.preventDefault()},l=p=>{r(p)&&(i=Math.max(0,i-1),i===0&&t(!1))},c=p=>{r(p)&&(p.preventDefault(),p.stopPropagation(),i=0,t(!1),e([...p.dataTransfer.files]))};return s.addEventListener("dragenter",o),s.addEventListener("dragover",n),s.addEventListener("dragleave",l),s.addEventListener("drop",c),()=>{s.removeEventListener("dragenter",o),s.removeEventListener("dragover",n),s.removeEventListener("dragleave",l),s.removeEventListener("drop",c)}}async function Vt(s,e,t,i){let r=s.appState.generation;try{return await s.appState.mutate(()=>t(e),i)}catch(o){throw r===s.appState.generation&&s.appState.invalidate(i),o}}async function Ae(s,e,t,i){if(s._busy||!s._csrf)throw new Error("Wait for the current operation to finish, then try again.");s._busy=!0;try{await Vt(s,e,t,i)}finally{await s._load(),s._busy=!1;let r=s._queue.splice(0);r.length>0&&s._upload(r)}}async function Y(s,e,t,i){if(e.length===0||(s._queue.push(...e),s._busy))return;s._busy=!0,s._error=null;let r=s.appState.generation,o=[],n=0;try{for(;s._queue.length>0;){if(s.appState.generation!==r){s._queue=[];break}let l=s._queue.shift();try{await Vt(s,l,t,i)}catch(c){if(c?.name==="AbortError"||s.appState.generation!==r){s._queue=[];break}o.push(`${l.name}: ${String(c?.message??c)}`)}n++}}finally{o.length>0&&(s._error=n===1?`Upload failed: ${o[0]}`:`Upload failed for ${o.length} of ${n} files: ${o.join("; ")}`),s._busy=!1,await s._load({preserveError:!0})}}var Te=`.local-import-toggle{flex-shrink:0;margin-block:calc(-.25rem - 1px);margin-left:auto;padding:.25rem .6rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:transparent;color:var(--muted);font:inherit;font-size:.75rem;line-height:1.5}.local-import-toggle:hover,.local-import-toggle[aria-expanded=true]{color:var(--text);background:rgb(from var(--text) r g b / .06)}.local-import-panel{display:grid;gap:.8rem;padding:1rem;margin-bottom:1.25rem;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:rgb(from var(--accent) r g b / .025)}.local-import-copy strong{font-size:.82rem;font-weight:600}.local-import-copy p,.local-import-message{margin:.3rem 0 0;color:var(--muted);font-size:.75rem;line-height:1.5}.local-import-controls{display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}managed-local-item-selector{flex:1 1 16rem;min-width:0}.local-import-controls button,.local-import-message button{padding:.35rem .7rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:transparent;color:var(--text);font:inherit;font-size:.75rem;line-height:1.5}.local-import-controls .local-import-submit{border-color:rgb(from var(--accent) r g b / .4);background:rgb(from var(--accent) r g b / .1);color:var(--accent)}.local-import-controls .local-import-close{color:var(--muted)}.local-import-panel button:disabled,.local-import-toggle:disabled{opacity:.5}.local-import-panel button:focus-visible,.local-import-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.local-import-message.error{color:var(--critical)}
4
- `;var Wt=`.home-section{margin-top:1.1rem;margin-bottom:2rem}.section-heading{display:flex;align-items:baseline;gap:1rem;margin-bottom:.85rem}.section-heading h2{margin:0;font-size:.86rem;font-weight:600}.section-heading>span{color:var(--muted);font-size:.75rem}.pages{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.9rem}.page{display:flex;flex-direction:column;gap:.85rem;padding:1.35rem;border:1px solid var(--border);border-radius:var(--ui-radius, 12px);color:var(--text);background:var(--panel);text-align:left;font:inherit}.page:hover{background:var(--panel-hover);border-color:color-mix(in srgb,var(--muted) 60%,var(--border))}.page-top{display:flex;align-items:center;gap:.75rem;width:100%}.page-icon{display:grid;place-items:center;flex-shrink:0;width:2.5rem;height:2.5rem;border:1px solid color-mix(in srgb,var(--accent) 16%,var(--border));border-radius:var(--ui-radius, 9px);background:color-mix(in srgb,var(--accent) 7%,var(--panel));color:var(--accent)}.page-bundle .page-icon{color:var(--green);border-color:color-mix(in srgb,var(--green) 18%,var(--border));background:color-mix(in srgb,var(--green) 6%,var(--panel))}.page-scan .page-icon{color:var(--scan-icon-color, var(--yellow));border-color:color-mix(in srgb,var(--scan-icon-color, var(--yellow)) 18%,var(--border));background:color-mix(in srgb,var(--scan-icon-color, var(--yellow)) 6%,var(--panel))}:host-context(body.theme-light) .page-scan .page-icon{--scan-icon-color: #bf8700}:host-context(body.theme-green) :is(.page-bundle,.page-scan) .page-icon,:host-context(body.theme-pink) :is(.page-bundle,.page-scan) .page-icon{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 16%,var(--border));background:color-mix(in srgb,var(--accent) 7%,var(--panel))}.page-icon svg{width:1.2rem;height:1.2rem}.arrow{display:flex;margin-left:auto;flex-shrink:0;color:var(--muted)}.arrow svg{width:1rem;height:1rem}.page:hover .arrow{color:var(--text)}.page-copy{display:grid;gap:.45rem}.page>.page-copy{margin-inline-start:3.25rem}.page-copy strong,.page-title{font-size:1rem;font-weight:600;letter-spacing:-.015em}.page-copy>span{color:var(--muted);font-size:.8rem;line-height:1.65}.workspace-pages .page{gap:.85rem;padding:1.2rem 1.35rem}.workspace-pages .page-icon{width:2rem;height:2rem;color:var(--muted);background:transparent;border-color:var(--border)}.workspace-pages .page-title{font-size:.9rem}.workspace-pages .page-copy{margin-inline-start:2.75rem}.history-link{display:flex;align-items:center;gap:1rem;width:100%;padding:1.25rem 0;border:0;border-top:1px solid var(--border);text-align:left;color:var(--text);background:transparent}.history-link>.page-icon{color:var(--muted);background:transparent;border-color:var(--border)}.history-link .page-copy strong{font-size:.85rem}.history-cta{display:flex;align-items:center;gap:.6rem;flex-shrink:0;margin-left:auto;color:var(--muted);font-size:.78rem}.history-cta svg{width:1rem;height:1rem}.history-link:hover .history-cta{color:var(--accent)}@container (max-width: 48rem){.pages{grid-template-columns:1fr;gap:.65rem}.page,.workspace-pages .page{gap:.65rem;padding:1.15rem}.page-top .arrow{display:none}.workspace-pages .page-icon{width:2.5rem;height:2.5rem}.workspace-pages .page-copy{margin-inline-start:3.25rem}.page-copy{gap:.2rem}.page-copy strong,.page-title{font-size:.95rem}.section-heading>span{display:none}.history-cta{font-size:0}}
5
- `;var Jt=`.toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.65rem;margin-bottom:.9rem}.toolbar input{flex:2 1 12rem}.toolbar select{flex:0 1 9rem}.toolbar repository-selector{flex:1 1 12rem}.toolbar user-selector{flex:1.5 1 16rem}.toolbar>*{min-width:0}.toolbar input[type=search],.toolbar select,.toolbar .btn{min-height:2rem;padding:.28rem .5rem;border-radius:var(--ui-radius, 5px)}.history{overflow-x:auto;border:1px solid var(--border);border-radius:var(--ui-radius, 9px);background:var(--panel)}.row,.history-head{display:grid;grid-template-columns:4.7rem minmax(16rem,1fr) minmax(12rem,1fr) 12rem;align-items:center;gap:.85rem;min-width:52rem;padding:.45rem .85rem}.history-head{background:rgb(from var(--text) r g b / .025);color:var(--muted);font-size:.7rem}.row{border-top:1px solid var(--border);min-height:2.35rem}.row:hover{background:var(--panel-hover)}.kind{display:inline-flex;align-items:center;justify-content:center;width:fit-content;padding:.05rem .35rem;border:1px solid var(--border);border-radius:4px;color:var(--muted);font-size:.65rem;text-transform:capitalize}.kind.triage{color:var(--accent);border-color:rgb(from var(--accent) r g b / .25);background:rgb(from var(--accent) r g b / .06)}.kind.upload{color:var(--green);border-color:rgb(from var(--green) r g b / .25);background:rgb(from var(--green) r g b / .06)}.kind.visibility{color:var(--yellow);border-color:rgb(from var(--yellow) r g b / .25);background:rgb(from var(--yellow) r g b / .06)}.activity-description,.detail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.75rem}.actor{color:var(--text);font-weight:500}.action,.detail{color:var(--muted)}.history-time{display:flex;align-items:center;gap:.35rem;color:var(--muted);font-size:.7rem;white-space:nowrap;font-variant-numeric:tabular-nums}.history .empty{border:0;margin:0}.pagination{display:flex;align-items:center;flex-wrap:wrap;gap:.65rem;margin-top:1rem;color:var(--muted);font-size:.75rem}.pagination>span:first-child{margin-right:auto}
6
- `;var Yt=`.icon-btn{display:inline-grid;place-items:center;flex:0 0 auto;width:1.8rem;height:1.8rem;padding:0;border:1px solid transparent;border-radius:var(--ui-radius, 5px);color:var(--muted);background:transparent}.icon-btn:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.icon-btn.danger:hover:not(:disabled){color:var(--critical, #e5534b);background:rgb(from var(--critical, #e5534b) r g b / .1)}.icon-btn svg,.btn svg{width:.9rem;height:.9rem}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.avatar img.broken{display:none}.list-head{color:var(--muted);font-size:.7rem;font-weight:500;min-height:2.25rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025)}.users{list-style:none;margin:0;padding:0}.users li+li{border-top:1px solid var(--border)}.who{display:grid;gap:.15rem;min-width:0}.name-text,.login{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.login{color:var(--muted);font-size:.75rem}.last-seen time,.last-activity time{color:var(--text)}.activity-link{display:block;min-width:0;padding:.15rem .2rem;border:0;border-radius:var(--ui-radius, 4px);color:inherit;background:transparent;text-align:left}.activity-link:hover{color:var(--accent);background:rgb(from var(--accent) r g b / .08)}.you{padding:.05rem .35rem;border-radius:4px;color:var(--accent);background:rgb(from var(--accent) r g b / .1);font-size:.75rem;font-weight:500}.permission-granted{color:var(--accent)}.permission-denied{color:var(--muted)}.no-team{color:var(--muted);font-size:.75rem}.access{display:flex;align-items:center;min-width:0}.role{width:100%;height:auto;font-size:.78rem}.self-note{display:flex;align-items:center;gap:.5rem;margin:1rem 0;color:var(--muted);font-size:.75rem}.users li:hover{background:var(--panel-hover)}.avatar{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;width:1.85rem;height:1.85rem;border-radius:50%;overflow:hidden;font-size:.85rem;font-weight:600}.directory{border:1px solid var(--border);border-radius:var(--ui-radius, 11px);overflow:hidden;background:var(--panel);overflow-x:auto}.list-head,.users{min-width:53rem}.list-head,.users li{display:grid;grid-template-columns:minmax(11rem,1fr) minmax(16rem,1.2fr) 6.2rem 6.2rem 6.5rem 2rem;gap:.7rem;padding:.5rem .85rem;align-items:center}.users li{padding-top:.6rem;padding-bottom:.6rem;cursor:default}.person{display:flex;align-items:center;gap:.65rem;min-width:0}.name{display:flex;align-items:center;gap:.4rem;font-size:.8rem;font-weight:500}.last-seen,.last-activity{display:grid;gap:.08rem;color:var(--muted);font-size:.68rem;font-variant-numeric:tabular-nums}.memberships{display:grid;gap:.1rem;min-width:0}.team-access{display:flex;gap:.2rem .5rem;min-width:0;font-size:.7rem;line-height:1.4;align-items:center;flex-wrap:nowrap}.team-access strong{display:inline-flex;align-items:center;gap:.25rem;color:var(--text);font-weight:500;min-width:0;max-width:8rem}.team-access strong.team-access-role{flex-shrink:0;max-width:none;white-space:nowrap}.team-access strong svg{width:.8rem;height:.8rem;flex-shrink:0;color:var(--muted)}.team-access strong span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.team-perms{display:inline-flex;flex-wrap:nowrap;gap:.45rem;font-size:inherit;flex-shrink:0}.view-as{display:flex;justify-content:flex-end}
7
- `;var Xt=`.icon-btn{display:inline-grid;place-items:center;flex:0 0 auto;width:1.8rem;height:1.8rem;padding:0;border:1px solid transparent;border-radius:var(--ui-radius, 5px);color:var(--muted);background:transparent}.icon-btn:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.icon-btn.danger:hover:not(:disabled){color:var(--critical, #e5534b);background:rgb(from var(--critical, #e5534b) r g b / .1)}.icon-btn svg,.btn svg{width:.9rem;height:.9rem}.avatar{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;width:2rem;height:2rem;border-radius:50%;overflow:hidden;background:var(--surface-active);color:var(--muted);font-family:system-ui,-apple-system,BlinkMacSystemFont,sans-serif;font-size:.8rem;font-weight:600;user-select:none}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.avatar img.broken{display:none}.toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.65rem;margin:1.5rem 0 1.65rem}.aliases-link{margin-top:.75rem}.aliases-link .btn{min-height:1.75rem;padding:.2rem .55rem}.repository-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.65rem;margin-left:auto;margin-block:calc(-.45rem - 1px)}.breadcrumb{flex-wrap:wrap}.breadcrumb .breadcrumb-current{margin:0;color:var(--text);font-size:.85rem;font-weight:500}.public-repository-form{padding:1rem;margin:-1rem 0 1.5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:var(--panel)}.public-repository-form .confirm-field{margin:0}.search{flex:1 1 14rem;max-width:25rem;margin-right:auto}.search input{width:100%}.show-all,.show-all-paper{align-items:center;gap:.5rem;white-space:nowrap;font-size:.78rem}.show-all{display:var(--switch-button-display, inline-flex)}.show-all-paper{display:var(--switch-checkbox-display, none);& input{width:.85rem;height:.85rem;margin:0;accent-color:var(--accent)}}.show-all input{appearance:none;width:2rem;height:1.15rem;margin:0;padding:2px;border:1px solid var(--border);border-radius:var(--ui-radius, 1rem);background:var(--surface-active)}.show-all input:before{content:"";display:block;width:.775rem;height:.775rem;border-radius:50%;background:var(--muted)}.show-all input:checked{border-color:var(--accent);background:var(--accent)}.show-all input:checked:before{transform:translate(.85rem);background:var(--bg)}.show-all input:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.repository-count{margin:-.8rem 0 .6rem;color:var(--muted);font-size:.75rem;font-variant-numeric:tabular-nums}.repository-browser{display:flex;overflow:hidden;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:var(--panel)}.organization-list{flex:0 0 12rem;padding:.4rem;border-right:1px solid var(--border);background:rgb(from var(--bg) r g b / .25)}.organization{display:flex;align-items:center;gap:.5rem;width:100%;padding:.5rem;border:0;border-radius:var(--ui-radius, 4px);color:var(--text);background:transparent;text-align:left;font-size:.76rem;cursor:default}.organization:hover{background:rgb(from var(--text) r g b / .05)}.organization[aria-pressed=true]{color:var(--accent);background:rgb(from var(--accent) r g b / .1)}.organization-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.organization-count{color:var(--muted);font-size:.7rem;font-variant-numeric:tabular-nums}.repo-results{flex:1;min-width:0}.organization-list,.repo-results{max-height:min(65vh,40rem);overflow:auto;overscroll-behavior:contain}.repo-group+.repo-group{border-top:1px solid var(--border)}.owner-head{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:.6rem;margin:0;padding:.55rem .85rem;color:var(--muted);background:var(--panel);font-size:.8rem;font-weight:500}.owner-icon{display:grid;place-items:center;width:1.6rem;height:1.6rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--surface);text-transform:uppercase;font-size:.75rem}.repos{margin:0;padding:0;list-style:none}.repos li+li{border-top:1px solid var(--border)}button.repo-row{border:0;background:transparent;color:var(--text);cursor:default}button.repo-row:hover{background:var(--surface-active)}button.repo-row:focus-visible{outline-offset:-2px}.btn.connect-app{min-height:1.9rem;padding:.3rem .6rem;font-size:.72rem}.repo-icon{width:1.15rem;height:1.15rem;flex-shrink:0;color:var(--muted)}.repo-meta:before{content:none}.arrow{width:1rem;height:1rem;flex:0 0 auto;color:var(--muted)}.connected{display:inline-flex;align-items:center;gap:.25rem;flex:0 0 auto;color:var(--muted);font-size:.75rem;white-space:nowrap}.connected svg{width:.85rem;height:.85rem}.access-note{display:flex;align-items:center;gap:.85rem;padding:.85rem 1rem;background:var(--surface);border:1px solid var(--border);border-radius:var(--ui-radius, 8px)}.access-note p{flex:1;margin:0;color:var(--muted);font-size:.78rem;line-height:1.5}a.btn{color:var(--text);text-decoration:none;cursor:default}.empty{padding:2.5rem 1rem;text-align:center}.empty strong{display:block;margin-bottom:.4rem;font-size:.9rem;font-weight:500}.empty p{margin:0;color:var(--muted);font-size:.8rem}.loading{min-height:8rem;display:grid;place-items:center;color:var(--muted);font-size:.8rem}.section{margin-top:1.75rem;border:1px solid var(--border);border-radius:var(--ui-radius, 10px);overflow:hidden;background:var(--panel)}.section h2{margin:0;padding:1rem 1.25rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025);font-size:.85rem;font-weight:600}.settings-row{display:flex;align-items:center;gap:1rem;padding:1.25rem}.settings-copy{flex:1;min-width:0}.settings-copy strong{font-size:.83rem;font-weight:500}.settings-copy p{margin:.25rem 0 0;color:var(--muted);font-size:.76rem;line-height:1.5}.settings-row+.settings-row{border-top:1px solid var(--border)}.btn.danger,.error{color:var(--critical, #e5534b)}.status-line{display:inline-flex;align-items:center;gap:.35rem;color:var(--muted);font-size:.75rem}.status-line.inactive{color:var(--warning, #d19a24)}.data-section{margin-top:1.5rem}.data-section h2{margin:0 0 .5rem;font-size:.85rem;font-weight:500}.data-empty{margin:0;color:var(--muted);font-size:.75rem}.dialog-backdrop{position:fixed;inset:0;z-index:20;display:grid;place-items:center;padding:1rem;background:#000000a6}.dialog{width:min(40rem,100%);max-height:calc(100vh - 3rem);overflow:auto;padding:1.5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 12px);background:var(--bg);box-shadow:0 1rem 3rem #00000059}.dialog.small{width:min(28rem,100%)}.dialog h2{margin:0;font-size:1.05rem;font-weight:600;overflow-wrap:anywhere}.dialog-copy{margin:.55rem 0 1rem;color:var(--muted);font-size:.78rem;line-height:1.5}.dialog-data{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.75rem;margin:0 0 1rem}.dialog-data section{min-width:0;padding:.65rem;border:1px solid var(--border);border-radius:var(--ui-radius, 7px)}.dialog-data h3{margin:0 0 .4rem;font-size:.75rem;font-weight:600}.dialog-data ul{max-height:9rem;overflow:auto;margin:0;padding-left:1rem;color:var(--muted);font-size:.75rem}.dialog-data li{margin:.2rem 0;overflow-wrap:anywhere}.confirm-line{display:flex;align-items:flex-start;gap:.5rem;margin:.7rem 0;color:var(--text);font-size:.76rem;line-height:1.4}.confirm-line input{flex:0 0 auto;margin-top:.15rem;accent-color:var(--accent)}.confirm-line span{min-width:0}.confirm-field{display:grid;gap:.5rem;margin-top:1.1rem;color:var(--text);font-size:.78rem;line-height:1.5;overflow-wrap:anywhere}.confirm-name{width:100%;min-width:0;padding:.45rem .55rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg);color:var(--text);font:inherit;font-size:.78rem}.dialog-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem;margin-top:1rem}.dialog-actions .danger{color:var(--critical, #e5534b);border-color:rgb(from var(--critical, #e5534b) r g b / .4)}@container (max-width: 35rem){.organization-list{flex-basis:9rem}.intro{margin-left:0}.search{flex-basis:100%;max-width:none}.access-note,.settings-row{flex-wrap:wrap}.access-note p,.settings-copy{flex-basis:100%}.head h1{font-size:1.35rem}.repo-copy{gap:.35rem}.repo-meta{max-width:100%}.dialog-data{grid-template-columns:1fr}}.repo-name{min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.83rem;font-weight:500}.repo-row{display:flex;align-items:center;gap:.75rem;width:100%;min-height:2.8rem;padding:.55rem .85rem;text-align:left}.repo-copy{display:flex;flex-direction:row;align-items:center;gap:.85rem;flex:1;min-width:0}.repo-meta{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:.72rem;margin-left:auto}@container (max-width: 35rem){.repo-copy{flex-direction:column;align-items:flex-start;gap:.1rem}.repo-meta{margin-left:0}}.data-section .dialog-data section{height:12rem;display:flex;flex-direction:column;align-items:flex-start}.data-section .dialog-data ul{width:100%;min-height:0;max-height:none}.access-action{flex-shrink:0}@container (max-width: 28rem){.repository-browser{flex-direction:column}.organization-list{display:flex;flex:0 0 auto;gap:.25rem;border-right:0;border-bottom:1px solid var(--border)}.organization{flex:0 0 auto;width:auto;max-width:12rem}}
8
- `;var ce=`.report-logo.brand-deepview{--brand-bg:#2563eb;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-claude{--brand-bg:#d97757;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-codex{--brand-bg:#fff;--brand-fg:#000;background:var(--brand-bg)}.report-logo.brand-vercel{--brand-bg:#000;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-markdown{--brand-bg:#374151;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-piolium{--brand-bg:#fbb829;--brand-fg:#1c1b19;background:var(--brand-bg)}.report-logo .fg{fill:var(--brand-fg)}.report-logo .bg{fill:var(--brand-bg)}.report-logo.brand-codex .bg,.report-logo.brand-vercel .bg{stroke:var(--brand-fg);stroke-width:.5}.dropzone{position:absolute;inset:.6rem;z-index:5;display:grid;place-items:center;border:2px dashed var(--accent);border-radius:var(--ui-radius, 10px);background:rgb(from var(--bg) r g b / .94);color:var(--accent);font-weight:600;pointer-events:none}.report-list{overflow-x:auto;border:1px solid var(--border);border-radius:var(--ui-radius, 9px);background:var(--panel)}.reports{min-width:61rem;margin:0;padding:0;list-style:none}.report-list-head,.report-main{display:grid;grid-template-columns:1.5rem minmax(12rem,1fr) minmax(8rem,.6fr) 8rem 6.5rem 4.5rem 4.1rem 9rem;align-items:center;gap:.7rem;padding:.35rem .85rem}.report-list-head{min-width:61rem;min-height:2.25rem;color:var(--muted);background:rgb(from var(--text) r g b / .025);border-bottom:1px solid var(--border);font-size:.7rem}.report-heading{grid-column:1 / 3}.actions-heading{text-align:right;padding-right:.25rem}.report+.report{border-top:1px solid var(--border)}.report-main{cursor:default}.report-main:hover{background:var(--panel-hover)}.report-logo{display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:5px;overflow:hidden}.report-logo svg{width:1.1rem;height:1.1rem}.report-name{color:var(--text);font-size:.8rem;font-weight:500}.report-name,.report-location,.report-meta{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.report-location{color:var(--muted);font-size:.7rem}.report-meta{color:var(--muted);font-size:.68rem;font-variant-numeric:tabular-nums}.report-uploader{color:var(--text);opacity:.8;font-size:.72rem}.report-size,.size-heading{padding-right:.65rem;text-align:right}.report-actions{display:flex;justify-content:flex-end;align-items:center;gap:.1rem}.report-actions .action,.action-spacer{display:grid;place-items:center;flex-shrink:0;width:1.7rem;height:1.8rem;padding:.3rem;border:1px solid transparent;border-radius:var(--ui-radius, 5px);background:transparent;color:var(--muted)}.action svg{width:.95rem;height:.95rem}.report-actions .action:hover:not(:disabled),.report-actions .action[aria-expanded=true]{color:var(--text);background:var(--surface-active);border-color:var(--border)}.report-actions .action.danger:hover{color:var(--critical);background:rgb(from var(--critical) r g b / .08)}.preview{height:20rem;border-top:1px solid var(--border);padding:.85rem}.preview pre{height:100%;overflow:auto;margin:0;padding:.85rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--bg);color:var(--text);font:.75rem/1.6 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.preview-loading{color:var(--muted);font-size:.8rem}
9
- `;var Zt=`button,select{font:inherit;cursor:default}button:focus-visible,a:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.dropzone{position:absolute;inset:.6rem;z-index:5;display:grid;place-items:center;border:2px dashed var(--accent);border-radius:var(--ui-radius, 10px);background:rgb(from var(--bg) r g b / .94);color:var(--accent);font-size:1rem;font-weight:600;pointer-events:none}.summary{min-height:1.5em;display:flex;flex-wrap:wrap;align-items:center;gap:.75rem;color:var(--muted);font-size:.75rem;font-variant-numeric:tabular-nums}.unassigned{color:var(--high, #d97732)}.bundles{margin:0;padding:0;list-style:none}.bundle-group-head strong{min-width:0;overflow-wrap:anywhere;font-size:.8rem;font-weight:500}.bundle-group-head span{color:var(--muted);font-size:.75rem}.bundle-row+.bundle-row{border-top:1px solid var(--border)}.bundle-icon svg,.bundle-icon img{width:1rem;height:1rem}.action{display:grid;place-items:center;width:2rem;height:2rem;padding:.45rem;border:1px solid transparent;border-radius:var(--ui-radius, 6px);background:transparent;color:var(--muted);text-decoration:none}.action svg{width:1rem;height:1rem}.action:hover{color:var(--text);border-color:var(--border);background:var(--surface)}.action.danger:hover{color:var(--critical, #e5534b)}.msg{padding:1rem 0;margin:0;color:var(--muted);font-size:.8rem}.msg.error{color:var(--critical, #e5534b)}.bundle-group{overflow:hidden;border:1px solid var(--border);border-radius:var(--ui-radius, 10px);background:var(--panel);overflow-x:auto}.bundle-group-head,.bundles{min-width:58rem}.bundle-row{display:grid;grid-template-columns:minmax(12rem,1fr) 8rem 6.5rem 4.5rem minmax(8rem,12rem) 4rem 8.6rem;align-items:center;gap:.85rem;padding:.25rem .5rem;cursor:default}.bundle-location{display:block;min-width:0;grid-column:auto;padding-left:0;color:var(--muted);font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.actions{display:flex;justify-content:flex-end;gap:.2rem;grid-column:auto;grid-row:auto}.bundle-group-head{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem .85rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025)}.bundle-groups{display:grid;gap:.85rem}.identity{display:flex;align-items:center;min-width:0;gap:.65rem}.bundle-icon{display:grid;place-items:center;width:1.6rem;height:1.6rem;flex-shrink:0;border:0;border-radius:var(--ui-radius, 7px);background:transparent;color:var(--muted)}.filename{min-width:0;font-size:.8rem;font-weight:500;overflow-wrap:anywhere;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta{min-width:0;color:var(--muted);font-size:.65rem;line-height:1.5;font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bundle-size{padding-right:.65rem;text-align:right}.bundle-provenance{flex-shrink:0;margin-left:-.35rem;padding:.05rem .35rem;border:1px solid rgb(from var(--accent) r g b / .25);border-radius:5px;background:rgb(from var(--accent) r g b / .07);color:var(--accent);font-size:.62rem;font-weight:500}.bundle-actions{display:flex;align-items:center;gap:.5rem}.bundle-open{padding:0;border:0;background:none;color:inherit;font:inherit;text-align:left}.bundle-open:hover{color:var(--accent)}.bundle-row>.location-editor{grid-column:1 / -1}.breadcrumb{flex-wrap:wrap}.breadcrumb .breadcrumb-current{margin:0;color:var(--text);font-size:.85rem;font-weight:500}
10
- `;var Ie=`.location-editor{display:grid;grid-template-columns:minmax(0,1fr) minmax(10rem,.7fr) auto;align-items:end;gap:.75rem;padding:.85rem;border-top:1px solid var(--border);background:rgb(from var(--bg) r g b / .35)}.location-field{display:grid;gap:.35rem;min-width:0}.location-field>span,.location-field label{color:var(--muted);font-size:.75rem}.location-field input{width:100%}.location-field input[type=text],.location-actions .action{height:2rem;min-height:2rem;padding-block:.28rem}.location-actions{display:flex;gap:.4rem}.location-actions .action{width:auto;padding-inline:.65rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);color:var(--text);background:var(--bg);font-size:.78rem}.location-field-header{display:flex;align-items:baseline;justify-content:space-between;gap:.5rem;min-width:0;color:var(--muted);font-size:.75rem}.location-field-header>:first-child{flex-shrink:0}.location-metadata{display:flex;align-items:baseline;gap:.25rem;min-width:0;padding:0;border:0;color:inherit;background:none;font:inherit}.location-metadata>.ui-hint{flex-shrink:0}.location-metadata-value{min-width:0;user-select:text;-webkit-user-select:text;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}button.location-metadata:hover:not(:disabled){color:var(--text)}.location-origin{grid-column:1 / -1;margin:0;color:var(--muted);font-size:.72rem;overflow-wrap:anywhere}.origin-retry{padding:0;border:0;background:none;color:var(--accent);font:inherit}
11
- `;var Qt=`.icon-btn{display:inline-grid;place-items:center;flex:0 0 auto;width:1.8rem;height:1.8rem;padding:0;border:1px solid transparent;border-radius:var(--ui-radius, 5px);color:var(--muted);background:transparent}.icon-btn:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.icon-btn.danger:hover:not(:disabled){color:var(--critical, #e5534b);background:rgb(from var(--critical, #e5534b) r g b / .1)}.icon-btn svg,.btn svg{width:.9rem;height:.9rem}.avatar{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;width:2rem;height:2rem;border-radius:50%;overflow:hidden;background:var(--surface-active);color:var(--muted);font-family:system-ui,-apple-system,BlinkMacSystemFont,sans-serif;font-size:.8rem;font-weight:600;user-select:none}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.avatar img.broken{display:none}.create-team{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;margin-bottom:1rem}.new-name{flex:1 1 14rem;width:16rem;max-width:24rem}.access-note{flex:1 1 24rem;margin:0 0 0 auto;color:var(--muted);font-size:.75rem;text-align:right}.team .icon-btn{width:1.8rem;height:1.8rem}.team{border:1px solid var(--border);border-radius:var(--ui-radius, 8px);margin-bottom:.85rem;background:var(--panel);overflow:hidden}.team-head{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.4rem .85rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025)}.team-icon{display:grid;place-items:center;flex:0 0 auto;width:1.25rem;height:1.25rem;color:var(--muted)}.team-icon svg{width:1.05rem;height:1.05rem}.team-name{margin:0;min-width:0;font-size:.875rem;font-weight:600;letter-spacing:-.015em;overflow-wrap:anywhere}.team-actions{display:flex;gap:.25rem;margin-left:auto}.rename-input{flex:1;max-width:22rem;width:0}.team-body{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr)}.sub{min-width:0;padding:.75rem .85rem}.sub+.sub{border-left:1px solid var(--border)}.sub-title{display:flex;align-items:center;gap:.5rem;margin:0 0 .4rem;font-size:.75rem;font-weight:600}.sub-title .count{height:1.1rem;min-width:1.1rem;font-size:.75rem;padding:0 .3rem}.links{list-style:none;margin:0 0 .5rem;padding:0}.links li{display:flex;align-items:center;gap:.5rem;min-height:2.25rem;padding:.25rem 0;cursor:default}.links li+li{border-top:1px solid var(--border)}.repo-icon{flex:0 0 auto;color:var(--muted);width:.95rem;height:.95rem}.repo-copy{display:flex;min-width:0;flex-direction:column;gap:.1rem}.ln{min-width:0;font-size:.8rem;font-weight:500;overflow-wrap:anywhere}.path{color:var(--muted);font-family:var(--mono);font-size:.75rem;overflow-wrap:anywhere}.repo-row .icon-btn{margin-left:auto}.links .member-row{display:grid;grid-template-columns:minmax(0,1fr) auto 1.8rem;gap:.45rem}.member{display:flex;align-items:center;gap:.45rem;min-width:0}.member .avatar{width:1.6rem;height:1.6rem;font-size:.75rem}.perms{display:flex;flex-wrap:wrap;gap:.3rem}.perm{display:inline-flex;align-items:center;gap:.3rem;padding:.15rem .3rem;border:1px solid var(--border);border-radius:4px;font-size:.7rem;color:var(--muted);user-select:none}.perm:has(:checked){color:var(--text);background:rgb(from var(--accent) r g b / .07);border-color:rgb(from var(--accent) r g b / .2)}.perm:has(:disabled){opacity:.5}.sub.npm-scopes{grid-column:1 / -1;border-top:1px solid var(--border);border-left:0}.npm-scopes .sub-head{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem .75rem;margin-bottom:.4rem}.npm-scopes .sub-head>.sub-title,.npm-scopes .sub-head>.ui-hint{margin:0}.npm-scopes .sub-head>.ui-hint{margin-left:auto;text-align:right}.npm-scope-row{flex-wrap:wrap;padding-top:0}.npm-scope-list{display:flex;flex:1 1 12rem;flex-wrap:wrap;align-items:center;gap:.35rem;min-width:0;margin:0;padding:0;list-style:none}.npm-scope{display:inline-flex;align-items:center;gap:.45rem;padding:.35rem .35rem .35rem .45rem;border:1px solid var(--border);border-radius:4px;font-family:var(--mono);font-size:.75rem}.npm-scope .icon-btn{width:1.3rem;height:1.3rem}.add-npm-scope{flex:1;width:0;max-width:18rem}.npm-scope-row>.add-npm-scope{min-width:8rem}.add-row{display:flex;align-items:center;gap:.5rem;padding-top:.45rem}.add-row select,.add-row repository-selector,.add-row user-selector{flex:1;width:0}.add-repo-path{flex:.75;width:0}.add-row .btn{flex:0 0 auto}.muted{color:var(--muted);font-size:.78rem;margin:.5rem 0}@container (max-width: 50rem){.access-note,.npm-scopes .sub-head>.ui-hint{flex-basis:100%;margin-left:0;text-align:left}.team-body{grid-template-columns:1fr}.sub+.sub{border-left:0;border-top:1px solid var(--border)}.add-row{max-width:36rem}}@container (max-width: 32rem){.create-team{flex-wrap:wrap}.new-name{flex:1;width:0}.team-head,.sub{padding-left:.75rem;padding-right:.75rem}.add-row:has(.add-repo-sel){display:grid;grid-template-columns:minmax(0,1fr) auto}.add-row .add-repo-sel{width:100%}.add-repo-path{grid-column:1 / -1;grid-row:2;width:100%}}@container (max-width: 26rem){.links .member-row{grid-template-columns:minmax(0,1fr) 1.8rem}.perms{grid-row:2;padding-left:2.05rem}.member-row>.icon-btn{grid-column:2;grid-row:1}}.npm-review-toggle{display:inline-flex;align-items:center;gap:.35rem;margin-left:.75rem;font-size:.85rem;font-weight:400}
12
- `;var E=s=>s??d;var ei=`:host{padding:0}.field,.browser,.entry-points{line-height:1.5}.note{color:var(--muted);font-size:.75rem}.source-fields{display:grid;grid-template-columns:minmax(12rem,1fr) minmax(0,1.6fr);align-items:end;gap:1rem;margin:1rem 0}.field{display:flex;flex-direction:column;gap:.4rem;min-width:0;font-size:.75rem;color:var(--muted)}.revision{display:flex;align-items:center;min-width:0;height:2rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg)}.revision:focus-within{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}.revision-name{flex:1}.revision input{height:100%;min-height:0;padding:.3rem .6rem;min-width:0;border:0;border-radius:0;background:transparent;color:var(--text);font-size:.76rem}.revision input:focus-visible{outline:none}.revision-switch{display:flex;flex:none;align-self:stretch;padding:2px;gap:2px}.revision-switch button{display:grid;place-items:center;width:1.8rem;padding:0;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted)}.revision-switch button:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.revision-switch button:focus-visible{outline-offset:-2px}.revision-switch button[aria-pressed=true]{color:var(--accent);background:color-mix(in srgb,var(--accent) 15%,var(--bg))}.revision-switch svg{width:1rem;height:1rem}.revision-expand{display:grid;place-items:center;align-self:stretch;flex:none;width:2rem;padding:0;border:0;border-radius:var(--ui-radius, 4px);color:var(--muted);background:transparent}.revision-expand svg{width:.9rem;height:.9rem}.revision-expand:hover:not(:disabled){color:var(--text)}.revision-expand:focus-visible{outline-offset:-2px}.revision-menu{visibility:hidden;position:fixed;inset:auto;margin:0;padding:.45rem;overflow:auto;overscroll-behavior:contain;scrollbar-gutter:stable;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:var(--surface-active);color:var(--text);box-shadow:0 .65rem 1.8rem #00000073}.revision-menu[data-positioned]{visibility:visible}.revision-options{display:flex;flex-direction:column;gap:.15rem}.revision-section{display:grid;grid-template-columns:repeat(var(--revision-columns, 1),minmax(0,1fr));gap:.15rem .5rem}.revision-section+.revision-section{padding-top:.15rem;border-top:1px solid var(--border)}.revision-options button{min-width:0;padding:.375rem .6rem;border:0;border-radius:var(--ui-radius, 4px);background:transparent;color:var(--text);text-align:left;font-size:.76rem}.revision-options button span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.revision-options button[aria-selected=true]{color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent)}.revision-options button:hover,.revision-options button[data-active]{background:color-mix(in srgb,var(--text) 8%,transparent)}.revision-options button[data-active]{outline:1px solid var(--accent);outline-offset:-1px}.revision-options .revision-group{display:flex;align-items:center;gap:.4rem}.revision-group svg{flex:none;width:.75rem;height:.75rem;color:var(--muted)}.revision-group[aria-expanded=false] svg{rotate:-90deg}.revision-options .revision-group .count{display:inline-flex;flex:none;min-width:1.1rem;padding:0 .35rem;background:transparent;font-size:.7rem}.revision-empty{margin:0;padding:.65rem;color:var(--muted);font-size:.75rem}button:disabled,input:disabled{opacity:.5}.browser{border:1px solid var(--border);border-radius:var(--ui-radius, 7px);overflow:hidden}.browser-head{display:flex;align-items:center;gap:.75rem;padding:.65rem .8rem;border-bottom:1px solid var(--border);background:var(--bg);font-size:.75rem}.commit-link{display:inline-flex;align-items:center;flex:none;gap:.3rem;margin-left:auto;color:var(--muted);text-decoration:none}.commit-link svg{width:1rem;height:1rem}.commit-link code{cursor:inherit}.commit-link:hover{color:var(--accent)}.commit-link:focus-visible{outline:1px solid var(--accent);outline-offset:3px;border-radius:var(--ui-radius, 2px)}.breadcrumbs{display:flex;align-items:center;flex-wrap:wrap;gap:.35rem;min-width:0}.breadcrumbs button{border:0;padding:.1rem;background:transparent;color:var(--muted);overflow-wrap:anywhere}.breadcrumbs button[aria-current]{color:var(--text)}.breadcrumbs button:hover:not(:disabled){color:var(--accent)}.file-browser{min-height:18rem;max-height:50vh;overflow:auto;padding:.75rem}.file-browser:has(>.empty){display:grid;place-items:center}.file-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,16rem),1fr));gap:.5rem}.file-tile{display:flex;align-items:center;gap:.5rem;min-width:0;height:2.05rem;padding:.4rem .6rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg);color:var(--text);font-size:.75rem}.file-tile>span:not(.arrow){overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.file-tile input{width:.85rem;height:.85rem;margin:0;accent-color:var(--accent);flex:none}.file-tile:hover,.file-tile:focus-within{border-color:var(--accent)}.file-tile.selected{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,var(--bg))}.directory{color:var(--muted)}.directory .arrow{margin-left:auto}.unsupported{opacity:.55}.empty{margin:0;padding:1rem;border:0;border-radius:0;text-align:center;color:var(--muted);font-size:.8rem;line-height:1.5}.error{color:var(--critical)}.message{padding:.5rem .8rem;color:var(--muted);font-size:.75rem;line-height:1.5}.text-action{border:0;padding:.1rem .2rem;color:var(--accent);background:transparent;font-size:.75rem}.entry-points{display:flex;align-items:center;gap:1rem;margin-top:1rem}.package-suggestions{display:flex;align-items:center;gap:1rem;margin-top:1rem;color:var(--muted);font-size:.75rem}.package-suggestions>div{flex:1;min-width:0}.package-suggestions p{margin:0 0 .4rem}.package-suggestions .suggestions-note{margin:.4rem 0 0}.package-suggestions ul{display:flex;flex-wrap:wrap;gap:.4rem .8rem;padding:0;margin:0;list-style:none;max-height:6rem;overflow:auto}.package-suggestions li{min-width:0;max-width:100%}.package-suggestions li code{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}.package-suggestions .btn{flex:none;font-size:.72rem}.selection{flex:1;min-width:0}.selection .note{margin:.5rem 0 0}.selection-head{display:flex;align-items:center;gap:.75rem}.btn.clear-selection{min-height:1.65rem;padding:.2rem .5rem;font-size:.72rem}h2{margin:0;font-size:.8rem;font-weight:500}h2 span{color:var(--muted);margin-left:.4rem}.entry-points ul{padding:0;display:flex;flex-wrap:wrap;gap:.4rem;list-style:none;max-height:7rem;overflow:auto;margin:.6rem 0 0}.entry-points li{display:flex;align-items:center;gap:.4rem;min-width:0;max-width:100%;padding:.2rem .4rem;border:1px solid var(--border);border-radius:var(--ui-radius, 4px);background:var(--bg);font-size:.72rem}.entry-points li span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.entry-points li button{display:grid;place-items:center;flex:none;width:1.3rem;height:1.3rem;padding:0;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted);cursor:default}.entry-points li button svg{width:1rem;height:1rem}.entry-points li button:hover{color:var(--critical);background:color-mix(in srgb,var(--critical) 12%,transparent)}.entry-points li button:focus-visible{outline:1px solid var(--accent);outline-offset:1px}@container (width <= 45rem){.source-fields{grid-template-columns:1fr}}
13
- `;function ti(s,e,t){return ri(s,e,t,a`Entry points declared in <code>package.json</code>`,"Suggested entry points")}function ii(s,e,t,i){return ri(s,e,t,"Suggested Solidity sources","Suggested Solidity sources",i)}function ri(s,e,t,i,r,o=!1){let n=s.filter(l=>!e.has(l));return n.length===0&&!o?d:a`<aside class="package-suggestions" aria-label="${r}"><div><p>${i}</p>${n.length>0?a`<ul>${n.map(l=>a`<li><code data-tooltip-truncated data-tooltip="${l}">${l}</code></li>`)}</ul>`:d} ${o?a`<p class="suggestions-note ui-hint">Suggestions are limited. Browse the source directories to select more files.</p>`:d}</div>${n.length>0?a`<button type="button" class="btn" @click="${()=>t(n)}">Use suggestions</button>`:d}</aside>`}var si=`:host{padding:0;margin:1.2rem 0}.conditions-head{display:flex;align-items:center;flex-wrap:wrap;gap:.65rem 1rem}.conditions-head[data-conditions-hidden]>:not(slot){visibility:hidden}slot[name=actions]::slotted(*){flex:none}h2{margin:0;font-size:.8rem;font-weight:500}.presets{display:flex;gap:2px;padding:3px;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--bg)}.presets button{display:inline-flex;align-items:center;gap:.35rem;padding:.3rem .65rem;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted);font-size:.75rem}.presets button:hover{background:var(--surface-active);color:var(--text)}.presets button[aria-pressed=true]{background:color-mix(in srgb,var(--accent) 15%,var(--bg));color:var(--accent)}.presets button:focus-visible{outline-offset:-1px}svg{width:1rem;height:1rem;flex:none}.platforms{display:flex;align-items:center;flex-wrap:wrap;gap:.75rem;font-size:.75rem}.platforms>span{color:var(--muted)}.platforms label{display:inline-flex;align-items:center;gap:.35rem}.platforms input{margin:0;width:.85rem;height:.85rem}.manual-toggle{display:flex;align-items:center;gap:.25rem;margin-left:auto;padding:.25rem 0;border:0;border-radius:var(--ui-radius, 2px);background:transparent;color:var(--muted);font-size:.75rem;white-space:nowrap}.manual-toggle:hover{color:var(--text)}.manual-toggle[hidden]{visibility:hidden}.manual-toggle[aria-expanded=true] svg{transform:rotate(90deg)}#manual-conditions{margin-top:.75rem}.condition-editor{display:flex;align-items:center;flex-wrap:wrap;gap:.35rem;min-height:2.25rem;padding:.3rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg)}.condition-editor:focus-within{border-color:var(--accent)}ul{display:flex;flex-wrap:wrap;gap:.35rem;max-width:100%;margin:0;padding:0;list-style:none}li{display:inline-flex;align-items:center;gap:.35rem;min-width:0;max-width:100%;min-height:1.5rem;padding:0 .25rem 0 .5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 4px);background:var(--surface);color:var(--text);font-size:.73rem}li.preset{padding-right:.5rem}li code{overflow-wrap:anywhere}li button{display:grid;place-items:center;flex:none;width:1.3rem;height:1.3rem;padding:0;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted)}li button:hover{color:var(--critical);background:color-mix(in srgb,var(--critical) 12%,transparent)}.condition-input{display:flex;align-items:center;flex:1;min-width:9rem}.condition-editor input{flex:1;width:0;min-width:0;min-height:1.5rem;padding:.15rem .4rem;border:0;border-radius:0;background:transparent;font-size:.75rem}.condition-editor input:focus-visible{outline:none}p{margin:.5rem 0 0;color:var(--muted);font-size:.7rem}.error{color:var(--critical)}@container (width <= 30rem){.conditions-head{gap:.6rem}.presets{margin-left:auto}.presets button{padding-inline:.4rem}.platforms{flex-basis:100%}}
14
- `;var Le=["import","require","default"],Sr=[...Le,"node","node-addons","module-sync"],X=[{id:"node",label:"Node.js",conditions:["node"],automatic:Sr,icon:ie`<path transform="scale(.6667)" fill="currentColor" stroke="none" d=${st}/>`},{id:"browser",label:"Browser",conditions:["browser","module"],automatic:Le,icon:ie`<rect x="1.5" y="2.5" width="13" height="11" rx="1.5"/><path d="M1.5 6h13M4 4.3h.1m2 0h.1"/>`},{id:"metro",label:"Metro",conditions:["react-native"],automatic:Le,icon:ie`<rect x="4" y="1.5" width="8" height="13" rx="2"/><path d="M6.5 3.5h3M7 12.5h2"/>`}],ai=16-Math.max(...X.map(s=>s.conditions.length)),Ne=[{id:"ios",label:"iOS"},{id:"android",label:"Android"}],Cr=new Intl.ListFormat("en",{type:"conjunction"});function oi(){return{preset:"node",conditions:["node"],platforms:[]}}var Oe=class extends M{static styles=[h(f),h(si)];static properties={showConditions:{attribute:!1},_preset:{state:!0},_manual:{state:!0},_platforms:{state:!0},_draft:{state:!0},_error:{state:!0},_manualOpen:{state:!0}};constructor(){super(),this.showConditions=!0,this._preset="node",this._manual=[],this._platforms=["ios","android"],this._draft="",this._error="",this._manualOpen=!1}get value(){return{preset:this._preset,conditions:this.conditions,platforms:this._preset==="metro"?[...this._platforms]:[]}}get presetConditions(){return X.find(e=>e.id===this._preset).conditions}get automaticConditions(){return X.find(e=>e.id===this._preset).automatic}get conditions(){return[...new Set([...this.presetConditions,...this._preset==="metro"?[]:this._manual])]}notifyChange(){this.dispatchEvent(new CustomEvent("conditions-change",{detail:this.value,bubbles:!0,composed:!0}))}selectPreset(e){X.find(i=>i.id===e)&&(this._preset=e,this._draft="",this._error="",this.notifyChange())}togglePlatform(e){if(!Ne.some(i=>i.id===e))return;let t=this._platforms.includes(e);t&&this._platforms.length===1||(this._platforms=Ne.map(i=>i.id).filter(i=>i===e?!t:this._platforms.includes(i)),this.notifyChange())}addConditions(){if(this._preset==="metro")return;let e=this._draft.trim().split(/[\s,]+/u).filter(Boolean);if(e.length===0)return;if(e.some(i=>this.automaticConditions.includes(i)&&!this.presetConditions.includes(i))){this._error=`${Cr.format(this.automaticConditions)} are handled automatically.`;return}if(e.some(i=>i.length>64||i.startsWith(".")||/^\d+$/u.test(i))){this._error="Use condition names of up to 64 characters, without a leading dot or an all-numeric name.";return}let t=[...new Set([...this._manual,...e.filter(i=>!this.presetConditions.includes(i))])];if(t.length>ai){this._error=`Use up to ${ai} manual conditions.`;return}this._manual=t,this._draft="",this._error="",this.notifyChange()}removeCondition(e){this.presetConditions.includes(e)||(this._manual=this._manual.filter(t=>t!==e),this._error="",this.notifyChange())}render(){let e=this._preset!=="metro",t=this.automaticConditions.filter(i=>i!=="import"&&i!=="require");return a`<section aria-label="${this.showConditions?"Conditions":"Bundle actions"}"><div class="conditions-head" ?data-conditions-hidden="${!this.showConditions}"><h2 id="conditions-heading">Conditions</h2><div class="presets" role="group" aria-label="Condition preset">${X.map(i=>a`<button type="button" aria-pressed="${this._preset===i.id}" @click="${()=>this.selectPreset(i.id)}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${i.icon}</svg>${i.label}</button>`)}</div>${this._preset==="metro"?a`<div class="platforms" role="group" aria-label="Metro platforms"><span>Platforms</span>${Ne.map(({id:i,label:r})=>a`<label><input type="checkbox" .checked="${this._platforms.includes(i)}" ?disabled="${this._platforms.includes(i)&&this._platforms.length===1}" @change="${()=>this.togglePlatform(i)}">${r}</label>`)}</div>`:d} <button type="button" class="manual-toggle" ?hidden="${!e}" aria-expanded="${this._manualOpen}" aria-controls="manual-conditions" @click="${()=>{this._manualOpen=!this._manualOpen}}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 4 4 4-4 4"/></svg>Manual conditions</button><slot name="actions"></slot></div><div id="manual-conditions" ?hidden="${!this.showConditions||!e||!this._manualOpen}"><form class="condition-editor" @submit="${i=>{i.preventDefault(),this.addConditions()}}"><ul aria-label="Export conditions">${this.conditions.map(i=>this.presetConditions.includes(i)?a`<li class="preset"><code>${i}</code></li>`:a`<li><code>${i}</code><button type="button" aria-label="${`Remove condition ${i}`}" @click="${()=>this.removeCondition(i)}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="m4 4 8 8m0-8-8 8"/></svg></button></li>`)}</ul><div class="condition-input"><input type="text" aria-label="Add conditions" aria-describedby="conditions-help" aria-invalid="${!!this._error}" aria-errormessage="condition-error" placeholder="Add condition…" autocomplete="off" maxlength="1040" .value="${this._draft}" @input="${i=>{this._draft=i.target.value,this._error=""}}" @keydown="${i=>{i.key===" "&&!i.isComposing&&(i.preventDefault(),this.addConditions())}}" @blur="${()=>this.addConditions()}"></div></form><p id="conditions-help">Package export conditions. <code>import</code> / <code>require</code>${t.map((i,r)=>a`${r<t.length-1?", ":t.length>1?", and ":" and "}<code>${i}</code>`)} are automatic.</p>${this._error?a`<p id="condition-error" class="error" role="alert">${this._error}</p>`:d}</div></section>`}};customElements.define("bundle-conditions",Oe);var li=a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" aria-hidden="true"><circle cx="8" cy="8" r="3"/><path d="M1 8h4m6 0h4"/></svg>`,ni=a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="m4 6 4 4 4-4"/></svg>`,Er=100,Ar=[{kind:"branch",label:"Branch",icon:a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" aria-hidden="true"><circle cx="4" cy="3" r="1.5"/><circle cx="4" cy="13" r="1.5"/><circle cx="12" cy="3" r="1.5"/><path d="M4 4.5v7m0-3h3a5 5 0 0 0 5-4"/></svg>`},{kind:"tag",label:"Tag",icon:a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round" aria-hidden="true"><path d="M2 2h5.5l6.5 6.5-5.5 5.5L2 7.5Z"/><circle cx="5" cy="5" r="1"/></svg>`},{kind:"commit",label:"Commit SHA",icon:li}],di=/^v?(\d+(?:\.(?:\d+|x))*)(?:[-+](.+))?$/iu;function Tr(s){let e=di.exec(s);return e?e[2]===void 0?"line":"version":"other"}function ci(s){let e=s.map(i=>{let r=di.exec(i);return{name:i,parts:r?.[1].split(".").map(o=>o.toLowerCase()==="x"?1/0:Number(o)),suffix:r?.[2]??""}}),t=(i,r)=>{if(!!i.suffix!=!!r.suffix)return i.suffix?1:-1;for(let o=0;o<Math.max(i.parts.length,r.parts.length);o++){let n=(r.parts[o]??1/0)-(i.parts[o]??1/0);if(n)return n}return i.suffix.localeCompare(r.suffix)};return[...e.filter(i=>i.parts).toSorted(t),...e.filter(i=>!i.parts)].map(i=>i.name)}function Ir(s,e,t){let i=n=>n===t||!n.includes("/")?null:n.slice(0,n.indexOf("/")),r=Map.groupBy(s.filter(i),i),o=s.filter(n=>!(r.get(i(n))?.length>2)).map(n=>({name:n}));for(let[n,l]of r)l.length<=2||(o.push({prefix:n,count:l.length,expanded:e.has(n)}),e.has(n)&&o.push(...ci(l.map(c=>c.slice(n.length+1))).map(c=>({name:`${n}/${c}`,label:c,group:n}))));return o}async function Pe(s,e,t){let i=await m(`/api/admin/repositories/${s}?${new URLSearchParams(e)}`,{credentials:"same-origin",headers:{accept:"application/json"},signal:t});if(!i.ok){let r=await i.json().catch(()=>null);if(r?.error==="github-rate-limited"){let o=Number(i.headers.get("retry-after")),n=Math.ceil(o/60),l=Number.isFinite(o)&&o>0?` Try again in about ${n} ${n===1?"minute":"minutes"}.`:" Try again after the limit resets.";throw new Error(`GitHub\u2019s API rate limit has been reached.${l}`)}throw r?.error==="github-status-403"?new Error("GitHub denied this request. Check repository access and the GitHub App\u2019s read permissions."):r?.error==="github-unauthorized"?new Error("GitHub authentication has expired or was revoked. Sign in again and check the repository App installation."):r?.error==="github-unreachable"?new Error("Could not connect to GitHub. Try again shortly."):i.status===404?new Error("This repository, revision, or directory is unavailable."):i.status===403?new Error("Repository access is required to browse files."):new Error("Could not load repository files from GitHub. Try again.")}return i.json()}var De=class extends M{static styles=[h(f),h(ei)];static properties={installTooltips:{attribute:!1},createBundle:{attribute:!1},_building:{state:!0},_opening:{state:!0},_buildError:{state:!0},initialRepoId:{attribute:!1},_repos:{state:!0},_loadingRepos:{state:!0},_reposError:{state:!0},_repoId:{state:!0},_refs:{state:!0},_refKind:{state:!0},_refName:{state:!0},_path:{state:!0},_entries:{state:!0},_selected:{state:!0},_commit:{state:!0},_packageEntryPoints:{state:!0},_solidityEntryPoints:{state:!0},_soliditySuggestionsLimited:{state:!0},_loadingRefs:{state:!0},_loading:{state:!0},_error:{state:!0},_refsError:{state:!0},_limited:{state:!0},_revisionOpen:{state:!0},_revisionQuery:{state:!0},_activeRevision:{state:!0},_expandedPrefixes:{state:!0}};constructor(){super(),this._repos=[],this._loadingRepos=!0,this._reposError="",this.initialRepoId=null,this._building=!1,this._opening=!1,this._buildError="",this._repoId=null,this._refs={branches:[],tags:[]},this._refKind="branch",this._refName="",this._path="",this._entries=null,this._selected=new Set,this._dismissedSuggestions=new Set,this._bundleConditions=oi(),this._packageEntryPoints=[],this._solidityEntryPoints=[],this._soliditySuggestionsLimited=!1,this._commit="",this._directories=new Map,this._loadingRefs=!1,this._loading=!1,this._error="",this._refsError="",this._limited=!1,this._revisionOpen=!1,this._revisionQuery="",this._activeRevision=-1,this._expandedPrefixes=new Set,this._onViewport=()=>this.positionRevisionSuggestions()}connectedCallback(){super.connectedCallback(),globalThis.addEventListener("resize",this._onViewport),globalThis.addEventListener("scroll",this._onViewport,!0)}updated(e){e.has("installTooltips")&&this.installTooltips?.(this.renderRoot),this.positionRevisionSuggestions()}firstUpdated(){this.loadRepositories()}async loadRepositories(){this._reposRequest?.abort(),this.selectRepository(null),this._repos=[],this._reposError="",this._loadingRepos=!0;let e=new AbortController;this._reposRequest=e;try{let t=await Pe("browsable",{},e.signal);if(e.signal.aborted)return;this._repos=t.repos,this._repos.some(i=>i.repoId===this.initialRepoId)&&this.selectRepository(this.initialRepoId)}catch{e.signal.aborted||(this._reposError="Could not load repositories. Try again.")}finally{e.signal.aborted||(this._loadingRepos=!1)}}disconnectedCallback(){this._buildRequest?.abort(),this._opening=!1,globalThis.removeEventListener("resize",this._onViewport),globalThis.removeEventListener("scroll",this._onViewport,!0),clearTimeout(this._browseTimer),this._reposRequest?.abort(),this._refsRequest?.abort(),this._request?.abort(),this._directories.clear(),this._dismissedSuggestions.clear(),this._packageEntryPoints=[],this._solidityEntryPoints=[],this._soliditySuggestionsLimited=!1,super.disconnectedCallback()}resetFiles(){this._buildError="",clearTimeout(this._browseTimer),this._request?.abort(),this._directories.clear(),this._loading=!1,this._entries=null,this._path="",this._commit="",this._selected=new Set,this._dismissedSuggestions.clear(),this._packageEntryPoints=[],this._solidityEntryPoints=[],this._soliditySuggestionsLimited=!1,this._error="",this._limited=!1}async selectRepository(e){if(this.closeRevisionSuggestions(),this._refsRequest?.abort(),this.resetFiles(),this._repoId=e,this._refs={branches:[],tags:[]},this._refsError="",this._refKind="branch",this._refName="",e==null){this._loadingRefs=!1;return}let t=new AbortController;this._refsRequest=t,this._loadingRefs=!0;try{let{defaultContents:i,...r}=await Pe("refs",{repoId:e,withDefault:"true"},t.signal);if(t.signal.aborted)return;this._refs=r,this._refName=r.defaultBranch||r.branches[0]||"",i?this.useDirectory(i,""):this._refName&&this.loadDirectory("")}catch(i){t.signal.aborted||(this._refsError=i.message)}finally{t.signal.aborted||(this._loadingRefs=!1)}}changeRevision(e,t){this._refsRequest?.abort(),this._loadingRefs=!1,this.resetFiles(),this._refKind=e,this._refName=t}selectRevisionType(e){this._refKind!==e&&(this.closeRevisionSuggestions(),this.changeRevision(e,e==="branch"&&this._refs.defaultBranch||""),this._refName&&this.loadDirectory(""))}editRevision(e){this.changeRevision(this._refKind,e);let t=e.trim();if(!t)return;let i=this._refKind==="branch"?this._refs.branches:this._refs.tags;this._refKind!=="commit"&&(i.includes(t)||this._refKind==="branch"&&t===this._refs.defaultBranch)?this.loadDirectory(""):this._browseTimer=setTimeout(()=>{this.loadDirectory("")},350)}revisionSuggestions(){let e=this._refKind==="branch"?this._refs.branches:this._refKind==="tag"?this._refs.tags:[],t=this._refKind==="branch"?[...this._refs.defaultBranch?[this._refs.defaultBranch]:[],...ci(e.filter(r=>r!==this._refs.defaultBranch))]:e,i=this._revisionQuery.trim().toLowerCase();return t.filter(r=>r.toLowerCase().includes(i))}revisionEntries(e=this._expandedPrefixes){let t=this.revisionSuggestions();return this._refKind==="branch"&&!this._revisionQuery.trim()?Ir(t,e,this._refs.defaultBranch):t.map(i=>({name:i}))}toggleRevisionGroup(e){let t=new Set(this._expandedPrefixes);t.delete(e)||t.add(e),this._expandedPrefixes=t}revisionSections(e){let t=o=>o.group??(this._refKind==="branch"?Tr(o.name):"all"),i=e[1]?.prefix==null?e[1]:void 0,r=[];for(let[o,n]of e.entries()){if(n.prefix!=null){r.push({header:n,index:o});continue}let l=t(o===0&&n.name===this._refs.defaultBranch&&i?i:n);r.at(-1)?.key===l?r.at(-1).items.push({entry:n,index:o}):r.push({key:l,items:[{entry:n,index:o}]})}return r}showRevisionSuggestions(e=!0){this._refKind==="commit"||this._repoId==null||this._loadingRefs||(this._revisionOpen||(this._expandedPrefixes=new Set(this._refName.includes("/")?[this._refName.slice(0,this._refName.indexOf("/"))]:[])),this._revisionQuery=e?"":this._refName,this._activeRevision=-1,this.renderRoot.querySelector(".revision-menu").showPopover())}closeRevisionSuggestions(){this.renderRoot?.querySelector(".revision-menu")?.hidePopover(),this._revisionOpen=!1,this._activeRevision=-1}pickRevision(e){this.editRevision(e),this.renderRoot.querySelector(".revision-name").focus({preventScroll:!0}),this.closeRevisionSuggestions()}positionRevisionSuggestions(){if(!this._revisionOpen)return;let e=this.renderRoot.querySelector(".revision-menu"),t=e.querySelector(".revision-options"),i=this.renderRoot.querySelector(".revision-name").getBoundingClientRect(),r=8,o=6,n=parseFloat(getComputedStyle(this).fontSize),l=document.createRange(),c=t.querySelector(".revision-section > button"),p=c?parseFloat(getComputedStyle(c).paddingLeft)+parseFloat(getComputedStyle(c).paddingRight):0,u=[...t.querySelectorAll(".revision-section")].map(O=>{let A=0;for(let fe of O.querySelectorAll("button > span"))l.selectNodeContents(fe),A=Math.max(A,l.getBoundingClientRect().width);return{section:O,count:O.children.length,columnWidth:Math.max(5*n,Math.min(15*n,Math.ceil(A+p)+1))}}),v=u.length>0&&parseFloat(getComputedStyle(u[0].section).columnGap)||0,_=e.offsetWidth-t.clientWidth,S=Math.min(window.innerWidth-2*r,Math.max(i.width,...u.map(({count:O,columnWidth:A})=>Math.min(3,Math.ceil(O/8))*(A+v)-v+_))),R=this.revisionEntries({has:()=>!0}).length<=8;for(let{section:O,count:A,columnWidth:fe}of u){let Mi=Math.max(1,Math.floor((S-_+v)/(fe+v)));O.style.setProperty("--revision-columns",R?1:Math.ceil(A/Math.ceil(A/Mi)))}e.style.width=`${S}px`,e.style.left=`${Math.max(r,Math.min(i.left,window.innerWidth-S-r))}px`;let Q=window.innerHeight-i.bottom-o-r,ee=i.top-o-r,te=Q<Math.min(e.scrollHeight,320)&&ee>Q;e.style.maxHeight=`${Math.max(0,Math.min(420,te?ee:Q))}px`,e.style.top=`${Math.max(r,te?i.top-e.offsetHeight-o:i.bottom+o)}px`,e.dataset.positioned=""}async revisionKeyDown(e){if(e.key==="Escape"||e.key==="Tab"){e.key==="Escape"&&this._revisionOpen&&(e.preventDefault(),e.stopPropagation()),this.closeRevisionSuggestions();return}if(e.key==="Enter"){let i=this.revisionEntries()[this._activeRevision];this._revisionOpen&&i?.prefix!=null?(e.preventDefault(),this.toggleRevisionGroup(i.prefix)):this._revisionOpen&&i!=null?(e.preventDefault(),this.pickRevision(i.name)):this.closeRevisionSuggestions();return}if(this._refKind==="commit"||!["ArrowDown","ArrowUp"].includes(e.key))return;e.preventDefault(),this._revisionOpen||this.showRevisionSuggestions();let t=this.revisionEntries().length;this._activeRevision=t===0?-1:e.key==="ArrowDown"?Math.min(this._activeRevision+1,t-1):this._activeRevision<=0?t-1:this._activeRevision-1,await this.updateComplete,this.renderRoot.querySelector("[data-active]")?.scrollIntoView({block:"nearest"})}async loadDirectory(e,t=!1){if(clearTimeout(this._browseTimer),this._repoId==null||!this._refName.trim())return;t&&this.resetFiles(),this._request?.abort();let i=new AbortController;this._request=i,this._path=e,this._entries=null,this._error="",this._limited=!1,this._packageEntryPoints=[],this._solidityEntryPoints=[],this._soliditySuggestionsLimited=!1,this._loading=!1;let r=this._refName.trim();if(this._refKind==="commit"&&!/^[a-f\d]{7,40}$/iu.test(r)){this._error="Enter a commit SHA with 7 to 40 hexadecimal characters.";return}let o=this._commit||(this._refKind==="commit"?r:`${this._refKind==="branch"?"heads":"tags"}/${r}`),n=JSON.stringify([this._repoId,this._commit,e]),l=this._commit&&this._directories.get(n);if(l){this._directories.delete(n),this._directories.set(n,l),this._entries=l.entries,this._limited=l.limited,this._packageEntryPoints=l.packageEntryPoints,this._solidityEntryPoints=l.solidityEntryPoints,this._soliditySuggestionsLimited=l.soliditySuggestionsLimited;return}this._loading=!0;try{let c=await Pe("contents",{repoId:this._repoId,ref:o,path:e},i.signal);if(i.signal.aborted)return;this.useDirectory(c,e)}catch(c){i.signal.aborted||(this._directories.clear(),this._error=c.message)}finally{i.signal.aborted||(this._loading=!1)}}useDirectory(e,t){this._path=t,this._commit=e.commit,this._entries=e.entries.toSorted((r,o)=>+(o.type==="dir")-+(r.type==="dir")||r.name.localeCompare(o.name)),this._limited=e.limited,this._packageEntryPoints=e.packageEntryPoints??[],this._solidityEntryPoints=e.solidityEntryPoints??[],this._soliditySuggestionsLimited=e.soliditySuggestionsLimited??!1;let i=[...this._packageEntryPoints,...this._solidityEntryPoints].filter(r=>!this._dismissedSuggestions.has(r));if(this._selected=new Set([...this._selected,...i]),/^[a-f\d]{40}$/iu.test(e.commit)){let r=JSON.stringify([this._repoId,e.commit,t]);this._directories.set(r,{entries:this._entries,limited:this._limited,packageEntryPoints:this._packageEntryPoints,solidityEntryPoints:this._solidityEntryPoints,soliditySuggestionsLimited:this._soliditySuggestionsLimited}),this._directories.size>Er&&this._directories.delete(this._directories.keys().next().value)}}toggleFile(e){let t=new Set(this._selected);t.has(e)?(t.delete(e),this._dismissedSuggestions.add(e)):(t.add(e),this._dismissedSuggestions.delete(e)),this._selected=t}clearFiles(){for(let e of this._selected)this._dismissedSuggestions.add(e);this._selected=new Set}hasScriptEntryPoints(){return[...this._selected].some(e=>/\.[cm]?[tj]sx?$/iu.test(e))}async buildBundle(){if(this._building||this._opening||!this.createBundle||!this._commit||this._selected.size===0)return;let e=new AbortController;this._buildRequest=e,this._building=!0,this._buildError="";try{let t=await this.createBundle({repoId:this._repoId,commit:this._commit,entries:[...this._selected],conditions:this._bundleConditions},e.signal);e.signal.aborted||(this._opening=!0,this.dispatchEvent(new CustomEvent("bundle-created",{detail:t,bubbles:!0,composed:!0})))}catch(t){e.signal.aborted||(this._buildError=t.message)}finally{this._building=!1}}render(){let e=this._building||this._opening,t=this._repos.find(l=>l.repoId===this._repoId),i=this._path.split("/").filter(Boolean),r=t&&this._commit?`https://github.com/${[...t.fullName.split("/"),"tree",this._commit,...i].map(encodeURIComponent).join("/")}`:null,o=this.revisionEntries(),n=this._refKind==="commit"?"Commit SHA":this._refKind==="tag"?"Tag":"Branch";return a`<p class="intro ui-hint">Choose a repository and revision, then select files to use as entry points.</p><div ?inert="${e}"><div class="source-fields"><div class="field"><span>Repository</span><repository-selector label="Repository" ?disabled="${this._loadingRepos}" .options="${this._repos.map(l=>({value:l.repoId,label:l.fullName}))}" .value="${this._repoId}" @repository-change="${l=>this.selectRepository(l.detail.value)}"></repository-selector></div><form class="revision" @focusout="${l=>{l.currentTarget.contains(l.relatedTarget)||this.closeRevisionSuggestions()}}" @submit="${l=>{l.preventDefault(),this.loadDirectory("",!0)}}"><div class="revision-switch" role="group" aria-label="Revision type">${Ar.map(({kind:l,label:c,icon:p})=>a`<button type="button" aria-label="${c}" data-tooltip="${c}" aria-pressed="${this._refKind===l}" ?disabled="${!t||this._loadingRefs}" @click="${()=>{this.selectRevisionType(l),this.renderRoot.querySelector(".revision-name").focus(),this.showRevisionSuggestions()}}">${p}</button>`)}</div><input class="revision-name" type="text" aria-label="${n}" role="${E(this._refKind==="commit"?void 0:"combobox")}" aria-autocomplete="${E(this._refKind==="commit"?void 0:"list")}" aria-expanded="${E(this._refKind==="commit"?void 0:String(this._revisionOpen))}" aria-controls="${E(this._refKind==="commit"?void 0:"bundle-revisions")}" aria-activedescendant="${E(this._revisionOpen&&this._activeRevision>=0?`revision-${this._activeRevision}`:void 0)}" autocomplete="off" placeholder="${this._refKind==="commit"?"Commit SHA\u2026":`Choose or enter a ${this._refKind}\u2026`}" .value="${this._refName}" ?disabled="${!t||this._loadingRefs}" @focus="${()=>this.showRevisionSuggestions()}" @click="${()=>this.showRevisionSuggestions()}" @keydown="${this.revisionKeyDown}" @input="${l=>{this.editRevision(l.target.value),this.showRevisionSuggestions(!1)}}"> ${this._refKind==="commit"?d:a`<button type="button" class="revision-expand" aria-label="${`Show ${this._refKind} suggestions`}" aria-expanded="${this._revisionOpen}" ?disabled="${!t||this._loadingRefs}" @mousedown="${l=>l.preventDefault()}" @click="${()=>{this._revisionOpen?this.closeRevisionSuggestions():(this.renderRoot.querySelector(".revision-name").focus(),this.showRevisionSuggestions())}}">${ni}</button>`}<div class="revision-menu" id="bundle-revisions" popover="auto" role="listbox" aria-label="${`${n} suggestions`}" @beforetoggle="${l=>{this._revisionOpen=l.newState==="open",delete l.target.dataset.positioned,this._revisionOpen||(this._activeRevision=-1)}}"><div class="revision-options">${this.revisionSections(o).map(({header:l,index:c,items:p})=>l?a`<button type="button" role="option" class="revision-group" id="${`revision-${c}`}" aria-selected="false" aria-expanded="${l.expanded}" ?data-active="${c===this._activeRevision}" tabindex="-1" @mousedown="${u=>u.preventDefault()}" @click="${()=>{this._activeRevision=-1,this.toggleRevisionGroup(l.prefix)}}">${ni}<span>${l.prefix}/</span><span class="count" aria-label="${`${l.count} branches`}">${l.count}</span></button>`:a`<div class="revision-section" role="none">${p.map(({entry:u,index:v})=>a`<button type="button" role="option" id="${`revision-${v}`}" aria-label="${E(u.label===void 0?void 0:u.name)}" aria-selected="${u.name===this._refName}" ?data-active="${v===this._activeRevision}" tabindex="-1" @mousedown="${_=>_.preventDefault()}" @click="${()=>this.pickRevision(u.name)}"><span data-tooltip-truncated data-tooltip="${u.name}">${u.label??u.name}</span></button>`)}</div>`)}</div>${o.length>0?d:a`<p class="revision-empty">${this._revisionQuery?"No matching suggestions. Enter a revision name to browse.":`No ${this._refKind} suggestions available.`}</p>`}</div></form></div>${this._reposError?a`<p class="message" role="alert">${this._reposError} <button type="button" class="text-action" @click="${()=>this.loadRepositories()}">Retry</button></p>`:d} ${this._refsError?a`<p class="message" role="status">${this._refsError} <button type="button" class="text-action" @click="${()=>this.selectRepository(this._repoId)}">Retry</button></p>`:d}<section class="browser" aria-label="Repository files" aria-busy="${this._loadingRepos||this._loading||this._loadingRefs}"><div class="browser-head"><nav class="breadcrumbs" aria-label="Repository directory"><button type="button" ?disabled="${!this._commit}" aria-current="${E(this._path?void 0:"location")}" @click="${()=>this.loadDirectory("")}">${t?.fullName??"Repository"}</button>${i.map((l,c)=>a`<span aria-hidden="true">/</span><button type="button" aria-current="${E(c===i.length-1?"location":void 0)}" @click="${()=>this.loadDirectory(i.slice(0,c+1).join("/"))}">${l}</button>`)}</nav>${r?a`<a class="commit-link" href="${r}" target="_blank" rel="noopener noreferrer" data-tooltip="${this._commit}" data-tooltip-icon="commit" aria-label="${`View directory at commit ${this._commit.slice(0,7)} on GitHub`}">${li}<code>${this._commit.slice(0,7)}</code></a>`:d}</div><div class="file-browser">${this._loadingRepos||this._loading||this._loadingRefs?a`<p class="empty" role="status">${this._loadingRepos?"Loading repositories\u2026":this._loadingRefs?"Loading revisions\u2026":"Loading files\u2026"}</p>`:this._error?a`<p class="empty error" role="alert">${this._error} <button type="button" class="text-action" @click="${()=>this.loadDirectory(this._path)}">Retry</button></p>`:this._entries==null?a`<p class="empty">${t?"Choose a revision to browse its files.":this._repos.length>0?"Select a repository to browse its files.":"No accessible repositories available."}</p>`:this._entries.length===0?a`<p class="empty">This directory is empty.</p>`:a`<div class="file-grid">${this._entries.map(l=>l.type==="dir"?a`<button type="button" class="file-tile directory" @click="${()=>this.loadDirectory(l.path)}">${_t}<span data-tooltip-truncated data-tooltip="${l.path}">${l.name}</span><span class="arrow" aria-hidden="true">›</span></button>`:a`<label class="${`file-tile ${this._selected.has(l.path)?"selected":""} ${l.type==="file"?"":"unsupported"}`}" data-tooltip="${l.type==="file"?d:`${l.path} (${l.type})`}"><input type="checkbox" aria-label="${`Select ${l.path} as an entry point`}" .checked="${this._selected.has(l.path)}" ?disabled="${l.type!=="file"}" @change="${()=>this.toggleFile(l.path)}">${_e(l.name)}<span data-tooltip-truncated data-tooltip="${l.type==="file"?l.path:d}">${l.name}</span></label>`)}</div>`}</div>${this._limited?a`<p class="message ui-hint">Showing GitHub’s first 1,000 entries in this directory.</p>`:d}</section>${ti(this._packageEntryPoints,this._selected,l=>{this._selected=new Set([...this._selected,...l])})} ${ii(this._solidityEntryPoints,this._selected,l=>{this._selected=new Set([...this._selected,...l])},this._soliditySuggestionsLimited)}<section class="entry-points" aria-label="Selected entry points"><div class="selection"><div class="selection-head"><h2>Entry points <span aria-live="polite">${this._selected.size}</span></h2>${this._selected.size>0?a`<button type="button" class="btn clear-selection" @click="${this.clearFiles}">Clear all</button>`:d}</div>${this._selected.size>0?a`<ul>${[...this._selected].map(l=>a`<li>${_e(l)}<span data-tooltip-truncated data-tooltip="${l}">${l}</span><button type="button" aria-label="${`Remove ${l}`}" @click="${()=>this.toggleFile(l)}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="m4 4 8 8m0-8-8 8"/></svg></button></li>`)}</ul>`:a`<p class="note ui-hint">Select files above. You can choose entry points from multiple directories.</p>`}</div></section><bundle-conditions .showConditions="${this.hasScriptEntryPoints()}" @conditions-change="${l=>{this._bundleConditions=l.detail}}"><button type="button" slot="actions" class="btn primary" ?disabled="${e||!this.createBundle||!this._commit||this._selected.size===0||this._loading||this._loadingRefs}" @click="${this.buildBundle}">${this._opening?"Opening\u2026":this._building?"Creating\u2026":"Create a bundle"}</button></bundle-conditions></div>${e?a`<p class="message" role="status">${this._opening?"Opening bundle\u2026":"Building the selected entry points with Stasis\u2026"}</p>`:d} ${this._buildError?a`<p class="message error" role="alert">${this._buildError}</p>`:d}`}};customElements.define("managed-create-bundle",De);function pi(s){let e=new Map((s.repos??[]).map(i=>[i.repoId,{id:i.repoId,label:i.fullName}])),t=(s.bundles??[]).map(i=>{let r=i.repoId??"unattached";return e.has(r)||e.set(r,{id:r,label:r==="unattached"?"Unattached":i.repoFullName??String(r)}),{...i,repoId:r,repo:e.get(r).label,size:U(i.byteSize),files:null,reasons:[]}});return{repositories:[...e.values()],bundles:t,scans:[]}}async function ui(s,e){let t=await we(s.id,{signal:e});e?.throwIfAborted();let i=yt(t,s.integrity);return wt(s,i)}function hi(s){return s.map(e=>{let t=e.login||String(e.id),i=e.name?.trim()||`@${t}`,r=i===`@${t}`?"":`@${t}`,o=i.replace(/^@/u,"").split(/\s+/u).filter(Boolean).slice(0,2).map(n=>n[0]).join("").toUpperCase();return{value:e.id,label:r?`${i} ${r}`:i,displayLabel:i,secondary:r,initials:o,disabled:e.disabled,detail:e.detail}})}function mi(s,e){let t=e.normalize("NFKC").toLocaleLowerCase().trim().split(/\s+/u).filter(Boolean),i=s.filter(o=>!o.reset),r=i.filter(o=>t.every(n=>o.label.normalize("NFKC").toLocaleLowerCase().includes(n))).toSorted((o,n)=>o.label.localeCompare(n.label,void 0,{sensitivity:"base",numeric:!0}));return{pinned:s.filter(o=>o.reset),sections:[{label:null,options:r}],facets:[],showFacets:!1,count:r.length,total:i.length}}var ze=class extends G{static properties={users:{attribute:!1},resetLabel:{type:String,attribute:"reset-label"}};static styles=[G.styles,rt`.avatar{position:relative;overflow:hidden}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}`];constructor(){super(),this.users=[],this.resetLabel="",this.label="Choose user",this.placeholder="Choose user"}get searchLabel(){return"Search users"}get optionsLabel(){return"Users"}get noMatchesLabel(){return"No matching users"}get emptyLabel(){return"No users available"}get changeEvent(){return"user-change"}willUpdate(e){(e.has("users")||e.has("resetLabel"))&&(this.options=[...this.resetLabel?[{value:"",label:this.resetLabel,reset:!0}]:[],...hi(this.users)])}choices(){return mi(this.options,this._query)}optionIcon(e){return e.initials?a`<span class="avatar" aria-hidden="true">${e.initials}${P()?d:kt(e.value,a`<img alt="" loading="lazy" decoding="async" src="${`/api/avatar/${encodeURIComponent(e.value)}`}" @error="${t=>{t.currentTarget.hidden=!0}}">`)}</span>`:d}};customElements.get("user-selector")||customElements.define("user-selector",ze);var gi=`:host{padding:0;container-type:normal}.alias-table{overflow-x:auto;padding-bottom:.5rem}table{width:100%;border-collapse:collapse;text-align:left}th,td{padding:.35rem .5rem;border-bottom:1px solid var(--border)}th{color:var(--muted);font-weight:500}td:not(.actions,.empty){overflow-wrap:anywhere}input{width:100%;min-width:7rem;padding:.3rem .45rem;border:1px solid var(--border);border-radius:.375rem;background:var(--bg);color:var(--text);font:inherit}.actions{white-space:nowrap;text-align:right}.actions .btn{min-height:1.75rem;padding:.2rem .55rem}.actions .btn+.btn{margin-left:.25rem}
15
- `;var Lr="/api/admin/repositories/aliases";async function fi(s="",e={}){let t=await m(`${Lr}${s}`,{credentials:"same-origin",...e}),i=await t.json();if(!t.ok){let r={"alias-exists":"An alias already exists for this old repository and path. Edit that row instead.","bad-old-repo":"Enter the old repository as owner/name or a GitHub URL.","bad-directory":"Enter repository directories without parent segments, backslashes, or surrounding whitespace.","bad-repo":"Choose a connected repository.","no-alias":"This alias was removed. Refresh the list and try again."};throw new Error(r[i?.error]??`HTTP ${t.status}`)}return i}var Be=class extends b{static properties={repositories:{attribute:!1},_data:{state:!0},_edit:{state:!0},_error:{state:!0},_busy:{state:!0}};static styles=[h(f),h(gi)];constructor(){super(),this._data=null,this._edit=null,this._error=null,this._busy=!1}connectedCallback(){super.connectedCallback(),this._load()}updated(e){e.has("repositories")&&e.get("repositories")!==void 0&&(this.appState.invalidate(["repository-aliases"]),this._load())}async _load(){this._error=null,await this._loadCollection("repository-aliases","repository aliases",e=>fi("",{signal:e}),e=>{this._data=e})}_start(e=null){this._error=null,this._edit=e?{...e}:{id:null,oldRepo:"",oldPath:"",repoId:null,newPath:""}}async _mutate(e,t,i){if(!(this._busy||!this._csrf||this._role!=="admin")){this._busy=!0,this._error=null;try{await this.appState.mutate(()=>fi(t?`/${encodeURIComponent(t)}`:"",{method:e,headers:{"content-type":"application/json","x-csrf-token":this._csrf},...i?{body:JSON.stringify(i)}:{}}),["repository-aliases","workspace-import"]),this._edit=null,await this._load()}catch(r){this._error=String(r?.message??r)}finally{this._busy=!1}}}_save(){let{id:e,...t}=this._edit;return this._mutate(e?"PATCH":"POST",e,t)}_field(e,t,i){return a`<td><input type="text" aria-label="${t}" placeholder="${i}" .value="${this._edit[e]}" ?disabled="${this._busy}" @input="${r=>{this._edit={...this._edit,[e]:r.target.value}}}"></td>`}_editor(){let e=(this._data?.repos??[]).filter(t=>t.active!==!1).map(t=>({value:t.repoId,label:t.fullName}));return a`<tr>${this._field("oldRepo","Old repository","owner/repository")}${this._field("oldPath","Old path","Repository root")}<td><repository-selector label="New repository" placeholder="Choose repository…" .options="${e}" .value="${this._edit.repoId}" ?disabled="${this._busy}" @repository-change="${t=>{this._edit={...this._edit,repoId:t.detail.value}}}"></repository-selector></td>${this._field("newPath","New path","Repository root")}<td class="actions"><button type="button" class="btn" ?disabled="${this._busy||!this._edit.oldRepo.trim()||this._edit.repoId==null}" @click="${()=>{this._save()}}">${this._busy?"Saving\u2026":"Save"}</button> <button type="button" class="btn" ?disabled="${this._busy}" @click="${()=>{this._edit=null,this._error=null}}">Cancel</button></td></tr>`}render(){let e=this._data?.aliases??[],t=this._data?.repos??[];return a`<section aria-label="Repository aliases"><div class="page-intro"><p class="intro">Map repository locations when importing new reports and bundles.</p><button type="button" class="btn" ?disabled="${this._busy||this._edit!=null||!this._data}" @click="${()=>this._start()}">Add alias</button></div>${this._error?a`<p class="msg error" role="alert">${this._error}</p>`:d}<div aria-busy="${this._loading}">${this._data===null?this._error?a`<button type="button" class="btn" @click="${()=>{this._load()}}">Try again</button>`:k("Loading repository aliases\u2026"):a`<div class="alias-table"><table><thead><tr><th>Old repository</th><th>Old path</th><th>New repository</th><th>New path</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody>${e.map(i=>this._edit?.id===i.id?this._editor():a`<tr><td>${i.oldRepo}</td><td class="mono">${i.oldPath||"/"}</td><td>${t.find(r=>r.repoId===i.repoId)?.fullName??"Removed repository"}${t.find(r=>r.repoId===i.repoId)?.active===!1?" (inactive)":""}</td><td class="mono">${i.newPath||"/"}</td><td class="actions"><button type="button" class="btn" ?disabled="${this._busy||this._edit!=null}" @click="${()=>this._start(i)}">Edit</button> <button type="button" class="btn" ?disabled="${this._busy||this._edit!=null}" @click="${()=>{this._mutate("DELETE",i.id)}}">Delete</button></td></tr>`)} ${this._edit?.id===null?this._editor():d} ${e.length===0&&!this._edit?a`<tr><td colspan="5" class="empty">No repository aliases yet.</td></tr>`:d}</tbody></table></div>`}</div></section>`}};customElements.define("managed-repository-aliases",Be);function bi(s){document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:s},bubbles:!0,composed:!0}))}function yi(s,e){return a`<span class="avatar" aria-hidden="true"><span>${(e?.[0]??"?").toUpperCase()}</span> ${P()?d:a`<img alt="" src="${`/api/avatar/${encodeURIComponent(s)}`}" @error="${t=>t.currentTarget.classList.add("broken")}">`}</span>`}var Or=re(at),Je=re(ot),Me=a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="m4 4 8 8m0-8-8 8"/></svg>`,pe=a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>`,Pr={admin:"Admin",manage:"Manager",triage:"Triage",view:"Viewer",none:"No access"},Dr={admin:"Manage workspace access and teams",manage:"Manage content and triage within team access",triage:"Review and triage findings",view:"Read-only access",none:"No workspace access"},qe=class extends b{static styles=[h(Wt),h(f)];render(){let e=[["manage-bundles","Bundles","Keep source archives ready for review.","bundle"],["manage-scans","Scans","Run and monitor scans from stored bundles.","scan"],["manage-reports","Reports","Review, publish, and organize findings.","report"]],t=[["manage-repos","Repositories","Connect sources and manage repository settings.","repo"],["admin-users","Users","Manage accounts, roles, and workspace access.","users"],["manage-teams","Teams","Bring people and repositories together.","team"]];return a`<div class="wrap">${w("manage",this._role,this.allowShare)}<h1 class="sr-only">Manage</h1>${this._role==null?a`<p class="msg" role="status">Loading management pages…</p>`:a`<section class="home-section" aria-labelledby="content-heading"><div class="section-heading"><h2 id="content-heading">Content & activity</h2><span>From source to findings</span></div><div class="pages">${e.filter(([i])=>i!=="manage-scans"||["admin","manage"].includes(this._role)).map(i=>this._page(i))}</div></section>${this._role==="admin"?a`<section class="home-section" aria-labelledby="workspace-heading"><div class="section-heading"><h2 id="workspace-heading">Workspace & access</h2><span>Sources, people, and permissions</span></div><div class="pages workspace-pages">${t.map(i=>this._page(i))}</div></section>`:d} <button type="button" class="history-link" @click="${()=>bi("manage-history")}"><span class="page-icon" aria-hidden="true">${y("history")}</span> <span class="page-copy"><strong>Workspace history</strong><span>Follow activity and triage changes across your workspace.</span></span> <span class="history-cta">View history ${y("arrow")}</span></button>`}</div>`}_page([e,t,i,r]){return a`<button type="button" class="${`page page-${r}`}" @click="${()=>bi(e)}"><span class="page-top"><span class="page-icon" aria-hidden="true">${y(r)}</span><strong class="page-title">${t}</strong><span class="arrow" aria-hidden="true">${y("arrow")}</span></span> <span class="page-copy"><span>${i}</span></span></button>`}};customElements.define("managed-admin-home",qe);var Ue=class extends b{static properties={_page:{state:!0},_history:{state:!0},_total:{state:!0},_error:{state:!0},_filter:{state:!0},_query:{state:!0},_repo:{state:!0},_actor:{state:!0},_options:{state:!0}};static styles=[h(Jt),h(f)];constructor(){super(),this._history=null,this._total=0,this._searchTimer=null,this._error=null,this._page=1,this._filter="all",this._query="",this._repo="",this._actor="",this._options={repos:[],users:[]},this._onActorFilter=e=>{let t=e.detail?.actor;if(typeof t!="string")return;let i=t.startsWith("user:")||t.startsWith("legacy:");this._query=i?"":t,this._filter="all",this._repo="",this._actor=i?t:"",this._load()}}connectedCallback(){super.connectedCallback(),document.addEventListener("managed-history-filter",this._onActorFilter),this._load()}disconnectedCallback(){clearTimeout(this._searchTimer),document.removeEventListener("managed-history-filter",this._onActorFilter),super.disconnectedCallback()}async _load(e=1){clearTimeout(this._searchTimer),this._error=null;let t=this._filter,i=this._query.trim(),r=this._actor,o=this._repo,n=`history:${JSON.stringify([e,t,i,o,r])}`;await this._loadCollection(n,"history",l=>At(l,e,t,i,o,r),l=>{this._history=l.history,this._total=l.total,this._page=l.page,this._options=l.filters??{repos:[],users:[]}})}_search(e){this._query=e,clearTimeout(this._searchTimer),this._loadRequest?.abort(),this._loadRequest=null,this._loading=!0,this._searchTimer=setTimeout(()=>{this._load()},250)}_setRepo(e){return this._repo=e,this._load()}_setActor(e){return this._actor=e,this._load()}_clearContext(){return this._repo="",this._actor="",this._load()}_contextFilters(){let e=this._options.repos,t=this._options.users??[],i=[{value:"",label:"All repositories",special:!0,reset:!0},...this._repo&&!e.includes(this._repo)?[{value:this._repo,label:this._repo}]:[],...e.map(r=>({value:r,label:r}))];return a`<repository-selector label="Filter history by repository" .options="${i}" .value="${this._repo}" @repository-change="${r=>{this._setRepo(r.detail.value)}}"></repository-selector><user-selector label="Filter history by user" reset-label="All users" placeholder="${this._actor?"Selected user":"All users"}" .users="${t}" .value="${this._actor}" @user-change="${r=>{this._setActor(r.detail.value)}}"></user-selector><button type="button" class="btn" aria-label="Clear repository and user filters" ?disabled="${!this._repo&&!this._actor}" @click="${()=>{this._clearContext()}}">Clear selection</button>`}render(){let e=this._history??[],t=this._page,i=(t-1)*100;return a`<div class="wrap">${w("manage-history",this._role,this.allowShare)}<h1 class="sr-only">History</h1><div class="page-intro"><p class="intro">${this._role==="admin"?"Uploads, builds, access changes, repository changes, deletions, and triage.":"Bundle, report, and triage history within your team access."}</p><span class="result-count">${this._history?this._total:"\u2026"} entries</span></div><div class="toolbar" role="search"><input type="search" maxlength="500" aria-label="Search history" placeholder="Search history…" .value="${this._query}" @input="${r=>this._search(r.target.value)}"> <select aria-label="Filter history by type" .value="${this._filter}" @change="${r=>{this._filter=r.target.value,this._load()}}"><option value="all">All activity</option><option value="triage">Triage</option><option value="visibility">Visibility</option><option value="upload">Uploads and builds</option><option value="repository">${this._role==="admin"?"Repositories":"Assignments"}</option>${this._role==="admin"?a`<option value="access">Access</option>`:d}<option value="delete">Deletions</option></select> ${this._contextFilters()} <button type="button" class="btn" ?disabled="${this._loading}" @click="${()=>this._load(t)}">Refresh</button></div>${this._error?a`<p class="msg error" role="alert">Couldn’t load history: ${this._error} <button type="button" class="btn" @click="${()=>this._load()}">Retry</button></p>`:d}<div class="manage-list" aria-busy="${this._loading}">${this._history==null?this._error?d:k("Loading history\u2026"):e.length===0?a`<div class="history"><p class="empty">${this._query.trim()||this._filter!=="all"||this._repo||this._actor?"No activity matches your filters.":"No history available yet."}</p></div>`:a`<div class="history" aria-label="Workspace history"><div class="history-head" aria-hidden="true"><span>Type</span><span>Activity</span><span>Repository / report / finding</span><span>Time</span></div>${e.map(r=>this._row(r))}</div>`}</div>${this._total>100?a`<nav class="pagination" aria-label="History pages"><span role="status">${i+1}–${Math.min(i+100,this._total)} of ${this._total} entries</span><button type="button" class="btn" ?disabled="${this._loading||t===1}" @click="${()=>this._changePage(t-1)}">Previous</button><span>Page ${t} of ${Math.ceil(this._total/100)}</span><button type="button" class="btn" ?disabled="${this._loading||i+100>=this._total}" @click="${()=>this._changePage(t+1)}">Next</button></nav>`:d}</div>`}async _changePage(e){await this._load(e),await this.updateComplete,this.renderRoot.querySelector(".manage-list")?.scrollTo({top:0})}_row(e){let t=[e.repo??e.repository,e.report,e.finding].filter(Boolean).join(" \xB7 "),i=e.actor??e.user??"Unknown user",r=e.action??"updated workspace data";return a`<div class="row"><span class="${`kind ${e.kind??""}`}">${e.kind??"activity"}</span><span class="activity-description" data-tooltip-truncated data-tooltip="${`${i} ${r}`}"><strong class="actor">${i}</strong> <span class="action">${r}</span></span><span class="detail" data-tooltip-truncated data-tooltip="${t}">${t||"\u2014"}</span><span class="history-time">${Fe(e.at)}</span></div>`}};customElements.define("managed-admin-history",Ue);function Fe(s){if(s==null||s==="")return a`<span>Unknown</span>`;let e=typeof s=="number"?s:Number(s);if(!Number.isFinite(e))return a`<span>Unknown</span>`;let t=new Date(e);return Number.isNaN(t.getTime())?a`<span>Unknown</span>`:a`<time datetime="${t.toISOString()}">${t.toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}</time><span>${t.toLocaleTimeString(void 0,{hour:"numeric",minute:"2-digit"})}</span>`}function vi(s){if(s==null||s==="")return"Unknown";let e=typeof s=="number"?s:Number(s);return Number.isFinite(e)&&!Number.isNaN(new Date(e).getTime())?`Last seen ${new Date(e).toLocaleString()}`:"Unknown"}function _i(s){return s?.lastActivityAt??s?.lastActivity??s?.lastWriteAt??s?.lastActiveAt}var je=class extends b{static properties={_query:{state:!0},_users:{state:!0},_teams:{state:!0},_error:{state:!0}};static styles=[h(Yt),h(f)];constructor(){super(),this._users=null,this._query="",this._teams=null,this._error=null}connectedCallback(){super.connectedCallback(),this._load()}async _load(){this._error=null,await this._loadCollection("users","users",e=>Promise.all([Tt(e),V(e)]),([e,t])=>{this._users=e,this._teams=Array.isArray(t?.teams)?t.teams:[]})}_filteredUsers(){let e=this._query.trim().toLocaleLowerCase();return(this._users??[]).filter(t=>[t.name,t.login,t.role,...(this._teams??[]).filter(i=>i.members?.some(r=>r.userId===t.id)).map(i=>i.name)].filter(Boolean).join(" ").toLocaleLowerCase().includes(e))}render(){let e=this._filteredUsers();return a`<div class="wrap">${w("admin-users",this._role,this.allowShare)}<h1 class="sr-only">Users</h1><div class="page-intro"><p class="intro">Manage workspace access and roles.</p></div><div class="collection-toolbar" role="search"><input type="search" aria-label="Search users" placeholder="Search by name, username, or team…" .value="${this._query}" @input="${t=>{this._query=t.target.value}}"><span class="result-count" role="status">${this._users&&this._query.trim()?`${e.length} matching out of `:""}${this._users?.length??"\u2026"} users</span></div>${this._error?a`<p class="msg error" role="alert">Couldn't load users: ${this._error}</p>`:d}<div class="manage-list" aria-busy="${this._loading}">${this._users==null?this._error?d:k("Loading users\u2026"):this._list(e)}</div></div>`}_list(e){return this._users.length===0?a`<p class="msg">No users yet.</p>`:e.length===0?a`<div class="empty"><strong>No matching users</strong><p>Try another name, username, or team.</p></div>`:a`<div class="directory"><div class="list-head" aria-hidden="true"><span>Account</span><span>Team access</span><span>Last seen</span><span>Last activity</span><span>Role</span><span></span></div><ul class="users">${e.map(t=>this._row(t))}</ul></div>${this._users.some(t=>t.id===this._me)?a`<p class="self-note ui-hint">Your own role can only be changed by another admin.</p>`:d}`}_row(e){let t=e.id===this._me,i=(this._teams??[]).flatMap(r=>{let o=r.members?.find(n=>n.userId===e.id);return o==null?[]:[{team:r,member:o}]});return a`<li><span class="person">${yi(e.id,e.login)} <span class="who"><span class="name"><span class="name-text">${e.name||e.login}</span>${t?a`<span class="you">You</span>`:d}</span> <span class="login">@${e.login}</span> </span></span><span class="memberships">${ae(e.role,"manage")?a`<span class="team-access"><strong class="team-access-role">${e.role==="admin"?"All reports":"Owned and team reports"}</strong><span class="team-perms"><span class="permission-granted">+ Deps</span><span class="permission-granted">+ Security</span></span></span>`:i.length===0?a`<span class="no-team">No team access</span>`:i.map(({team:r,member:o})=>a`<span class="team-access"><strong>${y("team")}<span>${r.name}</span></strong><span class="team-perms">${["dependencies","security"].map(n=>a`<span class="${o[n]===!0?"permission-granted":"permission-denied"}">${o[n]===!0?"+":"\u2212"} ${n==="dependencies"?"Deps":"Security"}</span>`)}</span></span>`)} </span><span class="last-seen" aria-label="${vi(e.lastSeenAt)}">${Fe(e.lastSeenAt)}</span> <button type="button" class="activity-link" aria-label="${`Show activity by ${e.login}`}" @click="${()=>this._showActivity(e.id)}"><span class="last-activity" aria-label="${`Last activity ${vi(_i(e)).replace(/^Last seen /u,"")}`}">${Fe(_i(e))}</span></button> <span class="access"><select class="role" ?disabled="${t}" aria-label="${`Change ${e.login}\u2019s role`}" aria-description="${Dr[e.role]??""}" @change="${r=>this._changeRole(e,r.target.value,r.target)}">${pt.map(r=>a`<option value="${r}" ?selected="${r===e.role}">${Pr[r]}</option>`)}</select> </span><span class="view-as">${t?d:a`<button type="button" class="icon-btn" aria-label="${`View as ${e.login}`}" data-tooltip="See the app as this user" @click="${r=>{this._viewAs(e,r.currentTarget)}}">${y("show")}</button>`}</span></li>`}async _viewAs(e,t){t.disabled=!0;try{await ft(e.id,this._csrf)}catch(i){t.disabled=!1,this.appState.notify(`Couldn't view as @${e.login}: ${i?.message??i}`)}}async _changeRole(e,t,i){let r=e.role;if(t!==r){try{await this.appState.mutate(()=>It(e.id,t,this._csrf),["users","teams","reports","history"]),e.role=t,await this._load()}catch(o){console.warn("admin: set role failed:",o),i.value=r}this.requestUpdate()}}_showActivity(e){document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:"manage-history",actor:`user:${e}`},bubbles:!0,composed:!0}))}};customElements.define("managed-admin-users",je);var wi=y("repo"),He=class extends b{static properties={_publicRepoOpen:{state:!0},_publicRepository:{state:!0},_publicRepoError:{state:!0},_addingPublic:{state:!0},_data:{state:!0},_error:{state:!0},_actionError:{state:!0},_scope:{state:!0},_showAll:{state:!0},_query:{state:!0},_organization:{state:!0},_loading:{state:!0},_busy:{state:!0},_connectingApp:{state:!0},_detail:{state:!0},_aliases:{state:!0},_impact:{state:!0},_impactLoading:{state:!0},_removeOpen:{state:!0},_acknowledge:{state:!0},_deleteTriage:{state:!0},_confirmName:{state:!0}};static styles=[h(Xt),h(f)];constructor(){super(),this._publicRepoOpen=!1,this._publicRepository="",this._publicRepoError=null,this._addingPublic=!1,this._data=null,this._error=null,this._actionError=null,this._scope="connected",this._showAll=!1,this._query="",this._organization=null,this._loading=!0,this._busy=null,this._connectingApp=!1,this._detail=null,this._aliases=!1,this._impact=null,this._impactLoading=!1,this._impactFresh=!1,this._removeOpen=!1,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName="",this._impactRequest=null}connectedCallback(){super.connectedCallback(),this._load()}disconnectedCallback(){super.disconnectedCallback(),this._impactRequest?.abort()}_repositoryKey(){return`repos:${JSON.stringify([this._scope,this._showAll])}`}async _load(e=!1){this._error=null;let{_scope:t,_showAll:i}=this;await this._loadCollection(this._repositoryKey(),"repositories",r=>Nt(t,i,e,r),r=>{this._data=r,this._organization=this._repositoryChoices().activeFacet})}_open(e){this._impactRequest?.abort(),this._publicRepoOpen=!1,this._scope=e,this._showAll=!1,this._query="",this._organization=null,this._detail=null,this._aliases=!1,this._impact=null,this._removeOpen=!1,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName="",this._data=null,this._actionError=null,this._load()}_setShowAll(e){this._showAll=e,this._organization=null,this._data=null,this._load()}_search(e){this._query=e}_repositoryChoices(){let e=(this._data?.repositories??[]).map(t=>({value:t.id,label:t.fullName,repo:t}));return vt(e,this._query,this._organization,{includeSingletonOrganizations:!0})}_back(e=null){return a`<div class="breadcrumb"><button type="button" class="breadcrumb-manage" @click="${()=>{document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:"manage"},bubbles:!0,composed:!0}))}}">Manage</button> <span class="breadcrumb-separator" aria-hidden="true">›</span> <button type="button" class="breadcrumb-manage" aria-label="Back to repositories" @click="${()=>{this._detail?(this._impactRequest?.abort(),this._detail=null,this._actionError=null):this._aliases?this._aliases=!1:this._open("connected")}}">Repositories</button> <span class="breadcrumb-separator" aria-hidden="true">›</span> ${e?a`<h1 class="breadcrumb-current">${e}</h1>`:d}</div>`}_openDetail(e){this._detail=e,this._actionError=null,this._impact=this.appState.read(`repo-impact:${e.id}`)??null,this._impactFresh=!1,this._removeOpen=!1,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName="",this._impactLoading=!0,this._impactRequest?.abort();let t=new AbortController;this._impactRequest=t,this.appState.load(`repo-impact:${e.id}`,"repository data",i=>Pt(e.id,i),{signal:t.signal,apply:i=>{this._impact=i}}).then(i=>(t.signal.aborted||(this._impactFresh=!0),i)).catch(i=>{!t.signal.aborted&&i?.name!=="AbortError"&&!this._impact&&(this._actionError=`Couldn't load repository data: ${i?.message??i}`)}).finally(()=>{this._impactRequest===t&&(this._impactLoading=!1)})}render(){if(this._detail)return this._detailPage(this._detail);if(this._aliases)return this._aliasesPage();let e=this._scope==="connected",t=e?"Repositories":`Add ${this._scope} repository`,i=this._repositoryChoices();return a`<div class="wrap">${w("manage-repos",this._role,this.allowShare)} ${e?a`<h1 class="sr-only">${t}</h1>`:this._back(t)}<div class="page-intro"><p class="intro">${e?"Manage connected repositories and their settings.":this._scope==="installed"?this._showAll?"Showing all repositories the GitHub App can read.":"Showing installed repositories you can access on GitHub.":"Choose a public repository your GitHub account is involved with."}</p>${e?a`<div class="repository-actions"><button type="button" class="btn" @click="${()=>this._open("installed")}">${this._accessIcon("private")} Add installed repository</button> <button type="button" class="btn" @click="${()=>this._open("public")}">${this._accessIcon("public")} Add your public repository</button> ${this._role==="admin"&&this._data?.canAddAnyPublicRepository?a`<button type="button" class="btn" aria-expanded="${this._publicRepoOpen}" @click="${()=>this._openPublicRepository()}">${this._accessIcon("public")} Add a public repository</button>`:d}</div>`:d}</div>${!e&&this._scope==="installed"?a`<div class="access-note"><p class="ui-hint">Installed repositories are readable through the GitHub App. Install it on a repository or organization to make it available here.</p><span class="access-action">${this._data?.installUrl?a`<a class="btn" href="${this._data.installUrl}" target="_blank" rel="noopener noreferrer">Configure GitHub access</a>`:a`<button type="button" class="btn" disabled="disabled">Configure GitHub access</button>`}</span></div>`:d}<div class="toolbar"><label class="search"><input type="search" aria-label="${e?"Search connected repositories":`Search ${this._scope} repositories`}" placeholder="Search by repository or owner…" .value="${this._query}" @input="${r=>this._search(r.target.value)}"></label> ${this._scope==="installed"?a`<label class="show-all"><input type="checkbox" role="switch" .checked="${this._showAll}" @change="${r=>this._setShowAll(r.target.checked)}"><span>Show all</span></label><label class="show-all-paper"><input type="checkbox" .checked="${this._showAll}" @change="${r=>this._setShowAll(r.target.checked)}"><span>Show all</span></label>`:d} ${e?a`<span class="result-count" role="status">${this._data&&(this._query.trim()||i.activeFacet!=null)?`${i.count} ${i.count===1?"repository":"repositories"} out of `:""}${this._data?.connectedCount??"\u2026"} connected</span>`:a`<button type="button" class="btn" ?disabled="${this._loading}" @click="${()=>{this._load(!0)}}">Refresh</button>`}</div>${e&&this._publicRepoOpen&&this._role==="admin"&&this._data?.canAddAnyPublicRepository?this._publicRepositoryForm():d} ${this._actionError?a`<p class="msg error" role="alert">${this._actionError}</p>`:d} ${this._error?a`<p class="msg error" role="alert">Couldn't load repositories: ${this._error}</p><button type="button" class="btn" @click="${()=>{this._load()}}">Try again</button>`:d} ${!e&&this._data?a`<p class="repository-count" role="status">${i.count}${i.count===i.total?"":` of ${i.total}`} ${i.total===1?"repository":"repositories"}</p>`:d}<div class="manage-list"><div aria-busy="${this._loading}">${this._body(i)}</div>${e&&this._role==="admin"?a`<div class="aliases-link"><button type="button" class="btn" @click="${()=>{this._publicRepoOpen=!1,this._actionError=null,this._aliases=!0}}">Aliases</button></div>`:d}</div></div>`}_aliasesPage(){return a`<div class="wrap">${w("manage-repos",this._role,this.allowShare)} ${this._back("Aliases")}<div class="manage-list"><managed-repository-aliases .session="${this.session}" .repositories="${this._data?.repositories}"></managed-repository-aliases></div></div>`}_body(e){return this._data?a`${this._data.tokenMissing&&!this._showAll&&this._scope!=="connected"?a`<p class="msg">Log out and back in to refresh your GitHub membership access.</p>`:d}<div class="repository-browser">${e.showFacets?a`<nav class="organization-list" aria-label="Filter by organization"><button type="button" class="organization" aria-pressed="${e.activeFacet==null}" @click="${()=>{this._organization=null}}"><span class="organization-name">All organizations</span><span class="organization-count">${e.total}</span></button> ${e.facets.map(t=>a`<button type="button" class="organization" aria-pressed="${e.activeFacet===t.value}" @click="${()=>{this._organization=t.value}}"><span class="organization-name" data-tooltip-truncated data-tooltip="${t.name}">${t.name}</span><span class="organization-count">${t.count}</span></button>`)}</nav>`:d}<div class="repo-results">${e.sections.map(t=>a`<section class="repo-group" aria-label="${t.label??"Repositories"}">${t.label?a`<h2 class="owner-head"><span class="owner-icon" aria-hidden="true">${t.label[0]??"?"}</span>${t.label}</h2>`:d}<ul class="repos">${t.options.map(i=>this._row(i.repo,t.organization?i.name:i.label))}</ul></section>`)} ${e.count?d:a`<div class="empty"><strong>${e.total?"No matching repositories":this._scope==="connected"?"No connected repositories yet":`No ${this._scope} repositories available`}</strong><p>${e.total?"Try a different search or organization.":this._scope==="connected"?"Add an installed or public repository to get started.":this._scope==="installed"?this._showAll?"Install the GitHub App, then refresh this list.":"No installed repositories match your GitHub access. Turn on Show all to browse every installation.":"Public repositories associated with your GitHub account will appear here."}</p></div>`}</div></div>`:this._error?d:k("Loading repositories\u2026")}_openPublicRepository(){this._publicRepoOpen=!0,this._publicRepoError=null,this.updateComplete.then(()=>this.renderRoot?.querySelector("#public-repository")?.focus())}_publicRepositoryForm(){return a`<form class="public-repository-form" aria-label="Add a public repository" @submit="${e=>{e.preventDefault(),this._addPublicRepository()}}"><label class="confirm-field" for="public-repository"><span>Public GitHub repository</span> <input id="public-repository" class="confirm-name" type="text" placeholder="owner/repo or https://github.com/owner/repo" autocomplete="off" required .value="${this._publicRepository}" ?disabled="${this._addingPublic}" @input="${e=>{this._publicRepository=e.target.value}}"></label><div class="dialog-actions"><button type="button" class="btn" ?disabled="${this._addingPublic}" @click="${()=>{this._publicRepoOpen=!1}}">Cancel</button><button type="submit" class="btn" ?disabled="${this._addingPublic||!this._publicRepository.trim()}">${this._addingPublic?"Adding\u2026":"Add repository"}</button></div>${this._publicRepoError?a`<p class="msg error" role="alert">${this._publicRepoError}</p>`:d}</form>`}async _addPublicRepository(){if(!(this._addingPublic||!this._publicRepository.trim())){this._addingPublic=!0,this._publicRepoError=null;try{await this.appState.mutate(()=>Ot(this._publicRepository.trim(),this._csrf),["repos","reports","bundles","teams","users","history","scan-sources"]),this._publicRepoOpen=!1,this._publicRepository="",await this._load()}catch(e){this._publicRepoError=e?.message??String(e)}finally{this._addingPublic=!1}}}_row(e,t){let i=`${this._accessLabel(e)}${this._scope==="connected"&&e.active===!1?" \xB7 Deactivated":""}`,r=a`${wi}<span class="repo-copy"><span class="repo-name">${t}</span><span class="repo-meta">${i}</span></span>`;return this._scope==="connected"?a`<li><button type="button" class="repo-row" aria-label="${`Manage ${e.fullName}`}" @click="${()=>this._openDetail(e)}">${r}<svg class="arrow" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" aria-hidden="true"><path d="m6 4 4 4-4 4"/></svg></button></li>`:a`<li class="repo-row">${r} ${e.selected?a`<span class="connected"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="m3 8 3 3 7-7"/></svg>Connected</span>`:e.private&&!e.installed?a`<span class="repo-meta">Needs App access</span>`:a`<button type="button" class="btn" aria-label="${`Add ${e.fullName}`}" ?disabled="${this._busy!=null}" @click="${()=>{this._setActive(e,!0)}}">${this._busy===e.id?"Adding\u2026":"Add"}</button>`}</li>`}_accessLabel(e){let t=e.visibility==="public"?"Public":e.visibility==="internal"?"Internal":e.private?"Private":null,i=e.installed?"GitHub App":"GitHub";return t?`${t} \xB7 ${i}`:i}_connectAppButton(e){return e.installed?d:a`<button type="button" class="btn connect-app" aria-label="${`Connect GitHub App to ${e.fullName}`}" ?disabled="${this._busy!=null}" @click="${()=>{this._connectApp(e)}}">${this._connectingApp&&this._busy===e.id?"Connecting\u2026":"Connect GitHub App"}</button>`}async _connectApp(e){if(!(this._busy!=null||e.installed)){this._busy=e.id,this._connectingApp=!0,this._actionError=null;try{let t=await this.appState.mutate(()=>Dt(e.id,this._csrf),["repos","history","scan-sources"]);if(!this.isConnected)return;if(!t.connected){globalThis.location.assign(t.installUrl);return}this._detail?.id===e.id&&(this._detail={...this._detail,installed:!0}),this._data&&(this._data={...this._data,repositories:this._data.repositories.map(i=>i.id===e.id?{...i,installed:!0}:i)}),await this._load()}catch(t){this._actionError=`Couldn't connect ${e.fullName}: ${t?.message??t}`}finally{this._busy=null,this._connectingApp=!1}}}_detailPage(e){let t=e.active!==!1,i=this._impact?.reports??[],r=this._impact?.bundles??[];return a`<div class="wrap">${w("manage-repos",this._role,this.allowShare)}<div class="head">${this._back()}<h1>${e.fullName}</h1></div><p class="intro ui-hint">Repository settings and stored data.</p>${this._actionError?a`<p class="msg error" role="alert">${this._actionError}</p>`:d}<section class="section" aria-label="Repository connection"><h2>Connection</h2><div class="settings-row"><div class="settings-copy"><strong>${this._accessLabel(e)}</strong><p>${t?"Active for new scans and uploads.":"Deactivated. Stored reports and bundles are retained."}</p></div><span class="${`status-line ${t?"":"inactive"}`}">${t?"Active":"Deactivated"}</span> ${this._connectAppButton(e)} ${e.htmlUrl?a`<a class="btn" href="${e.htmlUrl}" target="_blank" rel="noopener noreferrer">View on GitHub</a>`:d}</div><div class="settings-row"><div class="settings-copy"><strong>${t?"Deactivate repository":"Reactivate repository"}</strong><p>${t?"Pause new scans while preserving all stored data and attachments.":"Make this repository available for new scans and bundle attachments again."}</p></div><button type="button" class="btn" ?disabled="${this._busy!=null}" @click="${()=>{this._setActive(e,!t)}}">${this._busy===e.id&&!this._connectingApp?t?"Deactivating\u2026":"Reactivating\u2026":t?"Deactivate":"Reactivate"}</button></div></section><section class="data-section" aria-label="Stored repository data"><h2>Stored data</h2><div class="dialog-data" aria-busy="${this._impactLoading}">${[["Reports",i],["Bundles",r]].map(([o,n])=>a`<section><h3>${o} (${this._impact==null?"\u2026":n.length})</h3>${this._impactLoading&&this._impact==null?a`<p class="data-empty" role="status">Loading ${o.toLowerCase()}…</p>`:this._impact==null?a`<p class="data-empty">Attached data could not be loaded.</p><button type="button" class="btn" @click="${()=>this._openDetail(e)}">Try again</button>`:n.length>0?a`<ul>${n.map(l=>a`<li>${l.filename}${l.repoDirectory?` \xB7 ${l.repoDirectory}`:d}</li>`)}</ul>`:a`<p class="data-empty">No ${o.toLowerCase()} attached.</p>`}</section>`)}</div></section><section class="section" aria-label="Permanent repository removal"><h2>Permanent removal</h2><div class="settings-row"><div class="settings-copy"><strong>Delete repository and stored data</strong><p>Deactivation is reversible. Permanent removal deletes this repository’s attached reports and bundles; it cannot be undone.</p></div><button type="button" class="btn danger" ?disabled="${this._busy!=null||this._impactLoading||!this._impactFresh||this._impact==null}" @click="${()=>{this._removeOpen=!0,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName=""}}">Remove permanently</button></div></section>${this._removeOpen&&this._impact!=null&&!this._impactLoading?this._removeDialog(e,i,r):d}</div>`}_removeDialog(e,t,i){let r=t.length>0||i.length>0,o=this._canRemove(e);return a`<div class="dialog-backdrop" role="presentation" @click="${n=>{n.target===n.currentTarget&&(this._removeOpen=!1)}}"><section class="${`dialog ${r?"":"small"}`}" role="dialog" aria-modal="true" aria-labelledby="remove-repo-title"><h2 id="remove-repo-title">Remove ${e.fullName} permanently?</h2><p class="dialog-copy">${r?"This destructive action will remove the repository and the stored data listed below. Deactivation keeps all of it.":"This repository has no attached reports or bundles. Permanent removal deletes its connection record."}</p>${r?a`<div class="dialog-data"><section><h3>Reports to delete (${t.length})</h3><ul>${t.map(n=>a`<li>${q(n.filename)}${n.repoDirectory?` \xB7 ${n.repoDirectory}`:d}</li>`)}</ul></section><section><h3>Bundles to delete (${i.length})</h3><ul>${i.map(n=>a`<li>${n.filename}</li>`)}</ul></section></div>`:d} <label class="confirm-line"><input type="checkbox" .checked="${this._acknowledge}" @change="${n=>{this._acknowledge=n.target.checked}}"><span>I understand this permanently deletes the repository connection${r?", reports, and bundles":""}.</span></label> ${(this._impact?.triageCount??0)>0?a`<label class="confirm-line"><input type="checkbox" .checked="${this._deleteTriage}" @change="${n=>{this._deleteTriage=n.target.checked}}"><span>Also delete ${this._impact.triageCount} triage entr${this._impact.triageCount===1?"y":"ies"} belonging only to this repository.</span></label>`:d} ${r?a`<label class="confirm-field"><span>Type <strong>${e.fullName}</strong> to confirm.</span><input class="confirm-name" type="text" autocomplete="off" .value="${this._confirmName}" @input="${n=>{this._confirmName=n.target.value}}"></label>`:d}<div class="dialog-actions"><button type="button" class="btn" @click="${()=>{this._removeOpen=!1}}">Cancel</button><button type="button" class="btn danger" ?disabled="${!o}" @click="${()=>{this._remove(e)}}">${this._busy===e.id?"Removing\u2026":"Remove permanently"}</button></div></section></div>`}_accessIcon(e){return e==="private"?a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="7" width="10" height="7" rx="1"/><path d="M5 7V5a3 3 0 0 1 6 0v2"/></svg>`:a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="6"/><path d="M2.5 8h11M8 2c1.5 1.7 2.2 3.7 2.2 6S9.5 12.3 8 14c-1.5-1.7-2.2-3.7-2.2-6S6.5 3.7 8 2Z"/></svg>`}async _setActive(e,t){if(this._busy==null){this._busy=e.id,this._actionError=null;try{if(await this.appState.mutate(()=>Lt(e.id,t,this._csrf),["repos","reports","bundles","teams","users","history"]),!this.isConnected)return;this._detail?.id===e.id&&(this._detail={...this._detail,active:t}),this._data&&(this._data={...this._data,repositories:this._data.repositories.map(i=>i.id===e.id?{...i,active:t}:i)}),await this._load()}catch(i){let r=t?e.active===!1?"reactivate":"add":"deactivate";this._actionError=`Couldn't ${r} ${e.fullName}: ${i?.message??i}`}finally{this._busy=null}}}_canRemove(e){return this._busy!=null||this._impactLoading||!this._impactFresh||this._impact?.repoId!==e.id||!this._acknowledge?!1:!(this._impact.reports.length>0||this._impact.bundles.length>0)||this._confirmName===e.fullName}async _remove(e){if(this._canRemove(e)){this._busy=e.id,this._actionError=null;try{await this.appState.mutate(()=>zt(e.id,e.fullName,this._deleteTriage,this._csrf),["repos","repo-impact","reports","report-preview","bundles","teams","users","history","scan-sources"]),this._removeOpen=!1,this._detail=null,this._impact=null,await this._load()}catch(t){this._actionError=`Couldn't remove ${e.fullName}: ${t?.message??t}`}finally{this._busy=null}}}};customElements.define("managed-admin-repos",He);function $i(s){return[{value:null,label:"No repository",special:!0},...s.map(e=>({value:e.repoId,label:e.fullName}))]}function ki(s,e,t,i,r){let o=a`<span class="ui-hint">${s}: </span><span class="location-metadata-value" data-tooltip-truncated data-tooltip="${e}">${e}</span>`;return i?a`<button type="button" class="location-metadata" aria-label="${`Use ${t} from ${s}: ${e}`}" ?disabled="${r}" @click="${i}">${o}</button>`:a`<span class="location-metadata">${o}</span>`}var Ge=class extends b{static properties={localImportSource:{attribute:!1},_query:{state:!0},_visibility:{state:!0},_data:{state:!0},_error:{state:!0},_busy:{state:!0},_dragOver:{state:!0},_preview:{state:!0},_previewLoading:{state:!0},_locationReport:{state:!0},_locationOrigin:{state:!0},_locationOriginError:{state:!0},_locationRepo:{state:!0},_locationDirectory:{state:!0},_locationBusy:{state:!0}};static styles=[h(ce),h(Ie),h(f),h(Te)];constructor(){super(),this._query="",this._visibility="all",this._data=null,this._error=null,this._busy=!1,this._dragOver=!1,this._preview=null,this._previewLoading=null,this._previewRequest=null,this._locationReport=null,this._locationOrigin=null,this._locationOriginError=null,this._locationOriginRequest=null,this._locationRepo=null,this._locationDirectory="",this._locationBusy=!1,this._teardownDrop=null,this._queue=[],this._localImport=new K(this,"report",e=>Ae(this,e,t=>Se(t,this._csrf),["reports","repo-impact","history","scan-sources"]))}connectedCallback(){super.connectedCallback(),this._load(),this._teardownDrop=J(this,e=>{this._upload(e)},e=>{this._dragOver=e})}disconnectedCallback(){super.disconnectedCallback(),this._teardownDrop?.(),this._cancelPreview(),this._closeLocation()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection("reports","reports",Bt,t=>{this._data=t,this._preview&&!t.reports?.some(i=>i.id===this._preview)&&this._cancelPreview(),this._locationReport&&!t.reports?.some(i=>i.id===this._locationReport)&&this._closeLocation()})}render(){return a`${this._dragOver?a`<div class="dropzone">Drop reports to upload</div>`:d}<div class="wrap">${w("manage-reports",this._role,this.allowShare)}<h1 class="sr-only">Reports</h1><div class="page-intro"><p class="intro">Upload reports. New reports stay hidden until you make them visible.</p>${this._localImport.renderAction()}</div>${this._localImport.renderPanel(this._busy||!this._csrf)}<div class="drop-card"><span class="drop-icon" aria-hidden="true">${y("upload")}</span><span class="drop-copy"><strong>Upload reports</strong><span>Drop files anywhere on this page.</span></span><button type="button" class="drop-browse" ?disabled="${this._busy}" @click="${()=>W(e=>{this._upload(e)})}">${this._busy?"Uploading\u2026":"Browse files"}</button></div>${this._data?.repoScopes?.length?a`<p class="intro">Team paths: ${this._data.repoScopes.map(e=>`${this._data.repos.find(t=>t.repoId===e.repoId)?.fullName??e.repoId}/${e.path??""}`).join(", ")}</p>`:d} ${this._body()}</div>`}_body(){let e=Array.isArray(this._data?.reports)?this._data.reports:[],t=this._query.trim().toLocaleLowerCase(),i=e.filter(o=>[o.filename,q(o.filename),o.repoFullName,o.repoDirectory,o.uploadedByLogin].filter(Boolean).join(" ").toLocaleLowerCase().includes(t)&&(this._visibility==="all"||!!o.visible==(this._visibility==="visible"))),r=`${t||this._visibility!=="all"?`${i.length} of `:""}${e.length} ${e.length===1?"report":"reports"}`;return a`<div class="collection-toolbar" role="search"><input type="search" aria-label="Search reports" placeholder="Search reports or repositories…" .value="${this._query}" @input="${o=>{this._query=o.target.value}}"><select aria-label="Report visibility" .value="${this._visibility}" @change="${o=>{this._visibility=o.target.value}}"><option value="all">All reports</option><option value="visible">Visible to teams</option><option value="hidden">Hidden reports</option></select><span class="result-count" role="status">${this._data==null?"\u2026 reports":r}</span></div>${this._error?a`<p class="msg error" role="alert">${this._error}</p>`:d}<div class="manage-list" aria-busy="${this._loading}">${this._data==null?this._error?d:k("Loading reports\u2026"):i.length>0?a`<div class="report-list"><div class="report-list-head" aria-hidden="true"><span class="report-heading">Report</span><span>Repository</span><span>Uploaded by</span><span>Date</span><span class="size-heading">Size</span><span>Visibility</span><span class="actions-heading">Actions</span></div><ul class="reports">${i.map(o=>this._row(o))}</ul></div>`:a`<div class="empty"><strong>${e.length===0?"No reports uploaded yet":"No matching reports"}</strong><p>${e.length===0?"Drop a report here or browse files above.":"Try a different search or visibility filter."}</p></div>`}</div>`}_row(e){let t=q(e.filename),i=e.analyzer??e.source??e.producer??"default",r=ve[i]??ve.default,o=e.repoEmbedded!==!0&&e.canChangeRepo!==!1,n=e.repoEmbedded===!0||e.repoId!=null,l=e.repoFullName?`${e.repoFullName}${e.repoDirectory?`/${e.repoDirectory}`:""}`:"No repository assigned",c=Number.isFinite(e.uploadedAt)?new Date(e.uploadedAt).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"}):"";return a`<li class="${`report${e.visible===!1?" content-hidden":""}`}"><div class="report-main"><span class="report-mark" aria-hidden="true">${re(r)}</span> <span class="report-name" data-tooltip-truncated data-tooltip="${t}">${t}</span> <span class="report-location" data-tooltip-truncated data-tooltip="${l}">${l}</span> <span class="report-meta report-uploader" data-tooltip-truncated data-tooltip="${e.uploadedByLogin??"Uploader removed"}">${e.uploadedByLogin??"Uploader removed"}</span> <span class="report-meta report-date">${c}</span> <span class="report-meta report-size">${U(e.byteSize)}</span> <span class="${`status ${e.visible?"visible":"hidden"}`}">${e.visible?"Visible":"Hidden"}</span> <span class="report-actions">${o?a`<button type="button" class="action" data-tooltip="Set repository location" aria-label="${`Set location for ${t}`}" @click="${()=>this._openLocation(e)}">${y("repo")}</button>`:a`<span class="action-spacer"></span>`} <button type="button" class="action" aria-label="${`Preview ${t}`}" aria-expanded="${this._preview===e.id}" @click="${()=>{this._togglePreview(e)}}">${y("preview")}</button> <button type="button" class="action" data-tooltip="${e.visible?"Hide from teams":n?"Make visible to teams":"Assign a repository before publishing"}" aria-label="${`${e.visible?"Hide":"Make visible"} ${t}`}" ?disabled="${e.canChangeRepo===!1||!n&&!e.visible}" @click="${()=>{this._setVisible(e,!e.visible)}}">${y(e.visible?"hide":"show")}</button> <a class="action" aria-label="${`Download ${t}`}" href="${`/api/admin/reports/${encodeURIComponent(e.id)}`}">${y("download")}</a> <button type="button" class="action danger" aria-label="${`Delete ${t}`}" ?disabled="${e.canChangeRepo===!1}" @click="${()=>this._delete(e)}">${Je}</button></span></div>${this._preview===e.id?a`<div class="preview">${this._previewLoading===e.id?a`<span class="preview-loading">Loading preview…</span>`:a`<pre>${this._previewText??""}</pre>`}</div>`:d} ${this._locationReport===e.id?this._locationEditor(e):d}</li>`}_openLocation(e){e.canChangeRepo!==!1&&(this._closeLocation(),this._locationReport=e.id,this._locationRepo=e.repoId??null,this._locationDirectory=e.repoDirectory??"",this._error=null,this._loadLocationOrigin(e))}_closeLocation(){this._locationOriginRequest?.abort(),this._locationOriginRequest=null,this._locationReport=null,this._locationOrigin=null,this._locationOriginError=null}async _loadLocationOrigin(e){this._locationOriginRequest?.abort();let t=new AbortController;this._locationOriginRequest=t,this._locationOrigin=void 0,this._locationOriginError=null;try{let i=await Ft(e.id,AbortSignal.any([t.signal,this.appState.sessionController.signal]));if(this._locationOriginRequest!==t)return;i?.repoId!=null&&this._data&&(this._data={...this._data,repos:[...(this._data.repos??[]).filter(r=>r.repoId!==i.repoId),{repoId:i.repoId,fullName:i.github}]}),this._locationOrigin=typeof i?.github=="string"&&i.github?{github:i.github,repoId:i.repoId??null,directory:typeof i.directory=="string"?i.directory||"/":null}:null}catch(i){if(this._locationOriginRequest!==t)return;this._locationOrigin=null,i?.name!=="AbortError"&&(this._locationOriginError="Couldn't load the report\u2019s suggested location.")}}_locationEditor(e){let t=Array.isArray(this._data?.repos)?this._data.repos:[],i=this._locationOrigin,r=i?.repoId!=null&&t.find(n=>n.repoId===i.repoId),o=(n,l,c)=>ki("report",n,l,c,this._locationBusy);return a`<div class="location-editor"><div class="location-field"><div class="location-field-header"><span class="ui-hint">Repository</span>${i?o(i.github,"repository",r?()=>{this._locationRepo=r.repoId,i.directory!=null&&(this._locationDirectory=i.directory)}:null):d}</div><repository-selector label="Repository for report" .options="${$i(t)}" .value="${this._locationRepo}" ?disabled="${this._locationBusy}" @repository-change="${n=>{this._locationRepo=n.detail.value}}"></repository-selector></div><div class="location-field"><div class="location-field-header"><label for="${`report-dir-${e.id}`}">Directory (optional)</label>${i?o(i.directory??"Directory not specified","directory",i.directory==null?null:()=>{this._locationDirectory=i.directory}):d}</div><input id="${`report-dir-${e.id}`}" type="text" placeholder="Repository root" .value="${this._locationDirectory}" ?disabled="${this._locationBusy}" @input="${n=>{this._locationDirectory=n.target.value}}"></div><div class="location-actions"><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>this._closeLocation()}">Cancel</button><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>{this._saveLocation(e)}}">Save</button></div>${this._locationOriginError?a`<p class="location-origin" role="status">${this._locationOriginError} <button type="button" class="origin-retry" @click="${()=>{this._loadLocationOrigin(e)}}">Retry</button></p>`:d}</div>`}async _saveLocation(e){if(!this._locationBusy){this._locationBusy=!0,this._error=null;try{await this.appState.mutate(()=>Ut(e.id,this._locationRepo,this._locationDirectory.trim(),this._csrf),["reports","repo-impact","history","scan-sources"]),this._closeLocation(),await this._load({preserveError:!0})}catch(t){this._error=`Couldn't set report location: ${String(t?.message??t)}`}finally{this._locationBusy=!1}}}_cancelPreview(){this._previewRequest?.abort(),this._previewRequest=null,this._preview=null,this._previewLoading=null,this._previewText=""}async _togglePreview(e){let t=this._preview===e.id;if(this._cancelPreview(),t)return;let i=new AbortController;this._previewRequest=i;let r=()=>this._previewRequest===i&&!i.signal.aborted;this._preview=e.id,this._previewText=this.appState.read(`report-preview:${e.id}`)??"",this._previewLoading=this.appState.read(`report-preview:${e.id}`)===void 0?e.id:null;try{await this.appState.load(`report-preview:${e.id}`,"report preview",async o=>{let n=await m(`/api/admin/reports/${encodeURIComponent(e.id)}`,{credentials:"same-origin",signal:o});if(!n.ok)throw new Error(`HTTP ${n.status}`);let l=await n.text();return l.slice(0,4e3)+(l.length>4e3?`
16
- \u2026`:"")},{signal:i.signal,apply:o=>{this._previewText=o}})}catch(o){r()&&o?.name!=="AbortError"&&!this._previewText&&(this._previewText=`Preview unavailable: ${o?.message??o}`)}finally{r()&&(this._previewLoading=null)}}async _setVisible(e,t){this._error=null;try{await this.appState.mutate(()=>qt(e.id,t,this._csrf),["reports","history","scan-sources"]),e.visible=t,this.requestUpdate(),await this._load()}catch(i){this._error=`Couldn't change report visibility: ${String(i?.message??i)}`}}async _upload(e){await Y(this,e,t=>Se(t,this._csrf),["reports","repo-impact","history","scan-sources"])}async _delete(e){if(globalThis.confirm?.(`Delete \u201C${q(e.filename)}\u201D? This can't be undone.`)){this._error=null;try{await this.appState.mutate(()=>jt(e.id,this._csrf),["reports",`report-preview:${e.id}`,"repo-impact","history","scan-sources"])}catch(t){this._error=`Delete failed: ${String(t?.message??t)}`}await this._load({preserveError:!0})}}};customElements.define("managed-admin-reports",Ge);var zr=a`<svg class="report-icon" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M8.878.392a1.75 1.75 0 0 0-1.756 0l-5.25 3.045A1.75 1.75 0 0 0 1 4.951v6.098c0 .624.332 1.2.872 1.514l5.25 3.045a1.75 1.75 0 0 0 1.756 0l5.25-3.045c.54-.313.872-.89.872-1.514V4.951c0-.624-.332-1.2-.872-1.514ZM7.875 1.69a.25.25 0 0 1 .25 0l4.63 2.685L8 7.133 3.245 4.375Zm-5.125 4.4 4.5 2.61v5.317l-4.375-2.537a.25.25 0 0 1-.125-.216Zm6 7.927V8.7l4.5-2.61v3.96a.25.25 0 0 1-.125.216Z"/></svg>`,Ke=class extends b{static properties={createRepoId:{attribute:!1},installTooltips:{attribute:!1},localImportSource:{attribute:!1},_query:{state:!0},_visibility:{state:!0},_visibilityBusy:{state:!0},_creating:{state:!0},_data:{state:!0},_locationBundle:{state:!0},_locationOrigin:{state:!0},_locationOriginError:{state:!0},_locationRepo:{state:!0},_locationDirectory:{state:!0},_locationBusy:{state:!0},_error:{state:!0},_busy:{state:!0},_dragOver:{state:!0}};static styles=[h(Zt),h(Ie),h(f),h(Te)];constructor(){super(),this._query="",this._visibility="all",this._visibilityBusy=null,this._creating=!1,this._data=null,this._error=null,this._busy=!1,this._locationBundle=null,this._locationOrigin=null,this._locationOriginError=null,this._locationOriginRequest=null,this._locationRepo=null,this._locationDirectory="",this._locationBusy=!1,this._dragOver=!1,this._teardownDrop=null,this._queue=[],this._localImport=new K(this,"bundle",e=>Ae(this,e,t=>Ee(t,this._csrf),["bundles","reports","repo-impact","history","scan-sources"]))}connectedCallback(){super.connectedCallback(),this._load(),this._teardownDrop=J(this,e=>{this._creating||this._upload(e)},e=>{this._dragOver=!this._creating&&e})}disconnectedCallback(){super.disconnectedCallback(),this._teardownDrop?.(),this._closeLocation()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection("bundles","bundles",Ce,t=>{this._data=t,this._locationBundle&&!t.bundles?.some(i=>i.id===this._locationBundle)&&this._closeLocation()})}_showCreate(e){if(!e&&this.createRepoId!=null){document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:"manage-bundles"},bubbles:!0,composed:!0}));return}this._creating=e,this._dragOver=!1,e||this.updateComplete.then(()=>this.renderRoot.querySelector(".create-bundle-action")?.focus())}willUpdate(e){e.has("createRepoId")&&(this._creating=this.createRepoId!=null)}render(){return this._creating?a`<div class="wrap">${w("manage-bundles",this._role,this.allowShare)}<div class="breadcrumb"><button type="button" class="breadcrumb-manage" @click="${()=>document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:"manage"},bubbles:!0,composed:!0}))}">Manage</button> <span class="breadcrumb-separator" aria-hidden="true">›</span> <button type="button" class="breadcrumb-manage" aria-label="Back to bundles" @click="${()=>this._showCreate(!1)}">Bundles</button> <span class="breadcrumb-separator" aria-hidden="true">›</span><h1 class="breadcrumb-current">Create a bundle</h1></div><managed-create-bundle .initialRepoId="${this.createRepoId??null}" .installTooltips="${this.installTooltips}" .createBundle="${this._csrf?(e,t)=>this.appState.mutate(()=>Mt(e,this._csrf,t),["bundles","bundle-metadata","reports","repo-impact","history","scan-sources"]):void 0}" @bundle-created="${e=>this.dispatchEvent(new CustomEvent("managed-bundle-open",{detail:e.detail,bubbles:!0,composed:!0}))}"></managed-create-bundle></div>`:a`${this._dragOver?a`<div class="dropzone">Drop bundles to upload</div>`:d}<div class="wrap">${w("manage-bundles",this._role,this.allowShare)}<h1 class="sr-only">Bundles</h1><div class="page-intro"><p class="intro">Source bundles for your repositories.</p><div class="bundle-actions">${this._localImport.renderAction()}<button type="button" class="local-import-toggle create-bundle-action" ?disabled="${!this._data}" @click="${()=>this._showCreate(!0)}">Create</button></div></div>${this._localImport.renderPanel(this._busy||!this._csrf)}<section class="drop-card" aria-label="Upload bundles"><span class="drop-icon" aria-hidden="true">${y("upload")}</span><span class="drop-copy"><strong>Upload source bundles</strong><span>Drop source archives anywhere on this page.</span></span> <button type="button" class="drop-browse" ?disabled="${this._busy}" @click="${()=>W(e=>{this._upload(e)})}">${this._busy?"Uploading\u2026":"Browse files"}</button></section>${this._body()}</div>`}_body(){let e=Array.isArray(this._data?.bundles)?this._data.bundles:[],t=this._query.trim().toLocaleLowerCase(),i=e.filter(c=>[c.filename,c.repoFullName,c.repoDirectory,c.kind,c.provenance==="build"?"built":null,c.uploadedByLogin].filter(Boolean).join(" ").toLocaleLowerCase().includes(t)&&(this._visibility==="all"||c.visible!==!1==(this._visibility==="visible"))),r=i.filter(c=>c.repoId==null).length,o=i.reduce((c,p)=>c+(Number.isFinite(p.byteSize)?p.byteSize:0),0),n=`${t||this._visibility!=="all"?`${i.length} of `:""}${e.length} ${e.length===1?"bundle":"bundles"}`,l=Map.groupBy(i,c=>c.repoFullName||"Unattached");return a`<div class="collection-toolbar" role="search"><input type="search" aria-label="Search bundles" placeholder="Search bundles or repositories…" .value="${this._query}" @input="${c=>{this._query=c.target.value}}"> <select aria-label="Bundle visibility" .value="${this._visibility}" @change="${c=>{this._visibility=c.target.value}}"><option value="all">All bundles</option><option value="visible">Visible to teams</option><option value="hidden">Hidden bundles</option></select> <span class="summary result-count" role="status"><span>${this._data==null?"\u2026 bundles":n}</span><span>${this._data==null?"\u2026":U(o)}</span> ${this._data==null||r?a`<span class="unassigned">${this._data==null?"\u2026 unattached":`${r} unattached`}</span>`:d}</span></div>${this._error?a`<p class="msg error" role="alert">${this._error}</p>`:d}<div class="manage-list" aria-busy="${this._loading}">${this._data==null?this._error?d:k("Loading bundles\u2026"):i.length>0?a`<div class="bundle-groups">${[...l].toSorted(([c],[p])=>c==="Unattached"?-1:p==="Unattached"?1:c.localeCompare(p)).map(([c,p])=>a`<section class="bundle-group"><div class="bundle-group-head"><strong>${c}</strong><span>${p.length} ${p.length===1?"bundle":"bundles"}</span></div><ul class="bundles">${p.map(u=>this._row(u))}</ul></section>`)}</div>`:a`<div class="empty"><strong>${e.length>0?"No matching bundles":"No bundles uploaded yet"}</strong><p>${e.length>0?"Try a different search or visibility filter.":"Drop source archives here or browse files above."}</p></div>`}</div>`}_row(e){let t=e.visible!==!1,i=e.repoFullName?`${e.repoFullName}${e.repoDirectory?`/${e.repoDirectory}`:""}`:"No repository assigned",r=Number.isFinite(e.uploadedAt)?new Date(e.uploadedAt).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"}):"";return a`<li class="${`bundle-row${t?"":" content-hidden"}`}"><span class="identity"><span class="bundle-icon" aria-hidden="true">${e.kind==="stasis"?a`<img src="./stasis.svg" width="16" height="16" alt="">`:zr}</span> <button type="button" class="filename bundle-open" data-tooltip-truncated data-tooltip="${e.filename}" @click="${()=>this.dispatchEvent(new CustomEvent("managed-bundle-open",{detail:e,bubbles:!0,composed:!0}))}">${e.filename}</button> ${e.provenance==="build"?a`<span class="bundle-provenance" data-tooltip="Generated on this server from the repository">Built</span>`:d} </span><span class="meta bundle-uploader" data-tooltip-truncated data-tooltip="${e.uploadedByLogin?`@${e.uploadedByLogin}`:""}">${e.uploadedByLogin?`@${e.uploadedByLogin}`:""}</span> <span class="meta bundle-date">${r}</span> <span class="meta bundle-size">${U(e.byteSize)}</span> <span class="bundle-location" data-tooltip-truncated data-tooltip="${i}">${i}</span> <span class="${`status ${t?"visible":"hidden"}`}">${t?"Visible":"Hidden"}</span> <span class="actions">${e.canChangeRepo===!1?d:a`<button type="button" class="action" aria-label="${`Set location for ${e.filename}`}" data-tooltip="Set repository location" ?disabled="${this._locationBusy}" @click="${()=>this._openLocation(e)}">${y("repo")}</button>`} <button type="button" class="action" aria-label="${`${t?"Hide":"Make visible"} ${e.filename}`}" data-tooltip="${t?"Hide from teams":e.repoId==null?"Assign a repository before publishing":"Make visible to teams"}" ?disabled="${this._visibilityBusy!=null||e.canChangeRepo===!1||!t&&e.repoId==null}" @click="${()=>{this._setVisible(e,!t)}}">${y(t?"hide":"show")}</button> <a class="action" aria-label="${`Download ${e.filename}`}" href="${`/api/admin/bundles/${encodeURIComponent(e.id)}`}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2v8m-3-3 3 3 3-3M3 11v3h10v-3"/></svg></a><button type="button" class="action danger" aria-label="${`Delete ${e.filename}`}" ?disabled="${e.canChangeRepo===!1}" data-tooltip="${e.canChangeRepo===!1?"Repository access is required to detach or delete this bundle":d}" @click="${()=>this._delete(e)}">${Je}</button> </span>${this._locationBundle===e.id?this._locationEditor(e):d}</li>`}async _setVisible(e,t){if(!(this._visibilityBusy!=null||e.canChangeRepo===!1)){this._visibilityBusy=e.id,this._error=null;try{await this.appState.mutate(()=>Gt(e.id,t,this._csrf),["bundles","teams","history","scan-sources"]),e.visible=t,this.requestUpdate(),await this._load()}catch(i){this._error=`Couldn't change bundle visibility: ${String(i?.message??i)}`}finally{this._visibilityBusy=null}}}_openLocation(e){this._locationBusy||e.canChangeRepo===!1||(this._closeLocation(),this._locationBundle=e.id,this._locationRepo=e.repoId??null,this._locationDirectory=e.repoDirectory??"",this._error=null,e.kind==="stasis"&&this._loadLocationOrigin(e))}_closeLocation(){this._locationOriginRequest?.abort(),this._locationOriginRequest=null,this._locationBundle=null,this._locationOrigin=null,this._locationOriginError=null}async _loadLocationOrigin(e){this._locationOriginRequest?.abort();let t=new AbortController;this._locationOriginRequest=t,this._locationOrigin=void 0,this._locationOriginError=null;try{let i=await xt(e.id,{signal:t.signal});if(this._locationOriginRequest!==t)return;i?.repoId!=null&&this._data&&(this._data={...this._data,repos:[...(this._data.repos??[]).filter(r=>r.repoId!==i.repoId),{repoId:i.repoId,fullName:i.github}]}),this._locationOrigin=typeof i?.github=="string"&&i.github?{github:i.github,directory:typeof i.directory=="string"?i.directory:i.root===!0?"/":null}:null}catch(i){if(this._locationOriginRequest!==t)return;this._locationOrigin=null,i?.name!=="AbortError"&&(this._locationOriginError="Couldn't load the bundle\u2019s suggested location.")}}_locationEditor(e){let t=Array.isArray(this._data?.repos)?this._data.repos:[],i=this._locationOrigin,r=se({repo:i})?.toLowerCase(),o=r&&t.find(l=>l.fullName.toLowerCase()===r),n=(l,c,p)=>ki("metadata",l,c,p,this._locationBusy);return a`<div class="location-editor"><div class="location-field"><div class="location-field-header"><span class="ui-hint">Repository</span>${i?n(i.github,"repository",o?()=>{this._locationRepo=o.repoId,i.directory!=null&&(this._locationDirectory=i.directory)}:null):d}</div><repository-selector label="Repository for bundle" .options="${$i(t)}" .value="${this._locationRepo}" ?disabled="${this._locationBusy}" @repository-change="${l=>{this._locationRepo=l.detail.value}}"></repository-selector></div><div class="location-field"><div class="location-field-header"><label for="${`bundle-dir-${e.id}`}">Directory (optional)</label>${i?n(i.directory??"Directory not specified","directory",i.directory==null?null:()=>{this._locationDirectory=i.directory}):d}</div><input id="${`bundle-dir-${e.id}`}" type="text" placeholder="Repository root" .value="${this._locationDirectory}" ?disabled="${this._locationBusy}" @input="${l=>{this._locationDirectory=l.target.value}}"></div><div class="location-actions"><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>this._closeLocation()}">Cancel</button><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>{this._saveLocation(e)}}">Save</button></div>${this._locationOriginError?a`<p class="location-origin" role="status">${this._locationOriginError} <button type="button" class="origin-retry" @click="${()=>{this._loadLocationOrigin(e)}}">Retry</button></p>`:d}</div>`}async _saveLocation(e){if(!(this._locationBusy||e.canChangeRepo===!1)){this._locationBusy=!0,this._error=null;try{await this.appState.mutate(()=>Kt(e.id,this._locationRepo,this._locationDirectory.trim(),this._csrf),["bundles","teams","repo-impact","history","scan-sources"]),this._closeLocation(),await this._load({preserveError:!0})}catch(t){this._error=`Couldn't set bundle location: ${String(t?.message??t)}`}finally{this._locationBusy=!1}}}async _upload(e){await Y(this,e,t=>Ee(t,this._csrf),["bundles","bundle-metadata","reports","repo-impact","history","scan-sources"])}async _delete(e){if(globalThis.confirm?.(`Delete \u201C${e.filename}\u201D? Linked reports will keep their pending link.`)){this._error=null;try{await this.appState.mutate(()=>Ht(e.id,this._csrf),["bundles","bundle-metadata","reports","repo-impact","history","scan-sources"])}catch(t){this._error=`Delete failed: ${String(t?.message??t)}`}await this._load({preserveError:!0})}}};customElements.define("managed-admin-bundles",Ke);var Ve=class extends b{static properties={selection:{attribute:!1},_source:{state:!0},_error:{state:!0}};static styles=h(f);constructor(){super(),this._loadModels=(e,t)=>this.appState.load("models","scan models",i=>bt(i,m),{signal:e,apply:t}),this._source=null,this._error=null,this._loadReportSources=(e,t)=>this.appState.load("scan-sources","scan report inputs",async i=>{let[r,o]=await Promise.all([m("/api/admin/reports",{signal:i,credentials:"same-origin"}),m("/api/admin/scan-results",{signal:i,credentials:"same-origin"})]);if(!r.ok)throw new Error(`Reports: HTTP ${r.status}`);if(!o.ok&&o.status!==404)throw new Error(`Scan results: HTTP ${o.status}`);let n=await r.json();return n.reports=await Promise.all((n.reports??[]).filter(l=>l.visible&&l.repoId!=null).map(async l=>{let c=await m(`/api/admin/reports/${encodeURIComponent(l.id)}`,{signal:i,credentials:"same-origin"});if(!c.ok)throw new Error(`Report ${q(l.filename)}: HTTP ${c.status}`);return{...l,content:await c.text()}})),$t(n,o.ok?await o.json():{bundles:[],results:[]})},{signal:e,apply:t})}connectedCallback(){super.connectedCallback(),this._load()}async _load(){this._error=null,await this._loadCollection("bundles","bundles",Ce,e=>{this._source=pi(e)})}render(){return a`<div class="wrap">${w("manage-scans",this._role,this.allowShare)} ${this._error?a`<p class="msg error" role="alert">Couldn’t load scan sources: ${this._error} <button type="button" class="btn" @click="${()=>{this._load()}}">Retry</button></p>`:d}<deepview-scan-page hide-heading .selection="${this.selection}" .source="${this._source}" .sourceLoading="${this._loading&&this._source==null}" .loadBundle="${ui}" .loadModels="${this._loadModels}" .loadReportSources="${this._loadReportSources}" .createBundleHref="${e=>Number.isSafeInteger(e)&&e>0?H({view:"manage-bundles",createRepoId:e}):null}"></deepview-scan-page></div>`}};customElements.define("managed-admin-scans",Ve);var We=class extends b{static properties={_data:{state:!0},_error:{state:!0},_busy:{state:!0},_renamingId:{state:!0},_repoChoices:{state:!0},_memberChoices:{state:!0}};static styles=[h(Qt),h(f)];constructor(){super(),this._data=null,this._error=null,this._busy=!1,this._renamingId=null,this._repoChoices=new Map,this._memberChoices=new Map}connectedCallback(){super.connectedCallback(),this._load()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection("teams","teams",V,t=>{this._data=t})}async _do(e){if(!this._busy){this._busy=!0,this._error=null;try{await this.appState.mutate(e,["teams","users","reports","history"])}catch(t){this._error=String(t?.message??t)}finally{this._busy=!1,await this._load({preserveError:!0})}}}render(){return a`<div class="wrap">${w("manage-teams",this._role,this.allowShare)}<h1 class="sr-only">Teams</h1><div class="page-intro"><p class="intro">Manage repository and finding access for each team.</p><span class="result-count">${this._data?.teams?.length??"\u2026"} teams</span></div><div class="create-team"><label class="sr-only" for="new-team-name">New team</label> <input id="new-team-name" class="new-name" type="text" placeholder="Team name" maxlength="100" ?disabled="${this._busy}" @keydown="${e=>{e.key==="Enter"&&this._create()}}"> <button class="btn primary" ?disabled="${this._busy}" @click="${()=>this._create()}">${pe} Create team</button><p class="access-note ui-hint">All members can view standard findings. Set dependencies and security access per member.</p></div><div class="manage-list" aria-busy="${this._loading}">${this._body()}</div></div>`}_body(){if(this._error!=null&&this._data==null)return a`<p class="msg error">Couldn't load teams: ${this._error}</p>`;if(this._data==null)return k("Loading teams\u2026");let e=Array.isArray(this._data.teams)?this._data.teams:[];return a`${this._error==null?d:a`<p class="msg error">${this._error}</p>`} ${e.length===0?a`<p class="msg">No teams yet. Create one above.</p>`:e.map(t=>this._team(t))}`}_team(e){return a`<section class="team" aria-label="${e.name}"><div class="team-head"><span class="team-icon" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="5" r="2.5"/><path d="M1.5 13v-1c0-2 1.8-3.5 4.5-3.5s4.5 1.5 4.5 3.5v1M11 2.5a2.5 2.5 0 0 1 0 5M12 9c1.7.5 2.5 1.5 2.5 3v1"/></svg></span>${this._renamingId===e.id?a`<input class="rename-input" type="text" .value="${e.name}" maxlength="100" aria-label="Team name" @keydown="${t=>this._renameKey(t,e)}"> <button class="btn" ?disabled="${this._busy}" @click="${t=>this._saveRename(e,t)}">Save</button> <button class="btn" @click="${()=>{this._renamingId=null}}">Cancel</button>`:a`<h2 class="team-name">${e.name}</h2>${e.hidden?a`<span class="muted ui-hint">Disabled</span>`:d} <span class="team-actions"><button class="icon-btn" aria-label="${`${e.hidden?"Restore":"Hide"} ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._do(()=>x("/api/admin/teams/set-hidden",this._csrf,{teamId:e.id,hidden:!e.hidden}))}">${y(e.hidden?"show":"hide")}</button> <button class="icon-btn" aria-label="${`Rename ${e.name}`}" ?disabled="${this._busy}" @click="${()=>{this._renamingId=e.id}}">${Or}</button> <button class="icon-btn danger" aria-label="${`Delete ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._deleteTeam(e)}">${Je}</button></span>`}</div><div class="team-body"><div class="sub"><h3 class="sub-title">Repositories <span class="count">${e.repos.length}</span></h3>${e.repos.length===0?a`<p class="muted ui-hint">No repositories linked.</p>`:a`<ul class="links">${e.repos.map(t=>this._repoRow(e,t))}</ul>`} ${this._addRepoRow(e)}</div><div class="sub"><h3 class="sub-title">Members <span class="count">${e.members.length}</span></h3>${e.members.length===0?a`<p class="muted ui-hint">No members.</p>`:a`<ul class="links">${e.members.map(t=>this._memberRow(e,t))}</ul>`} ${this._addMemberRow(e)}</div>${this._npmScopes(e)}</div></section>`}_npmScopes(e){let t=Array.isArray(e.npmScopes)?e.npmScopes:[];return a`<div class="sub npm-scopes"><div class="sub-head"><h3 class="sub-title">npm scopes <span class="count">${t.length}</span><mode-switch class="npm-review-toggle" label="Enable dependency review" .checked="${!!e.dependencyReview}" .disabled="${this._busy}" @click="${()=>{this._busy||this._do(()=>x("/api/admin/teams/set-dependency-review",this._csrf,{teamId:e.id,enabled:!e.dependencyReview}))}}"></mode-switch></h3><p class="muted ui-hint">Members can open private packages in these scopes. Everyone can open public packages.</p></div><div class="add-row npm-scope-row"><input class="add-npm-scope" type="text" placeholder="@scope" aria-label="${`npm scope to add to ${e.name}`}" maxlength="215" ?disabled="${this._busy}" @keydown="${i=>{i.key==="Enter"&&this._addNpmScope(e,i)}}"> <button class="btn" aria-label="${`Add npm scope to ${e.name}`}" ?disabled="${this._busy}" @click="${i=>this._addNpmScope(e,i)}">${pe} Add</button> ${t.length===0?d:a`<ul class="npm-scope-list">${t.map(i=>a`<li class="npm-scope"><span>${i}</span> <button class="icon-btn danger" aria-label="${`Remove ${i} from ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._setNpmScopes(e,t.filter(r=>r!==i))}">${Me}</button></li>`)}</ul>`}</div></div>`}_addNpmScope(e,t){let i=t.target.closest(".add-row")?.querySelector(".add-npm-scope");if(!i?.value.trim())return;let r=dt(i.value);if(r===null){this._error=`\u201C${i.value.trim()}\u201D is not an npm scope. Scopes look like @example.`;return}let o=Array.isArray(e.npmScopes)?e.npmScopes:[];if(o.includes(r)){i.value="";return}this._setNpmScopes(e,[...o,r],()=>{i.value=""})}_setNpmScopes(e,t,i=()=>{}){return this._do(async()=>{await x("/api/admin/teams/set-npm-scopes",this._csrf,{teamId:e.id,scopes:t}),i()})}_repoRow(e,t){return a`<li class="repo-row">${wi} <span class="repo-copy"><span class="ln">${t.fullName}</span>${t.path?a`<span class="path">/${t.path.replace(/^\/+/u,"")}</span>`:d}</span> <button class="icon-btn danger" aria-label="${`Remove ${t.fullName}${t.path?`/${t.path}`:""} from ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._do(()=>x("/api/admin/teams/remove-repo",this._csrf,{teamId:e.id,repoId:t.repoId,path:t.path??null}))}">${Me}</button></li>`}_addRepoRow(e){let t=Array.isArray(this._data.repos)?this._data.repos:[];return t.length===0?a`<p class="muted ui-hint">No selected repositories to link — pick some on “Manage repositories”.</p>`:a`<div class="add-row"><repository-selector class="add-repo-sel" label="${`Repository to add to ${e.name}`}" placeholder="Add repository…" ?disabled="${this._busy}" .options="${t.map(i=>({value:i.repoId,label:i.fullName}))}" .value="${this._repoChoices.get(e.id)??null}" @repository-change="${i=>{this._repoChoices=new Map(this._repoChoices).set(e.id,i.detail.value)}}"></repository-selector><input class="add-repo-path" type="text" placeholder="Path (optional)" aria-label="${`Repository path in ${e.name} (optional)`}" maxlength="500" ?disabled="${this._busy}"> <button class="btn" aria-label="${`Add repository to ${e.name}`}" ?disabled="${this._busy||!this._repoChoices.has(e.id)}" @click="${i=>this._addRepo(e,i)}">${pe} Add</button></div>`}_memberRow(e,t){let i=Array.isArray(this._data.permissions)?this._data.permissions:[],r=this._data.users?.some(o=>o.id===t.userId&&ae(o.role,"manage"));return a`<li class="member-row"><span class="member">${yi(t.userId,t.login)}<span class="ln">${t.login}</span></span> <span class="perms">${i.map(o=>a`<label class="perm"><input type="checkbox" .checked="${r||t[o]===!0}" ?disabled="${this._busy||r}" aria-label="${`${be[o]??o} access for ${t.login} in ${e.name}`}" @change="${n=>this._togglePerm(e,t,o,n.target.checked)}"> ${be[o]??o}</label>`)} </span><button class="icon-btn danger" aria-label="${`Remove ${t.login} from ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._do(()=>x("/api/admin/teams/remove-member",this._csrf,{teamId:e.id,userId:t.userId}))}">${Me}</button></li>`}_addMemberRow(e){let t=Array.isArray(this._data.users)?this._data.users:[],i=new Set(e.members.map(r=>r.userId));return a`<div class="add-row"><user-selector class="add-member-sel" label="${`Member to add to ${e.name}`}" placeholder="Add member…" ?disabled="${this._busy}" .users="${t.map(r=>({...r,disabled:i.has(r.id),detail:i.has(r.id)?"Member":""}))}" .value="${this._memberChoices.get(e.id)??null}" @user-change="${r=>{this._memberChoices=new Map(this._memberChoices).set(e.id,r.detail.value)}}"></user-selector><button class="btn" aria-label="${`Add member to ${e.name}`}" ?disabled="${this._busy||!this._memberChoices.has(e.id)||i.has(this._memberChoices.get(e.id))}" @click="${()=>this._addMember(e)}">${pe} Add</button></div>`}_create(){let e=this.renderRoot.querySelector(".new-name"),t=e?.value.trim();t&&this._do(async()=>{await x("/api/admin/teams",this._csrf,{name:t}),e&&(e.value="")})}_deleteTeam(e){globalThis.confirm?.(`Delete team \u201C${e.name}\u201D? Its repo + member links are removed.`)&&this._do(()=>x("/api/admin/teams/delete",this._csrf,{teamId:e.id}))}_renameKey(e,t){e.key==="Enter"?this._saveRename(t,e):e.key==="Escape"&&(this._renamingId=null)}_saveRename(e,t){if(this._busy)return;let i=t.target.closest(".team-head")?.querySelector(".rename-input")?.value.trim()??"";this._renamingId=null,!(i===""||i===e.name)&&this._do(()=>x("/api/admin/teams/rename",this._csrf,{teamId:e.id,name:i}))}_addRepo(e,t){let i=t.target.closest(".add-row"),r=this._repoChoices.get(e.id);if(!Number.isSafeInteger(r)||r<=0)return;let o=i?.querySelector(".add-repo-path")?.value??"";this._do(async()=>{await x("/api/admin/teams/set-repo",this._csrf,{teamId:e.id,repoId:r,path:o});let n=new Map(this._repoChoices);n.delete(e.id),this._repoChoices=n;let l=i?.querySelector(".add-repo-path");l&&(l.value="")})}_addMember(e){let t=this._memberChoices.get(e.id);!t||e.members.some(i=>i.userId===t)||this._do(async()=>{await x("/api/admin/teams/set-member",this._csrf,{teamId:e.id,userId:t});let i=new Map(this._memberChoices);i.delete(e.id),this._memberChoices=i})}_togglePerm(e,t,i,r){if(this._data.users?.some(n=>n.id===t.userId&&ae(n.role,"manage")))return;let o={};for(let n of this._data.permissions??[])o[n]=t[n]===!0;o[i]=r,this._do(()=>x("/api/admin/teams/set-member",this._csrf,{teamId:e.id,userId:t.userId,...o}))}};customElements.define("managed-admin-teams",We);var F=`.link-team{margin-top:1.5rem}.link-team h2{margin:0 0 .5rem;font-size:1rem;font-weight:600}.link-table{overflow-x:auto}table{width:100%;border-collapse:collapse;text-align:left;font-size:.8rem}th{color:var(--muted);font-weight:500}th,td{padding:.6rem .65rem;border-bottom:1px solid var(--border);white-space:nowrap}th:first-child,td:first-child{padding-left:0}th:last-child,td:last-child{padding-right:0;text-align:right}
17
- `;async function Mr(s){let e=await m("/api/admin/links",{signal:s,credentials:"same-origin"});if(!e.ok)throw new Error(`HTTP ${e.status}`);let t=await e.json();if(!Array.isArray(t?.shares))throw new Error("No public links returned");return t}var Ye=class extends b{static properties={_data:{state:!0},_error:{state:!0}};static styles=[h(f),h(F)];constructor(){super(),this._data=null,this._error=null}connectedCallback(){super.connectedCallback(),this._load()}async _load(){this._error=null,await this._loadCollection("links","public links",Mr,e=>{this._data=e})}async _edit(e){let{openManagedShareDialog:t}=await import("./chunk-UTR2LVME.js");await t({id:e.teamId,name:e.teamName},e.id,this.session),this.isConnected&&await this._load()}_groups(){let e=new Map;for(let t of this._data?.shares??[])e.has(t.teamId)||e.set(t.teamId,{name:t.teamName,links:[]}),e.get(t.teamId).links.push(t);return[...e.values()]}_body(){return this._data==null?this._error?a`<p class="msg error">Couldn't load public links: ${this._error}</p>`:k("Loading public links\u2026"):this._data.shares.length===0?a`<p class="msg">No public links. Create one with the share button beside a workspace in the sidebar.</p>`:this._groups().map(e=>a`<section class="link-team" aria-label="${e.name}"><h2>${e.name}</h2><div class="link-table"><table><thead><tr><th>Link</th><th>Created by</th><th>Created</th><th>Security</th><th>Dependencies</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody>${e.links.map(t=>a`<tr><td><span data-tooltip="${t.id}">${t.id.slice(0,8)}</span></td><td>${t.createdBy}</td><td>${new Date(t.createdAt).toLocaleString()}</td><td>${t.permissions.security?"On":"Off"}</td><td>${t.permissions.dependencies?"On":"Off"}</td><td><button class="btn" aria-label="${`Edit public link ${t.id.slice(0,8)} for ${e.name}`}" @click="${()=>this._edit(t)}">Edit</button></td></tr>`)}</tbody></table></div></section>`)}render(){return a`<div class="wrap">${w("manage-links",this._role,this.allowShare)}<h1 class="sr-only">Public links</h1><div class="page-intro"><p class="intro">Manage public links and the findings each link can show.</p><span class="result-count">${this._data?.shares.length??"\u2026"} links</span></div>${this._loading&&this._data?a`<span class="sr-only" role="status">Refreshing public links…</span>`:d}<div class="manage-list" aria-busy="${this._loading}">${this._body()}</div></div>`}};customElements.define("managed-admin-links",Ye);var qr="/api/admin/deduplication";async function Xe(s="",e={}){let t=await m(`${qr}${s}`,{credentials:"same-origin",...e}),i=await t.json();if(!t.ok){let r={"storage-encryption-required":"Configure MANAGED_STORAGE_ENCRYPTION_KEY on the server to import encrypted link reports.","invalid-link-report":'Choose a link report containing arrays of finding IDs, such as [["id1", "id2"]].',"too-large":"This link report exceeds the server upload limit."};throw new Error(r[i?.error]??`HTTP ${t.status}`)}return i}var Ze=class extends b{static properties={_data:{state:!0},_error:{state:!0},_busy:{state:!0},_dragOver:{state:!0}};static styles=[h(f),h(ce),h(F)];constructor(){super(),this._data=null,this._error=null,this._busy=!1,this._dragOver=!1,this._queue=[]}connectedCallback(){super.connectedCallback(),this._load(),this._teardownDrop=J(this,e=>{this._upload(e)},e=>{this._dragOver=e})}disconnectedCallback(){this._teardownDrop?.(),super.disconnectedCallback()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection("deduplication","deduplication reports",t=>Xe("",{signal:t}),t=>{this._data=t})}_upload(e){if(!(!this._csrf||this._role!=="admin"))return Y(this,e,t=>Xe("",{method:"POST",headers:{"content-type":"application/json","x-report-filename":encodeURIComponent(t.name),"x-csrf-token":this._csrf},body:t}),["deduplication","reports","teams"])}async _toggle(e){if(!(this._busy||!this._csrf)){this._busy=!0,this._error=null;try{await this.appState.mutate(()=>Xe(`/${encodeURIComponent(e.id)}`,{method:"PATCH",headers:{"content-type":"application/json","x-csrf-token":this._csrf},body:JSON.stringify({enabled:!e.enabled})}),["deduplication","reports","teams"])}catch(t){this._error=String(t?.message??t)}finally{this._busy=!1,await this._load({preserveError:!0});let t=this._queue.splice(0);t.length>0&&this._upload(t)}}}_view(e){document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:"manage-deduplication",linkId:e.id},bubbles:!0,composed:!0}))}_linkReports(){document.dispatchEvent(new CustomEvent("managed-admin-navigate",{detail:{view:"manage-scans",scanMode:"link"},bubbles:!0,composed:!0}))}render(){let e=this._data?.reports??[];return a`${this._dragOver?a`<div class="dropzone">Drop link reports to import</div>`:d}<div class="wrap">${w("manage-deduplication",this._role,this.allowShare)}<h1 class="sr-only">Deduplication</h1><div class="page-intro"><p class="intro">Link duplicate findings across all teams.</p><span class="result-count">${this._data?e.length:"\u2026"} reports</span><button type="button" class="btn" @click="${()=>this._linkReports()}">Link reports</button></div><div class="drop-card"><span class="drop-icon" aria-hidden="true">${y("upload")}</span><span class="drop-copy"><strong>Import link reports</strong><span>Drop *.link.json files anywhere on this page.</span></span><button type="button" class="drop-browse" ?disabled="${this._busy||!this._csrf}" @click="${()=>W(t=>{this._upload(t)})}">${this._busy?"Saving\u2026":"Browse files"}</button></div>${this._error?a`<p class="msg error" role="alert">${this._error}</p>`:d}<div class="manage-list" aria-busy="${this._loading}">${this._data===null?this._error?d:k("Loading deduplication reports\u2026"):e.length===0?a`<div class="empty"><strong>No link reports imported yet</strong><p>Each row in a link report lists IDs for the same finding.</p></div>`:a`<div class="link-table"><table><thead><tr><th>Report</th><th>Groups</th><th>Finding IDs</th><th>Imported by</th><th>Imported</th><th>Status</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody>${e.map(t=>a`<tr><td>${t.filename}</td><td>${t.groupCount}</td><td>${t.findingCount}</td><td>${t.uploadedByLogin??"Removed user"}</td><td>${new Date(t.uploadedAt).toLocaleDateString()}</td><td>${t.enabled?"Enabled":"Disabled"}</td><td><button type="button" class="btn" aria-label="${`View ${t.filename}`}" @click="${()=>this._view(t)}">View</button> <button type="button" class="btn" ?disabled="${this._busy}" aria-label="${`${t.enabled?"Disable":"Enable"} ${t.filename}`}" @click="${()=>{this._toggle(t)}}">${t.enabled?"Disable":"Enable"}</button></td></tr>`)}</tbody></table></div>`}</div></div>`}};customElements.define("managed-admin-deduplication",Ze);var Ur=[[75,"critical"],[50,"high"],[25,"moderate"],[0,"low"]],xi=s=>Ur.find(([e])=>s>=e)[1];var Ri=`.risk-progress{margin:0 0 1rem;color:var(--muted);font-size:.8rem}.risk-section{margin-top:1rem}.risk-section:first-child{margin-top:0}.risk-section h2{margin:0 0 .5rem;font-size:1rem;font-weight:600}.risk-results-head{position:sticky;top:0;z-index:1;padding-bottom:.25rem;background:var(--bg)}.risk-results-head .collection-toolbar{margin-bottom:0}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}.risk-name,.risk-name:visited{color:var(--text)}.risk-name:hover{color:var(--accent);text-decoration:none}.risk-repos{margin:0;padding:0;list-style:none;font-size:.8rem}.risk-repos>li{display:grid;grid-template-columns:minmax(8rem,16rem) 1fr;gap:.75rem;align-items:baseline;padding:.3rem 0;border-bottom:1px solid var(--border)}.risk-repo-name{overflow:hidden;font-weight:500;text-overflow:ellipsis;white-space:nowrap}.risk-lockfiles{display:flex;flex-wrap:wrap;gap:.15rem 1.5rem;margin:0;padding:0;list-style:none}.risk-lockfiles li{white-space:nowrap}.risk-lockfile-meta{margin-left:.5rem;color:var(--muted)}@container (max-width: 40rem){.risk-repos>li{grid-template-columns:1fr;gap:0}}th:last-child,td:last-child{text-align:left}td{vertical-align:top}.risk-findings-column{width:100%}.risk-clip{display:block;max-width:18rem;overflow:hidden;text-overflow:ellipsis}.risk-used-in{max-width:14rem}.risk-pending,.risk-none{color:var(--muted)}.risk-error{color:var(--critical)}.risk-chip{display:inline-block;padding:0 .45rem;border-radius:999px;font-weight:600;white-space:nowrap;color:var(--sev);background:color-mix(in srgb,var(--sev) 14%,transparent)}.risk-score{display:inline-block;min-width:2.25rem;padding:0 .4rem;border-radius:999px;font-weight:600;font-variant-numeric:tabular-nums;text-align:center;color:var(--sev);background:color-mix(in srgb,var(--sev) 14%,transparent)}.risk-score.risk-low{color:var(--muted);background:none;font-weight:400}.is-stale .risk-score,.is-stale .risk-findings{opacity:.55}.risk-stale,.risk-dev{margin-left:.35rem;padding:0 .35rem;border:1px solid var(--border);border-radius:999px;color:var(--muted);font-size:.7rem}.risk-findings{display:flex;flex-wrap:wrap;gap:.25rem .75rem;margin:0;padding:0;list-style:none}.risk-findings li{color:var(--sev);white-space:nowrap}.risk-critical{--sev: var(--critical)}.risk-high{--sev: var(--high)}.risk-moderate{--sev: var(--yellow)}.risk-low,.risk-notice{--sev: var(--muted)}.risk-scope-bar{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem;margin:0 0 1rem}.risk-scope,.risk-tabs{display:flex;gap:2px;padding:3px;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--bg)}.risk-scope button,.risk-tabs button{padding:.3rem .65rem;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted);font-size:.75rem}.risk-scope button:hover:not(:disabled),.risk-tabs button:hover{background:var(--surface-active);color:var(--text)}.risk-scope button[aria-pressed=true],.risk-tabs button[aria-selected=true]{background:color-mix(in srgb,var(--accent) 15%,var(--bg));color:var(--accent)}.risk-scope button:focus-visible,.risk-tabs button:focus-visible{outline-offset:-1px}.risk-scope{flex-wrap:wrap;max-width:100%;box-sizing:border-box}.risk-scope-bar select{min-width:14rem}.risk-scope-bar repository-selector{flex:0 1 20rem;min-width:14rem}.risk-tabs{width:fit-content;margin-bottom:.5rem}
18
- `;var jr={malware:"Malware",deprecated:"Deprecated",publisher:"Publisher changed","provenance-lost":"Provenance lost","too-new":"Too new",popularity:"Unpopular","held-install-scripts":"Install scripts","held-runs-code":"Runs code","held-credentials":"Credentials","held-exfiltration":"Exfiltration host","held-remote":"Remote host","held-ip-lookup":"IP lookup","held-obfuscated":"Obfuscated","held-non-registry-deps":"Non-registry dependencies","held-unused-deps":"Unused deps","large-code":"Large new code","now-unreadable":"Now unreadable","binary-code":"Binary code","new-hosts":"New hosts"},Hr={"no-repository":"No GitHub access","github-not-found":"Not found on GitHub","github-unauthorized":"GitHub sign-in expired","github-rate-limited":"GitHub rate limit reached","github-unreachable":"GitHub unreachable","github-malformed":"GitHub answered unexpectedly","unsupported-format":"Format not read","lockfile-unreadable":"Unreadable","package-not-found":"Not on npm","version-not-found":"Version not on npm","integrity-mismatch":"Differs from npm\u2019s","npm-busy":"Server busy","package-too-large":"Too large to assess","upstream-busy":"npm busy","upstream-unavailable":"npm unavailable","upstream-too-large":"npm answered too much","upstream-invalid":"npm answered unexpectedly"},Z=s=>Hr[s]??s,Gr={401:"Sign in again to scan repositories.",403:"Only admins can scan repositories.",404:"That team or repository is no longer connected. Choose again."},Kr=[["all","All repositories"],["team","Team"],["repo","Repository"]],Vr=5,Wr={registry:"npm",mirror:"Mirror",git:"Git",tarball:"Tarball",file:"File"},L=s=>s==="registry"||s==="mirror",he=s=>s.risk?.error==="integrity-mismatch"?null:s.malware??null,Pi=s=>he(s)?"critical":s.risk?.severity??null,Di=s=>he(s)?100:s.risk&&!s.risk.error?s.risk.score??null:null,ue=s=>{let e=s.risk?.findings??[];return he(s)?[{id:"malware",severity:"critical"},...e.filter(({id:t})=>t!=="malware")]:e},Jr=s=>[...he(s)??[],...s.risk?.findings?.some(({id:e,takenDown:t})=>e==="malware"&&t)?["Taken down by npm"]:[]],Si=s=>!!s.dev&&!ue(s).some(({id:e})=>e==="malware"),Ci=s=>ne.includes(s)?ne.indexOf(s):ne.length,Yr=s=>`${s[0].toUpperCase()}${s.slice(1)}`,Ei={all:["All packages",()=>!0],flagged:["Flagged",s=>!!Pi(s)],failed:["Not assessed: failed",s=>!!s.risk?.error],elsewhere:["Not assessed: not from npm",s=>!L(s.source)]},Xr="Out of 100: what its findings call for, lowered by how long the version has been out among how many download its package. Malware is 100.",Zr="Only devDependencies need it, in every lockfile that locks it: an install without them leaves it out. Assessed after the rest, and listed after them unless it is malware.",Qr="Only devDependencies need these versions, in every lockfile that locks them: an install without them leaves them out.",es={production:["Production","Advisories of versions an install for production takes: some lockfile needs them as more than devDependencies do, or doesn\u2019t say. Malware\u2019s are shown either way."],development:["Development","Advisories of versions only devDependencies need, in every lockfile that locks them. Malware\u2019s are shown either way."]},Ai=s=>a`<span class="risk-dev" data-tooltip="${s}">dev</span>`;function ts(s,e){let t=s.stale??null;return s.error&&!t&&e?.stale&&!e.error?{...e,refreshFailed:s.detail?`${Z(s.error)}: ${s.detail}`:Z(s.error)}:s.error?{error:s.error,detail:s.detail??null,stale:t}:{severity:s.severity,score:s.score??null,findings:s.findings,published:s.published,stale:t}}var Qe=new Intl.RelativeTimeFormat("en",{numeric:"auto"});function is(s,e=Date.now()){let t=Math.round((s-e)/6e4);if(Math.abs(t)<60)return Qe.format(t,"minute");let i=Math.round(t/60);return Math.abs(i)<48?Qe.format(i,"hour"):Qe.format(Math.round(i/24),"day")}var Ti=100,Ii=3,j=1e3,rs=250,$=new Intl.NumberFormat,Ni=s=>({total:s.length,told:s.filter(e=>e.risk).length,flagged:s.filter(Pi).length,stale:s.filter(e=>e.risk?.stale).length});function Li(s){let e=[...s];return e.length===1?a`<span class="risk-clip risk-used-in" data-tooltip-truncated data-tooltip="${e[0]}">${e[0]}</span>`:a`<span class="risk-clip risk-used-in" data-tooltip="${e.join(`
19
- `)}">${$.format(e.length)} lockfiles</span>`}var ss=(s,e,t)=>C(`/api/admin/repositories/risk${s.size>0?`?${s}`:""}`,Gr,async i=>{for await(let r of $e(i))t(r)},e),zi=({name:s,version:e,integrity:t})=>`${s}@${e}\0${t??""}`,as=s=>L(s.source)?zi(s):`${s.source}\0${s.name}@${s.version??""}\0${s.from??""}`;function Oi(s){let e=Di(s);return e>0?-e:L(s.source)?e===0?3:s.risk?2:1:4}var et=class extends b{static properties={_state:{state:!0},_error:{state:!0},_filter:{state:!0},_kind:{state:!0},_query:{state:!0},_tab:{state:!0},_scope:{state:!0},_target:{state:!0},_choices:{state:!0}};static styles=[h(f),h(F),h(Ri)];constructor(){super(),this._state="idle",this._error=null,this._filter="all",this._kind="production",this._query="",this._tab="packages",this._scan=null,this._drawTimer=null,this._parts=0,this._scope="all",this._target="",this._choices=null,this._reset()}connectedCallback(){super.connectedCallback(),this._loadCollection("teams","teams",V,e=>{this._choices=e})}_choose(e,t=""){this._state==="running"||e===this._scope&&t===this._target||(this._scope=e,this._target=t,this._reset(),this._error=null,this._state="idle")}_reset(){this._repos=new Map,this._packages=new Map,this._advisories=new Map}disconnectedCallback(){this.stop(),super.disconnectedCallback()}async start(){if(this._state==="running"||this._scope!=="all"&&!this._target)return;let e=new URLSearchParams({...this._scope==="all"?{}:{[this._scope]:this._target},scan:crypto.randomUUID()});this._reset(),this._error=null,this._state="running";let t=new AbortController;this._scan=t,this._parts=0;try{for(let i="continue",r=0;i==="continue";){if(++this._parts>Ti)throw new Error(`Stopped after ${$.format(Ti)} parts. Scan again to go on from where it stopped.`);i=null;let o=this._told();if(await ss(e,t.signal,n=>{(n.type==="done"||n.type==="continue")&&(i=n.type),this._apply(n),this._draw()}),i===null)throw new Error("The scan ended before it finished. Try again.");if(r=this._told()>o?0:r+1,i==="continue"&&r>=Ii)throw new Error(`Stopped: the last ${$.format(Ii)} parts found nothing more. Scan again to try once more.`)}this._state="done"}catch(i){if(t.signal.aborted||i?.name==="AbortError")return;this._error=i?.message??String(i),this._state="stopped"}finally{this._scan===t&&(this._scan=null,this._state==="running"&&(this._state="stopped")),this._draw(!0)}}stop(){this._scan&&(this._scan.abort(),this._scan=null,this._state="stopped",this._draw(!0))}_draw(e=!1){if(e){clearTimeout(this._drawTimer),this._drawTimer=null,this.requestUpdate();return}this._drawTimer??=setTimeout(()=>{this._drawTimer=null,this.requestUpdate()},rs)}_told(){let e=0;for(let t of this._repos.values()){(t.lockfiles||t.error)&&e++;for(let i of t.lockfiles?.values()??[])e+=+(i.packages!==null||!!i.error)+ +!!(i.advisories||i.advisoriesError)}for(let t of this._packages.values())t.risk&&!t.risk.stale&&e++;return e}_apply(e){if(e.type==="repos"){let t=new Map(e.repos.map(({id:r,fullName:o})=>[r,o])),i=[...this._repos.values()].filter(r=>t.get(r.id)!==r.fullName);for(let r of i)this._repos.delete(r.id);this._forget(i.flatMap(r=>[...r.lockfiles?.keys()??[]].map(o=>`${r.fullName}/${o}`)));for(let{id:r,fullName:o}of e.repos)this._repos.has(r)||this._repos.set(r,{id:r,fullName:o,commit:null,lockfiles:null,error:null,detail:null})}else if(e.type==="repo"){let t=this._repos.get(e.id);if(!t)return;if(e.error){let n=[...t.lockfiles?.keys()??[]].map(l=>`${t.fullName}/${l}`);Object.assign(t,{lockfiles:null,error:e.error,detail:e.detail??null}),this._forget(n);return}let i=t.commit!==null&&t.commit!==e.commit,r=new Set(i?[]:e.lockfiles.map(({path:n})=>n)),o=[...t.lockfiles?.keys()??[]].filter(n=>!r.has(n)).map(n=>`${t.fullName}/${n}`);Object.assign(t,{commit:e.commit,error:null,detail:null}),t.lockfiles=new Map(e.lockfiles.map(n=>[n.path,!i&&t.lockfiles?.get(n.path)||{...n,packages:null,error:null}])),this._forget(o)}else if(e.type==="lockfile"){let t=this._repos.get(e.repo),i=t?.lockfiles?.get(e.path);if(!i)return;if(e.error){Object.assign(i,{error:e.error,detail:e.detail??null});return}Object.assign(i,{packages:e.packages.length,error:null,detail:null});let r=`${t.fullName}/${e.path}`;for(let o of e.packages){let n=as(o),l=this._packages.get(n);l||this._packages.set(n,l={...o,usedIn:new Set,neededIn:new Set,risk:null}),l.usedIn.add(r),o.dev!==!0&&l.neededIn.add(r),l.dev=l.neededIn.size===0}}else if(e.type==="risk"){let t=this._packages.get(zi(e));t&&(t.risk=ts(e,t.risk))}else e.type==="advisories"&&this._applyAdvisories(e)}_forget(e){if(e.length!==0){for(let[t,i]of this._packages){for(let r of e)i.usedIn.delete(r),i.neededIn.delete(r);i.usedIn.size===0&&this._packages.delete(t),i.dev=i.neededIn.size===0}this._readvise()}}_readvise(){this._advisories=new Map;for(let e of this._packages.values())e.malware=void 0;for(let e of this._repos.values())for(let[t,i]of e.lockfiles??[])i.advisories&&this._advise(`${e.fullName}/${t}`,i.advisories)}_applyAdvisories(e){let t=this._repos.get(e.repo),i=t?.lockfiles?.get(e.path);if(!i)return;if(e.error){i.advisoriesError=e.error;return}let r=i.advisories;Object.assign(i,{advisories:e.advisories,advisoriesError:null}),r?JSON.stringify(r)!==JSON.stringify(e.advisories)&&this._readvise():this._advise(`${t.fullName}/${e.path}`,e.advisories)}_advise(e,t){for(let{range:i,versions:r,...o}of t){let n=`${o.id}\0${o.name}`,l=this._advisories.get(n);l||this._advisories.set(n,l={...o,ranges:new Set,versions:new Set,usedIn:new Set,versionsIn:new Map}),i&&l.ranges.add(i);for(let p of r)l.versions.add(p);l.malware||=o.malware,l.usedIn.add(e);let c=l.versionsIn.get(e)??l.versionsIn.set(e,new Set).get(e);for(let p of r)c.add(p);if(l.malware)for(let p of this._packages.values())L(p.source)&&p.name===l.name&&l.versions.has(p.version)&&(p.malware??=new Set).add(l.id)}}_counts(){let e=[...this._repos.values()],t=e.flatMap(r=>[...r.lockfiles?.values()??[]]),i=[...this._packages.values()].filter(r=>L(r.source));return{repos:e.length,reposRead:e.filter(r=>r.lockfiles||r.error).length,lockfiles:t.length,lockfilesRead:t.filter(r=>r.packages!==null||r.error).length,needed:Ni(i.filter(r=>!r.dev)),dev:Ni(i.filter(r=>r.dev)),advisories:this._advisories.size,malware:[...this._advisories.values()].filter(r=>r.malware).length}}_rows(){let e=this._query.trim().toLowerCase(),[,t]=Ei[this._filter];return[...this._packages.values()].filter(i=>t(i)&&(!e||i.name.toLowerCase().includes(e))).toSorted((i,r)=>Number(Si(i))-Number(Si(r))||Oi(i)-Oi(r)||ue(r).length-ue(i).length||i.name.localeCompare(r.name)||(i.version??"").localeCompare(r.version??""))}_advisoryKinds(){let e=new Map;for(let i of this._packages.values()){let r=`${i.name}@${i.version}`;L(i.source)&&e.set(r,(e.get(r)??!0)&&i.dev)}let t={production:[],development:[]};for(let i of this._advisories.values()){let r=[...i.versions],o=r.filter(c=>e.get(`${i.name}@${c}`)===!0),n=r.filter(c=>e.get(`${i.name}@${c}`)!==!0);if(i.malware){let c={...i,dev:n.length===0};t.production.push(c),t.development.push(c);continue}let l=c=>({...i,versions:new Set(c),usedIn:new Set([...i.versionsIn].filter(([,p])=>c.some(u=>p.has(u))).map(([p])=>p))});n.length>0&&t.production.push({...l(n),dev:!1}),o.length>0&&t.development.push({...l(o),dev:!0})}return t}_advisoryRows(e=this._advisoryKinds()){let t=this._query.trim().toLowerCase();return e[this._kind].filter(i=>!t||i.name.toLowerCase().includes(t)).toSorted((i,r)=>Number(r.malware)-Number(i.malware)||Ci(i.severity)-Ci(r.severity)||i.name.localeCompare(r.name)||i.id.localeCompare(r.id))}_kindToggle(e){return a`<div class="risk-scope" role="group" aria-label="Which advisories">${Object.entries(es).map(([t,[i,r]])=>a`<button type="button" aria-pressed="${this._kind===t}" data-tooltip="${r}" @click="${()=>{this._kind=t}}">${i} (${$.format(e[t].length)})</button>`)}</div>`}render(){return a`<div class="wrap">${w("manage-repos",this._role,this.allowShare)}<h1 class="sr-only">Repository risk</h1><div class="page-intro"><p class="intro">Each connected repository’s npm lockfiles at its default branch, and what risk finds in each package they lock.</p>${this._state==="running"?a`<button type="button" class="btn" @click="${()=>this.stop()}">Stop</button>`:a`<button type="button" class="btn primary" ?disabled="${this._scope!=="all"&&!this._target}" @click="${()=>{this.start()}}">${this._state==="idle"?"Start scan":"Scan again"}</button>`}</div>${this._scopeBar()}<p class="risk-progress" role="status">${this._progress()}</p>${this._error?a`<p class="msg error" role="alert">${this._error}</p>`:d} ${this._repos.size===0?d:a`<div class="manage-list">${this._lockfiles()} ${this._packages.size===0?d:this._tab==="advisories"?this._advisoryTable():this._packageTable()}</div>`}</div>`}_tabs(){let e=[["packages","Packages"],["advisories",`Advisories${this._advisories.size>0?` (${$.format(this._advisories.size)})`:""}`]];return a`<div class="risk-tabs" role="tablist" aria-label="Results">${e.map(([t,i])=>a`<button type="button" role="tab" aria-selected="${this._tab===t}" @click="${()=>{this._tab=t}}">${i}</button>`)}</div>`}_search(e,t,i){return a`<input type="search" aria-label="${`Search ${i}`}" placeholder="Search by package…" .value="${this._query}" @input="${r=>{this._query=r.target.value}}"> <span class="result-count">${e===t?"":`${$.format(e)} of `}${$.format(t)} ${i}</span>`}_scopeBar(){let e=this._state==="running",t=this._choices?"":"Loading\u2026";return a`<div class="risk-scope-bar"><div class="risk-scope" role="group" aria-label="What to scan">${Kr.map(([i,r])=>a`<button type="button" aria-pressed="${this._scope===i}" ?disabled="${e}" @click="${()=>this._choose(i)}">${r}</button>`)}</div>${this._scope==="team"?this._teamPicker(e,t):d} ${this._scope==="repo"?a`<repository-selector label="Which repository" placeholder="${t||"Choose a repository\u2026"}" ?disabled="${e||!this._choices}" .options="${(this._choices?.repos??[]).map(i=>({value:String(i.repoId),label:i.fullName}))}" .value="${this._target||null}" @repository-change="${i=>this._choose("repo",i.detail.value)}"></repository-selector>`:d}</div>`}_teamPicker(e,t){let i=this._choices?.teams??[],r=o=>o.hidden?`${o.name} (hidden)`:o.name;return i.length>0&&i.length<=Vr?a`<div class="risk-scope" role="group" aria-label="Which team">${i.map(o=>a`<button type="button" aria-pressed="${o.id===this._target}" ?disabled="${e}" @click="${()=>this._choose("team",o.id)}">${r(o)}</button>`)}</div>`:a`<select aria-label="Which team" ?disabled="${e}" @change="${o=>this._choose("team",o.target.value)}"><option value="" ?selected="${!this._target}">${t||"Choose a team\u2026"}</option>${i.map(o=>a`<option value="${o.id}" ?selected="${o.id===this._target}">${r(o)}</option>`)}</select>`}_progress(){if(this._state==="idle")return"Not scanned yet. A scan reads each repository from GitHub and assesses each npm package it locks, which can take a while; a scan again within the hour is quicker.";let e=this._counts(),{needed:t,dev:i}=e,r=(l,c,p)=>`${$.format(l)} of ${$.format(c)}${p?` ${p}`:""}`,o=(l,c)=>i.total===0?`${c(t)} ${l}`:`${c(t)} non-dev and ${c(i)} dev ${l}`;return[this._state==="running"&&this._parts>1?`Scanning, part ${$.format(this._parts)}`:{running:"Scanning",stopped:"Stopped",done:"Done"}[this._state],r(e.reposRead,e.repos,"repositories read"),r(e.lockfilesRead,e.lockfiles,"lockfiles"),o("packages assessed",({told:l,total:c})=>r(l,c)),o("flagged",({flagged:l})=>$.format(l)),...t.stale+i.stale>0?[o("stale",({stale:l})=>$.format(l))]:[],...e.advisories>0?[`${$.format(e.advisories)} advisories${e.malware>0?`, ${$.format(e.malware)} of malware`:""}`]:[]].join(" \xB7 ")}_pending(e,t){return a`<span class="risk-pending">${this._state==="running"?e:t}</span>`}_repoStatus(e){return e.error?a`<span class="risk-error" data-tooltip="${e.detail??d}">${Z(e.error)}</span>`:e.lockfiles===null?this._pending("Waiting\u2026","Not read"):e.lockfiles.size===0?a`<span class="risk-none">No npm lockfiles</span>`:null}_lockfileStatus(e){return e.error?a`<span class="risk-error" data-tooltip="${e.detail??d}">${Z(e.error)}</span>`:e.packages===null?this._pending("Reading\u2026","Not read"):`${$.format(e.packages)} packages`}_lockfiles(){return a`<section class="risk-section" aria-label="Lockfiles"><h2>Lockfiles</h2><ul class="risk-repos">${[...this._repos.values()].map(e=>a`<li><span class="risk-repo-name" data-tooltip-truncated data-tooltip="${e.fullName}">${e.fullName}</span> ${this._repoStatus(e)??a`<ul class="risk-lockfiles">${[...e.lockfiles.values()].map(t=>a`<li><span class="mono">${t.path}</span><span class="risk-lockfile-meta">${t.format} · ${this._lockfileStatus(t)}</span></li>`)}</ul>`}</li>`)}</ul></section>`}_resultsHead(e){return a`<div class="risk-results-head">${this._tabs()}<div class="collection-toolbar">${e}</div></div>`}_packageTable(){let e=this._rows();return a`<section class="risk-section" aria-label="Packages">${this._resultsHead(a`<select aria-label="Show packages" .value="${this._filter}" @change="${t=>{this._filter=t.target.value}}">${Object.entries(Ei).map(([t,[i]])=>a`<option value="${t}">${i}</option>`)}</select> ${this._search(e.length,this._packages.size,"packages")}`)}<div class="link-table"><table><thead><tr><th>Package</th><th>Version</th><th><span data-tooltip="${Xr}">Risk</span></th><th class="risk-findings-column">Findings</th><th>Source</th><th>Used in</th></tr></thead><tbody>${e.slice(0,j).map(t=>this._packageRow(t))}</tbody></table></div>${e.length>j?a`<p class="msg">Showing the first ${$.format(j)}. Search or filter to see others.</p>`:d}</section>`}_packageRow(e){let t=L(e.source)?H({view:"npm",packageName:e.name,packageSpec:e.version}):null;return a`<tr class="${e.risk?.stale?"is-stale":""}"><td>${t?a`<a class="risk-name" href="${t}">${e.name}</a>`:e.name}${e.dev?Ai(Zr):d}</td><td class="mono">${e.version??"\u2014"}</td><td>${this._score(e)}</td><td>${this._findings(e)}</td><td><span data-tooltip="${e.from??d}">${Wr[e.source]??e.source}${e.source==="mirror"&&e.from?` (${new URL(e.from).host})`:""}</span></td><td>${Li(e.usedIn)}</td></tr>`}_score(e){let t=Di(e),i=t===null?d:a`<span class="${`risk-score risk-${xi(t)}`}">${t}</span>`;return e.risk?.stale?a`${i}<span class="risk-stale" data-tooltip="${this._staleSaid(e.risk)}">stale</span>`:i}_staleSaid({stale:e,refreshFailed:t}){let i=t?`couldn\u2019t be assessed again: ${t}`:this._state==="running"?"to be assessed again once the rest are":"not assessed again yet";return`Assessed ${is(e.assessedAt)}; ${i}`}_findings(e){let t=ue(e);return t.length>0?a`<ul class="risk-findings">${t.map(i=>a`<li class="${`risk-${i.severity}`}" data-tooltip="${i.id==="malware"?Jr(e).join(`
20
- `):d}">${jr[i.id]??i.id}</li>`)}</ul>`:L(e.source)?e.risk?e.risk.error?a`<span class="risk-error" data-tooltip="${e.risk.detail??d}">${Z(e.risk.error)}</span>`:a`<span class="risk-none">None found</span>`:this._pending("Waiting\u2026","Not assessed"):a`<span class="risk-none">Not assessed</span>`}_advisoryTable(){let e=this._advisoryKinds(),t=this._advisoryRows(e),i=[...this._repos.values()].flatMap(o=>[...o.lockfiles?.values()??[]].filter(n=>n.advisoriesError).map(n=>`${o.fullName}/${n.path}`)),r=this._kind==="production"?"npm has no advisories of the versions an install for production takes.":"npm has no advisories of the versions only devDependencies need.";return a`<section class="risk-section" aria-label="Advisories">${this._resultsHead(a`${this._kindToggle(e)}${this._search(t.length,e[this._kind].length,"advisories")}`)} ${i.length>0?a`<p class="msg error">npm’s advisories couldn’t be had for <span data-tooltip="${i.join(`
21
- `)}">${i.length===1?i[0]:`${$.format(i.length)} lockfiles`}</span>.</p>`:d} ${t.length===0?a`<p class="msg">${this._state==="running"?"None yet.":r}</p>`:a`<div class="link-table"><table><thead><tr><th>Package</th><th>Versions</th><th>Severity</th><th>Advisory</th><th>Title</th><th>Affected</th><th>Used in</th></tr></thead><tbody>${t.slice(0,j).map(o=>this._advisoryRow(o))}</tbody></table></div>`} ${t.length>j?a`<p class="msg">Showing the first ${$.format(j)}. Search to see others.</p>`:d}</section>`}_advisoryRow(e){let t=[...e.versions],i=e.malware?"critical":e.severity;return a`<tr><td><a class="risk-name" href="${H({view:"npm",packageName:e.name,packageSpec:t[0]})}">${e.name}</a>${e.dev?Ai(Qr):d}</td><td class="mono">${t.join(", ")}</td><td>${e.malware?a`<span class="risk-chip risk-critical">Malware</span>`:i?a`<span class="${`risk-chip risk-${i}`}">${Yr(i)}</span>`:d}</td><td class="mono">${nt(e.url)?a`<a href="${e.url}" target="_blank" rel="noopener noreferrer">${e.id}</a>`:e.id}</td><td><span class="risk-clip" data-tooltip-truncated data-tooltip="${e.title??d}">${e.title??""}</span></td><td class="mono">${[...e.ranges].join(" || ")}</td><td>${Li(e.usedIn)}</td></tr>`}};customElements.define("managed-admin-repo-risk",et);function os(s,e){return new Promise(t=>{if(e.aborted){t();return}let i=()=>{clearTimeout(r),e.removeEventListener("abort",i),t()},r=setTimeout(i,s);e.addEventListener("abort",i,{once:!0})})}async function ns(s,{signal:e,onUpdate:t,onTeams:i,onClose:r,reportId:o=null}){if(P())return;let n=1e3,l=async(c,p,u)=>{if(u.throwIfAborted(),c==="close")return await r(),!1;if(c==="triage"||c==="teams"){let v=null;if(c==="teams")try{let _=JSON.parse(p);typeof _?.revision=="string"&&(v=_.revision)}catch{}if(await(c==="teams"?i?.(u,v):t(u))===!1)throw new Error("Team refresh failed");u.throwIfAborted(),n=1e3}return!0};for(;!e.aborted;){let c=new AbortController,p=()=>c.abort();e.addEventListener("abort",p,{once:!0});let u,v,_=()=>{clearTimeout(v),v=setTimeout(p,45e3)};try{_();let S=o===null?"":`?reportId=${encodeURIComponent(o)}`,R=await m(s?`/api/teams/${encodeURIComponent(s)}/feed${S}`:"/api/teams/feed",{credentials:"same-origin",headers:{accept:"text/event-stream"},signal:c.signal});if([401,403,404].includes(R.status)){await R.body?.cancel(),e.aborted||await r();return}if(!R.ok||!R.headers.get("content-type")?.startsWith("text/event-stream"))throw await R.body?.cancel(),new Error("Team feed unavailable");if(u=R.body.getReader(),await ls(u,e,_,(ee,te)=>l(ee,te,c.signal)))return}catch{}finally{clearTimeout(v),p(),await u?.cancel().catch(()=>{}),e.removeEventListener("abort",p)}await os(n,e),n=Math.min(n*2,3e4)}}async function ls(s,e,t,i){let r=new TextDecoder,o="";for(;!e.aborted;){let{done:n,value:l}=await s.read();if(n)return!1;if(t(),o=(o+r.decode(l,{stream:!0})).replaceAll(`\r
1
+ import{b as e,d as t,i as n}from"./chunk-4UFAMJAX.js";import{a as r,b as i,c as a}from"./chunk-GDPCLSOS.js";import{A as o,B as s,a as c,b as l,c as u,d,e as f,f as ee,g as te,h as ne,i as re,j as ie,k as ae,l as oe,m as se,n as ce,o as le,p as ue,q as de,r as fe,s as pe,t as me,u as he,v as ge,w as _e,x as ve,y as ye,z as be}from"./chunk-BOIXMUU5.js";import"./chunk-QB4CBOX2.js";import{Q as xe,Qa as Se,Sa as Ce,Y as we,Z as Te,a as Ee,c as De,j as Oe,k as p,m as ke,n as Ae,p as je,s as Me,t as Ne,w as Pe,x as Fe,y as Ie}from"./chunk-S6GIXWQW.js";import{w as Le}from"./chunk-JKGQ3O7O.js";import{b as Re}from"./chunk-NRPC74AM.js";import"./chunk-PNHBZGDD.js";import"./chunk-VFWMQ3LG.js";import{a as m,e as ze}from"./chunk-3PS4KWD2.js";import"./chunk-IYPY47MC.js";import{c as Be,d as Ve}from"./chunk-OKRLLE5I.js";import{f as He,k as h}from"./chunk-BC2UCLFJ.js";import{B as Ue,D as We,J as Ge}from"./chunk-SXV2T5C4.js";import{B as Ke,C as qe,d as g,h as Je,i as Ye,j as Xe,w as Ze,x as Qe}from"./chunk-WFYLMF6Z.js";import"./chunk-C4Z6ZBXV.js";import"./chunk-TUII34K2.js";import{a as _,b as $e,c as v,d as et,g as y,j as tt}from"./chunk-2XUEZHIP.js";import"./chunk-OOJM4CTU.js";var b=class extends tt{static properties={session:{attribute:!1},allowShare:{attribute:!1},_loading:{state:!0}};constructor(){super(),this.session=null,this.allowShare=!1,this.appState=f,this._loading=!1,this._loadRequest=null}get _role(){return this.session?.role??null}get _csrf(){return this.session?.csrfToken??null}get _me(){return this.session?.id??null}disconnectedCallback(){this._loadRequest?.abort(),super.disconnectedCallback()}async _loadCollection(e,t,n,r){this._loadRequest?.abort();let i=new AbortController;this._loadRequest=i,this._loading=!0;try{await this.appState.load(e,t,n,{signal:i.signal,apply:r})}catch(t){!i.signal.aborted&&t?.name!==`AbortError`&&this.appState.read(e)===void 0&&(this._error=String(t?.message??t))}finally{this._loadRequest===i&&(this._loading=!1)}}};function x(e){return v`<div class="loading-rows" role="status"><span class="sr-only">${e}</span><div aria-hidden="true">${[0,1,2,3].map(()=>v`<div class="loading-row"><span></span><span></span></div>`)}</div></div>`}var nt=class extends ke{get changeEvent(){return`local-item-change`}get searchLabel(){return`Search local files`}get optionsLabel(){return`Local files`}get noMatchesLabel(){return`No matching files.`}get emptyLabel(){return`No local files available.`}choices(){let e=this._query.trim().toLocaleLowerCase(),t=this.options.filter(t=>`${t.label} ${t.secondary??``}`.toLocaleLowerCase().includes(e));return{pinned:[],sections:[{options:t}],count:t.length,total:this.options.length,showFacets:!1}}};customElements.define(`managed-local-item-selector`,nt);var rt=class{constructor(e,t,n){this.host=e,this.kind=t,this.upload=n,this.source=null,this.hasData=!1,this.open=!1,this.options=[],this.value=null,this.busy=!1,this.loading=!1,this.error=``,this.success=``,this.generation=0,this.readAbort=null,this.onChange=e=>{if(e?.kind){if(e.kind!==this.kind)return;if(e.value!==this.value){this.refresh();return}}this.readAbort&&!this.readAbort.signal.aborted&&(this.readAbort.abort(),this.error=`The local ${this.kind} changed or the list was refreshed. Select it again before importing.`),this.options=[],this.value=null,this.success=``,this.refresh()},this.onBlur=()=>{this.readAbort&&!this.readAbort.signal.aborted&&this.onChange()},this.onVisibilityChange=()=>{globalThis.document?.visibilityState===`hidden`&&this.onBlur()},e.addController(this)}hostConnected(){globalThis.addEventListener(`focus`,this.onChange),globalThis.addEventListener(`blur`,this.onBlur),globalThis.addEventListener(`storage`,this.onChange),globalThis.document?.addEventListener(`visibilitychange`,this.onVisibilityChange),this.connectSource()}hostUpdated(){this.connectSource()}connectSource(){this.source!==this.host.localImportSource&&(this.unsubscribe?.(),this.abort?.abort(),this.source=this.host.localImportSource,this.unsubscribe=this.source?.subscribe(this.onChange),this.onChange())}hostDisconnected(){++this.generation,this.abort?.abort(),this.unsubscribe?.(),this.source=null,globalThis.removeEventListener(`focus`,this.onChange),globalThis.removeEventListener(`blur`,this.onBlur),globalThis.removeEventListener(`storage`,this.onChange),globalThis.document?.removeEventListener(`visibilitychange`,this.onVisibilityChange)}async refresh(){let e=++this.generation,t=this.source;this.loading=!0,this.host.requestUpdate();try{let n=t?await t.hasData(this.kind):!1;if(e!==this.generation)return;this.hasData=n;let r=this.open&&!t?.locked?await t?.list(this.kind)??[]:[];if(e!==this.generation)return;this.options=r,r.some(e=>e.value===this.value)||(this.value=null)}catch(t){e===this.generation&&(this.error=String(t?.message??t))}finally{e===this.generation&&(this.loading=!1,this.host.requestUpdate())}}toggle(){this.busy||(this.open=!this.open,this.error=``,this.success=``,this.options=[],this.value=null,this.refresh())}async unlock(){if(this.busy)return;this.busy=!0,this.error=``;let e=this.abort=new AbortController;this.host.requestUpdate();try{await this.source.unlock({signal:e.signal})&&!e.signal.aborted&&await this.refresh()}catch(t){e.signal.aborted||(this.error=String(t?.message??t))}finally{this.busy=!1,this.host.requestUpdate()}}async importSelected(){if(this.busy||this.loading||!this.value||this.source?.locked)return;this.busy=!0,this.error=``,this.success=``;let e=this.options.find(e=>e.value===this.value)?.label,t=this.abort=new AbortController;this.readAbort=t,this.host.requestUpdate();try{await this.source.importItem(this.kind,this.value,e=>(this.readAbort=null,this.upload(e)),{signal:t.signal}),!t.signal.aborted&&!this.source?.locked&&(this.success=`Imported ${e}.`,this.value=null)}catch(e){t.signal.aborted||(this.error=String(e?.message??e))}finally{this.readAbort===t&&(this.readAbort=null),this.busy=!1,this.host.requestUpdate()}}renderAction(){return this.hasData||this.open?v`<button type="button" class="local-import-toggle" aria-expanded="${this.open}" aria-controls="local-import-panel" ?disabled="${this.busy}" @click="${()=>this.toggle()}">Import</button>`:y}renderPanel(e){if(!this.open)return y;let t=this.source?.locked;return v`<section class="local-import-panel" id="local-import-panel" aria-label="${`Import local ${this.kind}`}"><div class="local-import-copy"><strong>Import local ${this.kind}</strong><p>${t?`Unlock local data with your passkey to choose a file.`:`Copy a file from this browser to the managed workspace. The local copy stays on this device.`}</p></div><div class="local-import-controls">${t?v`<button type="button" class="local-import-submit" ?disabled="${this.busy}" @click="${()=>this.unlock()}">${this.busy?`Waiting for passkey…`:`Unlock with passkey`}</button>`:v`<managed-local-item-selector label="${`Choose local ${this.kind}`}" placeholder="${this.loading?`Loading local files…`:`Choose local ${this.kind}\u2026`}" .options="${this.options}" .value="${this.value}" ?disabled="${this.busy||this.loading}" @local-item-change="${e=>{this.value=e.detail.value,this.success=``,this.host.requestUpdate()}}"></managed-local-item-selector><button type="button" class="local-import-submit" ?disabled="${e||this.busy||this.loading||!this.value}" @click="${()=>this.importSelected()}">${this.busy?`Importing…`:`Import ${this.kind}`}</button>`} <button type="button" class="local-import-close" ?disabled="${this.busy}" @click="${()=>this.toggle()}">Close</button></div>${!t&&!this.loading&&this.options.length===0?v`<p class="local-import-message">No local ${this.kind}s available.</p>`:y} ${this.error?v`<p class="local-import-message error" role="alert">${this.error} <button type="button" ?disabled="${this.busy}" @click="${()=>{this.error=``,this.refresh()}}">Retry</button></p>`:y} ${this.success?v`<p class="local-import-message" role="status">${this.success}</p>`:y}</section>`}};async function it({signal:e}={}){e=e?AbortSignal.any([e,f.sessionController.signal]):f.sessionController.signal,e.throwIfAborted();let t=await d(`/api/admin/bundles`,{credentials:`same-origin`,signal:e});if(e.throwIfAborted(),!t.ok)throw Object.assign(Error(`Bundle catalogue request failed (${t.status})`),{status:t.status});let n=await t.json();return e.throwIfAborted(),n.bundles??[]}async function S(e,t,n){let r=f.generation,i=await d(`/api/bundles/${encodeURIComponent(e)}/${t}`,{credentials:`same-origin`,signal:n});if(n?.throwIfAborted(),!i.ok)throw Object.assign(Error(`Bundle ${t} request failed (${i.status})`),{status:i.status});let a=t===`contents`?await i.text():await i.json();if(n?.throwIfAborted(),r!==f.generation)throw new DOMException(`Managed session changed`,`AbortError`);return a}function at(e,{signal:t}={}){return f.load(`bundle-metadata:${e}`,`bundle metadata`,t=>S(e,`metadata`,t),{signal:t,retryInvalidated:!0})}async function ot(e,{signal:t}={}){t=t?AbortSignal.any([t,f.sessionController.signal]):f.sessionController.signal;let n=await S(e,`metadata`,t),r=n?.bundle?.repo??null,i=We({repo:r});if(!i)return r;let a=new URLSearchParams({repo:i,directory:r.directory??``}),o=new Set(n.unsized??[]),s=Re((n.files??[]).filter(([e,t])=>t!=null||o.has(e)).map(([e])=>e));s&&a.set(`filePrefix`,s);let c=await d(`/api/admin/repositories/resolve?${a}`,{credentials:`same-origin`,cache:`no-store`,signal:t});if(t.throwIfAborted(),!c.ok)throw Error(`Repository suggestion request failed (${c.status})`);let{location:l}=await c.json();return t.throwIfAborted(),l?{...r,github:l.github,...l.mapped?{directory:l.directory}:{},repoId:l.repoId}:r}async function st(e,{signal:t}={}){t=t?AbortSignal.any([t,f.sessionController.signal]):f.sessionController.signal;try{return await S(e,`contents`,t)}catch(e){throw e.name!==`AbortError`&&f.notify(`Couldn't load bundle contents: ${e.message}`),e}}function ct(e,t,n=``,r=!1,i=!1){let a=[t?`team=${encodeURIComponent(t)}`:``,n?`reason=${encodeURIComponent(n)}`:``,r?`repoAdvisories=true`:``,i?`details=true`:``].filter(Boolean).join(`&`);return S(e,`advisories${a?`?${a}`:``}`,f.sessionController.signal)}var C={"bad-tarball":`This package's tarball couldn't be read.`,"upstream-invalid":`The npm registry's answer for this package couldn't be read.`,"upstream-too-large":`The npm registry's answer for this package is too large to read here.`,400:`Not an npm package name and version.`,404:`No such package version, or it is not available to you.`,413:`This package is too large to open here.`,429:`Too many packages are loading. Try again shortly.`,502:`The npm registry couldn't be reached.`};async function w(e,t,n,r){r=r?AbortSignal.any([r,f.sessionController.signal]):f.sessionController.signal;let i=f.generation,a=await d(e,{credentials:`same-origin`,signal:r});if(r.throwIfAborted(),!a.ok){let e=await a.json().catch(()=>null),n=e?.error??null;throw Object.assign(Error(t[n]??t[a.status]??`Request failed (${a.status})`),{status:a.status,code:n,...typeof e?.commit==`string`?{commit:e.commit}:{}})}let o=await n(a);if(r.throwIfAborted(),i!==f.generation)throw new DOMException(`Managed session changed`,`AbortError`);return o}var T=(e,t,n)=>w(`/api/npm/${e}?${new URLSearchParams(t)}`,C,e=>e.json(),n),lt={"no-repository":`This repository is not available to you.`,"no-directory":`This directory is not at that commit, or not available to you.`,"directory-too-large":`This directory is too large to open here. Open one of its directories instead.`,"directory-unreadable":`GitHub’s archive of this directory couldn’t be read here, as when a symlink in it points outside the repository.`,"repository-busy":`Too many directories and packages are loading. Try again shortly.`,"repository-changed":`The repository changed while it was read. Try again.`,"github-rate-limited":`GitHub’s API rate limit has been reached. Try again later.`,"github-unauthorized":`GitHub authentication has expired or was revoked. Sign in again.`,"github-status-403":`GitHub denied this request. Check repository access and the GitHub App’s read permissions.`,"github-malformed":`GitHub’s archive of this directory could not be verified against its commit.`,"github-unreachable":`Could not connect to GitHub. Try again shortly.`,"github-timeout":`GitHub took too long to answer. Try again shortly.`,400:`Not a repository directory and commit.`,403:`Repository access is required to read its files.`,404:`This repository, commit or directory is unavailable.`,413:`This directory is too large to open here.`,429:`Too many directories and packages are loading. Try again shortly.`,502:`GitHub couldn’t be reached.`},E=(e,t,n)=>w(`/api/admin/repositories/${e}?${new URLSearchParams(t)}`,lt,e=>e.json(),n);function ut(e,t,n,{signal:r}={}){return E(`code`,{repoId:e,ref:t,path:n},r)}async function dt({signal:e}={}){return(await E(`browsable`,{},e)).repos??[]}function ft(e,{signal:t}={}){return E(`refs`,{repoId:e},t)}function pt(e,t,n,{signal:r}={}){return E(`contents`,{repoId:e,ref:t,path:n},r)}var mt={...lt,"no-directory":`This directory’s history is not available to you.`,"github-malformed":`GitHub answered with a history that couldn’t be read.`,"github-token-required":`Reading every branch needs your GitHub sign-in.`,400:`Not a repository’s history.`};function ht(e,t,n,{page:r=1,all:i=!1,fresh:a=!1,from:o=null,signal:s}={}){return w(`/api/admin/repositories/history?${new URLSearchParams({repoId:e,ref:t,path:n,page:r,...i?{all:`true`}:{},...a?{fresh:`true`}:{},...o?{from:o.join(`,`)}:{}})}`,mt,e=>e.json(),s)}var gt={...mt,"no-directory":`This directory’s changes are not available to you.`,"github-malformed":`GitHub answered with a commit’s files that couldn’t be read.`,400:`Not a repository’s commits.`};function _t(e,t,n,{signal:r}={}){return w(`/api/admin/repositories/changes?${new URLSearchParams({repoId:e,path:t,shas:n.join(`,`)})}`,gt,e=>e.json(),r)}function vt(e,t,n,{signal:r}={}){return w(`/api/admin/repositories/tree?${new URLSearchParams({repoId:e,path:t,commit:n})}`,gt,e=>e.json(),r)}var D={...lt,"no-directory":`Issues and pull requests show only with access to the whole repository.`,"github-malformed":`GitHub answered with a list that couldn’t be read.`,"github-token-required":`Reading issues and pull requests needs your GitHub sign-in.`,"github-status-403":`GitHub refused to list these. The GitHub App reading this repository needs Issues: read and Pull requests: read, which an owner of its installation approves.`,400:`Not a repository’s issues or pull requests.`};function yt(e,t,{state:n=`open`,after:r=null,signal:i}={}){return w(`/api/admin/repositories/issues?${new URLSearchParams({repoId:e,kind:t,state:n,...r?{after:r}:{}})}`,D,e=>e.json(),i)}var bt={...D,"no-directory":`Agents show only with access to the whole repository.`,"github-token-required":`Reading what the agents did needs your GitHub sign-in.`,400:`Not a repository’s agents.`};function xt(e,{pulls:t=null,commits:n=null,signal:r}={}){return w(`/api/admin/repositories/agents?${new URLSearchParams({repoId:e,...t?{pulls:t}:{},...n?{commits:n}:{}})}`,bt,e=>e.json(),r)}var St={...D,"github-not-found":`GitHub has no issue or pull request of that number here.`,400:`Not an issue or pull request of a repository.`};function Ct(e,t,{signal:n}={}){return w(`/api/admin/repositories/item?${new URLSearchParams({repoId:e,number:t})}`,St,e=>e.json(),n)}var wt={...St,"github-not-found":`GitHub has no pull request of that number here.`,"github-malformed":`GitHub answered with a pull request or lockfile that couldn’t be read.`,"github-status-403":`GitHub refused to read its lockfiles. The GitHub App reading this repository needs Contents: read and Pull requests: read, which an owner of its installation approves.`,400:`Not a pull request of a repository.`};function Tt(e,t,{review:n=!1,signal:r}={}){return w(`/api/admin/repositories/pull-dependencies?${new URLSearchParams({repoId:e,number:t,...n?{review:`1`}:{}})}`,wt,e=>e.json(),r)}async function Et(e,t,{review:n=!1,signal:r}={}){let{pulls:i}=await w(`/api/admin/repositories/pull-dependencies?${new URLSearchParams({repoId:e,numbers:t.join(`,`),...n?{review:`1`}:{}})}`,wt,e=>e.json(),r);return new Map((Array.isArray(i)?i:[]).filter(e=>Number.isSafeInteger(e?.number)).map(e=>[e.number,typeof e.error==`string`?Object.assign(Error(wt[e.error]??`It couldn\u2019t be read (${e.error}).`),{code:e.error}):e]))}var Dt={...St,"github-not-found":`GitHub has none of a lockfile it lists on the default branch.`,"github-malformed":`GitHub answered with a lockfile that couldn’t be read.`,"github-status-403":`GitHub refused to read its lockfiles. The GitHub App reading this repository needs Contents: read, which an owner of its installation approves.`,400:`Not a repository.`};function Ot(e,{signal:t}={}){return w(`/api/admin/repositories/branch-dependencies?${new URLSearchParams({repoId:e})}`,Dt,e=>e.json(),t)}var kt={...D,"no-directory":`Pulse shows only with access to the whole repository.`,"github-malformed":`GitHub answered with statistics that couldn’t be read.`,"github-token-required":`Reading a repository’s pulse needs your GitHub sign-in.`,"github-status-403":`GitHub refused to read these. The GitHub App reading this repository needs Contents, Issues and Pull requests: read, which an owner of its installation approves.`,400:`Not a repository’s pulse.`};function At(e,t,{signal:n}={}){return w(`/api/admin/repositories/pulse?${new URLSearchParams({repoId:e,weeks:t})}`,kt,e=>e.json(),n)}function jt(e,t,{from:n,to:r=null,authors:i=[]},{signal:a}={}){return w(`/api/admin/repositories/pulse/items?${new URLSearchParams({repoId:e,weeks:t,from:n,...r===null?{}:{to:r},...i.length>0?{authors:i.join(`,`)}:{}})}`,kt,e=>e.json(),a)}function Mt(e,t,{signal:n}={}){return T(`package`,{name:e,version:t},n)}function Nt(e,{signal:t}={}){return T(`versions`,{name:e},t)}function Pt(e,{signal:t}={}){return T(`stats`,{name:e},t)}function Ft(e,{signal:t}={}){return T(`advisories`,{name:e},t)}function It(e,t,{signal:n}={}){return T(`tags`,{name:e,version:t},n)}function Lt(e,t,{signal:n}={}){return T(`socket`,{name:e,version:t},n)}function Rt(e,t,n=null,{signal:r}={}){return T(`risk`,{name:e,version:t,...n===null?{}:{otherVersion:n}},r)}function zt(e,t,{signal:n}={}){return T(`provenance`,{name:e,version:t},n)}var O={404:`This file is no longer available.`,409:`This file has changed since it was opened.`,413:`This file is too large to pretty-print.`,422:`This file couldn't be read as code.`,"pretty-mismatch":`Pretty-printing would change more than its layout, so it is shown as published.`,unsupported:`This kind of file can't be checked once pretty-printed, so it is shown as published.`,429:`Too many files are being pretty-printed. Try again shortly.`,502:`The npm registry couldn't be reached.`};function Bt(e,t,n,{signal:r}={}){return w(`/api/bundles/${encodeURIComponent(e)}/pretty?${new URLSearchParams({path:t,hash:n})}`,O,Ht,r)}function Vt(e,t,n,r,{signal:i}={}){return w(`/api/npm/pretty?${new URLSearchParams({name:e,version:t,path:n,hash:r})}`,{...C,...O},Ht,i)}var Ht=async e=>({text:await e.text(),source:e.headers.get(`x-source-hash`)});async function*Ut(e){let t=e.body.pipeThrough(new TextDecoderStream).getReader(),n=[];for(;;){let{done:e,value:r}=await t.read();if(e)return;let i=0;for(let e=r.indexOf(`
2
+ `);e!==-1;i=e+1,e=r.indexOf(`
3
+ `,i))n.push(r.slice(i,e)),yield JSON.parse(n.join(``)),n=[];n.push(r.slice(i))}}function Wt(e,t,n,{signal:r}={}){return k(`/api/npm/pretty?${new URLSearchParams({name:e,version:t})}`,C,n,r)}function Gt(e,t,n,{signal:r}={}){return k(`/api/bundles/${encodeURIComponent(e)}/pretty?${new URLSearchParams({other:t})}`,O,n,r)}function Kt(e,t,n,r,{signal:i}={}){return k(`/api/npm/pretty?${new URLSearchParams({name:e,version:t,otherVersion:n})}`,C,r,i)}function k(e,t,n,r,i=O){return w(e,t,async e=>{let t=f.generation;for await(let{error:r,status:a,...o}of Ut(e)){if(t!==f.generation)throw new DOMException(`Managed session changed`,`AbortError`);await n(r?{...o,status:a,message:i[r]??i[a]??`Request failed (${a})`}:o)}},r)}var qt={...O,413:`This file is too large to compare with renamed names hidden.`,422:`This file couldn't be compared as code.`,"diff-busy":`Too many files are being compared. Try again shortly.`,504:`Comparing this file took too long.`},Jt=(e,t)=>w(e,qt,e=>e.json(),t);function Yt(e,t,{path:n,hash:r,otherPath:i,otherHash:a},{signal:o}={}){return Jt(`/api/bundles/${encodeURIComponent(e)}/rename-diff?${new URLSearchParams({path:n,hash:r,other:t,otherPath:i,otherHash:a})}`,o)}function Xt(e,t,n,{path:r,hash:i,otherPath:a,otherHash:o},{signal:s}={}){return Jt(`/api/npm/rename-diff?${new URLSearchParams({name:e,version:t,path:r,hash:i,otherVersion:n,otherPath:a,otherHash:o})}`,s)}var Zt=(e,t)=>new URLSearchParams({other:e,...t?{scope:t}:{}});function Qt(e,t,n,{signal:r,scope:i=``}={}){return k(`/api/bundles/${encodeURIComponent(e)}/rename-diff?${Zt(t,i)}`,O,n,r,qt)}function $t(e,t,n,r,{signal:i}={}){return k(`/api/npm/rename-diff?${new URLSearchParams({name:e,version:t,otherVersion:n})}`,C,r,i,qt)}function en(e,t,n,{signal:r,scope:i=``}={}){return k(`/api/bundles/${encodeURIComponent(e)}/type-only?${Zt(t,i)}`,O,n,r)}function tn(e,t,n,r,{signal:i}={}){return k(`/api/npm/type-only?${new URLSearchParams({name:e,version:t,otherVersion:n})}`,C,r,i)}var nn={...C,"delta-busy":`Too many packages are being counted. Try again shortly.`,"delta-timeout":`Counting its lines took too long.`,"delta-failed":`Its lines couldn’t be counted.`};function rn(e,t,n,{signal:r}={}){return w(`/api/npm/delta?${new URLSearchParams({name:e,version:t,otherVersion:n})}`,nn,e=>e.json(),r)}var an={404:`This bundle is no longer available.`,422:`This bundle couldn't be read.`,429:`Too many bundles are being compared. Try again shortly.`},on=async e=>{let t=await e.json();return t.files.basePaths=new Map(t.files.basePaths),t};function sn(e,t,{signal:n,scope:r=``}={}){return w(`/api/bundles/${encodeURIComponent(e)}/comparison?${Zt(t,r)}`,an,on,n)}function cn(e,t,n,{signal:r,otherName:i=e}={}){return w(`/api/npm/comparison?${new URLSearchParams({name:e,version:t,otherVersion:n,...i===e?{}:{otherName:i}})}`,C,on,r)}async function A(e,t){let n=await d(e,{signal:t,credentials:`same-origin`,headers:{accept:`application/json`}});if(!n.ok)throw Error(`HTTP ${n.status}`);return n.json()}function j(e,t,n){let r={"content-type":`application/json`};return t&&(r[`x-csrf-token`]=t),d(e,{method:`POST`,credentials:`same-origin`,headers:r,body:JSON.stringify(n)})}async function M(e){let t=await e.json().then(e=>typeof e?.error==`string`?e.error:``,()=>``);return[`repo-forbidden`,`forbidden`].includes(t)?`choose a repository and directory within your team access`:`HTTP 403${t?`: ${t}`:``}`}async function ln(e,t,n){let r=n?{"x-csrf-token":n}:{},i=await d(`/api/admin/${e}/${encodeURIComponent(t)}`,{method:`DELETE`,credentials:`same-origin`,headers:r});if(!i.ok)throw Error(`HTTP ${i.status}`)}async function un(e,t,n,r,i,a){let o=new URLSearchParams({page:String(t),limit:`100`,kind:n,q:r.trim()});i&&o.set(`repo`,i),a&&o.set(`actor`,a);let s=await A(`/api/admin/history?${o}`,e);if(!Array.isArray(s?.history)||!Number.isSafeInteger(s.total)||s.total<0||!Number.isSafeInteger(s.page)||s.page<1)throw Error(`No history returned`);return s}async function dn(e){let t=await A(`/api/admin/users`,e);return Array.isArray(t?.users)?t.users:[]}async function fn(e,t,n){let r=await j(`/api/admin/set-role`,n,{userId:e,role:t});if(!r.ok)throw Error(`HTTP ${r.status}`)}async function pn(e,t,n,r){let i=new URLSearchParams({scope:e});return e===`installed`&&i.set(`showAll`,String(t)),n&&i.set(`refresh`,`true`),await A(`/api/admin/repositories?${i}`,r)}async function mn(e,t,n){let r=await j(`/api/admin/repositories/select`,n,{repoId:e,selected:t});if(!r.ok)throw Error(`HTTP ${r.status}`)}async function hn(e,{enabled:t,required:n,since:r,lockfiles:i},a){let o=await j(`/api/admin/repositories/dependency-review`,a,{repoId:e,enabled:t,required:n,since:r,...i?{lockfiles:i}:{}});if(!o.ok)throw Error(o.status===400?`Enter 1 to 10 required reviews, the commit as its full 40-character id, and at most 100 lockfiles by their paths in the repository.`:`HTTP ${o.status}`);return(await o.json()).dependencyReview}async function gn(e,t){let n=await A(`/api/admin/repositories/lockfiles?repoId=${encodeURIComponent(e)}`,t);return Array.isArray(n?.lockfiles)?n.lockfiles.flatMap(e=>typeof e?.path==`string`?[e.path]:[]):[]}async function _n(e,t){let n=await d(`/api/admin/repositories/add-public`,{method:`POST`,credentials:`same-origin`,headers:{"content-type":`application/json`,"x-csrf-token":t},body:JSON.stringify({repository:e})});if(!n.ok)throw Error({400:`Enter a repository as owner/repo or a GitHub repository URL.`,403:`You do not have permission to add arbitrary public repositories.`,404:`No public repository was found at that address.`,409:`Choose a public, non-archived repository.`}[n.status]??`GitHub lookup failed (HTTP ${n.status}). Try again.`)}async function vn(e,t){let n=await A(`/api/admin/repositories/impact?repoId=${encodeURIComponent(e)}`,t);if(n?.repoId!==e||!Array.isArray(n.reports)||!Array.isArray(n.bundles)||!Number.isSafeInteger(n.triageCount)||n.triageCount<0)throw Error(`Invalid repository data`);return n}async function yn(e,t){let n=await d(`/api/admin/repositories/connect-app`,{method:`POST`,credentials:`same-origin`,headers:{"content-type":`application/json`,"x-csrf-token":t},body:JSON.stringify({repoId:e})}),r=await n.json();if(!n.ok)throw Error({"github-app-not-configured":`The GitHub App is not configured on this server.`,"repo-identity-changed":`The repository has changed on GitHub. Refresh and check its connection.`,"repo-connection-changed":`The connection or your permissions changed. Refresh and try again.`,"repo-not-connected":`This repository is no longer connected.`,forbidden:`Administrator access is required to connect the GitHub App.`}[r.error]??`Could not connect the GitHub App (HTTP ${n.status}). Try again.`);if(r.connected===!0)return r;if(r.connected!==!1||typeof r.installUrl!=`string`||!/^https:\/\/github\.com\/apps\/[^/?#]+\/installations\/new$/u.test(r.installUrl))throw Error(`Invalid GitHub installation response.`);return r}async function bn(e,t,n,r){let i=await j(`/api/admin/repositories/remove`,r,{repoId:e,fullName:t,acknowledge:!0,deleteTriage:n});if(!i.ok)throw Error(`HTTP ${i.status}`);return i.json()}async function xn(e){return await A(`/api/admin/reports`,e)}async function Sn(e,t,n){let r=await d(`/api/admin/bundles/create`,{method:`POST`,credentials:`same-origin`,signal:n,headers:{"content-type":`application/json`,"x-csrf-token":t},body:JSON.stringify(e)}),i=await r.json();if(!r.ok)throw Error({"unsupported-entries":`Select JavaScript/TypeScript files (including JSX/TSX) or Solidity files. Stasis cannot mix languages or use JSON or Rust as remote entry points.`,"bad-conditions":`Check the export conditions and selected platforms.`,"metro-conditions":`Stasis’s Metro preset requires the react-native condition without manual changes.`,"build-lockfile":`Stasis needs a supported lockfile: pnpm-lock.yaml, yarn.lock (Yarn 1), package-lock.json, or soldeer.lock.`,"build-scope":`Your team needs access to the bundle’s project root, including its lockfile and dependencies.`,"build-busy":`A bundle is already being built, or the server is busy. Try again shortly.`,"build-timeout":`The bundle build timed out. Try a smaller selection or retry.`,"too-large":`This bundle exceeds the server’s size limit.`,"github-rate-limited":`GitHub’s API rate limit has been reached. Retry after the limit resets.`,"github-build-failed":`Could not fetch the repository from GitHub. Check access and retry.`,"repository-changed":`The repository connection changed during the build. Reload and try again.`,"bundle-conflict":`This bundle already exists but is outside your current access.`,"build-failed":`Stasis could not build this selection. Check that its lockfile is supported and all entry points and imports exist at this commit.`}[i.error]??(r.status===401?`Sign in again to create a bundle.`:r.status===403||r.status===404?`Repository access is required to create this bundle.`:`Could not create the bundle. Try again.`));return i}async function Cn(e,t,n=null,r=``){let i=(await A(`/api/config`)).managed?.uploadMaxBytes?.reports;if(Number.isSafeInteger(i)&&i>0){if(e.size>i)throw Error(`too large`)}else if(e.size>3145728)return wn(e,t,n,r);let a=Ae(await e.text(),e.name);if(!a)return wn(e,t,n,r);let o=[],s=[];for(let{name:e,content:i}of a)try{s.push(await wn(new File([i],e,{type:`application/json`}),t,n,r))}catch(t){o.push(`${e}: ${String(t?.message??t)}`)}if(o.length>0)throw Error(`${o.length} of ${a.length} products failed (${o.join(`; `)})`);return s.at(-1)}async function wn(e,t,n,r){let i={"content-type":e.type||`application/json`,"x-report-filename":encodeURIComponent(e.name)};t&&(i[`x-csrf-token`]=t),n!=null&&(i[`x-repo-id`]=String(n)),r!==``&&(i[`x-repo-directory`]=encodeURIComponent(r));let a=await d(`/api/admin/reports`,{method:`POST`,credentials:`same-origin`,headers:i,body:e});if(!a.ok){if(a.status===413)throw Error(`too large`);if(a.status===403)throw Error(await M(a));let e=await a.json().catch(()=>null);if(e?.error===`storage-encryption-required`)throw Error(`Link reports require managed storage encryption. Configure MANAGED_STORAGE_ENCRYPTION_KEY.`);if(e?.error===`invalid-report`)throw Error(typeof e.reason==`string`&&e.reason?`This file is not a report: ${e.reason}`:`This file is not a recognized report.`);let t=e?.error===`repo-not-connected`&&typeof e.repo==`string`?`: ${e.repo} is not connected`:``;throw Error(`HTTP ${a.status}${t}`)}return a.json()}async function Tn(e,t,n){let r=await j(`/api/admin/reports/set-visible`,n,{reportId:e,visible:t});if(!r.ok)throw Error(`HTTP ${r.status}`)}async function En(e,t,n,r){let i=await j(`/api/admin/reports/set-repo`,r,{reportId:e,repoId:t,directory:n});if(!i.ok)throw i.status===409?Error(`this report already defines its repository`):i.status===403?Error(await M(i)):Error(i.status===400?`invalid repository or directory`:`HTTP ${i.status}`);return i.json()}async function Dn(e,t){let n=await d(`/api/admin/reports/${encodeURIComponent(e)}/location`,{signal:t,credentials:`same-origin`});if(!n.ok)throw Error(`Report location suggestion request failed (${n.status})`);return(await n.json())?.location??null}async function On(e,t){await ln(`reports`,e,t)}async function kn(e){return await A(`/api/admin/bundles`,e)}async function An(e,t,n,r=``){let i={"content-type":`application/octet-stream`,"x-bundle-filename":encodeURIComponent(e.name)};t&&(i[`x-csrf-token`]=t),n!=null&&(i[`x-repo-id`]=String(n)),r&&(i[`x-repo-directory`]=encodeURIComponent(r));let a=await d(`/api/admin/bundles`,{method:`POST`,credentials:`same-origin`,headers:i,body:e});if(!a.ok)throw Error(a.status===413?`too large`:a.status===403?await M(a):`HTTP ${a.status}`);return a.json()}async function jn(e,t){await ln(`bundles`,e,t)}async function Mn(e,t,n){let r=await j(`/api/admin/bundles/set-visible`,n,{bundleId:e,visible:t});if(!r.ok)throw Error(`HTTP ${r.status}`)}async function Nn(e,t,n,r){let i=await j(`/api/admin/bundles/set-repo`,r,{bundleId:e,repoId:t,directory:n});if(!i.ok)throw Error(i.status===403?await M(i):i.status===400?`invalid repository or directory`:`HTTP ${i.status}`)}async function Pn(e){return await A(`/api/admin/teams`,e)}async function N(e,t,n){let r=await j(e,t,n);if(!r.ok)throw Error(r.status===409?`name already taken`:`HTTP ${r.status}`)}function Fn(e,t=!0){let n=document.createElement(`input`);n.type=`file`,n.multiple=t,n.addEventListener(`change`,()=>{e([...n.files])},{once:!0}),n.click()}function In(e,t,n){let r=0,i=e=>Array.from(e.dataTransfer?.types??[]).includes(`Files`),a=e=>{i(e)&&(e.preventDefault(),r+=1,n(!0))},o=e=>{i(e)&&e.preventDefault()},s=e=>{i(e)&&(r=Math.max(0,r-1),r===0&&n(!1))},c=e=>{i(e)&&(e.preventDefault(),e.stopPropagation(),r=0,n(!1),t([...e.dataTransfer.files]))};return e.addEventListener(`dragenter`,a),e.addEventListener(`dragover`,o),e.addEventListener(`dragleave`,s),e.addEventListener(`drop`,c),()=>{e.removeEventListener(`dragenter`,a),e.removeEventListener(`dragover`,o),e.removeEventListener(`dragleave`,s),e.removeEventListener(`drop`,c)}}async function Ln(e,t,n,r){let i=e.appState.generation;try{return await e.appState.mutate(()=>n(t),r)}catch(t){throw i===e.appState.generation&&e.appState.invalidate(r),t}}async function Rn(e,t,n,r){if(e._busy||!e._csrf)throw Error(`Wait for the current operation to finish, then try again.`);e._busy=!0;try{await Ln(e,t,n,r)}finally{await e._load(),e._busy=!1;let t=e._queue.splice(0);t.length>0&&e._upload(t)}}async function zn(e,t,n,r){if(t.length===0||(e._queue.push(...t),e._busy))return;e._busy=!0,e._error=null;let i=e.appState.generation,a=[],o=0;try{for(;e._queue.length>0;){if(e.appState.generation!==i){e._queue=[];break}let t=e._queue.shift();try{await Ln(e,t,n,r)}catch(n){if(n?.name===`AbortError`||e.appState.generation!==i){e._queue=[];break}a.push(`${t.name}: ${String(n?.message??n)}`)}o++}}finally{a.length>0&&(e._error=o===1?`Upload failed: ${a[0]}`:`Upload failed for ${a.length} of ${o} files: ${a.join(`; `)}`),e._busy=!1,await e._load({preserveError:!0})}}var Bn=`.local-import-toggle{flex-shrink:0;margin-block:calc(-.25rem - 1px);margin-left:auto;padding:.25rem .6rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:transparent;color:var(--muted);font:inherit;font-size:.75rem;line-height:1.5}.local-import-toggle:hover,.local-import-toggle[aria-expanded=true]{color:var(--text);background:rgb(from var(--text) r g b / .06)}.local-import-panel{display:grid;gap:.8rem;padding:1rem;margin-bottom:1.25rem;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:rgb(from var(--accent) r g b / .025)}.local-import-copy strong{font-size:.82rem;font-weight:600}.local-import-copy p,.local-import-message{margin:.3rem 0 0;color:var(--muted);font-size:.75rem;line-height:1.5}.local-import-controls{display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}managed-local-item-selector{flex:1 1 16rem;min-width:0}.local-import-controls button,.local-import-message button{padding:.35rem .7rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:transparent;color:var(--text);font:inherit;font-size:.75rem;line-height:1.5}.local-import-controls .local-import-submit{border-color:rgb(from var(--accent) r g b / .4);background:rgb(from var(--accent) r g b / .1);color:var(--accent)}.local-import-controls .local-import-close{color:var(--muted)}.local-import-panel button:disabled,.local-import-toggle:disabled{opacity:.5}.local-import-panel button:focus-visible,.local-import-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.local-import-message.error{color:var(--critical)}
4
+ `,Vn=`.home-section{margin-top:1.1rem;margin-bottom:2rem}.section-heading{display:flex;align-items:baseline;gap:1rem;margin-bottom:.85rem}.section-heading h2{margin:0;font-size:.86rem;font-weight:600}.section-heading>span{color:var(--muted);font-size:.75rem}.pages{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.9rem}.page{display:flex;flex-direction:column;gap:.85rem;padding:1.35rem;border:1px solid var(--border);border-radius:var(--ui-radius, 12px);color:var(--text);background:var(--panel);text-align:left;font:inherit}.page:hover{background:var(--panel-hover);border-color:color-mix(in srgb,var(--muted) 60%,var(--border))}.page-top{display:flex;align-items:center;gap:.75rem;width:100%}.page-icon{display:grid;place-items:center;flex-shrink:0;width:2.5rem;height:2.5rem;border:1px solid color-mix(in srgb,var(--accent) 16%,var(--border));border-radius:var(--ui-radius, 9px);background:color-mix(in srgb,var(--accent) 7%,var(--panel));color:var(--accent)}.page-bundle .page-icon{color:var(--green);border-color:color-mix(in srgb,var(--green) 18%,var(--border));background:color-mix(in srgb,var(--green) 6%,var(--panel))}.page-scan .page-icon{color:var(--scan-icon-color, var(--yellow));border-color:color-mix(in srgb,var(--scan-icon-color, var(--yellow)) 18%,var(--border));background:color-mix(in srgb,var(--scan-icon-color, var(--yellow)) 6%,var(--panel))}:host-context(body.theme-light) .page-scan .page-icon{--scan-icon-color: #bf8700}:host-context(body.theme-green) :is(.page-bundle,.page-scan) .page-icon,:host-context(body.theme-pink) :is(.page-bundle,.page-scan) .page-icon{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 16%,var(--border));background:color-mix(in srgb,var(--accent) 7%,var(--panel))}.page-icon svg{width:1.2rem;height:1.2rem}.arrow{display:flex;margin-left:auto;flex-shrink:0;color:var(--muted)}.arrow svg{width:1rem;height:1rem}.page:hover .arrow{color:var(--text)}.page-copy{display:grid;gap:.45rem}.page>.page-copy{margin-inline-start:3.25rem}.page-copy strong,.page-title{font-size:1rem;font-weight:600;letter-spacing:-.015em}.page-copy>span{color:var(--muted);font-size:.8rem;line-height:1.65}.workspace-pages .page{gap:.85rem;padding:1.2rem 1.35rem}.workspace-pages .page-icon{width:2rem;height:2rem;color:var(--muted);background:transparent;border-color:var(--border)}.workspace-pages .page-title{font-size:.9rem}.workspace-pages .page-copy{margin-inline-start:2.75rem}.history-link{display:flex;align-items:center;gap:1rem;width:100%;padding:1.25rem 0;border:0;border-top:1px solid var(--border);text-align:left;color:var(--text);background:transparent}.history-link>.page-icon{color:var(--muted);background:transparent;border-color:var(--border)}.history-link .page-copy strong{font-size:.85rem}.history-cta{display:flex;align-items:center;gap:.6rem;flex-shrink:0;margin-left:auto;color:var(--muted);font-size:.78rem}.history-cta svg{width:1rem;height:1rem}.history-link:hover .history-cta{color:var(--accent)}@container (max-width: 48rem){.pages{grid-template-columns:1fr;gap:.65rem}.page,.workspace-pages .page{gap:.65rem;padding:1.15rem}.page-top .arrow{display:none}.workspace-pages .page-icon{width:2.5rem;height:2.5rem}.workspace-pages .page-copy{margin-inline-start:3.25rem}.page-copy{gap:.2rem}.page-copy strong,.page-title{font-size:.95rem}.section-heading>span{display:none}.history-cta{font-size:0}}
5
+ `,Hn=`.toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.65rem;margin-bottom:.9rem}.toolbar input{flex:2 1 12rem}.toolbar select{flex:0 1 9rem}.toolbar repository-selector{flex:1 1 12rem}.toolbar user-selector{flex:1.5 1 16rem}.toolbar>*{min-width:0}.toolbar input[type=search],.toolbar select,.toolbar .btn{min-height:2rem;padding:.28rem .5rem;border-radius:var(--ui-radius, 5px)}.history{overflow-x:auto;border:1px solid var(--border);border-radius:var(--ui-radius, 9px);background:var(--panel)}.row,.history-head{display:grid;grid-template-columns:4.7rem minmax(16rem,1fr) minmax(12rem,1fr) 12rem;align-items:center;gap:.85rem;min-width:52rem;padding:.45rem .85rem}.history-head{background:rgb(from var(--text) r g b / .025);color:var(--muted);font-size:.7rem}.row{border-top:1px solid var(--border);min-height:2.35rem}.row:hover{background:var(--panel-hover)}.kind{display:inline-flex;align-items:center;justify-content:center;width:fit-content;padding:.05rem .35rem;border:1px solid var(--border);border-radius:4px;color:var(--muted);font-size:.65rem;text-transform:capitalize}.kind.triage{color:var(--accent);border-color:rgb(from var(--accent) r g b / .25);background:rgb(from var(--accent) r g b / .06)}.kind.upload{color:var(--green);border-color:rgb(from var(--green) r g b / .25);background:rgb(from var(--green) r g b / .06)}.kind.visibility{color:var(--yellow);border-color:rgb(from var(--yellow) r g b / .25);background:rgb(from var(--yellow) r g b / .06)}.activity-description,.detail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.75rem}.actor{color:var(--text);font-weight:500}.action,.detail{color:var(--muted)}.history-time{display:flex;align-items:center;gap:.35rem;color:var(--muted);font-size:.7rem;white-space:nowrap;font-variant-numeric:tabular-nums}.history .empty{border:0;margin:0}.pagination{display:flex;align-items:center;flex-wrap:wrap;gap:.65rem;margin-top:1rem;color:var(--muted);font-size:.75rem}.pagination>span:first-child{margin-right:auto}
6
+ `,Un=`.icon-btn{display:inline-grid;place-items:center;flex:0 0 auto;width:1.8rem;height:1.8rem;padding:0;border:1px solid transparent;border-radius:var(--ui-radius, 5px);color:var(--muted);background:transparent}.icon-btn:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.icon-btn.danger:hover:not(:disabled){color:var(--critical, #e5534b);background:rgb(from var(--critical, #e5534b) r g b / .1)}.icon-btn svg,.btn svg{width:.9rem;height:.9rem}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.avatar img.broken{display:none}.list-head{color:var(--muted);font-size:.7rem;font-weight:500;min-height:2.25rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025)}.users{list-style:none;margin:0;padding:0}.users li+li{border-top:1px solid var(--border)}.who{display:grid;gap:.15rem;min-width:0}.name-text,.login{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.login{color:var(--muted);font-size:.75rem}.last-seen time,.last-activity time{color:var(--text)}.activity-link{display:block;min-width:0;padding:.15rem .2rem;border:0;border-radius:var(--ui-radius, 4px);color:inherit;background:transparent;text-align:left}.activity-link:hover{color:var(--accent);background:rgb(from var(--accent) r g b / .08)}.you{padding:.05rem .35rem;border-radius:4px;color:var(--accent);background:rgb(from var(--accent) r g b / .1);font-size:.75rem;font-weight:500}.permission-granted{color:var(--accent)}.permission-denied{color:var(--muted)}.no-team{color:var(--muted);font-size:.75rem}.access{display:flex;align-items:center;min-width:0}.role{width:100%;height:auto;font-size:.78rem}.self-note{display:flex;align-items:center;gap:.5rem;margin:1rem 0;color:var(--muted);font-size:.75rem}.users li:hover{background:var(--panel-hover)}.avatar{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;width:1.85rem;height:1.85rem;border-radius:50%;overflow:hidden;font-size:.85rem;font-weight:600}.directory{border:1px solid var(--border);border-radius:var(--ui-radius, 11px);overflow:hidden;background:var(--panel);overflow-x:auto}.list-head,.users{min-width:53rem}.list-head,.users li{display:grid;grid-template-columns:minmax(11rem,1fr) minmax(16rem,1.2fr) 6.2rem 6.2rem 6.5rem 2rem;gap:.7rem;padding:.5rem .85rem;align-items:center}.users li{padding-top:.6rem;padding-bottom:.6rem;cursor:default}.person{display:flex;align-items:center;gap:.65rem;min-width:0}.name{display:flex;align-items:center;gap:.4rem;font-size:.8rem;font-weight:500}.last-seen,.last-activity{display:grid;gap:.08rem;color:var(--muted);font-size:.68rem;font-variant-numeric:tabular-nums}.memberships{display:grid;gap:.1rem;min-width:0}.team-access{display:flex;gap:.2rem .5rem;min-width:0;font-size:.7rem;line-height:1.4;align-items:center;flex-wrap:nowrap}.team-access strong{display:inline-flex;align-items:center;gap:.25rem;color:var(--text);font-weight:500;min-width:0;max-width:8rem}.team-access strong.team-access-role{flex-shrink:0;max-width:none;white-space:nowrap}.team-access strong svg{width:.8rem;height:.8rem;flex-shrink:0;color:var(--muted)}.team-access strong span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.team-perms{display:inline-flex;flex-wrap:nowrap;gap:.45rem;font-size:inherit;flex-shrink:0}.view-as{display:flex;justify-content:flex-end}
7
+ `,Wn=`.icon-btn{display:inline-grid;place-items:center;flex:0 0 auto;width:1.8rem;height:1.8rem;padding:0;border:1px solid transparent;border-radius:var(--ui-radius, 5px);color:var(--muted);background:transparent}.icon-btn:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.icon-btn.danger:hover:not(:disabled){color:var(--critical, #e5534b);background:rgb(from var(--critical, #e5534b) r g b / .1)}.icon-btn svg,.btn svg{width:.9rem;height:.9rem}.avatar{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;width:2rem;height:2rem;border-radius:50%;overflow:hidden;background:var(--surface-active);color:var(--muted);font-family:system-ui,-apple-system,BlinkMacSystemFont,sans-serif;font-size:.8rem;font-weight:600;user-select:none}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.avatar img.broken{display:none}.toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.65rem;margin:1.5rem 0 1.65rem}.repository-pages{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.repository-pages .btn{min-height:1.75rem;padding:.2rem .55rem}.repository-actions{display:flex;flex-wrap:wrap;align-items:center;gap:.65rem;margin-left:auto;margin-block:calc(-.45rem - 1px)}.breadcrumb{flex-wrap:wrap}.breadcrumb .breadcrumb-current{margin:0;color:var(--text);font-size:.85rem;font-weight:500}.public-repository-form{padding:1rem;margin:-1rem 0 1.5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:var(--panel)}.public-repository-form .confirm-field{margin:0}.search{flex:1 1 14rem;max-width:25rem;margin-right:auto}.search input{width:100%}.show-all,.show-all-paper{align-items:center;gap:.5rem;white-space:nowrap;font-size:.78rem}.show-all{display:var(--switch-button-display, inline-flex)}.show-all-paper{display:var(--switch-checkbox-display, none);& input{width:.85rem;height:.85rem;margin:0;accent-color:var(--accent)}}.show-all input{appearance:none;width:2rem;height:1.15rem;margin:0;padding:2px;border:1px solid var(--border);border-radius:var(--ui-radius, 1rem);background:var(--surface-active)}.show-all input:before{content:"";display:block;width:.775rem;height:.775rem;border-radius:50%;background:var(--muted)}.show-all input:checked{border-color:var(--accent);background:var(--accent)}.show-all input:checked:before{transform:translate(.85rem);background:var(--bg)}.show-all input:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.repository-count{margin:-.8rem 0 .6rem;color:var(--muted);font-size:.75rem;font-variant-numeric:tabular-nums}.repository-browser{display:flex;overflow:hidden;border:1px solid var(--border);border-radius:var(--ui-radius, 8px);background:var(--panel)}.organization-list{flex:0 0 12rem;padding:.4rem;border-right:1px solid var(--border);background:rgb(from var(--bg) r g b / .25)}.organization{display:flex;align-items:center;gap:.5rem;width:100%;padding:.5rem;border:0;border-radius:var(--ui-radius, 4px);color:var(--text);background:transparent;text-align:left;font-size:.76rem;cursor:default}.organization:hover{background:rgb(from var(--text) r g b / .05)}.organization[aria-pressed=true]{color:var(--accent);background:rgb(from var(--accent) r g b / .1)}.organization-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.organization-count{color:var(--muted);font-size:.7rem;font-variant-numeric:tabular-nums}.repo-results{flex:1;min-width:0}.organization-list,.repo-results{max-height:min(65vh,40rem);overflow:auto;overscroll-behavior:contain}.repo-group+.repo-group{border-top:1px solid var(--border)}.owner-head{position:sticky;top:0;z-index:1;display:flex;align-items:center;gap:.6rem;margin:0;padding:.55rem .85rem;color:var(--muted);background:var(--panel);font-size:.8rem;font-weight:500}.owner-icon{display:grid;place-items:center;width:1.6rem;height:1.6rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--surface);text-transform:uppercase;font-size:.75rem}.repos{margin:0;padding:0;list-style:none}.repos li+li{border-top:1px solid var(--border)}button.repo-row{border:0;background:transparent;color:var(--text);cursor:default}button.repo-row:hover{background:var(--surface-active)}button.repo-row:focus-visible{outline-offset:-2px}.repo-item{position:relative}.repo-code-slot{flex:none;width:1.75rem}.repo-code{position:absolute;top:50%;right:2.6rem;translate:0 -50%;display:grid;place-items:center;width:1.75rem;height:1.75rem;border-radius:var(--ui-radius, 5px);color:var(--muted)}.repo-code svg{width:1rem;height:1rem}.repo-code:hover{color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent)}.repo-code:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}.btn.connect-app{min-height:1.9rem;padding:.3rem .6rem;font-size:.72rem}.repo-icon{width:1.15rem;height:1.15rem;flex-shrink:0;color:var(--muted)}.repo-meta:before{content:none}.arrow{width:1rem;height:1rem;flex:0 0 auto;color:var(--muted)}.connected{display:inline-flex;align-items:center;gap:.25rem;flex:0 0 auto;color:var(--muted);font-size:.75rem;white-space:nowrap}.connected svg{width:.85rem;height:.85rem}.access-note{display:flex;align-items:center;gap:.85rem;padding:.85rem 1rem;background:var(--surface);border:1px solid var(--border);border-radius:var(--ui-radius, 8px)}.access-note p{flex:1;margin:0;color:var(--muted);font-size:.78rem;line-height:1.5}a.btn{color:var(--text);text-decoration:none;cursor:default}.empty{padding:2.5rem 1rem;text-align:center}.empty strong{display:block;margin-bottom:.4rem;font-size:.9rem;font-weight:500}.empty p{margin:0;color:var(--muted);font-size:.8rem}.loading{min-height:8rem;display:grid;place-items:center;color:var(--muted);font-size:.8rem}.repository-detail{padding-bottom:1.5rem;>:first-child{margin-top:0}}.section{margin-top:1.75rem;border:1px solid var(--border);border-radius:var(--ui-radius, 10px);overflow:hidden;background:var(--panel)}.section h2{margin:0;padding:1rem 1.25rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025);font-size:.85rem;font-weight:600}.section-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:.6rem 1.25rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025);&:last-child{border-bottom:0}& h2{padding:0;border:0;background:none}}.settings-row{display:flex;align-items:center;gap:1rem;padding:1.25rem}.settings-copy{flex:1;min-width:0}.settings-copy strong{font-size:.83rem;font-weight:500}.settings-copy p{margin:.25rem 0 0;color:var(--muted);font-size:.76rem;line-height:1.5}.settings-row+.settings-row{border-top:1px solid var(--border)}.dependency-review-settings{flex-wrap:wrap;align-items:end}.dependency-review-settings label{display:flex;flex-direction:column;gap:.3rem;color:var(--muted);font-size:.76rem}.dependency-review-settings input{padding:.35rem .5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--surface);color:var(--text);font:inherit;font-size:.83rem}.dependency-review-settings input[type=number]{width:5rem}.dependency-review-since{flex:1;min-width:min(100%,22rem)}.dependency-review-since input{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.dependency-review-lockfiles{display:flex;flex-basis:100%;flex-wrap:wrap;align-items:end;gap:.5rem 1rem;min-width:0;margin:0;padding:0;border:0;& legend{margin-bottom:.3rem;padding:0;color:var(--muted);font-size:.76rem}& select{padding:.35rem .5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--surface);color:var(--text);font:inherit;font-size:.83rem}}.dependency-review-lockfile-list{display:flex;flex-basis:100%;flex-direction:column;gap:.25rem;max-height:16rem;margin:0;padding:.5rem .75rem;overflow:auto;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);list-style:none;& label{flex-direction:row;align-items:baseline;gap:.5rem;color:var(--text)}& code{font-size:.78rem;overflow-wrap:anywhere}& span{color:var(--muted);font-size:.72rem}}.dependency-review-lockfile-add{flex:1;min-width:min(100%,18rem)}.dependency-review-lockfile-add input{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.dependency-review-hint{flex-basis:100%;margin:0;color:var(--muted);font-size:.76rem;&.is-warning{color:var(--warning)}}.btn.danger,.error{color:var(--critical, #e5534b)}.status-line{display:inline-flex;align-items:center;gap:.35rem;color:var(--muted);font-size:.75rem}.status-line.inactive{color:var(--warning, #d19a24)}.data-section{margin-top:1.5rem}.data-section h2{margin:0 0 .5rem;font-size:.85rem;font-weight:500}.data-empty{margin:0;color:var(--muted);font-size:.75rem}.dialog-backdrop{position:fixed;inset:0;z-index:20;display:grid;place-items:center;padding:1rem;background:#000000a6}.dialog{width:min(40rem,100%);max-height:calc(100vh - 3rem);overflow:auto;padding:1.5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 12px);background:var(--bg);box-shadow:0 1rem 3rem #00000059}.dialog.small{width:min(28rem,100%)}.dialog h2{margin:0;font-size:1.05rem;font-weight:600;overflow-wrap:anywhere}.dialog-copy{margin:.55rem 0 1rem;color:var(--muted);font-size:.78rem;line-height:1.5}.dialog-data{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.75rem;margin:0 0 1rem}.dialog-data section{min-width:0;padding:.65rem;border:1px solid var(--border);border-radius:var(--ui-radius, 7px)}.dialog-data h3{margin:0 0 .4rem;font-size:.75rem;font-weight:600}.dialog-data ul{max-height:9rem;overflow:auto;margin:0;padding-left:1rem;color:var(--muted);font-size:.75rem}.dialog-data li{margin:.2rem 0;overflow-wrap:anywhere}.confirm-line{display:flex;align-items:flex-start;gap:.5rem;margin:.7rem 0;color:var(--text);font-size:.76rem;line-height:1.4}.confirm-line input{flex:0 0 auto;margin-top:.15rem;accent-color:var(--accent)}.confirm-line span{min-width:0}.confirm-field{display:grid;gap:.5rem;margin-top:1.1rem;color:var(--text);font-size:.78rem;line-height:1.5;overflow-wrap:anywhere}.confirm-name{width:100%;min-width:0;padding:.45rem .55rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg);color:var(--text);font:inherit;font-size:.78rem}.dialog-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.5rem;margin-top:1rem}.dialog-actions .danger{color:var(--critical, #e5534b);border-color:rgb(from var(--critical, #e5534b) r g b / .4)}@container (max-width: 35rem){.organization-list{flex-basis:9rem}.intro{margin-left:0}.search{flex-basis:100%;max-width:none}.access-note,.settings-row{flex-wrap:wrap}.access-note p,.settings-copy{flex-basis:100%}.head h1{font-size:1.35rem}.repo-copy{gap:.35rem}.repo-meta{max-width:100%}.dialog-data{grid-template-columns:1fr}}.repo-name{min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.83rem;font-weight:500}.repo-row{display:flex;align-items:center;gap:.75rem;width:100%;min-height:2.8rem;padding:.55rem .85rem;text-align:left}.repo-copy{display:flex;flex-direction:row;align-items:center;gap:.85rem;flex:1;min-width:0}.repo-meta{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:.72rem;margin-left:auto}@container (max-width: 35rem){.repo-copy{flex-direction:column;align-items:flex-start;gap:.1rem}.repo-meta{margin-left:0}}.data-section .dialog-data section{height:12rem;display:flex;flex-direction:column;align-items:flex-start}.data-section .dialog-data ul{width:100%;min-height:0;max-height:none}.access-action{flex-shrink:0}@container (max-width: 28rem){.repository-browser{flex-direction:column}.organization-list{display:flex;flex:0 0 auto;gap:.25rem;border-right:0;border-bottom:1px solid var(--border)}.organization{flex:0 0 auto;width:auto;max-width:12rem}}
8
+ `,Gn=`.report-logo.brand-deepview{--brand-bg:#2563eb;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-claude{--brand-bg:#d97757;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-codex{--brand-bg:#fff;--brand-fg:#000;background:var(--brand-bg)}.report-logo.brand-vercel{--brand-bg:#000;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-markdown{--brand-bg:#374151;--brand-fg:#fff;background:var(--brand-bg)}.report-logo.brand-piolium{--brand-bg:#fbb829;--brand-fg:#1c1b19;background:var(--brand-bg)}.report-logo .fg{fill:var(--brand-fg)}.report-logo .bg{fill:var(--brand-bg)}.report-logo.brand-codex .bg,.report-logo.brand-vercel .bg{stroke:var(--brand-fg);stroke-width:.5}.dropzone{position:absolute;inset:.6rem;z-index:5;display:grid;place-items:center;border:2px dashed var(--accent);border-radius:var(--ui-radius, 10px);background:rgb(from var(--bg) r g b / .94);color:var(--accent);font-weight:600;pointer-events:none}.report-list{overflow-x:auto;border:1px solid var(--border);border-radius:var(--ui-radius, 9px);background:var(--panel)}.reports{min-width:61rem;margin:0;padding:0;list-style:none}.report-list-head,.report-main{display:grid;grid-template-columns:1.5rem minmax(12rem,1fr) minmax(8rem,.6fr) 8rem 6.5rem 4.5rem 4.1rem 9rem;align-items:center;gap:.7rem;padding:.35rem .85rem}.report-list-head{min-width:61rem;min-height:2.25rem;color:var(--muted);background:rgb(from var(--text) r g b / .025);border-bottom:1px solid var(--border);font-size:.7rem}.report-heading{grid-column:1 / 3}.actions-heading{text-align:right;padding-right:.25rem}.report+.report{border-top:1px solid var(--border)}.report-main{cursor:default}.report-main:hover{background:var(--panel-hover)}.report-logo{display:grid;place-items:center;width:1.5rem;height:1.5rem;border-radius:5px;overflow:hidden}.report-logo svg{width:1.1rem;height:1.1rem}.report-name{color:var(--text);font-size:.8rem;font-weight:500}.report-name,.report-location,.report-meta{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.report-location{color:var(--muted);font-size:.7rem}.report-meta{color:var(--muted);font-size:.68rem;font-variant-numeric:tabular-nums}.report-uploader{color:var(--text);opacity:.8;font-size:.72rem}.report-size,.size-heading{padding-right:.65rem;text-align:right}.report-actions{display:flex;justify-content:flex-end;align-items:center;gap:.1rem}.report-actions .action,.action-spacer{display:grid;place-items:center;flex-shrink:0;width:1.7rem;height:1.8rem;padding:.3rem;border:1px solid transparent;border-radius:var(--ui-radius, 5px);background:transparent;color:var(--muted)}.action svg{width:.95rem;height:.95rem}.report-actions .action:hover:not(:disabled),.report-actions .action[aria-expanded=true]{color:var(--text);background:var(--surface-active);border-color:var(--border)}.report-actions .action.danger:hover{color:var(--critical);background:rgb(from var(--critical) r g b / .08)}.preview{height:20rem;border-top:1px solid var(--border);padding:.85rem}.preview pre{height:100%;overflow:auto;margin:0;padding:.85rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--bg);color:var(--text);font:.75rem/1.6 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.preview-loading{color:var(--muted);font-size:.8rem}
9
+ `,Kn=`button,select{font:inherit;cursor:default}button:focus-visible,a:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.dropzone{position:absolute;inset:.6rem;z-index:5;display:grid;place-items:center;border:2px dashed var(--accent);border-radius:var(--ui-radius, 10px);background:rgb(from var(--bg) r g b / .94);color:var(--accent);font-size:1rem;font-weight:600;pointer-events:none}.summary{min-height:1.5em;display:flex;flex-wrap:wrap;align-items:center;gap:.75rem;color:var(--muted);font-size:.75rem;font-variant-numeric:tabular-nums}.unassigned{color:var(--high, #d97732)}.bundles{margin:0;padding:0;list-style:none}.bundle-group-head strong{min-width:0;overflow-wrap:anywhere;font-size:.8rem;font-weight:500}.bundle-group-head span{color:var(--muted);font-size:.75rem}.bundle-row+.bundle-row{border-top:1px solid var(--border)}.bundle-icon svg,.bundle-icon img{width:1rem;height:1rem}.action{display:grid;place-items:center;width:2rem;height:2rem;padding:.45rem;border:1px solid transparent;border-radius:var(--ui-radius, 6px);background:transparent;color:var(--muted);text-decoration:none}.action svg{width:1rem;height:1rem}.action:hover{color:var(--text);border-color:var(--border);background:var(--surface)}.action.danger:hover{color:var(--critical, #e5534b)}.msg{padding:1rem 0;margin:0;color:var(--muted);font-size:.8rem}.msg.error{color:var(--critical, #e5534b)}.bundle-group{overflow:hidden;border:1px solid var(--border);border-radius:var(--ui-radius, 10px);background:var(--panel);overflow-x:auto}.bundle-group-head,.bundles{min-width:58rem}.bundle-row{display:grid;grid-template-columns:minmax(12rem,1fr) 8rem 6.5rem 4.5rem minmax(8rem,12rem) 4rem 8.6rem;align-items:center;gap:.85rem;padding:.25rem .5rem;cursor:default}.bundle-location{display:block;min-width:0;grid-column:auto;padding-left:0;color:var(--muted);font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.actions{display:flex;justify-content:flex-end;gap:.2rem;grid-column:auto;grid-row:auto}.bundle-group-head{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.5rem .85rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025)}.bundle-groups{display:grid;gap:.85rem}.identity{display:flex;align-items:center;min-width:0;gap:.65rem}.bundle-icon{display:grid;place-items:center;width:1.6rem;height:1.6rem;flex-shrink:0;border:0;border-radius:var(--ui-radius, 7px);background:transparent;color:var(--muted)}.filename{min-width:0;font-size:.8rem;font-weight:500;overflow-wrap:anywhere;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta{min-width:0;color:var(--muted);font-size:.65rem;line-height:1.5;font-variant-numeric:tabular-nums;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bundle-size{padding-right:.65rem;text-align:right}.bundle-provenance{flex-shrink:0;margin-left:-.35rem;padding:.05rem .35rem;border:1px solid rgb(from var(--accent) r g b / .25);border-radius:5px;background:rgb(from var(--accent) r g b / .07);color:var(--accent);font-size:.62rem;font-weight:500}.bundle-actions{display:flex;align-items:center;gap:.5rem}.bundle-open{padding:0;border:0;background:none;color:inherit;font:inherit;text-align:left}.bundle-open:hover{color:var(--accent)}.bundle-row>.location-editor{grid-column:1 / -1}.breadcrumb{flex-wrap:wrap}.breadcrumb .breadcrumb-current{margin:0;color:var(--text);font-size:.85rem;font-weight:500}
10
+ `,qn=`.location-editor{display:grid;grid-template-columns:minmax(0,1fr) minmax(10rem,.7fr) auto;align-items:end;gap:.75rem;padding:.85rem;border-top:1px solid var(--border);background:rgb(from var(--bg) r g b / .35)}.location-field{display:grid;gap:.35rem;min-width:0}.location-field>span,.location-field label{color:var(--muted);font-size:.75rem}.location-field input{width:100%}.location-field input[type=text],.location-actions .action{height:2rem;min-height:2rem;padding-block:.28rem}.location-actions{display:flex;gap:.4rem}.location-actions .action{width:auto;padding-inline:.65rem;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);color:var(--text);background:var(--bg);font-size:.78rem}.location-field-header{display:flex;align-items:baseline;justify-content:space-between;gap:.5rem;min-width:0;color:var(--muted);font-size:.75rem}.location-field-header>:first-child{flex-shrink:0}.location-metadata{display:flex;align-items:baseline;gap:.25rem;min-width:0;padding:0;border:0;color:inherit;background:none;font:inherit}.location-metadata>.ui-hint{flex-shrink:0}.location-metadata-value{min-width:0;user-select:text;-webkit-user-select:text;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}button.location-metadata:hover:not(:disabled){color:var(--text)}.location-origin{grid-column:1 / -1;margin:0;color:var(--muted);font-size:.72rem;overflow-wrap:anywhere}.origin-retry{padding:0;border:0;background:none;color:var(--accent);font:inherit}
11
+ `,Jn=`.icon-btn{display:inline-grid;place-items:center;flex:0 0 auto;width:1.8rem;height:1.8rem;padding:0;border:1px solid transparent;border-radius:var(--ui-radius, 5px);color:var(--muted);background:transparent}.icon-btn:hover:not(:disabled){color:var(--text);background:var(--surface-active)}.icon-btn.danger:hover:not(:disabled){color:var(--critical, #e5534b);background:rgb(from var(--critical, #e5534b) r g b / .1)}.icon-btn svg,.btn svg{width:.9rem;height:.9rem}.avatar{position:relative;display:inline-grid;place-items:center;flex:0 0 auto;width:2rem;height:2rem;border-radius:50%;overflow:hidden;background:var(--surface-active);color:var(--muted);font-family:system-ui,-apple-system,BlinkMacSystemFont,sans-serif;font-size:.8rem;font-weight:600;user-select:none}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}.avatar img.broken{display:none}.create-team{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;margin-bottom:1rem}.new-name{flex:1 1 14rem;width:16rem;max-width:24rem}.access-note{flex:1 1 24rem;margin:0 0 0 auto;color:var(--muted);font-size:.75rem;text-align:right}.team .icon-btn{width:1.8rem;height:1.8rem}.team{border:1px solid var(--border);border-radius:var(--ui-radius, 8px);margin-bottom:.85rem;background:var(--panel);overflow:hidden}.team-head{display:flex;align-items:center;gap:.5rem;min-height:2.75rem;padding:.4rem .85rem;border-bottom:1px solid var(--border);background:rgb(from var(--text) r g b / .025)}.team-icon{display:grid;place-items:center;flex:0 0 auto;width:1.25rem;height:1.25rem;color:var(--muted)}.team-icon svg{width:1.05rem;height:1.05rem}.team-name{margin:0;min-width:0;font-size:.875rem;font-weight:600;letter-spacing:-.015em;overflow-wrap:anywhere}.team-actions{display:flex;gap:.25rem;margin-left:auto}.rename-input{flex:1;max-width:22rem;width:0}.team-body{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr)}.sub{min-width:0;padding:.75rem .85rem}.sub+.sub{border-left:1px solid var(--border)}.sub-title{display:flex;align-items:center;gap:.5rem;margin:0 0 .4rem;font-size:.75rem;font-weight:600}.sub-title .count{height:1.1rem;min-width:1.1rem;font-size:.75rem;padding:0 .3rem}.links{list-style:none;margin:0 0 .5rem;padding:0}.links li{display:flex;align-items:center;gap:.5rem;min-height:2.25rem;padding:.25rem 0;cursor:default}.links li+li{border-top:1px solid var(--border)}.repo-icon{flex:0 0 auto;color:var(--muted);width:.95rem;height:.95rem}.repo-copy{display:flex;min-width:0;flex-direction:column;gap:.1rem}.ln{min-width:0;font-size:.8rem;font-weight:500;overflow-wrap:anywhere}.path{color:var(--muted);font-family:var(--mono);font-size:.75rem;overflow-wrap:anywhere}.repo-row .icon-btn{margin-left:auto}.links .member-row{display:grid;grid-template-columns:minmax(0,1fr) auto 1.8rem;gap:.45rem}.member{display:flex;align-items:center;gap:.45rem;min-width:0}.member .avatar{width:1.6rem;height:1.6rem;font-size:.75rem}.perms{display:flex;flex-wrap:wrap;gap:.3rem}.perm{display:inline-flex;align-items:center;gap:.3rem;padding:.15rem .3rem;border:1px solid var(--border);border-radius:4px;font-size:.7rem;color:var(--muted);user-select:none}.perm:has(:checked){color:var(--text);background:rgb(from var(--accent) r g b / .07);border-color:rgb(from var(--accent) r g b / .2)}.perm:has(:disabled){opacity:.5}.sub.npm-scopes{grid-column:1 / -1;border-top:1px solid var(--border);border-left:0}.npm-scopes .sub-head{display:flex;flex-wrap:wrap;align-items:center;gap:.15rem .75rem;margin-bottom:.4rem}.npm-scopes .sub-head>.sub-title,.npm-scopes .sub-head>.ui-hint{margin:0}.npm-scopes .sub-head>.ui-hint{margin-left:auto;text-align:right}.npm-scope-row{flex-wrap:wrap;padding-top:0}.npm-scope-list{display:flex;flex:1 1 12rem;flex-wrap:wrap;align-items:center;gap:.35rem;min-width:0;margin:0;padding:0;list-style:none}.npm-scope{display:inline-flex;align-items:center;gap:.45rem;padding:.35rem .35rem .35rem .45rem;border:1px solid var(--border);border-radius:4px;font-family:var(--mono);font-size:.75rem}.npm-scope .icon-btn{width:1.3rem;height:1.3rem}.add-npm-scope{flex:1;width:0;max-width:18rem}.npm-scope-row>.add-npm-scope{min-width:8rem}.add-row{display:flex;align-items:center;gap:.5rem;padding-top:.45rem}.add-row select,.add-row repository-selector,.add-row user-selector{flex:1;width:0}.add-repo-path{flex:.75;width:0}.add-row .btn{flex:0 0 auto}.muted{color:var(--muted);font-size:.78rem;margin:.5rem 0}@container (max-width: 50rem){.access-note,.npm-scopes .sub-head>.ui-hint{flex-basis:100%;margin-left:0;text-align:left}.team-body{grid-template-columns:1fr}.sub+.sub{border-left:0;border-top:1px solid var(--border)}.add-row{max-width:36rem}}@container (max-width: 32rem){.create-team{flex-wrap:wrap}.new-name{flex:1;width:0}.team-head,.sub{padding-left:.75rem;padding-right:.75rem}.add-row:has(.add-repo-sel){display:grid;grid-template-columns:minmax(0,1fr) auto}.add-row .add-repo-sel{width:100%}.add-repo-path{grid-column:1 / -1;grid-row:2;width:100%}}@container (max-width: 26rem){.links .member-row{grid-template-columns:minmax(0,1fr) 1.8rem}.perms{grid-row:2;padding-left:2.05rem}.member-row>.icon-btn{grid-column:2;grid-row:1}}.npm-review-toggle{display:inline-flex;align-items:center;gap:.35rem;margin-left:.75rem;font-size:.85rem;font-weight:400}
12
+ `,Yn=`.note{color:var(--muted);font-size:.75rem}.entry-points{display:flex;align-items:center;gap:1rem;margin-top:1rem;line-height:1.5}.package-suggestions{display:flex;align-items:center;gap:1rem;margin-top:1rem;color:var(--muted);font-size:.75rem}.package-suggestions>div{flex:1;min-width:0}.package-suggestions p{margin:0 0 .4rem}.package-suggestions .suggestions-note{margin:.4rem 0 0}.package-suggestions ul{display:flex;flex-wrap:wrap;gap:.4rem .8rem;padding:0;margin:0;list-style:none;max-height:6rem;overflow:auto}.package-suggestions li{min-width:0;max-width:100%}.package-suggestions li code{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}.package-suggestions .btn{flex:none;font-size:.72rem}.selection{flex:1;min-width:0}.selection .note{margin:.5rem 0 0}.selection-head{display:flex;align-items:center;gap:.75rem}.btn.clear-selection{min-height:1.65rem;padding:.2rem .5rem;font-size:.72rem}h2{margin:0;font-size:.8rem;font-weight:500}h2 span{color:var(--muted);margin-left:.4rem}.entry-points ul{padding:0;display:flex;flex-wrap:wrap;gap:.4rem;list-style:none;max-height:7rem;overflow:auto;margin:.6rem 0 0}.entry-points li{display:flex;align-items:center;gap:.4rem;min-width:0;max-width:100%;padding:.2rem .4rem;border:1px solid var(--border);border-radius:var(--ui-radius, 4px);background:var(--bg);font-size:.72rem}.entry-points li span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.entry-points li button{display:grid;place-items:center;flex:none;width:1.3rem;height:1.3rem;padding:0;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted);cursor:default}.entry-points li button svg{width:1rem;height:1rem}.entry-points li button:hover{color:var(--critical);background:color-mix(in srgb,var(--critical) 12%,transparent)}.entry-points li button:focus-visible{outline:1px solid var(--accent);outline-offset:1px}
13
+ `;function Xn(e,t,n){return Qn(e,t,n,v`Entry points declared in <code>package.json</code>`,`Suggested entry points`)}function Zn(e,t,n,r){return Qn(e,t,n,`Suggested Solidity sources`,`Suggested Solidity sources`,r)}function Qn(e,t,n,r,i,a=!1){let o=e.filter(e=>!t.has(e));return o.length===0&&!a?y:v`<aside class="package-suggestions" aria-label="${i}"><div><p>${r}</p>${o.length>0?v`<ul>${o.map(e=>v`<li><code data-tooltip-truncated data-tooltip="${e}">${e}</code></li>`)}</ul>`:y} ${a?v`<p class="suggestions-note ui-hint">Suggestions are limited. Browse the source directories to select more files.</p>`:y}</div>${o.length>0?v`<button type="button" class="btn" @click="${()=>n(o)}">Use suggestions</button>`:y}</aside>`}var $n=`:host{padding:0;margin:1.2rem 0}.conditions-head{display:flex;align-items:center;flex-wrap:wrap;gap:.65rem 1rem}.conditions-head[data-conditions-hidden]>:not(slot){visibility:hidden}slot[name=actions]::slotted(*){flex:none}h2{margin:0;font-size:.8rem;font-weight:500}.presets{display:flex;gap:2px;padding:3px;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--bg)}.presets button{display:inline-flex;align-items:center;gap:.35rem;padding:.3rem .65rem;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted);font-size:.75rem}.presets button:hover{background:var(--surface-active);color:var(--text)}.presets button[aria-pressed=true]{background:color-mix(in srgb,var(--accent) 15%,var(--bg));color:var(--accent)}.presets button:focus-visible{outline-offset:-1px}svg{width:1rem;height:1rem;flex:none}.platforms{display:flex;align-items:center;flex-wrap:wrap;gap:.75rem;font-size:.75rem}.platforms>span{color:var(--muted)}.platforms label{display:inline-flex;align-items:center;gap:.35rem}.platforms input{margin:0;width:.85rem;height:.85rem}.manual-toggle{display:flex;align-items:center;gap:.25rem;margin-left:auto;padding:.25rem 0;border:0;border-radius:var(--ui-radius, 2px);background:transparent;color:var(--muted);font-size:.75rem;white-space:nowrap}.manual-toggle:hover{color:var(--text)}.manual-toggle[hidden]{visibility:hidden}.manual-toggle[aria-expanded=true] svg{transform:rotate(90deg)}#manual-conditions{margin-top:.75rem}.condition-editor{display:flex;align-items:center;flex-wrap:wrap;gap:.35rem;min-height:2.25rem;padding:.3rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg)}.condition-editor:focus-within{border-color:var(--accent)}ul{display:flex;flex-wrap:wrap;gap:.35rem;max-width:100%;margin:0;padding:0;list-style:none}li{display:inline-flex;align-items:center;gap:.35rem;min-width:0;max-width:100%;min-height:1.5rem;padding:0 .25rem 0 .5rem;border:1px solid var(--border);border-radius:var(--ui-radius, 4px);background:var(--surface);color:var(--text);font-size:.73rem}li.preset{padding-right:.5rem}li code{overflow-wrap:anywhere}li button{display:grid;place-items:center;flex:none;width:1.3rem;height:1.3rem;padding:0;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted)}li button:hover{color:var(--critical);background:color-mix(in srgb,var(--critical) 12%,transparent)}.condition-input{display:flex;align-items:center;flex:1;min-width:9rem}.condition-editor input{flex:1;width:0;min-width:0;min-height:1.5rem;padding:.15rem .4rem;border:0;border-radius:0;background:transparent;font-size:.75rem}.condition-editor input:focus-visible{outline:none}p{margin:.5rem 0 0;color:var(--muted);font-size:.7rem}.error{color:var(--critical)}@container (width <= 30rem){.conditions-head{gap:.6rem}.presets{margin-left:auto}.presets button{padding-inline:.4rem}.platforms{flex-basis:100%}}
14
+ `,er=[`import`,`require`,`default`],P=[{id:`node`,label:`Node.js`,conditions:[`node`],automatic:[...er,`node`,`node-addons`,`module-sync`],icon:et`<path transform="scale(.6667)" fill="currentColor" stroke="none" d=${Je}/>`},{id:`browser`,label:`Browser`,conditions:[`browser`,`module`],automatic:er,icon:et`<rect x="1.5" y="2.5" width="13" height="11" rx="1.5"/><path d="M1.5 6h13M4 4.3h.1m2 0h.1"/>`},{id:`metro`,label:`Metro`,conditions:[`react-native`],automatic:er,icon:et`<rect x="4" y="1.5" width="8" height="13" rx="2"/><path d="M6.5 3.5h3M7 12.5h2"/>`}],tr=16-Math.max(...P.map(e=>e.conditions.length)),F=[{id:`ios`,label:`iOS`},{id:`android`,label:`Android`}],nr=new Intl.ListFormat(`en`,{type:`conjunction`});function rr(){return{preset:`node`,conditions:[`node`],platforms:[]}}var ir=class extends tt{static styles=[_(a),_($n)];static properties={showConditions:{attribute:!1},_preset:{state:!0},_manual:{state:!0},_platforms:{state:!0},_draft:{state:!0},_error:{state:!0},_manualOpen:{state:!0}};constructor(){super(),this.showConditions=!0,this._preset=`node`,this._manual=[],this._platforms=[`ios`,`android`],this._draft=``,this._error=``,this._manualOpen=!1}get value(){return{preset:this._preset,conditions:this.conditions,platforms:this._preset===`metro`?[...this._platforms]:[]}}get presetConditions(){return P.find(e=>e.id===this._preset).conditions}get automaticConditions(){return P.find(e=>e.id===this._preset).automatic}get conditions(){return[...new Set([...this.presetConditions,...this._preset===`metro`?[]:this._manual])]}notifyChange(){this.dispatchEvent(new CustomEvent(`conditions-change`,{detail:this.value,bubbles:!0,composed:!0}))}selectPreset(e){P.find(t=>t.id===e)&&(this._preset=e,this._draft=``,this._error=``,this.notifyChange())}togglePlatform(e){if(!F.some(t=>t.id===e))return;let t=this._platforms.includes(e);t&&this._platforms.length===1||(this._platforms=F.map(e=>e.id).filter(n=>n===e?!t:this._platforms.includes(n)),this.notifyChange())}addConditions(){if(this._preset===`metro`)return;let e=this._draft.trim().split(/[\s,]+/u).filter(Boolean);if(e.length===0)return;if(e.some(e=>this.automaticConditions.includes(e)&&!this.presetConditions.includes(e))){this._error=`${nr.format(this.automaticConditions)} are handled automatically.`;return}if(e.some(e=>e.length>64||e.startsWith(`.`)||/^\d+$/u.test(e))){this._error=`Use condition names of up to 64 characters, without a leading dot or an all-numeric name.`;return}let t=[...new Set([...this._manual,...e.filter(e=>!this.presetConditions.includes(e))])];if(t.length>tr){this._error=`Use up to ${tr} manual conditions.`;return}this._manual=t,this._draft=``,this._error=``,this.notifyChange()}removeCondition(e){this.presetConditions.includes(e)||(this._manual=this._manual.filter(t=>t!==e),this._error=``,this.notifyChange())}render(){let e=this._preset!==`metro`,t=this.automaticConditions.filter(e=>e!==`import`&&e!==`require`);return v`<section aria-label="${this.showConditions?`Conditions`:`Bundle actions`}"><div class="conditions-head" ?data-conditions-hidden="${!this.showConditions}"><h2 id="conditions-heading">Conditions</h2><div class="presets" role="group" aria-label="Condition preset">${P.map(e=>v`<button type="button" aria-pressed="${this._preset===e.id}" @click="${()=>this.selectPreset(e.id)}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${e.icon}</svg>${e.label}</button>`)}</div>${this._preset===`metro`?v`<div class="platforms" role="group" aria-label="Metro platforms"><span>Platforms</span>${F.map(({id:e,label:t})=>v`<label><input type="checkbox" .checked="${this._platforms.includes(e)}" ?disabled="${this._platforms.includes(e)&&this._platforms.length===1}" @change="${()=>this.togglePlatform(e)}">${t}</label>`)}</div>`:y} <button type="button" class="manual-toggle" ?hidden="${!e}" aria-expanded="${this._manualOpen}" aria-controls="manual-conditions" @click="${()=>{this._manualOpen=!this._manualOpen}}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 4 4 4-4 4"/></svg>Manual conditions</button><slot name="actions"></slot></div><div id="manual-conditions" ?hidden="${!this.showConditions||!e||!this._manualOpen}"><form class="condition-editor" @submit="${e=>{e.preventDefault(),this.addConditions()}}"><ul aria-label="Export conditions">${this.conditions.map(e=>this.presetConditions.includes(e)?v`<li class="preset"><code>${e}</code></li>`:v`<li><code>${e}</code><button type="button" aria-label="${`Remove condition ${e}`}" @click="${()=>this.removeCondition(e)}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="m4 4 8 8m0-8-8 8"/></svg></button></li>`)}</ul><div class="condition-input"><input type="text" aria-label="Add conditions" aria-describedby="conditions-help" aria-invalid="${!!this._error}" aria-errormessage="condition-error" placeholder="Add condition…" autocomplete="off" maxlength="1040" .value="${this._draft}" @input="${e=>{this._draft=e.target.value,this._error=``}}" @keydown="${e=>{e.key===` `&&!e.isComposing&&(e.preventDefault(),this.addConditions())}}" @blur="${()=>this.addConditions()}"></div></form><p id="conditions-help">Package export conditions. <code>import</code> / <code>require</code>${t.map((e,n)=>v`${n<t.length-1?`, `:t.length>1?`, and `:` and `}<code>${e}</code>`)} are automatic.</p>${this._error?v`<p id="condition-error" class="error" role="alert">${this._error}</p>`:y}</div></section>`}};customElements.define(`bundle-conditions`,ir);var ar=`:host{padding:0}.field,.browser{line-height:1.5}.source-fields{display:grid;grid-template-columns:minmax(12rem,1fr) minmax(0,1.6fr);align-items:end;gap:1rem;margin:1rem 0}.field{display:flex;flex-direction:column;gap:.4rem;min-width:0;font-size:.75rem;color:var(--muted)}button:disabled,input:disabled{opacity:.5}.browser{border:1px solid var(--border);border-radius:var(--ui-radius, 7px);overflow:hidden}.browser-head{display:flex;align-items:center;gap:.75rem;padding:.65rem .8rem;border-bottom:1px solid var(--border);background:var(--bg);font-size:.75rem}.commit-link{display:inline-flex;align-items:center;flex:none;gap:.3rem;margin-left:auto;color:var(--muted);text-decoration:none}.commit-link svg{width:1rem;height:1rem}.commit-link code{cursor:inherit}.commit-link:hover{color:var(--accent)}.commit-link:focus-visible{outline:1px solid var(--accent);outline-offset:3px;border-radius:var(--ui-radius, 2px)}.breadcrumbs{display:flex;align-items:center;flex-wrap:wrap;gap:.35rem;min-width:0}.breadcrumbs button{border:0;padding:.1rem;background:transparent;color:var(--muted);overflow-wrap:anywhere}.breadcrumbs button[aria-current]{color:var(--text)}.breadcrumbs button:hover:not(:disabled){color:var(--accent)}.file-browser{min-height:18rem;max-height:50vh;overflow:auto;padding:.75rem}.file-browser:has(>.empty){display:grid;place-items:center}.file-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,16rem),1fr));gap:.5rem}.file-tile{display:flex;align-items:center;gap:.5rem;min-width:0;height:2.05rem;padding:.4rem .6rem;border:1px solid var(--border);border-radius:var(--ui-radius, 5px);background:var(--bg);color:var(--text);font-size:.75rem}.file-tile>span:not(.arrow){overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.file-tile input{width:.85rem;height:.85rem;margin:0;accent-color:var(--accent);flex:none}.file-tile:hover,.file-tile:focus-within{border-color:var(--accent)}.file-tile.selected{border-color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,var(--bg))}.directory{color:var(--muted)}.directory .arrow{margin-left:auto}.unsupported{opacity:.55}.empty{margin:0;padding:1rem;border:0;border-radius:0;text-align:center;color:var(--muted);font-size:.8rem;line-height:1.5}.error{color:var(--critical)}.message{padding:.5rem .8rem;color:var(--muted);font-size:.75rem;line-height:1.5}.text-action{border:0;padding:.1rem .2rem;color:var(--accent);background:transparent;font-size:.75rem}@container (width <= 45rem){.source-fields{grid-template-columns:1fr}}
15
+ `,or=100;async function I(e,t,n){let r=await d(`/api/admin/repositories/${e}?${new URLSearchParams(t)}`,{credentials:`same-origin`,headers:{accept:`application/json`},signal:n});if(!r.ok){let e=await r.json().catch(()=>null);if(e?.error===`github-rate-limited`){let e=Number(r.headers.get(`retry-after`)),t=Math.ceil(e/60),n=Number.isFinite(e)&&e>0?` Try again in about ${t} ${t===1?`minute`:`minutes`}.`:` Try again after the limit resets.`;throw Error(`GitHub\u2019s API rate limit has been reached.${n}`)}throw e?.error===`github-status-403`?Error(`GitHub denied this request. Check repository access and the GitHub App’s read permissions.`):e?.error===`github-unauthorized`?Error(`GitHub authentication has expired or was revoked. Sign in again and check the repository App installation.`):e?.error===`github-unreachable`?Error(`Could not connect to GitHub. Try again shortly.`):r.status===404?Error(`This repository, revision, or directory is unavailable.`):r.status===403?Error(`Repository access is required to browse files.`):Error(`Could not load repository files from GitHub. Try again.`)}return r.json()}var L=class extends tt{static styles=[_(a),_(ar)];static properties={installTooltips:{attribute:!1},initialRepoId:{attribute:!1},_repos:{state:!0},_loadingRepos:{state:!0},_reposError:{state:!0},_repoId:{state:!0},_refs:{state:!0},_refKind:{state:!0},_refName:{state:!0},_path:{state:!0},_entries:{state:!0},_commit:{state:!0},_loadingRefs:{state:!0},_loading:{state:!0},_error:{state:!0},_refsError:{state:!0},_limited:{state:!0}};constructor(){super(),this._repos=[],this._loadingRepos=!0,this._reposError=``,this.initialRepoId=null,this._repoId=null,this._refs={branches:[],tags:[]},this._refKind=`branch`,this._refName=``,this._path=``,this._entries=null,this._commit=``,this._directories=new Map,this._loadingRefs=!1,this._loading=!1,this._error=``,this._refsError=``,this._limited=!1}updated(e){e.has(`installTooltips`)&&this.installTooltips?.(this.renderRoot)}firstUpdated(){this.loadRepositories()}async loadRepositories(){this._reposRequest?.abort(),this.selectRepository(null),this._repos=[],this._reposError=``,this._loadingRepos=!0;let e=new AbortController;this._reposRequest=e;try{let t=await I(`browsable`,{},e.signal);if(e.signal.aborted)return;this._repos=t.repos,this._repos.some(e=>e.repoId===this.initialRepoId)&&this.selectRepository(this.initialRepoId)}catch{e.signal.aborted||(this._reposError=`Could not load repositories. Try again.`)}finally{e.signal.aborted||(this._loadingRepos=!1)}}disconnectedCallback(){clearTimeout(this._browseTimer),this._reposRequest?.abort(),this._refsRequest?.abort(),this._request?.abort(),this._directories.clear(),super.disconnectedCallback()}showDirectory(e){}resetFiles(){clearTimeout(this._browseTimer),this._request?.abort(),this._directories.clear(),this._loading=!1,this._entries=null,this._path=``,this._commit=``,this.showDirectory(null),this._error=``,this._limited=!1}async selectRepository(e){if(this._refsRequest?.abort(),this.resetFiles(),this._repoId=e,this._refs={branches:[],tags:[]},this._refsError=``,this._refKind=`branch`,this._refName=``,e==null){this._loadingRefs=!1;return}let t=new AbortController;this._refsRequest=t,this._loadingRefs=!0;try{let{defaultContents:n,...r}=await I(`refs`,{repoId:e,withDefault:`true`},t.signal);if(t.signal.aborted)return;this._refs=r,this._refName=r.defaultBranch||r.branches[0]||``,n?this.useDirectory(n,``):this._refName&&this.loadDirectory(``)}catch(e){t.signal.aborted||(this._refsError=e.message)}finally{t.signal.aborted||(this._loadingRefs=!1)}}changeRevision(e,t){this._refsRequest?.abort(),this._loadingRefs=!1,this.resetFiles(),this._refKind=e,this._refName=t}selectRevisionType(e){this._refKind!==e&&(this.changeRevision(e,e===`branch`&&this._refs.defaultBranch||``),this._refName&&this.loadDirectory(``))}editRevision(e){this.changeRevision(this._refKind,e);let t=e.trim();if(!t)return;let n=this._refKind===`branch`?this._refs.branches:this._refs.tags;this._refKind!==`commit`&&(n.includes(t)||this._refKind===`branch`&&t===this._refs.defaultBranch)?this.loadDirectory(``):this._browseTimer=setTimeout(()=>{this.loadDirectory(``)},350)}revisionChanged({detail:{how:e,kind:t,name:n}}){e===`kind`?this.selectRevisionType(t):e===`submit`?this.loadDirectory(``,!0):this.editRevision(n)}async loadDirectory(e,t=!1){if(clearTimeout(this._browseTimer),this._repoId==null||!this._refName.trim())return;t&&this.resetFiles(),this._request?.abort();let n=new AbortController;this._request=n,this._path=e,this._entries=null,this._error=``,this._limited=!1,this.showDirectory(null),this._loading=!1;let r=this._refName.trim();if(this._refKind===`commit`&&!/^[a-f\d]{7,40}$/iu.test(r)){this._error=`Enter a commit SHA with 7 to 40 hexadecimal characters.`;return}let i=this._commit||(this._refKind===`commit`?r:`${this._refKind===`branch`?`heads`:`tags`}/${r}`),a=JSON.stringify([this._repoId,this._commit,e]),o=this._commit&&this._directories.get(a);if(o){this._directories.delete(a),this._directories.set(a,o),this._entries=o.entries,this._limited=o.limited,this.showDirectory(o);return}this._loading=!0;try{let t=await I(`contents`,{repoId:this._repoId,ref:i,path:e},n.signal);if(n.signal.aborted)return;this.useDirectory(t,e)}catch(e){n.signal.aborted||(this._directories.clear(),this._error=e.message)}finally{n.signal.aborted||(this._loading=!1)}}useDirectory(e,t){if(this._path=t,this._commit=e.commit,this._entries=e.entries.toSorted((e,t)=>+(t.type===`dir`)-(e.type===`dir`)||e.name.localeCompare(t.name)),this._limited=e.limited,this.showDirectory(e),/^[a-f\d]{40}$/iu.test(e.commit)){let n=JSON.stringify([this._repoId,e.commit,t]);this._directories.set(n,{...e,entries:this._entries}),this._directories.size>or&&this._directories.delete(this._directories.keys().next().value)}}repository(){return this._repos.find(e=>e.repoId===this._repoId)}renderSource(){let e=this.repository();return v`<div class="source-fields"><div class="field"><span>Repository</span><repository-selector label="Repository" ?disabled="${this._loadingRepos}" .options="${this._repos.map(e=>({value:e.repoId,label:e.fullName}))}" .value="${this._repoId}" @repository-change="${e=>this.selectRepository(e.detail.value)}"></repository-selector></div><revision-select .refs="${this._refs}" .kind="${this._refKind}" .name="${this._refName}" ?disabled="${!e||this._loadingRefs}" .installTooltips="${this.installTooltips}" @revision-change="${this.revisionChanged}"></revision-select></div>${this._reposError?v`<p class="message" role="alert">${this._reposError} <button type="button" class="text-action" @click="${()=>this.loadRepositories()}">Retry</button></p>`:y} ${this._refsError?v`<p class="message" role="status">${this._refsError} <button type="button" class="text-action" @click="${()=>this.selectRepository(this._repoId)}">Retry</button></p>`:y}`}renderBrowser(e){let t=this.repository(),n=this._path.split(`/`).filter(Boolean),r=t&&this._commit?`https://github.com/${[...t.fullName.split(`/`),`tree`,this._commit,...n].map(encodeURIComponent).join(`/`)}`:null;return v`<section class="browser" aria-label="Repository files" aria-busy="${this._loadingRepos||this._loading||this._loadingRefs}"><div class="browser-head"><nav class="breadcrumbs" aria-label="Repository directory"><button type="button" ?disabled="${!this._commit}" aria-current="${Pe(this._path?void 0:`location`)}" @click="${()=>this.loadDirectory(``)}">${t?.fullName??`Repository`}</button>${n.map((e,t)=>v`<span aria-hidden="true">/</span><button type="button" aria-current="${Pe(t===n.length-1?`location`:void 0)}" @click="${()=>this.loadDirectory(n.slice(0,t+1).join(`/`))}">${e}</button>`)}</nav>${r?v`<a class="commit-link" href="${r}" target="_blank" rel="noopener noreferrer" data-tooltip="${this._commit}" data-tooltip-icon="commit" aria-label="${`View directory at commit ${this._commit.slice(0,7)} on GitHub`}">${Fe}<code>${this._commit.slice(0,7)}</code></a>`:y}</div><div class="file-browser">${this._loadingRepos||this._loading||this._loadingRefs?v`<p class="empty" role="status">${this._loadingRepos?`Loading repositories…`:this._loadingRefs?`Loading revisions…`:`Loading files…`}</p>`:this._error?v`<p class="empty error" role="alert">${this._error} <button type="button" class="text-action" @click="${()=>this.loadDirectory(this._path)}">Retry</button></p>`:this._entries==null?v`<p class="empty">${t?`Choose a revision to browse its files.`:this._repos.length>0?`Select a repository to browse its files.`:`No accessible repositories available.`}</p>`:this._entries.length===0?v`<p class="empty">This directory is empty.</p>`:v`<div class="file-grid">${this._entries.map(t=>t.type===`dir`?v`<button type="button" class="file-tile directory" @click="${()=>this.loadDirectory(t.path)}">${Ne}<span data-tooltip-truncated data-tooltip="${t.path}">${t.name}</span><span class="arrow" aria-hidden="true">›</span></button>`:e(t))}</div>`}</div>${this._limited?v`<p class="message ui-hint">Showing GitHub’s first 1,000 entries in this directory.</p>`:y}</section>`}},sr=class extends L{static styles=[...L.styles,_(Yn)];static properties={...L.properties,createBundle:{attribute:!1},_building:{state:!0},_opening:{state:!0},_buildError:{state:!0},_selected:{state:!0},_packageEntryPoints:{state:!0},_solidityEntryPoints:{state:!0},_soliditySuggestionsLimited:{state:!0}};constructor(){super(),this._building=!1,this._opening=!1,this._buildError=``,this._selected=new Set,this._dismissedSuggestions=new Set,this._bundleConditions=rr(),this._packageEntryPoints=[],this._solidityEntryPoints=[],this._soliditySuggestionsLimited=!1}disconnectedCallback(){this._buildRequest?.abort(),this._opening=!1,this._dismissedSuggestions.clear(),this.showDirectory(null),super.disconnectedCallback()}resetFiles(){this._buildError=``,super.resetFiles(),this._selected=new Set,this._dismissedSuggestions.clear()}showDirectory(e){this._packageEntryPoints=e?.packageEntryPoints??[],this._solidityEntryPoints=e?.solidityEntryPoints??[],this._soliditySuggestionsLimited=e?.soliditySuggestionsLimited??!1}useDirectory(e,t){super.useDirectory(e,t);let n=[...this._packageEntryPoints,...this._solidityEntryPoints].filter(e=>!this._dismissedSuggestions.has(e));this._selected=new Set([...this._selected,...n])}toggleFile(e){let t=new Set(this._selected);t.has(e)?(t.delete(e),this._dismissedSuggestions.add(e)):(t.add(e),this._dismissedSuggestions.delete(e)),this._selected=t}clearFiles(){for(let e of this._selected)this._dismissedSuggestions.add(e);this._selected=new Set}hasScriptEntryPoints(){return[...this._selected].some(e=>/\.[cm]?[tj]sx?$/iu.test(e))}async buildBundle(){if(this._building||this._opening||!this.createBundle||!this._commit||this._selected.size===0)return;let e=new AbortController;this._buildRequest=e,this._building=!0,this._buildError=``;try{let t=await this.createBundle({repoId:this._repoId,commit:this._commit,entries:[...this._selected],conditions:this._bundleConditions},e.signal);e.signal.aborted||(this._opening=!0,this.dispatchEvent(new CustomEvent(`bundle-created`,{detail:t,bubbles:!0,composed:!0})))}catch(t){e.signal.aborted||(this._buildError=t.message)}finally{this._building=!1}}render(){let e=this._building||this._opening;return v`<p class="intro ui-hint">Choose a repository and revision, then select files to use as entry points.</p><div ?inert="${e}">${this.renderSource()} ${this.renderBrowser(e=>v`<label class="${`file-tile ${this._selected.has(e.path)?`selected`:``} ${e.type===`file`?``:`unsupported`}`}" data-tooltip="${e.type===`file`?y:`${e.path} (${e.type})`}"><input type="checkbox" aria-label="${`Select ${e.path} as an entry point`}" .checked="${this._selected.has(e.path)}" ?disabled="${e.type!==`file`}" @change="${()=>this.toggleFile(e.path)}">${Me(e.name)}<span data-tooltip-truncated data-tooltip="${e.type===`file`?e.path:y}">${e.name}</span></label>`)} ${Xn(this._packageEntryPoints,this._selected,e=>{this._selected=new Set([...this._selected,...e])})} ${Zn(this._solidityEntryPoints,this._selected,e=>{this._selected=new Set([...this._selected,...e])},this._soliditySuggestionsLimited)}<section class="entry-points" aria-label="Selected entry points"><div class="selection"><div class="selection-head"><h2>Entry points <span aria-live="polite">${this._selected.size}</span></h2>${this._selected.size>0?v`<button type="button" class="btn clear-selection" @click="${this.clearFiles}">Clear all</button>`:y}</div>${this._selected.size>0?v`<ul>${[...this._selected].map(e=>v`<li>${Me(e)}<span data-tooltip-truncated data-tooltip="${e}">${e}</span><button type="button" aria-label="${`Remove ${e}`}" @click="${()=>this.toggleFile(e)}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="m4 4 8 8m0-8-8 8"/></svg></button></li>`)}</ul>`:v`<p class="note ui-hint">Select files above. You can choose entry points from multiple directories.</p>`}</div></section><bundle-conditions .showConditions="${this.hasScriptEntryPoints()}" @conditions-change="${e=>{this._bundleConditions=e.detail}}"><button type="button" slot="actions" class="btn primary" ?disabled="${e||!this.createBundle||!this._commit||this._selected.size===0||this._loading||this._loadingRefs}" @click="${this.buildBundle}">${this._opening?`Opening…`:this._building?`Creating…`:`Create a bundle`}</button></bundle-conditions></div>${e?v`<p class="message" role="status">${this._opening?`Opening bundle…`:`Building the selected entry points with Stasis…`}</p>`:y} ${this._buildError?v`<p class="message error" role="alert">${this._buildError}</p>`:y}`}};customElements.define(`managed-create-bundle`,sr);function cr(e){let t=new Map((e.repos??[]).map(e=>[e.repoId,{id:e.repoId,label:e.fullName}])),n=(e.bundles??[]).map(e=>{let n=e.repoId??`unattached`;return t.has(n)||t.set(n,{id:n,label:n===`unattached`?`Unattached`:e.repoFullName??String(n)}),{...e,repoId:n,repo:t.get(n).label,size:m(e.byteSize),files:null,reasons:[]}});return{repositories:[...t.values()],bundles:n,scans:[]}}async function lr(t,n){let r=await at(t.id,{signal:n});n?.throwIfAborted();let i=Le(r,t.integrity);return e(t,i)}function ur(e){return e.map(e=>{let t=e.login||String(e.id),n=e.name?.trim()||`@${t}`,r=n===`@${t}`?``:`@${t}`,i=n.replace(/^@/u,``).split(/\s+/u).filter(Boolean).slice(0,2).map(e=>e[0]).join(``).toUpperCase();return{value:e.id,label:r?`${n} ${r}`:n,displayLabel:n,secondary:r,initials:i,disabled:e.disabled,detail:e.detail}})}function dr(e,t){let n=t.normalize(`NFKC`).toLocaleLowerCase().trim().split(/\s+/u).filter(Boolean),r=e.filter(e=>!e.reset),i=r.filter(e=>n.every(t=>e.label.normalize(`NFKC`).toLocaleLowerCase().includes(t))).toSorted((e,t)=>e.label.localeCompare(t.label,void 0,{sensitivity:`base`,numeric:!0}));return{pinned:e.filter(e=>e.reset),sections:[{label:null,options:i}],facets:[],showFacets:!1,count:i.length,total:r.length}}var fr=class extends ke{static properties={users:{attribute:!1},resetLabel:{type:String,attribute:`reset-label`}};static styles=[ke.styles,$e`.avatar{position:relative;overflow:hidden}.avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}`];constructor(){super(),this.users=[],this.resetLabel=``,this.label=`Choose user`,this.placeholder=`Choose user`}get searchLabel(){return`Search users`}get optionsLabel(){return`Users`}get noMatchesLabel(){return`No matching users`}get emptyLabel(){return`No users available`}get changeEvent(){return`user-change`}willUpdate(e){(e.has(`users`)||e.has(`resetLabel`))&&(this.options=[...this.resetLabel?[{value:``,label:this.resetLabel,reset:!0}]:[],...ur(this.users)])}choices(){return dr(this.options,this._query)}optionIcon(e){return e.initials?v`<span class="avatar" aria-hidden="true">${e.initials}${l()?y:ze(e.value,v`<img alt="" loading="lazy" decoding="async" src="${`/api/avatar/${encodeURIComponent(e.value)}`}" @error="${e=>{e.currentTarget.hidden=!0}}">`)}</span>`:y}};customElements.get(`user-selector`)||customElements.define(`user-selector`,fr);var pr=`:host{padding:0;container-type:normal}.alias-table{overflow-x:auto;padding-bottom:.5rem}table{width:100%;border-collapse:collapse;text-align:left}th,td{padding:.35rem .5rem;border-bottom:1px solid var(--border)}th{color:var(--muted);font-weight:500}td:not(.actions,.empty){overflow-wrap:anywhere}input{width:100%;min-width:7rem;padding:.3rem .45rem;border:1px solid var(--border);border-radius:.375rem;background:var(--bg);color:var(--text);font:inherit}.actions{white-space:nowrap;text-align:right}.actions .btn{min-height:1.75rem;padding:.2rem .55rem}.actions .btn+.btn{margin-left:.25rem}
16
+ `,mr=`/api/admin/repositories/aliases`;async function hr(e=``,t={}){let n=await d(`${mr}${e}`,{credentials:`same-origin`,...t}),r=await n.json();if(!n.ok)throw Error({"alias-exists":`An alias already exists for this old repository and path. Edit that row instead.`,"bad-old-repo":`Enter the old repository as owner/name or a GitHub URL.`,"bad-directory":`Enter repository directories without parent segments, backslashes, or surrounding whitespace.`,"bad-repo":`Choose a connected repository.`,"no-alias":`This alias was removed. Refresh the list and try again.`}[r?.error]??`HTTP ${n.status}`);return r}var gr=class extends b{static properties={repositories:{attribute:!1},_data:{state:!0},_edit:{state:!0},_error:{state:!0},_busy:{state:!0}};static styles=[_(a),_(pr)];constructor(){super(),this._data=null,this._edit=null,this._error=null,this._busy=!1}connectedCallback(){super.connectedCallback(),this._load()}updated(e){e.has(`repositories`)&&e.get(`repositories`)!==void 0&&(this.appState.invalidate([`repository-aliases`]),this._load())}async _load(){this._error=null,await this._loadCollection(`repository-aliases`,`repository aliases`,e=>hr(``,{signal:e}),e=>{this._data=e})}_start(e=null){this._error=null,this._edit=e?{...e}:{id:null,oldRepo:``,oldPath:``,repoId:null,newPath:``}}async _mutate(e,t,n){if(!this._busy&&this._csrf&&this._role===`admin`){this._busy=!0,this._error=null;try{await this.appState.mutate(()=>hr(t?`/${encodeURIComponent(t)}`:``,{method:e,headers:{"content-type":`application/json`,"x-csrf-token":this._csrf},...n?{body:JSON.stringify(n)}:{}}),[`repository-aliases`,`workspace-import`]),this._edit=null,await this._load()}catch(e){this._error=String(e?.message??e)}finally{this._busy=!1}}}_save(){let{id:e,...t}=this._edit;return this._mutate(e?`PATCH`:`POST`,e,t)}_field(e,t,n){return v`<td><input type="text" aria-label="${t}" placeholder="${n}" .value="${this._edit[e]}" ?disabled="${this._busy}" @input="${t=>{this._edit={...this._edit,[e]:t.target.value}}}"></td>`}_editor(){let e=(this._data?.repos??[]).filter(e=>e.active!==!1).map(e=>({value:e.repoId,label:e.fullName}));return v`<tr>${this._field(`oldRepo`,`Old repository`,`owner/repository`)}${this._field(`oldPath`,`Old path`,`Repository root`)}<td><repository-selector label="New repository" placeholder="Choose repository…" .options="${e}" .value="${this._edit.repoId}" ?disabled="${this._busy}" @repository-change="${e=>{this._edit={...this._edit,repoId:e.detail.value}}}"></repository-selector></td>${this._field(`newPath`,`New path`,`Repository root`)}<td class="actions"><button type="button" class="btn" ?disabled="${this._busy||!this._edit.oldRepo.trim()||this._edit.repoId==null}" @click="${()=>{this._save()}}">${this._busy?`Saving…`:`Save`}</button> <button type="button" class="btn" ?disabled="${this._busy}" @click="${()=>{this._edit=null,this._error=null}}">Cancel</button></td></tr>`}render(){let e=this._data?.aliases??[],t=this._data?.repos??[];return v`<section aria-label="Repository aliases"><div class="page-intro"><p class="intro">Map repository locations when importing new reports and bundles.</p><button type="button" class="btn" ?disabled="${this._busy||this._edit!=null||!this._data}" @click="${()=>this._start()}">Add alias</button></div>${this._error?v`<p class="msg error" role="alert">${this._error}</p>`:y}<div aria-busy="${this._loading}">${this._data===null?this._error?v`<button type="button" class="btn" @click="${()=>{this._load()}}">Try again</button>`:x(`Loading repository aliases…`):v`<div class="alias-table"><table><thead><tr><th>Old repository</th><th>Old path</th><th>New repository</th><th>New path</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody>${e.map(e=>this._edit?.id===e.id?this._editor():v`<tr><td>${e.oldRepo}</td><td class="mono">${e.oldPath||`/`}</td><td>${t.find(t=>t.repoId===e.repoId)?.fullName??`Removed repository`}${t.find(t=>t.repoId===e.repoId)?.active===!1?` (inactive)`:``}</td><td class="mono">${e.newPath||`/`}</td><td class="actions"><button type="button" class="btn" ?disabled="${this._busy||this._edit!=null}" @click="${()=>this._start(e)}">Edit</button> <button type="button" class="btn" ?disabled="${this._busy||this._edit!=null}" @click="${()=>{this._mutate(`DELETE`,e.id)}}">Delete</button></td></tr>`)} ${this._edit?.id===null?this._editor():y} ${e.length===0&&!this._edit?v`<tr><td colspan="5" class="empty">No repository aliases yet.</td></tr>`:y}</tbody></table></div>`}</div></section>`}};customElements.define(`managed-repository-aliases`,gr);function _r(e){document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:e},bubbles:!0,composed:!0}))}function vr(e,t){return v`<span class="avatar" aria-hidden="true"><span>${(t?.[0]??`?`).toUpperCase()}</span> ${l()?y:v`<img alt="" src="${`/api/avatar/${encodeURIComponent(e)}`}" @error="${e=>e.currentTarget.classList.add(`broken`)}">`}</span>`}var yr=g(Ke),R=g(qe),z=v`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="m4 4 8 8m0-8-8 8"/></svg>`,B=v`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>`,br={admin:`Admin`,manage:`Manager`,triage:`Triage`,view:`Viewer`,none:`No access`},xr={admin:`Manage workspace access and teams`,manage:`Manage content and triage within team access`,triage:`Review and triage findings`,view:`Read-only access`,none:`No workspace access`},Sr=class extends b{static styles=[_(Vn),_(a)];render(){return v`<div class="wrap">${r(`manage`,this._role,this.allowShare)}<h1 class="sr-only">Manage</h1>${this._role==null?v`<p class="msg" role="status">Loading management pages…</p>`:v`<section class="home-section" aria-labelledby="content-heading"><div class="section-heading"><h2 id="content-heading">Content & activity</h2><span>From source to findings</span></div><div class="pages">${[[`manage-bundles`,`Bundles`,`Keep source archives ready for review.`,`bundle`],[`manage-scans`,`Scans`,`Run and monitor scans from stored bundles.`,`scan`],[`manage-reports`,`Reports`,`Review, publish, and organize findings.`,`report`]].filter(([e])=>e!==`manage-scans`||[`admin`,`manage`].includes(this._role)).map(e=>this._page(e))}</div></section>${this._role===`admin`?v`<section class="home-section" aria-labelledby="workspace-heading"><div class="section-heading"><h2 id="workspace-heading">Workspace & access</h2><span>Sources, people, and permissions</span></div><div class="pages workspace-pages">${[[`manage-repos`,`Repositories`,`Connect sources and manage repository settings.`,`repo`],[`admin-users`,`Users`,`Manage accounts, roles, and workspace access.`,`users`],[`manage-teams`,`Teams`,`Bring people and repositories together.`,`team`]].map(e=>this._page(e))}</div></section>`:y} <button type="button" class="history-link" @click="${()=>_r(`manage-history`)}"><span class="page-icon" aria-hidden="true">${i(`history`)}</span> <span class="page-copy"><strong>Workspace history</strong><span>Follow activity and triage changes across your workspace.</span></span> <span class="history-cta">View history ${i(`arrow`)}</span></button>`}</div>`}_page([e,t,n,r]){return v`<button type="button" class="${`page page-${r}`}" @click="${()=>_r(e)}"><span class="page-top"><span class="page-icon" aria-hidden="true">${i(r)}</span><strong class="page-title">${t}</strong><span class="arrow" aria-hidden="true">${i(`arrow`)}</span></span> <span class="page-copy"><span>${n}</span></span></button>`}};customElements.define(`managed-admin-home`,Sr);var Cr=class extends b{static properties={_page:{state:!0},_history:{state:!0},_total:{state:!0},_error:{state:!0},_filter:{state:!0},_query:{state:!0},_repo:{state:!0},_actor:{state:!0},_options:{state:!0}};static styles=[_(Hn),_(a)];constructor(){super(),this._history=null,this._total=0,this._searchTimer=null,this._error=null,this._page=1,this._filter=`all`,this._query=``,this._repo=``,this._actor=``,this._options={repos:[],users:[]},this._onActorFilter=e=>{let t=e.detail?.actor;if(typeof t!=`string`)return;let n=t.startsWith(`user:`)||t.startsWith(`legacy:`);this._query=n?``:t,this._filter=`all`,this._repo=``,this._actor=n?t:``,this._load()}}connectedCallback(){super.connectedCallback(),document.addEventListener(`managed-history-filter`,this._onActorFilter),this._load()}disconnectedCallback(){clearTimeout(this._searchTimer),document.removeEventListener(`managed-history-filter`,this._onActorFilter),super.disconnectedCallback()}async _load(e=1){clearTimeout(this._searchTimer),this._error=null;let t=this._filter,n=this._query.trim(),r=this._actor,i=this._repo,a=`history:${JSON.stringify([e,t,n,i,r])}`;await this._loadCollection(a,`history`,a=>un(a,e,t,n,i,r),e=>{this._history=e.history,this._total=e.total,this._page=e.page,this._options=e.filters??{repos:[],users:[]}})}_search(e){this._query=e,clearTimeout(this._searchTimer),this._loadRequest?.abort(),this._loadRequest=null,this._loading=!0,this._searchTimer=setTimeout(()=>{this._load()},250)}_setRepo(e){return this._repo=e,this._load()}_setActor(e){return this._actor=e,this._load()}_clearContext(){return this._repo=``,this._actor=``,this._load()}_contextFilters(){let e=this._options.repos,t=this._options.users??[],n=[{value:``,label:`All repositories`,special:!0,reset:!0},...this._repo&&!e.includes(this._repo)?[{value:this._repo,label:this._repo}]:[],...e.map(e=>({value:e,label:e}))];return v`<repository-selector label="Filter history by repository" .options="${n}" .value="${this._repo}" @repository-change="${e=>{this._setRepo(e.detail.value)}}"></repository-selector><user-selector label="Filter history by user" reset-label="All users" placeholder="${this._actor?`Selected user`:`All users`}" .users="${t}" .value="${this._actor}" @user-change="${e=>{this._setActor(e.detail.value)}}"></user-selector><button type="button" class="btn" aria-label="Clear repository and user filters" ?disabled="${!this._repo&&!this._actor}" @click="${()=>{this._clearContext()}}">Clear selection</button>`}render(){let e=this._history??[],t=this._page,n=(t-1)*100;return v`<div class="wrap">${r(`manage-history`,this._role,this.allowShare)}<h1 class="sr-only">History</h1><div class="page-intro"><p class="intro">${this._role===`admin`?`Uploads, builds, access changes, repository changes, deletions, and triage.`:`Bundle, report, and triage history within your team access.`}</p><span class="result-count">${this._history?this._total:`…`} entries</span></div><div class="toolbar" role="search"><input type="search" maxlength="500" aria-label="Search history" placeholder="Search history…" .value="${this._query}" @input="${e=>this._search(e.target.value)}"> <select aria-label="Filter history by type" .value="${this._filter}" @change="${e=>{this._filter=e.target.value,this._load()}}"><option value="all">All activity</option><option value="triage">Triage</option><option value="visibility">Visibility</option><option value="upload">Uploads and builds</option><option value="repository">${this._role===`admin`?`Repositories`:`Assignments`}</option>${this._role===`admin`?v`<option value="access">Access</option>`:y}<option value="delete">Deletions</option></select> ${this._contextFilters()} <button type="button" class="btn" ?disabled="${this._loading}" @click="${()=>this._load(t)}">Refresh</button></div>${this._error?v`<p class="msg error" role="alert">Couldn’t load history: ${this._error} <button type="button" class="btn" @click="${()=>this._load()}">Retry</button></p>`:y}<div class="manage-list" aria-busy="${this._loading}">${this._history==null?this._error?y:x(`Loading history…`):e.length===0?v`<div class="history"><p class="empty">${this._query.trim()||this._filter!==`all`||this._repo||this._actor?`No activity matches your filters.`:`No history available yet.`}</p></div>`:v`<div class="history" aria-label="Workspace history"><div class="history-head" aria-hidden="true"><span>Type</span><span>Activity</span><span>Repository / report / finding</span><span>Time</span></div>${e.map(e=>this._row(e))}</div>`}</div>${this._total>100?v`<nav class="pagination" aria-label="History pages"><span role="status">${n+1}–${Math.min(n+100,this._total)} of ${this._total} entries</span><button type="button" class="btn" ?disabled="${this._loading||t===1}" @click="${()=>this._changePage(t-1)}">Previous</button><span>Page ${t} of ${Math.ceil(this._total/100)}</span><button type="button" class="btn" ?disabled="${this._loading||n+100>=this._total}" @click="${()=>this._changePage(t+1)}">Next</button></nav>`:y}</div>`}async _changePage(e){await this._load(e),await this.updateComplete,this.renderRoot.querySelector(`.manage-list`)?.scrollTo({top:0})}_row(e){let t=[e.repo??e.repository,e.report,e.finding].filter(Boolean).join(` · `),n=e.actor??e.user??`Unknown user`,r=e.action??`updated workspace data`;return v`<div class="row"><span class="${`kind ${e.kind??``}`}">${e.kind??`activity`}</span><span class="activity-description" data-tooltip-truncated data-tooltip="${`${n} ${r}`}"><strong class="actor">${n}</strong> <span class="action">${r}</span></span><span class="detail" data-tooltip-truncated data-tooltip="${t}">${t||`—`}</span><span class="history-time">${wr(e.at)}</span></div>`}};customElements.define(`managed-admin-history`,Cr);function wr(e){if(e==null||e===``)return v`<span>Unknown</span>`;let t=typeof e==`number`?e:Number(e);if(!Number.isFinite(t))return v`<span>Unknown</span>`;let n=new Date(t);return Number.isNaN(n.getTime())?v`<span>Unknown</span>`:v`<time datetime="${n.toISOString()}">${n.toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`})}</time><span>${n.toLocaleTimeString(void 0,{hour:`numeric`,minute:`2-digit`})}</span>`}function Tr(e){if(e==null||e===``)return`Unknown`;let t=typeof e==`number`?e:Number(e);return Number.isFinite(t)&&!Number.isNaN(new Date(t).getTime())?`Last seen ${new Date(t).toLocaleString()}`:`Unknown`}function Er(e){return e?.lastActivityAt??e?.lastActivity??e?.lastWriteAt??e?.lastActiveAt}var Dr=class extends b{static properties={_query:{state:!0},_users:{state:!0},_teams:{state:!0},_error:{state:!0}};static styles=[_(Un),_(a)];constructor(){super(),this._users=null,this._query=``,this._teams=null,this._error=null}connectedCallback(){super.connectedCallback(),this._load()}async _load(){this._error=null,await this._loadCollection(`users`,`users`,e=>Promise.all([dn(e),Pn(e)]),([e,t])=>{this._users=e,this._teams=Array.isArray(t?.teams)?t.teams:[]})}_filteredUsers(){let e=this._query.trim().toLocaleLowerCase();return(this._users??[]).filter(t=>[t.name,t.login,t.role,...(this._teams??[]).filter(e=>e.members?.some(e=>e.userId===t.id)).map(e=>e.name)].filter(Boolean).join(` `).toLocaleLowerCase().includes(e))}render(){let e=this._filteredUsers();return v`<div class="wrap">${r(`admin-users`,this._role,this.allowShare)}<h1 class="sr-only">Users</h1><div class="page-intro"><p class="intro">Manage workspace access and roles.</p></div><div class="collection-toolbar" role="search"><input type="search" aria-label="Search users" placeholder="Search by name, username, or team…" .value="${this._query}" @input="${e=>{this._query=e.target.value}}"><span class="result-count" role="status">${this._users&&this._query.trim()?`${e.length} matching out of `:``}${this._users?.length??`…`} users</span></div>${this._error?v`<p class="msg error" role="alert">Couldn't load users: ${this._error}</p>`:y}<div class="manage-list" aria-busy="${this._loading}">${this._users==null?this._error?y:x(`Loading users…`):this._list(e)}</div></div>`}_list(e){return this._users.length===0?v`<p class="msg">No users yet.</p>`:e.length===0?v`<div class="empty"><strong>No matching users</strong><p>Try another name, username, or team.</p></div>`:v`<div class="directory"><div class="list-head" aria-hidden="true"><span>Account</span><span>Team access</span><span>Last seen</span><span>Last activity</span><span>Role</span><span></span></div><ul class="users">${e.map(e=>this._row(e))}</ul></div>${this._users.some(e=>e.id===this._me)?v`<p class="self-note ui-hint">Your own role can only be changed by another admin.</p>`:y}`}_row(e){let t=e.id===this._me,n=(this._teams??[]).flatMap(t=>{let n=t.members?.find(t=>t.userId===e.id);return n==null?[]:[{team:t,member:n}]});return v`<li><span class="person">${vr(e.id,e.login)} <span class="who"><span class="name"><span class="name-text">${e.name||e.login}</span>${t?v`<span class="you">You</span>`:y}</span> <span class="login">@${e.login}</span> </span></span><span class="memberships">${De(e.role,`manage`)?v`<span class="team-access"><strong class="team-access-role">${e.role===`admin`?`All reports`:`Owned and team reports`}</strong><span class="team-perms"><span class="permission-granted">+ Deps</span><span class="permission-granted">+ Security</span></span></span>`:n.length===0?v`<span class="no-team">No team access</span>`:n.map(({team:e,member:t})=>v`<span class="team-access"><strong>${i(`team`)}<span>${e.name}</span></strong><span class="team-perms">${[`dependencies`,`security`].map(e=>v`<span class="${t[e]===!0?`permission-granted`:`permission-denied`}">${t[e]===!0?`+`:`−`} ${e===`dependencies`?`Deps`:`Security`}</span>`)}</span></span>`)} </span><span class="last-seen" aria-label="${Tr(e.lastSeenAt)}">${wr(e.lastSeenAt)}</span> <button type="button" class="activity-link" aria-label="${`Show activity by ${e.login}`}" @click="${()=>this._showActivity(e.id)}"><span class="last-activity" aria-label="${`Last activity ${Tr(Er(e)).replace(/^Last seen /u,``)}`}">${wr(Er(e))}</span></button> <span class="access"><select class="role" ?disabled="${t}" aria-label="${`Change ${e.login}\u2019s role`}" aria-description="${xr[e.role]??``}" @change="${t=>this._changeRole(e,t.target.value,t.target)}">${Ee.map(t=>v`<option value="${t}" ?selected="${t===e.role}">${br[t]}</option>`)}</select> </span><span class="view-as">${t?y:v`<button type="button" class="icon-btn" aria-label="${`View as ${e.login}`}" data-tooltip="See the app as this user" @click="${t=>{this._viewAs(e,t.currentTarget)}}">${i(`show`)}</button>`}</span></li>`}async _viewAs(e,t){t.disabled=!0;try{await ve(e.id,this._csrf)}catch(n){t.disabled=!1,this.appState.notify(`Couldn't view as @${e.login}: ${n?.message??n}`)}}async _changeRole(e,t,n){let r=e.role;if(t!==r){try{await this.appState.mutate(()=>fn(e.id,t,this._csrf),[`users`,`teams`,`reports`,`history`]),e.role=t,await this._load()}catch(e){console.warn(`admin: set role failed:`,e),n.value=r}this.requestUpdate()}}_showActivity(e){document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage-history`,actor:`user:${e}`},bubbles:!0,composed:!0}))}};customElements.define(`managed-admin-users`,Dr);var Or=i(`repo`),kr=e=>!e||e.mode===`exclude`&&e.paths.length===0?{mode:`all`,paths:[]}:{mode:e.mode,paths:[...e.paths].toSorted()},Ar=e=>e.mode===`all`?{mode:`exclude`,paths:[]}:{mode:e.mode,paths:e.paths},jr=class extends b{static properties={_publicRepoOpen:{state:!0},_publicRepository:{state:!0},_publicRepoError:{state:!0},_addingPublic:{state:!0},_data:{state:!0},_error:{state:!0},_actionError:{state:!0},_scope:{state:!0},_showAll:{state:!0},_query:{state:!0},_organization:{state:!0},_loading:{state:!0},_busy:{state:!0},_connectingApp:{state:!0},_detail:{state:!0},_aliases:{state:!0},_impact:{state:!0},_impactLoading:{state:!0},_removeOpen:{state:!0},_acknowledge:{state:!0},_deleteTriage:{state:!0},_confirmName:{state:!0},_reviewDraft:{state:!0}};static styles=[_(Wn),_(a)];constructor(){super(),this._publicRepoOpen=!1,this._publicRepository=``,this._publicRepoError=null,this._addingPublic=!1,this._data=null,this._error=null,this._actionError=null,this._scope=`connected`,this._showAll=!1,this._query=``,this._organization=null,this._loading=!0,this._busy=null,this._connectingApp=!1,this._detail=null,this._aliases=!1,this._impact=null,this._impactLoading=!1,this._impactFresh=!1,this._removeOpen=!1,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName=``,this._impactRequest=null}connectedCallback(){super.connectedCallback(),this._load()}disconnectedCallback(){super.disconnectedCallback(),this._impactRequest?.abort()}_repositoryKey(){return`repos:${JSON.stringify([this._scope,this._showAll])}`}async _load(e=!1){this._error=null;let{_scope:t,_showAll:n}=this;await this._loadCollection(this._repositoryKey(),`repositories`,r=>pn(t,n,e,r),e=>{this._data=e,this._organization=this._repositoryChoices().activeFacet})}_open(e){this._impactRequest?.abort(),this._publicRepoOpen=!1,this._scope=e,this._showAll=!1,this._query=``,this._organization=null,this._detail=null,this._aliases=!1,this._impact=null,this._removeOpen=!1,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName=``,this._data=null,this._actionError=null,this._load()}_setShowAll(e){this._showAll=e,this._organization=null,this._data=null,this._load()}_search(e){this._query=e}_repositoryChoices(){let e=(this._data?.repositories??[]).map(e=>({value:e.id,label:e.fullName,repo:e}));return Ie(e,this._query,this._organization,{includeSingletonOrganizations:!0})}_back(e=null){return v`<div class="breadcrumb"><button type="button" class="breadcrumb-manage" @click="${()=>{document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage`},bubbles:!0,composed:!0}))}}">Manage</button> <span class="breadcrumb-separator" aria-hidden="true">›</span> <button type="button" class="breadcrumb-manage" aria-label="Back to repositories" @click="${()=>{this._detail?(this._impactRequest?.abort(),this._detail=null,this._actionError=null):this._aliases?this._aliases=!1:this._open(`connected`)}}">Repositories</button> <span class="breadcrumb-separator" aria-hidden="true">›</span> ${e?v`<h1 class="breadcrumb-current">${e}</h1>`:y}</div>`}_openDetail(e){this._detail=e,this._reviewDraft=null,this._actionError=null,this._impact=this.appState.read(`repo-impact:${e.id}`)??null,this._impactFresh=!1,this._removeOpen=!1,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName=``,this._impactLoading=!0,this._impactRequest?.abort();let t=new AbortController;this._impactRequest=t,this.appState.load(`repo-impact:${e.id}`,`repository data`,t=>vn(e.id,t),{signal:t.signal,apply:e=>{this._impact=e}}).then(e=>(t.signal.aborted||(this._impactFresh=!0),e)).catch(e=>{!t.signal.aborted&&e?.name!==`AbortError`&&!this._impact&&(this._actionError=`Couldn't load repository data: ${e?.message??e}`)}).finally(()=>{this._impactRequest===t&&(this._impactLoading=!1)})}render(){if(this._detail)return this._detailPage(this._detail);if(this._aliases)return this._aliasesPage();let e=this._scope===`connected`,t=e?`Repositories`:`Add ${this._scope} repository`,n=this._repositoryChoices();return v`<div class="wrap">${r(`manage-repos`,this._role,this.allowShare)} ${e?v`<h1 class="sr-only">${t}</h1>`:this._back(t)}<div class="page-intro"><p class="intro">${e?`Manage connected repositories and their settings.`:this._scope===`installed`?this._showAll?`Showing all repositories the GitHub App can read.`:`Showing installed repositories you can access on GitHub.`:`Choose a public repository your GitHub account is involved with.`}</p>${e?v`<div class="repository-actions"><button type="button" class="btn" @click="${()=>this._open(`installed`)}">${this._accessIcon(`private`)} Add installed repository</button> <button type="button" class="btn" @click="${()=>this._open(`public`)}">${this._accessIcon(`public`)} Add your public repository</button> ${this._role===`admin`&&this._data?.canAddAnyPublicRepository?v`<button type="button" class="btn" aria-expanded="${this._publicRepoOpen}" @click="${()=>this._openPublicRepository()}">${this._accessIcon(`public`)} Add a public repository</button>`:y}</div>`:y}</div>${!e&&this._scope===`installed`?v`<div class="access-note"><p class="ui-hint">Installed repositories are readable through the GitHub App. Install it on a repository or organization to make it available here.</p><span class="access-action">${this._data?.installUrl?v`<a class="btn" href="${this._data.installUrl}" target="_blank" rel="noopener noreferrer">Configure GitHub access</a>`:v`<button type="button" class="btn" disabled="disabled">Configure GitHub access</button>`}</span></div>`:y}<div class="toolbar"><label class="search"><input type="search" aria-label="${e?`Search connected repositories`:`Search ${this._scope} repositories`}" placeholder="Search by repository or owner…" .value="${this._query}" @input="${e=>this._search(e.target.value)}"></label> ${this._scope===`installed`?v`<label class="show-all"><input type="checkbox" role="switch" .checked="${this._showAll}" @change="${e=>this._setShowAll(e.target.checked)}"><span>Show all</span></label><label class="show-all-paper"><input type="checkbox" .checked="${this._showAll}" @change="${e=>this._setShowAll(e.target.checked)}"><span>Show all</span></label>`:y} ${e?v`<span class="result-count" role="status">${this._data&&(this._query.trim()||n.activeFacet!=null)?`${n.count} ${n.count===1?`repository`:`repositories`} out of `:``}${this._data?.connectedCount??`…`} connected</span>`:v`<button type="button" class="btn" ?disabled="${this._loading}" @click="${()=>{this._load(!0)}}">Refresh</button>`}</div>${e&&this._publicRepoOpen&&this._role===`admin`&&this._data?.canAddAnyPublicRepository?this._publicRepositoryForm():y} ${this._actionError?v`<p class="msg error" role="alert">${this._actionError}</p>`:y} ${this._error?v`<p class="msg error" role="alert">Couldn't load repositories: ${this._error}</p><button type="button" class="btn" @click="${()=>{this._load()}}">Try again</button>`:y} ${!e&&this._data?v`<p class="repository-count" role="status">${n.count}${n.count===n.total?``:` of ${n.total}`} ${n.total===1?`repository`:`repositories`}</p>`:y}<div class="manage-list"><div aria-busy="${this._loading}">${this._body(n)}</div>${e&&this._role===`admin`?v`<div class="repository-pages"><button type="button" class="btn" @click="${()=>{this._publicRepoOpen=!1,this._actionError=null,this._aliases=!0}}">Aliases</button> <button type="button" class="btn" @click="${()=>document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage-repo-risk`},bubbles:!0,composed:!0}))}">Risk</button></div>`:y}</div></div>`}_aliasesPage(){return v`<div class="wrap">${r(`manage-repos`,this._role,this.allowShare)} ${this._back(`Aliases`)}<div class="manage-list has-intro"><managed-repository-aliases .session="${this.session}" .repositories="${this._data?.repositories}"></managed-repository-aliases></div></div>`}_body(e){return this._data?v`${this._data.tokenMissing&&!this._showAll&&this._scope!==`connected`?v`<p class="msg">Log out and back in to refresh your GitHub membership access.</p>`:y}<div class="repository-browser">${e.showFacets?v`<nav class="organization-list" aria-label="Filter by organization"><button type="button" class="organization" aria-pressed="${e.activeFacet==null}" @click="${()=>{this._organization=null}}"><span class="organization-name">All organizations</span><span class="organization-count">${e.total}</span></button> ${e.facets.map(t=>v`<button type="button" class="organization" aria-pressed="${e.activeFacet===t.value}" @click="${()=>{this._organization=t.value}}"><span class="organization-name" data-tooltip-truncated data-tooltip="${t.name}">${t.name}</span><span class="organization-count">${t.count}</span></button>`)}</nav>`:y}<div class="repo-results">${e.sections.map(e=>v`<section class="repo-group" aria-label="${e.label??`Repositories`}">${e.label?v`<h2 class="owner-head"><span class="owner-icon" aria-hidden="true">${e.label[0]??`?`}</span>${e.label}</h2>`:y}<ul class="repos">${e.options.map(t=>this._row(t.repo,e.organization?t.name:t.label))}</ul></section>`)} ${e.count?y:v`<div class="empty"><strong>${e.total?`No matching repositories`:this._scope===`connected`?`No connected repositories yet`:`No ${this._scope} repositories available`}</strong><p>${e.total?`Try a different search or organization.`:this._scope===`connected`?`Add an installed or public repository to get started.`:this._scope===`installed`?this._showAll?`Install the GitHub App, then refresh this list.`:`No installed repositories match your GitHub access. Turn on Show all to browse every installation.`:`Public repositories associated with your GitHub account will appear here.`}</p></div>`}</div></div>`:this._error?y:x(`Loading repositories…`)}_openPublicRepository(){this._publicRepoOpen=!0,this._publicRepoError=null,this.updateComplete.then(()=>this.renderRoot?.querySelector(`#public-repository`)?.focus())}_publicRepositoryForm(){return v`<form class="public-repository-form" aria-label="Add a public repository" @submit="${e=>{e.preventDefault(),this._addPublicRepository()}}"><label class="confirm-field" for="public-repository"><span>Public GitHub repository</span> <input id="public-repository" class="confirm-name" type="text" placeholder="owner/repo or https://github.com/owner/repo" autocomplete="off" required .value="${this._publicRepository}" ?disabled="${this._addingPublic}" @input="${e=>{this._publicRepository=e.target.value}}"></label><div class="dialog-actions"><button type="button" class="btn" ?disabled="${this._addingPublic}" @click="${()=>{this._publicRepoOpen=!1}}">Cancel</button><button type="submit" class="btn" ?disabled="${this._addingPublic||!this._publicRepository.trim()}">${this._addingPublic?`Adding…`:`Add repository`}</button></div>${this._publicRepoError?v`<p class="msg error" role="alert">${this._publicRepoError}</p>`:y}</form>`}async _addPublicRepository(){if(!this._addingPublic&&this._publicRepository.trim()){this._addingPublic=!0,this._publicRepoError=null;try{await this.appState.mutate(()=>_n(this._publicRepository.trim(),this._csrf),[`repos`,`reports`,`bundles`,`teams`,`users`,`history`,`scan-sources`]),this._publicRepoOpen=!1,this._publicRepository=``,await this._load()}catch(e){this._publicRepoError=e?.message??String(e)}finally{this._addingPublic=!1}}}_row(e,t){let n=`${this._accessLabel(e)}${this._scope===`connected`&&e.active===!1?` · Deactivated`:``}`,r=v`${Or}<span class="repo-copy"><span class="repo-name">${t}</span><span class="repo-meta">${n}</span></span>`;return this._scope===`connected`?v`<li class="repo-item"><button type="button" class="repo-row" aria-label="${`Manage ${e.fullName}`}" @click="${()=>this._openDetail(e)}">${r}<span class="repo-code-slot" aria-hidden="true"></span><svg class="arrow" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" aria-hidden="true"><path d="m6 4 4 4-4 4"/></svg></button>${e.active===!1?y:v`<a class="repo-code" href="${h({view:`repository-code`,repoId:e.id})}" aria-label="${`Open ${e.fullName}'s code`}" @click="${t=>this._openCode(t,e)}">${i(`code`)}</a>`}</li>`:v`<li class="repo-row">${r} ${e.selected?v`<span class="connected"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="m3 8 3 3 7-7"/></svg>Connected</span>`:e.private&&!e.installed?v`<span class="repo-meta">Needs App access</span>`:v`<button type="button" class="btn" aria-label="${`Add ${e.fullName}`}" ?disabled="${this._busy!=null}" @click="${()=>{this._setActive(e,!0)}}">${this._busy===e.id?`Adding…`:`Add`}</button>`}</li>`}_openCode(e,t){e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||(e.preventDefault(),this.dispatchEvent(new CustomEvent(`managed-repository-code-open`,{detail:{repoId:t.id},bubbles:!0,composed:!0})))}_accessLabel(e){let t=e.visibility===`public`?`Public`:e.visibility===`internal`?`Internal`:e.private?`Private`:null,n=e.installed?`GitHub App`:`GitHub`;return t?`${t} \xB7 ${n}`:n}_connectAppButton(e){return e.installed?y:v`<button type="button" class="btn connect-app" aria-label="${`Connect GitHub App to ${e.fullName}`}" ?disabled="${this._busy!=null}" @click="${()=>{this._connectApp(e)}}">${this._connectingApp&&this._busy===e.id?`Connecting…`:`Connect GitHub App`}</button>`}async _connectApp(e){if(!(this._busy!=null||e.installed)){this._busy=e.id,this._connectingApp=!0,this._actionError=null;try{let t=await this.appState.mutate(()=>yn(e.id,this._csrf),[`repos`,`history`,`scan-sources`]);if(!this.isConnected)return;if(!t.connected){globalThis.location.assign(t.installUrl);return}this._detail?.id===e.id&&(this._detail={...this._detail,installed:!0}),this._data&&={...this._data,repositories:this._data.repositories.map(t=>t.id===e.id?{...t,installed:!0}:t)},await this._load()}catch(t){this._actionError=`Couldn't connect ${e.fullName}: ${t?.message??t}`}finally{this._busy=null,this._connectingApp=!1}}}_detailPage(e){let t=e.active!==!1,n=this._impact?.reports??[],i=this._impact?.bundles??[];return v`<div class="wrap">${r(`manage-repos`,this._role,this.allowShare)}<div class="head">${this._back()}<h1>${e.fullName}</h1></div><p class="intro ui-hint">Repository settings and stored data.</p>${this._actionError?v`<p class="msg error" role="alert">${this._actionError}</p>`:y}<div class="manage-list repository-detail"><section class="section" aria-label="Repository connection"><h2>Connection</h2><div class="settings-row"><div class="settings-copy"><strong>${this._accessLabel(e)}</strong><p>${t?`Active for new scans and uploads.`:`Deactivated. Stored reports and bundles are retained.`}</p></div><span class="${`status-line ${t?``:`inactive`}`}">${t?`Active`:`Deactivated`}</span> ${this._connectAppButton(e)} ${e.htmlUrl?v`<a class="btn" href="${e.htmlUrl}" target="_blank" rel="noopener noreferrer">View on GitHub</a>`:y}</div><div class="settings-row"><div class="settings-copy"><strong>${t?`Deactivate repository`:`Reactivate repository`}</strong><p>${t?`Pause new scans while preserving all stored data and attachments.`:`Make this repository available for new scans and bundle attachments again.`}</p></div><button type="button" class="btn" ?disabled="${this._busy!=null}" @click="${()=>{this._setActive(e,!t)}}">${this._busy===e.id&&!this._connectingApp?t?`Deactivating…`:`Reactivating…`:t?`Deactivate`:`Reactivate`}</button></div></section>${this._dependencyReviewSection(e)}<section class="data-section" aria-label="Stored repository data"><h2>Stored data</h2><div class="dialog-data" aria-busy="${this._impactLoading}">${[[`Reports`,n],[`Bundles`,i]].map(([t,n])=>v`<section><h3>${t} (${this._impact==null?`…`:n.length})</h3>${this._impactLoading&&this._impact==null?v`<p class="data-empty" role="status">Loading ${t.toLowerCase()}…</p>`:this._impact==null?v`<p class="data-empty">Attached data could not be loaded.</p><button type="button" class="btn" @click="${()=>this._openDetail(e)}">Try again</button>`:n.length>0?v`<ul>${n.map(e=>v`<li>${e.filename}${e.repoDirectory?` \xB7 ${e.repoDirectory}`:y}</li>`)}</ul>`:v`<p class="data-empty">No ${t.toLowerCase()} attached.</p>`}</section>`)}</div></section><section class="section" aria-label="Permanent repository removal"><h2>Permanent removal</h2><div class="settings-row"><div class="settings-copy"><strong>Delete repository and stored data</strong><p>Deactivation is reversible. Permanent removal deletes this repository’s attached reports and bundles; it cannot be undone.</p></div><button type="button" class="btn danger" ?disabled="${this._busy!=null||this._impactLoading||!this._impactFresh||this._impact==null}" @click="${()=>{this._removeOpen=!0,this._acknowledge=!1,this._deleteTriage=!1,this._confirmName=``}}">Remove permanently</button></div></section></div>${this._removeOpen&&this._impact!=null&&!this._impactLoading?this._removeDialog(e,n,i):y}</div>`}_dependencyReviewSection(e){let t=this._data?.reviewedDependencies===!0,n=e.dependencyReview??{enabled:!1,required:1,since:null},r=kr(n.lockfiles),i={required:String(n.required),since:n.since??``,scope:r,adding:``,...this._reviewDraft},a=i.required!==String(n.required)||!t&&i.since.trim()!==(n.since??``)||JSON.stringify(i.scope)!==JSON.stringify(r),o=(e,t,n,r)=>this._reviewSetting(e,t,n,r),s=this._busy!=null;return v`<section class="section" aria-label="Dependency review"><div class="section-head"><h2>Dependency review</h2><mode-switch label="${n.enabled?`On`:`Off`}" accessible-label="Review dependencies" .checked="${n.enabled}" .disabled="${s}" @click="${()=>{s||this._saveDependencyReview(e,o(!n.enabled,n.required,n.since))}}"></mode-switch></div>${n.enabled?v`<form class="settings-row dependency-review-settings" aria-label="Dependency review settings" @submit="${t=>{t.preventDefault(),this._saveDependencyReview(e,o(!0,Number(i.required),i.since.trim().toLowerCase()||null,Ar(i.scope)))}}"><label><span>Reviews each version needs</span><input type="number" min="1" max="10" required .value="${i.required}" ?disabled="${s}" @input="${e=>{this._reviewDraft={...i,required:e.target.value}}}"></label> ${t?y:v`<label class="dependency-review-since"><span>Reviewed since commit (optional)</span><input type="text" placeholder="Full commit id" autocomplete="off" spellcheck="false" pattern="[0-9a-fA-F]{40}" .value="${i.since}" ?disabled="${s}" @input="${e=>{this._reviewDraft={...i,since:e.target.value}}}"></label>`} ${this._lockfileScope(e,i,s)} <button type="submit" class="btn" ?disabled="${s||!a}">Save</button> ${Array.isArray(e.reviewTeams)&&e.reviewTeams.length===0?v`<p class="dependency-review-hint is-warning" role="status">No team that reviews dependencies has this repository, so its pull requests show no review. Add it to such a team, or turn dependency review on for a team that has it.</p>`:t||i.since.trim()?v`<p class="dependency-review-hint">${t?`Versions this server’s reviewed dependencies pass need no reviews here; a patched one passes by them alone.`:`Versions the repository’s lockfiles locked at this commit need no review.`}</p>`:y}</form>`:y}</section>`}_lockfileScope(e,t,n){let{mode:r,paths:i}=t.scope,a=r===`all`?{status:`ready`,paths:[]}:this._lockfilesFor(e),o=e=>{this._reviewDraft={...t,scope:e}},s=[...new Set([...a.paths,...i])].toSorted(),c=()=>{let e=t.adding.trim().replace(/^\.?\/+/u,``);e&&(this._reviewDraft={...t,adding:``,scope:{mode:r,paths:[...new Set([...i,e])].toSorted()}})};return v`<fieldset class="dependency-review-lockfiles" ?disabled="${n}"><legend>Lockfiles reviewed</legend><select aria-label="Lockfiles reviewed" .value="${r}" @change="${e=>o({mode:e.target.value,paths:i})}"><option value="all">Every lockfile</option><option value="exclude">All but those selected</option><option value="include">Only those selected</option></select> ${r===`all`?y:v`${a.status===`loading`?v`<p class="dependency-review-hint" role="status">Reading the default branch’s lockfiles…</p>`:a.status===`error`?v`<p class="dependency-review-hint is-warning" role="alert">Its lockfiles couldn’t be read (${a.error}); name them below.</p>`:y} ${s.length>0?v`<ul class="dependency-review-lockfile-list">${s.map(e=>v`<li><label><input type="checkbox" .checked="${i.includes(e)}" @change="${t=>o({mode:r,paths:t.target.checked?[...i,e].toSorted():i.filter(t=>t!==e)})}"> <code>${e}</code>${a.status===`ready`&&!a.paths.includes(e)?v`<span>${e.endsWith(`/`)?`every lockfile under it`:`not on the default branch`}</span>`:y}</label></li>`)}</ul>`:a.status===`ready`?v`<p class="dependency-review-hint">Its default branch has no lockfile its review reads.</p>`:y} <label class="dependency-review-lockfile-add"><span>Another lockfile, or a directory ending in /</span> <input type="text" placeholder="examples/" autocomplete="off" spellcheck="false" .value="${t.adding}" @input="${e=>{this._reviewDraft={...t,adding:e.target.value}}}" @keydown="${e=>{e.key===`Enter`&&(e.preventDefault(),c())}}"></label> <button type="button" class="btn" ?disabled="${!t.adding.trim()}" @click="${c}">Add</button>`}</fieldset>`}_lockfilesFor(e){if(this._lockfileRead?.repoId!==e.id){let t={repoId:e.id,status:`loading`,paths:[]};this._lockfileRead=t,gn(e.id).then(e=>Object.assign(t,{status:`ready`,paths:e}),e=>Object.assign(t,{status:`error`,error:e?.message??String(e)})).finally(()=>{this._lockfileRead===t&&this.requestUpdate()})}return this._lockfileRead}_reviewSetting(e,t,n,r){return{...this._data?.reviewedDependencies===!0?{enabled:e,required:t}:{enabled:e,required:t,since:n},...r?{lockfiles:r}:{}}}async _saveDependencyReview(e,t){if(this._busy==null){this._busy=e.id,this._actionError=null;try{let n=await this.appState.mutate(()=>hn(e.id,t,this._csrf),[`repos`]);if(globalThis.dispatchEvent?.(new Event(`dependency-review-changed`)),!this.isConnected)return;this._detail?.id===e.id&&(this._detail={...this._detail,dependencyReview:n}),this._data&&={...this._data,repositories:this._data.repositories.map(t=>t.id===e.id?{...t,dependencyReview:n}:t)},this._reviewDraft=null}catch(t){this._actionError=`Couldn't save ${e.fullName}'s dependency review: ${t?.message??t}`}finally{this._busy=null}}}_removeDialog(e,t,n){let r=t.length>0||n.length>0,i=this._canRemove(e);return v`<div class="dialog-backdrop" role="presentation" @click="${e=>{e.target===e.currentTarget&&(this._removeOpen=!1)}}"><section class="${`dialog ${r?``:`small`}`}" role="dialog" aria-modal="true" aria-labelledby="remove-repo-title"><h2 id="remove-repo-title">Remove ${e.fullName} permanently?</h2><p class="dialog-copy">${r?`This destructive action will remove the repository and the stored data listed below. Deactivation keeps all of it.`:`This repository has no attached reports or bundles. Permanent removal deletes its connection record.`}</p>${r?v`<div class="dialog-data"><section><h3>Reports to delete (${t.length})</h3><ul>${t.map(e=>v`<li>${p(e.filename)}${e.repoDirectory?` \xB7 ${e.repoDirectory}`:y}</li>`)}</ul></section><section><h3>Bundles to delete (${n.length})</h3><ul>${n.map(e=>v`<li>${e.filename}</li>`)}</ul></section></div>`:y} <label class="confirm-line"><input type="checkbox" .checked="${this._acknowledge}" @change="${e=>{this._acknowledge=e.target.checked}}"><span>I understand this permanently deletes the repository connection${r?`, reports, and bundles`:``}.</span></label> ${(this._impact?.triageCount??0)>0?v`<label class="confirm-line"><input type="checkbox" .checked="${this._deleteTriage}" @change="${e=>{this._deleteTriage=e.target.checked}}"><span>Also delete ${this._impact.triageCount} triage entr${this._impact.triageCount===1?`y`:`ies`} belonging only to this repository.</span></label>`:y} ${r?v`<label class="confirm-field"><span>Type <strong>${e.fullName}</strong> to confirm.</span><input class="confirm-name" type="text" autocomplete="off" .value="${this._confirmName}" @input="${e=>{this._confirmName=e.target.value}}"></label>`:y}<div class="dialog-actions"><button type="button" class="btn" @click="${()=>{this._removeOpen=!1}}">Cancel</button><button type="button" class="btn danger" ?disabled="${!i}" @click="${()=>{this._remove(e)}}">${this._busy===e.id?`Removing…`:`Remove permanently`}</button></div></section></div>`}_accessIcon(e){return e===`private`?v`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="7" width="10" height="7" rx="1"/><path d="M5 7V5a3 3 0 0 1 6 0v2"/></svg>`:v`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="6"/><path d="M2.5 8h11M8 2c1.5 1.7 2.2 3.7 2.2 6S9.5 12.3 8 14c-1.5-1.7-2.2-3.7-2.2-6S6.5 3.7 8 2Z"/></svg>`}async _setActive(e,t){if(this._busy==null){this._busy=e.id,this._actionError=null;try{if(await this.appState.mutate(()=>mn(e.id,t,this._csrf),[`repos`,`reports`,`bundles`,`teams`,`users`,`history`]),!this.isConnected)return;this._detail?.id===e.id&&(this._detail={...this._detail,active:t}),this._data&&={...this._data,repositories:this._data.repositories.map(n=>n.id===e.id?{...n,active:t}:n)},await this._load()}catch(n){let r=t?e.active===!1?`reactivate`:`add`:`deactivate`;this._actionError=`Couldn't ${r} ${e.fullName}: ${n?.message??n}`}finally{this._busy=null}}}_canRemove(e){return this._busy!=null||this._impactLoading||!this._impactFresh||this._impact?.repoId!==e.id||!this._acknowledge?!1:!(this._impact.reports.length>0||this._impact.bundles.length>0)||this._confirmName===e.fullName}async _remove(e){if(this._canRemove(e)){this._busy=e.id,this._actionError=null;try{await this.appState.mutate(()=>bn(e.id,e.fullName,this._deleteTriage,this._csrf),[`repos`,`repo-impact`,`reports`,`report-preview`,`bundles`,`teams`,`users`,`history`,`scan-sources`]),this._removeOpen=!1,this._detail=null,this._impact=null,await this._load()}catch(t){this._actionError=`Couldn't remove ${e.fullName}: ${t?.message??t}`}finally{this._busy=null}}}};customElements.define(`managed-admin-repos`,jr);function Mr(e){return[{value:null,label:`No repository`,special:!0},...e.map(e=>({value:e.repoId,label:e.fullName}))]}function Nr(e,t,n,r,i){let a=v`<span class="ui-hint">${e}: </span><span class="location-metadata-value" data-tooltip-truncated data-tooltip="${t}">${t}</span>`;return r?v`<button type="button" class="location-metadata" aria-label="${`Use ${n} from ${e}: ${t}`}" ?disabled="${i}" @click="${r}">${a}</button>`:v`<span class="location-metadata">${a}</span>`}var Pr=class extends b{static properties={localImportSource:{attribute:!1},_query:{state:!0},_visibility:{state:!0},_data:{state:!0},_error:{state:!0},_busy:{state:!0},_dragOver:{state:!0},_preview:{state:!0},_previewLoading:{state:!0},_locationReport:{state:!0},_locationOrigin:{state:!0},_locationOriginError:{state:!0},_locationRepo:{state:!0},_locationDirectory:{state:!0},_locationBusy:{state:!0}};static styles=[_(Gn),_(qn),_(a),_(Bn)];constructor(){super(),this._query=``,this._visibility=`all`,this._data=null,this._error=null,this._busy=!1,this._dragOver=!1,this._preview=null,this._previewLoading=null,this._previewRequest=null,this._locationReport=null,this._locationOrigin=null,this._locationOriginError=null,this._locationOriginRequest=null,this._locationRepo=null,this._locationDirectory=``,this._locationBusy=!1,this._teardownDrop=null,this._queue=[],this._localImport=new rt(this,`report`,e=>Rn(this,e,e=>Cn(e,this._csrf),[`reports`,`repo-impact`,`history`,`scan-sources`]))}connectedCallback(){super.connectedCallback(),this._load(),this._teardownDrop=In(this,e=>{this._upload(e)},e=>{this._dragOver=e})}disconnectedCallback(){super.disconnectedCallback(),this._teardownDrop?.(),this._cancelPreview(),this._closeLocation()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection(`reports`,`reports`,xn,e=>{this._data=e,this._preview&&!e.reports?.some(e=>e.id===this._preview)&&this._cancelPreview(),this._locationReport&&!e.reports?.some(e=>e.id===this._locationReport)&&this._closeLocation()})}render(){return v`${this._dragOver?v`<div class="dropzone">Drop reports to upload</div>`:y}<div class="wrap">${r(`manage-reports`,this._role,this.allowShare)}<h1 class="sr-only">Reports</h1><div class="page-intro"><p class="intro">Upload reports. New reports stay hidden until you make them visible.</p>${this._localImport.renderAction()}</div>${this._localImport.renderPanel(this._busy||!this._csrf)}<div class="drop-card"><span class="drop-icon" aria-hidden="true">${i(`upload`)}</span><span class="drop-copy"><strong>Upload reports</strong><span>Drop files anywhere on this page.</span></span><button type="button" class="drop-browse" ?disabled="${this._busy}" @click="${()=>Fn(e=>{this._upload(e)})}">${this._busy?`Uploading…`:`Browse files`}</button></div>${this._data?.repoScopes?.length?v`<p class="intro">Team paths: ${this._data.repoScopes.map(e=>`${this._data.repos.find(t=>t.repoId===e.repoId)?.fullName??e.repoId}/${e.path??``}`).join(`, `)}</p>`:y} ${this._body()}</div>`}_body(){let e=Array.isArray(this._data?.reports)?this._data.reports:[],t=this._query.trim().toLocaleLowerCase(),n=e.filter(e=>[e.filename,p(e.filename),e.repoFullName,e.repoDirectory,e.uploadedByLogin].filter(Boolean).join(` `).toLocaleLowerCase().includes(t)&&(this._visibility===`all`||!!e.visible==(this._visibility===`visible`))),r=`${t||this._visibility!==`all`?`${n.length} of `:``}${e.length} ${e.length===1?`report`:`reports`}`;return v`<div class="collection-toolbar" role="search"><input type="search" aria-label="Search reports" placeholder="Search reports or repositories…" .value="${this._query}" @input="${e=>{this._query=e.target.value}}"><select aria-label="Report visibility" .value="${this._visibility}" @change="${e=>{this._visibility=e.target.value}}"><option value="all">All reports</option><option value="visible">Visible to teams</option><option value="hidden">Hidden reports</option></select><span class="result-count" role="status">${this._data==null?`… reports`:r}</span></div>${this._error?v`<p class="msg error" role="alert">${this._error}</p>`:y}<div class="manage-list" aria-busy="${this._loading}">${this._data==null?this._error?y:x(`Loading reports…`):n.length>0?v`<div class="report-list"><div class="report-list-head" aria-hidden="true"><span class="report-heading">Report</span><span>Repository</span><span>Uploaded by</span><span>Date</span><span class="size-heading">Size</span><span>Visibility</span><span class="actions-heading">Actions</span></div><ul class="reports">${n.map(e=>this._row(e))}</ul></div>`:v`<div class="empty"><strong>${e.length===0?`No reports uploaded yet`:`No matching reports`}</strong><p>${e.length===0?`Drop a report here or browse files above.`:`Try a different search or visibility filter.`}</p></div>`}</div>`}_row(e){let t=p(e.filename),n=e.analyzer??e.source??e.producer??`default`,r=Oe[n]??Oe.default,a=e.repoEmbedded!==!0&&e.canChangeRepo!==!1,o=e.repoEmbedded===!0||e.repoId!=null,s=e.repoFullName?`${e.repoFullName}${e.repoDirectory?`/${e.repoDirectory}`:``}`:`No repository assigned`,c=Number.isFinite(e.uploadedAt)?new Date(e.uploadedAt).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`}):``;return v`<li class="${`report${e.visible===!1?` content-hidden`:``}`}"><div class="report-main"><span class="report-mark" aria-hidden="true">${g(r)}</span> <span class="report-name" data-tooltip-truncated data-tooltip="${t}">${t}</span> <span class="report-location" data-tooltip-truncated data-tooltip="${s}">${s}</span> <span class="report-meta report-uploader" data-tooltip-truncated data-tooltip="${e.uploadedByLogin??`Uploader removed`}">${e.uploadedByLogin??`Uploader removed`}</span> <span class="report-meta report-date">${c}</span> <span class="report-meta report-size">${m(e.byteSize)}</span> <span class="${`status ${e.visible?`visible`:`hidden`}`}">${e.visible?`Visible`:`Hidden`}</span> <span class="report-actions">${a?v`<button type="button" class="action" data-tooltip="Set repository location" aria-label="${`Set location for ${t}`}" @click="${()=>this._openLocation(e)}">${i(`repo`)}</button>`:v`<span class="action-spacer"></span>`} <button type="button" class="action" aria-label="${`Preview ${t}`}" aria-expanded="${this._preview===e.id}" @click="${()=>{this._togglePreview(e)}}">${i(`preview`)}</button> <button type="button" class="action" data-tooltip="${e.visible?`Hide from teams`:o?`Make visible to teams`:`Assign a repository before publishing`}" aria-label="${`${e.visible?`Hide`:`Make visible`} ${t}`}" ?disabled="${e.canChangeRepo===!1||!o&&!e.visible}" @click="${()=>{this._setVisible(e,!e.visible)}}">${i(e.visible?`hide`:`show`)}</button> <a class="action" aria-label="${`Download ${t}`}" href="${`/api/admin/reports/${encodeURIComponent(e.id)}`}">${i(`download`)}</a> <button type="button" class="action danger" aria-label="${`Delete ${t}`}" ?disabled="${e.canChangeRepo===!1}" @click="${()=>this._delete(e)}">${R}</button></span></div>${this._preview===e.id?v`<div class="preview">${this._previewLoading===e.id?v`<span class="preview-loading">Loading preview…</span>`:v`<pre>${this._previewText??``}</pre>`}</div>`:y} ${this._locationReport===e.id?this._locationEditor(e):y}</li>`}_openLocation(e){e.canChangeRepo!==!1&&(this._closeLocation(),this._locationReport=e.id,this._locationRepo=e.repoId??null,this._locationDirectory=e.repoDirectory??``,this._error=null,this._loadLocationOrigin(e))}_closeLocation(){this._locationOriginRequest?.abort(),this._locationOriginRequest=null,this._locationReport=null,this._locationOrigin=null,this._locationOriginError=null}async _loadLocationOrigin(e){this._locationOriginRequest?.abort();let t=new AbortController;this._locationOriginRequest=t,this._locationOrigin=void 0,this._locationOriginError=null;try{let n=await Dn(e.id,AbortSignal.any([t.signal,this.appState.sessionController.signal]));if(this._locationOriginRequest!==t)return;n?.repoId!=null&&this._data&&(this._data={...this._data,repos:[...(this._data.repos??[]).filter(e=>e.repoId!==n.repoId),{repoId:n.repoId,fullName:n.github}]}),this._locationOrigin=typeof n?.github==`string`&&n.github?{github:n.github,repoId:n.repoId??null,directory:typeof n.directory==`string`?n.directory||`/`:null}:null}catch(e){if(this._locationOriginRequest!==t)return;this._locationOrigin=null,e?.name!==`AbortError`&&(this._locationOriginError=`Couldn't load the report’s suggested location.`)}}_locationEditor(e){let t=Array.isArray(this._data?.repos)?this._data.repos:[],n=this._locationOrigin,r=n?.repoId!=null&&t.find(e=>e.repoId===n.repoId),i=(e,t,n)=>Nr(`report`,e,t,n,this._locationBusy);return v`<div class="location-editor"><div class="location-field"><div class="location-field-header"><span class="ui-hint">Repository</span>${n?i(n.github,`repository`,r?()=>{this._locationRepo=r.repoId,n.directory!=null&&(this._locationDirectory=n.directory)}:null):y}</div><repository-selector label="Repository for report" .options="${Mr(t)}" .value="${this._locationRepo}" ?disabled="${this._locationBusy}" @repository-change="${e=>{this._locationRepo=e.detail.value}}"></repository-selector></div><div class="location-field"><div class="location-field-header"><label for="${`report-dir-${e.id}`}">Directory (optional)</label>${n?i(n.directory??`Directory not specified`,`directory`,n.directory==null?null:()=>{this._locationDirectory=n.directory}):y}</div><input id="${`report-dir-${e.id}`}" type="text" placeholder="Repository root" .value="${this._locationDirectory}" ?disabled="${this._locationBusy}" @input="${e=>{this._locationDirectory=e.target.value}}"></div><div class="location-actions"><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>this._closeLocation()}">Cancel</button><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>{this._saveLocation(e)}}">Save</button></div>${this._locationOriginError?v`<p class="location-origin" role="status">${this._locationOriginError} <button type="button" class="origin-retry" @click="${()=>{this._loadLocationOrigin(e)}}">Retry</button></p>`:y}</div>`}async _saveLocation(e){if(!this._locationBusy){this._locationBusy=!0,this._error=null;try{await this.appState.mutate(()=>En(e.id,this._locationRepo,this._locationDirectory.trim(),this._csrf),[`reports`,`repo-impact`,`history`,`scan-sources`]),this._closeLocation(),await this._load({preserveError:!0})}catch(e){this._error=`Couldn't set report location: ${String(e?.message??e)}`}finally{this._locationBusy=!1}}}_cancelPreview(){this._previewRequest?.abort(),this._previewRequest=null,this._preview=null,this._previewLoading=null,this._previewText=``}async _togglePreview(e){let t=this._preview===e.id;if(this._cancelPreview(),t)return;let n=new AbortController;this._previewRequest=n;let r=()=>this._previewRequest===n&&!n.signal.aborted;this._preview=e.id,this._previewText=this.appState.read(`report-preview:${e.id}`)??``,this._previewLoading=this.appState.read(`report-preview:${e.id}`)===void 0?e.id:null;try{await this.appState.load(`report-preview:${e.id}`,`report preview`,async t=>{let n=await d(`/api/admin/reports/${encodeURIComponent(e.id)}`,{credentials:`same-origin`,signal:t});if(!n.ok)throw Error(`HTTP ${n.status}`);let r=await n.text();return r.slice(0,4e3)+(r.length>4e3?`
17
+ …`:``)},{signal:n.signal,apply:e=>{this._previewText=e}})}catch(e){r()&&e?.name!==`AbortError`&&!this._previewText&&(this._previewText=`Preview unavailable: ${e?.message??e}`)}finally{r()&&(this._previewLoading=null)}}async _setVisible(e,t){this._error=null;try{await this.appState.mutate(()=>Tn(e.id,t,this._csrf),[`reports`,`history`,`scan-sources`]),e.visible=t,this.requestUpdate(),await this._load()}catch(e){this._error=`Couldn't change report visibility: ${String(e?.message??e)}`}}async _upload(e){await zn(this,e,e=>Cn(e,this._csrf),[`reports`,`repo-impact`,`history`,`scan-sources`])}async _delete(e){if(globalThis.confirm?.(`Delete \u201C${p(e.filename)}\u201D? This can't be undone.`)){this._error=null;try{await this.appState.mutate(()=>On(e.id,this._csrf),[`reports`,`report-preview:${e.id}`,`repo-impact`,`history`,`scan-sources`])}catch(e){this._error=`Delete failed: ${String(e?.message??e)}`}await this._load({preserveError:!0})}}};customElements.define(`managed-admin-reports`,Pr);var Fr=v`<svg class="report-icon" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M8.878.392a1.75 1.75 0 0 0-1.756 0l-5.25 3.045A1.75 1.75 0 0 0 1 4.951v6.098c0 .624.332 1.2.872 1.514l5.25 3.045a1.75 1.75 0 0 0 1.756 0l5.25-3.045c.54-.313.872-.89.872-1.514V4.951c0-.624-.332-1.2-.872-1.514ZM7.875 1.69a.25.25 0 0 1 .25 0l4.63 2.685L8 7.133 3.245 4.375Zm-5.125 4.4 4.5 2.61v5.317l-4.375-2.537a.25.25 0 0 1-.125-.216Zm6 7.927V8.7l4.5-2.61v3.96a.25.25 0 0 1-.125.216Z"/></svg>`,Ir=class extends b{static properties={createRepoId:{attribute:!1},installTooltips:{attribute:!1},localImportSource:{attribute:!1},_query:{state:!0},_visibility:{state:!0},_visibilityBusy:{state:!0},_creating:{state:!0},_data:{state:!0},_locationBundle:{state:!0},_locationOrigin:{state:!0},_locationOriginError:{state:!0},_locationRepo:{state:!0},_locationDirectory:{state:!0},_locationBusy:{state:!0},_error:{state:!0},_busy:{state:!0},_dragOver:{state:!0}};static styles=[_(Kn),_(qn),_(a),_(Bn)];constructor(){super(),this._query=``,this._visibility=`all`,this._visibilityBusy=null,this._creating=!1,this._data=null,this._error=null,this._busy=!1,this._locationBundle=null,this._locationOrigin=null,this._locationOriginError=null,this._locationOriginRequest=null,this._locationRepo=null,this._locationDirectory=``,this._locationBusy=!1,this._dragOver=!1,this._teardownDrop=null,this._queue=[],this._localImport=new rt(this,`bundle`,e=>Rn(this,e,e=>An(e,this._csrf),[`bundles`,`reports`,`repo-impact`,`history`,`scan-sources`]))}connectedCallback(){super.connectedCallback(),this._load(),this._teardownDrop=In(this,e=>{this._creating||this._upload(e)},e=>{this._dragOver=!this._creating&&e})}disconnectedCallback(){super.disconnectedCallback(),this._teardownDrop?.(),this._closeLocation()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection(`bundles`,`bundles`,kn,e=>{this._data=e,this._locationBundle&&!e.bundles?.some(e=>e.id===this._locationBundle)&&this._closeLocation()})}_showCreate(e){if(!e&&this.createRepoId!=null){document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage-bundles`},bubbles:!0,composed:!0}));return}this._creating=e,this._dragOver=!1,e||this.updateComplete.then(()=>this.renderRoot.querySelector(`.create-bundle-action`)?.focus())}willUpdate(e){e.has(`createRepoId`)&&(this._creating=this.createRepoId!=null)}render(){return this._creating?v`<div class="wrap">${r(`manage-bundles`,this._role,this.allowShare)}<div class="breadcrumb"><button type="button" class="breadcrumb-manage" @click="${()=>document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage`},bubbles:!0,composed:!0}))}">Manage</button> <span class="breadcrumb-separator" aria-hidden="true">›</span> <button type="button" class="breadcrumb-manage" aria-label="Back to bundles" @click="${()=>this._showCreate(!1)}">Bundles</button> <span class="breadcrumb-separator" aria-hidden="true">›</span><h1 class="breadcrumb-current">Create a bundle</h1></div><managed-create-bundle .initialRepoId="${this.createRepoId??null}" .installTooltips="${this.installTooltips}" .createBundle="${this._csrf?(e,t)=>this.appState.mutate(()=>Sn(e,this._csrf,t),[`bundles`,`bundle-metadata`,`reports`,`repo-impact`,`history`,`scan-sources`]):void 0}" @bundle-created="${e=>this.dispatchEvent(new CustomEvent(`managed-bundle-open`,{detail:e.detail,bubbles:!0,composed:!0}))}"></managed-create-bundle></div>`:v`${this._dragOver?v`<div class="dropzone">Drop bundles to upload</div>`:y}<div class="wrap">${r(`manage-bundles`,this._role,this.allowShare)}<h1 class="sr-only">Bundles</h1><div class="page-intro"><p class="intro">Source bundles for your repositories.</p><div class="bundle-actions">${this._localImport.renderAction()}<button type="button" class="local-import-toggle create-bundle-action" ?disabled="${!this._data}" @click="${()=>this._showCreate(!0)}">Create</button></div></div>${this._localImport.renderPanel(this._busy||!this._csrf)}<section class="drop-card" aria-label="Upload bundles"><span class="drop-icon" aria-hidden="true">${i(`upload`)}</span><span class="drop-copy"><strong>Upload source bundles</strong><span>Drop source archives anywhere on this page.</span></span> <button type="button" class="drop-browse" ?disabled="${this._busy}" @click="${()=>Fn(e=>{this._upload(e)})}">${this._busy?`Uploading…`:`Browse files`}</button></section>${this._body()}</div>`}_body(){let e=Array.isArray(this._data?.bundles)?this._data.bundles:[],t=this._query.trim().toLocaleLowerCase(),n=e.filter(e=>[e.filename,e.repoFullName,e.repoDirectory,e.kind,e.provenance===`build`?`built`:null,e.uploadedByLogin].filter(Boolean).join(` `).toLocaleLowerCase().includes(t)&&(this._visibility===`all`||e.visible!==!1==(this._visibility===`visible`))),r=n.filter(e=>e.repoId==null).length,i=n.reduce((e,t)=>e+(Number.isFinite(t.byteSize)?t.byteSize:0),0),a=`${t||this._visibility!==`all`?`${n.length} of `:``}${e.length} ${e.length===1?`bundle`:`bundles`}`,o=Map.groupBy(n,e=>e.repoFullName||`Unattached`);return v`<div class="collection-toolbar" role="search"><input type="search" aria-label="Search bundles" placeholder="Search bundles or repositories…" .value="${this._query}" @input="${e=>{this._query=e.target.value}}"> <select aria-label="Bundle visibility" .value="${this._visibility}" @change="${e=>{this._visibility=e.target.value}}"><option value="all">All bundles</option><option value="visible">Visible to teams</option><option value="hidden">Hidden bundles</option></select> <span class="summary result-count" role="status"><span>${this._data==null?`… bundles`:a}</span><span>${this._data==null?`…`:m(i)}</span> ${this._data==null||r?v`<span class="unassigned">${this._data==null?`… unattached`:`${r} unattached`}</span>`:y}</span></div>${this._error?v`<p class="msg error" role="alert">${this._error}</p>`:y}<div class="manage-list" aria-busy="${this._loading}">${this._data==null?this._error?y:x(`Loading bundles…`):n.length>0?v`<div class="bundle-groups">${[...o].toSorted(([e],[t])=>e===`Unattached`?-1:t===`Unattached`?1:e.localeCompare(t)).map(([e,t])=>v`<section class="bundle-group"><div class="bundle-group-head"><strong>${e}</strong><span>${t.length} ${t.length===1?`bundle`:`bundles`}</span></div><ul class="bundles">${t.map(e=>this._row(e))}</ul></section>`)}</div>`:v`<div class="empty"><strong>${e.length>0?`No matching bundles`:`No bundles uploaded yet`}</strong><p>${e.length>0?`Try a different search or visibility filter.`:`Drop source archives here or browse files above.`}</p></div>`}</div>`}_row(e){let t=e.visible!==!1,n=e.repoFullName?`${e.repoFullName}${e.repoDirectory?`/${e.repoDirectory}`:``}`:`No repository assigned`,r=Number.isFinite(e.uploadedAt)?new Date(e.uploadedAt).toLocaleDateString(void 0,{year:`numeric`,month:`short`,day:`numeric`}):``;return v`<li class="${`bundle-row${t?``:` content-hidden`}`}"><span class="identity"><span class="bundle-icon" aria-hidden="true">${e.kind===`stasis`?v`<img src="./stasis.svg" width="16" height="16" alt="">`:Fr}</span> <button type="button" class="filename bundle-open" data-tooltip-truncated data-tooltip="${e.filename}" @click="${()=>this.dispatchEvent(new CustomEvent(`managed-bundle-open`,{detail:e,bubbles:!0,composed:!0}))}">${e.filename}</button> ${e.provenance===`build`?v`<span class="bundle-provenance" data-tooltip="Generated on this server from the repository">Built</span>`:y} </span><span class="meta bundle-uploader" data-tooltip-truncated data-tooltip="${e.uploadedByLogin?`@${e.uploadedByLogin}`:``}">${e.uploadedByLogin?`@${e.uploadedByLogin}`:``}</span> <span class="meta bundle-date">${r}</span> <span class="meta bundle-size">${m(e.byteSize)}</span> <span class="bundle-location" data-tooltip-truncated data-tooltip="${n}">${n}</span> <span class="${`status ${t?`visible`:`hidden`}`}">${t?`Visible`:`Hidden`}</span> <span class="actions">${e.canChangeRepo===!1?y:v`<button type="button" class="action" aria-label="${`Set location for ${e.filename}`}" data-tooltip="Set repository location" ?disabled="${this._locationBusy}" @click="${()=>this._openLocation(e)}">${i(`repo`)}</button>`} <button type="button" class="action" aria-label="${`${t?`Hide`:`Make visible`} ${e.filename}`}" data-tooltip="${t?`Hide from teams`:e.repoId==null?`Assign a repository before publishing`:`Make visible to teams`}" ?disabled="${this._visibilityBusy!=null||e.canChangeRepo===!1||!t&&e.repoId==null}" @click="${()=>{this._setVisible(e,!t)}}">${i(t?`hide`:`show`)}</button> <a class="action" aria-label="${`Download ${e.filename}`}" href="${`/api/admin/bundles/${encodeURIComponent(e.id)}`}"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 2v8m-3-3 3 3 3-3M3 11v3h10v-3"/></svg></a><button type="button" class="action danger" aria-label="${`Delete ${e.filename}`}" ?disabled="${e.canChangeRepo===!1}" data-tooltip="${e.canChangeRepo===!1?`Repository access is required to detach or delete this bundle`:y}" @click="${()=>this._delete(e)}">${R}</button> </span>${this._locationBundle===e.id?this._locationEditor(e):y}</li>`}async _setVisible(e,t){if(this._visibilityBusy==null&&e.canChangeRepo!==!1){this._visibilityBusy=e.id,this._error=null;try{await this.appState.mutate(()=>Mn(e.id,t,this._csrf),[`bundles`,`teams`,`history`,`scan-sources`]),e.visible=t,this.requestUpdate(),await this._load()}catch(e){this._error=`Couldn't change bundle visibility: ${String(e?.message??e)}`}finally{this._visibilityBusy=null}}}_openLocation(e){this._locationBusy||e.canChangeRepo===!1||(this._closeLocation(),this._locationBundle=e.id,this._locationRepo=e.repoId??null,this._locationDirectory=e.repoDirectory??``,this._error=null,e.kind===`stasis`&&this._loadLocationOrigin(e))}_closeLocation(){this._locationOriginRequest?.abort(),this._locationOriginRequest=null,this._locationBundle=null,this._locationOrigin=null,this._locationOriginError=null}async _loadLocationOrigin(e){this._locationOriginRequest?.abort();let t=new AbortController;this._locationOriginRequest=t,this._locationOrigin=void 0,this._locationOriginError=null;try{let n=await ot(e.id,{signal:t.signal});if(this._locationOriginRequest!==t)return;n?.repoId!=null&&this._data&&(this._data={...this._data,repos:[...(this._data.repos??[]).filter(e=>e.repoId!==n.repoId),{repoId:n.repoId,fullName:n.github}]}),this._locationOrigin=typeof n?.github==`string`&&n.github?{github:n.github,directory:typeof n.directory==`string`?n.directory:n.root===!0?`/`:null}:null}catch(e){if(this._locationOriginRequest!==t)return;this._locationOrigin=null,e?.name!==`AbortError`&&(this._locationOriginError=`Couldn't load the bundle’s suggested location.`)}}_locationEditor(e){let t=Array.isArray(this._data?.repos)?this._data.repos:[],n=this._locationOrigin,r=We({repo:n})?.toLowerCase(),i=r&&t.find(e=>e.fullName.toLowerCase()===r),a=(e,t,n)=>Nr(`metadata`,e,t,n,this._locationBusy);return v`<div class="location-editor"><div class="location-field"><div class="location-field-header"><span class="ui-hint">Repository</span>${n?a(n.github,`repository`,i?()=>{this._locationRepo=i.repoId,n.directory!=null&&(this._locationDirectory=n.directory)}:null):y}</div><repository-selector label="Repository for bundle" .options="${Mr(t)}" .value="${this._locationRepo}" ?disabled="${this._locationBusy}" @repository-change="${e=>{this._locationRepo=e.detail.value}}"></repository-selector></div><div class="location-field"><div class="location-field-header"><label for="${`bundle-dir-${e.id}`}">Directory (optional)</label>${n?a(n.directory??`Directory not specified`,`directory`,n.directory==null?null:()=>{this._locationDirectory=n.directory}):y}</div><input id="${`bundle-dir-${e.id}`}" type="text" placeholder="Repository root" .value="${this._locationDirectory}" ?disabled="${this._locationBusy}" @input="${e=>{this._locationDirectory=e.target.value}}"></div><div class="location-actions"><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>this._closeLocation()}">Cancel</button><button type="button" class="action" ?disabled="${this._locationBusy}" @click="${()=>{this._saveLocation(e)}}">Save</button></div>${this._locationOriginError?v`<p class="location-origin" role="status">${this._locationOriginError} <button type="button" class="origin-retry" @click="${()=>{this._loadLocationOrigin(e)}}">Retry</button></p>`:y}</div>`}async _saveLocation(e){if(!(this._locationBusy||e.canChangeRepo===!1)){this._locationBusy=!0,this._error=null;try{await this.appState.mutate(()=>Nn(e.id,this._locationRepo,this._locationDirectory.trim(),this._csrf),[`bundles`,`teams`,`repo-impact`,`history`,`scan-sources`]),this._closeLocation(),await this._load({preserveError:!0})}catch(e){this._error=`Couldn't set bundle location: ${String(e?.message??e)}`}finally{this._locationBusy=!1}}}async _upload(e){await zn(this,e,e=>An(e,this._csrf),[`bundles`,`bundle-metadata`,`reports`,`repo-impact`,`history`,`scan-sources`])}async _delete(e){if(globalThis.confirm?.(`Delete \u201C${e.filename}\u201D? Linked reports will keep their pending link.`)){this._error=null;try{await this.appState.mutate(()=>jn(e.id,this._csrf),[`bundles`,`bundle-metadata`,`reports`,`repo-impact`,`history`,`scan-sources`])}catch(e){this._error=`Delete failed: ${String(e?.message??e)}`}await this._load({preserveError:!0})}}};customElements.define(`managed-admin-bundles`,Ir);var Lr=class extends b{static properties={selection:{attribute:!1},_source:{state:!0},_error:{state:!0}};static styles=_(a);constructor(){super(),this._loadModels=(e,t)=>this.appState.load(`models`,`scan models`,e=>n(e,d),{signal:e,apply:t}),this._source=null,this._error=null,this._loadReportSources=(e,n)=>this.appState.load(`scan-sources`,`scan report inputs`,async e=>{let[n,r]=await Promise.all([d(`/api/admin/reports`,{signal:e,credentials:`same-origin`}),d(`/api/admin/scan-results`,{signal:e,credentials:`same-origin`})]);if(!n.ok)throw Error(`Reports: HTTP ${n.status}`);if(!r.ok&&r.status!==404)throw Error(`Scan results: HTTP ${r.status}`);let i=await n.json();return i.reports=await Promise.all((i.reports??[]).filter(e=>e.visible&&e.repoId!=null).map(async t=>{let n=await d(`/api/admin/reports/${encodeURIComponent(t.id)}`,{signal:e,credentials:`same-origin`});if(!n.ok)throw Error(`Report ${p(t.filename)}: HTTP ${n.status}`);return{...t,content:await n.text()}})),t(i,r.ok?await r.json():{bundles:[],results:[]})},{signal:e,apply:n})}connectedCallback(){super.connectedCallback(),this._load()}async _load(){this._error=null,je().catch(e=>{this._error=String(e?.message??e)}),await this._loadCollection(`bundles`,`bundles`,kn,e=>{this._source=cr(e)})}render(){return v`<div class="wrap">${r(`manage-scans`,this._role,this.allowShare)} ${this._error?v`<p class="msg error" role="alert">Couldn’t load scan sources: ${this._error} <button type="button" class="btn" @click="${()=>{this._load()}}">Retry</button></p>`:y}<deepview-scan-page hide-heading .selection="${this.selection}" .source="${this._source}" .sourceLoading="${this._loading&&this._source==null}" .loadBundle="${lr}" .loadModels="${this._loadModels}" .loadReportSources="${this._loadReportSources}" .createBundleHref="${e=>Number.isSafeInteger(e)&&e>0?h({view:`manage-bundles`,createRepoId:e}):null}"></deepview-scan-page></div>`}};customElements.define(`managed-admin-scans`,Lr);var Rr=class extends b{static properties={_data:{state:!0},_error:{state:!0},_busy:{state:!0},_renamingId:{state:!0},_repoChoices:{state:!0},_memberChoices:{state:!0}};static styles=[_(Jn),_(a)];constructor(){super(),this._data=null,this._error=null,this._busy=!1,this._renamingId=null,this._repoChoices=new Map,this._memberChoices=new Map}connectedCallback(){super.connectedCallback(),this._load()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection(`teams`,`teams`,Pn,e=>{this._data=e})}async _do(e){if(!this._busy){this._busy=!0,this._error=null;try{await this.appState.mutate(e,[`teams`,`users`,`reports`,`history`,`repos`]),globalThis.dispatchEvent?.(new Event(`dependency-review-changed`))}catch(e){this._error=String(e?.message??e)}finally{this._busy=!1,await this._load({preserveError:!0})}}}render(){return v`<div class="wrap">${r(`manage-teams`,this._role,this.allowShare)}<h1 class="sr-only">Teams</h1><div class="page-intro"><p class="intro">Manage repository and finding access for each team.</p><span class="result-count">${this._data?.teams?.length??`…`} teams</span></div><div class="create-team"><label class="sr-only" for="new-team-name">New team</label> <input id="new-team-name" class="new-name" type="text" placeholder="Team name" maxlength="100" ?disabled="${this._busy}" @keydown="${e=>{e.key===`Enter`&&this._create()}}"> <button class="btn primary" ?disabled="${this._busy}" @click="${()=>this._create()}">${B} Create team</button><p class="access-note ui-hint">All members can view standard findings. Set dependencies and security access per member.</p></div><div class="manage-list" aria-busy="${this._loading}">${this._body()}</div></div>`}_body(){if(this._error!=null&&this._data==null)return v`<p class="msg error">Couldn't load teams: ${this._error}</p>`;if(this._data==null)return x(`Loading teams…`);let e=Array.isArray(this._data.teams)?this._data.teams:[];return v`${this._error==null?y:v`<p class="msg error">${this._error}</p>`} ${e.length===0?v`<p class="msg">No teams yet. Create one above.</p>`:e.map(e=>this._team(e))}`}_team(e){return v`<section class="team" aria-label="${e.name}"><div class="team-head"><span class="team-icon" aria-hidden="true"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="5" r="2.5"/><path d="M1.5 13v-1c0-2 1.8-3.5 4.5-3.5s4.5 1.5 4.5 3.5v1M11 2.5a2.5 2.5 0 0 1 0 5M12 9c1.7.5 2.5 1.5 2.5 3v1"/></svg></span>${this._renamingId===e.id?v`<input class="rename-input" type="text" .value="${e.name}" maxlength="100" aria-label="Team name" @keydown="${t=>this._renameKey(t,e)}"> <button class="btn" ?disabled="${this._busy}" @click="${t=>this._saveRename(e,t)}">Save</button> <button class="btn" @click="${()=>{this._renamingId=null}}">Cancel</button>`:v`<h2 class="team-name">${e.name}</h2>${e.hidden?v`<span class="muted ui-hint">Disabled</span>`:y} <span class="team-actions"><button class="icon-btn" aria-label="${`${e.hidden?`Restore`:`Hide`} ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._do(()=>N(`/api/admin/teams/set-hidden`,this._csrf,{teamId:e.id,hidden:!e.hidden}))}">${i(e.hidden?`show`:`hide`)}</button> <button class="icon-btn" aria-label="${`Rename ${e.name}`}" ?disabled="${this._busy}" @click="${()=>{this._renamingId=e.id}}">${yr}</button> <button class="icon-btn danger" aria-label="${`Delete ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._deleteTeam(e)}">${R}</button></span>`}</div><div class="team-body"><div class="sub"><h3 class="sub-title">Repositories <span class="count">${e.repos.length}</span></h3>${e.repos.length===0?v`<p class="muted ui-hint">No repositories linked.</p>`:v`<ul class="links">${e.repos.map(t=>this._repoRow(e,t))}</ul>`} ${this._addRepoRow(e)}</div><div class="sub"><h3 class="sub-title">Members <span class="count">${e.members.length}</span></h3>${e.members.length===0?v`<p class="muted ui-hint">No members.</p>`:v`<ul class="links">${e.members.map(t=>this._memberRow(e,t))}</ul>`} ${this._addMemberRow(e)}</div>${this._npmScopes(e)}</div></section>`}_npmScopes(e){let t=Array.isArray(e.npmScopes)?e.npmScopes:[];return v`<div class="sub npm-scopes"><div class="sub-head"><h3 class="sub-title">npm scopes <span class="count">${t.length}</span><mode-switch class="npm-review-toggle" label="Enable dependency review" .checked="${!!e.dependencyReview}" .disabled="${this._busy}" @click="${()=>{this._busy||this._do(()=>N(`/api/admin/teams/set-dependency-review`,this._csrf,{teamId:e.id,enabled:!e.dependencyReview}))}}"></mode-switch></h3><p class="muted ui-hint">Members can open private packages in these scopes. Everyone can open public packages.</p></div><div class="add-row npm-scope-row"><input class="add-npm-scope" type="text" placeholder="@scope" aria-label="${`npm scope to add to ${e.name}`}" maxlength="215" ?disabled="${this._busy}" @keydown="${t=>{t.key===`Enter`&&this._addNpmScope(e,t)}}"> <button class="btn" aria-label="${`Add npm scope to ${e.name}`}" ?disabled="${this._busy}" @click="${t=>this._addNpmScope(e,t)}">${B} Add</button> ${t.length===0?y:v`<ul class="npm-scope-list">${t.map(n=>v`<li class="npm-scope"><span>${n}</span> <button class="icon-btn danger" aria-label="${`Remove ${n} from ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._setNpmScopes(e,t.filter(e=>e!==n))}">${z}</button></li>`)}</ul>`}</div></div>`}_addNpmScope(e,t){let n=t.target.closest(`.add-row`)?.querySelector(`.add-npm-scope`);if(!n?.value.trim())return;let r=He(n.value);if(r===null){this._error=`\u201C${n.value.trim()}\u201D is not an npm scope. Scopes look like @example.`;return}let i=Array.isArray(e.npmScopes)?e.npmScopes:[];if(i.includes(r)){n.value=``;return}this._setNpmScopes(e,[...i,r],()=>{n.value=``})}_setNpmScopes(e,t,n=()=>{}){return this._do(async()=>{await N(`/api/admin/teams/set-npm-scopes`,this._csrf,{teamId:e.id,scopes:t}),n()})}_repoRow(e,t){return v`<li class="repo-row">${Or} <span class="repo-copy"><span class="ln">${t.fullName}</span>${t.path?v`<span class="path">/${t.path.replace(/^\/+/u,``)}</span>`:y}</span> <button class="icon-btn danger" aria-label="${`Remove ${t.fullName}${t.path?`/${t.path}`:``} from ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._do(()=>N(`/api/admin/teams/remove-repo`,this._csrf,{teamId:e.id,repoId:t.repoId,path:t.path??null}))}">${z}</button></li>`}_addRepoRow(e){let t=Array.isArray(this._data.repos)?this._data.repos:[];return t.length===0?v`<p class="muted ui-hint">No selected repositories to link — pick some on “Manage repositories”.</p>`:v`<div class="add-row"><repository-selector class="add-repo-sel" label="${`Repository to add to ${e.name}`}" placeholder="Add repository…" ?disabled="${this._busy}" .options="${t.map(e=>({value:e.repoId,label:e.fullName}))}" .value="${this._repoChoices.get(e.id)??null}" @repository-change="${t=>{this._repoChoices=new Map(this._repoChoices).set(e.id,t.detail.value)}}"></repository-selector><input class="add-repo-path" type="text" placeholder="Path (optional)" aria-label="${`Repository path in ${e.name} (optional)`}" maxlength="500" ?disabled="${this._busy}"> <button class="btn" aria-label="${`Add repository to ${e.name}`}" ?disabled="${this._busy||!this._repoChoices.has(e.id)}" @click="${t=>this._addRepo(e,t)}">${B} Add</button></div>`}_memberRow(e,t){let n=Array.isArray(this._data.permissions)?this._data.permissions:[],r=this._data.users?.some(e=>e.id===t.userId&&De(e.role,`manage`));return v`<li class="member-row"><span class="member">${vr(t.userId,t.login)}<span class="ln">${t.login}</span></span> <span class="perms">${n.map(n=>v`<label class="perm"><input type="checkbox" .checked="${r||t[n]===!0}" ?disabled="${this._busy||r}" aria-label="${`${c[n]??n} access for ${t.login} in ${e.name}`}" @change="${r=>this._togglePerm(e,t,n,r.target.checked)}"> ${c[n]??n}</label>`)} </span><button class="icon-btn danger" aria-label="${`Remove ${t.login} from ${e.name}`}" ?disabled="${this._busy}" @click="${()=>this._do(()=>N(`/api/admin/teams/remove-member`,this._csrf,{teamId:e.id,userId:t.userId}))}">${z}</button></li>`}_addMemberRow(e){let t=Array.isArray(this._data.users)?this._data.users:[],n=new Set(e.members.map(e=>e.userId));return v`<div class="add-row"><user-selector class="add-member-sel" label="${`Member to add to ${e.name}`}" placeholder="Add member…" ?disabled="${this._busy}" .users="${t.map(e=>({...e,disabled:n.has(e.id),detail:n.has(e.id)?`Member`:``}))}" .value="${this._memberChoices.get(e.id)??null}" @user-change="${t=>{this._memberChoices=new Map(this._memberChoices).set(e.id,t.detail.value)}}"></user-selector><button class="btn" aria-label="${`Add member to ${e.name}`}" ?disabled="${this._busy||!this._memberChoices.has(e.id)||n.has(this._memberChoices.get(e.id))}" @click="${()=>this._addMember(e)}">${B} Add</button></div>`}_create(){let e=this.renderRoot.querySelector(`.new-name`),t=e?.value.trim();t&&this._do(async()=>{await N(`/api/admin/teams`,this._csrf,{name:t}),e&&(e.value=``)})}_deleteTeam(e){globalThis.confirm?.(`Delete team \u201C${e.name}\u201D? Its repo + member links are removed.`)&&this._do(()=>N(`/api/admin/teams/delete`,this._csrf,{teamId:e.id}))}_renameKey(e,t){e.key===`Enter`?this._saveRename(t,e):e.key===`Escape`&&(this._renamingId=null)}_saveRename(e,t){if(this._busy)return;let n=t.target.closest(`.team-head`)?.querySelector(`.rename-input`)?.value.trim()??``;this._renamingId=null,n!==``&&n!==e.name&&this._do(()=>N(`/api/admin/teams/rename`,this._csrf,{teamId:e.id,name:n}))}_addRepo(e,t){let n=t.target.closest(`.add-row`),r=this._repoChoices.get(e.id);if(!Number.isSafeInteger(r)||r<=0)return;let i=n?.querySelector(`.add-repo-path`)?.value??``;this._do(async()=>{await N(`/api/admin/teams/set-repo`,this._csrf,{teamId:e.id,repoId:r,path:i});let t=new Map(this._repoChoices);t.delete(e.id),this._repoChoices=t;let a=n?.querySelector(`.add-repo-path`);a&&(a.value=``)})}_addMember(e){let t=this._memberChoices.get(e.id);!t||e.members.some(e=>e.userId===t)||this._do(async()=>{await N(`/api/admin/teams/set-member`,this._csrf,{teamId:e.id,userId:t});let n=new Map(this._memberChoices);n.delete(e.id),this._memberChoices=n})}_togglePerm(e,t,n,r){if(this._data.users?.some(e=>e.id===t.userId&&De(e.role,`manage`)))return;let i={};for(let e of this._data.permissions??[])i[e]=t[e]===!0;i[n]=r,this._do(()=>N(`/api/admin/teams/set-member`,this._csrf,{teamId:e.id,userId:t.userId,...i}))}};customElements.define(`managed-admin-teams`,Rr);var zr=`.link-team{margin-top:1.5rem}.link-team h2{margin:0 0 .5rem;font-size:1rem;font-weight:600}.link-table{overflow-x:auto}table{width:100%;border-collapse:collapse;text-align:left;font-size:.8rem}th{color:var(--muted);font-weight:500}th,td{padding:.6rem .65rem;border-bottom:1px solid var(--border);white-space:nowrap}th:first-child,td:first-child{padding-left:0}th:last-child,td:last-child{padding-right:0;text-align:right}
18
+ `;async function Br(e){let t=await d(`/api/admin/links`,{signal:e,credentials:`same-origin`});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();if(!Array.isArray(n?.shares))throw Error(`No public links returned`);return n}var Vr=class extends b{static properties={_data:{state:!0},_error:{state:!0}};static styles=[_(a),_(zr)];constructor(){super(),this._data=null,this._error=null}connectedCallback(){super.connectedCallback(),this._load()}async _load(){this._error=null,await this._loadCollection(`links`,`public links`,Br,e=>{this._data=e})}async _edit(e){await Te({id:e.teamId,name:e.teamName},e.id,this.session),this.isConnected&&await this._load()}_groups(){let e=new Map;for(let t of this._data?.shares??[])e.has(t.teamId)||e.set(t.teamId,{name:t.teamName,links:[]}),e.get(t.teamId).links.push(t);return[...e.values()]}_body(){return this._data==null?this._error?v`<p class="msg error">Couldn't load public links: ${this._error}</p>`:x(`Loading public links…`):this._data.shares.length===0?v`<p class="msg">No public links. Create one with the share button beside a workspace in the sidebar.</p>`:this._groups().map(e=>v`<section class="link-team" aria-label="${e.name}"><h2>${e.name}</h2><div class="link-table"><table><thead><tr><th>Link</th><th>Created by</th><th>Created</th><th>Security</th><th>Dependencies</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody>${e.links.map(t=>v`<tr><td><span data-tooltip="${t.id}">${t.id.slice(0,8)}</span></td><td>${t.createdBy}</td><td>${new Date(t.createdAt).toLocaleString()}</td><td>${t.permissions.security?`On`:`Off`}</td><td>${t.permissions.dependencies?`On`:`Off`}</td><td><button class="btn" aria-label="${`Edit public link ${t.id.slice(0,8)} for ${e.name}`}" @click="${()=>this._edit(t)}">Edit</button></td></tr>`)}</tbody></table></div></section>`)}render(){return v`<div class="wrap">${r(`manage-links`,this._role,this.allowShare)}<h1 class="sr-only">Public links</h1><div class="page-intro"><p class="intro">Manage public links and the findings each link can show.</p><span class="result-count">${this._data?.shares.length??`…`} links</span></div>${this._loading&&this._data?v`<span class="sr-only" role="status">Refreshing public links…</span>`:y}<div class="manage-list" aria-busy="${this._loading}">${this._body()}</div></div>`}};customElements.define(`managed-admin-links`,Vr);var Hr=`/api/admin/deduplication`;async function Ur(e=``,t={}){let n=await d(`${Hr}${e}`,{credentials:`same-origin`,...t}),r=await n.json();if(!n.ok)throw Error({"storage-encryption-required":`Configure MANAGED_STORAGE_ENCRYPTION_KEY on the server to import encrypted link reports.`,"invalid-link-report":`Choose a link report containing arrays of finding IDs, such as [["id1", "id2"]].`,"too-large":`This link report exceeds the server upload limit.`}[r?.error]??`HTTP ${n.status}`);return r}var Wr=class extends b{static properties={_data:{state:!0},_error:{state:!0},_busy:{state:!0},_dragOver:{state:!0}};static styles=[_(a),_(Gn),_(zr)];constructor(){super(),this._data=null,this._error=null,this._busy=!1,this._dragOver=!1,this._queue=[]}connectedCallback(){super.connectedCallback(),this._load(),this._teardownDrop=In(this,e=>{this._upload(e)},e=>{this._dragOver=e})}disconnectedCallback(){this._teardownDrop?.(),super.disconnectedCallback()}async _load({preserveError:e=!1}={}){e||(this._error=null),await this._loadCollection(`deduplication`,`deduplication reports`,e=>Ur(``,{signal:e}),e=>{this._data=e})}_upload(e){if(this._csrf&&this._role===`admin`)return zn(this,e,e=>Ur(``,{method:`POST`,headers:{"content-type":`application/json`,"x-report-filename":encodeURIComponent(e.name),"x-csrf-token":this._csrf},body:e}),[`deduplication`,`reports`,`teams`])}async _toggle(e){if(!this._busy&&this._csrf){this._busy=!0,this._error=null;try{await this.appState.mutate(()=>Ur(`/${encodeURIComponent(e.id)}`,{method:`PATCH`,headers:{"content-type":`application/json`,"x-csrf-token":this._csrf},body:JSON.stringify({enabled:!e.enabled})}),[`deduplication`,`reports`,`teams`])}catch(e){this._error=String(e?.message??e)}finally{this._busy=!1,await this._load({preserveError:!0});let e=this._queue.splice(0);e.length>0&&this._upload(e)}}}_view(e){document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage-deduplication`,linkId:e.id},bubbles:!0,composed:!0}))}_linkReports(){document.dispatchEvent(new CustomEvent(`managed-admin-navigate`,{detail:{view:`manage-scans`,scanMode:`link`},bubbles:!0,composed:!0}))}render(){let e=this._data?.reports??[];return v`${this._dragOver?v`<div class="dropzone">Drop link reports to import</div>`:y}<div class="wrap">${r(`manage-deduplication`,this._role,this.allowShare)}<h1 class="sr-only">Deduplication</h1><div class="page-intro"><p class="intro">Link duplicate findings across all teams.</p><span class="result-count">${this._data?e.length:`…`} reports</span><button type="button" class="btn" @click="${()=>this._linkReports()}">Link reports</button></div><div class="drop-card"><span class="drop-icon" aria-hidden="true">${i(`upload`)}</span><span class="drop-copy"><strong>Import link reports</strong><span>Drop *.link.json files anywhere on this page.</span></span><button type="button" class="drop-browse" ?disabled="${this._busy||!this._csrf}" @click="${()=>Fn(e=>{this._upload(e)})}">${this._busy?`Saving…`:`Browse files`}</button></div>${this._error?v`<p class="msg error" role="alert">${this._error}</p>`:y}<div class="manage-list" aria-busy="${this._loading}">${this._data===null?this._error?y:x(`Loading deduplication reports…`):e.length===0?v`<div class="empty"><strong>No link reports imported yet</strong><p>Each row in a link report lists IDs for the same finding.</p></div>`:v`<div class="link-table"><table><thead><tr><th>Report</th><th>Groups</th><th>Finding IDs</th><th>Imported by</th><th>Imported</th><th>Status</th><th><span class="sr-only">Actions</span></th></tr></thead><tbody>${e.map(e=>v`<tr><td>${e.filename}</td><td>${e.groupCount}</td><td>${e.findingCount}</td><td>${e.uploadedByLogin??`Removed user`}</td><td>${new Date(e.uploadedAt).toLocaleDateString()}</td><td>${e.enabled?`Enabled`:`Disabled`}</td><td><button type="button" class="btn" aria-label="${`View ${e.filename}`}" @click="${()=>this._view(e)}">View</button> <button type="button" class="btn" ?disabled="${this._busy}" aria-label="${`${e.enabled?`Disable`:`Enable`} ${e.filename}`}" @click="${()=>{this._toggle(e)}}">${e.enabled?`Disable`:`Enable`}</button></td></tr>`)}</tbody></table></div>`}</div></div>`}};customElements.define(`managed-admin-deduplication`,Wr);var Gr=[[75,`critical`],[50,`high`],[25,`moderate`],[0,`low`]],Kr=e=>Gr.find(([t])=>e>=t)[1],qr={unpinned:[`Unpinned`,`By a tag or a branch, which its repository’s owner can point anywhere, not a full commit sha.`],"short-sha":[`Short sha`,`A short sha, which GitHub reads as a branch or tag named so too.`],"unpinned-image":[`Image by tag`,`An image by a tag, which its publisher can move, not a digest.`],"fetched-package":[`Fetched package`,`A package fetched and run as it resolves now, past what a lockfile locks.`],"unlocked-install":[`Unlocked install`,`An install that resolves anew where package.json and the lockfile disagree; npm ci holds to the lockfile.`],"remote-script":[`Remote script`,`A script fetched and run as it is fetched.`],clone:[`Clone`,`A repository cloned at whatever its branch has.`],hosts:[`Host`,`A service malicious code sends what it takes to, or fetches what it runs from.`],"script-injection":[`Script injection`,`An expression anyone can write, in a script: what it holds runs as the script’s own code.`],"pwn-request":[`Runs a fork’s code`,`Checks out a pull request’s own code where the workflow runs with the base repository’s secrets.`],"untrusted-artifact":[`Untrusted artifact`,`Takes another run’s artifacts, which a fork’s pull request writes, where the workflow runs with secrets.`],"secrets-inherited":[`Inherits secrets`,`Another owner’s reusable workflow handed every secret.`],"invalid-uses":[`Invalid`,`A uses: GitHub can’t read.`],"deprecated-runtime":[`Old Node.js`,`A Node.js GitHub no longer runs actions on.`],"repo-missing":[`Repository missing`,`No such repository on GitHub: anyone who takes its owner’s name can publish one.`],"repo-moved":[`Repository moved`,`Renamed or transferred: GitHub redirects the old name until someone takes it.`],"repo-fork":[`Fork`,`A fork of another repository.`],"repo-archived":[`Archived`,`Archived by its owner.`],"branch-ref":[`Branch`,`A branch, which moves with every push.`],"ambiguous-ref":[`Tag and branch`,`A tag and a branch of the same name.`],"ref-missing":[`Ref missing`,`Neither a tag nor a branch: GitHub runs whichever is pushed first.`],"not-version":[`Not a version`,`A tag that is no version.`],"tag-off-release":[`Tag off release`,`A major or minor tag on a commit no release of its line is on, as a tag moved by whoever took the repository is.`],"tag-off-branch":[`Tag off branch`,`The tag’s commit is on none of its branches, as a release’s built files may be.`],outdated:[`Outdated`,`An older major version than the latest release.`],"imposter-commit":[`Imposter commit`,`In the history of none of the repository’s branches and releases: GitHub serves a fork’s commit under the name of the repository it forked.`],"unverified-commit":[`Unverified commit`,`In the history of none of the branches and releases looked at; it has more.`],"commit-missing":[`Commit missing`,`GitHub has no such commit.`],"untagged-commit":[`Untagged commit`,`A commit no tag names: no release.`],"comment-mismatch":[`Comment mismatch`,`The version the comment beside it names isn’t this commit’s.`],"action-missing":[`No action.yml`,`No action.yml where it names, at the commit.`],unreadable:[`Unreadable`,`Its file couldn’t be read as GitHub reads it.`]},Jr={all:`All`,actions:`Actions`,steps:`Steps`},V=e=>Se.includes(e)?Se.indexOf(e):Se.length,Yr=e=>e.reduce((e,{severity:t})=>V(t)<V(e)?t:e,null),Xr=e=>e.id===`hosts`?e.tag===`IP lookup`?e.tag:`${e.tag??``} host`.trimStart():qr[e.id]?.[0]??e.id;function Zr(e){let t=[];return e.id===`fetched-package`&&t.push(Qr(e),...e.localFirst?[e.locked?e.installed?``:`locked, but run before any install`:`no lockfile here locks it`]:[]),e.services&&t.push(e.services.join(`, `)),e.expression&&t.push(`\${{ ${e.expression} }}`),e.to&&t.push(`now ${e.to}`),e.parent&&t.push(`of ${e.parent}`),e.latest&&t.push(`latest ${e.latest}`),e.release&&t.push(`its line\u2019s latest release is ${e.release}`),e.comment&&t.push(`# ${e.comment}, ${e.tags?.length?`tags here: ${e.tags.join(`, `)}`:`no tag is on it`}`),e.image&&t.push(e.image),e.file&&t.push(`in ${e.file}${e.line?`, line ${e.line}`:``}`),e.detail&&t.push(e.detail),[qr[e.id]?.[1],...t.filter(Boolean)].filter(Boolean).join(`
19
+ `)}function Qr(e){return e.id===`fetched-package`?`${e.tool} ${e.name}${e.spec?`@${e.spec}`:``}`:e.id===`unlocked-install`?e.tool:e.id===`unpinned-image`?e.image:e.id===`clone`?`git clone ${e.url??``}`.trim():e.id===`hosts`?e.services.join(`, `):e.id===`script-injection`?`\${{ ${e.expression} }}`:e.id===`secrets-inherited`||e.id===`invalid-uses`?e.uses:e.id===`deprecated-runtime`?`runs.using: ${e.using}`:e.id===`remote-script`&&e.command?e.command:e.id===`pwn-request`&&e.ref?e.ref===`gh pr checkout`?e.ref:`actions/checkout ref: ${e.ref}`:Xr(e)}var $r=class{constructor(){this.listed=new Map,this.files=new Map,this.actions=new Map,this.built=null}apply(e){this.built=null,e.type===`workflows`?(this.forget(e.repo),this.listed.set(e.repo,e)):e.type===`workflow`?(this.files.get(e.repo)??this.files.set(e.repo,new Map).get(e.repo)).set(e.path,e):e.type===`action`&&(!e.error||!this.actions.has(e.key))&&this.actions.set(e.key,e)}forget(e){this.listed.delete(e),this.files.delete(e),this.built=null}filesOf(e){return[...this.files.get(e)?.values()??[]]}told(){return this.listed.size+this.rows(`actions`).filter(e=>e.line).length+[...this.files.values()].reduce((e,t)=>e+t.size,0)}counts(){let e=this.rows(`actions`);return{workflows:[...this.listed.values()].reduce((e,t)=>e+(t.paths?.length??0),0),workflowsRead:[...this.files.values()].reduce((e,t)=>e+[...t.values()].filter(e=>e.kind===`workflow`).length,0),actions:e.length,resolved:e.filter(e=>e.line).length}}#e(){let e=new Map,t=new Map,n=t=>e.get(t)??e.set(t,{key:t,kind:`action`,usedIn:[],local:[]}).get(t);for(let[e,r]of this.files)for(let i of r.values()){for(let t of i.uses??[])t.key&&Object.assign(n(t.key),{uses:t}).usedIn.push({repo:e,path:i.path,line:t.line});for(let r of i.findings??[]){if(r.key){n(r.key).local.push(r);continue}let a=Qr(r),o=`${r.id}\0${r.tag??``}\0${a}`,s=t.get(o)??t.set(o,{key:o,kind:`step`,name:a,findings:[r],severity:r.severity,usedIn:[]}).get(o);V(r.severity)<V(s.severity)&&Object.assign(s,{severity:r.severity,findings:[r]}),s.usedIn.push({repo:e,path:i.path,line:r.line})}}let r=[...e.keys()];for(let t=0;t<r.length;t++)for(let i of this.actions.get(r[t])?.uses??[])e.has(i)||r.push(i),n(i).usedIn.push({via:r[t]});for(let t of e.values()){let e=new Map;t.line=this.actions.get(t.key)??null;for(let n of[...t.local,...t.line?.findings??[]]){let t=`${n.id}\0${Qr(n)}\0${n.file??``}\0${n.file?n.line:``}`;(!e.has(t)||V(n.severity)<V(e.get(t).severity))&&e.set(t,n)}t.findings=[...e.values()],t.severity=Yr(t.findings)}let i=e=>e.findings.length>0?0:e.line?.error?1:e.line||e.kind===`step`?3:2;return[...e.values(),...t.values()].toSorted((e,t)=>V(e.severity)-V(t.severity)||i(e)-i(t)||t.findings.length-e.findings.length||(e.name??e.key).localeCompare(t.name??t.key))}rows(e,t=``){this.built??=this.#e();let n=t.trim().toLowerCase();return this.built.filter(t=>(e===`all`||e===`actions`==(t.kind===`action`))&&(!n||(t.name??t.key).toLowerCase().includes(n)))}};function ei(e){if(!e||e.error||!e.commit)return null;let t=e.commit.slice(0,7),n=e.tags?.length?` (${e.tags.join(`, `)})`:``;return e.at===`sha`?`${t}${n}`:`${e.at} \u2192 ${t}${n}`}function ti(e){return v`<ul class="risk-findings">${e.map(e=>v`<li class="${`risk-${e.severity}`}" data-tooltip="${Zr(e)||y}">${Xr(e)}${e.file?v`<span class="risk-in-code">in code</span>`:y}</li>`)}</ul>`}function ni({uses:e,line:t}){let n=t?.commit??e?.ref??t?.ref,r=t?.repository?.fullName??e?.repo??t?.repo;return r&&n?ri(r,n,e?.path??t?.path,t?.kind===`workflow`||e?.kind===`workflow`?`blob`:`tree`):null}var ri=(e,t,n,r=`blob`)=>`https://github.com/${e}/${r}/${encodeURIComponent(t)}${n?`/${Ce(n)}`:``}`,ii=`.risk-progress{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1.25rem;margin:0 0 1rem;color:var(--muted);font-size:.8rem}.risk-progress-idle{margin:0}.risk-state{display:inline-flex;align-items:center;gap:.4rem;margin-left:auto;padding:.15rem .6rem;border:1px solid var(--border);border-radius:999px;color:var(--text);font-weight:500;white-space:nowrap}.risk-state:before{width:.5rem;height:.5rem;border-radius:50%;background:var(--muted);content:""}.risk-state[data-state=running]:before{background:var(--accent);animation:risk-pulse 1.4s ease-in-out infinite}.risk-state[data-state=done]:before{background:var(--green)}@keyframes risk-pulse{50%{opacity:.3}}@media(prefers-reduced-motion:reduce){.risk-state[data-state=running]:before{animation:none}}.risk-metric{display:grid;grid-template-columns:auto auto;justify-content:start;align-items:baseline;gap:.35rem .45rem;min-width:6rem;line-height:1}.risk-metric-label{font-size:.7rem;letter-spacing:.02em;text-transform:uppercase}.risk-metric-value{color:var(--text);font-size:.95rem;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}.risk-metric-value:not(:has(.risk-metric-of)){min-width:3ch}.risk-metric-of{color:var(--muted);font-weight:400}.risk-metric-slash{margin:0 .1em}.risk-metric.risk-high .risk-metric-value{color:var(--high)}.risk-bar{display:flex;grid-column:1 / -1;height:3px;overflow:hidden;border-radius:2px;background:var(--border)}.risk-bar>span{height:100%;transition:width .25s}.risk-bar-read{background:var(--accent)}.risk-bar-prod{background:color-mix(in srgb,var(--accent) 70%,var(--text))}.risk-bar-dev{background:color-mix(in srgb,var(--accent) 50%,var(--bg))}.risk-bar-malware{background:var(--critical)}.risk-section{margin-top:1rem}.risk-section:first-child{margin-top:0}.risk-section h2{margin:0 0 .5rem;font-size:1rem;font-weight:600}.risk-section>.risk-tabs{width:max-content;margin-bottom:.5rem}.risk-results-head{position:sticky;top:0;z-index:1;padding-bottom:.25rem;background:var(--bg)}.risk-results-head .collection-toolbar{margin-bottom:0}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}.risk-name,.risk-name:visited{color:var(--text)}.risk-name:hover{color:var(--accent);text-decoration:none}.risk-icon{display:inline-flex;flex:none;color:var(--muted)}.risk-icon svg{display:block;width:14px;height:14px}.risk-package,.risk-used{display:inline-flex;align-items:center;gap:.4rem;max-width:100%}.risk-version{color:var(--muted);font-variant-numeric:tabular-nums}.risk-package .risk-dev{margin-left:0}.risk-used .risk-clip{min-width:0}.risk-used.is-dismissed,.risk-used.is-dismissed:visited{color:var(--muted)}.risk-used.is-dismissed .risk-used-in{text-decoration:line-through}.risk-name:hover .risk-icon{color:inherit}.risk-used-all summary{list-style:none}.risk-used-all summary::-webkit-details-marker{display:none}.risk-used-all summary:hover,.risk-used-all[open] summary{color:var(--accent)}.risk-used-all ul{display:grid;gap:.15rem;margin:.25rem 0 0;padding:0;list-style:none}.risk-repos{margin:0;padding:0;list-style:none;font-size:.8rem}.risk-repos>li{display:grid;grid-template-columns:minmax(8rem,16rem) 1fr;gap:.75rem;align-items:baseline;padding:.3rem 0;border-bottom:1px solid var(--border)}.risk-repo-name{overflow:hidden;font-weight:500;text-overflow:ellipsis;white-space:nowrap}.risk-lockfiles{display:flex;flex-wrap:wrap;gap:.15rem 1.5rem;margin:0;padding:0;list-style:none}.risk-lockfiles li{white-space:nowrap}.risk-lockfile-meta{margin-left:.5rem;color:var(--muted)}@container (max-width: 40rem){.risk-repos>li{grid-template-columns:1fr;gap:0}}th:last-child,td:last-child{text-align:left}td{padding-top:.35rem;padding-bottom:.35rem;vertical-align:top}.risk-used-column{width:100%}.risk-clip{display:block;max-width:18rem;overflow:hidden;text-overflow:ellipsis}.risk-used-in{max-width:14rem}.risk-pending,.risk-none{color:var(--muted)}.risk-dependabot{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem .5rem;margin:.25rem 0 .5rem;color:var(--muted);font-size:.75rem}.risk-dependabot-failed{color:var(--high)}.risk-error{color:var(--critical)}.risk-chip{display:inline-block;padding:0 .45rem;border-radius:999px;font-weight:600;white-space:nowrap;color:var(--sev);background:color-mix(in srgb,var(--sev) 14%,transparent)}.risk-score{display:inline-block;min-width:2.25rem;padding:0 .4rem;border-radius:999px;font-weight:600;font-variant-numeric:tabular-nums;text-align:center;color:var(--sev);background:color-mix(in srgb,var(--sev) 14%,transparent)}.risk-score.risk-low{color:var(--muted);background:none;font-weight:400}.is-stale .risk-score,.is-stale .risk-findings{opacity:.55}.risk-stale,.risk-dev{margin-left:.35rem;padding:0 .35rem;border:1px solid var(--border);border-radius:999px;color:var(--muted);font-size:.7rem}.risk-findings{display:flex;flex-wrap:wrap;width:max-content;max-width:24rem;gap:.25rem .75rem;margin:0;padding:0;list-style:none}.risk-findings li{color:var(--sev);white-space:nowrap}.risk-critical{--sev: var(--critical)}.risk-high{--sev: var(--high)}.risk-moderate{--sev: var(--yellow)}.risk-low,.risk-notice{--sev: var(--muted)}.risk-scope-bar{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem;margin:0 0 1rem}.risk-scope,.risk-tabs{display:flex;gap:2px;padding:3px;border:1px solid var(--border);border-radius:var(--ui-radius, 6px);background:var(--bg)}.risk-scope button,.risk-tabs button{display:inline-flex;align-items:center;gap:.35rem;padding:.3rem .65rem;border:0;border-radius:var(--ui-radius, 3px);background:transparent;color:var(--muted);font-size:.75rem}.risk-scope button:hover:not(:disabled),.risk-tabs button:hover{background:var(--surface-active);color:var(--text)}.risk-scope button[aria-pressed=true],.risk-tabs button[aria-selected=true]{background:color-mix(in srgb,var(--accent) 15%,var(--bg));color:var(--accent)}.risk-scope button:focus-visible,.risk-tabs button:focus-visible{outline-offset:-1px}.risk-scope .n,.risk-tabs .n{align-self:flex-start;margin:-1px -5px 0;color:var(--muted);font-variant-numeric:tabular-nums;font-size:8.5px;font-weight:600;background:var(--bg);border-radius:999px;padding:0 3px;min-width:11px;text-align:center;line-height:11px}.risk-scope button[aria-pressed=true] .n,.risk-tabs button[aria-selected=true] .n{color:inherit}.risk-scope{flex-wrap:wrap;max-width:100%;box-sizing:border-box}.risk-scope-bar select{min-width:14rem}.risk-scope-bar repository-selector{flex:0 1 20rem;min-width:14rem}.risk-tabs{width:fit-content;margin-bottom:.5rem}.risk-in-code{margin-left:.3em;color:var(--muted);font-size:.9em}
20
+ `,ai={malware:`Malware`,deprecated:`Deprecated`,publisher:`Publisher changed`,"provenance-lost":`Provenance lost`,"too-new":`Too new`,popularity:`Unpopular`,"held-install-scripts":`Install scripts`,"held-runs-code":`Runs code`,"held-credentials":`Credentials`,"held-exfiltration":`Exfiltration host`,"held-remote":`Remote host`,"held-ip-lookup":`IP lookup`,"held-obfuscated":`Obfuscated`,"held-non-registry-deps":`Non-registry dependencies`,"held-unused-deps":`Unused deps`,"large-code":`Large new code`,"now-unreadable":`Now unreadable`,"binary-code":`Binary code`,"new-hosts":`New hosts`},oi={"no-repository":`No GitHub access`,"github-not-found":`Not found on GitHub`,"github-unauthorized":`GitHub sign-in expired`,"github-rate-limited":`GitHub rate limit reached`,"github-unreachable":`GitHub unreachable`,"github-malformed":`GitHub answered unexpectedly`,"unsupported-format":`Format not read`,"lockfile-unreadable":`Unreadable`,"package-not-found":`Not on npm`,"version-not-found":`Version not on npm`,"integrity-mismatch":`Differs from npm’s`,"npm-busy":`Server busy`,"package-too-large":`Too large to assess`,"upstream-busy":`npm busy`,"upstream-unavailable":`npm unavailable`,"upstream-too-large":`npm answered too much`,"upstream-invalid":`npm answered unexpectedly`,"dependabot-disabled":`Dependabot alerts off`,"dependabot-forbidden":`No access to Dependabot alerts`,"dependabot-app-permission":`App lacks Dependabot alerts permission`,"dependabot-not-installed":`App not installed`,"dependabot-unverified":`Sign-in not verified, sign in again`,"github-app-not-configured":`GitHub App not configured`,"workflow-unreadable":`Unreadable`,"workflow-too-large":`Too large to read`,"invalid-uses":`Not a reference GitHub reads`},H=e=>oi[e]??e,U=({error:e,detail:t})=>v`<span class="risk-error" data-tooltip="${t??y}">${H(e)}</span>`,si={401:`Sign in again to scan repositories.`,403:`Only admins can scan repositories.`,404:`That team or repository is no longer connected. Choose again.`},ci=[[`all`,`All repositories`],[`team`,`Team`],[`repo`,`Repository`]],li=5,ui={registry:`npm`,mirror:`Mirror`,git:`Git`,tarball:`Tarball`,file:`File`},W=e=>e===`registry`||e===`mirror`,G=e=>K(e)?null:e.malware??null,K=e=>e.risk?.error===`integrity-mismatch`,di=e=>G(e)||K(e)?`critical`:e.risk?.severity??null,fi=e=>G(e)?100:e.risk&&!e.risk.error?e.risk.score??null:null,q=e=>{let t=e.risk?.findings??[];return G(e)?[{id:`malware`,severity:`critical`},...t.filter(({id:e})=>e!==`malware`)]:t},pi=e=>[...G(e)??[],...e.risk?.findings?.some(({id:e,takenDown:t})=>e===`malware`&&t)?[`Taken down by npm`]:[]],mi=e=>q(e).some(({id:e})=>e===`malware`),hi=e=>K(e)||mi(e),gi=(e,t)=>t===`all`||hi(e)||!!e.dev==(t===`development`),_i=e=>`${e[0].toUpperCase()}${e.slice(1)}`,vi={all:[`All`,()=>!0],flagged:[`Flagged`,e=>!!di(e)],failed:[`Failed`,e=>!!e.risk?.error&&!K(e)],elsewhere:[`Not from npm`,e=>!W(e.source)]},yi=`Out of 100: what its findings call for, lowered by how long the version has been out among how many download its package. Malware is 100.`,bi=`Only devDependencies need it, in every lockfile that locks it: an install without them leaves it out. Assessed after the rest.`,xi=`Only devDependencies need these versions, in every lockfile that locks them: an install without them leaves them out.`,Si=`Its lockfile’s integrity, a mirror’s, isn’t npm’s of this name and version: not npm’s package, as a private one of a public one’s name is, or one tampered with.`,Ci={production:`Production`,development:`Development`},wi={all:`All`,production:`Production`,development:`Development`},Ti=e=>v`<span class="risk-dev" data-tooltip="${e}">dev</span>`;function Ei({name:e,source:t,dev:n},r,i,a){let o=v`${e}${r?v`<span class="risk-version">@${r}</span>`:y}`;return v`<span class="risk-package">${X(W(t)?Xe:Ye)}${i?v`<a class="risk-name" href="${i}">${o}</a>`:v`<span>${o}</span>`}${n?Ti(a):y}</span>`}var Di=e=>!e.error||e.error===`integrity-mismatch`;function Oi(e,t){let n=e.stale??null;return!Di(e)&&!n&&t?.stale&&Di(t)?{...t,refreshFailed:e.detail?`${H(e.error)}: ${e.detail}`:H(e.error)}:e.error?{error:e.error,detail:e.detail??null,stale:n}:{severity:e.severity,score:e.score??null,findings:e.findings,published:e.published,stale:n}}var ki=new Intl.RelativeTimeFormat(`en`,{numeric:`auto`});function Ai(e,t=Date.now()){let n=Math.round((e-t)/6e4);if(Math.abs(n)<60)return ki.format(n,`minute`);let r=Math.round(n/60);return Math.abs(r)<48?ki.format(r,`hour`):ki.format(Math.round(r/24),`day`)}var ji=100,Mi=3,J=1e3,Ni=250,Y=new Intl.NumberFormat,Pi=e=>({total:e.length,told:e.filter(e=>e.risk).length,flagged:e.filter(di).length,stale:e.filter(e=>e.risk?.stale).length,wasStale:e.filter(e=>e.wasStale).length}),X=e=>v`<span class="risk-icon" aria-hidden="true">${g(e)}</span>`,Fi={fix_started:`A fix has already been started`,inaccurate:`This alert is inaccurate or incorrect`,no_bandwidth:`No bandwidth to fix this`,not_used:`Vulnerable code is not actually used`,tolerable_risk:`Risk is tolerable to this project`};function Ii({number:e,dismissed:t}){if(!t)return`Dependabot alert #${e}`;let n=t.auto?`auto-dismissed by a rule`:`dismissed${Fi[t.reason]?`: ${Fi[t.reason]}`:``}`,r=[t.by?`by @${t.by}`:``,t.at?.slice(0,10)??``].filter(Boolean).join(`, `);return[`Dependabot alert #${e}, ${n}${r?` (${r})`:``}`,...t.comment?[`\u201C${t.comment}\u201D`]:[]].join(`
21
+ `)}function Li(e,t,n){let r=n?.get(e);if(r&&Ue(r.url))return v`<a class="${r.dismissed?`risk-name risk-used is-dismissed`:`risk-name risk-used`}" href="${r.url}" target="_blank" rel="noopener noreferrer">${X(Qe)}<span class="risk-clip risk-used-in" data-tooltip="${`${e}
22
+ ${Ii(r)}`}">${e}</span>${r.dismissed?v`<span class="sr-only">(dismissed)</span>`:y}</a>`;let i=t.get(e),a=v`<span class="risk-clip risk-used-in" data-tooltip-truncated data-tooltip="${e}">${e}</span>`;return i?v`<a class="risk-name risk-used" href="${i}" target="_blank" rel="noopener noreferrer">${X(Ze)}${a}</a>`:a}function Ri(e,t,n,r=`lockfiles`){let i=[...e];if(i.length===1)return Li(i[0],t,n);let a=i.filter(e=>n?.get(e)?.dismissed).length;return v`<details class="risk-used-all"><summary>${Y.format(i.length)} ${r}${a>0?`, ${Y.format(a)} dismissed`:``}</summary><ul>${i.map(e=>v`<li>${Li(e,t,n)}</li>`)}</ul></details>`}var zi=e=>typeof e==`string`&&/^GHSA(?:-[\da-z]{4}){3}$/iu.test(e),Bi=(e,t,n)=>w(`/api/admin/repositories/risk${e.size>0?`?${e}`:``}`,si,async e=>{for await(let t of Ut(e))n(t)},t),Vi=({name:e,version:t,integrity:n})=>`${e}@${t}\0${n??``}`,Hi=e=>W(e.source)?Vi(e):`${e.source}\0${e.name}@${e.version??``}\0${e.from??``}`;function Ui(e){if(mi(e))return-102;if(K(e))return-101;let t=fi(e);return t>0?-t:W(e.source)?t===0?3:e.risk?2:1:4}var Wi=(e,t,n,r)=>v`<div class="risk-tabs" role="tablist" aria-label="${e}">${t.map(([e,t])=>v`<button type="button" role="tab" aria-selected="${n===e}" @click="${()=>r(e)}">${t}</button>`)}</div>`,Gi=class extends b{static properties={_state:{state:!0},_error:{state:!0},_filter:{state:!0},_kind:{state:!0},_packageKind:{state:!0},_query:{state:!0},_tab:{state:!0},_actionKind:{state:!0},_files:{state:!0},_scope:{state:!0},_target:{state:!0},_choices:{state:!0}};static styles=[_(a),_(zr),_(ii)];constructor(){super(),this._state=`idle`,this._error=null,this._filter=`all`,this._kind=`production`,this._packageKind=`all`,this._actionKind=`all`,this._query=``,this._tab=`packages`,this._files=`lockfiles`,this._scan=null,this._drawTimer=null,this._parts=0,this._scope=`all`,this._target=``,this._choices=null,this._reset()}connectedCallback(){super.connectedCallback(),this._loadCollection(`teams`,`teams`,Pn,e=>{this._choices=e})}_choose(e,t=``){this._state===`running`||e===this._scope&&t===this._target||(this._scope=e,this._target=t,this._reset(),this._error=null,this._state=`idle`)}_reset(){this._repos=new Map,this._packages=new Map,this._advisories=new Map,this._actions=new $r}disconnectedCallback(){this.stop(),super.disconnectedCallback()}async start(){if(this._state===`running`||this._scope!==`all`&&!this._target)return;let e=new URLSearchParams({...this._scope===`all`?{}:{[this._scope]:this._target},scan:crypto.randomUUID()});this._reset(),this._error=null,this._state=`running`;let t=new AbortController;this._scan=t,this._parts=0;try{for(let n=`continue`,r=0;n===`continue`;){if(++this._parts>ji)throw Error(`Stopped after ${Y.format(ji)} parts. Scan again to go on from where it stopped.`);n=null;let i=this._told();if(await Bi(e,t.signal,e=>{(e.type===`done`||e.type===`continue`)&&(n=e.type),this._apply(e),this._draw()}),n===null)throw Error(`The scan ended before it finished. Try again.`);if(r=this._told()>i?0:r+1,n===`continue`&&r>=Mi)throw Error(`Stopped: the last ${Y.format(Mi)} parts found nothing more. Scan again to try once more.`)}this._state=`done`}catch(e){if(t.signal.aborted||e?.name===`AbortError`)return;this._error=e?.message??String(e),this._state=`stopped`}finally{this._scan===t&&(this._scan=null,this._state===`running`&&(this._state=`stopped`)),this._draw(!0)}}stop(){this._scan&&(this._scan.abort(),this._scan=null,this._state=`stopped`,this._draw(!0))}_draw(e=!1){if(e){clearTimeout(this._drawTimer),this._drawTimer=null,this.requestUpdate();return}this._drawTimer??=setTimeout(()=>{this._drawTimer=null,this.requestUpdate()},Ni)}_told(){let e=0;for(let t of this._repos.values()){(t.lockfiles||t.error)&&e++,t.dependabot&&e++;for(let n of t.lockfiles?.values()??[])e+=+(n.packages!==null||!!n.error)+ +!!(n.advisories||n.advisoriesError)}for(let t of this._packages.values())t.risk&&!t.risk.stale&&e++;return e+this._actions.told()}_apply(e){if(e.type===`repos`){let t=new Map(e.repos.map(({id:e,fullName:t})=>[e,t])),n=[...this._repos.values()].filter(e=>t.get(e.id)!==e.fullName);for(let e of n)this._repos.delete(e.id),this._actions.forget(e.id);this._forget(n.flatMap(e=>[...e.lockfiles?.keys()??[]].map(t=>`${e.fullName}/${t}`)),n.some(e=>e.dependabot?.alerts));for(let{id:t,fullName:n}of e.repos)this._repos.has(t)||this._repos.set(t,{id:t,fullName:n,commit:null,lockfiles:null,error:null,detail:null,dependabot:null})}else if(e.type===`repo`){let t=this._repos.get(e.id);if(!t)return;if(e.error){let n=[...t.lockfiles?.keys()??[]].map(e=>`${t.fullName}/${e}`),r=!!t.dependabot?.alerts;Object.assign(t,{lockfiles:null,error:e.error,detail:e.detail??null,dependabot:null}),this._actions.forget(t.id),this._forget(n,r);return}let n=t.commit!==null&&t.commit!==e.commit,r=new Set(n?[]:e.lockfiles.map(({path:e})=>e)),i=[...t.lockfiles?.keys()??[]].filter(e=>!r.has(e)).map(e=>`${t.fullName}/${e}`);Object.assign(t,{commit:e.commit,error:null,detail:null}),t.lockfiles=new Map(e.lockfiles.map(e=>[e.path,!n&&t.lockfiles?.get(e.path)||{...e,packages:null,error:null}])),this._forget(i)}else if(e.type===`lockfile`){let t=this._repos.get(e.repo),n=t?.lockfiles?.get(e.path);if(!n)return;if(e.error){Object.assign(n,{error:e.error,detail:e.detail??null});return}Object.assign(n,{packages:e.packages.length,error:null,detail:null});let r=`${t.fullName}/${e.path}`;for(let t of e.packages){let e=Hi(t),n=this._packages.get(e);n||this._packages.set(e,n={...t,usedIn:new Set,neededIn:new Set,risk:null}),n.usedIn.add(r),t.dev!==!0&&n.neededIn.add(r),n.dev=n.neededIn.size===0}}else if(e.type===`risk`){let t=this._packages.get(Vi(e));t&&(t.risk=Oi(e,t.risk),t.wasStale||=!!t.risk.stale)}else e.type===`advisories`?this._applyAdvisories(e):e.type===`dependabot`?this._applyDependabot(e):(e.type===`action`||(e.type===`workflows`||e.type===`workflow`)&&this._repos.has(e.repo))&&this._actions.apply(e)}_forget(e,t=!1){if(e.length===0){t&&this._readvise();return}for(let[t,n]of this._packages){for(let t of e)n.usedIn.delete(t),n.neededIn.delete(t);n.usedIn.size===0&&this._packages.delete(t),n.dev=n.neededIn.size===0}this._readvise()}_readvise(){this._advisories=new Map;for(let e of this._packages.values())e.malware=void 0;for(let e of this._repos.values())for(let[t,n]of e.lockfiles??[])n.advisories&&this._advise(`${e.fullName}/${t}`,n.advisories);this._alert()}_alerted(){return[...this._repos.values()].some(e=>e.dependabot?.alerts?.length>0)}_applyAdvisories(e){let t=this._repos.get(e.repo),n=t?.lockfiles?.get(e.path);if(!n)return;if(e.error){n.advisoriesError=e.error;return}let r=n.advisories;Object.assign(n,{advisories:e.advisories,advisoriesError:null}),!r&&!this._alerted()?this._advise(`${t.fullName}/${e.path}`,e.advisories):JSON.stringify(r)!==JSON.stringify(e.advisories)&&this._readvise()}_applyDependabot(e){let t=this._repos.get(e.repo);if(!t)return;let n=t.dependabot;t.dependabot=e.error?{...n?.alerts&&{alerts:n.alerts},error:e.error,detail:e.detail??null}:{alerts:e.alerts},JSON.stringify(n?.alerts??null)!==JSON.stringify(t.dependabot.alerts??null)&&this._readvise()}_alert(){let e=new Map,t=(e,t)=>`${e.toUpperCase()}\0${t}`;for(let n of this._advisories.values())for(let r of[n.id,n.ghsa,...n.aliases??[]])zi(r)&&!e.has(t(r,n.name))&&e.set(t(r,n.name),n);let n=[...this._repos.values()].flatMap(e=>(e.dependabot?.alerts??[]).map(t=>({repo:e,alert:t})));for(let{repo:r,alert:i}of[...n.filter(e=>!e.alert.dismissed),...n.filter(e=>e.alert.dismissed)]){let n=`${r.fullName}/${i.manifest}`,a=e.get(t(i.ghsa,i.name));if(a||!i.dismissed){if(a||(a={id:i.ghsa,ghsa:i.ghsa,name:i.name,title:i.title,severity:i.severity,url:`https://github.com/advisories/${i.ghsa}`,aliases:i.aliases,cwe:i.cwe,malware:!1,dependabot:!0,ranges:new Set,versions:new Set,usedIn:new Set,versionsIn:new Map},this._advisories.set(`${i.ghsa}\0${i.name}`,a),e.set(t(i.ghsa,i.name),a)),a.dependabot&&i.range&&a.ranges.add(i.range),a.alerts??=new Map,a.alerts.set(n,i),a.usedIn.add(n),i.versions.length>0){let e=a.versionsIn.get(n)??a.versionsIn.set(n,new Set).get(n);for(let t of i.versions)e.add(t),a.versions.add(t)}a.malware||=i.malware,this._markMalware(a)}}}_advise(e,t){for(let{range:n,versions:r,...i}of t){let t=`${i.id}\0${i.name}`,a=this._advisories.get(t);a||this._advisories.set(t,a={...i,ranges:new Set,versions:new Set,usedIn:new Set,versionsIn:new Map}),n&&a.ranges.add(n);for(let e of r)a.versions.add(e);a.malware||=i.malware,a.usedIn.add(e);let o=a.versionsIn.get(e)??a.versionsIn.set(e,new Set).get(e);for(let e of r)o.add(e);this._markMalware(a)}}_markMalware(e){if(e.malware)for(let t of this._packages.values())W(t.source)&&t.name===e.name&&e.versions.has(t.version)&&(t.malware??=new Set).add(e.id)}_counts(){let e=[...this._repos.values()],t=e.flatMap(e=>[...e.lockfiles?.values()??[]]),n=[...this._packages.values()].filter(e=>W(e.source));return{repos:e.length,reposRead:e.filter(e=>e.lockfiles||e.error).length,lockfiles:t.length,lockfilesRead:t.filter(e=>e.packages!==null||e.error).length,needed:Pi(n.filter(e=>!e.dev)),dev:Pi(n.filter(e=>e.dev)),advisories:this._adviseCounts()}}_adviseCounts(){let e=this._advisoryKinds(),t=new Set(e.production.filter(e=>!e.malware).map(e=>`${e.id}\0${e.name}`)),n=[...this._advisories.values()].filter(e=>e.malware).length;return{total:this._advisories.size,malware:n,needed:t.size,dev:this._advisories.size-n-t.size}}_rows(){let e=this._query.trim().toLowerCase(),[,t]=vi[this._filter];return[...this._packages.values()].filter(n=>gi(n,this._packageKind)&&t(n)&&(!e||n.name.toLowerCase().includes(e))).toSorted((e,t)=>Ui(e)-Ui(t)||q(t).length-q(e).length||e.name.localeCompare(t.name)||(e.version??``).localeCompare(t.version??``))}_advisoryKinds(){let e=new Map;for(let t of this._packages.values()){let n=`${t.name}@${t.version}`;W(t.source)&&e.set(n,(e.get(n)??!0)&&t.dev)}let t={production:[],development:[]};for(let n of this._advisories.values()){let r=[...n.versions],i=r.filter(t=>e.get(`${n.name}@${t}`)===!0),a=r.filter(t=>e.get(`${n.name}@${t}`)!==!0),o=[...n.alerts??[]].filter(([e])=>!n.versionsIn.get(e)?.size),s=o.filter(([,e])=>e.dev).map(([e])=>e),c=o.filter(([,e])=>!e.dev).map(([e])=>e);if(n.malware){let e={...n,dev:a.length===0&&c.length===0};t.production.push(e),t.development.push(e);continue}let l=(e,t)=>({...n,versions:new Set(e),usedIn:new Set([...n.usedIn].filter(r=>t.includes(r)||e.some(e=>n.versionsIn.get(r)?.has(e))))});(a.length>0||c.length>0)&&t.production.push({...l(a,c),dev:!1}),(i.length>0||s.length>0)&&t.development.push({...l(i,s),dev:!0})}return t}_advisoryRows(e=this._advisoryKinds()){let t=this._query.trim().toLowerCase();return e[this._kind].filter(e=>!t||e.name.toLowerCase().includes(t)).toSorted((e,t)=>Number(t.malware)-Number(e.malware)||V(e.severity)-V(t.severity)||e.name.localeCompare(t.name)||e.id.localeCompare(t.id))}_kindToggle(e,t,n,r,i){return v`<div class="risk-scope" role="group" aria-label="${e}">${Object.entries(t).map(([e,t])=>v`<button type="button" aria-pressed="${r===e}" @click="${()=>i(e)}">${t}<span class="n">${Y.format(n[e])}</span></button>`)}</div>`}_filterToggle(e){let t=Object.fromEntries(Object.entries(vi).map(([t,[,n]])=>[t,e.filter(n).length])),n=Object.entries(vi).filter(([e])=>e===`all`||e===this._filter||t[e]>0);return n.length===1?y:this._kindToggle(`Show packages`,Object.fromEntries(n.map(([e,[t]])=>[e,t])),t,this._filter,e=>{this._filter=e})}_lockfileLinks(){let e=new Map;for(let t of this._repos.values())for(let n of t.commit?t.lockfiles?.keys()??[]:[])e.set(`${t.fullName}/${n}`,ri(t.fullName,t.commit,n));return e}render(){return v`<div class="wrap">${r(`manage-repos`,this._role,this.allowShare)}<h1 class="sr-only">Repository risk</h1><div class="page-intro"><p class="intro">Risks in each repository’s npm dependencies and GitHub Actions.</p>${this._stateBadge()}${this._state===`running`?v`<button type="button" class="btn" @click="${()=>this.stop()}">Stop</button>`:v`<button type="button" class="btn primary" ?disabled="${this._scope!==`all`&&!this._target}" @click="${()=>{this.start()}}">${this._state===`idle`?`Start scan`:`Scan again`}</button>`}</div>${this._scopeBar()} ${this._progress()} ${this._error?v`<p class="msg error" role="alert">${this._error}</p>`:y} ${this._repos.size===0?y:v`<div class="manage-list">${this._lockfiles()} ${this._packages.size===0&&this._actions.files.size===0?y:this._tab===`advisories`?this._advisoryTable():this._tab===`actions`?this._actionsTable():this._packageTable()}</div>`}</div>`}_tabs(){let e=this._actions.rows(`actions`).length;return Wi(`Results`,[[`packages`,`Packages`],[`advisories`,v`Advisories${this._advisories.size>0?v`<span class="n">${Y.format(this._advisories.size)}</span>`:y}`],[`actions`,v`Actions${e>0?v`<span class="n">${Y.format(e)}</span>`:y}`]],this._tab,e=>{this._tab=e})}_search(e,t,n,r=`package`){return v`<input type="search" aria-label="${`Search ${n}`}" placeholder="${`Search by ${r}\u2026`}" .value="${this._query}" @input="${e=>{this._query=e.target.value}}"> <span class="result-count">${e===t?``:`${Y.format(e)} of `}${Y.format(t)} ${n}</span>`}_scopeBar(){let e=this._state===`running`,t=this._choices?``:`Loading…`;return v`<div class="risk-scope-bar"><div class="risk-scope" role="group" aria-label="What to scan">${ci.map(([t,n])=>v`<button type="button" aria-pressed="${this._scope===t}" ?disabled="${e}" @click="${()=>this._choose(t)}">${n}</button>`)}</div>${this._scope===`team`?this._teamPicker(e,t):y} ${this._scope===`repo`?v`<repository-selector label="Which repository" placeholder="${t||`Choose a repository…`}" ?disabled="${e||!this._choices}" .options="${(this._choices?.repos??[]).map(e=>({value:String(e.repoId),label:e.fullName}))}" .value="${this._target||null}" @repository-change="${e=>this._choose(`repo`,e.detail.value)}"></repository-selector>`:y}</div>`}_teamPicker(e,t){let n=this._choices?.teams??[],r=e=>e.hidden?`${e.name} (hidden)`:e.name;return n.length>0&&n.length<=li?v`<div class="risk-scope" role="group" aria-label="Which team">${n.map(t=>v`<button type="button" aria-pressed="${t.id===this._target}" ?disabled="${e}" @click="${()=>this._choose(`team`,t.id)}">${r(t)}</button>`)}</div>`:v`<select aria-label="Which team" ?disabled="${e}" @change="${e=>this._choose(`team`,e.target.value)}"><option value="" ?selected="${!this._target}">${t||`Choose a team…`}</option>${n.map(e=>v`<option value="${e.id}" ?selected="${e.id===this._target}">${r(e)}</option>`)}</select>`}_metrics(){let e=this._counts(),{needed:t,dev:n,advisories:r}=e,i=e=>Y.format(e),a=e=>({bar:e.map(([e,t])=>[e,t]),split:e.filter(([,e,t=e])=>t>0)}),o=t.flagged+n.flagged,s=t.stale+n.stale,c=t.wasStale+n.wasStale,{workflows:l,workflowsRead:u}=this._actions.counts();return[{label:`Repositories`,value:e.reposRead,of:e.repos,bar:[[`read`,e.reposRead]],split:[[`lockfiles`,e.lockfilesRead,e.lockfiles],[`workflows`,u,l]].filter(([,,e])=>e>0)},{label:`Packages`,value:t.told+n.told,of:t.total+n.total,...a([[`prod`,t.told,t.total],[`dev`,n.told,n.total]])},{label:`Flagged`,value:o,...a([[`prod`,t.flagged],[`dev`,n.flagged]]),tone:o>0?`high`:null},...c>0?[{label:`Stale`,value:s,scale:c,bar:[[`prod`,t.wasStale-t.stale],[`dev`,n.wasStale-n.stale]],split:a([[`prod`,t.stale],[`dev`,n.stale]]).split,note:[...s>0?[`Assessed over an hour ago; ${this._state===`running`?`to be assessed again once the rest are`:`not assessed again yet`}.`]:[],`${i(c-s)} of ${i(c)} assessed again.`]}]:[],...r.total>0?[{label:`Advisories`,value:r.total,...a([[`malware`,r.malware],[`prod`,r.needed],[`dev`,r.dev]])}]:[],...this._actionsMetrics()]}_actionsMetrics(){if(this._actions.listed.size===0)return[];let{actions:e,resolved:t}=this._actions.counts(),n=this._actions.rows(`all`).filter(e=>e.severity&&e.severity!==`notice`&&e.severity!==`low`).length;return[{label:`Actions`,value:t,of:e,bar:[[`read`,t]]},{label:`Actions flagged`,value:n,bar:[],tone:n>0?`high`:null}]}_stateBadge(){if(this._state===`idle`)return y;let e=this._state===`running`&&this._parts>1?`Scanning \xB7 part ${Y.format(this._parts)}`:{running:`Scanning`,stopped:`Stopped`,done:`Done`}[this._state];return v`<span class="risk-state" role="status" data-state="${this._state}">${e}</span>`}_progress(){if(this._state===`idle`)return v`<div class="risk-progress" role="status"><p class="risk-progress-idle">Not scanned yet. A scan reads each repository from GitHub and assesses each npm package it locks, which can take a while; a scan again within the hour is quicker.</p></div>`;let e=e=>Y.format(e),t=({split:t=[],note:n=[]})=>[t.length>0?`${t.map(([t,n,r])=>`${e(n)}${r===void 0?``:`/${e(r)}`} ${t}`).join(`, `)}.`:``,...n].filter(Boolean).join(` `),n=({split:t=[],note:n=[]})=>v`${t.length>0?v`<div class="tooltip-counts">${t.map(([t,n,r])=>v`<span class="tooltip-count">${e(n)}${r===void 0?y:v`<span class="tooltip-count-of"><span class="tooltip-slash">/</span>${e(r)}</span>`}</span><span>${t}</span>`)}</div>`:y}${n.map(e=>v`<div class="tooltip-counts-note">${e}</div>`)}`;return v`<div class="risk-progress" role="status">${this._metrics().map(r=>{let{label:i,value:a,of:o,scale:s=o??a,bar:c,tone:l}=r,u=t(r);return v`<span class="${l?`risk-metric risk-${l}`:`risk-metric`}" data-tooltip="${u||y}" .tooltipContent="${u?n(r):null}"><span class="risk-metric-label">${i}</span> <span class="risk-metric-value">${e(a)}${o===void 0?y:v`<span class="risk-metric-of"><span class="risk-metric-slash">/</span>${e(o)}</span>`}${u?v`<span class="sr-only">${u}</span>`:y}</span> <span class="risk-bar" aria-hidden="true">${c.filter(([,e])=>e>0).map(([e,t])=>v`<span class="${`risk-bar-${e}`}" style="${Be({width:`${t/s*100}%`})}"></span>`)}</span></span>`})}</div>`}_pending(e,t){return v`<span class="risk-pending">${this._state===`running`?e:t}</span>`}_repoStatus(e,t=!1){if(e.error)return U(e);if(e.lockfiles===null)return this._pending(`Waiting…`,`Not read`);if(!t)return e.lockfiles.size===0?v`<span class="risk-none">No npm lockfiles</span>`:null;let n=this._actions.listed.get(e.id);return n?n.error||this._actions.filesOf(e.id).length>0?null:v`<span class="risk-none">No workflows</span>`:this._pending(`Waiting…`,`Not read`)}_lockfileStatus(e){return e.error?U(e):e.packages===null?this._pending(`Reading…`,`Not read`):`${Y.format(e.packages)} packages`}_lockfiles(){let e=this._actions.listed.size>0&&this._files===`workflows`;return v`<section class="risk-section" aria-label="Lockfiles and workflows">${this._actions.listed.size>0?Wi(`Files`,[[`lockfiles`,`Lockfiles`],[`workflows`,`Workflows`]],this._files,e=>{this._files=e}):v`<h2>Lockfiles</h2>`}<ul class="risk-repos">${[...this._repos.values()].map(t=>v`<li><span class="risk-repo-name" data-tooltip-truncated data-tooltip="${t.fullName}">${t.fullName}</span> ${this._repoStatus(t,e)??v`<ul class="risk-lockfiles">${e?this._workflowItems(t):[...t.lockfiles.values()].map(e=>v`<li><span class="mono">${e.path}</span><span class="risk-lockfile-meta">${e.format} · ${this._lockfileStatus(e)}</span></li>`)}</ul>`}</li>`)}</ul></section>`}_workflowItems(e){let t=this._actions.listed.get(e.id);return t?t.error?v`<li><span class="mono">.github/workflows</span><span class="risk-lockfile-meta">${U(t)}</span></li>`:this._actions.filesOf(e.id).map(e=>v`<li><span class="mono">${e.path}</span><span class="risk-lockfile-meta">${e.kind} · ${e.error?U(e):`${Y.format(e.findings.length)} findings`}</span></li>`):y}_resultsHead(e){return v`<div class="risk-results-head">${this._tabs()}<div class="collection-toolbar">${e}</div></div>`}_packageTable(){let e=this._rows(),t=[...this._packages.values()],n=Object.fromEntries(Object.keys(wi).map(e=>[e,t.filter(t=>gi(t,e)).length])),r=this._lockfileLinks(),i=t.some(e=>e.source!==`registry`);return v`<section class="risk-section" aria-label="Packages">${this._resultsHead(v`${this._kindToggle(`Which packages`,wi,n,this._packageKind,e=>{this._packageKind=e})} ${this._filterToggle(t.filter(e=>gi(e,this._packageKind)))} ${this._search(e.length,n[this._packageKind],`packages`)}`)}<div class="link-table"><table><thead><tr><th>Package</th><th><span data-tooltip="${yi}">Risk</span></th><th>Findings</th>${i?v`<th>Source</th>`:y}<th class="risk-used-column">Used in</th></tr></thead><tbody>${Ve(e.slice(0,J),Hi,e=>this._packageRow(e,r,i))}</tbody></table></div>${e.length>J?v`<p class="msg">Showing the first ${Y.format(J)}. Search or filter to see others.</p>`:y}</section>`}_packageRow(e,t,n){let r=W(e.source)?h({view:`npm`,packageName:e.name,packageSpec:e.version}):null;return v`<tr class="${e.risk?.stale?`is-stale`:``}"><td>${Ei(e,e.version,r,bi)}</td><td>${this._score(e)}</td><td>${this._findings(e)}</td>${n?v`<td><span data-tooltip="${e.from??y}">${ui[e.source]??e.source}${e.source===`mirror`&&e.from?` (${new URL(e.from).host})`:``}</span></td>`:y}<td>${Ri(e.usedIn,t)}</td></tr>`}_score(e){let t=fi(e),n=t===null?y:v`<span class="${`risk-score risk-${Kr(t)}`}">${t}</span>`;return e.risk?.stale?v`${n}<span class="risk-stale" data-tooltip="${this._staleSaid(e.risk)}">stale</span>`:n}_staleSaid({stale:e,refreshFailed:t}){let n=t?`couldn\u2019t be assessed again: ${t}`:this._state===`running`?`to be assessed again once the rest are`:`not assessed again yet`;return`Assessed ${Ai(e.assessedAt)}; ${n}`}_findings(e){let t=q(e);return t.length>0?v`<ul class="risk-findings">${t.map(t=>v`<li class="${`risk-${t.severity}`}" data-tooltip="${t.id===`malware`?pi(e).join(`
23
+ `):y}">${ai[t.id]??t.id}</li>`)}</ul>`:W(e.source)?e.risk?K(e)?v`<ul class="risk-findings"><li class="risk-critical" data-tooltip="${Si}">${H(e.risk.error)}</li></ul>`:e.risk.error?U(e.risk):v`<span class="risk-none">None found</span>`:this._pending(`Waiting…`,`Not assessed`):v`<span class="risk-none">Not assessed</span>`}_advisoryTable(){let e=this._advisoryKinds(),t=this._lockfileLinks(),n=this._advisoryRows(e),r=[...this._repos.values()].flatMap(e=>[...e.lockfiles?.values()??[]].filter(e=>e.advisoriesError).map(t=>`${e.fullName}/${t.path}`)),i=this._kind===`production`?`the versions an install for production takes`:`the versions only devDependencies need`,a=this._alerted()?`Neither npm nor Dependabot tells of advisories of ${i}.`:`npm has no advisories of ${i}.`;return v`<section class="risk-section" aria-label="Advisories">${this._resultsHead(v`${this._kindToggle(`Which advisories`,Ci,{production:e.production.length,development:e.development.length},this._kind,e=>{this._kind=e})}${this._search(n.length,e[this._kind].length,`advisories`)}`)} ${this._dependabotStatus()} ${r.length>0?v`<p class="msg error">npm’s advisories couldn’t be had for <span data-tooltip="${r.join(`
24
+ `)}">${r.length===1?r[0]:`${Y.format(r.length)} lockfiles`}</span>.</p>`:y} ${this._table(n,this._state===`running`?`None yet.`:a,v`<th>Package</th><th>Versions</th><th>Severity</th><th>Advisory</th><th>Title</th><th>Affected</th><th>Used in</th>`,e=>`${e.id}\0${e.name}`,e=>this._advisoryRow(e,t))}</section>`}_actionsTable(){let e=Object.fromEntries(Object.keys(Jr).map(e=>[e,this._actions.rows(e).length])),t=this._actions.rows(this._actionKind,this._query),n=this._state===`running`?`None yet.`:this._actions.listed.size===0?`No workflows were read.`:`Nothing found.`;return v`<section class="risk-section" aria-label="Actions">${this._resultsHead(v`${this._kindToggle(`Which`,Jr,e,this._actionKind,e=>{this._actionKind=e})} ${this._search(t.length,e[this._actionKind],`rows`,`name`)}`)} ${this._table(t,n,v`<th>Uses</th><th>Pinned to</th><th>Findings</th><th class="risk-used-column">Used in</th>`,e=>e.key,e=>this._actionRow(e))}</section>`}_table(e,t,n,r,i){return v`${e.length===0?v`<p class="msg">${t}</p>`:v`<div class="link-table"><table><thead><tr>${n}</tr></thead><tbody>${Ve(e.slice(0,J),r,i)}</tbody></table></div>`} ${e.length>J?v`<p class="msg">Showing the first ${Y.format(J)}. Search to see others.</p>`:y}`}_actionRow(e){let t=e.kind===`action`?ni(e):null,n=e.key.replace(/^[^@]*@/u,``).replace(/^([\da-f]{7})[\da-f]{33}\b/u,`$1`),r=e.kind===`action`?v`<span data-tooltip="${e.key}">${e.key.replace(/@.*$/u,``)}<span class="risk-version">@${n}</span></span>`:e.name,i=e.line?.error?U(e.line):e.kind===`action`&&!e.line?this._pending(`Resolving…`,`Not resolved`):y;return v`<tr><td><span class="risk-package">${X(e.kind===`action`?Ze:Ye)}${t?v`<a class="risk-name mono" href="${t}" target="_blank" rel="noopener noreferrer">${r}</a>`:v`<span class="mono">${r}</span>`}</span></td><td class="mono">${ei(e.line)??i}</td><td>${e.findings.length>0?ti(e.findings):e.line&&!e.line.error?v`<span class="risk-none">None found</span>`:y}</td><td>${this._actionUsedIn(e.usedIn)}</td></tr>`}_actionUsedIn(e){let t=new Map;return Ri(e.map(({repo:e,path:n,line:r,via:i})=>{if(i)return`via ${i}`;let{fullName:a=String(e),commit:o}=this._repos.get(e)??{},s=`${a}/${n}:${r}`;return o&&t.set(s,`${ri(a,o,n)}${r?`#L${r}`:``}`),s}),t,void 0,`places`)}_advisoryRow(e,t){let n=[...e.versions],r=e.malware?`critical`:e.severity;return v`<tr><td>${Ei({...e,source:`registry`},null,h({view:`npm`,packageName:e.name,packageSpec:n[0]}),xi)}</td><td class="mono">${n.join(`, `)}</td><td>${e.malware?v`<span class="risk-chip risk-critical">Malware</span>`:r?v`<span class="${`risk-chip risk-${r}`}">${_i(r)}</span>`:y}</td><td class="mono">${Ue(e.url)?v`<a href="${e.url}" target="_blank" rel="noopener noreferrer">${e.id}</a>`:e.id}</td><td><span class="risk-clip" data-tooltip-truncated data-tooltip="${e.title??y}">${e.title??``}</span></td><td class="mono">${[...e.ranges].join(` || `)}</td><td>${Ri(e.usedIn,t,e.alerts)}</td></tr>`}_dependabotStatus(){let e=[...this._repos.values()].filter(e=>e.dependabot);if(e.length===0)return y;let t=e.filter(e=>e.dependabot.alerts),n=e.filter(e=>e.dependabot.error),r=(e,t,n=`${t}s`)=>`${Y.format(e)} ${e===1?t:n}`,i=e=>{let t=e.filter(e=>e.dismissed).length,n=e.length-t;return t===0?r(n,`open alert`):`${Y.format(n)} open and ${Y.format(t)} dismissed ${e.length===1?`alert`:`alerts`}`},a=n.map(({fullName:e,dependabot:{error:t,detail:n}})=>`${e}: ${H(t)}${n?` (${n})`:``}`).join(`
25
+ `);return v`<p class="risk-dependabot" role="status">${X(Qe)}<span>Dependabot</span> ${t.length>0?v`<span data-tooltip="${t.map(e=>`${e.fullName}: ${i(e.dependabot.alerts)}`).join(`
26
+ `)}">${i(t.flatMap(e=>e.dependabot.alerts))} of ${r(t.length,`repository`,`repositories`)}</span>`:y} ${n.length>0?v`<span class="risk-dependabot-failed" data-tooltip="${a}">${t.length>0?`unavailable for `:`alerts unavailable for `}${n.length===1?n[0].fullName:r(n.length,`repository`,`repositories`)}${n.length===1?v`: ${H(n[0].dependabot.error)}`:y}</span>`:y}</p>`}};customElements.define(`managed-admin-repo-risk`,Gi);function Ki({signal:e}={}){return Yi(`/api/auth/profile`,{signal:e},`load your profile`)}function qi(e,t,{signal:n}={}){return Yi(`/api/auth/profile`,{method:`POST`,body:JSON.stringify(e),csrfToken:t,signal:n},`save your profile`)}function Ji(e,t,{signal:n}={}){return Yi(`/api/auth/profile/accounts/${encodeURIComponent(e)}`,{method:`DELETE`,csrfToken:t,signal:n},`unlink the account`)}async function Yi(e,{method:t=`GET`,body:n,csrfToken:r,signal:i},a){let o=await d(e,{method:t,credentials:`same-origin`,signal:i,...n?{body:n}:{},headers:{accept:`application/json`,...n?{"content-type":`application/json`}:{},...r?{"x-csrf-token":r}:{}}}),s=await o.json().catch(()=>null),c=o.ok?Xi(s?.profile):null;if(!c)throw Error(`Could not ${a} (${o.ok?`unreadable answer`:s?.error??o.status}).`);return c}function Xi(e){let t=e=>typeof e==`string`?e:null;return typeof e?.login!=`string`||!Array.isArray(e.accounts)?null:{login:e.login,name:t(e.name),githubName:t(e.githubName),nameAccount:t(e.nameAccount),avatarAccount:t(e.avatarAccount),accounts:e.accounts.filter(e=>typeof e?.id==`string`&&typeof e.login==`string`).map(e=>({id:e.id,login:e.login,name:t(e.name),linkedAt:Number.isSafeInteger(e.linkedAt)?e.linkedAt:null}))}}function Zi(e,t){return new Promise(n=>{if(t.aborted){n();return}let r=()=>{clearTimeout(i),t.removeEventListener(`abort`,r),n()},i=setTimeout(r,e);t.addEventListener(`abort`,r,{once:!0})})}async function Qi(e,{signal:t,onUpdate:n,onTeams:r,onClose:i,reportId:a=null}){if(l())return;let o=1e3,s=async(e,t,a)=>{if(a.throwIfAborted(),e===`close`)return await i(),!1;if(e===`triage`||e===`teams`){let i=null;if(e===`teams`)try{let e=JSON.parse(t);typeof e?.revision==`string`&&(i=e.revision)}catch{}if(await(e===`teams`?r?.(a,i):n(a))===!1)throw Error(`Team refresh failed`);a.throwIfAborted(),o=1e3}return!0};for(;!t.aborted;){let n=new AbortController,r=()=>n.abort();t.addEventListener(`abort`,r,{once:!0});let c,l,u=()=>{clearTimeout(l),l=setTimeout(r,45e3)};try{u();let r=a===null?``:`?reportId=${encodeURIComponent(a)}`,o=await d(e?`/api/teams/${encodeURIComponent(e)}/feed${r}`:`/api/teams/feed`,{credentials:`same-origin`,headers:{accept:`text/event-stream`},signal:n.signal});if([401,403,404].includes(o.status)){await o.body?.cancel(),t.aborted||await i();return}if(!o.ok||!o.headers.get(`content-type`)?.startsWith(`text/event-stream`))throw await o.body?.cancel(),Error(`Team feed unavailable`);if(c=o.body.getReader(),await $i(c,t,u,(e,t)=>s(e,t,n.signal)))return}catch{}finally{clearTimeout(l),r(),await c?.cancel().catch(()=>{}),t.removeEventListener(`abort`,r)}await Zi(o,t),o=Math.min(o*2,3e4)}}async function $i(e,t,n,r){let i=new TextDecoder,a=``;for(;!t.aborted;){let{done:o,value:s}=await e.read();if(o)return!1;if(n(),a=(a+i.decode(s,{stream:!0})).replaceAll(`\r
22
27
  `,`
23
- `),o.length>16384)throw new Error("Team feed frame too large");let c;for(;(c=o.indexOf(`
28
+ `),a.length>16384)throw Error(`Team feed frame too large`);let c;for(;(c=a.indexOf(`
24
29
 
25
- `))!==-1;){let p=o.slice(0,c);o=o.slice(c+2);let u=p.split(`
26
- `).find(_=>_.startsWith("event:"))?.slice(6).trim(),v=p.split(`
27
- `).filter(_=>_.startsWith("data:")).map(_=>_.slice(5).trimStart()).join(`
28
- `);if(e.aborted||await i(u,v)===!1)return!0}}return!0}var Bi=s=>`reports:content:${s}`;async function tt(s,e){let t=Bi(s),i=g.read(t);if(i!==void 0)return i;try{return await g.load(t,"report",async r=>{let o=await e(r);if(o===null)throw new Error("Could not load report");return o})}catch{return null}}function ds(s){return tt(s,e=>oe(s,{signal:e}))}async function cs(s){let e=[...new Set(s)].filter(r=>{let o=g.resources.get(Bi(r));return o?.data===void 0&&!o?.pending}).toSorted(),t,i=await Promise.all(s.map(r=>tt(r,async o=>(t??=ht(e,{signal:o}),(await t)?.[e.indexOf(r)]??null))));return i.some(r=>r===null)?null:i}function ps(s,{reportId:e=null}={}){let t=e===null?"":`:${e}`;return tt(`team:${s}${t}`,i=>mt(s,{signal:i,reportId:e}))}async function it(s,e){let t=await m(s,{credentials:"same-origin",signal:e});if(!t.ok)throw new Error(`Could not load link report (HTTP ${t.status})`);return t.json()}async function us(s,{signal:e}={}){let t=await it(`/api/admin/deduplication/${encodeURIComponent(s)}`,e),i=await it("/api/admin/reports",e),r=new Set(t.groups.flat()),o=[],n=0,l=await Promise.allSettled(Array.from({length:Math.min(4,i.reports.length)},async()=>{for(;n<i.reports.length;){e?.throwIfAborted();let c=n++,p=i.reports[c],u=await oe(p.id,{signal:e});if(!u)throw new Error(`Could not load ${p.filename}. Reopen this link report to try again.`);let _=(lt(u.data)??[]).filter(S=>(Array.isArray(S)?S:[S]).some(R=>r.has(R?.id)));_.length>0&&(o[c]={id:p.id,filename:p.filename,repo:u.repo,data:{...u.data,[Array.isArray(u.data.findings)?"findings":"groups"]:_}})}}));for(let c of l)if(c.status==="rejected")throw c.reason;return await it(`/api/admin/deduplication/${encodeURIComponent(s)}`,e),[...o.filter(Boolean),{id:t.id,filename:t.filename,repo:{github:null,directory:""},data:{source:"links",findings:[],links:t.groups}}]}function me(s,e){return g.resources.get(`report-sources:${e??""}:${s}`)}function hs(){g.invalidate(["report-sources"])}async function ms(s,e){let t=`report-sources:${e??""}:${s}`,i=me(s,e);if(i?.data!==void 0)return i.data;if(i?.error)return null;let r=g.load(t,"report sources",async n=>{let l=await m(`/api/reports/${encodeURIComponent(s)}/sources${gt(e)}`,{credentials:"same-origin",signal:n});if(l.status===204||l.status===404)return null;if(!l.ok)throw new Error(`Sources request failed (${l.status})`);let c=await l.json();return{integrity:c.integrity,sources:new Map(c.files),paths:new Map(c.paths),imports:new Map((c.imports??[]).map(([p,u])=>[p,new Map(u)])),formats:new Map(c.formats??[]),packageDirs:new Map(c.packageDirs??[])}}),o=me(s,e);try{return await r}catch(n){if(n.name!=="AbortError"){let l=me(s,e);l===o&&(l.error=n)}throw n}}var gs={"review-content-changed":"The package bytes changed. Reload the package before reviewing.","review-conflict":"This review changed or was published in another tab. Reload the page before editing it again.","package-not-found":"One of these package versions is no longer available to you.","unknown-review-file":"This file is not in the comparison.","non-text-review-file":"Verdicts for non-text files are not supported yet.","bad-review-teams":"Select at least one team you belong to with dependency review enabled. Refresh if team access changed.","no-reviewed-files":"Review at least one changed file before publishing.","package-json-not-reviewed":"Review package.json before publishing a partial review.","bad-final-verdict":"Choose a final verdict no more favorable than the file verdicts.","review-malware":"Malware detected. Only Reject is available.","review-critical-vulnerability":"Critical vulnerabilities detected. Choose Request changes or Reject.",forbidden:"Reviewing requires triage access."};async function ge(s,e,t,i,r){let o=g.generation,n=await m(`/api/npm/reviews${s}`,{credentials:"same-origin",signal:AbortSignal.any([e,g.sessionController.signal]),...i?{method:"POST",headers:{"content-type":"application/json","x-csrf-token":r},body:JSON.stringify(i)}:{}}),l=await n.json();if(o!==g.generation||e.aborted)throw new DOMException("Session changed","AbortError");if(!n.ok)throw new Error(gs[l.error]??`Could not ${t} (${n.status}).`);return l}function fs(s,e){let t=s?`?${new URLSearchParams({beforeTime:s.time,beforeId:s.id})}`:"";return ge(`/mine${t}`,e,"load your reviews")}function bs(s,e,t,i){return ge("/discard",i,"discard review",{reviewId:s,revision:e},t)}async function vs(s,e){let t=new URLSearchParams({package:s.package,version:s.version,integrity:s.integrity});return(await ge(`/latest?${t}`,e,"load your latest review")).review}function _s(s,e,t,i){let r=new URLSearchParams(Object.entries(s).filter(([,o])=>o!==null));return ge(e?"":`?${r}`,i,`${e?"save":"load"} reviews`,e&&{...s,...e},t)}function Dn(){g.invalidate(["finding-history"])}async function zn(){(await import("./client-managed-import.js")).registerWorkspaceImport(b,m)}async function Bn(...s){return(await import("./chunk-UTR2LVME.js")).openManagedShareDialog(...s)}async function Mn(s){return(await import("./chunk-GZ4MS3TE.js")).openManagedIssueDialog(s)}async function qn(s){return(await import("./chunk-UNTRGE26.js")).openFindingHistoryDialog(s)}export{Ls as changeWorkspaceShare,Dn as clearFindingHistory,hs as clearReportSources,Cs as deleteReportComment,_s as dependencyReviews,bs as discardDependencyReview,Os as downloadManagedBundle,Ki as fetchBundleAdvisories,hr as fetchBundleComparison,Gi as fetchBundleContents,we as fetchBundleMetadata,or as fetchBundleRenameDiff,lr as fetchBundleRenameDiffs,cr as fetchBundleTypeOnly,xs as fetchFixes,Hi as fetchManagedBundleCatalog,us as fetchManagedLinkWorkspace,Yi as fetchNpmAdvisories,mr as fetchNpmComparison,Vi as fetchNpmPackage,er as fetchNpmProvenance,nr as fetchNpmRenameDiff,dr as fetchNpmRenameDiffs,Qi as fetchNpmRisk,Zi as fetchNpmSocket,Ji as fetchNpmStats,Xi as fetchNpmTags,pr as fetchNpmTypeOnly,Wi as fetchNpmVersions,sr as fetchPrettyBundleChanges,tr as fetchPrettyBundleFile,ar as fetchPrettyNpmChanges,ir as fetchPrettyNpmFile,rr as fetchPrettyNpmFiles,ds as fetchReport,Rs as fetchReportComments,ms as fetchReportSources,ks as fetchReportTriage,cs as fetchReports,$s as fetchTeamAnnotations,ps as fetchTeamReports,P as getPreviewRole,vs as latestDependencyReview,Ns as listWorkspaceShares,zn as loadWorkspaceImportPage,As as login,Ts as logout,fs as myDependencyReviews,qn as openFindingHistoryDialog,Mn as openManagedIssueDialog,Bn as openManagedShareDialog,ys as probeSession,ws as probeTeams,Es as pushReportTriage,me as readReportSources,ji as resetManagedAppState,Ss as saveReportComment,Ui as setManagedAppSession,Fi as setManagedReportCatalog,qi as setPreviewRole,Is as stopViewing,gt as teamQuery,ft as viewAs,ns as watchTeamFeed};
29
- /*! Bundled license information:
30
-
31
- lit-html/directives/if-defined.js:
32
- (**
33
- * @license
34
- * Copyright 2018 Google LLC
35
- * SPDX-License-Identifier: BSD-3-Clause
36
- *)
37
- */
30
+ `))!==-1;){let e=a.slice(0,c);a=a.slice(c+2);let n=e.split(`
31
+ `).find(e=>e.startsWith(`event:`))?.slice(6).trim(),i=e.split(`
32
+ `).filter(e=>e.startsWith(`data:`)).map(e=>e.slice(5).trimStart()).join(`
33
+ `);if(t.aborted||await r(n,i)===!1)return!0}}return!0}var ea=e=>`reports:content:${e}`;async function ta(e,t){let n=ea(e),r=f.read(n);if(r!==void 0)return r;try{return await f.load(n,`report`,async e=>{let n=await t(e);if(n===null)throw Error(`Could not load report`);return n})}catch{return null}}function na(e){return ta(e,t=>ae(e,{signal:t}))}async function ra(e){let t=[...new Set(e)].filter(e=>{let t=f.resources.get(ea(e));return t?.data===void 0&&!t?.pending}).toSorted(),n,r=await Promise.all(e.map(e=>ta(e,async r=>(n??=oe(t,{signal:r}),(await n)?.[t.indexOf(e)]??null))));return r.some(e=>e===null)?null:r}function ia(e,{reportId:t=null}={}){return ta(`team:${e}${t===null?``:`:${t}`}`,n=>se(e,{signal:n,reportId:t}))}async function Z(e,t){let n=await d(e,{credentials:`same-origin`,signal:t});if(!n.ok)throw Error(`Could not load link report (HTTP ${n.status})`);return n.json()}async function aa(e,{signal:t}={}){let n=await Z(`/api/admin/deduplication/${encodeURIComponent(e)}`,t),r=await Z(`/api/admin/reports`,t),i=new Set(n.groups.flat()),a=[],o=0,s=await Promise.allSettled(Array.from({length:Math.min(4,r.reports.length)},async()=>{for(;o<r.reports.length;){t?.throwIfAborted();let e=o++,n=r.reports[e],s=await ae(n.id,{signal:t});if(!s)throw Error(`Could not load ${n.filename}. Reopen this link report to try again.`);let c=(Ge(s.data)??[]).filter(e=>(Array.isArray(e)?e:[e]).some(e=>i.has(e?.id)));c.length>0&&(a[e]={id:n.id,filename:n.filename,repo:s.repo,data:{...s.data,[Array.isArray(s.data.findings)?`findings`:`groups`]:c}})}}));for(let e of s)if(e.status===`rejected`)throw e.reason;return await Z(`/api/admin/deduplication/${encodeURIComponent(e)}`,t),[...a.filter(Boolean),{id:n.id,filename:n.filename,repo:{github:null,directory:``},data:{source:`links`,findings:[],links:n.groups}}]}function Q(e,t){return f.resources.get(`report-sources:${t??``}:${e}`)}function oa(){f.invalidate([`report-sources`])}async function sa(e,t){let n=`report-sources:${t??``}:${e}`,r=Q(e,t);if(r?.data!==void 0)return r.data;if(r?.error)return null;let i=f.load(n,`report sources`,async n=>{let r=await d(`/api/reports/${encodeURIComponent(e)}/sources${ce(t)}`,{credentials:`same-origin`,signal:n});if(r.status===204||r.status===404)return null;if(!r.ok)throw Error(`Sources request failed (${r.status})`);let i=await r.json();return{integrity:i.integrity,sources:new Map(i.files),paths:new Map(i.paths),imports:new Map((i.imports??[]).map(([e,t])=>[e,new Map(t)])),formats:new Map(i.formats??[]),packageDirs:new Map(i.packageDirs??[])}}),a=Q(e,t);try{return await i}catch(n){if(n.name!==`AbortError`){let r=Q(e,t);r===a&&(r.error=n)}throw n}}var ca={"review-content-changed":`The package bytes changed. Reload the package before reviewing.`,"review-conflict":`This review changed or was published in another tab. Reload the page before editing it again.`,"package-not-found":`One of these package versions is no longer available to you.`,"unknown-review-file":`This file is not in the comparison.`,"non-text-review-file":`Verdicts for non-text files are not supported yet.`,"bad-review-teams":`Select at least one team you belong to with dependency review enabled. Refresh if team access changed.`,"no-reviewed-files":`Review at least one changed file before publishing.`,"package-json-not-reviewed":`Review package.json before publishing a partial review.`,"bad-final-verdict":`Choose a final verdict no more favorable than the file verdicts.`,"review-malware":`Malware detected. Only Reject is available.`,"review-critical-vulnerability":`Critical vulnerabilities detected. Choose Request changes or Reject.`,forbidden:`Reviewing requires triage access.`,"no-team":`This team’s reviews aren’t available to you.`};async function $(e,t,n,r,i){let a=f.generation,o=await d(`/api/npm/reviews${e}`,{credentials:`same-origin`,signal:AbortSignal.any([t,f.sessionController.signal]),...r?{method:`POST`,headers:{"content-type":`application/json`,"x-csrf-token":i},body:JSON.stringify(r)}:{}}),s=await o.json();if(a!==f.generation||t.aborted)throw new DOMException(`Session changed`,`AbortError`);if(!o.ok)throw Error(ca[s.error]??`Could not ${n} (${o.status}).`);return s}function la(e,t){return $(`/mine${e?`?${new URLSearchParams({beforeTime:e.time,beforeId:e.id})}`:``}`,t,`load your reviews`)}function ua(e,t,n){return $(`/team?${new URLSearchParams({teamId:e,...t?{beforeTime:t.time,beforeId:t.id}:{}})}`,n,`load the team’s reviews`)}function da(e,t,n,r){return $(`/discard`,r,`discard review`,{reviewId:e,revision:t},n)}async function fa(e,t){return(await $(`/latest?${new URLSearchParams({package:e.package,version:e.version,integrity:e.integrity})}`,t,`load your latest review`)).review}function pa(e,t,n,r){let i=new URLSearchParams(Object.entries(e).filter(([,e])=>e!==null));return $(t?``:`?${i}`,r,`${t?`save`:`load`} reviews`,t&&{...e,...t},n)}function ma(){f.invalidate([`finding-history`])}async function ha(){(await import(`./client-managed-import.js`)).registerWorkspaceImport(b,d)}export{o as changeWorkspaceShare,qi as chooseProfileAccounts,ma as clearFindingHistory,oa as clearReportSources,me as deleteReportComment,pa as dependencyReviews,da as discardDependencyReview,s as downloadManagedBundle,Ot as fetchBranchDependencies,dt as fetchBrowsableRepositories,ct as fetchBundleAdvisories,sn as fetchBundleComparison,st as fetchBundleContents,at as fetchBundleMetadata,Yt as fetchBundleRenameDiff,Qt as fetchBundleRenameDiffs,en as fetchBundleTypeOnly,de as fetchFixes,it as fetchManagedBundleCatalog,aa as fetchManagedLinkWorkspace,Ft as fetchNpmAdvisories,cn as fetchNpmComparison,rn as fetchNpmDelta,Mt as fetchNpmPackage,zt as fetchNpmProvenance,Xt as fetchNpmRenameDiff,$t as fetchNpmRenameDiffs,Rt as fetchNpmRisk,Lt as fetchNpmSocket,Pt as fetchNpmStats,It as fetchNpmTags,tn as fetchNpmTypeOnly,Nt as fetchNpmVersions,Gt as fetchPrettyBundleChanges,Bt as fetchPrettyBundleFile,Kt as fetchPrettyNpmChanges,Vt as fetchPrettyNpmFile,Wt as fetchPrettyNpmFiles,Ki as fetchProfile,Tt as fetchPullDependencies,Et as fetchPullDependenciesOf,na as fetchReport,fe as fetchReportComments,sa as fetchReportSources,ue as fetchReportTriage,ra as fetchReports,xt as fetchRepositoryAgents,_t as fetchRepositoryChanges,ut as fetchRepositoryCode,pt as fetchRepositoryContents,ht as fetchRepositoryHistory,yt as fetchRepositoryIssues,Ct as fetchRepositoryItem,At as fetchRepositoryPulse,jt as fetchRepositoryPulseItems,ft as fetchRepositoryRefs,vt as fetchRepositoryTree,le as fetchTeamAnnotations,ia as fetchTeamReports,l as getPreviewRole,fa as latestDependencyReview,be as listWorkspaceShares,ha as loadWorkspaceImportPage,ge as login,_e as logout,la as myDependencyReviews,xe as openFindingHistoryDialog,we as openManagedIssueDialog,Te as openManagedShareDialog,re as probeSession,ie as probeTeams,he as pushReportTriage,Q as readReportSources,ne as resetManagedAppState,pe as saveReportComment,ee as setManagedAppSession,te as setManagedReportCatalog,u as setPreviewRole,ye as stopViewing,ua as teamDependencyReviews,ce as teamQuery,Ji as unlinkGithubAccount,ve as viewAs,Qi as watchTeamFeed};