gemi 0.84.1 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/dist/ai/Agent.d.ts +41 -3
  2. package/dist/ai/Agent.d.ts.map +1 -1
  3. package/dist/ai/AgentController.d.ts +238 -0
  4. package/dist/ai/AgentController.d.ts.map +1 -1
  5. package/dist/ai/AgentProvider.d.ts +15 -0
  6. package/dist/ai/AgentProvider.d.ts.map +1 -1
  7. package/dist/ai/client/index.d.ts +2 -2
  8. package/dist/ai/client/index.d.ts.map +1 -1
  9. package/dist/ai/client/index.js +138 -35
  10. package/dist/ai/client/index.js.map +1 -1
  11. package/dist/ai/client/reducer.d.ts +7 -1
  12. package/dist/ai/client/reducer.d.ts.map +1 -1
  13. package/dist/ai/generate.d.ts.map +1 -1
  14. package/dist/ai/index.d.ts +4 -2
  15. package/dist/ai/index.d.ts.map +1 -1
  16. package/dist/ai/index.js +12 -12
  17. package/dist/ai/index.js.map +19 -16
  18. package/dist/ai/providers/call.d.ts +4 -0
  19. package/dist/ai/providers/call.d.ts.map +1 -1
  20. package/dist/ai/providers/fileRejection.d.ts +84 -0
  21. package/dist/ai/providers/fileRejection.d.ts.map +1 -0
  22. package/dist/ai/providers/request.d.ts.map +1 -1
  23. package/dist/ai/redact.d.ts +70 -0
  24. package/dist/ai/redact.d.ts.map +1 -0
  25. package/dist/ai/signing.d.ts +33 -4
  26. package/dist/ai/signing.d.ts.map +1 -1
  27. package/dist/ai/store/Attachments.d.ts +5 -3
  28. package/dist/ai/store/Attachments.d.ts.map +1 -1
  29. package/dist/ai/store/FileOwners.d.ts +59 -0
  30. package/dist/ai/store/FileOwners.d.ts.map +1 -0
  31. package/dist/ai/store/LiveRuns.d.ts +25 -0
  32. package/dist/ai/store/LiveRuns.d.ts.map +1 -1
  33. package/dist/ai/store/MemoryAgentStore.d.ts +1 -0
  34. package/dist/ai/store/MemoryAgentStore.d.ts.map +1 -1
  35. package/dist/ai/store/Nonces.d.ts +109 -0
  36. package/dist/ai/store/Nonces.d.ts.map +1 -0
  37. package/dist/ai/store/index.d.ts +2 -0
  38. package/dist/ai/store/index.d.ts.map +1 -1
  39. package/dist/ai/types.d.ts +30 -1
  40. package/dist/ai/types.d.ts.map +1 -1
  41. package/dist/ai/useChat.d.ts +62 -3
  42. package/dist/ai/useChat.d.ts.map +1 -1
  43. package/dist/app/index.js +1 -1
  44. package/dist/bun/plugin.js +1 -1
  45. package/dist/bun/preload.js +1 -1
  46. package/dist/{chunk-82nn71zs.js → chunk-09sr33ff.js} +2 -2
  47. package/dist/{chunk-82nn71zs.js.map → chunk-09sr33ff.js.map} +1 -1
  48. package/dist/chunk-174jkg6d.js +7 -0
  49. package/dist/{chunk-302mkqeq.js.map → chunk-174jkg6d.js.map} +9 -8
  50. package/dist/{chunk-87x692j7.js → chunk-1b5s4w5f.js} +2 -2
  51. package/dist/{chunk-87x692j7.js.map → chunk-1b5s4w5f.js.map} +1 -1
  52. package/dist/{chunk-rmv1jp9p.js → chunk-1jcp8m8h.js} +2 -2
  53. package/dist/{chunk-rmv1jp9p.js.map → chunk-1jcp8m8h.js.map} +1 -1
  54. package/dist/{chunk-g6qe6wyb.js → chunk-1w5a11cd.js} +2 -2
  55. package/dist/{chunk-g6qe6wyb.js.map → chunk-1w5a11cd.js.map} +1 -1
  56. package/dist/chunk-1wby1sr2.js +5 -0
  57. package/dist/{chunk-e43drft2.js.map → chunk-1wby1sr2.js.map} +3 -3
  58. package/dist/{chunk-vmpzg4z5.js → chunk-1yq1e6sb.js} +3 -3
  59. package/dist/{chunk-vmpzg4z5.js.map → chunk-1yq1e6sb.js.map} +1 -1
  60. package/dist/chunk-1yzdxv2a.js +5 -0
  61. package/dist/{chunk-tmwsvf02.js.map → chunk-1yzdxv2a.js.map} +1 -1
  62. package/dist/{chunk-ah9ajys0.js → chunk-2gdhcswa.js} +1 -1
  63. package/dist/chunk-2k5kyk0h.js +24 -0
  64. package/dist/chunk-2k5kyk0h.js.map +17 -0
  65. package/dist/{chunk-1evk2pma.js → chunk-2yw23zhn.js} +4 -4
  66. package/dist/{chunk-1evk2pma.js.map → chunk-2yw23zhn.js.map} +1 -1
  67. package/dist/{chunk-3z6wkvwj.js → chunk-4ysar3ev.js} +2 -2
  68. package/dist/{chunk-3z6wkvwj.js.map → chunk-4ysar3ev.js.map} +1 -1
  69. package/dist/{chunk-z409rk5j.js → chunk-4zj05vry.js} +2 -2
  70. package/dist/{chunk-z409rk5j.js.map → chunk-4zj05vry.js.map} +1 -1
  71. package/dist/{chunk-1cebv3h8.js → chunk-55x9kkdt.js} +2 -2
  72. package/dist/{chunk-1cebv3h8.js.map → chunk-55x9kkdt.js.map} +1 -1
  73. package/dist/{chunk-0agfx93f.js → chunk-5ktfpty1.js} +2 -2
  74. package/dist/{chunk-0agfx93f.js.map → chunk-5ktfpty1.js.map} +1 -1
  75. package/dist/chunk-6k2czkkh.js +55 -0
  76. package/dist/{chunk-rp5j1mgk.js.map → chunk-6k2czkkh.js.map} +3 -3
  77. package/dist/{chunk-3zb2ycxj.js → chunk-7c33ngqs.js} +2 -2
  78. package/dist/{chunk-3zb2ycxj.js.map → chunk-7c33ngqs.js.map} +1 -1
  79. package/dist/{chunk-en3mtnsg.js → chunk-7n5775qx.js} +2 -2
  80. package/dist/{chunk-en3mtnsg.js.map → chunk-7n5775qx.js.map} +1 -1
  81. package/dist/{chunk-bn9pzgww.js → chunk-7nj2t2gm.js} +2 -2
  82. package/dist/{chunk-bn9pzgww.js.map → chunk-7nj2t2gm.js.map} +1 -1
  83. package/dist/{chunk-kfavcgv2.js → chunk-81k26w39.js} +2 -2
  84. package/dist/{chunk-kfavcgv2.js.map → chunk-81k26w39.js.map} +1 -1
  85. package/dist/{chunk-cg4k40zy.js → chunk-81v4c4b1.js} +2 -2
  86. package/dist/{chunk-cg4k40zy.js.map → chunk-81v4c4b1.js.map} +1 -1
  87. package/dist/{chunk-wh728wd6.js → chunk-8gexb1gt.js} +2 -2
  88. package/dist/{chunk-wh728wd6.js.map → chunk-8gexb1gt.js.map} +1 -1
  89. package/dist/{chunk-zfch4da5.js → chunk-9tsw1bmt.js} +2 -2
  90. package/dist/{chunk-8mmfpqgs.js.map → chunk-9tsw1bmt.js.map} +1 -1
  91. package/dist/{chunk-m0zba09s.js → chunk-9tv5j3b2.js} +3 -3
  92. package/dist/{chunk-m0zba09s.js.map → chunk-9tv5j3b2.js.map} +1 -1
  93. package/dist/{chunk-jg9eqd3r.js → chunk-c3gzpjba.js} +1 -1
  94. package/dist/{chunk-r5e4vpa1.js → chunk-cbycz5z3.js} +2 -2
  95. package/dist/{chunk-r5e4vpa1.js.map → chunk-cbycz5z3.js.map} +1 -1
  96. package/dist/{chunk-cfvq30n4.js → chunk-cfykfnqx.js} +2 -2
  97. package/dist/{chunk-cfvq30n4.js.map → chunk-cfykfnqx.js.map} +1 -1
  98. package/dist/{chunk-eysexnqb.js → chunk-ct7wxm98.js} +2 -2
  99. package/dist/{chunk-eysexnqb.js.map → chunk-ct7wxm98.js.map} +1 -1
  100. package/dist/{chunk-v27a4se1.js → chunk-d3jkypc7.js} +3 -3
  101. package/dist/{chunk-v27a4se1.js.map → chunk-d3jkypc7.js.map} +1 -1
  102. package/dist/{chunk-vfrrzr10.js → chunk-dadygfkf.js} +2 -2
  103. package/dist/{chunk-vfrrzr10.js.map → chunk-dadygfkf.js.map} +1 -1
  104. package/dist/{chunk-m4xw99vm.js → chunk-dwqh79e5.js} +2 -2
  105. package/dist/{chunk-m4xw99vm.js.map → chunk-dwqh79e5.js.map} +1 -1
  106. package/dist/{chunk-ng8pp9k2.js → chunk-fbwe0agk.js} +2 -2
  107. package/dist/{chunk-ng8pp9k2.js.map → chunk-fbwe0agk.js.map} +1 -1
  108. package/dist/{chunk-495qwteq.js → chunk-fc2je244.js} +3 -3
  109. package/dist/{chunk-495qwteq.js.map → chunk-fc2je244.js.map} +1 -1
  110. package/dist/{chunk-gr61ymse.js → chunk-gx0x772p.js} +2 -2
  111. package/dist/{chunk-gr61ymse.js.map → chunk-gx0x772p.js.map} +1 -1
  112. package/dist/{chunk-tdnfhe7x.js → chunk-ha705bcz.js} +3 -3
  113. package/dist/{chunk-tdnfhe7x.js.map → chunk-ha705bcz.js.map} +1 -1
  114. package/dist/chunk-jhe0t7yj.js +5 -0
  115. package/dist/chunk-jhe0t7yj.js.map +11 -0
  116. package/dist/{chunk-d0qwdeza.js → chunk-k5j65f2c.js} +2 -2
  117. package/dist/{chunk-d0qwdeza.js.map → chunk-k5j65f2c.js.map} +1 -1
  118. package/dist/{chunk-pt59xjfc.js → chunk-kmsrzbx1.js} +2 -2
  119. package/dist/{chunk-pt59xjfc.js.map → chunk-kmsrzbx1.js.map} +1 -1
  120. package/dist/{chunk-v1nm4tcq.js → chunk-m7y8d3k7.js} +2 -2
  121. package/dist/{chunk-v1nm4tcq.js.map → chunk-m7y8d3k7.js.map} +1 -1
  122. package/dist/{chunk-k2qh3hvd.js → chunk-mk8m3ffx.js} +2 -2
  123. package/dist/{chunk-k2qh3hvd.js.map → chunk-mk8m3ffx.js.map} +1 -1
  124. package/dist/{chunk-z7442w3q.js → chunk-mszy6cfw.js} +2 -2
  125. package/dist/{chunk-z7442w3q.js.map → chunk-mszy6cfw.js.map} +1 -1
  126. package/dist/{chunk-kb3xk9r8.js → chunk-ndat0nf0.js} +2 -2
  127. package/dist/{chunk-kb3xk9r8.js.map → chunk-ndat0nf0.js.map} +1 -1
  128. package/dist/{chunk-j9wqzemf.js → chunk-p0m3qgs5.js} +2 -2
  129. package/dist/{chunk-j9wqzemf.js.map → chunk-p0m3qgs5.js.map} +1 -1
  130. package/dist/{chunk-8mmfpqgs.js → chunk-p7r3ecpk.js} +2 -2
  131. package/dist/{chunk-zfch4da5.js.map → chunk-p7r3ecpk.js.map} +1 -1
  132. package/dist/{chunk-zp971jp2.js → chunk-pmmrhak1.js} +3 -3
  133. package/dist/{chunk-zp971jp2.js.map → chunk-pmmrhak1.js.map} +1 -1
  134. package/dist/{chunk-nvj1z2rs.js → chunk-pzwyg474.js} +2 -2
  135. package/dist/{chunk-nvj1z2rs.js.map → chunk-pzwyg474.js.map} +1 -1
  136. package/dist/{chunk-73dk6k4p.js → chunk-qje4kdff.js} +3 -3
  137. package/dist/{chunk-73dk6k4p.js.map → chunk-qje4kdff.js.map} +1 -1
  138. package/dist/{chunk-yk8s5egf.js → chunk-rdnm6rem.js} +2 -2
  139. package/dist/{chunk-yk8s5egf.js.map → chunk-rdnm6rem.js.map} +1 -1
  140. package/dist/{chunk-enf9mdac.js → chunk-s046a984.js} +2 -2
  141. package/dist/{chunk-enf9mdac.js.map → chunk-s046a984.js.map} +1 -1
  142. package/dist/{chunk-1s914cdj.js → chunk-saqfc6vp.js} +3 -3
  143. package/dist/{chunk-1s914cdj.js.map → chunk-saqfc6vp.js.map} +1 -1
  144. package/dist/{chunk-pgpqsgzx.js → chunk-sejnmn1q.js} +1 -1
  145. package/dist/{chunk-xhha1gb3.js → chunk-sjckrbr2.js} +2 -2
  146. package/dist/{chunk-xhha1gb3.js.map → chunk-sjckrbr2.js.map} +1 -1
  147. package/dist/{chunk-r8nhndzb.js → chunk-swhyp0yw.js} +2 -2
  148. package/dist/{chunk-r8nhndzb.js.map → chunk-swhyp0yw.js.map} +1 -1
  149. package/dist/{chunk-wkdzz0rx.js → chunk-trdwxm5x.js} +3 -3
  150. package/dist/{chunk-wkdzz0rx.js.map → chunk-trdwxm5x.js.map} +1 -1
  151. package/dist/{chunk-aztkrzvf.js → chunk-v2hvnxsf.js} +2 -2
  152. package/dist/{chunk-aztkrzvf.js.map → chunk-v2hvnxsf.js.map} +1 -1
  153. package/dist/{chunk-57ryyhh3.js → chunk-v4ngf77f.js} +2 -2
  154. package/dist/{chunk-57ryyhh3.js.map → chunk-v4ngf77f.js.map} +1 -1
  155. package/dist/{chunk-159hyeng.js → chunk-v8nf45gt.js} +2 -2
  156. package/dist/{chunk-159hyeng.js.map → chunk-v8nf45gt.js.map} +1 -1
  157. package/dist/{chunk-ys4fejmx.js → chunk-vwp1g8wh.js} +2 -2
  158. package/dist/{chunk-ys4fejmx.js.map → chunk-vwp1g8wh.js.map} +1 -1
  159. package/dist/chunk-w312e9nx.js +5 -0
  160. package/dist/{chunk-ash9e6fn.js.map → chunk-w312e9nx.js.map} +4 -3
  161. package/dist/{chunk-wwdaswxh.js → chunk-wwzg4dmy.js} +3 -3
  162. package/dist/{chunk-wwdaswxh.js.map → chunk-wwzg4dmy.js.map} +1 -1
  163. package/dist/{chunk-wsx3j5ws.js → chunk-xckeyg3v.js} +2 -2
  164. package/dist/{chunk-wsx3j5ws.js.map → chunk-xckeyg3v.js.map} +1 -1
  165. package/dist/chunk-xx2zg6sk.js +17 -0
  166. package/dist/{chunk-49akdtfe.js.map → chunk-xx2zg6sk.js.map} +11 -12
  167. package/dist/{chunk-rqh2wdhb.js → chunk-y7qnx8vm.js} +2 -2
  168. package/dist/{chunk-rqh2wdhb.js.map → chunk-y7qnx8vm.js.map} +1 -1
  169. package/dist/{chunk-rv7da58g.js → chunk-z4k18gnp.js} +2 -2
  170. package/dist/{chunk-rv7da58g.js.map → chunk-z4k18gnp.js.map} +1 -1
  171. package/dist/{chunk-w099t7zj.js → chunk-zf4r4kat.js} +2 -2
  172. package/dist/{chunk-w099t7zj.js.map → chunk-zf4r4kat.js.map} +1 -1
  173. package/dist/{chunk-dvpxkzms.js → chunk-zs90w6ke.js} +2 -2
  174. package/dist/{chunk-dvpxkzms.js.map → chunk-zs90w6ke.js.map} +1 -1
  175. package/dist/chunks/{ThemeProvider-Dn3UREDn.js → ThemeProvider-D1kDfCwY.js} +59 -2
  176. package/dist/chunks/ThemeProvider-D1kDfCwY.js.map +1 -0
  177. package/dist/client/Link.d.ts.map +1 -1
  178. package/dist/client/MutationError.d.ts +60 -50
  179. package/dist/client/MutationError.d.ts.map +1 -1
  180. package/dist/client/ProgressManager.d.ts +1 -1
  181. package/dist/client/QueryResource.d.ts +20 -0
  182. package/dist/client/QueryResource.d.ts.map +1 -1
  183. package/dist/client/index.d.ts +2 -1
  184. package/dist/client/index.d.ts.map +1 -1
  185. package/dist/client/index.js +109 -35
  186. package/dist/client/index.js.map +1 -1
  187. package/dist/client/useMutation.d.ts.map +1 -1
  188. package/dist/client/useQuery.d.ts.map +1 -1
  189. package/dist/config/index.js +1 -1
  190. package/dist/console/run.js +2 -2
  191. package/dist/console/run.js.map +1 -1
  192. package/dist/container/index.js +2 -2
  193. package/dist/container/index.js.map +1 -1
  194. package/dist/database/index.js +2 -2
  195. package/dist/database/index.js.map +1 -1
  196. package/dist/email/Email.d.ts.map +1 -1
  197. package/dist/email/debugEmail.d.ts +40 -0
  198. package/dist/email/debugEmail.d.ts.map +1 -0
  199. package/dist/email/index.js +4 -3
  200. package/dist/email/index.js.map +6 -5
  201. package/dist/facades/index.js +2 -2
  202. package/dist/facades/index.js.map +1 -1
  203. package/dist/foundation/index.js +2 -2
  204. package/dist/foundation/index.js.map +1 -1
  205. package/dist/http/ApiRouter.d.ts +12 -0
  206. package/dist/http/ApiRouter.d.ts.map +1 -1
  207. package/dist/http/CSRFMiddleware.d.ts +1 -1
  208. package/dist/http/CSRFMiddleware.d.ts.map +1 -1
  209. package/dist/http/Error.d.ts +50 -0
  210. package/dist/http/Error.d.ts.map +1 -1
  211. package/dist/http/HttpRequest.d.ts +26 -0
  212. package/dist/http/HttpRequest.d.ts.map +1 -1
  213. package/dist/http/RateLimitMiddleware.d.ts +6 -3
  214. package/dist/http/RateLimitMiddleware.d.ts.map +1 -1
  215. package/dist/http/Router.d.ts.map +1 -1
  216. package/dist/http/errors.d.ts.map +1 -1
  217. package/dist/http/index.d.ts +2 -1
  218. package/dist/http/index.d.ts.map +1 -1
  219. package/dist/http/index.js +2 -2
  220. package/dist/http/index.js.map +1 -1
  221. package/dist/http/mediaType.d.ts +16 -0
  222. package/dist/http/mediaType.d.ts.map +1 -0
  223. package/dist/http/refusal.d.ts +52 -0
  224. package/dist/http/refusal.d.ts.map +1 -0
  225. package/dist/i18n/dictionaryRuntime.js +2 -2
  226. package/dist/i18n/dictionaryRuntime.js.map +1 -1
  227. package/dist/i18n/index.js +2 -2
  228. package/dist/i18n/index.js.map +2 -2
  229. package/dist/kernel/index.js +2 -2
  230. package/dist/kernel/index.js.map +2 -2
  231. package/dist/orm/index.js +2 -2
  232. package/dist/orm/index.js.map +1 -1
  233. package/dist/server/devFetch.d.ts.map +1 -1
  234. package/dist/server/forwardedFor.d.ts +42 -0
  235. package/dist/server/forwardedFor.d.ts.map +1 -0
  236. package/dist/server/httpProd.d.ts.map +1 -1
  237. package/dist/server/index.js +2 -2
  238. package/dist/server/index.js.map +1 -1
  239. package/dist/server/staticFile.d.ts +33 -0
  240. package/dist/server/staticFile.d.ts.map +1 -0
  241. package/dist/server/unhandledError.d.ts.map +1 -1
  242. package/dist/services/index.js +2 -2
  243. package/dist/services/index.js.map +2 -2
  244. package/dist/services/mcp/McpRegistry.d.ts +2 -1
  245. package/dist/services/mcp/McpRegistry.d.ts.map +1 -1
  246. package/dist/services/mcp/toAgentTools.d.ts +1 -1
  247. package/dist/services/mcp/toAgentTools.d.ts.map +1 -1
  248. package/dist/services/queue/work.js +2 -2
  249. package/dist/services/queue/work.js.map +1 -1
  250. package/dist/services/router/notFound.d.ts.map +1 -1
  251. package/dist/services/router/policyDenied.d.ts.map +1 -1
  252. package/dist/services/router/serverQueryFetcher.d.ts.map +1 -1
  253. package/dist/support/index.js +2 -2
  254. package/dist/support/index.js.map +1 -1
  255. package/dist/testing/index.js +1 -1
  256. package/package.json +1 -1
  257. package/skills/gemi-react-best-practices/rules/controller-throw-framework-errors.md +5 -0
  258. package/dist/chunk-302mkqeq.js +0 -7
  259. package/dist/chunk-49akdtfe.js +0 -17
  260. package/dist/chunk-ash9e6fn.js +0 -5
  261. package/dist/chunk-e43drft2.js +0 -5
  262. package/dist/chunk-j5xcfeqx.js +0 -24
  263. package/dist/chunk-j5xcfeqx.js.map +0 -16
  264. package/dist/chunk-rp5j1mgk.js +0 -55
  265. package/dist/chunk-tmwsvf02.js +0 -5
  266. package/dist/chunks/ThemeProvider-Dn3UREDn.js.map +0 -1
  267. /package/dist/{chunk-ah9ajys0.js.map → chunk-2gdhcswa.js.map} +0 -0
  268. /package/dist/{chunk-jg9eqd3r.js.map → chunk-c3gzpjba.js.map} +0 -0
  269. /package/dist/{chunk-pgpqsgzx.js.map → chunk-sejnmn1q.js.map} +0 -0
