@kingsleyweb/bun-ui 0.0.0-stage → 3.0.0-rc.2

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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -2
  3. package/app/docs/App.tsx +72 -0
  4. package/app/docs/api/client.ts +303 -0
  5. package/app/docs/api/contract.ts +24 -0
  6. package/app/docs/api/docs.ts +38 -0
  7. package/app/docs/api/errors.ts +144 -0
  8. package/app/docs/boot.tsx +58 -0
  9. package/app/docs/components/Badge.tsx +65 -0
  10. package/app/docs/components/Button.tsx +37 -0
  11. package/app/docs/components/Card.tsx +41 -0
  12. package/app/docs/components/ConfirmDialog.tsx +173 -0
  13. package/app/docs/components/CopyButton.tsx +68 -0
  14. package/app/docs/components/Dialog.tsx +230 -0
  15. package/app/docs/components/EmptyState.tsx +34 -0
  16. package/app/docs/components/ErrorView.tsx +70 -0
  17. package/app/docs/components/Field.tsx +93 -0
  18. package/app/docs/components/JsonEditor.tsx +151 -0
  19. package/app/docs/components/JsonView.tsx +338 -0
  20. package/app/docs/components/KeyValue.tsx +63 -0
  21. package/app/docs/components/ProblemBanner.tsx +116 -0
  22. package/app/docs/components/ScreenErrorBoundary.tsx +141 -0
  23. package/app/docs/components/Spinner.tsx +33 -0
  24. package/app/docs/components/Table.tsx +33 -0
  25. package/app/docs/components/Tabs.tsx +226 -0
  26. package/app/docs/components/classNames.ts +4 -0
  27. package/app/docs/components/components.css +691 -0
  28. package/app/docs/components/copy.ts +89 -0
  29. package/app/docs/components/fieldContext.ts +29 -0
  30. package/app/docs/components/inputValues.ts +142 -0
  31. package/app/docs/components/inputs.tsx +387 -0
  32. package/app/docs/components/jsonParse.ts +338 -0
  33. package/app/docs/components/listKeys.ts +30 -0
  34. package/app/docs/config.ts +86 -0
  35. package/app/docs/context.ts +33 -0
  36. package/app/docs/embed.ts +74 -0
  37. package/app/docs/env.d.ts +2 -0
  38. package/app/docs/format.ts +9 -0
  39. package/app/docs/hooks/useUrlTab.ts +16 -0
  40. package/app/docs/main.tsx +11 -0
  41. package/app/docs/queryClient.ts +54 -0
  42. package/app/docs/router.tsx +194 -0
  43. package/app/docs/routing.ts +194 -0
  44. package/app/docs/screens/docs/document.ts +27 -0
  45. package/app/docs/screens/docs/http/OperationView.tsx +407 -0
  46. package/app/docs/screens/docs/http/Sidebar.tsx +190 -0
  47. package/app/docs/screens/docs/http/TryItPanel.tsx +603 -0
  48. package/app/docs/screens/docs/http/http.css +405 -0
  49. package/app/docs/screens/docs/http/index.tsx +395 -0
  50. package/app/docs/screens/docs/http/model.ts +604 -0
  51. package/app/docs/screens/docs/http/tryIt.ts +455 -0
  52. package/app/docs/screens/docs/permissions.ts +6 -0
  53. package/app/docs/screens/docs/schema/Prose.tsx +43 -0
  54. package/app/docs/screens/docs/schema/SchemaTree.tsx +319 -0
  55. package/app/docs/screens/docs/schema/index.ts +30 -0
  56. package/app/docs/screens/docs/schema/resolve.ts +466 -0
  57. package/app/docs/screens/docs/schema/schema.css +137 -0
  58. package/app/docs/screens/docs/schema/skeleton.ts +92 -0
  59. package/app/docs/screens/docs/viewer.tsx +154 -0
  60. package/app/docs/screens/docs/ws/InlineText.tsx +25 -0
  61. package/app/docs/screens/docs/ws/PayloadSchema.tsx +39 -0
  62. package/app/docs/screens/docs/ws/format.ts +82 -0
  63. package/app/docs/screens/docs/ws/index.tsx +286 -0
  64. package/app/docs/screens/docs/ws/items.tsx +786 -0
  65. package/app/docs/screens/docs/ws/model.ts +1178 -0
  66. package/app/docs/screens/docs/ws/panels.tsx +440 -0
  67. package/app/docs/screens/docs/ws/ws.css +231 -0
  68. package/app/docs/shortcuts.ts +94 -0
  69. package/app/docs/styles/base.css +847 -0
  70. package/app/docs/styles/tokens.css +143 -0
  71. package/app/docs/theme.ts +56 -0
  72. package/app/kit/unauthorized.ts +222 -0
  73. package/dist/docs/assets/main-0rchxtv5.js +18 -0
  74. package/dist/docs/assets/main-0rchxtv5.js.map +99 -0
  75. package/dist/docs/assets/main-cqgyvs86.css +1 -0
  76. package/dist/docs/manifest.json +26 -0
  77. package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js +6 -0
  78. package/dist/jobs/assets/AddFlowDialog-h6xkgx9b.js.map +11 -0
  79. package/dist/jobs/assets/AddFlowDialog-n7gtc84v.css +1 -0
  80. package/dist/jobs/assets/added-cbwsxv3e.js +4 -0
  81. package/dist/jobs/assets/added-cbwsxv3e.js.map +11 -0
  82. package/dist/jobs/assets/bodies-yyw5hmrp.js +6 -0
  83. package/dist/jobs/assets/bodies-yyw5hmrp.js.map +10 -0
  84. package/dist/jobs/assets/channel-tgkvqm8y.js +4 -0
  85. package/dist/jobs/assets/channel-tgkvqm8y.js.map +10 -0
  86. package/dist/jobs/assets/channelChecks-s4yz4yhw.js +4 -0
  87. package/dist/jobs/assets/channelChecks-s4yz4yhw.js.map +10 -0
  88. package/dist/jobs/assets/index-02427smp.css +1 -0
  89. package/dist/jobs/assets/index-09z2cjft.js +4 -0
  90. package/dist/jobs/assets/index-09z2cjft.js.map +16 -0
  91. package/dist/jobs/assets/index-18bn0gvy.css +1 -0
  92. package/dist/jobs/assets/index-47pxmyxn.js +4 -0
  93. package/dist/jobs/assets/index-47pxmyxn.js.map +10 -0
  94. package/dist/jobs/assets/index-4e55z986.js +4 -0
  95. package/dist/jobs/assets/index-4e55z986.js.map +11 -0
  96. package/dist/jobs/assets/index-5c933424.js +4 -0
  97. package/dist/jobs/assets/index-5c933424.js.map +18 -0
  98. package/dist/jobs/assets/index-5kbyqspm.css +1 -0
  99. package/dist/jobs/assets/index-5ng37hk6.css +1 -0
  100. package/dist/jobs/assets/index-5w8w7fvc.css +1 -0
  101. package/dist/jobs/assets/index-71qs5qyx.css +1 -0
  102. package/dist/jobs/assets/index-btpg4r8b.css +1 -0
  103. package/dist/jobs/assets/index-d5r5n0mm.js +4 -0
  104. package/dist/jobs/assets/index-d5r5n0mm.js.map +23 -0
  105. package/dist/jobs/assets/index-e0yy2skq.css +1 -0
  106. package/dist/jobs/assets/index-hs60b25v.js +10 -0
  107. package/dist/jobs/assets/index-hs60b25v.js.map +62 -0
  108. package/dist/jobs/assets/index-k2smrr70.js +4 -0
  109. package/dist/jobs/assets/index-k2smrr70.js.map +9 -0
  110. package/dist/jobs/assets/index-q24jw3w9.js +4 -0
  111. package/dist/jobs/assets/index-q24jw3w9.js.map +32 -0
  112. package/dist/jobs/assets/index-qfb80xen.css +1 -0
  113. package/dist/jobs/assets/index-rtynx6wj.js +4 -0
  114. package/dist/jobs/assets/index-rtynx6wj.js.map +10 -0
  115. package/dist/jobs/assets/live-6k7s6358.js +4 -0
  116. package/dist/jobs/assets/live-6k7s6358.js.map +10 -0
  117. package/dist/jobs/assets/main-0jmeh6mq.js +6 -0
  118. package/dist/jobs/assets/main-0jmeh6mq.js.map +12 -0
  119. package/dist/jobs/assets/main-3yj6bv90.js +5 -0
  120. package/dist/jobs/assets/main-3yj6bv90.js.map +10 -0
  121. package/dist/jobs/assets/main-4g69fn3x.js +5 -0
  122. package/dist/jobs/assets/main-4g69fn3x.js.map +10 -0
  123. package/dist/jobs/assets/main-4gte3eqq.js +5 -0
  124. package/dist/jobs/assets/main-4gte3eqq.js.map +10 -0
  125. package/dist/jobs/assets/main-4j1fcevh.js +5 -0
  126. package/dist/jobs/assets/main-4j1fcevh.js.map +10 -0
  127. package/dist/jobs/assets/main-54qwkz28.css +1 -0
  128. package/dist/jobs/assets/main-5grjvsy7.js +5 -0
  129. package/dist/jobs/assets/main-5grjvsy7.js.map +11 -0
  130. package/dist/jobs/assets/main-5zbx60gq.js +5 -0
  131. package/dist/jobs/assets/main-5zbx60gq.js.map +11 -0
  132. package/dist/jobs/assets/main-9prgjhg4.js +5 -0
  133. package/dist/jobs/assets/main-9prgjhg4.js.map +10 -0
  134. package/dist/jobs/assets/main-a250ffk7.js +17 -0
  135. package/dist/jobs/assets/main-a250ffk7.js.map +115 -0
  136. package/dist/jobs/assets/main-d6ge7w08.js +5 -0
  137. package/dist/jobs/assets/main-d6ge7w08.js.map +10 -0
  138. package/dist/jobs/assets/main-gngzht43.js +5 -0
  139. package/dist/jobs/assets/main-gngzht43.js.map +10 -0
  140. package/dist/jobs/assets/main-hg0hrg8j.js +5 -0
  141. package/dist/jobs/assets/main-hg0hrg8j.js.map +10 -0
  142. package/dist/jobs/assets/main-hm1ng3yg.js +5 -0
  143. package/dist/jobs/assets/main-hm1ng3yg.js.map +12 -0
  144. package/dist/jobs/assets/main-jkvd92z9.js +5 -0
  145. package/dist/jobs/assets/main-jkvd92z9.js.map +10 -0
  146. package/dist/jobs/assets/main-jv5xqd13.js +5 -0
  147. package/dist/jobs/assets/main-jv5xqd13.js.map +21 -0
  148. package/dist/jobs/assets/main-jxre7w93.js +5 -0
  149. package/dist/jobs/assets/main-jxre7w93.js.map +23 -0
  150. package/dist/jobs/assets/main-kwmqkjfx.js +5 -0
  151. package/dist/jobs/assets/main-kwmqkjfx.js.map +11 -0
  152. package/dist/jobs/assets/main-n9cf6bxm.js +5 -0
  153. package/dist/jobs/assets/main-n9cf6bxm.js.map +11 -0
  154. package/dist/jobs/assets/main-pegp0ygb.js +5 -0
  155. package/dist/jobs/assets/main-pegp0ygb.js.map +10 -0
  156. package/dist/jobs/assets/main-qr573853.js +5 -0
  157. package/dist/jobs/assets/main-qr573853.js.map +12 -0
  158. package/dist/jobs/assets/main-rq97rdr4.js +4 -0
  159. package/dist/jobs/assets/main-rq97rdr4.js.map +22 -0
  160. package/dist/jobs/assets/main-szjdmydc.js +5 -0
  161. package/dist/jobs/assets/main-szjdmydc.js.map +13 -0
  162. package/dist/jobs/assets/main-tnbhrm9n.js +7 -0
  163. package/dist/jobs/assets/main-tnbhrm9n.js.map +11 -0
  164. package/dist/jobs/assets/main-ts19j4n0.js +5 -0
  165. package/dist/jobs/assets/main-ts19j4n0.js.map +25 -0
  166. package/dist/jobs/assets/main-w93x1dzs.js +5 -0
  167. package/dist/jobs/assets/main-w93x1dzs.js.map +10 -0
  168. package/dist/jobs/assets/sections-0ksdxs8m.css +1 -0
  169. package/dist/jobs/assets/sections-0y7w4fb4.js +4 -0
  170. package/dist/jobs/assets/sections-0y7w4fb4.js.map +10 -0
  171. package/dist/jobs/assets/sse-mn0t0fh7.js +5 -0
  172. package/dist/jobs/assets/sse-mn0t0fh7.js.map +11 -0
  173. package/dist/jobs/assets/sseChecks-t7tcm7ra.js +4 -0
  174. package/dist/jobs/assets/sseChecks-t7tcm7ra.js.map +10 -0
  175. package/dist/jobs/assets/validation-ysjfy072.js +4 -0
  176. package/dist/jobs/assets/validation-ysjfy072.js.map +9 -0
  177. package/dist/jobs/manifest.json +511 -0
  178. package/dts/docs/assets.d.ts +144 -0
  179. package/dts/docs/assets.d.ts.map +1 -0
  180. package/dts/docs/browser/config.d.ts +61 -0
  181. package/dts/docs/browser/config.d.ts.map +1 -0
  182. package/dts/docs/browser/index.d.ts +12 -0
  183. package/dts/docs/browser/index.d.ts.map +1 -0
  184. package/dts/docs/docsUi.d.ts +42 -0
  185. package/dts/docs/docsUi.d.ts.map +1 -0
  186. package/dts/docs/hosted.d.ts +22 -0
  187. package/dts/docs/hosted.d.ts.map +1 -0
  188. package/dts/docs/index.d.ts +18 -0
  189. package/dts/docs/index.d.ts.map +1 -0
  190. package/dts/docs/shell.d.ts +57 -0
  191. package/dts/docs/shell.d.ts.map +1 -0
  192. package/dts/docs/types.d.ts +137 -0
  193. package/dts/docs/types.d.ts.map +1 -0
  194. package/dts/index.d.ts +21 -0
  195. package/dts/index.d.ts.map +1 -0
  196. package/dts/jobs/assets.d.ts +157 -0
  197. package/dts/jobs/assets.d.ts.map +1 -0
  198. package/dts/jobs/browser/config.d.ts +67 -0
  199. package/dts/jobs/browser/config.d.ts.map +1 -0
  200. package/dts/jobs/browser/index.d.ts +10 -0
  201. package/dts/jobs/browser/index.d.ts.map +1 -0
  202. package/dts/jobs/browser/unauthorized.d.ts +9 -0
  203. package/dts/jobs/browser/unauthorized.d.ts.map +1 -0
  204. package/dts/jobs/index.d.ts +24 -0
  205. package/dts/jobs/index.d.ts.map +1 -0
  206. package/dts/jobs/jobsUi.d.ts +63 -0
  207. package/dts/jobs/jobsUi.d.ts.map +1 -0
  208. package/dts/jobs/shell.d.ts +77 -0
  209. package/dts/jobs/shell.d.ts.map +1 -0
  210. package/dts/jobs/types.d.ts +146 -0
  211. package/dts/jobs/types.d.ts.map +1 -0
  212. package/dts/kit/browser/shared.d.ts +10 -0
  213. package/dts/kit/browser/shared.d.ts.map +1 -0
  214. package/dts/kit/browser/unauthorized.d.ts +74 -0
  215. package/dts/kit/browser/unauthorized.d.ts.map +1 -0
  216. package/dts/kit/unauthorized.d.ts +47 -0
  217. package/dts/kit/unauthorized.d.ts.map +1 -0
  218. package/guides/docs.md +170 -0
  219. package/guides/jobs.md +1120 -0
  220. package/lib/docs/assets.ts +427 -0
  221. package/lib/docs/browser/config.ts +66 -0
  222. package/lib/docs/browser/index.ts +24 -0
  223. package/lib/docs/docsUi.ts +623 -0
  224. package/lib/docs/hosted.ts +31 -0
  225. package/lib/docs/index.ts +37 -0
  226. package/lib/docs/shell.ts +156 -0
  227. package/lib/docs/types.ts +149 -0
  228. package/lib/index.ts +27 -0
  229. package/lib/jobs/assets.ts +448 -0
  230. package/lib/jobs/browser/config.ts +65 -0
  231. package/lib/jobs/browser/index.ts +9 -0
  232. package/lib/jobs/browser/unauthorized.ts +11 -0
  233. package/lib/jobs/index.ts +41 -0
  234. package/lib/jobs/jobsUi.ts +709 -0
  235. package/lib/jobs/shell.ts +205 -0
  236. package/lib/jobs/types.ts +162 -0
  237. package/lib/kit/browser/shared.ts +11 -0
  238. package/lib/kit/browser/unauthorized.ts +114 -0
  239. package/lib/kit/unauthorized.ts +222 -0
  240. package/package.json +198 -4
