@samyx/preview-stacks-ui 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/assets/{ActionButton.vue_vue_type_script_setup_true_lang-C0iLjBml.js → ActionButton.vue_vue_type_script_setup_true_lang-Dxrs5ae4.js} +2 -2
  2. package/dist/assets/{ActionButton.vue_vue_type_script_setup_true_lang-C0iLjBml.js.map → ActionButton.vue_vue_type_script_setup_true_lang-Dxrs5ae4.js.map} +1 -1
  3. package/dist/assets/{AxesTab-COaSNzrG.js → AxesTab-C_-hTfa-.js} +2 -2
  4. package/dist/assets/{AxesTab-COaSNzrG.js.map → AxesTab-C_-hTfa-.js.map} +1 -1
  5. package/dist/assets/{ConfigTab-XGvUbd66.js → ConfigTab-CtT8jXdX.js} +2 -2
  6. package/dist/assets/{ConfigTab-XGvUbd66.js.map → ConfigTab-CtT8jXdX.js.map} +1 -1
  7. package/dist/assets/{ConflictNote.vue_vue_type_script_setup_true_lang-DrzDcr4X.js → ConflictNote.vue_vue_type_script_setup_true_lang-CI8OVxmY.js} +2 -2
  8. package/dist/assets/{ConflictNote.vue_vue_type_script_setup_true_lang-DrzDcr4X.js.map → ConflictNote.vue_vue_type_script_setup_true_lang-CI8OVxmY.js.map} +1 -1
  9. package/dist/assets/{DangerTab-DsSJqxzj.js → DangerTab-xmgWlRkz.js} +2 -2
  10. package/dist/assets/{DangerTab-DsSJqxzj.js.map → DangerTab-xmgWlRkz.js.map} +1 -1
  11. package/dist/assets/{DashboardView-0BLBDth-.js → DashboardView-B0acQmUO.js} +2 -2
  12. package/dist/assets/{DashboardView-0BLBDth-.js.map → DashboardView-B0acQmUO.js.map} +1 -1
  13. package/dist/assets/{DeploymentDetailView-dJjqob1P.js → DeploymentDetailView-9cw7Bg78.js} +2 -2
  14. package/dist/assets/{DeploymentDetailView-dJjqob1P.js.map → DeploymentDetailView-9cw7Bg78.js.map} +1 -1
  15. package/dist/assets/{DeploymentsView-BM9LVpU-.js → DeploymentsView-BSo5BCl0.js} +2 -2
  16. package/dist/assets/{DeploymentsView-BM9LVpU-.js.map → DeploymentsView-BSo5BCl0.js.map} +1 -1
  17. package/dist/assets/{EquivalentCommand-DyCAI1Cy.js → EquivalentCommand-CzWlurm1.js} +2 -2
  18. package/dist/assets/{EquivalentCommand-DyCAI1Cy.js.map → EquivalentCommand-CzWlurm1.js.map} +1 -1
  19. package/dist/assets/{ErrorNote.vue_vue_type_script_setup_true_lang-DjEWoD0O.js → ErrorNote.vue_vue_type_script_setup_true_lang-BDF65M8c.js} +2 -2
  20. package/dist/assets/{ErrorNote.vue_vue_type_script_setup_true_lang-DjEWoD0O.js.map → ErrorNote.vue_vue_type_script_setup_true_lang-BDF65M8c.js.map} +1 -1
  21. package/dist/assets/{HelpModal.vue_vue_type_script_setup_true_lang-CACw-lfW.js → HelpModal.vue_vue_type_script_setup_true_lang-Ct07tZdh.js} +2 -2
  22. package/dist/assets/{HelpModal.vue_vue_type_script_setup_true_lang-CACw-lfW.js.map → HelpModal.vue_vue_type_script_setup_true_lang-Ct07tZdh.js.map} +1 -1
  23. package/dist/assets/{JobDetailView-DsYfLQUd.js → JobDetailView-DJCwIe8Y.js} +2 -2
  24. package/dist/assets/{JobDetailView-DsYfLQUd.js.map → JobDetailView-DJCwIe8Y.js.map} +1 -1
  25. package/dist/assets/{JobsView-UUwzBG2c.js → JobsView-Db034G-F.js} +2 -2
  26. package/dist/assets/{JobsView-UUwzBG2c.js.map → JobsView-Db034G-F.js.map} +1 -1
  27. package/dist/assets/{LogViewer.vue_vue_type_script_setup_true_lang-DYfYw8_a.js → LogViewer.vue_vue_type_script_setup_true_lang-KZIs6SW5.js} +2 -2
  28. package/dist/assets/{LogViewer.vue_vue_type_script_setup_true_lang-DYfYw8_a.js.map → LogViewer.vue_vue_type_script_setup_true_lang-KZIs6SW5.js.map} +1 -1
  29. package/dist/assets/{LoginView-cKuF7PhJ.js → LoginView-CUMSWqU7.js} +2 -2
  30. package/dist/assets/{LoginView-cKuF7PhJ.js.map → LoginView-CUMSWqU7.js.map} +1 -1
  31. package/dist/assets/{LogsTab-QEuDGrG2.js → LogsTab-BGvveov4.js} +2 -2
  32. package/dist/assets/{LogsTab-QEuDGrG2.js.map → LogsTab-BGvveov4.js.map} +1 -1
  33. package/dist/assets/{NotFoundView-Bpcd3Ptj.js → NotFoundView-CjAbcezT.js} +2 -2
  34. package/dist/assets/{NotFoundView-Bpcd3Ptj.js.map → NotFoundView-CjAbcezT.js.map} +1 -1
  35. package/dist/assets/NotifiersView-BQhuTkf8.js +2 -0
  36. package/dist/assets/NotifiersView-BQhuTkf8.js.map +1 -0
  37. package/dist/assets/{OverviewTab-B2aCu4e0.js → OverviewTab-DY2wspdv.js} +2 -2
  38. package/dist/assets/{OverviewTab-B2aCu4e0.js.map → OverviewTab-DY2wspdv.js.map} +1 -1
  39. package/dist/assets/{RegistriesView-CfblUxVo.js → RegistriesView-629Zecpw.js} +2 -2
  40. package/dist/assets/{RegistriesView-CfblUxVo.js.map → RegistriesView-629Zecpw.js.map} +1 -1
  41. package/dist/assets/{RelativeTime.vue_vue_type_script_setup_true_lang-Dx90hw4F.js → RelativeTime.vue_vue_type_script_setup_true_lang-BSyBq6iR.js} +2 -2
  42. package/dist/assets/{RelativeTime.vue_vue_type_script_setup_true_lang-Dx90hw4F.js.map → RelativeTime.vue_vue_type_script_setup_true_lang-BSyBq6iR.js.map} +1 -1
  43. package/dist/assets/{RequiresTab-DKFeob92.js → RequiresTab-yCkkTv9T.js} +2 -2
  44. package/dist/assets/{RequiresTab-DKFeob92.js.map → RequiresTab-yCkkTv9T.js.map} +1 -1
  45. package/dist/assets/{RoutingView-7SWVlOx8.js → RoutingView-DAkoZ5Kr.js} +2 -2
  46. package/dist/assets/{RoutingView-7SWVlOx8.js.map → RoutingView-DAkoZ5Kr.js.map} +1 -1
  47. package/dist/assets/{RuntimeTab-CiSAV3D0.js → RuntimeTab-DBmDhhF1.js} +2 -2
  48. package/dist/assets/{RuntimeTab-CiSAV3D0.js.map → RuntimeTab-DBmDhhF1.js.map} +1 -1
  49. package/dist/assets/{SelectMenu.vue_vue_type_script_setup_true_lang-B-DTK242.js → SelectMenu.vue_vue_type_script_setup_true_lang-BX6Mnmb6.js} +2 -2
  50. package/dist/assets/{SelectMenu.vue_vue_type_script_setup_true_lang-B-DTK242.js.map → SelectMenu.vue_vue_type_script_setup_true_lang-BX6Mnmb6.js.map} +1 -1
  51. package/dist/assets/{SettingsView-BEha1Bt3.js → SettingsView-_mIpwG7k.js} +2 -2
  52. package/dist/assets/{SettingsView-BEha1Bt3.js.map → SettingsView-_mIpwG7k.js.map} +1 -1
  53. package/dist/assets/{SkeletonList.vue_vue_type_script_setup_true_lang-DiCGtn2a.js → SkeletonList.vue_vue_type_script_setup_true_lang-ChGnSMn4.js} +2 -2
  54. package/dist/assets/{SkeletonList.vue_vue_type_script_setup_true_lang-DiCGtn2a.js.map → SkeletonList.vue_vue_type_script_setup_true_lang-ChGnSMn4.js.map} +1 -1
  55. package/dist/assets/{SpecDetailView-l86eWf2v.js → SpecDetailView-DpJxXFp9.js} +2 -2
  56. package/dist/assets/{SpecDetailView-l86eWf2v.js.map → SpecDetailView-DpJxXFp9.js.map} +1 -1
  57. package/dist/assets/{SpecsView-BfWq69K5.js → SpecsView-Ts0Z0_40.js} +2 -2
  58. package/dist/assets/{SpecsView-BfWq69K5.js.map → SpecsView-Ts0Z0_40.js.map} +1 -1
  59. package/dist/assets/{StateBadge.vue_vue_type_script_setup_true_lang-DMzCGltO.js → StateBadge.vue_vue_type_script_setup_true_lang-Bk9ZHovA.js} +2 -2
  60. package/dist/assets/{StateBadge.vue_vue_type_script_setup_true_lang-DMzCGltO.js.map → StateBadge.vue_vue_type_script_setup_true_lang-Bk9ZHovA.js.map} +1 -1
  61. package/dist/assets/{SubmitView-6cqvVYlz.js → SubmitView-_MTcTQXY.js} +2 -2
  62. package/dist/assets/{SubmitView-6cqvVYlz.js.map → SubmitView-_MTcTQXY.js.map} +1 -1
  63. package/dist/assets/{Teleport-SesEhfqH.js → Teleport-BANiI1QS.js} +2 -2
  64. package/dist/assets/{Teleport-SesEhfqH.js.map → Teleport-BANiI1QS.js.map} +1 -1
  65. package/dist/assets/{TerminalTab-gDAKYgTX.js → TerminalTab-CCO1wQmY.js} +2 -2
  66. package/dist/assets/{TerminalTab-gDAKYgTX.js.map → TerminalTab-CCO1wQmY.js.map} +1 -1
  67. package/dist/assets/{UsersView-Bvs30U8o.js → UsersView-ByMF4cza.js} +2 -2
  68. package/dist/assets/{UsersView-Bvs30U8o.js.map → UsersView-ByMF4cza.js.map} +1 -1
  69. package/dist/assets/{VarEditor.vue_vue_type_script_setup_true_lang-UEG5poOe.js → VarEditor.vue_vue_type_script_setup_true_lang-B0quSLDD.js} +2 -2
  70. package/dist/assets/{VarEditor.vue_vue_type_script_setup_true_lang-UEG5poOe.js.map → VarEditor.vue_vue_type_script_setup_true_lang-B0quSLDD.js.map} +1 -1
  71. package/dist/assets/{VariablesView-Xn79UX3b.js → VariablesView-Bb8fHnh9.js} +2 -2
  72. package/dist/assets/{VariablesView-Xn79UX3b.js.map → VariablesView-Bb8fHnh9.js.map} +1 -1
  73. package/dist/assets/{index-jLPJ82ve.js → index-CSRA6my_.js} +3 -3
  74. package/dist/assets/{index-jLPJ82ve.js.map → index-CSRA6my_.js.map} +1 -1
  75. package/dist/assets/{useDeployment-Bgo0U4-I.js → useDeployment-_b3SOnq-.js} +2 -2
  76. package/dist/assets/{useDeployment-Bgo0U4-I.js.map → useDeployment-_b3SOnq-.js.map} +1 -1
  77. package/dist/index.html +1 -1
  78. package/package.json +1 -1
  79. package/dist/assets/NotifiersView-B1xAKTwU.js +0 -2
  80. package/dist/assets/NotifiersView-B1xAKTwU.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{S as n,C as i,A as d,B as l,J as p,U as c}from"./index-jLPJ82ve.js";import{w as u,r as y}from"./useVars-VN9gYdR6.js";const e=n({id:"",detail:null,error:"",loading:!1,vars:[]}),f=i(()=>p(e.vars)),k=i(()=>c(e.id)),b=i(()=>{var a;return((a=e.detail)==null?void 0:a.kind)==="shared"}),h=i(()=>{var a;return(((a=e.detail)==null?void 0:a.axes)??[]).filter(s=>!s.verifiable).map(s=>s.name)});async function t(){const a=e.id;e.loading=!0;const s=await d.get(`/api/deployments/${encodeURIComponent(a)}${f.value}`);if(e.id!==a)return;if(e.loading=!1,!s.ok){e.detail=null,e.error=l(s,`GET /api/deployments/${a}`);return}e.error="";const r=s.body;e.detail={id:r.id??a,kind:r.kind==="shared"?"shared":"isolated",createdAt:r.createdAt,updatedAt:r.updatedAt,stack:typeof r.stack=="string"?r.stack:"",busy:r.busy??null,compose:r.compose?{file:r.compose.file??"?",profiles:r.compose.profiles??[],overlays:r.compose.overlays??[]}:null,requires:Array.isArray(r.requires)?r.requires:[],axes:(Array.isArray(r.axes)?r.axes:[]).map(o=>({name:o.name,hooks:Array.isArray(o.hooks)?o.hooks:[],verifiable:o.verifiable??(Array.isArray(o.hooks)&&o.hooks.includes("assert_gone"))})),env:Array.isArray(r.env)?r.env:[]}}function g(a){e.id===a&&(e.detail||e.error)||(e.id=a,e.detail=null,e.error="",e.vars=y(a),t())}function m(){u(e.id,e.vars)}function x(){m(),t()}export{x as a,e as d,b as i,g as o,m as p,k as r,h as u,f as v};