@@ -1,3 +1,4 @@
1
+ import { type RefusalKind } from "../http/refusal";
1
2
  /**
2
3
  * What a failed mutation hands `onError` and puts in `error` — `useMutation`
3
4
  * and its `usePost`/`usePut`/`usePatch`/`useDelete` shorthands, `useUpload`,
@@ -10,33 +11,54 @@
10
11
  * member by member, read off the server's error payloads and the client's
11
12
  * fetch code (issue #626).
12
13
  *
13
- * The value is exactly what the response's `error` field held, unchanged — a
14
- * bare string for most refusals — so it is not tagged with the status it came
15
- * with. Use the guards below rather than comparing strings, and
16
- * `mutationErrorKind` to branch on all of them at once.
14
+ * Since 0.85 every refusal is an object with a `kind`, its `message` and the
15
+ * `status` it came with (issue #673). Most refusals were a bare string before,
16
+ * which carried no status, so a refusal thrown with a message of its own could
17
+ * not be told apart from any other string. A server older than 0.85 still sends
18
+ * those strings; the client wraps them into the same object, so the guards and
19
+ * `error.message` work against either.
17
20
  */
18
21
  /** A server-side `ValidationError` (400): messages keyed by field. */
19
22
  export interface MutationValidationError {
20
23
  kind: "validation_error";
21
24
  messages: Record<string, string[]>;
25
+ status?: number;
22
26
  }