@@ -0,0 +1,4 @@
1
+ import{r,n,e,t,f,i,y,a,Q,s,H,d,p,R,L,u}from"./main-a250ffk7.js";import{Kt,bn,es,Nn}from"./main-n9cf6bxm.js";import{ae}from"./main-d6ge7w08.js";import{re}from"./main-jkvd92z9.js";import{D}from"./main-hm1ng3yg.js";import"./main-5grjvsy7.js";import{pt}from"./main-9prgjhg4.js";import{F}from"./main-pegp0ygb.js";var P=Q*2;function b(){let o=i(),v=y("providers.read"),h=re()("providers.validate"),l=H(P),m=a({queryKey:Kt.list,queryFn:({signal:g})=>bn(o,g),refetchInterval:l,enabled:v});return t("div",{className:"screen","data-testid":"providers-screen",children:[e("h1",{className:"screen-title",children:"Providers"}),!v?e(d,{title:"Nothing to show",description:"You may not read providers on this API."}):m.isPending?e(p,{label:"Loading providers",showLabel:!0}):m.isError?e(L,{error:m.error,title:"Could not load providers",onRetry:()=>void m.refetch()}):m.data.providers.length===0?e(d,{title:"No providers configured",description:"Compute providers appear here once the API's process configures one, e.g. for a queue's summoning."}):t(n,{children:[t("p",{className:"muted","data-testid":"providers-api",children:["Provider API ",u(m.data.api.core),", summon facet"," ",u(m.data.api.summon),". Ids are stable for this process's life only."]}),e("div",{className:"providers-list",children:m.data.providers.map((g)=>e(C,{provider:g,canValidate:h},g.id))})]})]})}function C({provider:o,canValidate:v}){let c=pt(o.readiness),h=u(o.provider.displayName??o.provider.kind),l=Object.entries(o.facts);return e(R,{title:h,children:t("div",{"data-testid":`provider-${o.id}`,children:[e(F,{items:[{key:"readiness",label:"Readiness",value:e(f,{tone:c.tone,title:c.hint,testId:"provider-readiness",children:c.label}),hint:c.hint},{key:"id",label:"Id",value:e("code",{children:u(o.id)})},{key:"package",label:"Package",value:t("span",{children:[e("code",{children:u(o.provider.name)})," ",u(o.provider.version)]})},...l.map(([m,g])=>({key:`fact-${m}`,label:u(m),value:e("code",{children:u(g)})}))]}),v&&o.preflight&&e(Nn,{providerId:o.id,label:h}),o.configSchema&&e(I,{providerId:o.id})]})})}function I({providerId:o}){let v=i(),[c,h]=r(!1),l=a({queryKey:Kt.schema(o),queryFn:({signal:m})=>es(v,o,m),enabled:c,staleTime:Number.POSITIVE_INFINITY});return t("div",{className:"provider-schema",children:[e(s,{size:"sm",variant:"ghost","aria-expanded":c,onClick:()=>h((m)=>!m),children:c?"Hide config schema":"Config schema"}),c&&(l.isPending?e(p,{label:"Loading the config schema"}):l.isError?e(D,{error:l.error,title:"Could not load the config schema"}):e("div",{"data-testid":"provider-schema",children:e(ae,{value:l.data.schema,label:`Config schema of ${o}`,expandDepth:4})}))]})}export{b as ProvidersScreen};
2
+
3
+ //# debugId=BD60E8DFB128DEA264756E2164756E21
4
+ //# sourceMappingURL=index-rtynx6wj.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/screens/providers/ProvidersScreen.tsx"],
4
+ "sourcesContent": [
5
+ "import type { ProviderDto } from \"../../api/types\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useState } from \"react\";\nimport {\n getProviderSchema,\n listProviders,\n providerKeys,\n} from \"../../api/providers\";\nimport { Badge } from \"../../components/Badge\";\nimport { Button } from \"../../components/Button\";\nimport { Card } from \"../../components/Card\";\nimport { EmptyState } from \"../../components/EmptyState\";\nimport { ErrorView } from \"../../components/ErrorView\";\nimport { JsonView } from \"../../components/JsonView\";\nimport { KeyValue } from \"../../components/KeyValue\";\nimport { ProblemBanner } from \"../../components/ProblemBanner\";\nimport { Spinner } from \"../../components/Spinner\";\nimport { useApiClient } from \"../../context\";\nimport { displayText } from \"../../format\";\nimport { usePollInterval } from \"../../live\";\nimport { useCan } from \"../../meta/hooks\";\nimport { POLL_INTERVAL_MS } from \"../../queryClient\";\nimport { useCanMutate } from \"../queues/gating\";\nimport { providerReadiness } from \"./providerText\";\nimport { TestConnection } from \"./TestConnection\";\nimport \"./providers.css\";\n\n/** How often the list is re-read: a provider's readiness changes as its config validates. */\nconst REFRESH_MS = POLL_INTERVAL_MS * 2;\n\n/**\n * `/providers`: the compute providers configured in the API's process\n * (`GET /providers`), each with its readiness, its secret-free facts, \"Test\n * connection\" where it has a preflight, and its config schema where it\n * publishes one.\n *\n * Routed only where the caller may read providers (`providers.read`, opt-in)\n * and the API serves them (`features.providers`, off in `runner` mode); the\n * nav entry follows the same rule.\n */\nexport function ProvidersScreen() {\n const api = useApiClient();\n const canRead = useCan(\"providers.read\");\n const canMutate = useCanMutate();\n const canValidate = canMutate(\"providers.validate\");\n const refetchInterval = usePollInterval(REFRESH_MS);\n const list = useQuery({\n queryKey: providerKeys.list,\n queryFn: ({ signal }) => listProviders(api, signal),\n refetchInterval,\n enabled: canRead,\n });\n return (\n <div\n className=\"screen\"\n data-testid=\"providers-screen\"\n >\n <h1 className=\"screen-title\">Providers</h1>\n {!canRead ? (\n <EmptyState\n title=\"Nothing to show\"\n description=\"You may not read providers on this API.\"\n />\n ) : list.isPending ? (\n <Spinner\n label=\"Loading providers\"\n showLabel\n />\n ) : list.isError ? (\n <ErrorView\n error={list.error}\n title=\"Could not load providers\"\n onRetry={() => void list.refetch()}\n />\n ) : list.data.providers.length === 0 ? (\n <EmptyState\n title=\"No providers configured\"\n description=\"Compute providers appear here once the API's process configures one, e.g. for a queue's summoning.\"\n />\n ) : (\n <>\n <p\n className=\"muted\"\n data-testid=\"providers-api\"\n >\n Provider API {displayText(list.data.api.core)}, summon facet{\" \"}\n {displayText(list.data.api.summon)}. Ids are stable for this\n process's life only.\n </p>\n <div className=\"providers-list\">\n {list.data.providers.map((provider) => (\n <ProviderCard\n key={provider.id}\n provider={provider}\n canValidate={canValidate}\n />\n ))}\n </div>\n </>\n )}\n </div>\n );\n}\n\n/** Props of {@link ProviderCard}. */\ninterface ProviderCardProps {\n /** The provider. */\n provider: ProviderDto;\n /** Whether the caller may run \"Test connection\" (`providers.validate`, not read-only). */\n canValidate: boolean;\n}\n\n/** One provider: who it is, its readiness and facts, and what can be done with it. */\nfunction ProviderCard({ provider, canValidate }: ProviderCardProps) {\n const readiness = providerReadiness(provider.readiness);\n const name = displayText(\n provider.provider.displayName ?? provider.provider.kind,\n );\n const facts = Object.entries(provider.facts);\n return (\n <Card title={name}>\n <div data-testid={`provider-${provider.id}`}>\n <KeyValue\n items={[\n {\n key: \"readiness\",\n label: \"Readiness\",\n value: (\n <Badge\n tone={readiness.tone}\n title={readiness.hint}\n testId=\"provider-readiness\"\n >\n {readiness.label}\n </Badge>\n ),\n hint: readiness.hint,\n },\n {\n key: \"id\",\n label: \"Id\",\n value: <code>{displayText(provider.id)}</code>,\n },\n {\n key: \"package\",\n label: \"Package\",\n value: (\n <span>\n <code>{displayText(provider.provider.name)}</code>{\" \"}\n {displayText(provider.provider.version)}\n </span>\n ),\n },\n ...facts.map(([key, value]) => ({\n key: `fact-${key}`,\n label: displayText(key),\n value: <code>{displayText(value)}</code>,\n })),\n ]}\n />\n {canValidate && provider.preflight && (\n <TestConnection\n providerId={provider.id}\n label={name}\n />\n )}\n {provider.configSchema && <ConfigSchema providerId={provider.id} />}\n </div>\n </Card>\n );\n}\n\n/**\n * A provider's config schema, read only when asked for: secret-free JSON\n * Schema, shown as it is (there is no route that sets a provider's config).\n */\nfunction ConfigSchema({ providerId }: { providerId: string }) {\n const api = useApiClient();\n const [open, setOpen] = useState(false);\n const schema = useQuery({\n queryKey: providerKeys.schema(providerId),\n queryFn: ({ signal }) => getProviderSchema(api, providerId, signal),\n enabled: open,\n staleTime: Number.POSITIVE_INFINITY,\n });\n return (\n <div className=\"provider-schema\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-expanded={open}\n onClick={() => setOpen((was) => !was)}\n >\n {open ? \"Hide config schema\" : \"Config schema\"}\n </Button>\n {open &&\n (schema.isPending ? (\n <Spinner label=\"Loading the config schema\" />\n ) : schema.isError ? (\n <ProblemBanner\n error={schema.error}\n title=\"Could not load the config schema\"\n />\n ) : (\n <div data-testid=\"provider-schema\">\n <JsonView\n value={schema.data.schema}\n label={`Config schema of ${providerId}`}\n // Opened to read it: show properties and their constraints.\n expandDepth={4}\n />\n </div>\n ))}\n </div>\n );\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "BD60E8DFB128DEA264756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,4 @@
1
+ import{G}from"./main-a250ffk7.js";var x={path:"/__live",replies:{subscribe:"hello",resume:"hello"}},X="GET /__live/sse";var K=Symbol.for("@kingsleyweb/bun-client");function E(g){let c=[];for(let d=0;d<g.length;d+=256)c.push(g.slice(d,d+256));return c}function C(g){let c=g;return typeof c?.epoch==="string"&&typeof c.seq==="number"&&Number.isSafeInteger(c.seq)?{epoch:c.epoch,seq:c.seq}:void 0}function j(g,c,d,A){let v=g[K]?.logger??console,m=new Map,f=new Map,y=new Set,w=new Set,S=!1,p=!1,l,_=new WeakMap,b,q=new Set,T=(e)=>{if(!Array.isArray(e))return;let n=e.filter((o)=>typeof o==="string");if(n.length===0||p)return;if(d.onDenied){d.onDenied(n);return}let t=n.filter((o)=>!q.has(o));for(let o of t)q.add(o);if(t.length>0)v.warn(`live(): the server refused the tags ${t.join(", ")}; their queries are not kept fresh`)},L=()=>{c.invalidateQueries()},D=(e,n)=>{if(l!==void 0&&l.epoch!==e.epoch){l=e,L();return}l=n||l===void 0?e:{epoch:e.epoch,seq:Math.max(l.seq,e.seq)}},h={hello(e){let n=C(e);if(n!==void 0)D(n,!1);T(e?.denied)},gap(e){let n=C(e);if(n===void 0)return;l=n,L()},invalidate(e){let n=C(e),t=e?.tags;if(n===void 0||!Array.isArray(t))return;let o=l!==void 0&&l.epoch!==n.epoch;if(D(n,!1),o)return;let i=`${n.epoch}:${n.seq}`,a=new Set(t.filter((r)=>typeof r==="string")),s=c.getQueryCache().findAll({predicate:(r)=>_.get(r)!==i&&A(c,r).some((k)=>a.has(k))});if(s.length===0)return;for(let r of s)_.set(r,i);let u=new Set(s);c.invalidateQueries({predicate:(r)=>u.has(r)})}},N=()=>{if(S)return;S=!0,queueMicrotask(()=>{if(S=!1,p||y.size===0&&w.size===0)return;let e=[...y],n=[...w];y.clear(),w.clear(),b?.changed(e,n)})},P=(e)=>{let n=(f.get(e)??0)+1;if(f.set(e,n),n===1&&!w.delete(e))y.add(e)},O=(e)=>{let n=(f.get(e)??0)-1;if(n>0){f.set(e,n);return}if(f.delete(e),!y.delete(e))w.add(e)},I=(e,n=!1)=>{let t=e.queryHash,o=m.get(t),i=!n&&e.getObserversCount()>0?new Set(A(c,e)):new Set;if(o===void 0&&i.size===0)return;for(let a of i)if(!o?.has(a))P(a);for(let a of o??[])if(!i.has(a))O(a);if(i.size===0)m.delete(t);else m.set(t,i);N()},M=c.getQueryCache();for(let e of M.getAll())I(e);let z=M.subscribe((e)=>{if(e.type==="observerResultsUpdated")return;I(e.query,e.type==="removed")}),Q=async()=>{let{sse:e}=await (G("mn0t0fh7"),import("./sse-mn0t0fh7.js")),n,t=()=>{let o=n;if(n=void 0,o?.close(),p||f.size===0)return;let i=o?.lastEventId||(l===void 0?void 0:`${l.epoch}:${l.seq}`),a=e(g,"GET /__live/sse",{query:{tag:[...f.keys()]},...i?{lastEventId:i}:{}});n=a,a.on("invalidate",(s)=>h.invalidate(s)),a.on("gap",(s)=>h.gap(s)),a.on("hello",(s)=>h.hello(s)),a.closed.catch((s)=>{if(n!==a)return;let u=s,r=u.error;if(u.status===403&&r?.code==="LIVE_TAGS_DENIED"){T(r.denied);return}v.error("live(): the live stream ended",s)})};return t(),{changed(o,i){if(o.length>0||i.length>0&&f.size===0)t()},close:()=>{let o=n;n=void 0,o?.close()}}},R=async()=>{let{channel:e}=await (G("tgkvqm8y"),import("./channel-tgkvqm8y.js")),n=!1,t=e(g,x,{async resubscribe(s){let u=l;for(let r of E([...f.keys()]))h.hello(await s.request("subscribe",{tags:r}));if(u!==void 0&&l?.epoch===u.epoch)h.hello(await s.request("resume",u))}});t.on("invalidate",(s)=>h.invalidate(s)),t.on("gap",(s)=>h.gap(s)),t.on("hello",(s)=>h.hello(s));let o={changed(s,u){if(t.state!=="open")return;if(u.length>0)for(let r of E(u))t.send("unsubscribe",{tags:r});for(let r of E(s))t.request("subscribe",{tags:r}).then((k)=>h.hello(k),(k)=>v.warn("live(): a subscribe failed",k))},close:()=>t.close()},i=setTimeout(()=>{if(n||p||b!==o)return;t.close(),v.warn("live(): the live channel did not open within 3000 ms; using its SSE fallback"),Q().then((s)=>{if(p)s.close();else b=s})},3000);t.on("$state",(s)=>{if(s!=="open")return;n=!0,clearTimeout(i)});let a=o.close;return o.close=()=>{clearTimeout(i),a()},o};return(d.transport==="sse"||d.transport===void 0&&typeof globalThis.WebSocket!=="function"?Q():R()).then((e)=>{if(p)e.close();else b??=e},(e)=>v.error("live(): could not start",e)),()=>{if(p)return;p=!0,z(),b?.close()}}export{x as LIVE_CHANNEL,X as LIVE_SSE_KEY,j as startLive};
2
+
3
+ //# debugId=619DEAB63211C7CA64756E2164756E21
4
+ //# sourceMappingURL=live-6k7s6358.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../bun-client/lib/live.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * The live layer's implementation (typed-client plan `websocket.md` §9, TC\n * D15, PR-W4), loaded by `./query`'s `live()` with `import()` on its first\n * call, so a query-only bundle carries none of it. It in turn loads\n * `./channel` (or `./sse`) the same way.\n *\n * - **Tags**: every query with an observer is held under its tags\n * (`tagsOfQuery`: the route's declared ones and its responses'\n * `Cache-Tag`/`Surrogate-Key`), refcounted, so a tag is subscribed once\n * whatever the number of queries under it, and dropped with its last\n * query; the changes of one task go out together.\n * - **Invalidation**: an `invalidate` frame invalidates the queries holding\n * its tags (query-core refetches the active ones). One invalidation may\n * arrive as several frames with the same `seq` (one per tag on the\n * server's pub/sub), so a query is invalidated once per `seq`.\n * - **Resume**: the client keeps the server's cursor (`{ epoch, seq }`, from\n * every `hello` and `invalidate`); after a reconnect it sends `subscribe`\n * with every tag it holds, then `resume` with the cursor it had, and the\n * server replays what it missed. A `gap`, or a `hello` or `invalidate` of another\n * epoch (a restarted server), invalidates every query.\n * - **Denials**: a `hello` may list tags the server refused (`denied`,\n * per-tag authorization), and the SSE fallback answers `403`\n * problem+json (`LIVE_TAGS_DENIED`, `denied`) when it refuses every tag:\n * either is reported to `onDenied`, else logged once per tag as a\n * warning. The `403` ends the stream (no reconnect); the tags stay held,\n * so a later subscription (a new tag, a reconnect, another login) asks\n * for them again.\n * - **Transports**: bun-common's live channel (`./channel`, at `/__live`\n * under the client's `baseUrl`), or its SSE fallback (`./sse`, at\n * `/__live/sse`, the tags in the query, the cursor as `Last-Event-ID`):\n * SSE when asked, when the platform has no `WebSocket`, or when the\n * socket has not opened 3 s after the start (a proxy that refuses\n * upgrades).\n */\nimport type { Query, QueryClient } from \"@tanstack/query-core\";\nimport type { ChannelClient, ChannelDescriptor } from \"./channel\";\nimport type { EventStream } from \"./sse\";\n\n/** A position in the server's invalidations. */\ninterface Cursor {\n /** The server process's epoch. */\n epoch: string;\n /** The last invalidation's number in it. */\n seq: number;\n}\n\n/** The live channel's types, as bun-common's `liveContract` declares them (§9). */\ninterface LiveEntry {\n /** The client sends. */\n receives: {\n /** Tags to add. */\n subscribe: { tags: string[] };\n /** Tags to drop. */\n unsubscribe: { tags: string[] };\n /** The cursor kept, after a reconnect. */\n resume: Cursor;\n };\n /** The server sends. */\n sends: {\n /** Tags one invalidation hit. */\n invalidate: Cursor & { tags: string[] };\n /** The server cannot replay what was missed. */\n gap: Cursor;\n /** Where the server is; `denied` lists the tags it refused, if any. */\n hello: Cursor & { denied?: string[] };\n };\n /** The replied types. */\n replies: { subscribe: \"hello\"; resume: \"hello\" };\n}\n\n/** The live channel, as a descriptor (bun-common's `liveContract`, which this package cannot import). */\nexport const LIVE_CHANNEL: ChannelDescriptor<LiveEntry> = {\n path: \"/__live\",\n replies: { subscribe: \"hello\", resume: \"hello\" },\n};\n\n/** The SSE fallback's route key. */\nexport const LIVE_SSE_KEY = \"GET /__live/sse\";\n\n/** How long the channel may take to open before the SSE fallback replaces it, ms. */\nconst OPEN_DEADLINE_MS = 3_000;\n\n/** The most tags one `subscribe` carries (the server's limit). */\nconst MAX_TAGS = 256;\n\n/** The symbol the client keeps its configuration under (`client.ts`). */\nconst CONFIG = Symbol.for(\"@kingsleyweb/bun-client\");\n\n/** What `live()` takes of the client. */\nexport interface LiveApi {\n /** Builds a URL (the channel's). */\n readonly url: (...args: never[]) => string;\n /** Calls a route (the SSE fallback's). */\n readonly request: (...args: never[]) => Promise<unknown>;\n}\n\n/** `live()`'s options, as `./query` declares them. */\nexport interface StartOptions {\n /** `\"websocket\"` or `\"sse\"`; `undefined` picks. */\n readonly transport?: \"websocket\" | \"sse\";\n /** Called with the tags a `hello` says were refused; `undefined` logs them. */\n readonly onDenied?: (tags: string[]) => void;\n}\n\n/** A transport: what the layer tells the server. */\ninterface Transport {\n /** The held tags changed. */\n readonly changed: (\n added: readonly string[],\n removed: readonly string[],\n ) => void;\n /** Stops it. */\n readonly close: () => void;\n}\n\n/** `tags` in frames of at most {@link MAX_TAGS}. */\nfunction chunked(tags: readonly string[]): string[][] {\n const out: string[][] = [];\n for (let at = 0; at < tags.length; at += MAX_TAGS)\n out.push(tags.slice(at, at + MAX_TAGS));\n return out;\n}\n\n/** `value` as a cursor, if it is one. */\nfunction asCursor(value: unknown): Cursor | undefined {\n const v = value as Partial<Cursor> | null | undefined;\n return typeof v?.epoch === \"string\" &&\n typeof v.seq === \"number\" &&\n Number.isSafeInteger(v.seq)\n ? { epoch: v.epoch, seq: v.seq }\n : undefined;\n}\n\n/**\n * Starts the live layer over `client`'s cache; answers the function that\n * stops it.\n *\n * @param api The client: its `baseUrl` and configuration.\n * @param client The `QueryClient` whose queries are kept fresh.\n * @param options The transport.\n * @param tagsOf `./query`'s `tagsOfQuery`.\n */\nexport function startLive(\n api: LiveApi,\n client: QueryClient,\n options: StartOptions,\n tagsOf: (client: QueryClient, query: Query) => string[],\n): () => void {\n const config = (api as unknown as Record<symbol, unknown>)[CONFIG] as\n { logger?: Pick<Console, \"warn\" | \"error\"> } | undefined;\n const logger = config?.logger ?? console;\n /** Each observed query's held tags, by hash. */\n const holders = new Map<string, ReadonlySet<string>>();\n /** Each held tag's number of queries. */\n const refs = new Map<string, number>();\n const added = new Set<string>();\n const removed = new Set<string>();\n let flushing = false;\n let stopped = false;\n let cursor: Cursor | undefined;\n /** The invalidation (`epoch:seq`) each query last took. */\n const taken = new WeakMap<Query, string>();\n let transport: Transport | undefined;\n /** Denied tags already logged (without an `onDenied`). */\n const logged = new Set<string>();\n\n /** Reports refused tags (`denied`): to `onDenied`, else a warning once per tag. */\n const refused = (denied: unknown): void => {\n if (!Array.isArray(denied)) return;\n const tags = denied.filter((tag): tag is string => typeof tag === \"string\");\n if (tags.length === 0 || stopped) return;\n if (options.onDenied) {\n options.onDenied(tags);\n return;\n }\n const fresh = tags.filter((tag) => !logged.has(tag));\n for (const tag of fresh) logged.add(tag);\n if (fresh.length > 0)\n logger.warn(\n `live(): the server refused the tags ${fresh.join(\", \")}; their queries are not kept fresh`,\n );\n };\n\n /** Every query invalid; the active ones refetch. */\n const invalidateAll = (): void => {\n void client.invalidateQueries();\n };\n\n /** Takes a cursor the server sent: another epoch than the one kept invalidates everything. */\n const moveTo = (next: Cursor, replace: boolean): void => {\n if (cursor !== undefined && cursor.epoch !== next.epoch) {\n cursor = next;\n invalidateAll();\n return;\n }\n cursor =\n replace || cursor === undefined\n ? next\n : { epoch: next.epoch, seq: Math.max(cursor.seq, next.seq) };\n };\n\n const handlers = {\n hello(data: unknown): void {\n const next = asCursor(data);\n if (next !== undefined) moveTo(next, false);\n refused((data as { denied?: unknown } | null)?.denied);\n },\n gap(data: unknown): void {\n const next = asCursor(data);\n if (next === undefined) return;\n cursor = next;\n invalidateAll();\n },\n invalidate(data: unknown): void {\n const next = asCursor(data);\n const tags = (data as { tags?: unknown } | null)?.tags;\n if (next === undefined || !Array.isArray(tags)) return;\n const epochMoved = cursor !== undefined && cursor.epoch !== next.epoch;\n moveTo(next, false);\n if (epochMoved) return;\n const key = `${next.epoch}:${next.seq}`;\n const wanted = new Set(tags.filter((tag) => typeof tag === \"string\"));\n // Chosen first, then invalidated: `invalidateQueries` runs its\n // predicate twice (to mark, then to refetch).\n const hits = client.getQueryCache().findAll({\n predicate: (query) =>\n taken.get(query) !== key &&\n tagsOf(client, query).some((tag) => wanted.has(tag)),\n });\n if (hits.length === 0) return;\n for (const query of hits) taken.set(query, key);\n const set = new Set(hits);\n void client.invalidateQueries({ predicate: (query) => set.has(query) });\n },\n };\n\n /** Sends the changes of this task, once it ends. */\n const schedule = (): void => {\n if (flushing) return;\n flushing = true;\n queueMicrotask(() => {\n flushing = false;\n if (stopped || (added.size === 0 && removed.size === 0)) return;\n const plus = [...added];\n const minus = [...removed];\n added.clear();\n removed.clear();\n transport?.changed(plus, minus);\n });\n };\n\n const hold = (tag: string): void => {\n const count = (refs.get(tag) ?? 0) + 1;\n refs.set(tag, count);\n if (count === 1 && !removed.delete(tag)) added.add(tag);\n };\n const release = (tag: string): void => {\n const count = (refs.get(tag) ?? 0) - 1;\n if (count > 0) {\n refs.set(tag, count);\n return;\n }\n refs.delete(tag);\n if (!added.delete(tag)) removed.add(tag);\n };\n\n /** Brings `query`'s held tags up to date: its tags while it has an observer, none otherwise. */\n const sync = (query: Query, gone = false): void => {\n const hash = query.queryHash;\n const before = holders.get(hash);\n const now: ReadonlySet<string> =\n !gone && query.getObserversCount() > 0\n ? new Set(tagsOf(client, query))\n : new Set();\n if (before === undefined && now.size === 0) return;\n for (const tag of now) if (!before?.has(tag)) hold(tag);\n for (const tag of before ?? []) if (!now.has(tag)) release(tag);\n if (now.size === 0) holders.delete(hash);\n else holders.set(hash, now);\n schedule();\n };\n\n const cache = client.getQueryCache();\n for (const query of cache.getAll()) sync(query);\n const unsubscribe = cache.subscribe((event) => {\n if (event.type === \"observerResultsUpdated\") return;\n sync(event.query as Query, event.type === \"removed\");\n });\n\n /** The SSE transport: one stream over the held tags, reopened when one is added. */\n const viaSse = async (): Promise<Transport> => {\n const { sse } = await import(\"./sse\");\n let stream: EventStream<Record<string, unknown>> | undefined;\n const open = (): void => {\n const previous = stream;\n stream = undefined;\n previous?.close();\n if (stopped || refs.size === 0) return;\n const lastEventId =\n previous?.lastEventId ||\n (cursor === undefined ? undefined : `${cursor.epoch}:${cursor.seq}`);\n const opened = (\n sse as unknown as (\n api: LiveApi,\n key: string,\n options: object,\n ) => EventStream<Record<string, unknown>>\n )(api, LIVE_SSE_KEY, {\n query: { tag: [...refs.keys()] },\n ...(lastEventId ? { lastEventId } : {}),\n });\n stream = opened;\n opened.on(\"invalidate\", (data: unknown) => handlers.invalidate(data));\n opened.on(\"gap\", (data: unknown) => handlers.gap(data));\n opened.on(\"hello\", (data: unknown) => handlers.hello(data));\n opened.closed.catch((error: unknown) => {\n if (stream !== opened) return;\n // Every tag refused: the fallback answers `403` problem+json\n // (`LIVE_TAGS_DENIED`, the tags in `denied`) and opens no stream.\n // A fatal status, so the stream does not reconnect; a new tag\n // reopens it, and the server decides again. The client has read\n // the body (an `HttpError`'s `error`).\n const failed = error as { status?: unknown; error?: unknown };\n const problem = failed.error as\n { code?: unknown; denied?: unknown } | null | undefined;\n if (failed.status === 403 && problem?.code === \"LIVE_TAGS_DENIED\") {\n refused(problem.denied);\n return;\n }\n logger.error(\"live(): the live stream ended\", error);\n });\n };\n open();\n return {\n changed(plus, minus) {\n // A dropped tag can wait for the next reopen; an added one cannot.\n if (plus.length > 0 || (minus.length > 0 && refs.size === 0)) open();\n },\n close: () => {\n const last = stream;\n stream = undefined;\n last?.close();\n },\n };\n };\n\n /** The WebSocket transport; falls back to SSE when the socket never opens. */\n const viaChannel = async (): Promise<Transport> => {\n const { channel } = await import(\"./channel\");\n let everOpened = false;\n const room: ChannelClient<LiveEntry> = channel(api, LIVE_CHANNEL, {\n async resubscribe(r) {\n // Subscribe first, then resume from the cursor kept before the\n // drop: the server replays what was missed for every tag held (an\n // invalidation also heard live meanwhile is taken once, by its seq).\n const from = cursor;\n for (const part of chunked([...refs.keys()]))\n handlers.hello(await r.request(\"subscribe\", { tags: part }));\n // A hello of another epoch has already invalidated everything.\n if (from !== undefined && cursor?.epoch === from.epoch)\n handlers.hello(await r.request(\"resume\", from));\n },\n });\n room.on(\"invalidate\", (data) => handlers.invalidate(data));\n room.on(\"gap\", (data) => handlers.gap(data));\n room.on(\"hello\", (data) => handlers.hello(data));\n const own: { -readonly [K in keyof Transport]: Transport[K] } = {\n changed(plus, minus) {\n if (room.state !== \"open\") return; // the next open subscribes them all\n if (minus.length > 0)\n for (const part of chunked(minus))\n room.send(\"unsubscribe\", { tags: part });\n for (const part of chunked(plus))\n room.request(\"subscribe\", { tags: part }).then(\n (data) => handlers.hello(data),\n (error: unknown) =>\n logger.warn(\"live(): a subscribe failed\", error),\n );\n },\n close: () => room.close(),\n };\n // The channel says \"connecting\" until its first open, however many\n // attempts fail; one that has not opened by the deadline (a proxy that\n // refuses upgrades, a platform whose sockets cannot reach the server)\n // gives way to the SSE fallback.\n const deadline = setTimeout(() => {\n if (everOpened || stopped || transport !== own) return;\n room.close();\n logger.warn(\n `live(): the live channel did not open within ${OPEN_DEADLINE_MS} ms; using its SSE fallback`,\n );\n void viaSse().then((next) => {\n if (stopped) next.close();\n else transport = next;\n });\n }, OPEN_DEADLINE_MS);\n room.on(\"$state\", (state) => {\n if (state !== \"open\") return;\n everOpened = true;\n clearTimeout(deadline);\n });\n const close = own.close;\n own.close = () => {\n clearTimeout(deadline);\n close();\n };\n return own;\n };\n\n const useSse =\n options.transport === \"sse\" ||\n (options.transport === undefined &&\n typeof (globalThis as { WebSocket?: unknown }).WebSocket !== \"function\");\n void (useSse ? viaSse() : viaChannel()).then(\n (started) => {\n if (stopped) started.close();\n else transport ??= started;\n },\n (error: unknown) => logger.error(\"live(): could not start\", error),\n );\n\n return () => {\n if (stopped) return;\n stopped = true;\n unsubscribe();\n transport?.close();\n };\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "619DEAB63211C7CA64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,6 @@
1
+ import{Ae,N,e}from"./main-a250ffk7.js";var u=1e4,s=new Set,l=Date.now(),a=null;function w(){l=Date.now();for(let n of s)n()}function v(n){if(s.size===0)l=Date.now(),a=setInterval(w,u);return s.add(n),()=>{if(s.delete(n),s.size===0&&a!==null)clearInterval(a),a=null}}function p(){return l}function Ie(){return Ae(v,p,p)}var T=[["second",1],["minute",60],["hour",3600],["day",86400],["week",604800],["month",2629800],["year",31557600]],S={second:45,minute:45,hour:22,day:6,week:4,month:11},b=new Map;function g(n){let r=n??"",t=b.get(r);if(!t)t=new Intl.RelativeTimeFormat(n,{numeric:"auto",style:"narrow"}),b.set(r,t);return t}var y=u/1000;function _(n,r,t){let o=(n-r)/1000,i=o>0&&o<=y?0:o,h=Math.abs(i);for(let m=0;m<T.length;m++){let[c,f]=T[m],d=S[c];if(d===void 0||h/f<d)return g(t).format(Math.round(i/f),c)}return g(t).format(Math.round(i/31557600),"year")}function R(n){if(n===null||n===void 0||n==="")return null;let r=n instanceof Date?n.getTime():typeof n==="number"?n:Date.parse(n);return Number.isFinite(r)?r:null}function A({value:n,fallback:r="—",className:t,hint:o}){let i=R(n);if(i===null)return e("span",{className:N("relative-time",t),children:r});return e(I,{ms:i,className:t,hint:o})}function I({ms:n,className:r,hint:t}){let o=Ie(),i=new Date(n).toISOString();return e("time",{className:N("relative-time",r),dateTime:i,title:t===void 0?i:`${i}
2
+ ${t}`,children:_(n,o)})}
3
+ export{Ie,A};
4
+
5
+ //# debugId=55346C2FCAC6EF3664756E2164756E21
6
+ //# sourceMappingURL=main-0jmeh6mq.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/hooks/useNow.ts", "app/jobs/components/formatRelative.ts", "app/jobs/components/RelativeTime.tsx"],
4
+ "sourcesContent": [
5
+ "import { useSyncExternalStore } from \"react\";\n\n/**\n * One app-wide clock for relative times. However many components show\n * \"3m ago\", there is a single `setInterval`, started with the first\n * subscriber and stopped with the last, so a table of 500 rows does not\n * run 500 timers.\n */\n\n/** How often the shared clock ticks, ms. */\nexport const NOW_TICK_MS = 10_000;\n\n/** Subscribers to the clock. */\nconst listeners = new Set<() => void>();\n/** The time every subscriber reads, updated on each tick. */\nlet now = Date.now();\n/** The one interval, while anything subscribes. */\nlet timer: ReturnType<typeof setInterval> | null = null;\n\n/** Advances the shared time and tells every subscriber. */\nfunction tick(): void {\n now = Date.now();\n for (const listener of listeners) {\n listener();\n }\n}\n\n/** Subscribes to the clock; starts it for the first subscriber, stops it after the last. */\nfunction subscribe(listener: () => void): () => void {\n if (listeners.size === 0) {\n // The clock was idle: refresh before anyone reads a stale time.\n now = Date.now();\n timer = setInterval(tick, NOW_TICK_MS);\n }\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0 && timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n };\n}\n\n/** The current shared time. */\nfunction getSnapshot(): number {\n return now;\n}\n\n/** The current time, epoch ms, re-rendering every {@link NOW_TICK_MS} on the shared clock. */\nexport function useNow(): number {\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** How many components are on the shared clock, and whether its timer runs. For tests. */\nexport function sharedClockState(): { subscribers: number; running: boolean } {\n return { subscribers: listeners.size, running: timer !== null };\n}\n",
6
+ "import { NOW_TICK_MS } from \"../hooks/useNow\";\n\n/** Units from the smallest up, with how many seconds each spans. */\nconst UNITS: readonly [Intl.RelativeTimeFormatUnit, number][] = [\n [\"second\", 1],\n [\"minute\", 60],\n [\"hour\", 3_600],\n [\"day\", 86_400],\n [\"week\", 604_800],\n [\"month\", 2_629_800],\n [\"year\", 31_557_600],\n];\n\n/** When to switch to the next unit: 45 s → minutes, 45 min → hours, 22 h → days, 6 d → weeks, 4 w → months, 11 mo → years. */\nconst THRESHOLDS: Readonly<\n Partial<Record<Intl.RelativeTimeFormatUnit, number>>\n> = {\n second: 45,\n minute: 45,\n hour: 22,\n day: 6,\n week: 4,\n month: 11,\n};\n\n/** Formatters by locale, built once. */\nconst formatters = new Map<string, Intl.RelativeTimeFormat>();\n\n/** A narrow, `numeric: \"auto\"` formatter for a locale (\"3m ago\", \"in 2h\", \"now\", \"yesterday\"). */\nfunction formatter(locale: string | undefined): Intl.RelativeTimeFormat {\n const key = locale ?? \"\";\n let found = formatters.get(key);\n if (!found) {\n found = new Intl.RelativeTimeFormat(locale, {\n numeric: \"auto\",\n style: \"narrow\",\n });\n formatters.set(key, found);\n }\n return found;\n}\n\n/**\n * How far ahead of `now` an instant may be and still read \"now\": one tick of\n * the shared clock. Every relative time in the app is rendered against that\n * cached clock, so anything recorded since its last tick is legitimately\n * ahead of it — a worker's heartbeat written a moment ago rendered as\n * \"in 2s\" until the clock caught up. Beyond a tick it is a real future time\n * (a delayed job, a next run) and is shown as one.\n */\nconst FUTURE_TOLERANCE_S = NOW_TICK_MS / 1_000;\n\n/**\n * `ms` relative to `now`: \"3m ago\", \"in 2h\", \"now\", \"yesterday\". The unit\n * is the largest that keeps the number at or above 1. An instant up to\n * {@link FUTURE_TOLERANCE_S} ahead reads \"now\".\n */\nexport function formatRelativeTime(\n ms: number,\n now: number,\n locale?: string,\n): string {\n const ahead = (ms - now) / 1000;\n const seconds = ahead > 0 && ahead <= FUTURE_TOLERANCE_S ? 0 : ahead;\n const abs = Math.abs(seconds);\n for (let i = 0; i < UNITS.length; i++) {\n const [unit, span] = UNITS[i];\n const limit = THRESHOLDS[unit];\n if (limit === undefined || abs / span < limit) {\n return formatter(locale).format(Math.round(seconds / span), unit);\n }\n }\n return formatter(locale).format(Math.round(seconds / 31_557_600), \"year\");\n}\n\n/** Normalises a time input to epoch ms; `null` for missing or invalid. */\nexport function toEpochMs(\n value: number | string | Date | null | undefined,\n): number | null {\n if (value === null || value === undefined || value === \"\") {\n return null;\n }\n const ms =\n value instanceof Date\n ? value.getTime()\n : typeof value === \"number\"\n ? value\n : Date.parse(value);\n return Number.isFinite(ms) ? ms : null;\n}\n",
7
+ "import { useNow } from \"../hooks/useNow\";\nimport { cx } from \"./classNames\";\nimport { formatRelativeTime, toEpochMs } from \"./formatRelative\";\n\n/** Props of {@link RelativeTime}. */\nexport interface RelativeTimeProps {\n /** The instant: epoch ms, an ISO string or a `Date`. `null`/`undefined` (or invalid) renders \"—\". */\n value: number | string | Date | null | undefined;\n /** What to render for a missing value. Defaults to `\"—\"`. */\n fallback?: string;\n /** Extra class names. */\n className?: string;\n /**\n * A note appended to the `<time>`'s tooltip, on its own line under the\n * absolute instant — so a caller can explain the instant without taking\n * the tooltip away from it. Absent leaves the tooltip the instant alone,\n * and it is ignored for a missing value (there is no `<time>` then).\n */\n hint?: string;\n}\n\n/**\n * \"3m ago\" / \"in 2h\", kept current by the one shared clock (`useNow`),\n * inside a `<time>` whose `dateTime` and `title` carry the absolute ISO\n * instant, so hovering shows exactly when.\n */\nexport function RelativeTime({\n value,\n fallback = \"—\",\n className,\n hint,\n}: RelativeTimeProps) {\n const ms = toEpochMs(value);\n if (ms === null) {\n return <span className={cx(\"relative-time\", className)}>{fallback}</span>;\n }\n return (\n <TickingTime\n ms={ms}\n className={className}\n hint={hint}\n />\n );\n}\n\n/** Props of {@link TickingTime}. */\ninterface TickingTimeProps {\n /** The instant, epoch ms. */\n ms: number;\n /** Extra class names. */\n className?: string;\n /** A note under the instant in the tooltip. See {@link RelativeTimeProps.hint}. */\n hint?: string;\n}\n\n/** The subscribed part, so a missing value never joins the clock. */\nfunction TickingTime({ ms, className, hint }: TickingTimeProps) {\n const now = useNow();\n const iso = new Date(ms).toISOString();\n return (\n <time\n className={cx(\"relative-time\", className)}\n dateTime={iso}\n title={hint === undefined ? iso : `${iso}\\n${hint}`}\n >\n {formatRelativeTime(ms, now)}\n </time>\n );\n}\n"
8
+ ],
9
+ "mappings": "uCAUO,IAAM,EAAc,IAGrB,EAAY,IAAI,IAElB,EAAM,KAAK,IAAI,EAEf,EAA+C,KAGnD,SAAS,CAAI,EAAS,CACpB,EAAM,KAAK,IAAI,EACf,QAAW,KAAY,EACrB,EAAS,EAKb,SAAS,CAAS,CAAC,EAAkC,CACnD,GAAI,EAAU,OAAS,EAErB,EAAM,KAAK,IAAI,EACf,EAAQ,YAAY,EAAM,CAAW,EAGvC,OADA,EAAU,IAAI,CAAQ,EACf,IAAM,CAEX,GADA,EAAU,OAAO,CAAQ,EACrB,EAAU,OAAS,GAAK,IAAU,KACpC,cAAc,CAAK,EACnB,EAAQ,MAMd,SAAS,CAAW,EAAW,CAC7B,OAAO,EAIF,SAAS,EAAM,EAAW,CAC/B,OAAO,GAAqB,EAAW,EAAa,CAAW,EChDjE,IAAM,EAA0D,CAC9D,CAAC,SAAU,CAAC,EACZ,CAAC,SAAU,EAAE,EACb,CAAC,OAAQ,IAAK,EACd,CAAC,MAAO,KAAM,EACd,CAAC,OAAQ,MAAO,EAChB,CAAC,QAAS,OAAS,EACnB,CAAC,OAAQ,QAAU,CACrB,EAGM,EAEF,CACF,OAAQ,GACR,OAAQ,GACR,KAAM,GACN,IAAK,EACL,KAAM,EACN,MAAO,EACT,EAGM,EAAa,IAAI,IAGvB,SAAS,CAAS,CAAC,EAAqD,CACtE,IAAM,EAAM,GAAU,GAClB,EAAQ,EAAW,IAAI,CAAG,EAC9B,GAAI,CAAC,EACH,EAAQ,IAAI,KAAK,mBAAmB,EAAQ,CAC1C,QAAS,OACT,MAAO,QACT,CAAC,EACD,EAAW,IAAI,EAAK,CAAK,EAE3B,OAAO,EAWT,IAAM,EAAqB,EAAc,KAOlC,SAAS,CAAkB,CAChC,EACA,EACA,EACQ,CACR,IAAM,GAAS,EAAK,GAAO,KACrB,EAAU,EAAQ,GAAK,GAAS,EAAqB,EAAI,EACzD,EAAM,KAAK,IAAI,CAAO,EAC5B,QAAS,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,IAAO,EAAM,GAAQ,EAAM,GACrB,EAAQ,EAAW,GACzB,GAAI,IAAU,QAAa,EAAM,EAAO,EACtC,OAAO,EAAU,CAAM,EAAE,OAAO,KAAK,MAAM,EAAU,CAAI,EAAG,CAAI,EAGpE,OAAO,EAAU,CAAM,EAAE,OAAO,KAAK,MAAM,EAAU,QAAU,EAAG,MAAM,EAInE,SAAS,CAAS,CACvB,EACe,CACf,GAAI,IAAU,MAAQ,IAAU,QAAa,IAAU,GACrD,OAAO,KAET,IAAM,EACJ,aAAiB,KACb,EAAM,QAAQ,EACd,OAAO,IAAU,SACf,EACA,KAAK,MAAM,CAAK,EACxB,OAAO,OAAO,SAAS,CAAE,EAAI,EAAK,KC9D7B,SAAS,CAAY,EAC1B,QACA,WAAW,IACX,YACA,QACoB,CACpB,IAAM,EAAK,EAAU,CAAK,EAC1B,GAAI,IAAO,KACT,OAAO,EAAC,OAAD,CAAM,UAAW,EAAG,gBAAiB,CAAS,EAA9C,SAAkD,EAAW,EAEtE,OACE,EAAC,EAAD,CACE,GAAI,EACJ,UAAW,EACX,KAAM,EACR,EAeJ,SAAS,CAAW,EAAG,KAAI,YAAW,QAA0B,CAC9D,IAAM,EAAM,GAAO,EACb,EAAM,IAAI,KAAK,CAAE,EAAE,YAAY,EACrC,OACE,EAAC,OAAD,CACE,UAAW,EAAG,gBAAiB,CAAS,EACxC,SAAU,EACV,MAAO,IAAS,OAAY,EAAM,GAAG;AAAA,EAAQ,IAH/C,SAKG,EAAmB,EAAI,CAAG,EAC3B",
10
+ "debugId": "55346C2FCAC6EF3664756E2164756E21",
11
+ "names": []
12
+ }
@@ -0,0 +1,5 @@
1
+ import{C,g,be}from"./main-a250ffk7.js";function W(){let{location:t,navigate:r}=be(),a=g(()=>new URLSearchParams(t.search),[t.search]),e=C((i)=>{let n=new URLSearchParams(window.location.search);for(let[c,o]of Object.entries(i))if(o===null||o==="")n.delete(c);else n.set(c,o);let s=n.toString();r(`${t.path??"/"}${s?`?${s}`:""}`,{replace:!0})},[t.path,r]);return[a,e]}function me(t,r,a){let e=t.get(r);if(e===null||!/^\d+$/.test(e))return a;return Number(e)}function Tt(t){return[...new Set(t.split(",").map((r)=>r.trim()).filter(Boolean))]}function we(t,r){return Math.min(Math.max(1,t),Math.max(1,r))}
2
+ export{W,me,Tt,we};
3
+
4
+ //# debugId=62BE333E99E6E35164756E2164756E21
5
+ //# sourceMappingURL=main-3yj6bv90.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/screens/queues/urlState.ts"],
4
+ "sourcesContent": [
5
+ "import { useCallback, useMemo } from \"react\";\nimport { useRouter } from \"../../routing\";\n\n/** A patch of query parameters: a string sets one, `null` removes it. */\nexport type ParamPatch = Readonly<Record<string, string | null>>;\n\n/**\n * The query string as state, several keys at a time: `update()` applies a\n * patch in one navigation (replacing the history entry), so changing a\n * filter and resetting `offset` is one URL change, not two.\n */\nexport function useUrlParams(): [URLSearchParams, (patch: ParamPatch) => void] {\n const { location, navigate } = useRouter();\n const params = useMemo(\n () => new URLSearchParams(location.search),\n [location.search],\n );\n const update = useCallback(\n (patch: ParamPatch) => {\n const next = new URLSearchParams(window.location.search);\n for (const [key, value] of Object.entries(patch)) {\n if (value === null || value === \"\") {\n next.delete(key);\n } else {\n next.set(key, value);\n }\n }\n const query = next.toString();\n navigate(`${location.path ?? \"/\"}${query ? `?${query}` : \"\"}`, {\n replace: true,\n });\n },\n [location.path, navigate],\n );\n return [params, update];\n}\n\n/** A non-negative integer query parameter, or `fallback`. */\nexport function intParam(\n params: URLSearchParams,\n key: string,\n fallback: number,\n): number {\n const raw = params.get(key);\n if (raw === null || !/^\\d+$/.test(raw)) {\n return fallback;\n }\n return Number(raw);\n}\n\n/** Splits a comma-separated list, trimming and dropping empties and duplicates. */\nexport function splitList(text: string): string[] {\n return [\n ...new Set(\n text\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean),\n ),\n ];\n}\n\n/** Clamps a page size to `1..max`. */\nexport function clampLimit(value: number, max: number): number {\n return Math.min(Math.max(1, value), Math.max(1, max));\n}\n"
6
+ ],
7
+ "mappings": "uCAWO,SAAS,CAAY,EAAmD,CAC7E,IAAQ,WAAU,YAAa,GAAU,EACnC,EAAS,EACb,IAAM,IAAI,gBAAgB,EAAS,MAAM,EACzC,CAAC,EAAS,MAAM,CAClB,EACM,EAAS,EACb,CAAC,IAAsB,CACrB,IAAM,EAAO,IAAI,gBAAgB,OAAO,SAAS,MAAM,EACvD,QAAY,EAAK,KAAU,OAAO,QAAQ,CAAK,EAC7C,GAAI,IAAU,MAAQ,IAAU,GAC9B,EAAK,OAAO,CAAG,EACf,KACA,EAAK,IAAI,EAAK,CAAK,EAGvB,IAAM,EAAQ,EAAK,SAAS,EAC5B,EAAS,GAAG,EAAS,MAAQ,MAAM,EAAQ,IAAI,IAAU,KAAM,CAC7D,QAAS,EACX,CAAC,GAEH,CAAC,EAAS,KAAM,CAAQ,CAC1B,EACA,MAAO,CAAC,EAAQ,CAAM,EAIjB,SAAS,EAAQ,CACtB,EACA,EACA,EACQ,CACR,IAAM,EAAM,EAAO,IAAI,CAAG,EAC1B,GAAI,IAAQ,MAAQ,CAAC,QAAQ,KAAK,CAAG,EACnC,OAAO,EAET,OAAO,OAAO,CAAG,EAIZ,SAAS,EAAS,CAAC,EAAwB,CAChD,MAAO,CACL,GAAG,IAAI,IACL,EACG,MAAM,GAAG,EACT,IAAI,CAAC,IAAS,EAAK,KAAK,CAAC,EACzB,OAAO,OAAO,CACnB,CACF,EAIK,SAAS,EAAU,CAAC,EAAe,EAAqB,CAC7D,OAAO,KAAK,IAAI,KAAK,IAAI,EAAG,CAAK,EAAG,KAAK,IAAI,EAAG,CAAG,CAAC",
8
+ "debugId": "62BE333E99E6E35164756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ import{T,r,n,e,t,s,oe,l,M}from"./main-a250ffk7.js";import{D}from"./main-hm1ng3yg.js";function k(i){return i.open?e(q,{...i}):null}function q({onClose:i,title:h,description:B,children:L,onConfirm:F,confirmLabel:m="Confirm",pendingLabel:N,cancelLabel:P="Cancel",variant:H="default",confirmText:a,confirmTextLabel:O,closeOnSuccess:S=!0,confirmDisabled:w=!1}){let[u,I]=r(""),[o,c]=r(!1),[p,g]=r(null),b=T(null),C=T(null),R=T(null),v=(a===void 0||u===a)&&!o&&!w,f=H==="danger",y=async()=>{if(!v)return;c(!0),g(null);try{if(await F(),c(!1),S)i()}catch(d){c(!1),g(d)}},z=(d)=>{d.preventDefault(),y()},E=()=>{if(!o)i()};return e(oe,{open:!0,onClose:E,title:h,description:B,role:f?"alertdialog":"dialog",size:"sm",closeOnEscape:!o,closeOnBackdrop:!o,initialFocusRef:a!==void 0?R:f?b:C,footer:t(n,{children:[e(s,{ref:b,onClick:E,disabled:o,children:P}),e(s,{ref:C,variant:f?"danger":"primary",disabled:!v,"aria-busy":o||void 0,onClick:()=>void y(),children:o?N??`${m}…`:m})]}),children:t("form",{className:"confirm-dialog-body",onSubmit:z,children:[L,a!==void 0&&e(l,{label:O??t(n,{children:["Type ",e("code",{children:a})," to confirm"]}),children:e(M,{ref:R,value:u,onChange:I,autoComplete:"off",spellCheck:!1,disabled:o})}),p!==null&&e(D,{error:p})]})})}
2
+ export{k};
3
+
4
+ //# debugId=0283959BD22E5C1264756E2164756E21
5
+ //# sourceMappingURL=main-4g69fn3x.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/components/ConfirmDialog.tsx"],
4
+ "sourcesContent": [
5
+ "import type { FormEvent, ReactNode } from \"react\";\nimport { useRef, useState } from \"react\";\nimport { Button } from \"./Button\";\nimport { Dialog } from \"./Dialog\";\nimport { Field } from \"./Field\";\nimport { TextInput } from \"./inputs\";\nimport { ProblemBanner } from \"./ProblemBanner\";\n\n/** Props of {@link ConfirmDialog}. */\nexport interface ConfirmDialogProps {\n /** Whether it is showing. State (typed text, error) resets on each opening. */\n open: boolean;\n /** Asks to close (Cancel, Escape, backdrop, or after a successful confirm). Ignored while pending. */\n onClose: () => void;\n /** The question, e.g. \"Drain queue emails?\". */\n title: ReactNode;\n /** What will happen, in a sentence. */\n description?: ReactNode;\n /** Extra body content, e.g. options such as a \"include delayed\" checkbox. */\n children?: ReactNode;\n /**\n * The action. May be async: the dialog shows a pending state until it\n * settles, closes on success, and on a throw stays open with the error\n * shown inline (an `ApiError` as a {@link ProblemBanner}).\n */\n onConfirm: () => unknown;\n /** The confirm button's text. Defaults to `\"Confirm\"`. */\n confirmLabel?: string;\n /** The confirm button's text while pending. Defaults to `confirmLabel` + \"…\". */\n pendingLabel?: string;\n /** The cancel button's text. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /** `\"danger\"` for destructive actions: a red button, `alertdialog`, and Cancel focused first. Defaults to `\"default\"`. */\n variant?: \"default\" | \"danger\";\n /** When set, the user must type exactly this (e.g. the queue name) before Confirm enables. */\n confirmText?: string;\n /** The typed-confirmation label. Defaults to \"Type <confirmText> to confirm\". */\n confirmTextLabel?: ReactNode;\n /** Close after a successful `onConfirm`. Defaults to `true`. */\n closeOnSuccess?: boolean;\n /** Keeps Confirm disabled, e.g. while the body's options are invalid. */\n confirmDisabled?: boolean;\n}\n\n/**\n * A yes/no dialog for an action, built on {@link Dialog}: an optional typed\n * confirmation for destructive ones, an async `onConfirm` with a pending\n * state, and the failure shown in place so the user can retry or cancel.\n */\nexport function ConfirmDialog(props: ConfirmDialogProps) {\n return props.open ? <OpenConfirmDialog {...props} /> : null;\n}\n\n/** The mounted dialog; its state lives exactly as long as one opening. */\nfunction OpenConfirmDialog({\n onClose,\n title,\n description,\n children,\n onConfirm,\n confirmLabel = \"Confirm\",\n pendingLabel,\n cancelLabel = \"Cancel\",\n variant = \"default\",\n confirmText,\n confirmTextLabel,\n closeOnSuccess = true,\n confirmDisabled = false,\n}: ConfirmDialogProps) {\n const [typed, setTyped] = useState(\"\");\n const [pending, setPending] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const cancelRef = useRef<HTMLButtonElement>(null);\n const confirmRef = useRef<HTMLButtonElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const matches = confirmText === undefined || typed === confirmText;\n const canConfirm = matches && !pending && !confirmDisabled;\n const danger = variant === \"danger\";\n\n const confirm = async () => {\n if (!canConfirm) {\n return;\n }\n setPending(true);\n setError(null);\n try {\n await onConfirm();\n setPending(false);\n if (closeOnSuccess) {\n onClose();\n }\n } catch (caught) {\n setPending(false);\n setError(caught);\n }\n };\n\n const onSubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n void confirm();\n };\n\n const close = () => {\n if (!pending) {\n onClose();\n }\n };\n\n return (\n <Dialog\n open\n onClose={close}\n title={title}\n description={description}\n role={danger ? \"alertdialog\" : \"dialog\"}\n size=\"sm\"\n closeOnEscape={!pending}\n closeOnBackdrop={!pending}\n initialFocusRef={\n confirmText !== undefined ? inputRef : danger ? cancelRef : confirmRef\n }\n footer={\n <>\n <Button\n ref={cancelRef}\n onClick={close}\n disabled={pending}\n >\n {cancelLabel}\n </Button>\n <Button\n ref={confirmRef}\n variant={danger ? \"danger\" : \"primary\"}\n disabled={!canConfirm}\n aria-busy={pending || undefined}\n onClick={() => void confirm()}\n >\n {pending ? (pendingLabel ?? `${confirmLabel}…`) : confirmLabel}\n </Button>\n </>\n }\n >\n <form\n className=\"confirm-dialog-body\"\n onSubmit={onSubmit}\n >\n {children}\n {confirmText !== undefined && (\n <Field\n label={\n confirmTextLabel ?? (\n <>\n Type <code>{confirmText}</code> to confirm\n </>\n )\n }\n >\n <TextInput\n ref={inputRef}\n value={typed}\n onChange={setTyped}\n autoComplete=\"off\"\n spellCheck={false}\n disabled={pending}\n />\n </Field>\n )}\n {error !== null && <ProblemBanner error={error} />}\n </form>\n </Dialog>\n );\n}\n"
6
+ ],
7
+ "mappings": "qFAiDO,SAAS,CAAa,CAAC,EAA2B,CACvD,OAAO,EAAM,KAAO,EAAC,EAAD,IAAuB,EAAO,EAAK,KAIzD,SAAS,CAAiB,EACxB,UACA,QACA,cACA,WACA,YACA,eAAe,UACf,eACA,cAAc,SACd,UAAU,UACV,cACA,mBACA,iBAAiB,GACjB,kBAAkB,IACG,CACrB,IAAO,EAAO,GAAY,EAAS,EAAE,GAC9B,EAAS,GAAc,EAAS,EAAK,GACrC,EAAO,GAAY,EAAkB,IAAI,EAC1C,EAAY,EAA0B,IAAI,EAC1C,EAAa,EAA0B,IAAI,EAC3C,EAAW,EAAyB,IAAI,EAGxC,GADU,IAAgB,QAAa,IAAU,IACzB,CAAC,GAAW,CAAC,EACrC,EAAS,IAAY,SAErB,EAAU,SAAY,CAC1B,GAAI,CAAC,EACH,OAEF,EAAW,EAAI,EACf,EAAS,IAAI,EACb,GAAI,CAGF,GAFA,MAAM,EAAU,EAChB,EAAW,EAAK,EACZ,EACF,EAAQ,EAEV,MAAO,EAAQ,CACf,EAAW,EAAK,EAChB,EAAS,CAAM,IAIb,EAAW,CAAC,IAAsC,CACtD,EAAM,eAAe,EAChB,EAAQ,GAGT,EAAQ,IAAM,CAClB,GAAI,CAAC,EACH,EAAQ,GAIZ,OACE,EAAC,GAAD,CACE,KAAI,GACJ,QAAS,EACT,MAAO,EACP,YAAa,EACb,KAAM,EAAS,cAAgB,SAC/B,KAAK,KACL,cAAe,CAAC,EAChB,gBAAiB,CAAC,EAClB,gBACE,IAAgB,OAAY,EAAW,EAAS,EAAY,EAE9D,OACE,cAiBE,CAhBA,EAAC,EAAD,CACE,IAAK,EACL,QAAS,EACT,SAAU,EAHZ,SAKG,EACD,EACF,EAAC,EAAD,CACE,IAAK,EACL,QAAS,EAAS,SAAW,UAC7B,SAAU,CAAC,EACX,YAAW,GAAW,OACtB,QAAS,IAAM,KAAK,EAAQ,EAL9B,SAOG,EAAW,GAAgB,GAAG,KAAmB,EAClD,GACF,EA9BN,SAiCE,EAAC,OAAD,CACE,UAAU,sBACV,SAAU,EAFZ,SA0BE,CAtBC,EACA,IAAgB,QACf,EAAC,EAAD,CACE,MACE,GACE,cAEE,CAFF,QACO,EAAC,OAAD,UAAO,EAAc,EAD5B,eAEE,EALR,SASE,EAAC,EAAD,CACE,IAAK,EACL,MAAO,EACP,SAAU,EACV,aAAa,MACb,WAAY,GACZ,SAAU,EACZ,EACA,EAEH,IAAU,MAAQ,EAAC,EAAD,CAAe,MAAO,EAAO,GAChD,EACF",
8
+ "debugId": "0283959BD22E5C1264756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ import{Xe,St,Mr,Br,ss,ue}from"./main-a250ffk7.js";var Mn=500,Or=500;function Ar(e,n,r=Mn){let o=[...n].reverse().concat(e);return o.length>r?o.slice(0,r):o}var y=Mn+Or;function co(e,n,r=y){if(n.kind!=="queue"||n.type!=="summon")return{duplicate:!1,seen:e};let o=n.payload,t=typeof o==="object"&&o!==null?o.eventId:void 0;if(typeof t!=="string"||t==="")return{duplicate:!1,seen:e};if(e.includes(t))return{duplicate:!0,seen:e};let s=[...e,t];return{duplicate:!1,seen:s.length>r?s.slice(s.length-r):s}}function Rr(e){let n=e!=="runner",r=e!=="jobs";return[...n&&r?["all"]:[],...n?["queues","queue","job","workers","queueWorkers"]:[],...r?["runners","runner"]:[]]}function mo(e){if(e==="both")return{scope:"all"};return{scope:e==="jobs"?"queues":"runners"}}function Dr(e){switch(e.scope){case"all":case"queues":case"runners":case"workers":return ue[e.scope];case"queueWorkers":return ue.queueWorkers(e.queue);case"queue":return ue.queue(e.queue);case"runner":return ue.runner(e.runner);case"job":return ue.job(e.queue,e.id)}}function At(e,n){if(e===null||e==="")return null;let r=q(e);return r&&Rr(n).includes(r.scope)?r:null}function q(e){if(e==="all"||e==="queues"||e==="runners"||e==="workers")return{scope:e};let n=/^queue\/([^/]+)\/workers$/.exec(e);if(n)return{scope:"queueWorkers",queue:n[1]};let r=/^queue\/([^/]+)\/job\/(.+)$/.exec(e);if(r)try{return{scope:"job",queue:r[1],id:ss(r[2])}}catch{return null}let o=/^queue\/([^/]+)$/.exec(e);if(o)return{scope:"queue",queue:o[1]};let t=/^runner\/([^/]+)$/.exec(e);if(t)return{scope:"runner",runner:t[1]};return null}function Vt(e){switch(e.scope){case"all":return Mr;case"queues":case"queue":case"job":return Xe;case"workers":case"queueWorkers":return Br;case"runners":case"runner":return St}}var g={queue:Xe,runner:St,worker:Br};function fo(e,n){let r=new Set(n),o=new Set(Mr),t=new Set,s=[],d=[...new Set((e??"").split(",").map((u)=>u.trim()).filter(Boolean))];for(let u of d){let a=/^(queue|runner)\.(.+)$/.exec(u);if(a){let i=g[a[1]],p=a[2];if(!i.includes(p))s.push({name:u,reason:"unknown"});else if(i.every((f)=>r.has(f)))t.add(p);else s.push({name:u,reason:"channel"})}else if(!o.has(u))s.push({name:u,reason:"unknown"});else if(r.has(u))t.add(u);else s.push({name:u,reason:"channel"})}let c=n.filter((u)=>t.has(u)),l=[...c,...s.map((u)=>u.name)];return{types:c,ignored:s,normalized:l.length>0?l.join(","):null}}function po(e,n){return n.length===0||n.includes(e.type)}
2
+ export{Mn,Or,Ar,co,Rr,mo,Dr,At,Vt,fo,po};
3
+
4
+ //# debugId=B2DB5554BB9DB2CD64756E2164756E21
5
+ //# sourceMappingURL=main-4gte3eqq.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/screens/events/eventLog.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n EventName,\n EventWire,\n JobsApiGapMessage,\n JobsApiMode,\n} from \"../../api/types\";\nimport {\n decodeJobId,\n EVENT_TYPES,\n QUEUE_EVENT_TYPES,\n RUNNER_EVENT_TYPES,\n WORKER_EVENT_TYPES,\n} from \"@kingsleyweb/bun-jobs/api/contract\";\nimport { liveChannels } from \"../../live\";\n\n/**\n * The Events console's pure half: which channel is chosen (and how it reads\n * from and writes to the URL), which event types it may filter on, and the\n * bounded log of what arrived.\n */\n\n/** Most rows the console keeps; older ones drop off the end. */\nexport const MAX_ROWS = 500;\n\n/** Most events held while the display is paused; later ones are counted as dropped. */\nexport const MAX_PAUSED = 500;\n\n/** One line of the console. */\nexport type LogRow =\n | {\n /** A stable React key, increasing with arrival. */\n key: number;\n /** An event frame. */\n kind: \"event\";\n /** When the browser received it, epoch ms. */\n receivedAt: number;\n /** The event. */\n event: EventWire;\n }\n | {\n /** A stable React key, increasing with arrival. */\n key: number;\n /** The server reported that events were lost. */\n kind: \"gap\";\n /** When the browser received it, epoch ms. */\n receivedAt: number;\n /** The gap frame. */\n gap: JobsApiGapMessage;\n };\n\n/**\n * `incoming` (oldest first) added ahead of `rows` (newest first), keeping at\n * most `cap` rows: the newest.\n */\nexport function prependRows(\n rows: readonly LogRow[],\n incoming: readonly LogRow[],\n cap: number = MAX_ROWS,\n): LogRow[] {\n const next = [...incoming].reverse().concat(rows);\n return next.length > cap ? next.slice(0, cap) : next;\n}\n\n/**\n * Most summon event ids {@link dedupeSummon} remembers. At least\n * {@link MAX_ROWS} + {@link MAX_PAUSED}, so every summon row still in the log\n * or held by a pause is remembered: a copy of one is never added again,\n * however far the log's cap has moved on.\n */\nexport const MAX_SEEN_EVENT_IDS = MAX_ROWS + MAX_PAUSED;\n\n/** What {@link dedupeSummon} decided about one event. */\nexport interface DedupeResult {\n /** Whether the event is a copy of a summon event already heard: drop it. */\n duplicate: boolean;\n /** The ids remembered afterwards, oldest first; the same array when nothing changed. */\n seen: readonly string[];\n}\n\n/**\n * Whether `event` repeats a summon event already heard, and the memory with\n * its id remembered. A shared summon unit's event is published once on each\n * of its queues, so a channel spanning several of them (`all`, `queues`)\n * hears it once per queue, every copy with the same `eventId`; the console\n * shows it once.\n *\n * Only a `summon` frame with an `eventId` is ever a duplicate: one from a\n * server older than `eventId` (none) is always kept, and so is every other\n * event. `seen` keeps the newest `cap` ids, oldest first.\n */\nexport function dedupeSummon(\n seen: readonly string[],\n event: EventWire,\n cap: number = MAX_SEEN_EVENT_IDS,\n): DedupeResult {\n if (event.kind !== \"queue\" || event.type !== \"summon\") {\n return { duplicate: false, seen };\n }\n const payload: unknown = event.payload;\n const eventId =\n typeof payload === \"object\" && payload !== null\n ? (payload as { eventId?: unknown }).eventId\n : undefined;\n if (typeof eventId !== \"string\" || eventId === \"\") {\n return { duplicate: false, seen };\n }\n if (seen.includes(eventId)) {\n return { duplicate: true, seen };\n }\n const next = [...seen, eventId];\n return {\n duplicate: false,\n seen: next.length > cap ? next.slice(next.length - cap) : next,\n };\n}\n\n/** What the channel picker chose. */\nexport type ChannelChoice =\n | {\n /** `all`, `queues`, `runners` or `workers`. */\n scope: \"all\" | \"queues\" | \"runners\" | \"workers\";\n }\n | {\n /** One queue's events. */\n scope: \"queue\";\n /** The queue. */\n queue: string;\n }\n | {\n /** One runner's events. */\n scope: \"runner\";\n /** The runner id. */\n runner: string;\n }\n | {\n /** One queue's worker events. */\n scope: \"queueWorkers\";\n /** The queue. */\n queue: string;\n }\n | {\n /** One job's events. */\n scope: \"job\";\n /** The job's queue. */\n queue: string;\n /** The job id, decoded. */\n id: string;\n };\n\n/** The picker's scopes. */\nexport type ChannelScope = ChannelChoice[\"scope\"];\n\n/**\n * The scopes a mode offers: `all` only in `both`, queue and worker scopes\n * with jobs, runner scopes with runners. Worker events travel on their own\n * channels — never on `all` or `queues` — so watching them is a scope of its\n * own rather than a filter over a queue channel.\n */\nexport function scopesFor(mode: JobsApiMode): ChannelScope[] {\n const queues = mode !== \"runner\";\n const runners = mode !== \"jobs\";\n return [\n ...(queues && runners ? ([\"all\"] as const) : []),\n ...(queues\n ? ([\"queues\", \"queue\", \"job\", \"workers\", \"queueWorkers\"] as const)\n : []),\n ...(runners ? ([\"runners\", \"runner\"] as const) : []),\n ];\n}\n\n/** The channel the console opens on: `all` in `both`, else the mode's broad channel. */\nexport function defaultChoice(mode: JobsApiMode): ChannelChoice {\n if (mode === \"both\") {\n return { scope: \"all\" };\n }\n return { scope: mode === \"jobs\" ? \"queues\" : \"runners\" };\n}\n\n/** The channel name of a choice (see `liveChannels`). */\nexport function channelName(choice: ChannelChoice): string {\n switch (choice.scope) {\n case \"all\":\n case \"queues\":\n case \"runners\":\n case \"workers\":\n return liveChannels[choice.scope];\n case \"queueWorkers\":\n return liveChannels.queueWorkers(choice.queue);\n case \"queue\":\n return liveChannels.queue(choice.queue);\n case \"runner\":\n return liveChannels.runner(choice.runner);\n case \"job\":\n return liveChannels.job(choice.queue, choice.id);\n }\n}\n\n/**\n * A channel name read back into a choice: `null` when it is malformed, or\n * not a channel `mode` has (a runner channel in `jobs` mode, `all` outside\n * `both`).\n */\nexport function parseChannel(\n raw: string | null,\n mode: JobsApiMode,\n): ChannelChoice | null {\n if (raw === null || raw === \"\") {\n return null;\n }\n const choice = readChannel(raw);\n return choice && scopesFor(mode).includes(choice.scope) ? choice : null;\n}\n\n/** {@link parseChannel} without the mode check. */\nfunction readChannel(raw: string): ChannelChoice | null {\n if (\n raw === \"all\" ||\n raw === \"queues\" ||\n raw === \"runners\" ||\n raw === \"workers\"\n ) {\n return { scope: raw };\n }\n // Before the one-queue pattern: `queue/<queue>/workers` is its own channel.\n const queueWorkers = /^queue\\/([^/]+)\\/workers$/.exec(raw);\n if (queueWorkers) {\n return { scope: \"queueWorkers\", queue: queueWorkers[1] };\n }\n const job = /^queue\\/([^/]+)\\/job\\/(.+)$/.exec(raw);\n if (job) {\n try {\n return { scope: \"job\", queue: job[1], id: decodeJobId(job[2]) };\n } catch {\n return null;\n }\n }\n const queue = /^queue\\/([^/]+)$/.exec(raw);\n if (queue) {\n return { scope: \"queue\", queue: queue[1] };\n }\n const runner = /^runner\\/([^/]+)$/.exec(raw);\n if (runner) {\n return { scope: \"runner\", runner: runner[1] };\n }\n return null;\n}\n\n/** The event types a choice can carry: queue events on queue channels, runner events on runner channels, every type on `all`. */\nexport function typesFor(choice: ChannelChoice): readonly EventName[] {\n switch (choice.scope) {\n case \"all\":\n return EVENT_TYPES;\n case \"queues\":\n case \"queue\":\n case \"job\":\n return QUEUE_EVENT_TYPES;\n case \"workers\":\n case \"queueWorkers\":\n return WORKER_EVENT_TYPES;\n case \"runners\":\n case \"runner\":\n return RUNNER_EVENT_TYPES;\n }\n}\n\n/** A name in the `types` URL parameter that the filter ignores, and why. */\nexport interface IgnoredType {\n /** The name as written in the URL. */\n name: string;\n /** `unknown`: no such event type; `channel`: a type the channel does not carry. */\n reason: \"unknown\" | \"channel\";\n}\n\n/** The `types` URL parameter, read (see {@link readTypes}). */\nexport interface TypesParam {\n /** The filter: the listed types the channel carries, in `allowed`'s order. Empty means every type. */\n types: EventName[];\n /** Listed names left out of the filter, in the order written. */\n ignored: IgnoredType[];\n /**\n * The parameter with every name the filter uses written bare\n * (`queue.completed` → `completed`, de-duplicated, in `allowed`'s order),\n * then the ignored names as written, so the note about them survives a\n * reload; `null` for no names.\n */\n normalized: string | null;\n}\n\n/** The event names of each family, for `queue.` / `runner.` / `worker.` prefixes. */\nconst FAMILY_TYPES: Readonly<\n Record<\"queue\" | \"runner\" | \"worker\", readonly string[]>\n> = {\n queue: QUEUE_EVENT_TYPES,\n runner: RUNNER_EVENT_TYPES,\n worker: WORKER_EVENT_TYPES,\n};\n\n/**\n * Reads the `types` URL parameter against the types a channel carries\n * (`allowed`, from {@link typesFor}). A name is bare (`completed`) or\n * prefixed with its family (`queue.completed`, `runner.failed`); a prefixed\n * one counts only on a channel that carries that family. Unknown names and\n * names the channel does not carry are reported in `ignored`, not dropped\n * silently: the console shows them, rather than quietly showing every type.\n */\nexport function readTypes(\n raw: string | null,\n allowed: readonly EventName[],\n): TypesParam {\n const allowedSet: ReadonlySet<string> = new Set(allowed);\n const known: ReadonlySet<string> = new Set(EVENT_TYPES);\n const listed = new Set<string>();\n const ignored: IgnoredType[] = [];\n const names = [\n ...new Set(\n (raw ?? \"\")\n .split(\",\")\n .map((name) => name.trim())\n .filter(Boolean),\n ),\n ];\n for (const name of names) {\n const prefixed = /^(queue|runner)\\.(.+)$/.exec(name);\n if (prefixed) {\n const family = FAMILY_TYPES[prefixed[1] as \"queue\" | \"runner\"];\n const bare = prefixed[2];\n if (!family.includes(bare)) {\n ignored.push({ name, reason: \"unknown\" });\n } else if (family.every((type) => allowedSet.has(type))) {\n listed.add(bare);\n } else {\n ignored.push({ name, reason: \"channel\" });\n }\n } else if (!known.has(name)) {\n ignored.push({ name, reason: \"unknown\" });\n } else if (allowedSet.has(name)) {\n listed.add(name);\n } else {\n ignored.push({ name, reason: \"channel\" });\n }\n }\n const types = allowed.filter((type) => listed.has(type));\n const written = [...types, ...ignored.map((entry) => entry.name)];\n return {\n types,\n ignored,\n normalized: written.length > 0 ? written.join(\",\") : null,\n };\n}\n\n/** The `types` URL parameter read as a filter: {@link readTypes}'s `types`. Empty means every type. */\nexport function parseTypes(\n raw: string | null,\n allowed: readonly EventName[],\n): EventName[] {\n return readTypes(raw, allowed).types;\n}\n\n/** Whether an event passes the type filter (empty: every type). */\nexport function matchesTypes(\n event: EventWire,\n types: readonly EventName[],\n): boolean {\n return types.length === 0 || types.includes(event.type);\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "B2DB5554BB9DB2CD64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ import{g,b,J,te}from"./main-a250ffk7.js";import{On}from"./main-hm1ng3yg.js";function Ir(e){let s={};for(let n of e){let a=n.path===""?n.target:n.path;if(!(a in s))s[a]=n.message}return s}function u(e){return e.target==="body"}function d(e){return b(e)&&e.code==="VALIDATION"?e.issues:[]}function R(e){let s=d(e);return s.length>0&&s.every(u)}function w(e){return`${e.target}${e.path?`.${e.path}`:""} ${e.message}`}function O({mutationFn:e,successMessage:s,invalidate:n,errorTitle:a,toastErrors:f=!0,onSuccess:m,onError:y,...D}){let M=J(),l=te(),p=On({...D,mutationFn:e,onSuccess:async(t,o)=>{let i=typeof n==="function"?n(t,o):n??[],r=typeof s==="function"?s(t,o):s;if(r)l.success(r);await m?.(t,o);for(let c of i)M.invalidateQueries({queryKey:c})},onError:async(t,o)=>{if(f&&!R(t))if(b(t)){let i=a??t.title,r=t.detail&&t.detail!==i?t.detail:void 0,c=d(t).filter((I)=>!u(I)).map(w).join("; ");l.error(i,{description:c||(a&&!r?t.title:r)})}else l.error(a??"Something went wrong",{description:t.message||void 0});await y?.(t,o)}}),{error:T}=p,{fieldErrors:E,unplacedIssues:V}=g(()=>{let t=d(T);return{fieldErrors:Ir(t.filter(u)),unplacedIssues:t.filter((o)=>!u(o))}},[T]);return{...p,fieldErrors:E,unplacedIssues:V}}
2
+ export{Ir,O};
3
+
4
+ //# debugId=85DBCF21D3B4A73064756E2164756E21
5
+ //# sourceMappingURL=main-4j1fcevh.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/hooks/useApiMutation.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n QueryKey,\n UseMutationOptions,\n UseMutationResult,\n} from \"@tanstack/react-query\";\nimport type { ProblemIssueDto } from \"../api/types\";\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { isApiError } from \"../api/errors\";\nimport { useToast } from \"../components/toast\";\n\n/** Field errors of a failed form submit: issue path (target stripped) → first message. */\nexport type FieldErrors = Record<string, string>;\n\n/**\n * Turns `VALIDATION` issues into a field → message map. The key is the\n * issue's path within its target, so `body.opts.delay` is `\"opts.delay\"`\n * and a root-level `body` issue (empty path) is `\"body\"`. The first issue\n * per key wins.\n */\nexport function issuesToFieldErrors(\n issues: readonly ProblemIssueDto[],\n): FieldErrors {\n const errors: FieldErrors = {};\n for (const issue of issues) {\n const key = issue.path === \"\" ? issue.target : issue.path;\n if (!(key in errors)) {\n errors[key] = issue.message;\n }\n }\n return errors;\n}\n\n/**\n * Whether an issue can be shown beside a form input: it is about the\n * request body, which every form's fields are sent in. Issues on `params`,\n * `query`, `headers`, `cookies` or `signedCookies` name nothing a form edits\n * (the one mutation with a query, `expectedSeq`, is not a field), so they are\n * {@link UseApiMutationResult.unplacedIssues} instead.\n */\nfunction isFieldIssue(issue: ProblemIssueDto): boolean {\n return issue.target === \"body\";\n}\n\n/** A `VALIDATION` problem's issues, or `[]` for any other error. */\nfunction validationIssues(error: unknown): readonly ProblemIssueDto[] {\n return isApiError(error) && error.code === \"VALIDATION\" ? error.issues : [];\n}\n\n/** Whether an error is a `VALIDATION` problem whose issues are all shown as field errors (so it is not toasted). */\nfunction isFieldValidation(error: unknown): boolean {\n const issues = validationIssues(error);\n return issues.length > 0 && issues.every(isFieldIssue);\n}\n\n/** An issue as one line of text, as the problem banner shows it: `cookies.session Required`. */\nfunction issueText(issue: ProblemIssueDto): string {\n return `${issue.target}${issue.path ? `.${issue.path}` : \"\"} ${issue.message}`;\n}\n\n/** Options of {@link useApiMutation}. */\nexport interface UseApiMutationOptions<\n TData,\n TVariables,\n TOnMutateResult = unknown,\n> extends Omit<\n UseMutationOptions<TData, Error, TVariables, TOnMutateResult>,\n \"mutationFn\" | \"onSuccess\" | \"onError\"\n> {\n /** The request, usually an `ApiClient` call; it rejects with an `ApiError`. */\n mutationFn: (variables: TVariables) => Promise<TData>;\n /** A success toast: a fixed message, or one built from the result (return `null` for none). No toast when omitted. */\n successMessage?:\n | string\n | ((data: TData, variables: TVariables) => string | null | undefined);\n /** Query keys to invalidate on success (prefix match, as TanStack does), or a function choosing them from the result. */\n invalidate?:\n | readonly QueryKey[]\n | ((data: TData, variables: TVariables) => readonly QueryKey[]);\n /** The error toast's headline, e.g. \"Could not pause queue\". Defaults to the problem's title. */\n errorTitle?: string;\n /** Toast failures (other than field validation). Defaults to `true`; turn off when the screen shows the error itself. */\n toastErrors?: boolean;\n /** Runs after a success, after invalidation has started. */\n onSuccess?: (data: TData, variables: TVariables) => unknown;\n /** Runs after a failure (including a validation failure). */\n onError?: (error: Error, variables: TVariables) => unknown;\n}\n\n/** What {@link useApiMutation} returns: TanStack's mutation, plus the field errors. */\nexport type UseApiMutationResult<\n TData,\n TVariables,\n TOnMutateResult = unknown,\n> = UseMutationResult<TData, Error, TVariables, TOnMutateResult> & {\n /** From the last failure's `VALIDATION` issues on the body (see {@link issuesToFieldErrors}); `{}` otherwise. Cleared by the next `mutate` or `reset`. */\n fieldErrors: FieldErrors;\n /**\n * The last failure's `VALIDATION` issues that no form field shows: those\n * not on the body, e.g. a host's own cookie check in front of the API.\n * `[]` otherwise. A screen that hides its banner while there are field\n * errors still shows it when this is non-empty, or they are shown nowhere.\n */\n unplacedIssues: readonly ProblemIssueDto[];\n};\n\n/**\n * TanStack's `useMutation` with the app's conventions: on success it toasts\n * `successMessage` and invalidates `invalidate`; on failure it toasts the\n * problem's title and detail, except a `VALIDATION` problem whose issues\n * are all on the body, which becomes `fieldErrors` for the form to show\n * beside its inputs. Issues on anything else are `unplacedIssues`, and are\n * listed in the toast.\n */\nexport function useApiMutation<\n TData,\n TVariables = void,\n TOnMutateResult = unknown,\n>({\n mutationFn,\n successMessage,\n invalidate,\n errorTitle,\n toastErrors = true,\n onSuccess,\n onError,\n ...options\n}: UseApiMutationOptions<\n TData,\n TVariables,\n TOnMutateResult\n>): UseApiMutationResult<TData, TVariables, TOnMutateResult> {\n const queryClient = useQueryClient();\n const toast = useToast();\n const mutation = useMutation<TData, Error, TVariables, TOnMutateResult>({\n ...options,\n mutationFn,\n onSuccess: async (data, variables) => {\n const keys =\n typeof invalidate === \"function\"\n ? invalidate(data, variables)\n : (invalidate ?? []);\n const message =\n typeof successMessage === \"function\"\n ? successMessage(data, variables)\n : successMessage;\n if (message) {\n toast.success(message);\n }\n await onSuccess?.(data, variables);\n // Not awaited: the mutation settles now; the refetches follow.\n for (const queryKey of keys) {\n void queryClient.invalidateQueries({ queryKey });\n }\n },\n onError: async (error, variables) => {\n if (toastErrors && !isFieldValidation(error)) {\n if (isApiError(error)) {\n const title = errorTitle ?? error.title;\n const detail =\n error.detail && error.detail !== title ? error.detail : undefined;\n const unplaced = validationIssues(error)\n .filter((issue) => !isFieldIssue(issue))\n .map(issueText)\n .join(\"; \");\n toast.error(title, {\n description:\n unplaced || (errorTitle && !detail ? error.title : detail),\n });\n } else {\n toast.error(errorTitle ?? \"Something went wrong\", {\n description: error.message || undefined,\n });\n }\n }\n await onError?.(error, variables);\n },\n });\n const { error } = mutation;\n const { fieldErrors, unplacedIssues } = useMemo(() => {\n const issues = validationIssues(error);\n return {\n fieldErrors: issuesToFieldErrors(issues.filter(isFieldIssue)),\n unplacedIssues: issues.filter((issue) => !isFieldIssue(issue)),\n };\n }, [error]);\n return { ...mutation, fieldErrors, unplacedIssues };\n}\n"
6
+ ],
7
+ "mappings": "4EAoBO,SAAS,EAAmB,CACjC,EACa,CACb,IAAM,EAAsB,CAAC,EAC7B,QAAW,KAAS,EAAQ,CAC1B,IAAM,EAAM,EAAM,OAAS,GAAK,EAAM,OAAS,EAAM,KACrD,GAAI,EAAE,KAAO,GACX,EAAO,GAAO,EAAM,QAGxB,OAAO,EAUT,SAAS,CAAY,CAAC,EAAiC,CACrD,OAAO,EAAM,SAAW,OAI1B,SAAS,CAAgB,CAAC,EAA4C,CACpE,OAAO,EAAW,CAAK,GAAK,EAAM,OAAS,aAAe,EAAM,OAAS,CAAC,EAI5E,SAAS,CAAiB,CAAC,EAAyB,CAClD,IAAM,EAAS,EAAiB,CAAK,EACrC,OAAO,EAAO,OAAS,GAAK,EAAO,MAAM,CAAY,EAIvD,SAAS,CAAS,CAAC,EAAgC,CACjD,MAAO,GAAG,EAAM,SAAS,EAAM,KAAO,IAAI,EAAM,OAAS,MAAM,EAAM,UAyDhE,SAAS,CAIf,EACC,aACA,iBACA,aACA,aACA,cAAc,GACd,YACA,aACG,GAKwD,CAC3D,IAAM,EAAc,EAAe,EAC7B,EAAQ,GAAS,EACjB,EAAW,GAAuD,IACnE,EACH,aACA,UAAW,MAAO,EAAM,IAAc,CACpC,IAAM,EACJ,OAAO,IAAe,WAClB,EAAW,EAAM,CAAS,EACzB,GAAc,CAAC,EAChB,EACJ,OAAO,IAAmB,WACtB,EAAe,EAAM,CAAS,EAC9B,EACN,GAAI,EACF,EAAM,QAAQ,CAAO,EAEvB,MAAM,IAAY,EAAM,CAAS,EAEjC,QAAW,KAAY,EAChB,EAAY,kBAAkB,CAAE,UAAS,CAAC,GAGnD,QAAS,MAAO,EAAO,IAAc,CACnC,GAAI,GAAe,CAAC,EAAkB,CAAK,EACzC,GAAI,EAAW,CAAK,EAAG,CACrB,IAAM,EAAQ,GAAc,EAAM,MAC5B,EACJ,EAAM,QAAU,EAAM,SAAW,EAAQ,EAAM,OAAS,OACpD,EAAW,EAAiB,CAAK,EACpC,OAAO,CAAC,IAAU,CAAC,EAAa,CAAK,CAAC,EACtC,IAAI,CAAS,EACb,KAAK,IAAI,EACZ,EAAM,MAAM,EAAO,CACjB,YACE,IAAa,GAAc,CAAC,EAAS,EAAM,MAAQ,EACvD,CAAC,EACD,KACA,EAAM,MAAM,GAAc,uBAAwB,CAChD,YAAa,EAAM,SAAW,MAChC,CAAC,EAGL,MAAM,IAAU,EAAO,CAAS,EAEpC,CAAC,GACO,SAAU,GACV,cAAa,kBAAmB,EAAQ,IAAM,CACpD,IAAM,EAAS,EAAiB,CAAK,EACrC,MAAO,CACL,YAAa,GAAoB,EAAO,OAAO,CAAY,CAAC,EAC5D,eAAgB,EAAO,OAAO,CAAC,IAAU,CAAC,EAAa,CAAK,CAAC,CAC/D,GACC,CAAC,CAAK,CAAC,EACV,MAAO,IAAK,EAAU,cAAa,gBAAe",
8
+ "debugId": "85DBCF21D3B4A73064756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1 @@
1
+ .breadcrumb ol{display:flex;gap:var(--space-1);margin:0 0 var(--space-3);list-style:none;font-size:var(--text-sm);color:var(--text-muted);flex-wrap:wrap;padding:0}.breadcrumb li+li:before{content:"/";margin-right:var(--space-1);color:var(--text-muted)}.breadcrumb [aria-current=page]{color:var(--text)}.job-header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-3);margin-bottom:var(--space-4);flex-wrap:wrap}.job-heading{min-width:0}.job-title{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-1);flex-wrap:wrap}.job-name{overflow-wrap:anywhere}.job-id-line{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm);flex-wrap:wrap;margin:0}.job-id{font-family:var(--font-mono);overflow-wrap:anywhere;word-break:break-all}.job-actions{display:flex;gap:var(--space-2);flex-wrap:wrap}.job-screen .card{margin-bottom:var(--space-4)}.job-error{display:grid;gap:var(--space-2)}.job-error-line{overflow-wrap:anywhere;margin:0}.job-error-name{color:var(--danger-text)}.job-error-code{margin-left:var(--space-2);font-size:var(--text-xs);color:var(--text-muted)}.job-error-stack{padding:var(--space-2)var(--space-3);overflow-x:auto;background:var(--surface-2);border-radius:var(--radius-sm);font-family:var(--font-mono);font-size:var(--text-xs);white-space:pre;max-height:320px;margin:0}.job-error-causes{display:grid;gap:var(--space-2);padding-left:var(--space-4);border-left:2px solid var(--border);list-style:none;margin:0}.job-error-caused-by{display:block;font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.04em}.job-details{margin-top:var(--space-3)}.job-details>summary{cursor:pointer;margin-bottom:var(--space-2);font-weight:600}.job-stacktraces{display:grid;gap:var(--space-3);list-style:none;margin:0;padding:0}.job-logs-controls{display:inline-flex;justify-content:flex-end;align-items:center;gap:var(--space-3);flex-wrap:wrap}.job-logs-clear{display:inline-flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.job-logs-clear-reason{font-size:var(--text-xs)}.job-logs-order{display:inline-flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.job-logs-follow,.job-logs-total{margin:0 0 var(--space-2);font-size:var(--text-xs)}.job-flow-summary{margin-bottom:var(--space-3)}.job-ref code{font-family:var(--font-mono);overflow-wrap:anywhere}.job-form{display:grid;gap:var(--space-3)}.job-form-options,.job-states-picker{display:grid;gap:var(--space-3);padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);margin:0}.job-states-picker{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:var(--space-2)}.job-form-options>legend,.job-states-picker>legend{padding:0 var(--space-1);font-weight:600;font-size:var(--text-sm)}.job-form-error{margin:0}@media (min-width:640px){.job-form-options{grid-template-columns:repeat(2,minmax(0,1fr))}.job-form-options>legend{grid-column:1/-1}}.job-note{padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);background:var(--surface-2);font-size:var(--text-sm);margin:0}.job-note-warning{background:var(--warning-bg);color:var(--warning-text)}.job-progress{display:inline-flex;align-items:center;gap:var(--space-2)}.job-progress-bar{display:inline-block;overflow:hidden;border-radius:var(--radius-sm);background:var(--surface-2);width:8rem;height:.5rem}.job-progress-fill{display:block;background:var(--accent);height:100%}.job-progress-value{font-variant-numeric:tabular-nums}.job-processed-by{display:inline-flex;align-items:baseline;gap:var(--space-1)var(--space-2);overflow-wrap:anywhere;flex-wrap:wrap}.flow-count{font-size:var(--text-sm);margin:0}.flow-tree{display:grid;gap:var(--space-3);list-style:none;margin:0;padding:0}.flow-children{margin-top:var(--space-3);padding-left:var(--space-4);border-left:2px solid var(--border)}.flow-node{display:grid;gap:var(--space-3);padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);min-width:0;margin:0}.flow-node>legend{padding:0 var(--space-1);font-weight:600}.flow-node[data-refused]{border-color:var(--danger)}.flow-node-queue>p{margin:0}.flow-node-actions{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.flow-node-blocked{flex-basis:100%;margin:0}.flow-result{display:grid;gap:var(--space-2)}.flow-result>p,.flow-result-list{margin:0}.log-lines{margin:0 0 var(--space-3);padding:var(--space-2)0;overflow:auto;list-style:none;background:var(--surface-2);border-radius:var(--radius-sm);font-family:var(--font-mono);font-size:var(--text-xs);max-height:480px}.log-line{display:flex;gap:var(--space-3);padding:0 var(--space-3)}.log-number{text-align:right;color:var(--text-muted);user-select:none;flex:none;min-width:4ch}.log-text{white-space:pre-wrap;overflow-wrap:anywhere}.run-log-line{align-items:baseline;gap:var(--space-2)}.run-log-time,.run-log-stream{color:var(--text-muted);user-select:none;flex:none}.run-log-stream{text-transform:uppercase;font-size:calc(var(--text-xs)*.9);letter-spacing:.04em;min-width:6ch}.run-log-line-stderr .run-log-stream,.run-log-line-stderr .log-text{color:var(--danger-text)}.run-log-level,.run-log-cut{flex:none;align-self:center}.run-log-notes{display:grid;gap:var(--space-2);margin:0 0 var(--space-3)}.run-log-notes p{font-size:var(--text-xs);margin:0}.run-log-filter{display:inline-flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.run-log-toggle,.run-log-section{margin-top:var(--space-3)}.worker-actions{display:flex;align-items:center;gap:var(--space-1);flex-wrap:wrap}.worker-actions-hint{display:inline-block;font-size:var(--text-sm);max-width:24rem}.worker-config-form{display:grid;gap:var(--space-3)}.worker-config-row{display:flex;align-items:flex-end;gap:var(--space-2);flex-wrap:wrap}.worker-config-row>.field{flex:12rem;min-width:0}.worker-config-note{padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);background:var(--surface-2);font-size:var(--text-sm);margin:0}.worker-config-instances{padding-left:var(--space-4);font-size:var(--text-sm);color:var(--text-muted);margin:0}.breadcrumb{font-size:var(--text-sm);color:var(--text-muted)}.queue-header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-3);flex-wrap:wrap}.queue-heading{display:flex;align-items:baseline;gap:var(--space-2)var(--space-3);flex-wrap:wrap;min-width:0}.queue-heading .screen-title{overflow-wrap:anywhere}.queue-total{font-variant-numeric:tabular-nums;color:var(--text-muted)}.queue-updated{font-size:var(--text-sm)}.queue-toolbar,.queue-actions{display:flex;gap:var(--space-2);flex-wrap:wrap}.jobs-section{display:flex;gap:var(--space-3);flex-direction:column;min-width:0}.jobs-filters{display:flex;align-items:flex-end;gap:var(--space-2)var(--space-3);flex-wrap:wrap}.jobs-filter{display:flex;gap:var(--space-1);font-size:var(--text-sm);flex-direction:column;min-width:0}.jobs-total{align-self:center}.bulk-bar{display:flex;align-items:center;gap:var(--space-2)var(--space-3);padding:var(--space-2)var(--space-3);border:1px solid var(--border);border-radius:var(--radius);background:var(--surface-2);flex-wrap:wrap}.bulk-count{font-size:var(--text-sm);font-variant-numeric:tabular-nums}.select-cell{text-align:center;width:2rem}.job-id{display:flex;align-items:center;gap:var(--space-2);font-family:var(--font-mono);max-width:22rem;font-weight:400}.job-id a{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.job-processed-by-col{white-space:nowrap;width:12rem}.job-processed-by-text{display:inline-block;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap;max-width:12rem}.job-failure{color:var(--text-muted);overflow-wrap:anywhere;max-width:24rem}tr[aria-selected=true]{background:var(--info-bg)}.queue-panels{min-width:0}.field-row{display:flex;gap:var(--space-3);flex-wrap:wrap}.field-row>.field{flex:10rem;min-width:0}.limits-editor{display:flex;gap:var(--space-3);flex-direction:column}.limits-names{display:flex;gap:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);padding:var(--space-3);flex-direction:column}.limits-name{border-top:1px solid var(--border);padding-top:var(--space-3)}.form-actions{display:flex;gap:var(--space-2);flex-wrap:wrap}.limits-summary{display:grid;grid-template-columns:max-content 1fr;gap:var(--space-1)var(--space-3);margin:0}.limits-summary>div{display:contents}.limits-summary dd{margin:0}.throughput-controls{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3)}.throughput-chart{margin:0}.throughput-legend{display:flex;gap:var(--space-3);font-size:var(--text-sm);margin-bottom:var(--space-2);flex-wrap:wrap}.swatch{display:inline-block;vertical-align:middle;border-radius:2px;width:10px;height:10px}.swatch-completed,.bar-completed{background:var(--state-completed);fill:var(--state-completed)}.swatch-failed,.bar-failed{background:var(--state-failed);fill:var(--state-failed)}.throughput-svg{display:block;width:100%;height:160px}.throughput-baseline{stroke:var(--border);stroke-width:1;vector-effect:non-scaling-stroke}.throughput-hit{fill:transparent}.throughput-hit:hover{fill:var(--surface-2)}.throughput-axis{display:flex;font-size:var(--text-xs);color:var(--text-muted);justify-content:space-between}.repeatable-data{max-width:24rem}.repeatable-actions{display:flex;gap:var(--space-2);flex-wrap:wrap}.demand-panel{display:grid;gap:var(--space-3)}.demand-urls{display:grid;gap:var(--space-2)}.demand-urls p{margin:0}.demand-url{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap;min-width:0}.demand-url-label{min-width:6rem;font-weight:600}.demand-url code{overflow-wrap:anywhere}.summon-panel{display:grid;gap:var(--space-3)}.summon-heading{margin:0 0 var(--space-2);font-size:1rem}.summon-actions{display:flex;gap:var(--space-2);flex-wrap:wrap}.summoning-unit{display:block;font-size:var(--text-sm);font-weight:400}.summon-budget{display:inline-grid;gap:var(--space-1)}.summon-budget-window{display:flex;align-items:center;gap:var(--space-2);font-variant-numeric:tabular-nums;flex-wrap:wrap}.summon-budget-window.is-exhausted{color:var(--warning-text);font-weight:600}.summon-budget-meter{flex:none;width:80px;height:8px}.summon-group{display:grid;gap:var(--space-2);padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}.summon-subheading{font-size:var(--text-sm);margin:0;font-weight:600}.summon-group-circuit.is-open{color:var(--warning-text)}.summon-group tr.is-current,.summon-groups tr.is-current{background:var(--surface-2);box-shadow:inset 3px 0 0 var(--accent)}.summon-groups{display:grid;gap:var(--space-2);margin-top:var(--space-5)}.summon-groups-title{font-size:var(--text-lg);margin:0}.summon-group-list{list-style:none;margin:0;padding:0}.summon-group-count{font-variant-numeric:tabular-nums;color:var(--text-muted)}.summon-coverage{display:flex;gap:var(--space-1)var(--space-2);list-style:none;flex-wrap:wrap;margin:0;padding:0}.summon-last-missing{display:block;color:var(--danger-text)}.summon-group-note{display:block;font-size:var(--text-sm);margin:0}.summon-policy-tag{font-size:var(--text-xs);font-style:italic}.summon-policy-names{display:inline-flex;gap:var(--space-1);flex-wrap:wrap}.summon-policy-names code{padding:0 var(--space-1);border:1px solid var(--border);border-radius:var(--radius-sm);overflow-wrap:anywhere}.range-picker{display:flex;align-items:flex-end;gap:var(--space-3);flex-wrap:wrap}.range-picker>.field{min-width:0}.range-scope{margin-top:var(--space-2)}.range-caption{font-size:var(--text-sm);color:var(--text-muted);margin:0}.range-not-retained{padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);color:var(--text-muted)}.range-not-retained-title{margin:0 0 var(--space-1);color:var(--text);font-weight:600}.range-not-retained-detail{font-size:var(--text-sm);margin:0}.analytics-section .analytics-headline{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-4);margin-bottom:var(--space-4);flex-wrap:wrap}.analytics-section .analytics-charts{display:flex;gap:var(--space-2);flex-direction:column;min-width:0}.analytics-section .analytics-note{font-size:var(--text-sm);color:var(--text-muted);max-width:34rem;margin:0}.overview-jobs-chart{margin-top:var(--space-3)}.events-screen{display:flex;gap:var(--space-4);flex-direction:column}.events-picker{display:flex;align-items:flex-end;gap:var(--space-2)var(--space-3);flex-wrap:wrap}.events-picker .field{min-width:12rem;margin:0}.events-types{margin-top:var(--space-3)}.events-types summary{cursor:pointer;overflow-wrap:anywhere}.events-types fieldset{margin:var(--space-2)0 0;border:0;padding:0}.events-type-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(9rem,1fr));gap:var(--space-1)var(--space-3);margin-bottom:var(--space-2)}.events-types-ignored{margin:var(--space-3)0 0;padding:var(--space-2)var(--space-3);background:var(--warning-bg);color:var(--warning-text);font-size:var(--text-sm);overflow-wrap:anywhere;border-radius:6px}.events-channel{margin:var(--space-3)0 0;font-size:var(--text-sm);overflow-wrap:anywhere}.events-rejected{margin-top:var(--space-3);padding:var(--space-2)var(--space-3);background:var(--warning-bg);color:var(--warning-text);border-radius:6px}.events-rejected p{overflow-wrap:anywhere;margin:0}.events-actions{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm);flex-wrap:wrap}.events-held{font-variant-numeric:tabular-nums}.events-table td{vertical-align:top}.events-time{font-variant-numeric:tabular-nums;white-space:nowrap}.events-kind{white-space:nowrap}.events-target,.events-id{overflow-wrap:anywhere}.events-payload{min-width:12rem}.events-gap td{font-style:italic}.events-summary{margin:0 0 var(--space-1)}.schema-tree{font-size:var(--text-sm);overflow-x:auto}.schema-list{list-style:none;margin:0;padding:0}.schema-list .schema-list{margin-left:var(--space-3);padding-left:var(--space-3);border-left:1px solid var(--border)}.schema-node{padding:var(--space-1)0}.schema-row{display:flex;align-items:baseline;gap:var(--space-1)var(--space-2);flex-wrap:wrap}.schema-toggle,.schema-toggle-spacer{text-align:center;flex:none;width:1.25rem}.schema-toggle{color:var(--text-muted);cursor:pointer;font:inherit;background:0 0;border:0;padding:0}.schema-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-radius:var(--radius-sm)}.schema-ref-link:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-radius:var(--radius-sm)}.schema-name{font-family:var(--font-mono);overflow-wrap:anywhere;font-weight:600}.schema-required{color:var(--danger-text);font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.03em}.schema-type{font-family:var(--font-mono);color:var(--accent);overflow-wrap:anywhere}.schema-ref{font-family:var(--font-mono);font-size:var(--text-sm)}.schema-ref-link{color:var(--accent);text-decoration:underline;cursor:pointer;background:0 0;border:0;padding:0}.schema-note-inline{font-size:var(--text-xs);color:var(--text-muted);font-style:italic}.schema-unresolved{color:var(--danger-text)}.schema-fact{padding:0 var(--space-1);border-radius:var(--radius-sm);background:var(--surface-2);font-size:var(--text-xs);overflow-wrap:anywhere}.schema-fact-label{color:var(--text-muted)}.schema-description,.schema-closed,.schema-open{margin:0 0 0 calc(1.25rem + var(--space-2));color:var(--text-muted)}.schema-description p{margin:var(--space-1)0 0;overflow-wrap:anywhere}.schema-closed,.schema-open{font-size:var(--text-xs)}.schema-closed{color:var(--warning-text)}.schema-composition{padding-top:var(--space-1);color:var(--text-muted);font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.03em;font-weight:600}.http-docs-title{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-2)var(--space-4);flex-wrap:wrap}.http-docs-layout{display:grid;grid-template-columns:minmax(14rem,20rem)minmax(0,1fr);gap:var(--space-4);align-items:start}@media (max-width:800px){.http-docs-layout{grid-template-columns:minmax(0,1fr)}}.http-muted{color:var(--text-muted)}.http-sidebar{position:sticky;top:var(--space-3);display:flex;gap:var(--space-2);overflow-y:auto;flex-direction:column;max-height:calc(100vh - 6rem)}@media (max-width:800px){.http-sidebar{position:static;max-height:22rem}}.http-sidebar-count{font-size:var(--text-xs);margin:0}.http-tag{margin-bottom:var(--space-3)}.http-section{margin-bottom:var(--space-4)}.http-section-name{margin:0 0 var(--space-2);font-size:var(--text-md);color:var(--text)}.http-section .http-tag{padding-left:var(--space-2);border-left:1px solid var(--border)}.http-overview-tag+.http-overview-tag{margin-top:var(--space-3)}.http-overview-tag-name,.http-tag-name{margin:0 0 var(--space-1);font-size:var(--text-sm);text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted)}.http-tag-ops,.http-overview-ops,.http-params,.http-responses,.http-components{list-style:none;margin:0;padding:0}.http-op-link{display:flex;gap:var(--space-2);padding:var(--space-1)var(--space-2);border-radius:var(--radius-sm);color:var(--text);text-decoration:none;align-items:flex-start}.http-op-link:hover{background:var(--surface-2)}.http-op-link:focus-visible{background:var(--surface-2)}.http-op-link:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}.http-op-link[aria-current=page]{background:var(--info-bg);color:var(--info-text)}.http-method{font-family:var(--font-mono);flex:none;justify-content:center;min-width:3.5rem}.http-op-text{display:flex;flex-direction:column;min-width:0}.http-op-path{font-family:var(--font-mono);font-size:var(--text-sm);overflow-wrap:anywhere}.http-op-summary{font-size:var(--text-xs);color:var(--text-muted)}.http-docs-main{display:flex;gap:var(--space-4);flex-direction:column;min-width:0}.http-info-line,.http-operation-line,.http-markers,.http-param-head,.http-response-head,.http-tryit-status,.http-tryit-actions{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.http-servers{display:grid;gap:var(--space-2);margin:var(--space-3)0}.http-servers dt{font-size:var(--text-sm);color:var(--text-muted)}.http-servers dd{display:flex;gap:var(--space-2);overflow-wrap:anywhere;align-items:center;margin:0}.http-overview{display:flex;gap:var(--space-3);flex-direction:column}.http-overview-ops li{padding:var(--space-1)0;overflow-wrap:anywhere}.http-components{display:flex;gap:var(--space-2)var(--space-3);flex-wrap:wrap}.http-operation{display:flex;gap:var(--space-3);flex-direction:column}.http-operation-path{font-size:var(--text-md);overflow-wrap:anywhere}.http-operation-title{margin:var(--space-2)0 0;font-size:var(--text-lg)}.http-operation-id{display:flex;align-items:center;gap:var(--space-2);margin:var(--space-1)0 0;font-size:var(--text-sm);flex-wrap:wrap}.http-requires code{margin-right:var(--space-1)}.http-csrf,.http-tryit-disabled{padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);background:var(--info-bg);color:var(--info-text)}.http-csrf p{margin:0}.http-csrf p+p{margin-top:var(--space-1)}.http-tryit-disabled{margin:0 0 var(--space-3);background:var(--warning-bg);color:var(--warning-text)}.http-description p{margin:0 0 var(--space-2);overflow-wrap:anywhere}.http-section h3,.http-tryit h3{margin:0 0 var(--space-2);font-size:var(--text-md)}.http-param,.http-response{padding:var(--space-2)0;border-top:1px solid var(--border)}.http-param-name{font-weight:600}.http-param-description p,.http-param-style{margin:var(--space-1)0;font-size:var(--text-sm)}.http-media{margin-top:var(--space-2)}.http-media-type{display:inline-block;margin-bottom:var(--space-1);font-size:var(--text-xs);color:var(--text-muted)}.http-codes{display:flex;gap:var(--space-1);list-style:none;margin:var(--space-1)0 0;flex-wrap:wrap;padding:0}.http-codes code{padding:0 var(--space-1);border-radius:var(--radius-sm);background:var(--surface-2);font-size:var(--text-xs)}.http-tryit{padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}.http-tryit-form{display:flex;gap:var(--space-2);flex-direction:column}.http-tryit-checks{display:flex;gap:var(--space-1)var(--space-3);flex-wrap:wrap}.http-snippets{margin-top:var(--space-3)}.http-snippet{position:relative}.http-snippet .copy-button,.http-snippet>button{position:absolute;top:var(--space-2);right:var(--space-2)}.http-snippet pre{padding:var(--space-3);border-radius:var(--radius-sm);background:var(--surface-2);font-family:var(--font-mono);font-size:var(--text-xs);overflow-x:auto;white-space:pre;margin:0}.http-tryit-result{display:flex;gap:var(--space-2);margin-top:var(--space-3);padding-top:var(--space-3);border-top:1px solid var(--border);flex-direction:column}.http-tryit-result p{font-size:var(--text-sm);margin:0}.http-tryit-timing{font-size:var(--text-sm);color:var(--text-muted)}.http-tryit-headers summary{cursor:pointer;font-size:var(--text-sm)}.http-tryit-headers dl{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:var(--space-1)var(--space-3);margin:var(--space-2)0 0;font-size:var(--text-xs)}.http-tryit-headers dl>div{display:contents}.http-tryit-headers dd{overflow-wrap:anywhere;margin:0}.http-tryit-text{padding:var(--space-2);border-radius:var(--radius-sm);background:var(--surface-2);font-family:var(--font-mono);font-size:var(--text-xs);overflow-x:auto;white-space:pre-wrap;margin:0}.ws-docs{display:flex;gap:var(--space-4);flex-direction:column}.ws-header .screen-title{display:flex;align-items:center;gap:var(--space-2);overflow-wrap:anywhere;flex-wrap:wrap}.ws-kicker{margin:0}.ws-description summary{cursor:pointer}.ws-description p{overflow-wrap:anywhere;max-width:72ch}.ws-overview{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));gap:var(--space-4)}.ws-layout{display:grid;grid-template-columns:minmax(14rem,18rem)minmax(0,1fr);gap:var(--space-4);align-items:start}@media (max-width:800px){.ws-layout{grid-template-columns:minmax(0,1fr)}}.ws-sidebar{position:sticky;top:var(--space-4);max-height:calc(100vh - 2*var(--space-4));overflow-y:auto;padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}@media (max-width:800px){.ws-sidebar{position:static;max-height:22rem}}.ws-group+.ws-group{margin-top:var(--space-3)}.ws-group-title{margin:0 0 var(--space-1);font-size:var(--text-xs);letter-spacing:.04em;text-transform:uppercase;color:var(--text-muted);font-weight:600}.ws-group ul{list-style:none;margin:0;padding:0}.ws-nav-link{display:flex;padding:var(--space-1)var(--space-2);border-radius:var(--radius-sm);color:var(--text);text-decoration:none;flex-direction:column}.ws-nav-link:hover{background:var(--surface-2)}.ws-nav-link[data-selected=true]{background:var(--info-bg);color:var(--info-text)}.ws-nav-label{font-family:var(--font-mono);font-size:var(--text-sm);overflow-wrap:anywhere}.ws-nav-hint{font-size:var(--text-xs);color:var(--text-muted);overflow-wrap:anywhere}.ws-main,.ws-pane{display:flex;gap:var(--space-4);flex-direction:column;min-width:0}.ws-links{display:flex;gap:var(--space-1)var(--space-3);list-style:none;flex-wrap:wrap;margin:0;padding:0}.ws-permissions{display:flex;gap:var(--space-2);flex-wrap:wrap}.ws-permission{display:inline-flex;align-items:center;gap:var(--space-1);flex-wrap:wrap}.ws-note{display:block;padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);background:var(--warning-bg);color:var(--warning-text);overflow-wrap:anywhere}.ws-requirements{margin:0 0 var(--space-3);padding-left:var(--space-5)}.ws-table td{vertical-align:top;overflow-wrap:anywhere}.ws-value{white-space:nowrap;font-variant-numeric:tabular-nums}.ws-highlight{border-color:var(--accent);box-shadow:inset 3px 0 0 var(--accent)}.ws-schema{overflow-x:auto}.ws-example+.ws-example{margin-top:var(--space-3)}.ws-try{display:flex;align-items:flex-start;gap:var(--space-2);flex-direction:column}.ws-try p{margin:0}.ws-try-fields{display:flex;gap:var(--space-2)var(--space-3);flex-wrap:wrap}.ws-try-fields .field{min-width:12rem;margin:0}.ws-try-channel{overflow-wrap:anywhere}.ws-disabled{opacity:.55;cursor:not-allowed}.ws-example-head{display:flex;justify-content:space-between;align-items:center;gap:var(--space-2)}.ws-example-event{margin-block:var(--space-2);padding:var(--space-2)var(--space-3);border:1px solid var(--accent);border-radius:var(--radius,6px)}.ws-try-reason{padding-left:var(--space-4);margin:0}.runner-actions{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.runner-actions-hint{font-size:var(--text-sm);color:var(--text-muted);flex-basis:100%;margin:0}.runner-form{display:grid;gap:var(--space-3)}.runner-form-row{display:flex;gap:var(--space-3);flex-wrap:wrap}.runner-form-row>.field{flex:10rem;min-width:0}.runner-note{padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);background:var(--surface-2);font-size:var(--text-sm);margin:0}.runner-note-pending{background:var(--warning-bg);color:var(--warning-text)}.schedule-modes{display:flex;gap:var(--space-2)var(--space-4);padding:var(--space-2)var(--space-3);border:1px solid var(--border);border-radius:var(--radius);flex-wrap:wrap;margin:0}.schedule-modes>legend{padding:0 var(--space-1);font-weight:600;font-size:var(--text-sm)}.schedule-mode{display:inline-flex;align-items:center;gap:var(--space-1);cursor:pointer}.run-id{display:inline-flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.run-id code{overflow-wrap:anywhere}.runner-note-refused{background:var(--danger-bg);color:var(--danger-text)}.config-source{display:flex;align-items:center;gap:var(--space-2);margin:calc(var(--space-2)*-1)0 0;font-size:var(--text-sm);color:var(--text-muted);flex-wrap:wrap}.runner-link{overflow-wrap:anywhere;font-weight:600}.runner-id{margin-left:var(--space-2);font-size:var(--text-sm);overflow-wrap:anywhere}.runners-where{white-space:nowrap;width:7rem}.runners-status{white-space:nowrap;width:16rem}.runners-count{margin:var(--space-2)0 0;font-size:var(--text-sm)}.runner-screen{display:flex;gap:var(--space-4);flex-direction:column}.runner-header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-3);flex-wrap:wrap}.runner-heading{display:flex;align-items:baseline;gap:var(--space-2)var(--space-3);flex-wrap:wrap;min-width:0}.runner-title{overflow-wrap:anywhere}.runner-badges{display:inline-flex;gap:var(--space-1);flex-wrap:wrap}.runner-last-error{color:var(--danger-text);overflow-wrap:anywhere}.run-list{display:flex;gap:var(--space-3);list-style:none;flex-direction:column;margin:0;padding:0}.run-list>li+li{padding-top:var(--space-3);border-top:1px solid var(--border)}.run-record{display:flex;gap:var(--space-3);flex-direction:column;min-width:0}.run-id-line{display:inline-flex;align-items:center;gap:var(--space-2);overflow-wrap:anywhere;flex-wrap:wrap}.run-id{font-size:var(--text-sm);overflow-wrap:anywhere}.run-toggle{display:inline-flex;border-radius:var(--radius-sm);color:inherit;cursor:pointer;background:0 0;border:1px solid #0000;justify-content:center;align-items:center;min-width:1.75rem;min-height:1.75rem;padding:0}.run-toggle:hover{border-color:var(--border)}.run-toggle:focus-visible{outline:2px solid var(--focus);outline-offset:1px}.run-details-row>td{background:var(--surface-2)}.history-table .numeric{text-align:right;font-variant-numeric:tabular-nums}.history-actions{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap}.history-limit{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.history-open-log-note{display:flex;align-items:center;gap:var(--space-2);margin:var(--space-3)0 0;font-size:var(--text-xs);flex-wrap:wrap}.run-logs-cell{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}.worker-server+.worker-server{margin-top:var(--space-4)}.worker-server-title{margin:0 0 var(--space-2);font-size:var(--text-sm);font-weight:600}.worker-service-note{margin:0 0 var(--space-3);font-size:var(--text-sm)}.workers-sweep-note{margin:0 0 var(--space-3);padding:var(--space-2)var(--space-3);border-left:3px solid var(--warning-text);border-radius:var(--radius-sm);background:var(--warning-bg);color:var(--warning-text);font-size:var(--text-sm)}.worker-filters{display:flex;align-items:flex-end;gap:var(--space-2)var(--space-3);flex-flow:wrap}.worker-filters .field{min-width:10rem;margin:0}.worker-key{margin-top:var(--space-1);font-size:var(--text-sm);font-weight:400}.worker-header{display:flex;gap:var(--space-2);flex-direction:column}.worker-header .screen-title{overflow-wrap:anywhere}.worker-config-summary{margin:0 0 var(--space-3)}.worker-analytics-title{margin:0 0 var(--space-2);font-size:var(--text-sm);font-weight:600}.worker-analytics>*+*{margin-top:var(--space-4)}.worker-target-note{margin:0 0 var(--space-3)}.worker-target-file{overflow-wrap:anywhere}.providers-list{display:grid;gap:var(--space-3)}.provider-test,.provider-schema{display:grid;gap:var(--space-2);margin-top:var(--space-3);justify-items:start}.provider-test-result p{margin:0}.provider-test-fail{color:var(--danger)}.provider-checks{margin:var(--space-1)0 0;padding-left:var(--space-3)}.job-defaults{display:flex;gap:var(--space-3);flex-direction:column}.job-defaults p{margin:0}.job-defaults-heading{font-size:var(--text-md);margin:0}.job-defaults-form{display:flex;gap:var(--space-3);flex-direction:column}.job-defaults-row{display:flex;align-items:flex-start;gap:var(--space-2);border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--space-3);flex-direction:column;margin:0}.job-defaults-row>.field,.job-defaults-row>.field-row{align-self:stretch}.job-defaults-row legend{font-weight:600}.job-defaults-values,.job-defaults-note,.job-defaults-uses-code{font-size:var(--text-sm);margin:0}.job-defaults-reset{display:flex;align-items:center;gap:var(--space-2)var(--space-3);margin-top:var(--space-3);flex-wrap:wrap}.job-defaults-reset-note{font-size:var(--text-sm);color:var(--text-muted);flex:16rem;margin:0}.job-defaults-conflict,.job-defaults-warning{border-radius:var(--radius-sm);padding:var(--space-2)var(--space-3);background:var(--warning-bg);color:var(--warning-text)}.job-defaults-conflict{display:flex;align-items:flex-start;gap:var(--space-2);margin-bottom:var(--space-3);flex-direction:column}.job-defaults-conflict p{margin:0}.job-defaults-apply-states{display:flex;gap:var(--space-1);border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--space-3);flex-direction:column}.job-defaults-apply-keys{padding-left:var(--space-4);margin:0}.job-defaults-preview h3{margin:var(--space-2)0;font-size:var(--text-md)}[data-testid=apply-progress] progress{width:100%}:root{color-scheme:light;--font-sans:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;--space-1:4px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:24px;--space-6:32px;--radius-sm:4px;--radius:8px;--radius-pill:999px;--text-xs:.75rem;--text-sm:.8125rem;--text-md:.9375rem;--text-lg:1.125rem;--text-xl:1.5rem;--bg:#f6f7f9;--surface:#fff;--surface-2:#f0f2f5;--border:#d9dde3;--border-strong:#838c99;--text:#1b1f24;--text-muted:#5b6573;--accent:#2957c7;--accent-contrast:#fff;--focus:#2957c7;--danger:#b42318;--danger-contrast:#fff;--warning-bg:#fff4d6;--warning-text:#7a4b00;--info-bg:#e3ecff;--info-text:#1f3f8f;--success-bg:#ddf5e6;--success-text:#13603a;--danger-bg:#fde5e3;--danger-text:#92211a;--neutral-bg:#eceff3;--neutral-text:#3b4450;--state-waiting:#2f6fdb;--state-delayed:#7a4fcf;--state-active:#0f8a8a;--state-completed:#238a4a;--state-failed:#d4541a;--state-dead:#b42318;--state-waiting-children:#7a6a1f;--shadow:0 1px 2px #1018280f,0 1px 3px #10182814;--header-height:56px;--nav-width:200px}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--bg:#0f1216;--surface:#171b21;--surface-2:#1e232b;--border:#2d343e;--border-strong:#65717f;--text:#e6e9ee;--text-muted:#9aa4b2;--accent:#7ea2ff;--accent-contrast:#0b1020;--focus:#7ea2ff;--danger:#ff7b70;--danger-contrast:#1a0806;--warning-bg:#3a2c0a;--warning-text:#ffd27a;--info-bg:#182646;--info-text:#b7caff;--success-bg:#11301f;--success-text:#8fe0ad;--danger-bg:#3d1512;--danger-text:#ffb4ad;--neutral-bg:#242a33;--neutral-text:#c9d0da;--state-waiting:#6f9ef0;--state-delayed:#b08cf0;--state-active:#3cc4c4;--state-completed:#52c47f;--state-failed:#f08a52;--state-dead:#ff7b70;--state-waiting-children:#cdb64a;--shadow:0 1px 2px #0006}}:root[data-theme=dark]{color-scheme:dark;--bg:#0f1216;--surface:#171b21;--surface-2:#1e232b;--border:#2d343e;--border-strong:#65717f;--text:#e6e9ee;--text-muted:#9aa4b2;--accent:#7ea2ff;--accent-contrast:#0b1020;--focus:#7ea2ff;--danger:#ff7b70;--danger-contrast:#1a0806;--warning-bg:#3a2c0a;--warning-text:#ffd27a;--info-bg:#182646;--info-text:#b7caff;--success-bg:#11301f;--success-text:#8fe0ad;--danger-bg:#3d1512;--danger-text:#ffb4ad;--neutral-bg:#242a33;--neutral-text:#c9d0da;--state-waiting:#6f9ef0;--state-delayed:#b08cf0;--state-active:#3cc4c4;--state-completed:#52c47f;--state-failed:#f08a52;--state-dead:#ff7b70;--state-waiting-children:#cdb64a;--shadow:0 1px 2px #0006}*,*:before,*:after{box-sizing:border-box}html,body{margin:0;padding:0}body{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:var(--text-md);-webkit-font-smoothing:antialiased;line-height:1.45}a{color:var(--accent)}code{font-family:var(--font-mono);font-size:.92em}:focus-visible{outline:2px solid var(--focus);outline-offset:2px}.visually-hidden{overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute!important}.muted{color:var(--text-muted)}.skip-link{position:absolute;left:var(--space-2);padding:var(--space-2)var(--space-3);background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-sm);z-index:10;top:-40px}.skip-link:focus{top:var(--space-2)}.app{display:flex;flex-direction:column;min-height:100vh}.app-header{position:sticky;z-index:5;display:flex;align-items:center;gap:var(--space-2)var(--space-4);min-height:var(--header-height);padding:var(--space-2)var(--space-4);background:var(--surface);border-bottom:1px solid var(--border);flex-wrap:wrap;top:0}.app-brand{font-weight:650;font-size:var(--text-lg);color:var(--text);text-decoration:none}.app-chips{display:flex;gap:var(--space-2);flex-wrap:wrap;min-width:0}.app-header-end{display:flex;align-items:center;gap:var(--space-2);min-width:0;margin-left:auto}.app-body{display:flex;flex:1;min-height:0}.app-nav{flex:0 0 var(--nav-width);padding:var(--space-4)var(--space-2);border-right:1px solid var(--border);background:var(--surface)}.app-nav ul{list-style:none;display:flex;gap:var(--space-1);flex-direction:column;margin:0;padding:0}.app-nav-link{display:block;padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);color:var(--text);text-decoration:none;white-space:nowrap}.app-nav .app-nav-sub{margin-top:var(--space-1);padding-left:var(--space-3)}.app-nav-sub .app-nav-link{font-size:var(--text-sm)}.app-nav-link:hover{background:var(--surface-2)}.app-nav-link[aria-current=page]{background:var(--info-bg);color:var(--info-text);font-weight:600}.app-main{padding:var(--space-5);flex:1;min-width:0}.app-main:focus{outline:none}.screen{display:flex;gap:var(--space-4);flex-direction:column;max-width:1400px}.screen-title{font-size:var(--text-xl);margin:0}.bootstrap-screen{display:flex;justify-content:center;align-items:center;gap:var(--space-4);padding:var(--space-4);flex-direction:column;min-height:100vh}.bootstrap-title{font-size:var(--text-xl);margin:0}.btn{display:inline-flex;align-items:center;gap:var(--space-2);padding:var(--space-2)var(--space-3);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface);color:var(--text);font:inherit;font-size:var(--text-sm);cursor:pointer}.btn:hover{background:var(--surface-2)}.btn:disabled{opacity:.55;cursor:not-allowed}.btn-primary{background:var(--accent);border-color:var(--accent);color:var(--accent-contrast)}.btn-primary:hover{background:var(--accent);filter:brightness(1.08)}.btn-danger{background:var(--danger);border-color:var(--danger);color:var(--danger-contrast)}.btn-danger:hover{background:var(--danger);filter:brightness(1.08)}.btn-ghost{background:0 0;border-color:#0000}.btn-sm{padding:var(--space-1)var(--space-2);font-size:var(--text-xs)}.badge{display:inline-flex;align-items:center;gap:var(--space-1);padding:2px var(--space-2);border-radius:var(--radius-pill);font-size:var(--text-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;font-weight:550}.badge-neutral{background:var(--neutral-bg);color:var(--neutral-text)}.badge-info{background:var(--info-bg);color:var(--info-text)}.badge-success{background:var(--success-bg);color:var(--success-text)}.badge-warning{background:var(--warning-bg);color:var(--warning-text)}.badge-danger{background:var(--danger-bg);color:var(--danger-text)}.badge-accent{background:var(--accent);color:var(--accent-contrast)}.chip{display:inline-flex;align-items:baseline;gap:var(--space-1);padding:2px var(--space-2);border:1px solid var(--border);border-radius:var(--radius-pill);font-size:var(--text-xs);max-width:100%}.chip-label{color:var(--text-muted)}.chip-value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}.live-dot{background:currentColor;border-radius:50%;width:6px;height:6px}.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);box-shadow:var(--shadow);min-width:0}.card-header{display:flex;justify-content:space-between;align-items:center;gap:var(--space-3);padding:var(--space-3)var(--space-4);border-bottom:1px solid var(--border);flex-wrap:wrap}.card-title{font-size:var(--text-lg);margin:0}.card-body{padding:var(--space-4)}.input{padding:var(--space-2)var(--space-3);border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:var(--surface);color:var(--text);font:inherit;font-size:var(--text-sm);width:100%;min-width:0}.search{flex:0 260px;min-width:0}.screen>.search,.queues-search{flex:none;width:min(100%,260px)}.table-wrap{overflow:auto;border:1px solid var(--border);border-radius:var(--radius-sm);max-height:70vh}.table{border-collapse:separate;border-spacing:0;font-size:var(--text-sm);width:100%}.table th,.table td{padding:var(--space-2)var(--space-3);border-bottom:1px solid var(--border);text-align:left;vertical-align:middle;white-space:nowrap}.table thead th{position:sticky;z-index:1;background:var(--surface-2);font-weight:600;top:0}.table tbody tr:hover{background:var(--surface-2)}.table .num{text-align:right;font-variant-numeric:tabular-nums}.table .zero{color:var(--text-muted)}.queue-name{font-weight:500}.queue-paused{margin-left:var(--space-2)}.empty-state{padding:var(--space-5)var(--space-4);text-align:center;color:var(--text-muted)}.empty-state-title{margin:0 0 var(--space-1);font-size:inherit;color:var(--text);font-weight:600}.empty-state-description{margin:0}.empty-state-action{margin-top:var(--space-3)}.error-view{display:flex;align-items:flex-start;gap:var(--space-2);padding:var(--space-3)var(--space-4);border:1px solid var(--danger);border-radius:var(--radius-sm);background:var(--danger-bg);color:var(--danger-text);flex-direction:column;max-width:640px}.error-view p{margin:0}.error-view-title{font-size:inherit;margin:0;font-weight:650}.error-view-issues{padding-left:var(--space-4);margin:0}.notice{margin:var(--space-3)0 0;padding:var(--space-2)var(--space-3);border-radius:var(--radius-sm);background:var(--warning-bg);color:var(--warning-text);font-size:var(--text-sm)}.spinner-wrap{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--text-muted)}.spinner{border:2px solid var(--border);border-top-color:var(--accent);animation:.8s linear infinite spin;border-radius:50%;width:16px;height:16px}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important;transition-delay:0s!important}.spinner{animation-duration:2.4s!important;animation-iteration-count:infinite!important}}.state-badge{display:inline-flex;white-space:nowrap;align-items:center;gap:6px}.state-dot{background:var(--state-color,var(--text-muted));border-radius:50%;flex:none;width:8px;height:8px}.state-waiting{--state-color:var(--state-waiting)}.state-delayed{--state-color:var(--state-delayed)}.state-active{--state-color:var(--state-active)}.state-completed{--state-color:var(--state-completed)}.state-failed{--state-color:var(--state-failed)}.state-dead{--state-color:var(--state-dead)}.state-waiting-children{--state-color:var(--state-waiting-children)}.overview-summary{display:flex;gap:var(--space-3);flex-direction:column}.stat-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--space-3);margin:0}.stat{padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface);min-width:0}.stat-state{border-top:3px solid var(--state-color)}.stat dd{margin:0}.stat-label{font-size:var(--text-sm);color:var(--text-muted)}.stat-value{font-size:var(--text-xl);font-variant-numeric:tabular-nums;overflow-wrap:anywhere;font-weight:650}.stat-hint{font-size:var(--text-xs);color:var(--text-muted)}.range-band{margin-top:var(--space-3);padding:var(--space-3);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface)}.range-band-head{display:flex;align-items:baseline;gap:var(--space-2);margin:0 0 var(--space-2);font-size:var(--text-sm);flex-wrap:wrap}.range-band-title{font-weight:600}.range-band-groups{display:flex;gap:var(--space-3)var(--space-5);flex-wrap:wrap}.range-group{flex:0 auto;min-width:0}.range-group-wide{flex:32rem}.range-group-title{margin:0 0 var(--space-1);font-size:var(--text-xs);color:var(--text-muted);font-weight:600}.range-cells{display:flex;gap:var(--space-1)var(--space-4);flex-wrap:wrap;margin:0}.range-cell dt{font-size:var(--text-xs);color:var(--text-muted);white-space:nowrap}.range-cell dd{font-variant-numeric:tabular-nums;margin:0;font-weight:600}.range-cell-total dt{color:var(--text);font-weight:600}.range-note{margin:var(--space-1)0 0;font-size:var(--text-xs);color:var(--text-muted)}.sparkline-cell{display:inline-flex;align-items:center;min-width:120px;min-height:28px}.sparkline{display:block;overflow:visible}.sparkline polyline{fill:none;stroke-width:1.5;stroke-linejoin:round;stroke-linecap:round}.sparkline-primary{stroke:var(--state-completed)}.sparkline-secondary{stroke:var(--state-failed);opacity:.8}.sparkline-baseline{stroke:var(--border);stroke-width:1}.sparkline-placeholder{display:block;background:var(--border);width:120px;height:2px}@media (max-width:720px){.app-body{flex-direction:column}.app-nav{padding:var(--space-2);border-right:0;border-bottom:1px solid var(--border);overflow-x:auto;flex:none}.app-nav ul{flex-direction:row}.app-nav li{display:flex;gap:var(--space-1)}.app-nav .app-nav-sub{margin-top:0;padding-left:0}.app-main{padding:var(--space-4)}.app-header{position:static;padding:var(--space-2)var(--space-4)}.app-header-end{justify-content:space-between;width:100%;margin-left:0}.live-status{overflow:hidden;min-width:0}.search{flex-basis:100%}.stat-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}.overview-header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-3);margin-bottom:var(--space-4);flex-wrap:wrap}.overview-header .screen-title{margin:0}.overview-range{display:flex;align-items:flex-end;gap:var(--space-2);flex-direction:column;margin-left:auto}@media (max-width:720px){.overview-range{align-items:stretch;width:100%;margin-left:0}}.queues-search{margin-bottom:var(--space-3)}:root{--json-key:var(--text);--json-string:var(--success-text);--json-number:var(--info-text);--json-boolean:var(--state-delayed);--json-null:var(--text-muted);--overlay:#10182873}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--overlay:#0009}}:root[data-theme=dark]{--overlay:#0009}.dialog{border:1px solid var(--border);border-radius:var(--radius);background:var(--surface);color:var(--text);box-shadow:var(--shadow);width:min(560px,calc(100vw - 2*var(--space-4)));max-height:calc(100vh - 2*var(--space-5));padding:0}.dialog-sm{width:min(400px,calc(100vw - 2*var(--space-4)))}.dialog-lg{width:min(800px,calc(100vw - 2*var(--space-4)))}.dialog::backdrop{background:var(--overlay)}.dialog:focus{outline:none}.dialog-panel{display:flex;gap:var(--space-3);padding:var(--space-4);max-height:inherit;flex-direction:column}.dialog-header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-3)}.dialog-title{font-size:var(--text-lg);margin:0}.dialog-close{margin:calc(-1*var(--space-1))calc(-1*var(--space-2))0 0;font-size:var(--text-lg);line-height:1}.dialog-description{color:var(--text-muted);font-size:var(--text-sm);margin:0}.dialog-body{overflow:auto;min-height:0}.dialog-footer{display:flex;justify-content:flex-end;gap:var(--space-2);flex-wrap:wrap}.confirm-dialog-body{display:flex;gap:var(--space-3);flex-direction:column}.problem-banner{display:flex;align-items:flex-start;gap:var(--space-3);padding:var(--space-2)var(--space-3);border:1px solid var(--danger);border-radius:var(--radius-sm);background:var(--danger-bg);color:var(--danger-text);font-size:var(--text-sm);border-left-width:3px;min-width:0}.problem-banner p{margin:0}.problem-banner-main{display:flex;gap:var(--space-1);overflow-wrap:anywhere;flex-direction:column;flex:1;min-width:0}.problem-banner-title{display:flex;align-items:baseline;gap:var(--space-2);flex-wrap:wrap}.problem-banner-code{font-size:var(--text-xs);opacity:.85}.problem-banner-context,.problem-banner-issues{list-style:none;display:flex;gap:var(--space-1)var(--space-3);font-size:var(--text-xs);flex-wrap:wrap;margin:0;padding:0}.problem-banner-issues{flex-direction:column}.problem-banner-key{opacity:.85}.problem-banner-actions{display:flex;gap:var(--space-1);flex:none}.toast-viewport{position:fixed;right:var(--space-4);bottom:var(--space-4);z-index:20;display:flex;gap:var(--space-2);width:min(380px,calc(100vw - 2*var(--space-4)));pointer-events:none;flex-direction:column}.toast-list{list-style:none;display:flex;gap:var(--space-2);flex-direction:column;margin:0;padding:0}.toast{display:flex;align-items:flex-start;gap:var(--space-2);padding:var(--space-3);border:1px solid var(--border);border-left:4px solid var(--toast-color,var(--border));border-radius:var(--radius-sm);background:var(--surface);color:var(--text);box-shadow:var(--shadow);font-size:var(--text-sm);pointer-events:auto}.toast-success{--toast-color:var(--state-completed)}.toast-error{--toast-color:var(--danger)}.toast-info{--toast-color:var(--accent)}.toast-text{overflow-wrap:anywhere;flex:1;min-width:0}.toast-text p{margin:0}.toast-message{font-weight:600}.toast-description{color:var(--text-muted)}.toast-dismiss{font-size:var(--text-md);line-height:1}.tabs{display:flex;gap:var(--space-3);flex-direction:column;min-width:0}.tabs-list{display:flex;gap:var(--space-1);border-bottom:1px solid var(--border);overflow-x:auto}.tab{display:inline-flex;align-items:center;gap:var(--space-2);padding:var(--space-2)var(--space-3);color:var(--text-muted);font:inherit;font-size:var(--text-sm);white-space:nowrap;cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;margin-bottom:-1px}.tab:hover{color:var(--text)}.tab[aria-selected=true]{border-bottom-color:var(--accent);color:var(--text);font-weight:600}.tab:disabled{opacity:.5;cursor:not-allowed}.tab-count{padding:0 var(--space-2);border-radius:var(--radius-pill);background:var(--neutral-bg);color:var(--neutral-text);font-size:var(--text-xs);font-variant-numeric:tabular-nums;font-weight:550}.tab[aria-selected=true] .tab-count{background:var(--info-bg);color:var(--info-text)}.tabs-panel:focus-visible{outline-offset:4px}.pager{display:flex;justify-content:flex-end;align-items:center;gap:var(--space-2)var(--space-4);font-size:var(--text-sm);flex-wrap:wrap}.pager-range{color:var(--text-muted);font-variant-numeric:tabular-nums;margin-right:auto}.pager-size{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--text-muted)}.pager-select{padding:var(--space-1)var(--space-2);width:auto}.pager-page{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--text-muted)}.pager-page-input{padding:var(--space-1)var(--space-2);font-variant-numeric:tabular-nums;width:9ch}.pager-page-count{font-variant-numeric:tabular-nums}.pager-buttons{display:inline-flex;gap:var(--space-2)}.field{display:flex;gap:var(--space-1);flex-direction:column;min-width:0}.field-label{font-size:var(--text-sm);font-weight:600}.field-required{color:var(--danger)}.field-hint,.field-error{font-size:var(--text-xs);margin:0}.field-hint{color:var(--text-muted)}.field-error{color:var(--danger)}.input[aria-invalid=true]{border-color:var(--danger)}.input:disabled{opacity:.6;cursor:not-allowed}.input-group{display:flex;align-items:center;gap:var(--space-2);min-width:0}.input-suffix{color:var(--text-muted);font-size:var(--text-xs);flex:none}.checkbox{display:grid;grid-template-columns:auto 1fr;align-items:center;column-gap:var(--space-2);font-size:var(--text-sm)}.checkbox input{accent-color:var(--accent);margin:0}.checkbox-hint{grid-column:2}.copy-button[data-status=copied]{color:var(--success-text)}.copy-button[data-status=failed]{color:var(--danger)}.json-view{position:relative;padding:var(--space-2)var(--space-3);border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--surface-2);font-family:var(--font-mono);font-size:var(--text-sm);overflow:auto;max-height:60vh}.json-view-toolbar{position:sticky;float:right;font-family:var(--font-sans);top:0}.json-tree,.json-children{list-style:none;margin:0;padding:0}.json-children{padding-left:var(--space-4);border-left:1px dotted var(--border);margin-left:5px}.json-row{white-space:pre-wrap;overflow-wrap:anywhere}.json-toggle,.json-more{color:inherit;font:inherit;cursor:pointer;text-align:left;background:0 0;border:0;padding:0}.json-more{margin-left:var(--space-2);color:var(--accent);font-family:var(--font-sans);font-size:var(--text-xs);text-decoration:underline}.json-caret{display:inline-block;margin-right:var(--space-1);border-top:4px solid #0000;border-bottom:4px solid #0000;border-left:6px solid var(--text-muted);width:0;height:0;transition:transform .1s}.json-toggle[aria-expanded=true] .json-caret{transform:rotate(90deg)}.json-key{color:var(--json-key);font-weight:550}.json-string{color:var(--json-string)}.json-number{color:var(--json-number)}.json-boolean{color:var(--json-boolean)}.json-null,.json-undefined,.json-other,.json-circular{color:var(--json-null);font-style:italic}.json-punct{color:var(--text-muted)}.json-summary{margin:0 var(--space-1);color:var(--text-muted);font-family:var(--font-sans);font-size:var(--text-xs)}.json-editor{display:flex;gap:var(--space-1);flex-direction:column;min-width:0}.json-editor-text{font-family:var(--font-mono);font-size:var(--text-sm);resize:vertical;tab-size:2;line-height:1.5}.json-editor-bar{display:flex;align-items:center;gap:var(--space-1)var(--space-3);font-size:var(--text-xs);flex-wrap:wrap}.json-editor-bar p{flex:1;min-width:0;margin:0}.json-editor-error{color:var(--danger)}.json-editor-size{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--text-muted);font-variant-numeric:tabular-nums}.json-editor-size.is-over{color:var(--danger);font-weight:600}.json-editor-meter{width:80px;height:8px}.json-editor-actions{display:inline-flex;gap:var(--space-1)}.kv{display:grid;gap:var(--space-2)var(--space-4);font-size:var(--text-sm);margin:0}.kv-grid{grid-template-columns:max-content minmax(0,1fr)}.kv-row{display:contents}.kv-stacked{grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}.kv-stacked .kv-row{display:flex;flex-direction:column;gap:2px;min-width:0}.kv-label{color:var(--text-muted)}.kv-value{overflow-wrap:anywhere;min-width:0;margin:0}.kv-hint{display:block;color:var(--text-muted);font-size:var(--text-xs)}.relative-time{white-space:nowrap}@media (prefers-reduced-motion:reduce){.json-caret{transition:none}}@media (max-width:720px){.kv-grid{grid-template-columns:minmax(0,1fr);gap:var(--space-1)}.kv-grid .kv-value{margin-bottom:var(--space-2)}.pager-range{flex-basis:100%}}.shortcut-list{display:grid;gap:var(--space-2);font-size:var(--text-sm);margin:0}.shortcut-row{display:grid;grid-template-columns:minmax(7rem,max-content)minmax(0,1fr);gap:var(--space-3);align-items:baseline}.shortcut-row dd{margin:0}kbd{display:inline-block;padding:0 var(--space-1);border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:var(--surface-2);font-family:var(--font-mono);font-size:var(--text-xs);text-align:center;min-width:1.6em}
@@ -0,0 +1,5 @@
1
+ import{v,r,N,e,s}from"./main-a250ffk7.js";var c=1500;async function y(o){try{if(typeof navigator>"u"||!navigator.clipboard)return!1;return await navigator.clipboard.writeText(o),!0}catch{return!1}}var m="[Circular]";function g(o){let i=new WeakSet,a=(t)=>{if(typeof t==="bigint")return t.toString();if(typeof t==="function"||typeof t==="symbol")return;if(typeof t!=="object"||t===null)return t;if(i.has(t))return m;let u=t;if(typeof u.toJSON==="function")return a(u.toJSON.call(t));i.add(t);try{if(Array.isArray(t))return t.map((n)=>{let f=a(n);return f===void 0?null:f});let l={};for(let[n,f]of Object.entries(t)){let p=a(f);if(p!==void 0)l[n]=p}return l}finally{i.delete(t)}};return a(o)}function ns(o,i=2){return JSON.stringify(g(o),null,i)??"undefined"}function ge({text:o,label:i="Copy",ariaLabel:a,size:t="sm",className:u,onCopied:l}){let[n,f]=r("idle");v(()=>{if(n==="idle")return;let d=setTimeout(f,c,"idle");return()=>clearTimeout(d)},[n]);let p=async()=>{let d=await y(typeof o==="function"?o():o);f(d?"copied":"failed"),l?.(d)};return e(s,{variant:"ghost",size:t,className:N("copy-button",u),"aria-label":a,"data-status":n,onClick:()=>void p(),children:e("span",{"aria-live":"polite",children:n==="copied"?"Copied":n==="failed"?"Copy failed":i})})}
2
+ export{ns,ge};
3
+
4
+ //# debugId=2ABB7DE28FFACA5164756E2164756E21
5
+ //# sourceMappingURL=main-5grjvsy7.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["app/jobs/components/copy.ts", "app/jobs/components/CopyButton.tsx"],
4
+ "sourcesContent": [
5
+ "/**\n * Clipboard and JSON-serialisation helpers shared by {@link CopyButton} and\n * {@link JsonView}.\n */\n\n/** How long a {@link CopyButton}'s \"Copied\" / \"Copy failed\" feedback shows, in ms. */\nexport const COPY_FEEDBACK_MS = 1_500;\n\n/**\n * Writes `text` to the clipboard. Resolves `false` instead of throwing when\n * the Clipboard API is missing (an insecure origin, an old browser) or the\n * write is refused (no permission, the document not focused).\n */\nexport async function copyText(text: string): Promise<boolean> {\n try {\n if (typeof navigator === \"undefined\" || !navigator.clipboard) {\n return false;\n }\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** What {@link toJsonSafe} puts where a reference points back at an ancestor. */\nexport const CIRCULAR_MARKER = \"[Circular]\";\n\n/**\n * A JSON-safe copy of any value: circular references become\n * {@link CIRCULAR_MARKER} (a shared, non-circular reference is kept), a\n * `bigint` becomes its decimal string, `undefined` inside an array becomes\n * `null` (as `JSON.stringify` would), functions and symbols are dropped from\n * objects, and anything with `toJSON` (a `Date`) is serialised through it.\n *\n * The guard is a `WeakSet` of the objects on the current path: added on the\n * way down, deleted on the way back up, so it flags cycles and nothing else.\n */\nexport function toJsonSafe(value: unknown): unknown {\n const path = new WeakSet<object>();\n const walk = (current: unknown): unknown => {\n if (typeof current === \"bigint\") {\n return current.toString();\n }\n if (typeof current === \"function\" || typeof current === \"symbol\") {\n return undefined;\n }\n if (typeof current !== \"object\" || current === null) {\n return current;\n }\n if (path.has(current)) {\n return CIRCULAR_MARKER;\n }\n const withJson = current as { toJSON?: unknown };\n if (typeof withJson.toJSON === \"function\") {\n return walk((withJson.toJSON as () => unknown).call(current));\n }\n path.add(current);\n try {\n if (Array.isArray(current)) {\n return current.map((item) => {\n const safe = walk(item);\n return safe === undefined ? null : safe;\n });\n }\n const out: Record<string, unknown> = {};\n for (const [key, item] of Object.entries(current)) {\n const safe = walk(item);\n if (safe !== undefined) {\n out[key] = safe;\n }\n }\n return out;\n } finally {\n path.delete(current);\n }\n };\n return walk(value);\n}\n\n/**\n * `JSON.stringify` that never throws: circular input and bigints are handled\n * by {@link toJsonSafe}, and a bare `undefined` becomes the text `undefined`.\n */\nexport function safeStringify(value: unknown, indent = 2): string {\n const text = JSON.stringify(toJsonSafe(value), null, indent) as\n string | undefined;\n return text ?? \"undefined\";\n}\n",
6
+ "import { useEffect, useState } from \"react\";\nimport { Button } from \"./Button\";\nimport { cx } from \"./classNames\";\nimport { COPY_FEEDBACK_MS, copyText } from \"./copy\";\n\n/** Props of {@link CopyButton}. */\nexport interface CopyButtonProps {\n /** What to copy, or a function producing it on click (so a large payload is only serialised when asked). */\n text: string | (() => string);\n /** The button's visible text. Defaults to `\"Copy\"`. */\n label?: string;\n /** Accessible name when it differs from `label`, e.g. `\"Copy job id\"`. */\n ariaLabel?: string;\n /** Size. Defaults to `\"sm\"`. */\n size?: \"sm\" | \"md\";\n /** Extra class names. */\n className?: string;\n /** Called after each attempt with whether the clipboard write succeeded. */\n onCopied?: (ok: boolean) => void;\n}\n\n/**\n * Copies text to the clipboard and says so: the label turns into \"Copied\"\n * (or \"Copy failed\") for {@link COPY_FEEDBACK_MS}, announced politely.\n */\nexport function CopyButton({\n text,\n label = \"Copy\",\n ariaLabel,\n size = \"sm\",\n className,\n onCopied,\n}: CopyButtonProps) {\n const [status, setStatus] = useState<\"idle\" | \"copied\" | \"failed\">(\"idle\");\n\n useEffect(() => {\n if (status === \"idle\") {\n return;\n }\n const timer = setTimeout(setStatus, COPY_FEEDBACK_MS, \"idle\");\n return () => clearTimeout(timer);\n }, [status]);\n\n const onClick = async () => {\n const ok = await copyText(typeof text === \"function\" ? text() : text);\n setStatus(ok ? \"copied\" : \"failed\");\n onCopied?.(ok);\n };\n\n return (\n <Button\n variant=\"ghost\"\n size={size}\n className={cx(\"copy-button\", className)}\n aria-label={ariaLabel}\n data-status={status}\n onClick={() => void onClick()}\n >\n <span aria-live=\"polite\">\n {status === \"copied\"\n ? \"Copied\"\n : status === \"failed\"\n ? \"Copy failed\"\n : label}\n </span>\n </Button>\n );\n}\n"
7
+ ],
8
+ "mappings": "0CAMO,IAAM,EAAmB,KAOzB,eAAe,CAAQ,CAAC,EAAgC,CAC7D,GAAI,CACF,GAAI,OAAO,UAAc,KAAe,CAAC,UAAU,UACjD,MAAO,GAGT,OADA,MAAM,UAAU,UAAU,UAAU,CAAI,EACjC,GACP,KAAM,CACN,MAAO,IAKJ,IAAM,EAAkB,aAYxB,SAAS,CAAU,CAAC,EAAyB,CAClD,IAAM,EAAO,IAAI,QACX,EAAO,CAAC,IAA8B,CAC1C,GAAI,OAAO,IAAY,SACrB,OAAO,EAAQ,SAAS,EAE1B,GAAI,OAAO,IAAY,YAAc,OAAO,IAAY,SACtD,OAEF,GAAI,OAAO,IAAY,UAAY,IAAY,KAC7C,OAAO,EAET,GAAI,EAAK,IAAI,CAAO,EAClB,OAAO,EAET,IAAM,EAAW,EACjB,GAAI,OAAO,EAAS,SAAW,WAC7B,OAAO,EAAM,EAAS,OAAyB,KAAK,CAAO,CAAC,EAE9D,EAAK,IAAI,CAAO,EAChB,GAAI,CACF,GAAI,MAAM,QAAQ,CAAO,EACvB,OAAO,EAAQ,IAAI,CAAC,IAAS,CAC3B,IAAM,EAAO,EAAK,CAAI,EACtB,OAAO,IAAS,OAAY,KAAO,EACpC,EAEH,IAAM,EAA+B,CAAC,EACtC,QAAY,EAAK,KAAS,OAAO,QAAQ,CAAO,EAAG,CACjD,IAAM,EAAO,EAAK,CAAI,EACtB,GAAI,IAAS,OACX,EAAI,GAAO,EAGf,OAAO,EACP,OAAQ,CACR,EAAK,OAAO,CAAO,IAGvB,OAAO,EAAK,CAAK,EAOZ,SAAS,EAAa,CAAC,EAAgB,EAAS,EAAW,CAGhE,OAFa,KAAK,UAAU,EAAW,CAAK,EAAG,KAAM,CAAM,GAE5C,YC9DV,SAAS,EAAU,EACxB,OACA,QAAQ,OACR,YACA,OAAO,KACP,YACA,YACkB,CAClB,IAAO,EAAQ,GAAa,EAAuC,MAAM,EAEzE,EAAU,IAAM,CACd,GAAI,IAAW,OACb,OAEF,IAAM,EAAQ,WAAW,EAAW,EAAkB,MAAM,EAC5D,MAAO,IAAM,aAAa,CAAK,GAC9B,CAAC,CAAM,CAAC,EAEX,IAAM,EAAU,SAAY,CAC1B,IAAM,EAAK,MAAM,EAAS,OAAO,IAAS,WAAa,EAAK,EAAI,CAAI,EACpE,EAAU,EAAK,SAAW,QAAQ,EAClC,IAAW,CAAE,GAGf,OACE,EAAC,EAAD,CACE,QAAQ,QACR,KAAM,EACN,UAAW,EAAG,cAAe,CAAS,EACtC,aAAY,EACZ,cAAa,EACb,QAAS,IAAM,KAAK,EAAQ,EAN9B,SAQE,EAAC,OAAD,CAAM,YAAU,SAAhB,SACG,IAAW,SACR,SACA,IAAW,SACT,cACA,EACN,EACF",
9
+ "debugId": "2ABB7DE28FFACA5164756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,5 @@
1
+ import{C,v,g,r,Ae,J,rr,or,X,Sn,tt,Ee,x,Pt,sr,ir,ar,ur,_n,lr}from"./main-a250ffk7.js";function O(i,e){let s=new Set(e);return i.filter((t)=>!s.has(t))}var Q=class extends Ee{#i;#e;#n;#t;#s;#r;#o;#u;#h;#c=[];constructor(i,e,s){super();this.#i=i,this.#t=s,this.#n=[],this.#s=[],this.#e=[],this.setQueries(e)}onSubscribe(){if(this.listeners.size===1)this.#s.forEach((i)=>{i.subscribe((e)=>{this.#p(i,e)})})}onUnsubscribe(){if(!this.listeners.size)this.destroy()}destroy(){this.listeners=new Set,this.#s.forEach((i)=>{i.destroy()})}setQueries(i,e){this.#n=i,this.#t=e,x.batch(()=>{let s=this.#s,t=this.#f(this.#n);t.forEach((u)=>u.observer.setOptions(u.defaultedQueryOptions));let n=t.map((u)=>u.observer),o=n.map((u)=>u.getCurrentResult()),l=s.length!==n.length,c=n.some((u,d)=>u!==s[d]),a=l||c,b=a?!0:o.some((u,d)=>{let m=this.#e[d];return!m||!tt(u,m)});if(!a&&!b)return;if(a)this.#c=t,this.#s=n;if(this.#e=o,!this.hasListeners())return;if(a)O(s,n).forEach((u)=>{u.destroy()}),O(n,s).forEach((u)=>{u.subscribe((d)=>{this.#p(u,d)})});this.#d()})}getCurrentResult(){return this.#e}getQueries(){return this.#s.map((i)=>i.getCurrentQuery())}getObservers(){return this.#s}getOptimisticResult(i,e){let s=this.#f(i),t=s.map((o)=>o.observer.getOptimisticResult(o.defaultedQueryOptions)),n=s.map((o)=>o.defaultedQueryOptions.queryHash);return[t,(o)=>this.#l(o??t,e,n),()=>this.#a(t,s)]}#a(i,e){let s=new Set;return e.map((t,n)=>{let o=i[n];return!t.defaultedQueryOptions.notifyOnChangeProps?t.observer.trackResult(o,(l)=>{if(!s.has(l))s.add(l),e.forEach((c)=>{c.observer.trackProp(l)})}):o})}#l(i,e,s){if(e){let t=this.#h,n=s!==void 0&&t!==void 0&&(t.length!==s.length||s.some((o,l)=>o!==t[l]));if(this.#e!==this.#u||n||e!==this.#o){if(this.#o=e,this.#u=this.#e,s!==void 0)this.#h=s;this.#r=Sn(this.#r,e(i))}return this.#r}return i}#b(){return!this.#t?.combine||this.#s.some((i,e)=>i.options.suspense&&this.#e[e]?.data===void 0)}#f(i){let e=new Map;this.#s.forEach((t)=>{let n=t.options.queryHash;if(!n)return;let o=e.get(n);if(o)o.push(t);else e.set(n,[t])});let s=[];return i.forEach((t)=>{let n=this.#i.defaultQueryOptions(t),o=e.get(n.queryHash)?.shift()??new Pt(this.#i,n);s.push({defaultedQueryOptions:n,observer:o})}),s}#p(i,e){let s=this.#s.indexOf(i);if(s!==-1)this.#e=this.#e.slice(),this.#e[s]=e,this.#d()}#d(){if(this.hasListeners()){let i=this.#b(),e=this.#r,s=i?e:this.#l(this.#a(this.#e,this.#c),this.#t?.combine);if(i||e!==s)x.batch(()=>{this.listeners.forEach((t)=>{t(this.#e)})})}}};function rn({queries:i,...e},s){let t=J(s),n=rr(),o=or(),l=e.subscribed!==!1,c=g(()=>i.map((h)=>{let f=t.defaultQueryOptions(h);return f._optimisticResults=n?"isRestoring":l?"optimistic":void 0,f}),[i,t,n,l]);c.forEach((h)=>{ur(h);let f=t.getQueryCache().get(h.queryHash);sr(h,o,f)}),ir(o);let[a]=r(()=>new Q(t,c,e)),[b,u,d]=a.getOptimisticResult(c,e.combine),m=!n&&l;Ae(C((h)=>m?a.subscribe(x.batchCalls(h)):X,[a,m]),()=>a.getCurrentResult(),()=>a.getCurrentResult()),v(()=>{a.setQueries(c,e)},[c,e,a]);let y=b.some((h,f)=>_n(c[f],h))?b.flatMap((h,f)=>{let p=c[f];if(p&&_n(p,h)){let E=new Pt(t,p);return lr(p,E,o)}return[]}):[];if(y.length>0)throw Promise.all(y);let R=b.find((h,f)=>{let p=c[f];return p&&ar({result:h,errorResetBoundary:o,throwOnError:p.throwOnError,query:t.getQueryCache().get(p.queryHash),suspense:p.suspense})});if(R)throw R.error;return u(d())}
2
+ export{rn};
3
+
4
+ //# debugId=FE494B8581FB73F764756E2164756E21
5
+ //# sourceMappingURL=main-5zbx60gq.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../node_modules/@tanstack/query-core/build/modern/queriesObserver.js", "../../node_modules/@tanstack/react-query/build/modern/useQueries.js"],
4
+ "sourcesContent": [
5
+ "import { replaceEqualDeep, shallowEqualObjects } from \"./utils.js\";\nimport { Subscribable } from \"./subscribable.js\";\nimport { notifyManager } from \"./notifyManager.js\";\nimport { QueryObserver } from \"./queryObserver.js\";\n//#region src/queriesObserver.ts\nfunction difference(array1, array2) {\n\tconst excludeSet = new Set(array2);\n\treturn array1.filter((x) => !excludeSet.has(x));\n}\n/**\n* A `QueriesObserver` watches an array of queries at once, exposing them as\n* a single array of `QueryObserverResult`s (or, when a `combine` option is\n* given, as a combined value derived from that array). It manages one\n* internal `QueryObserver` per query, and is the primitive that framework\n* adapters (e.g. `useQueries`) build their hooks on top of.\n*\n* @example\n* ```ts\n* const observer = new QueriesObserver(queryClient, [\n* { queryKey: ['post', 1], queryFn: fetchPost },\n* { queryKey: ['post', 2], queryFn: fetchPost },\n* ])\n*\n* const unsubscribe = observer.subscribe((result) => {\n* console.log(result)\n* })\n* ```\n*/\nvar QueriesObserver = class extends Subscribable {\n\t#client;\n\t#result;\n\t#queries;\n\t#options;\n\t#observers;\n\t#combinedResult;\n\t#lastCombine;\n\t#lastResult;\n\t#lastQueryHashes;\n\t#observerMatches = [];\n\tconstructor(client, queries, options) {\n\t\tsuper();\n\t\tthis.#client = client;\n\t\tthis.#options = options;\n\t\tthis.#queries = [];\n\t\tthis.#observers = [];\n\t\tthis.#result = [];\n\t\tthis.setQueries(queries);\n\t}\n\tonSubscribe() {\n\t\tif (this.listeners.size === 1) this.#observers.forEach((observer) => {\n\t\t\tobserver.subscribe((result) => {\n\t\t\t\tthis.#onUpdate(observer, result);\n\t\t\t});\n\t\t});\n\t}\n\tonUnsubscribe() {\n\t\tif (!this.listeners.size) this.destroy();\n\t}\n\t/**\n\t* Stops observing all queries: clears all listeners and destroys every\n\t* underlying `QueryObserver` this observer manages.\n\t*/\n\tdestroy() {\n\t\tthis.listeners = /* @__PURE__ */ new Set();\n\t\tthis.#observers.forEach((observer) => {\n\t\t\tobserver.destroy();\n\t\t});\n\t}\n\t/**\n\t* Replaces the set of queries being observed. Existing `QueryObserver`s\n\t* are reused for queries that match an already-observed query hash;\n\t* observers for queries that are no longer present are destroyed, and new\n\t* observers are created and subscribed to for newly added queries.\n\t*\n\t* @example\n\t* ```ts\n\t* observer.setQueries([\n\t* { queryKey: ['post', 1], queryFn: fetchPost },\n\t* { queryKey: ['post', 3], queryFn: fetchPost },\n\t* ])\n\t* ```\n\t*/\n\tsetQueries(queries, options) {\n\t\tthis.#queries = queries;\n\t\tthis.#options = options;\n\t\tif (process.env.NODE_ENV !== \"production\") {\n\t\t\tconst queryHashes = queries.map((query) => this.#client.defaultQueryOptions(query).queryHash);\n\t\t\tif (new Set(queryHashes).size !== queryHashes.length) console.warn(\"[QueriesObserver]: Duplicate Queries found. This might result in unexpected behavior.\");\n\t\t}\n\t\tnotifyManager.batch(() => {\n\t\t\tconst prevObservers = this.#observers;\n\t\t\tconst newObserverMatches = this.#findMatchingObservers(this.#queries);\n\t\t\tnewObserverMatches.forEach((match) => match.observer.setOptions(match.defaultedQueryOptions));\n\t\t\tconst newObservers = newObserverMatches.map((match) => match.observer);\n\t\t\tconst newResult = newObservers.map((observer) => observer.getCurrentResult());\n\t\t\tconst hasLengthChange = prevObservers.length !== newObservers.length;\n\t\t\tconst hasIndexChange = newObservers.some((observer, index) => observer !== prevObservers[index]);\n\t\t\tconst hasStructuralChange = hasLengthChange || hasIndexChange;\n\t\t\tconst hasResultChange = hasStructuralChange ? true : newResult.some((result, index) => {\n\t\t\t\tconst prev = this.#result[index];\n\t\t\t\treturn !prev || !shallowEqualObjects(result, prev);\n\t\t\t});\n\t\t\tif (!hasStructuralChange && !hasResultChange) return;\n\t\t\tif (hasStructuralChange) {\n\t\t\t\tthis.#observerMatches = newObserverMatches;\n\t\t\t\tthis.#observers = newObservers;\n\t\t\t}\n\t\t\tthis.#result = newResult;\n\t\t\tif (!this.hasListeners()) return;\n\t\t\tif (hasStructuralChange) {\n\t\t\t\tdifference(prevObservers, newObservers).forEach((observer) => {\n\t\t\t\t\tobserver.destroy();\n\t\t\t\t});\n\t\t\t\tdifference(newObservers, prevObservers).forEach((observer) => {\n\t\t\t\t\tobserver.subscribe((result) => {\n\t\t\t\t\t\tthis.#onUpdate(observer, result);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t\tthis.#notify();\n\t\t});\n\t}\n\t/**\n\t* Returns the most recently computed array of `QueryObserverResult`s, one\n\t* per observed query, in the same order as the queries passed to the\n\t* constructor or `setQueries`.\n\t*\n\t* @example\n\t* ```ts\n\t* const results = observer.getCurrentResult()\n\t* const data = results.map((result) => result.data)\n\t* ```\n\t*/\n\tgetCurrentResult() {\n\t\treturn this.#result;\n\t}\n\t/**\n\t* Returns the underlying `Query` instances currently being observed, in\n\t* the same order as the queries passed to the constructor or `setQueries`.\n\t*/\n\tgetQueries() {\n\t\treturn this.#observers.map((observer) => observer.getCurrentQuery());\n\t}\n\t/**\n\t* Returns the underlying `QueryObserver` instances this observer manages,\n\t* in the same order as the queries passed to the constructor or\n\t* `setQueries`.\n\t*/\n\tgetObservers() {\n\t\treturn this.#observers;\n\t}\n\t/**\n\t* The `QueriesObserver` counterpart of {@link QueryObserver#getOptimisticResult} — computes\n\t* the result for the given (already-defaulted) queries right now, synchronously. Called by\n\t* framework adapters (e.g. `useQueries`) ahead of subscribing, returning a tuple of the raw\n\t* per-query results, a function to compute the combined result from them, and a function to\n\t* wrap the results for property-access tracking.\n\t*/\n\tgetOptimisticResult(queries, combine) {\n\t\tconst matches = this.#findMatchingObservers(queries);\n\t\tconst result = matches.map((match) => match.observer.getOptimisticResult(match.defaultedQueryOptions));\n\t\tconst queryHashes = matches.map((match) => match.defaultedQueryOptions.queryHash);\n\t\treturn [\n\t\t\tresult,\n\t\t\t(r) => {\n\t\t\t\treturn this.#combineResult(r ?? result, combine, queryHashes);\n\t\t\t},\n\t\t\t() => {\n\t\t\t\treturn this.#trackResult(result, matches);\n\t\t\t}\n\t\t];\n\t}\n\t#trackResult(result, matches) {\n\t\tconst trackedProps = /* @__PURE__ */ new Set();\n\t\treturn matches.map((match, index) => {\n\t\t\tconst observerResult = result[index];\n\t\t\treturn !match.defaultedQueryOptions.notifyOnChangeProps ? match.observer.trackResult(observerResult, (accessedProp) => {\n\t\t\t\tif (!trackedProps.has(accessedProp)) {\n\t\t\t\t\ttrackedProps.add(accessedProp);\n\t\t\t\t\tmatches.forEach((m) => {\n\t\t\t\t\t\tm.observer.trackProp(accessedProp);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}) : observerResult;\n\t\t});\n\t}\n\t#combineResult(input, combine, queryHashes) {\n\t\tif (combine) {\n\t\t\tconst lastHashes = this.#lastQueryHashes;\n\t\t\tconst queryHashesChanged = queryHashes !== void 0 && lastHashes !== void 0 && (lastHashes.length !== queryHashes.length || queryHashes.some((hash, i) => hash !== lastHashes[i]));\n\t\t\tif (this.#result !== this.#lastResult || queryHashesChanged || combine !== this.#lastCombine) {\n\t\t\t\tthis.#lastCombine = combine;\n\t\t\t\tthis.#lastResult = this.#result;\n\t\t\t\tif (queryHashes !== void 0) this.#lastQueryHashes = queryHashes;\n\t\t\t\tthis.#combinedResult = replaceEqualDeep(this.#combinedResult, combine(input));\n\t\t\t}\n\t\t\treturn this.#combinedResult;\n\t\t}\n\t\treturn input;\n\t}\n\t#shouldSkipCombine() {\n\t\treturn !this.#options?.combine || this.#observers.some((observer, index) => {\n\t\t\treturn observer.options.suspense && this.#result[index]?.data === void 0;\n\t\t});\n\t}\n\t#findMatchingObservers(queries) {\n\t\tconst prevObserversMap = /* @__PURE__ */ new Map();\n\t\tthis.#observers.forEach((observer) => {\n\t\t\tconst key = observer.options.queryHash;\n\t\t\tif (!key) return;\n\t\t\tconst previousObservers = prevObserversMap.get(key);\n\t\t\tif (previousObservers) previousObservers.push(observer);\n\t\t\telse prevObserversMap.set(key, [observer]);\n\t\t});\n\t\tconst observers = [];\n\t\tqueries.forEach((options) => {\n\t\t\tconst defaultedOptions = this.#client.defaultQueryOptions(options);\n\t\t\tconst observer = prevObserversMap.get(defaultedOptions.queryHash)?.shift() ?? new QueryObserver(this.#client, defaultedOptions);\n\t\t\tobservers.push({\n\t\t\t\tdefaultedQueryOptions: defaultedOptions,\n\t\t\t\tobserver\n\t\t\t});\n\t\t});\n\t\treturn observers;\n\t}\n\t#onUpdate(observer, result) {\n\t\tconst index = this.#observers.indexOf(observer);\n\t\tif (index !== -1) {\n\t\t\tthis.#result = this.#result.slice();\n\t\t\tthis.#result[index] = result;\n\t\t\tthis.#notify();\n\t\t}\n\t}\n\t#notify() {\n\t\tif (this.hasListeners()) {\n\t\t\tconst shouldSkipCombine = this.#shouldSkipCombine();\n\t\t\tconst previousResult = this.#combinedResult;\n\t\t\tconst newResult = shouldSkipCombine ? previousResult : this.#combineResult(this.#trackResult(this.#result, this.#observerMatches), this.#options?.combine);\n\t\t\tif (shouldSkipCombine || previousResult !== newResult) notifyManager.batch(() => {\n\t\t\t\tthis.listeners.forEach((listener) => {\n\t\t\t\t\tlistener(this.#result);\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n};\n//#endregion\nexport { QueriesObserver };\n\n//# sourceMappingURL=queriesObserver.js.map",
6
+ "\"use client\";\nimport { useQueryClient } from \"./QueryClientProvider.js\";\nimport { useIsRestoring } from \"./IsRestoringProvider.js\";\nimport { useQueryErrorResetBoundary } from \"./QueryErrorResetBoundary.js\";\nimport { ensurePreventErrorBoundaryRetry, getHasError, useClearResetErrorBoundary } from \"./errorBoundaryUtils.js\";\nimport { ensureSuspenseTimers, fetchOptimistic, shouldSuspend } from \"./suspense.js\";\nimport * as React from \"react\";\nimport { QueriesObserver, QueryObserver, noop, notifyManager } from \"@tanstack/query-core\";\n//#region src/useQueries.ts\n/**\n* The `useQueries` hook can be used to fetch a variable number of queries.\n*\n* The `queries` key accepts an array with query option objects mostly identical to `useQuery` — the top-level\n* `subscribed` option isn't accepted per query (see `placeholderData` below for another difference). A custom\n* `QueryClient` is supplied once, as `useQueries`' own top-level second argument, rather than per query.\n*\n* Having the same query key more than once in the array of query objects may cause some data to be shared\n* between queries. To avoid this, consider de-duplicating the queries and map the results back to the desired\n* structure.\n*\n* The `combine` option can be used to combine the results of the queries into a single value. The result will\n* be structurally shared to be as referentially stable as possible.\n*\n* @remarks The `combine` function only re-runs if it changed referentially, or if any of the query results\n* changed. An inlined `combine` function, as shown in the example below, therefore runs on every render — wrap\n* it in `useCallback`, or extract it to a stable function reference if it doesn't have any dependencies, to\n* avoid that.\n*\n* Unlike `useQuery`, `useQueries` cannot infer the `data` argument of an _inline_ `select` from its sibling\n* `queryFn`. Because `useQueries` infers the type of the whole `queries` array at once, the `select` parameter\n* of a query object written inline cannot be contextually typed from that same object's `queryFn`, so it falls\n* back to `unknown` — a [known TypeScript limitation](https://github.com/TanStack/query/issues/6556). Annotate\n* the `select` parameter explicitly, or define the query with {@link queryOptions}, which resolves its types in\n* a single object _before_ it reaches `useQueries`, to work around this — see the example below. The same\n* limitation applies to {@link useSuspenseQueries}.\n*\n* `placeholderData` is supported here too, but unlike `useQuery`, it doesn't receive information from\n* previously rendered queries, because the number of queries can differ between renders.\n* @param queryClient - Use this to provide a custom `QueryClient`. Otherwise, the one from the nearest context\n* will be used.\n* @returns The combined result. Without `combine`, this is an array with all the query results, in the same\n* order as the input. When `combine` is provided, this is the value returned by `combine` instead.\n*\n* @example\n* ```tsx\n* import { useQueries } from '@tanstack/react-query'\n*\n* function Posts({ ids }: { ids: Array<number> }) {\n* const postQueries = useQueries({\n* queries: ids.map((id) => ({\n* queryKey: ['post', id],\n* queryFn: () => fetchPost(id),\n* staleTime: Infinity,\n* })),\n* })\n*\n* return (\n* <ul>\n* {postQueries.map((query, index) => {\n* if (query.isPending) return <li key={ids[index]}>Loading...</li>\n* if (query.isError) return <li key={ids[index]}>Error: {query.error.message}</li>\n* return <li key={ids[index]}>{query.data.title}</li>\n* })}\n* </ul>\n* )\n* }\n* ```\n*\n* @example\n* Combining results into a single value:\n* ```tsx\n* import { useQueries } from '@tanstack/react-query'\n*\n* function Posts({ ids }: { ids: Array<number> }) {\n* const { data, isPending, isError } = useQueries({\n* queries: ids.map((id) => ({\n* queryKey: ['post', id],\n* queryFn: () => fetchPost(id),\n* })),\n* combine: (postQueries) => {\n* return {\n* data: postQueries.map((query) => query.data),\n* isPending: postQueries.some((query) => query.isPending),\n* isError: postQueries.some((query) => query.isError),\n* }\n* },\n* })\n*\n* if (isPending) return 'Loading...'\n* if (isError) return 'Error loading posts'\n*\n* return (\n* <ul>\n* {data.map((post) => (\n* <li key={post?.id}>{post?.title}</li>\n* ))}\n* </ul>\n* )\n* }\n* ```\n*\n* @example\n* Typing `select` via {@link queryOptions}. Note that spreading a `queryOptions` result and overriding\n* `select` inline still falls back to `unknown` — wrap the spread in `queryOptions` again so the override is\n* resolved before it reaches `useQueries`:\n* ```tsx\n* import { queryOptions, useQueries } from '@tanstack/react-query'\n*\n* const postOptions = (id: number) =>\n* queryOptions({\n* queryKey: ['post', id],\n* queryFn: () => fetchPost(id),\n* })\n*\n* function PostTitle({ id }: { id: number }) {\n* const [{ data: broken }] = useQueries({\n* queries: [\n* {\n* ...postOptions(id),\n* // ❌ `data` is `unknown` here\n* select: (data) => data.title,\n* },\n* ],\n* })\n*\n* const [{ data: fixed }] = useQueries({\n* queries: [\n* queryOptions({\n* ...postOptions(id),\n* // ✅ `data` is `Post`\n* select: (data) => data.title,\n* }),\n* ],\n* })\n*\n* return <h1>{fixed}</h1>\n* }\n* ```\n*/\nfunction useQueries({ queries, ...options }, queryClient) {\n\tconst client = useQueryClient(queryClient);\n\tconst isRestoring = useIsRestoring();\n\tconst errorResetBoundary = useQueryErrorResetBoundary();\n\tconst subscribed = options.subscribed !== false;\n\tconst defaultedQueries = React.useMemo(() => queries.map((opts) => {\n\t\tconst defaultedOptions = client.defaultQueryOptions(opts);\n\t\tdefaultedOptions._optimisticResults = isRestoring ? \"isRestoring\" : subscribed ? \"optimistic\" : void 0;\n\t\treturn defaultedOptions;\n\t}), [\n\t\tqueries,\n\t\tclient,\n\t\tisRestoring,\n\t\tsubscribed\n\t]);\n\tdefaultedQueries.forEach((queryOptions) => {\n\t\tensureSuspenseTimers(queryOptions);\n\t\tconst query = client.getQueryCache().get(queryOptions.queryHash);\n\t\tensurePreventErrorBoundaryRetry(queryOptions, errorResetBoundary, query);\n\t});\n\tuseClearResetErrorBoundary(errorResetBoundary);\n\tconst [observer] = React.useState(() => new QueriesObserver(client, defaultedQueries, options));\n\tconst [optimisticResult, getCombinedResult, trackResult] = observer.getOptimisticResult(defaultedQueries, options.combine);\n\tconst shouldSubscribe = !isRestoring && subscribed;\n\tReact.useSyncExternalStore(React.useCallback((onStoreChange) => shouldSubscribe ? observer.subscribe(notifyManager.batchCalls(onStoreChange)) : noop, [observer, shouldSubscribe]), () => observer.getCurrentResult(), () => observer.getCurrentResult());\n\tReact.useEffect(() => {\n\t\tobserver.setQueries(defaultedQueries, options);\n\t}, [\n\t\tdefaultedQueries,\n\t\toptions,\n\t\tobserver\n\t]);\n\tconst suspensePromises = optimisticResult.some((result, index) => shouldSuspend(defaultedQueries[index], result)) ? optimisticResult.flatMap((result, index) => {\n\t\tconst opts = defaultedQueries[index];\n\t\tif (opts && shouldSuspend(opts, result)) {\n\t\t\tconst queryObserver = new QueryObserver(client, opts);\n\t\t\treturn fetchOptimistic(opts, queryObserver, errorResetBoundary);\n\t\t}\n\t\treturn [];\n\t}) : [];\n\tif (suspensePromises.length > 0) throw Promise.all(suspensePromises);\n\tconst firstSingleResultWhichShouldThrow = optimisticResult.find((result, index) => {\n\t\tconst query = defaultedQueries[index];\n\t\treturn query && getHasError({\n\t\t\tresult,\n\t\t\terrorResetBoundary,\n\t\t\tthrowOnError: query.throwOnError,\n\t\t\tquery: client.getQueryCache().get(query.queryHash),\n\t\t\tsuspense: query.suspense\n\t\t});\n\t});\n\tif (firstSingleResultWhichShouldThrow) throw firstSingleResultWhichShouldThrow.error;\n\treturn getCombinedResult(trackResult());\n}\n//#endregion\nexport { useQueries };\n\n//# sourceMappingURL=useQueries.js.map"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "FE494B8581FB73F764756E2164756E21",
10
+ "names": []
11
+ }