2
- //# sourceMappingURL=useDeployment-Bgo0U4-I.js.map
1
+ import{S as n,C as i,A as d,B as l,J as p,U as c}from"./index-CSRA6my_.js";import{w as u,r as y}from"./useVars-VN9gYdR6.js";const e=n({id:"",detail:null,error:"",loading:!1,vars:[]}),f=i(()=>p(e.vars)),k=i(()=>c(e.id)),b=i(()=>{var a;return((a=e.detail)==null?void 0:a.kind)==="shared"}),h=i(()=>{var a;return(((a=e.detail)==null?void 0:a.axes)??[]).filter(s=>!s.verifiable).map(s=>s.name)});async function t(){const a=e.id;e.loading=!0;const s=await d.get(`/api/deployments/${encodeURIComponent(a)}${f.value}`);if(e.id!==a)return;if(e.loading=!1,!s.ok){e.detail=null,e.error=l(s,`GET /api/deployments/${a}`);return}e.error="";const r=s.body;e.detail={id:r.id??a,kind:r.kind==="shared"?"shared":"isolated",createdAt:r.createdAt,updatedAt:r.updatedAt,stack:typeof r.stack=="string"?r.stack:"",busy:r.busy??null,compose:r.compose?{file:r.compose.file??"?",profiles:r.compose.profiles??[],overlays:r.compose.overlays??[]}:null,requires:Array.isArray(r.requires)?r.requires:[],axes:(Array.isArray(r.axes)?r.axes:[]).map(o=>({name:o.name,hooks:Array.isArray(o.hooks)?o.hooks:[],verifiable:o.verifiable??(Array.isArray(o.hooks)&&o.hooks.includes("assert_gone"))})),env:Array.isArray(r.env)?r.env:[]}}function g(a){e.id===a&&(e.detail||e.error)||(e.id=a,e.detail=null,e.error="",e.vars=y(a),t())}function m(){u(e.id,e.vars)}function x(){m(),t()}export{x as a,e as d,b as i,g as o,m as p,k as r,h as u,f as v};
2
+ //# sourceMappingURL=useDeployment-_b3SOnq-.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useDeployment-Bgo0U4-I.js","sources":["../../src/composables/useDeployment.ts"],"sourcesContent":["/**\n * The deployment currently open in the detail view.\n *\n * A module singleton rather than provide/inject, because the six tabs are CHILD ROUTES: they are\n * siblings of each other and are mounted and unmounted independently, so passing the loaded\n * deployment down as a prop would mean re-fetching it on every tab change. Switching tabs must not\n * re-fetch or blank the panel — only opening a DIFFERENT deployment does.\n *\n * `vars` here are REQUEST-TIME variables, sent as `?query` on every route that resolves this\n * deployment. See `useVars.ts` for why they matter and what they can get wrong.\n */\n\nimport { computed, reactive } from 'vue';\nimport { api, problem, query } from '../api/client';\nimport type { Deployment, VarPair } from '../api/types';\nimport { readVars, writeVars } from './useVars';\nimport { rowFor } from './useControlPlane';\n\nexport const dep = reactive({\n id: '',\n detail: null as Deployment | null,\n /** The resolve failure, verbatim. It is a 400 that NAMES the missing variable. */\n error: '',\n loading: false,\n vars: [] as VarPair[],\n});\n\nexport const varsQuery = computed(() => query(dep.vars));\n\n/** The list row, which is the only place the server exposes stored `vars` and `specName` today. */\nexport const row = computed(() => rowFor(dep.id));\n\nexport const isShared = computed(() => dep.detail?.kind === 'shared');\n\nexport const unverifiableAxes = computed(() =>\n (dep.detail?.axes ?? []).filter((a) => !a.verifiable).map((a) => a.name),\n);\n\nexport async function loadDetail(): Promise<void> {\n const id = dep.id;\n dep.loading = true;\n const r = await api.get<Deployment>(`/api/deployments/${encodeURIComponent(id)}${varsQuery.value}`);\n // Navigated to another deployment while this was in flight: drop the answer rather than render\n // one deployment's spec under another's id.\n if (dep.id !== id) return;\n dep.loading = false;\n\n if (!r.ok) {\n dep.detail = null;\n dep.error = problem(r, `GET /api/deployments/${id}`);\n return;\n }\n dep.error = '';\n const b = r.body;\n dep.detail = {\n id: b.id ?? id,\n kind: b.kind === 'shared' ? 'shared' : 'isolated',\n createdAt: b.createdAt,\n updatedAt: b.updatedAt,\n stack: typeof b.stack === 'string' ? b.stack : '',\n busy: b.busy ?? null,\n compose: b.compose\n ? {\n file: b.compose.file ?? '?',\n profiles: b.compose.profiles ?? [],\n overlays: b.compose.overlays ?? [],\n }\n : null,\n requires: Array.isArray(b.requires) ? b.requires : [],\n axes: (Array.isArray(b.axes) ? b.axes : []).map((a) => ({\n name: a.name,\n hooks: Array.isArray(a.hooks) ? a.hooks : [],\n // Derive it if an older build omits the field. Defaulting to `false` would claim an axis is\n // unverifiable when it may define a perfectly good `assert_gone`.\n verifiable: a.verifiable ?? (Array.isArray(a.hooks) && a.hooks.includes('assert_gone')),\n })),\n env: Array.isArray(b.env) ? b.env : [],\n };\n}\n\n/** Point the singleton at a deployment. Resets everything a stale id could leak into the new one. */\nexport function openDeployment(id: string): void {\n if (dep.id === id && (dep.detail || dep.error)) return; // a tab change, not a navigation\n dep.id = id;\n dep.detail = null;\n dep.error = '';\n dep.vars = readVars(id);\n void loadDetail();\n}\n\nexport function persistVars(): void {\n writeVars(dep.id, dep.vars);\n}\n\nexport function applyVars(): void {\n persistVars();\n void loadDetail();\n}\n"],"names":["dep","reactive","varsQuery","computed","query","row","rowFor","isShared","_a","unverifiableAxes","a","loadDetail","id","r","api","problem","b","openDeployment","readVars","persistVars","writeVars","applyVars"],"mappings":"4HAkBO,MAAMA,EAAMC,EAAS,CAC1B,GAAI,GACJ,OAAQ,KAER,MAAO,GACP,QAAS,GACT,KAAM,CAAA,CACR,CAAC,EAEYC,EAAYC,EAAS,IAAMC,EAAMJ,EAAI,IAAI,CAAC,EAG1CK,EAAMF,EAAS,IAAMG,EAAON,EAAI,EAAE,CAAC,EAEnCO,EAAWJ,EAAS,IAAA,OAAM,QAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,QAAS,SAAQ,EAEvDC,EAAmBN,EAAS,IAAA,OACtC,SAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,OAAQ,CAAA,GAAI,OAAQE,GAAM,CAACA,EAAE,UAAU,EAAE,IAAKA,GAAMA,EAAE,IAAI,EACzE,EAEA,eAAsBC,GAA4B,CAChD,MAAMC,EAAKZ,EAAI,GACfA,EAAI,QAAU,GACd,MAAMa,EAAI,MAAMC,EAAI,IAAgB,oBAAoB,mBAAmBF,CAAE,CAAC,GAAGV,EAAU,KAAK,EAAE,EAGlG,GAAIF,EAAI,KAAOY,EAAI,OAGnB,GAFAZ,EAAI,QAAU,GAEV,CAACa,EAAE,GAAI,CACTb,EAAI,OAAS,KACbA,EAAI,MAAQe,EAAQF,EAAG,wBAAwBD,CAAE,EAAE,EACnD,MACF,CACAZ,EAAI,MAAQ,GACZ,MAAMgB,EAAIH,EAAE,KACZb,EAAI,OAAS,CACX,GAAIgB,EAAE,IAAMJ,EACZ,KAAMI,EAAE,OAAS,SAAW,SAAW,WACvC,UAAWA,EAAE,UACb,UAAWA,EAAE,UACb,MAAO,OAAOA,EAAE,OAAU,SAAWA,EAAE,MAAQ,GAC/C,KAAMA,EAAE,MAAQ,KAChB,QAASA,EAAE,QACP,CACE,KAAMA,EAAE,QAAQ,MAAQ,IACxB,SAAUA,EAAE,QAAQ,UAAY,CAAA,EAChC,SAAUA,EAAE,QAAQ,UAAY,CAAA,CAAC,EAEnC,KACJ,SAAU,MAAM,QAAQA,EAAE,QAAQ,EAAIA,EAAE,SAAW,CAAA,EACnD,MAAO,MAAM,QAAQA,EAAE,IAAI,EAAIA,EAAE,KAAO,CAAA,GAAI,IAAKN,IAAO,CACtD,KAAMA,EAAE,KACR,MAAO,MAAM,QAAQA,EAAE,KAAK,EAAIA,EAAE,MAAQ,CAAA,EAG1C,WAAYA,EAAE,aAAe,MAAM,QAAQA,EAAE,KAAK,GAAKA,EAAE,MAAM,SAAS,aAAa,EAAA,EACrF,EACF,IAAK,MAAM,QAAQM,EAAE,GAAG,EAAIA,EAAE,IAAM,CAAA,CAAC,CAEzC,CAGO,SAASC,EAAeL,EAAkB,CAC3CZ,EAAI,KAAOY,IAAOZ,EAAI,QAAUA,EAAI,SACxCA,EAAI,GAAKY,EACTZ,EAAI,OAAS,KACbA,EAAI,MAAQ,GACZA,EAAI,KAAOkB,EAASN,CAAE,EACjBD,EAAA,EACP,CAEO,SAASQ,GAAoB,CAClCC,EAAUpB,EAAI,GAAIA,EAAI,IAAI,CAC5B,CAEO,SAASqB,GAAkB,CAChCF,EAAA,EACKR,EAAA,CACP"}
1
+ {"version":3,"file":"useDeployment-_b3SOnq-.js","sources":["../../src/composables/useDeployment.ts"],"sourcesContent":["/**\n * The deployment currently open in the detail view.\n *\n * A module singleton rather than provide/inject, because the six tabs are CHILD ROUTES: they are\n * siblings of each other and are mounted and unmounted independently, so passing the loaded\n * deployment down as a prop would mean re-fetching it on every tab change. Switching tabs must not\n * re-fetch or blank the panel — only opening a DIFFERENT deployment does.\n *\n * `vars` here are REQUEST-TIME variables, sent as `?query` on every route that resolves this\n * deployment. See `useVars.ts` for why they matter and what they can get wrong.\n */\n\nimport { computed, reactive } from 'vue';\nimport { api, problem, query } from '../api/client';\nimport type { Deployment, VarPair } from '../api/types';\nimport { readVars, writeVars } from './useVars';\nimport { rowFor } from './useControlPlane';\n\nexport const dep = reactive({\n id: '',\n detail: null as Deployment | null,\n /** The resolve failure, verbatim. It is a 400 that NAMES the missing variable. */\n error: '',\n loading: false,\n vars: [] as VarPair[],\n});\n\nexport const varsQuery = computed(() => query(dep.vars));\n\n/** The list row, which is the only place the server exposes stored `vars` and `specName` today. */\nexport const row = computed(() => rowFor(dep.id));\n\nexport const isShared = computed(() => dep.detail?.kind === 'shared');\n\nexport const unverifiableAxes = computed(() =>\n (dep.detail?.axes ?? []).filter((a) => !a.verifiable).map((a) => a.name),\n);\n\nexport async function loadDetail(): Promise<void> {\n const id = dep.id;\n dep.loading = true;\n const r = await api.get<Deployment>(`/api/deployments/${encodeURIComponent(id)}${varsQuery.value}`);\n // Navigated to another deployment while this was in flight: drop the answer rather than render\n // one deployment's spec under another's id.\n if (dep.id !== id) return;\n dep.loading = false;\n\n if (!r.ok) {\n dep.detail = null;\n dep.error = problem(r, `GET /api/deployments/${id}`);\n return;\n }\n dep.error = '';\n const b = r.body;\n dep.detail = {\n id: b.id ?? id,\n kind: b.kind === 'shared' ? 'shared' : 'isolated',\n createdAt: b.createdAt,\n updatedAt: b.updatedAt,\n stack: typeof b.stack === 'string' ? b.stack : '',\n busy: b.busy ?? null,\n compose: b.compose\n ? {\n file: b.compose.file ?? '?',\n profiles: b.compose.profiles ?? [],\n overlays: b.compose.overlays ?? [],\n }\n : null,\n requires: Array.isArray(b.requires) ? b.requires : [],\n axes: (Array.isArray(b.axes) ? b.axes : []).map((a) => ({\n name: a.name,\n hooks: Array.isArray(a.hooks) ? a.hooks : [],\n // Derive it if an older build omits the field. Defaulting to `false` would claim an axis is\n // unverifiable when it may define a perfectly good `assert_gone`.\n verifiable: a.verifiable ?? (Array.isArray(a.hooks) && a.hooks.includes('assert_gone')),\n })),\n env: Array.isArray(b.env) ? b.env : [],\n };\n}\n\n/** Point the singleton at a deployment. Resets everything a stale id could leak into the new one. */\nexport function openDeployment(id: string): void {\n if (dep.id === id && (dep.detail || dep.error)) return; // a tab change, not a navigation\n dep.id = id;\n dep.detail = null;\n dep.error = '';\n dep.vars = readVars(id);\n void loadDetail();\n}\n\nexport function persistVars(): void {\n writeVars(dep.id, dep.vars);\n}\n\nexport function applyVars(): void {\n persistVars();\n void loadDetail();\n}\n"],"names":["dep","reactive","varsQuery","computed","query","row","rowFor","isShared","_a","unverifiableAxes","a","loadDetail","id","r","api","problem","b","openDeployment","readVars","persistVars","writeVars","applyVars"],"mappings":"4HAkBO,MAAMA,EAAMC,EAAS,CAC1B,GAAI,GACJ,OAAQ,KAER,MAAO,GACP,QAAS,GACT,KAAM,CAAA,CACR,CAAC,EAEYC,EAAYC,EAAS,IAAMC,EAAMJ,EAAI,IAAI,CAAC,EAG1CK,EAAMF,EAAS,IAAMG,EAAON,EAAI,EAAE,CAAC,EAEnCO,EAAWJ,EAAS,IAAA,OAAM,QAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,QAAS,SAAQ,EAEvDC,EAAmBN,EAAS,IAAA,OACtC,SAAAK,EAAAR,EAAI,SAAJ,YAAAQ,EAAY,OAAQ,CAAA,GAAI,OAAQE,GAAM,CAACA,EAAE,UAAU,EAAE,IAAKA,GAAMA,EAAE,IAAI,EACzE,EAEA,eAAsBC,GAA4B,CAChD,MAAMC,EAAKZ,EAAI,GACfA,EAAI,QAAU,GACd,MAAMa,EAAI,MAAMC,EAAI,IAAgB,oBAAoB,mBAAmBF,CAAE,CAAC,GAAGV,EAAU,KAAK,EAAE,EAGlG,GAAIF,EAAI,KAAOY,EAAI,OAGnB,GAFAZ,EAAI,QAAU,GAEV,CAACa,EAAE,GAAI,CACTb,EAAI,OAAS,KACbA,EAAI,MAAQe,EAAQF,EAAG,wBAAwBD,CAAE,EAAE,EACnD,MACF,CACAZ,EAAI,MAAQ,GACZ,MAAMgB,EAAIH,EAAE,KACZb,EAAI,OAAS,CACX,GAAIgB,EAAE,IAAMJ,EACZ,KAAMI,EAAE,OAAS,SAAW,SAAW,WACvC,UAAWA,EAAE,UACb,UAAWA,EAAE,UACb,MAAO,OAAOA,EAAE,OAAU,SAAWA,EAAE,MAAQ,GAC/C,KAAMA,EAAE,MAAQ,KAChB,QAASA,EAAE,QACP,CACE,KAAMA,EAAE,QAAQ,MAAQ,IACxB,SAAUA,EAAE,QAAQ,UAAY,CAAA,EAChC,SAAUA,EAAE,QAAQ,UAAY,CAAA,CAAC,EAEnC,KACJ,SAAU,MAAM,QAAQA,EAAE,QAAQ,EAAIA,EAAE,SAAW,CAAA,EACnD,MAAO,MAAM,QAAQA,EAAE,IAAI,EAAIA,EAAE,KAAO,CAAA,GAAI,IAAKN,IAAO,CACtD,KAAMA,EAAE,KACR,MAAO,MAAM,QAAQA,EAAE,KAAK,EAAIA,EAAE,MAAQ,CAAA,EAG1C,WAAYA,EAAE,aAAe,MAAM,QAAQA,EAAE,KAAK,GAAKA,EAAE,MAAM,SAAS,aAAa,EAAA,EACrF,EACF,IAAK,MAAM,QAAQM,EAAE,GAAG,EAAIA,EAAE,IAAM,CAAA,CAAC,CAEzC,CAGO,SAASC,EAAeL,EAAkB,CAC3CZ,EAAI,KAAOY,IAAOZ,EAAI,QAAUA,EAAI,SACxCA,EAAI,GAAKY,EACTZ,EAAI,OAAS,KACbA,EAAI,MAAQ,GACZA,EAAI,KAAOkB,EAASN,CAAE,EACjBD,EAAA,EACP,CAEO,SAASQ,GAAoB,CAClCC,EAAUpB,EAAI,GAAIA,EAAI,IAAI,CAC5B,CAEO,SAASqB,GAAkB,CAChCF,EAAA,EACKR,EAAA,CACP"}
package/dist/index.html CHANGED
@@ -27,7 +27,7 @@
27
27
  /* private mode: fall through to the OS preference */
