@stacksjs/ts-cloud 0.12.12 → 0.12.14

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 (233) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/chunk-16rs9egs.js +6 -0
  3. package/dist/bin/chunk-1j2sja1j.js +1 -0
  4. package/dist/bin/chunk-1rcsm0px.js +1 -0
  5. package/dist/bin/chunk-1s4dny8d.js +1 -0
  6. package/dist/bin/chunk-1wvrtg42.js +8 -0
  7. package/dist/bin/chunk-1x7mm26k.js +1 -0
  8. package/dist/bin/chunk-2paqksap.js +6 -0
  9. package/dist/bin/chunk-3gwmejhk.js +1 -0
  10. package/dist/bin/chunk-4201mvaj.js +2 -0
  11. package/dist/bin/chunk-49sthm4q.js +2 -0
  12. package/dist/bin/chunk-4yntpqbe.js +1 -0
  13. package/dist/bin/chunk-4zbnwt9b.js +2 -0
  14. package/dist/{chunk-2ybcnrte.js → bin/chunk-57w9nsjk.js} +3 -3
  15. package/dist/bin/chunk-61ysn56t.js +1 -0
  16. package/dist/bin/chunk-6vay4ggv.js +9 -0
  17. package/dist/bin/{chunk-wcem4cqb.js → chunk-7a7n6p2m.js} +2 -2
  18. package/dist/bin/chunk-7x0hrna6.js +1 -0
  19. package/dist/bin/{chunk-e2dnxp8d.js → chunk-80zkjpfz.js} +29 -29
  20. package/dist/bin/chunk-92nng29y.js +1 -0
  21. package/dist/bin/chunk-94cfdvrn.js +2 -0
  22. package/dist/bin/chunk-9q8zjavc.js +725 -0
  23. package/dist/bin/chunk-a929za72.js +2 -0
  24. package/dist/{chunk-ac87ds1k.js → bin/chunk-bckm6fre.js} +6 -6
  25. package/dist/bin/chunk-bj5nq0kn.js +7364 -0
  26. package/dist/bin/chunk-c51xp8f7.js +1 -0
  27. package/dist/bin/chunk-d7r6mhyv.js +34 -0
  28. package/dist/bin/chunk-dbmk60r7.js +60 -0
  29. package/dist/bin/chunk-dhxwmkhz.js +2 -0
  30. package/dist/bin/chunk-f1ke4ygp.js +1 -0
  31. package/dist/bin/chunk-f35pte64.js +44 -0
  32. package/dist/bin/{chunk-t5ngva49.js → chunk-f8mbjwme.js} +8 -8
  33. package/dist/bin/chunk-fnr6k11h.js +1 -0
  34. package/dist/bin/chunk-mzfct5en.js +1 -0
  35. package/dist/bin/chunk-n6qqa2fr.js +511 -0
  36. package/dist/bin/chunk-ngav845g.js +2 -0
  37. package/dist/bin/chunk-nrnq9adz.js +1 -0
  38. package/dist/bin/chunk-p36ns96s.js +1 -0
  39. package/dist/bin/chunk-pega3x2x.js +1 -0
  40. package/dist/bin/chunk-pt2bz3kr.js +1 -0
  41. package/dist/bin/chunk-q5aj280b.js +1 -0
  42. package/dist/bin/chunk-r6cvc2pr.js +1 -0
  43. package/dist/bin/chunk-rh2sqtew.js +1 -0
  44. package/dist/bin/chunk-rpg5k3wt.js +3 -0
  45. package/dist/bin/chunk-tkzpbb7n.js +1 -0
  46. package/dist/bin/chunk-vwyq2s2k.js +1 -0
  47. package/dist/bin/chunk-vx649y7t.js +1 -0
  48. package/dist/bin/chunk-vymg9ywg.js +2 -0
  49. package/dist/bin/chunk-w637s5q0.js +3 -0
  50. package/dist/bin/chunk-wge61ccr.js +2 -0
  51. package/dist/bin/{chunk-jxd3j00s.js → chunk-wr6a423y.js} +13 -13
  52. package/dist/bin/chunk-y7ece16e.js +111 -0
  53. package/dist/bin/chunk-ydpnsp4x.js +3 -0
  54. package/dist/bin/{chunk-t7rcfwqc.js → chunk-yhxpmk29.js} +32 -32
  55. package/dist/bin/chunk-yn34zgr2.js +1 -0
  56. package/dist/bin/chunk-ynr22ma8.js +2 -0
  57. package/dist/bin/chunk-yt8rgkqt.js +2 -0
  58. package/dist/bin/chunk-z2ez8wn9.js +37 -0
  59. package/dist/bin/cli.js +428 -428
  60. package/dist/bin/dashboard-server.js +1 -1
  61. package/dist/chunk-30h9rgfn.js +6 -0
  62. package/dist/chunk-3kapcdpn.js +92 -0
  63. package/dist/chunk-5g1hsrab.js +4 -0
  64. package/dist/chunk-5qqb671d.js +1 -0
  65. package/dist/chunk-5ww7kc5z.js +114 -0
  66. package/dist/chunk-6g81m01r.js +141 -0
  67. package/dist/{chunk-q9a1z53k.js → chunk-6j8f4ahv.js} +51 -51
  68. package/dist/{chunk-6cxb8d6y.js → chunk-6nvn041c.js} +3 -3
  69. package/dist/chunk-7hy9p6xr.js +5 -0
  70. package/dist/chunk-7kwha0fw.js +585 -0
  71. package/dist/chunk-9mhcjht7.js +37 -0
  72. package/dist/chunk-9w32efae.js +1 -0
  73. package/dist/chunk-bqaqkmtr.js +2 -0
  74. package/dist/chunk-djd9xgkz.js +709 -0
  75. package/dist/chunk-e0919h5g.js +2 -0
  76. package/dist/{chunk-dndxwssj.js → chunk-e7ds04wb.js} +2 -2
  77. package/dist/chunk-fdexq9e1.js +1 -0
  78. package/dist/chunk-hw3p6pth.js +1 -0
  79. package/dist/chunk-jb8em9ba.js +2 -0
  80. package/dist/chunk-pkan6evc.js +2 -0
  81. package/dist/chunk-qzwack6w.js +44 -0
  82. package/dist/chunk-r5emv4x8.js +2 -0
  83. package/dist/chunk-thpce63q.js +34 -0
  84. package/dist/chunk-ttq6dvft.js +22 -0
  85. package/dist/chunk-vpy3zjqv.js +1 -0
  86. package/dist/chunk-vva43vnp.js +60 -0
  87. package/dist/{bin/chunk-m9r5jype.js → chunk-wjgnfg6q.js} +6 -6
  88. package/dist/chunk-wrnhbb13.js +1 -0
  89. package/dist/chunk-xxbvjq8g.js +7355 -0
  90. package/dist/chunk-zftpjxkr.js +2 -0
  91. package/dist/deploy/index.js +1 -1
  92. package/dist/dns/index.js +1 -1
  93. package/dist/drivers/index.d.ts +1 -0
  94. package/dist/drivers/index.js +1 -1
  95. package/dist/index.d.ts +1 -1
  96. package/dist/index.js +91 -91
  97. package/dist/operations/index.js +1 -1
  98. package/dist/protection/index.js +1 -1
  99. package/dist/push/index.js +1 -1
  100. package/dist/spend/index.js +1 -1
  101. package/dist/ui/404.html +1 -1
  102. package/dist/ui/accept-invitation.html +1 -1
  103. package/dist/ui/access-denied.html +1 -1
  104. package/dist/ui/account/automation.html +6 -6
  105. package/dist/ui/account/security.html +2 -2
  106. package/dist/ui/applications/compose.html +6 -6
  107. package/dist/ui/applications/new.html +1 -1
  108. package/dist/ui/data/backups.html +6 -6
  109. package/dist/ui/data/services.html +7 -7
  110. package/dist/ui/data/volumes.html +6 -6
  111. package/dist/ui/index.html +6 -6
  112. package/dist/ui/infrastructure/topology.html +9 -9
  113. package/dist/ui/integrations.html +1 -1
  114. package/dist/ui/operations/alerts.html +6 -6
  115. package/dist/ui/operations/configuration.html +6 -6
  116. package/dist/ui/operations/jobs.html +6 -6
  117. package/dist/ui/operations/maintenance.html +6 -6
  118. package/dist/ui/operations/observability.html +6 -6
  119. package/dist/ui/operations/previews.html +6 -6
  120. package/dist/ui/operations/queue.html +6 -6
  121. package/dist/ui/operations/regions.html +6 -6
  122. package/dist/ui/operations/releases.html +6 -6
  123. package/dist/ui/operations/spend.html +6 -6
  124. package/dist/ui/operations/workloads.html +9 -9
  125. package/dist/ui/security.html +2 -2
  126. package/dist/ui/server/actions.html +6 -6
  127. package/dist/ui/server/activity.html +1 -1
  128. package/dist/ui/server/capacity.html +6 -6
  129. package/dist/ui/server/database.html +6 -6
  130. package/dist/ui/server/deployments.html +6 -6
  131. package/dist/ui/server/diagnostics.html +2 -2
  132. package/dist/ui/server/firewall.html +6 -6
  133. package/dist/ui/server/fleet.html +6 -6
  134. package/dist/ui/server/logs.html +6 -6
  135. package/dist/ui/server/metrics.html +6 -6
  136. package/dist/ui/server/security.html +2 -2
  137. package/dist/ui/server/services.html +1 -1
  138. package/dist/ui/server/sites.html +17 -17
  139. package/dist/ui/server/ssh-keys.html +6 -6
  140. package/dist/ui/server/team.html +5 -5
  141. package/dist/ui/server/terminal.html +2 -2
  142. package/dist/ui/serverless/alarms.html +5 -5
  143. package/dist/ui/serverless/assets.html +2 -2
  144. package/dist/ui/serverless/cost.html +2 -2
  145. package/dist/ui/serverless/data.html +6 -6
  146. package/dist/ui/serverless/deployments.html +2 -2
  147. package/dist/ui/serverless/firewall.html +2 -2
  148. package/dist/ui/serverless/functions.html +5 -5
  149. package/dist/ui/serverless/logs.html +6 -6
  150. package/dist/ui/serverless/metrics.html +2 -2
  151. package/dist/ui/serverless/queues.html +6 -6
  152. package/dist/ui/serverless/secrets.html +6 -6
  153. package/dist/ui/serverless/traces.html +5 -5
  154. package/dist/ui/serverless.html +6 -6
  155. package/dist/ui-src/src/charts.ts +1141 -1294
  156. package/dist/ui-src/src/topology.ts +3 -3
  157. package/package.json +3 -3
  158. package/dist/bin/chunk-0b49jjgr.js +0 -2
  159. package/dist/bin/chunk-0xnnkeb1.js +0 -1
  160. package/dist/bin/chunk-227jmf2b.js +0 -2
  161. package/dist/bin/chunk-2nyyg44g.js +0 -1
  162. package/dist/bin/chunk-2ztr119n.js +0 -3
  163. package/dist/bin/chunk-43xj5cny.js +0 -1
  164. package/dist/bin/chunk-5w6y9pmz.js +0 -1
  165. package/dist/bin/chunk-5x4rdx8k.js +0 -37
  166. package/dist/bin/chunk-6zc6a6t3.js +0 -725
  167. package/dist/bin/chunk-7aagqqr9.js +0 -1
  168. package/dist/bin/chunk-85qrgshq.js +0 -44
  169. package/dist/bin/chunk-8zk8msx0.js +0 -2
  170. package/dist/bin/chunk-9j83q0r4.js +0 -1
  171. package/dist/bin/chunk-9nhqbes6.js +0 -60
  172. package/dist/bin/chunk-a4js49mx.js +0 -1
  173. package/dist/bin/chunk-a9e0hvwe.js +0 -6
  174. package/dist/bin/chunk-a9tgxf2h.js +0 -1
  175. package/dist/bin/chunk-aahrv359.js +0 -1
  176. package/dist/bin/chunk-bfx23be3.js +0 -1
  177. package/dist/bin/chunk-bpps61am.js +0 -111
  178. package/dist/bin/chunk-bzth6d1s.js +0 -6
  179. package/dist/bin/chunk-ca3taw2m.js +0 -1
  180. package/dist/bin/chunk-cgzp0328.js +0 -1
  181. package/dist/bin/chunk-d2aaef9v.js +0 -1
  182. package/dist/bin/chunk-e0z2t4mf.js +0 -6
  183. package/dist/bin/chunk-empfsmdk.js +0 -2
  184. package/dist/bin/chunk-er3mww4m.js +0 -1
  185. package/dist/bin/chunk-fmp5bv0j.js +0 -3
  186. package/dist/bin/chunk-g3kp5ddx.js +0 -1
  187. package/dist/bin/chunk-grepda40.js +0 -1
  188. package/dist/bin/chunk-h6xqtypj.js +0 -2
  189. package/dist/bin/chunk-hwk9ahms.js +0 -2
  190. package/dist/bin/chunk-k1xw3zbm.js +0 -34
  191. package/dist/bin/chunk-m07s5esk.js +0 -2
  192. package/dist/bin/chunk-n20kbxwb.js +0 -7364
  193. package/dist/bin/chunk-n2fnav53.js +0 -3
  194. package/dist/bin/chunk-nv211m42.js +0 -8
  195. package/dist/bin/chunk-psgjy3z4.js +0 -1
  196. package/dist/bin/chunk-qmnr82da.js +0 -1
  197. package/dist/bin/chunk-qqpb82ty.js +0 -2
  198. package/dist/bin/chunk-rqc8btkj.js +0 -2
  199. package/dist/bin/chunk-rs85xvt7.js +0 -1
  200. package/dist/bin/chunk-sj5csg49.js +0 -2
  201. package/dist/bin/chunk-tjgy10zm.js +0 -9
  202. package/dist/bin/chunk-v0beqdna.js +0 -1
  203. package/dist/bin/chunk-vf2s3tba.js +0 -1
  204. package/dist/bin/chunk-vzkfjrx2.js +0 -511
  205. package/dist/bin/chunk-wsh5ervz.js +0 -1
  206. package/dist/bin/chunk-xenhbdmr.js +0 -1
  207. package/dist/bin/chunk-xrdpxwbf.js +0 -1
  208. package/dist/bin/chunk-y68m9bx7.js +0 -2
  209. package/dist/chunk-4884der5.js +0 -1
  210. package/dist/chunk-4wdxsnn2.js +0 -44
  211. package/dist/chunk-5hhyyhjt.js +0 -1
  212. package/dist/chunk-5zkacdw1.js +0 -1
  213. package/dist/chunk-6f68caq0.js +0 -1
  214. package/dist/chunk-7z50g5xz.js +0 -4
  215. package/dist/chunk-8fh4m5ge.js +0 -1
  216. package/dist/chunk-97pb7wb1.js +0 -1
  217. package/dist/chunk-ea7tn8nn.js +0 -709
  218. package/dist/chunk-ess6vxfj.js +0 -2
  219. package/dist/chunk-j06r5rwv.js +0 -2
  220. package/dist/chunk-j1g67djb.js +0 -92
  221. package/dist/chunk-k8x8mrkr.js +0 -2
  222. package/dist/chunk-mnmz8t7q.js +0 -34
  223. package/dist/chunk-n1fyryha.js +0 -141
  224. package/dist/chunk-n1hg0jxs.js +0 -2
  225. package/dist/chunk-n5xmh0ma.js +0 -37
  226. package/dist/chunk-q22qfwsc.js +0 -22
  227. package/dist/chunk-r8t25tbm.js +0 -7355
  228. package/dist/chunk-t8hzekmk.js +0 -585
  229. package/dist/chunk-whyttetx.js +0 -5
  230. package/dist/chunk-yf8stygs.js +0 -114
  231. package/dist/chunk-ze5x2bpm.js +0 -2
  232. package/dist/chunk-zh0apedk.js +0 -60
  233. package/dist/chunk-zjyz926j.js +0 -2