23
27
  /**
24
- * A single form-level message, which `<FormError>` renders. gemi never sends
25
- * one itself; a `RequestBreakerError` of the app's own can.
28
+ * A single form-level message, which `<FormError>` renders: a
29
+ * `RequestBreakerError` of the app's own, or any other 4xx that answered a
30
+ * message without a kind of its own.
26
31
  */
27
32
  export interface MutationFormError {
28
33
  kind: "form_error";
29
34
  message: string;
35
+ status?: number;
30
36
  }
31
- /** `useUpload` only: an upload that failed with a body that was not JSON. */
37
+ /**
38
+ * The server failed: an unhandled exception (500; under `gemi dev` the message
39
+ * is the exception's), or a failed `useUpload` whose body was not JSON.
40
+ */
32
41
  export interface MutationServerError {
33
42
  kind: "server_error";
34
43
  message: string;
44
+ status?: number;
35
45
  }
46
+ /** The refusals other than the three above. */
47
+ export type MutationRefusalKind = Exclude<RefusalKind, "validation_error" | "form_error" | "server_error">;
36
48
  /**
37
- * A `{ message }` body: a missing record, file or route (404, `"Not found"`),
38
- * a policy denial (403, `"Forbidden"`), a rate limit (429,
39
- * `"Rate limit exceeded"`) or an unsatisfiable range (416).
49
+ * A refusal: `authentication` (401), `authorization` (`AuthorizationError`,
50
+ * 401), `permission` (`InsufficientPermissionsError` or a policy, 403), `csrf`
51
+ * (403), `not_found` (404), `range_not_satisfiable` (416) or `rate_limit`
52
+ * (429). `message` is the one it was thrown with.
53
+ */
54
+ export interface MutationRefusal<K extends MutationRefusalKind = MutationRefusalKind> {
55
+ kind: K;
56
+ message: string;
57
+ status: number;
58
+ }
59
+ /**
60
+ * @deprecated A `{ message }` body is wrapped into a `MutationRefusal` or
61
+ * `MutationFormError` since 0.85, and `MutationError` no longer includes this.
40
62
  */