28
28
  }
29
29
  </script>
30
- <script type="module" crossorigin src="/assets/index-jLPJ82ve.js"></script>
30
+ <script type="module" crossorigin src="/assets/index-CSRA6my_.js"></script>
31
31
  <link rel="stylesheet" crossorigin href="/assets/index-WMJXAtiA.css">
32
32
  </head>
33
33
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samyx/preview-stacks-ui",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "private": false,
5
5
  "description": "The advanced web UI for preview-stacks — an opt-in SPA that talks to the pstack HTTP API.",
6
6
  "type": "module",
@@ -1,2 +0,0 @@
1
- import{d as J,H as K,c as o,a as t,f as n,e as h,w as g,_ as T,x as E,g as c,F as f,t as r,s as N,i as j,v as U,r as v,C as S,A as y,B as _,o as l,D as Q,E as X,u as Z,N as D}from"./index-jLPJ82ve.js";import{s as ee}from"./useFormat-CKJxQp_i.js";import{_ as F}from"./ActionButton.vue_vue_type_script_setup_true_lang-C0iLjBml.js";import{_ as I}from"./ErrorNote.vue_vue_type_script_setup_true_lang-DjEWoD0O.js";import{_ as te}from"./SkeletonList.vue_vue_type_script_setup_true_lang-DiCGtn2a.js";import{_ as se}from"./RelativeTime.vue_vue_type_script_setup_true_lang-Dx90hw4F.js";import{_ as ae}from"./SelectMenu.vue_vue_type_script_setup_true_lang-B-DTK242.js";import"./Teleport-SesEhfqH.js";const le={class:"page-head"},oe={class:"sub"},ie={key:1,class:"panel"},ne={key:0,class:"banner ok"},re={class:"code"},de={class:"row"},ue={class:"panel"},ve={key:1,class:"cards"},ce={class:"stagger"},pe={class:"name","data-label":"name"},he={class:"mute",style:{"font-size":"var(--t-sm)"}},me={"data-label":"events"},fe={key:0,class:"badge"},ye={key:1},ke={"data-label":"last delivery"},ge={key:0,class:"mute"},_e={key:2,class:"mute",style:{"font-size":"var(--t-sm)"}},be={"data-label":""},we={class:"row",style:{"justify-content":"flex-end"}},$e={key:0,class:"badge off"},xe=["onClick"],Ce=["onClick"],Te=["onClick"],Ne={colspan:"4"},Ve={key:0,class:"kvlist"},Ae={class:"k"},Ee={class:"v"},Se={class:"mute",style:{"font-size":"var(--t-sm)"}},De={key:0,class:"s-failed",style:{"font-size":"var(--t-sm)"}},Re={key:1,class:"mute"},ze={key:2,class:"mute"},Be={class:"panel"},He={key:0,class:"field",style:{"max-width":"320px"}},Pe={class:"field",style:{"max-width":"380px"}},je=["for"],Ue=["id","onUpdate:modelValue","placeholder"],Xe={class:"section",style:{margin:"var(--s5) 0 var(--s3)"}},Fe={class:"row"},Ie={class:"check"},Me=["checked"],Oe={key:1,class:"check-grid"},We=["checked","onChange"],qe={class:"row",style:{"margin-top":"var(--s4)"}},Le={class:"hint"},at=J({__name:"NotifiersView",setup(Ye){const V=v([]),k=v(null),R=v(!1),p=v(""),z=v(!1),b=v(null),i=v({name:"",type:"webhook",events:[],config:{}}),w=v(!1),x=v(""),m=v(null),A=v([]),M=S(()=>{var a;return(((a=k.value)==null?void 0:a.types)??[]).map(e=>({value:e.kind,label:e.label}))}),B=S(()=>{var a;return((a=k.value)==null?void 0:a.types.find(e=>e.kind===i.value.type))??null});K(()=>i.value.type,()=>{i.value.config={}});const O=S(()=>{var a;return!w.value&&!!i.value.name.trim()&&i.value.events.length>0&&(((a=B.value)==null?void 0:a.fields)??[]).every(e=>{var u;return!e.required||!!((u=i.value.config[e.key])!=null&&u.trim())})});async function $(){const[a,e]=await Promise.all([y.get("/api/notifiers"),y.get("/api/notifiers/meta")]);if(R.value=!0,a.status===404||e.status===404){z.value=!0;return}if(!a.ok){p.value=_(a,"load the notifiers");return}p.value="",V.value=a.body.notifiers??[],e.ok&&(k.value=e.body)}$();function H(a){const e=i.value.events.indexOf(a);e===-1?i.value.events.push(a):i.value.events.splice(e,1)}async function W(){w.value=!0,x.value="";const a=await y.post("/api/notifiers",{name:i.value.name.trim(),type:i.value.type,events:i.value.events,config:i.value.config});if(w.value=!1,!a.ok){x.value=_(a,"register this notifier");return}b.value=a.body.secret?{name:a.body.notifier.name,secret:a.body.secret}:null,i.value={name:"",type:i.value.type,events:[],config:{}},$()}async function q(a,e){const u=await y.patch(`/api/notifiers/${a.id}`,{enabled:e});u.ok||(p.value=_(u,"update this notifier")),$()}async function L(a){const e=await y.del(`/api/notifiers/${a.id}`);if(!e.ok){p.value=_(e,"delete this notifier");return}m.value===a.id&&(m.value=null),D("ok",`Removed ${a.name}.`),$()}async function Y(a){const e=await y.post(`/api/notifiers/${a.id}/test`,{});if(!e.ok){p.value=_(e,"send a test delivery");return}const u=e.body.result;u.ok?D("ok",`${a.name} accepted the test delivery.`):D("error",`${a.name}: ${u.error??`HTTP ${u.status}`}`),$()}async function G(a){if(m.value===a.id){m.value=null;return}const e=await y.get(`/api/notifiers/${a.id}/deliveries`);if(!e.ok){p.value=_(e,"load the delivery log");return}A.value=e.body.deliveries??[],m.value=a.id}return(a,e)=>{var u,P;return l(),o("div",null,[t("div",le,[t("div",null,[e[6]||(e[6]=t("h1",null,"Notifiers",-1)),t("div",oe,[e[5]||(e[5]=n(" Where events on this host get sent ",-1)),h(T,{label:"what a notifier is"},{default:g(()=>[...e[4]||(e[4]=[n(" A registration that receives events — a teardown that leaked, a deployment created, a job that failed. Webhooks today; the server decides what other kinds exist, and this page renders whatever it offers. ",-1)])]),_:1})])])]),p.value?(l(),E(I,{key:0,text:p.value,title:"Could not load the notifiers."},null,8,["text"])):c("",!0),z.value?(l(),o("section",ie,[...e[7]||(e[7]=[t("div",{class:"banner plain"},[t("b",null,"This server has no notifiers."),t("p",null,"It is an older build of pstack. Upgrade the host to register webhooks.")],-1)])])):(l(),o(f,{key:2},[b.value?(l(),o("div",ne,[t("b",null,"Signing secret for “"+r(b.value.name)+"” — copy it now.",1),t("p",null,[e[9]||(e[9]=n(" This is the only time it is shown — the server keeps no way to show it again. Your receiver uses it to check that a delivery really came from here. ",-1)),h(T,{label:"how a receiver checks it"},{default:g(()=>[...e[8]||(e[8]=[n(" Each delivery carries a signature header computed from this secret and the exact body sent. Recompute it on your side and compare; a mismatch means the delivery was not sent by this host, or was altered on the way. ",-1)])]),_:1})]),t("pre",re,r(b.value.secret),1),t("div",de,[t("button",{class:"btn",onClick:e[0]||(e[0]=s=>b.value=null)},"I have stored it")])])):c("",!0),t("section",ue,[e[12]||(e[12]=t("div",{class:"phead"},[t("h2",{class:"section"},"Registered")],-1)),R.value?V.value.length?(l(),o("table",ve,[e[11]||(e[11]=t("thead",null,[t("tr",null,[t("th",null,"name"),t("th",null,"events"),t("th",null,"last delivery"),t("th")])],-1)),t("tbody",ce,[(l(!0),o(f,null,N(V.value,(s,C)=>(l(),o(f,{key:s.id},[t("tr",{style:Q({"--i":C})},[t("td",pe,[n(r(s.name)+" ",1),t("div",he,r(s.type)+" · "+r(String(s.config.url??"")),1)]),t("td",me,[s.events.includes("*")?(l(),o("span",fe,"all events")):(l(),o("span",ye,r(s.events.join(", ")),1))]),t("td",ke,[s.lastStatus?(l(),o("span",{key:1,class:X(s.lastStatus==="ok"?"s-ok":"s-failed")},r(s.lastStatus),3)):(l(),o("span",ge,"never")),s.lastAt?(l(),o("div",_e,[h(se,{at:s.lastAt},null,8,["at"])])):c("",!0)]),t("td",be,[t("div",we,[s.enabled?c("",!0):(l(),o("span",$e,"disabled")),t("button",{class:"ghost sm",onClick:d=>G(s)},r(m.value===s.id?"Hide":"Deliveries"),9,xe),t("button",{class:"ghost sm",onClick:d=>Y(s)},"Test",8,Ce),t("button",{class:"ghost sm",onClick:d=>q(s,!s.enabled)},r(s.enabled?"Disable":"Enable"),9,Te),h(F,{variant:"danger",onClick:d=>L(s)},{default:g(()=>[...e[10]||(e[10]=[n("Remove",-1)])]),_:1},8,["onClick"])])])],4),m.value===s.id?(l(),o("tr",{key:`d${s.id}`},[t("td",Ne,[A.value.length?(l(),o("ul",Ve,[(l(!0),o(f,null,N(A.value,d=>(l(),o("li",{key:d.id},[t("span",Ae,[t("span",{class:X(d.status==="ok"?"s-ok":"s-failed")},r(d.status),3)]),t("span",Ee,[n(r(d.event)+" ",1),t("span",Se,[n(" · "+r(Z(ee)(d.createdAt))+" · "+r(d.attempts)+" attempt(s)",1),d.responseCode?(l(),o(f,{key:0},[n(" · HTTP "+r(d.responseCode),1)],64)):c("",!0)]),d.error?(l(),o("div",De,r(d.error),1)):c("",!0)])]))),128))])):(l(),o("p",Re,"Nothing delivered yet."))])])):c("",!0)],64))),128))])])):(l(),o("p",ze," Nothing registered. Events still happen — nobody is being told about them. ")):(l(),E(te,{key:0,rows:2}))]),t("section",Be,[e[20]||(e[20]=t("h2",{class:"section",style:{"margin-bottom":"var(--s3)"}},"Add a notifier",-1)),k.value&&k.value.types.length>1?(l(),o("div",He,[e[13]||(e[13]=t("label",{for:"ty"},"Type",-1)),h(ae,{modelValue:i.value.type,"onUpdate:modelValue":e[1]||(e[1]=s=>i.value.type=s),id:"ty",label:"Notifier type",options:M.value},null,8,["modelValue","options"])])):c("",!0),t("div",Pe,[e[14]||(e[14]=t("label",{for:"nn"},"Name",-1)),j(t("input",{id:"nn","onUpdate:modelValue":e[2]||(e[2]=s=>i.value.name=s),type:"text",placeholder:"ops-slack-bridge",spellcheck:"false"},null,512),[[U,i.value.name,void 0,{trim:!0}]])]),(l(!0),o(f,null,N(((u=B.value)==null?void 0:u.fields)??[],s=>(l(),o("div",{key:s.key,class:"field",style:{"max-width":"380px"}},[t("label",{for:`cfg-${s.key}`},r(s.label),9,je),j(t("input",{id:`cfg-${s.key}`,"onUpdate:modelValue":C=>i.value.config[s.key]=C,type:"text",placeholder:s.placeholder,spellcheck:"false"},null,8,Ue),[[U,i.value.config[s.key],void 0,{trim:!0}]])]))),128)),t("h2",Xe,[e[16]||(e[16]=n(" Events ",-1)),h(T,{label:"which events to pick"},{default:g(()=>[...e[15]||(e[15]=[t("b",null,"All events",-1),n(" also covers events added in later versions — a specific list does not, and the failure mode of that is silence nobody can explain. ",-1),t("code",null,"job.leaked",-1),n(" is the one worth alerting on: a teardown ran and something survived it. ",-1)])]),_:1})]),t("div",Fe,[t("label",Ie,[t("input",{type:"checkbox",checked:i.value.events.includes("*"),onChange:e[3]||(e[3]=s=>H("*"))},null,40,Me),e[17]||(e[17]=n(" All events ",-1))])]),i.value.events.includes("*")?c("",!0):(l(),o("div",Oe,[(l(!0),o(f,null,N(((P=k.value)==null?void 0:P.events)??[],s=>(l(),o("label",{key:s,class:"check"},[t("input",{type:"checkbox",checked:i.value.events.includes(s),onChange:C=>H(s)},null,40,We),n(" "+r(s),1)]))),128))])),x.value?(l(),E(I,{key:2,text:x.value,title:"Could not register this notifier."},null,8,["text"])):c("",!0),t("div",qe,[h(F,{variant:"primary",pending:w.value,disabled:!O.value,onClick:W},{default:g(()=>[n(r(w.value?"Registering…":"Register"),1)]),_:1},8,["pending","disabled"])]),t("p",Le,[e[19]||(e[19]=n(" Deliveries from a signing type are signed with a secret shown once at registration, retried twice on failure, and logged here. ",-1)),h(T,{label:"how a receiver verifies a delivery"},{default:g(()=>[...e[18]||(e[18]=[n(" Recompute ",-1),t("code",null,"HMAC-SHA256(secret, `${timestamp}.${rawBody}`)",-1),n(" and compare against ",-1),t("code",null,"X-Pstack-Signature",-1),n(", using the ",-1),t("em",null,"raw",-1),n(" body — re-serialising it changes the bytes. Reject anything whose ",-1),t("code",null,"X-Pstack-Timestamp",-1),n(" is more than five minutes old, and dedupe on ",-1),t("code",null,"X-Pstack-Delivery",-1),n(": delivery is at-least-once, and that id is stable across retries. ",-1)])]),_:1})])])],64))])}}});export{at as default};
2
- //# sourceMappingURL=NotifiersView-B1xAKTwU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NotifiersView-B1xAKTwU.js","sources":["../../src/views/NotifiersView.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Notifiers — where events on this host get sent.\n *\n * THE FORM IS SERVER-DRIVEN. The event list and the per-type fields come from `/api/notifiers/meta`,\n * so adding a Slack or Discord type on the server puts it in this picker with its own form and no\n * change here. That is the composability seam reaching the UI; hard-coding the fields would have\n * quietly made the seam a lie.\n *\n * THE SIGNING SECRET IS SHOWN ONCE. Same discipline as a personal token and a registry credential:\n * there is no read path on the server, so this page cannot offer a reveal — it can only show the\n * value at the moment of creation and say plainly that this is the only time.\n */\nimport { computed, ref, watch } from 'vue';\nimport { api, problem } from '../api/client';\nimport type { DeliveryRow, NotifierMeta, NotifierRow } from '../api/types';\nimport { stamp } from '../composables/useFormat';\nimport { toast } from '../composables/useToasts';\nimport ActionButton from '../components/ActionButton.vue';\nimport ErrorNote from '../components/ErrorNote.vue';\nimport InfoHint from '../components/InfoHint.vue';\nimport SkeletonList from '../components/SkeletonList.vue';\nimport RelativeTime from '../components/RelativeTime.vue';\nimport SelectMenu from '../components/SelectMenu.vue';\n\nconst notifiers = ref<NotifierRow[]>([]);\nconst meta = ref<NotifierMeta | null>(null);\nconst loaded = ref(false);\nconst listError = ref('');\nconst unsupported = ref(false);\n\n/** The freshly-minted secret, held only until the operator dismisses it. */\nconst revealed = ref<{ name: string; secret: string } | null>(null);\n\nconst form = ref({ name: '', type: 'webhook', events: [] as string[], config: {} as Record<string, string> });\nconst saving = ref(false);\nconst formError = ref('');\n\nconst openDeliveries = ref<number | null>(null);\nconst deliveries = ref<DeliveryRow[]>([]);\n\n/** Server-driven, so a new notifier type appears here with no change to this file. */\nconst typeOptions = computed(() => (meta.value?.types ?? []).map((x) => ({ value: x.kind, label: x.label })));\n\nconst chosenType = computed(() => meta.value?.types.find((t) => t.kind === form.value.type) ?? null);\n\n/**\n * `config` is one bag shared by every type, so switching the picker leaves the previous type's\n * fields behind — fill a webhook URL, switch to Slack, and the POST carries a stray `url` alongside\n * `webhookUrl`. Nothing downstream rejects it: `config` is stored whole and each type validates only\n * its OWN fields, so the dead value is persisted forever and shows up in the detail view. Clearing on\n * change costs one line; unknown-key rejection on the server would cost a migration path for every\n * future type.\n */\nwatch(\n () => form.value.type,\n () => {\n form.value.config = {};\n },\n);\nconst canSave = computed(\n () =>\n !saving.value &&\n !!form.value.name.trim() &&\n form.value.events.length > 0 &&\n (chosenType.value?.fields ?? []).every((f) => !f.required || !!form.value.config[f.key]?.trim()),\n);\n\nasync function load(): Promise<void> {\n const [list, m] = await Promise.all([\n api.get<{ notifiers: NotifierRow[] }>('/api/notifiers'),\n api.get<NotifierMeta>('/api/notifiers/meta'),\n ]);\n loaded.value = true;\n // A server built before this feature answers 404 — a capability difference, not an error.\n if (list.status === 404 || m.status === 404) {\n unsupported.value = true;\n return;\n }\n if (!list.ok) {\n listError.value = problem(list, 'load the notifiers');\n return;\n }\n listError.value = '';\n notifiers.value = list.body.notifiers ?? [];\n if (m.ok) meta.value = m.body;\n}\n\nvoid load();\n\nfunction toggleEvent(name: string): void {\n const at = form.value.events.indexOf(name);\n if (at === -1) form.value.events.push(name);\n else form.value.events.splice(at, 1);\n}\n\nasync function create(): Promise<void> {\n saving.value = true;\n formError.value = '';\n const r = await api.post<{ notifier: NotifierRow; secret: string | null }>('/api/notifiers', {\n name: form.value.name.trim(),\n type: form.value.type,\n events: form.value.events,\n config: form.value.config,\n });\n saving.value = false;\n if (!r.ok) {\n formError.value = problem(r, 'register this notifier');\n return;\n }\n // `null` for a type whose config already carries its credential — a Slack notifier must not be\n // handed 48 hex characters and told its receiver needs them.\n revealed.value = r.body.secret ? { name: r.body.notifier.name, secret: r.body.secret } : null;\n form.value = { name: '', type: form.value.type, events: [], config: {} };\n void load();\n}\n\nasync function setEnabled(n: NotifierRow, enabled: boolean): Promise<void> {\n const r = await api.patch<{ notifier: NotifierRow }>(`/api/notifiers/${n.id}`, { enabled });\n if (!r.ok) listError.value = problem(r, 'update this notifier');\n void load();\n}\n\nasync function remove(n: NotifierRow): Promise<void> {\n const r = await api.del(`/api/notifiers/${n.id}`);\n if (!r.ok) {\n listError.value = problem(r, 'delete this notifier');\n return;\n }\n if (openDeliveries.value === n.id) openDeliveries.value = null;\n toast('ok', `Removed ${n.name}.`);\n void load();\n}\n\nasync function test(n: NotifierRow): Promise<void> {\n const r = await api.post<{ result: { ok: boolean; status?: number; error?: string } }>(\n `/api/notifiers/${n.id}/test`,\n {},\n );\n if (!r.ok) {\n listError.value = problem(r, 'send a test delivery');\n return;\n }\n const res = r.body.result;\n // The endpoint's own answer, verbatim — \"it failed\" without the reason is the thing this page\n // exists to avoid.\n if (res.ok) toast('ok', `${n.name} accepted the test delivery.`);\n else toast('error', `${n.name}: ${res.error ?? `HTTP ${res.status}`}`);\n void load();\n}\n\nasync function showDeliveries(n: NotifierRow): Promise<void> {\n if (openDeliveries.value === n.id) {\n openDeliveries.value = null;\n return;\n }\n const r = await api.get<{ deliveries: DeliveryRow[] }>(`/api/notifiers/${n.id}/deliveries`);\n if (!r.ok) {\n listError.value = problem(r, 'load the delivery log');\n return;\n }\n deliveries.value = r.body.deliveries ?? [];\n openDeliveries.value = n.id;\n}\n</script>\n\n<template>\n <div>\n <div class=\"page-head\">\n <div>\n <h1>Notifiers</h1>\n <div class=\"sub\">\n Where events on this host get sent\n <InfoHint label=\"what a notifier is\">\n A registration that receives events — a teardown that leaked, a deployment created, a job\n that failed. Webhooks today; the server decides what other kinds exist, and this page\n renders whatever it offers.\n </InfoHint>\n </div>\n </div>\n </div>\n\n <ErrorNote v-if=\"listError\" :text=\"listError\" title=\"Could not load the notifiers.\" />\n\n <section v-if=\"unsupported\" class=\"panel\">\n <div class=\"banner plain\">\n <b>This server has no notifiers.</b>\n <p>It is an older build of pstack. Upgrade the host to register webhooks.</p>\n </div>\n </section>\n\n <template v-else>\n <!--\n Shown once, and the page says so. There is no read path on the server, so this is not a\n design choice that could be softened later — the value genuinely does not exist anywhere\n retrievable after this moment.\n -->\n <!-- Only a signing type ever produces one; see `signs` in notify.ts. -->\n <div v-if=\"revealed\" class=\"banner ok\">\n <b>Signing secret for “{{ revealed.name }}” — copy it now.</b>\n <p>\n This is the only time it is shown — the server keeps no way to show it again. Your\n receiver uses it to check that a delivery really came from here.\n <InfoHint label=\"how a receiver checks it\">\n Each delivery carries a signature header computed from this secret and the exact body\n sent. Recompute it on your side and compare; a mismatch means the delivery was not sent\n by this host, or was altered on the way.\n </InfoHint>\n </p>\n <pre class=\"code\">{{ revealed.secret }}</pre>\n <div class=\"row\">\n <button class=\"btn\" @click=\"revealed = null\">I have stored it</button>\n </div>\n </div>\n\n <section class=\"panel\">\n <div class=\"phead\">\n <h2 class=\"section\">Registered</h2>\n </div>\n\n <SkeletonList v-if=\"!loaded\" :rows=\"2\" />\n <table v-else-if=\"notifiers.length\" class=\"cards\">\n <thead>\n <tr>\n <th>name</th>\n <th>events</th>\n <th>last delivery</th>\n <th></th>\n </tr>\n </thead>\n <tbody class=\"stagger\">\n <template v-for=\"(n, i) in notifiers\" :key=\"n.id\">\n <tr :style=\"{ '--i': i }\">\n <td class=\"name\" data-label=\"name\">\n {{ n.name }}\n <div class=\"mute\" style=\"font-size: var(--t-sm)\">\n {{ n.type }} · {{ String(n.config.url ?? '') }}\n </div>\n </td>\n <td data-label=\"events\">\n <span v-if=\"n.events.includes('*')\" class=\"badge\">all events</span>\n <span v-else>{{ n.events.join(', ') }}</span>\n </td>\n <td data-label=\"last delivery\">\n <span v-if=\"!n.lastStatus\" class=\"mute\">never</span>\n <span v-else :class=\"n.lastStatus === 'ok' ? 's-ok' : 's-failed'\">\n {{ n.lastStatus }}\n </span>\n <div v-if=\"n.lastAt\" class=\"mute\" style=\"font-size: var(--t-sm)\">\n <RelativeTime :at=\"n.lastAt\" />\n </div>\n </td>\n <td data-label=\"\">\n <div class=\"row\" style=\"justify-content: flex-end\">\n <span v-if=\"!n.enabled\" class=\"badge off\">disabled</span>\n <button class=\"ghost sm\" @click=\"showDeliveries(n)\">\n {{ openDeliveries === n.id ? 'Hide' : 'Deliveries' }}\n </button>\n <button class=\"ghost sm\" @click=\"test(n)\">Test</button>\n <button class=\"ghost sm\" @click=\"setEnabled(n, !n.enabled)\">\n {{ n.enabled ? 'Disable' : 'Enable' }}\n </button>\n <ActionButton variant=\"danger\" @click=\"remove(n)\">Remove</ActionButton>\n </div>\n </td>\n </tr>\n <tr v-if=\"openDeliveries === n.id\" :key=\"`d${n.id}`\">\n <td colspan=\"4\">\n <ul v-if=\"deliveries.length\" class=\"kvlist\">\n <li v-for=\"d in deliveries\" :key=\"d.id\">\n <span class=\"k\">\n <span :class=\"d.status === 'ok' ? 's-ok' : 's-failed'\">{{ d.status }}</span>\n </span>\n <span class=\"v\">\n {{ d.event }}\n <span class=\"mute\" style=\"font-size: var(--t-sm)\">\n · {{ stamp(d.createdAt) }} · {{ d.attempts }} attempt(s)<template\n v-if=\"d.responseCode\"\n >\n · HTTP {{ d.responseCode }}</template\n >\n </span>\n <div v-if=\"d.error\" class=\"s-failed\" style=\"font-size: var(--t-sm)\">\n {{ d.error }}\n </div>\n </span>\n </li>\n </ul>\n <p v-else class=\"mute\">Nothing delivered yet.</p>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n <p v-else class=\"mute\">\n Nothing registered. Events still happen — nobody is being told about them.\n </p>\n </section>\n\n <section class=\"panel\">\n <h2 class=\"section\" style=\"margin-bottom: var(--s3)\">Add a notifier</h2>\n\n <div v-if=\"meta && meta.types.length > 1\" class=\"field\" style=\"max-width: 320px\">\n <label for=\"ty\">Type</label>\n <SelectMenu v-model=\"form.type\" id=\"ty\" label=\"Notifier type\" :options=\"typeOptions\" />\n </div>\n\n <div class=\"field\" style=\"max-width: 380px\">\n <label for=\"nn\">Name</label>\n <input id=\"nn\" v-model.trim=\"form.name\" type=\"text\" placeholder=\"ops-slack-bridge\" spellcheck=\"false\" />\n </div>\n\n <!-- Rendered from the server's field list — see the header. -->\n <div v-for=\"f in chosenType?.fields ?? []\" :key=\"f.key\" class=\"field\" style=\"max-width: 380px\">\n <label :for=\"`cfg-${f.key}`\">{{ f.label }}</label>\n <input\n :id=\"`cfg-${f.key}`\"\n v-model.trim=\"form.config[f.key]\"\n type=\"text\"\n :placeholder=\"f.placeholder\"\n spellcheck=\"false\"\n />\n </div>\n\n <h2 class=\"section\" style=\"margin: var(--s5) 0 var(--s3)\">\n Events\n <InfoHint label=\"which events to pick\">\n <b>All events</b> also covers events added in later versions — a specific list does not,\n and the failure mode of that is silence nobody can explain. <code>job.leaked</code> is the\n one worth alerting on: a teardown ran and something survived it.\n </InfoHint>\n </h2>\n <div class=\"row\">\n <label class=\"check\">\n <input\n type=\"checkbox\"\n :checked=\"form.events.includes('*')\"\n @change=\"toggleEvent('*')\"\n />\n All events\n </label>\n </div>\n <!-- A grid, not a wrapping row: eleven items of differing width wrapped into ragged lines\n with one stranded on its own, which reads as a layout accident. -->\n <div v-if=\"!form.events.includes('*')\" class=\"check-grid\">\n <label v-for=\"e in meta?.events ?? []\" :key=\"e\" class=\"check\">\n <input type=\"checkbox\" :checked=\"form.events.includes(e)\" @change=\"toggleEvent(e)\" />\n {{ e }}\n </label>\n </div>\n\n <ErrorNote v-if=\"formError\" :text=\"formError\" title=\"Could not register this notifier.\" />\n\n <div class=\"row\" style=\"margin-top: var(--s4)\">\n <ActionButton variant=\"primary\" :pending=\"saving\" :disabled=\"!canSave\" @click=\"create\">\n {{ saving ? 'Registering…' : 'Register' }}\n </ActionButton>\n </div>\n\n <p class=\"hint\">\n Deliveries from a signing type are signed with a secret shown once at registration, retried twice on failure,\n and logged here.\n <InfoHint label=\"how a receiver verifies a delivery\">\n Recompute <code>HMAC-SHA256(secret, `${timestamp}.${rawBody}`)</code> and compare against\n <code>X-Pstack-Signature</code>, using the <em>raw</em> body — re-serialising it changes\n the bytes. Reject anything whose <code>X-Pstack-Timestamp</code> is more than five minutes\n old, and dedupe on <code>X-Pstack-Delivery</code>: delivery is at-least-once, and that id\n is stable across retries.\n </InfoHint>\n </p>\n </section>\n </template>\n </div>\n</template>\n"],"names":["notifiers","ref","meta","loaded","listError","unsupported","revealed","form","saving","formError","openDeliveries","deliveries","typeOptions","computed","_a","x","chosenType","t","watch","canSave","f","load","list","m","api","problem","toggleEvent","name","at","create","r","setEnabled","n","enabled","remove","toast","test","res","showDeliveries","_createElementBlock","_createElementVNode","_hoisted_1","_cache","_hoisted_2","_createVNode","InfoHint","_createBlock","ErrorNote","_openBlock","_hoisted_3","_Fragment","_hoisted_4","_toDisplayString","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_renderList","i","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_normalizeClass","_hoisted_16","_hoisted_17","RelativeTime","_hoisted_18","_hoisted_19","_hoisted_20","$event","_hoisted_21","_hoisted_22","_hoisted_23","ActionButton","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","_createTextVNode","_unref","stamp","_hoisted_29","_hoisted_30","_hoisted_31","SkeletonList","_hoisted_32","_hoisted_33","SelectMenu","_hoisted_34","_hoisted_35","_hoisted_37","_hoisted_38","_hoisted_39","_hoisted_41","_b","e","_hoisted_43","_hoisted_44"],"mappings":"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"}