@@ -1,5 +1,5 @@
1
- <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtklnzmompqjwa"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud · Regions &amp; failover</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
2
- function __stx_setup_1788384013763_15() {
1
+ <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtqnk36z5iozjf"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud · Regions &amp; failover</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
2
+ function __stx_setup_1788749987980_16() {
3
3
  const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
4
4
 
5
5
  const items = state([]), selected = state(null), adding = state(false), busy = state(false), error = state(""), notice = state("");
@@ -72,9 +72,9 @@ function sync(item) {
72
72
 
73
73
  return { items, api, load, pollingState, pollingError, lastUpdatedAt, refresh, post, create, action, tone, sync };
74
74
  }
75
- window.__stx_latestSetup=__stx_setup_1788384013763_15;
76
- if(window.stx)window.stx._latestSetup=__stx_setup_1788384013763_15;
77
- </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788384013763_15"><a data-stx-scope="stx_scope_nav_19" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="active" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
75
+ window.__stx_latestSetup=__stx_setup_1788749987980_16;
76
+ if(window.stx)window.stx._latestSetup=__stx_setup_1788749987980_16;
77
+ </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788749987980_16"><a data-stx-scope="stx_scope_nav_20" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="active" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
78
78
  (function() {
79
79
  var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
80
80
  var __destroyHooks = [];
@@ -425,6 +425,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1788384013763_15;
425
425
 
426
426
 
427
427
  try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
428
- window.stx._scopes['stx_scope_nav_19'] = __scopeRegistration;
428
+ window.stx._scopes['stx_scope_nav_20'] = __scopeRegistration;
429
429
  })();
430
430
  </script> <main class="wrap" id="main-content"><div class="crumbs">Operations <span class="sep">/</span> Regions & failover</div><header class="page"><div><h1>Regions & failover</h1><p>Stage immutable stacks, replication, edge traffic, failover, failback, and retained-data teardown from one durable timeline.</p></div><div class="actions" x-cloak><span class="pill" :class="pollingState()==='live'?'ok':'warn'" x-cloak>{{ pollingState() }}</span><small x-cloak>{{ lastUpdatedAt()?.toLocaleTimeString()||'connecting' }}</small><button class="btn sm" @click="adding.set(!adding())" x-cloak>{{ adding()?'Close':'New topology' }}</button></div></header><p class="notice" role="status" @show="!!notice()" x-cloak>{{ notice() }}</p><p class="bad notice" role="alert" @show="!!error()||!!pollingError()" x-cloak>{{ error()||pollingError() }}</p><form class="create panel" @show="adding()" @submit="create($event)" x-cloak><div class="wide"><h2>New regional topology</h2><p>List the primary first. Replication is configured in both directions so failback has a fresh path.</p></div><label>Name<input name="name" required pattern="[a-z0-9][a-z0-9-]{1,62}"></label><label>Hostname<input name="hostname" required placeholder="api.example.com"></label><label>Regions<input name="regions" required placeholder="us-west-2,us-east-1"></label><label>Traffic policy<select name="trafficPolicy"><option value="active_passive">Active / passive</option><option value="weighted">Weighted</option><option value="latency">Latency</option></select></label><label>Maximum replication lag<input name="maxLagSeconds" type="number" min="0" value="30"></label><label class="check"><input name="cdnEnabled" type="checkbox"> CloudFront</label><label class="check"><input name="wafEnabled" type="checkbox"> WAF</label><button class="btn" type="submit">Save topology</button></form><section class="layout" x-cloak><div class="cards" x-cloak><template :for="item in items()"><article class="card panel" x-cloak><div x-cloak><span class="pill" :class="tone(item.topology.status)" x-cloak>{{ item.topology.status }}</span><h2 x-cloak>{{ item.topology.name }}</h2><p x-cloak>{{ item.topology.hostname }} · active {{ item.topology.activeRegion }}</p></div><div class="facts" x-cloak><span x-cloak>{{ item.topology.regions.length }} regions</span><span x-cloak>{{ sync(item) }} replication paths in sync</span><span x-cloak>{{ item.route?.dnsProvider }} · {{ item.route?.cdnEnabled?'CloudFront · ':'' }}{{ item.route?.wafEnabled?'WAF':'' }}</span></div><button class="btn ghost sm" @click="selected.set(item)">Inspect</button></article></template></div><aside class="detail panel" @show="!!selected()" x-cloak><div class="actions" x-cloak><h2 x-cloak>{{ selected()?.topology.name }}</h2><button class="btn ghost sm" @click="selected.set(null)">Close</button></div><div class="actions"><button class="btn sm" @click="action('rollout')" :disabled="busy()">Roll out</button><button class="btn sm warn" @click="action('failover')" :disabled="busy()">Fail over</button><button class="btn ghost sm" @click="action('failback')" :disabled="busy()">Fail back</button><button class="btn danger sm" @click="action('destroy')" :disabled="busy()">Drain & destroy</button></div><h3>Regional stacks</h3><template :for="target in selected()?.targets||[]"><p class="row" x-cloak><b x-cloak>{{ target.region }}</b><span x-cloak>{{ target.role }} · {{ target.status }}</span></p></template><h3>Replication</h3><template :for="channel in selected()?.channels||[]"><p class="row" x-cloak><b x-cloak>{{ channel.kind }} → {{ channel.targetRegion }}</b><span x-cloak>{{ channel.status }} · {{ channel.lagSeconds??'—' }}s</span></p></template><h3>Traffic</h3><pre x-cloak>{{ JSON.stringify(selected()?.route?.weights||{},null,2) }}</pre><h3>Execution timeline</h3><template :for="execution in selected()?.executions||[]"><div class="execution" x-cloak><span class="pill" :class="tone(execution.status)" x-cloak>{{ execution.status }}</span><b x-cloak>{{ execution.kind }}</b><small x-cloak>{{ execution.currentStep||execution.completedSteps.at(-1)||'queued' }}</small><p @show="!!execution.error" x-cloak>{{ execution.error }}</p></div></template></aside></section></main><style>.actions{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap}.actions h2{margin-right:auto}.create{display:grid;grid-template-columns:repeat(4,1fr);gap:1rem;margin-bottom:1rem}.create label{display:grid;gap:.3rem}.create .check{display:flex;align-items:center}.wide{grid-column:1/-1}.layout{display:grid;grid-template-columns:1fr 430px;gap:1rem}.cards{display:grid;gap:1rem}.card{display:grid;grid-template-columns:1fr 1fr auto;align-items:center;gap:1rem}.facts{display:grid;gap:.3rem}.detail{position:sticky;top:1rem;align-self:start}.row{display:flex;justify-content:space-between;border-bottom:1px solid var(--border);padding:.5rem 0}.execution{display:grid;grid-template-columns:auto 1fr auto;gap:.5rem;align-items:center;border-bottom:1px solid var(--border);padding:.6rem 0}.execution p{grid-column:1/-1;color:var(--danger)}@media(max-width:1000px){.layout{grid-template-columns:1fr}.detail{position:static}.create{grid-template-columns:1fr 1fr}.card{grid-template-columns:1fr}}@media(max-width:600px){.create{grid-template-columns:1fr}.wide{grid-column:auto}}</style></body></html>
@@ -1,5 +1,5 @@
1
- <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtklnzmompqjwa"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Releases &amp; promotion</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
2
- function __stx_setup_1788384013580_10() {
1
+ <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtqnk36z5iozjf"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Releases &amp; promotion</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
2
+ function __stx_setup_1788749987877_12() {
3
3
  const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
4
4
 
5
5
  const data = state({ releases: [], resources: [], environments: [] });
@@ -116,9 +116,9 @@ onMount(() => {
116
116
 
117
117
  return { data, selected, message, filters, promote, request, refresh, current, visible, tone, short, duration, configObject, act, approve, rollback, promoteRelease };
118
118
  }
119
- window.__stx_latestSetup=__stx_setup_1788384013580_10;
120
- if(window.stx)window.stx._latestSetup=__stx_setup_1788384013580_10;
121
- </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788384013580_10"><a data-stx-scope="stx_scope_nav_13" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="active" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
119
+ window.__stx_latestSetup=__stx_setup_1788749987877_12;
120
+ if(window.stx)window.stx._latestSetup=__stx_setup_1788749987877_12;
121
+ </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788749987877_12"><a data-stx-scope="stx_scope_nav_16" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="active" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
122
122
  (function() {
123
123
  var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
124
124
  var __destroyHooks = [];
@@ -469,6 +469,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1788384013580_10;
469
469
 
470
470
 
471
471
  try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
472
- window.stx._scopes['stx_scope_nav_13'] = __scopeRegistration;
472
+ window.stx._scopes['stx_scope_nav_16'] = __scopeRegistration;
473
473
  })();
474
474
  </script> <main class="releases-wrap wrap" id="main-content"><div class="crumbs">Operations <span class="sep">/</span> Releases & promotion</div><header class="page"><div><h1>Releases & promotion</h1><p>One immutable artifact history across static, compute, serverless, containers, and Compose.</p></div><button class="btn ghost" @click="refresh()">Refresh</button></header><p class="notice" @show="!!message()" x-cloak>{{message()}}</p><section class="section stats"><div class="panel"><small>Total releases</small><strong x-cloak>{{data().releases.length}}</strong></div><div class="panel"><small>Active</small><strong x-cloak>{{data().releases.filter(v=>v.status==='active').length}}</strong></div><div class="panel"><small>Needs attention</small><strong x-cloak>{{data().releases.filter(v=>['failed','awaiting_approval'].includes(v.status)).length}}</strong></div><div class="panel"><small>Pinned</small><strong x-cloak>{{data().releases.filter(v=>v.pinned).length}}</strong></div></section><section class="panel section toolbar"><label>Environment<select :value="filters().environment" @change="filters.set({...filters(),environment:$event.target.value})"><option value="">All</option><option @each="env in data().environments" :value="env.id">{{env.name}}</option></select></label><label>Status<select :value="filters().status" @change="filters.set({...filters(),status:$event.target.value})"><option value="">All</option><option @each="status in ['built','awaiting_approval','activating','active','failed','rolled_back','superseded']" :value="status">{{status}}</option></select></label><label>Kind<select :value="filters().kind" @change="filters.set({...filters(),kind:$event.target.value})"><option value="">All</option><option @each="kind in ['static','compute','serverless_zip','serverless_image','container','compose']" :value="kind">{{kind}}</option></select></label></section><div class="release-layout section"><section class="panel release-list"><div class="empty" @show="!visible().length" x-cloak><b>No releases match this view</b><span>Create a release from a verified artifact with the CLI or API.</span></div><button class="release-row" :class="selected()===item.id?'selected':''" @each="item in visible()" :key="item.id" @click="selected.set(item.id)" x-cloak><span class="pill" :class="tone(item.status)" x-cloak>{{item.status}}</span><strong x-cloak>{{item.resource?.name||item.resourceId}}</strong><small x-cloak>{{item.environment?.name}} · {{item.kind}} · {{item.strategy}}</small><code x-cloak>{{short(item.sourceSha)}} · {{short(item.artifact?.digest)}}</code><time x-cloak>{{new Date(item.createdAt).toLocaleString()}}</time></button></section><section class="detail" @show="!!current()" x-cloak><article class="hero panel" x-cloak><div x-cloak><span class="pill" :class="tone(current()?.status)" x-cloak>{{current()?.status}}</span><h2 x-cloak>{{current()?.resource?.name}}</h2><p x-cloak>{{current()?.environment?.name}} · {{current()?.kind}} · {{current()?.strategy}}</p></div><div class="actions"></div></article><article class="facts panel"><h3>Immutable identity</h3><dl><div><dt>Source commit</dt><dd class="mono" x-cloak>{{current()?.sourceSha||'Not recorded'}}</dd></div><div><dt>Artifact digest</dt><dd class="mono" x-cloak>{{current()?.artifact?.digest}}</dd></div><div><dt>Artifact URI</dt><dd class="mono" x-cloak>{{current()?.artifact?.uri}}</dd></div><div><dt>Config hash</dt><dd class="mono" x-cloak>{{current()?.configHash}}</dd></div><div><dt>Trigger / actor</dt><dd x-cloak>{{current()?.trigger}} · {{short(current()?.actorId)}}</dd></div><div><dt>Duration</dt><dd x-cloak>{{duration(current())}}</dd></div><div><dt>Provider versions</dt><dd class="mono" x-cloak>{{JSON.stringify(current()?.transitions.at(-1)?.health||{})}}</dd></div><div><dt>Provenance / attestation</dt><dd class="mono" x-cloak>{{JSON.stringify({provenance:current()?.artifact?.provenance,attestation:current()?.artifact?.attestation})}}</dd></div></dl></article><article class="caveat panel" @show="!!current()?.comparison" x-cloak><h3>Change and rollback preview</h3><div class="change-grid" x-cloak><span x-cloak>Artifact <b x-cloak>{{current()?.comparison.artifactChanged?'changed':'identical'}}</b></span><span x-cloak>Source <b x-cloak>{{current()?.comparison.sourceChanged?'changed':'identical'}}</b></span><span x-cloak>Config <b x-cloak>{{current()?.comparison.configChanged?'changed':'identical'}}</b></span><span x-cloak>Manifest <b x-cloak>{{current()?.comparison.manifestChanges.length}} change(s)</b></span></div><p x-cloak>{{current()?.comparison.dataCaveat}}</p><p class="bad-text" @show="current()?.hooks.migrations==='irreversible'" x-cloak>Irreversible migration hooks are recorded. Traffic rollback will not restore data.</p></article><article class="panel"><h3>Activation steps & health</h3><div class="timeline" x-cloak><div @each="step in current()?.transitions||[]" x-cloak><span x-cloak>{{step.trafficPercent==null?'—':step.trafficPercent+'%'}}</span><b x-cloak>{{step.toStatus}}</b><p x-cloak>{{step.message}}</p><time x-cloak>{{new Date(step.createdAt).toLocaleString()}}</time></div></div></article><article class="panel"><h3>Strategy capability</h3><div class="strategy-grid" x-cloak><div @each="cap in current()?.capabilities||[]" :class="cap.supported?'supported':'unsupported'" x-cloak><b x-cloak>{{cap.strategy}}</b><span x-cloak>{{cap.supported?'Available':'Unavailable'}}</span><p x-cloak>{{cap.explanation}}</p><small x-cloak>{{cap.capacityMultiplier}}× capacity · {{cap.costImpact}} cost</small><small x-cloak>{{cap.rollback}}</small></div></div></article></section></div></main><style>.releases-wrap{max-width:1500px}.page,.hero,.actions{display:flex;justify-content:space-between;gap:12px;align-items:flex-start}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}.stats strong{display:block;font-size:1.7rem;margin-top:8px}.toolbar{display:flex;gap:12px}.toolbar label,.promotion label{display:grid;gap:5px}.release-layout{display:grid;grid-template-columns:340px minmax(0,1fr);gap:14px;align-items:start}.release-list{padding:7px;max-height:1100px;overflow:auto}.release-row{width:100%;display:grid;grid-template-columns:auto 1fr;text-align:left;gap:4px 8px;padding:12px;background:transparent;color:inherit;border:0;border-bottom:1px solid var(--line);cursor:pointer}.release-row:hover,.release-row.selected{background:var(--bg3)}.release-row small,.release-row code,.release-row time{grid-column:2;color:var(--txt3);font-size:11px}.detail{display:grid;gap:12px}.hero h2{margin:8px 0 3px}.hero p{margin:0;color:var(--txt3)}.facts dl{display:grid;grid-template-columns:1fr 1fr;gap:10px}.facts dt{color:var(--txt3);font-size:10px}.facts dd{margin:3px 0;overflow-wrap:anywhere}.change-grid,.strategy-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.change-grid span,.strategy-grid>div{border:1px solid var(--line);padding:10px;border-radius:8px}.strategy-grid>div{display:grid;gap:6px}.strategy-grid .unsupported{opacity:.6}.strategy-grid p{margin:0;font-size:12px}.strategy-grid small{color:var(--txt3)}.timeline>div{display:grid;grid-template-columns:55px 110px 1fr auto;gap:10px;padding:10px 0;border-bottom:1px solid var(--line);align-items:center}.timeline p{margin:0}.timeline time{color:var(--txt3);font-size:11px}.promotion{display:grid;gap:10px}.check{display:flex!important;align-items:center}.empty span{display:block;color:var(--txt3);margin-top:5px}@media(max-width:1050px){.release-layout{grid-template-columns:1fr}.release-list{max-height:360px}.strategy-grid{grid-template-columns:1fr 1fr}}@media(max-width:650px){.stats,.facts dl,.change-grid,.strategy-grid{grid-template-columns:1fr 1fr}.toolbar,.page,.hero{display:grid}.timeline>div{grid-template-columns:45px 1fr}.timeline p,.timeline time{grid-column:2}}@media(max-width:420px){.stats,.facts dl,.change-grid,.strategy-grid{grid-template-columns:1fr}}</style></body></html>
@@ -1,5 +1,5 @@
1
- <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtklnzmompqjwa"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud · Spend &amp; budgets</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <script data-stx-scoped>
2
- function __stx_setup_1788384013583_12() {
1
+ <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtqnk36z5iozjf"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud · Spend &amp; budgets</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <script data-stx-scoped>
2
+ function __stx_setup_1788749987878_13() {
3
3
  const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
4
4
 
5
5
  var acknowledge = undefined;
@@ -205,9 +205,9 @@ trusted = __stxBundle_55dcf44f8138["trusted"];
205
205
  when = __stxBundle_55dcf44f8138["when"];
206
206
  return { acknowledge, api, createBudget, form, guard, lastUpdatedAt, load, money, optional, patchBudget, pct, pollingError, pollingState, refresh, release, removeBudget, report, runCheck, scopeOf, setPeriod, severityTone, tone, trusted, when, __stxBundle_55dcf44f8138 };
207
207
  }
208
- window.__stx_latestSetup=__stx_setup_1788384013583_12;
209
- if(window.stx)window.stx._latestSetup=__stx_setup_1788384013583_12;
210
- </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788384013583_12"><a data-stx-scope="stx_scope_nav_16" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="active" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
208
+ window.__stx_latestSetup=__stx_setup_1788749987878_13;
209
+ if(window.stx)window.stx._latestSetup=__stx_setup_1788749987878_13;
210
+ </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788749987878_13"><a data-stx-scope="stx_scope_nav_17" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="active" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
211
211
  (function() {
212
212
  var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
213
213
  var __destroyHooks = [];
@@ -558,6 +558,6 @@ if(window.stx)window.stx._latestSetup=__stx_setup_1788384013583_12;
558
558
 
559
559
 
560
560
  try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
561
- window.stx._scopes['stx_scope_nav_16'] = __scopeRegistration;
561
+ window.stx._scopes['stx_scope_nav_17'] = __scopeRegistration;
562
562
  })();
563
563
  </script> <main class="wrap" id="main-content"><div class="crumbs">Operations <span class="sep">/</span> Spend &amp; budgets</div><header class="page"><div><h1>Spend &amp; budgets</h1><p>Metered usage, soft and hard caps, enforcement in force, and anomaly detection. Costs are estimated from observed usage, so they update within the hour rather than waiting on a provider invoice.</p></div><div class="header-actions"><select aria-label="Budget period" @change="setPeriod($event)"><option value="monthly">Monthly</option><option value="weekly">Weekly</option><option value="daily">Daily</option></select><span class="pill" :class="pollingState()==='live'?'ok':'warn'" x-cloak>{{ pollingState() }}</span><small x-cloak>{{ lastUpdatedAt()?.toLocaleTimeString()||'connecting' }}</small><button class="btn ghost sm" @click="refresh()">Refresh</button></div></header><p class="notice" role="status" @show="!!notice()" x-cloak>{{ notice() }}</p><p class="bad notice" role="alert" @show="!!actionError()" x-cloak>{{ actionError() }}</p><p class="bad notice" role="alert" @show="!!pollingError()" x-cloak>{{ pollingError() }}</p><div class="notice panel warn" @show="enforcement().some(item=>!item.simulated)" x-cloak><strong>Spend enforcement is in force.</strong><span x-cloak>{{ enforcement().filter(item=>!item.simulated).map(item=>item.action).join(', ') }} — see the Enforcement tab.</span></div><nav class="tabs" aria-label="Spend workspace"><button :class="{active:tab()==='overview'}" @click="tab.set('overview')">Overview</button><button :class="{active:tab()==='budgets'}" @click="tab.set('budgets')">Budgets</button><button :class="{active:tab()==='enforcement'}" @click="tab.set('enforcement')">Enforcement</button><button :class="{active:tab()==='anomalies'}" @click="tab.set('anomalies')">Anomalies</button></nav><section @show="tab()==='overview'" x-cloak><div class="summary"><article class="panel"><b>Spent this period</b><strong x-cloak>{{ money(report()?.totalCents) }}</strong><small x-cloak>{{ report()?.window?.label||'—' }}</small></article><article class="panel"><b>Budgets</b><strong x-cloak>{{ report()?.budgets?.length||0 }}</strong><small x-cloak>{{ (report()?.budgets||[]).filter(b=>b.dryRun).length }} in dry run</small></article><article class="panel"><b>Enforcement</b><strong x-cloak>{{ report()?.enforcement?.strongestAction||'none' }}</strong><small x-cloak>{{ enforcement().length }} action(s) recorded</small></article><article class="panel"><b>Anomalies</b><strong x-cloak>{{ anomalies().filter(a=>!a.acknowledgedAt).length }}</strong><small>unacknowledged</small></article></div><h2>Budget headroom</h2><div class="cards-list" x-cloak><template :for="budget in (report()?.budgets||[])"><article class="row-card panel" x-cloak><div x-cloak><span class="pill" :class="tone(budget.level)" x-cloak>{{ budget.level }}</span><span class="pill" @show="budget.dryRun" x-cloak>dry run</span><b x-cloak>{{ budget.name }}</b><code x-cloak>{{ budget.period }}</code></div><p class="note" x-cloak>{{ money(budget.spentCents) }} of {{ money(budget.limitCents) }} · {{ pct(budget.usedPercent) }} used · {{ money(budget.remainingCents) }} remaining</p><progress :value="Math.min(100,budget.usedPercent||0)" max="100"></progress><p class="note" :class="trusted(budget)?'':'muted'" x-cloak> Projected {{ money(budget.projectedCents) }} ({{ pct(budget.projectedPercent) }}) at {{ pct((budget.projectionConfidence||0)*100) }} confidence. <template :if="!trusted(budget)" x-cloak><span> Too early in the period to act on this forecast.</span></template><template :if="budget.timeToCap" x-cloak><span x-cloak> Reaches the cap in {{ budget.timeToCap }}.</span></template></p><div class="actions" @show="!!budget.activeActions?.length" x-cloak><span class="bad pill" x-cloak>enforcing {{ budget.activeActions.join(', ') }}</span></div></article></template><div class="empty panel" @show="!(report()?.budgets||[]).length" x-cloak><strong>No budgets</strong><span>Usage is metered regardless, but nothing is capped. Create a budget to get warnings and, if you want them, hard caps.</span></div></div><h2>Usage by meter</h2><div class="panel table-wrap"><table><thead><tr><th scope="col">Meter</th><th scope="col">Provider</th><th scope="col">Quantity</th><th scope="col">Cost</th></tr></thead><tbody><template :for="row in (report()?.byMeter||[])"><tr><td x-cloak>{{ row.meter }}</td><td x-cloak>{{ row.provider||'—' }}</td><td x-cloak>{{ row.quantity.toLocaleString(undefined,{maximumFractionDigits:3}) }}</td><td x-cloak>{{ money(row.costCents) }}</td></tr></template></tbody></table><div class="empty" @show="!(report()?.byMeter||[]).length" x-cloak><strong>No metered usage yet</strong><span>Usage rolls up hourly. A freshly deployed project shows nothing until its first full hour.</span></div></div></section><section @show="tab()==='budgets'" class="split" x-cloak><div x-cloak><template :for="item in budgets()"><article class="row-card panel" x-cloak><div x-cloak><span class="pill" :class="item.enabled?'ok':'warn'" x-cloak>{{ item.enabled?'enabled':'disabled' }}</span><span class="pill" @show="item.dryRun" x-cloak>dry run</span><b x-cloak>{{ item.name }}</b><code x-cloak>{{ scopeOf(item) }} · {{ item.period }} · {{ item.timezone }}</code></div><p class="note" x-cloak>Soft {{ money(item.softLimitCents,item.currency) }} · hard {{ money(item.hardLimitCents,item.currency) }} · grace {{ item.graceSeconds }}s · hysteresis {{ item.hysteresisPercent }}%</p><p class="note" x-cloak>Ladder: <template :for="threshold in item.thresholds"><span class="pill" x-cloak>{{ threshold.atPercent }}%{{ threshold.onProjection?' (forecast)':'' }} → {{ threshold.actions.join('+') }}</span></template></p><div class="actions" x-cloak><button class="btn ghost sm" :disabled="busy()" @click="patchBudget(item.id,{dryRun:!item.dryRun})" x-cloak>{{ item.dryRun?'Start enforcing':'Return to dry run' }}</button><button class="btn ghost sm" :disabled="busy()" @click="patchBudget(item.id,{enabled:!item.enabled})" x-cloak>{{ item.enabled?'Disable':'Enable' }}</button><button class="btn danger ghost sm" :disabled="busy()" @click="removeBudget(item.id,item.name)">Delete</button></div></article></template><div class="empty panel" @show="!budgets().length" x-cloak><strong>No budgets configured</strong><span>Nothing is capping this project.</span></div></div><form class="editor panel" @submit="createBudget($event)"><h2>New budget</h2><label>Name<input name="name" required placeholder="Production monthly"></label><label>Scope<select name="scope"><option value="project">This project</option><option value="environment">This environment</option><option value="organization">Whole organization</option></select></label><label>Period<select name="period"><option value="monthly">Monthly</option><option value="weekly">Weekly</option><option value="daily">Daily</option></select></label><label>Timezone<input name="timezone" value="UTC" placeholder="America/Los_Angeles"></label><label>Soft limit (warn only, dollars)<input name="soft" type="number" step="0.01" min="0"></label><label>Hard limit (enforces, dollars)<input name="hard" type="number" step="0.01" min="0"></label><label>Grace seconds<input name="graceSeconds" type="number" min="0" value="300"></label><label class="checkbox"><input name="dryRun" type="checkbox" checked> Dry run — evaluate and report, enforce nothing</label><button class="btn" type="submit" :disabled="busy()">Create budget</button><p class="note">New budgets start in dry run. Watch one for a full period before letting it enforce: the first thing enforcement does is stop your deployments.</p></form></section><section @show="tab()==='enforcement'" x-cloak><div class="header-actions"><button class="btn ghost sm" :disabled="busy()" @click="runCheck(false)">Preview a cycle</button><button class="btn sm" :disabled="busy()" @click="runCheck(true)">Run and apply</button></div><div class="panel table-wrap"><table><thead><tr><th scope="col">Action</th><th scope="col">Scope</th><th scope="col">Mode</th><th scope="col">Since</th><th scope="col">Reason</th><th scope="col"></th></tr></thead><tbody><template :for="item in enforcement()"><tr><td x-cloak><span class="pill" :class="item.simulated?'warn':'bad'" x-cloak>{{ item.action }}</span></td><td x-cloak>{{ scopeOf(item) }}</td><td x-cloak>{{ item.simulated?'dry run':'enforcing' }}</td><td x-cloak>{{ when(item.appliedAt) }}</td><td x-cloak>{{ item.reason }}</td><td><button class="btn ghost sm" :disabled="busy()" @click="release(item.budgetId,item.action)">Lift</button></td></tr></template></tbody></table><div class="empty" @show="!enforcement().length" x-cloak><strong>Nothing is being enforced</strong><span>Builds, deployments, and traffic are unrestricted by spend.</span></div></div><p class="note">Lifting an action is a stopgap. The next spend cycle re-applies it unless the underlying spend falls back below the threshold, or the budget is raised, disabled, or deleted.</p></section><section @show="tab()==='anomalies'" x-cloak><div class="cards-list" x-cloak><template :for="item in anomalies()"><article class="row-card panel" x-cloak><div x-cloak><span class="pill" :class="severityTone(item.severity)" x-cloak>{{ item.severity }}</span><span class="pill" x-cloak>{{ item.direction }}</span><b x-cloak>{{ item.signal }}</b><code x-cloak>{{ when(item.bucketStart) }}</code></div><p class="note" x-cloak>Observed {{ money(item.observed) }} against an expected {{ money(item.expected) }} for this hour · score {{ item.score.toFixed(1) }}</p><p class="muted note">The baseline is the median of the same hour on previous days, so a normal daily peak is not an anomaly.</p><div class="actions"><button class="btn ghost sm" @show="!item.acknowledgedAt" :disabled="busy()" @click="acknowledge(item.id)" x-cloak>Acknowledge</button><span class="note" @show="!!item.acknowledgedAt" x-cloak>Acknowledged {{ when(item.acknowledgedAt) }}</span></div></article></template><div class="empty panel" @show="!anomalies().length" x-cloak><strong>No anomalies detected</strong><span>Detection needs several days of history before it reports anything, so a new project stays quiet at first.</span></div></div></section></main></body></html>
@@ -1,5 +1,5 @@
1
- <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtklnzmompqjwa"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Workloads</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
2
- function __stx_setup_1788384013582_11() {
1
+ <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtqnk36z5iozjf"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <script data-stx-composables src="/_stx/chunk.5ddb5087.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Workloads</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"> <script data-stx-scoped>
2
+ function __stx_setup_1788749987876_11() {
3
3
  const { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
4
4
 
5
5
  var age = undefined;
@@ -315,9 +315,9 @@ async function chooseUpload(event) {
315
315
  event.target.value = "";
316
316
  return;
317
317
  }
318
- const bytes2 = new Uint8Array(await file.arrayBuffer());
318
+ const bytes = new Uint8Array(await file.arrayBuffer());
319
319
  let binary = "";
320
- for (const byte of bytes2)
320
+ for (const byte of bytes)
321
321
  binary += String.fromCharCode(byte);
322
322
  uploadBase64.set(btoa(binary));
323
323
  uploadName.set(file.name);
@@ -336,8 +336,8 @@ async function fileRequest(action) {
336
336
  throw new Error(body.error || `File ${action} failed.`);
337
337
  if (action === "read") {
338
338
  const binary = atob(body.contentBase64 || "");
339
- const bytes2 = Uint8Array.from(binary, (char) => char.charCodeAt(0));
340
- const url = URL.createObjectURL(new Blob([bytes2]));
339
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
340
+ const url = URL.createObjectURL(new Blob([bytes]));
341
341
  const link = document.createElement("a");
342
342
  link.href = url;
343
343
  link.download = filePath().split("/").pop() || "download";
@@ -409,9 +409,9 @@ uploadName = __stxBundle_cc737a64e01f["uploadName"];
409
409
  visible = __stxBundle_cc737a64e01f["visible"];
410
410
  return { age, bytes, capability, chooseUpload, close, columns, connectStream, disconnectStream, eventStream, execCommand, fileBusy, filePath, fileRequest, inventory, lastUpdatedAt, load, logs, logsBusy, message, open, operationBusy, params, pollingError, pollingLabel, pollingState, provider, query, readLogs, refresh, replicaLabel, replicas, run, selected, selectedId, serviceFilter, setFilter, sources, startExec, startLogFollow, status, stopStream, streamSession, streamState, syncUrl, tone, typed, uploadBase64, uploadName, visible, __stxBundle_cc737a64e01f };
411
411
  }
412
- window.__stx_latestSetup=__stx_setup_1788384013582_11;
413
- if(window.stx)window.stx._latestSetup=__stx_setup_1788384013582_11;
414
- </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788384013582_11"><a data-stx-scope="stx_scope_nav_15" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="active" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
412
+ window.__stx_latestSetup=__stx_setup_1788749987876_11;
413
+ if(window.stx)window.stx._latestSetup=__stx_setup_1788749987876_11;
414
+ </script> <style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx="__stx_setup_1788749987876_11"><a data-stx-scope="stx_scope_nav_15" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="active" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
415
415
  (function() {
416
416
  var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
417
417
  var __destroyHooks = [];
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtklnzmompqjwa"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Security posture</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"><style> .security-hero { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:24px; align-items:start } .security-actions { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px } .posture-score { font-size:2.5rem; line-height:1; font-weight:760; letter-spacing:-.05em } .severity-grid { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:10px } .severity-card { border-left:3px solid var(--line); min-height:110px } .severity-card.critical { border-color:#ff5f68 }.severity-card.high { border-color:#f39b52 }.severity-card.medium { border-color:#e4c35e }.severity-card.low { border-color:#65a2ee }.severity-card.info { border-color:#8290a4 } .severity-value { display:block; font-size:1.8rem; font-weight:720; margin-top:12px } .security-layout { display:grid; grid-template-columns:minmax(0,2fr) minmax(290px,1fr); gap:18px; align-items:start } .security-sidebar { display:grid; gap:18px; position:sticky; top:20px } .filter-bar { display:grid; grid-template-columns:minmax(180px,1fr) repeat(3,minmax(130px,.4fr)); gap:8px; margin-bottom:12px } .filter-bar input,.filter-bar select,.finding-actions select,#policy-form input,#policy-form select,.security-dialog input,.security-dialog textarea { width:100%; min-width:0; background:rgba(255,255,255,.045); border:1px solid var(--panel-br); border-radius:8px; padding:9px 10px; color:var(--txt); font:inherit } .filter-bar input:focus,.filter-bar select:focus,.finding-actions select:focus,#policy-form input:focus,#policy-form select:focus,.security-dialog input:focus,.security-dialog textarea:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(90,139,224,.12) } .finding-list,.scanner-list,.decision-list { display:grid; gap:10px } .finding { border:1px solid var(--line); border-radius:10px; padding:16px; background:var(--panel); display:grid; gap:12px } .finding-head { display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:10px; align-items:start } .severity-dot { width:10px; height:10px; border-radius:50%; margin-top:6px; background:#8290a4 } .severity-dot.critical { background:#ff5f68 }.severity-dot.high { background:#f39b52 }.severity-dot.medium { background:#e4c35e }.severity-dot.low { background:#65a2ee } .finding h3 { margin:0; font-size:1rem }.finding p { margin:3px 0 0 } .finding-meta { display:flex; gap:7px; flex-wrap:wrap; color:var(--muted); font-size:.78rem } .finding-actions { display:flex; flex-wrap:wrap; align-items:center; gap:7px } .finding-actions select { width:auto; min-width:150px } .remediation { border-left:2px solid var(--accent); padding-left:10px; color:var(--muted) } .evidence { white-space:pre-wrap; overflow-wrap:anywhere; max-height:150px; overflow:auto; font-size:.75rem; color:var(--muted) } .scanner-row,.decision-row { border:1px solid var(--line); border-radius:8px; padding:12px; display:grid; gap:5px } .scanner-top,.decision-top { display:flex; justify-content:space-between; gap:10px; align-items:center } .policy-rules { display:grid; gap:7px; margin:12px 0 } .policy-rule { display:grid; grid-template-columns:1fr 1fr; gap:7px } #policy-form { display:grid; gap:10px } #policy-form label,.policy-rule label,.security-dialog label { display:grid; gap:6px; color:var(--txt3); font-size:.72rem; font-weight:750; letter-spacing:.04em } #policy-form label input,#policy-form label select,.security-dialog label input,.security-dialog label textarea { color:var(--txt); font-weight:450; letter-spacing:0 } .status-line { min-height:1.3em; color:var(--muted); margin-top:8px } dialog.security-dialog { width:min(560px,calc(100vw - 32px)); border:1px solid var(--line); border-radius:12px; background:var(--panel); color:inherit; padding:22px } dialog.security-dialog::backdrop { background:rgba(0,0,0,.68) } dialog.security-dialog form { display:grid; gap:12px }.dialog-actions { display:flex; justify-content:flex-end; gap:8px } .empty-security { padding:28px; text-align:center; border:1px dashed var(--line); border-radius:10px; color:var(--muted) } @media (max-width:900px) { .security-layout,.security-hero { grid-template-columns:1fr }.security-sidebar { position:static }.security-actions { justify-content:flex-start }.severity-grid { grid-template-columns:repeat(2,1fr) }.filter-bar { grid-template-columns:1fr 1fr } } @media (max-width:560px) { .severity-grid,.filter-bar { grid-template-columns:1fr }.finding-head { grid-template-columns:auto minmax(0,1fr) }.finding-head > :last-child { grid-column:2 } } </style><style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx-auto><a data-stx-scope="stx_scope_nav_53" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
1
+ <!DOCTYPE html><html lang="en" data-theme="dark"><head><meta charset="UTF-8"><meta name="stx-build" content="mtqnk36z5iozjf"><meta name="title" content="stx Project"><meta name="description" content="A website built with stx templating engine"><meta property="og:title" content="stx Project"><meta property="og:description" content="A website built with stx templating engine"><meta property="og:type" content="website"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="stx Project"><meta name="twitter:description" content="A website built with stx templating engine"> <script data-stx-runtime src="/_stx/runtime.dbee66d1.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"><title>ts-cloud - Security posture</title><link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect x='3' y='3' width='26' height='26' rx='8' fill='%235a8be0'/%3E%3C/svg%3E"><link rel="preconnect" href="https://fonts.googleapis.com"><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"><link rel="stylesheet" href="/_stx/style.448ab192.css"><style> .security-hero { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:24px; align-items:start } .security-actions { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px } .posture-score { font-size:2.5rem; line-height:1; font-weight:760; letter-spacing:-.05em } .severity-grid { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:10px } .severity-card { border-left:3px solid var(--line); min-height:110px } .severity-card.critical { border-color:#ff5f68 }.severity-card.high { border-color:#f39b52 }.severity-card.medium { border-color:#e4c35e }.severity-card.low { border-color:#65a2ee }.severity-card.info { border-color:#8290a4 } .severity-value { display:block; font-size:1.8rem; font-weight:720; margin-top:12px } .security-layout { display:grid; grid-template-columns:minmax(0,2fr) minmax(290px,1fr); gap:18px; align-items:start } .security-sidebar { display:grid; gap:18px; position:sticky; top:20px } .filter-bar { display:grid; grid-template-columns:minmax(180px,1fr) repeat(3,minmax(130px,.4fr)); gap:8px; margin-bottom:12px } .filter-bar input,.filter-bar select,.finding-actions select,#policy-form input,#policy-form select,.security-dialog input,.security-dialog textarea { width:100%; min-width:0; background:rgba(255,255,255,.045); border:1px solid var(--panel-br); border-radius:8px; padding:9px 10px; color:var(--txt); font:inherit } .filter-bar input:focus,.filter-bar select:focus,.finding-actions select:focus,#policy-form input:focus,#policy-form select:focus,.security-dialog input:focus,.security-dialog textarea:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px rgba(90,139,224,.12) } .finding-list,.scanner-list,.decision-list { display:grid; gap:10px } .finding { border:1px solid var(--line); border-radius:10px; padding:16px; background:var(--panel); display:grid; gap:12px } .finding-head { display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:10px; align-items:start } .severity-dot { width:10px; height:10px; border-radius:50%; margin-top:6px; background:#8290a4 } .severity-dot.critical { background:#ff5f68 }.severity-dot.high { background:#f39b52 }.severity-dot.medium { background:#e4c35e }.severity-dot.low { background:#65a2ee } .finding h3 { margin:0; font-size:1rem }.finding p { margin:3px 0 0 } .finding-meta { display:flex; gap:7px; flex-wrap:wrap; color:var(--muted); font-size:.78rem } .finding-actions { display:flex; flex-wrap:wrap; align-items:center; gap:7px } .finding-actions select { width:auto; min-width:150px } .remediation { border-left:2px solid var(--accent); padding-left:10px; color:var(--muted) } .evidence { white-space:pre-wrap; overflow-wrap:anywhere; max-height:150px; overflow:auto; font-size:.75rem; color:var(--muted) } .scanner-row,.decision-row { border:1px solid var(--line); border-radius:8px; padding:12px; display:grid; gap:5px } .scanner-top,.decision-top { display:flex; justify-content:space-between; gap:10px; align-items:center } .policy-rules { display:grid; gap:7px; margin:12px 0 } .policy-rule { display:grid; grid-template-columns:1fr 1fr; gap:7px } #policy-form { display:grid; gap:10px } #policy-form label,.policy-rule label,.security-dialog label { display:grid; gap:6px; color:var(--txt3); font-size:.72rem; font-weight:750; letter-spacing:.04em } #policy-form label input,#policy-form label select,.security-dialog label input,.security-dialog label textarea { color:var(--txt); font-weight:450; letter-spacing:0 } .status-line { min-height:1.3em; color:var(--muted); margin-top:8px } dialog.security-dialog { width:min(560px,calc(100vw - 32px)); border:1px solid var(--line); border-radius:12px; background:var(--panel); color:inherit; padding:22px } dialog.security-dialog::backdrop { background:rgba(0,0,0,.68) } dialog.security-dialog form { display:grid; gap:12px }.dialog-actions { display:flex; justify-content:flex-end; gap:8px } .empty-security { padding:28px; text-align:center; border:1px dashed var(--line); border-radius:10px; color:var(--muted) } @media (max-width:900px) { .security-layout,.security-hero { grid-template-columns:1fr }.security-sidebar { position:static }.security-actions { justify-content:flex-start }.severity-grid { grid-template-columns:repeat(2,1fr) }.filter-bar { grid-template-columns:1fr 1fr } } @media (max-width:560px) { .severity-grid,.filter-bar { grid-template-columns:1fr }.finding-head { grid-template-columns:auto minmax(0,1fr) }.finding-head > :last-child { grid-column:2 } } </style><style data-stx-cloak>[x-cloak]{display:none !important}</style><link data-crosswind="generated" rel="stylesheet" href="/_stx/crosswind.906ee17c.css"></head><body data-stx-auto><a data-stx-scope="stx_scope_nav_52" class="skip-link" href="#main-content">Skip to content</a><button class="nav-toggle-button" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false"><span></span><span></span><span></span></button><button class="nav-scrim" type="button" aria-label="Close navigation"></button><aside class="app-sidebar" id="primary-navigation" aria-label="Primary navigation"><a class="brand" href="/?env=production"><span class="dot"></span><span>ts-cloud</span></a><div class="sidebar-context"><span class="context-label">Project</span><strong>Project</strong></div><div class="environment-picker" aria-label="Environment"><span class="context-label">Environment</span><details><summary class="environment-current production"><span>PROD</span><strong>production</strong></summary></details></div><button class="command-trigger" type="button" aria-keyshortcuts="Meta+K Control+K"><span>Search resources</span><kbd>⌘ K</kbd></button><div class="nav-groups"><section class="nav-group"><h2>Overview</h2><a class="" href="/?env=production">Dashboard</a><a href="/server/activity?env=production">Activity</a></section><section class="nav-group"><h2>Applications</h2><a class="" href="/server/sites?env=production">Services</a><a class="" href="/server/deployments?env=production">Deployments</a><a class="" href="/server/logs?env=production">Logs</a><a class="" href="/integrations?env=production">Git integrations</a><a class="" href="/applications/new?env=production">Create application</a><a class="" href="/applications/compose?env=production">Compose applications</a></section><section class="nav-group"><h2>Operations</h2><a class="" href="/operations/queue?env=production">Deployment queue</a><a class="" href="/operations/previews?env=production">Preview environments</a><a class="" href="/operations/releases?env=production">Releases & promotion</a><a class="" href="/operations/regions?env=production">Regions & failover</a><a class="" href="/operations/maintenance?env=production">Maintenance & DR</a><a class="" href="/operations/workloads?env=production">Workloads</a><a class="" href="/operations/observability?env=production">Observability</a><a class="" href="/operations/alerts?env=production">Alerts & health</a><a class="" href="/operations/spend?env=production">Spend & budgets</a><a href="/server/metrics?env=production">Metrics</a><a href="/server/services?env=production">Runtime services</a><a class="" href="/operations/jobs?env=production">Workers & schedules</a><a class="" href="/operations/configuration?env=production">Environment &amp; secrets</a><a class="" href="/data/backups?env=production">Backups &amp; recovery</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/actions?env=production">Run operations</a></section><section class="nav-group"><h2>Infrastructure</h2><a class="" href="/infrastructure/topology?env=production">Infrastructure map</a><a class="" href="/data/services?env=production">Data services</a><a class="" href="/data/volumes?env=production">Persistent volumes</a><a href="/server/firewall?env=production">Network & firewall</a><a href="/server/ssh-keys?env=production">SSH keys</a><a class="" href="/server/fleet?env=production">Fleet inventory</a><a class="" href="/server/capacity?env=production">Capacity & placement</a><a href="/security?env=production">Security posture</a><a href="/server/terminal?env=production">Terminal</a></section><section class="nav-group"><h2>Organization</h2><a class="" href="/server/team?env=production">People & access</a><a class="" href="/account/automation?env=production">API & automation</a></section><section class="nav-group"><h2>Account</h2><a class="" href="/account/security?env=production">Sign-in & security</a></section></div><form method="post" action="/api/logout" class="signout"><button type="submit">Sign out</button></form></aside><dialog class="command-palette" aria-labelledby="command-title"><div class="command-search"><span aria-hidden="true">⌕</span><input type="search" placeholder="Search services, domains, deployments…" aria-label="Search resources" autocomplete="off"><button type="button" class="command-close" aria-label="Close search">Esc</button></div><h2 id="command-title" class="sr-only">Search resources and navigation</h2><div class="command-status" role="status">Start typing to search this project.</div><section class="saved-views" aria-labelledby="saved-views-title"><div class="saved-views-heading"><h3 id="saved-views-title">Saved views</h3><form class="save-view-form"><label class="sr-only" for="save-view-name">Saved view name</label><input id="save-view-name" maxlength="64" placeholder="Name this view" autocomplete="off"><button type="submit">Save current filters</button></form></div><div class="saved-view-list"></div></section><form class="tag-result-form"><label for="tag-result-name">Tag selected resource</label><input id="tag-result-name" maxlength="32" placeholder="customer-facing" pattern="[A-Za-z0-9][A-Za-z0-9 -]{0,31}" autocomplete="off"><input class="tag-color" type="color" value="#5a8be0" aria-label="Tag color"><button type="submit">Add tag</button></form><div class="command-results" role="listbox" aria-label="Search results"></div><footer><span>↑ ↓ navigate</span><span>Enter open</span><span>Esc close</span></footer></dialog><div class="context-bar" aria-label="Current scope"><div class="context-path"><div class="context-breadcrumb"><span>Project</span><i>/</i><strong>production</strong></div><div class="context-filters" aria-label="Active filters"></div></div><span class="scope-safety production">Production scope</span></div> <script data-stx-scoped data-stx-run="always">
2
2
  (function() {
3
3
  var { batch, computed, configureFetch, defineEmits, defineExpose, definePageMeta, defineProps, defineSlots, defineStore, derived, effect, goBack, goForward, inject, invalidateRoute, isDerived, isSignal, navigate, nextTick, onBeforeMount, onBeforeUnmount, onDestroy, onMount, onMounted, onUnmounted, peek, provide, reactive, ref, refresh, registerStoresClient, setRouteParams, state, untrack, useAsync, useClickOutside, useColorMode, useCookie, useCounter, useDark, useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus, useHead, useId, useInterval, useLocalStorage, useMediaQuery, useMutation, useOptimistic, usePreferredContrast, usePreferredDark, usePreferredLight, usePreferredReducedMotion, useQuery, useReactiveProp, useRef, useRoute, useRouteParam, useRouteParams, useScrollLock, useSearchParams, useSeoMeta, useSessionStorage, useSlots, useStore, useThrottle, useTimeout, useToggle, useWebSocket, watch, watchEffect, watchMultiple, withDefaults } = window.stx;
4
4
  var __destroyHooks = [];
@@ -349,7 +349,7 @@
349
349
 
350
350
 
351
351
  try { if (typeof __stxScopeRenames !== 'undefined' && __stxScopeRenames) { for (var __stxRK in __stxScopeRenames) __scopeRegistration[__stxRK] = __stxScopeRenames[__stxRK]; } } catch (e) { /* no renames */ }
352
- window.stx._scopes['stx_scope_nav_53'] = __scopeRegistration;
352
+ window.stx._scopes['stx_scope_nav_52'] = __scopeRegistration;
353
353
  })();
354
354
  </script> <div class="wrap" id="main-content"><div class="crumbs"><a href="/">Project</a><span class="sep">/</span> Security posture</div><header class="page security-hero"><div><h1>Security posture</h1><p>Findings, supply-chain checks, policy gates, and time-limited exceptions for <strong>production</strong>.</p></div><div class="security-actions"><button class="btn ghost" id="export-posture" type="button">Export report</button><button class="btn ghost" id="review-change" type="button">Review production change</button><button class="btn" id="run-scans" type="button">Run checks</button></div></header><div class="section severity-grid" aria-label="Open findings by severity"><div class="critical panel severity-card"><span class="note">Critical</span><strong class="severity-value" data-severity="critical">—</strong><small>Immediate action</small></div><div class="high panel severity-card"><span class="note">High</span><strong class="severity-value" data-severity="high">—</strong><small>Prioritize remediation</small></div><div class="medium panel severity-card"><span class="note">Medium</span><strong class="severity-value" data-severity="medium">—</strong><small>Review and schedule</small></div><div class="low panel severity-card"><span class="note">Low</span><strong class="severity-value" data-severity="low">—</strong><small>Defense in depth</small></div><div class="info panel severity-card"><span class="note">Waived</span><strong class="severity-value" id="waived-count">—</strong><small>Expires automatically</small></div></div><div class="section security-layout"><main><div class="section-heading"><div><h2>Findings</h2><p class="note">Repeated observations update one lifecycle and preserve recurrence history.</p></div></div><div class="filter-bar" aria-label="Finding filters"><input id="finding-search" type="search" placeholder="Search title, resource, scanner…" aria-label="Search findings"><select id="severity-filter" aria-label="Severity"><option value="">All severities</option><option>critical</option><option>high</option><option>medium</option><option>low</option><option>info</option></select><select id="status-filter" aria-label="Status"><option value="">All statuses</option><option>open</option><option>acknowledged</option><option>waived</option><option>resolved</option></select><select id="scanner-filter" aria-label="Scanner"><option value="">All scanners</option></select></div><div class="finding-list" id="finding-list"><div class="empty-security">Loading security findings…</div></div></main><aside class="security-sidebar"><section class="panel"><div class="scanner-top"><h2>Deploy policy</h2><span class="pill" id="policy-version">—</span></div><form id="policy-form"><label>Name<input name="name" maxlength="100" required></label><label>Scanner outage behavior<select name="scannerFailMode"><option value="closed">Fail closed</option><option value="open">Fail open with warning</option></select></label><label>Required scanners<input name="requiredScanners" placeholder="source-secrets, trivy-image"></label><div class="policy-rules"><div class="policy-rule"><label>Critical<select name="critical"><option value="block">Block</option><option value="warn">Warn</option><option value="record">Record</option></select></label><label>High<select name="high"><option value="block">Block</option><option value="warn">Warn</option><option value="record">Record</option></select></label></div><div class="policy-rule"><label>Medium<select name="medium"><option value="warn">Warn</option><option value="block">Block</option><option value="record">Record</option></select></label><label>Low<select name="low"><option value="record">Record</option><option value="warn">Warn</option><option value="block">Block</option></select></label></div></div><button class="btn sm" type="submit">Save policy</button><p class="status-line" id="policy-status" role="status"></p></form></section><section class="panel"><div class="scanner-top"><h2>Scanner health</h2><span class="pill" id="last-scan">—</span></div><div class="scanner-list" id="scanner-list"><div class="note">Loading checks…</div></div></section><section class="panel"><h2>Recent decisions</h2><div class="decision-list" id="decision-list"><div class="note">No policy decisions yet.</div></div></section></aside></div><p class="status-line" id="page-status" role="status"></p></div><dialog class="security-dialog" id="waiver-dialog"><form id="waiver-form"><div><h2>Time-limited waiver</h2><p class="note" id="waiver-finding-title"></p></div><input type="hidden" name="findingId"><label>Reason<textarea name="reason" minlength="8" maxlength="1000" rows="4" required placeholder="Why is accepting this risk necessary, and what is the remediation plan?"></textarea></label><label>Tracking link<input name="referenceUrl" type="url" placeholder="https://tickets.example/SEC-123"></label><label>Expires<input name="expiresAt" type="datetime-local" required></label><p class="note">Creating a waiver requires recent authentication and is recorded in the organization audit log.</p><div class="dialog-actions"><button class="btn ghost" type="button" data-close-dialog>Cancel</button><button class="btn" type="submit">Create waiver</button></div><p class="status-line" id="waiver-status" role="status"></p></form></dialog><dialog class="security-dialog" id="comment-dialog"><form id="comment-form"><div><h2>Add finding note</h2><p class="note" id="comment-finding-title"></p></div><input type="hidden" name="findingId"><label>Note<textarea name="body" minlength="2" maxlength="4000" rows="4" required></textarea></label><label>Reference link<input name="referenceUrl" type="url" placeholder="https://tickets.example/SEC-123"></label><div class="dialog-actions"><button class="btn ghost" type="button" data-close-dialog>Cancel</button><button class="btn" type="submit">Save note</button></div><p class="status-line" id="comment-status" role="status"></p></form></dialog> <script data-stx-scoped data-stx-run="always">
355
355
  ;(function() {