41
63
  export interface MutationMessageError {
42
64
  kind?: undefined;
@@ -46,44 +68,35 @@ export interface MutationMessageError {
46
68
  * Every value `onError` receives and `error` holds for a request gemi's server
47
69
  * answered, or failed to reach:
48
70
  *
49
- * - `MutationValidationError`, `MutationFormError`, `MutationServerError` —
50
- * tagged with `kind`.
51
- * - `MutationMessageError` — `{ message }`, see above.
52
- * - `string` — a refusal or failure answered with a bare string:
53
- * `"Authentication error"` (401), `"Not authorized"` (401), `"Insufficient
54
- * permissions"` (403), `"Invalid CSRF token"` (403), `"Internal Server
55
- * Error"` (500; the exception's message under `gemi dev`). A refusal thrown
56
- * with a message of its own arrives as that message.
71
+ * - `MutationValidationError`, `MutationFormError`, `MutationServerError`,
72
+ * `MutationRefusal` — tagged with `kind`, and (from the server) `status`.
57
73
  * - `Error` — raised in the browser: a `TypeError` when the request never got
58
74
  * an answer (offline, DNS, CORS), a `SyntaxError` when the answer was not
59
75
  * JSON (a proxy's HTML error page, say). A throw from an `onSuccess` of
60
76
  * yours is reported through `onError` as well, as whatever it threw.
61
77
  *
62
- * A cancelled request is not an error: `onCanceled` runs and `error` stays
63
- * `null`. A route that answers an error body of its own shape is outside this
64
- * type: a body with an `error` field (`HttpResponse.json({ error }, { status:
65
- * 409 })`) hands over that field, as gemi's own errors do, and any other body
66
- * is handed over whole.
78
+ * Never a string since 0.85. A cancelled request is not an error: `onCanceled`
79
+ * runs and `error` stays `null`. A route that answers an error body of its own
80
+ * shape is outside this type: a body with an `error` field
81
+ * (`HttpResponse.json({ error }, { status: 409 })`) hands over that field, as
82
+ * gemi's own errors do, and any other body is handed over whole. Either is
83
+ * given a `kind` (from the status) and the `status` when it is an object with
84
+ * a string `message` and no `kind`, and becomes one when it is a string.
67
85
  */
68
- export type MutationError = MutationValidationError | MutationFormError | MutationServerError | MutationMessageError | string | Error;
86
+ export type MutationError = MutationValidationError | MutationFormError | MutationServerError | MutationRefusal | Error;
69
87
  /** What `mutationErrorKind` answers, one per guard below. */
70
88
  export type MutationErrorKind = "validation" | "form" | "authentication" | "permission" | "csrf" | "not_found" | "rate_limit" | "server" | "network" | "unknown";
71
- declare const AUTHENTICATION = "Authentication error";
72
- declare const CSRF = "Invalid CSRF token";
73
- declare const SERVER = "Internal Server Error";
74
- type PermissionRefusal = "Insufficient permissions" | "Not authorized";
75
- type MessageOf<M extends string> = MutationMessageError & {
76
- message: M;
77
- };
78
89
  /**
79
90
  * The `MutationError` a non-2xx response's parsed body stands for.
80
91
  *
81
92
  * gemi's own error bodies are `{ error }`, and the value under `error` is what
82
- * the guards above read, so that is what is handed over. An app's body without
83
- * one — `HttpResponse.json({ message: "Taken" }, { status: 409 })` — is handed
84
- * over whole: read as `body.error` it was `undefined`, and a failed request
85
- * left `error` looking like no error at all. A body with no content to hand
86
- * over (`null`) becomes a `{ message }` naming the status.
93
+ * is handed over. An app's body without one —
94
+ * `HttpResponse.json({ message: "Taken" }, { status: 409 })` — is handed over
95
+ * whole. A body with no content (`null`) becomes a refusal naming the status.
96
+ *
97
+ * What is handed over carries `status`, and a `kind` when it has a `message`:
98
+ * a bare string, which servers before 0.85 sent for most refusals, becomes
99
+ * `{ kind, message, status }`, and so does a `{ message }` without a kind.
87
100
  *
88
101
  * @internal
89
102
  */
@@ -93,32 +106,29 @@ export declare function isValidationError(error: unknown): error is MutationVali
93
106
  /** A form-level message, as `<FormError>` renders it. */
94
107
  export declare function isFormError(error: unknown): error is MutationFormError;
95
108
  /** No signed-in user: `AuthenticationError` (401). */
96
- export declare function isAuthenticationError(error: unknown): error is typeof AUTHENTICATION;
109
+ export declare function isAuthenticationError(error: unknown): error is MutationRefusal<"authentication">;
97
110
  /**
98
111
  * A signed-in user who may not do this: `InsufficientPermissionsError` (403),
99
- * `AuthorizationError` (401) or a policy denial (403, `{ message:
100
- * "Forbidden" }`). Recognised by the framework's default messages.
112
+ * `AuthorizationError` (401) or a policy denial (403), whatever message it was
113
+ * thrown with.
101
114
  */
102
- export declare function isPermissionError(error: unknown): error is PermissionRefusal | MessageOf<"Forbidden">;
115
+ export declare function isPermissionError(error: unknown): error is MutationRefusal<"permission" | "authorization">;
103
116
  /** The CSRF cookie is missing or stale (403). A reload fixes it. */
104
- export declare function isCsrfError(error: unknown): error is typeof CSRF;
117
+ export declare function isCsrfError(error: unknown): error is MutationRefusal<"csrf">;
105
118
  /** A missing record, file or route (404). */
106
- export declare function isNotFoundError(error: unknown): error is MessageOf<"Not found">;
119
+ export declare function isNotFoundError(error: unknown): error is MutationRefusal<"not_found">;
107
120
  /** `RateLimitMiddleware` refused the request (429). */
108
- export declare function isRateLimitError(error: unknown): error is MessageOf<"Rate limit exceeded">;
121
+ export declare function isRateLimitError(error: unknown): error is MutationRefusal<"rate_limit">;
109
122
  /**
110
- * The server failed (a production 500), or answered something that is not
111
- * JSON. Under `gemi dev` a 500 carries the exception's message instead, which
112
- * is `"unknown"`.
123
+ * The server failed (a 500, under `gemi dev` too), or answered something that
124
+ * is not JSON.
113
125
  */
114
- export declare function isServerError(error: unknown): error is typeof SERVER | MutationServerError | SyntaxError;
126
+ export declare function isServerError(error: unknown): error is MutationServerError | SyntaxError;
115
127
  /** The request got no answer: offline, DNS, CORS, a dropped connection. */
116
128
  export declare function isNetworkError(error: unknown): error is TypeError;
117
129
  /**
118
130
  * Which of the guards above `error` passes, for a `switch` over all of them.
119
- * `"unknown"` is everything else: a refusal thrown with a message of its own,
120
- * a 500 under `gemi dev`, an error body of the app's own shape.
131
+ * `"unknown"` is everything else: a 416, an error body of the app's own shape.
121
132
  */
122
133
  export declare function mutationErrorKind(error: unknown): MutationErrorKind;
123
- export {};
124
134
  //# sourceMappingURL=MutationError.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MutationError.d.ts","sourceRoot":"","sources":["../../client/MutationError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,sEAAsE;AACtE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,aAAa,GACrB,uBAAuB,GACvB,iBAAiB,GACjB,mBAAmB,GACnB,oBAAoB,GACpB,MAAM,GACN,KAAK,CAAC;AAEV,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GACzB,YAAY,GACZ,MAAM,GACN,gBAAgB,GAChB,YAAY,GACZ,MAAM,GACN,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,SAAS,GACT,SAAS,CAAC;AAUd,QAAA,MAAM,cAAc,yBAAyB,CAAC;AAK9C,QAAA,MAAM,IAAI,uBAAuB,CAAC;AAClC,QAAA,MAAM,MAAM,0BAA0B,CAAC;AAEvC,KAAK,iBAAiB,GAAG,0BAA0B,GAAG,gBAAgB,CAAC;AACvE,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,IAAI,oBAAoB,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC;AAczE;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAQlF;AAED,4DAA4D;AAC5D,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,uBAAuB,CAElC;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAEtE;AAED,sDAAsD;AACtD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,OAAO,cAAc,CAEhC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,iBAAiB,GAAG,SAAS,CAAC,WAAW,CAAC,CAKrD;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,IAAI,CAEhE;AAED,6CAA6C;AAC7C,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,SAAS,CAAC,WAAW,CAAC,CAEjC;AAED,uDAAuD;AACvD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,SAAS,CAAC,qBAAqB,CAAC,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,OAAO,MAAM,GAAG,mBAAmB,GAAG,WAAW,CAM5D;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAWnE"}
1
+ {"version":3,"file":"MutationError.d.ts","sourceRoot":"","sources":["../../client/MutationError.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ export declare class ProgressManager {
7
7
  isTicking: boolean;
8
8
  constructor(subject: Subject<boolean>);
9
9
  getNextIncrement(): number;
10
- getNextInterval(): 1000 | 200 | 100 | 400 | 2000;
10
+ getNextInterval(): 400 | 1000 | 200 | 100 | 2000;
11
11
  nextTick(): Promise<void>;
12
12
  start(): void;
13
13
  end(): void;
@@ -65,6 +65,13 @@ export declare class QueryResource {
65
65
  private seq;
66
66
  private issued;
67
67
  private applied;
68
+ /**
69
+ * The abort controller of every request on the wire, per variant (#659).
70
+ * When the last mounted reader of a variant lets go of it, its requests are
71
+ * aborted: nobody is left to render the answer, and the server sees the
72
+ * disconnect through `req.signal`.
73
+ */
74
+ private controllers;
68
75
  constructor(key: string, initialState: Record<string, any>);
69
76
  /**
70
77
  * Adopt server-prefetched data into the cache.
@@ -128,6 +135,19 @@ export declare class QueryResource {
128
135
  * put on screen.
129
136
  */
130
137
  retain(variantKey: string): () => void;
138
+ /**
139
+ * Abort the variant's requests on the wire once nobody renders it (#659) —
140
+ * e.g. a `search` that changed again before its answer landed. Deferred a
141
+ * task so a reader that lets go and takes hold again in the same commit
142
+ * (StrictMode's double effects, a resubscribe) never cancels anything.
143
+ *
144
+ * A request with no mounted reader at all — a hover `prefetch`, a render
145
+ * that suspended for the first time — is never aborted here: only losing
146
+ * the *last* reader does that.
147
+ */
148
+ private scheduleAbort;
149
+ /** Abort every request on the wire for this variant. */
150
+ private abort;
131
151
  /** How many fetches of this variant have failed in a row (0 after a success). */
132
152
  failureCount(variantKey: string): number;
133
153
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"QueryResource.d.ts","sourceRoot":"","sources":["../../client/QueryResource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAIF,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC,qBAAa,aAAa;IACxB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACnC,aAAa,cAAqB;IAClC,eAAe,sBAA6B;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAqB;IACrC;;;;;OAKG;IACH,OAAO,CAAC,OAAO,CAA+B;IAC9C;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAA6B;IAC7C;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAA6B;IAC7C;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAoD;IACvE;;;;;;;;OAQG;IACH,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,OAAO,CAA6B;gBAEhC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAM1D;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS;IAwC5D,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,OAAO;IAQf;;;;;;;;;;OAUG;IACH,IAAI,CAAC,UAAU,EAAE,MAAM;IAIvB;;;;;;;;OAQG;IACH,IAAI,CACF,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA2B,GACrC;QAAE,KAAK,CAAC,EAAE,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE;IA+B7C,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B;IA2BrE;;;;;;;;;;OAUG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B;IAcrE;;;;OAIG;IACH,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM;IAe9B;;;;OAIG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,IAAI;IAiBtC,iFAAiF;IACjF,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIxC;;;;;OAKG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAqB/C,WAAW,CAAC,UAAU,EAAE,MAAM;IAQ9B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM;IAQ3B,2EAA2E;IAC3E,WAAW,IAAI,MAAM,EAAE;IAIvB;;;;;OAKG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG;IAgBtD,OAAO,CAAC,aAAa;IAiBrB,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,GAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAoB;IA8BlE,OAAO,CAAC,UAAU,EAAE,MAAM;IAI1B,4EAA4E;IAC5E,OAAO,CAAC,WAAW;YAIL,cAAc;CAwI7B"}
1
+ {"version":3,"file":"QueryResource.d.ts","sourceRoot":"","sources":["../../client/QueryResource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,GAAG,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAIF,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC,qBAAa,aAAa;IACxB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACnC,aAAa,cAAqB;IAClC,eAAe,sBAA6B;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAqB;IACrC;;;;;OAKG;IACH,OAAO,CAAC,OAAO,CAA+B;IAC9C;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAA6B;IAC7C;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAA6B;IAC7C;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAoD;IACvE;;;;;;;;OAQG;IACH,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,OAAO,CAA6B;IAC5C;;;;;OAKG;IACH,OAAO,CAAC,WAAW,CAA2C;gBAElD,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAM1D;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS;IAwC5D,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,OAAO;IAQf;;;;;;;;;;OAUG;IACH,IAAI,CAAC,UAAU,EAAE,MAAM;IAIvB;;;;;;;;OAQG;IACH,IAAI,CACF,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA2B,GACrC;QAAE,KAAK,CAAC,EAAE,KAAK,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE;IA+B7C,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B;IA2BrE;;;;;;;;;;OAUG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B;IAcrE;;;;OAIG;IACH,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM;IAe9B;;;;OAIG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,IAAI;IAkBtC;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAQrB,wDAAwD;IACxD,OAAO,CAAC,KAAK;IASb,iFAAiF;IACjF,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIxC;;;;;OAKG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAqB/C,WAAW,CAAC,UAAU,EAAE,MAAM;IAQ9B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM;IAQ3B,2EAA2E;IAC3E,WAAW,IAAI,MAAM,EAAE;IAIvB;;;;;OAKG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG;IAgBtD,OAAO,CAAC,aAAa;IAiBrB,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,GAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAoB;IA8BlE,OAAO,CAAC,UAAU,EAAE,MAAM;IAI1B,4EAA4E;IAC5E,OAAO,CAAC,WAAW;YAIL,cAAc;CAsK7B"}
@@ -9,7 +9,8 @@ export type { QueryFailure, RetryOption, RetryDelayOption, } from "./retryPolicy
9
9
  export { useMutation, useDelete, usePatch, usePost, usePut, useUpload } from "./useMutation";
10
10
  export { useMutate } from "./useMutate";
11
11
  export { isValidationError, isFormError, isAuthenticationError, isPermissionError, isCsrfError, isNotFoundError, isRateLimitError, isServerError, isNetworkError, mutationErrorKind, } from "./MutationError";
12
- export type { MutationError, MutationErrorKind, MutationValidationError, MutationFormError, MutationServerError, MutationMessageError, } from "./MutationError";
12
+ export type { MutationError, MutationErrorKind, MutationValidationError, MutationFormError, MutationServerError, MutationRefusal, MutationRefusalKind, MutationMessageError, } from "./MutationError";
13
+ export type { RefusalKind } from "../http/refusal";
13
14
  export { Form, FormError, useMutationStatus, useFormStatus, useFormData, FormFieldContainer, ValidationErrors, } from "./Mutation";
14
15
  export { QueryManagerProvider } from "./QueryManagerContext";
15
16
  export type { QueryConfig, UserQueryConfig } from "./QueryManagerContext";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../client/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../client/index.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { A as Action, B as isRetryableQueryError, C as I18nProvider, D as domainUrl, E as useLocation, F as QueryManagerContext, H as shouldRetryQuery, I as QueryManagerProvider, L as USER_QUERY_CONFIG_KEYS, M as toVariantKey, N as applyParams$1, O as isAbsoluteUrl, P as QueryConfigContext, R as pickDefined, S as I18nContext, T as ServerDataProvider, U as QueryError, V as retryDelayFor, W as Subject, _ as readRoutePayload, a as useRouteTransition, b as useSearchParams, c as ComponentsContext, d as loadViewModule, f as subscribeViewModules, g as setActiveLocale, h as registerDictionary, i as RouteTransitionProvider, l as ComponentsProvider, m as loadDictionaryForRender, n as useTheme, o as ClientRouterContext, p as loadDictionary, r as m, s as ClientRouterProvider, t as ThemeProvider, u as initialViewModulesReady, v as routeDataUrl, w as ServerDataContext, x as useNavigate, y as useRoute, z as DEFAULT_STALE_TIME } from "../chunks/ThemeProvider-Dn3UREDn.js";
1
+ import { A as Action, B as isRetryableQueryError, C as I18nProvider, D as domainUrl, E as useLocation, F as QueryManagerContext, H as shouldRetryQuery, I as QueryManagerProvider, L as USER_QUERY_CONFIG_KEYS, M as toVariantKey, N as applyParams$1, O as isAbsoluteUrl, P as QueryConfigContext, R as pickDefined, S as I18nContext, T as ServerDataProvider, U as QueryError, V as retryDelayFor, W as Subject, _ as readRoutePayload, a as useRouteTransition, b as useSearchParams, c as ComponentsContext, d as loadViewModule, f as subscribeViewModules, g as setActiveLocale, h as registerDictionary, i as RouteTransitionProvider, l as ComponentsProvider, m as loadDictionaryForRender, n as useTheme, o as ClientRouterContext, p as loadDictionary, r as m, s as ClientRouterProvider, t as ThemeProvider, u as initialViewModulesReady, v as routeDataUrl, w as ServerDataContext, x as useNavigate, y as useRoute, z as DEFAULT_STALE_TIME } from "../chunks/ThemeProvider-D1kDfCwY.js";
2
2
  import { n as RouteStateContext, r as RouteStateProvider, t as useParams } from "../chunks/useParams-BN3XXfmG.js";
3
3
  import { Fragment, StrictMode, Suspense, createContext, createElement, isValidElement, memo, use, useCallback, useContext, useDeferredValue, useEffect, useMemo, useRef, useState, useSyncExternalStore, useTransition } from "react";
4
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -151,6 +151,17 @@ function useFrameworkQuery(url, ...args) {
151
151
  const searchHint = variantKey ? `, { search: ${JSON.stringify(Object.fromEntries(new URLSearchParams(variantKey)))} }` : "";
152
152
  console.warn(`[gemi] useQuery("${url}") rendered on the server without data. The server never fetches, so this page ships without it and the client suspends after hydration. Add \`Query.prefetch("${url}"${searchHint})\` to the route's view handler.`);
153
153
  }
154
+ useEffect(() => {
155
+ if (!isDeferred) return;
156
+ const targetSeed = configRef.current.fallbackData != null ? { [currentVariantKey]: configRef.current.fallbackData } : prefetchedData?.[currentPath];
157
+ return getResource(currentPath, targetSeed ?? void 0).retain(currentVariantKey);
158
+ }, [
159
+ isDeferred,
160
+ getResource,
161
+ currentPath,
162
+ currentVariantKey,
163
+ prefetchedData
164
+ ]);
154
165
  useEffect(() => {
155
166
  if (fetchedRef.current) resource.getVariant(variantKey, configRef.current.staleTime);
156
167
  }, [variantKey, resource]);
@@ -485,33 +496,82 @@ function useInfiniteQuery(url, options, config) {
485
496
  };
486
497
  }
487
498
  //#endregion
499
+ //#region http/refusal.ts
500
+ /**
501
+ * The kind a status stands for, for a refusal that does not name one: an app's
502
+ * own `RequestBreakerError`, or an older server's `{ message }`. Any other 4xx
503
+ * is a `form_error`, a message about this request for `<FormError>` to show.
504
+ */
505
+ function refusalKindForStatus(status) {
506
+ if (status === 401) return "authentication";
507
+ if (status === 403) return "permission";
508
+ if (status === 404) return "not_found";
509
+ if (status === 416) return "range_not_satisfiable";
510
+ if (status === 429) return "rate_limit";
511
+ if (status >= 500) return "server_error";
512
+ return "form_error";
513
+ }
514
+ //#endregion
488
515
  //#region client/MutationError.ts
489
- var AUTHENTICATION = "Authentication error";
490
- var PERMISSION = ["Insufficient permissions", "Not authorized"];
491
- var CSRF = "Invalid CSRF token";
492
- var SERVER = "Internal Server Error";
516
+ var LEGACY_MESSAGES = {
517
+ "Authentication error": "authentication",
518
+ "Not authorized": "authorization",
519
+ "Insufficient permissions": "permission",
520
+ "Invalid CSRF token": "csrf",
521
+ "Internal Server Error": "server_error",
522
+ Forbidden: "permission",
523
+ "Not found": "not_found",
524
+ "Rate limit exceeded": "rate_limit"
525
+ };
493
526
  function isObject(error) {
494
527
  return typeof error === "object" && error !== null;
495
528
  }
496
- function bodyMessage(error) {
497
- return isObject(error) && !(error instanceof Error) && !("kind" in error) ? error.message : void 0;
529
+ function legacyKind(message, status) {
530
+ return LEGACY_MESSAGES[message] ?? (status === 401 ? "authorization" : refusalKindForStatus(status));
498
531
  }
499
532
  /**
500
533
  * The `MutationError` a non-2xx response's parsed body stands for.
501
534
  *
502
535
  * gemi's own error bodies are `{ error }`, and the value under `error` is what
503
- * the guards above read, so that is what is handed over. An app's body without
504
- * one — `HttpResponse.json({ message: "Taken" }, { status: 409 })` — is handed
505
- * over whole: read as `body.error` it was `undefined`, and a failed request
506
- * left `error` looking like no error at all. A body with no content to hand
507
- * over (`null`) becomes a `{ message }` naming the status.
536
+ * is handed over. An app's body without one —
537
+ * `HttpResponse.json({ message: "Taken" }, { status: 409 })` — is handed over
538
+ * whole. A body with no content (`null`) becomes a refusal naming the status.
539
+ *
540
+ * What is handed over carries `status`, and a `kind` when it has a `message`:
541
+ * a bare string, which servers before 0.85 sent for most refusals, becomes
542
+ * `{ kind, message, status }`, and so does a `{ message }` without a kind.
508
543
  *
509
544
  * @internal
510
545
  */
511
546
  function mutationErrorFromBody(body, status) {
512
- if (isObject(body) && "error" in body && body.error != null) return body.error;
513
- if (body == null) return { message: `Request failed with status ${status}` };
514
- return body;
547
+ const error = isObject(body) && "error" in body && body.error != null ? body.error : body;
548
+ if (error == null) return {
549
+ kind: refusalKindForStatus(status),
550
+ message: `Request failed with status ${status}`,
551
+ status
552
+ };
553
+ if (typeof error === "string") return {
554
+ kind: legacyKind(error, status),
555
+ message: error,
556
+ status
557
+ };
558
+ if (!isObject(error) || error instanceof Error) return error;
559
+ const withStatus = {
560
+ ...error,
561
+ status: typeof error.status === "number" ? error.status : status
562
+ };
563
+ if (typeof error.kind !== "string" && typeof error.message === "string") return {
564
+ ...withStatus,
565
+ kind: refusalKindForStatus(withStatus.status)
566
+ };
567
+ return withStatus;
568
+ }
569
+ function kindOf(error) {
570
+ if (typeof error === "string") return LEGACY_MESSAGES[error];
571
+ if (!isObject(error) || error instanceof Error) return void 0;
572
+ if (typeof error.kind === "string") return error.kind;
573
+ if (typeof error.status === "number") return refusalKindForStatus(error.status);
574
+ return typeof error.message === "string" ? LEGACY_MESSAGES[error.message] : void 0;
515
575
  }
516
576
  /** Field messages, as `<ValidationErrors>` renders them. */
517
577
  function isValidationError(error) {
@@ -523,35 +583,35 @@ function isFormError(error) {
523
583
  }
524
584
  /** No signed-in user: `AuthenticationError` (401). */
525
585
  function isAuthenticationError(error) {
526
- return error === AUTHENTICATION;
586
+ return kindOf(error) === "authentication";
527
587
  }
528
588
  /**
529
589
  * A signed-in user who may not do this: `InsufficientPermissionsError` (403),
530
- * `AuthorizationError` (401) or a policy denial (403, `{ message:
531
- * "Forbidden" }`). Recognised by the framework's default messages.
590
+ * `AuthorizationError` (401) or a policy denial (403), whatever message it was
591
+ * thrown with.
532
592
  */
533
593
  function isPermissionError(error) {
534
- return typeof error === "string" && PERMISSION.includes(error) || bodyMessage(error) === "Forbidden";
594
+ const kind = kindOf(error);
595
+ return kind === "permission" || kind === "authorization";
535
596
  }
536
597
  /** The CSRF cookie is missing or stale (403). A reload fixes it. */
537
598
  function isCsrfError(error) {
538
- return error === CSRF;
599
+ return kindOf(error) === "csrf";
539
600
  }
540
601
  /** A missing record, file or route (404). */
541
602
  function isNotFoundError(error) {
542
- return bodyMessage(error) === "Not found";
603
+ return kindOf(error) === "not_found";
543
604
  }
544
605
  /** `RateLimitMiddleware` refused the request (429). */
545
606
  function isRateLimitError(error) {
546
- return bodyMessage(error) === "Rate limit exceeded";
607
+ return kindOf(error) === "rate_limit";
547
608
  }
548
609
  /**
549
- * The server failed (a production 500), or answered something that is not
550
- * JSON. Under `gemi dev` a 500 carries the exception's message instead, which
551
- * is `"unknown"`.
610
+ * The server failed (a 500, under `gemi dev` too), or answered something that
611
+ * is not JSON.
552
612
  */
553
613
  function isServerError(error) {
554
- return error === SERVER || isObject(error) && error.kind === "server_error" || error instanceof SyntaxError;
614
+ return kindOf(error) === "server_error" || error instanceof SyntaxError;
555
615
  }
556
616
  /** The request got no answer: offline, DNS, CORS, a dropped connection. */
557
617
  function isNetworkError(error) {
@@ -559,8 +619,7 @@ function isNetworkError(error) {
559
619
  }
560
620
  /**
561
621
  * Which of the guards above `error` passes, for a `switch` over all of them.
562
- * `"unknown"` is everything else: a refusal thrown with a message of its own,
563
- * a 500 under `gemi dev`, an error body of the app's own shape.
622
+ * `"unknown"` is everything else: a 416, an error body of the app's own shape.
564
623
  */
565
624
  function mutationErrorKind(error) {
566
625
  if (isValidationError(error)) return "validation";
@@ -773,7 +832,8 @@ function useUpload(url, ...args) {
773
832
  if (outcome.status < 200 || outcome.status > 299) {
774
833
  let error = {
775
834
  kind: "server_error",
776
- message: outcome.statusText
835
+ message: outcome.statusText,
836
+ status: outcome.status
777
837
  };
778
838
  try {
779
839
  error = mutationErrorFromBody(JSON.parse(outcome.body), outcome.status);
@@ -1135,6 +1195,21 @@ var Link = memo((props) => {
1135
1195
  }
1136
1196
  return /* @__PURE__ */ jsx(RouteLink, { ...props });
1137
1197
  });
1198
+ /**
1199
+ * Clicks the router must not take over, so the browser does what it would for a
1200
+ * plain anchor: a new tab or window for `target="_blank"` and for cmd/ctrl/
1201
+ * shift/alt-clicks, the context action for a middle click, a file for
1202
+ * `download`, and nothing at all when a handler has already cancelled the click.
1203
+ */
1204
+ function leaveClickToBrowser(event) {
1205
+ if (event.defaultPrevented) return true;
1206
+ if (event.button !== 0) return true;
1207
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return true;
1208
+ const anchor = event.currentTarget;
1209
+ const target = anchor.getAttribute("target");
1210
+ if (target && target !== "_self") return true;
1211
+ return anchor.hasAttribute("download");
1212
+ }
1138
1213
  var RouteLink = memo((props) => {
1139
1214
  const _params = useParams();
1140
1215
  const { isTransitioning, targetPath } = useRouteTransition();
@@ -1227,15 +1302,14 @@ var RouteLink = memo((props) => {
1227
1302
  "data-pending": isTransitioning && resolvedPath === targetPath,
1228
1303
  href: targetHref === "" ? "/" : targetHref,
1229
1304
  onClick: (e) => {
1230
- if (typeof window !== "undefined") {
1231
- if (currentHref === targetHref) {
1232
- e.preventDefault();
1233
- return;
1234
- }
1305
+ onClick?.(e);
1306
+ if (leaveClickToBrowser(e)) return;
1307
+ if (currentHref === targetHref) {
1308
+ e.preventDefault();
1309
+ return;
1235
1310
  }
1236
1311
  let currentPath = window.location.pathname.replace(localeSegment, "");
1237
1312
  currentPath = currentPath === "" ? "/" : currentPath;
1238
- onClick?.(e);
1239
1313
  if (hash === "") e.preventDefault();
1240
1314
  push(href, {
1241
1315
  hash,